1*6e778a7eSPedro F. Giffuni /*-
2*6e778a7eSPedro F. Giffuni * SPDX-License-Identifier: ISC
3*6e778a7eSPedro F. Giffuni *
459efa8b5SSam Leffler * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
514779705SSam Leffler * Copyright (c) 2002-2008 Atheros Communications, Inc.
614779705SSam Leffler *
714779705SSam Leffler * Permission to use, copy, modify, and/or distribute this software for any
814779705SSam Leffler * purpose with or without fee is hereby granted, provided that the above
914779705SSam Leffler * copyright notice and this permission notice appear in all copies.
1014779705SSam Leffler *
1114779705SSam Leffler * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1214779705SSam Leffler * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1314779705SSam Leffler * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1414779705SSam Leffler * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1514779705SSam Leffler * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1614779705SSam Leffler * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1714779705SSam Leffler * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1814779705SSam Leffler */
1914779705SSam Leffler #include "opt_ah.h"
2014779705SSam Leffler
2114779705SSam Leffler #ifdef AH_SUPPORT_AR5312
2214779705SSam Leffler
2314779705SSam Leffler #include "ah.h"
2414779705SSam Leffler #include "ah_internal.h"
2514779705SSam Leffler #include "ah_devid.h"
2614779705SSam Leffler
2714779705SSam Leffler #include "ar5312/ar5312.h"
2814779705SSam Leffler #include "ar5312/ar5312reg.h"
2914779705SSam Leffler #include "ar5312/ar5312phy.h"
3014779705SSam Leffler
3114779705SSam Leffler #include "ah_eeprom_v3.h"
3214779705SSam Leffler
3314779705SSam Leffler /* Additional Time delay to wait after activiting the Base band */
3414779705SSam Leffler #define BASE_ACTIVATE_DELAY 100 /* 100 usec */
3514779705SSam Leffler #define PLL_SETTLE_DELAY 300 /* 300 usec */
3614779705SSam Leffler
3759efa8b5SSam Leffler extern int16_t ar5212GetNf(struct ath_hal *, const struct ieee80211_channel *);
3859efa8b5SSam Leffler extern void ar5212SetRateDurationTable(struct ath_hal *,
3959efa8b5SSam Leffler const struct ieee80211_channel *);
4014779705SSam Leffler extern HAL_BOOL ar5212SetTransmitPower(struct ath_hal *ah,
4159efa8b5SSam Leffler const struct ieee80211_channel *chan, uint16_t *rfXpdGain);
4259efa8b5SSam Leffler extern void ar5212SetDeltaSlope(struct ath_hal *,
4359efa8b5SSam Leffler const struct ieee80211_channel *);
4459efa8b5SSam Leffler extern HAL_BOOL ar5212SetBoardValues(struct ath_hal *,
4559efa8b5SSam Leffler const struct ieee80211_channel *);
4659efa8b5SSam Leffler extern void ar5212SetIFSTiming(struct ath_hal *,
4759efa8b5SSam Leffler const struct ieee80211_channel *);
4859efa8b5SSam Leffler extern HAL_BOOL ar5212IsSpurChannel(struct ath_hal *,
4959efa8b5SSam Leffler const struct ieee80211_channel *);
5059efa8b5SSam Leffler extern HAL_BOOL ar5212ChannelChange(struct ath_hal *,
5159efa8b5SSam Leffler const struct ieee80211_channel *);
5214779705SSam Leffler
5314779705SSam Leffler static HAL_BOOL ar5312SetResetReg(struct ath_hal *, uint32_t resetMask);
5414779705SSam Leffler
5514779705SSam Leffler static int
write_common(struct ath_hal * ah,const HAL_INI_ARRAY * ia,HAL_BOOL bChannelChange,int writes)5614779705SSam Leffler write_common(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
5714779705SSam Leffler HAL_BOOL bChannelChange, int writes)
5814779705SSam Leffler {
5914779705SSam Leffler #define IS_NO_RESET_TIMER_ADDR(x) \
6014779705SSam Leffler ( (((x) >= AR_BEACON) && ((x) <= AR_CFP_DUR)) || \
6114779705SSam Leffler (((x) >= AR_SLEEP1) && ((x) <= AR_SLEEP3)))
6214779705SSam Leffler #define V(r, c) (ia)->data[((r)*(ia)->cols) + (c)]
6314779705SSam Leffler int i;
6414779705SSam Leffler
6514779705SSam Leffler /* Write Common Array Parameters */
6614779705SSam Leffler for (i = 0; i < ia->rows; i++) {
6714779705SSam Leffler uint32_t reg = V(i, 0);
6814779705SSam Leffler /* XXX timer/beacon setup registers? */
6914779705SSam Leffler /* On channel change, don't reset the PCU registers */
7014779705SSam Leffler if (!(bChannelChange && IS_NO_RESET_TIMER_ADDR(reg))) {
7114779705SSam Leffler OS_REG_WRITE(ah, reg, V(i, 1));
7214779705SSam Leffler DMA_YIELD(writes);
7314779705SSam Leffler }
7414779705SSam Leffler }
7514779705SSam Leffler return writes;
7614779705SSam Leffler #undef IS_NO_RESET_TIMER_ADDR
7714779705SSam Leffler #undef V
7814779705SSam Leffler }
7914779705SSam Leffler
8014779705SSam Leffler /*
8114779705SSam Leffler * Places the device in and out of reset and then places sane
8214779705SSam Leffler * values in the registers based on EEPROM config, initialization
8314779705SSam Leffler * vectors (as determined by the mode), and station configuration
8414779705SSam Leffler *
8514779705SSam Leffler * bChannelChange is used to preserve DMA/PCU registers across
8614779705SSam Leffler * a HW Reset during channel change.
8714779705SSam Leffler */
8814779705SSam Leffler HAL_BOOL
ar5312Reset(struct ath_hal * ah,HAL_OPMODE opmode,struct ieee80211_channel * chan,HAL_BOOL bChannelChange,HAL_RESET_TYPE resetType,HAL_STATUS * status)8914779705SSam Leffler ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode,
9059efa8b5SSam Leffler struct ieee80211_channel *chan,
91f50e4ebfSAdrian Chadd HAL_BOOL bChannelChange,
92f50e4ebfSAdrian Chadd HAL_RESET_TYPE resetType,
93f50e4ebfSAdrian Chadd HAL_STATUS *status)
9414779705SSam Leffler {
9514779705SSam Leffler #define N(a) (sizeof (a) / sizeof (a[0]))
9614779705SSam Leffler #define FAIL(_code) do { ecode = _code; goto bad; } while (0)
9714779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
9814779705SSam Leffler HAL_CHANNEL_INTERNAL *ichan;
9914779705SSam Leffler const HAL_EEPROM *ee;
10014779705SSam Leffler uint32_t saveFrameSeqCount, saveDefAntenna;
10114779705SSam Leffler uint32_t macStaId1, synthDelay, txFrm2TxDStart;
10214779705SSam Leffler uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL];
10314779705SSam Leffler int16_t cckOfdmPwrDelta = 0;
10414779705SSam Leffler u_int modesIndex, freqIndex;
10514779705SSam Leffler HAL_STATUS ecode;
10614779705SSam Leffler int i, regWrites = 0;
10714779705SSam Leffler uint32_t testReg;
10814779705SSam Leffler uint32_t saveLedState = 0;
10914779705SSam Leffler
11014779705SSam Leffler HALASSERT(ah->ah_magic == AR5212_MAGIC);
11114779705SSam Leffler ee = AH_PRIVATE(ah)->ah_eeprom;
11214779705SSam Leffler
11314779705SSam Leffler OS_MARK(ah, AH_MARK_RESET, bChannelChange);
11414779705SSam Leffler /*
11514779705SSam Leffler * Map public channel to private.
11614779705SSam Leffler */
11714779705SSam Leffler ichan = ath_hal_checkchannel(ah, chan);
11814779705SSam Leffler if (ichan == AH_NULL) {
11914779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
12014779705SSam Leffler "%s: invalid channel %u/0x%x; no mapping\n",
12159efa8b5SSam Leffler __func__, chan->ic_freq, chan->ic_flags);
12214779705SSam Leffler FAIL(HAL_EINVAL);
12314779705SSam Leffler }
12414779705SSam Leffler switch (opmode) {
12514779705SSam Leffler case HAL_M_STA:
12614779705SSam Leffler case HAL_M_IBSS:
12714779705SSam Leffler case HAL_M_HOSTAP:
12814779705SSam Leffler case HAL_M_MONITOR:
12914779705SSam Leffler break;
13014779705SSam Leffler default:
13114779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n",
13214779705SSam Leffler __func__, opmode);
13314779705SSam Leffler FAIL(HAL_EINVAL);
13414779705SSam Leffler break;
13514779705SSam Leffler }
13614779705SSam Leffler HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3);
13714779705SSam Leffler
13814779705SSam Leffler /* Preserve certain DMA hardware registers on a channel change */
13914779705SSam Leffler if (bChannelChange) {
14014779705SSam Leffler /*
14114779705SSam Leffler * On Venice, the TSF is almost preserved across a reset;
14214779705SSam Leffler * it requires the doubling writes to the RESET_TSF
14314779705SSam Leffler * bit in the AR_BEACON register; it also has the quirk
14414779705SSam Leffler * of the TSF going back in time on the station (station
14514779705SSam Leffler * latches onto the last beacon's tsf during a reset 50%
14614779705SSam Leffler * of the times); the latter is not a problem for adhoc
14714779705SSam Leffler * stations since as long as the TSF is behind, it will
14814779705SSam Leffler * get resynchronized on receiving the next beacon; the
14914779705SSam Leffler * TSF going backwards in time could be a problem for the
15014779705SSam Leffler * sleep operation (supported on infrastructure stations
15114779705SSam Leffler * only) - the best and most general fix for this situation
15214779705SSam Leffler * is to resynchronize the various sleep/beacon timers on
15314779705SSam Leffler * the receipt of the next beacon i.e. when the TSF itself
15414779705SSam Leffler * gets resynchronized to the AP's TSF - power save is
15514779705SSam Leffler * needed to be temporarily disabled until that time
15614779705SSam Leffler *
15714779705SSam Leffler * Need to save the sequence number to restore it after
15814779705SSam Leffler * the reset!
15914779705SSam Leffler */
16014779705SSam Leffler saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM);
16114779705SSam Leffler } else
16214779705SSam Leffler saveFrameSeqCount = 0; /* NB: silence compiler */
16314779705SSam Leffler
16414779705SSam Leffler /* If the channel change is across the same mode - perform a fast channel change */
16514779705SSam Leffler if ((IS_2413(ah) || IS_5413(ah))) {
16614779705SSam Leffler /*
16714779705SSam Leffler * Channel change can only be used when:
16814779705SSam Leffler * -channel change requested - so it's not the initial reset.
16914779705SSam Leffler * -it's not a change to the current channel - often called when switching modes
17014779705SSam Leffler * on a channel
17114779705SSam Leffler * -the modes of the previous and requested channel are the same - some ugly code for XR
17214779705SSam Leffler */
17314779705SSam Leffler if (bChannelChange &&
17459efa8b5SSam Leffler AH_PRIVATE(ah)->ah_curchan != AH_NULL &&
17559efa8b5SSam Leffler (chan->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) &&
17659efa8b5SSam Leffler ((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) ==
17759efa8b5SSam Leffler (AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) {
17814779705SSam Leffler if (ar5212ChannelChange(ah, chan))
17914779705SSam Leffler /* If ChannelChange completed - skip the rest of reset */
18014779705SSam Leffler return AH_TRUE;
18114779705SSam Leffler }
18214779705SSam Leffler }
18314779705SSam Leffler
18414779705SSam Leffler /*
18514779705SSam Leffler * Preserve the antenna on a channel change
18614779705SSam Leffler */
18714779705SSam Leffler saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);
18814779705SSam Leffler if (saveDefAntenna == 0) /* XXX magic constants */
18914779705SSam Leffler saveDefAntenna = 1;
19014779705SSam Leffler
19114779705SSam Leffler /* Save hardware flag before chip reset clears the register */
19214779705SSam Leffler macStaId1 = OS_REG_READ(ah, AR_STA_ID1) &
19314779705SSam Leffler (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT);
19414779705SSam Leffler
19514779705SSam Leffler /* Save led state from pci config register */
19614779705SSam Leffler if (!IS_5315(ah))
19714779705SSam Leffler saveLedState = OS_REG_READ(ah, AR5312_PCICFG) &
19814779705SSam Leffler (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK |
19914779705SSam Leffler AR_PCICFG_LEDSLOW);
20014779705SSam Leffler
20114779705SSam Leffler ar5312RestoreClock(ah, opmode); /* move to refclk operation */
20214779705SSam Leffler
20314779705SSam Leffler /*
20414779705SSam Leffler * Adjust gain parameters before reset if
20514779705SSam Leffler * there's an outstanding gain updated.
20614779705SSam Leffler */
20714779705SSam Leffler (void) ar5212GetRfgain(ah);
20814779705SSam Leffler
20914779705SSam Leffler if (!ar5312ChipReset(ah, chan)) {
21014779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);
21114779705SSam Leffler FAIL(HAL_EIO);
21214779705SSam Leffler }
21314779705SSam Leffler
21414779705SSam Leffler /* Setup the indices for the next set of register array writes */
21559efa8b5SSam Leffler if (IEEE80211_IS_CHAN_2GHZ(chan)) {
21659efa8b5SSam Leffler freqIndex = 2;
21759efa8b5SSam Leffler modesIndex = IEEE80211_IS_CHAN_108G(chan) ? 5 :
21859efa8b5SSam Leffler IEEE80211_IS_CHAN_G(chan) ? 4 : 3;
21959efa8b5SSam Leffler } else {
22014779705SSam Leffler freqIndex = 1;
22159efa8b5SSam Leffler modesIndex = IEEE80211_IS_CHAN_ST(chan) ? 2 : 1;
22214779705SSam Leffler }
22314779705SSam Leffler
22414779705SSam Leffler OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
22514779705SSam Leffler
22614779705SSam Leffler /* Set correct Baseband to analog shift setting to access analog chips. */
22714779705SSam Leffler OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
22814779705SSam Leffler
22914779705SSam Leffler regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0);
23014779705SSam Leffler regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange,
23114779705SSam Leffler regWrites);
23214779705SSam Leffler ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites);
23314779705SSam Leffler
23414779705SSam Leffler OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
23514779705SSam Leffler
23659efa8b5SSam Leffler if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))
23714779705SSam Leffler ar5212SetIFSTiming(ah, chan);
23814779705SSam Leffler
23914779705SSam Leffler /* Overwrite INI values for revised chipsets */
24014779705SSam Leffler if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) {
24114779705SSam Leffler /* ADC_CTL */
24214779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_ADC_CTL,
24314779705SSam Leffler SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) |
24414779705SSam Leffler SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) |
24514779705SSam Leffler AR_PHY_ADC_CTL_OFF_PWDDAC |
24614779705SSam Leffler AR_PHY_ADC_CTL_OFF_PWDADC);
24714779705SSam Leffler
24814779705SSam Leffler /* TX_PWR_ADJ */
24914779705SSam Leffler if (chan->channel == 2484) {
25014779705SSam Leffler cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta);
25114779705SSam Leffler } else {
25214779705SSam Leffler cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta);
25314779705SSam Leffler }
25414779705SSam Leffler
25559efa8b5SSam Leffler if (IEEE80211_IS_CHAN_G(chan)) {
25614779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_TXPWRADJ,
25714779705SSam Leffler SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) |
25814779705SSam Leffler SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX));
25914779705SSam Leffler } else {
26014779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0);
26114779705SSam Leffler }
26214779705SSam Leffler
26314779705SSam Leffler /* Add barker RSSI thresh enable as disabled */
26414779705SSam Leffler OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK,
26514779705SSam Leffler AR_PHY_DAG_CTRLCCK_EN_RSSI_THR);
26614779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK,
26714779705SSam Leffler AR_PHY_DAG_CTRLCCK_RSSI_THR, 2);
26814779705SSam Leffler
26914779705SSam Leffler /* Set the mute mask to the correct default */
27014779705SSam Leffler OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F);
27114779705SSam Leffler }
27214779705SSam Leffler
27314779705SSam Leffler if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) {
27414779705SSam Leffler /* Clear reg to alllow RX_CLEAR line debug */
27514779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0);
27614779705SSam Leffler }
27714779705SSam Leffler if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) {
27814779705SSam Leffler #ifdef notyet
27914779705SSam Leffler /* Enable burst prefetch for the data queues */
28014779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... );
28114779705SSam Leffler /* Enable double-buffering */
28214779705SSam Leffler OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS);
28314779705SSam Leffler #endif
28414779705SSam Leffler }
28514779705SSam Leffler
28614779705SSam Leffler if (IS_5312_2_X(ah)) {
28714779705SSam Leffler /* ADC_CTRL */
28814779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA,
28914779705SSam Leffler SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) |
29014779705SSam Leffler SM(4, AR_PHY_SIGMA_DELTA_FILT2) |
29114779705SSam Leffler SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) |
29214779705SSam Leffler SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP));
29314779705SSam Leffler
29459efa8b5SSam Leffler if (IEEE80211_IS_CHAN_2GHZ(chan))
29514779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F);
29614779705SSam Leffler
29714779705SSam Leffler /* CCK Short parameter adjustment in 11B mode */
29859efa8b5SSam Leffler if (IEEE80211_IS_CHAN_B(chan))
29914779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12);
30014779705SSam Leffler
30114779705SSam Leffler /* Set ADC/DAC select values */
30214779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04);
30314779705SSam Leffler
30414779705SSam Leffler /* Increase 11A AGC Settling */
30559efa8b5SSam Leffler if (IEEE80211_IS_CHAN_A(chan))
30614779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32);
30714779705SSam Leffler } else {
30814779705SSam Leffler /* Set ADC/DAC select values */
30914779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
31014779705SSam Leffler }
31114779705SSam Leffler
31214779705SSam Leffler /* Setup the transmit power values. */
31359efa8b5SSam Leffler if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) {
31414779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
31514779705SSam Leffler "%s: error init'ing transmit power\n", __func__);
31614779705SSam Leffler FAIL(HAL_EIO);
31714779705SSam Leffler }
31814779705SSam Leffler
31914779705SSam Leffler /* Write the analog registers */
32059efa8b5SSam Leffler if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) {
32114779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n",
32214779705SSam Leffler __func__);
32314779705SSam Leffler FAIL(HAL_EIO);
32414779705SSam Leffler }
32514779705SSam Leffler
32614779705SSam Leffler /* Write delta slope for OFDM enabled modes (A, G, Turbo) */
32759efa8b5SSam Leffler if (IEEE80211_IS_CHAN_OFDM(chan)) {
32859efa8b5SSam Leffler if (IS_5413(ah) ||
32959efa8b5SSam Leffler AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3)
33059efa8b5SSam Leffler ar5212SetSpurMitigation(ah, chan);
33114779705SSam Leffler ar5212SetDeltaSlope(ah, chan);
33214779705SSam Leffler }
33314779705SSam Leffler
33414779705SSam Leffler /* Setup board specific options for EEPROM version 3 */
33559efa8b5SSam Leffler if (!ar5212SetBoardValues(ah, chan)) {
33614779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
33714779705SSam Leffler "%s: error setting board options\n", __func__);
33814779705SSam Leffler FAIL(HAL_EIO);
33914779705SSam Leffler }
34014779705SSam Leffler
34114779705SSam Leffler /* Restore certain DMA hardware registers on a channel change */
34214779705SSam Leffler if (bChannelChange)
34314779705SSam Leffler OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount);
34414779705SSam Leffler
34514779705SSam Leffler OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
34614779705SSam Leffler
34714779705SSam Leffler OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));
34814779705SSam Leffler OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)
34914779705SSam Leffler | macStaId1
35014779705SSam Leffler | AR_STA_ID1_RTS_USE_DEF
35114779705SSam Leffler | ahp->ah_staId1Defaults
35214779705SSam Leffler );
35314779705SSam Leffler ar5212SetOperatingMode(ah, opmode);
35414779705SSam Leffler
35514779705SSam Leffler /* Set Venice BSSID mask according to current state */
35614779705SSam Leffler OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));
35714779705SSam Leffler OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));
35814779705SSam Leffler
35914779705SSam Leffler /* Restore previous led state */
36014779705SSam Leffler if (!IS_5315(ah))
36114779705SSam Leffler OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState);
36214779705SSam Leffler
36314779705SSam Leffler /* Restore previous antenna */
36414779705SSam Leffler OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
36514779705SSam Leffler
36614779705SSam Leffler /* then our BSSID */
36714779705SSam Leffler OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
36814779705SSam Leffler OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4));
36914779705SSam Leffler
37014779705SSam Leffler /* Restore bmiss rssi & count thresholds */
37114779705SSam Leffler OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
37214779705SSam Leffler
37314779705SSam Leffler OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */
37414779705SSam Leffler
37559efa8b5SSam Leffler if (!ar5212SetChannel(ah, chan))
37614779705SSam Leffler FAIL(HAL_EIO);
37714779705SSam Leffler
37814779705SSam Leffler OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
37914779705SSam Leffler
38014779705SSam Leffler ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1);
38114779705SSam Leffler
38214779705SSam Leffler ar5212SetRateDurationTable(ah, chan);
38314779705SSam Leffler
38414779705SSam Leffler /* Set Tx frame start to tx data start delay */
38514779705SSam Leffler if (IS_RAD5112_ANY(ah) &&
38659efa8b5SSam Leffler (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) {
38714779705SSam Leffler txFrm2TxDStart =
38859efa8b5SSam Leffler IEEE80211_IS_CHAN_HALF(chan) ?
38914779705SSam Leffler TX_FRAME_D_START_HALF_RATE:
39014779705SSam Leffler TX_FRAME_D_START_QUARTER_RATE;
39114779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL,
39214779705SSam Leffler AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart);
39314779705SSam Leffler }
39414779705SSam Leffler
39514779705SSam Leffler /*
39614779705SSam Leffler * Setup fast diversity.
39714779705SSam Leffler * Fast diversity can be enabled or disabled via regadd.txt.
39814779705SSam Leffler * Default is enabled.
39914779705SSam Leffler * For reference,
40014779705SSam Leffler * Disable: reg val
40114779705SSam Leffler * 0x00009860 0x00009d18 (if 11a / 11g, else no change)
40214779705SSam Leffler * 0x00009970 0x192bb514
40314779705SSam Leffler * 0x0000a208 0xd03e4648
40414779705SSam Leffler *
40514779705SSam Leffler * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change)
40614779705SSam Leffler * 0x00009970 0x192fb514
40714779705SSam Leffler * 0x0000a208 0xd03e6788
40814779705SSam Leffler */
40914779705SSam Leffler
41014779705SSam Leffler /* XXX Setup pre PHY ENABLE EAR additions */
41114779705SSam Leffler
41214779705SSam Leffler /* flush SCAL reg */
41314779705SSam Leffler if (IS_5312_2_X(ah)) {
41414779705SSam Leffler (void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL);
41514779705SSam Leffler }
41614779705SSam Leffler
41714779705SSam Leffler /*
41814779705SSam Leffler * Wait for the frequency synth to settle (synth goes on
41914779705SSam Leffler * via AR_PHY_ACTIVE_EN). Read the phy active delay register.
42014779705SSam Leffler * Value is in 100ns increments.
42114779705SSam Leffler */
42214779705SSam Leffler synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
42359efa8b5SSam Leffler if (IEEE80211_IS_CHAN_B(chan)) {
42414779705SSam Leffler synthDelay = (4 * synthDelay) / 22;
42514779705SSam Leffler } else {
42614779705SSam Leffler synthDelay /= 10;
42714779705SSam Leffler }
42814779705SSam Leffler
42914779705SSam Leffler /* Activate the PHY (includes baseband activate and synthesizer on) */
43014779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
43114779705SSam Leffler
43214779705SSam Leffler /*
43314779705SSam Leffler * There is an issue if the AP starts the calibration before
43414779705SSam Leffler * the base band timeout completes. This could result in the
43514779705SSam Leffler * rx_clear false triggering. As a workaround we add delay an
43614779705SSam Leffler * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
43714779705SSam Leffler * does not happen.
43814779705SSam Leffler */
43959efa8b5SSam Leffler if (IEEE80211_IS_CHAN_HALF(chan)) {
44014779705SSam Leffler OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY);
44159efa8b5SSam Leffler } else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
44214779705SSam Leffler OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY);
44314779705SSam Leffler } else {
44414779705SSam Leffler OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);
44514779705SSam Leffler }
44614779705SSam Leffler
44714779705SSam Leffler /*
44814779705SSam Leffler * The udelay method is not reliable with notebooks.
44914779705SSam Leffler * Need to check to see if the baseband is ready
45014779705SSam Leffler */
45114779705SSam Leffler testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL);
45214779705SSam Leffler /* Selects the Tx hold */
45314779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD);
45414779705SSam Leffler i = 0;
45514779705SSam Leffler while ((i++ < 20) &&
45614779705SSam Leffler (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200);
45714779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg);
45814779705SSam Leffler
45914779705SSam Leffler /* Calibrate the AGC and start a NF calculation */
46014779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
46114779705SSam Leffler OS_REG_READ(ah, AR_PHY_AGC_CONTROL)
46214779705SSam Leffler | AR_PHY_AGC_CONTROL_CAL
46314779705SSam Leffler | AR_PHY_AGC_CONTROL_NF);
46414779705SSam Leffler
46559efa8b5SSam Leffler if (!IEEE80211_IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) {
46614779705SSam Leffler /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */
46714779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,
46814779705SSam Leffler AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
46914779705SSam Leffler INIT_IQCAL_LOG_COUNT_MAX);
47014779705SSam Leffler OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,
47114779705SSam Leffler AR_PHY_TIMING_CTRL4_DO_IQCAL);
47214779705SSam Leffler ahp->ah_bIQCalibration = IQ_CAL_RUNNING;
47314779705SSam Leffler } else
47414779705SSam Leffler ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;
47514779705SSam Leffler
47614779705SSam Leffler /* Setup compression registers */
47714779705SSam Leffler ar5212SetCompRegs(ah);
47814779705SSam Leffler
47914779705SSam Leffler /* Set 1:1 QCU to DCU mapping for all queues */
48014779705SSam Leffler for (i = 0; i < AR_NUM_DCU; i++)
48114779705SSam Leffler OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
48214779705SSam Leffler
48314779705SSam Leffler ahp->ah_intrTxqs = 0;
48414779705SSam Leffler for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++)
48514779705SSam Leffler ar5212ResetTxQueue(ah, i);
48614779705SSam Leffler
48714779705SSam Leffler /*
48814779705SSam Leffler * Setup interrupt handling. Note that ar5212ResetTxQueue
48914779705SSam Leffler * manipulates the secondary IMR's as queues are enabled
49014779705SSam Leffler * and disabled. This is done with RMW ops to insure the
49114779705SSam Leffler * settings we make here are preserved.
49214779705SSam Leffler */
49314779705SSam Leffler ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN
49414779705SSam Leffler | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN
49514779705SSam Leffler | AR_IMR_HIUERR
49614779705SSam Leffler ;
49714779705SSam Leffler if (opmode == HAL_M_HOSTAP)
49814779705SSam Leffler ahp->ah_maskReg |= AR_IMR_MIB;
49914779705SSam Leffler OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
50014779705SSam Leffler /* Enable bus errors that are OR'd to set the HIUERR bit */
50114779705SSam Leffler OS_REG_WRITE(ah, AR_IMR_S2,
50214779705SSam Leffler OS_REG_READ(ah, AR_IMR_S2)
50314779705SSam Leffler | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR);
50414779705SSam Leffler
50514779705SSam Leffler if (AH_PRIVATE(ah)->ah_rfkillEnabled)
50614779705SSam Leffler ar5212EnableRfKill(ah);
50714779705SSam Leffler
50814779705SSam Leffler if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
50914779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
51014779705SSam Leffler "%s: offset calibration failed to complete in 1ms;"
51114779705SSam Leffler " noisy environment?\n", __func__);
51214779705SSam Leffler }
51314779705SSam Leffler
51414779705SSam Leffler /*
51514779705SSam Leffler * Set clocks back to 32kHz if they had been using refClk, then
51614779705SSam Leffler * use an external 32kHz crystal when sleeping, if one exists.
51714779705SSam Leffler */
51814779705SSam Leffler ar5312SetupClock(ah, opmode);
51914779705SSam Leffler
52014779705SSam Leffler /*
52114779705SSam Leffler * Writing to AR_BEACON will start timers. Hence it should
52214779705SSam Leffler * be the last register to be written. Do not reset tsf, do
52314779705SSam Leffler * not enable beacons at this point, but preserve other values
52414779705SSam Leffler * like beaconInterval.
52514779705SSam Leffler */
52614779705SSam Leffler OS_REG_WRITE(ah, AR_BEACON,
52714779705SSam Leffler (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF)));
52814779705SSam Leffler
52914779705SSam Leffler /* XXX Setup post reset EAR additions */
53014779705SSam Leffler
53114779705SSam Leffler /* QoS support */
53214779705SSam Leffler if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE ||
53314779705SSam Leffler (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE &&
53414779705SSam Leffler AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) {
53514779705SSam Leffler OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */
53614779705SSam Leffler OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */
53714779705SSam Leffler }
53814779705SSam Leffler
53914779705SSam Leffler /* Turn on NOACK Support for QoS packets */
54014779705SSam Leffler OS_REG_WRITE(ah, AR_NOACK,
54114779705SSam Leffler SM(2, AR_NOACK_2BIT_VALUE) |
54214779705SSam Leffler SM(5, AR_NOACK_BIT_OFFSET) |
54314779705SSam Leffler SM(0, AR_NOACK_BYTE_OFFSET));
54414779705SSam Leffler
54514779705SSam Leffler /* Restore user-specified settings */
54614779705SSam Leffler if (ahp->ah_miscMode != 0)
54714779705SSam Leffler OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);
54814779705SSam Leffler if (ahp->ah_slottime != (u_int) -1)
54914779705SSam Leffler ar5212SetSlotTime(ah, ahp->ah_slottime);
55014779705SSam Leffler if (ahp->ah_acktimeout != (u_int) -1)
55114779705SSam Leffler ar5212SetAckTimeout(ah, ahp->ah_acktimeout);
55214779705SSam Leffler if (ahp->ah_ctstimeout != (u_int) -1)
55314779705SSam Leffler ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout);
55414779705SSam Leffler if (ahp->ah_sifstime != (u_int) -1)
55514779705SSam Leffler ar5212SetSifsTime(ah, ahp->ah_sifstime);
55614779705SSam Leffler if (AH_PRIVATE(ah)->ah_diagreg != 0)
55714779705SSam Leffler OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
55814779705SSam Leffler
55914779705SSam Leffler AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */
56014779705SSam Leffler
56159efa8b5SSam Leffler if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan))
56259efa8b5SSam Leffler chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;
56314779705SSam Leffler
56414779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__);
56514779705SSam Leffler
56614779705SSam Leffler OS_MARK(ah, AH_MARK_RESET_DONE, 0);
56714779705SSam Leffler
56814779705SSam Leffler return AH_TRUE;
56914779705SSam Leffler bad:
57014779705SSam Leffler OS_MARK(ah, AH_MARK_RESET_DONE, ecode);
5718698ea65SSam Leffler if (status != AH_NULL)
57214779705SSam Leffler *status = ecode;
57314779705SSam Leffler return AH_FALSE;
57414779705SSam Leffler #undef FAIL
57514779705SSam Leffler #undef N
57614779705SSam Leffler }
57714779705SSam Leffler
57814779705SSam Leffler /*
57914779705SSam Leffler * Places the PHY and Radio chips into reset. A full reset
58014779705SSam Leffler * must be called to leave this state. The PCI/MAC/PCU are
58114779705SSam Leffler * not placed into reset as we must receive interrupt to
58214779705SSam Leffler * re-enable the hardware.
58314779705SSam Leffler */
58414779705SSam Leffler HAL_BOOL
ar5312PhyDisable(struct ath_hal * ah)58514779705SSam Leffler ar5312PhyDisable(struct ath_hal *ah)
58614779705SSam Leffler {
58714779705SSam Leffler return ar5312SetResetReg(ah, AR_RC_BB);
58814779705SSam Leffler }
58914779705SSam Leffler
59014779705SSam Leffler /*
59114779705SSam Leffler * Places all of hardware into reset
59214779705SSam Leffler */
59314779705SSam Leffler HAL_BOOL
ar5312Disable(struct ath_hal * ah)59414779705SSam Leffler ar5312Disable(struct ath_hal *ah)
59514779705SSam Leffler {
59614779705SSam Leffler if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
59714779705SSam Leffler return AH_FALSE;
59814779705SSam Leffler /*
59914779705SSam Leffler * Reset the HW - PCI must be reset after the rest of the
60014779705SSam Leffler * device has been reset.
60114779705SSam Leffler */
60214779705SSam Leffler return ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB);
60314779705SSam Leffler }
60414779705SSam Leffler
60514779705SSam Leffler /*
60614779705SSam Leffler * Places the hardware into reset and then pulls it out of reset
60714779705SSam Leffler *
60814779705SSam Leffler * TODO: Only write the PLL if we're changing to or from CCK mode
60914779705SSam Leffler *
61014779705SSam Leffler * WARNING: The order of the PLL and mode registers must be correct.
61114779705SSam Leffler */
61214779705SSam Leffler HAL_BOOL
ar5312ChipReset(struct ath_hal * ah,const struct ieee80211_channel * chan)61359efa8b5SSam Leffler ar5312ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan)
61414779705SSam Leffler {
61514779705SSam Leffler
61659efa8b5SSam Leffler OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);
61714779705SSam Leffler
61814779705SSam Leffler /*
61914779705SSam Leffler * Reset the HW
62014779705SSam Leffler */
62114779705SSam Leffler if (!ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB)) {
62214779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
62314779705SSam Leffler __func__);
62414779705SSam Leffler return AH_FALSE;
62514779705SSam Leffler }
62614779705SSam Leffler
62714779705SSam Leffler /* Bring out of sleep mode (AGAIN) */
62814779705SSam Leffler if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {
62914779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetPowerMode failed\n",
63014779705SSam Leffler __func__);
63114779705SSam Leffler return AH_FALSE;
63214779705SSam Leffler }
63314779705SSam Leffler
63414779705SSam Leffler /* Clear warm reset register */
63514779705SSam Leffler if (!ar5312SetResetReg(ah, 0)) {
63614779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
63714779705SSam Leffler __func__);
63814779705SSam Leffler return AH_FALSE;
63914779705SSam Leffler }
64014779705SSam Leffler
64114779705SSam Leffler /*
64214779705SSam Leffler * Perform warm reset before the mode/PLL/turbo registers
64314779705SSam Leffler * are changed in order to deactivate the radio. Mode changes
64414779705SSam Leffler * with an active radio can result in corrupted shifts to the
64514779705SSam Leffler * radio device.
64614779705SSam Leffler */
64714779705SSam Leffler
64814779705SSam Leffler /*
64914779705SSam Leffler * Set CCK and Turbo modes correctly.
65014779705SSam Leffler */
65114779705SSam Leffler if (chan != AH_NULL) { /* NB: can be null during attach */
65214779705SSam Leffler uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo;
65314779705SSam Leffler
65414779705SSam Leffler if (IS_RAD5112_ANY(ah)) {
65514779705SSam Leffler rfMode = AR_PHY_MODE_AR5112;
65614779705SSam Leffler if (!IS_5315(ah)) {
65759efa8b5SSam Leffler if (IEEE80211_IS_CHAN_CCK(chan)) {
65814779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_44_5312;
65914779705SSam Leffler } else {
66059efa8b5SSam Leffler if (IEEE80211_IS_CHAN_HALF(chan)) {
66114779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_40_5312_HALF;
66259efa8b5SSam Leffler } else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
66314779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_40_5312_QUARTER;
66414779705SSam Leffler } else {
66514779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_40_5312;
66614779705SSam Leffler }
66714779705SSam Leffler }
66814779705SSam Leffler } else {
66959efa8b5SSam Leffler if (IEEE80211_IS_CHAN_CCK(chan))
67014779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_44_5112;
67114779705SSam Leffler else
67214779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_40_5112;
67359efa8b5SSam Leffler if (IEEE80211_IS_CHAN_HALF(chan))
67414779705SSam Leffler phyPLL |= AR_PHY_PLL_CTL_HALF;
67559efa8b5SSam Leffler else if (IEEE80211_IS_CHAN_QUARTER(chan))
67614779705SSam Leffler phyPLL |= AR_PHY_PLL_CTL_QUARTER;
67714779705SSam Leffler }
67814779705SSam Leffler } else {
67914779705SSam Leffler rfMode = AR_PHY_MODE_AR5111;
68059efa8b5SSam Leffler if (IEEE80211_IS_CHAN_CCK(chan))
68114779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_44;
68214779705SSam Leffler else
68314779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_40;
68459efa8b5SSam Leffler if (IEEE80211_IS_CHAN_HALF(chan))
68514779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_HALF;
68659efa8b5SSam Leffler else if (IEEE80211_IS_CHAN_QUARTER(chan))
68714779705SSam Leffler phyPLL = AR_PHY_PLL_CTL_QUARTER;
68814779705SSam Leffler }
68959efa8b5SSam Leffler if (IEEE80211_IS_CHAN_G(chan))
69014779705SSam Leffler rfMode |= AR_PHY_MODE_DYNAMIC;
69159efa8b5SSam Leffler else if (IEEE80211_IS_CHAN_OFDM(chan))
69214779705SSam Leffler rfMode |= AR_PHY_MODE_OFDM;
69314779705SSam Leffler else
69414779705SSam Leffler rfMode |= AR_PHY_MODE_CCK;
69559efa8b5SSam Leffler if (IEEE80211_IS_CHAN_5GHZ(chan))
69614779705SSam Leffler rfMode |= AR_PHY_MODE_RF5GHZ;
69714779705SSam Leffler else
69814779705SSam Leffler rfMode |= AR_PHY_MODE_RF2GHZ;
69959efa8b5SSam Leffler turbo = IEEE80211_IS_CHAN_TURBO(chan) ?
70014779705SSam Leffler (AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0;
70114779705SSam Leffler curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL);
70214779705SSam Leffler /*
70314779705SSam Leffler * PLL, Mode, and Turbo values must be written in the correct
70414779705SSam Leffler * order to ensure:
70514779705SSam Leffler * - The PLL cannot be set to 44 unless the CCK or DYNAMIC
70614779705SSam Leffler * mode bit is set
70714779705SSam Leffler * - Turbo cannot be set at the same time as CCK or DYNAMIC
70814779705SSam Leffler */
70959efa8b5SSam Leffler if (IEEE80211_IS_CHAN_CCK(chan)) {
71014779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
71114779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
71214779705SSam Leffler if (curPhyPLL != phyPLL) {
71314779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL);
71414779705SSam Leffler /* Wait for the PLL to settle */
71514779705SSam Leffler OS_DELAY(PLL_SETTLE_DELAY);
71614779705SSam Leffler }
71714779705SSam Leffler } else {
71814779705SSam Leffler if (curPhyPLL != phyPLL) {
71914779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL);
72014779705SSam Leffler /* Wait for the PLL to settle */
72114779705SSam Leffler OS_DELAY(PLL_SETTLE_DELAY);
72214779705SSam Leffler }
72314779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
72414779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
72514779705SSam Leffler }
72614779705SSam Leffler }
72714779705SSam Leffler return AH_TRUE;
72814779705SSam Leffler }
72914779705SSam Leffler
73014779705SSam Leffler /*
73114779705SSam Leffler * Write the given reset bit mask into the reset register
73214779705SSam Leffler */
73314779705SSam Leffler static HAL_BOOL
ar5312SetResetReg(struct ath_hal * ah,uint32_t resetMask)73414779705SSam Leffler ar5312SetResetReg(struct ath_hal *ah, uint32_t resetMask)
73514779705SSam Leffler {
73614779705SSam Leffler uint32_t mask = resetMask ? resetMask : ~0;
73714779705SSam Leffler HAL_BOOL rt;
73814779705SSam Leffler
73914779705SSam Leffler if ((rt = ar5312MacReset(ah, mask)) == AH_FALSE) {
74014779705SSam Leffler return rt;
74114779705SSam Leffler }
74214779705SSam Leffler if ((resetMask & AR_RC_MAC) == 0) {
74314779705SSam Leffler if (isBigEndian()) {
74414779705SSam Leffler /*
745a47f39daSAdrian Chadd * Set CFG, little-endian for descriptor accesses.
74614779705SSam Leffler */
74714779705SSam Leffler #ifdef AH_NEED_DESC_SWAP
74814779705SSam Leffler mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;
74914779705SSam Leffler #else
75014779705SSam Leffler mask = INIT_CONFIG_STATUS |
75114779705SSam Leffler AR_CFG_SWTD | AR_CFG_SWRD;
75214779705SSam Leffler #endif
75314779705SSam Leffler OS_REG_WRITE(ah, AR_CFG, mask);
75414779705SSam Leffler } else
75514779705SSam Leffler OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);
75614779705SSam Leffler }
75714779705SSam Leffler return rt;
75814779705SSam Leffler }
75914779705SSam Leffler
76014779705SSam Leffler /*
76114779705SSam Leffler * ar5312MacReset resets (and then un-resets) the specified
76214779705SSam Leffler * wireless components.
76314779705SSam Leffler * Note: The RCMask cannot be zero on entering from ar5312SetResetReg.
76414779705SSam Leffler */
76514779705SSam Leffler
76614779705SSam Leffler HAL_BOOL
ar5312MacReset(struct ath_hal * ah,unsigned int RCMask)76714779705SSam Leffler ar5312MacReset(struct ath_hal *ah, unsigned int RCMask)
76814779705SSam Leffler {
76914779705SSam Leffler int wlanNum = AR5312_UNIT(ah);
77014779705SSam Leffler uint32_t resetBB, resetBits, regMask;
77114779705SSam Leffler uint32_t reg;
77214779705SSam Leffler
77314779705SSam Leffler if (RCMask == 0)
77414779705SSam Leffler return(AH_FALSE);
77514779705SSam Leffler #if ( AH_SUPPORT_2316 || AH_SUPPORT_2317 )
77614779705SSam Leffler if (IS_5315(ah)) {
77714779705SSam Leffler switch(wlanNum) {
77814779705SSam Leffler case 0:
77914779705SSam Leffler resetBB = AR5315_RC_BB0_CRES | AR5315_RC_WBB0_RES;
78014779705SSam Leffler /* Warm and cold reset bits for wbb */
78114779705SSam Leffler resetBits = AR5315_RC_WMAC0_RES;
78214779705SSam Leffler break;
78314779705SSam Leffler case 1:
78414779705SSam Leffler resetBB = AR5315_RC_BB1_CRES | AR5315_RC_WBB1_RES;
78514779705SSam Leffler /* Warm and cold reset bits for wbb */
78614779705SSam Leffler resetBits = AR5315_RC_WMAC1_RES;
78714779705SSam Leffler break;
78814779705SSam Leffler default:
78914779705SSam Leffler return(AH_FALSE);
79014779705SSam Leffler }
79114779705SSam Leffler regMask = ~(resetBB | resetBits);
79214779705SSam Leffler
79314779705SSam Leffler /* read before */
79414779705SSam Leffler reg = OS_REG_READ(ah,
79514779705SSam Leffler (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5315_RESET));
79614779705SSam Leffler
79714779705SSam Leffler if (RCMask == AR_RC_BB) {
79814779705SSam Leffler /* Put baseband in reset */
79914779705SSam Leffler reg |= resetBB; /* Cold and warm reset the baseband bits */
80014779705SSam Leffler } else {
80114779705SSam Leffler /*
80214779705SSam Leffler * Reset the MAC and baseband. This is a bit different than
80314779705SSam Leffler * the PCI version, but holding in reset causes problems.
80414779705SSam Leffler */
80514779705SSam Leffler reg &= regMask;
80614779705SSam Leffler reg |= (resetBits | resetBB) ;
80714779705SSam Leffler }
80814779705SSam Leffler OS_REG_WRITE(ah,
80914779705SSam Leffler (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET),
81014779705SSam Leffler reg);
81114779705SSam Leffler /* read after */
81214779705SSam Leffler OS_REG_READ(ah,
81314779705SSam Leffler (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5315_RESET));
81414779705SSam Leffler OS_DELAY(100);
81514779705SSam Leffler
81614779705SSam Leffler /* Bring MAC and baseband out of reset */
81714779705SSam Leffler reg &= regMask;
81814779705SSam Leffler /* read before */
81914779705SSam Leffler OS_REG_READ(ah,
82014779705SSam Leffler (AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET));
82114779705SSam Leffler OS_REG_WRITE(ah,
82214779705SSam Leffler (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET),
82314779705SSam Leffler reg);
82414779705SSam Leffler /* read after */
82514779705SSam Leffler OS_REG_READ(ah,
82614779705SSam Leffler (AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET));
82714779705SSam Leffler
82814779705SSam Leffler }
82914779705SSam Leffler else
83014779705SSam Leffler #endif
83114779705SSam Leffler {
83214779705SSam Leffler switch(wlanNum) {
83314779705SSam Leffler case 0:
83414779705SSam Leffler resetBB = AR5312_RC_BB0_CRES | AR5312_RC_WBB0_RES;
83514779705SSam Leffler /* Warm and cold reset bits for wbb */
83614779705SSam Leffler resetBits = AR5312_RC_WMAC0_RES;
83714779705SSam Leffler break;
83814779705SSam Leffler case 1:
83914779705SSam Leffler resetBB = AR5312_RC_BB1_CRES | AR5312_RC_WBB1_RES;
84014779705SSam Leffler /* Warm and cold reset bits for wbb */
84114779705SSam Leffler resetBits = AR5312_RC_WMAC1_RES;
84214779705SSam Leffler break;
84314779705SSam Leffler default:
84414779705SSam Leffler return(AH_FALSE);
84514779705SSam Leffler }
84614779705SSam Leffler regMask = ~(resetBB | resetBits);
84714779705SSam Leffler
84814779705SSam Leffler /* read before */
84914779705SSam Leffler reg = OS_REG_READ(ah,
85014779705SSam Leffler (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5312_RESET));
85114779705SSam Leffler
85214779705SSam Leffler if (RCMask == AR_RC_BB) {
85314779705SSam Leffler /* Put baseband in reset */
85414779705SSam Leffler reg |= resetBB; /* Cold and warm reset the baseband bits */
85514779705SSam Leffler } else {
85614779705SSam Leffler /*
85714779705SSam Leffler * Reset the MAC and baseband. This is a bit different than
85814779705SSam Leffler * the PCI version, but holding in reset causes problems.
85914779705SSam Leffler */
86014779705SSam Leffler reg &= regMask;
86114779705SSam Leffler reg |= (resetBits | resetBB) ;
86214779705SSam Leffler }
86314779705SSam Leffler OS_REG_WRITE(ah,
86414779705SSam Leffler (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET),
86514779705SSam Leffler reg);
86614779705SSam Leffler /* read after */
86714779705SSam Leffler OS_REG_READ(ah,
86814779705SSam Leffler (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5312_RESET));
86914779705SSam Leffler OS_DELAY(100);
87014779705SSam Leffler
87114779705SSam Leffler /* Bring MAC and baseband out of reset */
87214779705SSam Leffler reg &= regMask;
87314779705SSam Leffler /* read before */
87414779705SSam Leffler OS_REG_READ(ah,
87514779705SSam Leffler (AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET));
87614779705SSam Leffler OS_REG_WRITE(ah,
87714779705SSam Leffler (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET),
87814779705SSam Leffler reg);
87914779705SSam Leffler /* read after */
88014779705SSam Leffler OS_REG_READ(ah,
88114779705SSam Leffler (AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET));
88214779705SSam Leffler }
88314779705SSam Leffler return(AH_TRUE);
88414779705SSam Leffler }
88514779705SSam Leffler
88614779705SSam Leffler #endif /* AH_SUPPORT_AR5312 */
887