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