Path: blob/main/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2006 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920/*21* Chips specific device attachment and device info collection22* Connects Init Reg Vectors, EEPROM Data, and device Functions.23*/24#include "ah.h"25#include "ah_internal.h"26#include "ah_devid.h"2728#include "ar5211/ar5211.h"29#include "ar5211/ar5211reg.h"30#include "ar5211/ar5211phy.h"3132#include "ah_eeprom_v3.h"3334/* Add static register initialization vectors */35#include "ar5211/boss.ini"3637/*38* Structure to hold 11b tuning information for Beanie/Sombrero39* 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=1240*/41typedef struct {42uint32_t refClkSel; /* reference clock, 1 for 16 MHz */43uint32_t channelSelect; /* P[7:4]S[3:0] bits */44uint16_t channel5111; /* 11a channel for 5111 */45} CHAN_INFO_2GHZ;4647#define CI_2GHZ_INDEX_CORRECTION 1948static const CHAN_INFO_2GHZ chan2GHzData[] = {49{ 1, 0x46, 96 }, /* 2312 -19 */50{ 1, 0x46, 97 }, /* 2317 -18 */51{ 1, 0x46, 98 }, /* 2322 -17 */52{ 1, 0x46, 99 }, /* 2327 -16 */53{ 1, 0x46, 100 }, /* 2332 -15 */54{ 1, 0x46, 101 }, /* 2337 -14 */55{ 1, 0x46, 102 }, /* 2342 -13 */56{ 1, 0x46, 103 }, /* 2347 -12 */57{ 1, 0x46, 104 }, /* 2352 -11 */58{ 1, 0x46, 105 }, /* 2357 -10 */59{ 1, 0x46, 106 }, /* 2362 -9 */60{ 1, 0x46, 107 }, /* 2367 -8 */61{ 1, 0x46, 108 }, /* 2372 -7 */62/* index -6 to 0 are pad to make this a nolookup table */63{ 1, 0x46, 116 }, /* -6 */64{ 1, 0x46, 116 }, /* -5 */65{ 1, 0x46, 116 }, /* -4 */66{ 1, 0x46, 116 }, /* -3 */67{ 1, 0x46, 116 }, /* -2 */68{ 1, 0x46, 116 }, /* -1 */69{ 1, 0x46, 116 }, /* 0 */70{ 1, 0x46, 116 }, /* 2412 1 */71{ 1, 0x46, 117 }, /* 2417 2 */72{ 1, 0x46, 118 }, /* 2422 3 */73{ 1, 0x46, 119 }, /* 2427 4 */74{ 1, 0x46, 120 }, /* 2432 5 */75{ 1, 0x46, 121 }, /* 2437 6 */76{ 1, 0x46, 122 }, /* 2442 7 */77{ 1, 0x46, 123 }, /* 2447 8 */78{ 1, 0x46, 124 }, /* 2452 9 */79{ 1, 0x46, 125 }, /* 2457 10 */80{ 1, 0x46, 126 }, /* 2462 11 */81{ 1, 0x46, 127 }, /* 2467 12 */82{ 1, 0x46, 128 }, /* 2472 13 */83{ 1, 0x44, 124 }, /* 2484 14 */84{ 1, 0x46, 136 }, /* 2512 15 */85{ 1, 0x46, 140 }, /* 2532 16 */86{ 1, 0x46, 144 }, /* 2552 17 */87{ 1, 0x46, 148 }, /* 2572 18 */88{ 1, 0x46, 152 }, /* 2592 19 */89{ 1, 0x46, 156 }, /* 2612 20 */90{ 1, 0x46, 160 }, /* 2632 21 */91{ 1, 0x46, 164 }, /* 2652 22 */92{ 1, 0x46, 168 }, /* 2672 23 */93{ 1, 0x46, 172 }, /* 2692 24 */94{ 1, 0x46, 176 }, /* 2712 25 */95{ 1, 0x46, 180 } /* 2732 26 */96};9798/* Power timeouts in usec to wait for chip to wake-up. */99#define POWER_UP_TIME 2000100101#define DELAY_PLL_SETTLE 300 /* 300 us */102#define DELAY_BASE_ACTIVATE 100 /* 100 us */103104#define NUM_RATES 8105106static HAL_BOOL ar5211SetResetReg(struct ath_hal *ah, uint32_t resetMask);107static HAL_BOOL ar5211SetChannel(struct ath_hal *,108const struct ieee80211_channel *);109static int16_t ar5211RunNoiseFloor(struct ath_hal *,110uint8_t runTime, int16_t startingNF);111static HAL_BOOL ar5211IsNfGood(struct ath_hal *,112struct ieee80211_channel *chan);113static HAL_BOOL ar5211SetRf6and7(struct ath_hal *,114const struct ieee80211_channel *chan);115static HAL_BOOL ar5211SetBoardValues(struct ath_hal *,116const struct ieee80211_channel *chan);117static void ar5211SetPowerTable(struct ath_hal *,118PCDACS_EEPROM *pSrcStruct, uint16_t channel);119static HAL_BOOL ar5211SetTransmitPower(struct ath_hal *,120const struct ieee80211_channel *);121static void ar5211SetRateTable(struct ath_hal *,122RD_EDGES_POWER *pRdEdgesPower, TRGT_POWER_INFO *pPowerInfo,123uint16_t numChannels, const struct ieee80211_channel *chan);124static uint16_t ar5211GetScaledPower(uint16_t channel, uint16_t pcdacValue,125const PCDACS_EEPROM *pSrcStruct);126static HAL_BOOL ar5211FindValueInList(uint16_t channel, uint16_t pcdacValue,127const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue);128static uint16_t ar5211GetInterpolatedValue(uint16_t target,129uint16_t srcLeft, uint16_t srcRight,130uint16_t targetLeft, uint16_t targetRight, HAL_BOOL scaleUp);131static void ar5211GetLowerUpperValues(uint16_t value,132const uint16_t *pList, uint16_t listSize,133uint16_t *pLowerValue, uint16_t *pUpperValue);134static void ar5211GetLowerUpperPcdacs(uint16_t pcdac,135uint16_t channel, const PCDACS_EEPROM *pSrcStruct,136uint16_t *pLowerPcdac, uint16_t *pUpperPcdac);137138static void ar5211SetRfgain(struct ath_hal *, const GAIN_VALUES *);139static void ar5211RequestRfgain(struct ath_hal *);140static HAL_BOOL ar5211InvalidGainReadback(struct ath_hal *, GAIN_VALUES *);141static HAL_BOOL ar5211IsGainAdjustNeeded(struct ath_hal *, const GAIN_VALUES *);142static int32_t ar5211AdjustGain(struct ath_hal *, GAIN_VALUES *);143static void ar5211SetOperatingMode(struct ath_hal *, int opmode);144145/*146* Places the device in and out of reset and then places sane147* values in the registers based on EEPROM config, initialization148* vectors (as determined by the mode), and station configuration149*150* bChannelChange is used to preserve DMA/PCU registers across151* a HW Reset during channel change.152*/153HAL_BOOL154ar5211Reset(struct ath_hal *ah, HAL_OPMODE opmode,155struct ieee80211_channel *chan, HAL_BOOL bChannelChange,156HAL_RESET_TYPE resetType,157HAL_STATUS *status)158{159uint32_t softLedCfg, softLedState;160#define N(a) (sizeof (a) /sizeof (a[0]))161#define FAIL(_code) do { ecode = _code; goto bad; } while (0)162struct ath_hal_5211 *ahp = AH5211(ah);163HAL_CHANNEL_INTERNAL *ichan;164uint32_t i, ledstate;165HAL_STATUS ecode;166int q;167168uint32_t data, synthDelay;169uint32_t macStaId1;170uint16_t modesIndex = 0, freqIndex = 0;171uint32_t saveFrameSeqCount[AR_NUM_DCU];172uint32_t saveTsfLow = 0, saveTsfHigh = 0;173uint32_t saveDefAntenna;174175HALDEBUG(ah, HAL_DEBUG_RESET,176"%s: opmode %u channel %u/0x%x %s channel\n",177__func__, opmode, chan->ic_freq, chan->ic_flags,178bChannelChange ? "change" : "same");179180OS_MARK(ah, AH_MARK_RESET, bChannelChange);181/*182* Map public channel to private.183*/184ichan = ath_hal_checkchannel(ah, chan);185if (ichan == AH_NULL)186FAIL(HAL_EINVAL);187switch (opmode) {188case HAL_M_STA:189case HAL_M_IBSS:190case HAL_M_HOSTAP:191case HAL_M_MONITOR:192break;193default:194HALDEBUG(ah, HAL_DEBUG_ANY,195"%s: invalid operating mode %u\n", __func__, opmode);196FAIL(HAL_EINVAL);197break;198}199HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3);200201/* Preserve certain DMA hardware registers on a channel change */202if (bChannelChange) {203/*204* Need to save/restore the TSF because of an issue205* that accelerates the TSF during a chip reset.206*207* We could use system timer routines to more208* accurately restore the TSF, but209* 1. Timer routines on certain platforms are210* not accurate enough (e.g. 1 ms resolution).211* 2. It would still not be accurate.212*213* The most important aspect of this workaround,214* is that, after reset, the TSF is behind215* other STAs TSFs. This will allow the STA to216* properly resynchronize its TSF in adhoc mode.217*/218saveTsfLow = OS_REG_READ(ah, AR_TSF_L32);219saveTsfHigh = OS_REG_READ(ah, AR_TSF_U32);220221/* Read frame sequence count */222if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) {223saveFrameSeqCount[0] = OS_REG_READ(ah, AR_D0_SEQNUM);224} else {225for (i = 0; i < AR_NUM_DCU; i++)226saveFrameSeqCount[i] = OS_REG_READ(ah, AR_DSEQNUM(i));227}228if (!IEEE80211_IS_CHAN_DFS(chan))229chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;230}231232/*233* Preserve the antenna on a channel change234*/235saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);236if (saveDefAntenna == 0)237saveDefAntenna = 1;238239/* Save hardware flag before chip reset clears the register */240macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;241242/* Save led state from pci config register */243ledstate = OS_REG_READ(ah, AR_PCICFG) &244(AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK |245AR_PCICFG_LEDSLOW);246softLedCfg = OS_REG_READ(ah, AR_GPIOCR);247softLedState = OS_REG_READ(ah, AR_GPIODO);248249if (!ar5211ChipReset(ah, chan)) {250HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);251FAIL(HAL_EIO);252}253254/* Setup the indices for the next set of register array writes */255if (IEEE80211_IS_CHAN_5GHZ(chan)) {256freqIndex = 1;257if (IEEE80211_IS_CHAN_TURBO(chan))258modesIndex = 2;259else if (IEEE80211_IS_CHAN_A(chan))260modesIndex = 1;261else {262HALDEBUG(ah, HAL_DEBUG_ANY,263"%s: invalid channel %u/0x%x\n",264__func__, chan->ic_freq, chan->ic_flags);265FAIL(HAL_EINVAL);266}267} else {268freqIndex = 2;269if (IEEE80211_IS_CHAN_B(chan))270modesIndex = 3;271else if (IEEE80211_IS_CHAN_PUREG(chan))272modesIndex = 4;273else {274HALDEBUG(ah, HAL_DEBUG_ANY,275"%s: invalid channel %u/0x%x\n",276__func__, chan->ic_freq, chan->ic_flags);277FAIL(HAL_EINVAL);278}279}280281/* Set correct Baseband to analog shift setting to access analog chips. */282if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) {283OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007);284} else {285OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000047);286}287288/* Write parameters specific to AR5211 */289if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) {290if (IEEE80211_IS_CHAN_2GHZ(chan) &&291AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1) {292HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;293uint32_t ob2GHz, db2GHz;294295if (IEEE80211_IS_CHAN_CCK(chan)) {296ob2GHz = ee->ee_ob2GHz[0];297db2GHz = ee->ee_db2GHz[0];298} else {299ob2GHz = ee->ee_ob2GHz[1];300db2GHz = ee->ee_db2GHz[1];301}302ob2GHz = ath_hal_reverseBits(ob2GHz, 3);303db2GHz = ath_hal_reverseBits(db2GHz, 3);304ar5211Mode2_4[25][freqIndex] =305(ar5211Mode2_4[25][freqIndex] & ~0xC0) |306((ob2GHz << 6) & 0xC0);307ar5211Mode2_4[26][freqIndex] =308(ar5211Mode2_4[26][freqIndex] & ~0x0F) |309(((ob2GHz >> 2) & 0x1) |310((db2GHz << 1) & 0x0E));311}312for (i = 0; i < N(ar5211Mode2_4); i++)313OS_REG_WRITE(ah, ar5211Mode2_4[i][0],314ar5211Mode2_4[i][freqIndex]);315}316317/* Write the analog registers 6 and 7 before other config */318ar5211SetRf6and7(ah, chan);319320/* Write registers that vary across all modes */321for (i = 0; i < N(ar5211Modes); i++)322OS_REG_WRITE(ah, ar5211Modes[i][0], ar5211Modes[i][modesIndex]);323324/* Write RFGain Parameters that differ between 2.4 and 5 GHz */325for (i = 0; i < N(ar5211BB_RfGain); i++)326OS_REG_WRITE(ah, ar5211BB_RfGain[i][0], ar5211BB_RfGain[i][freqIndex]);327328/* Write Common Array Parameters */329for (i = 0; i < N(ar5211Common); i++) {330uint32_t reg = ar5211Common[i][0];331/* On channel change, don't reset the PCU registers */332if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000)))333OS_REG_WRITE(ah, reg, ar5211Common[i][1]);334}335336/* Fix pre-AR5211 register values, this includes AR5311s. */337if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) {338/*339* The TX and RX latency values have changed locations340* within the USEC register in AR5211. Since they're341* set via the .ini, for both AR5211 and AR5311, they342* are written properly here for AR5311.343*/344data = OS_REG_READ(ah, AR_USEC);345/* Must be 0 for proper write in AR5311 */346HALASSERT((data & 0x00700000) == 0);347OS_REG_WRITE(ah, AR_USEC,348(data & (AR_USEC_M | AR_USEC_32_M | AR5311_USEC_TX_LAT_M)) |349((29 << AR5311_USEC_RX_LAT_S) & AR5311_USEC_RX_LAT_M));350/* The following registers exist only on AR5311. */351OS_REG_WRITE(ah, AR5311_QDCLKGATE, 0);352353/* Set proper ADC & DAC delays for AR5311. */354OS_REG_WRITE(ah, 0x00009878, 0x00000008);355356/* Enable the PCU FIFO corruption ECO on AR5311. */357OS_REG_WRITE(ah, AR_DIAG_SW,358OS_REG_READ(ah, AR_DIAG_SW) | AR5311_DIAG_SW_USE_ECO);359}360361/* Restore certain DMA hardware registers on a channel change */362if (bChannelChange) {363/* Restore TSF */364OS_REG_WRITE(ah, AR_TSF_L32, saveTsfLow);365OS_REG_WRITE(ah, AR_TSF_U32, saveTsfHigh);366367if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) {368OS_REG_WRITE(ah, AR_D0_SEQNUM, saveFrameSeqCount[0]);369} else {370for (i = 0; i < AR_NUM_DCU; i++)371OS_REG_WRITE(ah, AR_DSEQNUM(i), saveFrameSeqCount[i]);372}373}374375OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));376OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)377| macStaId1378);379ar5211SetOperatingMode(ah, opmode);380381/* Restore previous led state */382OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate);383OS_REG_WRITE(ah, AR_GPIOCR, softLedCfg);384OS_REG_WRITE(ah, AR_GPIODO, softLedState);385386/* Restore previous antenna */387OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);388389OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));390OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4));391392/* Restore bmiss rssi & count thresholds */393OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);394395OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */396397/*398* for pre-Production Oahu only.399* Disable clock gating in all DMA blocks. Helps when using400* 11B and AES but results in higher power consumption.401*/402if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_OAHU &&403AH_PRIVATE(ah)->ah_macRev < AR_SREV_OAHU_PROD) {404OS_REG_WRITE(ah, AR_CFG,405OS_REG_READ(ah, AR_CFG) | AR_CFG_CLK_GATE_DIS);406}407408/* Setup the transmit power values. */409if (!ar5211SetTransmitPower(ah, chan)) {410HALDEBUG(ah, HAL_DEBUG_ANY,411"%s: error init'ing transmit power\n", __func__);412FAIL(HAL_EIO);413}414415/*416* Configurable OFDM spoofing for 11n compatibility; used417* only when operating in station mode.418*/419if (opmode != HAL_M_HOSTAP &&420(AH_PRIVATE(ah)->ah_11nCompat & HAL_DIAG_11N_SERVICES) != 0) {421/* NB: override the .ini setting */422OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,423AR_PHY_FRAME_CTL_ERR_SERV,424MS(AH_PRIVATE(ah)->ah_11nCompat, HAL_DIAG_11N_SERVICES)&1);425}426427/* Setup board specific options for EEPROM version 3 */428ar5211SetBoardValues(ah, chan);429430if (!ar5211SetChannel(ah, chan)) {431HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set channel\n",432__func__);433FAIL(HAL_EIO);434}435436/* Activate the PHY */437if (AH_PRIVATE(ah)->ah_devid == AR5211_FPGA11B &&438IEEE80211_IS_CHAN_2GHZ(chan))439OS_REG_WRITE(ah, 0xd808, 0x502); /* required for FPGA */440OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);441442/*443* Wait for the frequency synth to settle (synth goes on444* via AR_PHY_ACTIVE_EN). Read the phy active delay register.445* Value is in 100ns increments.446*/447data = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_M;448if (IEEE80211_IS_CHAN_CCK(chan)) {449synthDelay = (4 * data) / 22;450} else {451synthDelay = data / 10;452}453/*454* There is an issue if the AP starts the calibration before455* the baseband timeout completes. This could result in the456* rxclear false triggering. Add an extra delay to ensure this457* this does not happen.458*/459OS_DELAY(synthDelay + DELAY_BASE_ACTIVATE);460461/* Calibrate the AGC and wait for completion. */462OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,463OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);464(void) ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0);465466/* Perform noise floor and set status */467if (!ar5211CalNoiseFloor(ah, chan)) {468if (!IEEE80211_IS_CHAN_CCK(chan))469chan->ic_state |= IEEE80211_CHANSTATE_CWINT;470HALDEBUG(ah, HAL_DEBUG_ANY,471"%s: noise floor calibration failed\n", __func__);472FAIL(HAL_EIO);473}474475/* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */476if (ahp->ah_calibrationTime != 0) {477OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4,478AR_PHY_TIMING_CTRL4_DO_IQCAL | (INIT_IQCAL_LOG_COUNT_MAX << AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S));479ahp->ah_bIQCalibration = AH_TRUE;480}481482/* set 1:1 QCU to DCU mapping for all queues */483for (q = 0; q < AR_NUM_DCU; q++)484OS_REG_WRITE(ah, AR_DQCUMASK(q), 1<<q);485486for (q = 0; q < HAL_NUM_TX_QUEUES; q++)487ar5211ResetTxQueue(ah, q);488489/* Setup QCU0 transmit interrupt masks (TX_ERR, TX_OK, TX_DESC, TX_URN) */490OS_REG_WRITE(ah, AR_IMR_S0,491(AR_IMR_S0_QCU_TXOK & AR_QCU_0) |492(AR_IMR_S0_QCU_TXDESC & (AR_QCU_0<<AR_IMR_S0_QCU_TXDESC_S)));493OS_REG_WRITE(ah, AR_IMR_S1, (AR_IMR_S1_QCU_TXERR & AR_QCU_0));494OS_REG_WRITE(ah, AR_IMR_S2, (AR_IMR_S2_QCU_TXURN & AR_QCU_0));495496/*497* GBL_EIFS must always be written after writing498* to any QCUMASK register.499*/500OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, OS_REG_READ(ah, AR_D_GBL_IFS_EIFS));501502/* Now set up the Interrupt Mask Register and save it for future use */503OS_REG_WRITE(ah, AR_IMR, INIT_INTERRUPT_MASK);504ahp->ah_maskReg = INIT_INTERRUPT_MASK;505506/* Enable bus error interrupts */507OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) |508AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR);509510/* Enable interrupts specific to AP */511if (opmode == HAL_M_HOSTAP) {512OS_REG_WRITE(ah, AR_IMR, OS_REG_READ(ah, AR_IMR) | AR_IMR_MIB);513ahp->ah_maskReg |= AR_IMR_MIB;514}515516if (AH_PRIVATE(ah)->ah_rfkillEnabled)517ar5211EnableRfKill(ah);518519/*520* Writing to AR_BEACON will start timers. Hence it should521* be the last register to be written. Do not reset tsf, do522* not enable beacons at this point, but preserve other values523* like beaconInterval.524*/525OS_REG_WRITE(ah, AR_BEACON,526(OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF)));527528/* Restore user-specified slot time and timeouts */529if (ahp->ah_sifstime != (u_int) -1)530ar5211SetSifsTime(ah, ahp->ah_sifstime);531if (ahp->ah_slottime != (u_int) -1)532ar5211SetSlotTime(ah, ahp->ah_slottime);533if (ahp->ah_acktimeout != (u_int) -1)534ar5211SetAckTimeout(ah, ahp->ah_acktimeout);535if (ahp->ah_ctstimeout != (u_int) -1)536ar5211SetCTSTimeout(ah, ahp->ah_ctstimeout);537if (AH_PRIVATE(ah)->ah_diagreg != 0)538OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);539540AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */541542HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__);543544return AH_TRUE;545bad:546if (status != AH_NULL)547*status = ecode;548return AH_FALSE;549#undef FAIL550#undef N551}552553/*554* Places the PHY and Radio chips into reset. A full reset555* must be called to leave this state. The PCI/MAC/PCU are556* not placed into reset as we must receive interrupt to557* re-enable the hardware.558*/559HAL_BOOL560ar5211PhyDisable(struct ath_hal *ah)561{562return ar5211SetResetReg(ah, AR_RC_BB);563}564565/*566* Places all of hardware into reset567*/568HAL_BOOL569ar5211Disable(struct ath_hal *ah)570{571if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))572return AH_FALSE;573/*574* Reset the HW - PCI must be reset after the rest of the575* device has been reset.576*/577if (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI))578return AH_FALSE;579OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */580581return AH_TRUE;582}583584/*585* Places the hardware into reset and then pulls it out of reset586*587* Only write the PLL if we're changing to or from CCK mode588*589* Attach calls with channelFlags = 0, as the coldreset should have590* us in the correct mode and we cannot check the hwchannel flags.591*/592HAL_BOOL593ar5211ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan)594{595if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))596return AH_FALSE;597598/* NB: called from attach with chan null */599if (chan != AH_NULL) {600/* Set CCK and Turbo modes correctly */601OS_REG_WRITE(ah, AR_PHY_TURBO, IEEE80211_IS_CHAN_TURBO(chan) ?602AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT : 0);603if (IEEE80211_IS_CHAN_B(chan)) {604OS_REG_WRITE(ah, AR5211_PHY_MODE,605AR5211_PHY_MODE_CCK | AR5211_PHY_MODE_RF2GHZ);606OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_44);607/* Wait for the PLL to settle */608OS_DELAY(DELAY_PLL_SETTLE);609} else if (AH_PRIVATE(ah)->ah_devid == AR5211_DEVID) {610OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_40);611OS_DELAY(DELAY_PLL_SETTLE);612OS_REG_WRITE(ah, AR5211_PHY_MODE,613AR5211_PHY_MODE_OFDM | (IEEE80211_IS_CHAN_2GHZ(chan) ?614AR5211_PHY_MODE_RF2GHZ :615AR5211_PHY_MODE_RF5GHZ));616}617}618619/*620* Reset the HW - PCI must be reset after the rest of the621* device has been reset622*/623if (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI))624return AH_FALSE;625OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */626627/* Bring out of sleep mode (AGAIN) */628if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))629return AH_FALSE;630631/* Clear warm reset register */632return ar5211SetResetReg(ah, 0);633}634635/*636* Recalibrate the lower PHY chips to account for temperature/environment637* changes.638*/639HAL_BOOL640ar5211PerCalibrationN(struct ath_hal *ah, struct ieee80211_channel *chan,641u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone)642{643struct ath_hal_5211 *ahp = AH5211(ah);644HAL_CHANNEL_INTERNAL *ichan;645int32_t qCoff, qCoffDenom;646uint32_t data;647int32_t iqCorrMeas;648int32_t iCoff, iCoffDenom;649uint32_t powerMeasQ, powerMeasI;650651ichan = ath_hal_checkchannel(ah, chan);652if (ichan == AH_NULL) {653HALDEBUG(ah, HAL_DEBUG_ANY,654"%s: invalid channel %u/0x%x; no mapping\n",655__func__, chan->ic_freq, chan->ic_flags);656return AH_FALSE;657}658/* IQ calibration in progress. Check to see if it has finished. */659if (ahp->ah_bIQCalibration &&660!(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_IQCAL)) {661/* IQ Calibration has finished. */662ahp->ah_bIQCalibration = AH_FALSE;663664/* Read calibration results. */665powerMeasI = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_I);666powerMeasQ = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_Q);667iqCorrMeas = OS_REG_READ(ah, AR_PHY_IQCAL_RES_IQ_CORR_MEAS);668669/*670* Prescale these values to remove 64-bit operation requirement at the loss671* of a little precision.672*/673iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;674qCoffDenom = powerMeasQ / 64;675676/* Protect against divide-by-0. */677if (iCoffDenom != 0 && qCoffDenom != 0) {678iCoff = (-iqCorrMeas) / iCoffDenom;679/* IQCORR_Q_I_COFF is a signed 6 bit number */680iCoff = iCoff & 0x3f;681682qCoff = ((int32_t)powerMeasI / qCoffDenom) - 64;683/* IQCORR_Q_Q_COFF is a signed 5 bit number */684qCoff = qCoff & 0x1f;685686HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasI = 0x%08x\n",687powerMeasI);688HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasQ = 0x%08x\n",689powerMeasQ);690HALDEBUG(ah, HAL_DEBUG_PERCAL, "iqCorrMeas = 0x%08x\n",691iqCorrMeas);692HALDEBUG(ah, HAL_DEBUG_PERCAL, "iCoff = %d\n",693iCoff);694HALDEBUG(ah, HAL_DEBUG_PERCAL, "qCoff = %d\n",695qCoff);696697/* Write IQ */698data = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) |699AR_PHY_TIMING_CTRL4_IQCORR_ENABLE |700(((uint32_t)iCoff) << AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S) |701((uint32_t)qCoff);702OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, data);703}704}705*isCalDone = !ahp->ah_bIQCalibration;706707if (longCal) {708/* Perform noise floor and set status */709if (!ar5211IsNfGood(ah, chan)) {710/* report up and clear internal state */711chan->ic_state |= IEEE80211_CHANSTATE_CWINT;712return AH_FALSE;713}714if (!ar5211CalNoiseFloor(ah, chan)) {715/*716* Delay 5ms before retrying the noise floor717* just to make sure, as we are in an error718* condition here.719*/720OS_DELAY(5000);721if (!ar5211CalNoiseFloor(ah, chan)) {722if (!IEEE80211_IS_CHAN_CCK(chan))723chan->ic_state |= IEEE80211_CHANSTATE_CWINT;724return AH_FALSE;725}726}727ar5211RequestRfgain(ah);728}729return AH_TRUE;730}731732HAL_BOOL733ar5211PerCalibration(struct ath_hal *ah, struct ieee80211_channel *chan,734HAL_BOOL *isIQdone)735{736return ar5211PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone);737}738739HAL_BOOL740ar5211ResetCalValid(struct ath_hal *ah, const struct ieee80211_channel *chan)741{742/* XXX */743return AH_TRUE;744}745746/*747* Writes the given reset bit mask into the reset register748*/749static HAL_BOOL750ar5211SetResetReg(struct ath_hal *ah, uint32_t resetMask)751{752uint32_t mask = resetMask ? resetMask : ~0;753HAL_BOOL rt;754755(void) OS_REG_READ(ah, AR_RXDP);/* flush any pending MMR writes */756OS_REG_WRITE(ah, AR_RC, resetMask);757758/* need to wait at least 128 clocks when reseting PCI before read */759OS_DELAY(15);760761resetMask &= AR_RC_MAC | AR_RC_BB;762mask &= AR_RC_MAC | AR_RC_BB;763rt = ath_hal_wait(ah, AR_RC, mask, resetMask);764if ((resetMask & AR_RC_MAC) == 0) {765if (isBigEndian()) {766/*767* Set CFG, little-endian for descriptor accesses.768*/769mask = INIT_CONFIG_STATUS | AR_CFG_SWTD | AR_CFG_SWRD;770OS_REG_WRITE(ah, AR_CFG, mask);771} else772OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);773}774return rt;775}776777/*778* Takes the MHz channel value and sets the Channel value779*780* ASSUMES: Writes enabled to analog bus before AGC is active781* or by disabling the AGC.782*/783static HAL_BOOL784ar5211SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan)785{786uint32_t refClk, reg32, data2111;787int16_t chan5111, chanIEEE;788789chanIEEE = chan->ic_ieee;790if (IEEE80211_IS_CHAN_2GHZ(chan)) {791const CHAN_INFO_2GHZ* ci =792&chan2GHzData[chanIEEE + CI_2GHZ_INDEX_CORRECTION];793794data2111 = ((ath_hal_reverseBits(ci->channelSelect, 8) & 0xff)795<< 5)796| (ci->refClkSel << 4);797chan5111 = ci->channel5111;798} else {799data2111 = 0;800chan5111 = chanIEEE;801}802803/* Rest of the code is common for 5 GHz and 2.4 GHz. */804if (chan5111 >= 145 || (chan5111 & 0x1)) {805reg32 = ath_hal_reverseBits(chan5111 - 24, 8) & 0xFF;806refClk = 1;807} else {808reg32 = ath_hal_reverseBits(((chan5111 - 24) / 2), 8) & 0xFF;809refClk = 0;810}811812reg32 = (reg32 << 2) | (refClk << 1) | (1 << 10) | 0x1;813OS_REG_WRITE(ah, AR_PHY(0x27), ((data2111 & 0xff) << 8) | (reg32 & 0xff));814reg32 >>= 8;815OS_REG_WRITE(ah, AR_PHY(0x34), (data2111 & 0xff00) | (reg32 & 0xff));816817AH_PRIVATE(ah)->ah_curchan = chan;818return AH_TRUE;819}820821static int16_t822ar5211GetNoiseFloor(struct ath_hal *ah)823{824int16_t nf;825826nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff;827if (nf & 0x100)828nf = 0 - ((nf ^ 0x1ff) + 1);829return nf;830}831832/*833* Peform the noisefloor calibration for the length of time set834* in runTime (valid values 1 to 7)835*836* Returns: The NF value at the end of the given time (or 0 for failure)837*/838int16_t839ar5211RunNoiseFloor(struct ath_hal *ah, uint8_t runTime, int16_t startingNF)840{841int i, searchTime;842843HALASSERT(runTime <= 7);844845/* Setup noise floor run time and starting value */846OS_REG_WRITE(ah, AR_PHY(25),847(OS_REG_READ(ah, AR_PHY(25)) & ~0xFFF) |848((runTime << 9) & 0xE00) | (startingNF & 0x1FF));849/* Calibrate the noise floor */850OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,851OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);852853/* Compute the required amount of searchTime needed to finish NF */854if (runTime == 0) {855/* 8 search windows * 6.4us each */856searchTime = 8 * 7;857} else {858/* 512 * runtime search windows * 6.4us each */859searchTime = (runTime * 512) * 7;860}861862/*863* Do not read noise floor until it has been updated864*865* As a guesstimate - we may only get 1/60th the time on866* the air to see search windows in a heavily congested867* network (40 us every 2400 us of time)868*/869for (i = 0; i < 60; i++) {870if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0)871break;872OS_DELAY(searchTime);873}874if (i >= 60) {875HALDEBUG(ah, HAL_DEBUG_NFCAL,876"NF with runTime %d failed to end on channel %d\n",877runTime, AH_PRIVATE(ah)->ah_curchan->ic_freq);878HALDEBUG(ah, HAL_DEBUG_NFCAL,879" PHY NF Reg state: 0x%x\n",880OS_REG_READ(ah, AR_PHY_AGC_CONTROL));881HALDEBUG(ah, HAL_DEBUG_NFCAL,882" PHY Active Reg state: 0x%x\n",883OS_REG_READ(ah, AR_PHY_ACTIVE));884return 0;885}886887return ar5211GetNoiseFloor(ah);888}889890static HAL_BOOL891getNoiseFloorThresh(struct ath_hal *ah, const struct ieee80211_channel *chan,892int16_t *nft)893{894HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;895896switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {897case IEEE80211_CHAN_A:898*nft = ee->ee_noiseFloorThresh[0];899break;900case IEEE80211_CHAN_B:901*nft = ee->ee_noiseFloorThresh[1];902break;903case IEEE80211_CHAN_PUREG:904*nft = ee->ee_noiseFloorThresh[2];905break;906default:907HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",908__func__, chan->ic_flags);909return AH_FALSE;910}911return AH_TRUE;912}913914/*915* Read the NF and check it against the noise floor threshold916*917* Returns: TRUE if the NF is good918*/919static HAL_BOOL920ar5211IsNfGood(struct ath_hal *ah, struct ieee80211_channel *chan)921{922HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);923int16_t nf, nfThresh;924925if (!getNoiseFloorThresh(ah, chan, &nfThresh))926return AH_FALSE;927if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {928HALDEBUG(ah, HAL_DEBUG_ANY,929"%s: NF did not complete in calibration window\n", __func__);930}931nf = ar5211GetNoiseFloor(ah);932if (nf > nfThresh) {933HALDEBUG(ah, HAL_DEBUG_ANY,934"%s: noise floor failed; detected %u, threshold %u\n",935__func__, nf, nfThresh);936/*937* NB: Don't discriminate 2.4 vs 5Ghz, if this938* happens it indicates a problem regardless939* of the band.940*/941chan->ic_state |= IEEE80211_CHANSTATE_CWINT;942}943ichan->rawNoiseFloor = nf;944return (nf <= nfThresh);945}946947/*948* Peform the noisefloor calibration and check for any constant channel949* interference.950*951* NOTE: preAR5211 have a lengthy carrier wave detection process - hence952* it is if'ed for MKK regulatory domain only.953*954* Returns: TRUE for a successful noise floor calibration; else FALSE955*/956HAL_BOOL957ar5211CalNoiseFloor(struct ath_hal *ah, const struct ieee80211_channel *chan)958{959#define N(a) (sizeof (a) / sizeof (a[0]))960/* Check for Carrier Wave interference in MKK regulatory zone */961if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU &&962(chan->ic_flags & CHANNEL_NFCREQUIRED)) {963static const uint8_t runtime[3] = { 0, 2, 7 };964HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);965int16_t nf, nfThresh;966int i;967968if (!getNoiseFloorThresh(ah, chan, &nfThresh))969return AH_FALSE;970/*971* Run a quick noise floor that will hopefully972* complete (decrease delay time).973*/974for (i = 0; i < N(runtime); i++) {975nf = ar5211RunNoiseFloor(ah, runtime[i], 0);976if (nf > nfThresh) {977HALDEBUG(ah, HAL_DEBUG_ANY,978"%s: run failed with %u > threshold %u "979"(runtime %u)\n", __func__,980nf, nfThresh, runtime[i]);981ichan->rawNoiseFloor = 0;982} else983ichan->rawNoiseFloor = nf;984}985return (i <= N(runtime));986} else {987/* Calibrate the noise floor */988OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,989OS_REG_READ(ah, AR_PHY_AGC_CONTROL) |990AR_PHY_AGC_CONTROL_NF);991}992return AH_TRUE;993#undef N994}995996/*997* Adjust NF based on statistical values for 5GHz frequencies.998*/999int16_t1000ar5211GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c)1001{1002static const struct {1003uint16_t freqLow;1004int16_t adjust;1005} adjust5111[] = {1006{ 5790, 11 }, /* NB: ordered high -> low */1007{ 5730, 10 },1008{ 5690, 9 },1009{ 5660, 8 },1010{ 5610, 7 },1011{ 5530, 5 },1012{ 5450, 4 },1013{ 5379, 2 },1014{ 5209, 0 }, /* XXX? bogus but doesn't matter */1015{ 0, 1 },1016};1017int i;10181019for (i = 0; c->channel <= adjust5111[i].freqLow; i++)1020;1021/* NB: placeholder for 5111's less severe requirement */1022return adjust5111[i].adjust / 3;1023}10241025/*1026* Reads EEPROM header info from device structure and programs1027* analog registers 6 and 71028*1029* REQUIRES: Access to the analog device1030*/1031static HAL_BOOL1032ar5211SetRf6and7(struct ath_hal *ah, const struct ieee80211_channel *chan)1033{1034#define N(a) (sizeof (a) / sizeof (a[0]))1035uint16_t freq = ath_hal_gethwchannel(ah, chan);1036HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1037struct ath_hal_5211 *ahp = AH5211(ah);1038uint16_t rfXpdGain, rfPloSel, rfPwdXpd;1039uint16_t tempOB, tempDB;1040uint16_t freqIndex;1041int i;10421043freqIndex = IEEE80211_IS_CHAN_2GHZ(chan) ? 2 : 1;10441045/*1046* TODO: This array mode correspondes with the index used1047* during the read.1048* For readability, this should be changed to an enum or #define1049*/1050switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {1051case IEEE80211_CHAN_A:1052if (freq > 4000 && freq < 5260) {1053tempOB = ee->ee_ob1;1054tempDB = ee->ee_db1;1055} else if (freq >= 5260 && freq < 5500) {1056tempOB = ee->ee_ob2;1057tempDB = ee->ee_db2;1058} else if (freq >= 5500 && freq < 5725) {1059tempOB = ee->ee_ob3;1060tempDB = ee->ee_db3;1061} else if (freq >= 5725) {1062tempOB = ee->ee_ob4;1063tempDB = ee->ee_db4;1064} else {1065/* XXX panic?? */1066tempOB = tempDB = 0;1067}10681069rfXpdGain = ee->ee_xgain[0];1070rfPloSel = ee->ee_xpd[0];1071rfPwdXpd = !ee->ee_xpd[0];10721073ar5211Rf6n7[5][freqIndex] =1074(ar5211Rf6n7[5][freqIndex] & ~0x10000000) |1075(ee->ee_cornerCal.pd84<< 28);1076ar5211Rf6n7[6][freqIndex] =1077(ar5211Rf6n7[6][freqIndex] & ~0x04000000) |1078(ee->ee_cornerCal.pd90 << 26);1079ar5211Rf6n7[21][freqIndex] =1080(ar5211Rf6n7[21][freqIndex] & ~0x08) |1081(ee->ee_cornerCal.gSel << 3);1082break;1083case IEEE80211_CHAN_B:1084tempOB = ee->ee_obFor24;1085tempDB = ee->ee_dbFor24;1086rfXpdGain = ee->ee_xgain[1];1087rfPloSel = ee->ee_xpd[1];1088rfPwdXpd = !ee->ee_xpd[1];1089break;1090case IEEE80211_CHAN_PUREG:1091tempOB = ee->ee_obFor24g;1092tempDB = ee->ee_dbFor24g;1093rfXpdGain = ee->ee_xgain[2];1094rfPloSel = ee->ee_xpd[2];1095rfPwdXpd = !ee->ee_xpd[2];1096break;1097default:1098HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",1099__func__, chan->ic_flags);1100return AH_FALSE;1101}11021103HALASSERT(1 <= tempOB && tempOB <= 5);1104HALASSERT(1 <= tempDB && tempDB <= 5);11051106/* Set rfXpdGain and rfPwdXpd */1107ar5211Rf6n7[11][freqIndex] = (ar5211Rf6n7[11][freqIndex] & ~0xC0) |1108(((ath_hal_reverseBits(rfXpdGain, 4) << 7) | (rfPwdXpd << 6)) & 0xC0);1109ar5211Rf6n7[12][freqIndex] = (ar5211Rf6n7[12][freqIndex] & ~0x07) |1110((ath_hal_reverseBits(rfXpdGain, 4) >> 1) & 0x07);11111112/* Set OB */1113ar5211Rf6n7[12][freqIndex] = (ar5211Rf6n7[12][freqIndex] & ~0x80) |1114((ath_hal_reverseBits(tempOB, 3) << 7) & 0x80);1115ar5211Rf6n7[13][freqIndex] = (ar5211Rf6n7[13][freqIndex] & ~0x03) |1116((ath_hal_reverseBits(tempOB, 3) >> 1) & 0x03);11171118/* Set DB */1119ar5211Rf6n7[13][freqIndex] = (ar5211Rf6n7[13][freqIndex] & ~0x1C) |1120((ath_hal_reverseBits(tempDB, 3) << 2) & 0x1C);11211122/* Set rfPloSel */1123ar5211Rf6n7[17][freqIndex] = (ar5211Rf6n7[17][freqIndex] & ~0x08) |1124((rfPloSel << 3) & 0x08);11251126/* Write the Rf registers 6 & 7 */1127for (i = 0; i < N(ar5211Rf6n7); i++)1128OS_REG_WRITE(ah, ar5211Rf6n7[i][0], ar5211Rf6n7[i][freqIndex]);11291130/* Now that we have reprogrammed rfgain value, clear the flag. */1131ahp->ah_rfgainState = RFGAIN_INACTIVE;11321133return AH_TRUE;1134#undef N1135}11361137HAL_BOOL1138ar5211SetAntennaSwitchInternal(struct ath_hal *ah, HAL_ANT_SETTING settings,1139const struct ieee80211_channel *chan)1140{1141#define ANT_SWITCH_TABLE1 0x99601142#define ANT_SWITCH_TABLE2 0x99641143HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1144struct ath_hal_5211 *ahp = AH5211(ah);1145uint32_t antSwitchA, antSwitchB;1146int ix;11471148switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {1149case IEEE80211_CHAN_A: ix = 0; break;1150case IEEE80211_CHAN_B: ix = 1; break;1151case IEEE80211_CHAN_PUREG: ix = 2; break;1152default:1153HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",1154__func__, chan->ic_flags);1155return AH_FALSE;1156}11571158antSwitchA = ee->ee_antennaControl[1][ix]1159| (ee->ee_antennaControl[2][ix] << 6)1160| (ee->ee_antennaControl[3][ix] << 12)1161| (ee->ee_antennaControl[4][ix] << 18)1162| (ee->ee_antennaControl[5][ix] << 24)1163;1164antSwitchB = ee->ee_antennaControl[6][ix]1165| (ee->ee_antennaControl[7][ix] << 6)1166| (ee->ee_antennaControl[8][ix] << 12)1167| (ee->ee_antennaControl[9][ix] << 18)1168| (ee->ee_antennaControl[10][ix] << 24)1169;1170/*1171* For fixed antenna, give the same setting for both switch banks1172*/1173switch (settings) {1174case HAL_ANT_FIXED_A:1175antSwitchB = antSwitchA;1176break;1177case HAL_ANT_FIXED_B:1178antSwitchA = antSwitchB;1179break;1180case HAL_ANT_VARIABLE:1181break;1182default:1183HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad antenna setting %u\n",1184__func__, settings);1185return AH_FALSE;1186}1187ahp->ah_diversityControl = settings;11881189OS_REG_WRITE(ah, ANT_SWITCH_TABLE1, antSwitchA);1190OS_REG_WRITE(ah, ANT_SWITCH_TABLE2, antSwitchB);11911192return AH_TRUE;1193#undef ANT_SWITCH_TABLE11194#undef ANT_SWITCH_TABLE21195}11961197/*1198* Reads EEPROM header info and programs the device for correct operation1199* given the channel value1200*/1201static HAL_BOOL1202ar5211SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan)1203{1204HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1205struct ath_hal_5211 *ahp = AH5211(ah);1206int arrayMode, falseDectectBackoff;12071208switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {1209case IEEE80211_CHAN_A:1210arrayMode = 0;1211OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,1212AR_PHY_FRAME_CTL_TX_CLIP, ee->ee_cornerCal.clip);1213break;1214case IEEE80211_CHAN_B:1215arrayMode = 1;1216break;1217case IEEE80211_CHAN_PUREG:1218arrayMode = 2;1219break;1220default:1221HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",1222__func__, chan->ic_flags);1223return AH_FALSE;1224}12251226/* Set the antenna register(s) correctly for the chip revision */1227if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) {1228OS_REG_WRITE(ah, AR_PHY(68),1229(OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) | 0x3);1230} else {1231OS_REG_WRITE(ah, AR_PHY(68),1232(OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFC06) |1233(ee->ee_antennaControl[0][arrayMode] << 4) | 0x1);12341235ar5211SetAntennaSwitchInternal(ah,1236ahp->ah_diversityControl, chan);12371238/* Set the Noise Floor Thresh on ar5211 devices */1239OS_REG_WRITE(ah, AR_PHY_BASE + (90 << 2),1240(ee->ee_noiseFloorThresh[arrayMode] & 0x1FF) | (1<<9));1241}1242OS_REG_WRITE(ah, AR_PHY_BASE + (17 << 2),1243(OS_REG_READ(ah, AR_PHY_BASE + (17 << 2)) & 0xFFFFC07F) |1244((ee->ee_switchSettling[arrayMode] << 7) & 0x3F80));1245OS_REG_WRITE(ah, AR_PHY_BASE + (18 << 2),1246(OS_REG_READ(ah, AR_PHY_BASE + (18 << 2)) & 0xFFFC0FFF) |1247((ee->ee_txrxAtten[arrayMode] << 12) & 0x3F000));1248OS_REG_WRITE(ah, AR_PHY_BASE + (20 << 2),1249(OS_REG_READ(ah, AR_PHY_BASE + (20 << 2)) & 0xFFFF0000) |1250((ee->ee_pgaDesiredSize[arrayMode] << 8) & 0xFF00) |1251(ee->ee_adcDesiredSize[arrayMode] & 0x00FF));1252OS_REG_WRITE(ah, AR_PHY_BASE + (13 << 2),1253(ee->ee_txEndToXPAOff[arrayMode] << 24) |1254(ee->ee_txEndToXPAOff[arrayMode] << 16) |1255(ee->ee_txFrameToXPAOn[arrayMode] << 8) |1256ee->ee_txFrameToXPAOn[arrayMode]);1257OS_REG_WRITE(ah, AR_PHY_BASE + (10 << 2),1258(OS_REG_READ(ah, AR_PHY_BASE + (10 << 2)) & 0xFFFF00FF) |1259(ee->ee_txEndToXLNAOn[arrayMode] << 8));1260OS_REG_WRITE(ah, AR_PHY_BASE + (25 << 2),1261(OS_REG_READ(ah, AR_PHY_BASE + (25 << 2)) & 0xFFF80FFF) |1262((ee->ee_thresh62[arrayMode] << 12) & 0x7F000));12631264#define NO_FALSE_DETECT_BACKOFF 21265#define CB22_FALSE_DETECT_BACKOFF 61266/*1267* False detect backoff - suspected 32 MHz spur causes1268* false detects in OFDM, causing Tx Hangs. Decrease1269* weak signal sensitivity for this card.1270*/1271falseDectectBackoff = NO_FALSE_DETECT_BACKOFF;1272if (AH_PRIVATE(ah)->ah_eeversion < AR_EEPROM_VER3_3) {1273if (AH_PRIVATE(ah)->ah_subvendorid == 0x1022 &&1274IEEE80211_IS_CHAN_OFDM(chan))1275falseDectectBackoff += CB22_FALSE_DETECT_BACKOFF;1276} else {1277uint16_t freq = ath_hal_gethwchannel(ah, chan);1278uint32_t remainder = freq % 32;12791280if (remainder && (remainder < 10 || remainder > 22))1281falseDectectBackoff += ee->ee_falseDetectBackoff[arrayMode];1282}1283OS_REG_WRITE(ah, 0x9924,1284(OS_REG_READ(ah, 0x9924) & 0xFFFFFF01)1285| ((falseDectectBackoff << 1) & 0xF7));12861287return AH_TRUE;1288#undef NO_FALSE_DETECT_BACKOFF1289#undef CB22_FALSE_DETECT_BACKOFF1290}12911292/*1293* Set the limit on the overall output power. Used for dynamic1294* transmit power control and the like.1295*1296* NOTE: The power is passed in is in units of 0.5 dBm.1297*/1298HAL_BOOL1299ar5211SetTxPowerLimit(struct ath_hal *ah, uint32_t limit)1300{13011302AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER);1303OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, limit);1304return AH_TRUE;1305}13061307/*1308* Sets the transmit power in the baseband for the given1309* operating channel and mode.1310*/1311static HAL_BOOL1312ar5211SetTransmitPower(struct ath_hal *ah, const struct ieee80211_channel *chan)1313{1314uint16_t freq = ath_hal_gethwchannel(ah, chan);1315HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1316TRGT_POWER_INFO *pi;1317RD_EDGES_POWER *rep;1318PCDACS_EEPROM eepromPcdacs;1319u_int nchan, cfgCtl;1320int i;13211322/* setup the pcdac struct to point to the correct info, based on mode */1323switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {1324case IEEE80211_CHAN_A:1325eepromPcdacs.numChannels = ee->ee_numChannels11a;1326eepromPcdacs.pChannelList= ee->ee_channels11a;1327eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11a;1328nchan = ee->ee_numTargetPwr_11a;1329pi = ee->ee_trgtPwr_11a;1330break;1331case IEEE80211_CHAN_PUREG:1332eepromPcdacs.numChannels = ee->ee_numChannels2_4;1333eepromPcdacs.pChannelList= ee->ee_channels11g;1334eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11g;1335nchan = ee->ee_numTargetPwr_11g;1336pi = ee->ee_trgtPwr_11g;1337break;1338case IEEE80211_CHAN_B:1339eepromPcdacs.numChannels = ee->ee_numChannels2_4;1340eepromPcdacs.pChannelList= ee->ee_channels11b;1341eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11b;1342nchan = ee->ee_numTargetPwr_11b;1343pi = ee->ee_trgtPwr_11b;1344break;1345default:1346HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",1347__func__, chan->ic_flags);1348return AH_FALSE;1349}13501351ar5211SetPowerTable(ah, &eepromPcdacs, freq);13521353rep = AH_NULL;1354/* Match CTL to EEPROM value */1355cfgCtl = ath_hal_getctl(ah, chan);1356for (i = 0; i < ee->ee_numCtls; i++)1357if (ee->ee_ctl[i] != 0 && ee->ee_ctl[i] == cfgCtl) {1358rep = &ee->ee_rdEdgesPower[i * NUM_EDGES];1359break;1360}1361ar5211SetRateTable(ah, rep, pi, nchan, chan);13621363return AH_TRUE;1364}13651366/*1367* Read the transmit power levels from the structures taken1368* from EEPROM. Interpolate read transmit power values for1369* this channel. Organize the transmit power values into a1370* table for writing into the hardware.1371*/1372void1373ar5211SetPowerTable(struct ath_hal *ah, PCDACS_EEPROM *pSrcStruct,1374uint16_t channel)1375{1376static FULL_PCDAC_STRUCT pcdacStruct;1377static uint16_t pcdacTable[PWR_TABLE_SIZE];13781379uint16_t i, j;1380uint16_t *pPcdacValues;1381int16_t *pScaledUpDbm;1382int16_t minScaledPwr;1383int16_t maxScaledPwr;1384int16_t pwr;1385uint16_t pcdacMin = 0;1386uint16_t pcdacMax = 63;1387uint16_t pcdacTableIndex;1388uint16_t scaledPcdac;1389uint32_t addr;1390uint32_t temp32;13911392OS_MEMZERO(&pcdacStruct, sizeof(FULL_PCDAC_STRUCT));1393OS_MEMZERO(pcdacTable, sizeof(uint16_t) * PWR_TABLE_SIZE);1394pPcdacValues = pcdacStruct.PcdacValues;1395pScaledUpDbm = pcdacStruct.PwrValues;13961397/* Initialize the pcdacs to dBM structs pcdacs to be 1 to 63 */1398for (i = PCDAC_START, j = 0; i <= PCDAC_STOP; i+= PCDAC_STEP, j++)1399pPcdacValues[j] = i;14001401pcdacStruct.numPcdacValues = j;1402pcdacStruct.pcdacMin = PCDAC_START;1403pcdacStruct.pcdacMax = PCDAC_STOP;14041405/* Fill out the power values for this channel */1406for (j = 0; j < pcdacStruct.numPcdacValues; j++ )1407pScaledUpDbm[j] = ar5211GetScaledPower(channel, pPcdacValues[j], pSrcStruct);14081409/* Now scale the pcdac values to fit in the 64 entry power table */1410minScaledPwr = pScaledUpDbm[0];1411maxScaledPwr = pScaledUpDbm[pcdacStruct.numPcdacValues - 1];14121413/* find minimum and make monotonic */1414for (j = 0; j < pcdacStruct.numPcdacValues; j++) {1415if (minScaledPwr >= pScaledUpDbm[j]) {1416minScaledPwr = pScaledUpDbm[j];1417pcdacMin = j;1418}1419/*1420* Make the full_hsh monotonically increasing otherwise1421* interpolation algorithm will get fooled gotta start1422* working from the top, hence i = 63 - j.1423*/1424i = (uint16_t)(pcdacStruct.numPcdacValues - 1 - j);1425if (i == 0)1426break;1427if (pScaledUpDbm[i-1] > pScaledUpDbm[i]) {1428/*1429* It could be a glitch, so make the power for1430* this pcdac the same as the power from the1431* next highest pcdac.1432*/1433pScaledUpDbm[i - 1] = pScaledUpDbm[i];1434}1435}14361437for (j = 0; j < pcdacStruct.numPcdacValues; j++)1438if (maxScaledPwr < pScaledUpDbm[j]) {1439maxScaledPwr = pScaledUpDbm[j];1440pcdacMax = j;1441}14421443/* Find the first power level with a pcdac */1444pwr = (uint16_t)(PWR_STEP * ((minScaledPwr - PWR_MIN + PWR_STEP / 2) / PWR_STEP) + PWR_MIN);14451446/* Write all the first pcdac entries based off the pcdacMin */1447pcdacTableIndex = 0;1448for (i = 0; i < (2 * (pwr - PWR_MIN) / EEP_SCALE + 1); i++)1449pcdacTable[pcdacTableIndex++] = pcdacMin;14501451i = 0;1452while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1]) {1453pwr += PWR_STEP;1454/* stop if dbM > max_power_possible */1455while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] &&1456(pwr - pScaledUpDbm[i])*(pwr - pScaledUpDbm[i+1]) > 0)1457i++;1458/* scale by 2 and add 1 to enable round up or down as needed */1459scaledPcdac = (uint16_t)(ar5211GetInterpolatedValue(pwr,1460pScaledUpDbm[i], pScaledUpDbm[i+1],1461(uint16_t)(pPcdacValues[i] * 2),1462(uint16_t)(pPcdacValues[i+1] * 2), 0) + 1);14631464pcdacTable[pcdacTableIndex] = scaledPcdac / 2;1465if (pcdacTable[pcdacTableIndex] > pcdacMax)1466pcdacTable[pcdacTableIndex] = pcdacMax;1467pcdacTableIndex++;1468}14691470/* Write all the last pcdac entries based off the last valid pcdac */1471while (pcdacTableIndex < PWR_TABLE_SIZE) {1472pcdacTable[pcdacTableIndex] = pcdacTable[pcdacTableIndex - 1];1473pcdacTableIndex++;1474}14751476/* Finally, write the power values into the baseband power table */1477addr = AR_PHY_BASE + (608 << 2);1478for (i = 0; i < 32; i++) {1479temp32 = 0xffff & ((pcdacTable[2 * i + 1] << 8) | 0xff);1480temp32 = (temp32 << 16) | (0xffff & ((pcdacTable[2 * i] << 8) | 0xff));1481OS_REG_WRITE(ah, addr, temp32);1482addr += 4;1483}14841485}14861487/*1488* Set the transmit power in the baseband for the given1489* operating channel and mode.1490*/1491static void1492ar5211SetRateTable(struct ath_hal *ah, RD_EDGES_POWER *pRdEdgesPower,1493TRGT_POWER_INFO *pPowerInfo, uint16_t numChannels,1494const struct ieee80211_channel *chan)1495{1496uint16_t freq = ath_hal_gethwchannel(ah, chan);1497HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1498struct ath_hal_5211 *ahp = AH5211(ah);1499static uint16_t ratesArray[NUM_RATES];1500static const uint16_t tpcScaleReductionTable[5] =1501{ 0, 3, 6, 9, MAX_RATE_POWER };15021503uint16_t *pRatesPower;1504uint16_t lowerChannel, lowerIndex=0, lowerPower=0;1505uint16_t upperChannel, upperIndex=0, upperPower=0;1506uint16_t twiceMaxEdgePower=63;1507uint16_t twicePower = 0;1508uint16_t i, numEdges;1509uint16_t tempChannelList[NUM_EDGES]; /* temp array for holding edge channels */1510uint16_t twiceMaxRDPower;1511int16_t scaledPower = 0; /* for gcc -O2 */1512uint16_t mask = 0x3f;1513HAL_BOOL paPreDEnable = 0;1514int8_t twiceAntennaGain, twiceAntennaReduction = 0;15151516pRatesPower = ratesArray;1517twiceMaxRDPower = chan->ic_maxregpower * 2;15181519if (IEEE80211_IS_CHAN_5GHZ(chan)) {1520twiceAntennaGain = ee->ee_antennaGainMax[0];1521} else {1522twiceAntennaGain = ee->ee_antennaGainMax[1];1523}15241525twiceAntennaReduction = ath_hal_getantennareduction(ah, chan, twiceAntennaGain);15261527if (pRdEdgesPower) {1528/* Get the edge power */1529for (i = 0; i < NUM_EDGES; i++) {1530if (pRdEdgesPower[i].rdEdge == 0)1531break;1532tempChannelList[i] = pRdEdgesPower[i].rdEdge;1533}1534numEdges = i;15351536ar5211GetLowerUpperValues(freq, tempChannelList,1537numEdges, &lowerChannel, &upperChannel);1538/* Get the index for this channel */1539for (i = 0; i < numEdges; i++)1540if (lowerChannel == tempChannelList[i])1541break;1542HALASSERT(i != numEdges);15431544if ((lowerChannel == upperChannel &&1545lowerChannel == freq) ||1546pRdEdgesPower[i].flag) {1547twiceMaxEdgePower = pRdEdgesPower[i].twice_rdEdgePower;1548HALASSERT(twiceMaxEdgePower > 0);1549}1550}15511552/* extrapolate the power values for the test Groups */1553for (i = 0; i < numChannels; i++)1554tempChannelList[i] = pPowerInfo[i].testChannel;15551556ar5211GetLowerUpperValues(freq, tempChannelList,1557numChannels, &lowerChannel, &upperChannel);15581559/* get the index for the channel */1560for (i = 0; i < numChannels; i++) {1561if (lowerChannel == tempChannelList[i])1562lowerIndex = i;1563if (upperChannel == tempChannelList[i]) {1564upperIndex = i;1565break;1566}1567}15681569for (i = 0; i < NUM_RATES; i++) {1570if (IEEE80211_IS_CHAN_OFDM(chan)) {1571/* power for rates 6,9,12,18,24 is all the same */1572if (i < 5) {1573lowerPower = pPowerInfo[lowerIndex].twicePwr6_24;1574upperPower = pPowerInfo[upperIndex].twicePwr6_24;1575} else if (i == 5) {1576lowerPower = pPowerInfo[lowerIndex].twicePwr36;1577upperPower = pPowerInfo[upperIndex].twicePwr36;1578} else if (i == 6) {1579lowerPower = pPowerInfo[lowerIndex].twicePwr48;1580upperPower = pPowerInfo[upperIndex].twicePwr48;1581} else if (i == 7) {1582lowerPower = pPowerInfo[lowerIndex].twicePwr54;1583upperPower = pPowerInfo[upperIndex].twicePwr54;1584}1585} else {1586switch (i) {1587case 0:1588case 1:1589lowerPower = pPowerInfo[lowerIndex].twicePwr6_24;1590upperPower = pPowerInfo[upperIndex].twicePwr6_24;1591break;1592case 2:1593case 3:1594lowerPower = pPowerInfo[lowerIndex].twicePwr36;1595upperPower = pPowerInfo[upperIndex].twicePwr36;1596break;1597case 4:1598case 5:1599lowerPower = pPowerInfo[lowerIndex].twicePwr48;1600upperPower = pPowerInfo[upperIndex].twicePwr48;1601break;1602case 6:1603case 7:1604lowerPower = pPowerInfo[lowerIndex].twicePwr54;1605upperPower = pPowerInfo[upperIndex].twicePwr54;1606break;1607}1608}16091610twicePower = ar5211GetInterpolatedValue(freq,1611lowerChannel, upperChannel, lowerPower, upperPower, 0);16121613/* Reduce power by band edge restrictions */1614twicePower = AH_MIN(twicePower, twiceMaxEdgePower);16151616/*1617* If turbo is set, reduce power to keep power1618* consumption under 2 Watts. Note that we always do1619* this unless specially configured. Then we limit1620* power only for non-AP operation.1621*/1622if (IEEE80211_IS_CHAN_TURBO(chan) &&1623AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_11624#ifdef AH_ENABLE_AP_SUPPORT1625&& AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP1626#endif1627) {1628twicePower = AH_MIN(twicePower, ee->ee_turbo2WMaxPower5);1629}16301631/* Reduce power by max regulatory domain allowed restrictions */1632pRatesPower[i] = AH_MIN(twicePower, twiceMaxRDPower - twiceAntennaReduction);16331634/* Use 6 Mb power level for transmit power scaling reduction */1635/* We don't want to reduce higher rates if its not needed */1636if (i == 0) {1637scaledPower = pRatesPower[0] -1638(tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2);1639if (scaledPower < 1)1640scaledPower = 1;1641}16421643pRatesPower[i] = AH_MIN(pRatesPower[i], scaledPower);1644}16451646/* Record txPower at Rate 6 for info gathering */1647ahp->ah_tx6PowerInHalfDbm = pRatesPower[0];16481649#ifdef AH_DEBUG1650HALDEBUG(ah, HAL_DEBUG_RESET,1651"%s: final output power setting %d MHz:\n",1652__func__, chan->ic_freq);1653HALDEBUG(ah, HAL_DEBUG_RESET,1654"6 Mb %d dBm, MaxRD: %d dBm, MaxEdge %d dBm\n",1655scaledPower / 2, twiceMaxRDPower / 2, twiceMaxEdgePower / 2);1656HALDEBUG(ah, HAL_DEBUG_RESET, "TPC Scale %d dBm - Ant Red %d dBm\n",1657tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2,1658twiceAntennaReduction / 2);1659if (IEEE80211_IS_CHAN_TURBO(chan) &&1660AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1)1661HALDEBUG(ah, HAL_DEBUG_RESET, "Max Turbo %d dBm\n",1662ee->ee_turbo2WMaxPower5);1663HALDEBUG(ah, HAL_DEBUG_RESET,1664" %2d | %2d | %2d | %2d | %2d | %2d | %2d | %2d dBm\n",1665pRatesPower[0] / 2, pRatesPower[1] / 2, pRatesPower[2] / 2,1666pRatesPower[3] / 2, pRatesPower[4] / 2, pRatesPower[5] / 2,1667pRatesPower[6] / 2, pRatesPower[7] / 2);1668#endif /* AH_DEBUG */16691670/* Write the power table into the hardware */1671OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,1672((paPreDEnable & 1)<< 30) | ((pRatesPower[3] & mask) << 24) |1673((paPreDEnable & 1)<< 22) | ((pRatesPower[2] & mask) << 16) |1674((paPreDEnable & 1)<< 14) | ((pRatesPower[1] & mask) << 8) |1675((paPreDEnable & 1)<< 6 ) | (pRatesPower[0] & mask));1676OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,1677((paPreDEnable & 1)<< 30) | ((pRatesPower[7] & mask) << 24) |1678((paPreDEnable & 1)<< 22) | ((pRatesPower[6] & mask) << 16) |1679((paPreDEnable & 1)<< 14) | ((pRatesPower[5] & mask) << 8) |1680((paPreDEnable & 1)<< 6 ) | (pRatesPower[4] & mask));16811682/* set max power to the power value at rate 6 */1683ar5211SetTxPowerLimit(ah, pRatesPower[0]);16841685AH_PRIVATE(ah)->ah_maxPowerLevel = pRatesPower[0];1686}16871688/*1689* Get or interpolate the pcdac value from the calibrated data1690*/1691uint16_t1692ar5211GetScaledPower(uint16_t channel, uint16_t pcdacValue,1693const PCDACS_EEPROM *pSrcStruct)1694{1695uint16_t powerValue;1696uint16_t lFreq, rFreq; /* left and right frequency values */1697uint16_t llPcdac, ulPcdac; /* lower and upper left pcdac values */1698uint16_t lrPcdac, urPcdac; /* lower and upper right pcdac values */1699uint16_t lPwr, uPwr; /* lower and upper temp pwr values */1700uint16_t lScaledPwr, rScaledPwr; /* left and right scaled power */17011702if (ar5211FindValueInList(channel, pcdacValue, pSrcStruct, &powerValue))1703/* value was copied from srcStruct */1704return powerValue;17051706ar5211GetLowerUpperValues(channel, pSrcStruct->pChannelList,1707pSrcStruct->numChannels, &lFreq, &rFreq);1708ar5211GetLowerUpperPcdacs(pcdacValue, lFreq, pSrcStruct,1709&llPcdac, &ulPcdac);1710ar5211GetLowerUpperPcdacs(pcdacValue, rFreq, pSrcStruct,1711&lrPcdac, &urPcdac);17121713/* get the power index for the pcdac value */1714ar5211FindValueInList(lFreq, llPcdac, pSrcStruct, &lPwr);1715ar5211FindValueInList(lFreq, ulPcdac, pSrcStruct, &uPwr);1716lScaledPwr = ar5211GetInterpolatedValue(pcdacValue,1717llPcdac, ulPcdac, lPwr, uPwr, 0);17181719ar5211FindValueInList(rFreq, lrPcdac, pSrcStruct, &lPwr);1720ar5211FindValueInList(rFreq, urPcdac, pSrcStruct, &uPwr);1721rScaledPwr = ar5211GetInterpolatedValue(pcdacValue,1722lrPcdac, urPcdac, lPwr, uPwr, 0);17231724return ar5211GetInterpolatedValue(channel, lFreq, rFreq,1725lScaledPwr, rScaledPwr, 0);1726}17271728/*1729* Find the value from the calibrated source data struct1730*/1731HAL_BOOL1732ar5211FindValueInList(uint16_t channel, uint16_t pcdacValue,1733const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue)1734{1735const DATA_PER_CHANNEL *pChannelData;1736const uint16_t *pPcdac;1737uint16_t i, j;17381739pChannelData = pSrcStruct->pDataPerChannel;1740for (i = 0; i < pSrcStruct->numChannels; i++ ) {1741if (pChannelData->channelValue == channel) {1742pPcdac = pChannelData->PcdacValues;1743for (j = 0; j < pChannelData->numPcdacValues; j++ ) {1744if (*pPcdac == pcdacValue) {1745*powerValue = pChannelData->PwrValues[j];1746return AH_TRUE;1747}1748pPcdac++;1749}1750}1751pChannelData++;1752}1753return AH_FALSE;1754}17551756/*1757* Returns interpolated or the scaled up interpolated value1758*/1759uint16_t1760ar5211GetInterpolatedValue(uint16_t target,1761uint16_t srcLeft, uint16_t srcRight,1762uint16_t targetLeft, uint16_t targetRight,1763HAL_BOOL scaleUp)1764{1765uint16_t rv;1766int16_t lRatio;1767uint16_t scaleValue = EEP_SCALE;17681769/* to get an accurate ratio, always scale, if want to scale, then don't scale back down */1770if ((targetLeft * targetRight) == 0)1771return 0;1772if (scaleUp)1773scaleValue = 1;17741775if (srcRight != srcLeft) {1776/*1777* Note the ratio always need to be scaled,1778* since it will be a fraction.1779*/1780lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft);1781if (lRatio < 0) {1782/* Return as Left target if value would be negative */1783rv = targetLeft * (scaleUp ? EEP_SCALE : 1);1784} else if (lRatio > EEP_SCALE) {1785/* Return as Right target if Ratio is greater than 100% (SCALE) */1786rv = targetRight * (scaleUp ? EEP_SCALE : 1);1787} else {1788rv = (lRatio * targetRight + (EEP_SCALE - lRatio) *1789targetLeft) / scaleValue;1790}1791} else {1792rv = targetLeft;1793if (scaleUp)1794rv *= EEP_SCALE;1795}1796return rv;1797}17981799/*1800* Look for value being within 0.1 of the search values1801* however, NDIS can't do float calculations, so multiply everything1802* up by EEP_SCALE so can do integer arithmatic1803*1804* INPUT value -value to search for1805* INPUT pList -ptr to the list to search1806* INPUT listSize -number of entries in list1807* OUTPUT pLowerValue -return the lower value1808* OUTPUT pUpperValue -return the upper value1809*/1810void1811ar5211GetLowerUpperValues(uint16_t value,1812const uint16_t *pList, uint16_t listSize,1813uint16_t *pLowerValue, uint16_t *pUpperValue)1814{1815const uint16_t listEndValue = *(pList + listSize - 1);1816uint32_t target = value * EEP_SCALE;1817int i;18181819/*1820* See if value is lower than the first value in the list1821* if so return first value1822*/1823if (target < (uint32_t)(*pList * EEP_SCALE - EEP_DELTA)) {1824*pLowerValue = *pList;1825*pUpperValue = *pList;1826return;1827}18281829/*1830* See if value is greater than last value in list1831* if so return last value1832*/1833if (target > (uint32_t)(listEndValue * EEP_SCALE + EEP_DELTA)) {1834*pLowerValue = listEndValue;1835*pUpperValue = listEndValue;1836return;1837}18381839/* look for value being near or between 2 values in list */1840for (i = 0; i < listSize; i++) {1841/*1842* If value is close to the current value of the list1843* then target is not between values, it is one of the values1844*/1845if (abs(pList[i] * EEP_SCALE - (int32_t) target) < EEP_DELTA) {1846*pLowerValue = pList[i];1847*pUpperValue = pList[i];1848return;1849}18501851/*1852* Look for value being between current value and next value1853* if so return these 2 values1854*/1855if (target < (uint32_t)(pList[i + 1] * EEP_SCALE - EEP_DELTA)) {1856*pLowerValue = pList[i];1857*pUpperValue = pList[i + 1];1858return;1859}1860}1861}18621863/*1864* Get the upper and lower pcdac given the channel and the pcdac1865* used in the search1866*/1867void1868ar5211GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel,1869const PCDACS_EEPROM *pSrcStruct,1870uint16_t *pLowerPcdac, uint16_t *pUpperPcdac)1871{1872const DATA_PER_CHANNEL *pChannelData;1873int i;18741875/* Find the channel information */1876pChannelData = pSrcStruct->pDataPerChannel;1877for (i = 0; i < pSrcStruct->numChannels; i++) {1878if (pChannelData->channelValue == channel)1879break;1880pChannelData++;1881}1882ar5211GetLowerUpperValues(pcdac, pChannelData->PcdacValues,1883pChannelData->numPcdacValues, pLowerPcdac, pUpperPcdac);1884}18851886#define DYN_ADJ_UP_MARGIN 151887#define DYN_ADJ_LO_MARGIN 2018881889static const GAIN_OPTIMIZATION_LADDER gainLadder = {18909, /* numStepsInLadder */18914, /* defaultStepNum */1892{ { {4, 1, 1, 1}, 6, "FG8"},1893{ {4, 0, 1, 1}, 4, "FG7"},1894{ {3, 1, 1, 1}, 3, "FG6"},1895{ {4, 0, 0, 1}, 1, "FG5"},1896{ {4, 1, 1, 0}, 0, "FG4"}, /* noJack */1897{ {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */1898{ {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */1899{ {4, 0, 0, 0}, -4, "FG1"}, /* noJack */1900{ {2, 1, 1, 0}, -6, "FG0"} /* clip2 */1901}1902};19031904/*1905* Initialize the gain structure to good values1906*/1907void1908ar5211InitializeGainValues(struct ath_hal *ah)1909{1910struct ath_hal_5211 *ahp = AH5211(ah);1911GAIN_VALUES *gv = &ahp->ah_gainValues;19121913/* initialize gain optimization values */1914gv->currStepNum = gainLadder.defaultStepNum;1915gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum];1916gv->active = AH_TRUE;1917gv->loTrig = 20;1918gv->hiTrig = 35;1919}19201921static HAL_BOOL1922ar5211InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv)1923{1924const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;1925uint32_t gStep, g;1926uint32_t L1, L2, L3, L4;19271928if (IEEE80211_IS_CHAN_CCK(chan)) {1929gStep = 0x18;1930L1 = 0;1931L2 = gStep + 4;1932L3 = 0x40;1933L4 = L3 + 50;19341935gv->loTrig = L1;1936gv->hiTrig = L4+5;1937} else {1938gStep = 0x3f;1939L1 = 0;1940L2 = 50;1941L3 = L1;1942L4 = L3 + 50;19431944gv->loTrig = L1 + DYN_ADJ_LO_MARGIN;1945gv->hiTrig = L4 - DYN_ADJ_UP_MARGIN;1946}1947g = gv->currGain;19481949return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4));1950}19511952/*1953* Enable the probe gain check on the next packet1954*/1955static void1956ar5211RequestRfgain(struct ath_hal *ah)1957{1958struct ath_hal_5211 *ahp = AH5211(ah);19591960/* Enable the gain readback probe */1961OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE,1962SM(ahp->ah_tx6PowerInHalfDbm, AR_PHY_PAPD_PROBE_POWERTX)1963| AR_PHY_PAPD_PROBE_NEXT_TX);19641965ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED;1966}19671968/*1969* Exported call to check for a recent gain reading and return1970* the current state of the thermal calibration gain engine.1971*/1972HAL_RFGAIN1973ar5211GetRfgain(struct ath_hal *ah)1974{1975struct ath_hal_5211 *ahp = AH5211(ah);1976GAIN_VALUES *gv = &ahp->ah_gainValues;1977uint32_t rddata;19781979if (!gv->active)1980return HAL_RFGAIN_INACTIVE;19811982if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) {1983/* Caller had asked to setup a new reading. Check it. */1984rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE);19851986if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) {1987/* bit got cleared, we have a new reading. */1988gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S;1989/* inactive by default */1990ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;19911992if (!ar5211InvalidGainReadback(ah, gv) &&1993ar5211IsGainAdjustNeeded(ah, gv) &&1994ar5211AdjustGain(ah, gv) > 0) {1995/*1996* Change needed. Copy ladder info1997* into eeprom info.1998*/1999ar5211SetRfgain(ah, gv);2000ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE;2001}2002}2003}2004return ahp->ah_rfgainState;2005}20062007/*2008* Check to see if our readback gain level sits within the linear2009* region of our current variable attenuation window2010*/2011static HAL_BOOL2012ar5211IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv)2013{2014return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig);2015}20162017/*2018* Move the rabbit ears in the correct direction.2019*/2020static int32_t2021ar5211AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv)2022{2023/* return > 0 for valid adjustments. */2024if (!gv->active)2025return -1;20262027gv->currStep = &gainLadder.optStep[gv->currStepNum];2028if (gv->currGain >= gv->hiTrig) {2029if (gv->currStepNum == 0) {2030HALDEBUG(ah, HAL_DEBUG_RFPARAM,2031"%s: Max gain limit.\n", __func__);2032return -1;2033}2034HALDEBUG(ah, HAL_DEBUG_RFPARAM,2035"%s: Adding gain: currG=%d [%s] --> ",2036__func__, gv->currGain, gv->currStep->stepName);2037gv->targetGain = gv->currGain;2038while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) {2039gv->targetGain -= 2 * (gainLadder.optStep[--(gv->currStepNum)].stepGain -2040gv->currStep->stepGain);2041gv->currStep = &gainLadder.optStep[gv->currStepNum];2042}2043HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",2044gv->targetGain, gv->currStep->stepName);2045return 1;2046}2047if (gv->currGain <= gv->loTrig) {2048if (gv->currStepNum == gainLadder.numStepsInLadder-1) {2049HALDEBUG(ah, HAL_DEBUG_RFPARAM,2050"%s: Min gain limit.\n", __func__);2051return -2;2052}2053HALDEBUG(ah, HAL_DEBUG_RFPARAM,2054"%s: Deducting gain: currG=%d [%s] --> ",2055__func__, gv->currGain, gv->currStep->stepName);2056gv->targetGain = gv->currGain;2057while (gv->targetGain <= gv->loTrig &&2058gv->currStepNum < (gainLadder.numStepsInLadder - 1)) {2059gv->targetGain -= 2 *2060(gainLadder.optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain);2061gv->currStep = &gainLadder.optStep[gv->currStepNum];2062}2063HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n",2064gv->targetGain, gv->currStep->stepName);2065return 2;2066}2067return 0; /* caller didn't call needAdjGain first */2068}20692070/*2071* Adjust the 5GHz EEPROM information with the desired calibration values.2072*/2073static void2074ar5211SetRfgain(struct ath_hal *ah, const GAIN_VALUES *gv)2075{2076HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;20772078if (!gv->active)2079return;2080ee->ee_cornerCal.clip = gv->currStep->paramVal[0]; /* bb_tx_clip */2081ee->ee_cornerCal.pd90 = gv->currStep->paramVal[1]; /* rf_pwd_90 */2082ee->ee_cornerCal.pd84 = gv->currStep->paramVal[2]; /* rf_pwd_84 */2083ee->ee_cornerCal.gSel = gv->currStep->paramVal[3]; /* rf_rfgainsel */2084}20852086static void2087ar5211SetOperatingMode(struct ath_hal *ah, int opmode)2088{2089struct ath_hal_5211 *ahp = AH5211(ah);2090uint32_t val;20912092val = OS_REG_READ(ah, AR_STA_ID1) & 0xffff;2093switch (opmode) {2094case HAL_M_HOSTAP:2095OS_REG_WRITE(ah, AR_STA_ID1, val2096| AR_STA_ID1_STA_AP2097| AR_STA_ID1_RTS_USE_DEF2098| ahp->ah_staId1Defaults);2099break;2100case HAL_M_IBSS:2101OS_REG_WRITE(ah, AR_STA_ID1, val2102| AR_STA_ID1_ADHOC2103| AR_STA_ID1_DESC_ANTENNA2104| ahp->ah_staId1Defaults);2105break;2106case HAL_M_STA:2107case HAL_M_MONITOR:2108OS_REG_WRITE(ah, AR_STA_ID1, val2109| AR_STA_ID1_DEFAULT_ANTENNA2110| ahp->ah_staId1Defaults);2111break;2112}2113}21142115void2116ar5211SetPCUConfig(struct ath_hal *ah)2117{2118ar5211SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode);2119}212021212122