1203930Srpaulo/* 2203930Srpaulo * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3203930Srpaulo * Copyright (c) 2002-2008 Atheros Communications, Inc. 4203930Srpaulo * 5203930Srpaulo * Permission to use, copy, modify, and/or distribute this software for any 6203930Srpaulo * purpose with or without fee is hereby granted, provided that the above 7203930Srpaulo * copyright notice and this permission notice appear in all copies. 8203930Srpaulo * 9203930Srpaulo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10203930Srpaulo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11203930Srpaulo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12203930Srpaulo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13203930Srpaulo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14203930Srpaulo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15203930Srpaulo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16203930Srpaulo * 17203930Srpaulo * $FreeBSD$ 18203930Srpaulo */ 19203930Srpaulo 20203930Srpaulo/* 21203930Srpaulo * This is almost the same as ar5416_reset.c but uses the v4k EEPROM and 22203930Srpaulo * supports only 2Ghz operation. 23203930Srpaulo */ 24203930Srpaulo 25203930Srpaulo#include "opt_ah.h" 26203930Srpaulo 27203930Srpaulo#include "ah.h" 28203930Srpaulo#include "ah_internal.h" 29203930Srpaulo#include "ah_devid.h" 30203930Srpaulo 31203930Srpaulo#include "ah_eeprom_v14.h" 32203930Srpaulo#include "ah_eeprom_v4k.h" 33203930Srpaulo 34217631Sadrian#include "ar9002/ar9285.h" 35203930Srpaulo#include "ar5416/ar5416.h" 36203930Srpaulo#include "ar5416/ar5416reg.h" 37203930Srpaulo#include "ar5416/ar5416phy.h" 38220590Sadrian#include "ar9002/ar9002phy.h" 39219627Sadrian#include "ar9002/ar9285phy.h" 40221806Sadrian#include "ar9002/ar9285an.h" 41251655Sadrian#include "ar9002/ar9285_diversity.h" 42219627Sadrian 43203930Srpaulo/* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */ 44203930Srpaulo#define EEP_MINOR(_ah) \ 45203930Srpaulo (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK) 46203930Srpaulo#define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2) 47203930Srpaulo#define IS_EEP_MINOR_V3(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3) 48203930Srpaulo 49203930Srpaulo/* Additional Time delay to wait after activiting the Base band */ 50203930Srpaulo#define BASE_ACTIVATE_DELAY 100 /* 100 usec */ 51203930Srpaulo#define PLL_SETTLE_DELAY 300 /* 300 usec */ 52203930Srpaulo#define RTC_PLL_SETTLE_DELAY 1000 /* 1 ms */ 53203930Srpaulo 54203930Srpaulostatic HAL_BOOL ar9285SetPowerPerRateTable(struct ath_hal *ah, 55203930Srpaulo struct ar5416eeprom_4k *pEepData, 56203930Srpaulo const struct ieee80211_channel *chan, int16_t *ratesArray, 57203930Srpaulo uint16_t cfgCtl, uint16_t AntennaReduction, 58203930Srpaulo uint16_t twiceMaxRegulatoryPower, 59203930Srpaulo uint16_t powerLimit); 60203930Srpaulostatic HAL_BOOL ar9285SetPowerCalTable(struct ath_hal *ah, 61203930Srpaulo struct ar5416eeprom_4k *pEepData, 62203930Srpaulo const struct ieee80211_channel *chan, 63203930Srpaulo int16_t *pTxPowerIndexOffset); 64203930Srpaulostatic void ar9285GetGainBoundariesAndPdadcs(struct ath_hal *ah, 65203930Srpaulo const struct ieee80211_channel *chan, CAL_DATA_PER_FREQ_4K *pRawDataSet, 66203930Srpaulo uint8_t * bChans, uint16_t availPiers, 67203930Srpaulo uint16_t tPdGainOverlap, int16_t *pMinCalPower, 68203930Srpaulo uint16_t * pPdGainBoundaries, uint8_t * pPDADCValues, 69203930Srpaulo uint16_t numXpdGains); 70203930Srpaulo 71203930SrpauloHAL_BOOL 72203930Srpauloar9285SetTransmitPower(struct ath_hal *ah, 73203930Srpaulo const struct ieee80211_channel *chan, uint16_t *rfXpdGain) 74203930Srpaulo{ 75203930Srpaulo#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) 76203930Srpaulo#define N(a) (sizeof (a) / sizeof (a[0])) 77203930Srpaulo 78203930Srpaulo MODAL_EEP4K_HEADER *pModal; 79203930Srpaulo struct ath_hal_5212 *ahp = AH5212(ah); 80203930Srpaulo int16_t txPowerIndexOffset = 0; 81203930Srpaulo int i; 82203930Srpaulo 83203930Srpaulo uint16_t cfgCtl; 84203930Srpaulo uint16_t powerLimit; 85203930Srpaulo uint16_t twiceAntennaReduction; 86203930Srpaulo uint16_t twiceMaxRegulatoryPower; 87203930Srpaulo int16_t maxPower; 88203930Srpaulo HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; 89203930Srpaulo struct ar5416eeprom_4k *pEepData = &ee->ee_base; 90203930Srpaulo 91203930Srpaulo HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1); 92203930Srpaulo 93249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc = 2; 94249580Sadrian 95203930Srpaulo /* Setup info for the actual eeprom */ 96249580Sadrian OS_MEMZERO(AH5416(ah)->ah_ratesArray, sizeof(AH5416(ah)->ah_ratesArray)); 97203930Srpaulo cfgCtl = ath_hal_getctl(ah, chan); 98203930Srpaulo powerLimit = chan->ic_maxregpower * 2; 99203930Srpaulo twiceAntennaReduction = chan->ic_maxantgain; 100203930Srpaulo twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit); 101203930Srpaulo pModal = &pEepData->modalHeader; 102203930Srpaulo HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n", 103203930Srpaulo __func__,chan->ic_freq, cfgCtl ); 104203930Srpaulo 105203930Srpaulo if (IS_EEP_MINOR_V2(ah)) { 106249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; 107203930Srpaulo } 108203930Srpaulo 109203930Srpaulo if (!ar9285SetPowerPerRateTable(ah, pEepData, chan, 110249580Sadrian &AH5416(ah)->ah_ratesArray[0],cfgCtl, 111203930Srpaulo twiceAntennaReduction, 112203930Srpaulo twiceMaxRegulatoryPower, powerLimit)) { 113203930Srpaulo HALDEBUG(ah, HAL_DEBUG_ANY, 114203930Srpaulo "%s: unable to set tx power per rate table\n", __func__); 115203930Srpaulo return AH_FALSE; 116203930Srpaulo } 117203930Srpaulo 118203930Srpaulo if (!ar9285SetPowerCalTable(ah, pEepData, chan, &txPowerIndexOffset)) { 119203930Srpaulo HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n", 120203930Srpaulo __func__); 121203930Srpaulo return AH_FALSE; 122203930Srpaulo } 123203930Srpaulo 124249580Sadrian maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb], 125249580Sadrian AH5416(ah)->ah_ratesArray[rateHt20_0]); 126249580Sadrian maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rate1l]); 127203930Srpaulo 128203930Srpaulo if (IEEE80211_IS_CHAN_HT40(chan)) { 129249580Sadrian maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rateHt40_0]); 130203930Srpaulo } 131203930Srpaulo 132203930Srpaulo ahp->ah_tx6PowerInHalfDbm = maxPower; 133203930Srpaulo AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower; 134203930Srpaulo ahp->ah_txPowerIndexOffset = txPowerIndexOffset; 135203930Srpaulo 136203930Srpaulo /* 137203930Srpaulo * txPowerIndexOffset is set by the SetPowerTable() call - 138203930Srpaulo * adjust the rate table (0 offset if rates EEPROM not loaded) 139203930Srpaulo */ 140249580Sadrian for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) { 141249580Sadrian AH5416(ah)->ah_ratesArray[i] = (int16_t)(txPowerIndexOffset + AH5416(ah)->ah_ratesArray[i]); 142219393Sadrian /* -5 dBm offset for Merlin and later; this includes Kite */ 143249580Sadrian AH5416(ah)->ah_ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; 144249580Sadrian if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER) 145249580Sadrian AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER; 146249580Sadrian if (AH5416(ah)->ah_ratesArray[i] < 0) 147249580Sadrian AH5416(ah)->ah_ratesArray[i] = 0; 148203930Srpaulo } 149203930Srpaulo 150203930Srpaulo#ifdef AH_EEPROM_DUMP 151249580Sadrian ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray); 152203930Srpaulo#endif 153203930Srpaulo 154220989Sadrian /* 155220989Sadrian * Adjust the HT40 power to meet the correct target TX power 156220989Sadrian * for 40MHz mode, based on TX power curves that are established 157220989Sadrian * for 20MHz mode. 158220989Sadrian * 159220989Sadrian * XXX handle overflow/too high power level? 160220989Sadrian */ 161203930Srpaulo if (IEEE80211_IS_CHAN_HT40(chan)) { 162249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_0] += 163249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 164249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_1] += 165249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 166249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_2] += 167249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 168249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_3] += 169249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 170249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_4] += 171249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 172249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_5] += 173249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 174249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_6] += 175249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 176249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_7] += 177249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 178203930Srpaulo } 179203930Srpaulo 180220989Sadrian /* Write the TX power rate registers */ 181249580Sadrian ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray); 182220989Sadrian 183203930Srpaulo return AH_TRUE; 184203930Srpaulo#undef POW_SM 185203930Srpaulo#undef N 186203930Srpaulo} 187203930Srpaulo 188219627Sadrianstatic void 189219628Sadrianar9285SetBoardGain(struct ath_hal *ah, const MODAL_EEP4K_HEADER *pModal, 190219627Sadrian const struct ar5416eeprom_4k *eep, uint8_t txRxAttenLocal) 191219627Sadrian{ 192219627Sadrian OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, 193219627Sadrian pModal->antCtrlChain[0]); 194219627Sadrian 195219627Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0), 196219627Sadrian (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)) & 197219627Sadrian ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | 198219627Sadrian AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 199219627Sadrian SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 200219627Sadrian SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 201219627Sadrian 202219627Sadrian if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= 203219627Sadrian AR5416_EEP_MINOR_VER_3) { 204219627Sadrian txRxAttenLocal = pModal->txRxAttenCh[0]; 205219627Sadrian 206219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 207219627Sadrian AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); 208219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 209219627Sadrian AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); 210219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 211219627Sadrian AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, pModal->xatten2Margin[0]); 212219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 213219627Sadrian AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); 214219627Sadrian 215219627Sadrian /* Set the block 1 value to block 0 value */ 216219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 217219627Sadrian AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 218219627Sadrian pModal->bswMargin[0]); 219219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 220219627Sadrian AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); 221219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 222219627Sadrian AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, 223219627Sadrian pModal->xatten2Margin[0]); 224219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 225219627Sadrian AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); 226219627Sadrian } 227219627Sadrian 228219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, 229219627Sadrian AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); 230219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, 231219627Sadrian AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); 232219627Sadrian 233219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, 234219627Sadrian AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); 235219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, 236219627Sadrian AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); 237219627Sadrian} 238219627Sadrian 239219627Sadrian/* 240219627Sadrian * Read EEPROM header info and program the device for correct operation 241219627Sadrian * given the channel value. 242219627Sadrian */ 243203930SrpauloHAL_BOOL 244203930Srpauloar9285SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan) 245203930Srpaulo{ 246219627Sadrian const HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; 247219627Sadrian const struct ar5416eeprom_4k *eep = &ee->ee_base; 248219627Sadrian const MODAL_EEP4K_HEADER *pModal; 249219627Sadrian uint8_t txRxAttenLocal; 250219627Sadrian uint8_t ob[5], db1[5], db2[5]; 251203930Srpaulo 252219627Sadrian pModal = &eep->modalHeader; 253219627Sadrian txRxAttenLocal = 23; 254203930Srpaulo 255219627Sadrian OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 256203930Srpaulo 257219627Sadrian /* Single chain for 4K EEPROM*/ 258219627Sadrian ar9285SetBoardGain(ah, pModal, eep, txRxAttenLocal); 259219627Sadrian 260221694Sadrian /* Initialize Ant Diversity settings if supported */ 261221694Sadrian (void) ar9285SetAntennaSwitch(ah, AH5212(ah)->ah_antControl); 262219627Sadrian 263221694Sadrian /* Configure TX power calibration */ 264219627Sadrian if (pModal->version >= 2) { 265219627Sadrian ob[0] = pModal->ob_0; 266219627Sadrian ob[1] = pModal->ob_1; 267219627Sadrian ob[2] = pModal->ob_2; 268219627Sadrian ob[3] = pModal->ob_3; 269219627Sadrian ob[4] = pModal->ob_4; 270203930Srpaulo 271219627Sadrian db1[0] = pModal->db1_0; 272219627Sadrian db1[1] = pModal->db1_1; 273219627Sadrian db1[2] = pModal->db1_2; 274219627Sadrian db1[3] = pModal->db1_3; 275219627Sadrian db1[4] = pModal->db1_4; 276208712Srpaulo 277219627Sadrian db2[0] = pModal->db2_0; 278219627Sadrian db2[1] = pModal->db2_1; 279219627Sadrian db2[2] = pModal->db2_2; 280219627Sadrian db2[3] = pModal->db2_3; 281219627Sadrian db2[4] = pModal->db2_4; 282219627Sadrian } else if (pModal->version == 1) { 283219627Sadrian ob[0] = pModal->ob_0; 284219627Sadrian ob[1] = ob[2] = ob[3] = ob[4] = pModal->ob_1; 285219627Sadrian db1[0] = pModal->db1_0; 286219627Sadrian db1[1] = db1[2] = db1[3] = db1[4] = pModal->db1_1; 287219627Sadrian db2[0] = pModal->db2_0; 288219627Sadrian db2[1] = db2[2] = db2[3] = db2[4] = pModal->db2_1; 289219627Sadrian } else { 290219627Sadrian int i; 291203930Srpaulo 292219627Sadrian for (i = 0; i < 5; i++) { 293219627Sadrian ob[i] = pModal->ob_0; 294219627Sadrian db1[i] = pModal->db1_0; 295219627Sadrian db2[i] = pModal->db1_0; 296219627Sadrian } 297219627Sadrian } 298203930Srpaulo 299219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_0, ob[0]); 300219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_1, ob[1]); 301219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_2, ob[2]); 302219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_3, ob[3]); 303219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_4, ob[4]); 304203930Srpaulo 305219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_DB1_0, db1[0]); 306219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_DB1_1, db1[1]); 307219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_DB1_2, db1[2]); 308219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB1_3, db1[3]); 309219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB1_4, db1[4]); 310219627Sadrian 311219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_0, db2[0]); 312219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_1, db2[1]); 313219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_2, db2[2]); 314219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_3, db2[3]); 315219627Sadrian OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_4, db2[4]); 316219627Sadrian 317219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, 318219627Sadrian pModal->switchSettling); 319219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, 320219627Sadrian pModal->adcDesiredSize); 321219627Sadrian 322219627Sadrian OS_REG_WRITE(ah, AR_PHY_RF_CTL4, 323219627Sadrian SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | 324219627Sadrian SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | 325219627Sadrian SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | 326219627Sadrian SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); 327219627Sadrian 328219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, 329219627Sadrian pModal->txEndToRxOn); 330219627Sadrian 331219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, 332219627Sadrian pModal->thresh62); 333219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, 334219627Sadrian pModal->thresh62); 335219627Sadrian 336219627Sadrian if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= 337219627Sadrian AR5416_EEP_MINOR_VER_2) { 338219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_DATA_START, 339219627Sadrian pModal->txFrameToDataStart); 340219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_PA_ON, 341219627Sadrian pModal->txFrameToPaOn); 342219627Sadrian } 343219627Sadrian 344219627Sadrian if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= 345219627Sadrian AR5416_EEP_MINOR_VER_3) { 346219627Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) 347219627Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 348219627Sadrian AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); 349219627Sadrian } 350219627Sadrian 351220590Sadrian /* 352220590Sadrian * Program the CCK TX gain factor appropriately if needed. 353220590Sadrian * The AR9285/AR9271 has a non-constant PA tx gain behaviour 354220590Sadrian * for CCK versus OFDM rates; other chips deal with this 355220590Sadrian * differently. 356220590Sadrian * 357220590Sadrian * The mask/shift/multiply hackery is done so place the same 358220590Sadrian * value (bb_desired_scale) into multiple 5-bit fields. 359220590Sadrian * For example, AR_PHY_TX_PWRCTRL9 has bb_desired_scale written 360220590Sadrian * to three fields: (0..4), (5..9) and (10..14). 361220590Sadrian */ 362220590Sadrian if (AR_SREV_9271(ah) || AR_SREV_KITE(ah)) { 363220590Sadrian uint8_t bb_desired_scale = (pModal->bb_scale_smrt_antenna & EEP_4K_BB_DESIRED_SCALE_MASK); 364220590Sadrian if ((eep->baseEepHeader.txGainType == 0) && (bb_desired_scale != 0)) { 365221694Sadrian ath_hal_printf(ah, "[ath]: adjusting cck tx gain factor\n"); 366220590Sadrian uint32_t pwrctrl, mask, clr; 367220590Sadrian 368220590Sadrian mask = (1<<0) | (1<<5) | (1<<10) | (1<<15) | (1<<20) | (1<<25); 369220590Sadrian pwrctrl = mask * bb_desired_scale; 370220590Sadrian clr = mask * 0x1f; 371220590Sadrian OS_REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr); 372220590Sadrian OS_REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr); 373220590Sadrian OS_REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr); 374220590Sadrian 375220590Sadrian mask = (1<<0) | (1<<5) | (1<<15); 376220590Sadrian pwrctrl = mask * bb_desired_scale; 377220590Sadrian clr = mask * 0x1f; 378220590Sadrian OS_REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr); 379220590Sadrian 380220590Sadrian mask = (1<<0) | (1<<5); 381220590Sadrian pwrctrl = mask * bb_desired_scale; 382220590Sadrian clr = mask * 0x1f; 383220590Sadrian OS_REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr); 384220590Sadrian OS_REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr); 385220590Sadrian } 386220590Sadrian } 387220590Sadrian 388219627Sadrian return AH_TRUE; 389203930Srpaulo} 390203930Srpaulo 391203930Srpaulo/* 392203930Srpaulo * Helper functions common for AP/CB/XB 393203930Srpaulo */ 394203930Srpaulo 395203930Srpaulostatic HAL_BOOL 396203930Srpauloar9285SetPowerPerRateTable(struct ath_hal *ah, struct ar5416eeprom_4k *pEepData, 397203930Srpaulo const struct ieee80211_channel *chan, 398203930Srpaulo int16_t *ratesArray, uint16_t cfgCtl, 399203930Srpaulo uint16_t AntennaReduction, 400203930Srpaulo uint16_t twiceMaxRegulatoryPower, 401203930Srpaulo uint16_t powerLimit) 402203930Srpaulo{ 403203930Srpaulo#define N(a) (sizeof(a)/sizeof(a[0])) 404203930Srpaulo/* Local defines to distinguish between extension and control CTL's */ 405203930Srpaulo#define EXT_ADDITIVE (0x8000) 406203930Srpaulo#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) 407203930Srpaulo#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) 408203930Srpaulo 409203930Srpaulo uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 410203930Srpaulo int i; 411203930Srpaulo int16_t twiceLargestAntenna; 412203930Srpaulo CAL_CTL_DATA_4K *rep; 413203930Srpaulo CAL_TARGET_POWER_LEG targetPowerOfdm, targetPowerCck = {0, {0, 0, 0, 0}}; 414203930Srpaulo CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}, targetPowerCckExt = {0, {0, 0, 0, 0}}; 415203930Srpaulo CAL_TARGET_POWER_HT targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0}}; 416203930Srpaulo int16_t scaledPower, minCtlPower; 417203930Srpaulo 418203930Srpaulo#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ 419203930Srpaulo static const uint16_t ctlModesFor11g[] = { 420203930Srpaulo CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 421203930Srpaulo }; 422203930Srpaulo const uint16_t *pCtlMode; 423203930Srpaulo uint16_t numCtlModes, ctlMode, freq; 424203930Srpaulo CHAN_CENTERS centers; 425203930Srpaulo 426203930Srpaulo ar5416GetChannelCenters(ah, chan, ¢ers); 427203930Srpaulo 428203930Srpaulo /* Compute TxPower reduction due to Antenna Gain */ 429203930Srpaulo 430203930Srpaulo twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; 431203930Srpaulo twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0); 432203930Srpaulo 433203930Srpaulo /* XXX setup for 5212 use (really used?) */ 434203930Srpaulo ath_hal_eepromSet(ah, AR_EEP_ANTGAINMAX_2, twiceLargestAntenna); 435203930Srpaulo 436203930Srpaulo /* 437203930Srpaulo * scaledPower is the minimum of the user input power level and 438203930Srpaulo * the regulatory allowed power level 439203930Srpaulo */ 440203930Srpaulo scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna); 441203930Srpaulo 442203930Srpaulo /* Get target powers from EEPROM - our baseline for TX Power */ 443203930Srpaulo /* Setup for CTL modes */ 444203930Srpaulo numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */ 445203930Srpaulo pCtlMode = ctlModesFor11g; 446203930Srpaulo 447203930Srpaulo ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 448203930Srpaulo AR5416_4K_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE); 449203930Srpaulo ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 450203930Srpaulo AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); 451203930Srpaulo ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20, 452203930Srpaulo AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); 453203930Srpaulo 454203930Srpaulo if (IEEE80211_IS_CHAN_HT40(chan)) { 455203930Srpaulo numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */ 456203930Srpaulo 457203930Srpaulo ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40, 458203930Srpaulo AR5416_4K_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); 459203930Srpaulo /* Get target powers for extension channels */ 460203930Srpaulo ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 461203930Srpaulo AR5416_4K_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE); 462203930Srpaulo ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 463203930Srpaulo AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); 464203930Srpaulo } 465203930Srpaulo 466203930Srpaulo /* 467203930Srpaulo * For MIMO, need to apply regulatory caps individually across dynamically 468203930Srpaulo * running modes: CCK, OFDM, HT20, HT40 469203930Srpaulo * 470203930Srpaulo * The outer loop walks through each possible applicable runtime mode. 471203930Srpaulo * The inner loop walks through each ctlIndex entry in EEPROM. 472203930Srpaulo * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. 473203930Srpaulo * 474203930Srpaulo */ 475203930Srpaulo for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { 476203930Srpaulo HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || 477203930Srpaulo (pCtlMode[ctlMode] == CTL_2GHT40); 478203930Srpaulo if (isHt40CtlMode) { 479203930Srpaulo freq = centers.ctl_center; 480203930Srpaulo } else if (pCtlMode[ctlMode] & EXT_ADDITIVE) { 481203930Srpaulo freq = centers.ext_center; 482203930Srpaulo } else { 483203930Srpaulo freq = centers.ctl_center; 484203930Srpaulo } 485203930Srpaulo 486203930Srpaulo /* walk through each CTL index stored in EEPROM */ 487203930Srpaulo for (i = 0; (i < AR5416_4K_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { 488203930Srpaulo uint16_t twiceMinEdgePower; 489203930Srpaulo 490203930Srpaulo /* compare test group from regulatory channel list with test mode from pCtlMode list */ 491203930Srpaulo if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || 492203930Srpaulo (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == 493203930Srpaulo ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { 494203930Srpaulo rep = &(pEepData->ctlData[i]); 495220713Sadrian twiceMinEdgePower = ar5416GetMaxEdgePower(freq, 496203930Srpaulo rep->ctlEdges[ 497220713Sadrian owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1], AH_TRUE); 498203930Srpaulo if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { 499203930Srpaulo /* Find the minimum of all CTL edge powers that apply to this channel */ 500203930Srpaulo twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower); 501203930Srpaulo } else { 502203930Srpaulo /* specific */ 503203930Srpaulo twiceMaxEdgePower = twiceMinEdgePower; 504203930Srpaulo break; 505203930Srpaulo } 506203930Srpaulo } 507203930Srpaulo } 508203930Srpaulo minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower); 509203930Srpaulo /* Apply ctl mode to correct target power set */ 510203930Srpaulo switch(pCtlMode[ctlMode]) { 511203930Srpaulo case CTL_11B: 512203930Srpaulo for (i = 0; i < N(targetPowerCck.tPow2x); i++) { 513203930Srpaulo targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower); 514203930Srpaulo } 515203930Srpaulo break; 516203930Srpaulo case CTL_11A: 517203930Srpaulo case CTL_11G: 518203930Srpaulo for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) { 519203930Srpaulo targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower); 520203930Srpaulo } 521203930Srpaulo break; 522203930Srpaulo case CTL_5GHT20: 523203930Srpaulo case CTL_2GHT20: 524203930Srpaulo for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { 525203930Srpaulo targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower); 526203930Srpaulo } 527203930Srpaulo break; 528203930Srpaulo case CTL_11B_EXT: 529203930Srpaulo targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower); 530203930Srpaulo break; 531203930Srpaulo case CTL_11G_EXT: 532203930Srpaulo targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower); 533203930Srpaulo break; 534203930Srpaulo case CTL_5GHT40: 535203930Srpaulo case CTL_2GHT40: 536203930Srpaulo for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { 537203930Srpaulo targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower); 538203930Srpaulo } 539203930Srpaulo break; 540203930Srpaulo default: 541203930Srpaulo return AH_FALSE; 542203930Srpaulo break; 543203930Srpaulo } 544203930Srpaulo } /* end ctl mode checking */ 545203930Srpaulo 546221834Sadrian /* Set rates Array from collected data */ 547221834Sadrian ar5416SetRatesArrayFromTargetPower(ah, chan, ratesArray, 548221834Sadrian &targetPowerCck, 549221834Sadrian &targetPowerCckExt, 550221834Sadrian &targetPowerOfdm, 551221834Sadrian &targetPowerOfdmExt, 552221834Sadrian &targetPowerHt20, 553221834Sadrian &targetPowerHt40); 554203930Srpaulo 555203930Srpaulo return AH_TRUE; 556203930Srpaulo#undef EXT_ADDITIVE 557203930Srpaulo#undef CTL_11G_EXT 558203930Srpaulo#undef CTL_11B_EXT 559203930Srpaulo#undef SUB_NUM_CTL_MODES_AT_2G_40 560203930Srpaulo#undef N 561203930Srpaulo} 562203930Srpaulo 563203930Srpaulostatic HAL_BOOL 564203930Srpauloar9285SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom_4k *pEepData, 565203930Srpaulo const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset) 566203930Srpaulo{ 567203930Srpaulo CAL_DATA_PER_FREQ_4K *pRawDataset; 568203930Srpaulo uint8_t *pCalBChans = AH_NULL; 569203930Srpaulo uint16_t pdGainOverlap_t2; 570203930Srpaulo static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES]; 571203930Srpaulo uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK]; 572219393Sadrian uint16_t numPiers, i; 573203930Srpaulo int16_t tMinCalPower; 574203930Srpaulo uint16_t numXpdGain, xpdMask; 575219393Sadrian uint16_t xpdGainValues[4]; /* v4k eeprom has 2; the other two stay 0 */ 576219393Sadrian uint32_t regChainOffset; 577203930Srpaulo 578203930Srpaulo OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues)); 579203930Srpaulo 580203930Srpaulo xpdMask = pEepData->modalHeader.xpdGain; 581203930Srpaulo 582203930Srpaulo if (IS_EEP_MINOR_V2(ah)) { 583203930Srpaulo pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; 584203930Srpaulo } else { 585203930Srpaulo pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); 586203930Srpaulo } 587203930Srpaulo 588203930Srpaulo pCalBChans = pEepData->calFreqPier2G; 589203930Srpaulo numPiers = AR5416_4K_NUM_2G_CAL_PIERS; 590203930Srpaulo numXpdGain = 0; 591219393Sadrian 592203930Srpaulo /* Calculate the value of xpdgains from the xpdGain Mask */ 593203930Srpaulo for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { 594203930Srpaulo if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { 595203930Srpaulo if (numXpdGain >= AR5416_4K_NUM_PD_GAINS) { 596203930Srpaulo HALASSERT(0); 597203930Srpaulo break; 598203930Srpaulo } 599203930Srpaulo xpdGainValues[numXpdGain] = (uint16_t)(AR5416_PD_GAINS_IN_MASK - i); 600203930Srpaulo numXpdGain++; 601203930Srpaulo } 602203930Srpaulo } 603203930Srpaulo 604203930Srpaulo /* Write the detector gain biases and their number */ 605219393Sadrian ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues); 606203930Srpaulo 607203930Srpaulo for (i = 0; i < AR5416_MAX_CHAINS; i++) { 608219393Sadrian regChainOffset = ar5416GetRegChainOffset(ah, i); 609203930Srpaulo if (pEepData->baseEepHeader.txMask & (1 << i)) { 610203930Srpaulo pRawDataset = pEepData->calPierData2G[i]; 611203930Srpaulo 612203930Srpaulo ar9285GetGainBoundariesAndPdadcs(ah, chan, pRawDataset, 613203930Srpaulo pCalBChans, numPiers, 614203930Srpaulo pdGainOverlap_t2, 615203930Srpaulo &tMinCalPower, gainBoundaries, 616203930Srpaulo pdadcValues, numXpdGain); 617203930Srpaulo 618221574Sadrian if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { 619203930Srpaulo /* 620203930Srpaulo * Note the pdadc table may not start at 0 dBm power, could be 621203930Srpaulo * negative or greater than 0. Need to offset the power 622203930Srpaulo * values by the amount of minPower for griffin 623203930Srpaulo */ 624219585Sadrian ar5416SetGainBoundariesClosedLoop(ah, i, pdGainOverlap_t2, gainBoundaries); 625203930Srpaulo } 626203930Srpaulo 627203930Srpaulo /* Write the power values into the baseband power table */ 628219585Sadrian ar5416WritePdadcValues(ah, i, pdadcValues); 629203930Srpaulo } 630203930Srpaulo } 631203930Srpaulo *pTxPowerIndexOffset = 0; 632203930Srpaulo 633203930Srpaulo return AH_TRUE; 634203930Srpaulo} 635203930Srpaulo 636203930Srpaulostatic void 637203930Srpauloar9285GetGainBoundariesAndPdadcs(struct ath_hal *ah, 638203930Srpaulo const struct ieee80211_channel *chan, 639203930Srpaulo CAL_DATA_PER_FREQ_4K *pRawDataSet, 640203930Srpaulo uint8_t * bChans, uint16_t availPiers, 641203930Srpaulo uint16_t tPdGainOverlap, int16_t *pMinCalPower, uint16_t * pPdGainBoundaries, 642203930Srpaulo uint8_t * pPDADCValues, uint16_t numXpdGains) 643203930Srpaulo{ 644203930Srpaulo 645203930Srpaulo int i, j, k; 646203930Srpaulo int16_t ss; /* potentially -ve index for taking care of pdGainOverlap */ 647203930Srpaulo uint16_t idxL, idxR, numPiers; /* Pier indexes */ 648203930Srpaulo 649203930Srpaulo /* filled out Vpd table for all pdGains (chanL) */ 650203930Srpaulo static uint8_t vpdTableL[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 651203930Srpaulo 652203930Srpaulo /* filled out Vpd table for all pdGains (chanR) */ 653203930Srpaulo static uint8_t vpdTableR[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 654203930Srpaulo 655203930Srpaulo /* filled out Vpd table for all pdGains (interpolated) */ 656203930Srpaulo static uint8_t vpdTableI[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 657203930Srpaulo 658203930Srpaulo uint8_t *pVpdL, *pVpdR, *pPwrL, *pPwrR; 659203930Srpaulo uint8_t minPwrT4[AR5416_4K_NUM_PD_GAINS]; 660203930Srpaulo uint8_t maxPwrT4[AR5416_4K_NUM_PD_GAINS]; 661203930Srpaulo int16_t vpdStep; 662203930Srpaulo int16_t tmpVal; 663203930Srpaulo uint16_t sizeCurrVpdTable, maxIndex, tgtIndex; 664203930Srpaulo HAL_BOOL match; 665203930Srpaulo int16_t minDelta = 0; 666203930Srpaulo CHAN_CENTERS centers; 667203930Srpaulo 668203930Srpaulo ar5416GetChannelCenters(ah, chan, ¢ers); 669203930Srpaulo 670203930Srpaulo /* Trim numPiers for the number of populated channel Piers */ 671203930Srpaulo for (numPiers = 0; numPiers < availPiers; numPiers++) { 672203930Srpaulo if (bChans[numPiers] == AR5416_BCHAN_UNUSED) { 673203930Srpaulo break; 674203930Srpaulo } 675203930Srpaulo } 676203930Srpaulo 677203930Srpaulo /* Find pier indexes around the current channel */ 678219586Sadrian match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center, 679219586Sadrian IEEE80211_IS_CHAN_2GHZ(chan)), bChans, numPiers, &idxL, &idxR); 680203930Srpaulo 681203930Srpaulo if (match) { 682203930Srpaulo /* Directly fill both vpd tables from the matching index */ 683203930Srpaulo for (i = 0; i < numXpdGains; i++) { 684203930Srpaulo minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; 685203930Srpaulo maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; 686219586Sadrian ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], 687203930Srpaulo pRawDataSet[idxL].pwrPdg[i], 688203930Srpaulo pRawDataSet[idxL].vpdPdg[i], 689203930Srpaulo AR5416_PD_GAIN_ICEPTS, vpdTableI[i]); 690203930Srpaulo } 691203930Srpaulo } else { 692203930Srpaulo for (i = 0; i < numXpdGains; i++) { 693203930Srpaulo pVpdL = pRawDataSet[idxL].vpdPdg[i]; 694203930Srpaulo pPwrL = pRawDataSet[idxL].pwrPdg[i]; 695203930Srpaulo pVpdR = pRawDataSet[idxR].vpdPdg[i]; 696203930Srpaulo pPwrR = pRawDataSet[idxR].pwrPdg[i]; 697203930Srpaulo 698203930Srpaulo /* Start Vpd interpolation from the max of the minimum powers */ 699203930Srpaulo minPwrT4[i] = AH_MAX(pPwrL[0], pPwrR[0]); 700203930Srpaulo 701203930Srpaulo /* End Vpd interpolation from the min of the max powers */ 702203930Srpaulo maxPwrT4[i] = AH_MIN(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); 703203930Srpaulo HALASSERT(maxPwrT4[i] > minPwrT4[i]); 704203930Srpaulo 705203930Srpaulo /* Fill pier Vpds */ 706219586Sadrian ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrL, pVpdL, 707203930Srpaulo AR5416_PD_GAIN_ICEPTS, vpdTableL[i]); 708219586Sadrian ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrR, pVpdR, 709203930Srpaulo AR5416_PD_GAIN_ICEPTS, vpdTableR[i]); 710203930Srpaulo 711203930Srpaulo /* Interpolate the final vpd */ 712203930Srpaulo for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { 713219586Sadrian vpdTableI[i][j] = (uint8_t)(ath_ee_interpolate((uint16_t)FREQ2FBIN(centers.synth_center, 714219586Sadrian IEEE80211_IS_CHAN_2GHZ(chan)), 715203930Srpaulo bChans[idxL], bChans[idxR], vpdTableL[i][j], vpdTableR[i][j])); 716203930Srpaulo } 717203930Srpaulo } 718203930Srpaulo } 719203930Srpaulo *pMinCalPower = (int16_t)(minPwrT4[0] / 2); 720203930Srpaulo 721203930Srpaulo k = 0; /* index for the final table */ 722203930Srpaulo for (i = 0; i < numXpdGains; i++) { 723203930Srpaulo if (i == (numXpdGains - 1)) { 724203930Srpaulo pPdGainBoundaries[i] = (uint16_t)(maxPwrT4[i] / 2); 725203930Srpaulo } else { 726203930Srpaulo pPdGainBoundaries[i] = (uint16_t)((maxPwrT4[i] + minPwrT4[i+1]) / 4); 727203930Srpaulo } 728203930Srpaulo 729203930Srpaulo pPdGainBoundaries[i] = (uint16_t)AH_MIN(AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); 730203930Srpaulo 731203930Srpaulo /* NB: only applies to owl 1.0 */ 732221574Sadrian if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah) ) { 733203930Srpaulo /* 734203930Srpaulo * fix the gain delta, but get a delta that can be applied to min to 735203930Srpaulo * keep the upper power values accurate, don't think max needs to 736203930Srpaulo * be adjusted because should not be at that area of the table? 737203930Srpaulo */ 738203930Srpaulo minDelta = pPdGainBoundaries[0] - 23; 739203930Srpaulo pPdGainBoundaries[0] = 23; 740203930Srpaulo } 741203930Srpaulo else { 742203930Srpaulo minDelta = 0; 743203930Srpaulo } 744203930Srpaulo 745203930Srpaulo /* Find starting index for this pdGain */ 746203930Srpaulo if (i == 0) { 747219475Sadrian if (AR_SREV_MERLIN_20_OR_LATER(ah)) 748219475Sadrian ss = (int16_t)(0 - (minPwrT4[i] / 2)); 749219475Sadrian else 750219475Sadrian ss = 0; /* for the first pdGain, start from index 0 */ 751203930Srpaulo } else { 752203930Srpaulo /* need overlap entries extrapolated below. */ 753203930Srpaulo ss = (int16_t)((pPdGainBoundaries[i-1] - (minPwrT4[i] / 2)) - tPdGainOverlap + 1 + minDelta); 754203930Srpaulo } 755203930Srpaulo vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); 756203930Srpaulo vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 757203930Srpaulo /* 758203930Srpaulo *-ve ss indicates need to extrapolate data below for this pdGain 759203930Srpaulo */ 760203930Srpaulo while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 761203930Srpaulo tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); 762203930Srpaulo pPDADCValues[k++] = (uint8_t)((tmpVal < 0) ? 0 : tmpVal); 763203930Srpaulo ss++; 764203930Srpaulo } 765203930Srpaulo 766203930Srpaulo sizeCurrVpdTable = (uint8_t)((maxPwrT4[i] - minPwrT4[i]) / 2 +1); 767203930Srpaulo tgtIndex = (uint8_t)(pPdGainBoundaries[i] + tPdGainOverlap - (minPwrT4[i] / 2)); 768203930Srpaulo maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; 769203930Srpaulo 770203930Srpaulo while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 771203930Srpaulo pPDADCValues[k++] = vpdTableI[i][ss++]; 772203930Srpaulo } 773203930Srpaulo 774203930Srpaulo vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - vpdTableI[i][sizeCurrVpdTable - 2]); 775203930Srpaulo vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 776203930Srpaulo /* 777203930Srpaulo * for last gain, pdGainBoundary == Pmax_t2, so will 778203930Srpaulo * have to extrapolate 779203930Srpaulo */ 780211307Sadrian if (tgtIndex >= maxIndex) { /* need to extrapolate above */ 781203930Srpaulo while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 782203930Srpaulo tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + 783203930Srpaulo (ss - maxIndex +1) * vpdStep)); 784203930Srpaulo pPDADCValues[k++] = (uint8_t)((tmpVal > 255) ? 255 : tmpVal); 785203930Srpaulo ss++; 786203930Srpaulo } 787203930Srpaulo } /* extrapolated above */ 788203930Srpaulo } /* for all pdGainUsed */ 789203930Srpaulo 790203930Srpaulo /* Fill out pdGainBoundaries - only up to 2 allowed here, but hardware allows up to 4 */ 791203930Srpaulo while (i < AR5416_PD_GAINS_IN_MASK) { 792220946Sadrian pPdGainBoundaries[i] = AR5416_4K_EEP_PD_GAIN_BOUNDARY_DEFAULT; 793203930Srpaulo i++; 794203930Srpaulo } 795203930Srpaulo 796203930Srpaulo while (k < AR5416_NUM_PDADC_VALUES) { 797203930Srpaulo pPDADCValues[k] = pPDADCValues[k-1]; 798203930Srpaulo k++; 799203930Srpaulo } 800203930Srpaulo return; 801203930Srpaulo} 802