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,
91290612Sadrian	HAL_BOOL bChannelChange,
92290612Sadrian	HAL_RESET_TYPE resetType,
93290612Sadrian	HAL_STATUS *status)
94185377Ssam{
95185377Ssam#define	N(a)	(sizeof (a) / sizeof (a[0]))
96185377Ssam#define	FAIL(_code)	do { ecode = _code; goto bad; } while (0)
97185377Ssam	struct ath_hal_5212 *ahp = AH5212(ah);
98185377Ssam	HAL_CHANNEL_INTERNAL *ichan;
99185377Ssam	const HAL_EEPROM *ee;
100185377Ssam	uint32_t saveFrameSeqCount, saveDefAntenna;
101185377Ssam	uint32_t macStaId1, synthDelay, txFrm2TxDStart;
102185377Ssam	uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL];
103185377Ssam	int16_t cckOfdmPwrDelta = 0;
104185377Ssam	u_int modesIndex, freqIndex;
105185377Ssam	HAL_STATUS ecode;
106185377Ssam	int i, regWrites = 0;
107185377Ssam	uint32_t testReg;
108185377Ssam	uint32_t saveLedState = 0;
109185377Ssam
110185377Ssam	HALASSERT(ah->ah_magic == AR5212_MAGIC);
111185377Ssam	ee = AH_PRIVATE(ah)->ah_eeprom;
112185377Ssam
113185377Ssam	OS_MARK(ah, AH_MARK_RESET, bChannelChange);
114185377Ssam	/*
115185377Ssam	 * Map public channel to private.
116185377Ssam	 */
117185377Ssam	ichan = ath_hal_checkchannel(ah, chan);
118185377Ssam	if (ichan == AH_NULL) {
119185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
120185377Ssam		    "%s: invalid channel %u/0x%x; no mapping\n",
121187831Ssam		    __func__, chan->ic_freq, chan->ic_flags);
122185377Ssam		FAIL(HAL_EINVAL);
123185377Ssam	}
124185377Ssam	switch (opmode) {
125185377Ssam	case HAL_M_STA:
126185377Ssam	case HAL_M_IBSS:
127185377Ssam	case HAL_M_HOSTAP:
128185377Ssam	case HAL_M_MONITOR:
129185377Ssam		break;
130185377Ssam	default:
131185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n",
132185377Ssam		    __func__, opmode);
133185377Ssam		FAIL(HAL_EINVAL);
134185377Ssam		break;
135185377Ssam	}
136185377Ssam	HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3);
137185377Ssam
138185377Ssam	/* Preserve certain DMA hardware registers on a channel change */
139185377Ssam	if (bChannelChange) {
140185377Ssam		/*
141185377Ssam		 * On Venice, the TSF is almost preserved across a reset;
142185377Ssam		 * it requires the doubling writes to the RESET_TSF
143185377Ssam		 * bit in the AR_BEACON register; it also has the quirk
144185377Ssam		 * of the TSF going back in time on the station (station
145185377Ssam		 * latches onto the last beacon's tsf during a reset 50%
146185377Ssam		 * of the times); the latter is not a problem for adhoc
147185377Ssam		 * stations since as long as the TSF is behind, it will
148185377Ssam		 * get resynchronized on receiving the next beacon; the
149185377Ssam		 * TSF going backwards in time could be a problem for the
150185377Ssam		 * sleep operation (supported on infrastructure stations
151185377Ssam		 * only) - the best and most general fix for this situation
152185377Ssam		 * is to resynchronize the various sleep/beacon timers on
153185377Ssam		 * the receipt of the next beacon i.e. when the TSF itself
154185377Ssam		 * gets resynchronized to the AP's TSF - power save is
155185377Ssam		 * needed to be temporarily disabled until that time
156185377Ssam		 *
157185377Ssam		 * Need to save the sequence number to restore it after
158185377Ssam		 * the reset!
159185377Ssam		 */
160185377Ssam		saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM);
161185377Ssam	} else
162185377Ssam		saveFrameSeqCount = 0;		/* NB: silence compiler */
163185377Ssam
164185377Ssam	/* If the channel change is across the same mode - perform a fast channel change */
165185377Ssam	if ((IS_2413(ah) || IS_5413(ah))) {
166185377Ssam		/*
167185377Ssam		 * Channel change can only be used when:
168185377Ssam		 *  -channel change requested - so it's not the initial reset.
169185377Ssam		 *  -it's not a change to the current channel - often called when switching modes
170185377Ssam		 *   on a channel
171185380Ssam		 *  -the modes of the previous and requested channel are the same - some ugly code for XR
172185377Ssam		 */
173185377Ssam		if (bChannelChange &&
174187831Ssam		    AH_PRIVATE(ah)->ah_curchan != AH_NULL &&
175187831Ssam		    (chan->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) &&
176187831Ssam		    ((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) ==
177187831Ssam		     (AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) {
178185377Ssam			if (ar5212ChannelChange(ah, chan))
179185377Ssam				/* If ChannelChange completed - skip the rest of reset */
180185377Ssam				return AH_TRUE;
181185377Ssam		}
182185377Ssam	}
183185377Ssam
184185377Ssam	/*
185185377Ssam	 * Preserve the antenna on a channel change
186185377Ssam	 */
187185377Ssam	saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);
188185377Ssam	if (saveDefAntenna == 0)		/* XXX magic constants */
189185377Ssam		saveDefAntenna = 1;
190185377Ssam
191185377Ssam	/* Save hardware flag before chip reset clears the register */
192185377Ssam	macStaId1 = OS_REG_READ(ah, AR_STA_ID1) &
193185377Ssam		(AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT);
194185377Ssam
195185377Ssam	/* Save led state from pci config register */
196185377Ssam	if (!IS_5315(ah))
197185377Ssam		saveLedState = OS_REG_READ(ah, AR5312_PCICFG) &
198185377Ssam			(AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK |
199185377Ssam			 AR_PCICFG_LEDSLOW);
200185377Ssam
201185377Ssam	ar5312RestoreClock(ah, opmode);		/* move to refclk operation */
202185377Ssam
203185377Ssam	/*
204185377Ssam	 * Adjust gain parameters before reset if
205185377Ssam	 * there's an outstanding gain updated.
206185377Ssam	 */
207185377Ssam	(void) ar5212GetRfgain(ah);
208185377Ssam
209185377Ssam	if (!ar5312ChipReset(ah, chan)) {
210185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);
211185377Ssam		FAIL(HAL_EIO);
212185377Ssam	}
213185377Ssam
214185377Ssam	/* Setup the indices for the next set of register array writes */
215187831Ssam	if (IEEE80211_IS_CHAN_2GHZ(chan)) {
216187831Ssam		freqIndex  = 2;
217187831Ssam		modesIndex = IEEE80211_IS_CHAN_108G(chan) ? 5 :
218187831Ssam			     IEEE80211_IS_CHAN_G(chan) ? 4 : 3;
219187831Ssam	} else {
220185377Ssam		freqIndex  = 1;
221187831Ssam		modesIndex = IEEE80211_IS_CHAN_ST(chan) ? 2 : 1;
222185377Ssam	}
223185377Ssam
224185377Ssam	OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
225185377Ssam
226185377Ssam	/* Set correct Baseband to analog shift setting to access analog chips. */
227185377Ssam	OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
228185377Ssam
229185377Ssam	regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0);
230185377Ssam	regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange,
231185377Ssam		regWrites);
232185377Ssam	ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites);
233185377Ssam
234185377Ssam	OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
235185377Ssam
236187831Ssam	if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))
237185377Ssam		ar5212SetIFSTiming(ah, chan);
238185377Ssam
239185377Ssam	/* Overwrite INI values for revised chipsets */
240185377Ssam	if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) {
241185377Ssam		/* ADC_CTL */
242185377Ssam		OS_REG_WRITE(ah, AR_PHY_ADC_CTL,
243185377Ssam			     SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) |
244185377Ssam			     SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) |
245185377Ssam			     AR_PHY_ADC_CTL_OFF_PWDDAC |
246185377Ssam			     AR_PHY_ADC_CTL_OFF_PWDADC);
247185377Ssam
248185377Ssam		/* TX_PWR_ADJ */
249185377Ssam		if (chan->channel == 2484) {
250185377Ssam			cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta);
251185377Ssam		} else {
252185377Ssam			cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta);
253185377Ssam		}
254185377Ssam
255187831Ssam		if (IEEE80211_IS_CHAN_G(chan)) {
256185377Ssam			OS_REG_WRITE(ah, AR_PHY_TXPWRADJ,
257185377Ssam				     SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) |
258185377Ssam				     SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX));
259185377Ssam		} else {
260185377Ssam			OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0);
261185377Ssam		}
262185377Ssam
263185377Ssam		/* Add barker RSSI thresh enable as disabled */
264185377Ssam		OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK,
265185377Ssam			       AR_PHY_DAG_CTRLCCK_EN_RSSI_THR);
266185377Ssam		OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK,
267185377Ssam				 AR_PHY_DAG_CTRLCCK_RSSI_THR, 2);
268185377Ssam
269185377Ssam		/* Set the mute mask to the correct default */
270185377Ssam		OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F);
271185377Ssam	}
272185377Ssam
273185377Ssam	if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) {
274185377Ssam		/* Clear reg to alllow RX_CLEAR line debug */
275185377Ssam		OS_REG_WRITE(ah, AR_PHY_BLUETOOTH,  0);
276185377Ssam	}
277185377Ssam	if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) {
278185377Ssam#ifdef notyet
279185377Ssam		/* Enable burst prefetch for the data queues */
280185377Ssam		OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... );
281185377Ssam		/* Enable double-buffering */
282185377Ssam		OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS);
283185377Ssam#endif
284185377Ssam	}
285185377Ssam
286185377Ssam	if (IS_5312_2_X(ah)) {
287185377Ssam		/* ADC_CTRL */
288185377Ssam		OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA,
289185377Ssam			     SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) |
290185377Ssam			     SM(4, AR_PHY_SIGMA_DELTA_FILT2) |
291185377Ssam			     SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) |
292185377Ssam			     SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP));
293185377Ssam
294187831Ssam		if (IEEE80211_IS_CHAN_2GHZ(chan))
295185377Ssam			OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F);
296185377Ssam
297185377Ssam		/* CCK Short parameter adjustment in 11B mode */
298187831Ssam		if (IEEE80211_IS_CHAN_B(chan))
299185377Ssam			OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12);
300185377Ssam
301185377Ssam		/* Set ADC/DAC select values */
302185377Ssam		OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04);
303185377Ssam
304185377Ssam		/* Increase 11A AGC Settling */
305187831Ssam		if (IEEE80211_IS_CHAN_A(chan))
306185377Ssam			OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32);
307185377Ssam	} else {
308185377Ssam		/* Set ADC/DAC select values */
309185377Ssam		OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
310185377Ssam	}
311185377Ssam
312185377Ssam	/* Setup the transmit power values. */
313187831Ssam	if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) {
314185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
315185377Ssam		    "%s: error init'ing transmit power\n", __func__);
316185377Ssam		FAIL(HAL_EIO);
317185377Ssam	}
318185377Ssam
319185377Ssam	/* Write the analog registers */
320187831Ssam	if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) {
321185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n",
322185377Ssam		    __func__);
323185377Ssam		FAIL(HAL_EIO);
324185377Ssam	}
325185377Ssam
326185377Ssam	/* Write delta slope for OFDM enabled modes (A, G, Turbo) */
327187831Ssam	if (IEEE80211_IS_CHAN_OFDM(chan)) {
328187831Ssam		if (IS_5413(ah) ||
329187831Ssam		   AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3)
330187831Ssam			ar5212SetSpurMitigation(ah, chan);
331185377Ssam		ar5212SetDeltaSlope(ah, chan);
332185377Ssam	}
333185377Ssam
334185377Ssam	/* Setup board specific options for EEPROM version 3 */
335187831Ssam	if (!ar5212SetBoardValues(ah, chan)) {
336185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
337185377Ssam		    "%s: error setting board options\n", __func__);
338185377Ssam		FAIL(HAL_EIO);
339185377Ssam	}
340185377Ssam
341185377Ssam	/* Restore certain DMA hardware registers on a channel change */
342185377Ssam	if (bChannelChange)
343185377Ssam		OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount);
344185377Ssam
345185377Ssam	OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
346185377Ssam
347185377Ssam	OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr));
348185377Ssam	OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)
349185377Ssam		| macStaId1
350185377Ssam		| AR_STA_ID1_RTS_USE_DEF
351185377Ssam		| ahp->ah_staId1Defaults
352185377Ssam	);
353185377Ssam	ar5212SetOperatingMode(ah, opmode);
354185377Ssam
355185377Ssam	/* Set Venice BSSID mask according to current state */
356185377Ssam	OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));
357185377Ssam	OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));
358185377Ssam
359185377Ssam	/* Restore previous led state */
360185377Ssam	if (!IS_5315(ah))
361185377Ssam		OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState);
362185377Ssam
363185377Ssam	/* Restore previous antenna */
364185377Ssam	OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
365185377Ssam
366185377Ssam	/* then our BSSID */
367185377Ssam	OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
368185377Ssam	OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4));
369185377Ssam
370185377Ssam	/* Restore bmiss rssi & count thresholds */
371185377Ssam	OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
372185377Ssam
373185377Ssam	OS_REG_WRITE(ah, AR_ISR, ~0);		/* cleared on write */
374185377Ssam
375187831Ssam	if (!ar5212SetChannel(ah, chan))
376185377Ssam		FAIL(HAL_EIO);
377185377Ssam
378185377Ssam	OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__);
379185377Ssam
380185377Ssam	ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1);
381185377Ssam
382185377Ssam	ar5212SetRateDurationTable(ah, chan);
383185377Ssam
384185377Ssam	/* Set Tx frame start to tx data start delay */
385185380Ssam	if (IS_RAD5112_ANY(ah) &&
386187831Ssam	    (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) {
387185377Ssam		txFrm2TxDStart =
388187831Ssam			IEEE80211_IS_CHAN_HALF(chan) ?
389185377Ssam					TX_FRAME_D_START_HALF_RATE:
390185377Ssam					TX_FRAME_D_START_QUARTER_RATE;
391185377Ssam		OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL,
392185377Ssam			AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart);
393185377Ssam	}
394185377Ssam
395185377Ssam	/*
396185377Ssam	 * Setup fast diversity.
397185377Ssam	 * Fast diversity can be enabled or disabled via regadd.txt.
398185377Ssam	 * Default is enabled.
399185377Ssam	 * For reference,
400185377Ssam	 *    Disable: reg        val
401185377Ssam	 *             0x00009860 0x00009d18 (if 11a / 11g, else no change)
402185377Ssam	 *             0x00009970 0x192bb514
403185377Ssam	 *             0x0000a208 0xd03e4648
404185377Ssam	 *
405185377Ssam	 *    Enable:  0x00009860 0x00009d10 (if 11a / 11g, else no change)
406185377Ssam	 *             0x00009970 0x192fb514
407185377Ssam	 *             0x0000a208 0xd03e6788
408185377Ssam	 */
409185377Ssam
410185377Ssam	/* XXX Setup pre PHY ENABLE EAR additions */
411185377Ssam
412185377Ssam	/* flush SCAL reg */
413185377Ssam	if (IS_5312_2_X(ah)) {
414185377Ssam		(void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL);
415185377Ssam	}
416185377Ssam
417185377Ssam	/*
418185377Ssam	 * Wait for the frequency synth to settle (synth goes on
419185377Ssam	 * via AR_PHY_ACTIVE_EN).  Read the phy active delay register.
420185377Ssam	 * Value is in 100ns increments.
421185377Ssam	 */
422185377Ssam	synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
423187831Ssam	if (IEEE80211_IS_CHAN_B(chan)) {
424185377Ssam		synthDelay = (4 * synthDelay) / 22;
425185377Ssam	} else {
426185377Ssam		synthDelay /= 10;
427185377Ssam	}
428185377Ssam
429185377Ssam	/* Activate the PHY (includes baseband activate and synthesizer on) */
430185377Ssam	OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
431185377Ssam
432185377Ssam	/*
433185377Ssam	 * There is an issue if the AP starts the calibration before
434185377Ssam	 * the base band timeout completes.  This could result in the
435185377Ssam	 * rx_clear false triggering.  As a workaround we add delay an
436185377Ssam	 * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
437185377Ssam	 * does not happen.
438185377Ssam	 */
439187831Ssam	if (IEEE80211_IS_CHAN_HALF(chan)) {
440185377Ssam		OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY);
441187831Ssam	} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
442185377Ssam		OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY);
443185377Ssam	} else {
444185377Ssam		OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY);
445185377Ssam	}
446185377Ssam
447185377Ssam	/*
448185377Ssam	 * The udelay method is not reliable with notebooks.
449185377Ssam	 * Need to check to see if the baseband is ready
450185377Ssam	 */
451185377Ssam	testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL);
452185377Ssam	/* Selects the Tx hold */
453185377Ssam	OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD);
454185377Ssam	i = 0;
455185377Ssam	while ((i++ < 20) &&
456185377Ssam	       (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */		OS_DELAY(200);
457185377Ssam	OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg);
458185377Ssam
459185377Ssam	/* Calibrate the AGC and start a NF calculation */
460185377Ssam	OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL,
461185377Ssam		  OS_REG_READ(ah, AR_PHY_AGC_CONTROL)
462185377Ssam		| AR_PHY_AGC_CONTROL_CAL
463185377Ssam		| AR_PHY_AGC_CONTROL_NF);
464185377Ssam
465187831Ssam	if (!IEEE80211_IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) {
466185377Ssam		/* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */
467185377Ssam		OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4,
468185377Ssam			AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
469185377Ssam			INIT_IQCAL_LOG_COUNT_MAX);
470185377Ssam		OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4,
471185377Ssam			AR_PHY_TIMING_CTRL4_DO_IQCAL);
472185377Ssam		ahp->ah_bIQCalibration = IQ_CAL_RUNNING;
473185377Ssam	} else
474185377Ssam		ahp->ah_bIQCalibration = IQ_CAL_INACTIVE;
475185377Ssam
476185377Ssam	/* Setup compression registers */
477185377Ssam	ar5212SetCompRegs(ah);
478185377Ssam
479185377Ssam	/* Set 1:1 QCU to DCU mapping for all queues */
480185377Ssam	for (i = 0; i < AR_NUM_DCU; i++)
481185377Ssam		OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
482185377Ssam
483185377Ssam	ahp->ah_intrTxqs = 0;
484185377Ssam	for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++)
485185377Ssam		ar5212ResetTxQueue(ah, i);
486185377Ssam
487185377Ssam	/*
488185377Ssam	 * Setup interrupt handling.  Note that ar5212ResetTxQueue
489185377Ssam	 * manipulates the secondary IMR's as queues are enabled
490185377Ssam	 * and disabled.  This is done with RMW ops to insure the
491185377Ssam	 * settings we make here are preserved.
492185377Ssam	 */
493185377Ssam	ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN
494185377Ssam			| AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN
495185377Ssam			| AR_IMR_HIUERR
496185377Ssam			;
497185377Ssam	if (opmode == HAL_M_HOSTAP)
498185377Ssam		ahp->ah_maskReg |= AR_IMR_MIB;
499185377Ssam	OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
500185377Ssam	/* Enable bus errors that are OR'd to set the HIUERR bit */
501185377Ssam	OS_REG_WRITE(ah, AR_IMR_S2,
502185377Ssam		OS_REG_READ(ah, AR_IMR_S2)
503185377Ssam		| AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR);
504185377Ssam
505185377Ssam	if (AH_PRIVATE(ah)->ah_rfkillEnabled)
506185377Ssam		ar5212EnableRfKill(ah);
507185377Ssam
508185377Ssam	if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
509185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
510185377Ssam		    "%s: offset calibration failed to complete in 1ms;"
511185377Ssam		    " noisy environment?\n", __func__);
512185377Ssam	}
513185377Ssam
514185377Ssam	/*
515185377Ssam	 * Set clocks back to 32kHz if they had been using refClk, then
516185377Ssam	 * use an external 32kHz crystal when sleeping, if one exists.
517185377Ssam	 */
518185377Ssam	ar5312SetupClock(ah, opmode);
519185377Ssam
520185377Ssam	/*
521185377Ssam	 * Writing to AR_BEACON will start timers. Hence it should
522185377Ssam	 * be the last register to be written. Do not reset tsf, do
523185377Ssam	 * not enable beacons at this point, but preserve other values
524185377Ssam	 * like beaconInterval.
525185377Ssam	 */
526185377Ssam	OS_REG_WRITE(ah, AR_BEACON,
527185377Ssam		(OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF)));
528185377Ssam
529185377Ssam	/* XXX Setup post reset EAR additions */
530185377Ssam
531185377Ssam	/*  QoS support */
532185377Ssam	if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE ||
533185377Ssam	    (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE &&
534185377Ssam	     AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) {
535185377Ssam		OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa);	/* XXX magic */
536185377Ssam		OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210);	/* XXX magic */
537185377Ssam	}
538185377Ssam
539185377Ssam	/* Turn on NOACK Support for QoS packets */
540185377Ssam	OS_REG_WRITE(ah, AR_NOACK,
541185377Ssam		     SM(2, AR_NOACK_2BIT_VALUE) |
542185377Ssam		     SM(5, AR_NOACK_BIT_OFFSET) |
543185377Ssam		     SM(0, AR_NOACK_BYTE_OFFSET));
544185377Ssam
545185377Ssam	/* Restore user-specified settings */
546185377Ssam	if (ahp->ah_miscMode != 0)
547185377Ssam		OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);
548185377Ssam	if (ahp->ah_slottime != (u_int) -1)
549185377Ssam		ar5212SetSlotTime(ah, ahp->ah_slottime);
550185377Ssam	if (ahp->ah_acktimeout != (u_int) -1)
551185377Ssam		ar5212SetAckTimeout(ah, ahp->ah_acktimeout);
552185377Ssam	if (ahp->ah_ctstimeout != (u_int) -1)
553185377Ssam		ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout);
554185377Ssam	if (ahp->ah_sifstime != (u_int) -1)
555185377Ssam		ar5212SetSifsTime(ah, ahp->ah_sifstime);
556185377Ssam	if (AH_PRIVATE(ah)->ah_diagreg != 0)
557185377Ssam		OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
558185377Ssam
559185377Ssam	AH_PRIVATE(ah)->ah_opmode = opmode;	/* record operating mode */
560185377Ssam
561187831Ssam	if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan))
562187831Ssam		chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT;
563185377Ssam
564185377Ssam	HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__);
565185377Ssam
566185377Ssam	OS_MARK(ah, AH_MARK_RESET_DONE, 0);
567185377Ssam
568185377Ssam	return AH_TRUE;
569185377Ssambad:
570185377Ssam	OS_MARK(ah, AH_MARK_RESET_DONE, ecode);
571187611Ssam	if (status != AH_NULL)
572185377Ssam		*status = ecode;
573185377Ssam	return AH_FALSE;
574185377Ssam#undef FAIL
575185377Ssam#undef N
576185377Ssam}
577185377Ssam
578185377Ssam/*
579185377Ssam * Places the PHY and Radio chips into reset.  A full reset
580185377Ssam * must be called to leave this state.  The PCI/MAC/PCU are
581185377Ssam * not placed into reset as we must receive interrupt to
582185377Ssam * re-enable the hardware.
583185377Ssam */
584185377SsamHAL_BOOL
585185377Ssamar5312PhyDisable(struct ath_hal *ah)
586185377Ssam{
587185377Ssam    return ar5312SetResetReg(ah, AR_RC_BB);
588185377Ssam}
589185377Ssam
590185377Ssam/*
591185377Ssam * Places all of hardware into reset
592185377Ssam */
593185377SsamHAL_BOOL
594185377Ssamar5312Disable(struct ath_hal *ah)
595185377Ssam{
596185377Ssam	if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
597185377Ssam		return AH_FALSE;
598185377Ssam	/*
599185377Ssam	 * Reset the HW - PCI must be reset after the rest of the
600185377Ssam	 * device has been reset.
601185377Ssam	 */
602185377Ssam	return ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB);
603185377Ssam}
604185377Ssam
605185377Ssam/*
606185377Ssam * Places the hardware into reset and then pulls it out of reset
607185377Ssam *
608185377Ssam * TODO: Only write the PLL if we're changing to or from CCK mode
609185377Ssam *
610185377Ssam * WARNING: The order of the PLL and mode registers must be correct.
611185377Ssam */
612185377SsamHAL_BOOL
613187831Ssamar5312ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan)
614185377Ssam{
615185377Ssam
616187831Ssam	OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);
617185377Ssam
618185377Ssam	/*
619185377Ssam	 * Reset the HW
620185377Ssam	 */
621185377Ssam	if (!ar5312SetResetReg(ah, AR_RC_MAC | AR_RC_BB)) {
622185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
623185377Ssam		    __func__);
624185377Ssam		return AH_FALSE;
625185377Ssam	}
626185377Ssam
627185377Ssam	/* Bring out of sleep mode (AGAIN) */
628185377Ssam	if (!ar5312SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {
629185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetPowerMode failed\n",
630185377Ssam		    __func__);
631185377Ssam		return AH_FALSE;
632185377Ssam	}
633185377Ssam
634185377Ssam	/* Clear warm reset register */
635185377Ssam	if (!ar5312SetResetReg(ah, 0)) {
636185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5312SetResetReg failed\n",
637185377Ssam		    __func__);
638185377Ssam		return AH_FALSE;
639185377Ssam	}
640185377Ssam
641185377Ssam	/*
642185377Ssam	 * Perform warm reset before the mode/PLL/turbo registers
643185377Ssam	 * are changed in order to deactivate the radio.  Mode changes
644185377Ssam	 * with an active radio can result in corrupted shifts to the
645185377Ssam	 * radio device.
646185377Ssam	 */
647185377Ssam
648185377Ssam	/*
649185377Ssam	 * Set CCK and Turbo modes correctly.
650185377Ssam	 */
651185377Ssam	if (chan != AH_NULL) {		/* NB: can be null during attach */
652185377Ssam		uint32_t rfMode, phyPLL = 0, curPhyPLL, turbo;
653185377Ssam
654185380Ssam		if (IS_RAD5112_ANY(ah)) {
655185377Ssam			rfMode = AR_PHY_MODE_AR5112;
656185377Ssam			if (!IS_5315(ah)) {
657187831Ssam				if (IEEE80211_IS_CHAN_CCK(chan)) {
658185377Ssam					phyPLL = AR_PHY_PLL_CTL_44_5312;
659185377Ssam				} else {
660187831Ssam					if (IEEE80211_IS_CHAN_HALF(chan)) {
661185377Ssam						phyPLL = AR_PHY_PLL_CTL_40_5312_HALF;
662187831Ssam					} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
663185377Ssam						phyPLL = AR_PHY_PLL_CTL_40_5312_QUARTER;
664185377Ssam					} else {
665185377Ssam						phyPLL = AR_PHY_PLL_CTL_40_5312;
666185377Ssam					}
667185377Ssam				}
668185377Ssam			} else {
669187831Ssam				if (IEEE80211_IS_CHAN_CCK(chan))
670185377Ssam					phyPLL = AR_PHY_PLL_CTL_44_5112;
671185380Ssam				else
672185380Ssam					phyPLL = AR_PHY_PLL_CTL_40_5112;
673187831Ssam				if (IEEE80211_IS_CHAN_HALF(chan))
674185380Ssam					phyPLL |= AR_PHY_PLL_CTL_HALF;
675187831Ssam				else if (IEEE80211_IS_CHAN_QUARTER(chan))
676185380Ssam					phyPLL |= AR_PHY_PLL_CTL_QUARTER;
677185377Ssam			}
678185377Ssam		} else {
679185377Ssam			rfMode = AR_PHY_MODE_AR5111;
680187831Ssam			if (IEEE80211_IS_CHAN_CCK(chan))
681185377Ssam				phyPLL = AR_PHY_PLL_CTL_44;
682185380Ssam			else
683185380Ssam				phyPLL = AR_PHY_PLL_CTL_40;
684187831Ssam			if (IEEE80211_IS_CHAN_HALF(chan))
685185380Ssam				phyPLL = AR_PHY_PLL_CTL_HALF;
686187831Ssam			else if (IEEE80211_IS_CHAN_QUARTER(chan))
687185380Ssam				phyPLL = AR_PHY_PLL_CTL_QUARTER;
688185377Ssam		}
689187831Ssam		if (IEEE80211_IS_CHAN_G(chan))
690185377Ssam			rfMode |= AR_PHY_MODE_DYNAMIC;
691187831Ssam		else if (IEEE80211_IS_CHAN_OFDM(chan))
692185377Ssam			rfMode |= AR_PHY_MODE_OFDM;
693185377Ssam		else
694185377Ssam			rfMode |= AR_PHY_MODE_CCK;
695187831Ssam		if (IEEE80211_IS_CHAN_5GHZ(chan))
696185377Ssam			rfMode |= AR_PHY_MODE_RF5GHZ;
697185377Ssam		else
698185377Ssam			rfMode |= AR_PHY_MODE_RF2GHZ;
699187831Ssam		turbo = IEEE80211_IS_CHAN_TURBO(chan) ?
700185377Ssam			(AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT) : 0;
701185377Ssam		curPhyPLL = OS_REG_READ(ah, AR_PHY_PLL_CTL);
702185377Ssam		/*
703185377Ssam		 * PLL, Mode, and Turbo values must be written in the correct
704185377Ssam		 * order to ensure:
705185377Ssam		 * - The PLL cannot be set to 44 unless the CCK or DYNAMIC
706185377Ssam		 *   mode bit is set
707185377Ssam		 * - Turbo cannot be set at the same time as CCK or DYNAMIC
708185377Ssam		 */
709187831Ssam		if (IEEE80211_IS_CHAN_CCK(chan)) {
710185377Ssam			OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
711185377Ssam			OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
712185377Ssam			if (curPhyPLL != phyPLL) {
713185377Ssam				OS_REG_WRITE(ah,  AR_PHY_PLL_CTL,  phyPLL);
714185377Ssam				/* Wait for the PLL to settle */
715185377Ssam				OS_DELAY(PLL_SETTLE_DELAY);
716185377Ssam			}
717185377Ssam		} else {
718185377Ssam			if (curPhyPLL != phyPLL) {
719185377Ssam				OS_REG_WRITE(ah,  AR_PHY_PLL_CTL,  phyPLL);
720185377Ssam				/* Wait for the PLL to settle */
721185377Ssam				OS_DELAY(PLL_SETTLE_DELAY);
722185377Ssam			}
723185377Ssam			OS_REG_WRITE(ah, AR_PHY_TURBO, turbo);
724185377Ssam			OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
725185377Ssam		}
726185377Ssam	}
727185377Ssam	return AH_TRUE;
728185377Ssam}
729185377Ssam
730185377Ssam/*
731185377Ssam * Write the given reset bit mask into the reset register
732185377Ssam */
733185377Ssamstatic HAL_BOOL
734185377Ssamar5312SetResetReg(struct ath_hal *ah, uint32_t resetMask)
735185377Ssam{
736185377Ssam	uint32_t mask = resetMask ? resetMask : ~0;
737185377Ssam	HAL_BOOL rt;
738185377Ssam
739185377Ssam        if ((rt = ar5312MacReset(ah, mask)) == AH_FALSE) {
740185377Ssam		return rt;
741185377Ssam	}
742185377Ssam        if ((resetMask & AR_RC_MAC) == 0) {
743185377Ssam		if (isBigEndian()) {
744185377Ssam			/*
745234450Sadrian			 * Set CFG, little-endian for descriptor accesses.
746185377Ssam			 */
747185377Ssam#ifdef AH_NEED_DESC_SWAP
748185377Ssam			mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;
749185377Ssam#else
750185377Ssam			mask = INIT_CONFIG_STATUS |
751185377Ssam                                AR_CFG_SWTD | AR_CFG_SWRD;
752185377Ssam#endif
753185377Ssam			OS_REG_WRITE(ah, AR_CFG, mask);
754185377Ssam		} else
755185377Ssam			OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);
756185377Ssam	}
757185377Ssam	return rt;
758185377Ssam}
759185377Ssam
760185377Ssam/*
761185377Ssam * ar5312MacReset resets (and then un-resets) the specified
762185377Ssam * wireless components.
763185377Ssam * Note: The RCMask cannot be zero on entering from ar5312SetResetReg.
764185377Ssam */
765185377Ssam
766185377SsamHAL_BOOL
767185377Ssamar5312MacReset(struct ath_hal *ah, unsigned int RCMask)
768185377Ssam{
769185377Ssam	int wlanNum = AR5312_UNIT(ah);
770185377Ssam	uint32_t resetBB, resetBits, regMask;
771185377Ssam	uint32_t reg;
772185377Ssam
773185377Ssam	if (RCMask == 0)
774185377Ssam		return(AH_FALSE);
775185377Ssam#if ( AH_SUPPORT_2316 || AH_SUPPORT_2317 )
776185377Ssam	    if (IS_5315(ah)) {
777185377Ssam			switch(wlanNum) {
778185377Ssam			case 0:
779185377Ssam				resetBB = AR5315_RC_BB0_CRES | AR5315_RC_WBB0_RES;
780185377Ssam				/* Warm and cold reset bits for wbb */
781185377Ssam				resetBits = AR5315_RC_WMAC0_RES;
782185377Ssam				break;
783185377Ssam			case 1:
784185377Ssam				resetBB = AR5315_RC_BB1_CRES | AR5315_RC_WBB1_RES;
785185377Ssam				/* Warm and cold reset bits for wbb */
786185377Ssam				resetBits = AR5315_RC_WMAC1_RES;
787185377Ssam				break;
788185377Ssam			default:
789185377Ssam				return(AH_FALSE);
790185377Ssam			}
791185377Ssam			regMask = ~(resetBB | resetBits);
792185377Ssam
793185377Ssam			/* read before */
794185377Ssam			reg = OS_REG_READ(ah,
795185377Ssam							  (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5315_RESET));
796185377Ssam
797185377Ssam			if (RCMask == AR_RC_BB) {
798185377Ssam				/* Put baseband in reset */
799185377Ssam				reg |= resetBB;    /* Cold and warm reset the baseband bits */
800185377Ssam			} else {
801185377Ssam				/*
802185377Ssam				 * Reset the MAC and baseband.  This is a bit different than
803185377Ssam				 * the PCI version, but holding in reset causes problems.
804185377Ssam				 */
805185377Ssam				reg &= regMask;
806185377Ssam				reg |= (resetBits | resetBB) ;
807185377Ssam			}
808185377Ssam			OS_REG_WRITE(ah,
809185377Ssam						 (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET),
810185377Ssam						 reg);
811185377Ssam			/* read after */
812185377Ssam			OS_REG_READ(ah,
813185377Ssam						(AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5315_RESET));
814185377Ssam			OS_DELAY(100);
815185377Ssam
816185377Ssam			/* Bring MAC and baseband out of reset */
817185377Ssam			reg &= regMask;
818185377Ssam			/* read before */
819185377Ssam			OS_REG_READ(ah,
820185377Ssam						(AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET));
821185377Ssam			OS_REG_WRITE(ah,
822185377Ssam						 (AR5315_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5315_RESET),
823185377Ssam						 reg);
824185377Ssam			/* read after */
825185377Ssam			OS_REG_READ(ah,
826185377Ssam						(AR5315_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5315_RESET));
827185377Ssam
828185377Ssam
829185377Ssam		}
830185377Ssam        else
831185377Ssam#endif
832185377Ssam		{
833185377Ssam
834185377Ssam			switch(wlanNum) {
835185377Ssam			case 0:
836185377Ssam				resetBB = AR5312_RC_BB0_CRES | AR5312_RC_WBB0_RES;
837185377Ssam				/* Warm and cold reset bits for wbb */
838185377Ssam				resetBits = AR5312_RC_WMAC0_RES;
839185377Ssam				break;
840185377Ssam			case 1:
841185377Ssam				resetBB = AR5312_RC_BB1_CRES | AR5312_RC_WBB1_RES;
842185377Ssam				/* Warm and cold reset bits for wbb */
843185377Ssam				resetBits = AR5312_RC_WMAC1_RES;
844185377Ssam				break;
845185377Ssam			default:
846185377Ssam				return(AH_FALSE);
847185377Ssam			}
848185377Ssam			regMask = ~(resetBB | resetBits);
849185377Ssam
850185377Ssam			/* read before */
851185377Ssam			reg = OS_REG_READ(ah,
852185377Ssam							  (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) + AR5312_RESET));
853185377Ssam
854185377Ssam			if (RCMask == AR_RC_BB) {
855185377Ssam				/* Put baseband in reset */
856185377Ssam				reg |= resetBB;    /* Cold and warm reset the baseband bits */
857185377Ssam			} else {
858185377Ssam				/*
859185377Ssam				 * Reset the MAC and baseband.  This is a bit different than
860185377Ssam				 * the PCI version, but holding in reset causes problems.
861185377Ssam				 */
862185377Ssam				reg &= regMask;
863185377Ssam				reg |= (resetBits | resetBB) ;
864185377Ssam			}
865185377Ssam			OS_REG_WRITE(ah,
866185377Ssam						 (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET),
867185377Ssam						 reg);
868185377Ssam			/* read after */
869185377Ssam			OS_REG_READ(ah,
870185377Ssam						(AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh) +AR5312_RESET));
871185377Ssam			OS_DELAY(100);
872185377Ssam
873185377Ssam			/* Bring MAC and baseband out of reset */
874185377Ssam			reg &= regMask;
875185377Ssam			/* read before */
876185377Ssam			OS_REG_READ(ah,
877185377Ssam						(AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET));
878185377Ssam			OS_REG_WRITE(ah,
879185377Ssam						 (AR5312_RSTIMER_BASE - ((uint32_t) ah->ah_sh)+AR5312_RESET),
880185377Ssam						 reg);
881185377Ssam			/* read after */
882185377Ssam			OS_REG_READ(ah,
883185377Ssam						(AR5312_RSTIMER_BASE- ((uint32_t) ah->ah_sh) +AR5312_RESET));
884185377Ssam		}
885185377Ssam	return(AH_TRUE);
886185377Ssam}
887185377Ssam
888185377Ssam#endif /* AH_SUPPORT_AR5312 */
889