1185377Ssam/* 2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc. 4185377Ssam * 5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any 6185377Ssam * purpose with or without fee is hereby granted, provided that the above 7185377Ssam * copyright notice and this permission notice appear in all copies. 8185377Ssam * 9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16185377Ssam * 17187611Ssam * $FreeBSD$ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#ifdef AH_SUPPORT_AR5312 22185377Ssam 23185377Ssam#include "ah.h" 24185377Ssam#include "ah_internal.h" 25185377Ssam#include "ah_devid.h" 26185377Ssam 27185377Ssam#include "ar5312/ar5312.h" 28185377Ssam#include "ar5312/ar5312reg.h" 29185377Ssam#include "ar5312/ar5312phy.h" 30185377Ssam 31185377Ssam#include "ah_eeprom_v3.h" 32185377Ssam 33185377Ssam/* Additional Time delay to wait after activiting the Base band */ 34185377Ssam#define BASE_ACTIVATE_DELAY 100 /* 100 usec */ 35185377Ssam#define PLL_SETTLE_DELAY 300 /* 300 usec */ 36185377Ssam 37187831Ssamextern int16_t ar5212GetNf(struct ath_hal *, const struct ieee80211_channel *); 38187831Ssamextern void ar5212SetRateDurationTable(struct ath_hal *, 39187831Ssam const struct ieee80211_channel *); 40185377Ssamextern HAL_BOOL ar5212SetTransmitPower(struct ath_hal *ah, 41187831Ssam const struct ieee80211_channel *chan, uint16_t *rfXpdGain); 42187831Ssamextern void ar5212SetDeltaSlope(struct ath_hal *, 43187831Ssam const struct ieee80211_channel *); 44187831Ssamextern HAL_BOOL ar5212SetBoardValues(struct ath_hal *, 45187831Ssam const struct ieee80211_channel *); 46187831Ssamextern void ar5212SetIFSTiming(struct ath_hal *, 47187831Ssam const struct ieee80211_channel *); 48187831Ssamextern HAL_BOOL ar5212IsSpurChannel(struct ath_hal *, 49187831Ssam const struct ieee80211_channel *); 50187831Ssamextern HAL_BOOL ar5212ChannelChange(struct ath_hal *, 51187831Ssam const struct ieee80211_channel *); 52185377Ssam 53185377Ssamstatic HAL_BOOL ar5312SetResetReg(struct ath_hal *, uint32_t resetMask); 54185377Ssam 55185377Ssamstatic int 56185377Ssamwrite_common(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 57185377Ssam HAL_BOOL bChannelChange, int writes) 58185377Ssam{ 59185377Ssam#define IS_NO_RESET_TIMER_ADDR(x) \ 60185377Ssam ( (((x) >= AR_BEACON) && ((x) <= AR_CFP_DUR)) || \ 61185377Ssam (((x) >= AR_SLEEP1) && ((x) <= AR_SLEEP3))) 62185377Ssam#define V(r, c) (ia)->data[((r)*(ia)->cols) + (c)] 63185377Ssam int i; 64185377Ssam 65185377Ssam /* Write Common Array Parameters */ 66185377Ssam for (i = 0; i < ia->rows; i++) { 67185377Ssam uint32_t reg = V(i, 0); 68185377Ssam /* XXX timer/beacon setup registers? */ 69185377Ssam /* On channel change, don't reset the PCU registers */ 70185377Ssam if (!(bChannelChange && IS_NO_RESET_TIMER_ADDR(reg))) { 71185377Ssam OS_REG_WRITE(ah, reg, V(i, 1)); 72185377Ssam DMA_YIELD(writes); 73185377Ssam } 74185377Ssam } 75185377Ssam return writes; 76185377Ssam#undef IS_NO_RESET_TIMER_ADDR 77185377Ssam#undef V 78185377Ssam} 79185377Ssam 80185377Ssam/* 81185377Ssam * Places the device in and out of reset and then places sane 82185377Ssam * values in the registers based on EEPROM config, initialization 83185377Ssam * vectors (as determined by the mode), and station configuration 84185377Ssam * 85185377Ssam * bChannelChange is used to preserve DMA/PCU registers across 86185377Ssam * a HW Reset during channel change. 87185377Ssam */ 88185377SsamHAL_BOOL 89185377Ssamar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode, 90187831Ssam struct ieee80211_channel *chan, 91187831Ssam HAL_BOOL bChannelChange, HAL_STATUS *status) 92185377Ssam{ 93185377Ssam#define N(a) (sizeof (a) / sizeof (a[0])) 94185377Ssam#define FAIL(_code) do { ecode = _code; goto bad; } while (0) 95185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 96185377Ssam HAL_CHANNEL_INTERNAL *ichan; 97185377Ssam const HAL_EEPROM *ee; 98185377Ssam uint32_t saveFrameSeqCount, saveDefAntenna; 99185377Ssam uint32_t macStaId1, synthDelay, txFrm2TxDStart; 100185377Ssam uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL]; 101185377Ssam int16_t cckOfdmPwrDelta = 0; 102185377Ssam u_int modesIndex, freqIndex; 103185377Ssam HAL_STATUS ecode; 104185377Ssam int i, regWrites = 0; 105185377Ssam uint32_t testReg; 106185377Ssam uint32_t saveLedState = 0; 107185377Ssam 108185377Ssam HALASSERT(ah->ah_magic == AR5212_MAGIC); 109185377Ssam ee = AH_PRIVATE(ah)->ah_eeprom; 110185377Ssam 111185377Ssam OS_MARK(ah, AH_MARK_RESET, bChannelChange); 112185377Ssam /* 113185377Ssam * Map public channel to private. 114185377Ssam */ 115185377Ssam ichan = ath_hal_checkchannel(ah, chan); 116185377Ssam if (ichan == AH_NULL) { 117185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 118185377Ssam "%s: invalid channel %u/0x%x; no mapping\n", 119187831Ssam __func__, chan->ic_freq, chan->ic_flags); 120185377Ssam FAIL(HAL_EINVAL); 121185377Ssam } 122185377Ssam switch (opmode) { 123185377Ssam case HAL_M_STA: 124185377Ssam case HAL_M_IBSS: 125185377Ssam case HAL_M_HOSTAP: 126185377Ssam case HAL_M_MONITOR: 127185377Ssam break; 128185377Ssam default: 129185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n", 130185377Ssam __func__, opmode); 131185377Ssam FAIL(HAL_EINVAL); 132185377Ssam break; 133185377Ssam } 134185377Ssam HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3); 135185377Ssam 136185377Ssam /* Preserve certain DMA hardware registers on a channel change */ 137185377Ssam if (bChannelChange) { 138185377Ssam /* 139185377Ssam * On Venice, the TSF is almost preserved across a reset; 140185377Ssam * it requires the doubling writes to the RESET_TSF 141185377Ssam * bit in the AR_BEACON register; it also has the quirk 142185377Ssam * of the TSF going back in time on the station (station 143185377Ssam * latches onto the last beacon's tsf during a reset 50% 144185377Ssam * of the times); the latter is not a problem for adhoc 145185377Ssam * stations since as long as the TSF is behind, it will 146185377Ssam * get resynchronized on receiving the next beacon; the 147185377Ssam * TSF going backwards in time could be a problem for the 148185377Ssam * sleep operation (supported on infrastructure stations 149185377Ssam * only) - the best and most general fix for this situation 150185377Ssam * is to resynchronize the various sleep/beacon timers on 151185377Ssam * the receipt of the next beacon i.e. when the TSF itself 152185377Ssam * gets resynchronized to the AP's TSF - power save is 153185377Ssam * needed to be temporarily disabled until that time 154185377Ssam * 155185377Ssam * Need to save the sequence number to restore it after 156185377Ssam * the reset! 157185377Ssam */ 158185377Ssam saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM); 159185377Ssam } else 160185377Ssam saveFrameSeqCount = 0; /* NB: silence compiler */ 161185377Ssam 162185377Ssam /* If the channel change is across the same mode - perform a fast channel change */ 163185377Ssam if ((IS_2413(ah) || IS_5413(ah))) { 164185377Ssam /* 165185377Ssam * Channel change can only be used when: 166185377Ssam * -channel change requested - so it's not the initial reset. 167185377Ssam * -it's not a change to the current channel - often called when switching modes 168185377Ssam * on a channel 169185380Ssam * -the modes of the previous and requested channel are the same - some ugly code for XR 170185377Ssam */ 171185377Ssam if (bChannelChange && 172187831Ssam AH_PRIVATE(ah)->ah_curchan != AH_NULL && 173187831Ssam (chan->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) && 174187831Ssam ((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) == 175187831Ssam (AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) { 176185377Ssam if (ar5212ChannelChange(ah, chan)) 177185377Ssam /* If ChannelChange completed - skip the rest of reset */ 178185377Ssam return AH_TRUE; 179185377Ssam } 180185377Ssam } 181185377Ssam 182185377Ssam /* 183185377Ssam * Preserve the antenna on a channel change 184185377Ssam */ 185185377Ssam saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); 186185377Ssam if (saveDefAntenna == 0) /* XXX magic constants */ 187185377Ssam saveDefAntenna = 1; 188185377Ssam 189185377Ssam /* Save hardware flag before chip reset clears the register */ 190185377Ssam macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & 191185377Ssam (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT); 192185377Ssam 193185377Ssam /* Save led state from pci config register */ 194185377Ssam if (!IS_5315(ah)) 195185377Ssam saveLedState = OS_REG_READ(ah, AR5312_PCICFG) & 196185377Ssam (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | 197185377Ssam AR_PCICFG_LEDSLOW); 198185377Ssam 199185377Ssam ar5312RestoreClock(ah, opmode); /* move to refclk operation */ 200185377Ssam 201185377Ssam /* 202185377Ssam * Adjust gain parameters before reset if 203185377Ssam * there's an outstanding gain updated. 204185377Ssam */ 205185377Ssam (void) ar5212GetRfgain(ah); 206185377Ssam 207185377Ssam if (!ar5312ChipReset(ah, chan)) { 208185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); 209185377Ssam FAIL(HAL_EIO); 210185377Ssam } 211185377Ssam 212185377Ssam /* Setup the indices for the next set of register array writes */ 213187831Ssam if (IEEE80211_IS_CHAN_2GHZ(chan)) { 214187831Ssam freqIndex = 2; 215187831Ssam modesIndex = IEEE80211_IS_CHAN_108G(chan) ? 5 : 216187831Ssam IEEE80211_IS_CHAN_G(chan) ? 4 : 3; 217187831Ssam } else { 218185377Ssam freqIndex = 1; 219187831Ssam modesIndex = IEEE80211_IS_CHAN_ST(chan) ? 2 : 1; 220185377Ssam } 221185377Ssam 222185377Ssam OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 223185377Ssam 224185377Ssam /* Set correct Baseband to analog shift setting to access analog chips. */ 225185377Ssam OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); 226185377Ssam 227185377Ssam regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0); 228185377Ssam regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange, 229185377Ssam regWrites); 230185377Ssam ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); 231185377Ssam 232185377Ssam OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 233185377Ssam 234187831Ssam if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) 235185377Ssam ar5212SetIFSTiming(ah, chan); 236185377Ssam 237185377Ssam /* Overwrite INI values for revised chipsets */ 238185377Ssam if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { 239185377Ssam /* ADC_CTL */ 240185377Ssam OS_REG_WRITE(ah, AR_PHY_ADC_CTL, 241185377Ssam SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) | 242185377Ssam SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) | 243185377Ssam AR_PHY_ADC_CTL_OFF_PWDDAC | 244185377Ssam AR_PHY_ADC_CTL_OFF_PWDADC); 245185377Ssam 246185377Ssam /* TX_PWR_ADJ */ 247185377Ssam if (chan->channel == 2484) { 248185377Ssam cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta); 249185377Ssam } else { 250185377Ssam cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta); 251185377Ssam } 252185377Ssam 253187831Ssam if (IEEE80211_IS_CHAN_G(chan)) { 254185377Ssam OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 255185377Ssam SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) | 256185377Ssam SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX)); 257185377Ssam } else { 258185377Ssam OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0); 259185377Ssam } 260185377Ssam 261185377Ssam /* Add barker RSSI thresh enable as disabled */ 262185377Ssam OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK, 263185377Ssam AR_PHY_DAG_CTRLCCK_EN_RSSI_THR); 264185377Ssam OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK, 265185377Ssam AR_PHY_DAG_CTRLCCK_RSSI_THR, 2); 266185377Ssam 267185377Ssam /* Set the mute mask to the correct default */ 268185377Ssam OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F); 269185377Ssam } 270185377Ssam 271185377Ssam if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) { 272185377Ssam /* Clear reg to alllow RX_CLEAR line debug */ 273185377Ssam OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0); 274185377Ssam } 275185377Ssam if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) { 276185377Ssam#ifdef notyet 277185377Ssam /* Enable burst prefetch for the data queues */ 278185377Ssam OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... ); 279185377Ssam /* Enable double-buffering */ 280185377Ssam OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS); 281185377Ssam#endif 282185377Ssam } 283185377Ssam 284185377Ssam if (IS_5312_2_X(ah)) { 285185377Ssam /* ADC_CTRL */ 286185377Ssam OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA, 287185377Ssam SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) | 288185377Ssam SM(4, AR_PHY_SIGMA_DELTA_FILT2) | 289185377Ssam SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) | 290185377Ssam SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP)); 291185377Ssam 292187831Ssam if (IEEE80211_IS_CHAN_2GHZ(chan)) 293185377Ssam OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F); 294185377Ssam 295185377Ssam /* CCK Short parameter adjustment in 11B mode */ 296187831Ssam if (IEEE80211_IS_CHAN_B(chan)) 297185377Ssam OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12); 298185377Ssam 299185377Ssam /* Set ADC/DAC select values */ 300185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04); 301185377Ssam 302185377Ssam /* Increase 11A AGC Settling */ 303187831Ssam if (IEEE80211_IS_CHAN_A(chan)) 304185377Ssam OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32); 305185377Ssam } else { 306185377Ssam /* Set ADC/DAC select values */ 307185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 308185377Ssam } 309185377Ssam 310185377Ssam /* Setup the transmit power values. */ 311187831Ssam if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) { 312185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 313185377Ssam "%s: error init'ing transmit power\n", __func__); 314185377Ssam FAIL(HAL_EIO); 315185377Ssam } 316185377Ssam 317185377Ssam /* Write the analog registers */ 318187831Ssam if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) { 319185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n", 320185377Ssam __func__); 321185377Ssam FAIL(HAL_EIO); 322185377Ssam } 323185377Ssam 324185377Ssam /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ 325187831Ssam if (IEEE80211_IS_CHAN_OFDM(chan)) { 326187831Ssam if (IS_5413(ah) || 327187831Ssam AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3) 328187831Ssam ar5212SetSpurMitigation(ah, chan); 329185377Ssam ar5212SetDeltaSlope(ah, chan); 330185377Ssam } 331185377Ssam 332185377Ssam /* Setup board specific options for EEPROM version 3 */ 333187831Ssam if (!ar5212SetBoardValues(ah, chan)) { 334185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 335185377Ssam "%s: error setting board options\n", __func__); 336185377Ssam FAIL(HAL_EIO); 337185377Ssam } 338185377Ssam 339185377Ssam /* Restore certain DMA hardware registers on a channel change */ 340185377Ssam if (bChannelChange) 341185377Ssam OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount); 342185377Ssam 343185377Ssam OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 344185377Ssam 345185377Ssam OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); 346185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) 347185377Ssam | macStaId1 348185377Ssam | AR_STA_ID1_RTS_USE_DEF 349185377Ssam | ahp->ah_staId1Defaults 350185377Ssam ); 351185377Ssam ar5212SetOperatingMode(ah, opmode); 352185377Ssam 353185377Ssam /* Set Venice BSSID mask according to current state */ 354185377Ssam OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); 355185377Ssam OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); 356185377Ssam 357185377Ssam /* Restore previous led state */ 358185377Ssam if (!IS_5315(ah)) 359185377Ssam OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState); 360185377Ssam 361185377Ssam /* Restore previous antenna */ 362185377Ssam OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); 363185377Ssam 364185377Ssam /* then our BSSID */ 365185377Ssam OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 366185377Ssam OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); 367185377Ssam 368185377Ssam /* Restore bmiss rssi & count thresholds */ 369185377Ssam OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); 370185377Ssam 371185377Ssam OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ 372185377Ssam 373187831Ssam if (!ar5212SetChannel(ah, chan)) 374185377Ssam FAIL(HAL_EIO); 375185377Ssam 376185377Ssam OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); 377185377Ssam 378185377Ssam ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); 379185377Ssam 380185377Ssam ar5212SetRateDurationTable(ah, chan); 381185377Ssam 382185377Ssam /* Set Tx frame start to tx data start delay */ 383185380Ssam if (IS_RAD5112_ANY(ah) && 384187831Ssam (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { 385185377Ssam txFrm2TxDStart = 386187831Ssam IEEE80211_IS_CHAN_HALF(chan) ? 387185377Ssam TX_FRAME_D_START_HALF_RATE: 388185377Ssam TX_FRAME_D_START_QUARTER_RATE; 389185377Ssam OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL, 390185377Ssam AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart); 391185377Ssam } 392185377Ssam 393185377Ssam /* 394185377Ssam * Setup fast diversity. 395185377Ssam * Fast diversity can be enabled or disabled via regadd.txt. 396185377Ssam * Default is enabled. 397185377Ssam * For reference, 398185377Ssam * Disable: reg val 399185377Ssam * 0x00009860 0x00009d18 (if 11a / 11g, else no change) 400185377Ssam * 0x00009970 0x192bb514 401185377Ssam * 0x0000a208 0xd03e4648 402185377Ssam * 403185377Ssam * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change) 404185377Ssam * 0x00009970 0x192fb514 405185377Ssam * 0x0000a208 0xd03e6788 406185377Ssam */ 407185377Ssam 408185377Ssam /* XXX Setup pre PHY ENABLE EAR additions */ 409185377Ssam 410185377Ssam /* flush SCAL reg */ 411185377Ssam if (IS_5312_2_X(ah)) { 412185377Ssam (void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL); 413185377Ssam } 414185377Ssam 415185377Ssam /* 416185377Ssam * Wait for the frequency synth to settle (synth goes on 417185377Ssam * via AR_PHY_ACTIVE_EN). Read the phy active delay register. 418185377Ssam * Value is in 100ns increments. 419185377Ssam */ 420185377Ssam synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; 421187831Ssam if (IEEE80211_IS_CHAN_B(chan)) { 422185377Ssam synthDelay = (4 * synthDelay) / 22; 423185377Ssam } else { 424185377Ssam synthDelay /= 10; 425185377Ssam } 426185377Ssam 427185377Ssam /* Activate the PHY (includes baseband activate and synthesizer on) */ 428185377Ssam OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 429185377Ssam 430185377Ssam /* 431185377Ssam * There is an issue if the AP starts the calibration before 432185377Ssam * the base band timeout completes. This could result in the 433185377Ssam * rx_clear false triggering. As a workaround we add delay an 434185377Ssam * extra BASE_ACTIVATE_DELAY usecs to ensure this condition 435185377Ssam * does not happen. 436185377Ssam */ 437187831Ssam if (IEEE80211_IS_CHAN_HALF(chan)) { 438185377Ssam OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY); 439187831Ssam } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { 440185377Ssam OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY); 441185377Ssam } else { 442185377Ssam OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); 443185377Ssam } 444185377Ssam 445185377Ssam /* 446185377Ssam * The udelay method is not reliable with notebooks. 447185377Ssam * Need to check to see if the baseband is ready 448185377Ssam */ 449185377Ssam testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL); 450185377Ssam /* Selects the Tx hold */ 451185377Ssam OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD); 452185377Ssam i = 0; 453185377Ssam while ((i++ < 20) && 454185377Ssam (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200); 455185377Ssam OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg); 456185377Ssam 457185377Ssam /* Calibrate the AGC and start a NF calculation */ 458185377Ssam OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, 459185377Ssam OS_REG_READ(ah, AR_PHY_AGC_CONTROL) 460185377Ssam | AR_PHY_AGC_CONTROL_CAL 461185377Ssam | AR_PHY_AGC_CONTROL_NF); 462185377Ssam 463187831Ssam if (!IEEE80211_IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) { 464185377Ssam /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ 465185377Ssam OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, 466185377Ssam AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, 467185377Ssam INIT_IQCAL_LOG_COUNT_MAX); 468185377Ssam OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, 469185377Ssam AR_PHY_TIMING_CTRL4_DO_IQCAL); 470185377Ssam ahp->ah_bIQCalibration = IQ_CAL_RUNNING; 471185377Ssam } else 472185377Ssam ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; 473185377Ssam 474185377Ssam /* Setup compression registers */ 475185377Ssam ar5212SetCompRegs(ah); 476185377Ssam 477185377Ssam /* Set 1:1 QCU to DCU mapping for all queues */ 478185377Ssam for (i = 0; i < AR_NUM_DCU; i++) 479185377Ssam OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); 480185377Ssam 481185377Ssam ahp->ah_intrTxqs = 0; 482185377Ssam for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) 483185377Ssam ar5212ResetTxQueue(ah, i); 484185377Ssam 485185377Ssam /* 486185377Ssam * Setup interrupt handling. Note that ar5212ResetTxQueue 487185377Ssam * manipulates the secondary IMR's as queues are enabled 488185377Ssam * and disabled. This is done with RMW ops to insure the 489185377Ssam * settings we make here are preserved. 490185377Ssam */ 491185377Ssam ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN 492185377Ssam | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN 493185377Ssam | AR_IMR_HIUERR 494185377Ssam ; 495185377Ssam if (opmode == HAL_M_HOSTAP) 496185377Ssam ahp->ah_maskReg |= AR_IMR_MIB; 497185377Ssam OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); 498185377Ssam /* Enable bus errors that are OR'd to set the HIUERR bit */ 499185377Ssam OS_REG_WRITE(ah, AR_IMR_S2, 500185377Ssam OS_REG_READ(ah, AR_IMR_S2) 501185377Ssam | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); 502185377Ssam 503185377Ssam if (AH_PRIVATE(ah)->ah_rfkillEnabled) 504185377Ssam ar5212EnableRfKill(ah); 505185377Ssam 506185377Ssam if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { 507185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 508185377Ssam "%s: offset calibration failed to complete in 1ms;" 509185377Ssam " noisy environment?\n", __func__); 510185377Ssam } 511185377Ssam 512185377Ssam /* 513185377Ssam * Set clocks back to 32kHz if they had been using refClk, then 514185377Ssam * use an external 32kHz crystal when sleeping, if one exists. 515185377Ssam */ 516185377Ssam ar5312SetupClock(ah, opmode); 517185377Ssam 518185377Ssam /* 519185377Ssam * Writing to AR_BEACON will start timers. Hence it should 520185377Ssam * be the last register to be written. Do not reset tsf, do 521185377Ssam * not enable beacons at this point, but preserve other values 522185377Ssam * like beaconInterval. 523185377Ssam */ 524185377Ssam OS_REG_WRITE(ah, AR_BEACON, 525185377Ssam (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF))); 526185377Ssam 527185377Ssam /* XXX Setup post reset EAR additions */ 528185377Ssam 529185377Ssam /* QoS support */ 530185377Ssam if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE || 531185377Ssam (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && 532185377Ssam AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) { 533185377Ssam OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */ 534185377Ssam OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */ 535185377Ssam } 536185377Ssam 537185377Ssam /* Turn on NOACK Support for QoS packets */ 538185377Ssam OS_REG_WRITE(ah, AR_NOACK, 539185377Ssam SM(2, AR_NOACK_2BIT_VALUE) | 540185377Ssam SM(5, AR_NOACK_BIT_OFFSET) | 541185377Ssam SM(0, AR_NOACK_BYTE_OFFSET)); 542185377Ssam 543185377Ssam /* Restore user-specified settings */ 544185377Ssam if (ahp->ah_miscMode != 0) 545185377Ssam OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); 546185377Ssam if (ahp->ah_slottime != (u_int) -1) 547185377Ssam ar5212SetSlotTime(ah, ahp->ah_slottime); 548185377Ssam if (ahp->ah_acktimeout != (u_int) -1) 549185377Ssam ar5212SetAckTimeout(ah, ahp->ah_acktimeout); 550185377Ssam if (ahp->ah_ctstimeout != (u_int) -1) 551185377Ssam ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout); 552185377Ssam if (ahp->ah_sifstime != (u_int) -1) 553185377Ssam ar5212SetSifsTime(ah, ahp->ah_sifstime); 554185377Ssam if (AH_PRIVATE(ah)->ah_diagreg != 0) 555185377Ssam OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 556185377Ssam 557185377Ssam AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ 558185377Ssam 559187831Ssam if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan)) 560187831Ssam chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; 561185377Ssam 562185377Ssam HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); 563185377Ssam 564185377Ssam OS_MARK(ah, AH_MARK_RESET_DONE, 0); 565185377Ssam 566185377Ssam return AH_TRUE; 567185377Ssambad: 568185377Ssam OS_MARK(ah, AH_MARK_RESET_DONE, ecode); 569187611Ssam if (status != AH_NULL) 570185377Ssam *status = ecode; 571185377Ssam return AH_FALSE; 572185377Ssam#undef FAIL 573185377Ssam#undef N 574185377Ssam} 575185377Ssam 576185377Ssam/* 577185377Ssam * Places the PHY and Radio chips into reset. A full reset 578185377Ssam * must be called to leave this state. The PCI/MAC/PCU are 579185377Ssam * not placed into reset as we must receive interrupt to 580185377Ssam * re-enable the hardware. 581185377Ssam */ 582185377SsamHAL_BOOL 583185377Ssamar5312PhyDisable(struct ath_hal *ah) 584185377Ssam{ 585185377Ssam return ar5312SetResetReg(ah, AR_RC_BB); 586185377Ssam} 587185377Ssam 588185377Ssam/* 589185377Ssam * Places all of hardware into reset 590185377Ssam */ 591185377SsamHAL_BOOL 592185377Ssamar5312Disable(struct ath_hal *ah) 593185377Ssam{ 594185377Ssam if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) 595185377Ssam return AH_FALSE; 596185377Ssam /* 597185377Ssam * Reset the HW - PCI must be reset after the rest of the 598185377Ssam * device has been reset. 599185377Ssam */ 600185377Ssam return ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB); 601185377Ssam} 602185377Ssam 603185377Ssam/* 604185377Ssam * Places the hardware into reset and then pulls it out of reset 605185377Ssam * 606185377Ssam * TODO: Only write the PLL if we're changing to or from CCK mode 607185377Ssam * 608185377Ssam * WARNING: The order of the PLL and mode registers must be correct. 609185377Ssam */ 610185377SsamHAL_BOOL 611187831Ssamar5312ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan) 612185377Ssam{ 613185377Ssam 614187831Ssam OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0); 615185377Ssam 616185377Ssam /* 617185377Ssam * Reset the HW 618185377Ssam */ 619185377Ssam if (!ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB)) { 620185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n", 621185377Ssam __func__); 622185377Ssam return AH_FALSE; 623185377Ssam } 624185377Ssam 625185377Ssam /* Bring out of sleep mode (AGAIN) */ 626185377Ssam if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { 627185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetPowerMode failed\n", 628185377Ssam __func__); 629185377Ssam return AH_FALSE; 630185377Ssam } 631185377Ssam 632185377Ssam /* Clear warm reset register */ 633185377Ssam if (!ar5312SetResetReg(ah, 0)) { 634185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n", 635185377Ssam __func__); 636185377Ssam return AH_FALSE; 637185377Ssam } 638185377Ssam 639185377Ssam /* 640185377Ssam * Perform warm reset before the mode/PLL/turbo registers 641185377Ssam * are changed in order to deactivate the radio. Mode changes 642185377Ssam * with an active radio can result in corrupted shifts to the 643185377Ssam * radio device. 644185377Ssam */ 645185377Ssam 646185377Ssam /* 647185377Ssam * Set CCK and Turbo modes correctly. 648185377Ssam */ 649185377Ssam if (chan != AH_NULL) { /* NB: can be null during attach */ 650185377Ssam uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo; 651185377Ssam 652185380Ssam if (IS_RAD5112_ANY(ah)) { 653185377Ssam rfMode = AR_PHY_MODE_AR5112; 654185377Ssam if (!IS_5315(ah)) { 655187831Ssam if (IEEE80211_IS_CHAN_CCK(chan)) { 656185377Ssam phyPLL = AR_PHY_PLL_CTL_44_5312; 657185377Ssam } else { 658187831Ssam if (IEEE80211_IS_CHAN_HALF(chan)) { 659185377Ssam phyPLL = AR_PHY_PLL_CTL_40_5312_HALF; 660187831Ssam } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { 661185377Ssam phyPLL = AR_PHY_PLL_CTL_40_5312_QUARTER; 662185377Ssam } else { 663185377Ssam phyPLL = AR_PHY_PLL_CTL_40_5312; 664185377Ssam } 665185377Ssam } 666185377Ssam } else { 667187831Ssam if (IEEE80211_IS_CHAN_CCK(chan)) 668185377Ssam phyPLL = AR_PHY_PLL_CTL_44_5112; 669185380Ssam else 670185380Ssam phyPLL = AR_PHY_PLL_CTL_40_5112; 671187831Ssam if (IEEE80211_IS_CHAN_HALF(chan)) 672185380Ssam phyPLL |= AR_PHY_PLL_CTL_HALF; 673187831Ssam else if (IEEE80211_IS_CHAN_QUARTER(chan)) 674185380Ssam phyPLL |= AR_PHY_PLL_CTL_QUARTER; 675185377Ssam } 676185377Ssam } else { 677185377Ssam rfMode = AR_PHY_MODE_AR5111; 678187831Ssam if (IEEE80211_IS_CHAN_CCK(chan)) 679185377Ssam phyPLL = AR_PHY_PLL_CTL_44; 680185380Ssam else 681185380Ssam phyPLL = AR_PHY_PLL_CTL_40; 682187831Ssam if (IEEE80211_IS_CHAN_HALF(chan)) 683185380Ssam phyPLL = AR_PHY_PLL_CTL_HALF; 684187831Ssam else if (IEEE80211_IS_CHAN_QUARTER(chan)) 685185380Ssam phyPLL = AR_PHY_PLL_CTL_QUARTER; 686185377Ssam } 687187831Ssam if (IEEE80211_IS_CHAN_G(chan)) 688185377Ssam rfMode |= AR_PHY_MODE_DYNAMIC; 689187831Ssam else if (IEEE80211_IS_CHAN_OFDM(chan)) 690185377Ssam rfMode |= AR_PHY_MODE_OFDM; 691185377Ssam else 692185377Ssam rfMode |= AR_PHY_MODE_CCK; 693187831Ssam if (IEEE80211_IS_CHAN_5GHZ(chan)) 694185377Ssam rfMode |= AR_PHY_MODE_RF5GHZ; 695185377Ssam else 696185377Ssam rfMode |= AR_PHY_MODE_RF2GHZ; 697187831Ssam turbo = IEEE80211_IS_CHAN_TURBO(chan) ? 698185377Ssam (AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0; 699185377Ssam curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL); 700185377Ssam /* 701185377Ssam * PLL, Mode, and Turbo values must be written in the correct 702185377Ssam * order to ensure: 703185377Ssam * - The PLL cannot be set to 44 unless the CCK or DYNAMIC 704185377Ssam * mode bit is set 705185377Ssam * - Turbo cannot be set at the same time as CCK or DYNAMIC 706185377Ssam */ 707187831Ssam if (IEEE80211_IS_CHAN_CCK(chan)) { 708185377Ssam OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); 709185377Ssam OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); 710185377Ssam if (curPhyPLL != phyPLL) { 711185377Ssam OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); 712185377Ssam /* Wait for the PLL to settle */ 713185377Ssam OS_DELAY(PLL_SETTLE_DELAY); 714185377Ssam } 715185377Ssam } else { 716185377Ssam if (curPhyPLL != phyPLL) { 717185377Ssam OS_REG_WRITE(ah, AR_PHY_PLL_CTL, phyPLL); 718185377Ssam /* Wait for the PLL to settle */ 719185377Ssam OS_DELAY(PLL_SETTLE_DELAY); 720185377Ssam } 721185377Ssam OS_REG_WRITE(ah, AR_PHY_TURBO, turbo); 722185377Ssam OS_REG_WRITE(ah, AR_PHY_MODE, rfMode); 723185377Ssam } 724185377Ssam } 725185377Ssam return AH_TRUE; 726185377Ssam} 727185377Ssam 728185377Ssam/* 729185377Ssam * Write the given reset bit mask into the reset register 730185377Ssam */ 731185377Ssamstatic HAL_BOOL 732185377Ssamar5312SetResetReg(struct ath_hal *ah, uint32_t resetMask) 733185377Ssam{ 734185377Ssam uint32_t mask = resetMask ? resetMask : ~0; 735185377Ssam HAL_BOOL rt; 736185377Ssam 737185377Ssam if ((rt = ar5312MacReset(ah, mask)) == AH_FALSE) { 738185377Ssam return rt; 739185377Ssam } 740185377Ssam if ((resetMask & AR_RC_MAC) == 0) { 741185377Ssam if (isBigEndian()) { 742185377Ssam /* 743234450Sadrian * Set CFG, little-endian for descriptor accesses. 744185377Ssam */ 745185377Ssam#ifdef AH_NEED_DESC_SWAP 746185377Ssam mask = INIT_CONFIG_STATUS | AR_CFG_SWRD; 747185377Ssam#else 748185377Ssam mask = INIT_CONFIG_STATUS | 749185377Ssam AR_CFG_SWTD | AR_CFG_SWRD; 750185377Ssam#endif 751185377Ssam OS_REG_WRITE(ah, AR_CFG, mask); 752185377Ssam } else 753185377Ssam OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS); 754185377Ssam } 755185377Ssam return rt; 756185377Ssam} 757185377Ssam 758185377Ssam/* 759185377Ssam * ar5312MacReset resets (and then un-resets) the specified 760185377Ssam * wireless components. 761185377Ssam * Note: The RCMask cannot be zero on entering from ar5312SetResetReg. 762185377Ssam */ 763185377Ssam 764185377SsamHAL_BOOL 765185377Ssamar5312MacReset(struct ath_hal *ah, unsigned int RCMask) 766185377Ssam{ 767185377Ssam int wlanNum = AR5312_UNIT(ah); 768185377Ssam uint32_t resetBB, resetBits, regMask; 769185377Ssam uint32_t reg; 770185377Ssam 771185377Ssam if (RCMask == 0) 772185377Ssam return(AH_FALSE); 773185377Ssam#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317 ) 774185377Ssam if (IS_5315(ah)) { 775185377Ssam switch(wlanNum) { 776185377Ssam case 0: 777185377Ssam resetBB = AR5315_RC_BB0_CRES | AR5315_RC_WBB0_RES; 778185377Ssam /* Warm and cold reset bits for wbb */ 779185377Ssam resetBits = AR5315_RC_WMAC0_RES; 780185377Ssam break; 781185377Ssam case 1: 782185377Ssam resetBB = AR5315_RC_BB1_CRES | AR5315_RC_WBB1_RES; 783185377Ssam /* Warm and cold reset bits for wbb */ 784185377Ssam resetBits = AR5315_RC_WMAC1_RES; 785185377Ssam break; 786185377Ssam default: 787185377Ssam return(AH_FALSE); 788185377Ssam } 789185377Ssam regMask = ~(resetBB | resetBits); 790185377Ssam 791185377Ssam /* read before */ 792185377Ssam reg = OS_REG_READ(ah, 793185377Ssam (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5315_RESET)); 794185377Ssam 795185377Ssam if (RCMask == AR_RC_BB) { 796185377Ssam /* Put baseband in reset */ 797185377Ssam reg |= resetBB; /* Cold and warm reset the baseband bits */ 798185377Ssam } else { 799185377Ssam /* 800185377Ssam * Reset the MAC and baseband. This is a bit different than 801185377Ssam * the PCI version, but holding in reset causes problems. 802185377Ssam */ 803185377Ssam reg &= regMask; 804185377Ssam reg |= (resetBits | resetBB) ; 805185377Ssam } 806185377Ssam OS_REG_WRITE(ah, 807185377Ssam (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET), 808185377Ssam reg); 809185377Ssam /* read after */ 810185377Ssam OS_REG_READ(ah, 811185377Ssam (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5315_RESET)); 812185377Ssam OS_DELAY(100); 813185377Ssam 814185377Ssam /* Bring MAC and baseband out of reset */ 815185377Ssam reg &= regMask; 816185377Ssam /* read before */ 817185377Ssam OS_REG_READ(ah, 818185377Ssam (AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET)); 819185377Ssam OS_REG_WRITE(ah, 820185377Ssam (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET), 821185377Ssam reg); 822185377Ssam /* read after */ 823185377Ssam OS_REG_READ(ah, 824185377Ssam (AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET)); 825185377Ssam 826185377Ssam 827185377Ssam } 828185377Ssam else 829185377Ssam#endif 830185377Ssam { 831185377Ssam 832185377Ssam switch(wlanNum) { 833185377Ssam case 0: 834185377Ssam resetBB = AR5312_RC_BB0_CRES | AR5312_RC_WBB0_RES; 835185377Ssam /* Warm and cold reset bits for wbb */ 836185377Ssam resetBits = AR5312_RC_WMAC0_RES; 837185377Ssam break; 838185377Ssam case 1: 839185377Ssam resetBB = AR5312_RC_BB1_CRES | AR5312_RC_WBB1_RES; 840185377Ssam /* Warm and cold reset bits for wbb */ 841185377Ssam resetBits = AR5312_RC_WMAC1_RES; 842185377Ssam break; 843185377Ssam default: 844185377Ssam return(AH_FALSE); 845185377Ssam } 846185377Ssam regMask = ~(resetBB | resetBits); 847185377Ssam 848185377Ssam /* read before */ 849185377Ssam reg = OS_REG_READ(ah, 850185377Ssam (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5312_RESET)); 851185377Ssam 852185377Ssam if (RCMask == AR_RC_BB) { 853185377Ssam /* Put baseband in reset */ 854185377Ssam reg |= resetBB; /* Cold and warm reset the baseband bits */ 855185377Ssam } else { 856185377Ssam /* 857185377Ssam * Reset the MAC and baseband. This is a bit different than 858185377Ssam * the PCI version, but holding in reset causes problems. 859185377Ssam */ 860185377Ssam reg &= regMask; 861185377Ssam reg |= (resetBits | resetBB) ; 862185377Ssam } 863185377Ssam OS_REG_WRITE(ah, 864185377Ssam (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET), 865185377Ssam reg); 866185377Ssam /* read after */ 867185377Ssam OS_REG_READ(ah, 868185377Ssam (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5312_RESET)); 869185377Ssam OS_DELAY(100); 870185377Ssam 871185377Ssam /* Bring MAC and baseband out of reset */ 872185377Ssam reg &= regMask; 873185377Ssam /* read before */ 874185377Ssam OS_REG_READ(ah, 875185377Ssam (AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET)); 876185377Ssam OS_REG_WRITE(ah, 877185377Ssam (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET), 878185377Ssam reg); 879185377Ssam /* read after */ 880185377Ssam OS_REG_READ(ah, 881185377Ssam (AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET)); 882185377Ssam } 883185377Ssam return(AH_TRUE); 884185377Ssam} 885185377Ssam 886185377Ssam#endif /* AH_SUPPORT_AR5312 */ 887