Path: blob/main/sys/dev/ath/ath_hal/ar5312/ar5312_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#ifdef AH_SUPPORT_AR53122122#include "ah.h"23#include "ah_internal.h"24#include "ah_devid.h"2526#include "ar5312/ar5312.h"27#include "ar5312/ar5312reg.h"28#include "ar5312/ar5312phy.h"2930#include "ah_eeprom_v3.h"3132/* Additional Time delay to wait after activiting the Base band */33#define BASE_ACTIVATE_DELAY 100 /* 100 usec */34#define PLL_SETTLE_DELAY 300 /* 300 usec */3536extern int16_t ar5212GetNf(struct ath_hal *, const struct ieee80211_channel *);37extern void ar5212SetRateDurationTable(struct ath_hal *,38const struct ieee80211_channel *);39extern HAL_BOOL ar5212SetTransmitPower(struct ath_hal *ah,40const struct ieee80211_channel *chan, uint16_t *rfXpdGain);41extern void ar5212SetDeltaSlope(struct ath_hal *,42const struct ieee80211_channel *);43extern HAL_BOOL ar5212SetBoardValues(struct ath_hal *,44const struct ieee80211_channel *);45extern void ar5212SetIFSTiming(struct ath_hal *,46const struct ieee80211_channel *);47extern HAL_BOOL ar5212IsSpurChannel(struct ath_hal *,48const struct ieee80211_channel *);49extern HAL_BOOL ar5212ChannelChange(struct ath_hal *,50const struct ieee80211_channel *);5152static HAL_BOOL ar5312SetResetReg(struct ath_hal *, uint32_t resetMask);5354static int55write_common(struct ath_hal *ah, const HAL_INI_ARRAY *ia,56HAL_BOOL bChannelChange, int writes)57{58#define IS_NO_RESET_TIMER_ADDR(x) \59( (((x) >= AR_BEACON) && ((x) <= AR_CFP_DUR)) || \60(((x) >= AR_SLEEP1) && ((x) <= AR_SLEEP3)))61#define V(r, c) (ia)->data[((r)*(ia)->cols) + (c)]62int i;6364/* Write Common Array Parameters */65for (i = 0; i < ia->rows; i++) {66uint32_t reg = V(i, 0);67/* XXX timer/beacon setup registers? */68/* On channel change, don't reset the PCU registers */69if (!(bChannelChange && IS_NO_RESET_TIMER_ADDR(reg))) {70OS_REG_WRITE(ah, reg, V(i, 1));71DMA_YIELD(writes);72}73}74return writes;75#undef IS_NO_RESET_TIMER_ADDR76#undef V77}7879/*80* Places the device in and out of reset and then places sane81* values in the registers based on EEPROM config, initialization82* vectors (as determined by the mode), and station configuration83*84* bChannelChange is used to preserve DMA/PCU registers across85* a HW Reset during channel change.86*/87HAL_BOOL88ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode,89struct ieee80211_channel *chan,90HAL_BOOL bChannelChange,91HAL_RESET_TYPE resetType,92HAL_STATUS *status)93{94#define N(a) (sizeof (a) / sizeof (a[0]))95#define FAIL(_code) do { ecode = _code; goto bad; } while (0)96struct ath_hal_5212 *ahp = AH5212(ah);97HAL_CHANNEL_INTERNAL *ichan;98const HAL_EEPROM *ee;99uint32_t saveFrameSeqCount, saveDefAntenna;100uint32_t macStaId1, synthDelay, txFrm2TxDStart;101uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL];102int16_t cckOfdmPwrDelta = 0;103u_int modesIndex, freqIndex;104HAL_STATUS ecode;105int i, regWrites = 0;106uint32_t testReg;107uint32_t saveLedState = 0;108109HALASSERT(ah->ah_magic == AR5212_MAGIC);110ee = AH_PRIVATE(ah)->ah_eeprom;111112OS_MARK(ah, AH_MARK_RESET, bChannelChange);113/*114* Map public channel to private.115*/116ichan = ath_hal_checkchannel(ah, chan);117if (ichan == AH_NULL) {118HALDEBUG(ah, HAL_DEBUG_ANY,119"%s: invalid channel %u/0x%x; no mapping\n",120__func__, chan->ic_freq, chan->ic_flags);121FAIL(HAL_EINVAL);122}123switch (opmode) {124case HAL_M_STA:125case HAL_M_IBSS:126case HAL_M_HOSTAP:127case HAL_M_MONITOR:128break;129default:130HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n",131__func__, opmode);132FAIL(HAL_EINVAL);133break;134}135HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3);136137/* Preserve certain DMA hardware registers on a channel change */138if (bChannelChange) {139/*140* On Venice, the TSF is almost preserved across a reset;141* it requires the doubling writes to the RESET_TSF142* bit in the AR_BEACON register; it also has the quirk143* of the TSF going back in time on the station (station144* latches onto the last beacon's tsf during a reset 50%145* of the times); the latter is not a problem for adhoc146* stations since as long as the TSF is behind, it will147* get resynchronized on receiving the next beacon; the148* TSF going backwards in time could be a problem for the149* sleep operation (supported on infrastructure stations150* only) - the best and most general fix for this situation151* is to resynchronize the various sleep/beacon timers on152* the receipt of the next beacon i.e. when the TSF itself153* gets resynchronized to the AP's TSF - power save is154* needed to be temporarily disabled until that time155*156* Need to save the sequence number to restore it after157* the reset!158*/159saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM);160} else161saveFrameSeqCount = 0; /* NB: silence compiler */162163/* If the channel change is across the same mode - perform a fast channel change */164if ((IS_2413(ah) || IS_5413(ah))) {165/*166* Channel change can only be used when:167* -channel change requested - so it's not the initial reset.168* -it's not a change to the current channel - often called when switching modes169* on a channel170* -the modes of the previous and requested channel are the same - some ugly code for XR171*/172if (bChannelChange &&173AH_PRIVATE(ah)->ah_curchan != AH_NULL &&174(chan->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) &&175((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) ==176(AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) {177if (ar5212ChannelChange(ah, chan))178/* If ChannelChange completed - skip the rest of reset */179return AH_TRUE;180}181}182183/*184* Preserve the antenna on a channel change185*/186saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);187if (saveDefAntenna == 0) /* XXX magic constants */188saveDefAntenna = 1;189190/* Save hardware flag before chip reset clears the register */191macStaId1 = OS_REG_READ(ah, AR_STA_ID1) &192(AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT);193194/* Save led state from pci config register */195if (!IS_5315(ah))196saveLedState = OS_REG_READ(ah, AR5312_PCICFG) &197(AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK |198AR_PCICFG_LEDSLOW);199200ar5312RestoreClock(ah, opmode); /* move to refclk operation */201202/*203* Adjust gain parameters before reset if204* there's an outstanding gain updated.205*/206(void) ar5212GetRfgain(ah);207208if (!ar5312ChipReset(ah, chan)) {209HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);210FAIL(HAL_EIO);211}212213/* Setup the indices for the next set of register array writes */214if (IEEE80211_IS_CHAN_2GHZ(chan)) {215freqIndex = 2;216modesIndex = IEEE80211_IS_CHAN_108G(chan) ? 5 :217IEEE80211_IS_CHAN_G(chan) ? 4 : 3;218} else {219freqIndex = 1;220modesIndex = IEEE80211_IS_CHAN_ST(chan) ? 2 : 1;221}222223OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);224225/* Set correct Baseband to analog shift setting to access analog chips. */226OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);227228regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0);229regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange,230regWrites);231ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites);232233OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);234235if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))236ar5212SetIFSTiming(ah, chan);237238/* Overwrite INI values for revised chipsets */239if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) {240/* ADC_CTL */241OS_REG_WRITE(ah, AR_PHY_ADC_CTL,242SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) |243SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) |244AR_PHY_ADC_CTL_OFF_PWDDAC |245AR_PHY_ADC_CTL_OFF_PWDADC);246247/* TX_PWR_ADJ */248if (chan->channel == 2484) {249cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta);250} else {251cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta);252}253254if (IEEE80211_IS_CHAN_G(chan)) {255OS_REG_WRITE(ah, AR_PHY_TXPWRADJ,256SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) |257SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX));258} else {259OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0);260}261262/* Add barker RSSI thresh enable as disabled */263OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK,264AR_PHY_DAG_CTRLCCK_EN_RSSI_THR);265OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK,266AR_PHY_DAG_CTRLCCK_RSSI_THR, 2);267268/* Set the mute mask to the correct default */269OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F);270}271272if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) {273/* Clear reg to alllow RX_CLEAR line debug */274OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0);275}276if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) {277#ifdef notyet278/* Enable burst prefetch for the data queues */279OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... );280/* Enable double-buffering */281OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS);282#endif283}284285if (IS_5312_2_X(ah)) {286/* ADC_CTRL */287OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA,288SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) |289SM(4, AR_PHY_SIGMA_DELTA_FILT2) |290SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) |291SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP));292293if (IEEE80211_IS_CHAN_2GHZ(chan))294OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F);295296/* CCK Short parameter adjustment in 11B mode */297if (IEEE80211_IS_CHAN_B(chan))298OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12);299300/* Set ADC/DAC select values */301OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04);302303/* Increase 11A AGC Settling */304if (IEEE80211_IS_CHAN_A(chan))305OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32);306} else {307/* Set ADC/DAC select values */308OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);309}310311/* Setup the transmit power values. */312if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) {313HALDEBUG(ah, HAL_DEBUG_ANY,314"%s: error init'ing transmit power\n", __func__);315FAIL(HAL_EIO);316}317318/* Write the analog registers */319if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) {320HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n",321__func__);322FAIL(HAL_EIO);323}324325/* Write delta slope for OFDM enabled modes (A, G, Turbo) */326if (IEEE80211_IS_CHAN_OFDM(chan)) {327if (IS_5413(ah) ||328AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3)329ar5212SetSpurMitigation(ah, chan);330ar5212SetDeltaSlope(ah, chan);331}332333/* Setup board specific options for EEPROM version 3 */334if (!ar5212SetBoardValues(ah, chan)) {335HALDEBUG(ah, HAL_DEBUG_ANY,336"%s: error setting board options\n", __func__);337FAIL(HAL_EIO);338}339340/* Restore certain DMA hardware registers on a channel change */341if (bChannelChange)342OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount);343344OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);345346OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));347OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)348| macStaId1349| AR_STA_ID1_RTS_USE_DEF350| ahp->ah_staId1Defaults351);352ar5212SetOperatingMode(ah, opmode);353354/* Set Venice BSSID mask according to current state */355OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));356OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));357358/* Restore previous led state */359if (!IS_5315(ah))360OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState);361362/* Restore previous antenna */363OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);364365/* then our BSSID */366OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));367OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4));368369/* Restore bmiss rssi & count thresholds */370OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);371372OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */373374if (!ar5212SetChannel(ah, chan))375FAIL(HAL_EIO);376377OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);378379ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1);380381ar5212SetRateDurationTable(ah, chan);382383/* Set Tx frame start to tx data start delay */384if (IS_RAD5112_ANY(ah) &&385(IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) {386txFrm2TxDStart =387IEEE80211_IS_CHAN_HALF(chan) ?388TX_FRAME_D_START_HALF_RATE:389TX_FRAME_D_START_QUARTER_RATE;390OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL,391AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart);392}393394/*395* Setup fast diversity.396* Fast diversity can be enabled or disabled via regadd.txt.397* Default is enabled.398* For reference,399* Disable: reg val400* 0x00009860 0x00009d18 (if 11a / 11g, else no change)401* 0x00009970 0x192bb514402* 0x0000a208 0xd03e4648403*404* Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change)405* 0x00009970 0x192fb514406* 0x0000a208 0xd03e6788407*/408409/* XXX Setup pre PHY ENABLE EAR additions */410411/* flush SCAL reg */412if (IS_5312_2_X(ah)) {413(void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL);414}415416/*417* Wait for the frequency synth to settle (synth goes on418* via AR_PHY_ACTIVE_EN). Read the phy active delay register.419* Value is in 100ns increments.420*/421synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;422if (IEEE80211_IS_CHAN_B(chan)) {423synthDelay = (4 * synthDelay) / 22;424} else {425synthDelay /= 10;426}427428/* Activate the PHY (includes baseband activate and synthesizer on) */429OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);430431/*432* There is an issue if the AP starts the calibration before433* the base band timeout completes. This could result in the434* rx_clear false triggering. As a workaround we add delay an435* extra BASE_ACTIVATE_DELAY usecs to ensure this condition436* does not happen.437*/438if (IEEE80211_IS_CHAN_HALF(chan)) {439OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY);440} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {441OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY);442} else {443OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);444}445446/*447* The udelay method is not reliable with notebooks.448* Need to check to see if the baseband is ready449*/450testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL);451/* Selects the Tx hold */452OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD);453i = 0;454while ((i++ < 20) &&455(OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200);456OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg);457458/* Calibrate the AGC and start a NF calculation */459OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,460OS_REG_READ(ah, AR_PHY_AGC_CONTROL)461| AR_PHY_AGC_CONTROL_CAL462| AR_PHY_AGC_CONTROL_NF);463464if (!IEEE80211_IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) {465/* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */466OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,467AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,468INIT_IQCAL_LOG_COUNT_MAX);469OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,470AR_PHY_TIMING_CTRL4_DO_IQCAL);471ahp->ah_bIQCalibration = IQ_CAL_RUNNING;472} else473ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;474475/* Setup compression registers */476ar5212SetCompRegs(ah);477478/* Set 1:1 QCU to DCU mapping for all queues */479for (i = 0; i < AR_NUM_DCU; i++)480OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);481482ahp->ah_intrTxqs = 0;483for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++)484ar5212ResetTxQueue(ah, i);485486/*487* Setup interrupt handling. Note that ar5212ResetTxQueue488* manipulates the secondary IMR's as queues are enabled489* and disabled. This is done with RMW ops to insure the490* settings we make here are preserved.491*/492ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN493| AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN494| AR_IMR_HIUERR495;496if (opmode == HAL_M_HOSTAP)497ahp->ah_maskReg |= AR_IMR_MIB;498OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);499/* Enable bus errors that are OR'd to set the HIUERR bit */500OS_REG_WRITE(ah, AR_IMR_S2,501OS_REG_READ(ah, AR_IMR_S2)502| AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR);503504if (AH_PRIVATE(ah)->ah_rfkillEnabled)505ar5212EnableRfKill(ah);506507if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {508HALDEBUG(ah, HAL_DEBUG_ANY,509"%s: offset calibration failed to complete in 1ms;"510" noisy environment?\n", __func__);511}512513/*514* Set clocks back to 32kHz if they had been using refClk, then515* use an external 32kHz crystal when sleeping, if one exists.516*/517ar5312SetupClock(ah, opmode);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/* XXX Setup post reset EAR additions */529530/* QoS support */531if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE ||532(AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE &&533AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) {534OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */535OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */536}537538/* Turn on NOACK Support for QoS packets */539OS_REG_WRITE(ah, AR_NOACK,540SM(2, AR_NOACK_2BIT_VALUE) |541SM(5, AR_NOACK_BIT_OFFSET) |542SM(0, AR_NOACK_BYTE_OFFSET));543544/* Restore user-specified settings */545if (ahp->ah_miscMode != 0)546OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);547if (ahp->ah_slottime != (u_int) -1)548ar5212SetSlotTime(ah, ahp->ah_slottime);549if (ahp->ah_acktimeout != (u_int) -1)550ar5212SetAckTimeout(ah, ahp->ah_acktimeout);551if (ahp->ah_ctstimeout != (u_int) -1)552ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout);553if (ahp->ah_sifstime != (u_int) -1)554ar5212SetSifsTime(ah, ahp->ah_sifstime);555if (AH_PRIVATE(ah)->ah_diagreg != 0)556OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);557558AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */559560if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan))561chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;562563HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__);564565OS_MARK(ah, AH_MARK_RESET_DONE, 0);566567return AH_TRUE;568bad:569OS_MARK(ah, AH_MARK_RESET_DONE, ecode);570if (status != AH_NULL)571*status = ecode;572return AH_FALSE;573#undef FAIL574#undef N575}576577/*578* Places the PHY and Radio chips into reset. A full reset579* must be called to leave this state. The PCI/MAC/PCU are580* not placed into reset as we must receive interrupt to581* re-enable the hardware.582*/583HAL_BOOL584ar5312PhyDisable(struct ath_hal *ah)585{586return ar5312SetResetReg(ah, AR_RC_BB);587}588589/*590* Places all of hardware into reset591*/592HAL_BOOL593ar5312Disable(struct ath_hal *ah)594{595if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))596return AH_FALSE;597/*598* Reset the HW - PCI must be reset after the rest of the599* device has been reset.600*/601return ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB);602}603604/*605* Places the hardware into reset and then pulls it out of reset606*607* TODO: Only write the PLL if we're changing to or from CCK mode608*609* WARNING: The order of the PLL and mode registers must be correct.610*/611HAL_BOOL612ar5312ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan)613{614615OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);616617/*618* Reset the HW619*/620if (!ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB)) {621HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",622__func__);623return AH_FALSE;624}625626/* Bring out of sleep mode (AGAIN) */627if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {628HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetPowerMode failed\n",629__func__);630return AH_FALSE;631}632633/* Clear warm reset register */634if (!ar5312SetResetReg(ah, 0)) {635HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",636__func__);637return AH_FALSE;638}639640/*641* Perform warm reset before the mode/PLL/turbo registers642* are changed in order to deactivate the radio. Mode changes643* with an active radio can result in corrupted shifts to the644* radio device.645*/646647/*648* Set CCK and Turbo modes correctly.649*/650if (chan != AH_NULL) { /* NB: can be null during attach */651uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo;652653if (IS_RAD5112_ANY(ah)) {654rfMode = AR_PHY_MODE_AR5112;655if (!IS_5315(ah)) {656if (IEEE80211_IS_CHAN_CCK(chan)) {657phyPLL = AR_PHY_PLL_CTL_44_5312;658} else {659if (IEEE80211_IS_CHAN_HALF(chan)) {660phyPLL = AR_PHY_PLL_CTL_40_5312_HALF;661} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {662phyPLL = AR_PHY_PLL_CTL_40_5312_QUARTER;663} else {664phyPLL = AR_PHY_PLL_CTL_40_5312;665}666}667} else {668if (IEEE80211_IS_CHAN_CCK(chan))669phyPLL = AR_PHY_PLL_CTL_44_5112;670else671phyPLL = AR_PHY_PLL_CTL_40_5112;672if (IEEE80211_IS_CHAN_HALF(chan))673phyPLL |= AR_PHY_PLL_CTL_HALF;674else if (IEEE80211_IS_CHAN_QUARTER(chan))675phyPLL |= AR_PHY_PLL_CTL_QUARTER;676}677} else {678rfMode = AR_PHY_MODE_AR5111;679if (IEEE80211_IS_CHAN_CCK(chan))680phyPLL = AR_PHY_PLL_CTL_44;681else682phyPLL = AR_PHY_PLL_CTL_40;683if (IEEE80211_IS_CHAN_HALF(chan))684phyPLL = AR_PHY_PLL_CTL_HALF;685else if (IEEE80211_IS_CHAN_QUARTER(chan))686phyPLL = AR_PHY_PLL_CTL_QUARTER;687}688if (IEEE80211_IS_CHAN_G(chan))689rfMode |= AR_PHY_MODE_DYNAMIC;690else if (IEEE80211_IS_CHAN_OFDM(chan))691rfMode |= AR_PHY_MODE_OFDM;692else693rfMode |= AR_PHY_MODE_CCK;694if (IEEE80211_IS_CHAN_5GHZ(chan))695rfMode |= AR_PHY_MODE_RF5GHZ;696else697rfMode |= AR_PHY_MODE_RF2GHZ;698turbo = IEEE80211_IS_CHAN_TURBO(chan) ?699(AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0;700curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL);701/*702* PLL, Mode, and Turbo values must be written in the correct703* order to ensure:704* - The PLL cannot be set to 44 unless the CCK or DYNAMIC705* mode bit is set706* - Turbo cannot be set at the same time as CCK or DYNAMIC707*/708if (IEEE80211_IS_CHAN_CCK(chan)) {709OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);710OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);711if (curPhyPLL != phyPLL) {712OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL);713/* Wait for the PLL to settle */714OS_DELAY(PLL_SETTLE_DELAY);715}716} else {717if (curPhyPLL != phyPLL) {718OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL);719/* Wait for the PLL to settle */720OS_DELAY(PLL_SETTLE_DELAY);721}722OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);723OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);724}725}726return AH_TRUE;727}728729/*730* Write the given reset bit mask into the reset register731*/732static HAL_BOOL733ar5312SetResetReg(struct ath_hal *ah, uint32_t resetMask)734{735uint32_t mask = resetMask ? resetMask : ~0;736HAL_BOOL rt;737738if ((rt = ar5312MacReset(ah, mask)) == AH_FALSE) {739return rt;740}741if ((resetMask & AR_RC_MAC) == 0) {742if (isBigEndian()) {743/*744* Set CFG, little-endian for descriptor accesses.745*/746#ifdef AH_NEED_DESC_SWAP747mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;748#else749mask = INIT_CONFIG_STATUS |750AR_CFG_SWTD | AR_CFG_SWRD;751#endif752OS_REG_WRITE(ah, AR_CFG, mask);753} else754OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);755}756return rt;757}758759/*760* ar5312MacReset resets (and then un-resets) the specified761* wireless components.762* Note: The RCMask cannot be zero on entering from ar5312SetResetReg.763*/764765HAL_BOOL766ar5312MacReset(struct ath_hal *ah, unsigned int RCMask)767{768int wlanNum = AR5312_UNIT(ah);769uint32_t resetBB, resetBits, regMask;770uint32_t reg;771772if (RCMask == 0)773return(AH_FALSE);774#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317 )775if (IS_5315(ah)) {776switch(wlanNum) {777case 0:778resetBB = AR5315_RC_BB0_CRES | AR5315_RC_WBB0_RES;779/* Warm and cold reset bits for wbb */780resetBits = AR5315_RC_WMAC0_RES;781break;782case 1:783resetBB = AR5315_RC_BB1_CRES | AR5315_RC_WBB1_RES;784/* Warm and cold reset bits for wbb */785resetBits = AR5315_RC_WMAC1_RES;786break;787default:788return(AH_FALSE);789}790regMask = ~(resetBB | resetBits);791792/* read before */793reg = OS_REG_READ(ah,794(AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5315_RESET));795796if (RCMask == AR_RC_BB) {797/* Put baseband in reset */798reg |= resetBB; /* Cold and warm reset the baseband bits */799} else {800/*801* Reset the MAC and baseband. This is a bit different than802* the PCI version, but holding in reset causes problems.803*/804reg &= regMask;805reg |= (resetBits | resetBB) ;806}807OS_REG_WRITE(ah,808(AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET),809reg);810/* read after */811OS_REG_READ(ah,812(AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5315_RESET));813OS_DELAY(100);814815/* Bring MAC and baseband out of reset */816reg &= regMask;817/* read before */818OS_REG_READ(ah,819(AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET));820OS_REG_WRITE(ah,821(AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET),822reg);823/* read after */824OS_REG_READ(ah,825(AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET));826827}828else829#endif830{831switch(wlanNum) {832case 0:833resetBB = AR5312_RC_BB0_CRES | AR5312_RC_WBB0_RES;834/* Warm and cold reset bits for wbb */835resetBits = AR5312_RC_WMAC0_RES;836break;837case 1:838resetBB = AR5312_RC_BB1_CRES | AR5312_RC_WBB1_RES;839/* Warm and cold reset bits for wbb */840resetBits = AR5312_RC_WMAC1_RES;841break;842default:843return(AH_FALSE);844}845regMask = ~(resetBB | resetBits);846847/* read before */848reg = OS_REG_READ(ah,849(AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5312_RESET));850851if (RCMask == AR_RC_BB) {852/* Put baseband in reset */853reg |= resetBB; /* Cold and warm reset the baseband bits */854} else {855/*856* Reset the MAC and baseband. This is a bit different than857* the PCI version, but holding in reset causes problems.858*/859reg &= regMask;860reg |= (resetBits | resetBB) ;861}862OS_REG_WRITE(ah,863(AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET),864reg);865/* read after */866OS_REG_READ(ah,867(AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5312_RESET));868OS_DELAY(100);869870/* Bring MAC and baseband out of reset */871reg &= regMask;872/* read before */873OS_REG_READ(ah,874(AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET));875OS_REG_WRITE(ah,876(AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET),877reg);878/* read after */879OS_REG_READ(ah,880(AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET));881}882return(AH_TRUE);883}884885#endif /* AH_SUPPORT_AR5312 */886887888