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 *
17186018Ssam * $FreeBSD$
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23185377Ssam#include "ah_devid.h"
24220298Sadrian#include "ah_eeprom.h"			/* for 5ghz fast clock flag */
25185377Ssam
26188968Ssam#include "ar5416/ar5416reg.h"		/* NB: includes ar5212reg.h */
27239604Sadrian#include "ar9003/ar9300_devid.h"
28188968Ssam
29185406Ssam/* linker set of registered chips */
30185406SsamOS_SET_DECLARE(ah_chips, struct ath_hal_chip);
31185406Ssam
32185406Ssam/*
33185406Ssam * Check the set of registered chips to see if any recognize
34185406Ssam * the device as one they can support.
35185406Ssam */
36185406Ssamconst char*
37185406Ssamath_hal_probe(uint16_t vendorid, uint16_t devid)
38185377Ssam{
39186018Ssam	struct ath_hal_chip * const *pchip;
40185377Ssam
41185417Ssam	OS_SET_FOREACH(pchip, ah_chips) {
42185406Ssam		const char *name = (*pchip)->probe(vendorid, devid);
43185406Ssam		if (name != AH_NULL)
44185406Ssam			return name;
45185377Ssam	}
46185377Ssam	return AH_NULL;
47185377Ssam}
48185377Ssam
49185377Ssam/*
50185377Ssam * Attach detects device chip revisions, initializes the hwLayer
51185377Ssam * function list, reads EEPROM information,
52185377Ssam * selects reset vectors, and performs a short self test.
53185377Ssam * Any failures will return an error that should cause a hardware
54185377Ssam * disable.
55185377Ssam */
56185377Ssamstruct ath_hal*
57185377Ssamath_hal_attach(uint16_t devid, HAL_SOFTC sc,
58217624Sadrian	HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error)
59185377Ssam{
60186018Ssam	struct ath_hal_chip * const *pchip;
61185377Ssam
62185417Ssam	OS_SET_FOREACH(pchip, ah_chips) {
63185406Ssam		struct ath_hal_chip *chip = *pchip;
64185406Ssam		struct ath_hal *ah;
65185406Ssam
66185406Ssam		/* XXX don't have vendorid, assume atheros one works */
67185406Ssam		if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
68185406Ssam			continue;
69217624Sadrian		ah = chip->attach(devid, sc, st, sh, eepromdata, error);
70185406Ssam		if (ah != AH_NULL) {
71185406Ssam			/* copy back private state to public area */
72185406Ssam			ah->ah_devid = AH_PRIVATE(ah)->ah_devid;
73185406Ssam			ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid;
74185406Ssam			ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion;
75185406Ssam			ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev;
76185406Ssam			ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev;
77185406Ssam			ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev;
78185406Ssam			ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev;
79185406Ssam			return ah;
80185406Ssam		}
81185377Ssam	}
82185406Ssam	return AH_NULL;
83185406Ssam}
84185406Ssam
85188968Ssamconst char *
86188968Ssamath_hal_mac_name(struct ath_hal *ah)
87188968Ssam{
88188968Ssam	switch (ah->ah_macVersion) {
89188968Ssam	case AR_SREV_VERSION_CRETE:
90188968Ssam	case AR_SREV_VERSION_MAUI_1:
91188968Ssam		return "5210";
92188968Ssam	case AR_SREV_VERSION_MAUI_2:
93188968Ssam	case AR_SREV_VERSION_OAHU:
94188968Ssam		return "5211";
95188968Ssam	case AR_SREV_VERSION_VENICE:
96188968Ssam		return "5212";
97188968Ssam	case AR_SREV_VERSION_GRIFFIN:
98188968Ssam		return "2413";
99188968Ssam	case AR_SREV_VERSION_CONDOR:
100188968Ssam		return "5424";
101188968Ssam	case AR_SREV_VERSION_EAGLE:
102188968Ssam		return "5413";
103188968Ssam	case AR_SREV_VERSION_COBRA:
104188968Ssam		return "2415";
105239603Sadrian	case AR_SREV_2425:	/* Swan */
106188968Ssam		return "2425";
107239603Sadrian	case AR_SREV_2417:	/* Nala */
108188968Ssam		return "2417";
109188968Ssam	case AR_XSREV_VERSION_OWL_PCI:
110188968Ssam		return "5416";
111188968Ssam	case AR_XSREV_VERSION_OWL_PCIE:
112188968Ssam		return "5418";
113221163Sadrian	case AR_XSREV_VERSION_HOWL:
114221163Sadrian		return "9130";
115188968Ssam	case AR_XSREV_VERSION_SOWL:
116188968Ssam		return "9160";
117188968Ssam	case AR_XSREV_VERSION_MERLIN:
118227372Sadrian		if (AH_PRIVATE(ah)->ah_ispcie)
119227372Sadrian			return "9280";
120227372Sadrian		return "9220";
121188968Ssam	case AR_XSREV_VERSION_KITE:
122188968Ssam		return "9285";
123222305Sadrian	case AR_XSREV_VERSION_KIWI:
124227372Sadrian		if (AH_PRIVATE(ah)->ah_ispcie)
125227372Sadrian			return "9287";
126227372Sadrian		return "9227";
127239604Sadrian	case AR_SREV_VERSION_AR9380:
128239604Sadrian		if (ah->ah_macRev >= AR_SREV_REVISION_AR9580_10)
129239604Sadrian			return "9580";
130239604Sadrian		return "9380";
131239604Sadrian	case AR_SREV_VERSION_AR9460:
132239604Sadrian		return "9460";
133239604Sadrian	case AR_SREV_VERSION_AR9330:
134239604Sadrian		return "9330";
135239604Sadrian	case AR_SREV_VERSION_AR9340:
136239604Sadrian		return "9340";
137239604Sadrian	case AR_SREV_VERSION_QCA9550:
138239604Sadrian		/* XXX should say QCA, not AR */
139239604Sadrian		return "9550";
140239604Sadrian	case AR_SREV_VERSION_AR9485:
141239604Sadrian		return "9485";
142250166Sadrian	case AR_SREV_VERSION_QCA9565:
143250166Sadrian		/* XXX should say QCA, not AR */
144250166Sadrian		return "9565";
145188968Ssam	}
146188968Ssam	return "????";
147188968Ssam}
148188968Ssam
149187831Ssam/*
150187831Ssam * Return the mask of available modes based on the hardware capabilities.
151187831Ssam */
152187831Ssamu_int
153187831Ssamath_hal_getwirelessmodes(struct ath_hal*ah)
154187831Ssam{
155187831Ssam	return ath_hal_getWirelessModes(ah);
156187831Ssam}
157187831Ssam
158185406Ssam/* linker set of registered RF backends */
159185406SsamOS_SET_DECLARE(ah_rfs, struct ath_hal_rf);
160185406Ssam
161185406Ssam/*
162185406Ssam * Check the set of registered RF backends to see if
163185406Ssam * any recognize the device as one they can support.
164185406Ssam */
165185406Ssamstruct ath_hal_rf *
166185406Ssamath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode)
167185406Ssam{
168186018Ssam	struct ath_hal_rf * const *prf;
169185406Ssam
170185417Ssam	OS_SET_FOREACH(prf, ah_rfs) {
171185406Ssam		struct ath_hal_rf *rf = *prf;
172185406Ssam		if (rf->probe(ah))
173185406Ssam			return rf;
174185377Ssam	}
175185406Ssam	*ecode = HAL_ENOTSUPP;
176185406Ssam	return AH_NULL;
177185377Ssam}
178185377Ssam
179188968Ssamconst char *
180188968Ssamath_hal_rf_name(struct ath_hal *ah)
181188968Ssam{
182188968Ssam	switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
183188968Ssam	case 0:			/* 5210 */
184188968Ssam		return "5110";	/* NB: made up */
185188968Ssam	case AR_RAD5111_SREV_MAJOR:
186188968Ssam	case AR_RAD5111_SREV_PROD:
187188968Ssam		return "5111";
188188968Ssam	case AR_RAD2111_SREV_MAJOR:
189188968Ssam		return "2111";
190188968Ssam	case AR_RAD5112_SREV_MAJOR:
191188968Ssam	case AR_RAD5112_SREV_2_0:
192188968Ssam	case AR_RAD5112_SREV_2_1:
193188968Ssam		return "5112";
194188968Ssam	case AR_RAD2112_SREV_MAJOR:
195188968Ssam	case AR_RAD2112_SREV_2_0:
196188968Ssam	case AR_RAD2112_SREV_2_1:
197188968Ssam		return "2112";
198188968Ssam	case AR_RAD2413_SREV_MAJOR:
199188968Ssam		return "2413";
200188968Ssam	case AR_RAD5413_SREV_MAJOR:
201188968Ssam		return "5413";
202188968Ssam	case AR_RAD2316_SREV_MAJOR:
203188968Ssam		return "2316";
204188968Ssam	case AR_RAD2317_SREV_MAJOR:
205188968Ssam		return "2317";
206188968Ssam	case AR_RAD5424_SREV_MAJOR:
207188968Ssam		return "5424";
208188968Ssam
209188968Ssam	case AR_RAD5133_SREV_MAJOR:
210188968Ssam		return "5133";
211188968Ssam	case AR_RAD2133_SREV_MAJOR:
212188968Ssam		return "2133";
213188968Ssam	case AR_RAD5122_SREV_MAJOR:
214188968Ssam		return "5122";
215188968Ssam	case AR_RAD2122_SREV_MAJOR:
216188968Ssam		return "2122";
217188968Ssam	}
218188968Ssam	return "????";
219188968Ssam}
220188968Ssam
221185377Ssam/*
222185377Ssam * Poll the register looking for a specific value.
223185377Ssam */
224185377SsamHAL_BOOL
225185377Ssamath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val)
226185377Ssam{
227185377Ssam#define	AH_TIMEOUT	1000
228217622Sadrian	return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT);
229217622Sadrian#undef AH_TIMEOUT
230217622Sadrian}
231217622Sadrian
232217622SadrianHAL_BOOL
233217622Sadrianath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout)
234217622Sadrian{
235185377Ssam	int i;
236185377Ssam
237217622Sadrian	for (i = 0; i < timeout; i++) {
238185377Ssam		if ((OS_REG_READ(ah, reg) & mask) == val)
239185377Ssam			return AH_TRUE;
240185377Ssam		OS_DELAY(10);
241185377Ssam	}
242185377Ssam	HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO,
243185377Ssam	    "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
244185377Ssam	    __func__, reg, OS_REG_READ(ah, reg), mask, val);
245185377Ssam	return AH_FALSE;
246185377Ssam}
247185377Ssam
248185377Ssam/*
249185377Ssam * Reverse the bits starting at the low bit for a value of
250185377Ssam * bit_count in size
251185377Ssam */
252185377Ssamuint32_t
253185377Ssamath_hal_reverseBits(uint32_t val, uint32_t n)
254185377Ssam{
255185377Ssam	uint32_t retval;
256185377Ssam	int i;
257185377Ssam
258185377Ssam	for (i = 0, retval = 0; i < n; i++) {
259185377Ssam		retval = (retval << 1) | (val & 1);
260185377Ssam		val >>= 1;
261185377Ssam	}
262185377Ssam	return retval;
263185377Ssam}
264185377Ssam
265218011Sadrian/* 802.11n related timing definitions */
266218011Sadrian
267218011Sadrian#define	OFDM_PLCP_BITS	22
268218011Sadrian#define	HT_L_STF	8
269218011Sadrian#define	HT_L_LTF	8
270218011Sadrian#define	HT_L_SIG	4
271218011Sadrian#define	HT_SIG		8
272218011Sadrian#define	HT_STF		4
273218011Sadrian#define	HT_LTF(n)	((n) * 4)
274218011Sadrian
275218011Sadrian#define	HT_RC_2_MCS(_rc)	((_rc) & 0xf)
276218011Sadrian#define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
277218011Sadrian#define	IS_HT_RATE(_rc)		( (_rc) & IEEE80211_RATE_MCS)
278218011Sadrian
279185377Ssam/*
280218011Sadrian * Calculate the duration of a packet whether it is 11n or legacy.
281218011Sadrian */
282218011Sadrianuint32_t
283218011Sadrianath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen,
284218011Sadrian    uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble)
285218011Sadrian{
286218011Sadrian	uint8_t rc;
287218011Sadrian	int numStreams;
288218011Sadrian
289218011Sadrian	rc = rates->info[rateix].rateCode;
290218011Sadrian
291218011Sadrian	/* Legacy rate? Return the old way */
292218011Sadrian	if (! IS_HT_RATE(rc))
293218011Sadrian		return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble);
294218011Sadrian
295218011Sadrian	/* 11n frame - extract out the number of spatial streams */
296218011Sadrian	numStreams = HT_RC_2_STREAMS(rc);
297239287Sadrian	KASSERT(numStreams > 0 && numStreams <= 4,
298239287Sadrian	    ("number of spatial streams needs to be 1..3: MCS rate 0x%x!",
299239287Sadrian	    rateix));
300218011Sadrian
301218011Sadrian	return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble);
302218011Sadrian}
303218011Sadrian
304239287Sadrianstatic const uint16_t ht20_bps[32] = {
305239287Sadrian    26, 52, 78, 104, 156, 208, 234, 260,
306239287Sadrian    52, 104, 156, 208, 312, 416, 468, 520,
307239287Sadrian    78, 156, 234, 312, 468, 624, 702, 780,
308239287Sadrian    104, 208, 312, 416, 624, 832, 936, 1040
309239287Sadrian};
310239287Sadrianstatic const uint16_t ht40_bps[32] = {
311239287Sadrian    54, 108, 162, 216, 324, 432, 486, 540,
312239287Sadrian    108, 216, 324, 432, 648, 864, 972, 1080,
313239287Sadrian    162, 324, 486, 648, 972, 1296, 1458, 1620,
314239287Sadrian    216, 432, 648, 864, 1296, 1728, 1944, 2160
315239287Sadrian};
316239287Sadrian
317218011Sadrian/*
318218011Sadrian * Calculate the transmit duration of an 11n frame.
319218011Sadrian */
320218011Sadrianuint32_t
321239287Sadrianath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams,
322239287Sadrian    HAL_BOOL isht40, HAL_BOOL isShortGI)
323218011Sadrian{
324218011Sadrian	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
325218011Sadrian
326218011Sadrian	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
327239287Sadrian	KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
328218011Sadrian
329218011Sadrian	if (isht40)
330250824Sadrian		bitsPerSymbol = ht40_bps[rate & 0x1f];
331218011Sadrian	else
332250824Sadrian		bitsPerSymbol = ht20_bps[rate & 0x1f];
333218011Sadrian	numBits = OFDM_PLCP_BITS + (frameLen << 3);
334218011Sadrian	numSymbols = howmany(numBits, bitsPerSymbol);
335218011Sadrian	if (isShortGI)
336218011Sadrian		txTime = ((numSymbols * 18) + 4) / 5;   /* 3.6us */
337218011Sadrian	else
338218011Sadrian		txTime = numSymbols * 4;                /* 4us */
339218011Sadrian	return txTime + HT_L_STF + HT_L_LTF +
340218011Sadrian	    HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
341218011Sadrian}
342218011Sadrian
343218011Sadrian/*
344185377Ssam * Compute the time to transmit a frame of length frameLen bytes
345185377Ssam * using the specified rate, phy, and short preamble setting.
346185377Ssam */
347185377Ssamuint16_t
348185377Ssamath_hal_computetxtime(struct ath_hal *ah,
349185377Ssam	const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix,
350185377Ssam	HAL_BOOL shortPreamble)
351185377Ssam{
352185377Ssam	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
353185377Ssam	uint32_t kbps;
354185377Ssam
355218923Sadrian	/* Warn if this function is called for 11n rates; it should not be! */
356218923Sadrian	if (IS_HT_RATE(rates->info[rateix].rateCode))
357218923Sadrian		ath_hal_printf(ah, "%s: MCS rate? (index %d; hwrate 0x%x)\n",
358218923Sadrian		    __func__, rateix, rates->info[rateix].rateCode);
359218923Sadrian
360185377Ssam	kbps = rates->info[rateix].rateKbps;
361185377Ssam	/*
362185377Ssam	 * index can be invalid duting dynamic Turbo transitions.
363187831Ssam	 * XXX
364185377Ssam	 */
365187831Ssam	if (kbps == 0)
366187831Ssam		return 0;
367185377Ssam	switch (rates->info[rateix].phy) {
368185377Ssam	case IEEE80211_T_CCK:
369185377Ssam		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
370185377Ssam		if (shortPreamble && rates->info[rateix].shortPreamble)
371185377Ssam			phyTime >>= 1;
372185377Ssam		numBits		= frameLen << 3;
373185377Ssam		txTime		= CCK_SIFS_TIME + phyTime
374185377Ssam				+ ((numBits * 1000)/kbps);
375185377Ssam		break;
376185377Ssam	case IEEE80211_T_OFDM:
377188773Ssam		bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
378188773Ssam		HALASSERT(bitsPerSymbol != 0);
379185377Ssam
380188773Ssam		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
381188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
382188773Ssam		txTime		= OFDM_SIFS_TIME
383188773Ssam				+ OFDM_PREAMBLE_TIME
384188773Ssam				+ (numSymbols * OFDM_SYMBOL_TIME);
385188773Ssam		break;
386188773Ssam	case IEEE80211_T_OFDM_HALF:
387188773Ssam		bitsPerSymbol	= (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
388188773Ssam		HALASSERT(bitsPerSymbol != 0);
389185377Ssam
390188773Ssam		numBits		= OFDM_HALF_PLCP_BITS + (frameLen << 3);
391188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
392188773Ssam		txTime		= OFDM_HALF_SIFS_TIME
393188773Ssam				+ OFDM_HALF_PREAMBLE_TIME
394188773Ssam				+ (numSymbols * OFDM_HALF_SYMBOL_TIME);
395188773Ssam		break;
396188773Ssam	case IEEE80211_T_OFDM_QUARTER:
397188773Ssam		bitsPerSymbol	= (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
398188773Ssam		HALASSERT(bitsPerSymbol != 0);
399185377Ssam
400188773Ssam		numBits		= OFDM_QUARTER_PLCP_BITS + (frameLen << 3);
401188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
402188773Ssam		txTime		= OFDM_QUARTER_SIFS_TIME
403188773Ssam				+ OFDM_QUARTER_PREAMBLE_TIME
404188773Ssam				+ (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
405185377Ssam		break;
406185377Ssam	case IEEE80211_T_TURBO:
407191022Ssam		bitsPerSymbol	= (kbps * TURBO_SYMBOL_TIME) / 1000;
408185377Ssam		HALASSERT(bitsPerSymbol != 0);
409185377Ssam
410188773Ssam		numBits		= TURBO_PLCP_BITS + (frameLen << 3);
411188773Ssam		numSymbols	= howmany(numBits, bitsPerSymbol);
412188773Ssam		txTime		= TURBO_SIFS_TIME
413188773Ssam				+ TURBO_PREAMBLE_TIME
414188773Ssam				+ (numSymbols * TURBO_SYMBOL_TIME);
415185377Ssam		break;
416185377Ssam	default:
417185377Ssam		HALDEBUG(ah, HAL_DEBUG_PHYIO,
418185377Ssam		    "%s: unknown phy %u (rate ix %u)\n",
419185377Ssam		    __func__, rates->info[rateix].phy, rateix);
420185377Ssam		txTime = 0;
421185377Ssam		break;
422185377Ssam	}
423185377Ssam	return txTime;
424185377Ssam}
425185377Ssam
426239634Sadrianint
427239634Sadrianath_hal_get_curmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
428239634Sadrian{
429239634Sadrian	/*
430239634Sadrian	 * Pick a default mode at bootup. A channel change is inevitable.
431239634Sadrian	 */
432239634Sadrian	if (!chan)
433239634Sadrian		return HAL_MODE_11NG_HT20;
434239634Sadrian
435239634Sadrian	if (IEEE80211_IS_CHAN_TURBO(chan))
436239634Sadrian		return HAL_MODE_TURBO;
437239634Sadrian
438239634Sadrian	/* check for NA_HT before plain A, since IS_CHAN_A includes NA_HT */
439239634Sadrian	if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan))
440239634Sadrian		return HAL_MODE_11NA_HT20;
441239634Sadrian	if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan))
442239634Sadrian		return HAL_MODE_11NA_HT40PLUS;
443239634Sadrian	if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan))
444239634Sadrian		return HAL_MODE_11NA_HT40MINUS;
445239634Sadrian	if (IEEE80211_IS_CHAN_A(chan))
446239634Sadrian		return HAL_MODE_11A;
447239634Sadrian
448239634Sadrian	/* check for NG_HT before plain G, since IS_CHAN_G includes NG_HT */
449239634Sadrian	if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan))
450239634Sadrian		return HAL_MODE_11NG_HT20;
451239634Sadrian	if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan))
452239634Sadrian		return HAL_MODE_11NG_HT40PLUS;
453239634Sadrian	if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan))
454239634Sadrian		return HAL_MODE_11NG_HT40MINUS;
455239634Sadrian
456239634Sadrian	/*
457239634Sadrian	 * XXX For FreeBSD, will this work correctly given the DYN
458239634Sadrian	 * chan mode (OFDM+CCK dynamic) ? We have pure-G versions DYN-BG..
459239634Sadrian	 */
460239634Sadrian	if (IEEE80211_IS_CHAN_G(chan))
461239634Sadrian		return HAL_MODE_11G;
462239634Sadrian	if (IEEE80211_IS_CHAN_B(chan))
463239634Sadrian		return HAL_MODE_11B;
464239634Sadrian
465239634Sadrian	HALASSERT(0);
466239634Sadrian	return HAL_MODE_11NG_HT20;
467239634Sadrian}
468239634Sadrian
469239634Sadrian
470185377Ssamtypedef enum {
471185377Ssam	WIRELESS_MODE_11a   = 0,
472185377Ssam	WIRELESS_MODE_TURBO = 1,
473185377Ssam	WIRELESS_MODE_11b   = 2,
474185377Ssam	WIRELESS_MODE_11g   = 3,
475185377Ssam	WIRELESS_MODE_108g  = 4,
476185377Ssam
477185377Ssam	WIRELESS_MODE_MAX
478185377Ssam} WIRELESS_MODE;
479185377Ssam
480185377Ssamstatic WIRELESS_MODE
481187831Ssamath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
482185377Ssam{
483187831Ssam	if (IEEE80211_IS_CHAN_B(chan))
484185377Ssam		return WIRELESS_MODE_11b;
485187831Ssam	if (IEEE80211_IS_CHAN_G(chan))
486185377Ssam		return WIRELESS_MODE_11g;
487187831Ssam	if (IEEE80211_IS_CHAN_108G(chan))
488185377Ssam		return WIRELESS_MODE_108g;
489187831Ssam	if (IEEE80211_IS_CHAN_TURBO(chan))
490185377Ssam		return WIRELESS_MODE_TURBO;
491185377Ssam	return WIRELESS_MODE_11a;
492185377Ssam}
493185377Ssam
494185377Ssam/*
495185377Ssam * Convert between microseconds and core system clocks.
496185377Ssam */
497185377Ssam                                     /* 11a Turbo  11b  11g  108g */
498185377Ssamstatic const uint8_t CLOCK_RATE[]  = { 40,  80,   22,  44,   88  };
499185377Ssam
500220298Sadrian#define	CLOCK_FAST_RATE_5GHZ_OFDM	44
501220298Sadrian
502185377Ssamu_int
503185377Ssamath_hal_mac_clks(struct ath_hal *ah, u_int usecs)
504185377Ssam{
505187831Ssam	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
506185377Ssam	u_int clks;
507185377Ssam
508185377Ssam	/* NB: ah_curchan may be null when called attach time */
509220298Sadrian	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
510220298Sadrian	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
511220298Sadrian		clks = usecs * CLOCK_FAST_RATE_5GHZ_OFDM;
512220298Sadrian		if (IEEE80211_IS_CHAN_HT40(c))
513220298Sadrian			clks <<= 1;
514220298Sadrian	} else if (c != AH_NULL) {
515185377Ssam		clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
516187831Ssam		if (IEEE80211_IS_CHAN_HT40(c))
517185377Ssam			clks <<= 1;
518185377Ssam	} else
519185377Ssam		clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
520240444Sadrian
521240444Sadrian	/* Compensate for half/quarter rate */
522240444Sadrian	if (c != AH_NULL && IEEE80211_IS_CHAN_HALF(c))
523240444Sadrian		clks = clks / 2;
524240444Sadrian	else if (c != AH_NULL && IEEE80211_IS_CHAN_QUARTER(c))
525240444Sadrian		clks = clks / 4;
526240444Sadrian
527185377Ssam	return clks;
528185377Ssam}
529185377Ssam
530185377Ssamu_int
531185377Ssamath_hal_mac_usec(struct ath_hal *ah, u_int clks)
532185377Ssam{
533187831Ssam	const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan;
534185377Ssam	u_int usec;
535185377Ssam
536185377Ssam	/* NB: ah_curchan may be null when called attach time */
537220298Sadrian	/* XXX merlin and later specific workaround - 5ghz fast clock is 44 */
538220298Sadrian	if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) {
539220298Sadrian		usec = clks / CLOCK_FAST_RATE_5GHZ_OFDM;
540220298Sadrian		if (IEEE80211_IS_CHAN_HT40(c))
541220298Sadrian			usec >>= 1;
542220298Sadrian	} else if (c != AH_NULL) {
543185377Ssam		usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
544187831Ssam		if (IEEE80211_IS_CHAN_HT40(c))
545185377Ssam			usec >>= 1;
546185377Ssam	} else
547185377Ssam		usec = clks / CLOCK_RATE[WIRELESS_MODE_11b];
548185377Ssam	return usec;
549185377Ssam}
550185377Ssam
551185377Ssam/*
552185377Ssam * Setup a h/w rate table's reverse lookup table and
553185377Ssam * fill in ack durations.  This routine is called for
554185377Ssam * each rate table returned through the ah_getRateTable
555185377Ssam * method.  The reverse lookup tables are assumed to be
556185377Ssam * initialized to zero (or at least the first entry).
557185377Ssam * We use this as a key that indicates whether or not
558185377Ssam * we've previously setup the reverse lookup table.
559185377Ssam *
560185377Ssam * XXX not reentrant, but shouldn't matter
561185377Ssam */
562185377Ssamvoid
563185377Ssamath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt)
564185377Ssam{
565185377Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
566185377Ssam	int i;
567185377Ssam
568185377Ssam	if (rt->rateCodeToIndex[0] != 0)	/* already setup */
569185377Ssam		return;
570185377Ssam	for (i = 0; i < N(rt->rateCodeToIndex); i++)
571185377Ssam		rt->rateCodeToIndex[i] = (uint8_t) -1;
572185377Ssam	for (i = 0; i < rt->rateCount; i++) {
573185377Ssam		uint8_t code = rt->info[i].rateCode;
574185377Ssam		uint8_t cix = rt->info[i].controlRate;
575185377Ssam
576185377Ssam		HALASSERT(code < N(rt->rateCodeToIndex));
577185377Ssam		rt->rateCodeToIndex[code] = i;
578185377Ssam		HALASSERT((code | rt->info[i].shortPreamble) <
579185377Ssam		    N(rt->rateCodeToIndex));
580185377Ssam		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
581185377Ssam		/*
582185377Ssam		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
583185377Ssam		 *     depends on whether they are marked as basic rates;
584185377Ssam		 *     the static tables are setup with an 11b-compatible
585185377Ssam		 *     2Mb/s rate which will work but is suboptimal
586185377Ssam		 */
587185377Ssam		rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt,
588185377Ssam			WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE);
589185377Ssam		rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt,
590185377Ssam			WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE);
591185377Ssam	}
592185377Ssam#undef N
593185377Ssam}
594185377Ssam
595185377SsamHAL_STATUS
596185377Ssamath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
597185377Ssam	uint32_t capability, uint32_t *result)
598185377Ssam{
599185377Ssam	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
600185377Ssam
601185377Ssam	switch (type) {
602185377Ssam	case HAL_CAP_REG_DMN:		/* regulatory domain */
603185377Ssam		*result = AH_PRIVATE(ah)->ah_currentRD;
604185377Ssam		return HAL_OK;
605224716Sadrian	case HAL_CAP_DFS_DMN:		/* DFS Domain */
606224716Sadrian		*result = AH_PRIVATE(ah)->ah_dfsDomain;
607224716Sadrian		return HAL_OK;
608185377Ssam	case HAL_CAP_CIPHER:		/* cipher handled in hardware */
609185377Ssam	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
610185377Ssam		return HAL_ENOTSUPP;
611185377Ssam	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
612185377Ssam		return HAL_ENOTSUPP;
613185377Ssam	case HAL_CAP_PHYCOUNTERS:	/* hardware PHY error counters */
614185377Ssam		return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO;
615185377Ssam	case HAL_CAP_WME_TKIPMIC:   /* hardware can do TKIP MIC when WMM is turned on */
616185377Ssam		return HAL_ENOTSUPP;
617185377Ssam	case HAL_CAP_DIVERSITY:		/* hardware supports fast diversity */
618185377Ssam		return HAL_ENOTSUPP;
619185377Ssam	case HAL_CAP_KEYCACHE_SIZE:	/* hardware key cache size */
620185377Ssam		*result =  pCap->halKeyCacheSize;
621185377Ssam		return HAL_OK;
622185377Ssam	case HAL_CAP_NUM_TXQUEUES:	/* number of hardware tx queues */
623185377Ssam		*result = pCap->halTotalQueues;
624185377Ssam		return HAL_OK;
625185377Ssam	case HAL_CAP_VEOL:		/* hardware supports virtual EOL */
626185377Ssam		return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP;
627185377Ssam	case HAL_CAP_PSPOLL:		/* hardware PS-Poll support works */
628185377Ssam		return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK;
629185377Ssam	case HAL_CAP_COMPRESSION:
630185377Ssam		return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP;
631185377Ssam	case HAL_CAP_BURST:
632185377Ssam		return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP;
633185377Ssam	case HAL_CAP_FASTFRAME:
634185377Ssam		return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP;
635185377Ssam	case HAL_CAP_DIAG:		/* hardware diagnostic support */
636185377Ssam		*result = AH_PRIVATE(ah)->ah_diagreg;
637185377Ssam		return HAL_OK;
638185377Ssam	case HAL_CAP_TXPOW:		/* global tx power limit  */
639185377Ssam		switch (capability) {
640185377Ssam		case 0:			/* facility is supported */
641185377Ssam			return HAL_OK;
642185377Ssam		case 1:			/* current limit */
643185377Ssam			*result = AH_PRIVATE(ah)->ah_powerLimit;
644185377Ssam			return HAL_OK;
645185377Ssam		case 2:			/* current max tx power */
646185377Ssam			*result = AH_PRIVATE(ah)->ah_maxPowerLevel;
647185377Ssam			return HAL_OK;
648185377Ssam		case 3:			/* scale factor */
649185377Ssam			*result = AH_PRIVATE(ah)->ah_tpScale;
650185377Ssam			return HAL_OK;
651185377Ssam		}
652185377Ssam		return HAL_ENOTSUPP;
653185377Ssam	case HAL_CAP_BSSIDMASK:		/* hardware supports bssid mask */
654185377Ssam		return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP;
655185377Ssam	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
656185377Ssam		return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
657185377Ssam	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
658185377Ssam		return HAL_ENOTSUPP;
659185377Ssam	case HAL_CAP_RFSILENT:		/* rfsilent support  */
660185377Ssam		switch (capability) {
661185377Ssam		case 0:			/* facility is supported */
662185377Ssam			return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP;
663185377Ssam		case 1:			/* current setting */
664185377Ssam			return AH_PRIVATE(ah)->ah_rfkillEnabled ?
665185377Ssam				HAL_OK : HAL_ENOTSUPP;
666185377Ssam		case 2:			/* rfsilent config */
667185377Ssam			*result = AH_PRIVATE(ah)->ah_rfsilent;
668185377Ssam			return HAL_OK;
669185377Ssam		}
670185377Ssam		return HAL_ENOTSUPP;
671185377Ssam	case HAL_CAP_11D:
672185377Ssam		return HAL_OK;
673221603Sadrian
674185377Ssam	case HAL_CAP_HT:
675185377Ssam		return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP;
676221603Sadrian	case HAL_CAP_GTXTO:
677221603Sadrian		return pCap->halGTTSupport ? HAL_OK : HAL_ENOTSUPP;
678221603Sadrian	case HAL_CAP_FAST_CC:
679221603Sadrian		return pCap->halFastCCSupport ? HAL_OK : HAL_ENOTSUPP;
680185377Ssam	case HAL_CAP_TX_CHAINMASK:	/* mask of TX chains supported */
681185377Ssam		*result = pCap->halTxChainMask;
682185377Ssam		return HAL_OK;
683185377Ssam	case HAL_CAP_RX_CHAINMASK:	/* mask of RX chains supported */
684185377Ssam		*result = pCap->halRxChainMask;
685185377Ssam		return HAL_OK;
686221603Sadrian	case HAL_CAP_NUM_GPIO_PINS:
687221603Sadrian		*result = pCap->halNumGpioPins;
688221603Sadrian		return HAL_OK;
689221603Sadrian	case HAL_CAP_CST:
690221603Sadrian		return pCap->halCSTSupport ? HAL_OK : HAL_ENOTSUPP;
691221603Sadrian	case HAL_CAP_RTS_AGGR_LIMIT:
692221603Sadrian		*result = pCap->halRtsAggrLimit;
693221603Sadrian		return HAL_OK;
694221603Sadrian	case HAL_CAP_4ADDR_AGGR:
695221603Sadrian		return pCap->hal4AddrAggrSupport ? HAL_OK : HAL_ENOTSUPP;
696222584Sadrian	case HAL_CAP_EXT_CHAN_DFS:
697222584Sadrian		return pCap->halExtChanDfsSupport ? HAL_OK : HAL_ENOTSUPP;
698247366Sadrian	case HAL_CAP_RX_STBC:
699247366Sadrian		return pCap->halRxStbcSupport ? HAL_OK : HAL_ENOTSUPP;
700247366Sadrian	case HAL_CAP_TX_STBC:
701247366Sadrian		return pCap->halTxStbcSupport ? HAL_OK : HAL_ENOTSUPP;
702238333Sadrian	case HAL_CAP_COMBINED_RADAR_RSSI:
703238333Sadrian		return pCap->halUseCombinedRadarRssi ? HAL_OK : HAL_ENOTSUPP;
704238333Sadrian	case HAL_CAP_AUTO_SLEEP:
705238333Sadrian		return pCap->halAutoSleepSupport ? HAL_OK : HAL_ENOTSUPP;
706238333Sadrian	case HAL_CAP_MBSSID_AGGR_SUPPORT:
707238333Sadrian		return pCap->halMbssidAggrSupport ? HAL_OK : HAL_ENOTSUPP;
708238333Sadrian	case HAL_CAP_SPLIT_4KB_TRANS:	/* hardware handles descriptors straddling 4k page boundary */
709238333Sadrian		return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP;
710238333Sadrian	case HAL_CAP_REG_FLAG:
711238333Sadrian		*result = AH_PRIVATE(ah)->ah_currentRDext;
712238333Sadrian		return HAL_OK;
713238333Sadrian	case HAL_CAP_ENHANCED_DMA_SUPPORT:
714238333Sadrian		return pCap->halEnhancedDmaSupport ? HAL_OK : HAL_ENOTSUPP;
715238280Sadrian	case HAL_CAP_NUM_TXMAPS:
716238280Sadrian		*result = pCap->halNumTxMaps;
717238280Sadrian		return HAL_OK;
718238280Sadrian	case HAL_CAP_TXDESCLEN:
719238280Sadrian		*result = pCap->halTxDescLen;
720238280Sadrian		return HAL_OK;
721238280Sadrian	case HAL_CAP_TXSTATUSLEN:
722238280Sadrian		*result = pCap->halTxStatusLen;
723238280Sadrian		return HAL_OK;
724238280Sadrian	case HAL_CAP_RXSTATUSLEN:
725238280Sadrian		*result = pCap->halRxStatusLen;
726238280Sadrian		return HAL_OK;
727238280Sadrian	case HAL_CAP_RXFIFODEPTH:
728238280Sadrian		switch (capability) {
729238280Sadrian		case HAL_RX_QUEUE_HP:
730238280Sadrian			*result = pCap->halRxHpFifoDepth;
731238280Sadrian			return HAL_OK;
732238280Sadrian		case HAL_RX_QUEUE_LP:
733238280Sadrian			*result = pCap->halRxLpFifoDepth;
734238280Sadrian			return HAL_OK;
735238280Sadrian		default:
736238280Sadrian			return HAL_ENOTSUPP;
737238280Sadrian	}
738238280Sadrian	case HAL_CAP_RXBUFSIZE:
739238280Sadrian	case HAL_CAP_NUM_MR_RETRIES:
740238858Sadrian		*result = pCap->halNumMRRetries;
741238858Sadrian		return HAL_OK;
742221603Sadrian	case HAL_CAP_BT_COEX:
743221603Sadrian		return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP;
744244854Sadrian	case HAL_CAP_SPECTRAL_SCAN:
745244854Sadrian		return pCap->halSpectralScanSupport ? HAL_OK : HAL_ENOTSUPP;
746221603Sadrian	case HAL_CAP_HT20_SGI:
747221603Sadrian		return pCap->halHTSGI20Support ? HAL_OK : HAL_ENOTSUPP;
748185377Ssam	case HAL_CAP_RXTSTAMP_PREC:	/* rx desc tstamp precision (bits) */
749185377Ssam		*result = pCap->halTstampPrecision;
750185377Ssam		return HAL_OK;
751251360Sadrian	case HAL_CAP_ANT_DIV_COMB:	/* AR9285/AR9485 LNA diversity */
752251360Sadrian		return pCap->halAntDivCombSupport ? HAL_OK  : HAL_ENOTSUPP;
753251360Sadrian
754222584Sadrian	case HAL_CAP_ENHANCED_DFS_SUPPORT:
755222584Sadrian		return pCap->halEnhancedDfsSupport ? HAL_OK : HAL_ENOTSUPP;
756221603Sadrian
757221603Sadrian	/* FreeBSD-specific entries for now */
758221603Sadrian	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
759221603Sadrian		return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP;
760192396Ssam	case HAL_CAP_INTRMASK:		/* mask of supported interrupts */
761192396Ssam		*result = pCap->halIntrMask;
762192396Ssam		return HAL_OK;
763195114Ssam	case HAL_CAP_BSSIDMATCH:	/* hardware has disable bssid match */
764195114Ssam		return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP;
765218150Sadrian	case HAL_CAP_STREAMS:		/* number of 11n spatial streams */
766218150Sadrian		switch (capability) {
767218150Sadrian		case 0:			/* TX */
768218150Sadrian			*result = pCap->halTxStreams;
769218150Sadrian			return HAL_OK;
770218150Sadrian		case 1:			/* RX */
771218150Sadrian			*result = pCap->halRxStreams;
772218150Sadrian			return HAL_OK;
773218150Sadrian		default:
774218150Sadrian			return HAL_ENOTSUPP;
775218150Sadrian		}
776220324Sadrian	case HAL_CAP_RXDESC_SELFLINK:	/* hardware supports self-linked final RX descriptors correctly */
777220324Sadrian		return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP;
778225444Sadrian	case HAL_CAP_LONG_RXDESC_TSF:		/* 32 bit TSF in RX descriptor? */
779225444Sadrian		return pCap->halHasLongRxDescTsf ? HAL_OK : HAL_ENOTSUPP;
780226488Sadrian	case HAL_CAP_BB_READ_WAR:		/* Baseband read WAR */
781226488Sadrian		return pCap->halHasBBReadWar? HAL_OK : HAL_ENOTSUPP;
782227410Sadrian	case HAL_CAP_SERIALISE_WAR:		/* PCI register serialisation */
783227410Sadrian		return pCap->halSerialiseRegWar ? HAL_OK : HAL_ENOTSUPP;
784239630Sadrian	case HAL_CAP_MFP:			/* Management frame protection setting */
785239630Sadrian		*result = pCap->halMfpSupport;
786239630Sadrian		return HAL_OK;
787251400Sadrian	case HAL_CAP_RX_LNA_MIXING:	/* Hardware uses an RX LNA mixer to map 2 antennas to a 1 stream receiver */
788251400Sadrian		return pCap->halRxUsingLnaMixing ? HAL_OK : HAL_ENOTSUPP;
789185377Ssam	default:
790185377Ssam		return HAL_EINVAL;
791185377Ssam	}
792185377Ssam}
793185377Ssam
794185377SsamHAL_BOOL
795185377Ssamath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
796185377Ssam	uint32_t capability, uint32_t setting, HAL_STATUS *status)
797185377Ssam{
798185377Ssam
799185377Ssam	switch (type) {
800185377Ssam	case HAL_CAP_TXPOW:
801185377Ssam		switch (capability) {
802185377Ssam		case 3:
803185377Ssam			if (setting <= HAL_TP_SCALE_MIN) {
804185377Ssam				AH_PRIVATE(ah)->ah_tpScale = setting;
805185377Ssam				return AH_TRUE;
806185377Ssam			}
807185377Ssam			break;
808185377Ssam		}
809185377Ssam		break;
810185377Ssam	case HAL_CAP_RFSILENT:		/* rfsilent support  */
811185377Ssam		/*
812185377Ssam		 * NB: allow even if halRfSilentSupport is false
813185377Ssam		 *     in case the EEPROM is misprogrammed.
814185377Ssam		 */
815185377Ssam		switch (capability) {
816185377Ssam		case 1:			/* current setting */
817185377Ssam			AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0);
818185377Ssam			return AH_TRUE;
819185377Ssam		case 2:			/* rfsilent config */
820185377Ssam			/* XXX better done per-chip for validation? */
821185377Ssam			AH_PRIVATE(ah)->ah_rfsilent = setting;
822185377Ssam			return AH_TRUE;
823185377Ssam		}
824185377Ssam		break;
825185377Ssam	case HAL_CAP_REG_DMN:		/* regulatory domain */
826185377Ssam		AH_PRIVATE(ah)->ah_currentRD = setting;
827185377Ssam		return AH_TRUE;
828185377Ssam	case HAL_CAP_RXORN_FATAL:	/* HAL_INT_RXORN treated as fatal  */
829185377Ssam		AH_PRIVATE(ah)->ah_rxornIsFatal = setting;
830185377Ssam		return AH_TRUE;
831185377Ssam	default:
832185377Ssam		break;
833185377Ssam	}
834185377Ssam	if (status)
835185377Ssam		*status = HAL_EINVAL;
836185377Ssam	return AH_FALSE;
837185377Ssam}
838185377Ssam
839185377Ssam/*
840185377Ssam * Common support for getDiagState method.
841185377Ssam */
842185377Ssam
843185377Ssamstatic u_int
844185377Ssamath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
845185377Ssam	void *dstbuf, int space)
846185377Ssam{
847185377Ssam	uint32_t *dp = dstbuf;
848185377Ssam	int i;
849185377Ssam
850185377Ssam	for (i = 0; space >= 2*sizeof(uint32_t); i++) {
851185377Ssam		u_int r = regs[i].start;
852185377Ssam		u_int e = regs[i].end;
853185377Ssam		*dp++ = (r<<16) | e;
854185377Ssam		space -= sizeof(uint32_t);
855185377Ssam		do {
856185377Ssam			*dp++ = OS_REG_READ(ah, r);
857185377Ssam			r += sizeof(uint32_t);
858185377Ssam			space -= sizeof(uint32_t);
859185377Ssam		} while (r <= e && space >= sizeof(uint32_t));
860185377Ssam	}
861185377Ssam	return (char *) dp - (char *) dstbuf;
862185377Ssam}
863188771Ssam
864188771Ssamstatic void
865188771Ssamath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space)
866188771Ssam{
867188771Ssam	while (space >= sizeof(HAL_REGWRITE)) {
868188771Ssam		OS_REG_WRITE(ah, regs->addr, regs->value);
869188771Ssam		regs++, space -= sizeof(HAL_REGWRITE);
870188771Ssam	}
871188771Ssam}
872185377Ssam
873185377SsamHAL_BOOL
874185377Ssamath_hal_getdiagstate(struct ath_hal *ah, int request,
875185377Ssam	const void *args, uint32_t argsize,
876185377Ssam	void **result, uint32_t *resultsize)
877185377Ssam{
878185377Ssam	switch (request) {
879185377Ssam	case HAL_DIAG_REVS:
880185377Ssam		*result = &AH_PRIVATE(ah)->ah_devid;
881185377Ssam		*resultsize = sizeof(HAL_REVS);
882185377Ssam		return AH_TRUE;
883185377Ssam	case HAL_DIAG_REGS:
884185377Ssam		*resultsize = ath_hal_getregdump(ah, args, *result,*resultsize);
885185377Ssam		return AH_TRUE;
886188771Ssam	case HAL_DIAG_SETREGS:
887188771Ssam		ath_hal_setregs(ah, args, argsize);
888188771Ssam		*resultsize = 0;
889188771Ssam		return AH_TRUE;
890185377Ssam	case HAL_DIAG_FATALERR:
891185377Ssam		*result = &AH_PRIVATE(ah)->ah_fatalState[0];
892185377Ssam		*resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState);
893185377Ssam		return AH_TRUE;
894185377Ssam	case HAL_DIAG_EEREAD:
895185377Ssam		if (argsize != sizeof(uint16_t))
896185377Ssam			return AH_FALSE;
897185377Ssam		if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result))
898185377Ssam			return AH_FALSE;
899185377Ssam		*resultsize = sizeof(uint16_t);
900185377Ssam		return AH_TRUE;
901185377Ssam#ifdef AH_PRIVATE_DIAG
902185377Ssam	case HAL_DIAG_SETKEY: {
903185377Ssam		const HAL_DIAG_KEYVAL *dk;
904185377Ssam
905185377Ssam		if (argsize != sizeof(HAL_DIAG_KEYVAL))
906185377Ssam			return AH_FALSE;
907185377Ssam		dk = (const HAL_DIAG_KEYVAL *)args;
908185377Ssam		return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix,
909185377Ssam			&dk->dk_keyval, dk->dk_mac, dk->dk_xor);
910185377Ssam	}
911185377Ssam	case HAL_DIAG_RESETKEY:
912185377Ssam		if (argsize != sizeof(uint16_t))
913185377Ssam			return AH_FALSE;
914185377Ssam		return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
915185380Ssam#ifdef AH_SUPPORT_WRITE_EEPROM
916185380Ssam	case HAL_DIAG_EEWRITE: {
917185380Ssam		const HAL_DIAG_EEVAL *ee;
918185380Ssam		if (argsize != sizeof(HAL_DIAG_EEVAL))
919185380Ssam			return AH_FALSE;
920185380Ssam		ee = (const HAL_DIAG_EEVAL *)args;
921185380Ssam		return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
922185380Ssam	}
923185380Ssam#endif /* AH_SUPPORT_WRITE_EEPROM */
924185377Ssam#endif /* AH_PRIVATE_DIAG */
925185377Ssam	case HAL_DIAG_11NCOMPAT:
926185377Ssam		if (argsize == 0) {
927185377Ssam			*resultsize = sizeof(uint32_t);
928185377Ssam			*((uint32_t *)(*result)) =
929185377Ssam				AH_PRIVATE(ah)->ah_11nCompat;
930185377Ssam		} else if (argsize == sizeof(uint32_t)) {
931185377Ssam			AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args;
932185377Ssam		} else
933185377Ssam			return AH_FALSE;
934185377Ssam		return AH_TRUE;
935185377Ssam	}
936185377Ssam	return AH_FALSE;
937185377Ssam}
938185377Ssam
939185377Ssam/*
940185377Ssam * Set the properties of the tx queue with the parameters
941185377Ssam * from qInfo.
942185377Ssam */
943185377SsamHAL_BOOL
944185377Ssamath_hal_setTxQProps(struct ath_hal *ah,
945185377Ssam	HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo)
946185377Ssam{
947185377Ssam	uint32_t cw;
948185377Ssam
949185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
950185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
951185377Ssam		    "%s: inactive queue\n", __func__);
952185377Ssam		return AH_FALSE;
953185377Ssam	}
954185377Ssam	/* XXX validate parameters */
955185377Ssam	qi->tqi_ver = qInfo->tqi_ver;
956185377Ssam	qi->tqi_subtype = qInfo->tqi_subtype;
957185377Ssam	qi->tqi_qflags = qInfo->tqi_qflags;
958185377Ssam	qi->tqi_priority = qInfo->tqi_priority;
959185377Ssam	if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT)
960185377Ssam		qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255);
961185377Ssam	else
962185377Ssam		qi->tqi_aifs = INIT_AIFS;
963185377Ssam	if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) {
964185377Ssam		cw = AH_MIN(qInfo->tqi_cwmin, 1024);
965185377Ssam		/* make sure that the CWmin is of the form (2^n - 1) */
966185377Ssam		qi->tqi_cwmin = 1;
967185377Ssam		while (qi->tqi_cwmin < cw)
968185377Ssam			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
969185377Ssam	} else
970185377Ssam		qi->tqi_cwmin = qInfo->tqi_cwmin;
971185377Ssam	if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) {
972185377Ssam		cw = AH_MIN(qInfo->tqi_cwmax, 1024);
973185377Ssam		/* make sure that the CWmax is of the form (2^n - 1) */
974185377Ssam		qi->tqi_cwmax = 1;
975185377Ssam		while (qi->tqi_cwmax < cw)
976185377Ssam			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
977185377Ssam	} else
978185377Ssam		qi->tqi_cwmax = INIT_CWMAX;
979185377Ssam	/* Set retry limit values */
980185377Ssam	if (qInfo->tqi_shretry != 0)
981185377Ssam		qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15);
982185377Ssam	else
983185377Ssam		qi->tqi_shretry = INIT_SH_RETRY;
984185377Ssam	if (qInfo->tqi_lgretry != 0)
985185377Ssam		qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15);
986185377Ssam	else
987185377Ssam		qi->tqi_lgretry = INIT_LG_RETRY;
988185377Ssam	qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod;
989185377Ssam	qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit;
990185377Ssam	qi->tqi_burstTime = qInfo->tqi_burstTime;
991185377Ssam	qi->tqi_readyTime = qInfo->tqi_readyTime;
992185377Ssam
993185377Ssam	switch (qInfo->tqi_subtype) {
994185377Ssam	case HAL_WME_UPSD:
995185377Ssam		if (qi->tqi_type == HAL_TX_QUEUE_DATA)
996185377Ssam			qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS;
997185377Ssam		break;
998185377Ssam	default:
999185377Ssam		break;		/* NB: silence compiler */
1000185377Ssam	}
1001185377Ssam	return AH_TRUE;
1002185377Ssam}
1003185377Ssam
1004185377SsamHAL_BOOL
1005185377Ssamath_hal_getTxQProps(struct ath_hal *ah,
1006185377Ssam	HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi)
1007185377Ssam{
1008185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
1009185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
1010185377Ssam		    "%s: inactive queue\n", __func__);
1011185377Ssam		return AH_FALSE;
1012185377Ssam	}
1013185377Ssam
1014185377Ssam	qInfo->tqi_qflags = qi->tqi_qflags;
1015185377Ssam	qInfo->tqi_ver = qi->tqi_ver;
1016185377Ssam	qInfo->tqi_subtype = qi->tqi_subtype;
1017185377Ssam	qInfo->tqi_qflags = qi->tqi_qflags;
1018185377Ssam	qInfo->tqi_priority = qi->tqi_priority;
1019185377Ssam	qInfo->tqi_aifs = qi->tqi_aifs;
1020185377Ssam	qInfo->tqi_cwmin = qi->tqi_cwmin;
1021185377Ssam	qInfo->tqi_cwmax = qi->tqi_cwmax;
1022185377Ssam	qInfo->tqi_shretry = qi->tqi_shretry;
1023185377Ssam	qInfo->tqi_lgretry = qi->tqi_lgretry;
1024185377Ssam	qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
1025185377Ssam	qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
1026185377Ssam	qInfo->tqi_burstTime = qi->tqi_burstTime;
1027185377Ssam	qInfo->tqi_readyTime = qi->tqi_readyTime;
1028185377Ssam	return AH_TRUE;
1029185377Ssam}
1030185377Ssam
1031185377Ssam                                     /* 11a Turbo  11b  11g  108g */
1032185377Ssamstatic const int16_t NOISE_FLOOR[] = { -96, -93,  -98, -96,  -93 };
1033185377Ssam
1034185377Ssam/*
1035185377Ssam * Read the current channel noise floor and return.
1036185377Ssam * If nf cal hasn't finished, channel noise floor should be 0
1037185377Ssam * and we return a nominal value based on band and frequency.
1038185377Ssam *
1039185377Ssam * NB: This is a private routine used by per-chip code to
1040185377Ssam *     implement the ah_getChanNoise method.
1041185377Ssam */
1042185377Ssamint16_t
1043187831Ssamath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan)
1044185377Ssam{
1045185377Ssam	HAL_CHANNEL_INTERNAL *ichan;
1046185377Ssam
1047185377Ssam	ichan = ath_hal_checkchannel(ah, chan);
1048185377Ssam	if (ichan == AH_NULL) {
1049185377Ssam		HALDEBUG(ah, HAL_DEBUG_NFCAL,
1050185377Ssam		    "%s: invalid channel %u/0x%x; no mapping\n",
1051187831Ssam		    __func__, chan->ic_freq, chan->ic_flags);
1052185377Ssam		return 0;
1053185377Ssam	}
1054185377Ssam	if (ichan->rawNoiseFloor == 0) {
1055185377Ssam		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
1056185377Ssam
1057185377Ssam		HALASSERT(mode < WIRELESS_MODE_MAX);
1058185377Ssam		return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan);
1059185377Ssam	} else
1060185377Ssam		return ichan->rawNoiseFloor + ichan->noiseFloorAdjust;
1061185377Ssam}
1062185377Ssam
1063185377Ssam/*
1064220443Sadrian * Fetch the current setup of ctl/ext noise floor values.
1065220443Sadrian *
1066220443Sadrian * If the CHANNEL_MIMO_NF_VALID flag isn't set, the array is simply
1067220443Sadrian * populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust().
1068220443Sadrian *
1069220443Sadrian * The caller must supply ctl/ext NF arrays which are at least
1070240623Sadrian * AH_MAX_CHAINS entries long.
1071220443Sadrian */
1072220443Sadrianint
1073220443Sadrianath_hal_get_mimo_chan_noise(struct ath_hal *ah,
1074220444Sadrian    const struct ieee80211_channel *chan, int16_t *nf_ctl,
1075220444Sadrian    int16_t *nf_ext)
1076220443Sadrian{
1077221019Sadrian#ifdef	AH_SUPPORT_AR5416
1078220443Sadrian	HAL_CHANNEL_INTERNAL *ichan;
1079220443Sadrian	int i;
1080220443Sadrian
1081220443Sadrian	ichan = ath_hal_checkchannel(ah, chan);
1082220443Sadrian	if (ichan == AH_NULL) {
1083220443Sadrian		HALDEBUG(ah, HAL_DEBUG_NFCAL,
1084220443Sadrian		    "%s: invalid channel %u/0x%x; no mapping\n",
1085220443Sadrian		    __func__, chan->ic_freq, chan->ic_flags);
1086240623Sadrian		for (i = 0; i < AH_MAX_CHAINS; i++) {
1087220443Sadrian			nf_ctl[i] = nf_ext[i] = 0;
1088220443Sadrian		}
1089220443Sadrian		return 0;
1090220443Sadrian	}
1091220443Sadrian
1092220443Sadrian	/* Return 0 if there's no valid MIMO values (yet) */
1093220443Sadrian	if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) {
1094240623Sadrian		for (i = 0; i < AH_MAX_CHAINS; i++) {
1095220443Sadrian			nf_ctl[i] = nf_ext[i] = 0;
1096220443Sadrian		}
1097220443Sadrian		return 0;
1098220443Sadrian	}
1099220443Sadrian	if (ichan->rawNoiseFloor == 0) {
1100220443Sadrian		WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
1101220443Sadrian		HALASSERT(mode < WIRELESS_MODE_MAX);
1102220443Sadrian		/*
1103220443Sadrian		 * See the comment below - this could cause issues for
1104220443Sadrian		 * stations which have a very low RSSI, below the
1105220443Sadrian		 * 'normalised' NF values in NOISE_FLOOR[].
1106220443Sadrian		 */
1107240623Sadrian		for (i = 0; i < AH_MAX_CHAINS; i++) {
1108220443Sadrian			nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] +
1109220443Sadrian			    ath_hal_getNfAdjust(ah, ichan);
1110220443Sadrian		}
1111220443Sadrian		return 1;
1112220443Sadrian	} else {
1113220443Sadrian		/*
1114220443Sadrian		 * The value returned here from a MIMO radio is presumed to be
1115220443Sadrian		 * "good enough" as a NF calculation. As RSSI values are calculated
1116220443Sadrian		 * against this, an adjusted NF may be higher than the RSSI value
1117220443Sadrian		 * returned from a vary weak station, resulting in an obscenely
1118220443Sadrian		 * high signal strength calculation being returned.
1119220443Sadrian		 *
1120220443Sadrian		 * This should be re-evaluated at a later date, along with any
1121220443Sadrian		 * signal strength calculations which are made. Quite likely the
1122220443Sadrian		 * RSSI values will need to be adjusted to ensure the calculations
1123220443Sadrian		 * don't "wrap" when RSSI is less than the "adjusted" NF value.
1124220443Sadrian		 * ("Adjust" here is via ichan->noiseFloorAdjust.)
1125220443Sadrian		 */
1126240623Sadrian		for (i = 0; i < AH_MAX_CHAINS; i++) {
1127220443Sadrian			nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan);
1128220443Sadrian			nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan);
1129220443Sadrian		}
1130220443Sadrian		return 1;
1131220443Sadrian	}
1132221019Sadrian#else
1133221019Sadrian	return 0;
1134221019Sadrian#endif	/* AH_SUPPORT_AR5416 */
1135220443Sadrian}
1136220443Sadrian
1137220443Sadrian/*
1138185377Ssam * Process all valid raw noise floors into the dBm noise floor values.
1139185377Ssam * Though our device has no reference for a dBm noise floor, we perform
1140185377Ssam * a relative minimization of NF's based on the lowest NF found across a
1141185377Ssam * channel scan.
1142185377Ssam */
1143185377Ssamvoid
1144185377Ssamath_hal_process_noisefloor(struct ath_hal *ah)
1145185377Ssam{
1146185377Ssam	HAL_CHANNEL_INTERNAL *c;
1147185377Ssam	int16_t correct2, correct5;
1148185377Ssam	int16_t lowest2, lowest5;
1149185377Ssam	int i;
1150185377Ssam
1151185377Ssam	/*
1152185377Ssam	 * Find the lowest 2GHz and 5GHz noise floor values after adjusting
1153185377Ssam	 * for statistically recorded NF/channel deviation.
1154185377Ssam	 */
1155185377Ssam	correct2 = lowest2 = 0;
1156185377Ssam	correct5 = lowest5 = 0;
1157185377Ssam	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
1158185377Ssam		WIRELESS_MODE mode;
1159185377Ssam		int16_t nf;
1160185377Ssam
1161185377Ssam		c = &AH_PRIVATE(ah)->ah_channels[i];
1162185377Ssam		if (c->rawNoiseFloor >= 0)
1163185377Ssam			continue;
1164187831Ssam		/* XXX can't identify proper mode */
1165187831Ssam		mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g;
1166185377Ssam		nf = c->rawNoiseFloor + NOISE_FLOOR[mode] +
1167185377Ssam			ath_hal_getNfAdjust(ah, c);
1168185377Ssam		if (IS_CHAN_5GHZ(c)) {
1169185377Ssam			if (nf < lowest5) {
1170185377Ssam				lowest5 = nf;
1171185377Ssam				correct5 = NOISE_FLOOR[mode] -
1172185377Ssam				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1173185377Ssam			}
1174185377Ssam		} else {
1175185377Ssam			if (nf < lowest2) {
1176185377Ssam				lowest2 = nf;
1177185377Ssam				correct2 = NOISE_FLOOR[mode] -
1178185377Ssam				    (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
1179185377Ssam			}
1180185377Ssam		}
1181185377Ssam	}
1182185377Ssam
1183185377Ssam	/* Correct the channels to reach the expected NF value */
1184185377Ssam	for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
1185185377Ssam		c = &AH_PRIVATE(ah)->ah_channels[i];
1186185377Ssam		if (c->rawNoiseFloor >= 0)
1187185377Ssam			continue;
1188185377Ssam		/* Apply correction factor */
1189185377Ssam		c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) +
1190185377Ssam			(IS_CHAN_5GHZ(c) ? correct5 : correct2);
1191187831Ssam		HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n",
1192187831Ssam		    c->channel, c->rawNoiseFloor, c->noiseFloorAdjust);
1193185377Ssam	}
1194185377Ssam}
1195185377Ssam
1196185377Ssam/*
1197185377Ssam * INI support routines.
1198185377Ssam */
1199185377Ssam
1200185377Ssamint
1201185377Ssamath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1202185377Ssam	int col, int regWr)
1203185377Ssam{
1204185377Ssam	int r;
1205185377Ssam
1206189713Ssam	HALASSERT(col < ia->cols);
1207185377Ssam	for (r = 0; r < ia->rows; r++) {
1208185377Ssam		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0),
1209185377Ssam		    HAL_INI_VAL(ia, r, col));
1210217921Sadrian
1211217921Sadrian		/* Analog shift register delay seems needed for Merlin - PR kern/154220 */
1212222157Sadrian		if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x7900)
1213217921Sadrian			OS_DELAY(100);
1214217921Sadrian
1215185377Ssam		DMA_YIELD(regWr);
1216185377Ssam	}
1217185377Ssam	return regWr;
1218185377Ssam}
1219185377Ssam
1220185377Ssamvoid
1221185377Ssamath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col)
1222185377Ssam{
1223185377Ssam	int r;
1224185377Ssam
1225189713Ssam	HALASSERT(col < ia->cols);
1226185377Ssam	for (r = 0; r < ia->rows; r++)
1227185377Ssam		data[r] = HAL_INI_VAL(ia, r, col);
1228185377Ssam}
1229185377Ssam
1230185377Ssamint
1231185377Ssamath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
1232185377Ssam	const uint32_t data[], int regWr)
1233185377Ssam{
1234185377Ssam	int r;
1235185377Ssam
1236185377Ssam	for (r = 0; r < ia->rows; r++) {
1237185377Ssam		OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]);
1238185377Ssam		DMA_YIELD(regWr);
1239185377Ssam	}
1240185377Ssam	return regWr;
1241185377Ssam}
1242219586Sadrian
1243219586Sadrian/*
1244219586Sadrian * These are EEPROM board related routines which should likely live in
1245219586Sadrian * a helper library of some sort.
1246219586Sadrian */
1247219586Sadrian
1248219586Sadrian/**************************************************************
1249219586Sadrian * ath_ee_getLowerUppderIndex
1250219586Sadrian *
1251219586Sadrian * Return indices surrounding the value in sorted integer lists.
1252219586Sadrian * Requirement: the input list must be monotonically increasing
1253219586Sadrian *     and populated up to the list size
1254219586Sadrian * Returns: match is set if an index in the array matches exactly
1255219586Sadrian *     or a the target is before or after the range of the array.
1256219586Sadrian */
1257219586SadrianHAL_BOOL
1258219586Sadrianath_ee_getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize,
1259219586Sadrian                   uint16_t *indexL, uint16_t *indexR)
1260219586Sadrian{
1261219586Sadrian    uint16_t i;
1262219586Sadrian
1263219586Sadrian    /*
1264219586Sadrian     * Check first and last elements for beyond ordered array cases.
1265219586Sadrian     */
1266219586Sadrian    if (target <= pList[0]) {
1267219586Sadrian        *indexL = *indexR = 0;
1268219586Sadrian        return AH_TRUE;
1269219586Sadrian    }
1270219586Sadrian    if (target >= pList[listSize-1]) {
1271219586Sadrian        *indexL = *indexR = (uint16_t)(listSize - 1);
1272219586Sadrian        return AH_TRUE;
1273219586Sadrian    }
1274219586Sadrian
1275219586Sadrian    /* look for value being near or between 2 values in list */
1276219586Sadrian    for (i = 0; i < listSize - 1; i++) {
1277219586Sadrian        /*
1278219586Sadrian         * If value is close to the current value of the list
1279219586Sadrian         * then target is not between values, it is one of the values
1280219586Sadrian         */
1281219586Sadrian        if (pList[i] == target) {
1282219586Sadrian            *indexL = *indexR = i;
1283219586Sadrian            return AH_TRUE;
1284219586Sadrian        }
1285219586Sadrian        /*
1286219586Sadrian         * Look for value being between current value and next value
1287219586Sadrian         * if so return these 2 values
1288219586Sadrian         */
1289219586Sadrian        if (target < pList[i + 1]) {
1290219586Sadrian            *indexL = i;
1291219586Sadrian            *indexR = (uint16_t)(i + 1);
1292219586Sadrian            return AH_FALSE;
1293219586Sadrian        }
1294219586Sadrian    }
1295219586Sadrian    HALASSERT(0);
1296219586Sadrian    *indexL = *indexR = 0;
1297219586Sadrian    return AH_FALSE;
1298219586Sadrian}
1299219586Sadrian
1300219586Sadrian/**************************************************************
1301219586Sadrian * ath_ee_FillVpdTable
1302219586Sadrian *
1303219586Sadrian * Fill the Vpdlist for indices Pmax-Pmin
1304219586Sadrian * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4
1305219586Sadrian */
1306219586SadrianHAL_BOOL
1307219586Sadrianath_ee_FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList,
1308219586Sadrian                   uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList)
1309219586Sadrian{
1310219586Sadrian    uint16_t  i, k;
1311219586Sadrian    uint8_t   currPwr = pwrMin;
1312219586Sadrian    uint16_t  idxL, idxR;
1313219586Sadrian
1314219586Sadrian    HALASSERT(pwrMax > pwrMin);
1315219586Sadrian    for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
1316219586Sadrian        ath_ee_getLowerUpperIndex(currPwr, pPwrList, numIntercepts,
1317219586Sadrian                           &(idxL), &(idxR));
1318219586Sadrian        if (idxR < 1)
1319219586Sadrian            idxR = 1;           /* extrapolate below */
1320219586Sadrian        if (idxL == numIntercepts - 1)
1321219586Sadrian            idxL = (uint16_t)(numIntercepts - 2);   /* extrapolate above */
1322219586Sadrian        if (pPwrList[idxL] == pPwrList[idxR])
1323219586Sadrian            k = pVpdList[idxL];
1324219586Sadrian        else
1325219586Sadrian            k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
1326219586Sadrian                  (pPwrList[idxR] - pPwrList[idxL]) );
1327219586Sadrian        HALASSERT(k < 256);
1328219586Sadrian        pRetVpdList[i] = (uint8_t)k;
1329219586Sadrian        currPwr += 2;               /* half dB steps */
1330219586Sadrian    }
1331219586Sadrian
1332219586Sadrian    return AH_TRUE;
1333219586Sadrian}
1334219586Sadrian
1335219586Sadrian/**************************************************************************
1336219586Sadrian * ath_ee_interpolate
1337219586Sadrian *
1338219586Sadrian * Returns signed interpolated or the scaled up interpolated value
1339219586Sadrian */
1340219586Sadrianint16_t
1341219586Sadrianath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
1342219586Sadrian            int16_t targetLeft, int16_t targetRight)
1343219586Sadrian{
1344219586Sadrian    int16_t rv;
1345219586Sadrian
1346219586Sadrian    if (srcRight == srcLeft) {
1347219586Sadrian        rv = targetLeft;
1348219586Sadrian    } else {
1349219586Sadrian        rv = (int16_t)( ((target - srcLeft) * targetRight +
1350219586Sadrian              (srcRight - target) * targetLeft) / (srcRight - srcLeft) );
1351219586Sadrian    }
1352219586Sadrian    return rv;
1353219586Sadrian}
1354225444Sadrian
1355225444Sadrian/*
1356225444Sadrian * Adjust the TSF.
1357225444Sadrian */
1358225444Sadrianvoid
1359225444Sadrianath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta)
1360225444Sadrian{
1361225444Sadrian	/* XXX handle wrap/overflow */
1362225444Sadrian	OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta);
1363225444Sadrian}
1364225444Sadrian
1365225444Sadrian/*
1366225444Sadrian * Enable or disable CCA.
1367225444Sadrian */
1368225444Sadrianvoid
1369225444Sadrianath_hal_setcca(struct ath_hal *ah, int ena)
1370225444Sadrian{
1371225444Sadrian	/*
1372225444Sadrian	 * NB: fill me in; this is not provided by default because disabling
1373225444Sadrian	 *     CCA in most locales violates regulatory.
1374225444Sadrian	 */
1375225444Sadrian}
1376225444Sadrian
1377225444Sadrian/*
1378225444Sadrian * Get CCA setting.
1379225444Sadrian */
1380225444Sadrianint
1381225444Sadrianath_hal_getcca(struct ath_hal *ah)
1382225444Sadrian{
1383225444Sadrian	u_int32_t diag;
1384225444Sadrian	if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK)
1385225444Sadrian		return 1;
1386225444Sadrian	return ((diag & 0x500000) == 0);
1387225444Sadrian}
1388230147Sadrian
1389230147Sadrian/*
1390230147Sadrian * This routine is only needed when supporting EEPROM-in-RAM setups
1391230147Sadrian * (eg embedded SoCs and on-board PCI/PCIe devices.)
1392230147Sadrian */
1393230147Sadrian/* NB: This is in 16 bit words; not bytes */
1394230147Sadrian/* XXX This doesn't belong here!  */
1395230147Sadrian#define ATH_DATA_EEPROM_SIZE    2048
1396230147Sadrian
1397230147SadrianHAL_BOOL
1398230147Sadrianath_hal_EepromDataRead(struct ath_hal *ah, u_int off, uint16_t *data)
1399230147Sadrian{
1400230147Sadrian	if (ah->ah_eepromdata == AH_NULL) {
1401230147Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no eeprom data!\n", __func__);
1402230147Sadrian		return AH_FALSE;
1403230147Sadrian	}
1404230147Sadrian	if (off > ATH_DATA_EEPROM_SIZE) {
1405230147Sadrian		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset %x > %x\n",
1406230147Sadrian		    __func__, off, ATH_DATA_EEPROM_SIZE);
1407230147Sadrian		return AH_FALSE;
1408230147Sadrian	}
1409230147Sadrian	(*data) = ah->ah_eepromdata[off];
1410230147Sadrian	return AH_TRUE;
1411230147Sadrian}
1412252236Sadrian
1413252236Sadrian/*
1414252236Sadrian * Do a 2GHz specific MHz->IEEE based on the hardware
1415252236Sadrian * frequency.
1416252236Sadrian *
1417252236Sadrian * This is the unmapped frequency which is programmed into the hardware.
1418252236Sadrian */
1419252236Sadrianint
1420252236Sadrianath_hal_mhz2ieee_2ghz(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
1421252236Sadrian{
1422252236Sadrian
1423252236Sadrian	if (ichan->channel == 2484)
1424252236Sadrian		return 14;
1425252236Sadrian	if (ichan->channel < 2484)
1426252236Sadrian		return ((int) ichan->channel - 2407) / 5;
1427252236Sadrian	else
1428252236Sadrian		return 15 + ((ichan->channel - 2512) / 20);
1429252236Sadrian}
1430