1222301Sadrian/* 2222301Sadrian * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3222301Sadrian * Copyright (c) 2002-2008 Atheros Communications, Inc. 4222301Sadrian * 5222301Sadrian * Permission to use, copy, modify, and/or distribute this software for any 6222301Sadrian * purpose with or without fee is hereby granted, provided that the above 7222301Sadrian * copyright notice and this permission notice appear in all copies. 8222301Sadrian * 9222301Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10222301Sadrian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11222301Sadrian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12222301Sadrian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13222301Sadrian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14222301Sadrian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15222301Sadrian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16222301Sadrian * 17222301Sadrian * $FreeBSD$ 18222301Sadrian */ 19222301Sadrian 20222301Sadrian#include "opt_ah.h" 21222301Sadrian 22222301Sadrian#include "ah.h" 23222301Sadrian#include "ah_internal.h" 24222301Sadrian#include "ah_devid.h" 25222301Sadrian 26222301Sadrian#include "ah_eeprom_v14.h" 27222301Sadrian#include "ah_eeprom_9287.h" 28222301Sadrian 29222301Sadrian#include "ar5416/ar5416.h" 30222301Sadrian#include "ar5416/ar5416reg.h" 31222301Sadrian#include "ar5416/ar5416phy.h" 32222301Sadrian 33222301Sadrian#include "ar9002/ar9287phy.h" 34222301Sadrian#include "ar9002/ar9287an.h" 35222301Sadrian 36222308Sadrian#include "ar9002/ar9287_olc.h" 37222301Sadrian#include "ar9002/ar9287_reset.h" 38222301Sadrian 39222308Sadrian/* 40222308Sadrian * Set the TX power calibration table per-chain. 41222308Sadrian * 42222308Sadrian * This only supports open-loop TX power control for the AR9287. 43222308Sadrian */ 44222308Sadrianstatic void 45222308Sadrianar9287SetPowerCalTable(struct ath_hal *ah, 46222308Sadrian const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset) 47222308Sadrian{ 48237184Sadrian struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; 49237184Sadrian uint8_t *pCalBChans = NULL; 50237184Sadrian uint16_t pdGainOverlap_t2; 51237184Sadrian uint16_t numPiers = 0, i; 52237184Sadrian uint16_t numXpdGain, xpdMask; 53237184Sadrian uint16_t xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0}; 54237184Sadrian uint32_t regChainOffset; 55222308Sadrian HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 56237184Sadrian struct ar9287_eeprom *pEepData = &ee->ee_base; 57222308Sadrian 58237184Sadrian xpdMask = pEepData->modalHeader.xpdGain; 59222308Sadrian 60237184Sadrian if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= 61237184Sadrian AR9287_EEP_MINOR_VER_2) 62237184Sadrian pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; 63237184Sadrian else 64237184Sadrian pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), 65237184Sadrian AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); 66222308Sadrian 67222308Sadrian /* Note: Kiwi should only be 2ghz.. */ 68237184Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan)) { 69237184Sadrian pCalBChans = pEepData->calFreqPier2G; 70237184Sadrian numPiers = AR9287_NUM_2G_CAL_PIERS; 71237184Sadrian pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0]; 72237184Sadrian AH5416(ah)->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; 73237184Sadrian } 74237184Sadrian numXpdGain = 0; 75222308Sadrian 76237184Sadrian /* Calculate the value of xpdgains from the xpdGain Mask */ 77237184Sadrian for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { 78237184Sadrian if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { 79237184Sadrian if (numXpdGain >= AR5416_NUM_PD_GAINS) 80237184Sadrian break; 81237184Sadrian xpdGainValues[numXpdGain] = 82237184Sadrian (uint16_t)(AR5416_PD_GAINS_IN_MASK-i); 83237184Sadrian numXpdGain++; 84237184Sadrian } 85237184Sadrian } 86222308Sadrian 87237184Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, 88237184Sadrian (numXpdGain - 1) & 0x3); 89237184Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, 90237184Sadrian xpdGainValues[0]); 91237184Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, 92237184Sadrian xpdGainValues[1]); 93237184Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 94237184Sadrian xpdGainValues[2]); 95222308Sadrian 96237184Sadrian for (i = 0; i < AR9287_MAX_CHAINS; i++) { 97237184Sadrian regChainOffset = i * 0x1000; 98222308Sadrian 99237184Sadrian if (pEepData->baseEepHeader.txMask & (1 << i)) { 100237184Sadrian int8_t txPower; 101237184Sadrian pRawDatasetOpenLoop = 102237184Sadrian (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i]; 103237184Sadrian ar9287olcGetTxGainIndex(ah, chan, 104237184Sadrian pRawDatasetOpenLoop, 105237184Sadrian pCalBChans, numPiers, 106237184Sadrian &txPower); 107237184Sadrian ar9287olcSetPDADCs(ah, txPower, i); 108237184Sadrian } 109237184Sadrian } 110222308Sadrian 111237184Sadrian *pTxPowerIndexOffset = 0; 112222308Sadrian} 113222308Sadrian 114222312Sadrian 115222312Sadrian/* XXX hard-coded values? */ 116222312Sadrian#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 117222312Sadrian 118222310Sadrian/* 119222312Sadrian * ar9287SetPowerPerRateTable 120222310Sadrian * 121222312Sadrian * Sets the transmit power in the baseband for the given 122222312Sadrian * operating channel and mode. 123222312Sadrian * 124222312Sadrian * This is like the v14 EEPROM table except the 5GHz code. 125222310Sadrian */ 126222310Sadrianstatic HAL_BOOL 127222312Sadrianar9287SetPowerPerRateTable(struct ath_hal *ah, 128222310Sadrian struct ar9287_eeprom *pEepData, 129222310Sadrian const struct ieee80211_channel *chan, 130222310Sadrian int16_t *ratesArray, uint16_t cfgCtl, 131222312Sadrian uint16_t AntennaReduction, 132222310Sadrian uint16_t twiceMaxRegulatoryPower, 133222310Sadrian uint16_t powerLimit) 134222310Sadrian{ 135222312Sadrian#define N(a) (sizeof(a)/sizeof(a[0])) 136222312Sadrian/* Local defines to distinguish between extension and control CTL's */ 137222312Sadrian#define EXT_ADDITIVE (0x8000) 138222312Sadrian#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) 139222312Sadrian#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) 140222312Sadrian#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) 141222312Sadrian 142222312Sadrian uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 143222310Sadrian int i; 144222312Sadrian int16_t twiceLargestAntenna; 145222312Sadrian struct cal_ctl_data_ar9287 *rep; 146222312Sadrian CAL_TARGET_POWER_LEG targetPowerOfdm; 147222312Sadrian CAL_TARGET_POWER_LEG targetPowerCck = {0, {0, 0, 0, 0}}; 148222312Sadrian CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}; 149222312Sadrian CAL_TARGET_POWER_LEG targetPowerCckExt = {0, {0, 0, 0, 0}}; 150222312Sadrian CAL_TARGET_POWER_HT targetPowerHt20; 151222312Sadrian CAL_TARGET_POWER_HT targetPowerHt40 = {0, {0, 0, 0, 0}}; 152222312Sadrian int16_t scaledPower, minCtlPower; 153222310Sadrian 154222312Sadrian#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ 155222312Sadrian static const uint16_t ctlModesFor11g[] = { 156222312Sadrian CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 157222312Sadrian }; 158222312Sadrian const uint16_t *pCtlMode; 159222312Sadrian uint16_t numCtlModes, ctlMode, freq; 160222312Sadrian CHAN_CENTERS centers; 161222310Sadrian 162222312Sadrian ar5416GetChannelCenters(ah, chan, ¢ers); 163222312Sadrian 164222312Sadrian /* Compute TxPower reduction due to Antenna Gain */ 165222312Sadrian 166222312Sadrian twiceLargestAntenna = AH_MAX( 167222312Sadrian pEepData->modalHeader.antennaGainCh[0], 168222312Sadrian pEepData->modalHeader.antennaGainCh[1]); 169222312Sadrian 170222312Sadrian twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0); 171222312Sadrian 172222312Sadrian /* XXX setup for 5212 use (really used?) */ 173222312Sadrian ath_hal_eepromSet(ah, AR_EEP_ANTGAINMAX_2, twiceLargestAntenna); 174222312Sadrian 175222312Sadrian /* 176222312Sadrian * scaledPower is the minimum of the user input power level and 177222312Sadrian * the regulatory allowed power level 178222312Sadrian */ 179222312Sadrian scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna); 180222312Sadrian 181222312Sadrian /* Reduce scaled Power by number of chains active to get to per chain tx power level */ 182222312Sadrian /* TODO: better value than these? */ 183222312Sadrian switch (owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask)) { 184222312Sadrian case 1: 185222312Sadrian break; 186222312Sadrian case 2: 187222312Sadrian scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; 188222424Sadrian break; 189222312Sadrian default: 190222312Sadrian return AH_FALSE; /* Unsupported number of chains */ 191222312Sadrian } 192222312Sadrian 193222312Sadrian scaledPower = AH_MAX(0, scaledPower); 194222312Sadrian 195222312Sadrian /* Get target powers from EEPROM - our baseline for TX Power */ 196222312Sadrian /* XXX assume channel is 2ghz */ 197222312Sadrian if (1) { 198222312Sadrian /* Setup for CTL modes */ 199222312Sadrian numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */ 200222312Sadrian pCtlMode = ctlModesFor11g; 201222312Sadrian 202222312Sadrian ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 203222312Sadrian AR9287_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE); 204222312Sadrian ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 205222312Sadrian AR9287_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); 206222312Sadrian ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20, 207222312Sadrian AR9287_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); 208222312Sadrian 209222312Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 210222312Sadrian numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */ 211222312Sadrian 212222312Sadrian ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40, 213222312Sadrian AR9287_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); 214222312Sadrian /* Get target powers for extension channels */ 215222312Sadrian ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 216222312Sadrian AR9287_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE); 217222312Sadrian ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 218222312Sadrian AR9287_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); 219222312Sadrian } 220222312Sadrian } 221222312Sadrian 222222312Sadrian /* 223222312Sadrian * For MIMO, need to apply regulatory caps individually across dynamically 224222312Sadrian * running modes: CCK, OFDM, HT20, HT40 225222312Sadrian * 226222312Sadrian * The outer loop walks through each possible applicable runtime mode. 227222312Sadrian * The inner loop walks through each ctlIndex entry in EEPROM. 228222312Sadrian * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. 229222312Sadrian * 230222312Sadrian */ 231222312Sadrian for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { 232222312Sadrian HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || 233222312Sadrian (pCtlMode[ctlMode] == CTL_2GHT40); 234222312Sadrian if (isHt40CtlMode) { 235222312Sadrian freq = centers.ctl_center; 236222312Sadrian } else if (pCtlMode[ctlMode] & EXT_ADDITIVE) { 237222312Sadrian freq = centers.ext_center; 238222312Sadrian } else { 239222312Sadrian freq = centers.ctl_center; 240222312Sadrian } 241222312Sadrian 242222312Sadrian /* walk through each CTL index stored in EEPROM */ 243222312Sadrian for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { 244222312Sadrian uint16_t twiceMinEdgePower; 245222312Sadrian 246222312Sadrian /* compare test group from regulatory channel list with test mode from pCtlMode list */ 247222312Sadrian if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || 248222312Sadrian (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == 249222312Sadrian ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { 250222312Sadrian rep = &(pEepData->ctlData[i]); 251222312Sadrian twiceMinEdgePower = ar5416GetMaxEdgePower(freq, 252222312Sadrian rep->ctlEdges[owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1], 253222312Sadrian IEEE80211_IS_CHAN_2GHZ(chan)); 254222312Sadrian if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { 255222312Sadrian /* Find the minimum of all CTL edge powers that apply to this channel */ 256222312Sadrian twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower); 257222312Sadrian } else { 258222312Sadrian /* specific */ 259222312Sadrian twiceMaxEdgePower = twiceMinEdgePower; 260222312Sadrian break; 261222312Sadrian } 262222312Sadrian } 263222312Sadrian } 264222312Sadrian minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower); 265222312Sadrian /* Apply ctl mode to correct target power set */ 266222312Sadrian switch(pCtlMode[ctlMode]) { 267222312Sadrian case CTL_11B: 268222312Sadrian for (i = 0; i < N(targetPowerCck.tPow2x); i++) { 269222312Sadrian targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower); 270222312Sadrian } 271222312Sadrian break; 272222312Sadrian case CTL_11A: 273222312Sadrian case CTL_11G: 274222312Sadrian for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) { 275222312Sadrian targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower); 276222312Sadrian } 277222312Sadrian break; 278222312Sadrian case CTL_5GHT20: 279222312Sadrian case CTL_2GHT20: 280222312Sadrian for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { 281222312Sadrian targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower); 282222312Sadrian } 283222312Sadrian break; 284222312Sadrian case CTL_11B_EXT: 285222312Sadrian targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower); 286222312Sadrian break; 287222312Sadrian case CTL_11A_EXT: 288222312Sadrian case CTL_11G_EXT: 289222312Sadrian targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower); 290222312Sadrian break; 291222312Sadrian case CTL_5GHT40: 292222312Sadrian case CTL_2GHT40: 293222312Sadrian for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { 294222312Sadrian targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower); 295222312Sadrian } 296222312Sadrian break; 297222312Sadrian default: 298222312Sadrian return AH_FALSE; 299222312Sadrian break; 300222312Sadrian } 301222312Sadrian } /* end ctl mode checking */ 302222312Sadrian 303222312Sadrian /* Set rates Array from collected data */ 304222312Sadrian ar5416SetRatesArrayFromTargetPower(ah, chan, ratesArray, 305222312Sadrian &targetPowerCck, 306222312Sadrian &targetPowerCckExt, 307222312Sadrian &targetPowerOfdm, 308222312Sadrian &targetPowerOfdmExt, 309222312Sadrian &targetPowerHt20, 310222312Sadrian &targetPowerHt40); 311222310Sadrian return AH_TRUE; 312222312Sadrian#undef EXT_ADDITIVE 313222312Sadrian#undef CTL_11A_EXT 314222312Sadrian#undef CTL_11G_EXT 315222312Sadrian#undef CTL_11B_EXT 316222312Sadrian#undef SUB_NUM_CTL_MODES_AT_5G_40 317222312Sadrian#undef SUB_NUM_CTL_MODES_AT_2G_40 318222312Sadrian#undef N 319222310Sadrian} 320222310Sadrian 321222312Sadrian#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN 322222312Sadrian 323222310Sadrian/* 324222310Sadrian * This is based off of the AR5416/AR9285 code and likely could 325222310Sadrian * be unified in the future. 326222310Sadrian */ 327222301SadrianHAL_BOOL 328222301Sadrianar9287SetTransmitPower(struct ath_hal *ah, 329222301Sadrian const struct ieee80211_channel *chan, uint16_t *rfXpdGain) 330222301Sadrian{ 331222310Sadrian#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) 332237184Sadrian#define N(a) (sizeof (a) / sizeof (a[0])) 333222308Sadrian 334222310Sadrian const struct modal_eep_ar9287_header *pModal; 335222310Sadrian struct ath_hal_5212 *ahp = AH5212(ah); 336237184Sadrian int16_t txPowerIndexOffset = 0; 337237184Sadrian int i; 338222308Sadrian 339237184Sadrian uint16_t cfgCtl; 340237184Sadrian uint16_t powerLimit; 341237184Sadrian uint16_t twiceAntennaReduction; 342237184Sadrian uint16_t twiceMaxRegulatoryPower; 343237184Sadrian int16_t maxPower; 344222310Sadrian HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 345222310Sadrian struct ar9287_eeprom *pEepData = &ee->ee_base; 346222310Sadrian 347249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc = 2; 348249580Sadrian 349222310Sadrian /* Setup info for the actual eeprom */ 350249580Sadrian OS_MEMZERO(AH5416(ah)->ah_ratesArray, 351249580Sadrian sizeof(AH5416(ah)->ah_ratesArray)); 352222310Sadrian cfgCtl = ath_hal_getctl(ah, chan); 353222310Sadrian powerLimit = chan->ic_maxregpower * 2; 354222310Sadrian twiceAntennaReduction = chan->ic_maxantgain; 355237184Sadrian twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, 356237184Sadrian AH_PRIVATE(ah)->ah_powerLimit); 357222310Sadrian pModal = &pEepData->modalHeader; 358222310Sadrian HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n", 359222310Sadrian __func__,chan->ic_freq, cfgCtl ); 360222310Sadrian 361222310Sadrian /* XXX Assume Minor is v2 or later */ 362249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; 363222310Sadrian 364222308Sadrian /* Fetch per-rate power table for the given channel */ 365222312Sadrian if (! ar9287SetPowerPerRateTable(ah, pEepData, chan, 366249580Sadrian &AH5416(ah)->ah_ratesArray[0], 367249580Sadrian cfgCtl, 368237184Sadrian twiceAntennaReduction, 369237184Sadrian twiceMaxRegulatoryPower, powerLimit)) { 370222310Sadrian HALDEBUG(ah, HAL_DEBUG_ANY, 371222310Sadrian "%s: unable to set tx power per rate table\n", __func__); 372222310Sadrian return AH_FALSE; 373222310Sadrian } 374222308Sadrian 375222310Sadrian /* Set TX power control calibration curves for each TX chain */ 376222308Sadrian ar9287SetPowerCalTable(ah, chan, &txPowerIndexOffset); 377222308Sadrian 378222310Sadrian /* Calculate maximum power level */ 379249580Sadrian maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb], 380249580Sadrian AH5416(ah)->ah_ratesArray[rateHt20_0]); 381249580Sadrian maxPower = AH_MAX(maxPower, 382249580Sadrian AH5416(ah)->ah_ratesArray[rate1l]); 383222308Sadrian 384222310Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) 385249580Sadrian maxPower = AH_MAX(maxPower, 386249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_0]); 387222308Sadrian 388222310Sadrian ahp->ah_tx6PowerInHalfDbm = maxPower; 389222310Sadrian AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower; 390222310Sadrian ahp->ah_txPowerIndexOffset = txPowerIndexOffset; 391222308Sadrian 392222310Sadrian /* 393222310Sadrian * txPowerIndexOffset is set by the SetPowerTable() call - 394222310Sadrian * adjust the rate table (0 offset if rates EEPROM not loaded) 395222310Sadrian */ 396222310Sadrian /* XXX what about the pwrTableOffset? */ 397249580Sadrian for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) { 398249580Sadrian AH5416(ah)->ah_ratesArray[i] = 399249580Sadrian (int16_t)(txPowerIndexOffset + 400249580Sadrian AH5416(ah)->ah_ratesArray[i]); 401222310Sadrian /* -5 dBm offset for Merlin and later; this includes Kiwi */ 402249580Sadrian AH5416(ah)->ah_ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; 403249580Sadrian if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER) 404249580Sadrian AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER; 405249580Sadrian if (AH5416(ah)->ah_ratesArray[i] < 0) 406249580Sadrian AH5416(ah)->ah_ratesArray[i] = 0; 407222310Sadrian } 408222310Sadrian 409222310Sadrian#ifdef AH_EEPROM_DUMP 410249580Sadrian ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray); 411222310Sadrian#endif 412222310Sadrian 413222310Sadrian /* 414222310Sadrian * Adjust the HT40 power to meet the correct target TX power 415222310Sadrian * for 40MHz mode, based on TX power curves that are established 416222310Sadrian * for 20MHz mode. 417222310Sadrian * 418222310Sadrian * XXX handle overflow/too high power level? 419222310Sadrian */ 420222310Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) { 421249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_0] += 422249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 423249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_1] += 424249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 425249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_2] += 426249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 427249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_3] += 428249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 429249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_4] += 430249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 431249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_5] += 432249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 433249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_6] += 434249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 435249580Sadrian AH5416(ah)->ah_ratesArray[rateHt40_7] += 436249580Sadrian AH5416(ah)->ah_ht40PowerIncForPdadc; 437222310Sadrian } 438222310Sadrian 439222310Sadrian /* Write the TX power rate registers */ 440249580Sadrian ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray); 441222310Sadrian 442222301Sadrian return AH_TRUE; 443222310Sadrian#undef POW_SM 444222310Sadrian#undef N 445222301Sadrian} 446222301Sadrian 447222301Sadrian/* 448222301Sadrian * Read EEPROM header info and program the device for correct operation 449222301Sadrian * given the channel value. 450222301Sadrian */ 451222301SadrianHAL_BOOL 452222301Sadrianar9287SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan) 453222301Sadrian{ 454222301Sadrian const HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 455222301Sadrian const struct ar9287_eeprom *eep = &ee->ee_base; 456222301Sadrian const struct modal_eep_ar9287_header *pModal = &eep->modalHeader; 457222301Sadrian uint16_t antWrites[AR9287_ANT_16S]; 458222301Sadrian uint32_t regChainOffset, regval; 459222301Sadrian uint8_t txRxAttenLocal; 460222301Sadrian int i, j, offset_num; 461222301Sadrian 462222301Sadrian pModal = &eep->modalHeader; 463222301Sadrian 464222301Sadrian antWrites[0] = (uint16_t)((pModal->antCtrlCommon >> 28) & 0xF); 465222301Sadrian antWrites[1] = (uint16_t)((pModal->antCtrlCommon >> 24) & 0xF); 466222301Sadrian antWrites[2] = (uint16_t)((pModal->antCtrlCommon >> 20) & 0xF); 467222301Sadrian antWrites[3] = (uint16_t)((pModal->antCtrlCommon >> 16) & 0xF); 468222301Sadrian antWrites[4] = (uint16_t)((pModal->antCtrlCommon >> 12) & 0xF); 469222301Sadrian antWrites[5] = (uint16_t)((pModal->antCtrlCommon >> 8) & 0xF); 470222301Sadrian antWrites[6] = (uint16_t)((pModal->antCtrlCommon >> 4) & 0xF); 471222301Sadrian antWrites[7] = (uint16_t)(pModal->antCtrlCommon & 0xF); 472222301Sadrian 473222301Sadrian offset_num = 8; 474222301Sadrian 475222301Sadrian for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { 476222301Sadrian antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 28) & 0xf); 477222301Sadrian antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 10) & 0x3); 478222301Sadrian antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 8) & 0x3); 479222301Sadrian antWrites[j++] = 0; 480222301Sadrian antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 6) & 0x3); 481222301Sadrian antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 4) & 0x3); 482222301Sadrian antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 2) & 0x3); 483222301Sadrian antWrites[j++] = (uint16_t)(pModal->antCtrlChain[i] & 0x3); 484222301Sadrian } 485222301Sadrian 486222301Sadrian OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 487222301Sadrian 488222301Sadrian for (i = 0; i < AR9287_MAX_CHAINS; i++) { 489222301Sadrian regChainOffset = i * 0x1000; 490222301Sadrian 491222301Sadrian OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, 492222301Sadrian pModal->antCtrlChain[i]); 493222301Sadrian 494222301Sadrian OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) + regChainOffset, 495237184Sadrian (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) 496237184Sadrian + regChainOffset) 497222301Sadrian & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | 498222301Sadrian AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 499222301Sadrian SM(pModal->iqCalICh[i], 500222301Sadrian AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 501222301Sadrian SM(pModal->iqCalQCh[i], 502222301Sadrian AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 503222301Sadrian 504222301Sadrian txRxAttenLocal = pModal->txRxAttenCh[i]; 505222301Sadrian 506222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 507222301Sadrian AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 508222301Sadrian pModal->bswMargin[i]); 509222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 510222301Sadrian AR_PHY_GAIN_2GHZ_XATTEN1_DB, 511222301Sadrian pModal->bswAtten[i]); 512222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 513222301Sadrian AR9280_PHY_RXGAIN_TXRX_ATTEN, 514222301Sadrian txRxAttenLocal); 515222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 516222301Sadrian AR9280_PHY_RXGAIN_TXRX_MARGIN, 517222301Sadrian pModal->rxTxMarginCh[i]); 518222301Sadrian } 519222301Sadrian 520222301Sadrian if (IEEE80211_IS_CHAN_HT40(chan)) 521222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 522222301Sadrian AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); 523222301Sadrian else 524222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 525222301Sadrian AR_PHY_SETTLING_SWITCH, pModal->switchSettling); 526222301Sadrian 527222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, 528222301Sadrian AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); 529222301Sadrian 530222301Sadrian OS_REG_WRITE(ah, AR_PHY_RF_CTL4, 531222301Sadrian SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) 532222301Sadrian | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) 533222301Sadrian | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) 534222301Sadrian | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); 535222301Sadrian 536222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, 537222301Sadrian AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); 538222301Sadrian 539222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_CCA, 540222301Sadrian AR9280_PHY_CCA_THRESH62, pModal->thresh62); 541222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, 542222301Sadrian AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); 543222301Sadrian 544222301Sadrian regval = OS_REG_READ(ah, AR9287_AN_RF2G3_CH0); 545222301Sadrian regval &= ~(AR9287_AN_RF2G3_DB1 | 546222301Sadrian AR9287_AN_RF2G3_DB2 | 547222301Sadrian AR9287_AN_RF2G3_OB_CCK | 548222301Sadrian AR9287_AN_RF2G3_OB_PSK | 549222301Sadrian AR9287_AN_RF2G3_OB_QAM | 550222301Sadrian AR9287_AN_RF2G3_OB_PAL_OFF); 551222301Sadrian regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 552222301Sadrian SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 553222301Sadrian SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 554222301Sadrian SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 555222301Sadrian SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 556222301Sadrian SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 557222301Sadrian 558237184Sadrian /* Analog write - requires a 100usec delay */ 559237184Sadrian OS_A_REG_WRITE(ah, AR9287_AN_RF2G3_CH0, regval); 560222301Sadrian 561222301Sadrian regval = OS_REG_READ(ah, AR9287_AN_RF2G3_CH1); 562222301Sadrian regval &= ~(AR9287_AN_RF2G3_DB1 | 563222301Sadrian AR9287_AN_RF2G3_DB2 | 564222301Sadrian AR9287_AN_RF2G3_OB_CCK | 565222301Sadrian AR9287_AN_RF2G3_OB_PSK | 566222301Sadrian AR9287_AN_RF2G3_OB_QAM | 567222301Sadrian AR9287_AN_RF2G3_OB_PAL_OFF); 568222301Sadrian regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 569222301Sadrian SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 570222301Sadrian SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 571222301Sadrian SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 572222301Sadrian SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 573222301Sadrian SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 574222301Sadrian 575237184Sadrian OS_A_REG_WRITE(ah, AR9287_AN_RF2G3_CH1, regval); 576222301Sadrian 577222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 578222301Sadrian AR_PHY_TX_FRAME_TO_DATA_START, pModal->txFrameToDataStart); 579222301Sadrian OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 580222301Sadrian AR_PHY_TX_FRAME_TO_PA_ON, pModal->txFrameToPaOn); 581222301Sadrian 582222301Sadrian OS_A_REG_RMW_FIELD(ah, AR9287_AN_TOP2, 583222301Sadrian AR9287_AN_TOP2_XPABIAS_LVL, pModal->xpaBiasLvl); 584222301Sadrian 585222301Sadrian return AH_TRUE; 586222301Sadrian} 587