ar9285_reset.c revision 219627
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 219627 2011-03-14 00:42:48Z 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#include "ar9002/ar9285phy.h" 40 41/* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */ 42#define EEP_MINOR(_ah) \ 43 (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK) 44#define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2) 45#define IS_EEP_MINOR_V3(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3) 46 47/* Additional Time delay to wait after activiting the Base band */ 48#define BASE_ACTIVATE_DELAY 100 /* 100 usec */ 49#define PLL_SETTLE_DELAY 300 /* 300 usec */ 50#define RTC_PLL_SETTLE_DELAY 1000 /* 1 ms */ 51 52static HAL_BOOL ar9285SetPowerPerRateTable(struct ath_hal *ah, 53 struct ar5416eeprom_4k *pEepData, 54 const struct ieee80211_channel *chan, int16_t *ratesArray, 55 uint16_t cfgCtl, uint16_t AntennaReduction, 56 uint16_t twiceMaxRegulatoryPower, 57 uint16_t powerLimit); 58static HAL_BOOL ar9285SetPowerCalTable(struct ath_hal *ah, 59 struct ar5416eeprom_4k *pEepData, 60 const struct ieee80211_channel *chan, 61 int16_t *pTxPowerIndexOffset); 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 241static void 242ath9285SetBoardGain(struct ath_hal *ah, const MODAL_EEP4K_HEADER *pModal, 243 const struct ar5416eeprom_4k *eep, uint8_t txRxAttenLocal) 244{ 245 OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, 246 pModal->antCtrlChain[0]); 247 248 OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0), 249 (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)) & 250 ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | 251 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 252 SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 253 SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 254 255 if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= 256 AR5416_EEP_MINOR_VER_3) { 257 txRxAttenLocal = pModal->txRxAttenCh[0]; 258 259 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 260 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); 261 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 262 AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); 263 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 264 AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, pModal->xatten2Margin[0]); 265 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 266 AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); 267 268 /* Set the block 1 value to block 0 value */ 269 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 270 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 271 pModal->bswMargin[0]); 272 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 273 AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); 274 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 275 AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, 276 pModal->xatten2Margin[0]); 277 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 278 AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); 279 } 280 281 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, 282 AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); 283 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, 284 AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); 285 286 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, 287 AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); 288 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, 289 AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); 290} 291 292/* 293 * Read EEPROM header info and program the device for correct operation 294 * given the channel value. 295 */ 296HAL_BOOL 297ar9285SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan) 298{ 299 const HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; 300 const struct ar5416eeprom_4k *eep = &ee->ee_base; 301 const MODAL_EEP4K_HEADER *pModal; 302 uint8_t txRxAttenLocal; 303 uint8_t ob[5], db1[5], db2[5]; 304 uint8_t ant_div_control1, ant_div_control2; 305 uint32_t regVal; 306 307 pModal = &eep->modalHeader; 308 txRxAttenLocal = 23; 309 310 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 311 312 /* Single chain for 4K EEPROM*/ 313 ar9285SetBoardGain(ah, pModal, eep, txRxAttenLocal); 314 315 /* Initialize Ant Diversity settings from EEPROM */ 316 if (pModal->version >= 3) { 317 ant_div_control1 = pModal->antdiv_ctl1; 318 ant_div_control2 = pModal->antdiv_ctl2; 319 320 regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); 321 regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL)); 322 323 regVal |= SM(ant_div_control1, 324 AR_PHY_9285_ANT_DIV_CTL); 325 regVal |= SM(ant_div_control2, 326 AR_PHY_9285_ANT_DIV_ALT_LNACONF); 327 regVal |= SM((ant_div_control2 >> 2), 328 AR_PHY_9285_ANT_DIV_MAIN_LNACONF); 329 regVal |= SM((ant_div_control1 >> 1), 330 AR_PHY_9285_ANT_DIV_ALT_GAINTB); 331 regVal |= SM((ant_div_control1 >> 2), 332 AR_PHY_9285_ANT_DIV_MAIN_GAINTB); 333 334 OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); 335 regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); 336 regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 337 regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); 338 regVal |= SM((ant_div_control1 >> 3), 339 AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); 340 341 OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); 342 regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 343 } 344 345 if (pModal->version >= 2) { 346 ob[0] = pModal->ob_0; 347 ob[1] = pModal->ob_1; 348 ob[2] = pModal->ob_2; 349 ob[3] = pModal->ob_3; 350 ob[4] = pModal->ob_4; 351 352 db1[0] = pModal->db1_0; 353 db1[1] = pModal->db1_1; 354 db1[2] = pModal->db1_2; 355 db1[3] = pModal->db1_3; 356 db1[4] = pModal->db1_4; 357 358 db2[0] = pModal->db2_0; 359 db2[1] = pModal->db2_1; 360 db2[2] = pModal->db2_2; 361 db2[3] = pModal->db2_3; 362 db2[4] = pModal->db2_4; 363 } else if (pModal->version == 1) { 364 ob[0] = pModal->ob_0; 365 ob[1] = ob[2] = ob[3] = ob[4] = pModal->ob_1; 366 db1[0] = pModal->db1_0; 367 db1[1] = db1[2] = db1[3] = db1[4] = pModal->db1_1; 368 db2[0] = pModal->db2_0; 369 db2[1] = db2[2] = db2[3] = db2[4] = pModal->db2_1; 370 } else { 371 int i; 372 373 for (i = 0; i < 5; i++) { 374 ob[i] = pModal->ob_0; 375 db1[i] = pModal->db1_0; 376 db2[i] = pModal->db1_0; 377 } 378 } 379 380 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_0, ob[0]); 381 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_1, ob[1]); 382 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_2, ob[2]); 383 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_3, ob[3]); 384 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_4, ob[4]); 385 386 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_DB1_0, db1[0]); 387 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_DB1_1, db1[1]); 388 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_DB1_2, db1[2]); 389 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB1_3, db1[3]); 390 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB1_4, db1[4]); 391 392 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_0, db2[0]); 393 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_1, db2[1]); 394 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_2, db2[2]); 395 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_3, db2[3]); 396 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_4, db2[4]); 397 398 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, 399 pModal->switchSettling); 400 OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, 401 pModal->adcDesiredSize); 402 403 OS_REG_WRITE(ah, AR_PHY_RF_CTL4, 404 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | 405 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | 406 SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | 407 SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); 408 409 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, 410 pModal->txEndToRxOn); 411 412 OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, 413 pModal->thresh62); 414 OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, 415 pModal->thresh62); 416 417 if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= 418 AR5416_EEP_MINOR_VER_2) { 419 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_DATA_START, 420 pModal->txFrameToDataStart); 421 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_PA_ON, 422 pModal->txFrameToPaOn); 423 } 424 425 if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= 426 AR5416_EEP_MINOR_VER_3) { 427 if (IEEE80211_IS_CHAN_HT40(chan)) 428 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 429 AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); 430 } 431 432 return AH_TRUE; 433} 434 435/* 436 * Helper functions common for AP/CB/XB 437 */ 438 439static HAL_BOOL 440ar9285SetPowerPerRateTable(struct ath_hal *ah, struct ar5416eeprom_4k *pEepData, 441 const struct ieee80211_channel *chan, 442 int16_t *ratesArray, uint16_t cfgCtl, 443 uint16_t AntennaReduction, 444 uint16_t twiceMaxRegulatoryPower, 445 uint16_t powerLimit) 446{ 447#define N(a) (sizeof(a)/sizeof(a[0])) 448/* Local defines to distinguish between extension and control CTL's */ 449#define EXT_ADDITIVE (0x8000) 450#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) 451#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) 452 453 uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 454 int i; 455 int16_t twiceLargestAntenna; 456 CAL_CTL_DATA_4K *rep; 457 CAL_TARGET_POWER_LEG targetPowerOfdm, targetPowerCck = {0, {0, 0, 0, 0}}; 458 CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}, targetPowerCckExt = {0, {0, 0, 0, 0}}; 459 CAL_TARGET_POWER_HT targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0}}; 460 int16_t scaledPower, minCtlPower; 461 462#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ 463 static const uint16_t ctlModesFor11g[] = { 464 CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 465 }; 466 const uint16_t *pCtlMode; 467 uint16_t numCtlModes, ctlMode, freq; 468 CHAN_CENTERS centers; 469 470 ar5416GetChannelCenters(ah, chan, ¢ers); 471 472 /* Compute TxPower reduction due to Antenna Gain */ 473 474 twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; 475 twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0); 476 477 /* XXX setup for 5212 use (really used?) */ 478 ath_hal_eepromSet(ah, AR_EEP_ANTGAINMAX_2, twiceLargestAntenna); 479 480 /* 481 * scaledPower is the minimum of the user input power level and 482 * the regulatory allowed power level 483 */ 484 scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna); 485 486 /* Get target powers from EEPROM - our baseline for TX Power */ 487 /* Setup for CTL modes */ 488 numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */ 489 pCtlMode = ctlModesFor11g; 490 491 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 492 AR5416_4K_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE); 493 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 494 AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); 495 ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20, 496 AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); 497 498 if (IEEE80211_IS_CHAN_HT40(chan)) { 499 numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */ 500 501 ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40, 502 AR5416_4K_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); 503 /* Get target powers for extension channels */ 504 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 505 AR5416_4K_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE); 506 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 507 AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); 508 } 509 510 /* 511 * For MIMO, need to apply regulatory caps individually across dynamically 512 * running modes: CCK, OFDM, HT20, HT40 513 * 514 * The outer loop walks through each possible applicable runtime mode. 515 * The inner loop walks through each ctlIndex entry in EEPROM. 516 * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. 517 * 518 */ 519 for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { 520 HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || 521 (pCtlMode[ctlMode] == CTL_2GHT40); 522 if (isHt40CtlMode) { 523 freq = centers.ctl_center; 524 } else if (pCtlMode[ctlMode] & EXT_ADDITIVE) { 525 freq = centers.ext_center; 526 } else { 527 freq = centers.ctl_center; 528 } 529 530 /* walk through each CTL index stored in EEPROM */ 531 for (i = 0; (i < AR5416_4K_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { 532 uint16_t twiceMinEdgePower; 533 534 /* compare test group from regulatory channel list with test mode from pCtlMode list */ 535 if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || 536 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == 537 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { 538 rep = &(pEepData->ctlData[i]); 539 twiceMinEdgePower = ar9285GetMaxEdgePower(freq, 540 rep->ctlEdges[ 541 owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1]); 542 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { 543 /* Find the minimum of all CTL edge powers that apply to this channel */ 544 twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower); 545 } else { 546 /* specific */ 547 twiceMaxEdgePower = twiceMinEdgePower; 548 break; 549 } 550 } 551 } 552 minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower); 553 /* Apply ctl mode to correct target power set */ 554 switch(pCtlMode[ctlMode]) { 555 case CTL_11B: 556 for (i = 0; i < N(targetPowerCck.tPow2x); i++) { 557 targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower); 558 } 559 break; 560 case CTL_11A: 561 case CTL_11G: 562 for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) { 563 targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower); 564 } 565 break; 566 case CTL_5GHT20: 567 case CTL_2GHT20: 568 for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { 569 targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower); 570 } 571 break; 572 case CTL_11B_EXT: 573 targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower); 574 break; 575 case CTL_11G_EXT: 576 targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower); 577 break; 578 case CTL_5GHT40: 579 case CTL_2GHT40: 580 for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { 581 targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower); 582 } 583 break; 584 default: 585 return AH_FALSE; 586 break; 587 } 588 } /* end ctl mode checking */ 589 590 /* Set rates Array from collected data */ 591 ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = ratesArray[rate18mb] = ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0]; 592 ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; 593 ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; 594 ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; 595 ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; 596 597 for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { 598 ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; 599 } 600 601 ratesArray[rate1l] = targetPowerCck.tPow2x[0]; 602 ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; 603 ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; 604 ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; 605 if (IEEE80211_IS_CHAN_HT40(chan)) { 606 for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { 607 ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; 608 } 609 ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; 610 ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; 611 ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; 612 if (IEEE80211_IS_CHAN_2GHZ(chan)) { 613 ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; 614 } 615 } 616 return AH_TRUE; 617#undef EXT_ADDITIVE 618#undef CTL_11G_EXT 619#undef CTL_11B_EXT 620#undef SUB_NUM_CTL_MODES_AT_2G_40 621#undef N 622} 623 624/************************************************************************** 625 * fbin2freq 626 * 627 * Get channel value from binary representation held in eeprom 628 * RETURNS: the frequency in MHz 629 */ 630static uint16_t 631fbin2freq(uint8_t fbin) 632{ 633 /* 634 * Reserved value 0xFF provides an empty definition both as 635 * an fbin and as a frequency - do not convert 636 */ 637 if (fbin == AR5416_BCHAN_UNUSED) { 638 return fbin; 639 } 640 641 return (uint16_t)(2300 + fbin); 642} 643 644/* 645 * XXX almost the same as ar5416GetMaxEdgePower. 646 */ 647static uint16_t 648ar9285GetMaxEdgePower(uint16_t freq, CAL_CTL_EDGES *pRdEdgesPower) 649{ 650 uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 651 int i; 652 653 /* Get the edge power */ 654 for (i = 0; (i < AR5416_NUM_BAND_EDGES) && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED) ; i++) { 655 /* 656 * If there's an exact channel match or an inband flag set 657 * on the lower channel use the given rdEdgePower 658 */ 659 if (freq == fbin2freq(pRdEdgesPower[i].bChannel)) { 660 twiceMaxEdgePower = MS(pRdEdgesPower[i].tPowerFlag, CAL_CTL_EDGES_POWER); 661 break; 662 } else if ((i > 0) && (freq < fbin2freq(pRdEdgesPower[i].bChannel))) { 663 if (fbin2freq(pRdEdgesPower[i - 1].bChannel) < freq && (pRdEdgesPower[i - 1].tPowerFlag & CAL_CTL_EDGES_FLAG) != 0) { 664 twiceMaxEdgePower = MS(pRdEdgesPower[i - 1].tPowerFlag, CAL_CTL_EDGES_POWER); 665 } 666 /* Leave loop - no more affecting edges possible in this monotonic increasing list */ 667 break; 668 } 669 } 670 HALASSERT(twiceMaxEdgePower > 0); 671 return twiceMaxEdgePower; 672} 673 674 675 676static HAL_BOOL 677ar9285SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom_4k *pEepData, 678 const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset) 679{ 680 CAL_DATA_PER_FREQ_4K *pRawDataset; 681 uint8_t *pCalBChans = AH_NULL; 682 uint16_t pdGainOverlap_t2; 683 static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES]; 684 uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK]; 685 uint16_t numPiers, i; 686 int16_t tMinCalPower; 687 uint16_t numXpdGain, xpdMask; 688 uint16_t xpdGainValues[4]; /* v4k eeprom has 2; the other two stay 0 */ 689 uint32_t regChainOffset; 690 691 OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues)); 692 693 xpdMask = pEepData->modalHeader.xpdGain; 694 695 if (IS_EEP_MINOR_V2(ah)) { 696 pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; 697 } else { 698 pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); 699 } 700 701 pCalBChans = pEepData->calFreqPier2G; 702 numPiers = AR5416_4K_NUM_2G_CAL_PIERS; 703 numXpdGain = 0; 704 705 /* Calculate the value of xpdgains from the xpdGain Mask */ 706 for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { 707 if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { 708 if (numXpdGain >= AR5416_4K_NUM_PD_GAINS) { 709 HALASSERT(0); 710 break; 711 } 712 xpdGainValues[numXpdGain] = (uint16_t)(AR5416_PD_GAINS_IN_MASK - i); 713 numXpdGain++; 714 } 715 } 716 717 /* Write the detector gain biases and their number */ 718 ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues); 719 720 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 721 regChainOffset = ar5416GetRegChainOffset(ah, i); 722 if (pEepData->baseEepHeader.txMask & (1 << i)) { 723 pRawDataset = pEepData->calPierData2G[i]; 724 725 ar9285GetGainBoundariesAndPdadcs(ah, chan, pRawDataset, 726 pCalBChans, numPiers, 727 pdGainOverlap_t2, 728 &tMinCalPower, gainBoundaries, 729 pdadcValues, numXpdGain); 730 731 if ((i == 0) || AR_SREV_OWL_20_OR_LATER(ah)) { 732 /* 733 * Note the pdadc table may not start at 0 dBm power, could be 734 * negative or greater than 0. Need to offset the power 735 * values by the amount of minPower for griffin 736 */ 737 ar5416SetGainBoundariesClosedLoop(ah, i, pdGainOverlap_t2, gainBoundaries); 738 } 739 740 /* Write the power values into the baseband power table */ 741 ar5416WritePdadcValues(ah, i, pdadcValues); 742 } 743 } 744 *pTxPowerIndexOffset = 0; 745 746 return AH_TRUE; 747} 748 749static void 750ar9285GetGainBoundariesAndPdadcs(struct ath_hal *ah, 751 const struct ieee80211_channel *chan, 752 CAL_DATA_PER_FREQ_4K *pRawDataSet, 753 uint8_t * bChans, uint16_t availPiers, 754 uint16_t tPdGainOverlap, int16_t *pMinCalPower, uint16_t * pPdGainBoundaries, 755 uint8_t * pPDADCValues, uint16_t numXpdGains) 756{ 757 758 int i, j, k; 759 int16_t ss; /* potentially -ve index for taking care of pdGainOverlap */ 760 uint16_t idxL, idxR, numPiers; /* Pier indexes */ 761 762 /* filled out Vpd table for all pdGains (chanL) */ 763 static uint8_t vpdTableL[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 764 765 /* filled out Vpd table for all pdGains (chanR) */ 766 static uint8_t vpdTableR[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 767 768 /* filled out Vpd table for all pdGains (interpolated) */ 769 static uint8_t vpdTableI[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 770 771 uint8_t *pVpdL, *pVpdR, *pPwrL, *pPwrR; 772 uint8_t minPwrT4[AR5416_4K_NUM_PD_GAINS]; 773 uint8_t maxPwrT4[AR5416_4K_NUM_PD_GAINS]; 774 int16_t vpdStep; 775 int16_t tmpVal; 776 uint16_t sizeCurrVpdTable, maxIndex, tgtIndex; 777 HAL_BOOL match; 778 int16_t minDelta = 0; 779 CHAN_CENTERS centers; 780 781 ar5416GetChannelCenters(ah, chan, ¢ers); 782 783 /* Trim numPiers for the number of populated channel Piers */ 784 for (numPiers = 0; numPiers < availPiers; numPiers++) { 785 if (bChans[numPiers] == AR5416_BCHAN_UNUSED) { 786 break; 787 } 788 } 789 790 /* Find pier indexes around the current channel */ 791 match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center, 792 IEEE80211_IS_CHAN_2GHZ(chan)), bChans, numPiers, &idxL, &idxR); 793 794 if (match) { 795 /* Directly fill both vpd tables from the matching index */ 796 for (i = 0; i < numXpdGains; i++) { 797 minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; 798 maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; 799 ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], 800 pRawDataSet[idxL].pwrPdg[i], 801 pRawDataSet[idxL].vpdPdg[i], 802 AR5416_PD_GAIN_ICEPTS, vpdTableI[i]); 803 } 804 } else { 805 for (i = 0; i < numXpdGains; i++) { 806 pVpdL = pRawDataSet[idxL].vpdPdg[i]; 807 pPwrL = pRawDataSet[idxL].pwrPdg[i]; 808 pVpdR = pRawDataSet[idxR].vpdPdg[i]; 809 pPwrR = pRawDataSet[idxR].pwrPdg[i]; 810 811 /* Start Vpd interpolation from the max of the minimum powers */ 812 minPwrT4[i] = AH_MAX(pPwrL[0], pPwrR[0]); 813 814 /* End Vpd interpolation from the min of the max powers */ 815 maxPwrT4[i] = AH_MIN(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); 816 HALASSERT(maxPwrT4[i] > minPwrT4[i]); 817 818 /* Fill pier Vpds */ 819 ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrL, pVpdL, 820 AR5416_PD_GAIN_ICEPTS, vpdTableL[i]); 821 ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrR, pVpdR, 822 AR5416_PD_GAIN_ICEPTS, vpdTableR[i]); 823 824 /* Interpolate the final vpd */ 825 for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { 826 vpdTableI[i][j] = (uint8_t)(ath_ee_interpolate((uint16_t)FREQ2FBIN(centers.synth_center, 827 IEEE80211_IS_CHAN_2GHZ(chan)), 828 bChans[idxL], bChans[idxR], vpdTableL[i][j], vpdTableR[i][j])); 829 } 830 } 831 } 832 *pMinCalPower = (int16_t)(minPwrT4[0] / 2); 833 834 k = 0; /* index for the final table */ 835 for (i = 0; i < numXpdGains; i++) { 836 if (i == (numXpdGains - 1)) { 837 pPdGainBoundaries[i] = (uint16_t)(maxPwrT4[i] / 2); 838 } else { 839 pPdGainBoundaries[i] = (uint16_t)((maxPwrT4[i] + minPwrT4[i+1]) / 4); 840 } 841 842 pPdGainBoundaries[i] = (uint16_t)AH_MIN(AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); 843 844 /* NB: only applies to owl 1.0 */ 845 if ((i == 0) && !AR_SREV_OWL_20_OR_LATER(ah) ) { 846 /* 847 * fix the gain delta, but get a delta that can be applied to min to 848 * keep the upper power values accurate, don't think max needs to 849 * be adjusted because should not be at that area of the table? 850 */ 851 minDelta = pPdGainBoundaries[0] - 23; 852 pPdGainBoundaries[0] = 23; 853 } 854 else { 855 minDelta = 0; 856 } 857 858 /* Find starting index for this pdGain */ 859 if (i == 0) { 860 if (AR_SREV_MERLIN_20_OR_LATER(ah)) 861 ss = (int16_t)(0 - (minPwrT4[i] / 2)); 862 else 863 ss = 0; /* for the first pdGain, start from index 0 */ 864 } else { 865 /* need overlap entries extrapolated below. */ 866 ss = (int16_t)((pPdGainBoundaries[i-1] - (minPwrT4[i] / 2)) - tPdGainOverlap + 1 + minDelta); 867 } 868 vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); 869 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 870 /* 871 *-ve ss indicates need to extrapolate data below for this pdGain 872 */ 873 while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 874 tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); 875 pPDADCValues[k++] = (uint8_t)((tmpVal < 0) ? 0 : tmpVal); 876 ss++; 877 } 878 879 sizeCurrVpdTable = (uint8_t)((maxPwrT4[i] - minPwrT4[i]) / 2 +1); 880 tgtIndex = (uint8_t)(pPdGainBoundaries[i] + tPdGainOverlap - (minPwrT4[i] / 2)); 881 maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; 882 883 while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 884 pPDADCValues[k++] = vpdTableI[i][ss++]; 885 } 886 887 vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - vpdTableI[i][sizeCurrVpdTable - 2]); 888 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 889 /* 890 * for last gain, pdGainBoundary == Pmax_t2, so will 891 * have to extrapolate 892 */ 893 if (tgtIndex >= maxIndex) { /* need to extrapolate above */ 894 while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 895 tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + 896 (ss - maxIndex +1) * vpdStep)); 897 pPDADCValues[k++] = (uint8_t)((tmpVal > 255) ? 255 : tmpVal); 898 ss++; 899 } 900 } /* extrapolated above */ 901 } /* for all pdGainUsed */ 902 903 /* Fill out pdGainBoundaries - only up to 2 allowed here, but hardware allows up to 4 */ 904 while (i < AR5416_PD_GAINS_IN_MASK) { 905 pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; 906 i++; 907 } 908 909 while (k < AR5416_NUM_PDADC_VALUES) { 910 pPDADCValues[k] = pPDADCValues[k-1]; 911 k++; 912 } 913 return; 914} 915