16e778a7eSPedro F. Giffuni /*-
26e778a7eSPedro F. Giffuni * SPDX-License-Identifier: ISC
36e778a7eSPedro F. Giffuni *
459efa8b5SSam Leffler * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
514779705SSam Leffler * Copyright (c) 2002-2008 Atheros Communications, Inc.
614779705SSam Leffler *
714779705SSam Leffler * Permission to use, copy, modify, and/or distribute this software for any
814779705SSam Leffler * purpose with or without fee is hereby granted, provided that the above
914779705SSam Leffler * copyright notice and this permission notice appear in all copies.
1014779705SSam Leffler *
1114779705SSam Leffler * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1214779705SSam Leffler * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1314779705SSam Leffler * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1414779705SSam Leffler * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1514779705SSam Leffler * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1614779705SSam Leffler * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1714779705SSam Leffler * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1814779705SSam Leffler */
1914779705SSam Leffler #include "opt_ah.h"
2014779705SSam Leffler
2114779705SSam Leffler #include "ah.h"
2214779705SSam Leffler #include "ah_internal.h"
2314779705SSam Leffler #include "ah_devid.h"
2414779705SSam Leffler #include "ah_desc.h" /* NB: for HAL_PHYERR* */
2514779705SSam Leffler
2614779705SSam Leffler #include "ar5212/ar5212.h"
2714779705SSam Leffler #include "ar5212/ar5212reg.h"
2814779705SSam Leffler #include "ar5212/ar5212phy.h"
2914779705SSam Leffler
3014779705SSam Leffler #include "ah_eeprom_v3.h"
3114779705SSam Leffler
3214779705SSam Leffler #define AR_NUM_GPIO 6 /* 6 GPIO pins */
3314779705SSam Leffler #define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */
3414779705SSam Leffler
3514779705SSam Leffler void
ar5212GetMacAddress(struct ath_hal * ah,uint8_t * mac)3614779705SSam Leffler ar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac)
3714779705SSam Leffler {
3814779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
3914779705SSam Leffler
4014779705SSam Leffler OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN);
4114779705SSam Leffler }
4214779705SSam Leffler
4314779705SSam Leffler HAL_BOOL
ar5212SetMacAddress(struct ath_hal * ah,const uint8_t * mac)4414779705SSam Leffler ar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac)
4514779705SSam Leffler {
4614779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
4714779705SSam Leffler
4814779705SSam Leffler OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN);
4914779705SSam Leffler return AH_TRUE;
5014779705SSam Leffler }
5114779705SSam Leffler
5214779705SSam Leffler void
ar5212GetBssIdMask(struct ath_hal * ah,uint8_t * mask)5314779705SSam Leffler ar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask)
5414779705SSam Leffler {
5514779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
5614779705SSam Leffler
5714779705SSam Leffler OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN);
5814779705SSam Leffler }
5914779705SSam Leffler
6014779705SSam Leffler HAL_BOOL
ar5212SetBssIdMask(struct ath_hal * ah,const uint8_t * mask)6114779705SSam Leffler ar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask)
6214779705SSam Leffler {
6314779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
6414779705SSam Leffler
6514779705SSam Leffler /* save it since it must be rewritten on reset */
6614779705SSam Leffler OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN);
6714779705SSam Leffler
6814779705SSam Leffler OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));
6914779705SSam Leffler OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));
7014779705SSam Leffler return AH_TRUE;
7114779705SSam Leffler }
7214779705SSam Leffler
7314779705SSam Leffler /*
7414779705SSam Leffler * Attempt to change the cards operating regulatory domain to the given value
7514779705SSam Leffler */
7614779705SSam Leffler HAL_BOOL
ar5212SetRegulatoryDomain(struct ath_hal * ah,uint16_t regDomain,HAL_STATUS * status)7714779705SSam Leffler ar5212SetRegulatoryDomain(struct ath_hal *ah,
7814779705SSam Leffler uint16_t regDomain, HAL_STATUS *status)
7914779705SSam Leffler {
8014779705SSam Leffler HAL_STATUS ecode;
8114779705SSam Leffler
8214779705SSam Leffler if (AH_PRIVATE(ah)->ah_currentRD == regDomain) {
8314779705SSam Leffler ecode = HAL_EINVAL;
8414779705SSam Leffler goto bad;
8514779705SSam Leffler }
8614779705SSam Leffler if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) {
8714779705SSam Leffler ecode = HAL_EEWRITE;
8814779705SSam Leffler goto bad;
8914779705SSam Leffler }
9014779705SSam Leffler #ifdef AH_SUPPORT_WRITE_REGDOMAIN
9114779705SSam Leffler if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) {
9214779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
9314779705SSam Leffler "%s: set regulatory domain to %u (0x%x)\n",
9414779705SSam Leffler __func__, regDomain, regDomain);
9514779705SSam Leffler AH_PRIVATE(ah)->ah_currentRD = regDomain;
9614779705SSam Leffler return AH_TRUE;
9714779705SSam Leffler }
9814779705SSam Leffler #endif
9914779705SSam Leffler ecode = HAL_EIO;
10014779705SSam Leffler bad:
10114779705SSam Leffler if (status)
10214779705SSam Leffler *status = ecode;
10314779705SSam Leffler return AH_FALSE;
10414779705SSam Leffler }
10514779705SSam Leffler
10614779705SSam Leffler /*
10714779705SSam Leffler * Return the wireless modes (a,b,g,t) supported by hardware.
10814779705SSam Leffler *
10914779705SSam Leffler * This value is what is actually supported by the hardware
11014779705SSam Leffler * and is unaffected by regulatory/country code settings.
11114779705SSam Leffler */
11214779705SSam Leffler u_int
ar5212GetWirelessModes(struct ath_hal * ah)11314779705SSam Leffler ar5212GetWirelessModes(struct ath_hal *ah)
11414779705SSam Leffler {
11514779705SSam Leffler u_int mode = 0;
11614779705SSam Leffler
11714779705SSam Leffler if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) {
11814779705SSam Leffler mode = HAL_MODE_11A;
11914779705SSam Leffler if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE))
12014779705SSam Leffler mode |= HAL_MODE_TURBO | HAL_MODE_108A;
12114779705SSam Leffler if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate)
12214779705SSam Leffler mode |= HAL_MODE_11A_HALF_RATE;
12314779705SSam Leffler if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate)
12414779705SSam Leffler mode |= HAL_MODE_11A_QUARTER_RATE;
12514779705SSam Leffler }
12614779705SSam Leffler if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE))
12714779705SSam Leffler mode |= HAL_MODE_11B;
12814779705SSam Leffler if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) &&
12914779705SSam Leffler AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) {
13014779705SSam Leffler mode |= HAL_MODE_11G;
13114779705SSam Leffler if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE))
13214779705SSam Leffler mode |= HAL_MODE_108G;
13314779705SSam Leffler if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate)
13414779705SSam Leffler mode |= HAL_MODE_11G_HALF_RATE;
13514779705SSam Leffler if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate)
13614779705SSam Leffler mode |= HAL_MODE_11G_QUARTER_RATE;
13714779705SSam Leffler }
13814779705SSam Leffler return mode;
13914779705SSam Leffler }
14014779705SSam Leffler
14114779705SSam Leffler /*
14214779705SSam Leffler * Set the interrupt and GPIO values so the ISR can disable RF
14314779705SSam Leffler * on a switch signal. Assumes GPIO port and interrupt polarity
14414779705SSam Leffler * are set prior to call.
14514779705SSam Leffler */
14614779705SSam Leffler void
ar5212EnableRfKill(struct ath_hal * ah)14714779705SSam Leffler ar5212EnableRfKill(struct ath_hal *ah)
14814779705SSam Leffler {
14914779705SSam Leffler uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent;
15014779705SSam Leffler int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL);
15114779705SSam Leffler int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY);
15214779705SSam Leffler
15314779705SSam Leffler /*
15414779705SSam Leffler * Configure the desired GPIO port for input
15514779705SSam Leffler * and enable baseband rf silence.
15614779705SSam Leffler */
15714779705SSam Leffler ath_hal_gpioCfgInput(ah, select);
15814779705SSam Leffler OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000);
15914779705SSam Leffler /*
16014779705SSam Leffler * If radio disable switch connection to GPIO bit x is enabled
16114779705SSam Leffler * program GPIO interrupt.
16214779705SSam Leffler * If rfkill bit on eeprom is 1, setupeeprommap routine has already
16314779705SSam Leffler * verified that it is a later version of eeprom, it has a place for
16414779705SSam Leffler * rfkill bit and it is set to 1, indicating that GPIO bit x hardware
16514779705SSam Leffler * connection is present.
16614779705SSam Leffler */
16714779705SSam Leffler ath_hal_gpioSetIntr(ah, select,
16814779705SSam Leffler (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity));
16914779705SSam Leffler }
17014779705SSam Leffler
17114779705SSam Leffler /*
17214779705SSam Leffler * Change the LED blinking pattern to correspond to the connectivity
17314779705SSam Leffler */
17414779705SSam Leffler void
ar5212SetLedState(struct ath_hal * ah,HAL_LED_STATE state)17514779705SSam Leffler ar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state)
17614779705SSam Leffler {
17714779705SSam Leffler static const uint32_t ledbits[8] = {
17814779705SSam Leffler AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */
17914779705SSam Leffler AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */
18014779705SSam Leffler AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */
18114779705SSam Leffler AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/
18214779705SSam Leffler AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */
18314779705SSam Leffler AR_PCICFG_LEDCTL_NONE,
18414779705SSam Leffler AR_PCICFG_LEDCTL_NONE,
18514779705SSam Leffler AR_PCICFG_LEDCTL_NONE,
18614779705SSam Leffler };
18714779705SSam Leffler uint32_t bits;
18814779705SSam Leffler
18914779705SSam Leffler bits = OS_REG_READ(ah, AR_PCICFG);
19014779705SSam Leffler if (IS_2417(ah)) {
19114779705SSam Leffler /*
19214779705SSam Leffler * Enable LED for Nala. There is a bit marked reserved
19314779705SSam Leffler * that must be set and we also turn on the power led.
19414779705SSam Leffler * Because we mark s/w LED control setting the control
19514779705SSam Leffler * status bits below is meangless (the driver must flash
19614779705SSam Leffler * the LED(s) using the GPIO lines).
19714779705SSam Leffler */
19814779705SSam Leffler bits = (bits &~ AR_PCICFG_LEDMODE)
19914779705SSam Leffler | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE)
20014779705SSam Leffler #if 0
20114779705SSam Leffler | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE)
20214779705SSam Leffler #endif
20314779705SSam Leffler | 0x08000000;
20414779705SSam Leffler }
20514779705SSam Leffler bits = (bits &~ AR_PCICFG_LEDCTL)
20614779705SSam Leffler | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL);
20714779705SSam Leffler OS_REG_WRITE(ah, AR_PCICFG, bits);
20814779705SSam Leffler }
20914779705SSam Leffler
21014779705SSam Leffler /*
21114779705SSam Leffler * Change association related fields programmed into the hardware.
21214779705SSam Leffler * Writing a valid BSSID to the hardware effectively enables the hardware
21314779705SSam Leffler * to synchronize its TSF to the correct beacons and receive frames coming
21414779705SSam Leffler * from that BSSID. It is called by the SME JOIN operation.
21514779705SSam Leffler */
21614779705SSam Leffler void
ar5212WriteAssocid(struct ath_hal * ah,const uint8_t * bssid,uint16_t assocId)21714779705SSam Leffler ar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId)
21814779705SSam Leffler {
21914779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
22014779705SSam Leffler
2210047ff70SAdrian Chadd /* save bssid for possible re-use on reset */
22214779705SSam Leffler OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);
2230047ff70SAdrian Chadd ahp->ah_assocId = assocId;
22414779705SSam Leffler OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
22514779705SSam Leffler OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) |
22614779705SSam Leffler ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S));
22714779705SSam Leffler }
22814779705SSam Leffler
22914779705SSam Leffler /*
23014779705SSam Leffler * Get the current hardware tsf for stamlme
23114779705SSam Leffler */
23214779705SSam Leffler uint64_t
ar5212GetTsf64(struct ath_hal * ah)23314779705SSam Leffler ar5212GetTsf64(struct ath_hal *ah)
23414779705SSam Leffler {
23514779705SSam Leffler uint32_t low1, low2, u32;
23614779705SSam Leffler
23714779705SSam Leffler /* sync multi-word read */
23814779705SSam Leffler low1 = OS_REG_READ(ah, AR_TSF_L32);
23914779705SSam Leffler u32 = OS_REG_READ(ah, AR_TSF_U32);
24014779705SSam Leffler low2 = OS_REG_READ(ah, AR_TSF_L32);
24114779705SSam Leffler if (low2 < low1) { /* roll over */
24214779705SSam Leffler /*
24314779705SSam Leffler * If we are not preempted this will work. If we are
24414779705SSam Leffler * then we re-reading AR_TSF_U32 does no good as the
24514779705SSam Leffler * low bits will be meaningless. Likewise reading
24614779705SSam Leffler * L32, U32, U32, then comparing the last two reads
24714779705SSam Leffler * to check for rollover doesn't help if preempted--so
24814779705SSam Leffler * we take this approach as it costs one less PCI read
24914779705SSam Leffler * which can be noticeable when doing things like
25014779705SSam Leffler * timestamping packets in monitor mode.
25114779705SSam Leffler */
25214779705SSam Leffler u32++;
25314779705SSam Leffler }
25414779705SSam Leffler return (((uint64_t) u32) << 32) | ((uint64_t) low2);
25514779705SSam Leffler }
25614779705SSam Leffler
25714779705SSam Leffler /*
25814779705SSam Leffler * Get the current hardware tsf for stamlme
25914779705SSam Leffler */
26014779705SSam Leffler uint32_t
ar5212GetTsf32(struct ath_hal * ah)26114779705SSam Leffler ar5212GetTsf32(struct ath_hal *ah)
26214779705SSam Leffler {
26314779705SSam Leffler return OS_REG_READ(ah, AR_TSF_L32);
26414779705SSam Leffler }
26514779705SSam Leffler
266beb4faf3SAdrian Chadd void
ar5212SetTsf64(struct ath_hal * ah,uint64_t tsf64)267beb4faf3SAdrian Chadd ar5212SetTsf64(struct ath_hal *ah, uint64_t tsf64)
268beb4faf3SAdrian Chadd {
269beb4faf3SAdrian Chadd OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);
270beb4faf3SAdrian Chadd OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
271beb4faf3SAdrian Chadd }
272beb4faf3SAdrian Chadd
27314779705SSam Leffler /*
27414779705SSam Leffler * Reset the current hardware tsf for stamlme.
27514779705SSam Leffler */
27614779705SSam Leffler void
ar5212ResetTsf(struct ath_hal * ah)27714779705SSam Leffler ar5212ResetTsf(struct ath_hal *ah)
27814779705SSam Leffler {
27914779705SSam Leffler
28014779705SSam Leffler uint32_t val = OS_REG_READ(ah, AR_BEACON);
28114779705SSam Leffler
28214779705SSam Leffler OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);
28314779705SSam Leffler /*
28414779705SSam Leffler * When resetting the TSF, write twice to the
28514779705SSam Leffler * corresponding register; each write to the RESET_TSF bit toggles
28614779705SSam Leffler * the internal signal to cause a reset of the TSF - but if the signal
28714779705SSam Leffler * is left high, it will reset the TSF on the next chip reset also!
28814779705SSam Leffler * writing the bit an even number of times fixes this issue
28914779705SSam Leffler */
29014779705SSam Leffler OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);
29114779705SSam Leffler }
29214779705SSam Leffler
29314779705SSam Leffler /*
29414779705SSam Leffler * Set or clear hardware basic rate bit
29514779705SSam Leffler * Set hardware basic rate set if basic rate is found
29614779705SSam Leffler * and basic rate is equal or less than 2Mbps
29714779705SSam Leffler */
29814779705SSam Leffler void
ar5212SetBasicRate(struct ath_hal * ah,HAL_RATE_SET * rs)29914779705SSam Leffler ar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs)
30014779705SSam Leffler {
30159efa8b5SSam Leffler const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
30214779705SSam Leffler uint32_t reg;
30314779705SSam Leffler uint8_t xset;
30414779705SSam Leffler int i;
30514779705SSam Leffler
30659efa8b5SSam Leffler if (chan == AH_NULL || !IEEE80211_IS_CHAN_CCK(chan))
30714779705SSam Leffler return;
30814779705SSam Leffler xset = 0;
30914779705SSam Leffler for (i = 0; i < rs->rs_count; i++) {
31014779705SSam Leffler uint8_t rset = rs->rs_rates[i];
31114779705SSam Leffler /* Basic rate defined? */
31214779705SSam Leffler if ((rset & 0x80) && (rset &= 0x7f) >= xset)
31314779705SSam Leffler xset = rset;
31414779705SSam Leffler }
31514779705SSam Leffler /*
31614779705SSam Leffler * Set the h/w bit to reflect whether or not the basic
31714779705SSam Leffler * rate is found to be equal or less than 2Mbps.
31814779705SSam Leffler */
31914779705SSam Leffler reg = OS_REG_READ(ah, AR_STA_ID1);
32014779705SSam Leffler if (xset && xset/2 <= 2)
32114779705SSam Leffler OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B);
32214779705SSam Leffler else
32314779705SSam Leffler OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B);
32414779705SSam Leffler }
32514779705SSam Leffler
32614779705SSam Leffler /*
32714779705SSam Leffler * Grab a semi-random value from hardware registers - may not
32814779705SSam Leffler * change often
32914779705SSam Leffler */
33014779705SSam Leffler uint32_t
ar5212GetRandomSeed(struct ath_hal * ah)33114779705SSam Leffler ar5212GetRandomSeed(struct ath_hal *ah)
33214779705SSam Leffler {
33314779705SSam Leffler uint32_t nf;
33414779705SSam Leffler
33514779705SSam Leffler nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff;
33614779705SSam Leffler if (nf & 0x100)
33714779705SSam Leffler nf = 0 - ((nf ^ 0x1ff) + 1);
33814779705SSam Leffler return (OS_REG_READ(ah, AR_TSF_U32) ^
33914779705SSam Leffler OS_REG_READ(ah, AR_TSF_L32) ^ nf);
34014779705SSam Leffler }
34114779705SSam Leffler
34214779705SSam Leffler /*
34314779705SSam Leffler * Detect if our card is present
34414779705SSam Leffler */
34514779705SSam Leffler HAL_BOOL
ar5212DetectCardPresent(struct ath_hal * ah)34614779705SSam Leffler ar5212DetectCardPresent(struct ath_hal *ah)
34714779705SSam Leffler {
34814779705SSam Leffler uint16_t macVersion, macRev;
34914779705SSam Leffler uint32_t v;
35014779705SSam Leffler
35114779705SSam Leffler /*
35214779705SSam Leffler * Read the Silicon Revision register and compare that
35314779705SSam Leffler * to what we read at attach time. If the same, we say
35414779705SSam Leffler * a card/device is present.
35514779705SSam Leffler */
35614779705SSam Leffler v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID;
35714779705SSam Leffler macVersion = v >> AR_SREV_ID_S;
35814779705SSam Leffler macRev = v & AR_SREV_REVISION;
35914779705SSam Leffler return (AH_PRIVATE(ah)->ah_macVersion == macVersion &&
36014779705SSam Leffler AH_PRIVATE(ah)->ah_macRev == macRev);
36114779705SSam Leffler }
36214779705SSam Leffler
36314779705SSam Leffler void
ar5212EnableMibCounters(struct ath_hal * ah)36414779705SSam Leffler ar5212EnableMibCounters(struct ath_hal *ah)
36514779705SSam Leffler {
36614779705SSam Leffler /* NB: this just resets the mib counter machinery */
36714779705SSam Leffler OS_REG_WRITE(ah, AR_MIBC,
36814779705SSam Leffler ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f);
36914779705SSam Leffler }
37014779705SSam Leffler
37114779705SSam Leffler void
ar5212DisableMibCounters(struct ath_hal * ah)37214779705SSam Leffler ar5212DisableMibCounters(struct ath_hal *ah)
37314779705SSam Leffler {
37414779705SSam Leffler OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC);
37514779705SSam Leffler }
37614779705SSam Leffler
37714779705SSam Leffler /*
37814779705SSam Leffler * Update MIB Counters
37914779705SSam Leffler */
38014779705SSam Leffler void
ar5212UpdateMibCounters(struct ath_hal * ah,HAL_MIB_STATS * stats)38114779705SSam Leffler ar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats)
38214779705SSam Leffler {
38314779705SSam Leffler stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL);
38414779705SSam Leffler stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL);
38514779705SSam Leffler stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL);
38614779705SSam Leffler stats->rts_good += OS_REG_READ(ah, AR_RTS_OK);
38714779705SSam Leffler stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT);
38814779705SSam Leffler }
38914779705SSam Leffler
39014779705SSam Leffler /*
39114779705SSam Leffler * Detect if the HW supports spreading a CCK signal on channel 14
39214779705SSam Leffler */
39314779705SSam Leffler HAL_BOOL
ar5212IsJapanChannelSpreadSupported(struct ath_hal * ah)39414779705SSam Leffler ar5212IsJapanChannelSpreadSupported(struct ath_hal *ah)
39514779705SSam Leffler {
39614779705SSam Leffler return AH_TRUE;
39714779705SSam Leffler }
39814779705SSam Leffler
39914779705SSam Leffler /*
40014779705SSam Leffler * Get the rssi of frame curently being received.
40114779705SSam Leffler */
40214779705SSam Leffler uint32_t
ar5212GetCurRssi(struct ath_hal * ah)40314779705SSam Leffler ar5212GetCurRssi(struct ath_hal *ah)
40414779705SSam Leffler {
40514779705SSam Leffler return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff);
40614779705SSam Leffler }
40714779705SSam Leffler
40814779705SSam Leffler u_int
ar5212GetDefAntenna(struct ath_hal * ah)40914779705SSam Leffler ar5212GetDefAntenna(struct ath_hal *ah)
41014779705SSam Leffler {
41114779705SSam Leffler return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7);
41214779705SSam Leffler }
41314779705SSam Leffler
41414779705SSam Leffler void
ar5212SetDefAntenna(struct ath_hal * ah,u_int antenna)41514779705SSam Leffler ar5212SetDefAntenna(struct ath_hal *ah, u_int antenna)
41614779705SSam Leffler {
41714779705SSam Leffler OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
41814779705SSam Leffler }
41914779705SSam Leffler
42014779705SSam Leffler HAL_ANT_SETTING
ar5212GetAntennaSwitch(struct ath_hal * ah)42114779705SSam Leffler ar5212GetAntennaSwitch(struct ath_hal *ah)
42214779705SSam Leffler {
42314779705SSam Leffler return AH5212(ah)->ah_antControl;
42414779705SSam Leffler }
42514779705SSam Leffler
42614779705SSam Leffler HAL_BOOL
ar5212SetAntennaSwitch(struct ath_hal * ah,HAL_ANT_SETTING setting)42714779705SSam Leffler ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting)
42814779705SSam Leffler {
42914779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
43059efa8b5SSam Leffler const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
43114779705SSam Leffler
43259efa8b5SSam Leffler if (!ahp->ah_phyPowerOn || chan == AH_NULL) {
43314779705SSam Leffler /* PHY powered off, just stash settings */
43414779705SSam Leffler ahp->ah_antControl = setting;
43514779705SSam Leffler ahp->ah_diversity = (setting == HAL_ANT_VARIABLE);
43614779705SSam Leffler return AH_TRUE;
43714779705SSam Leffler }
43859efa8b5SSam Leffler return ar5212SetAntennaSwitchInternal(ah, setting, chan);
43914779705SSam Leffler }
44014779705SSam Leffler
44114779705SSam Leffler HAL_BOOL
ar5212IsSleepAfterBeaconBroken(struct ath_hal * ah)44214779705SSam Leffler ar5212IsSleepAfterBeaconBroken(struct ath_hal *ah)
44314779705SSam Leffler {
44414779705SSam Leffler return AH_TRUE;
44514779705SSam Leffler }
44614779705SSam Leffler
44714779705SSam Leffler HAL_BOOL
ar5212SetSifsTime(struct ath_hal * ah,u_int us)44814779705SSam Leffler ar5212SetSifsTime(struct ath_hal *ah, u_int us)
44914779705SSam Leffler {
45014779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
45114779705SSam Leffler
45214779705SSam Leffler if (us > ath_hal_mac_usec(ah, 0xffff)) {
45314779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n",
45414779705SSam Leffler __func__, us);
45514779705SSam Leffler ahp->ah_sifstime = (u_int) -1; /* restore default handling */
45614779705SSam Leffler return AH_FALSE;
45714779705SSam Leffler } else {
45814779705SSam Leffler /* convert to system clocks */
459dc6592f8SSam Leffler OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us-2));
4603118fac3SAdrian Chadd ahp->ah_sifstime = us;
46114779705SSam Leffler return AH_TRUE;
46214779705SSam Leffler }
46314779705SSam Leffler }
46414779705SSam Leffler
46514779705SSam Leffler u_int
ar5212GetSifsTime(struct ath_hal * ah)46614779705SSam Leffler ar5212GetSifsTime(struct ath_hal *ah)
46714779705SSam Leffler {
46814779705SSam Leffler u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff;
469dc6592f8SSam Leffler return ath_hal_mac_usec(ah, clks)+2; /* convert from system clocks */
47014779705SSam Leffler }
47114779705SSam Leffler
47214779705SSam Leffler HAL_BOOL
ar5212SetSlotTime(struct ath_hal * ah,u_int us)47314779705SSam Leffler ar5212SetSlotTime(struct ath_hal *ah, u_int us)
47414779705SSam Leffler {
47514779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
47614779705SSam Leffler
47714779705SSam Leffler if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) {
47814779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n",
47914779705SSam Leffler __func__, us);
48014779705SSam Leffler ahp->ah_slottime = (u_int) -1; /* restore default handling */
48114779705SSam Leffler return AH_FALSE;
48214779705SSam Leffler } else {
48314779705SSam Leffler /* convert to system clocks */
48414779705SSam Leffler OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us));
48514779705SSam Leffler ahp->ah_slottime = us;
48614779705SSam Leffler return AH_TRUE;
48714779705SSam Leffler }
48814779705SSam Leffler }
48914779705SSam Leffler
49014779705SSam Leffler u_int
ar5212GetSlotTime(struct ath_hal * ah)49114779705SSam Leffler ar5212GetSlotTime(struct ath_hal *ah)
49214779705SSam Leffler {
49314779705SSam Leffler u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff;
49414779705SSam Leffler return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
49514779705SSam Leffler }
49614779705SSam Leffler
49714779705SSam Leffler HAL_BOOL
ar5212SetAckTimeout(struct ath_hal * ah,u_int us)49814779705SSam Leffler ar5212SetAckTimeout(struct ath_hal *ah, u_int us)
49914779705SSam Leffler {
50014779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
50114779705SSam Leffler
50214779705SSam Leffler if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
50314779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n",
50414779705SSam Leffler __func__, us);
50514779705SSam Leffler ahp->ah_acktimeout = (u_int) -1; /* restore default handling */
50614779705SSam Leffler return AH_FALSE;
50714779705SSam Leffler } else {
50814779705SSam Leffler /* convert to system clocks */
50914779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_TIME_OUT,
51014779705SSam Leffler AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us));
51114779705SSam Leffler ahp->ah_acktimeout = us;
51214779705SSam Leffler return AH_TRUE;
51314779705SSam Leffler }
51414779705SSam Leffler }
51514779705SSam Leffler
51614779705SSam Leffler u_int
ar5212GetAckTimeout(struct ath_hal * ah)51714779705SSam Leffler ar5212GetAckTimeout(struct ath_hal *ah)
51814779705SSam Leffler {
51914779705SSam Leffler u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK);
52014779705SSam Leffler return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
52114779705SSam Leffler }
52214779705SSam Leffler
52314779705SSam Leffler u_int
ar5212GetAckCTSRate(struct ath_hal * ah)52414779705SSam Leffler ar5212GetAckCTSRate(struct ath_hal *ah)
52514779705SSam Leffler {
52614779705SSam Leffler return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0);
52714779705SSam Leffler }
52814779705SSam Leffler
52914779705SSam Leffler HAL_BOOL
ar5212SetAckCTSRate(struct ath_hal * ah,u_int high)53014779705SSam Leffler ar5212SetAckCTSRate(struct ath_hal *ah, u_int high)
53114779705SSam Leffler {
53214779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
53314779705SSam Leffler
53414779705SSam Leffler if (high) {
53514779705SSam Leffler OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);
53614779705SSam Leffler ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB;
53714779705SSam Leffler } else {
53814779705SSam Leffler OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);
53914779705SSam Leffler ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB;
54014779705SSam Leffler }
54114779705SSam Leffler return AH_TRUE;
54214779705SSam Leffler }
54314779705SSam Leffler
54414779705SSam Leffler HAL_BOOL
ar5212SetCTSTimeout(struct ath_hal * ah,u_int us)54514779705SSam Leffler ar5212SetCTSTimeout(struct ath_hal *ah, u_int us)
54614779705SSam Leffler {
54714779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
54814779705SSam Leffler
54914779705SSam Leffler if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
55014779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n",
55114779705SSam Leffler __func__, us);
55214779705SSam Leffler ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */
55314779705SSam Leffler return AH_FALSE;
55414779705SSam Leffler } else {
55514779705SSam Leffler /* convert to system clocks */
55614779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_TIME_OUT,
55714779705SSam Leffler AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us));
55814779705SSam Leffler ahp->ah_ctstimeout = us;
55914779705SSam Leffler return AH_TRUE;
56014779705SSam Leffler }
56114779705SSam Leffler }
56214779705SSam Leffler
56314779705SSam Leffler u_int
ar5212GetCTSTimeout(struct ath_hal * ah)56414779705SSam Leffler ar5212GetCTSTimeout(struct ath_hal *ah)
56514779705SSam Leffler {
56614779705SSam Leffler u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS);
56714779705SSam Leffler return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
56814779705SSam Leffler }
56914779705SSam Leffler
57014779705SSam Leffler /* Setup decompression for given key index */
57114779705SSam Leffler HAL_BOOL
ar5212SetDecompMask(struct ath_hal * ah,uint16_t keyidx,int en)57214779705SSam Leffler ar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)
57314779705SSam Leffler {
57414779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
57514779705SSam Leffler
57614779705SSam Leffler if (keyidx >= HAL_DECOMP_MASK_SIZE)
577ead07963SAdrian Chadd return AH_FALSE;
57814779705SSam Leffler OS_REG_WRITE(ah, AR_DCM_A, keyidx);
57914779705SSam Leffler OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0);
58014779705SSam Leffler ahp->ah_decompMask[keyidx] = en;
58114779705SSam Leffler
58214779705SSam Leffler return AH_TRUE;
58314779705SSam Leffler }
58414779705SSam Leffler
58514779705SSam Leffler /* Setup coverage class */
58614779705SSam Leffler void
ar5212SetCoverageClass(struct ath_hal * ah,uint8_t coverageclass,int now)58714779705SSam Leffler ar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
58814779705SSam Leffler {
58914779705SSam Leffler uint32_t slot, timeout, eifs;
59014779705SSam Leffler u_int clkRate;
59114779705SSam Leffler
59214779705SSam Leffler AH_PRIVATE(ah)->ah_coverageClass = coverageclass;
59314779705SSam Leffler
59414779705SSam Leffler if (now) {
59514779705SSam Leffler if (AH_PRIVATE(ah)->ah_coverageClass == 0)
59614779705SSam Leffler return;
59714779705SSam Leffler
59814779705SSam Leffler /* Don't apply coverage class to non A channels */
59959efa8b5SSam Leffler if (!IEEE80211_IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan))
60014779705SSam Leffler return;
60114779705SSam Leffler
60214779705SSam Leffler /* Get core clock rate */
60314779705SSam Leffler clkRate = ath_hal_mac_clks(ah, 1);
60414779705SSam Leffler
60514779705SSam Leffler /* Compute EIFS */
60614779705SSam Leffler slot = coverageclass * 3 * clkRate;
60714779705SSam Leffler eifs = coverageclass * 6 * clkRate;
60859efa8b5SSam Leffler if (IEEE80211_IS_CHAN_HALF(AH_PRIVATE(ah)->ah_curchan)) {
60914779705SSam Leffler slot += IFS_SLOT_HALF_RATE;
61014779705SSam Leffler eifs += IFS_EIFS_HALF_RATE;
61159efa8b5SSam Leffler } else if (IEEE80211_IS_CHAN_QUARTER(AH_PRIVATE(ah)->ah_curchan)) {
61214779705SSam Leffler slot += IFS_SLOT_QUARTER_RATE;
61314779705SSam Leffler eifs += IFS_EIFS_QUARTER_RATE;
61414779705SSam Leffler } else { /* full rate */
61514779705SSam Leffler slot += IFS_SLOT_FULL_RATE;
61614779705SSam Leffler eifs += IFS_EIFS_FULL_RATE;
61714779705SSam Leffler }
61814779705SSam Leffler
61914779705SSam Leffler /*
62014779705SSam Leffler * Add additional time for air propagation for ACK and CTS
62114779705SSam Leffler * timeouts. This value is in core clocks.
62214779705SSam Leffler */
62314779705SSam Leffler timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate);
62414779705SSam Leffler
62514779705SSam Leffler /*
62614779705SSam Leffler * Write the values: slot, eifs, ack/cts timeouts.
62714779705SSam Leffler */
62814779705SSam Leffler OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot);
62914779705SSam Leffler OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);
63014779705SSam Leffler OS_REG_WRITE(ah, AR_TIME_OUT,
63114779705SSam Leffler SM(timeout, AR_TIME_OUT_CTS)
63214779705SSam Leffler | SM(timeout, AR_TIME_OUT_ACK));
63314779705SSam Leffler }
63414779705SSam Leffler }
63514779705SSam Leffler
63604d172dbSAdrian Chadd HAL_STATUS
ar5212SetQuiet(struct ath_hal * ah,uint32_t period,uint32_t duration,uint32_t nextStart,HAL_QUIET_FLAG flag)63704d172dbSAdrian Chadd ar5212SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration,
63804d172dbSAdrian Chadd uint32_t nextStart, HAL_QUIET_FLAG flag)
63904d172dbSAdrian Chadd {
64004d172dbSAdrian Chadd OS_REG_WRITE(ah, AR_QUIET2, period | (duration << AR_QUIET2_QUIET_DUR_S));
64104d172dbSAdrian Chadd if (flag & HAL_QUIET_ENABLE) {
64204d172dbSAdrian Chadd OS_REG_WRITE(ah, AR_QUIET1, nextStart | (1 << 16));
64304d172dbSAdrian Chadd }
64404d172dbSAdrian Chadd else {
64504d172dbSAdrian Chadd OS_REG_WRITE(ah, AR_QUIET1, nextStart);
64604d172dbSAdrian Chadd }
64704d172dbSAdrian Chadd return HAL_OK;
64804d172dbSAdrian Chadd }
64904d172dbSAdrian Chadd
65014779705SSam Leffler void
ar5212SetPCUConfig(struct ath_hal * ah)65114779705SSam Leffler ar5212SetPCUConfig(struct ath_hal *ah)
65214779705SSam Leffler {
65314779705SSam Leffler ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode);
65414779705SSam Leffler }
65514779705SSam Leffler
65614779705SSam Leffler /*
65714779705SSam Leffler * Return whether an external 32KHz crystal should be used
65814779705SSam Leffler * to reduce power consumption when sleeping. We do so if
65914779705SSam Leffler * the crystal is present (obtained from EEPROM) and if we
66014779705SSam Leffler * are not running as an AP and are configured to use it.
66114779705SSam Leffler */
66214779705SSam Leffler HAL_BOOL
ar5212Use32KHzclock(struct ath_hal * ah,HAL_OPMODE opmode)66314779705SSam Leffler ar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode)
66414779705SSam Leffler {
66514779705SSam Leffler if (opmode != HAL_M_HOSTAP) {
66614779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
66714779705SSam Leffler return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) &&
66814779705SSam Leffler (ahp->ah_enable32kHzClock == USE_32KHZ ||
66914779705SSam Leffler ahp->ah_enable32kHzClock == AUTO_32KHZ);
67014779705SSam Leffler } else
67114779705SSam Leffler return AH_FALSE;
67214779705SSam Leffler }
67314779705SSam Leffler
67414779705SSam Leffler /*
67514779705SSam Leffler * If 32KHz clock exists, use it to lower power consumption during sleep
67614779705SSam Leffler *
67714779705SSam Leffler * Note: If clock is set to 32 KHz, delays on accessing certain
67814779705SSam Leffler * baseband registers (27-31, 124-127) are required.
67914779705SSam Leffler */
68014779705SSam Leffler void
ar5212SetupClock(struct ath_hal * ah,HAL_OPMODE opmode)68114779705SSam Leffler ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode)
68214779705SSam Leffler {
68314779705SSam Leffler if (ar5212Use32KHzclock(ah, opmode)) {
68414779705SSam Leffler /*
68514779705SSam Leffler * Enable clocks to be turned OFF in BB during sleep
68614779705SSam Leffler * and also enable turning OFF 32MHz/40MHz Refclk
68714779705SSam Leffler * from A2.
68814779705SSam Leffler */
68914779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
69014779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
69114779705SSam Leffler IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18);
69214779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1);
69314779705SSam Leffler OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */
69414779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1);
69514779705SSam Leffler
69614779705SSam Leffler if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) {
69714779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26);
69814779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d);
69914779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07);
70014779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f);
70114779705SSam Leffler /* # Set sleep clock rate to 32 KHz. */
70214779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2);
70314779705SSam Leffler } else {
70414779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a);
70514779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c);
70614779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03);
70714779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20);
70814779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3);
70914779705SSam Leffler }
71014779705SSam Leffler } else {
71114779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0);
71214779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0);
71314779705SSam Leffler
71414779705SSam Leffler OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */
71514779705SSam Leffler
71614779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
71714779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f);
71814779705SSam Leffler
71914779705SSam Leffler if (IS_2417(ah))
72014779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a);
72114779705SSam Leffler else if (IS_HB63(ah))
72214779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32);
72314779705SSam Leffler else
72414779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
72514779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);
72614779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);
72714779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
72814779705SSam Leffler IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18);
72914779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,
73014779705SSam Leffler IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31);
73114779705SSam Leffler }
73214779705SSam Leffler }
73314779705SSam Leffler
73414779705SSam Leffler /*
73514779705SSam Leffler * If 32KHz clock exists, turn it off and turn back on the 32Mhz
73614779705SSam Leffler */
73714779705SSam Leffler void
ar5212RestoreClock(struct ath_hal * ah,HAL_OPMODE opmode)73814779705SSam Leffler ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode)
73914779705SSam Leffler {
74014779705SSam Leffler if (ar5212Use32KHzclock(ah, opmode)) {
74114779705SSam Leffler /* # Set sleep clock rate back to 32 MHz. */
74214779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0);
74314779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0);
74414779705SSam Leffler
74514779705SSam Leffler OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */
74614779705SSam Leffler OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,
74714779705SSam Leffler IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31);
74814779705SSam Leffler
74914779705SSam Leffler /*
75014779705SSam Leffler * Restore BB registers to power-on defaults
75114779705SSam Leffler */
75214779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);
75314779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f);
75414779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);
75514779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);
75614779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);
75714779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_REFCLKPD,
75814779705SSam Leffler IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18);
75914779705SSam Leffler }
76014779705SSam Leffler }
76114779705SSam Leffler
76214779705SSam Leffler /*
76314779705SSam Leffler * Adjust NF based on statistical values for 5GHz frequencies.
76414779705SSam Leffler * Default method: this may be overridden by the rf backend.
76514779705SSam Leffler */
76614779705SSam Leffler int16_t
ar5212GetNfAdjust(struct ath_hal * ah,const HAL_CHANNEL_INTERNAL * c)76714779705SSam Leffler ar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c)
76814779705SSam Leffler {
76914779705SSam Leffler static const struct {
77014779705SSam Leffler uint16_t freqLow;
77114779705SSam Leffler int16_t adjust;
77214779705SSam Leffler } adjustDef[] = {
77314779705SSam Leffler { 5790, 11 }, /* NB: ordered high -> low */
77414779705SSam Leffler { 5730, 10 },
77514779705SSam Leffler { 5690, 9 },
77614779705SSam Leffler { 5660, 8 },
77714779705SSam Leffler { 5610, 7 },
77814779705SSam Leffler { 5530, 5 },
77914779705SSam Leffler { 5450, 4 },
78014779705SSam Leffler { 5379, 2 },
78114779705SSam Leffler { 5209, 0 },
78214779705SSam Leffler { 3000, 1 },
78314779705SSam Leffler { 0, 0 },
78414779705SSam Leffler };
78514779705SSam Leffler int i;
78614779705SSam Leffler
78714779705SSam Leffler for (i = 0; c->channel <= adjustDef[i].freqLow; i++)
78814779705SSam Leffler ;
78914779705SSam Leffler return adjustDef[i].adjust;
79014779705SSam Leffler }
79114779705SSam Leffler
79214779705SSam Leffler HAL_STATUS
ar5212GetCapability(struct ath_hal * ah,HAL_CAPABILITY_TYPE type,uint32_t capability,uint32_t * result)79314779705SSam Leffler ar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
79414779705SSam Leffler uint32_t capability, uint32_t *result)
79514779705SSam Leffler {
79614779705SSam Leffler #define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion
79714779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
79814779705SSam Leffler const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
79914779705SSam Leffler const struct ar5212AniState *ani;
80014779705SSam Leffler
80114779705SSam Leffler switch (type) {
80214779705SSam Leffler case HAL_CAP_CIPHER: /* cipher handled in hardware */
80314779705SSam Leffler switch (capability) {
80414779705SSam Leffler case HAL_CIPHER_AES_CCM:
80514779705SSam Leffler return pCap->halCipherAesCcmSupport ?
80614779705SSam Leffler HAL_OK : HAL_ENOTSUPP;
80714779705SSam Leffler case HAL_CIPHER_AES_OCB:
80814779705SSam Leffler case HAL_CIPHER_TKIP:
80914779705SSam Leffler case HAL_CIPHER_WEP:
81014779705SSam Leffler case HAL_CIPHER_MIC:
81114779705SSam Leffler case HAL_CIPHER_CLR:
81214779705SSam Leffler return HAL_OK;
81314779705SSam Leffler default:
81414779705SSam Leffler return HAL_ENOTSUPP;
81514779705SSam Leffler }
81614779705SSam Leffler case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */
81714779705SSam Leffler switch (capability) {
81814779705SSam Leffler case 0: /* hardware capability */
81914779705SSam Leffler return HAL_OK;
82014779705SSam Leffler case 1:
82114779705SSam Leffler return (ahp->ah_staId1Defaults &
82214779705SSam Leffler AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO;
82314779705SSam Leffler }
82413f209a3SSam Leffler return HAL_EINVAL;
82514779705SSam Leffler case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */
82614779705SSam Leffler switch (capability) {
82714779705SSam Leffler case 0: /* hardware capability */
82814779705SSam Leffler return pCap->halTkipMicTxRxKeySupport ?
82914779705SSam Leffler HAL_ENXIO : HAL_OK;
83014779705SSam Leffler case 1: /* current setting */
83114779705SSam Leffler return (ahp->ah_miscMode &
83214779705SSam Leffler AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK;
83314779705SSam Leffler }
83414779705SSam Leffler return HAL_EINVAL;
83514779705SSam Leffler case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */
83614779705SSam Leffler /* XXX move to capability bit */
83714779705SSam Leffler return MACVERSION(ah) > AR_SREV_VERSION_VENICE ||
83814779705SSam Leffler (MACVERSION(ah) == AR_SREV_VERSION_VENICE &&
83914779705SSam Leffler AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP;
84014779705SSam Leffler case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */
84114779705SSam Leffler switch (capability) {
84214779705SSam Leffler case 0: /* hardware capability */
84314779705SSam Leffler return HAL_OK;
84414779705SSam Leffler case 1: /* current setting */
84514779705SSam Leffler return ahp->ah_diversity ? HAL_OK : HAL_ENXIO;
846d6af4e0fSAdrian Chadd case HAL_CAP_STRONG_DIV:
847d6af4e0fSAdrian Chadd *result = OS_REG_READ(ah, AR_PHY_RESTART);
848d6af4e0fSAdrian Chadd *result = MS(*result, AR_PHY_RESTART_DIV_GC);
849d6af4e0fSAdrian Chadd return HAL_OK;
85014779705SSam Leffler }
85114779705SSam Leffler return HAL_EINVAL;
85214779705SSam Leffler case HAL_CAP_DIAG:
85314779705SSam Leffler *result = AH_PRIVATE(ah)->ah_diagreg;
85414779705SSam Leffler return HAL_OK;
85514779705SSam Leffler case HAL_CAP_TPC:
85614779705SSam Leffler switch (capability) {
85714779705SSam Leffler case 0: /* hardware capability */
85814779705SSam Leffler return HAL_OK;
85914779705SSam Leffler case 1:
86014779705SSam Leffler return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO;
86114779705SSam Leffler }
86214779705SSam Leffler return HAL_OK;
86314779705SSam Leffler case HAL_CAP_PHYDIAG: /* radar pulse detection capability */
86414779705SSam Leffler switch (capability) {
86514779705SSam Leffler case HAL_CAP_RADAR:
86614779705SSam Leffler return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ?
86714779705SSam Leffler HAL_OK: HAL_ENXIO;
86814779705SSam Leffler case HAL_CAP_AR:
86914779705SSam Leffler return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) ||
87014779705SSam Leffler ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ?
87114779705SSam Leffler HAL_OK: HAL_ENXIO;
87214779705SSam Leffler }
87314779705SSam Leffler return HAL_ENXIO;
87414779705SSam Leffler case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */
87514779705SSam Leffler switch (capability) {
87614779705SSam Leffler case 0: /* hardware capability */
877fdc2e66cSAdrian Chadd return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENXIO;
87814779705SSam Leffler case 1:
87914779705SSam Leffler return (ahp->ah_staId1Defaults &
88014779705SSam Leffler AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO;
88114779705SSam Leffler }
88214779705SSam Leffler return HAL_EINVAL;
88314779705SSam Leffler case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */
88414779705SSam Leffler switch (capability) {
88514779705SSam Leffler case 0: /* hardware capability */
88614779705SSam Leffler return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP;
88714779705SSam Leffler case 1:
88814779705SSam Leffler return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ?
88914779705SSam Leffler HAL_OK : HAL_ENXIO;
89014779705SSam Leffler }
89114779705SSam Leffler return HAL_EINVAL;
89214779705SSam Leffler case HAL_CAP_TPC_ACK:
89314779705SSam Leffler *result = MS(ahp->ah_macTPC, AR_TPC_ACK);
89414779705SSam Leffler return HAL_OK;
89514779705SSam Leffler case HAL_CAP_TPC_CTS:
89614779705SSam Leffler *result = MS(ahp->ah_macTPC, AR_TPC_CTS);
89714779705SSam Leffler return HAL_OK;
89814779705SSam Leffler case HAL_CAP_INTMIT: /* interference mitigation */
89914779705SSam Leffler switch (capability) {
900727edca4SAdrian Chadd case HAL_CAP_INTMIT_PRESENT: /* hardware capability */
90114779705SSam Leffler return HAL_OK;
902727edca4SAdrian Chadd case HAL_CAP_INTMIT_ENABLE:
90314779705SSam Leffler return (ahp->ah_procPhyErr & HAL_ANI_ENA) ?
90414779705SSam Leffler HAL_OK : HAL_ENXIO;
905727edca4SAdrian Chadd case HAL_CAP_INTMIT_NOISE_IMMUNITY_LEVEL:
906727edca4SAdrian Chadd case HAL_CAP_INTMIT_OFDM_WEAK_SIGNAL_LEVEL:
907727edca4SAdrian Chadd case HAL_CAP_INTMIT_CCK_WEAK_SIGNAL_THR:
908727edca4SAdrian Chadd case HAL_CAP_INTMIT_FIRSTEP_LEVEL:
909727edca4SAdrian Chadd case HAL_CAP_INTMIT_SPUR_IMMUNITY_LEVEL:
91014779705SSam Leffler ani = ar5212AniGetCurrentState(ah);
91114779705SSam Leffler if (ani == AH_NULL)
91214779705SSam Leffler return HAL_ENXIO;
91314779705SSam Leffler switch (capability) {
91414779705SSam Leffler case 2: *result = ani->noiseImmunityLevel; break;
91514779705SSam Leffler case 3: *result = !ani->ofdmWeakSigDetectOff; break;
91614779705SSam Leffler case 4: *result = ani->cckWeakSigThreshold; break;
91714779705SSam Leffler case 5: *result = ani->firstepLevel; break;
91814779705SSam Leffler case 6: *result = ani->spurImmunityLevel; break;
91914779705SSam Leffler }
92014779705SSam Leffler return HAL_OK;
92114779705SSam Leffler }
92214779705SSam Leffler return HAL_EINVAL;
92314779705SSam Leffler default:
92414779705SSam Leffler return ath_hal_getcapability(ah, type, capability, result);
92514779705SSam Leffler }
92614779705SSam Leffler #undef MACVERSION
92714779705SSam Leffler }
92814779705SSam Leffler
92914779705SSam Leffler HAL_BOOL
ar5212SetCapability(struct ath_hal * ah,HAL_CAPABILITY_TYPE type,uint32_t capability,uint32_t setting,HAL_STATUS * status)93014779705SSam Leffler ar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
93114779705SSam Leffler uint32_t capability, uint32_t setting, HAL_STATUS *status)
93214779705SSam Leffler {
93314779705SSam Leffler #define N(a) (sizeof(a)/sizeof(a[0]))
93414779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
93514779705SSam Leffler const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
93614779705SSam Leffler uint32_t v;
93714779705SSam Leffler
93814779705SSam Leffler switch (type) {
93914779705SSam Leffler case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */
94014779705SSam Leffler if (setting)
94114779705SSam Leffler ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE;
94214779705SSam Leffler else
94314779705SSam Leffler ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE;
94414779705SSam Leffler return AH_TRUE;
94514779705SSam Leffler case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */
94614779705SSam Leffler if (!pCap->halTkipMicTxRxKeySupport)
94714779705SSam Leffler return AH_FALSE;
94814779705SSam Leffler /* NB: true =>'s use split key cache layout */
94914779705SSam Leffler if (setting)
95014779705SSam Leffler ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE;
95114779705SSam Leffler else
95214779705SSam Leffler ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE;
95314779705SSam Leffler /* NB: write here so keys can be setup w/o a reset */
954534f8ec8SAdrian Chadd OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode);
95514779705SSam Leffler return AH_TRUE;
95614779705SSam Leffler case HAL_CAP_DIVERSITY:
957d6af4e0fSAdrian Chadd switch (capability) {
958d6af4e0fSAdrian Chadd case 0:
959d6af4e0fSAdrian Chadd return AH_FALSE;
960d6af4e0fSAdrian Chadd case 1: /* setting */
96114779705SSam Leffler if (ahp->ah_phyPowerOn) {
962d6af4e0fSAdrian Chadd if (capability == HAL_CAP_STRONG_DIV) {
96314779705SSam Leffler v = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
96414779705SSam Leffler if (setting)
96514779705SSam Leffler v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
96614779705SSam Leffler else
96714779705SSam Leffler v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
96814779705SSam Leffler OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
96914779705SSam Leffler }
97011f0fa78SAdrian Chadd }
97114779705SSam Leffler ahp->ah_diversity = (setting != 0);
97214779705SSam Leffler return AH_TRUE;
973d6af4e0fSAdrian Chadd
974d6af4e0fSAdrian Chadd case HAL_CAP_STRONG_DIV:
975d6af4e0fSAdrian Chadd if (! ahp->ah_phyPowerOn)
976d6af4e0fSAdrian Chadd return AH_FALSE;
977d6af4e0fSAdrian Chadd v = OS_REG_READ(ah, AR_PHY_RESTART);
978d6af4e0fSAdrian Chadd v &= ~AR_PHY_RESTART_DIV_GC;
979d6af4e0fSAdrian Chadd v |= SM(setting, AR_PHY_RESTART_DIV_GC);
980d6af4e0fSAdrian Chadd OS_REG_WRITE(ah, AR_PHY_RESTART, v);
981d6af4e0fSAdrian Chadd return AH_TRUE;
982d6af4e0fSAdrian Chadd default:
983d6af4e0fSAdrian Chadd return AH_FALSE;
984d6af4e0fSAdrian Chadd }
98514779705SSam Leffler case HAL_CAP_DIAG: /* hardware diagnostic support */
98614779705SSam Leffler /*
98714779705SSam Leffler * NB: could split this up into virtual capabilities,
98814779705SSam Leffler * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly
98914779705SSam Leffler * seems worth the additional complexity.
99014779705SSam Leffler */
99114779705SSam Leffler AH_PRIVATE(ah)->ah_diagreg = setting;
99214779705SSam Leffler OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
99314779705SSam Leffler return AH_TRUE;
99414779705SSam Leffler case HAL_CAP_TPC:
99514779705SSam Leffler ahp->ah_tpcEnabled = (setting != 0);
99614779705SSam Leffler return AH_TRUE;
99714779705SSam Leffler case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */
99814779705SSam Leffler if (setting)
99914779705SSam Leffler ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
100014779705SSam Leffler else
100114779705SSam Leffler ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
100214779705SSam Leffler return AH_TRUE;
100314779705SSam Leffler case HAL_CAP_TPC_ACK:
100414779705SSam Leffler case HAL_CAP_TPC_CTS:
100514779705SSam Leffler setting += ahp->ah_txPowerIndexOffset;
100614779705SSam Leffler if (setting > 63)
100714779705SSam Leffler setting = 63;
100814779705SSam Leffler if (type == HAL_CAP_TPC_ACK) {
100914779705SSam Leffler ahp->ah_macTPC &= AR_TPC_ACK;
101014779705SSam Leffler ahp->ah_macTPC |= MS(setting, AR_TPC_ACK);
101114779705SSam Leffler } else {
101214779705SSam Leffler ahp->ah_macTPC &= AR_TPC_CTS;
101314779705SSam Leffler ahp->ah_macTPC |= MS(setting, AR_TPC_CTS);
101414779705SSam Leffler }
101514779705SSam Leffler OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC);
101614779705SSam Leffler return AH_TRUE;
101714779705SSam Leffler case HAL_CAP_INTMIT: { /* interference mitigation */
1018727edca4SAdrian Chadd /* This maps the public ANI commands to the internal ANI commands */
1019727edca4SAdrian Chadd /* Private: HAL_ANI_CMD; Public: HAL_CAP_INTMIT_CMD */
102014779705SSam Leffler static const HAL_ANI_CMD cmds[] = {
102114779705SSam Leffler HAL_ANI_PRESENT,
102214779705SSam Leffler HAL_ANI_MODE,
102314779705SSam Leffler HAL_ANI_NOISE_IMMUNITY_LEVEL,
102414779705SSam Leffler HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
102514779705SSam Leffler HAL_ANI_CCK_WEAK_SIGNAL_THR,
102614779705SSam Leffler HAL_ANI_FIRSTEP_LEVEL,
102714779705SSam Leffler HAL_ANI_SPUR_IMMUNITY_LEVEL,
102814779705SSam Leffler };
102914779705SSam Leffler return capability < N(cmds) ?
10309f456336SAdrian Chadd AH5212(ah)->ah_aniControl(ah, cmds[capability], setting) :
103114779705SSam Leffler AH_FALSE;
103214779705SSam Leffler }
103314779705SSam Leffler case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */
103414779705SSam Leffler if (pCap->halTsfAddSupport) {
103514779705SSam Leffler if (setting)
103614779705SSam Leffler ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF;
103714779705SSam Leffler else
103814779705SSam Leffler ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF;
103914779705SSam Leffler return AH_TRUE;
104014779705SSam Leffler }
104114779705SSam Leffler /* fall thru... */
104214779705SSam Leffler default:
104314779705SSam Leffler return ath_hal_setcapability(ah, type, capability,
104414779705SSam Leffler setting, status);
104514779705SSam Leffler }
104614779705SSam Leffler #undef N
104714779705SSam Leffler }
104814779705SSam Leffler
104914779705SSam Leffler HAL_BOOL
ar5212GetDiagState(struct ath_hal * ah,int request,const void * args,uint32_t argsize,void ** result,uint32_t * resultsize)105014779705SSam Leffler ar5212GetDiagState(struct ath_hal *ah, int request,
105114779705SSam Leffler const void *args, uint32_t argsize,
105214779705SSam Leffler void **result, uint32_t *resultsize)
105314779705SSam Leffler {
105414779705SSam Leffler struct ath_hal_5212 *ahp = AH5212(ah);
105503ab0935SAdrian Chadd HAL_ANI_STATS *astats;
105614779705SSam Leffler
105714779705SSam Leffler (void) ahp;
105814779705SSam Leffler if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
105914779705SSam Leffler return AH_TRUE;
106014779705SSam Leffler switch (request) {
106114779705SSam Leffler case HAL_DIAG_EEPROM:
106214779705SSam Leffler case HAL_DIAG_EEPROM_EXP_11A:
106314779705SSam Leffler case HAL_DIAG_EEPROM_EXP_11B:
106414779705SSam Leffler case HAL_DIAG_EEPROM_EXP_11G:
106514779705SSam Leffler case HAL_DIAG_RFGAIN:
106614779705SSam Leffler return ath_hal_eepromDiag(ah, request,
106714779705SSam Leffler args, argsize, result, resultsize);
106814779705SSam Leffler case HAL_DIAG_RFGAIN_CURSTEP:
106914779705SSam Leffler *result = __DECONST(void *, ahp->ah_gainValues.currStep);
107014779705SSam Leffler *resultsize = (*result == AH_NULL) ?
107114779705SSam Leffler 0 : sizeof(GAIN_OPTIMIZATION_STEP);
107214779705SSam Leffler return AH_TRUE;
107314779705SSam Leffler case HAL_DIAG_PCDAC:
107414779705SSam Leffler *result = ahp->ah_pcdacTable;
107514779705SSam Leffler *resultsize = ahp->ah_pcdacTableSize;
107614779705SSam Leffler return AH_TRUE;
107714779705SSam Leffler case HAL_DIAG_TXRATES:
107814779705SSam Leffler *result = &ahp->ah_ratesArray[0];
107914779705SSam Leffler *resultsize = sizeof(ahp->ah_ratesArray);
108014779705SSam Leffler return AH_TRUE;
108114779705SSam Leffler case HAL_DIAG_ANI_CURRENT:
108214779705SSam Leffler *result = ar5212AniGetCurrentState(ah);
108314779705SSam Leffler *resultsize = (*result == AH_NULL) ?
108414779705SSam Leffler 0 : sizeof(struct ar5212AniState);
108514779705SSam Leffler return AH_TRUE;
108614779705SSam Leffler case HAL_DIAG_ANI_STATS:
108703ab0935SAdrian Chadd OS_MEMZERO(&ahp->ext_ani_stats, sizeof(ahp->ext_ani_stats));
108803ab0935SAdrian Chadd astats = ar5212AniGetCurrentStats(ah);
108903ab0935SAdrian Chadd if (astats == NULL) {
1090b3ab2271SAdrian Chadd *result = NULL;
1091b3ab2271SAdrian Chadd *resultsize = 0;
1092b3ab2271SAdrian Chadd } else {
109303ab0935SAdrian Chadd OS_MEMCPY(&ahp->ext_ani_stats, astats, sizeof(HAL_ANI_STATS));
109403ab0935SAdrian Chadd *result = &ahp->ext_ani_stats;
109503ab0935SAdrian Chadd *resultsize = sizeof(ahp->ext_ani_stats);
1096b3ab2271SAdrian Chadd }
109714779705SSam Leffler return AH_TRUE;
109814779705SSam Leffler case HAL_DIAG_ANI_CMD:
109914779705SSam Leffler if (argsize != 2*sizeof(uint32_t))
110014779705SSam Leffler return AH_FALSE;
11019f456336SAdrian Chadd AH5212(ah)->ah_aniControl(ah, ((const uint32_t *)args)[0],
110214779705SSam Leffler ((const uint32_t *)args)[1]);
110314779705SSam Leffler return AH_TRUE;
110414779705SSam Leffler case HAL_DIAG_ANI_PARAMS:
110514779705SSam Leffler /*
110614779705SSam Leffler * NB: We assume struct ar5212AniParams is identical
110714779705SSam Leffler * to HAL_ANI_PARAMS; if they diverge then we'll need
110814779705SSam Leffler * to handle it here
110914779705SSam Leffler */
111014779705SSam Leffler if (argsize == 0 && args == AH_NULL) {
111114779705SSam Leffler struct ar5212AniState *aniState =
111214779705SSam Leffler ar5212AniGetCurrentState(ah);
111314779705SSam Leffler if (aniState == AH_NULL)
111414779705SSam Leffler return AH_FALSE;
111514779705SSam Leffler *result = __DECONST(void *, aniState->params);
111614779705SSam Leffler *resultsize = sizeof(struct ar5212AniParams);
111714779705SSam Leffler return AH_TRUE;
111814779705SSam Leffler } else {
111914779705SSam Leffler if (argsize != sizeof(struct ar5212AniParams))
112014779705SSam Leffler return AH_FALSE;
112114779705SSam Leffler return ar5212AniSetParams(ah, args, args);
112214779705SSam Leffler }
11239dc50580SAdrian Chadd break;
112414779705SSam Leffler }
112514779705SSam Leffler return AH_FALSE;
112614779705SSam Leffler }
112785b035b3SAdrian Chadd
112885b035b3SAdrian Chadd /*
112985b035b3SAdrian Chadd * Check whether there's an in-progress NF completion.
113085b035b3SAdrian Chadd *
113185b035b3SAdrian Chadd * Returns AH_TRUE if there's a in-progress NF calibration, AH_FALSE
113285b035b3SAdrian Chadd * otherwise.
113385b035b3SAdrian Chadd */
113485b035b3SAdrian Chadd HAL_BOOL
ar5212IsNFCalInProgress(struct ath_hal * ah)113585b035b3SAdrian Chadd ar5212IsNFCalInProgress(struct ath_hal *ah)
113685b035b3SAdrian Chadd {
113785b035b3SAdrian Chadd if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF)
113885b035b3SAdrian Chadd return AH_TRUE;
113985b035b3SAdrian Chadd return AH_FALSE;
114085b035b3SAdrian Chadd }
114185b035b3SAdrian Chadd
114285b035b3SAdrian Chadd /*
114385b035b3SAdrian Chadd * Wait for an in-progress NF calibration to complete.
114485b035b3SAdrian Chadd *
114585b035b3SAdrian Chadd * The completion function waits "i" times 10uS.
114685b035b3SAdrian Chadd * It returns AH_TRUE if the NF calibration completed (or was never
114785b035b3SAdrian Chadd * in progress); AH_FALSE if it was still in progress after "i" checks.
114885b035b3SAdrian Chadd */
114985b035b3SAdrian Chadd HAL_BOOL
ar5212WaitNFCalComplete(struct ath_hal * ah,int i)115085b035b3SAdrian Chadd ar5212WaitNFCalComplete(struct ath_hal *ah, int i)
115185b035b3SAdrian Chadd {
115285b035b3SAdrian Chadd int j;
115385b035b3SAdrian Chadd if (i <= 0)
115485b035b3SAdrian Chadd i = 1; /* it should run at least once */
115585b035b3SAdrian Chadd for (j = 0; j < i; j++) {
115685b035b3SAdrian Chadd if (! ar5212IsNFCalInProgress(ah))
115785b035b3SAdrian Chadd return AH_TRUE;
115885b035b3SAdrian Chadd OS_DELAY(10);
115985b035b3SAdrian Chadd }
116085b035b3SAdrian Chadd return AH_FALSE;
116185b035b3SAdrian Chadd }
11622cb5233bSAdrian Chadd
11632cb5233bSAdrian Chadd void
ar5212EnableDfs(struct ath_hal * ah,HAL_PHYERR_PARAM * pe)11642cb5233bSAdrian Chadd ar5212EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
11652cb5233bSAdrian Chadd {
11662cb5233bSAdrian Chadd uint32_t val;
11672cb5233bSAdrian Chadd val = OS_REG_READ(ah, AR_PHY_RADAR_0);
11682cb5233bSAdrian Chadd
11692cb5233bSAdrian Chadd if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
11702cb5233bSAdrian Chadd val &= ~AR_PHY_RADAR_0_FIRPWR;
11712cb5233bSAdrian Chadd val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
11722cb5233bSAdrian Chadd }
11732cb5233bSAdrian Chadd if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
11742cb5233bSAdrian Chadd val &= ~AR_PHY_RADAR_0_RRSSI;
11752cb5233bSAdrian Chadd val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
11762cb5233bSAdrian Chadd }
11772cb5233bSAdrian Chadd if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
11782cb5233bSAdrian Chadd val &= ~AR_PHY_RADAR_0_HEIGHT;
11792cb5233bSAdrian Chadd val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
11802cb5233bSAdrian Chadd }
11812cb5233bSAdrian Chadd if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
11822cb5233bSAdrian Chadd val &= ~AR_PHY_RADAR_0_PRSSI;
11832cb5233bSAdrian Chadd val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
11842cb5233bSAdrian Chadd }
11852cb5233bSAdrian Chadd if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
11862cb5233bSAdrian Chadd val &= ~AR_PHY_RADAR_0_INBAND;
11872cb5233bSAdrian Chadd val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
11882cb5233bSAdrian Chadd }
118951816abcSAdrian Chadd if (pe->pe_enabled)
119051816abcSAdrian Chadd val |= AR_PHY_RADAR_0_ENA;
119151816abcSAdrian Chadd else
119251816abcSAdrian Chadd val &= ~ AR_PHY_RADAR_0_ENA;
119351816abcSAdrian Chadd
1194d6af4e0fSAdrian Chadd if (IS_5413(ah)) {
1195d6af4e0fSAdrian Chadd if (pe->pe_blockradar == 1)
1196d6af4e0fSAdrian Chadd OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
1197d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_BLOCKOFDMWEAK);
1198d6af4e0fSAdrian Chadd else
1199d6af4e0fSAdrian Chadd OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
1200d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_BLOCKOFDMWEAK);
1201d6af4e0fSAdrian Chadd
1202d6af4e0fSAdrian Chadd if (pe->pe_en_relstep_check == 1)
1203d6af4e0fSAdrian Chadd OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
1204d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_ENRELSTEPCHK);
1205d6af4e0fSAdrian Chadd else
1206d6af4e0fSAdrian Chadd OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
1207d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_ENRELSTEPCHK);
1208d6af4e0fSAdrian Chadd
1209d6af4e0fSAdrian Chadd if (pe->pe_usefir128 == 1)
1210d6af4e0fSAdrian Chadd OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
1211d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_USEFIR128);
1212d6af4e0fSAdrian Chadd else
1213d6af4e0fSAdrian Chadd OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
1214d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_USEFIR128);
1215d6af4e0fSAdrian Chadd
1216d6af4e0fSAdrian Chadd if (pe->pe_enmaxrssi == 1)
1217d6af4e0fSAdrian Chadd OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
1218d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_ENMAXRSSI);
1219d6af4e0fSAdrian Chadd else
1220d6af4e0fSAdrian Chadd OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
1221d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_ENMAXRSSI);
1222d6af4e0fSAdrian Chadd
1223d6af4e0fSAdrian Chadd if (pe->pe_enrelpwr == 1)
1224d6af4e0fSAdrian Chadd OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
1225d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_ENRELPWRCHK);
1226d6af4e0fSAdrian Chadd else
1227d6af4e0fSAdrian Chadd OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
1228d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_ENRELPWRCHK);
1229d6af4e0fSAdrian Chadd
1230d6af4e0fSAdrian Chadd if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL)
1231d6af4e0fSAdrian Chadd OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_2,
1232d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_RELPWR, pe->pe_relpwr);
1233d6af4e0fSAdrian Chadd
1234d6af4e0fSAdrian Chadd if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL)
1235d6af4e0fSAdrian Chadd OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_2,
1236d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_RELSTEP, pe->pe_relstep);
1237d6af4e0fSAdrian Chadd
1238d6af4e0fSAdrian Chadd if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL)
1239d6af4e0fSAdrian Chadd OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_2,
1240d6af4e0fSAdrian Chadd AR_PHY_RADAR_2_MAXLEN, pe->pe_maxlen);
1241d6af4e0fSAdrian Chadd }
1242d6af4e0fSAdrian Chadd
124351816abcSAdrian Chadd OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
12442cb5233bSAdrian Chadd }
12452cb5233bSAdrian Chadd
124647152caeSAdrian Chadd /*
124747152caeSAdrian Chadd * Parameters for the AR5212 PHY.
124847152caeSAdrian Chadd */
124911f0fa78SAdrian Chadd #define AR5212_DFS_FIRPWR -35
125011f0fa78SAdrian Chadd #define AR5212_DFS_RRSSI 20
125111f0fa78SAdrian Chadd #define AR5212_DFS_HEIGHT 14
125211f0fa78SAdrian Chadd #define AR5212_DFS_PRSSI 6
125311f0fa78SAdrian Chadd #define AR5212_DFS_INBAND 4
125447152caeSAdrian Chadd
1255d6af4e0fSAdrian Chadd /*
1256d6af4e0fSAdrian Chadd * Default parameters for the AR5413 PHY.
1257d6af4e0fSAdrian Chadd */
1258d6af4e0fSAdrian Chadd #define AR5413_DFS_FIRPWR -34
1259d6af4e0fSAdrian Chadd #define AR5413_DFS_RRSSI 20
1260d6af4e0fSAdrian Chadd #define AR5413_DFS_HEIGHT 10
1261d6af4e0fSAdrian Chadd #define AR5413_DFS_PRSSI 15
1262d6af4e0fSAdrian Chadd #define AR5413_DFS_INBAND 6
1263d6af4e0fSAdrian Chadd #define AR5413_DFS_RELPWR 8
1264d6af4e0fSAdrian Chadd #define AR5413_DFS_RELSTEP 31
1265d6af4e0fSAdrian Chadd #define AR5413_DFS_MAXLEN 255
1266d6af4e0fSAdrian Chadd
126747152caeSAdrian Chadd HAL_BOOL
ar5212GetDfsDefaultThresh(struct ath_hal * ah,HAL_PHYERR_PARAM * pe)126847152caeSAdrian Chadd ar5212GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
126947152caeSAdrian Chadd {
127047152caeSAdrian Chadd
1271d6af4e0fSAdrian Chadd if (IS_5413(ah)) {
1272d6af4e0fSAdrian Chadd pe->pe_firpwr = AR5413_DFS_FIRPWR;
1273d6af4e0fSAdrian Chadd pe->pe_rrssi = AR5413_DFS_RRSSI;
1274d6af4e0fSAdrian Chadd pe->pe_height = AR5413_DFS_HEIGHT;
1275d6af4e0fSAdrian Chadd pe->pe_prssi = AR5413_DFS_PRSSI;
1276d6af4e0fSAdrian Chadd pe->pe_inband = AR5413_DFS_INBAND;
1277d6af4e0fSAdrian Chadd pe->pe_relpwr = AR5413_DFS_RELPWR;
1278d6af4e0fSAdrian Chadd pe->pe_relstep = AR5413_DFS_RELSTEP;
1279d6af4e0fSAdrian Chadd pe->pe_maxlen = AR5413_DFS_MAXLEN;
1280d6af4e0fSAdrian Chadd pe->pe_usefir128 = 0;
1281d6af4e0fSAdrian Chadd pe->pe_blockradar = 1;
1282d6af4e0fSAdrian Chadd pe->pe_enmaxrssi = 1;
1283d6af4e0fSAdrian Chadd pe->pe_enrelpwr = 1;
1284d6af4e0fSAdrian Chadd pe->pe_en_relstep_check = 0;
1285d6af4e0fSAdrian Chadd } else {
128647152caeSAdrian Chadd pe->pe_firpwr = AR5212_DFS_FIRPWR;
128747152caeSAdrian Chadd pe->pe_rrssi = AR5212_DFS_RRSSI;
128847152caeSAdrian Chadd pe->pe_height = AR5212_DFS_HEIGHT;
128947152caeSAdrian Chadd pe->pe_prssi = AR5212_DFS_PRSSI;
129047152caeSAdrian Chadd pe->pe_inband = AR5212_DFS_INBAND;
129147152caeSAdrian Chadd pe->pe_relpwr = 0;
129247152caeSAdrian Chadd pe->pe_relstep = 0;
129347152caeSAdrian Chadd pe->pe_maxlen = 0;
1294d6af4e0fSAdrian Chadd pe->pe_usefir128 = 0;
1295d6af4e0fSAdrian Chadd pe->pe_blockradar = 0;
1296d6af4e0fSAdrian Chadd pe->pe_enmaxrssi = 0;
1297d6af4e0fSAdrian Chadd pe->pe_enrelpwr = 0;
1298d6af4e0fSAdrian Chadd pe->pe_en_relstep_check = 0;
1299d6af4e0fSAdrian Chadd }
130047152caeSAdrian Chadd
130147152caeSAdrian Chadd return (AH_TRUE);
130247152caeSAdrian Chadd }
130347152caeSAdrian Chadd
13042cb5233bSAdrian Chadd void
ar5212GetDfsThresh(struct ath_hal * ah,HAL_PHYERR_PARAM * pe)13052cb5233bSAdrian Chadd ar5212GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
13062cb5233bSAdrian Chadd {
13072cb5233bSAdrian Chadd uint32_t val,temp;
13082cb5233bSAdrian Chadd
13092cb5233bSAdrian Chadd val = OS_REG_READ(ah, AR_PHY_RADAR_0);
13102cb5233bSAdrian Chadd
13112cb5233bSAdrian Chadd temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
13122cb5233bSAdrian Chadd temp |= 0xFFFFFF80;
13132cb5233bSAdrian Chadd pe->pe_firpwr = temp;
13142cb5233bSAdrian Chadd pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
13152cb5233bSAdrian Chadd pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT);
13162cb5233bSAdrian Chadd pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
13172cb5233bSAdrian Chadd pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
131851816abcSAdrian Chadd pe->pe_enabled = !! (val & AR_PHY_RADAR_0_ENA);
13192cb5233bSAdrian Chadd
13202cb5233bSAdrian Chadd pe->pe_relpwr = 0;
13212cb5233bSAdrian Chadd pe->pe_relstep = 0;
13222cb5233bSAdrian Chadd pe->pe_maxlen = 0;
1323d6af4e0fSAdrian Chadd pe->pe_usefir128 = 0;
1324d6af4e0fSAdrian Chadd pe->pe_blockradar = 0;
1325d6af4e0fSAdrian Chadd pe->pe_enmaxrssi = 0;
1326d6af4e0fSAdrian Chadd pe->pe_enrelpwr = 0;
1327d6af4e0fSAdrian Chadd pe->pe_en_relstep_check = 0;
13282cb5233bSAdrian Chadd pe->pe_extchannel = AH_FALSE;
1329d6af4e0fSAdrian Chadd
1330d6af4e0fSAdrian Chadd if (IS_5413(ah)) {
1331d6af4e0fSAdrian Chadd val = OS_REG_READ(ah, AR_PHY_RADAR_2);
1332d6af4e0fSAdrian Chadd pe->pe_relpwr = !! MS(val, AR_PHY_RADAR_2_RELPWR);
1333d6af4e0fSAdrian Chadd pe->pe_relstep = !! MS(val, AR_PHY_RADAR_2_RELSTEP);
1334d6af4e0fSAdrian Chadd pe->pe_maxlen = !! MS(val, AR_PHY_RADAR_2_MAXLEN);
1335d6af4e0fSAdrian Chadd
1336d6af4e0fSAdrian Chadd pe->pe_usefir128 = !! (val & AR_PHY_RADAR_2_USEFIR128);
1337d6af4e0fSAdrian Chadd pe->pe_blockradar = !! (val & AR_PHY_RADAR_2_BLOCKOFDMWEAK);
1338d6af4e0fSAdrian Chadd pe->pe_enmaxrssi = !! (val & AR_PHY_RADAR_2_ENMAXRSSI);
1339d6af4e0fSAdrian Chadd pe->pe_enrelpwr = !! (val & AR_PHY_RADAR_2_ENRELPWRCHK);
1340d6af4e0fSAdrian Chadd pe->pe_en_relstep_check =
1341d6af4e0fSAdrian Chadd !! (val & AR_PHY_RADAR_2_ENRELSTEPCHK);
1342d6af4e0fSAdrian Chadd }
13432cb5233bSAdrian Chadd }
13442cb5233bSAdrian Chadd
13453d423111SAdrian Chadd /*
13463d423111SAdrian Chadd * Process the radar phy error and extract the pulse duration.
13473d423111SAdrian Chadd */
13483d423111SAdrian Chadd HAL_BOOL
ar5212ProcessRadarEvent(struct ath_hal * ah,struct ath_rx_status * rxs,uint64_t fulltsf,const char * buf,HAL_DFS_EVENT * event)13493d423111SAdrian Chadd ar5212ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
13503d423111SAdrian Chadd uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
13513d423111SAdrian Chadd {
13523d423111SAdrian Chadd uint8_t dur;
13533d423111SAdrian Chadd uint8_t rssi;
13543d423111SAdrian Chadd
13553d423111SAdrian Chadd /* Check whether the given phy error is a radar event */
13563d423111SAdrian Chadd if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&
13573d423111SAdrian Chadd (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT))
13583d423111SAdrian Chadd return AH_FALSE;
13593d423111SAdrian Chadd
13603d423111SAdrian Chadd /*
13613d423111SAdrian Chadd * The first byte is the pulse width - if there's
13623d423111SAdrian Chadd * no data, simply set the duration to 0
13633d423111SAdrian Chadd */
13643d423111SAdrian Chadd if (rxs->rs_datalen >= 1)
13653d423111SAdrian Chadd /* The pulse width is byte 0 of the data */
13663d423111SAdrian Chadd dur = ((uint8_t) buf[0]) & 0xff;
13673d423111SAdrian Chadd else
13683d423111SAdrian Chadd dur = 0;
13693d423111SAdrian Chadd
13703d423111SAdrian Chadd /* Pulse RSSI is the normal reported RSSI */
13713d423111SAdrian Chadd rssi = (uint8_t) rxs->rs_rssi;
13723d423111SAdrian Chadd
13733d423111SAdrian Chadd /* 0 duration/rssi is not a valid radar event */
13743d423111SAdrian Chadd if (dur == 0 && rssi == 0)
13753d423111SAdrian Chadd return AH_FALSE;
13763d423111SAdrian Chadd
13773d423111SAdrian Chadd HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n",
13783d423111SAdrian Chadd __func__, rssi, dur);
13793d423111SAdrian Chadd
13803d423111SAdrian Chadd /* Record the event */
13813d423111SAdrian Chadd event->re_full_ts = fulltsf;
13823d423111SAdrian Chadd event->re_ts = rxs->rs_tstamp;
13833d423111SAdrian Chadd event->re_rssi = rssi;
13843d423111SAdrian Chadd event->re_dur = dur;
13853d423111SAdrian Chadd event->re_flags = HAL_DFS_EVENT_PRICH;
13863d423111SAdrian Chadd
13873d423111SAdrian Chadd return AH_TRUE;
13883d423111SAdrian Chadd }
138960829c48SAdrian Chadd
139060829c48SAdrian Chadd /*
139160829c48SAdrian Chadd * Return whether 5GHz fast-clock (44MHz) is enabled.
139260829c48SAdrian Chadd * It's always disabled for AR5212 series NICs.
139360829c48SAdrian Chadd */
139460829c48SAdrian Chadd HAL_BOOL
ar5212IsFastClockEnabled(struct ath_hal * ah)139560829c48SAdrian Chadd ar5212IsFastClockEnabled(struct ath_hal *ah)
139660829c48SAdrian Chadd {
139760829c48SAdrian Chadd return AH_FALSE;
139860829c48SAdrian Chadd }
13997f925de1SAdrian Chadd
14007f925de1SAdrian Chadd /*
14017f925de1SAdrian Chadd * Return what percentage of the extension channel is busy.
14027f925de1SAdrian Chadd * This is always disabled for AR5212 series NICs.
14037f925de1SAdrian Chadd */
14047f925de1SAdrian Chadd uint32_t
ar5212Get11nExtBusy(struct ath_hal * ah)14057f925de1SAdrian Chadd ar5212Get11nExtBusy(struct ath_hal *ah)
14067f925de1SAdrian Chadd {
14077f925de1SAdrian Chadd return 0;
14087f925de1SAdrian Chadd }
1409352f07f6SAdrian Chadd
1410352f07f6SAdrian Chadd /*
14110a2cefc6SAdrian Chadd * Channel survey support.
1412352f07f6SAdrian Chadd */
1413352f07f6SAdrian Chadd HAL_BOOL
ar5212GetMibCycleCounts(struct ath_hal * ah,HAL_SURVEY_SAMPLE * hsample)1414352f07f6SAdrian Chadd ar5212GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
1415352f07f6SAdrian Chadd {
14160a2cefc6SAdrian Chadd struct ath_hal_5212 *ahp = AH5212(ah);
14170a2cefc6SAdrian Chadd u_int32_t good = AH_TRUE;
1418352f07f6SAdrian Chadd
14190a2cefc6SAdrian Chadd /* XXX freeze/unfreeze mib counters */
14200a2cefc6SAdrian Chadd uint32_t rc = OS_REG_READ(ah, AR_RCCNT);
14210a2cefc6SAdrian Chadd uint32_t rf = OS_REG_READ(ah, AR_RFCNT);
14220a2cefc6SAdrian Chadd uint32_t tf = OS_REG_READ(ah, AR_TFCNT);
14230a2cefc6SAdrian Chadd uint32_t cc = OS_REG_READ(ah, AR_CCCNT); /* read cycles last */
14240a2cefc6SAdrian Chadd
14250a2cefc6SAdrian Chadd if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cc) {
14260a2cefc6SAdrian Chadd /*
14270a2cefc6SAdrian Chadd * Cycle counter wrap (or initial call); it's not possible
14280a2cefc6SAdrian Chadd * to accurately calculate a value because the registers
14290a2cefc6SAdrian Chadd * right shift rather than wrap--so punt and return 0.
14300a2cefc6SAdrian Chadd */
14310a2cefc6SAdrian Chadd HALDEBUG(ah, HAL_DEBUG_ANY,
14320a2cefc6SAdrian Chadd "%s: cycle counter wrap. ExtBusy = 0\n", __func__);
14330a2cefc6SAdrian Chadd good = AH_FALSE;
14340a2cefc6SAdrian Chadd } else {
14350a2cefc6SAdrian Chadd hsample->cycle_count = cc - ahp->ah_cycleCount;
14360a2cefc6SAdrian Chadd hsample->chan_busy = rc - ahp->ah_ctlBusy;
14370a2cefc6SAdrian Chadd hsample->ext_chan_busy = 0;
14380a2cefc6SAdrian Chadd hsample->rx_busy = rf - ahp->ah_rxBusy;
14390a2cefc6SAdrian Chadd hsample->tx_busy = tf - ahp->ah_txBusy;
14400a2cefc6SAdrian Chadd }
14410a2cefc6SAdrian Chadd
14420a2cefc6SAdrian Chadd /*
14430a2cefc6SAdrian Chadd * Keep a copy of the MIB results so the next sample has something
14440a2cefc6SAdrian Chadd * to work from.
14450a2cefc6SAdrian Chadd */
14460a2cefc6SAdrian Chadd ahp->ah_cycleCount = cc;
14470a2cefc6SAdrian Chadd ahp->ah_rxBusy = rf;
14480a2cefc6SAdrian Chadd ahp->ah_ctlBusy = rc;
14490a2cefc6SAdrian Chadd ahp->ah_txBusy = tf;
14500a2cefc6SAdrian Chadd
14510a2cefc6SAdrian Chadd return (good);
1452352f07f6SAdrian Chadd }
1453d2a72d67SAdrian Chadd
1454d2a72d67SAdrian Chadd void
ar5212SetChainMasks(struct ath_hal * ah,uint32_t tx_chainmask,uint32_t rx_chainmask)1455d2a72d67SAdrian Chadd ar5212SetChainMasks(struct ath_hal *ah, uint32_t tx_chainmask,
1456d2a72d67SAdrian Chadd uint32_t rx_chainmask)
1457d2a72d67SAdrian Chadd {
1458d2a72d67SAdrian Chadd }
1459*bed90bf8SAdrian Chadd
1460*bed90bf8SAdrian Chadd /*
1461*bed90bf8SAdrian Chadd * Get the current NAV value from the hardware.
1462*bed90bf8SAdrian Chadd *
1463*bed90bf8SAdrian Chadd * 0xdeadbeef indicates the hardware is currently powered off.
1464*bed90bf8SAdrian Chadd */
1465*bed90bf8SAdrian Chadd u_int
ar5212GetNav(struct ath_hal * ah)1466*bed90bf8SAdrian Chadd ar5212GetNav(struct ath_hal *ah)
1467*bed90bf8SAdrian Chadd {
1468*bed90bf8SAdrian Chadd uint32_t reg;
1469*bed90bf8SAdrian Chadd
1470*bed90bf8SAdrian Chadd reg = OS_REG_READ(ah, AR_NAV);
1471*bed90bf8SAdrian Chadd
1472*bed90bf8SAdrian Chadd if (reg == 0xdeadbeef)
1473*bed90bf8SAdrian Chadd return (0);
1474*bed90bf8SAdrian Chadd return (reg);
1475*bed90bf8SAdrian Chadd }
1476*bed90bf8SAdrian Chadd
1477*bed90bf8SAdrian Chadd /*
1478*bed90bf8SAdrian Chadd * Set the current NAV value to the hardware.
1479*bed90bf8SAdrian Chadd */
1480*bed90bf8SAdrian Chadd void
ar5212SetNav(struct ath_hal * ah,u_int val)1481*bed90bf8SAdrian Chadd ar5212SetNav(struct ath_hal *ah, u_int val)
1482*bed90bf8SAdrian Chadd {
1483*bed90bf8SAdrian Chadd
1484*bed90bf8SAdrian Chadd OS_REG_WRITE(ah, AR_NAV, val);
1485*bed90bf8SAdrian Chadd }
1486