118334Speter/* 290075Sobrien * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 390075Sobrien * Copyright (c) 2002-2008 Atheros Communications, Inc. 418334Speter * 518334Speter * Permission to use, copy, modify, and/or distribute this software for any 618334Speter * purpose with or without fee is hereby granted, provided that the above 718334Speter * copyright notice and this permission notice appear in all copies. 818334Speter * 918334Speter * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1018334Speter * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1118334Speter * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1218334Speter * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1318334Speter * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1418334Speter * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1518334Speter * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1618334Speter * 1718334Speter * $Id: ar5212_misc.c,v 1.3 2012/02/12 13:48:45 wiz Exp $ 1818334Speter */ 1918334Speter#include "opt_ah.h" 2018334Speter 2118334Speter#include "ah.h" 2218334Speter#include "ah_internal.h" 2318334Speter#include "ah_devid.h" 2418334Speter#ifdef AH_DEBUG 2518334Speter#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 2618334Speter#endif 2718334Speter 2818334Speter#include "ar5212/ar5212.h" 2918334Speter#include "ar5212/ar5212reg.h" 3050397Sobrien#include "ar5212/ar5212phy.h" 3118334Speter 3218334Speter#include "ah_eeprom_v3.h" 3318334Speter 3418334Speter#define AR_NUM_GPIO 6 /* 6 GPIO pins */ 3552284Sobrien#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ 3652284Sobrien 3718334Speterextern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *); 3890075Sobrien 3990075Sobrienvoid 4090075Sobrienar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac) 4190075Sobrien{ 4250397Sobrien struct ath_hal_5212 *ahp = AH5212(ah); 4318334Speter 4418334Speter OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); 4518334Speter} 4618334Speter 4718334SpeterHAL_BOOL 4818334Speterar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac) 4918334Speter{ 5018334Speter struct ath_hal_5212 *ahp = AH5212(ah); 5118334Speter 5218334Speter OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); 5318334Speter return AH_TRUE; 5418334Speter} 5518334Speter 5618334Spetervoid 5718334Speterar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask) 5818334Speter{ 5918334Speter struct ath_hal_5212 *ahp = AH5212(ah); 6018334Speter 6118334Speter OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN); 6218334Speter} 6318334Speter 6418334SpeterHAL_BOOL 6518334Speterar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) 6618334Speter{ 6718334Speter struct ath_hal_5212 *ahp = AH5212(ah); 6818334Speter 6918334Speter /* save it since it must be rewritten on reset */ 7090075Sobrien OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN); 7190075Sobrien 7290075Sobrien OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); 7350397Sobrien OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); 7418334Speter return AH_TRUE; 7590075Sobrien} 7618334Speter 7790075Sobrien/* 7818334Speter * Attempt to change the cards operating regulatory domain to the given value 7918334Speter */ 8018334SpeterHAL_BOOL 8150397Sobrienar5212SetRegulatoryDomain(struct ath_hal *ah, 8218334Speter uint16_t regDomain, HAL_STATUS *status) 8350397Sobrien{ 8450397Sobrien HAL_STATUS ecode; 8550397Sobrien 8690075Sobrien if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { 8750397Sobrien ecode = HAL_EINVAL; 8890075Sobrien goto bad; 8950397Sobrien } 9050397Sobrien if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { 9150397Sobrien ecode = HAL_EEWRITE; 9250397Sobrien goto bad; 9352284Sobrien } 9450397Sobrien#ifdef AH_SUPPORT_WRITE_REGDOMAIN 9550397Sobrien if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { 9650397Sobrien HALDEBUG(ah, HAL_DEBUG_ANY, 9790075Sobrien "%s: set regulatory domain to %u (0x%x)\n", 9850397Sobrien __func__, regDomain, regDomain); 9950397Sobrien AH_PRIVATE(ah)->ah_currentRD = regDomain; 10050397Sobrien return AH_TRUE; 10150397Sobrien } 10250397Sobrien#endif 10350397Sobrien ecode = HAL_EIO; 10450397Sobrienbad: 10550397Sobrien if (status) 10690075Sobrien *status = ecode; 10750397Sobrien return AH_FALSE; 10850397Sobrien} 10950397Sobrien 11050397Sobrien/* 11150397Sobrien * Return the wireless modes (a,b,g,t) supported by hardware. 11250397Sobrien * 11352284Sobrien * This value is what is actually supported by the hardware 11450397Sobrien * and is unaffected by regulatory/country code settings. 11550397Sobrien */ 11650397Sobrienu_int 11750397Sobrienar5212GetWirelessModes(struct ath_hal *ah) 11850397Sobrien{ 11950397Sobrien u_int mode = 0; 12050397Sobrien 12150397Sobrien if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { 12250397Sobrien mode = HAL_MODE_11A; 12350397Sobrien if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) 12450397Sobrien mode |= HAL_MODE_TURBO | HAL_MODE_108A; 12550397Sobrien if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 12690075Sobrien mode |= HAL_MODE_11A_HALF_RATE; 12750397Sobrien if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 12850397Sobrien mode |= HAL_MODE_11A_QUARTER_RATE; 12950397Sobrien } 13050397Sobrien if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) 13150397Sobrien mode |= HAL_MODE_11B; 13250397Sobrien if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && 13318334Speter AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { 13418334Speter mode |= HAL_MODE_11G; 13552284Sobrien if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) 13618334Speter mode |= HAL_MODE_108G; 13718334Speter if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 13818334Speter mode |= HAL_MODE_11G_HALF_RATE; 13918334Speter if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 14052284Sobrien mode |= HAL_MODE_11G_QUARTER_RATE; 14118334Speter } 14250397Sobrien return mode; 14350397Sobrien} 14490075Sobrien 14518334Speter/* 14618334Speter * Set the interrupt and GPIO values so the ISR can disable RF 14790075Sobrien * on a switch signal. Assumes GPIO port and interrupt polarity 14890075Sobrien * are set prior to call. 14990075Sobrien */ 15090075Sobrienvoid 15190075Sobrienar5212EnableRfKill(struct ath_hal *ah) 15290075Sobrien{ 15318334Speter uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; 15490075Sobrien int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); 15590075Sobrien int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); 15690075Sobrien 15718334Speter /* 15818334Speter * Configure the desired GPIO port for input 15990075Sobrien * and enable baseband rf silence. 16090075Sobrien */ 16118334Speter ath_hal_gpioCfgInput(ah, select); 16218334Speter OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000); 16390075Sobrien /* 16490075Sobrien * If radio disable switch connection to GPIO bit x is enabled 16590075Sobrien * program GPIO interrupt. 16690075Sobrien * If rfkill bit on eeprom is 1, setupeeprommap routine has already 16718334Speter * verified that it is a later version of eeprom, it has a place for 16890075Sobrien * rfkill bit and it is set to 1, indicating that GPIO bit x hardware 16990075Sobrien * connection is present. 17090075Sobrien */ 17118334Speter ath_hal_gpioSetIntr(ah, select, 17290075Sobrien (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity)); 17318334Speter} 17418334Speter 17518334Speter/* 17652284Sobrien * Change the LED blinking pattern to correspond to the connectivity 17718334Speter */ 17890075Sobrienvoid 17990075Sobrienar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 18090075Sobrien{ 18150397Sobrien static const uint32_t ledbits[8] = { 18290075Sobrien AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */ 18350397Sobrien AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */ 18490075Sobrien AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */ 18590075Sobrien AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/ 18690075Sobrien AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */ 18790075Sobrien AR_PCICFG_LEDCTL_NONE, 18850397Sobrien AR_PCICFG_LEDCTL_NONE, 18990075Sobrien AR_PCICFG_LEDCTL_NONE, 19050397Sobrien }; 19150397Sobrien uint32_t bits; 19218334Speter 19318334Speter bits = OS_REG_READ(ah, AR_PCICFG); 19490075Sobrien if (IS_2417(ah)) { 19590075Sobrien /* 19690075Sobrien * Enable LED for Nala. There is a bit marked reserved 19790075Sobrien * that must be set and we also turn on the power led. 19890075Sobrien * Because we mark s/w LED control setting the control 19990075Sobrien * status bits below is meangless (the driver must flash 20090075Sobrien * the LED(s) using the GPIO lines). 20190075Sobrien */ 20290075Sobrien bits = (bits &~ AR_PCICFG_LEDMODE) 20390075Sobrien | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE) 20490075Sobrien#if 0 20590075Sobrien | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE) 20690075Sobrien#endif 20790075Sobrien | 0x08000000; 20890075Sobrien } 20990075Sobrien bits = (bits &~ AR_PCICFG_LEDCTL) 21090075Sobrien | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL); 21190075Sobrien OS_REG_WRITE(ah, AR_PCICFG, bits); 21290075Sobrien} 21390075Sobrien 21490075Sobrien/* 21590075Sobrien * Change association related fields programmed into the hardware. 21690075Sobrien * Writing a valid BSSID to the hardware effectively enables the hardware 21718334Speter * to synchronize its TSF to the correct beacons and receive frames coming 21852284Sobrien * from that BSSID. It is called by the SME JOIN operation. 21918334Speter */ 22090075Sobrienvoid 22118334Speterar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) 22218334Speter{ 22318334Speter struct ath_hal_5212 *ahp = AH5212(ah); 22418334Speter 22550397Sobrien /* XXX save bssid for possible re-use on reset */ 22650397Sobrien OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); 22750397Sobrien OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 22818334Speter OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | 22952284Sobrien ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); 23090075Sobrien} 23152284Sobrien 23252284Sobrien/* 23390075Sobrien * Get the current hardware tsf for stamlme 23452284Sobrien */ 23552284Sobrienuint64_t 23652284Sobrienar5212GetTsf64(struct ath_hal *ah) 23718334Speter{ 23818334Speter uint32_t low1, low2, u32; 23918334Speter 24018334Speter /* sync multi-word read */ 24118334Speter low1 = OS_REG_READ(ah, AR_TSF_L32); 24252284Sobrien u32 = OS_REG_READ(ah, AR_TSF_U32); 24352284Sobrien low2 = OS_REG_READ(ah, AR_TSF_L32); 24490075Sobrien if (low2 < low1) { /* roll over */ 24590075Sobrien /* 24690075Sobrien * If we are not preempted this will work. If we are 24790075Sobrien * then we re-reading AR_TSF_U32 does no good as the 24890075Sobrien * low bits will be meaningless. Likewise reading 24990075Sobrien * L32, U32, U32, then comparing the last two reads 25090075Sobrien * to check for rollover doesn't help if preempted--so 25118334Speter * we take this approach as it costs one less PCI read 25218334Speter * which can be noticeable when doing things like 25318334Speter * timestamping packets in monitor mode. 25418334Speter */ 25518334Speter u32++; 25618334Speter } 25750397Sobrien return (((uint64_t) u32) << 32) | ((uint64_t) low2); 25818334Speter} 25950397Sobrien 26018334Speter/* 26118334Speter * Get the current hardware tsf for stamlme 26218334Speter */ 26318334Speteruint32_t 26418334Speterar5212GetTsf32(struct ath_hal *ah) 26518334Speter{ 26618334Speter return OS_REG_READ(ah, AR_TSF_L32); 26718334Speter} 26818334Speter 26952284Sobrien/* 27090075Sobrien * Reset the current hardware tsf for stamlme. 27152284Sobrien */ 27290075Sobrienvoid 27318334Speterar5212ResetTsf(struct ath_hal *ah) 27418334Speter{ 27518334Speter 27618334Speter uint32_t val = OS_REG_READ(ah, AR_BEACON); 27718334Speter 27818334Speter OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 27918334Speter /* 28050397Sobrien * When resetting the TSF, write twice to the 28118334Speter * corresponding register; each write to the RESET_TSF bit toggles 28218334Speter * the internal signal to cause a reset of the TSF - but if the signal 28318334Speter * is left high, it will reset the TSF on the next chip reset also! 28418334Speter * writing the bit an even number of times fixes this issue 28518334Speter */ 28618334Speter OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 28718334Speter} 28818334Speter 28918334Speter/* 29018334Speter * Set or clear hardware basic rate bit 29118334Speter * Set hardware basic rate set if basic rate is found 29218334Speter * and basic rate is equal or less than 2Mbps 29318334Speter */ 29418334Spetervoid 29518334Speterar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs) 29618334Speter{ 29718334Speter HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 29818334Speter uint32_t reg; 29918334Speter uint8_t xset; 30018334Speter int i; 30150397Sobrien 30250397Sobrien if (chan == AH_NULL || !IS_CHAN_CCK(chan)) 30318334Speter return; 30418334Speter xset = 0; 30518334Speter for (i = 0; i < rs->rs_count; i++) { 30690075Sobrien uint8_t rset = rs->rs_rates[i]; 30790075Sobrien /* Basic rate defined? */ 30890075Sobrien if ((rset & 0x80) && (rset &= 0x7f) >= xset) 30990075Sobrien xset = rset; 31090075Sobrien } 31118334Speter /* 31290075Sobrien * Set the h/w bit to reflect whether or not the basic 31390075Sobrien * rate is found to be equal or less than 2Mbps. 31490075Sobrien */ 31518334Speter reg = OS_REG_READ(ah, AR_STA_ID1); 31690075Sobrien if (xset && xset/2 <= 2) 31790075Sobrien OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B); 31890075Sobrien else 31918334Speter OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B); 32090075Sobrien} 32190075Sobrien 32290075Sobrien/* 32390075Sobrien * Grab a semi-random value from hardware registers - may not 32490075Sobrien * change often 32590075Sobrien */ 32690075Sobrienuint32_t 32790075Sobrienar5212GetRandomSeed(struct ath_hal *ah) 32890075Sobrien{ 32990075Sobrien uint32_t nf; 33018334Speter 33190075Sobrien nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; 33218334Speter if (nf & 0x100) 33318334Speter nf = 0 - ((nf ^ 0x1ff) + 1); 33418334Speter return (OS_REG_READ(ah, AR_TSF_U32) ^ 33590075Sobrien OS_REG_READ(ah, AR_TSF_L32) ^ nf); 33618334Speter} 33718334Speter 33818334Speter/* 33918334Speter * Detect if our card is present 34018334Speter */ 34118334SpeterHAL_BOOL 34218334Speterar5212DetectCardPresent(struct ath_hal *ah) 34390075Sobrien{ 34490075Sobrien uint16_t macVersion, macRev; 34550397Sobrien uint32_t v; 34618334Speter 34790075Sobrien /* 34890075Sobrien * Read the Silicon Revision register and compare that 34952284Sobrien * to what we read at attach time. If the same, we say 35018334Speter * a card/device is present. 35150397Sobrien */ 35218334Speter v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; 35318334Speter macVersion = v >> AR_SREV_ID_S; 35490075Sobrien macRev = v & AR_SREV_REVISION; 35518334Speter return (AH_PRIVATE(ah)->ah_macVersion == macVersion && 35618334Speter AH_PRIVATE(ah)->ah_macRev == macRev); 35750397Sobrien} 35850397Sobrien 35950397Sobrienvoid 36090075Sobrienar5212EnableMibCounters(struct ath_hal *ah) 36190075Sobrien{ 36250397Sobrien /* NB: this just resets the mib counter machinery */ 36390075Sobrien OS_REG_WRITE(ah, AR_MIBC, 36490075Sobrien ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 36590075Sobrien} 36690075Sobrien 36790075Sobrienvoid 36890075Sobrienar5212DisableMibCounters(struct ath_hal *ah) 36990075Sobrien{ 37090075Sobrien OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC); 37190075Sobrien} 37290075Sobrien 37390075Sobrien/* 37490075Sobrien * Update MIB Counters 37590075Sobrien */ 37690075Sobrienvoid 37750397Sobrienar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats) 37850397Sobrien{ 37990075Sobrien stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); 38090075Sobrien stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); 38190075Sobrien stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); 38250397Sobrien stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); 38390075Sobrien stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); 38490075Sobrien} 38550397Sobrien 38690075Sobrien/* 38752284Sobrien * Detect if the HW supports spreading a CCK signal on channel 14 38850397Sobrien */ 38950397SobrienHAL_BOOL 39090075Sobrienar5212IsJapanChannelSpreadSupported(struct ath_hal *ah) 39150397Sobrien{ 39290075Sobrien return AH_TRUE; 39350397Sobrien} 39450397Sobrien 39550397Sobrien/* 39652284Sobrien * Get the rssi of frame curently being received. 39752284Sobrien */ 39852284Sobrienuint32_t 39918334Speterar5212GetCurRssi(struct ath_hal *ah) 40018334Speter{ 40118334Speter return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); 40218334Speter} 40318334Speter 40490075Sobrienu_int 40590075Sobrienar5212GetDefAntenna(struct ath_hal *ah) 40618334Speter{ 40718334Speter return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); 40818334Speter} 40918334Speter 41090075Sobrienvoid 41118334Speterar5212SetDefAntenna(struct ath_hal *ah, u_int antenna) 41218334Speter{ 41350397Sobrien OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); 41450397Sobrien} 41550397Sobrien 41650397SobrienHAL_ANT_SETTING 41790075Sobrienar5212GetAntennaSwitch(struct ath_hal *ah) 41890075Sobrien{ 41990075Sobrien return AH5212(ah)->ah_antControl; 42090075Sobrien} 42190075Sobrien 42290075SobrienHAL_BOOL 42390075Sobrienar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting) 42418334Speter{ 42518334Speter struct ath_hal_5212 *ahp = AH5212(ah); 42618334Speter const HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan; 42790075Sobrien 42890075Sobrien if (!ahp->ah_phyPowerOn || ichan == AH_NULL) { 42990075Sobrien /* PHY powered off, just stash settings */ 43090075Sobrien ahp->ah_antControl = setting; 43190075Sobrien ahp->ah_diversity = (setting == HAL_ANT_VARIABLE); 43290075Sobrien return AH_TRUE; 43390075Sobrien } 43490075Sobrien return ar5212SetAntennaSwitchInternal(ah, setting, ichan); 43590075Sobrien} 43690075Sobrien 43790075SobrienHAL_BOOL 43890075Sobrienar5212IsSleepAfterBeaconBroken(struct ath_hal *ah) 43990075Sobrien{ 44090075Sobrien return AH_TRUE; 44190075Sobrien} 44290075Sobrien 44390075SobrienHAL_BOOL 44490075Sobrienar5212SetSifsTime(struct ath_hal *ah, u_int us) 44590075Sobrien{ 44690075Sobrien struct ath_hal_5212 *ahp = AH5212(ah); 44790075Sobrien 44890075Sobrien if (us > ath_hal_mac_usec(ah, 0xffff)) { 44990075Sobrien HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", 45090075Sobrien __func__, us); 45190075Sobrien ahp->ah_sifstime = (u_int) -1; /* restore default handling */ 45290075Sobrien return AH_FALSE; 45390075Sobrien } else { 45490075Sobrien /* convert to system clocks */ 45590075Sobrien OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us-2)); 45690075Sobrien ahp->ah_slottime = us; 45790075Sobrien return AH_TRUE; 45818334Speter } 45918334Speter} 46018334Speter 46118334Speteru_int 46218334Speterar5212GetSifsTime(struct ath_hal *ah) 46318334Speter{ 46418334Speter u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; 46518334Speter return ath_hal_mac_usec(ah, clks)+2; /* convert from system clocks */ 46618334Speter} 46718334Speter 46818334SpeterHAL_BOOL 46918334Speterar5212SetSlotTime(struct ath_hal *ah, u_int us) 47018334Speter{ 47118334Speter struct ath_hal_5212 *ahp = AH5212(ah); 47218334Speter 47318334Speter if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) { 47418334Speter HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", 47518334Speter __func__, us); 47618334Speter ahp->ah_slottime = (u_int) -1; /* restore default handling */ 47752284Sobrien return AH_FALSE; 47852284Sobrien } else { 47952284Sobrien /* convert to system clocks */ 48090075Sobrien OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); 48190075Sobrien ahp->ah_slottime = us; 48252284Sobrien return AH_TRUE; 48352284Sobrien } 48452284Sobrien} 48552284Sobrien 48652284Sobrienu_int 48752284Sobrienar5212GetSlotTime(struct ath_hal *ah) 48890075Sobrien{ 48918334Speter u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; 49018334Speter return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 49118334Speter} 49218334Speter 49318334SpeterHAL_BOOL 49418334Speterar5212SetAckTimeout(struct ath_hal *ah, u_int us) 49518334Speter{ 49618334Speter struct ath_hal_5212 *ahp = AH5212(ah); 49718334Speter 49818334Speter if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { 49950397Sobrien HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", 50052284Sobrien __func__, us); 50118334Speter ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ 50218334Speter return AH_FALSE; 50318334Speter } else { 50418334Speter /* convert to system clocks */ 50518334Speter OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 50618334Speter AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); 50718334Speter ahp->ah_acktimeout = us; 50818334Speter return AH_TRUE; 50918334Speter } 51018334Speter} 51118334Speter 51218334Speteru_int 51318334Speterar5212GetAckTimeout(struct ath_hal *ah) 51418334Speter{ 51518334Speter u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); 51618334Speter return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 51718334Speter} 51852284Sobrien 51918334Speteru_int 52090075Sobrienar5212GetAckCTSRate(struct ath_hal *ah) 52190075Sobrien{ 52290075Sobrien return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); 52390075Sobrien} 52452284Sobrien 52590075SobrienHAL_BOOL 52652284Sobrienar5212SetAckCTSRate(struct ath_hal *ah, u_int high) 52718334Speter{ 52818334Speter struct ath_hal_5212 *ahp = AH5212(ah); 52990075Sobrien 53018334Speter if (high) { 53118334Speter OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 53218334Speter ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; 53318334Speter } else { 53418334Speter OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 53518334Speter ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; 53618334Speter } 53718334Speter return AH_TRUE; 53818334Speter} 53918334Speter 54018334SpeterHAL_BOOL 54152284Sobrienar5212SetCTSTimeout(struct ath_hal *ah, u_int us) 54252284Sobrien{ 54390075Sobrien struct ath_hal_5212 *ahp = AH5212(ah); 54418334Speter 54518334Speter if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { 54618334Speter HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", 54718334Speter __func__, us); 54850397Sobrien ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ 54950397Sobrien return AH_FALSE; 55018334Speter } else { 55118334Speter /* convert to system clocks */ 55218334Speter OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 55350397Sobrien AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); 55418334Speter ahp->ah_ctstimeout = us; 55550397Sobrien return AH_TRUE; 55650397Sobrien } 55752284Sobrien} 55852284Sobrien 55990075Sobrienu_int 56090075Sobrienar5212GetCTSTimeout(struct ath_hal *ah) 56118334Speter{ 56218334Speter u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); 56318334Speter return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 56418334Speter} 56550397Sobrien 56618334Speter/* Setup decompression for given key index */ 56718334SpeterHAL_BOOL 56818334Speterar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 56918334Speter{ 57018334Speter struct ath_hal_5212 *ahp = AH5212(ah); 57118334Speter 57290075Sobrien if (keyidx >= HAL_DECOMP_MASK_SIZE) 57318334Speter return AH_FALSE; 57418334Speter OS_REG_WRITE(ah, AR_DCM_A, keyidx); 57518334Speter OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0); 57618334Speter ahp->ah_decompMask[keyidx] = en; 57718334Speter 57818334Speter return AH_TRUE; 57918334Speter} 58018334Speter 58150397Sobrien/* Setup coverage class */ 58250397Sobrienvoid 58318334Speterar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 58418334Speter{ 58518334Speter uint32_t slot, timeout, eifs; 58618334Speter u_int clkRate; 58718334Speter 58818334Speter AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 58918334Speter 59018334Speter if (now) { 59118334Speter if (AH_PRIVATE(ah)->ah_coverageClass == 0) 59290075Sobrien return; 59318334Speter 59418334Speter /* Don't apply coverage class to non A channels */ 59550397Sobrien if (!IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan)) 59690075Sobrien return; 59790075Sobrien 59818334Speter /* Get core clock rate */ 59918334Speter clkRate = ath_hal_mac_clks(ah, 1); 60090075Sobrien 60190075Sobrien /* Compute EIFS */ 60218334Speter slot = coverageclass * 3 * clkRate; 60390075Sobrien eifs = coverageclass * 6 * clkRate; 60490075Sobrien if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { 60590075Sobrien slot += IFS_SLOT_HALF_RATE; 60690075Sobrien eifs += IFS_EIFS_HALF_RATE; 60790075Sobrien } else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { 60818334Speter slot += IFS_SLOT_QUARTER_RATE; 60918334Speter eifs += IFS_EIFS_QUARTER_RATE; 61050397Sobrien } else { /* full rate */ 61150397Sobrien slot += IFS_SLOT_FULL_RATE; 61250397Sobrien eifs += IFS_EIFS_FULL_RATE; 61350397Sobrien } 61450397Sobrien 61550397Sobrien /* 61650397Sobrien * Add additional time for air propagation for ACK and CTS 61750397Sobrien * timeouts. This value is in core clocks. 61850397Sobrien */ 61918334Speter timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate); 62018334Speter 62118334Speter /* 62218334Speter * Write the values: slot, eifs, ack/cts timeouts. 62318334Speter */ 62450397Sobrien OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); 62518334Speter OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); 62618334Speter OS_REG_WRITE(ah, AR_TIME_OUT, 62718334Speter SM(timeout, AR_TIME_OUT_CTS) 62818334Speter | SM(timeout, AR_TIME_OUT_ACK)); 62918334Speter } 63018334Speter} 63150397Sobrien 63250397Sobrienvoid 63318334Speterar5212SetPCUConfig(struct ath_hal *ah) 63418334Speter{ 63590075Sobrien ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); 63690075Sobrien} 63750397Sobrien 63890075Sobrien/* 63990075Sobrien * Return whether an external 32KHz crystal should be used 64050397Sobrien * to reduce power consumption when sleeping. We do so if 64150397Sobrien * the crystal is present (obtained from EEPROM) and if we 64250397Sobrien * are not running as an AP and are configured to use it. 64350397Sobrien */ 64450397SobrienHAL_BOOL 64518334Speterar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode) 64618334Speter{ 64752284Sobrien if (opmode != HAL_M_HOSTAP) { 64852284Sobrien struct ath_hal_5212 *ahp = AH5212(ah); 64952284Sobrien return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) && 65052284Sobrien (ahp->ah_enable32kHzClock == USE_32KHZ || 65152284Sobrien ahp->ah_enable32kHzClock == AUTO_32KHZ); 65252284Sobrien } else 65352284Sobrien return AH_FALSE; 65452284Sobrien} 65552284Sobrien 65690075Sobrien/* 65790075Sobrien * If 32KHz clock exists, use it to lower power consumption during sleep 65890075Sobrien * 65990075Sobrien * Note: If clock is set to 32 KHz, delays on accessing certain 66052284Sobrien * baseband registers (27-31, 124-127) are required. 66152284Sobrien */ 66252284Sobrienvoid 66352284Sobrienar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) 66418334Speter{ 66552284Sobrien if (ar5212Use32KHzclock(ah, opmode)) { 66690075Sobrien /* 66752284Sobrien * Enable clocks to be turned OFF in BB during sleep 66852284Sobrien * and also enable turning OFF 32MHz/40MHz Refclk 66952284Sobrien * from A2. 67018334Speter */ 67118334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 67218334Speter OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 67318334Speter IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 67418334Speter OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); 67518334Speter OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ 67618334Speter OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1); 67718334Speter 67818334Speter if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) { 67918334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26); 68018334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d); 68118334Speter OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07); 68218334Speter OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f); 68350397Sobrien /* # Set sleep clock rate to 32 KHz. */ 68450397Sobrien OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2); 68552284Sobrien } else { 68650397Sobrien OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a); 68750397Sobrien OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); 68818334Speter OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); 68990075Sobrien OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20); 69018334Speter OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3); 69118334Speter } 69218334Speter } else { 69318334Speter OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0); 69418334Speter OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 69518334Speter 69618334Speter OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */ 69752284Sobrien 69818334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 69918334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 70018334Speter 70190075Sobrien if (IS_2417(ah)) 70218334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a); 70318334Speter else if (IS_HB63(ah)) 70418334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32); 70518334Speter else 70618334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 70750397Sobrien OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 70890075Sobrien OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 70990075Sobrien OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 71050397Sobrien IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18); 71150397Sobrien OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 71250397Sobrien IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 71390075Sobrien } 71490075Sobrien} 71590075Sobrien 71690075Sobrien/* 71790075Sobrien * If 32KHz clock exists, turn it off and turn back on the 32Mhz 71890075Sobrien */ 71990075Sobrienvoid 72050397Sobrienar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) 72118334Speter{ 72218334Speter if (ar5212Use32KHzclock(ah, opmode)) { 72318334Speter /* # Set sleep clock rate back to 32 MHz. */ 72418334Speter OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0); 72590075Sobrien OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 72690075Sobrien 72790075Sobrien OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ 72850397Sobrien OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 72918334Speter IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 73018334Speter 73118334Speter /* 73218334Speter * Restore BB registers to power-on defaults 73352284Sobrien */ 73418334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 73518334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 73618334Speter OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 73718334Speter OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 73890075Sobrien OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 73918334Speter OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 74018334Speter IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 74150397Sobrien } 74250397Sobrien} 74350397Sobrien 74450397Sobrien/* 74518334Speter * Adjust NF based on statistical values for 5GHz frequencies. 74618334Speter * Default method: this may be overridden by the rf backend. 74718334Speter */ 74818334Speterint16_t 74918334Speterar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 75018334Speter{ 75118334Speter static const struct { 75218334Speter uint16_t freqLow; 75318334Speter int16_t adjust; 75418334Speter } adjustDef[] = { 75518334Speter { 5790, 11 }, /* NB: ordered high -> low */ 75618334Speter { 5730, 10 }, 75718334Speter { 5690, 9 }, 75818334Speter { 5660, 8 }, 75918334Speter { 5610, 7 }, 76018334Speter { 5530, 5 }, 76118334Speter { 5450, 4 }, 76218334Speter { 5379, 2 }, 76318334Speter { 5209, 0 }, 76450397Sobrien { 3000, 1 }, 76518334Speter { 0, 0 }, 76690075Sobrien }; 76790075Sobrien int i; 76852284Sobrien 76950397Sobrien for (i = 0; c->channel <= adjustDef[i].freqLow; i++) 77050397Sobrien ; 77150397Sobrien return adjustDef[i].adjust; 77250397Sobrien} 77350397Sobrien 77450397SobrienHAL_STATUS 77590075Sobrienar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 77690075Sobrien uint32_t capability, uint32_t *result) 77790075Sobrien{ 77890075Sobrien#define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion 77950397Sobrien struct ath_hal_5212 *ahp = AH5212(ah); 78050397Sobrien const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 78150397Sobrien const struct ar5212AniState *ani; 78218334Speter 78318334Speter switch (type) { 78418334Speter case HAL_CAP_CIPHER: /* cipher handled in hardware */ 78550397Sobrien switch (capability) { 78618334Speter case HAL_CIPHER_AES_CCM: 78718334Speter return pCap->halCipherAesCcmSupport ? 78818334Speter HAL_OK : HAL_ENOTSUPP; 78918334Speter case HAL_CIPHER_AES_OCB: 79018334Speter case HAL_CIPHER_TKIP: 79118334Speter case HAL_CIPHER_WEP: 79218334Speter case HAL_CIPHER_MIC: 79390075Sobrien case HAL_CIPHER_CLR: 79418334Speter return HAL_OK; 79518334Speter default: 79618334Speter return HAL_ENOTSUPP; 79718334Speter } 79818334Speter case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 79918334Speter switch (capability) { 80090075Sobrien case 0: /* hardware capability */ 80190075Sobrien return HAL_OK; 80290075Sobrien case 1: 80390075Sobrien return (ahp->ah_staId1Defaults & 80490075Sobrien AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO; 80590075Sobrien } 80690075Sobrien return HAL_EINVAL; 80790075Sobrien case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 80890075Sobrien switch (capability) { 80990075Sobrien case 0: /* hardware capability */ 81090075Sobrien return pCap->halTkipMicTxRxKeySupport ? 81190075Sobrien HAL_ENXIO : HAL_OK; 81290075Sobrien case 1: /* current setting */ 81390075Sobrien return (ahp->ah_miscMode & 81490075Sobrien AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; 81590075Sobrien } 81690075Sobrien return HAL_EINVAL; 81790075Sobrien case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ 81890075Sobrien /* XXX move to capability bit */ 81990075Sobrien return MACVERSION(ah) > AR_SREV_VERSION_VENICE || 82090075Sobrien (MACVERSION(ah) == AR_SREV_VERSION_VENICE && 82190075Sobrien AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; 82290075Sobrien case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 82390075Sobrien switch (capability) { 82490075Sobrien case 0: /* hardware capability */ 82590075Sobrien return HAL_OK; 82690075Sobrien case 1: /* current setting */ 82790075Sobrien return ahp->ah_diversity ? HAL_OK : HAL_ENXIO; 82890075Sobrien } 82990075Sobrien return HAL_EINVAL; 83090075Sobrien case HAL_CAP_DIAG: 83190075Sobrien *result = AH_PRIVATE(ah)->ah_diagreg; 83290075Sobrien return HAL_OK; 83390075Sobrien case HAL_CAP_TPC: 83490075Sobrien switch (capability) { 83590075Sobrien case 0: /* hardware capability */ 83690075Sobrien return HAL_OK; 83790075Sobrien case 1: 83890075Sobrien return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; 83990075Sobrien } 84090075Sobrien return HAL_OK; 84190075Sobrien case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ 84290075Sobrien switch (capability) { 84390075Sobrien case HAL_CAP_RADAR: 84490075Sobrien return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? 84590075Sobrien HAL_OK: HAL_ENXIO; 84690075Sobrien case HAL_CAP_AR: 84790075Sobrien return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || 84890075Sobrien ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? 84990075Sobrien HAL_OK: HAL_ENXIO; 85090075Sobrien } 85190075Sobrien return HAL_ENXIO; 85290075Sobrien case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 85390075Sobrien switch (capability) { 85490075Sobrien case 0: /* hardware capability */ 85590075Sobrien return HAL_OK; 85690075Sobrien case 1: 85790075Sobrien return (ahp->ah_staId1Defaults & 85890075Sobrien AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; 85990075Sobrien } 86090075Sobrien return HAL_EINVAL; 86190075Sobrien case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 86290075Sobrien switch (capability) { 86390075Sobrien case 0: /* hardware capability */ 86490075Sobrien return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; 86590075Sobrien case 1: 86690075Sobrien return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? 86790075Sobrien HAL_OK : HAL_ENXIO; 86890075Sobrien } 86990075Sobrien return HAL_EINVAL; 87090075Sobrien case HAL_CAP_TPC_ACK: 87190075Sobrien *result = MS(ahp->ah_macTPC, AR_TPC_ACK); 87290075Sobrien return HAL_OK; 87390075Sobrien case HAL_CAP_TPC_CTS: 87490075Sobrien *result = MS(ahp->ah_macTPC, AR_TPC_CTS); 87590075Sobrien return HAL_OK; 87690075Sobrien case HAL_CAP_INTMIT: /* interference mitigation */ 87790075Sobrien switch (capability) { 87890075Sobrien case 0: /* hardware capability */ 87990075Sobrien return HAL_OK; 88090075Sobrien case 1: 88190075Sobrien return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? 88290075Sobrien HAL_OK : HAL_ENXIO; 88390075Sobrien case 2: /* HAL_ANI_NOISE_IMMUNITY_LEVEL */ 88490075Sobrien case 3: /* HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION */ 88590075Sobrien case 4: /* HAL_ANI_CCK_WEAK_SIGNAL_THR */ 88690075Sobrien case 5: /* HAL_ANI_FIRSTEP_LEVEL */ 88790075Sobrien case 6: /* HAL_ANI_SPUR_IMMUNITY_LEVEL */ 88890075Sobrien ani = ar5212AniGetCurrentState(ah); 88990075Sobrien if (ani == AH_NULL) 89090075Sobrien return HAL_ENXIO; 89190075Sobrien switch (capability) { 89290075Sobrien case 2: *result = ani->noiseImmunityLevel; break; 89390075Sobrien case 3: *result = !ani->ofdmWeakSigDetectOff; break; 89490075Sobrien case 4: *result = ani->cckWeakSigThreshold; break; 89590075Sobrien case 5: *result = ani->firstepLevel; break; 89690075Sobrien case 6: *result = ani->spurImmunityLevel; break; 89790075Sobrien } 89890075Sobrien return HAL_OK; 89990075Sobrien } 90090075Sobrien return HAL_EINVAL; 90190075Sobrien default: 90290075Sobrien return ath_hal_getcapability(ah, type, capability, result); 90390075Sobrien } 90490075Sobrien#undef MACVERSION 90590075Sobrien} 90690075Sobrien 90790075SobrienHAL_BOOL 90890075Sobrienar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 90990075Sobrien uint32_t capability, uint32_t setting, HAL_STATUS *status) 91090075Sobrien{ 91190075Sobrien#define N(a) (sizeof(a)/sizeof(a[0])) 91290075Sobrien struct ath_hal_5212 *ahp = AH5212(ah); 91390075Sobrien const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 91490075Sobrien uint32_t v; 91590075Sobrien 91690075Sobrien switch (type) { 91790075Sobrien case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 91890075Sobrien if (setting) 91990075Sobrien ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; 92090075Sobrien else 92190075Sobrien ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; 92290075Sobrien return AH_TRUE; 92390075Sobrien case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 92490075Sobrien if (!pCap->halTkipMicTxRxKeySupport) 92590075Sobrien return AH_FALSE; 92690075Sobrien /* NB: true =>'s use split key cache layout */ 92790075Sobrien if (setting) 92890075Sobrien ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 92990075Sobrien else 93090075Sobrien ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 93190075Sobrien /* NB: write here so keys can be setup w/o a reset */ 93290075Sobrien OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); 93390075Sobrien return AH_TRUE; 93490075Sobrien case HAL_CAP_DIVERSITY: 93590075Sobrien if (ahp->ah_phyPowerOn) { 93690075Sobrien v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 93790075Sobrien if (setting) 93890075Sobrien v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 93918334Speter else 94018334Speter v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 94118334Speter OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); 94218334Speter } 94350397Sobrien ahp->ah_diversity = (setting != 0); 94418334Speter return AH_TRUE; 94550397Sobrien case HAL_CAP_DIAG: /* hardware diagnostic support */ 94650397Sobrien /* 94750397Sobrien * NB: could split this up into virtual capabilities, 94850397Sobrien * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly 94950397Sobrien * seems worth the additional complexity. 95050397Sobrien */ 95190075Sobrien AH_PRIVATE(ah)->ah_diagreg = setting; 95250397Sobrien OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 95350397Sobrien return AH_TRUE; 95450397Sobrien case HAL_CAP_TPC: 95550397Sobrien ahp->ah_tpcEnabled = (setting != 0); 95618334Speter return AH_TRUE; 95718334Speter case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 95818334Speter if (setting) 95918334Speter ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; 96050397Sobrien else 96150397Sobrien ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; 96250397Sobrien return AH_TRUE; 96350397Sobrien case HAL_CAP_TPC_ACK: 96450397Sobrien case HAL_CAP_TPC_CTS: 96550397Sobrien setting += ahp->ah_txPowerIndexOffset; 96650397Sobrien if (setting > 63) 96750397Sobrien setting = 63; 96850397Sobrien if (type == HAL_CAP_TPC_ACK) { 96990075Sobrien ahp->ah_macTPC &= AR_TPC_ACK; 97050397Sobrien ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); 97150397Sobrien } else { 97250397Sobrien ahp->ah_macTPC &= AR_TPC_CTS; 97350397Sobrien ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); 97450397Sobrien } 97518334Speter OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); 97618334Speter return AH_TRUE; 97750397Sobrien case HAL_CAP_INTMIT: { /* interference mitigation */ 97818334Speter static const HAL_ANI_CMD cmds[] = { 97918334Speter HAL_ANI_PRESENT, 98050397Sobrien HAL_ANI_MODE, 98118334Speter HAL_ANI_NOISE_IMMUNITY_LEVEL, 98218334Speter HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 98318334Speter HAL_ANI_CCK_WEAK_SIGNAL_THR, 98418334Speter HAL_ANI_FIRSTEP_LEVEL, 98518334Speter HAL_ANI_SPUR_IMMUNITY_LEVEL, 98618334Speter }; 98718334Speter return capability < N(cmds) ? 98818334Speter ar5212AniControl(ah, cmds[capability], setting) : 98918334Speter AH_FALSE; 99018334Speter } 99118334Speter case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 99218334Speter if (pCap->halTsfAddSupport) { 99318334Speter if (setting) 99418334Speter ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; 99518334Speter else 99618334Speter ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; 99718334Speter return AH_TRUE; 99818334Speter } 99918334Speter /* fall thru... */ 100018334Speter default: 100118334Speter return ath_hal_setcapability(ah, type, capability, 100218334Speter setting, status); 100318334Speter } 100418334Speter#undef N 100518334Speter} 100618334Speter 100750397SobrienHAL_BOOL 100818334Speterar5212GetDiagState(struct ath_hal *ah, int request, 100918334Speter const void *args, uint32_t argsize, 101018334Speter void **result, uint32_t *resultsize) 101150397Sobrien{ 101218334Speter struct ath_hal_5212 *ahp = AH5212(ah); 101318334Speter 101418334Speter (void) ahp; 101518334Speter if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 101618334Speter return AH_TRUE; 101718334Speter switch (request) { 101818334Speter case HAL_DIAG_EEPROM: 101918334Speter case HAL_DIAG_EEPROM_EXP_11A: 102018334Speter case HAL_DIAG_EEPROM_EXP_11B: 102118334Speter case HAL_DIAG_EEPROM_EXP_11G: 102218334Speter case HAL_DIAG_RFGAIN: 102318334Speter return ath_hal_eepromDiag(ah, request, 102418334Speter args, argsize, result, resultsize); 102518334Speter case HAL_DIAG_RFGAIN_CURSTEP: 102618334Speter *result = __DECONST(void *, ahp->ah_gainValues.currStep); 102718334Speter *resultsize = (*result == AH_NULL) ? 102818334Speter 0 : sizeof(GAIN_OPTIMIZATION_STEP); 102918334Speter return AH_TRUE; 103018334Speter case HAL_DIAG_PCDAC: 103118334Speter *result = ahp->ah_pcdacTable; 103252284Sobrien *resultsize = ahp->ah_pcdacTableSize; 103318334Speter return AH_TRUE; 103418334Speter case HAL_DIAG_TXRATES: 103518334Speter *result = &ahp->ah_ratesArray[0]; 103618334Speter *resultsize = sizeof(ahp->ah_ratesArray); 103718334Speter return AH_TRUE; 103850397Sobrien case HAL_DIAG_ANI_CURRENT: 103950397Sobrien *result = ar5212AniGetCurrentState(ah); 104018334Speter *resultsize = (*result == AH_NULL) ? 104118334Speter 0 : sizeof(struct ar5212AniState); 104218334Speter return AH_TRUE; 104318334Speter case HAL_DIAG_ANI_STATS: 104418334Speter *result = ar5212AniGetCurrentStats(ah); 104518334Speter *resultsize = (*result == AH_NULL) ? 104618334Speter 0 : sizeof(struct ar5212Stats); 104718334Speter return AH_TRUE; 104818334Speter case HAL_DIAG_ANI_CMD: 104918334Speter if (argsize != 2*sizeof(uint32_t)) 105018334Speter return AH_FALSE; 105118334Speter ar5212AniControl(ah, ((const uint32_t *)args)[0], 105218334Speter ((const uint32_t *)args)[1]); 105318334Speter return AH_TRUE; 105452284Sobrien case HAL_DIAG_ANI_PARAMS: 105518334Speter /* 105618334Speter * NB: We assume struct ar5212AniParams is identical 105752284Sobrien * to HAL_ANI_PARAMS; if they diverge then we'll need 105852284Sobrien * to handle it here 105952284Sobrien */ 106090075Sobrien if (argsize == 0 && args == AH_NULL) { 106152284Sobrien struct ar5212AniState *aniState = 106252284Sobrien ar5212AniGetCurrentState(ah); 106318334Speter if (aniState == AH_NULL) 106418334Speter return AH_FALSE; 106518334Speter *result = __DECONST(void *, aniState->params); 106618334Speter *resultsize = sizeof(struct ar5212AniParams); 106790075Sobrien return AH_TRUE; 106890075Sobrien } else { 106990075Sobrien if (argsize != sizeof(struct ar5212AniParams)) 107018334Speter return AH_FALSE; 107118334Speter return ar5212AniSetParams(ah, args, args); 107218334Speter } 107318334Speter } 107452284Sobrien return AH_FALSE; 107518334Speter} 107650397Sobrien 107718334Speter/* 107818334Speter * Check whether there's an in-progress NF completion. 107918334Speter * 108018334Speter * Returns AH_TRUE if there's a in-progress NF calibration, AH_FALSE 108118334Speter * otherwise. 108218334Speter */ 108318334SpeterHAL_BOOL 108418334Speterar5212IsNFCalInProgress(struct ath_hal *ah) 108518334Speter{ 108618334Speter if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) 108718334Speter return AH_TRUE; 108818334Speter return AH_FALSE; 108918334Speter} 109018334Speter 109118334Speter/* 109218334Speter * Wait for an in-progress NF calibration to complete. 109318334Speter * 109418334Speter * The completion function waits "i" times 10uS. 109550397Sobrien * It returns AH_TRUE if the NF calibration completed (or was never 109650397Sobrien * in progress); AH_FALSE if it was still in progress after "i" checks. 109750397Sobrien */ 109818334SpeterHAL_BOOL 109918334Speterar5212WaitNFCalComplete(struct ath_hal *ah, int i) 110018334Speter{ 110118334Speter int j; 110218334Speter 110318334Speter if (i <= 0) 110418334Speter i = 1; /* it should run at least once */ 110550397Sobrien for (j = 0; j < i; i++) { 110618334Speter if (! ar5212IsNFCalInProgress(ah)) 110750397Sobrien return AH_TRUE; 110818334Speter OS_DELAY(10); 110918334Speter } 111050397Sobrien return AH_FALSE; 111118334Speter} 111218334Speter