ar5416_misc.c revision 224709
155682Smarkm/*
2233294Sstas * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3233294Sstas * Copyright (c) 2002-2008 Atheros Communications, Inc.
4233294Sstas *
555682Smarkm * Permission to use, copy, modify, and/or distribute this software for any
6233294Sstas * purpose with or without fee is hereby granted, provided that the above
755682Smarkm * copyright notice and this permission notice appear in all copies.
8233294Sstas *
9233294Sstas * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10233294Sstas * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1155682Smarkm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12233294Sstas * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13233294Sstas * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1455682Smarkm * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15233294Sstas * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16233294Sstas *
17233294Sstas * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 224709 2011-08-08 13:15:39Z adrian $
1855682Smarkm */
19233294Sstas#include "opt_ah.h"
20233294Sstas
21233294Sstas#include "ah.h"
22233294Sstas#include "ah_internal.h"
23233294Sstas#include "ah_devid.h"
24233294Sstas#ifdef AH_DEBUG
25233294Sstas#include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
26233294Sstas#endif
27233294Sstas
28233294Sstas#include "ar5416/ar5416.h"
29233294Sstas#include "ar5416/ar5416reg.h"
30233294Sstas#include "ar5416/ar5416phy.h"
31233294Sstas
32233294Sstas/*
33233294Sstas * Return the wireless modes (a,b,g,n,t) supported by hardware.
3455682Smarkm *
3555682Smarkm * This value is what is actually supported by the hardware
3655682Smarkm * and is unaffected by regulatory/country code settings.
3755682Smarkm *
38233294Sstas */
39233294Sstasu_int
40233294Sstasar5416GetWirelessModes(struct ath_hal *ah)
41233294Sstas{
42233294Sstas	u_int mode;
43233294Sstas	struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
44233294Sstas	HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
45233294Sstas
46233294Sstas	mode = ar5212GetWirelessModes(ah);
47233294Sstas
48233294Sstas	/* Only enable HT modes if the NIC supports HT */
4955682Smarkm	if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11A))
50233294Sstas		mode |= HAL_MODE_11NA_HT20
5155682Smarkm		     |  HAL_MODE_11NA_HT40PLUS
5255682Smarkm		     |  HAL_MODE_11NA_HT40MINUS
5355682Smarkm		     ;
5455682Smarkm	if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11G))
5555682Smarkm		mode |= HAL_MODE_11NG_HT20
5655682Smarkm		     |  HAL_MODE_11NG_HT40PLUS
57178825Sdfr		     |  HAL_MODE_11NG_HT40MINUS
5855682Smarkm		     ;
5955682Smarkm	return mode;
6055682Smarkm}
61233294Sstas
62233294Sstas/*
63233294Sstas * Change the LED blinking pattern to correspond to the connectivity
64233294Sstas */
65233294Sstasvoid
66233294Sstasar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state)
67233294Sstas{
68233294Sstas	static const uint32_t ledbits[8] = {
69233294Sstas		AR_MAC_LED_ASSOC_NONE,		/* HAL_LED_INIT */
70233294Sstas		AR_MAC_LED_ASSOC_PEND,		/* HAL_LED_SCAN */
71233294Sstas		AR_MAC_LED_ASSOC_PEND,		/* HAL_LED_AUTH */
72233294Sstas		AR_MAC_LED_ASSOC_ACTIVE,	/* HAL_LED_ASSOC*/
73233294Sstas		AR_MAC_LED_ASSOC_ACTIVE,	/* HAL_LED_RUN */
74233294Sstas		AR_MAC_LED_ASSOC_NONE,
7555682Smarkm		AR_MAC_LED_ASSOC_NONE,
7655682Smarkm		AR_MAC_LED_ASSOC_NONE,
7755682Smarkm	};
7855682Smarkm	uint32_t bits;
7955682Smarkm
80127808Snectar	if (AR_SREV_HOWL(ah))
81127808Snectar		return;
82127808Snectar
83127808Snectar	bits = OS_REG_READ(ah, AR_MAC_LED);
8478527Sassar	bits = (bits &~ AR_MAC_LED_MODE)
85233294Sstas	     | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE)
86233294Sstas#if 1
8755682Smarkm	     | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE)
8878527Sassar#endif
8955682Smarkm	     ;
9055682Smarkm	bits = (bits &~ AR_MAC_LED_ASSOC)
9155682Smarkm	     | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC);
9255682Smarkm	OS_REG_WRITE(ah, AR_MAC_LED, bits);
9355682Smarkm}
9455682Smarkm
9555682Smarkm/*
96127808Snectar * Reset the current hardware tsf for stamlme.
9755682Smarkm */
9855682Smarkmvoid
99127808Snectarar5416ResetTsf(struct ath_hal *ah)
10055682Smarkm{
10155682Smarkm	uint32_t v;
10255682Smarkm	int i;
103127808Snectar
10455682Smarkm	for (i = 0; i < 10; i++) {
10555682Smarkm		v = OS_REG_READ(ah, AR_SLP32_MODE);
10655682Smarkm		if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0)
10755682Smarkm			break;
10855682Smarkm		OS_DELAY(10);
109178825Sdfr	}
110233294Sstas	OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
111233294Sstas}
112233294Sstas
113233294SstasHAL_BOOL
114233294Sstasar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
115233294Sstas{
116233294Sstas	return AH_TRUE;
117233294Sstas}
118233294Sstas
119233294Sstas/* Setup decompression for given key index */
120233294SstasHAL_BOOL
121233294Sstasar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)
122233294Sstas{
123233294Sstas	return HAL_OK;
124178825Sdfr}
125178825Sdfr
126178825Sdfr/* Setup coverage class */
127178825Sdfrvoid
128178825Sdfrar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
129178825Sdfr{
130178825Sdfr	AH_PRIVATE(ah)->ah_coverageClass = coverageclass;
131233294Sstas}
132233294Sstas
133233294Sstas/*
134233294Sstas * Return approximation of extension channel busy over an time interval
135233294Sstas * 0% (clear) -> 100% (busy)
136233294Sstas *
137233294Sstas */
138233294Sstasuint32_t
139233294Sstasar5416Get11nExtBusy(struct ath_hal *ah)
140233294Sstas{
141233294Sstas    struct ath_hal_5416 *ahp = AH5416(ah);
142233294Sstas    uint32_t busy; /* percentage */
143233294Sstas    uint32_t cycleCount, ctlBusy, extBusy;
144233294Sstas
145178825Sdfr    ctlBusy = OS_REG_READ(ah, AR_RCCNT);
146178825Sdfr    extBusy = OS_REG_READ(ah, AR_EXTRCCNT);
147178825Sdfr    cycleCount = OS_REG_READ(ah, AR_CCCNT);
148178825Sdfr
149178825Sdfr    if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) {
150178825Sdfr        /*
151178825Sdfr         * Cycle counter wrap (or initial call); it's not possible
152233294Sstas         * to accurately calculate a value because the registers
153233294Sstas         * right shift rather than wrap--so punt and return 0.
154233294Sstas         */
155233294Sstas        busy = 0;
156233294Sstas        HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n",
157233294Sstas	    __func__);
158233294Sstas
159233294Sstas    } else {
160233294Sstas        uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount;
161233294Sstas        uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy;
162233294Sstas        uint32_t extBusyDelta = extBusy - ahp->ah_extBusy;
163233294Sstas        uint32_t ctlClearDelta = 0;
164178825Sdfr
165178825Sdfr        /* Compute control channel rxclear.
166178825Sdfr         * The cycle delta may be less than the control channel delta.
167178825Sdfr         * This could be solved by freezing the timers (or an atomic read,
168178825Sdfr         * if one was available). Checking for the condition should be
169178825Sdfr         * sufficient.
170233294Sstas         */
171233294Sstas        if (cycleDelta > ctlBusyDelta) {
172233294Sstas            ctlClearDelta = cycleDelta - ctlBusyDelta;
173233294Sstas        }
174233294Sstas
175233294Sstas        /* Compute ratio of extension channel busy to control channel clear
176233294Sstas         * as an approximation to extension channel cleanliness.
177233294Sstas         *
178233294Sstas         * According to the hardware folks, ext rxclear is undefined
179233294Sstas         * if the ctrl rxclear is de-asserted (i.e. busy)
180233294Sstas         */
181233294Sstas        if (ctlClearDelta) {
182233294Sstas            busy = (extBusyDelta * 100) / ctlClearDelta;
183233294Sstas        } else {
184233294Sstas            busy = 100;
185233294Sstas        }
186233294Sstas        if (busy > 100) {
187178825Sdfr            busy = 100;
188178825Sdfr        }
189233294Sstas#if 0
190178825Sdfr        HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, "
191178825Sdfr             "extBusyDelta 0x%x, ctlClearDelta 0x%x, "
192178825Sdfr             "busy %d\n",
193178825Sdfr              __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy);
194178825Sdfr#endif
195178825Sdfr    }
196178825Sdfr
197178825Sdfr    ahp->ah_cycleCount = cycleCount;
198233294Sstas    ahp->ah_ctlBusy = ctlBusy;
199178825Sdfr    ahp->ah_extBusy = extBusy;
200178825Sdfr
201178825Sdfr    return busy;
202233294Sstas}
203233294Sstas
204233294Sstas/*
205233294Sstas * Configure 20/40 operation
206178825Sdfr *
207178825Sdfr * 20/40 = joint rx clear (control and extension)
208178825Sdfr * 20    = rx clear (control)
209178825Sdfr *
210178825Sdfr * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing
211178825Sdfr *         from 20/40 => 20 only
212178825Sdfr */
213178825Sdfrvoid
214178825Sdfrar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode)
215178825Sdfr{
216178825Sdfr    uint32_t macmode;
217178825Sdfr
218233294Sstas    /* Configure MAC for 20/40 operation */
219233294Sstas    if (mode == HAL_HT_MACMODE_2040) {
220178825Sdfr        macmode = AR_2040_JOINED_RX_CLEAR;
221178825Sdfr    } else {
222178825Sdfr        macmode = 0;
223178825Sdfr    }
224178825Sdfr    OS_REG_WRITE(ah, AR_2040_MODE, macmode);
225178825Sdfr}
226178825Sdfr
227178825Sdfr/*
228178825Sdfr * Get Rx clear (control/extension channel)
229178825Sdfr *
230178825Sdfr * Returns active low (busy) for ctrl/ext channel
231178825Sdfr * Owl 2.0
232178825Sdfr */
233233294SstasHAL_HT_RXCLEAR
234233294Sstasar5416Get11nRxClear(struct ath_hal *ah)
235233294Sstas{
236233294Sstas    HAL_HT_RXCLEAR rxclear = 0;
237178825Sdfr    uint32_t val;
238178825Sdfr
239178825Sdfr    val = OS_REG_READ(ah, AR_DIAG_SW);
240178825Sdfr
241178825Sdfr    /* control channel */
242178825Sdfr    if (val & AR_DIAG_RXCLEAR_CTL_LOW) {
243178825Sdfr        rxclear |= HAL_RX_CLEAR_CTL_LOW;
244178825Sdfr    }
245178825Sdfr    /* extension channel */
246178825Sdfr    if (val & AR_DIAG_RXCLEAR_CTL_LOW) {
247178825Sdfr        rxclear |= HAL_RX_CLEAR_EXT_LOW;
248178825Sdfr    }
249178825Sdfr    return rxclear;
250178825Sdfr}
251178825Sdfr
252178825Sdfr/*
253178825Sdfr * Set Rx clear (control/extension channel)
254178825Sdfr *
255233294Sstas * Useful for forcing the channel to appear busy for
256233294Sstas * debugging/diagnostics
257233294Sstas * Owl 2.0
258233294Sstas */
259178825Sdfrvoid
260178825Sdfrar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear)
261178825Sdfr{
262178825Sdfr    /* control channel */
263178825Sdfr    if (rxclear & HAL_RX_CLEAR_CTL_LOW) {
264178825Sdfr        OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW);
265178825Sdfr    } else {
266233294Sstas        OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW);
267178825Sdfr    }
268178825Sdfr    /* extension channel */
269178825Sdfr    if (rxclear & HAL_RX_CLEAR_EXT_LOW) {
270233294Sstas        OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW);
271178825Sdfr    } else {
272178825Sdfr        OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW);
273178825Sdfr    }
274178825Sdfr}
275178825Sdfr
276178825Sdfr/* XXX shouldn't be here! */
277178825Sdfr#define	TU_TO_USEC(_tu)		((_tu) << 10)
278178825Sdfr
279178825SdfrHAL_STATUS
280178825Sdfrar5416SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration,
281178825Sdfr    uint32_t nextStart, HAL_QUIET_FLAG flag)
282178825Sdfr{
283178825Sdfr	uint32_t period_us = TU_TO_USEC(period); /* convert to us unit */
284233294Sstas	uint32_t nextStart_us = TU_TO_USEC(nextStart); /* convert to us unit */
285178825Sdfr	if (flag & HAL_QUIET_ENABLE) {
286178825Sdfr		if ((!nextStart) || (flag & HAL_QUIET_ADD_CURRENT_TSF)) {
287178825Sdfr			/* Add the nextStart offset to the current TSF */
288178825Sdfr			nextStart_us += OS_REG_READ(ah, AR_TSF_L32);
289178825Sdfr		}
290178825Sdfr		if (flag & HAL_QUIET_ADD_SWBA_RESP_TIME) {
291178825Sdfr			nextStart_us += ah->ah_config.ah_sw_beacon_response_time;
292178825Sdfr		}
293178825Sdfr		OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
294178825Sdfr		OS_REG_WRITE(ah, AR_QUIET2, SM(duration, AR_QUIET2_QUIET_DUR));
295178825Sdfr		OS_REG_WRITE(ah, AR_QUIET_PERIOD, period_us);
296178825Sdfr		OS_REG_WRITE(ah, AR_NEXT_QUIET, nextStart_us);
297178825Sdfr		OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
298178825Sdfr	} else {
299178825Sdfr		OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
300178825Sdfr	}
301178825Sdfr	return HAL_OK;
302233294Sstas}
303233294Sstas#undef	TU_TO_USEC
304233294Sstas
305233294SstasHAL_STATUS
306178825Sdfrar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
307178825Sdfr        uint32_t capability, uint32_t *result)
308178825Sdfr{
309178825Sdfr	switch (type) {
310178825Sdfr	case HAL_CAP_BB_HANG:
311233294Sstas		switch (capability) {
312233294Sstas		case HAL_BB_HANG_RIFS:
313233294Sstas			return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP;
314233294Sstas		case HAL_BB_HANG_DFS:
315178825Sdfr			return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP;
316178825Sdfr		case HAL_BB_HANG_RX_CLEAR:
317178825Sdfr			return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP;
318178825Sdfr		}
319178825Sdfr		break;
320178825Sdfr	case HAL_CAP_MAC_HANG:
321178825Sdfr		return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) ||
322178825Sdfr		    (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) ||
323178825Sdfr		    AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ?
324178825Sdfr			HAL_OK : HAL_ENOTSUPP;
325178825Sdfr	case HAL_CAP_DIVERSITY:		/* disable classic fast diversity */
326178825Sdfr		return HAL_ENXIO;
327178825Sdfr	default:
328233294Sstas		break;
329233294Sstas	}
330233294Sstas	return ar5212GetCapability(ah, type, capability, result);
331233294Sstas}
332233294Sstas
333233294Sstasstatic int ar5416DetectMacHang(struct ath_hal *ah);
334233294Sstasstatic int ar5416DetectBBHang(struct ath_hal *ah);
335233294Sstas
336233294SstasHAL_BOOL
337233294Sstasar5416GetDiagState(struct ath_hal *ah, int request,
338233294Sstas	const void *args, uint32_t argsize,
339178825Sdfr	void **result, uint32_t *resultsize)
340178825Sdfr{
341233294Sstas	struct ath_hal_5416 *ahp = AH5416(ah);
342178825Sdfr	int hangs;
343178825Sdfr
344178825Sdfr	if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
345178825Sdfr		return AH_TRUE;
346178825Sdfr	switch (request) {
347178825Sdfr	case HAL_DIAG_EEPROM:
348178825Sdfr		return ath_hal_eepromDiag(ah, request,
349178825Sdfr		    args, argsize, result, resultsize);
350178825Sdfr	case HAL_DIAG_CHECK_HANGS:
351178825Sdfr		if (argsize != sizeof(int))
352178825Sdfr			return AH_FALSE;
353178825Sdfr		hangs = *(const int *) args;
354178825Sdfr		ahp->ah_hangs = 0;
355233294Sstas		if (hangs & HAL_BB_HANGS)
356233294Sstas			ahp->ah_hangs |= ar5416DetectBBHang(ah);
357178825Sdfr		/* NB: if BB is hung MAC will be hung too so skip check */
358178825Sdfr		if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS))
359178825Sdfr			ahp->ah_hangs |= ar5416DetectMacHang(ah);
360178825Sdfr		*result = &ahp->ah_hangs;
361178825Sdfr		*resultsize = sizeof(ahp->ah_hangs);
362178825Sdfr		return AH_TRUE;
363178825Sdfr	}
364178825Sdfr	return ar5212GetDiagState(ah, request,
365233294Sstas	    args, argsize, result, resultsize);
366233294Sstas}
367233294Sstas
368233294Sstastypedef struct {
369178825Sdfr	uint32_t dma_dbg_3;
370178825Sdfr	uint32_t dma_dbg_4;
371178825Sdfr	uint32_t dma_dbg_5;
372178825Sdfr	uint32_t dma_dbg_6;
373233294Sstas} mac_dbg_regs_t;
374233294Sstas
375233294Sstastypedef enum {
376233294Sstas	dcu_chain_state		= 0x1,
377233294Sstas	dcu_complete_state	= 0x2,
378233294Sstas	qcu_state		= 0x4,
379233294Sstas	qcu_fsp_ok		= 0x8,
380233294Sstas	qcu_fsp_state		= 0x10,
381233294Sstas	qcu_stitch_state	= 0x20,
382233294Sstas	qcu_fetch_state		= 0x40,
383233294Sstas	qcu_complete_state	= 0x80
384233294Sstas} hal_mac_hangs_t;
385233294Sstas
386233294Sstastypedef struct {
387233294Sstas	int states;
388233294Sstas	uint8_t dcu_chain_state;
389233294Sstas	uint8_t dcu_complete_state;
390233294Sstas	uint8_t qcu_state;
391233294Sstas	uint8_t qcu_fsp_ok;
392233294Sstas	uint8_t qcu_fsp_state;
393233294Sstas	uint8_t qcu_stitch_state;
394233294Sstas	uint8_t qcu_fetch_state;
395233294Sstas	uint8_t qcu_complete_state;
396233294Sstas} hal_mac_hang_check_t;
397233294Sstas
398233294SstasHAL_BOOL
399233294Sstasar5416SetRifsDelay(struct ath_hal *ah, const struct ieee80211_channel *chan,
400233294Sstas    HAL_BOOL enable)
401233294Sstas{
402233294Sstas	uint32_t val;
403233294Sstas	HAL_BOOL is_chan_2g = AH_FALSE;
404233294Sstas	HAL_BOOL is_ht40 = AH_FALSE;
405233294Sstas
406233294Sstas	if (chan)
407233294Sstas		is_chan_2g = IEEE80211_IS_CHAN_2GHZ(chan);
408233294Sstas
409233294Sstas	if (chan)
410233294Sstas		is_ht40 = IEEE80211_IS_CHAN_HT40(chan);
411233294Sstas
412233294Sstas	/* Only support disabling RIFS delay for now */
413233294Sstas	HALASSERT(enable == AH_FALSE);
414233294Sstas
415233294Sstas	if (enable == AH_TRUE)
416233294Sstas		return AH_FALSE;
417233294Sstas
418233294Sstas	/* Change RIFS init delay to 0 */
419233294Sstas	val = OS_REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS);
420233294Sstas	val &= ~AR_PHY_RIFS_INIT_DELAY;
421233294Sstas	OS_REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val);
422233294Sstas
423233294Sstas	/*
424233294Sstas	 * For Owl, RIFS RX parameters are controlled differently;
425233294Sstas	 * it isn't enabled in the inivals by default.
426233294Sstas	 *
427233294Sstas	 * For Sowl/Howl, RIFS RX is enabled in the inivals by default;
428233294Sstas	 * the following code sets them back to non-RIFS values.
429233294Sstas	 *
430233294Sstas	 * For > Sowl/Howl, RIFS RX can be left on by default and so
431233294Sstas	 * this function shouldn't be called.
432233294Sstas	 */
433233294Sstas	if ((! AR_SREV_SOWL(ah)) && (! AR_SREV_HOWL(ah)))
434233294Sstas		return AH_TRUE;
435233294Sstas
436233294Sstas	/* Reset search delay to default values */
437233294Sstas	if (is_chan_2g)
438233294Sstas		if (is_ht40)
439233294Sstas			OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x268);
440233294Sstas		else
441233294Sstas			OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x134);
442233294Sstas	else
443233294Sstas		if (is_ht40)
444233294Sstas			OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x370);
445233294Sstas		else
446233294Sstas			OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x1b8);
447233294Sstas
448233294Sstas	return AH_TRUE;
449233294Sstas}
450233294Sstas
451233294Sstasstatic HAL_BOOL
452233294Sstasar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs,
453233294Sstas    const hal_mac_hang_check_t *check)
454233294Sstas{
455233294Sstas	int found_states;
456233294Sstas
457233294Sstas	found_states = 0;
458233294Sstas	if (check->states & dcu_chain_state) {
459233294Sstas		int i;
460233294Sstas
461233294Sstas		for (i = 0; i < 6; i++) {
462233294Sstas			if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) ==
463233294Sstas			    check->dcu_chain_state)
464233294Sstas				found_states |= dcu_chain_state;
465233294Sstas		}
466233294Sstas		for (i = 0; i < 4; i++) {
467233294Sstas			if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) ==
468233294Sstas			    check->dcu_chain_state)
469233294Sstas				found_states |= dcu_chain_state;
470233294Sstas		}
471233294Sstas	}
472233294Sstas	if (check->states & dcu_complete_state) {
473233294Sstas		if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state)
474233294Sstas			found_states |= dcu_complete_state;
475233294Sstas	}
476233294Sstas	if (check->states & qcu_stitch_state) {
477233294Sstas		if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state)
478233294Sstas			found_states |= qcu_stitch_state;
479233294Sstas	}
480233294Sstas	if (check->states & qcu_fetch_state) {
481233294Sstas		if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state)
482233294Sstas			found_states |= qcu_fetch_state;
483233294Sstas	}
484233294Sstas	if (check->states & qcu_complete_state) {
485233294Sstas		if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state)
486233294Sstas			found_states |= qcu_complete_state;
487233294Sstas	}
488233294Sstas	return (found_states == check->states);
489233294Sstas}
490233294Sstas
491233294Sstas#define NUM_STATUS_READS 50
492233294Sstas
493233294Sstasstatic int
494233294Sstasar5416DetectMacHang(struct ath_hal *ah)
495233294Sstas{
496233294Sstas	static const hal_mac_hang_check_t hang_sig1 = {
497233294Sstas		.dcu_chain_state	= 0x6,
498233294Sstas		.dcu_complete_state	= 0x1,
499233294Sstas		.states			= dcu_chain_state
500233294Sstas					| dcu_complete_state,
501233294Sstas	};
502233294Sstas	static const hal_mac_hang_check_t hang_sig2 = {
503233294Sstas		.qcu_stitch_state	= 0x9,
504233294Sstas		.qcu_fetch_state	= 0x8,
505233294Sstas		.qcu_complete_state	= 0x4,
506233294Sstas		.states			= qcu_stitch_state
507233294Sstas					| qcu_fetch_state
508233294Sstas					| qcu_complete_state,
509233294Sstas        };
510233294Sstas	mac_dbg_regs_t mac_dbg;
511233294Sstas	int i;
512233294Sstas
513233294Sstas	mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3);
514233294Sstas	mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4);
515233294Sstas	mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5);
516233294Sstas	mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6);
517233294Sstas	for (i = 1; i <= NUM_STATUS_READS; i++) {
518233294Sstas		if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) ||
519233294Sstas		    mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) ||
520233294Sstas		    mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) ||
521233294Sstas		    mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6))
522233294Sstas			return 0;
523233294Sstas	}
524233294Sstas
525233294Sstas	if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1))
526233294Sstas		return HAL_MAC_HANG_SIG1;
527233294Sstas	if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2))
528233294Sstas		return HAL_MAC_HANG_SIG2;
529233294Sstas
530233294Sstas	HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown MAC hang signature "
531233294Sstas	    "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n",
532233294Sstas	    __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5,
533233294Sstas	    mac_dbg.dma_dbg_6);
534233294Sstas
535233294Sstas	return 0;
536233294Sstas}
537233294Sstas
538233294Sstas/*
539233294Sstas * Determine if the baseband using the Observation Bus Register
540233294Sstas */
541233294Sstasstatic int
542233294Sstasar5416DetectBBHang(struct ath_hal *ah)
543233294Sstas{
544233294Sstas#define N(a) (sizeof(a)/sizeof(a[0]))
545233294Sstas	/*
546233294Sstas	 * Check the PCU Observation Bus 1 register (0x806c)
547233294Sstas	 * NUM_STATUS_READS times
548233294Sstas	 *
549233294Sstas	 * 4 known BB hang signatures -
550233294Sstas	 * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E
551233294Sstas	 * [2] bits 8,9 are 1, bit 11 is 0. State machine state
552233294Sstas	 *     (bits 25-31) is 0x52
553233294Sstas	 * [3] bits 8,9 are 1, bit 11 is 0. State machine state
554233294Sstas	 *     (bits 25-31) is 0x18
555233294Sstas	 * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2,
556233294Sstas	 *     Rx State (bits 20-24) is 0x7.
557233294Sstas	 */
558233294Sstas	static const struct {
559233294Sstas		uint32_t val;
560233294Sstas		uint32_t mask;
561233294Sstas		int code;
562233294Sstas	} hang_list[] = {
563233294Sstas		/* Reg Value   Reg Mask    Hang Code XXX */
564233294Sstas		{ 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS },
565233294Sstas		{ 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS },
566233294Sstas		{ 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR },
567233294Sstas		{ 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR }
568233294Sstas	};
569233294Sstas	uint32_t hang_sig;
570233294Sstas	int i;
571233294Sstas
572233294Sstas	hang_sig = OS_REG_READ(ah, AR_OBSERV_1);
573233294Sstas	for (i = 1; i <= NUM_STATUS_READS; i++) {
574233294Sstas		if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1))
575233294Sstas			return 0;
576233294Sstas	}
577233294Sstas	for (i = 0; i < N(hang_list); i++)
578233294Sstas		if ((hang_sig & hang_list[i].mask) == hang_list[i].val) {
579233294Sstas			HALDEBUG(ah, HAL_DEBUG_HANG,
580233294Sstas			    "%s BB hang, signature 0x%x, code 0x%x\n",
581233294Sstas			    __func__, hang_sig, hang_list[i].code);
582233294Sstas			return hang_list[i].code;
583233294Sstas		}
584233294Sstas
585233294Sstas	HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown BB hang signature! "
586233294Sstas	    "<0x806c>=0x%x\n", __func__, hang_sig);
587233294Sstas
588233294Sstas	return 0;
589233294Sstas#undef N
590233294Sstas}
591233294Sstas#undef NUM_STATUS_READS
592233294Sstas
593233294Sstas/*
594233294Sstas * Get the radar parameter values and return them in the pe
595233294Sstas * structure
596233294Sstas */
597233294Sstasvoid
598233294Sstasar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
599233294Sstas{
600233294Sstas	uint32_t val, temp;
601233294Sstas
602233294Sstas	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
603233294Sstas
604233294Sstas	temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
605233294Sstas	temp |= 0xFFFFFF80;
606233294Sstas	pe->pe_firpwr = temp;
607233294Sstas	pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
608233294Sstas	pe->pe_height =  MS(val, AR_PHY_RADAR_0_HEIGHT);
609233294Sstas	pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
610233294Sstas	pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
611233294Sstas
612233294Sstas	val = OS_REG_READ(ah, AR_PHY_RADAR_1);
613233294Sstas	temp = val & AR_PHY_RADAR_1_RELPWR_ENA;
614233294Sstas	pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
615233294Sstas	if (temp)
616233294Sstas		pe->pe_relpwr |= HAL_PHYERR_PARAM_ENABLE;
617233294Sstas	temp = val & AR_PHY_RADAR_1_RELSTEP_CHECK;
618233294Sstas	pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
619233294Sstas	if (temp)
620233294Sstas		pe->pe_enabled = 1;
621233294Sstas	else
622233294Sstas		pe->pe_enabled = 0;
623233294Sstas
624233294Sstas	pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
625233294Sstas	pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
626233294Sstas	    AR_PHY_RADAR_EXT_ENA);
627233294Sstas
628233294Sstas	pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
629233294Sstas	    AR_PHY_RADAR_1_USE_FIR128);
630233294Sstas	pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
631233294Sstas	    AR_PHY_RADAR_1_BLOCK_CHECK);
632233294Sstas	pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
633233294Sstas	    AR_PHY_RADAR_1_MAX_RRSSI);
634233294Sstas}
635233294Sstas
636233294Sstas/*
637233294Sstas * Enable radar detection and set the radar parameters per the
638233294Sstas * values in pe
639233294Sstas */
640233294Sstasvoid
641233294Sstasar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
642233294Sstas{
643233294Sstas	uint32_t val;
644233294Sstas
645233294Sstas	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
646233294Sstas
647233294Sstas	if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
648233294Sstas		val &= ~AR_PHY_RADAR_0_FIRPWR;
649233294Sstas		val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
650233294Sstas	}
651233294Sstas	if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
652233294Sstas		val &= ~AR_PHY_RADAR_0_RRSSI;
653233294Sstas		val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
654233294Sstas	}
655233294Sstas	if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
656233294Sstas		val &= ~AR_PHY_RADAR_0_HEIGHT;
657233294Sstas		val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
658233294Sstas	}
659233294Sstas	if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
660233294Sstas		val &= ~AR_PHY_RADAR_0_PRSSI;
661233294Sstas		val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
662233294Sstas	}
663233294Sstas	if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
664233294Sstas		val &= ~AR_PHY_RADAR_0_INBAND;
665233294Sstas		val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
666233294Sstas	}
667233294Sstas
668233294Sstas	/*Enable FFT data*/
669233294Sstas	val |= AR_PHY_RADAR_0_FFT_ENA;
670233294Sstas
671233294Sstas	OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA);
672233294Sstas
673233294Sstas	if (pe->pe_usefir128 == 1)
674233294Sstas		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
675233294Sstas	else if (pe->pe_usefir128 == 0)
676233294Sstas		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
677233294Sstas
678233294Sstas	if (pe->pe_enmaxrssi == 1)
679233294Sstas		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
680233294Sstas	else if (pe->pe_enmaxrssi == 0)
681233294Sstas		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
682233294Sstas
683233294Sstas	if (pe->pe_blockradar == 1)
684233294Sstas		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
685233294Sstas	else if (pe->pe_blockradar == 0)
686233294Sstas		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
687233294Sstas
688233294Sstas	if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
689233294Sstas		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
690233294Sstas		val &= ~AR_PHY_RADAR_1_MAXLEN;
691233294Sstas		val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
692233294Sstas		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
693233294Sstas	}
694233294Sstas
695233294Sstas	/*
696233294Sstas	 * Enable HT/40 if the upper layer asks;
697233294Sstas	 * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
698233294Sstas	 * is available.
699233294Sstas	 */
700233294Sstas	if (pe->pe_extchannel == 1)
701233294Sstas		OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
702233294Sstas	else if (pe->pe_extchannel == 0)
703233294Sstas		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
704233294Sstas
705233294Sstas	if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
706233294Sstas		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
707233294Sstas		val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
708233294Sstas		val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
709233294Sstas		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
710233294Sstas	}
711233294Sstas	if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
712233294Sstas		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
713233294Sstas		val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
714233294Sstas		val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
715233294Sstas		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
716320907Sdelphij	}
717320907Sdelphij}
718233294Sstas
719233294Sstas/*
720233294Sstas * Extract the radar event information from the given phy error.
721233294Sstas *
722233294Sstas * Returns AH_TRUE if the phy error was actually a phy error,
723233294Sstas * AH_FALSE if the phy error wasn't a phy error.
724233294Sstas */
725233294SstasHAL_BOOL
726233294Sstasar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
727233294Sstas    uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
728233294Sstas{
729233294Sstas	/*
730233294Sstas	 * For now, this isn't implemented.
731233294Sstas	 */
732233294Sstas	return AH_FALSE;
733233294Sstas}
734233294Sstas
735233294Sstas/*
736233294Sstas * Return whether fast-clock is currently enabled for this
737233294Sstas * channel.
738233294Sstas */
739233294SstasHAL_BOOL
740233294Sstasar5416IsFastClockEnabled(struct ath_hal *ah)
741233294Sstas{
742233294Sstas	struct ath_hal_private *ahp = AH_PRIVATE(ah);
743233294Sstas
744233294Sstas	return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);
745233294Sstas}
746233294Sstas