ar5212_misc.c revision 185377
1/*
2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2008 Atheros Communications, Inc.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 * $Id: ar5212_misc.c,v 1.8 2008/11/10 04:08:03 sam Exp $
18 */
19#include "opt_ah.h"
20
21#ifdef AH_SUPPORT_AR5212
22
23#include "ah.h"
24#include "ah_internal.h"
25#include "ah_devid.h"
26#ifdef AH_DEBUG
27#include "ah_desc.h"			/* NB: for HAL_PHYERR* */
28#endif
29
30#include "ar5212/ar5212.h"
31#include "ar5212/ar5212reg.h"
32#include "ar5212/ar5212phy.h"
33#ifdef AH_SUPPORT_AR5311
34#include "ar5212/ar5311reg.h"
35#endif
36
37#include "ah_eeprom_v3.h"
38
39#define	AR_NUM_GPIO	6		/* 6 GPIO pins */
40#define	AR_GPIOD_MASK	0x0000002F	/* GPIO data reg r/w mask */
41
42extern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *);
43
44void
45ar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac)
46{
47	struct ath_hal_5212 *ahp = AH5212(ah);
48
49	OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN);
50}
51
52HAL_BOOL
53ar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac)
54{
55	struct ath_hal_5212 *ahp = AH5212(ah);
56
57	OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN);
58	return AH_TRUE;
59}
60
61void
62ar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask)
63{
64	struct ath_hal_5212 *ahp = AH5212(ah);
65
66	OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN);
67}
68
69HAL_BOOL
70ar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask)
71{
72	struct ath_hal_5212 *ahp = AH5212(ah);
73
74	/* save it since it must be rewritten on reset */
75	OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN);
76
77	OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));
78	OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));
79	return AH_TRUE;
80}
81
82/*
83 * Return the wireless modes (a,b,g,t) supported by hardware.
84 *
85 * This value is what is actually supported by the hardware
86 * and is unaffected by regulatory/country code settings.
87 *
88 */
89u_int
90ar5212GetWirelessModes(struct ath_hal *ah)
91{
92	u_int mode = 0;
93
94	if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) {
95		mode = HAL_MODE_11A;
96		if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE))
97			mode |= HAL_MODE_TURBO | HAL_MODE_108A;
98	}
99	if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE))
100		mode |= HAL_MODE_11B;
101	if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) &&
102	    AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) {
103		mode |= HAL_MODE_11G;
104		if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE))
105			mode |= HAL_MODE_108G;
106	}
107	return mode;
108}
109
110/*
111 * Set the interrupt and GPIO values so the ISR can disable RF
112 * on a switch signal.  Assumes GPIO port and interrupt polarity
113 * are set prior to call.
114 */
115void
116ar5212EnableRfKill(struct ath_hal *ah)
117{
118	uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent;
119	int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL);
120	int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY);
121
122	/*
123	 * Configure the desired GPIO port for input
124	 * and enable baseband rf silence.
125	 */
126	ath_hal_gpioCfgInput(ah, select);
127	OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000);
128	/*
129	 * If radio disable switch connection to GPIO bit x is enabled
130	 * program GPIO interrupt.
131	 * If rfkill bit on eeprom is 1, setupeeprommap routine has already
132	 * verified that it is a later version of eeprom, it has a place for
133	 * rfkill bit and it is set to 1, indicating that GPIO bit x hardware
134	 * connection is present.
135	 */
136	ath_hal_gpioSetIntr(ah, select,
137	    (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity));
138}
139
140/*
141 * Change the LED blinking pattern to correspond to the connectivity
142 */
143void
144ar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state)
145{
146	static const uint32_t ledbits[8] = {
147		AR_PCICFG_LEDCTL_NONE,	/* HAL_LED_INIT */
148		AR_PCICFG_LEDCTL_PEND,	/* HAL_LED_SCAN */
149		AR_PCICFG_LEDCTL_PEND,	/* HAL_LED_AUTH */
150		AR_PCICFG_LEDCTL_ASSOC,	/* HAL_LED_ASSOC*/
151		AR_PCICFG_LEDCTL_ASSOC,	/* HAL_LED_RUN */
152		AR_PCICFG_LEDCTL_NONE,
153		AR_PCICFG_LEDCTL_NONE,
154		AR_PCICFG_LEDCTL_NONE,
155	};
156	uint32_t bits;
157
158	bits = OS_REG_READ(ah, AR_PCICFG);
159	if (IS_2417(ah)) {
160		/*
161		 * Enable LED for Nala. There is a bit marked reserved
162		 * that must be set and we also turn on the power led.
163		 * Because we mark s/w LED control setting the control
164		 * status bits below is meangless (the driver must flash
165		 * the LED(s) using the GPIO lines).
166		 */
167		bits = (bits &~ AR_PCICFG_LEDMODE)
168		     | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE)
169#if 0
170		     | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE)
171#endif
172		     | 0x08000000;
173	}
174	bits = (bits &~ AR_PCICFG_LEDCTL)
175	     | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL);
176	OS_REG_WRITE(ah, AR_PCICFG, bits);
177}
178
179/*
180 * Change association related fields programmed into the hardware.
181 * Writing a valid BSSID to the hardware effectively enables the hardware
182 * to synchronize its TSF to the correct beacons and receive frames coming
183 * from that BSSID. It is called by the SME JOIN operation.
184 */
185void
186ar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId)
187{
188	struct ath_hal_5212 *ahp = AH5212(ah);
189
190	/* XXX save bssid for possible re-use on reset */
191	OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);
192	OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
193	OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) |
194				     ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S));
195}
196
197/*
198 * Get the current hardware tsf for stamlme
199 */
200uint64_t
201ar5212GetTsf64(struct ath_hal *ah)
202{
203	uint32_t low1, low2, u32;
204
205	/* sync multi-word read */
206	low1 = OS_REG_READ(ah, AR_TSF_L32);
207	u32 = OS_REG_READ(ah, AR_TSF_U32);
208	low2 = OS_REG_READ(ah, AR_TSF_L32);
209	if (low2 < low1) {	/* roll over */
210		/*
211		 * If we are not preempted this will work.  If we are
212		 * then we re-reading AR_TSF_U32 does no good as the
213		 * low bits will be meaningless.  Likewise reading
214		 * L32, U32, U32, then comparing the last two reads
215		 * to check for rollover
216		 * doesn't help if preempted--so we take this approach
217		 * as it costs one less PCI read which can be noticeable
218		 * when doing things like timestamping packets in
219		 * monitor mode.
220		 */
221		u32++;
222	}
223	return (((uint64_t) u32) << 32) | ((uint64_t) low2);
224}
225
226/*
227 * Get the current hardware tsf for stamlme
228 */
229uint32_t
230ar5212GetTsf32(struct ath_hal *ah)
231{
232	return OS_REG_READ(ah, AR_TSF_L32);
233}
234
235/*
236 * Reset the current hardware tsf for stamlme.
237 */
238void
239ar5212ResetTsf(struct ath_hal *ah)
240{
241
242	uint32_t val = OS_REG_READ(ah, AR_BEACON);
243
244	OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);
245	/*
246	 * When resetting the TSF, write twice to the
247	 * corresponding register; each write to the RESET_TSF bit toggles
248	 * the internal signal to cause a reset of the TSF - but if the signal
249	 * is left high, it will reset the TSF on the next chip reset also!
250	 * writing the bit an even number of times fixes this issue
251	 */
252	OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);
253}
254
255/*
256 * Set or clear hardware basic rate bit
257 * Set hardware basic rate set if basic rate is found
258 * and basic rate is equal or less than 2Mbps
259 */
260void
261ar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs)
262{
263	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
264	uint32_t reg;
265	uint8_t xset;
266	int i;
267
268	if (chan == AH_NULL || !IS_CHAN_CCK(chan))
269		return;
270	xset = 0;
271	for (i = 0; i < rs->rs_count; i++) {
272		uint8_t rset = rs->rs_rates[i];
273		/* Basic rate defined? */
274		if ((rset & 0x80) && (rset &= 0x7f) >= xset)
275			xset = rset;
276	}
277	/*
278	 * Set the h/w bit to reflect whether or not the basic
279	 * rate is found to be equal or less than 2Mbps.
280	 */
281	reg = OS_REG_READ(ah, AR_STA_ID1);
282	if (xset && xset/2 <= 2)
283		OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B);
284	else
285		OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B);
286}
287
288/*
289 * Grab a semi-random value from hardware registers - may not
290 * change often
291 */
292uint32_t
293ar5212GetRandomSeed(struct ath_hal *ah)
294{
295	uint32_t nf;
296
297	nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff;
298	if (nf & 0x100)
299		nf = 0 - ((nf ^ 0x1ff) + 1);
300	return (OS_REG_READ(ah, AR_TSF_U32) ^
301		OS_REG_READ(ah, AR_TSF_L32) ^ nf);
302}
303
304/*
305 * Detect if our card is present
306 */
307HAL_BOOL
308ar5212DetectCardPresent(struct ath_hal *ah)
309{
310	uint16_t macVersion, macRev;
311	uint32_t v;
312
313	/*
314	 * Read the Silicon Revision register and compare that
315	 * to what we read at attach time.  If the same, we say
316	 * a card/device is present.
317	 */
318	v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID;
319	macVersion = v >> AR_SREV_ID_S;
320	macRev = v & AR_SREV_REVISION;
321	return (AH_PRIVATE(ah)->ah_macVersion == macVersion &&
322		AH_PRIVATE(ah)->ah_macRev == macRev);
323}
324
325void
326ar5212EnableMibCounters(struct ath_hal *ah)
327{
328	/* NB: this just resets the mib counter machinery */
329	OS_REG_WRITE(ah, AR_MIBC,
330	    ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f);
331}
332
333void
334ar5212DisableMibCounters(struct ath_hal *ah)
335{
336	OS_REG_WRITE(ah, AR_MIBC,  AR_MIBC | AR_MIBC_CMC);
337}
338
339/*
340 * Update MIB Counters
341 */
342void
343ar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats)
344{
345	stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL);
346	stats->rts_bad	  += OS_REG_READ(ah, AR_RTS_FAIL);
347	stats->fcs_bad	  += OS_REG_READ(ah, AR_FCS_FAIL);
348	stats->rts_good	  += OS_REG_READ(ah, AR_RTS_OK);
349	stats->beacons	  += OS_REG_READ(ah, AR_BEACON_CNT);
350}
351
352/*
353 * Detect if the HW supports spreading a CCK signal on channel 14
354 */
355HAL_BOOL
356ar5212IsJapanChannelSpreadSupported(struct ath_hal *ah)
357{
358	return AH_TRUE;
359}
360
361/*
362 * Get the rssi of frame curently being received.
363 */
364uint32_t
365ar5212GetCurRssi(struct ath_hal *ah)
366{
367	return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff);
368}
369
370u_int
371ar5212GetDefAntenna(struct ath_hal *ah)
372{
373	return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7);
374}
375
376void
377ar5212SetDefAntenna(struct ath_hal *ah, u_int antenna)
378{
379	OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
380}
381
382HAL_ANT_SETTING
383ar5212GetAntennaSwitch(struct ath_hal *ah)
384{
385	return AH5212(ah)->ah_diversityControl;
386}
387
388HAL_BOOL
389ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
390{
391	const HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
392
393	if (chan == AH_NULL) {
394		AH5212(ah)->ah_diversityControl = settings;
395		return AH_TRUE;
396	}
397	return ar5212SetAntennaSwitchInternal(ah, settings, chan);
398}
399
400HAL_BOOL
401ar5212IsSleepAfterBeaconBroken(struct ath_hal *ah)
402{
403	return AH_TRUE;
404}
405
406HAL_BOOL
407ar5212SetSifsTime(struct ath_hal *ah, u_int us)
408{
409	struct ath_hal_5212 *ahp = AH5212(ah);
410
411	if (us > ath_hal_mac_usec(ah, 0xffff)) {
412		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n",
413		    __func__, us);
414		ahp->ah_sifstime = (u_int) -1;	/* restore default handling */
415		return AH_FALSE;
416	} else {
417		/* convert to system clocks */
418		OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us));
419		ahp->ah_slottime = us;
420		return AH_TRUE;
421	}
422}
423
424u_int
425ar5212GetSifsTime(struct ath_hal *ah)
426{
427	u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff;
428	return ath_hal_mac_usec(ah, clks);	/* convert from system clocks */
429}
430
431HAL_BOOL
432ar5212SetSlotTime(struct ath_hal *ah, u_int us)
433{
434	struct ath_hal_5212 *ahp = AH5212(ah);
435
436	if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) {
437		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n",
438		    __func__, us);
439		ahp->ah_slottime = (u_int) -1;	/* restore default handling */
440		return AH_FALSE;
441	} else {
442		/* convert to system clocks */
443		OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us));
444		ahp->ah_slottime = us;
445		return AH_TRUE;
446	}
447}
448
449u_int
450ar5212GetSlotTime(struct ath_hal *ah)
451{
452	u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff;
453	return ath_hal_mac_usec(ah, clks);	/* convert from system clocks */
454}
455
456HAL_BOOL
457ar5212SetAckTimeout(struct ath_hal *ah, u_int us)
458{
459	struct ath_hal_5212 *ahp = AH5212(ah);
460
461	if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
462		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n",
463		    __func__, us);
464		ahp->ah_acktimeout = (u_int) -1; /* restore default handling */
465		return AH_FALSE;
466	} else {
467		/* convert to system clocks */
468		OS_REG_RMW_FIELD(ah, AR_TIME_OUT,
469			AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us));
470		ahp->ah_acktimeout = us;
471		return AH_TRUE;
472	}
473}
474
475u_int
476ar5212GetAckTimeout(struct ath_hal *ah)
477{
478	u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK);
479	return ath_hal_mac_usec(ah, clks);	/* convert from system clocks */
480}
481
482u_int
483ar5212GetAckCTSRate(struct ath_hal *ah)
484{
485	return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0);
486}
487
488HAL_BOOL
489ar5212SetAckCTSRate(struct ath_hal *ah, u_int high)
490{
491	struct ath_hal_5212 *ahp = AH5212(ah);
492
493	if (high) {
494		OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);
495		ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB;
496	} else {
497		OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);
498		ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB;
499	}
500	return AH_TRUE;
501}
502
503HAL_BOOL
504ar5212SetCTSTimeout(struct ath_hal *ah, u_int us)
505{
506	struct ath_hal_5212 *ahp = AH5212(ah);
507
508	if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
509		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n",
510		    __func__, us);
511		ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */
512		return AH_FALSE;
513	} else {
514		/* convert to system clocks */
515		OS_REG_RMW_FIELD(ah, AR_TIME_OUT,
516			AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us));
517		ahp->ah_ctstimeout = us;
518		return AH_TRUE;
519	}
520}
521
522u_int
523ar5212GetCTSTimeout(struct ath_hal *ah)
524{
525	u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS);
526	return ath_hal_mac_usec(ah, clks);	/* convert from system clocks */
527}
528
529/* Setup decompression for given key index */
530HAL_BOOL
531ar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)
532{
533	struct ath_hal_5212 *ahp = AH5212(ah);
534
535        if (keyidx >= HAL_DECOMP_MASK_SIZE)
536                return HAL_EINVAL;
537        OS_REG_WRITE(ah, AR_DCM_A, keyidx);
538        OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0);
539        ahp->ah_decompMask[keyidx] = en;
540
541        return AH_TRUE;
542}
543
544/* Setup coverage class */
545void
546ar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
547{
548	uint32_t slot, timeout, eifs;
549	u_int clkRate;
550
551	AH_PRIVATE(ah)->ah_coverageClass = coverageclass;
552
553	if (now) {
554		if (AH_PRIVATE(ah)->ah_coverageClass == 0)
555			return;
556
557		/* Don't apply coverage class to non A channels */
558		if (!IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan))
559			return;
560
561		/* Get core clock rate */
562		clkRate = ath_hal_mac_clks(ah, 1);
563
564		/* Compute EIFS */
565		slot = coverageclass * 3 * clkRate;
566		eifs = coverageclass * 6 * clkRate;
567		if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) {
568			slot += IFS_SLOT_HALF_RATE;
569			eifs += IFS_EIFS_HALF_RATE;
570		} else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) {
571			slot += IFS_SLOT_QUARTER_RATE;
572			eifs += IFS_EIFS_QUARTER_RATE;
573		} else { /* full rate */
574			slot += IFS_SLOT_FULL_RATE;
575			eifs += IFS_EIFS_FULL_RATE;
576		}
577
578		/*
579		 * Add additional time for air propagation for ACK and CTS
580		 * timeouts. This value is in core clocks.
581  		 */
582		timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate);
583
584		/*
585		 * Write the values: slot, eifs, ack/cts timeouts.
586		 */
587		OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot);
588		OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);
589		OS_REG_WRITE(ah, AR_TIME_OUT,
590			  SM(timeout, AR_TIME_OUT_CTS)
591			| SM(timeout, AR_TIME_OUT_ACK));
592	}
593}
594
595void
596ar5212SetPCUConfig(struct ath_hal *ah)
597{
598	ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode);
599}
600
601/*
602 * Return whether an external 32KHz crystal should be used
603 * to reduce power consumption when sleeping.  We do so if
604 * the crystal is present (obtained from EEPROM) and if we
605 * are not running as an AP and are configured to use it.
606 */
607HAL_BOOL
608ar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode)
609{
610	if (opmode != HAL_M_HOSTAP) {
611		struct ath_hal_5212 *ahp = AH5212(ah);
612		return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) &&
613		       (ahp->ah_enable32kHzClock == USE_32KHZ ||
614		        ahp->ah_enable32kHzClock == AUTO_32KHZ);
615	} else
616		return AH_FALSE;
617}
618
619/*
620 * If 32KHz clock exists, use it to lower power consumption during sleep
621 *
622 * Note: If clock is set to 32 KHz, delays on accessing certain
623 *       baseband registers (27-31, 124-127) are required.
624 */
625void
626ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode)
627{
628	if (ar5212Use32KHzclock(ah, opmode)) {
629		/*
630		 * Enable clocks to be turned OFF in BB during sleep
631		 * and also enable turning OFF 32MHz/40MHz Refclk
632		 * from A2.
633		 */
634		OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
635		OS_REG_WRITE(ah, AR_PHY_REFCLKPD, IS_5112(ah) ?  0x14 : 0x18);
636		OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1);
637		OS_REG_WRITE(ah, AR_TSF_PARM, 61);  /* 32 KHz TSF incr */
638		OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1);
639
640		if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) {
641			OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT,   0x26);
642			OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL,        0x0d);
643			OS_REG_WRITE(ah, AR_PHY_M_SLEEP,           0x07);
644			OS_REG_WRITE(ah, AR_PHY_REFCLKDLY,         0x3f);
645			/* # Set sleep clock rate to 32 KHz. */
646			OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2);
647		} else {
648			OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT,   0x0a);
649			OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL,        0x0c);
650			OS_REG_WRITE(ah, AR_PHY_M_SLEEP,           0x03);
651			OS_REG_WRITE(ah, AR_PHY_REFCLKDLY,         0x20);
652			OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3);
653		}
654	} else {
655		OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0);
656		OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0);
657
658		OS_REG_WRITE(ah, AR_TSF_PARM, 1);	/* 32MHz TSF inc */
659
660		OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
661		OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT,   0x7f);
662
663		if (IS_2417(ah))
664			OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a);
665		else if (IS_HB63(ah))
666			OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32);
667		else
668			OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
669		OS_REG_WRITE(ah, AR_PHY_M_SLEEP,           0x0c);
670		OS_REG_WRITE(ah, AR_PHY_REFCLKDLY,         0xff);
671		OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
672		    IS_5112(ah) || IS_2417(ah) ? 0x14 : 0x18);
673		OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, IS_5112(ah) ? 39 : 31);
674	}
675}
676
677/*
678 * If 32KHz clock exists, turn it off and turn back on the 32Mhz
679 */
680void
681ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode)
682{
683	if (ar5212Use32KHzclock(ah, opmode)) {
684		/* # Set sleep clock rate back to 32 MHz. */
685		OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0);
686		OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0);
687
688		OS_REG_WRITE(ah, AR_TSF_PARM, 1);	/* 32 MHz TSF incr */
689		OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, IS_5112(ah) ? 39 : 31);
690
691		/*
692		 * Restore BB registers to power-on defaults
693		 */
694		OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
695		OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT,   0x7f);
696		OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL,        0x0e);
697		OS_REG_WRITE(ah, AR_PHY_M_SLEEP,           0x0c);
698		OS_REG_WRITE(ah, AR_PHY_REFCLKDLY,         0xff);
699		OS_REG_WRITE(ah, AR_PHY_REFCLKPD, IS_5112(ah) ?  0x14 : 0x18);
700	}
701}
702
703/*
704 * Adjust NF based on statistical values for 5GHz frequencies.
705 * Default method: this may be overridden by the rf backend.
706 */
707int16_t
708ar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c)
709{
710	static const struct {
711		uint16_t freqLow;
712		int16_t	  adjust;
713	} adjustDef[] = {
714		{ 5790,	11 },	/* NB: ordered high -> low */
715		{ 5730, 10 },
716		{ 5690,  9 },
717		{ 5660,  8 },
718		{ 5610,  7 },
719		{ 5530,  5 },
720		{ 5450,  4 },
721		{ 5379,  2 },
722		{ 5209,  0 },
723		{ 3000,  1 },
724		{    0,  0 },
725	};
726	int i;
727
728	for (i = 0; c->channel <= adjustDef[i].freqLow; i++)
729		;
730	return adjustDef[i].adjust;
731}
732
733HAL_STATUS
734ar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
735	uint32_t capability, uint32_t *result)
736{
737#define	MACVERSION(ah)	AH_PRIVATE(ah)->ah_macVersion
738	struct ath_hal_5212 *ahp = AH5212(ah);
739	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
740	const struct ar5212AniState *ani;
741
742	switch (type) {
743	case HAL_CAP_CIPHER:		/* cipher handled in hardware */
744		switch (capability) {
745		case HAL_CIPHER_AES_CCM:
746			return pCap->halCipherAesCcmSupport ?
747				HAL_OK : HAL_ENOTSUPP;
748		case HAL_CIPHER_AES_OCB:
749		case HAL_CIPHER_TKIP:
750		case HAL_CIPHER_WEP:
751		case HAL_CIPHER_MIC:
752		case HAL_CIPHER_CLR:
753			return HAL_OK;
754		default:
755			return HAL_ENOTSUPP;
756		}
757	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
758		switch (capability) {
759		case 0:			/* hardware capability */
760			return HAL_OK;
761		case 1:
762			return (ahp->ah_staId1Defaults &
763			    AR_STA_ID1_CRPT_MIC_ENABLE) ?  HAL_OK : HAL_ENXIO;
764		}
765	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
766		switch (capability) {
767		case 0:			/* hardware capability */
768			return pCap->halTkipMicTxRxKeySupport ?
769				HAL_ENXIO : HAL_OK;
770		case 1:			/* current setting */
771			return (ahp->ah_miscMode &
772			    AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK;
773		}
774		return HAL_EINVAL;
775	case HAL_CAP_WME_TKIPMIC:	/* hardware can do TKIP MIC w/ WMM */
776		/* XXX move to capability bit */
777		return MACVERSION(ah) > AR_SREV_VERSION_VENICE ||
778		    (MACVERSION(ah) == AR_SREV_VERSION_VENICE &&
779		     AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP;
780	case HAL_CAP_DIVERSITY:		/* hardware supports fast diversity */
781		switch (capability) {
782		case 0:			/* hardware capability */
783			return HAL_OK;
784		case 1:			/* current setting */
785			return (OS_REG_READ(ah, AR_PHY_CCK_DETECT) &
786				AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
787				HAL_OK : HAL_ENXIO;
788		}
789		return HAL_EINVAL;
790	case HAL_CAP_DIAG:
791		*result = AH_PRIVATE(ah)->ah_diagreg;
792		return HAL_OK;
793	case HAL_CAP_TPC:
794		switch (capability) {
795		case 0:			/* hardware capability */
796			return HAL_OK;
797		case 1:
798			return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO;
799		}
800		return HAL_OK;
801	case HAL_CAP_PHYDIAG:		/* radar pulse detection capability */
802		switch (capability) {
803		case HAL_CAP_RADAR:
804			return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ?
805			    HAL_OK: HAL_ENXIO;
806		case HAL_CAP_AR:
807			return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) ||
808			    ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ?
809			       HAL_OK: HAL_ENXIO;
810		}
811		return HAL_ENXIO;
812	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
813		switch (capability) {
814		case 0:			/* hardware capability */
815			return HAL_OK;
816		case 1:
817			return (ahp->ah_staId1Defaults &
818			    AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO;
819		}
820		return HAL_EINVAL;
821	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
822		switch (capability) {
823		case 0:			/* hardware capability */
824			return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP;
825		case 1:
826			return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ?
827				HAL_OK : HAL_ENXIO;
828		}
829		return HAL_EINVAL;
830	case HAL_CAP_TPC_ACK:
831		*result = MS(ahp->ah_macTPC, AR_TPC_ACK);
832		return HAL_OK;
833	case HAL_CAP_TPC_CTS:
834		*result = MS(ahp->ah_macTPC, AR_TPC_CTS);
835		return HAL_OK;
836	case HAL_CAP_INTMIT:		/* interference mitigation */
837		switch (capability) {
838		case 0:			/* hardware capability */
839			return HAL_OK;
840		case 1:
841			return (ahp->ah_procPhyErr & HAL_ANI_ENA) ?
842				HAL_OK : HAL_ENXIO;
843		case 2:			/* HAL_ANI_NOISE_IMMUNITY_LEVEL */
844		case 3:			/* HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION */
845		case 4:			/* HAL_ANI_CCK_WEAK_SIGNAL_THR */
846		case 5:			/* HAL_ANI_FIRSTEP_LEVEL */
847		case 6:			/* HAL_ANI_SPUR_IMMUNITY_LEVEL */
848			ani = ar5212AniGetCurrentState(ah);
849			if (ani == AH_NULL)
850				return HAL_ENXIO;
851			switch (capability) {
852			case 2:	*result = ani->noiseImmunityLevel; break;
853			case 3: *result = !ani->ofdmWeakSigDetectOff; break;
854			case 4: *result = ani->cckWeakSigThreshold; break;
855			case 5: *result = ani->firstepLevel; break;
856			case 6: *result = ani->spurImmunityLevel; break;
857			}
858			return HAL_OK;
859		}
860		return HAL_EINVAL;
861	default:
862		return ath_hal_getcapability(ah, type, capability, result);
863	}
864#undef MACVERSION
865}
866
867HAL_BOOL
868ar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
869	uint32_t capability, uint32_t setting, HAL_STATUS *status)
870{
871#define	N(a)	(sizeof(a)/sizeof(a[0]))
872	struct ath_hal_5212 *ahp = AH5212(ah);
873	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
874	uint32_t v;
875
876	switch (type) {
877	case HAL_CAP_TKIP_MIC:		/* handle TKIP MIC in hardware */
878		if (setting)
879			ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE;
880		else
881			ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE;
882		return AH_TRUE;
883	case HAL_CAP_TKIP_SPLIT:	/* hardware TKIP uses split keys */
884		if (!pCap->halTkipMicTxRxKeySupport)
885			return AH_FALSE;
886		/* NB: true =>'s use split key cache layout */
887		if (setting)
888			ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE;
889		else
890			ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE;
891		/* NB: write here so keys can be setup w/o a reset */
892		OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode);
893		return AH_TRUE;
894	case HAL_CAP_DIVERSITY:
895		v = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
896		if (setting)
897			v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
898		else
899			v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
900		OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
901		return AH_TRUE;
902	case HAL_CAP_DIAG:		/* hardware diagnostic support */
903		/*
904		 * NB: could split this up into virtual capabilities,
905		 *     (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly
906		 *     seems worth the additional complexity.
907		 */
908		AH_PRIVATE(ah)->ah_diagreg = setting;
909		OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
910		return AH_TRUE;
911	case HAL_CAP_TPC:
912		ahp->ah_tpcEnabled = (setting != 0);
913		return AH_TRUE;
914	case HAL_CAP_MCAST_KEYSRCH:	/* multicast frame keycache search */
915		if (setting)
916			ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
917		else
918			ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
919		return AH_TRUE;
920	case HAL_CAP_TPC_ACK:
921	case HAL_CAP_TPC_CTS:
922		setting += ahp->ah_txPowerIndexOffset;
923		if (setting > 63)
924			setting = 63;
925		if (type == HAL_CAP_TPC_ACK) {
926			ahp->ah_macTPC &= AR_TPC_ACK;
927			ahp->ah_macTPC |= MS(setting, AR_TPC_ACK);
928		} else {
929			ahp->ah_macTPC &= AR_TPC_CTS;
930			ahp->ah_macTPC |= MS(setting, AR_TPC_CTS);
931		}
932		OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC);
933		return AH_TRUE;
934	case HAL_CAP_INTMIT: {		/* interference mitigation */
935		static const HAL_ANI_CMD cmds[] = {
936			HAL_ANI_PRESENT,
937			HAL_ANI_MODE,
938			HAL_ANI_NOISE_IMMUNITY_LEVEL,
939			HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
940			HAL_ANI_CCK_WEAK_SIGNAL_THR,
941			HAL_ANI_FIRSTEP_LEVEL,
942			HAL_ANI_SPUR_IMMUNITY_LEVEL,
943		};
944		return capability < N(cmds) ?
945			ar5212AniControl(ah, cmds[capability], setting) :
946			AH_FALSE;
947	}
948	case HAL_CAP_TSF_ADJUST:	/* hardware has beacon tsf adjust */
949		if (pCap->halTsfAddSupport) {
950			if (setting)
951				ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF;
952			else
953				ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF;
954			return AH_TRUE;
955		}
956		/* fall thru... */
957	default:
958		return ath_hal_setcapability(ah, type, capability,
959				setting, status);
960	}
961#undef N
962}
963
964HAL_BOOL
965ar5212GetDiagState(struct ath_hal *ah, int request,
966	const void *args, uint32_t argsize,
967	void **result, uint32_t *resultsize)
968{
969	struct ath_hal_5212 *ahp = AH5212(ah);
970
971	(void) ahp;
972	if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
973		return AH_TRUE;
974	switch (request) {
975	case HAL_DIAG_EEPROM:
976	case HAL_DIAG_EEPROM_EXP_11A:
977	case HAL_DIAG_EEPROM_EXP_11B:
978	case HAL_DIAG_EEPROM_EXP_11G:
979	case HAL_DIAG_RFGAIN:
980		return ath_hal_eepromDiag(ah, request,
981		    args, argsize, result, resultsize);
982	case HAL_DIAG_RFGAIN_CURSTEP:
983		*result = __DECONST(void *, ahp->ah_gainValues.currStep);
984		*resultsize = (*result == AH_NULL) ?
985			0 : sizeof(GAIN_OPTIMIZATION_STEP);
986		return AH_TRUE;
987	case HAL_DIAG_PCDAC:
988		*result = ahp->ah_pcdacTable;
989		*resultsize = ahp->ah_pcdacTableSize;
990		return AH_TRUE;
991	case HAL_DIAG_TXRATES:
992		*result = &ahp->ah_ratesArray[0];
993		*resultsize = sizeof(ahp->ah_ratesArray);
994		return AH_TRUE;
995	case HAL_DIAG_ANI_CURRENT:
996		*result = ar5212AniGetCurrentState(ah);
997		*resultsize = (*result == AH_NULL) ?
998			0 : sizeof(struct ar5212AniState);
999		return AH_TRUE;
1000	case HAL_DIAG_ANI_STATS:
1001		*result = ar5212AniGetCurrentStats(ah);
1002		*resultsize = (*result == AH_NULL) ?
1003			0 : sizeof(struct ar5212Stats);
1004		return AH_TRUE;
1005	case HAL_DIAG_ANI_CMD:
1006		if (argsize != 2*sizeof(uint32_t))
1007			return AH_FALSE;
1008		ar5212AniControl(ah, ((const uint32_t *)args)[0],
1009			((const uint32_t *)args)[1]);
1010		return AH_TRUE;
1011	case HAL_DIAG_ANI_PARAMS:
1012		/*
1013		 * NB: We assume struct ar5212AniParams is identical
1014		 * to HAL_ANI_PARAMS; if they diverge then we'll need
1015		 * to handle it here
1016		 */
1017		if (argsize == 0 && args == AH_NULL) {
1018			struct ar5212AniState *aniState =
1019			    ar5212AniGetCurrentState(ah);
1020			if (aniState == AH_NULL)
1021				return AH_FALSE;
1022			*result = __DECONST(void *, aniState->params);
1023			*resultsize = sizeof(struct ar5212AniParams);
1024			return AH_TRUE;
1025		} else {
1026			if (argsize != sizeof(struct ar5212AniParams))
1027				return AH_FALSE;
1028			return ar5212AniSetParams(ah, args, args);
1029		}
1030	}
1031	return AH_FALSE;
1032}
1033#endif /* AH_SUPPORT_AR5212 */
1034