Path: blob/main/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2008 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#include "ah.h"21#include "ah_internal.h"22#include "ah_devid.h"2324#include "ar5212/ar5212.h"25#include "ar5212/ar5212reg.h"26#include "ar5212/ar5212phy.h"2728#include "ah_eeprom_v3.h"2930/* Additional Time delay to wait after activiting the Base band */31#define BASE_ACTIVATE_DELAY 100 /* 100 usec */32#define PLL_SETTLE_DELAY 300 /* 300 usec */3334static HAL_BOOL ar5212SetResetReg(struct ath_hal *, uint32_t resetMask);35/* NB: public for 5312 use */36HAL_BOOL ar5212IsSpurChannel(struct ath_hal *,37const struct ieee80211_channel *);38HAL_BOOL ar5212ChannelChange(struct ath_hal *,39const struct ieee80211_channel *);40int16_t ar5212GetNf(struct ath_hal *, struct ieee80211_channel *);41HAL_BOOL ar5212SetBoardValues(struct ath_hal *,42const struct ieee80211_channel *);43void ar5212SetDeltaSlope(struct ath_hal *,44const struct ieee80211_channel *);45HAL_BOOL ar5212SetTransmitPower(struct ath_hal *ah,46const struct ieee80211_channel *chan, uint16_t *rfXpdGain);47static HAL_BOOL ar5212SetRateTable(struct ath_hal *,48const struct ieee80211_channel *, int16_t tpcScaleReduction,49int16_t powerLimit,50HAL_BOOL commit, int16_t *minPower, int16_t *maxPower);51static void ar5212CorrectGainDelta(struct ath_hal *, int twiceOfdmCckDelta);52static void ar5212GetTargetPowers(struct ath_hal *,53const struct ieee80211_channel *,54const TRGT_POWER_INFO *pPowerInfo, uint16_t numChannels,55TRGT_POWER_INFO *pNewPower);56static uint16_t ar5212GetMaxEdgePower(uint16_t channel,57const RD_EDGES_POWER *pRdEdgesPower);58void ar5212SetRateDurationTable(struct ath_hal *,59const struct ieee80211_channel *);60void ar5212SetIFSTiming(struct ath_hal *,61const struct ieee80211_channel *);6263/* NB: public for RF backend use */64void ar5212GetLowerUpperValues(uint16_t value,65uint16_t *pList, uint16_t listSize,66uint16_t *pLowerValue, uint16_t *pUpperValue);67void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,68uint32_t numBits, uint32_t firstBit, uint32_t column);6970static int71write_common(struct ath_hal *ah, const HAL_INI_ARRAY *ia,72HAL_BOOL bChannelChange, int writes)73{74#define IS_NO_RESET_TIMER_ADDR(x) \75( (((x) >= AR_BEACON) && ((x) <= AR_CFP_DUR)) || \76(((x) >= AR_SLEEP1) && ((x) <= AR_SLEEP3)))77#define V(r, c) (ia)->data[((r)*(ia)->cols) + (c)]78int r;7980/* Write Common Array Parameters */81for (r = 0; r < ia->rows; r++) {82uint32_t reg = V(r, 0);83/* XXX timer/beacon setup registers? */84/* On channel change, don't reset the PCU registers */85if (!(bChannelChange && IS_NO_RESET_TIMER_ADDR(reg))) {86OS_REG_WRITE(ah, reg, V(r, 1));87DMA_YIELD(writes);88}89}90return writes;91#undef IS_NO_RESET_TIMER_ADDR92#undef V93}9495#define IS_DISABLE_FAST_ADC_CHAN(x) (((x) == 2462) || ((x) == 2467))9697/*98* XXX NDIS 5.x code had MAX_RESET_WAIT set to 2000 for AP code99* and 10 for Client code100*/101#define MAX_RESET_WAIT 10102103#define TX_QUEUEPEND_CHECK 1104#define TX_ENABLE_CHECK 2105#define RX_ENABLE_CHECK 4106107/*108* Places the device in and out of reset and then places sane109* values in the registers based on EEPROM config, initialization110* vectors (as determined by the mode), and station configuration111*112* bChannelChange is used to preserve DMA/PCU registers across113* a HW Reset during channel change.114*/115HAL_BOOL116ar5212Reset(struct ath_hal *ah, HAL_OPMODE opmode,117struct ieee80211_channel *chan,118HAL_BOOL bChannelChange,119HAL_RESET_TYPE resetType,120HAL_STATUS *status)121{122#define N(a) (sizeof (a) / sizeof (a[0]))123#define FAIL(_code) do { ecode = _code; goto bad; } while (0)124struct ath_hal_5212 *ahp = AH5212(ah);125HAL_CHANNEL_INTERNAL *ichan = AH_NULL;126const HAL_EEPROM *ee;127uint32_t softLedCfg, softLedState;128uint32_t saveFrameSeqCount, saveDefAntenna, saveLedState;129uint32_t macStaId1, synthDelay, txFrm2TxDStart;130uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL];131int16_t cckOfdmPwrDelta = 0;132u_int modesIndex, freqIndex;133HAL_STATUS ecode;134int i, regWrites;135uint32_t testReg, powerVal;136int8_t twiceAntennaGain, twiceAntennaReduction;137uint32_t ackTpcPow, ctsTpcPow, chirpTpcPow;138HAL_BOOL isBmode = AH_FALSE;139140HALASSERT(ah->ah_magic == AR5212_MAGIC);141ee = AH_PRIVATE(ah)->ah_eeprom;142143OS_MARK(ah, AH_MARK_RESET, bChannelChange);144145/* Bring out of sleep mode */146if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {147HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip did not wakeup\n",148__func__);149FAIL(HAL_EIO);150}151152/*153* Map public channel to private.154*/155ichan = ath_hal_checkchannel(ah, chan);156if (ichan == AH_NULL)157FAIL(HAL_EINVAL);158switch (opmode) {159case HAL_M_STA:160case HAL_M_IBSS:161case HAL_M_HOSTAP:162case HAL_M_MONITOR:163break;164default:165HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n",166__func__, opmode);167FAIL(HAL_EINVAL);168break;169}170HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3);171172SAVE_CCK(ah, chan, isBmode);173174/* Preserve certain DMA hardware registers on a channel change */175if (bChannelChange) {176/*177* On Venice, the TSF is almost preserved across a reset;178* it requires doubling writes to the RESET_TSF179* bit in the AR_BEACON register; it also has the quirk180* of the TSF going back in time on the station (station181* latches onto the last beacon's tsf during a reset 50%182* of the times); the latter is not a problem for adhoc183* stations since as long as the TSF is behind, it will184* get resynchronized on receiving the next beacon; the185* TSF going backwards in time could be a problem for the186* sleep operation (supported on infrastructure stations187* only) - the best and most general fix for this situation188* is to resynchronize the various sleep/beacon timers on189* the receipt of the next beacon i.e. when the TSF itself190* gets resynchronized to the AP's TSF - power save is191* needed to be temporarily disabled until that time192*193* Need to save the sequence number to restore it after194* the reset!195*/196saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM);197} else198saveFrameSeqCount = 0; /* NB: silence compiler */199200/* Blank the channel survey statistics */201ath_hal_survey_clear(ah);202203#if 0204/*205* XXX disable for now; this appears to sometimes cause OFDM206* XXX timing error floods when ani is enabled and bg scanning207* XXX kicks in208*/209/* If the channel change is across the same mode - perform a fast channel change */210if (IS_2413(ah) || IS_5413(ah)) {211/*212* Fast channel change can only be used when:213* -channel change requested - so it's not the initial reset.214* -it's not a change to the current channel -215* often called when switching modes on a channel216* -the modes of the previous and requested channel are the217* same218* XXX opmode shouldn't change either?219*/220if (bChannelChange &&221(AH_PRIVATE(ah)->ah_curchan != AH_NULL) &&222(chan->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) &&223((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) ==224(AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) {225if (ar5212ChannelChange(ah, chan)) {226/* If ChannelChange completed - skip the rest of reset */227/* XXX ani? */228goto done;229}230}231}232#endif233/*234* Preserve the antenna on a channel change235*/236saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);237if (saveDefAntenna == 0) /* XXX magic constants */238saveDefAntenna = 1;239240/* Save hardware flag before chip reset clears the register */241macStaId1 = OS_REG_READ(ah, AR_STA_ID1) &242(AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT);243244/* Save led state from pci config register */245saveLedState = OS_REG_READ(ah, AR_PCICFG) &246(AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK |247AR_PCICFG_LEDSLOW);248softLedCfg = OS_REG_READ(ah, AR_GPIOCR);249softLedState = OS_REG_READ(ah, AR_GPIODO);250251ar5212RestoreClock(ah, opmode); /* move to refclk operation */252253/*254* Adjust gain parameters before reset if255* there's an outstanding gain updated.256*/257(void) ar5212GetRfgain(ah);258259if (!ar5212ChipReset(ah, chan)) {260HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);261FAIL(HAL_EIO);262}263264/* Setup the indices for the next set of register array writes */265if (IEEE80211_IS_CHAN_2GHZ(chan)) {266freqIndex = 2;267if (IEEE80211_IS_CHAN_108G(chan))268modesIndex = 5;269else if (IEEE80211_IS_CHAN_G(chan))270modesIndex = 4;271else if (IEEE80211_IS_CHAN_B(chan))272modesIndex = 3;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} else {280freqIndex = 1;281if (IEEE80211_IS_CHAN_TURBO(chan))282modesIndex = 2;283else if (IEEE80211_IS_CHAN_A(chan))284modesIndex = 1;285else {286HALDEBUG(ah, HAL_DEBUG_ANY,287"%s: invalid channel %u/0x%x\n",288__func__, chan->ic_freq, chan->ic_flags);289FAIL(HAL_EINVAL);290}291}292293OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);294295/* Set correct Baseband to analog shift setting to access analog chips. */296OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);297298regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0);299regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange,300regWrites);301#ifdef AH_RXCFG_SDMAMW_4BYTES302/*303* Nala doesn't work with 128 byte bursts on pb42(hydra) (ar71xx),304* use 4 instead. Enabling it on all platforms would hurt performance,305* so we only enable it on the ones that are affected by it.306*/307OS_REG_WRITE(ah, AR_RXCFG, 0);308#endif309ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites);310311OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);312313if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) {314ar5212SetIFSTiming(ah, chan);315if (IS_5413(ah)) {316/*317* Force window_length for 1/2 and 1/4 rate channels,318* the ini file sets this to zero otherwise.319*/320OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,321AR_PHY_FRAME_CTL_WINLEN, 3);322}323}324325/* Overwrite INI values for revised chipsets */326if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) {327/* ADC_CTL */328OS_REG_WRITE(ah, AR_PHY_ADC_CTL,329SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) |330SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) |331AR_PHY_ADC_CTL_OFF_PWDDAC |332AR_PHY_ADC_CTL_OFF_PWDADC);333334/* TX_PWR_ADJ */335if (ichan->channel == 2484) {336cckOfdmPwrDelta = SCALE_OC_DELTA(337ee->ee_cckOfdmPwrDelta -338ee->ee_scaledCh14FilterCckDelta);339} else {340cckOfdmPwrDelta = SCALE_OC_DELTA(341ee->ee_cckOfdmPwrDelta);342}343344if (IEEE80211_IS_CHAN_G(chan)) {345OS_REG_WRITE(ah, AR_PHY_TXPWRADJ,346SM((ee->ee_cckOfdmPwrDelta*-1),347AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) |348SM((cckOfdmPwrDelta*-1),349AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX));350} else {351OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0);352}353354/* Add barker RSSI thresh enable as disabled */355OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK,356AR_PHY_DAG_CTRLCCK_EN_RSSI_THR);357OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK,358AR_PHY_DAG_CTRLCCK_RSSI_THR, 2);359360/* Set the mute mask to the correct default */361OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F);362}363364if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) {365/* Clear reg to alllow RX_CLEAR line debug */366OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0);367}368if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) {369#ifdef notyet370/* Enable burst prefetch for the data queues */371OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... );372/* Enable double-buffering */373OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS);374#endif375}376377/* Set ADC/DAC select values */378OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);379380if (IS_5413(ah) || IS_2417(ah)) {381uint32_t newReg = 1;382if (IS_DISABLE_FAST_ADC_CHAN(ichan->channel))383newReg = 0;384/* As it's a clock changing register, only write when the value needs to be changed */385if (OS_REG_READ(ah, AR_PHY_FAST_ADC) != newReg)386OS_REG_WRITE(ah, AR_PHY_FAST_ADC, newReg);387}388389/* Setup the transmit power values. */390if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) {391HALDEBUG(ah, HAL_DEBUG_ANY,392"%s: error init'ing transmit power\n", __func__);393FAIL(HAL_EIO);394}395396/* Write the analog registers */397if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) {398HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n",399__func__);400FAIL(HAL_EIO);401}402403/* Write delta slope for OFDM enabled modes (A, G, Turbo) */404if (IEEE80211_IS_CHAN_OFDM(chan)) {405if (IS_5413(ah) ||406AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3)407ar5212SetSpurMitigation(ah, chan);408ar5212SetDeltaSlope(ah, chan);409}410411/* Setup board specific options for EEPROM version 3 */412if (!ar5212SetBoardValues(ah, chan)) {413HALDEBUG(ah, HAL_DEBUG_ANY,414"%s: error setting board options\n", __func__);415FAIL(HAL_EIO);416}417418/* Restore certain DMA hardware registers on a channel change */419if (bChannelChange)420OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount);421422OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);423424OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));425OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)426| macStaId1427| AR_STA_ID1_RTS_USE_DEF428| ahp->ah_staId1Defaults429);430ar5212SetOperatingMode(ah, opmode);431432/* Set Venice BSSID mask according to current state */433OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));434OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));435436/* Restore previous led state */437OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState);438439/* Restore soft Led state to GPIO */440OS_REG_WRITE(ah, AR_GPIOCR, softLedCfg);441OS_REG_WRITE(ah, AR_GPIODO, softLedState);442443/* Restore previous antenna */444OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);445446/* then our BSSID and associate id */447OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));448OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4) |449(ahp->ah_assocId & 0x3fff) << AR_BSS_ID1_AID_S);450451/* Restore bmiss rssi & count thresholds */452OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);453454OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */455456if (!ar5212SetChannel(ah, chan))457FAIL(HAL_EIO);458459OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);460461ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1);462463ar5212SetRateDurationTable(ah, chan);464465/* Set Tx frame start to tx data start delay */466if (IS_RAD5112_ANY(ah) &&467(IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) {468txFrm2TxDStart =469IEEE80211_IS_CHAN_HALF(chan) ?470TX_FRAME_D_START_HALF_RATE:471TX_FRAME_D_START_QUARTER_RATE;472OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL,473AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart);474}475476/*477* Setup fast diversity.478* Fast diversity can be enabled or disabled via regadd.txt.479* Default is enabled.480* For reference,481* Disable: reg val482* 0x00009860 0x00009d18 (if 11a / 11g, else no change)483* 0x00009970 0x192bb514484* 0x0000a208 0xd03e4648485*486* Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change)487* 0x00009970 0x192fb514488* 0x0000a208 0xd03e6788489*/490491/* XXX Setup pre PHY ENABLE EAR additions */492/*493* Wait for the frequency synth to settle (synth goes on494* via AR_PHY_ACTIVE_EN). Read the phy active delay register.495* Value is in 100ns increments.496*/497synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;498if (IEEE80211_IS_CHAN_B(chan)) {499synthDelay = (4 * synthDelay) / 22;500} else {501synthDelay /= 10;502}503504/* Activate the PHY (includes baseband activate and synthesizer on) */505OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);506507/*508* There is an issue if the AP starts the calibration before509* the base band timeout completes. This could result in the510* rx_clear false triggering. As a workaround we add delay an511* extra BASE_ACTIVATE_DELAY usecs to ensure this condition512* does not happen.513*/514if (IEEE80211_IS_CHAN_HALF(chan)) {515OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY);516} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {517OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY);518} else {519OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);520}521522/*523* The udelay method is not reliable with notebooks.524* Need to check to see if the baseband is ready525*/526testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL);527/* Selects the Tx hold */528OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD);529i = 0;530while ((i++ < 20) &&531(OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200);532OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg);533534/* Calibrate the AGC and start a NF calculation */535OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,536OS_REG_READ(ah, AR_PHY_AGC_CONTROL)537| AR_PHY_AGC_CONTROL_CAL538| AR_PHY_AGC_CONTROL_NF);539540if (!IEEE80211_IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) {541/* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */542OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,543AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,544INIT_IQCAL_LOG_COUNT_MAX);545OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,546AR_PHY_TIMING_CTRL4_DO_IQCAL);547ahp->ah_bIQCalibration = IQ_CAL_RUNNING;548} else549ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;550551/* Setup compression registers */552ar5212SetCompRegs(ah);553554/* Set 1:1 QCU to DCU mapping for all queues */555for (i = 0; i < AR_NUM_DCU; i++)556OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);557558ahp->ah_intrTxqs = 0;559for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++)560ar5212ResetTxQueue(ah, i);561562/*563* Setup interrupt handling. Note that ar5212ResetTxQueue564* manipulates the secondary IMR's as queues are enabled565* and disabled. This is done with RMW ops to insure the566* settings we make here are preserved.567*/568ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN569| AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN570| AR_IMR_HIUERR571;572if (opmode == HAL_M_HOSTAP)573ahp->ah_maskReg |= AR_IMR_MIB;574OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);575/* Enable bus errors that are OR'd to set the HIUERR bit */576OS_REG_WRITE(ah, AR_IMR_S2,577OS_REG_READ(ah, AR_IMR_S2)578| AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR);579580if (AH_PRIVATE(ah)->ah_rfkillEnabled)581ar5212EnableRfKill(ah);582583if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {584HALDEBUG(ah, HAL_DEBUG_ANY,585"%s: offset calibration failed to complete in 1ms;"586" noisy environment?\n", __func__);587}588589/*590* Set clocks back to 32kHz if they had been using refClk, then591* use an external 32kHz crystal when sleeping, if one exists.592*/593ar5212SetupClock(ah, opmode);594595/*596* Writing to AR_BEACON will start timers. Hence it should597* be the last register to be written. Do not reset tsf, do598* not enable beacons at this point, but preserve other values599* like beaconInterval.600*/601OS_REG_WRITE(ah, AR_BEACON,602(OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF)));603604/* XXX Setup post reset EAR additions */605606/* QoS support */607if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE ||608(AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE &&609AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) {610OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */611OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */612}613614/* Turn on NOACK Support for QoS packets */615OS_REG_WRITE(ah, AR_NOACK,616SM(2, AR_NOACK_2BIT_VALUE) |617SM(5, AR_NOACK_BIT_OFFSET) |618SM(0, AR_NOACK_BYTE_OFFSET));619620/* Get Antenna Gain reduction */621if (IEEE80211_IS_CHAN_5GHZ(chan)) {622ath_hal_eepromGet(ah, AR_EEP_ANTGAINMAX_5, &twiceAntennaGain);623} else {624ath_hal_eepromGet(ah, AR_EEP_ANTGAINMAX_2, &twiceAntennaGain);625}626twiceAntennaReduction =627ath_hal_getantennareduction(ah, chan, twiceAntennaGain);628629/* TPC for self-generated frames */630631ackTpcPow = MS(ahp->ah_macTPC, AR_TPC_ACK);632if ((ackTpcPow-ahp->ah_txPowerIndexOffset) > chan->ic_maxpower)633ackTpcPow = chan->ic_maxpower+ahp->ah_txPowerIndexOffset;634635if (ackTpcPow > (2*chan->ic_maxregpower - twiceAntennaReduction))636ackTpcPow = (2*chan->ic_maxregpower - twiceAntennaReduction)637+ ahp->ah_txPowerIndexOffset;638639ctsTpcPow = MS(ahp->ah_macTPC, AR_TPC_CTS);640if ((ctsTpcPow-ahp->ah_txPowerIndexOffset) > chan->ic_maxpower)641ctsTpcPow = chan->ic_maxpower+ahp->ah_txPowerIndexOffset;642643if (ctsTpcPow > (2*chan->ic_maxregpower - twiceAntennaReduction))644ctsTpcPow = (2*chan->ic_maxregpower - twiceAntennaReduction)645+ ahp->ah_txPowerIndexOffset;646647chirpTpcPow = MS(ahp->ah_macTPC, AR_TPC_CHIRP);648if ((chirpTpcPow-ahp->ah_txPowerIndexOffset) > chan->ic_maxpower)649chirpTpcPow = chan->ic_maxpower+ahp->ah_txPowerIndexOffset;650651if (chirpTpcPow > (2*chan->ic_maxregpower - twiceAntennaReduction))652chirpTpcPow = (2*chan->ic_maxregpower - twiceAntennaReduction)653+ ahp->ah_txPowerIndexOffset;654655if (ackTpcPow > 63)656ackTpcPow = 63;657if (ctsTpcPow > 63)658ctsTpcPow = 63;659if (chirpTpcPow > 63)660chirpTpcPow = 63;661662powerVal = SM(ackTpcPow, AR_TPC_ACK) |663SM(ctsTpcPow, AR_TPC_CTS) |664SM(chirpTpcPow, AR_TPC_CHIRP);665666OS_REG_WRITE(ah, AR_TPC, powerVal);667668/* Restore user-specified settings */669if (ahp->ah_miscMode != 0)670OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);671if (ahp->ah_sifstime != (u_int) -1)672ar5212SetSifsTime(ah, ahp->ah_sifstime);673if (ahp->ah_slottime != (u_int) -1)674ar5212SetSlotTime(ah, ahp->ah_slottime);675if (ahp->ah_acktimeout != (u_int) -1)676ar5212SetAckTimeout(ah, ahp->ah_acktimeout);677if (ahp->ah_ctstimeout != (u_int) -1)678ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout);679if (AH_PRIVATE(ah)->ah_diagreg != 0)680OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);681682AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */683#if 0684done:685#endif686if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan))687chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;688689HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__);690691RESTORE_CCK(ah, chan, isBmode);692693OS_MARK(ah, AH_MARK_RESET_DONE, 0);694695return AH_TRUE;696bad:697RESTORE_CCK(ah, chan, isBmode);698699OS_MARK(ah, AH_MARK_RESET_DONE, ecode);700if (status != AH_NULL)701*status = ecode;702return AH_FALSE;703#undef FAIL704#undef N705}706707/*708* Call the rf backend to change the channel.709*/710HAL_BOOL711ar5212SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan)712{713struct ath_hal_5212 *ahp = AH5212(ah);714715/* Change the synth */716if (!ahp->ah_rfHal->setChannel(ah, chan))717return AH_FALSE;718return AH_TRUE;719}720721/*722* This channel change evaluates whether the selected hardware can723* perform a synthesizer-only channel change (no reset). If the724* TX is not stopped, or the RFBus cannot be granted in the given725* time, the function returns false as a reset is necessary726*/727HAL_BOOL728ar5212ChannelChange(struct ath_hal *ah, const struct ieee80211_channel *chan)729{730uint32_t ulCount;731uint32_t data, synthDelay, qnum;732uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL];733HAL_BOOL txStopped = AH_TRUE;734HAL_CHANNEL_INTERNAL *ichan;735736/*737* Map public channel to private.738*/739ichan = ath_hal_checkchannel(ah, chan);740741/* TX must be stopped or RF Bus grant will not work */742for (qnum = 0; qnum < AH_PRIVATE(ah)->ah_caps.halTotalQueues; qnum++) {743if (ar5212NumTxPending(ah, qnum)) {744txStopped = AH_FALSE;745break;746}747}748if (!txStopped)749return AH_FALSE;750751/* Kill last Baseband Rx Frame */752OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_REQUEST); /* Request analog bus grant */753for (ulCount = 0; ulCount < 100; ulCount++) {754if (OS_REG_READ(ah, AR_PHY_RFBUS_GNT))755break;756OS_DELAY(5);757}758if (ulCount >= 100)759return AH_FALSE;760761/* Change the synth */762if (!ar5212SetChannel(ah, chan))763return AH_FALSE;764765/*766* Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN).767* Read the phy active delay register. Value is in 100ns increments.768*/769data = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;770if (IEEE80211_IS_CHAN_B(chan)) {771synthDelay = (4 * data) / 22;772} else {773synthDelay = data / 10;774}775OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);776777/* Setup the transmit power values. */778if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) {779HALDEBUG(ah, HAL_DEBUG_ANY,780"%s: error init'ing transmit power\n", __func__);781return AH_FALSE;782}783784/* Write delta slope for OFDM enabled modes (A, G, Turbo) */785if (IEEE80211_IS_CHAN_OFDM(chan)) {786if (IS_5413(ah) ||787AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3)788ar5212SetSpurMitigation(ah, chan);789ar5212SetDeltaSlope(ah, chan);790}791792/* Release the RFBus Grant */793OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);794795/* Start Noise Floor Cal */796OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);797return AH_TRUE;798}799800void801ar5212SetOperatingMode(struct ath_hal *ah, int opmode)802{803uint32_t val;804805val = OS_REG_READ(ah, AR_STA_ID1);806val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);807switch (opmode) {808case HAL_M_HOSTAP:809OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP810| AR_STA_ID1_KSRCH_MODE);811OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);812break;813case HAL_M_IBSS:814OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC815| AR_STA_ID1_KSRCH_MODE);816OS_REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);817break;818case HAL_M_STA:819case HAL_M_MONITOR:820OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);821break;822}823}824825/*826* Places the PHY and Radio chips into reset. A full reset827* must be called to leave this state. The PCI/MAC/PCU are828* not placed into reset as we must receive interrupt to829* re-enable the hardware.830*/831HAL_BOOL832ar5212PhyDisable(struct ath_hal *ah)833{834return ar5212SetResetReg(ah, AR_RC_BB);835}836837/*838* Places all of hardware into reset839*/840HAL_BOOL841ar5212Disable(struct ath_hal *ah)842{843if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))844return AH_FALSE;845/*846* Reset the HW - PCI must be reset after the rest of the847* device has been reset.848*/849return ar5212SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI);850}851852/*853* Places the hardware into reset and then pulls it out of reset854*855* TODO: Only write the PLL if we're changing to or from CCK mode856*857* WARNING: The order of the PLL and mode registers must be correct.858*/859HAL_BOOL860ar5212ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan)861{862863OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);864865/*866* Reset the HW - PCI must be reset after the rest of the867* device has been reset868*/869if (!ar5212SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI))870return AH_FALSE;871872/* Bring out of sleep mode (AGAIN) */873if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))874return AH_FALSE;875876/* Clear warm reset register */877if (!ar5212SetResetReg(ah, 0))878return AH_FALSE;879880/*881* Perform warm reset before the mode/PLL/turbo registers882* are changed in order to deactivate the radio. Mode changes883* with an active radio can result in corrupted shifts to the884* radio device.885*/886887/*888* Set CCK and Turbo modes correctly.889*/890if (chan != AH_NULL) { /* NB: can be null during attach */891uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo;892893if (IS_5413(ah)) { /* NB: =>'s 5424 also */894rfMode = AR_PHY_MODE_AR5112;895if (IEEE80211_IS_CHAN_HALF(chan))896rfMode |= AR_PHY_MODE_HALF;897else if (IEEE80211_IS_CHAN_QUARTER(chan))898rfMode |= AR_PHY_MODE_QUARTER;899900if (IEEE80211_IS_CHAN_CCK(chan))901phyPLL = AR_PHY_PLL_CTL_44_5112;902else903phyPLL = AR_PHY_PLL_CTL_40_5413;904} else if (IS_RAD5111(ah)) {905rfMode = AR_PHY_MODE_AR5111;906if (IEEE80211_IS_CHAN_CCK(chan))907phyPLL = AR_PHY_PLL_CTL_44;908else909phyPLL = AR_PHY_PLL_CTL_40;910if (IEEE80211_IS_CHAN_HALF(chan))911phyPLL = AR_PHY_PLL_CTL_HALF;912else if (IEEE80211_IS_CHAN_QUARTER(chan))913phyPLL = AR_PHY_PLL_CTL_QUARTER;914} else { /* 5112, 2413, 2316, 2317 */915rfMode = AR_PHY_MODE_AR5112;916if (IEEE80211_IS_CHAN_CCK(chan))917phyPLL = AR_PHY_PLL_CTL_44_5112;918else919phyPLL = AR_PHY_PLL_CTL_40_5112;920if (IEEE80211_IS_CHAN_HALF(chan))921phyPLL |= AR_PHY_PLL_CTL_HALF;922else if (IEEE80211_IS_CHAN_QUARTER(chan))923phyPLL |= AR_PHY_PLL_CTL_QUARTER;924}925if (IEEE80211_IS_CHAN_G(chan))926rfMode |= AR_PHY_MODE_DYNAMIC;927else if (IEEE80211_IS_CHAN_OFDM(chan))928rfMode |= AR_PHY_MODE_OFDM;929else930rfMode |= AR_PHY_MODE_CCK;931if (IEEE80211_IS_CHAN_5GHZ(chan))932rfMode |= AR_PHY_MODE_RF5GHZ;933else934rfMode |= AR_PHY_MODE_RF2GHZ;935turbo = IEEE80211_IS_CHAN_TURBO(chan) ?936(AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0;937curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL);938/*939* PLL, Mode, and Turbo values must be written in the correct940* order to ensure:941* - The PLL cannot be set to 44 unless the CCK or DYNAMIC942* mode bit is set943* - Turbo cannot be set at the same time as CCK or DYNAMIC944*/945if (IEEE80211_IS_CHAN_CCK(chan)) {946OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);947OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);948if (curPhyPLL != phyPLL) {949OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL);950/* Wait for the PLL to settle */951OS_DELAY(PLL_SETTLE_DELAY);952}953} else {954if (curPhyPLL != phyPLL) {955OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL);956/* Wait for the PLL to settle */957OS_DELAY(PLL_SETTLE_DELAY);958}959OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);960OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);961}962}963return AH_TRUE;964}965966/*967* Recalibrate the lower PHY chips to account for temperature/environment968* changes.969*/970HAL_BOOL971ar5212PerCalibrationN(struct ath_hal *ah,972struct ieee80211_channel *chan,973u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone)974{975#define IQ_CAL_TRIES 10976struct ath_hal_5212 *ahp = AH5212(ah);977HAL_CHANNEL_INTERNAL *ichan;978int32_t qCoff, qCoffDenom;979int32_t iqCorrMeas, iCoff, iCoffDenom;980uint32_t powerMeasQ, powerMeasI;981HAL_BOOL isBmode = AH_FALSE;982983OS_MARK(ah, AH_MARK_PERCAL, chan->ic_freq);984*isCalDone = AH_FALSE;985ichan = ath_hal_checkchannel(ah, chan);986if (ichan == AH_NULL) {987HALDEBUG(ah, HAL_DEBUG_ANY,988"%s: invalid channel %u/0x%x; no mapping\n",989__func__, chan->ic_freq, chan->ic_flags);990return AH_FALSE;991}992SAVE_CCK(ah, chan, isBmode);993994if (ahp->ah_bIQCalibration == IQ_CAL_DONE ||995ahp->ah_bIQCalibration == IQ_CAL_INACTIVE)996*isCalDone = AH_TRUE;997998/* IQ calibration in progress. Check to see if it has finished. */999if (ahp->ah_bIQCalibration == IQ_CAL_RUNNING &&1000!(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_IQCAL)) {1001int i;10021003/* IQ Calibration has finished. */1004ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;1005*isCalDone = AH_TRUE;10061007/* workaround for misgated IQ Cal results */1008i = 0;1009do {1010/* Read calibration results. */1011powerMeasI = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_I);1012powerMeasQ = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_Q);1013iqCorrMeas = OS_REG_READ(ah, AR_PHY_IQCAL_RES_IQ_CORR_MEAS);1014if (powerMeasI && powerMeasQ)1015break;1016/* Do we really need this??? */1017OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,1018AR_PHY_TIMING_CTRL4_DO_IQCAL);1019} while (++i < IQ_CAL_TRIES);10201021HALDEBUG(ah, HAL_DEBUG_PERCAL,1022"%s: IQ cal finished: %d tries\n", __func__, i);1023HALDEBUG(ah, HAL_DEBUG_PERCAL,1024"%s: powerMeasI %u powerMeasQ %u iqCorrMeas %d\n",1025__func__, powerMeasI, powerMeasQ, iqCorrMeas);10261027/*1028* Prescale these values to remove 64-bit operation1029* requirement at the loss of a little precision.1030*/1031iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;1032qCoffDenom = powerMeasQ / 128;10331034/* Protect against divide-by-0 and loss of sign bits. */1035if (iCoffDenom != 0 && qCoffDenom >= 2) {1036iCoff = (int8_t)(-iqCorrMeas) / iCoffDenom;1037/* IQCORR_Q_I_COFF is a signed 6 bit number */1038if (iCoff < -32) {1039iCoff = -32;1040} else if (iCoff > 31) {1041iCoff = 31;1042}10431044/* IQCORR_Q_Q_COFF is a signed 5 bit number */1045qCoff = (powerMeasI / qCoffDenom) - 128;1046if (qCoff < -16) {1047qCoff = -16;1048} else if (qCoff > 15) {1049qCoff = 15;1050}10511052HALDEBUG(ah, HAL_DEBUG_PERCAL,1053"%s: iCoff %d qCoff %d\n", __func__, iCoff, qCoff);10541055/* Write values and enable correction */1056OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,1057AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, iCoff);1058OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,1059AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff);1060OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,1061AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);10621063ahp->ah_bIQCalibration = IQ_CAL_DONE;1064ichan->privFlags |= CHANNEL_IQVALID;1065ichan->iCoff = iCoff;1066ichan->qCoff = qCoff;1067}1068} else if (!IEEE80211_IS_CHAN_B(chan) &&1069ahp->ah_bIQCalibration == IQ_CAL_DONE &&1070(ichan->privFlags & CHANNEL_IQVALID) == 0) {1071/*1072* Start IQ calibration if configured channel has changed.1073* Use a magic number of 15 based on default value.1074*/1075OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,1076AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,1077INIT_IQCAL_LOG_COUNT_MAX);1078OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,1079AR_PHY_TIMING_CTRL4_DO_IQCAL);1080ahp->ah_bIQCalibration = IQ_CAL_RUNNING;1081}1082/* XXX EAR */10831084if (longCal) {1085/* Check noise floor results */1086ar5212GetNf(ah, chan);1087if (!IEEE80211_IS_CHAN_CWINT(chan)) {1088/* Perform cal for 5Ghz channels and any OFDM on 5112 */1089if (IEEE80211_IS_CHAN_5GHZ(chan) ||1090(IS_RAD5112(ah) && IEEE80211_IS_CHAN_OFDM(chan)))1091ar5212RequestRfgain(ah);1092}1093}1094RESTORE_CCK(ah, chan, isBmode);10951096return AH_TRUE;1097#undef IQ_CAL_TRIES1098}10991100HAL_BOOL1101ar5212PerCalibration(struct ath_hal *ah, struct ieee80211_channel *chan,1102HAL_BOOL *isIQdone)1103{1104return ar5212PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone);1105}11061107HAL_BOOL1108ar5212ResetCalValid(struct ath_hal *ah, const struct ieee80211_channel *chan)1109{1110HAL_CHANNEL_INTERNAL *ichan;11111112ichan = ath_hal_checkchannel(ah, chan);1113if (ichan == AH_NULL) {1114HALDEBUG(ah, HAL_DEBUG_ANY,1115"%s: invalid channel %u/0x%x; no mapping\n",1116__func__, chan->ic_freq, chan->ic_flags);1117return AH_FALSE;1118}1119ichan->privFlags &= ~CHANNEL_IQVALID;1120return AH_TRUE;1121}11221123/**************************************************************1124* ar5212MacStop1125*1126* Disables all active QCUs and ensure that the mac is in a1127* quiessence state.1128*/1129static HAL_BOOL1130ar5212MacStop(struct ath_hal *ah)1131{1132HAL_BOOL status;1133uint32_t count;1134uint32_t pendFrameCount;1135uint32_t macStateFlag;1136uint32_t queue;11371138status = AH_FALSE;11391140/* Disable Rx Operation ***********************************/1141OS_REG_SET_BIT(ah, AR_CR, AR_CR_RXD);11421143/* Disable TX Operation ***********************************/1144#ifdef NOT_YET1145ar5212SetTxdpInvalid(ah);1146#endif1147OS_REG_SET_BIT(ah, AR_Q_TXD, AR_Q_TXD_M);11481149/* Polling operation for completion of disable ************/1150macStateFlag = TX_ENABLE_CHECK | RX_ENABLE_CHECK;11511152for (count = 0; count < MAX_RESET_WAIT; count++) {1153if (macStateFlag & RX_ENABLE_CHECK) {1154if (!OS_REG_IS_BIT_SET(ah, AR_CR, AR_CR_RXE)) {1155macStateFlag &= ~RX_ENABLE_CHECK;1156}1157}11581159if (macStateFlag & TX_ENABLE_CHECK) {1160if (!OS_REG_IS_BIT_SET(ah, AR_Q_TXE, AR_Q_TXE_M)) {1161macStateFlag &= ~TX_ENABLE_CHECK;1162macStateFlag |= TX_QUEUEPEND_CHECK;1163}1164}1165if (macStateFlag & TX_QUEUEPEND_CHECK) {1166pendFrameCount = 0;1167for (queue = 0; queue < AR_NUM_DCU; queue++) {1168pendFrameCount += OS_REG_READ(ah,1169AR_Q0_STS + (queue * 4)) &1170AR_Q_STS_PEND_FR_CNT;1171}1172if (pendFrameCount == 0) {1173macStateFlag &= ~TX_QUEUEPEND_CHECK;1174}1175}1176if (macStateFlag == 0) {1177status = AH_TRUE;1178break;1179}1180OS_DELAY(50);1181}11821183if (status != AH_TRUE) {1184HALDEBUG(ah, HAL_DEBUG_RESET,1185"%s:Failed to stop the MAC state 0x%x\n",1186__func__, macStateFlag);1187}11881189return status;1190}11911192/*1193* Write the given reset bit mask into the reset register1194*/1195static HAL_BOOL1196ar5212SetResetReg(struct ath_hal *ah, uint32_t resetMask)1197{1198uint32_t mask = resetMask ? resetMask : ~0;1199HAL_BOOL rt;12001201/* Never reset the PCIE core */1202if (AH_PRIVATE(ah)->ah_ispcie) {1203resetMask &= ~AR_RC_PCI;1204}12051206if (resetMask & (AR_RC_MAC | AR_RC_PCI)) {1207/*1208* To ensure that the driver can reset the1209* MAC, wake up the chip1210*/1211rt = ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE);12121213if (rt != AH_TRUE) {1214return rt;1215}12161217/*1218* Disable interrupts1219*/1220OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE);1221OS_REG_READ(ah, AR_IER);12221223if (ar5212MacStop(ah) != AH_TRUE) {1224/*1225* Failed to stop the MAC gracefully; let's be more forceful then1226*/12271228/* need some delay before flush any pending MMR writes */1229OS_DELAY(15);1230OS_REG_READ(ah, AR_RXDP);12311232resetMask |= AR_RC_MAC | AR_RC_BB;1233/* _Never_ reset PCI Express core */1234if (! AH_PRIVATE(ah)->ah_ispcie) {1235resetMask |= AR_RC_PCI;1236}1237#if 01238/*1239* Flush the park address of the PCI controller1240*/1241/* Read PCI slot information less than Hainan revision */1242if (AH_PRIVATE(ah)->ah_bustype == HAL_BUS_TYPE_PCI) {1243if (!IS_5112_REV5_UP(ah)) {1244#define PCI_COMMON_CONFIG_STATUS 0x061245u_int32_t i;1246u_int16_t reg16;12471248for (i = 0; i < 32; i++) {1249ath_hal_read_pci_config_space(ah,1250PCI_COMMON_CONFIG_STATUS,1251®16, sizeof(reg16));1252}1253}1254#undef PCI_COMMON_CONFIG_STATUS1255}1256#endif1257} else {1258/*1259* MAC stopped gracefully; no need to warm-reset the PCI bus1260*/12611262resetMask &= ~AR_RC_PCI;12631264/* need some delay before flush any pending MMR writes */1265OS_DELAY(15);1266OS_REG_READ(ah, AR_RXDP);1267}1268}12691270(void) OS_REG_READ(ah, AR_RXDP);/* flush any pending MMR writes */1271OS_REG_WRITE(ah, AR_RC, resetMask);1272OS_DELAY(15); /* need to wait at least 128 clocks1273when reseting PCI before read */1274mask &= (AR_RC_MAC | AR_RC_BB);1275resetMask &= (AR_RC_MAC | AR_RC_BB);1276rt = ath_hal_wait(ah, AR_RC, mask, resetMask);1277if ((resetMask & AR_RC_MAC) == 0) {1278if (isBigEndian()) {1279/*1280* Set CFG, little-endian for descriptor accesses.1281*/1282mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;1283#ifndef AH_NEED_DESC_SWAP1284mask |= AR_CFG_SWTD;1285#endif1286OS_REG_WRITE(ah, AR_CFG, mask);1287} else1288OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);1289if (ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))1290(void) OS_REG_READ(ah, AR_ISR_RAC);1291}12921293/* track PHY power state so we don't try to r/w BB registers */1294AH5212(ah)->ah_phyPowerOn = ((resetMask & AR_RC_BB) == 0);1295return rt;1296}12971298int16_t1299ar5212GetNoiseFloor(struct ath_hal *ah)1300{1301int16_t nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff;1302if (nf & 0x100)1303nf = 0 - ((nf ^ 0x1ff) + 1);1304return nf;1305}13061307static HAL_BOOL1308getNoiseFloorThresh(struct ath_hal *ah, const struct ieee80211_channel *chan,1309int16_t *nft)1310{1311const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;13121313HALASSERT(ah->ah_magic == AR5212_MAGIC);13141315switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {1316case IEEE80211_CHAN_A:1317*nft = ee->ee_noiseFloorThresh[headerInfo11A];1318break;1319case IEEE80211_CHAN_B:1320*nft = ee->ee_noiseFloorThresh[headerInfo11B];1321break;1322case IEEE80211_CHAN_G:1323case IEEE80211_CHAN_PUREG: /* NB: really 108G */1324*nft = ee->ee_noiseFloorThresh[headerInfo11G];1325break;1326default:1327HALDEBUG(ah, HAL_DEBUG_ANY,1328"%s: invalid channel flags %u/0x%x\n",1329__func__, chan->ic_freq, chan->ic_flags);1330return AH_FALSE;1331}1332return AH_TRUE;1333}13341335/*1336* Setup the noise floor cal history buffer.1337*/1338void1339ar5212InitNfCalHistBuffer(struct ath_hal *ah)1340{1341struct ath_hal_5212 *ahp = AH5212(ah);1342int i;13431344ahp->ah_nfCalHist.first_run = 1;1345ahp->ah_nfCalHist.currIndex = 0;1346ahp->ah_nfCalHist.privNF = AR5212_CCA_MAX_GOOD_VALUE;1347ahp->ah_nfCalHist.invalidNFcount = AR512_NF_CAL_HIST_MAX;1348for (i = 0; i < AR512_NF_CAL_HIST_MAX; i ++)1349ahp->ah_nfCalHist.nfCalBuffer[i] = AR5212_CCA_MAX_GOOD_VALUE;1350}13511352/*1353* Add a noise floor value to the ring buffer.1354*/1355static __inline void1356updateNFHistBuff(struct ar5212NfCalHist *h, int16_t nf)1357{1358h->nfCalBuffer[h->currIndex] = nf;1359if (++h->currIndex >= AR512_NF_CAL_HIST_MAX)1360h->currIndex = 0;1361}13621363/*1364* Return the median noise floor value in the ring buffer.1365*/1366int16_t1367ar5212GetNfHistMid(const int16_t calData[AR512_NF_CAL_HIST_MAX])1368{1369int16_t sort[AR512_NF_CAL_HIST_MAX];1370int i, j;13711372OS_MEMCPY(sort, calData, AR512_NF_CAL_HIST_MAX*sizeof(int16_t));1373for (i = 0; i < AR512_NF_CAL_HIST_MAX-1; i ++) {1374for (j = 1; j < AR512_NF_CAL_HIST_MAX-i; j ++) {1375if (sort[j] > sort[j-1]) {1376int16_t nf = sort[j];1377sort[j] = sort[j-1];1378sort[j-1] = nf;1379}1380}1381}1382return sort[(AR512_NF_CAL_HIST_MAX-1)>>1];1383}13841385/*1386* Read the NF and check it against the noise floor threshold1387*/1388int16_t1389ar5212GetNf(struct ath_hal *ah, struct ieee80211_channel *chan)1390{1391struct ath_hal_5212 *ahp = AH5212(ah);1392struct ar5212NfCalHist *h = &ahp->ah_nfCalHist;1393HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);1394int16_t nf, nfThresh;1395int32_t val;13961397if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {1398HALDEBUG(ah, HAL_DEBUG_ANY,1399"%s: NF did not complete in calibration window\n", __func__);1400ichan->rawNoiseFloor = h->privNF; /* most recent value */1401return ichan->rawNoiseFloor;1402}14031404/*1405* Finished NF cal, check against threshold.1406*/1407nf = ar5212GetNoiseFloor(ah);1408if (getNoiseFloorThresh(ah, chan, &nfThresh)) {1409if (nf > nfThresh) {1410HALDEBUG(ah, HAL_DEBUG_ANY,1411"%s: noise floor failed detected; detected %u, "1412"threshold %u\n", __func__, nf, nfThresh);1413/*1414* NB: Don't discriminate 2.4 vs 5Ghz, if this1415* happens it indicates a problem regardless1416* of the band.1417*/1418chan->ic_state |= IEEE80211_CHANSTATE_CWINT;1419nf = 0;1420}1421} else1422nf = 0;14231424/*1425* Pass through histogram and write median value as1426* calculated from the accrued window. We require a1427* full window of in-range values to be seen before we1428* start using the history.1429*/1430updateNFHistBuff(h, nf);1431if (h->first_run) {1432if (nf < AR5212_CCA_MIN_BAD_VALUE ||1433nf > AR5212_CCA_MAX_HIGH_VALUE) {1434nf = AR5212_CCA_MAX_GOOD_VALUE;1435h->invalidNFcount = AR512_NF_CAL_HIST_MAX;1436} else if (--(h->invalidNFcount) == 0) {1437h->first_run = 0;1438h->privNF = nf = ar5212GetNfHistMid(h->nfCalBuffer);1439} else {1440nf = AR5212_CCA_MAX_GOOD_VALUE;1441}1442} else {1443h->privNF = nf = ar5212GetNfHistMid(h->nfCalBuffer);1444}14451446val = OS_REG_READ(ah, AR_PHY(25));1447val &= 0xFFFFFE00;1448val |= (((uint32_t)nf << 1) & 0x1FF);1449OS_REG_WRITE(ah, AR_PHY(25), val);1450OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);1451OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);1452OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);14531454if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF, 0)) {1455#ifdef AH_DEBUG1456ath_hal_printf(ah, "%s: AGC not ready AGC_CONTROL 0x%x\n",1457__func__, OS_REG_READ(ah, AR_PHY_AGC_CONTROL));1458#endif1459}14601461/*1462* Now load a high maxCCAPower value again so that we're1463* not capped by the median we just loaded1464*/1465val &= 0xFFFFFE00;1466val |= (((uint32_t)(-50) << 1) & 0x1FF);1467OS_REG_WRITE(ah, AR_PHY(25), val);1468OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);1469OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);1470OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);14711472return (ichan->rawNoiseFloor = nf);1473}14741475/*1476* Set up compression configuration registers1477*/1478void1479ar5212SetCompRegs(struct ath_hal *ah)1480{1481struct ath_hal_5212 *ahp = AH5212(ah);1482int i;14831484/* Check if h/w supports compression */1485if (!AH_PRIVATE(ah)->ah_caps.halCompressSupport)1486return;14871488OS_REG_WRITE(ah, AR_DCCFG, 1);14891490OS_REG_WRITE(ah, AR_CCFG,1491(AR_COMPRESSION_WINDOW_SIZE >> 8) & AR_CCFG_WIN_M);14921493OS_REG_WRITE(ah, AR_CCFG,1494OS_REG_READ(ah, AR_CCFG) | AR_CCFG_MIB_INT_EN);1495OS_REG_WRITE(ah, AR_CCUCFG,1496AR_CCUCFG_RESET_VAL | AR_CCUCFG_CATCHUP_EN);14971498OS_REG_WRITE(ah, AR_CPCOVF, 0);14991500/* reset decompression mask */1501for (i = 0; i < HAL_DECOMP_MASK_SIZE; i++) {1502OS_REG_WRITE(ah, AR_DCM_A, i);1503OS_REG_WRITE(ah, AR_DCM_D, ahp->ah_decompMask[i]);1504}1505}15061507HAL_BOOL1508ar5212SetAntennaSwitchInternal(struct ath_hal *ah, HAL_ANT_SETTING settings,1509const struct ieee80211_channel *chan)1510{1511#define ANT_SWITCH_TABLE1 AR_PHY(88)1512#define ANT_SWITCH_TABLE2 AR_PHY(89)1513struct ath_hal_5212 *ahp = AH5212(ah);1514const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1515uint32_t antSwitchA, antSwitchB;1516int ix;15171518HALASSERT(ah->ah_magic == AR5212_MAGIC);1519HALASSERT(ahp->ah_phyPowerOn);15201521switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {1522case IEEE80211_CHAN_A:1523ix = 0;1524break;1525case IEEE80211_CHAN_G:1526case IEEE80211_CHAN_PUREG: /* NB: 108G */1527ix = 2;1528break;1529case IEEE80211_CHAN_B:1530if (IS_2425(ah) || IS_2417(ah)) {1531/* NB: Nala/Swan: 11b is handled using 11g */1532ix = 2;1533} else1534ix = 1;1535break;1536default:1537HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",1538__func__, chan->ic_flags);1539return AH_FALSE;1540}15411542antSwitchA = ee->ee_antennaControl[1][ix]1543| (ee->ee_antennaControl[2][ix] << 6)1544| (ee->ee_antennaControl[3][ix] << 12)1545| (ee->ee_antennaControl[4][ix] << 18)1546| (ee->ee_antennaControl[5][ix] << 24)1547;1548antSwitchB = ee->ee_antennaControl[6][ix]1549| (ee->ee_antennaControl[7][ix] << 6)1550| (ee->ee_antennaControl[8][ix] << 12)1551| (ee->ee_antennaControl[9][ix] << 18)1552| (ee->ee_antennaControl[10][ix] << 24)1553;1554/*1555* For fixed antenna, give the same setting for both switch banks1556*/1557switch (settings) {1558case HAL_ANT_FIXED_A:1559antSwitchB = antSwitchA;1560break;1561case HAL_ANT_FIXED_B:1562antSwitchA = antSwitchB;1563break;1564case HAL_ANT_VARIABLE:1565break;1566default:1567HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad antenna setting %u\n",1568__func__, settings);1569return AH_FALSE;1570}1571if (antSwitchB == antSwitchA) {1572HALDEBUG(ah, HAL_DEBUG_RFPARAM,1573"%s: Setting fast diversity off.\n", __func__);1574OS_REG_CLR_BIT(ah,AR_PHY_CCK_DETECT,1575AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);1576ahp->ah_diversity = AH_FALSE;1577} else {1578HALDEBUG(ah, HAL_DEBUG_RFPARAM,1579"%s: Setting fast diversity on.\n", __func__);1580OS_REG_SET_BIT(ah,AR_PHY_CCK_DETECT,1581AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);1582ahp->ah_diversity = AH_TRUE;1583}1584ahp->ah_antControl = settings;15851586OS_REG_WRITE(ah, ANT_SWITCH_TABLE1, antSwitchA);1587OS_REG_WRITE(ah, ANT_SWITCH_TABLE2, antSwitchB);15881589return AH_TRUE;1590#undef ANT_SWITCH_TABLE21591#undef ANT_SWITCH_TABLE11592}15931594HAL_BOOL1595ar5212IsSpurChannel(struct ath_hal *ah, const struct ieee80211_channel *chan)1596{1597uint16_t freq = ath_hal_gethwchannel(ah, chan);1598uint32_t clockFreq =1599((IS_5413(ah) || IS_RAD5112_ANY(ah) || IS_2417(ah)) ? 40 : 32);1600return ( ((freq % clockFreq) != 0)1601&& (((freq % clockFreq) < 10)1602|| (((freq) % clockFreq) > 22)) );1603}16041605/*1606* Read EEPROM header info and program the device for correct operation1607* given the channel value.1608*/1609HAL_BOOL1610ar5212SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan)1611{1612#define NO_FALSE_DETECT_BACKOFF 21613#define CB22_FALSE_DETECT_BACKOFF 61614#define AR_PHY_BIS(_ah, _reg, _mask, _val) \1615OS_REG_WRITE(_ah, AR_PHY(_reg), \1616(OS_REG_READ(_ah, AR_PHY(_reg)) & _mask) | (_val));1617struct ath_hal_5212 *ahp = AH5212(ah);1618const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;1619int arrayMode, falseDectectBackoff;1620int is2GHz = IEEE80211_IS_CHAN_2GHZ(chan);1621HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);1622int8_t adcDesiredSize, pgaDesiredSize;1623uint16_t switchSettling, txrxAtten, rxtxMargin;1624int iCoff, qCoff;16251626HALASSERT(ah->ah_magic == AR5212_MAGIC);16271628switch (chan->ic_flags & IEEE80211_CHAN_ALLTURBOFULL) {1629case IEEE80211_CHAN_A:1630case IEEE80211_CHAN_ST:1631arrayMode = headerInfo11A;1632if (!IS_RAD5112_ANY(ah) && !IS_2413(ah) && !IS_5413(ah))1633OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,1634AR_PHY_FRAME_CTL_TX_CLIP,1635ahp->ah_gainValues.currStep->paramVal[GP_TXCLIP]);1636break;1637case IEEE80211_CHAN_B:1638arrayMode = headerInfo11B;1639break;1640case IEEE80211_CHAN_G:1641case IEEE80211_CHAN_108G:1642arrayMode = headerInfo11G;1643break;1644default:1645HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",1646__func__, chan->ic_flags);1647return AH_FALSE;1648}16491650/* Set the antenna register(s) correctly for the chip revision */1651AR_PHY_BIS(ah, 68, 0xFFFFFC06,1652(ee->ee_antennaControl[0][arrayMode] << 4) | 0x1);16531654ar5212SetAntennaSwitchInternal(ah, ahp->ah_antControl, chan);16551656/* Set the Noise Floor Thresh on ar5211 devices */1657OS_REG_WRITE(ah, AR_PHY(90),1658(ee->ee_noiseFloorThresh[arrayMode] & 0x1FF)1659| (1 << 9));16601661if (ee->ee_version >= AR_EEPROM_VER5_0 && IEEE80211_IS_CHAN_TURBO(chan)) {1662switchSettling = ee->ee_switchSettlingTurbo[is2GHz];1663adcDesiredSize = ee->ee_adcDesiredSizeTurbo[is2GHz];1664pgaDesiredSize = ee->ee_pgaDesiredSizeTurbo[is2GHz];1665txrxAtten = ee->ee_txrxAttenTurbo[is2GHz];1666rxtxMargin = ee->ee_rxtxMarginTurbo[is2GHz];1667} else {1668switchSettling = ee->ee_switchSettling[arrayMode];1669adcDesiredSize = ee->ee_adcDesiredSize[arrayMode];1670pgaDesiredSize = ee->ee_pgaDesiredSize[is2GHz];1671txrxAtten = ee->ee_txrxAtten[is2GHz];1672rxtxMargin = ee->ee_rxtxMargin[is2GHz];1673}16741675OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING,1676AR_PHY_SETTLING_SWITCH, switchSettling);1677OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,1678AR_PHY_DESIRED_SZ_ADC, adcDesiredSize);1679OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,1680AR_PHY_DESIRED_SZ_PGA, pgaDesiredSize);1681OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN,1682AR_PHY_RXGAIN_TXRX_ATTEN, txrxAtten);1683OS_REG_WRITE(ah, AR_PHY(13),1684(ee->ee_txEndToXPAOff[arrayMode] << 24)1685| (ee->ee_txEndToXPAOff[arrayMode] << 16)1686| (ee->ee_txFrameToXPAOn[arrayMode] << 8)1687| ee->ee_txFrameToXPAOn[arrayMode]);1688AR_PHY_BIS(ah, 10, 0xFFFF00FF,1689ee->ee_txEndToXLNAOn[arrayMode] << 8);1690AR_PHY_BIS(ah, 25, 0xFFF80FFF,1691(ee->ee_thresh62[arrayMode] << 12) & 0x7F000);16921693/*1694* False detect backoff - suspected 32 MHz spur causes false1695* detects in OFDM, causing Tx Hangs. Decrease weak signal1696* sensitivity for this card.1697*/1698falseDectectBackoff = NO_FALSE_DETECT_BACKOFF;1699if (ee->ee_version < AR_EEPROM_VER3_3) {1700/* XXX magic number */1701if (AH_PRIVATE(ah)->ah_subvendorid == 0x1022 &&1702IEEE80211_IS_CHAN_OFDM(chan))1703falseDectectBackoff += CB22_FALSE_DETECT_BACKOFF;1704} else {1705if (ar5212IsSpurChannel(ah, chan))1706falseDectectBackoff += ee->ee_falseDetectBackoff[arrayMode];1707}1708AR_PHY_BIS(ah, 73, 0xFFFFFF01, (falseDectectBackoff << 1) & 0xFE);17091710if (ichan->privFlags & CHANNEL_IQVALID) {1711iCoff = ichan->iCoff;1712qCoff = ichan->qCoff;1713} else {1714iCoff = ee->ee_iqCalI[is2GHz];1715qCoff = ee->ee_iqCalQ[is2GHz];1716}17171718/* write previous IQ results */1719OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,1720AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, iCoff);1721OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,1722AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff);1723OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,1724AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);17251726if (ee->ee_version >= AR_EEPROM_VER4_1) {1727if (!IEEE80211_IS_CHAN_108G(chan) || ee->ee_version >= AR_EEPROM_VER5_0)1728OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,1729AR_PHY_GAIN_2GHZ_RXTX_MARGIN, rxtxMargin);1730}1731if (ee->ee_version >= AR_EEPROM_VER5_1) {1732/* for now always disabled */1733OS_REG_WRITE(ah, AR_PHY_HEAVY_CLIP_ENABLE, 0);1734}17351736return AH_TRUE;1737#undef AR_PHY_BIS1738#undef NO_FALSE_DETECT_BACKOFF1739#undef CB22_FALSE_DETECT_BACKOFF1740}17411742/*1743* Apply Spur Immunity to Boards that require it.1744* Applies only to OFDM RX operation.1745*/17461747void1748ar5212SetSpurMitigation(struct ath_hal *ah,1749const struct ieee80211_channel *chan)1750{1751uint32_t pilotMask[2] = {0, 0}, binMagMask[4] = {0, 0, 0 , 0};1752uint16_t i, finalSpur, curChanAsSpur, binWidth = 0, spurDetectWidth, spurChan;1753int32_t spurDeltaPhase = 0, spurFreqSd = 0, spurOffset, binOffsetNumT16, curBinOffset;1754int16_t numBinOffsets;1755static const uint16_t magMapFor4[4] = {1, 2, 2, 1};1756static const uint16_t magMapFor3[3] = {1, 2, 1};1757const uint16_t *pMagMap;1758HAL_BOOL is2GHz = IEEE80211_IS_CHAN_2GHZ(chan);1759HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);1760uint32_t val;17611762#define CHAN_TO_SPUR(_f, _freq) ( ((_freq) - ((_f) ? 2300 : 4900)) * 10 )1763if (IS_2417(ah)) {1764HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: no spur mitigation\n",1765__func__);1766return;1767}17681769curChanAsSpur = CHAN_TO_SPUR(is2GHz, ichan->channel);17701771if (ichan->mainSpur) {1772/* Pull out the saved spur value */1773finalSpur = ichan->mainSpur;1774} else {1775/*1776* Check if spur immunity should be performed for this channel1777* Should only be performed once per channel and then saved1778*/1779finalSpur = AR_NO_SPUR;1780spurDetectWidth = HAL_SPUR_CHAN_WIDTH;1781if (IEEE80211_IS_CHAN_TURBO(chan))1782spurDetectWidth *= 2;17831784/* Decide if any spur affects the current channel */1785for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {1786spurChan = ath_hal_getSpurChan(ah, i, is2GHz);1787if (spurChan == AR_NO_SPUR) {1788break;1789}1790if ((curChanAsSpur - spurDetectWidth <= (spurChan & HAL_SPUR_VAL_MASK)) &&1791(curChanAsSpur + spurDetectWidth >= (spurChan & HAL_SPUR_VAL_MASK))) {1792finalSpur = spurChan & HAL_SPUR_VAL_MASK;1793break;1794}1795}1796/* Save detected spur (or no spur) for this channel */1797ichan->mainSpur = finalSpur;1798}17991800/* Write spur immunity data */1801if (finalSpur == AR_NO_SPUR) {1802/* Disable Spur Immunity Regs if they appear set */1803if (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER) {1804/* Clear Spur Delta Phase, Spur Freq, and enable bits */1805OS_REG_RMW_FIELD(ah, AR_PHY_MASK_CTL, AR_PHY_MASK_CTL_RATE, 0);1806val = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4);1807val &= ~(AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |1808AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |1809AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);1810OS_REG_WRITE(ah, AR_PHY_MASK_CTL, val);1811OS_REG_WRITE(ah, AR_PHY_TIMING11, 0);18121813/* Clear pilot masks */1814OS_REG_WRITE(ah, AR_PHY_TIMING7, 0);1815OS_REG_RMW_FIELD(ah, AR_PHY_TIMING8, AR_PHY_TIMING8_PILOT_MASK_2, 0);1816OS_REG_WRITE(ah, AR_PHY_TIMING9, 0);1817OS_REG_RMW_FIELD(ah, AR_PHY_TIMING10, AR_PHY_TIMING10_PILOT_MASK_2, 0);18181819/* Clear magnitude masks */1820OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, 0);1821OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, 0);1822OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, 0);1823OS_REG_RMW_FIELD(ah, AR_PHY_MASK_CTL, AR_PHY_MASK_CTL_MASK_4, 0);1824OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, 0);1825OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, 0);1826OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, 0);1827OS_REG_RMW_FIELD(ah, AR_PHY_BIN_MASK2_4, AR_PHY_BIN_MASK2_4_MASK_4, 0);1828}1829} else {1830spurOffset = finalSpur - curChanAsSpur;1831/*1832* Spur calculations:1833* spurDeltaPhase is (spurOffsetIn100KHz / chipFrequencyIn100KHz) << 211834* spurFreqSd is (spurOffsetIn100KHz / sampleFrequencyIn100KHz) << 111835*/1836if (IEEE80211_IS_CHAN_TURBO(chan)) {1837/* Chip Frequency & sampleFrequency are 80 MHz */1838spurDeltaPhase = (spurOffset << 16) / 25;1839spurFreqSd = spurDeltaPhase >> 10;1840binWidth = HAL_BIN_WIDTH_TURBO_100HZ;1841} else if (IEEE80211_IS_CHAN_G(chan)) {1842/* Chip Frequency is 44MHz, sampleFrequency is 40 MHz */1843spurFreqSd = (spurOffset << 8) / 55;1844spurDeltaPhase = (spurOffset << 17) / 25;1845binWidth = HAL_BIN_WIDTH_BASE_100HZ;1846} else {1847HALASSERT(!IEEE80211_IS_CHAN_B(chan));1848/* Chip Frequency & sampleFrequency are 40 MHz */1849spurDeltaPhase = (spurOffset << 17) / 25;1850spurFreqSd = spurDeltaPhase >> 10;1851binWidth = HAL_BIN_WIDTH_BASE_100HZ;1852}18531854/* Compute Pilot Mask */1855binOffsetNumT16 = ((spurOffset * 1000) << 4) / binWidth;1856/* The spur is on a bin if it's remainder at times 16 is 0 */1857if (binOffsetNumT16 & 0xF) {1858numBinOffsets = 4;1859pMagMap = magMapFor4;1860} else {1861numBinOffsets = 3;1862pMagMap = magMapFor3;1863}1864for (i = 0; i < numBinOffsets; i++) {1865if ((binOffsetNumT16 >> 4) > HAL_MAX_BINS_ALLOWED) {1866HALDEBUG(ah, HAL_DEBUG_ANY,1867"Too man bins in spur mitigation\n");1868return;1869}18701871/* Get Pilot Mask values */1872curBinOffset = (binOffsetNumT16 >> 4) + i + 25;1873if ((curBinOffset >= 0) && (curBinOffset <= 32)) {1874if (curBinOffset <= 25)1875pilotMask[0] |= 1 << curBinOffset;1876else if (curBinOffset >= 27)1877pilotMask[0] |= 1 << (curBinOffset - 1);1878} else if ((curBinOffset >= 33) && (curBinOffset <= 52))1879pilotMask[1] |= 1 << (curBinOffset - 33);18801881/* Get viterbi values */1882if ((curBinOffset >= -1) && (curBinOffset <= 14))1883binMagMask[0] |= pMagMap[i] << (curBinOffset + 1) * 2;1884else if ((curBinOffset >= 15) && (curBinOffset <= 30))1885binMagMask[1] |= pMagMap[i] << (curBinOffset - 15) * 2;1886else if ((curBinOffset >= 31) && (curBinOffset <= 46))1887binMagMask[2] |= pMagMap[i] << (curBinOffset -31) * 2;1888else if((curBinOffset >= 47) && (curBinOffset <= 53))1889binMagMask[3] |= pMagMap[i] << (curBinOffset -47) * 2;1890}18911892/* Write Spur Delta Phase, Spur Freq, and enable bits */1893OS_REG_RMW_FIELD(ah, AR_PHY_MASK_CTL, AR_PHY_MASK_CTL_RATE, 0xFF);1894val = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4);1895val |= (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |1896AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |1897AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);1898OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, val);1899OS_REG_WRITE(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_IN_AGC |1900SM(spurFreqSd, AR_PHY_TIMING11_SPUR_FREQ_SD) |1901SM(spurDeltaPhase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));19021903/* Write pilot masks */1904OS_REG_WRITE(ah, AR_PHY_TIMING7, pilotMask[0]);1905OS_REG_RMW_FIELD(ah, AR_PHY_TIMING8, AR_PHY_TIMING8_PILOT_MASK_2, pilotMask[1]);1906OS_REG_WRITE(ah, AR_PHY_TIMING9, pilotMask[0]);1907OS_REG_RMW_FIELD(ah, AR_PHY_TIMING10, AR_PHY_TIMING10_PILOT_MASK_2, pilotMask[1]);19081909/* Write magnitude masks */1910OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, binMagMask[0]);1911OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, binMagMask[1]);1912OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, binMagMask[2]);1913OS_REG_RMW_FIELD(ah, AR_PHY_MASK_CTL, AR_PHY_MASK_CTL_MASK_4, binMagMask[3]);1914OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, binMagMask[0]);1915OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, binMagMask[1]);1916OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, binMagMask[2]);1917OS_REG_RMW_FIELD(ah, AR_PHY_BIN_MASK2_4, AR_PHY_BIN_MASK2_4_MASK_4, binMagMask[3]);1918}1919#undef CHAN_TO_SPUR1920}19211922/*1923* Delta slope coefficient computation.1924* Required for OFDM operation.1925*/1926void1927ar5212SetDeltaSlope(struct ath_hal *ah, const struct ieee80211_channel *chan)1928{1929#define COEF_SCALE_S 241930#define INIT_CLOCKMHZSCALED 0x640000001931uint16_t freq = ath_hal_gethwchannel(ah, chan);1932unsigned long coef_scaled, coef_exp, coef_man, ds_coef_exp, ds_coef_man;1933unsigned long clockMhzScaled = INIT_CLOCKMHZSCALED;19341935if (IEEE80211_IS_CHAN_TURBO(chan))1936clockMhzScaled *= 2;1937/* half and quarter rate can divide the scaled clock by 2 or 4 respectively */1938/* scale for selected channel bandwidth */1939if (IEEE80211_IS_CHAN_HALF(chan)) {1940clockMhzScaled = clockMhzScaled >> 1;1941} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {1942clockMhzScaled = clockMhzScaled >> 2;1943}19441945/*1946* ALGO -> coef = 1e8/fcarrier*fclock/40;1947* scaled coef to provide precision for this floating calculation1948*/1949coef_scaled = clockMhzScaled / freq;19501951/*1952* ALGO -> coef_exp = 14-floor(log2(coef));1953* floor(log2(x)) is the highest set bit position1954*/1955for (coef_exp = 31; coef_exp > 0; coef_exp--)1956if ((coef_scaled >> coef_exp) & 0x1)1957break;1958/* A coef_exp of 0 is a legal bit position but an unexpected coef_exp */1959HALASSERT(coef_exp);1960coef_exp = 14 - (coef_exp - COEF_SCALE_S);19611962/*1963* ALGO -> coef_man = floor(coef* 2^coef_exp+0.5);1964* The coefficient is already shifted up for scaling1965*/1966coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1));1967ds_coef_man = coef_man >> (COEF_SCALE_S - coef_exp);1968ds_coef_exp = coef_exp - 16;19691970OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3,1971AR_PHY_TIMING3_DSC_MAN, ds_coef_man);1972OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3,1973AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);1974#undef INIT_CLOCKMHZSCALED1975#undef COEF_SCALE_S1976}19771978/*1979* Set a limit on the overall output power. Used for dynamic1980* transmit power control and the like.1981*1982* NB: limit is in units of 0.5 dbM.1983*/1984HAL_BOOL1985ar5212SetTxPowerLimit(struct ath_hal *ah, uint32_t limit)1986{1987/* XXX blech, construct local writable copy */1988struct ieee80211_channel dummy = *AH_PRIVATE(ah)->ah_curchan;1989uint16_t dummyXpdGains[2];1990HAL_BOOL isBmode;19911992SAVE_CCK(ah, &dummy, isBmode);1993AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER);1994return ar5212SetTransmitPower(ah, &dummy, dummyXpdGains);1995}19961997/*1998* Set the transmit power in the baseband for the given1999* operating channel and mode.2000*/2001HAL_BOOL2002ar5212SetTransmitPower(struct ath_hal *ah,2003const struct ieee80211_channel *chan, uint16_t *rfXpdGain)2004{2005#define POW_OFDM(_r, _s) (((0 & 1)<< ((_s)+6)) | (((_r) & 0x3f) << (_s)))2006#define POW_CCK(_r, _s) (((_r) & 0x3f) << (_s))2007#define N(a) (sizeof (a) / sizeof (a[0]))2008static const uint16_t tpcScaleReductionTable[5] =2009{ 0, 3, 6, 9, MAX_RATE_POWER };2010struct ath_hal_5212 *ahp = AH5212(ah);2011uint16_t freq = ath_hal_gethwchannel(ah, chan);2012const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;2013int16_t minPower, maxPower, tpcInDb, powerLimit;2014int i;20152016HALASSERT(ah->ah_magic == AR5212_MAGIC);20172018OS_MEMZERO(ahp->ah_pcdacTable, ahp->ah_pcdacTableSize);2019OS_MEMZERO(ahp->ah_ratesArray, sizeof(ahp->ah_ratesArray));20202021powerLimit = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit);2022if (powerLimit >= MAX_RATE_POWER || powerLimit == 0)2023tpcInDb = tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale];2024else2025tpcInDb = 0;2026if (!ar5212SetRateTable(ah, chan, tpcInDb, powerLimit,2027AH_TRUE, &minPower, &maxPower)) {2028HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set rate table\n",2029__func__);2030return AH_FALSE;2031}2032if (!ahp->ah_rfHal->setPowerTable(ah,2033&minPower, &maxPower, chan, rfXpdGain)) {2034HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n",2035__func__);2036return AH_FALSE;2037}20382039/*2040* Adjust XR power/rate up by 2 dB to account for greater peak2041* to avg ratio - except in newer avg power designs2042*/2043if (!IS_2413(ah) && !IS_5413(ah))2044ahp->ah_ratesArray[15] += 4;2045/*2046* txPowerIndexOffset is set by the SetPowerTable() call -2047* adjust the rate table2048*/2049for (i = 0; i < N(ahp->ah_ratesArray); i++) {2050ahp->ah_ratesArray[i] += ahp->ah_txPowerIndexOffset;2051if (ahp->ah_ratesArray[i] > 63)2052ahp->ah_ratesArray[i] = 63;2053}20542055if (ee->ee_eepMap < 2) {2056/*2057* Correct gain deltas for 5212 G operation -2058* Removed with revised chipset2059*/2060if (AH_PRIVATE(ah)->ah_phyRev < AR_PHY_CHIP_ID_REV_2 &&2061IEEE80211_IS_CHAN_G(chan)) {2062uint16_t cckOfdmPwrDelta;20632064if (freq == 2484)2065cckOfdmPwrDelta = SCALE_OC_DELTA(2066ee->ee_cckOfdmPwrDelta -2067ee->ee_scaledCh14FilterCckDelta);2068else2069cckOfdmPwrDelta = SCALE_OC_DELTA(2070ee->ee_cckOfdmPwrDelta);2071ar5212CorrectGainDelta(ah, cckOfdmPwrDelta);2072}2073/*2074* Finally, write the power values into the2075* baseband power table2076*/2077for (i = 0; i < (PWR_TABLE_SIZE/2); i++) {2078OS_REG_WRITE(ah, AR_PHY_PCDAC_TX_POWER(i),2079((((ahp->ah_pcdacTable[2*i + 1] << 8) | 0xff) & 0xffff) << 16)2080| (((ahp->ah_pcdacTable[2*i] << 8) | 0xff) & 0xffff)2081);2082}2083}20842085/* Write the OFDM power per rate set */2086OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,2087POW_OFDM(ahp->ah_ratesArray[3], 24)2088| POW_OFDM(ahp->ah_ratesArray[2], 16)2089| POW_OFDM(ahp->ah_ratesArray[1], 8)2090| POW_OFDM(ahp->ah_ratesArray[0], 0)2091);2092OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,2093POW_OFDM(ahp->ah_ratesArray[7], 24)2094| POW_OFDM(ahp->ah_ratesArray[6], 16)2095| POW_OFDM(ahp->ah_ratesArray[5], 8)2096| POW_OFDM(ahp->ah_ratesArray[4], 0)2097);20982099/* Write the CCK power per rate set */2100OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,2101POW_CCK(ahp->ah_ratesArray[10], 24)2102| POW_CCK(ahp->ah_ratesArray[9], 16)2103| POW_CCK(ahp->ah_ratesArray[15], 8) /* XR target power */2104| POW_CCK(ahp->ah_ratesArray[8], 0)2105);2106OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,2107POW_CCK(ahp->ah_ratesArray[14], 24)2108| POW_CCK(ahp->ah_ratesArray[13], 16)2109| POW_CCK(ahp->ah_ratesArray[12], 8)2110| POW_CCK(ahp->ah_ratesArray[11], 0)2111);21122113/*2114* Set max power to 30 dBm and, optionally,2115* enable TPC in tx descriptors.2116*/2117OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER |2118(ahp->ah_tpcEnabled ? AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE : 0));21192120return AH_TRUE;2121#undef N2122#undef POW_CCK2123#undef POW_OFDM2124}21252126/*2127* Sets the transmit power in the baseband for the given2128* operating channel and mode.2129*/2130static HAL_BOOL2131ar5212SetRateTable(struct ath_hal *ah, const struct ieee80211_channel *chan,2132int16_t tpcScaleReduction, int16_t powerLimit, HAL_BOOL commit,2133int16_t *pMinPower, int16_t *pMaxPower)2134{2135struct ath_hal_5212 *ahp = AH5212(ah);2136uint16_t freq = ath_hal_gethwchannel(ah, chan);2137const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;2138uint16_t *rpow = ahp->ah_ratesArray;2139uint16_t twiceMaxEdgePower = MAX_RATE_POWER;2140uint16_t twiceMaxEdgePowerCck = MAX_RATE_POWER;2141uint16_t twiceMaxRDPower = MAX_RATE_POWER;2142int i;2143uint8_t cfgCtl;2144int8_t twiceAntennaGain, twiceAntennaReduction;2145const RD_EDGES_POWER *rep;2146TRGT_POWER_INFO targetPowerOfdm, targetPowerCck;2147int16_t scaledPower, maxAvailPower = 0;2148int16_t r13, r9, r7, r0;21492150HALASSERT(ah->ah_magic == AR5212_MAGIC);21512152twiceMaxRDPower = chan->ic_maxregpower * 2;2153*pMaxPower = -MAX_RATE_POWER;2154*pMinPower = MAX_RATE_POWER;21552156/* Get conformance test limit maximum for this channel */2157cfgCtl = ath_hal_getctl(ah, chan);2158for (i = 0; i < ee->ee_numCtls; i++) {2159uint16_t twiceMinEdgePower;21602161if (ee->ee_ctl[i] == 0)2162continue;2163if (ee->ee_ctl[i] == cfgCtl ||2164cfgCtl == ((ee->ee_ctl[i] & CTL_MODE_M) | SD_NO_CTL)) {2165rep = &ee->ee_rdEdgesPower[i * NUM_EDGES];2166twiceMinEdgePower = ar5212GetMaxEdgePower(freq, rep);2167if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {2168/* Find the minimum of all CTL edge powers that apply to this channel */2169twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower);2170} else {2171twiceMaxEdgePower = twiceMinEdgePower;2172break;2173}2174}2175}21762177if (IEEE80211_IS_CHAN_G(chan)) {2178/* Check for a CCK CTL for 11G CCK powers */2179cfgCtl = (cfgCtl & ~CTL_MODE_M) | CTL_11B;2180for (i = 0; i < ee->ee_numCtls; i++) {2181uint16_t twiceMinEdgePowerCck;21822183if (ee->ee_ctl[i] == 0)2184continue;2185if (ee->ee_ctl[i] == cfgCtl ||2186cfgCtl == ((ee->ee_ctl[i] & CTL_MODE_M) | SD_NO_CTL)) {2187rep = &ee->ee_rdEdgesPower[i * NUM_EDGES];2188twiceMinEdgePowerCck = ar5212GetMaxEdgePower(freq, rep);2189if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {2190/* Find the minimum of all CTL edge powers that apply to this channel */2191twiceMaxEdgePowerCck = AH_MIN(twiceMaxEdgePowerCck, twiceMinEdgePowerCck);2192} else {2193twiceMaxEdgePowerCck = twiceMinEdgePowerCck;2194break;2195}2196}2197}2198} else {2199/* Set the 11B cck edge power to the one found before */2200twiceMaxEdgePowerCck = twiceMaxEdgePower;2201}22022203/* Get Antenna Gain reduction */2204if (IEEE80211_IS_CHAN_5GHZ(chan)) {2205ath_hal_eepromGet(ah, AR_EEP_ANTGAINMAX_5, &twiceAntennaGain);2206} else {2207ath_hal_eepromGet(ah, AR_EEP_ANTGAINMAX_2, &twiceAntennaGain);2208}2209twiceAntennaReduction =2210ath_hal_getantennareduction(ah, chan, twiceAntennaGain);22112212if (IEEE80211_IS_CHAN_OFDM(chan)) {2213/* Get final OFDM target powers */2214if (IEEE80211_IS_CHAN_2GHZ(chan)) {2215ar5212GetTargetPowers(ah, chan, ee->ee_trgtPwr_11g,2216ee->ee_numTargetPwr_11g, &targetPowerOfdm);2217} else {2218ar5212GetTargetPowers(ah, chan, ee->ee_trgtPwr_11a,2219ee->ee_numTargetPwr_11a, &targetPowerOfdm);2220}22212222/* Get Maximum OFDM power */2223/* Minimum of target and edge powers */2224scaledPower = AH_MIN(twiceMaxEdgePower,2225twiceMaxRDPower - twiceAntennaReduction);22262227/*2228* If turbo is set, reduce power to keep power2229* consumption under 2 Watts. Note that we always do2230* this unless specially configured. Then we limit2231* power only for non-AP operation.2232*/2233if (IEEE80211_IS_CHAN_TURBO(chan)2234#ifdef AH_ENABLE_AP_SUPPORT2235&& AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP2236#endif2237) {2238/*2239* If turbo is set, reduce power to keep power2240* consumption under 2 Watts2241*/2242if (ee->ee_version >= AR_EEPROM_VER3_1)2243scaledPower = AH_MIN(scaledPower,2244ee->ee_turbo2WMaxPower5);2245/*2246* EEPROM version 4.0 added an additional2247* constraint on 2.4GHz channels.2248*/2249if (ee->ee_version >= AR_EEPROM_VER4_0 &&2250IEEE80211_IS_CHAN_2GHZ(chan))2251scaledPower = AH_MIN(scaledPower,2252ee->ee_turbo2WMaxPower2);2253}22542255maxAvailPower = AH_MIN(scaledPower,2256targetPowerOfdm.twicePwr6_24);22572258/* Reduce power by max regulatory domain allowed restrictions */2259scaledPower = maxAvailPower - (tpcScaleReduction * 2);2260scaledPower = (scaledPower < 0) ? 0 : scaledPower;2261scaledPower = AH_MIN(scaledPower, powerLimit);22622263if (commit) {2264/* Set OFDM rates 9, 12, 18, 24 */2265r0 = rpow[0] = rpow[1] = rpow[2] = rpow[3] = rpow[4] = scaledPower;22662267/* Set OFDM rates 36, 48, 54, XR */2268rpow[5] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr36);2269rpow[6] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr48);2270r7 = rpow[7] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr54);22712272if (ee->ee_version >= AR_EEPROM_VER4_0) {2273/* Setup XR target power from EEPROM */2274rpow[15] = AH_MIN(scaledPower, IEEE80211_IS_CHAN_2GHZ(chan) ?2275ee->ee_xrTargetPower2 : ee->ee_xrTargetPower5);2276} else {2277/* XR uses 6mb power */2278rpow[15] = rpow[0];2279}2280ahp->ah_ofdmTxPower = *pMaxPower;22812282} else {2283r0 = scaledPower;2284r7 = AH_MIN(r0, targetPowerOfdm.twicePwr54);2285}2286*pMinPower = r7;2287*pMaxPower = r0;22882289HALDEBUG(ah, HAL_DEBUG_RFPARAM,2290"%s: MaxRD: %d TurboMax: %d MaxCTL: %d "2291"TPC_Reduction %d chan=%d (0x%x) maxAvailPower=%d pwr6_24=%d, maxPower=%d\n",2292__func__, twiceMaxRDPower, ee->ee_turbo2WMaxPower5,2293twiceMaxEdgePower, tpcScaleReduction * 2,2294chan->ic_freq, chan->ic_flags,2295maxAvailPower, targetPowerOfdm.twicePwr6_24, *pMaxPower);2296}22972298if (IEEE80211_IS_CHAN_CCK(chan)) {2299/* Get final CCK target powers */2300ar5212GetTargetPowers(ah, chan, ee->ee_trgtPwr_11b,2301ee->ee_numTargetPwr_11b, &targetPowerCck);23022303/* Reduce power by max regulatory domain allowed restrictions */2304scaledPower = AH_MIN(twiceMaxEdgePowerCck,2305twiceMaxRDPower - twiceAntennaReduction);2306if (maxAvailPower < AH_MIN(scaledPower, targetPowerCck.twicePwr6_24))2307maxAvailPower = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24);23082309/* Reduce power by user selection */2310scaledPower = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24) - (tpcScaleReduction * 2);2311scaledPower = (scaledPower < 0) ? 0 : scaledPower;2312scaledPower = AH_MIN(scaledPower, powerLimit);23132314if (commit) {2315/* Set CCK rates 2L, 2S, 5.5L, 5.5S, 11L, 11S */2316rpow[8] = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24);2317r9 = rpow[9] = AH_MIN(scaledPower, targetPowerCck.twicePwr36);2318rpow[10] = rpow[9];2319rpow[11] = AH_MIN(scaledPower, targetPowerCck.twicePwr48);2320rpow[12] = rpow[11];2321r13 = rpow[13] = AH_MIN(scaledPower, targetPowerCck.twicePwr54);2322rpow[14] = rpow[13];2323} else {2324r9 = AH_MIN(scaledPower, targetPowerCck.twicePwr36);2325r13 = AH_MIN(scaledPower, targetPowerCck.twicePwr54);2326}23272328/* Set min/max power based off OFDM values or initialization */2329if (r13 < *pMinPower)2330*pMinPower = r13;2331if (r9 > *pMaxPower)2332*pMaxPower = r9;23332334HALDEBUG(ah, HAL_DEBUG_RFPARAM,2335"%s: cck: MaxRD: %d MaxCTL: %d "2336"TPC_Reduction %d chan=%d (0x%x) maxAvailPower=%d pwr6_24=%d, maxPower=%d\n",2337__func__, twiceMaxRDPower, twiceMaxEdgePowerCck,2338tpcScaleReduction * 2, chan->ic_freq, chan->ic_flags,2339maxAvailPower, targetPowerCck.twicePwr6_24, *pMaxPower);2340}2341if (commit) {2342ahp->ah_tx6PowerInHalfDbm = *pMaxPower;2343AH_PRIVATE(ah)->ah_maxPowerLevel = ahp->ah_tx6PowerInHalfDbm;2344}2345return AH_TRUE;2346}23472348HAL_BOOL2349ar5212GetChipPowerLimits(struct ath_hal *ah, struct ieee80211_channel *chan)2350{2351struct ath_hal_5212 *ahp = AH5212(ah);2352#if 02353static const uint16_t tpcScaleReductionTable[5] =2354{ 0, 3, 6, 9, MAX_RATE_POWER };2355int16_t tpcInDb, powerLimit;2356#endif2357int16_t minPower, maxPower;23582359/*2360* Get Pier table max and min powers.2361*/2362if (ahp->ah_rfHal->getChannelMaxMinPower(ah, chan, &maxPower, &minPower)) {2363/* NB: rf code returns 1/4 dBm units, convert */2364chan->ic_maxpower = maxPower / 2;2365chan->ic_minpower = minPower / 2;2366} else {2367HALDEBUG(ah, HAL_DEBUG_ANY,2368"%s: no min/max power for %u/0x%x\n",2369__func__, chan->ic_freq, chan->ic_flags);2370chan->ic_maxpower = MAX_RATE_POWER;2371chan->ic_minpower = 0;2372}2373#if 02374/*2375* Now adjust to reflect any global scale and/or CTL's.2376* (XXX is that correct?)2377*/2378powerLimit = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit);2379if (powerLimit >= MAX_RATE_POWER || powerLimit == 0)2380tpcInDb = tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale];2381else2382tpcInDb = 0;2383if (!ar5212SetRateTable(ah, chan, tpcInDb, powerLimit,2384AH_FALSE, &minPower, &maxPower)) {2385HALDEBUG(ah, HAL_DEBUG_ANY,2386"%s: unable to find max/min power\n",__func__);2387return AH_FALSE;2388}2389if (maxPower < chan->ic_maxpower)2390chan->ic_maxpower = maxPower;2391if (minPower < chan->ic_minpower)2392chan->ic_minpower = minPower;2393HALDEBUG(ah, HAL_DEBUG_RESET,2394"Chan %d: MaxPow = %d MinPow = %d\n",2395chan->ic_freq, chan->ic_maxpower, chans->ic_minpower);2396#endif2397return AH_TRUE;2398}23992400/*2401* Correct for the gain-delta between ofdm and cck mode target2402* powers. Write the results to the rate table and the power table.2403*2404* Conventions :2405* 1. rpow[ii] is the integer value of 2*(desired power2406* for the rate ii in dBm) to provide 0.5dB resolution. rate2407* mapping is as following :2408* [0..7] --> ofdm 6, 9, .. 48, 542409* [8..14] --> cck 1L, 2L, 2S, .. 11L, 11S2410* [15] --> XR (all rates get the same power)2411* 2. powv[ii] is the pcdac corresponding to ii/2 dBm.2412*/2413static void2414ar5212CorrectGainDelta(struct ath_hal *ah, int twiceOfdmCckDelta)2415{2416#define N(_a) (sizeof(_a) / sizeof(_a[0]))2417struct ath_hal_5212 *ahp = AH5212(ah);2418const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;2419int16_t ratesIndex[N(ahp->ah_ratesArray)];2420uint16_t ii, jj, iter;2421int32_t cckIndex;2422int16_t gainDeltaAdjust;24232424HALASSERT(ah->ah_magic == AR5212_MAGIC);24252426gainDeltaAdjust = ee->ee_cckOfdmGainDelta;24272428/* make a local copy of desired powers as initial indices */2429OS_MEMCPY(ratesIndex, ahp->ah_ratesArray, sizeof(ratesIndex));24302431/* fix only the CCK indices */2432for (ii = 8; ii < 15; ii++) {2433/* apply a gain_delta correction of -15 for CCK */2434ratesIndex[ii] -= gainDeltaAdjust;24352436/* Now check for contention with all ofdm target powers */2437jj = 0;2438iter = 0;2439/* indicates not all ofdm rates checked forcontention yet */2440while (jj < 16) {2441if (ratesIndex[ii] < 0)2442ratesIndex[ii] = 0;2443if (jj == 8) { /* skip CCK rates */2444jj = 15;2445continue;2446}2447if (ratesIndex[ii] == ahp->ah_ratesArray[jj]) {2448if (ahp->ah_ratesArray[jj] == 0)2449ratesIndex[ii]++;2450else if (iter > 50) {2451/*2452* To avoid pathological case of of2453* dm target powers 0 and 0.5dBm2454*/2455ratesIndex[ii]++;2456} else2457ratesIndex[ii]--;2458/* check with all rates again */2459jj = 0;2460iter++;2461} else2462jj++;2463}2464if (ratesIndex[ii] >= PWR_TABLE_SIZE)2465ratesIndex[ii] = PWR_TABLE_SIZE -1;2466cckIndex = ahp->ah_ratesArray[ii] - twiceOfdmCckDelta;2467if (cckIndex < 0)2468cckIndex = 0;24692470/*2471* Validate that the indexes for the powv are not2472* out of bounds.2473*/2474HALASSERT(cckIndex < PWR_TABLE_SIZE);2475HALASSERT(ratesIndex[ii] < PWR_TABLE_SIZE);2476ahp->ah_pcdacTable[ratesIndex[ii]] =2477ahp->ah_pcdacTable[cckIndex];2478}2479/* Override rate per power table with new values */2480for (ii = 8; ii < 15; ii++)2481ahp->ah_ratesArray[ii] = ratesIndex[ii];2482#undef N2483}24842485/*2486* Find the maximum conformance test limit for the given channel and CTL info2487*/2488static uint16_t2489ar5212GetMaxEdgePower(uint16_t channel, const RD_EDGES_POWER *pRdEdgesPower)2490{2491/* temp array for holding edge channels */2492uint16_t tempChannelList[NUM_EDGES];2493uint16_t clo, chi, twiceMaxEdgePower;2494int i, numEdges;24952496/* Get the edge power */2497for (i = 0; i < NUM_EDGES; i++) {2498if (pRdEdgesPower[i].rdEdge == 0)2499break;2500tempChannelList[i] = pRdEdgesPower[i].rdEdge;2501}2502numEdges = i;25032504ar5212GetLowerUpperValues(channel, tempChannelList,2505numEdges, &clo, &chi);2506/* Get the index for the lower channel */2507for (i = 0; i < numEdges && clo != tempChannelList[i]; i++)2508;2509/* Is lower channel ever outside the rdEdge? */2510HALASSERT(i != numEdges);25112512if ((clo == chi && clo == channel) || (pRdEdgesPower[i].flag)) {2513/*2514* If there's an exact channel match or an inband flag set2515* on the lower channel use the given rdEdgePower2516*/2517twiceMaxEdgePower = pRdEdgesPower[i].twice_rdEdgePower;2518HALASSERT(twiceMaxEdgePower > 0);2519} else2520twiceMaxEdgePower = MAX_RATE_POWER;2521return twiceMaxEdgePower;2522}25232524/*2525* Returns interpolated or the scaled up interpolated value2526*/2527static uint16_t2528interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight,2529uint16_t targetLeft, uint16_t targetRight)2530{2531uint16_t rv;2532int16_t lRatio;25332534/* to get an accurate ratio, always scale, if want to scale, then don't scale back down */2535if ((targetLeft * targetRight) == 0)2536return 0;25372538if (srcRight != srcLeft) {2539/*2540* Note the ratio always need to be scaled,2541* since it will be a fraction.2542*/2543lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft);2544if (lRatio < 0) {2545/* Return as Left target if value would be negative */2546rv = targetLeft;2547} else if (lRatio > EEP_SCALE) {2548/* Return as Right target if Ratio is greater than 100% (SCALE) */2549rv = targetRight;2550} else {2551rv = (lRatio * targetRight + (EEP_SCALE - lRatio) *2552targetLeft) / EEP_SCALE;2553}2554} else {2555rv = targetLeft;2556}2557return rv;2558}25592560/*2561* Return the four rates of target power for the given target power table2562* channel, and number of channels2563*/2564static void2565ar5212GetTargetPowers(struct ath_hal *ah, const struct ieee80211_channel *chan,2566const TRGT_POWER_INFO *powInfo,2567uint16_t numChannels, TRGT_POWER_INFO *pNewPower)2568{2569uint16_t freq = ath_hal_gethwchannel(ah, chan);2570/* temp array for holding target power channels */2571uint16_t tempChannelList[NUM_TEST_FREQUENCIES];2572uint16_t clo, chi, ixlo, ixhi;2573int i;25742575/* Copy the target powers into the temp channel list */2576for (i = 0; i < numChannels; i++)2577tempChannelList[i] = powInfo[i].testChannel;25782579ar5212GetLowerUpperValues(freq, tempChannelList,2580numChannels, &clo, &chi);25812582/* Get the indices for the channel */2583ixlo = ixhi = 0;2584for (i = 0; i < numChannels; i++) {2585if (clo == tempChannelList[i]) {2586ixlo = i;2587}2588if (chi == tempChannelList[i]) {2589ixhi = i;2590break;2591}2592}25932594/*2595* Get the lower and upper channels, target powers,2596* and interpolate between them.2597*/2598pNewPower->twicePwr6_24 = interpolate(freq, clo, chi,2599powInfo[ixlo].twicePwr6_24, powInfo[ixhi].twicePwr6_24);2600pNewPower->twicePwr36 = interpolate(freq, clo, chi,2601powInfo[ixlo].twicePwr36, powInfo[ixhi].twicePwr36);2602pNewPower->twicePwr48 = interpolate(freq, clo, chi,2603powInfo[ixlo].twicePwr48, powInfo[ixhi].twicePwr48);2604pNewPower->twicePwr54 = interpolate(freq, clo, chi,2605powInfo[ixlo].twicePwr54, powInfo[ixhi].twicePwr54);2606}26072608static uint32_t2609udiff(uint32_t u, uint32_t v)2610{2611return (u >= v ? u - v : v - u);2612}26132614/*2615* Search a list for a specified value v that is within2616* EEP_DELTA of the search values. Return the closest2617* values in the list above and below the desired value.2618* EEP_DELTA is a factional value; everything is scaled2619* so only integer arithmetic is used.2620*2621* NB: the input list is assumed to be sorted in ascending order2622*/2623void2624ar5212GetLowerUpperValues(uint16_t v, uint16_t *lp, uint16_t listSize,2625uint16_t *vlo, uint16_t *vhi)2626{2627uint32_t target = v * EEP_SCALE;2628uint16_t *ep = lp+listSize;26292630/*2631* Check first and last elements for out-of-bounds conditions.2632*/2633if (target < (uint32_t)(lp[0] * EEP_SCALE - EEP_DELTA)) {2634*vlo = *vhi = lp[0];2635return;2636}2637if (target > (uint32_t)(ep[-1] * EEP_SCALE + EEP_DELTA)) {2638*vlo = *vhi = ep[-1];2639return;2640}26412642/* look for value being near or between 2 values in list */2643for (; lp < ep; lp++) {2644/*2645* If value is close to the current value of the list2646* then target is not between values, it is one of the values2647*/2648if (udiff(lp[0] * EEP_SCALE, target) < EEP_DELTA) {2649*vlo = *vhi = lp[0];2650return;2651}2652/*2653* Look for value being between current value and next value2654* if so return these 2 values2655*/2656if (target < (uint32_t)(lp[1] * EEP_SCALE - EEP_DELTA)) {2657*vlo = lp[0];2658*vhi = lp[1];2659return;2660}2661}2662HALASSERT(AH_FALSE); /* should not reach here */2663}26642665/*2666* Perform analog "swizzling" of parameters into their location2667*2668* NB: used by RF backends2669*/2670void2671ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, uint32_t numBits,2672uint32_t firstBit, uint32_t column)2673{2674#define MAX_ANALOG_START 319 /* XXX */2675uint32_t tmp32, mask, arrayEntry, lastBit;2676int32_t bitPosition, bitsLeft;26772678HALASSERT(column <= 3);2679HALASSERT(numBits <= 32);2680HALASSERT(firstBit + numBits <= MAX_ANALOG_START);26812682tmp32 = ath_hal_reverseBits(reg32, numBits);2683arrayEntry = (firstBit - 1) / 8;2684bitPosition = (firstBit - 1) % 8;2685bitsLeft = numBits;2686while (bitsLeft > 0) {2687lastBit = (bitPosition + bitsLeft > 8) ?26888 : bitPosition + bitsLeft;2689mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<2690(column * 8);2691rfBuf[arrayEntry] &= ~mask;2692rfBuf[arrayEntry] |= ((tmp32 << bitPosition) <<2693(column * 8)) & mask;2694bitsLeft -= 8 - bitPosition;2695tmp32 = tmp32 >> (8 - bitPosition);2696bitPosition = 0;2697arrayEntry++;2698}2699#undef MAX_ANALOG_START2700}27012702/*2703* Sets the rate to duration values in MAC - used for multi-2704* rate retry.2705* The rate duration table needs to cover all valid rate codes;2706* the 11g table covers all ofdm rates, while the 11b table2707* covers all cck rates => all valid rates get covered between2708* these two mode's ratetables!2709* But if we're turbo, the ofdm phy is replaced by the turbo phy2710* and cck is not valid with turbo => all rates get covered2711* by the turbo ratetable only2712*/2713void2714ar5212SetRateDurationTable(struct ath_hal *ah,2715const struct ieee80211_channel *chan)2716{2717const HAL_RATE_TABLE *rt;2718int i;27192720/* NB: band doesn't matter for 1/2 and 1/4 rate */2721if (IEEE80211_IS_CHAN_HALF(chan)) {2722rt = ar5212GetRateTable(ah, HAL_MODE_11A_HALF_RATE);2723} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {2724rt = ar5212GetRateTable(ah, HAL_MODE_11A_QUARTER_RATE);2725} else {2726rt = ar5212GetRateTable(ah,2727IEEE80211_IS_CHAN_TURBO(chan) ? HAL_MODE_TURBO : HAL_MODE_11G);2728}27292730for (i = 0; i < rt->rateCount; ++i)2731OS_REG_WRITE(ah,2732AR_RATE_DURATION(rt->info[i].rateCode),2733ath_hal_computetxtime(ah, rt,2734WLAN_CTRL_FRAME_SIZE,2735rt->info[i].controlRate, AH_FALSE, AH_TRUE));2736if (!IEEE80211_IS_CHAN_TURBO(chan)) {2737/* 11g Table is used to cover the CCK rates. */2738rt = ar5212GetRateTable(ah, HAL_MODE_11G);2739for (i = 0; i < rt->rateCount; ++i) {2740uint32_t reg = AR_RATE_DURATION(rt->info[i].rateCode);27412742if (rt->info[i].phy != IEEE80211_T_CCK)2743continue;27442745OS_REG_WRITE(ah, reg,2746ath_hal_computetxtime(ah, rt,2747WLAN_CTRL_FRAME_SIZE,2748rt->info[i].controlRate, AH_FALSE,2749AH_TRUE));2750/* cck rates have short preamble option also */2751if (rt->info[i].shortPreamble) {2752reg += rt->info[i].shortPreamble << 2;2753OS_REG_WRITE(ah, reg,2754ath_hal_computetxtime(ah, rt,2755WLAN_CTRL_FRAME_SIZE,2756rt->info[i].controlRate,2757AH_TRUE, AH_TRUE));2758}2759}2760}2761}27622763/* Adjust various register settings based on half/quarter rate clock setting.2764* This includes: +USEC, TX/RX latency,2765* + IFS params: slot, eifs, misc etc.2766*/2767void2768ar5212SetIFSTiming(struct ath_hal *ah, const struct ieee80211_channel *chan)2769{2770uint32_t txLat, rxLat, usec, slot, refClock, eifs, init_usec;27712772HALASSERT(IEEE80211_IS_CHAN_HALF(chan) ||2773IEEE80211_IS_CHAN_QUARTER(chan));27742775refClock = OS_REG_READ(ah, AR_USEC) & AR_USEC_USEC32;2776if (IEEE80211_IS_CHAN_HALF(chan)) {2777slot = IFS_SLOT_HALF_RATE;2778rxLat = RX_NON_FULL_RATE_LATENCY << AR5212_USEC_RX_LAT_S;2779txLat = TX_HALF_RATE_LATENCY << AR5212_USEC_TX_LAT_S;2780usec = HALF_RATE_USEC;2781eifs = IFS_EIFS_HALF_RATE;2782init_usec = INIT_USEC >> 1;2783} else { /* quarter rate */2784slot = IFS_SLOT_QUARTER_RATE;2785rxLat = RX_NON_FULL_RATE_LATENCY << AR5212_USEC_RX_LAT_S;2786txLat = TX_QUARTER_RATE_LATENCY << AR5212_USEC_TX_LAT_S;2787usec = QUARTER_RATE_USEC;2788eifs = IFS_EIFS_QUARTER_RATE;2789init_usec = INIT_USEC >> 2;2790}27912792OS_REG_WRITE(ah, AR_USEC, (usec | refClock | txLat | rxLat));2793OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot);2794OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);2795OS_REG_RMW_FIELD(ah, AR_D_GBL_IFS_MISC,2796AR_D_GBL_IFS_MISC_USEC_DURATION, init_usec);2797}279827992800