ar9287_reset.c revision 249580
1272343Sngie/* 2272343Sngie * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3272343Sngie * Copyright (c) 2002-2008 Atheros Communications, Inc. 4272343Sngie * 5272343Sngie * Permission to use, copy, modify, and/or distribute this software for any 6272343Sngie * purpose with or without fee is hereby granted, provided that the above 7272343Sngie * copyright notice and this permission notice appear in all copies. 8272343Sngie * 9272343Sngie * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10272343Sngie * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11272343Sngie * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12272343Sngie * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13272343Sngie * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14272343Sngie * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15272343Sngie * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16272343Sngie * 17272343Sngie * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c 249580 2013-04-17 07:31:53Z adrian $ 18272343Sngie */ 19272343Sngie 20272343Sngie#include "opt_ah.h" 21272343Sngie 22272343Sngie#include "ah.h" 23272343Sngie#include "ah_internal.h" 24272343Sngie#include "ah_devid.h" 25272343Sngie 26272343Sngie#include "ah_eeprom_v14.h" 27272343Sngie#include "ah_eeprom_9287.h" 28272343Sngie 29272343Sngie#include "ar5416/ar5416.h" 30272343Sngie#include "ar5416/ar5416reg.h" 31272343Sngie#include "ar5416/ar5416phy.h" 32272343Sngie 33272343Sngie#include "ar9002/ar9287phy.h" 34272343Sngie#include "ar9002/ar9287an.h" 35272343Sngie 36272343Sngie#include "ar9002/ar9287_olc.h" 37272343Sngie#include "ar9002/ar9287_reset.h" 38272343Sngie 39272343Sngie/* 40272343Sngie * Set the TX power calibration table per-chain. 41272343Sngie * 42272343Sngie * This only supports open-loop TX power control for the AR9287. 43272343Sngie */ 44272343Sngiestatic void 45272343Sngiear9287SetPowerCalTable(struct ath_hal *ah, 46272343Sngie const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset) 47276478Sngie{ 48272343Sngie struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; 49276478Sngie uint8_t *pCalBChans = NULL; 50272343Sngie uint16_t pdGainOverlap_t2; 51272343Sngie uint16_t numPiers = 0, i; 52272343Sngie uint16_t numXpdGain, xpdMask; 53272343Sngie uint16_t xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0}; 54272343Sngie uint32_t regChainOffset; 55272343Sngie HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 56272343Sngie struct ar9287_eeprom *pEepData = &ee->ee_base; 57272343Sngie 58272343Sngie xpdMask = pEepData->modalHeader.xpdGain; 59272343Sngie 60272343Sngie if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= 61272343Sngie AR9287_EEP_MINOR_VER_2) 62272343Sngie pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; 63272343Sngie else 64272343Sngie pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), 65272343Sngie AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); 66272343Sngie 67272343Sngie /* Note: Kiwi should only be 2ghz.. */ 68272343Sngie if (IEEE80211_IS_CHAN_2GHZ(chan)) { 69272343Sngie pCalBChans = pEepData->calFreqPier2G; 70272343Sngie numPiers = AR9287_NUM_2G_CAL_PIERS; 71272343Sngie pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0]; 72272343Sngie AH5416(ah)->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; 73272343Sngie } 74272343Sngie numXpdGain = 0; 75272343Sngie 76272343Sngie /* Calculate the value of xpdgains from the xpdGain Mask */ 77272343Sngie for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { 78272343Sngie if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { 79272343Sngie if (numXpdGain >= AR5416_NUM_PD_GAINS) 80272343Sngie break; 81272343Sngie xpdGainValues[numXpdGain] = 82272343Sngie (uint16_t)(AR5416_PD_GAINS_IN_MASK-i); 83272343Sngie numXpdGain++; 84272343Sngie } 85272343Sngie } 86272343Sngie 87272343Sngie OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, 88272343Sngie (numXpdGain - 1) & 0x3); 89272343Sngie OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, 90272343Sngie xpdGainValues[0]); 91272343Sngie OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, 92272343Sngie xpdGainValues[1]); 93272343Sngie OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 94272343Sngie xpdGainValues[2]); 95272343Sngie 96272343Sngie for (i = 0; i < AR9287_MAX_CHAINS; i++) { 97272343Sngie regChainOffset = i * 0x1000; 98272343Sngie 99272343Sngie if (pEepData->baseEepHeader.txMask & (1 << i)) { 100272343Sngie int8_t txPower; 101272343Sngie pRawDatasetOpenLoop = 102272343Sngie (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i]; 103272343Sngie ar9287olcGetTxGainIndex(ah, chan, 104272343Sngie pRawDatasetOpenLoop, 105272343Sngie pCalBChans, numPiers, 106272343Sngie &txPower); 107272343Sngie ar9287olcSetPDADCs(ah, txPower, i); 108272343Sngie } 109272343Sngie } 110272343Sngie 111272343Sngie *pTxPowerIndexOffset = 0; 112272343Sngie} 113272343Sngie 114272343Sngie 115272343Sngie/* XXX hard-coded values? */ 116272343Sngie#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 117272343Sngie 118272343Sngie/* 119272343Sngie * ar9287SetPowerPerRateTable 120272343Sngie * 121272343Sngie * Sets the transmit power in the baseband for the given 122272343Sngie * operating channel and mode. 123272343Sngie * 124272343Sngie * This is like the v14 EEPROM table except the 5GHz code. 125272343Sngie */ 126272343Sngiestatic HAL_BOOL 127272343Sngiear9287SetPowerPerRateTable(struct ath_hal *ah, 128272343Sngie struct ar9287_eeprom *pEepData, 129272343Sngie const struct ieee80211_channel *chan, 130272343Sngie int16_t *ratesArray, uint16_t cfgCtl, 131272343Sngie uint16_t AntennaReduction, 132272343Sngie uint16_t twiceMaxRegulatoryPower, 133272343Sngie uint16_t powerLimit) 134272343Sngie{ 135272343Sngie#define N(a) (sizeof(a)/sizeof(a[0])) 136272343Sngie/* Local defines to distinguish between extension and control CTL's */ 137272343Sngie#define EXT_ADDITIVE (0x8000) 138272343Sngie#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) 139272343Sngie#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) 140272343Sngie#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) 141272343Sngie 142272343Sngie uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 143272343Sngie int i; 144272343Sngie int16_t twiceLargestAntenna; 145272343Sngie struct cal_ctl_data_ar9287 *rep; 146272343Sngie CAL_TARGET_POWER_LEG targetPowerOfdm; 147272343Sngie CAL_TARGET_POWER_LEG targetPowerCck = {0, {0, 0, 0, 0}}; 148272343Sngie CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}; 149272343Sngie CAL_TARGET_POWER_LEG targetPowerCckExt = {0, {0, 0, 0, 0}}; 150272343Sngie CAL_TARGET_POWER_HT targetPowerHt20; 151272343Sngie CAL_TARGET_POWER_HT targetPowerHt40 = {0, {0, 0, 0, 0}}; 152272343Sngie int16_t scaledPower, minCtlPower; 153272343Sngie 154272343Sngie#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ 155272343Sngie static const uint16_t ctlModesFor11g[] = { 156272343Sngie CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 157272343Sngie }; 158272343Sngie const uint16_t *pCtlMode; 159272343Sngie uint16_t numCtlModes, ctlMode, freq; 160272343Sngie CHAN_CENTERS centers; 161272343Sngie 162272343Sngie ar5416GetChannelCenters(ah, chan, ¢ers); 163272343Sngie 164272343Sngie /* Compute TxPower reduction due to Antenna Gain */ 165276478Sngie 166272343Sngie twiceLargestAntenna = AH_MAX( 167272343Sngie pEepData->modalHeader.antennaGainCh[0], 168272343Sngie pEepData->modalHeader.antennaGainCh[1]); 169272343Sngie 170272343Sngie twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0); 171272343Sngie 172272343Sngie /* XXX setup for 5212 use (really used?) */ 173272343Sngie ath_hal_eepromSet(ah, AR_EEP_ANTGAINMAX_2, twiceLargestAntenna); 174272343Sngie 175272343Sngie /* 176272343Sngie * scaledPower is the minimum of the user input power level and 177272343Sngie * the regulatory allowed power level 178272343Sngie */ 179272343Sngie scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna); 180272343Sngie 181272343Sngie /* Reduce scaled Power by number of chains active to get to per chain tx power level */ 182272343Sngie /* TODO: better value than these? */ 183272343Sngie switch (owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask)) { 184272343Sngie case 1: 185272343Sngie break; 186272343Sngie case 2: 187272343Sngie scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; 188272343Sngie break; 189272343Sngie default: 190272343Sngie return AH_FALSE; /* Unsupported number of chains */ 191272343Sngie } 192272343Sngie 193272343Sngie scaledPower = AH_MAX(0, scaledPower); 194272343Sngie 195272343Sngie /* Get target powers from EEPROM - our baseline for TX Power */ 196272343Sngie /* XXX assume channel is 2ghz */ 197272343Sngie if (1) { 198272343Sngie /* Setup for CTL modes */ 199272343Sngie numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */ 200272343Sngie pCtlMode = ctlModesFor11g; 201272343Sngie 202272343Sngie ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 203272343Sngie AR9287_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE); 204272343Sngie ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 205272343Sngie AR9287_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); 206272343Sngie ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20, 207272343Sngie AR9287_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); 208272343Sngie 209272343Sngie if (IEEE80211_IS_CHAN_HT40(chan)) { 210272343Sngie numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */ 211272343Sngie 212272343Sngie ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40, 213272343Sngie AR9287_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); 214272343Sngie /* Get target powers for extension channels */ 215272343Sngie ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 216272343Sngie AR9287_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE); 217272343Sngie ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 218272343Sngie AR9287_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); 219272343Sngie } 220272343Sngie } 221272343Sngie 222272343Sngie /* 223272343Sngie * For MIMO, need to apply regulatory caps individually across dynamically 224272343Sngie * running modes: CCK, OFDM, HT20, HT40 225272343Sngie * 226272343Sngie * The outer loop walks through each possible applicable runtime mode. 227272343Sngie * The inner loop walks through each ctlIndex entry in EEPROM. 228272343Sngie * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. 229272343Sngie * 230272343Sngie */ 231272343Sngie for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { 232272343Sngie HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || 233272343Sngie (pCtlMode[ctlMode] == CTL_2GHT40); 234272343Sngie if (isHt40CtlMode) { 235272343Sngie freq = centers.ctl_center; 236272343Sngie } else if (pCtlMode[ctlMode] & EXT_ADDITIVE) { 237272343Sngie freq = centers.ext_center; 238272343Sngie } else { 239272343Sngie freq = centers.ctl_center; 240272343Sngie } 241272343Sngie 242272343Sngie /* walk through each CTL index stored in EEPROM */ 243272343Sngie for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { 244272343Sngie uint16_t twiceMinEdgePower; 245272343Sngie 246272343Sngie /* compare test group from regulatory channel list with test mode from pCtlMode list */ 247272343Sngie if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || 248276478Sngie (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == 249272343Sngie ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { 250272343Sngie rep = &(pEepData->ctlData[i]); 251272343Sngie twiceMinEdgePower = ar5416GetMaxEdgePower(freq, 252272343Sngie rep->ctlEdges[owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1], 253272343Sngie IEEE80211_IS_CHAN_2GHZ(chan)); 254272343Sngie if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { 255272343Sngie /* Find the minimum of all CTL edge powers that apply to this channel */ 256272343Sngie twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower); 257272343Sngie } else { 258272343Sngie /* specific */ 259272343Sngie twiceMaxEdgePower = twiceMinEdgePower; 260272343Sngie break; 261272343Sngie } 262272343Sngie } 263272343Sngie } 264272343Sngie minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower); 265272343Sngie /* Apply ctl mode to correct target power set */ 266272343Sngie switch(pCtlMode[ctlMode]) { 267272343Sngie case CTL_11B: 268272343Sngie for (i = 0; i < N(targetPowerCck.tPow2x); i++) { 269272343Sngie targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower); 270272343Sngie } 271272343Sngie break; 272272343Sngie case CTL_11A: 273272343Sngie case CTL_11G: 274272343Sngie for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) { 275272343Sngie targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower); 276272343Sngie } 277272343Sngie break; 278272343Sngie case CTL_5GHT20: 279272343Sngie case CTL_2GHT20: 280272343Sngie for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { 281272343Sngie targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower); 282272343Sngie } 283272343Sngie break; 284272343Sngie case CTL_11B_EXT: 285272343Sngie targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower); 286272343Sngie break; 287272343Sngie case CTL_11A_EXT: 288272343Sngie case CTL_11G_EXT: 289272343Sngie targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower); 290272343Sngie break; 291272343Sngie case CTL_5GHT40: 292272343Sngie case CTL_2GHT40: 293272343Sngie for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { 294272343Sngie targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower); 295272343Sngie } 296272343Sngie break; 297272343Sngie default: 298272343Sngie return AH_FALSE; 299272343Sngie break; 300272343Sngie } 301272343Sngie } /* end ctl mode checking */ 302272343Sngie 303272343Sngie /* Set rates Array from collected data */ 304272343Sngie ar5416SetRatesArrayFromTargetPower(ah, chan, ratesArray, 305272343Sngie &targetPowerCck, 306272343Sngie &targetPowerCckExt, 307272343Sngie &targetPowerOfdm, 308272343Sngie &targetPowerOfdmExt, 309272343Sngie &targetPowerHt20, 310272343Sngie &targetPowerHt40); 311272343Sngie return AH_TRUE; 312272343Sngie#undef EXT_ADDITIVE 313272343Sngie#undef CTL_11A_EXT 314272343Sngie#undef CTL_11G_EXT 315272343Sngie#undef CTL_11B_EXT 316272343Sngie#undef SUB_NUM_CTL_MODES_AT_5G_40 317272343Sngie#undef SUB_NUM_CTL_MODES_AT_2G_40 318272343Sngie#undef N 319272343Sngie} 320272343Sngie 321272343Sngie#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN 322272343Sngie 323272343Sngie/* 324272343Sngie * This is based off of the AR5416/AR9285 code and likely could 325272343Sngie * be unified in the future. 326272343Sngie */ 327272343SngieHAL_BOOL 328272343Sngiear9287SetTransmitPower(struct ath_hal *ah, 329272343Sngie const struct ieee80211_channel *chan, uint16_t *rfXpdGain) 330272343Sngie{ 331272343Sngie#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) 332272343Sngie#define N(a) (sizeof (a) / sizeof (a[0])) 333272343Sngie 334272343Sngie const struct modal_eep_ar9287_header *pModal; 335272343Sngie struct ath_hal_5212 *ahp = AH5212(ah); 336272343Sngie int16_t txPowerIndexOffset = 0; 337272343Sngie int i; 338272343Sngie 339272343Sngie uint16_t cfgCtl; 340272343Sngie uint16_t powerLimit; 341272343Sngie uint16_t twiceAntennaReduction; 342272343Sngie uint16_t twiceMaxRegulatoryPower; 343272343Sngie int16_t maxPower; 344272343Sngie HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 345272343Sngie struct ar9287_eeprom *pEepData = &ee->ee_base; 346272343Sngie 347272343Sngie AH5416(ah)->ah_ht40PowerIncForPdadc = 2; 348272343Sngie 349272343Sngie /* Setup info for the actual eeprom */ 350272343Sngie OS_MEMZERO(AH5416(ah)->ah_ratesArray, 351272343Sngie sizeof(AH5416(ah)->ah_ratesArray)); 352272343Sngie cfgCtl = ath_hal_getctl(ah, chan); 353272343Sngie powerLimit = chan->ic_maxregpower * 2; 354272343Sngie twiceAntennaReduction = chan->ic_maxantgain; 355272343Sngie twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, 356272343Sngie AH_PRIVATE(ah)->ah_powerLimit); 357272343Sngie pModal = &pEepData->modalHeader; 358276478Sngie HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n", 359272343Sngie __func__,chan->ic_freq, cfgCtl ); 360276478Sngie 361272343Sngie /* XXX Assume Minor is v2 or later */ 362272343Sngie AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; 363272343Sngie 364272343Sngie /* Fetch per-rate power table for the given channel */ 365272343Sngie if (! ar9287SetPowerPerRateTable(ah, pEepData, chan, 366 &AH5416(ah)->ah_ratesArray[0], 367 cfgCtl, 368 twiceAntennaReduction, 369 twiceMaxRegulatoryPower, powerLimit)) { 370 HALDEBUG(ah, HAL_DEBUG_ANY, 371 "%s: unable to set tx power per rate table\n", __func__); 372 return AH_FALSE; 373 } 374 375 /* Set TX power control calibration curves for each TX chain */ 376 ar9287SetPowerCalTable(ah, chan, &txPowerIndexOffset); 377 378 /* Calculate maximum power level */ 379 maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb], 380 AH5416(ah)->ah_ratesArray[rateHt20_0]); 381 maxPower = AH_MAX(maxPower, 382 AH5416(ah)->ah_ratesArray[rate1l]); 383 384 if (IEEE80211_IS_CHAN_HT40(chan)) 385 maxPower = AH_MAX(maxPower, 386 AH5416(ah)->ah_ratesArray[rateHt40_0]); 387 388 ahp->ah_tx6PowerInHalfDbm = maxPower; 389 AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower; 390 ahp->ah_txPowerIndexOffset = txPowerIndexOffset; 391 392 /* 393 * txPowerIndexOffset is set by the SetPowerTable() call - 394 * adjust the rate table (0 offset if rates EEPROM not loaded) 395 */ 396 /* XXX what about the pwrTableOffset? */ 397 for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) { 398 AH5416(ah)->ah_ratesArray[i] = 399 (int16_t)(txPowerIndexOffset + 400 AH5416(ah)->ah_ratesArray[i]); 401 /* -5 dBm offset for Merlin and later; this includes Kiwi */ 402 AH5416(ah)->ah_ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; 403 if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER) 404 AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER; 405 if (AH5416(ah)->ah_ratesArray[i] < 0) 406 AH5416(ah)->ah_ratesArray[i] = 0; 407 } 408 409#ifdef AH_EEPROM_DUMP 410 ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray); 411#endif 412 413 /* 414 * Adjust the HT40 power to meet the correct target TX power 415 * for 40MHz mode, based on TX power curves that are established 416 * for 20MHz mode. 417 * 418 * XXX handle overflow/too high power level? 419 */ 420 if (IEEE80211_IS_CHAN_HT40(chan)) { 421 AH5416(ah)->ah_ratesArray[rateHt40_0] += 422 AH5416(ah)->ah_ht40PowerIncForPdadc; 423 AH5416(ah)->ah_ratesArray[rateHt40_1] += 424 AH5416(ah)->ah_ht40PowerIncForPdadc; 425 AH5416(ah)->ah_ratesArray[rateHt40_2] += 426 AH5416(ah)->ah_ht40PowerIncForPdadc; 427 AH5416(ah)->ah_ratesArray[rateHt40_3] += 428 AH5416(ah)->ah_ht40PowerIncForPdadc; 429 AH5416(ah)->ah_ratesArray[rateHt40_4] += 430 AH5416(ah)->ah_ht40PowerIncForPdadc; 431 AH5416(ah)->ah_ratesArray[rateHt40_5] += 432 AH5416(ah)->ah_ht40PowerIncForPdadc; 433 AH5416(ah)->ah_ratesArray[rateHt40_6] += 434 AH5416(ah)->ah_ht40PowerIncForPdadc; 435 AH5416(ah)->ah_ratesArray[rateHt40_7] += 436 AH5416(ah)->ah_ht40PowerIncForPdadc; 437 } 438 439 /* Write the TX power rate registers */ 440 ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray); 441 442 return AH_TRUE; 443#undef POW_SM 444#undef N 445} 446 447/* 448 * Read EEPROM header info and program the device for correct operation 449 * given the channel value. 450 */ 451HAL_BOOL 452ar9287SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan) 453{ 454 const HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 455 const struct ar9287_eeprom *eep = &ee->ee_base; 456 const struct modal_eep_ar9287_header *pModal = &eep->modalHeader; 457 uint16_t antWrites[AR9287_ANT_16S]; 458 uint32_t regChainOffset, regval; 459 uint8_t txRxAttenLocal; 460 int i, j, offset_num; 461 462 pModal = &eep->modalHeader; 463 464 antWrites[0] = (uint16_t)((pModal->antCtrlCommon >> 28) & 0xF); 465 antWrites[1] = (uint16_t)((pModal->antCtrlCommon >> 24) & 0xF); 466 antWrites[2] = (uint16_t)((pModal->antCtrlCommon >> 20) & 0xF); 467 antWrites[3] = (uint16_t)((pModal->antCtrlCommon >> 16) & 0xF); 468 antWrites[4] = (uint16_t)((pModal->antCtrlCommon >> 12) & 0xF); 469 antWrites[5] = (uint16_t)((pModal->antCtrlCommon >> 8) & 0xF); 470 antWrites[6] = (uint16_t)((pModal->antCtrlCommon >> 4) & 0xF); 471 antWrites[7] = (uint16_t)(pModal->antCtrlCommon & 0xF); 472 473 offset_num = 8; 474 475 for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { 476 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 28) & 0xf); 477 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 10) & 0x3); 478 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 8) & 0x3); 479 antWrites[j++] = 0; 480 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 6) & 0x3); 481 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 4) & 0x3); 482 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 2) & 0x3); 483 antWrites[j++] = (uint16_t)(pModal->antCtrlChain[i] & 0x3); 484 } 485 486 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 487 488 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 489 regChainOffset = i * 0x1000; 490 491 OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, 492 pModal->antCtrlChain[i]); 493 494 OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) + regChainOffset, 495 (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) 496 + regChainOffset) 497 & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | 498 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 499 SM(pModal->iqCalICh[i], 500 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 501 SM(pModal->iqCalQCh[i], 502 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 503 504 txRxAttenLocal = pModal->txRxAttenCh[i]; 505 506 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 507 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 508 pModal->bswMargin[i]); 509 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 510 AR_PHY_GAIN_2GHZ_XATTEN1_DB, 511 pModal->bswAtten[i]); 512 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 513 AR9280_PHY_RXGAIN_TXRX_ATTEN, 514 txRxAttenLocal); 515 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 516 AR9280_PHY_RXGAIN_TXRX_MARGIN, 517 pModal->rxTxMarginCh[i]); 518 } 519 520 if (IEEE80211_IS_CHAN_HT40(chan)) 521 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 522 AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); 523 else 524 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 525 AR_PHY_SETTLING_SWITCH, pModal->switchSettling); 526 527 OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, 528 AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); 529 530 OS_REG_WRITE(ah, AR_PHY_RF_CTL4, 531 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) 532 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) 533 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) 534 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); 535 536 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, 537 AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); 538 539 OS_REG_RMW_FIELD(ah, AR_PHY_CCA, 540 AR9280_PHY_CCA_THRESH62, pModal->thresh62); 541 OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, 542 AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); 543 544 regval = OS_REG_READ(ah, AR9287_AN_RF2G3_CH0); 545 regval &= ~(AR9287_AN_RF2G3_DB1 | 546 AR9287_AN_RF2G3_DB2 | 547 AR9287_AN_RF2G3_OB_CCK | 548 AR9287_AN_RF2G3_OB_PSK | 549 AR9287_AN_RF2G3_OB_QAM | 550 AR9287_AN_RF2G3_OB_PAL_OFF); 551 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 552 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 553 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 554 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 555 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 556 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 557 558 /* Analog write - requires a 100usec delay */ 559 OS_A_REG_WRITE(ah, AR9287_AN_RF2G3_CH0, regval); 560 561 regval = OS_REG_READ(ah, AR9287_AN_RF2G3_CH1); 562 regval &= ~(AR9287_AN_RF2G3_DB1 | 563 AR9287_AN_RF2G3_DB2 | 564 AR9287_AN_RF2G3_OB_CCK | 565 AR9287_AN_RF2G3_OB_PSK | 566 AR9287_AN_RF2G3_OB_QAM | 567 AR9287_AN_RF2G3_OB_PAL_OFF); 568 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 569 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 570 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 571 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 572 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 573 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 574 575 OS_A_REG_WRITE(ah, AR9287_AN_RF2G3_CH1, regval); 576 577 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 578 AR_PHY_TX_FRAME_TO_DATA_START, pModal->txFrameToDataStart); 579 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 580 AR_PHY_TX_FRAME_TO_PA_ON, pModal->txFrameToPaOn); 581 582 OS_A_REG_RMW_FIELD(ah, AR9287_AN_TOP2, 583 AR9287_AN_TOP2_XPABIAS_LVL, pModal->xpaBiasLvl); 584 585 return AH_TRUE; 586} 587