ar5212_misc.c revision 222027
1185377Ssam/* 2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc. 4185377Ssam * 5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any 6185377Ssam * purpose with or without fee is hereby granted, provided that the above 7185377Ssam * copyright notice and this permission notice appear in all copies. 8185377Ssam * 9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16185377Ssam * 17185907Ssam * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c 222027 2011-05-17 15:03:39Z adrian $ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam#include "ah_devid.h" 24185377Ssam#ifdef AH_DEBUG 25185377Ssam#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 26185377Ssam#endif 27185377Ssam 28185377Ssam#include "ar5212/ar5212.h" 29185377Ssam#include "ar5212/ar5212reg.h" 30185377Ssam#include "ar5212/ar5212phy.h" 31185377Ssam 32185377Ssam#include "ah_eeprom_v3.h" 33185377Ssam 34185377Ssam#define AR_NUM_GPIO 6 /* 6 GPIO pins */ 35185377Ssam#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ 36185377Ssam 37185377Ssamvoid 38185377Ssamar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac) 39185377Ssam{ 40185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 41185377Ssam 42185377Ssam OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); 43185377Ssam} 44185377Ssam 45185377SsamHAL_BOOL 46185377Ssamar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac) 47185377Ssam{ 48185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 49185377Ssam 50185377Ssam OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); 51185377Ssam return AH_TRUE; 52185377Ssam} 53185377Ssam 54185377Ssamvoid 55185377Ssamar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask) 56185377Ssam{ 57185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 58185377Ssam 59185377Ssam OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN); 60185377Ssam} 61185377Ssam 62185377SsamHAL_BOOL 63185377Ssamar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) 64185377Ssam{ 65185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 66185377Ssam 67185377Ssam /* save it since it must be rewritten on reset */ 68185377Ssam OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN); 69185377Ssam 70185377Ssam OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); 71185377Ssam OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); 72185377Ssam return AH_TRUE; 73185377Ssam} 74185377Ssam 75185377Ssam/* 76185380Ssam * Attempt to change the cards operating regulatory domain to the given value 77185380Ssam */ 78185380SsamHAL_BOOL 79185380Ssamar5212SetRegulatoryDomain(struct ath_hal *ah, 80185380Ssam uint16_t regDomain, HAL_STATUS *status) 81185380Ssam{ 82185380Ssam HAL_STATUS ecode; 83185380Ssam 84185380Ssam if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { 85185380Ssam ecode = HAL_EINVAL; 86185380Ssam goto bad; 87185380Ssam } 88185380Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { 89185380Ssam ecode = HAL_EEWRITE; 90185380Ssam goto bad; 91185380Ssam } 92185380Ssam#ifdef AH_SUPPORT_WRITE_REGDOMAIN 93185380Ssam if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { 94185380Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 95185380Ssam "%s: set regulatory domain to %u (0x%x)\n", 96185380Ssam __func__, regDomain, regDomain); 97185380Ssam AH_PRIVATE(ah)->ah_currentRD = regDomain; 98185380Ssam return AH_TRUE; 99185380Ssam } 100185380Ssam#endif 101185380Ssam ecode = HAL_EIO; 102185380Ssambad: 103185380Ssam if (status) 104185380Ssam *status = ecode; 105185380Ssam return AH_FALSE; 106185380Ssam} 107185380Ssam 108185380Ssam/* 109185377Ssam * Return the wireless modes (a,b,g,t) supported by hardware. 110185377Ssam * 111185377Ssam * This value is what is actually supported by the hardware 112185377Ssam * and is unaffected by regulatory/country code settings. 113185377Ssam */ 114185377Ssamu_int 115185377Ssamar5212GetWirelessModes(struct ath_hal *ah) 116185377Ssam{ 117185377Ssam u_int mode = 0; 118185377Ssam 119185377Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { 120185377Ssam mode = HAL_MODE_11A; 121185377Ssam if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) 122185377Ssam mode |= HAL_MODE_TURBO | HAL_MODE_108A; 123185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 124185380Ssam mode |= HAL_MODE_11A_HALF_RATE; 125185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 126185380Ssam mode |= HAL_MODE_11A_QUARTER_RATE; 127185377Ssam } 128185377Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) 129185377Ssam mode |= HAL_MODE_11B; 130185377Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && 131185377Ssam AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { 132185377Ssam mode |= HAL_MODE_11G; 133185377Ssam if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) 134185377Ssam mode |= HAL_MODE_108G; 135185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 136185380Ssam mode |= HAL_MODE_11G_HALF_RATE; 137185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 138185380Ssam mode |= HAL_MODE_11G_QUARTER_RATE; 139185377Ssam } 140185377Ssam return mode; 141185377Ssam} 142185377Ssam 143185377Ssam/* 144185377Ssam * Set the interrupt and GPIO values so the ISR can disable RF 145185377Ssam * on a switch signal. Assumes GPIO port and interrupt polarity 146185377Ssam * are set prior to call. 147185377Ssam */ 148185377Ssamvoid 149185377Ssamar5212EnableRfKill(struct ath_hal *ah) 150185377Ssam{ 151185377Ssam uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; 152185377Ssam int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); 153185377Ssam int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); 154185377Ssam 155185377Ssam /* 156185377Ssam * Configure the desired GPIO port for input 157185377Ssam * and enable baseband rf silence. 158185377Ssam */ 159185377Ssam ath_hal_gpioCfgInput(ah, select); 160185377Ssam OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000); 161185377Ssam /* 162185377Ssam * If radio disable switch connection to GPIO bit x is enabled 163185377Ssam * program GPIO interrupt. 164185377Ssam * If rfkill bit on eeprom is 1, setupeeprommap routine has already 165185377Ssam * verified that it is a later version of eeprom, it has a place for 166185377Ssam * rfkill bit and it is set to 1, indicating that GPIO bit x hardware 167185377Ssam * connection is present. 168185377Ssam */ 169185377Ssam ath_hal_gpioSetIntr(ah, select, 170185377Ssam (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity)); 171185377Ssam} 172185377Ssam 173185377Ssam/* 174185377Ssam * Change the LED blinking pattern to correspond to the connectivity 175185377Ssam */ 176185377Ssamvoid 177185377Ssamar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 178185377Ssam{ 179185377Ssam static const uint32_t ledbits[8] = { 180185377Ssam AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */ 181185377Ssam AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */ 182185377Ssam AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */ 183185377Ssam AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/ 184185377Ssam AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */ 185185377Ssam AR_PCICFG_LEDCTL_NONE, 186185377Ssam AR_PCICFG_LEDCTL_NONE, 187185377Ssam AR_PCICFG_LEDCTL_NONE, 188185377Ssam }; 189185377Ssam uint32_t bits; 190185377Ssam 191185377Ssam bits = OS_REG_READ(ah, AR_PCICFG); 192185377Ssam if (IS_2417(ah)) { 193185377Ssam /* 194185377Ssam * Enable LED for Nala. There is a bit marked reserved 195185377Ssam * that must be set and we also turn on the power led. 196185377Ssam * Because we mark s/w LED control setting the control 197185377Ssam * status bits below is meangless (the driver must flash 198185377Ssam * the LED(s) using the GPIO lines). 199185377Ssam */ 200185377Ssam bits = (bits &~ AR_PCICFG_LEDMODE) 201185377Ssam | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE) 202185377Ssam#if 0 203185377Ssam | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE) 204185377Ssam#endif 205185377Ssam | 0x08000000; 206185377Ssam } 207185377Ssam bits = (bits &~ AR_PCICFG_LEDCTL) 208185377Ssam | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL); 209185377Ssam OS_REG_WRITE(ah, AR_PCICFG, bits); 210185377Ssam} 211185377Ssam 212185377Ssam/* 213185377Ssam * Change association related fields programmed into the hardware. 214185377Ssam * Writing a valid BSSID to the hardware effectively enables the hardware 215185377Ssam * to synchronize its TSF to the correct beacons and receive frames coming 216185377Ssam * from that BSSID. It is called by the SME JOIN operation. 217185377Ssam */ 218185377Ssamvoid 219185377Ssamar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) 220185377Ssam{ 221185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 222185377Ssam 223185377Ssam /* XXX save bssid for possible re-use on reset */ 224185377Ssam OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); 225185377Ssam OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 226185377Ssam OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | 227185377Ssam ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); 228185377Ssam} 229185377Ssam 230185377Ssam/* 231185377Ssam * Get the current hardware tsf for stamlme 232185377Ssam */ 233185377Ssamuint64_t 234185377Ssamar5212GetTsf64(struct ath_hal *ah) 235185377Ssam{ 236185377Ssam uint32_t low1, low2, u32; 237185377Ssam 238185377Ssam /* sync multi-word read */ 239185377Ssam low1 = OS_REG_READ(ah, AR_TSF_L32); 240185377Ssam u32 = OS_REG_READ(ah, AR_TSF_U32); 241185377Ssam low2 = OS_REG_READ(ah, AR_TSF_L32); 242185377Ssam if (low2 < low1) { /* roll over */ 243185377Ssam /* 244185377Ssam * If we are not preempted this will work. If we are 245185377Ssam * then we re-reading AR_TSF_U32 does no good as the 246185377Ssam * low bits will be meaningless. Likewise reading 247185377Ssam * L32, U32, U32, then comparing the last two reads 248185380Ssam * to check for rollover doesn't help if preempted--so 249185380Ssam * we take this approach as it costs one less PCI read 250185380Ssam * which can be noticeable when doing things like 251185380Ssam * timestamping packets in monitor mode. 252185377Ssam */ 253185377Ssam u32++; 254185377Ssam } 255185377Ssam return (((uint64_t) u32) << 32) | ((uint64_t) low2); 256185377Ssam} 257185377Ssam 258185377Ssam/* 259185377Ssam * Get the current hardware tsf for stamlme 260185377Ssam */ 261185377Ssamuint32_t 262185377Ssamar5212GetTsf32(struct ath_hal *ah) 263185377Ssam{ 264185377Ssam return OS_REG_READ(ah, AR_TSF_L32); 265185377Ssam} 266185377Ssam 267219419Sadrianvoid 268219419Sadrianar5212SetTsf64(struct ath_hal *ah, uint64_t tsf64) 269219419Sadrian{ 270219419Sadrian OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); 271219419Sadrian OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); 272219419Sadrian} 273219419Sadrian 274185377Ssam/* 275185377Ssam * Reset the current hardware tsf for stamlme. 276185377Ssam */ 277185377Ssamvoid 278185377Ssamar5212ResetTsf(struct ath_hal *ah) 279185377Ssam{ 280185377Ssam 281185377Ssam uint32_t val = OS_REG_READ(ah, AR_BEACON); 282185377Ssam 283185377Ssam OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 284185377Ssam /* 285185377Ssam * When resetting the TSF, write twice to the 286185377Ssam * corresponding register; each write to the RESET_TSF bit toggles 287185377Ssam * the internal signal to cause a reset of the TSF - but if the signal 288185377Ssam * is left high, it will reset the TSF on the next chip reset also! 289185377Ssam * writing the bit an even number of times fixes this issue 290185377Ssam */ 291185377Ssam OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 292185377Ssam} 293185377Ssam 294185377Ssam/* 295185377Ssam * Set or clear hardware basic rate bit 296185377Ssam * Set hardware basic rate set if basic rate is found 297185377Ssam * and basic rate is equal or less than 2Mbps 298185377Ssam */ 299185377Ssamvoid 300185377Ssamar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs) 301185377Ssam{ 302187831Ssam const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 303185377Ssam uint32_t reg; 304185377Ssam uint8_t xset; 305185377Ssam int i; 306185377Ssam 307187831Ssam if (chan == AH_NULL || !IEEE80211_IS_CHAN_CCK(chan)) 308185377Ssam return; 309185377Ssam xset = 0; 310185377Ssam for (i = 0; i < rs->rs_count; i++) { 311185377Ssam uint8_t rset = rs->rs_rates[i]; 312185377Ssam /* Basic rate defined? */ 313185377Ssam if ((rset & 0x80) && (rset &= 0x7f) >= xset) 314185377Ssam xset = rset; 315185377Ssam } 316185377Ssam /* 317185377Ssam * Set the h/w bit to reflect whether or not the basic 318185377Ssam * rate is found to be equal or less than 2Mbps. 319185377Ssam */ 320185377Ssam reg = OS_REG_READ(ah, AR_STA_ID1); 321185377Ssam if (xset && xset/2 <= 2) 322185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B); 323185377Ssam else 324185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B); 325185377Ssam} 326185377Ssam 327185377Ssam/* 328185377Ssam * Grab a semi-random value from hardware registers - may not 329185377Ssam * change often 330185377Ssam */ 331185377Ssamuint32_t 332185377Ssamar5212GetRandomSeed(struct ath_hal *ah) 333185377Ssam{ 334185377Ssam uint32_t nf; 335185377Ssam 336185377Ssam nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; 337185377Ssam if (nf & 0x100) 338185377Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 339185377Ssam return (OS_REG_READ(ah, AR_TSF_U32) ^ 340185377Ssam OS_REG_READ(ah, AR_TSF_L32) ^ nf); 341185377Ssam} 342185377Ssam 343185377Ssam/* 344185377Ssam * Detect if our card is present 345185377Ssam */ 346185377SsamHAL_BOOL 347185377Ssamar5212DetectCardPresent(struct ath_hal *ah) 348185377Ssam{ 349185377Ssam uint16_t macVersion, macRev; 350185377Ssam uint32_t v; 351185377Ssam 352185377Ssam /* 353185377Ssam * Read the Silicon Revision register and compare that 354185377Ssam * to what we read at attach time. If the same, we say 355185377Ssam * a card/device is present. 356185377Ssam */ 357185377Ssam v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; 358185377Ssam macVersion = v >> AR_SREV_ID_S; 359185377Ssam macRev = v & AR_SREV_REVISION; 360185377Ssam return (AH_PRIVATE(ah)->ah_macVersion == macVersion && 361185377Ssam AH_PRIVATE(ah)->ah_macRev == macRev); 362185377Ssam} 363185377Ssam 364185377Ssamvoid 365185377Ssamar5212EnableMibCounters(struct ath_hal *ah) 366185377Ssam{ 367185377Ssam /* NB: this just resets the mib counter machinery */ 368185377Ssam OS_REG_WRITE(ah, AR_MIBC, 369185377Ssam ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 370185377Ssam} 371185377Ssam 372185377Ssamvoid 373185377Ssamar5212DisableMibCounters(struct ath_hal *ah) 374185377Ssam{ 375185377Ssam OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC); 376185377Ssam} 377185377Ssam 378185377Ssam/* 379185377Ssam * Update MIB Counters 380185377Ssam */ 381185377Ssamvoid 382185377Ssamar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats) 383185377Ssam{ 384185377Ssam stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); 385185377Ssam stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); 386185377Ssam stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); 387185377Ssam stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); 388185377Ssam stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); 389185377Ssam} 390185377Ssam 391185377Ssam/* 392185377Ssam * Detect if the HW supports spreading a CCK signal on channel 14 393185377Ssam */ 394185377SsamHAL_BOOL 395185377Ssamar5212IsJapanChannelSpreadSupported(struct ath_hal *ah) 396185377Ssam{ 397185377Ssam return AH_TRUE; 398185377Ssam} 399185377Ssam 400185377Ssam/* 401185377Ssam * Get the rssi of frame curently being received. 402185377Ssam */ 403185377Ssamuint32_t 404185377Ssamar5212GetCurRssi(struct ath_hal *ah) 405185377Ssam{ 406185377Ssam return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); 407185377Ssam} 408185377Ssam 409185377Ssamu_int 410185377Ssamar5212GetDefAntenna(struct ath_hal *ah) 411185377Ssam{ 412185377Ssam return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); 413185377Ssam} 414185377Ssam 415185377Ssamvoid 416185377Ssamar5212SetDefAntenna(struct ath_hal *ah, u_int antenna) 417185377Ssam{ 418185377Ssam OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); 419185377Ssam} 420185377Ssam 421185377SsamHAL_ANT_SETTING 422185377Ssamar5212GetAntennaSwitch(struct ath_hal *ah) 423185377Ssam{ 424185380Ssam return AH5212(ah)->ah_antControl; 425185377Ssam} 426185377Ssam 427185377SsamHAL_BOOL 428185380Ssamar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting) 429185377Ssam{ 430185380Ssam struct ath_hal_5212 *ahp = AH5212(ah); 431187831Ssam const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 432185377Ssam 433187831Ssam if (!ahp->ah_phyPowerOn || chan == AH_NULL) { 434185380Ssam /* PHY powered off, just stash settings */ 435185380Ssam ahp->ah_antControl = setting; 436185380Ssam ahp->ah_diversity = (setting == HAL_ANT_VARIABLE); 437185377Ssam return AH_TRUE; 438185377Ssam } 439187831Ssam return ar5212SetAntennaSwitchInternal(ah, setting, chan); 440185377Ssam} 441185377Ssam 442185377SsamHAL_BOOL 443185377Ssamar5212IsSleepAfterBeaconBroken(struct ath_hal *ah) 444185377Ssam{ 445185377Ssam return AH_TRUE; 446185377Ssam} 447185377Ssam 448185377SsamHAL_BOOL 449185377Ssamar5212SetSifsTime(struct ath_hal *ah, u_int us) 450185377Ssam{ 451185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 452185377Ssam 453185377Ssam if (us > ath_hal_mac_usec(ah, 0xffff)) { 454185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", 455185377Ssam __func__, us); 456185377Ssam ahp->ah_sifstime = (u_int) -1; /* restore default handling */ 457185377Ssam return AH_FALSE; 458185377Ssam } else { 459185377Ssam /* convert to system clocks */ 460188866Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us-2)); 461218409Sadrian ahp->ah_sifstime = us; 462185377Ssam return AH_TRUE; 463185377Ssam } 464185377Ssam} 465185377Ssam 466185377Ssamu_int 467185377Ssamar5212GetSifsTime(struct ath_hal *ah) 468185377Ssam{ 469185377Ssam u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; 470188866Ssam return ath_hal_mac_usec(ah, clks)+2; /* convert from system clocks */ 471185377Ssam} 472185377Ssam 473185377SsamHAL_BOOL 474185377Ssamar5212SetSlotTime(struct ath_hal *ah, u_int us) 475185377Ssam{ 476185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 477185377Ssam 478185377Ssam if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) { 479185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", 480185377Ssam __func__, us); 481185377Ssam ahp->ah_slottime = (u_int) -1; /* restore default handling */ 482185377Ssam return AH_FALSE; 483185377Ssam } else { 484185377Ssam /* convert to system clocks */ 485185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); 486185377Ssam ahp->ah_slottime = us; 487185377Ssam return AH_TRUE; 488185377Ssam } 489185377Ssam} 490185377Ssam 491185377Ssamu_int 492185377Ssamar5212GetSlotTime(struct ath_hal *ah) 493185377Ssam{ 494185377Ssam u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; 495185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 496185377Ssam} 497185377Ssam 498185377SsamHAL_BOOL 499185377Ssamar5212SetAckTimeout(struct ath_hal *ah, u_int us) 500185377Ssam{ 501185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 502185377Ssam 503185377Ssam if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { 504185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", 505185377Ssam __func__, us); 506185377Ssam ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ 507185377Ssam return AH_FALSE; 508185377Ssam } else { 509185377Ssam /* convert to system clocks */ 510185377Ssam OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 511185377Ssam AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); 512185377Ssam ahp->ah_acktimeout = us; 513185377Ssam return AH_TRUE; 514185377Ssam } 515185377Ssam} 516185377Ssam 517185377Ssamu_int 518185377Ssamar5212GetAckTimeout(struct ath_hal *ah) 519185377Ssam{ 520185377Ssam u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); 521185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 522185377Ssam} 523185377Ssam 524185377Ssamu_int 525185377Ssamar5212GetAckCTSRate(struct ath_hal *ah) 526185377Ssam{ 527185377Ssam return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); 528185377Ssam} 529185377Ssam 530185377SsamHAL_BOOL 531185377Ssamar5212SetAckCTSRate(struct ath_hal *ah, u_int high) 532185377Ssam{ 533185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 534185377Ssam 535185377Ssam if (high) { 536185377Ssam OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 537185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; 538185377Ssam } else { 539185377Ssam OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 540185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; 541185377Ssam } 542185377Ssam return AH_TRUE; 543185377Ssam} 544185377Ssam 545185377SsamHAL_BOOL 546185377Ssamar5212SetCTSTimeout(struct ath_hal *ah, u_int us) 547185377Ssam{ 548185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 549185377Ssam 550185377Ssam if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { 551185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", 552185377Ssam __func__, us); 553185377Ssam ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ 554185377Ssam return AH_FALSE; 555185377Ssam } else { 556185377Ssam /* convert to system clocks */ 557185377Ssam OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 558185377Ssam AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); 559185377Ssam ahp->ah_ctstimeout = us; 560185377Ssam return AH_TRUE; 561185377Ssam } 562185377Ssam} 563185377Ssam 564185377Ssamu_int 565185377Ssamar5212GetCTSTimeout(struct ath_hal *ah) 566185377Ssam{ 567185377Ssam u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); 568185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 569185377Ssam} 570185377Ssam 571185377Ssam/* Setup decompression for given key index */ 572185377SsamHAL_BOOL 573185377Ssamar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 574185377Ssam{ 575185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 576185377Ssam 577185377Ssam if (keyidx >= HAL_DECOMP_MASK_SIZE) 578185377Ssam return HAL_EINVAL; 579185377Ssam OS_REG_WRITE(ah, AR_DCM_A, keyidx); 580185377Ssam OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0); 581185377Ssam ahp->ah_decompMask[keyidx] = en; 582185377Ssam 583185377Ssam return AH_TRUE; 584185377Ssam} 585185377Ssam 586185377Ssam/* Setup coverage class */ 587185377Ssamvoid 588185377Ssamar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 589185377Ssam{ 590185377Ssam uint32_t slot, timeout, eifs; 591185377Ssam u_int clkRate; 592185377Ssam 593185377Ssam AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 594185377Ssam 595185377Ssam if (now) { 596185377Ssam if (AH_PRIVATE(ah)->ah_coverageClass == 0) 597185377Ssam return; 598185377Ssam 599185377Ssam /* Don't apply coverage class to non A channels */ 600187831Ssam if (!IEEE80211_IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan)) 601185377Ssam return; 602185377Ssam 603185377Ssam /* Get core clock rate */ 604185377Ssam clkRate = ath_hal_mac_clks(ah, 1); 605185377Ssam 606185377Ssam /* Compute EIFS */ 607185377Ssam slot = coverageclass * 3 * clkRate; 608185377Ssam eifs = coverageclass * 6 * clkRate; 609187831Ssam if (IEEE80211_IS_CHAN_HALF(AH_PRIVATE(ah)->ah_curchan)) { 610185377Ssam slot += IFS_SLOT_HALF_RATE; 611185377Ssam eifs += IFS_EIFS_HALF_RATE; 612187831Ssam } else if (IEEE80211_IS_CHAN_QUARTER(AH_PRIVATE(ah)->ah_curchan)) { 613185377Ssam slot += IFS_SLOT_QUARTER_RATE; 614185377Ssam eifs += IFS_EIFS_QUARTER_RATE; 615185377Ssam } else { /* full rate */ 616185377Ssam slot += IFS_SLOT_FULL_RATE; 617185377Ssam eifs += IFS_EIFS_FULL_RATE; 618185377Ssam } 619185377Ssam 620185377Ssam /* 621185377Ssam * Add additional time for air propagation for ACK and CTS 622185377Ssam * timeouts. This value is in core clocks. 623185377Ssam */ 624185377Ssam timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate); 625185377Ssam 626185377Ssam /* 627185377Ssam * Write the values: slot, eifs, ack/cts timeouts. 628185377Ssam */ 629185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); 630185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); 631185377Ssam OS_REG_WRITE(ah, AR_TIME_OUT, 632185377Ssam SM(timeout, AR_TIME_OUT_CTS) 633185377Ssam | SM(timeout, AR_TIME_OUT_ACK)); 634185377Ssam } 635185377Ssam} 636185377Ssam 637185377Ssamvoid 638185377Ssamar5212SetPCUConfig(struct ath_hal *ah) 639185377Ssam{ 640185377Ssam ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); 641185377Ssam} 642185377Ssam 643185377Ssam/* 644185377Ssam * Return whether an external 32KHz crystal should be used 645185377Ssam * to reduce power consumption when sleeping. We do so if 646185377Ssam * the crystal is present (obtained from EEPROM) and if we 647185377Ssam * are not running as an AP and are configured to use it. 648185377Ssam */ 649185377SsamHAL_BOOL 650185377Ssamar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode) 651185377Ssam{ 652185377Ssam if (opmode != HAL_M_HOSTAP) { 653185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 654185377Ssam return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) && 655185377Ssam (ahp->ah_enable32kHzClock == USE_32KHZ || 656185377Ssam ahp->ah_enable32kHzClock == AUTO_32KHZ); 657185377Ssam } else 658185377Ssam return AH_FALSE; 659185377Ssam} 660185377Ssam 661185377Ssam/* 662185377Ssam * If 32KHz clock exists, use it to lower power consumption during sleep 663185377Ssam * 664185377Ssam * Note: If clock is set to 32 KHz, delays on accessing certain 665185377Ssam * baseband registers (27-31, 124-127) are required. 666185377Ssam */ 667185377Ssamvoid 668185377Ssamar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) 669185377Ssam{ 670185377Ssam if (ar5212Use32KHzclock(ah, opmode)) { 671185377Ssam /* 672185377Ssam * Enable clocks to be turned OFF in BB during sleep 673185377Ssam * and also enable turning OFF 32MHz/40MHz Refclk 674185377Ssam * from A2. 675185377Ssam */ 676185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 677185380Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 678185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 679185377Ssam OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); 680185377Ssam OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ 681185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1); 682185377Ssam 683185377Ssam if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) { 684185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26); 685185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d); 686185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07); 687185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f); 688185377Ssam /* # Set sleep clock rate to 32 KHz. */ 689185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2); 690185377Ssam } else { 691185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a); 692185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); 693185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); 694185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20); 695185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3); 696185377Ssam } 697185377Ssam } else { 698185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0); 699185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 700185377Ssam 701185377Ssam OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */ 702185377Ssam 703185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 704185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 705185377Ssam 706185377Ssam if (IS_2417(ah)) 707185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a); 708185377Ssam else if (IS_HB63(ah)) 709185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32); 710185377Ssam else 711185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 712185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 713185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 714185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 715185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18); 716185380Ssam OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 717185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 718185377Ssam } 719185377Ssam} 720185377Ssam 721185377Ssam/* 722185377Ssam * If 32KHz clock exists, turn it off and turn back on the 32Mhz 723185377Ssam */ 724185377Ssamvoid 725185377Ssamar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) 726185377Ssam{ 727185377Ssam if (ar5212Use32KHzclock(ah, opmode)) { 728185377Ssam /* # Set sleep clock rate back to 32 MHz. */ 729185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0); 730185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 731185377Ssam 732185377Ssam OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ 733185380Ssam OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 734185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 735185377Ssam 736185377Ssam /* 737185377Ssam * Restore BB registers to power-on defaults 738185377Ssam */ 739185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 740185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 741185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 742185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 743185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 744185380Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 745185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 746185377Ssam } 747185377Ssam} 748185377Ssam 749185377Ssam/* 750185377Ssam * Adjust NF based on statistical values for 5GHz frequencies. 751185377Ssam * Default method: this may be overridden by the rf backend. 752185377Ssam */ 753185377Ssamint16_t 754185377Ssamar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 755185377Ssam{ 756185377Ssam static const struct { 757185377Ssam uint16_t freqLow; 758185377Ssam int16_t adjust; 759185377Ssam } adjustDef[] = { 760185377Ssam { 5790, 11 }, /* NB: ordered high -> low */ 761185377Ssam { 5730, 10 }, 762185377Ssam { 5690, 9 }, 763185377Ssam { 5660, 8 }, 764185377Ssam { 5610, 7 }, 765185377Ssam { 5530, 5 }, 766185377Ssam { 5450, 4 }, 767185377Ssam { 5379, 2 }, 768185377Ssam { 5209, 0 }, 769185377Ssam { 3000, 1 }, 770185377Ssam { 0, 0 }, 771185377Ssam }; 772185377Ssam int i; 773185377Ssam 774185377Ssam for (i = 0; c->channel <= adjustDef[i].freqLow; i++) 775185377Ssam ; 776185377Ssam return adjustDef[i].adjust; 777185377Ssam} 778185377Ssam 779185377SsamHAL_STATUS 780185377Ssamar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 781185377Ssam uint32_t capability, uint32_t *result) 782185377Ssam{ 783185377Ssam#define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion 784185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 785185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 786185377Ssam const struct ar5212AniState *ani; 787185377Ssam 788185377Ssam switch (type) { 789185377Ssam case HAL_CAP_CIPHER: /* cipher handled in hardware */ 790185377Ssam switch (capability) { 791185377Ssam case HAL_CIPHER_AES_CCM: 792185377Ssam return pCap->halCipherAesCcmSupport ? 793185377Ssam HAL_OK : HAL_ENOTSUPP; 794185377Ssam case HAL_CIPHER_AES_OCB: 795185377Ssam case HAL_CIPHER_TKIP: 796185377Ssam case HAL_CIPHER_WEP: 797185377Ssam case HAL_CIPHER_MIC: 798185377Ssam case HAL_CIPHER_CLR: 799185377Ssam return HAL_OK; 800185377Ssam default: 801185377Ssam return HAL_ENOTSUPP; 802185377Ssam } 803185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 804185377Ssam switch (capability) { 805185377Ssam case 0: /* hardware capability */ 806185377Ssam return HAL_OK; 807185377Ssam case 1: 808185377Ssam return (ahp->ah_staId1Defaults & 809185377Ssam AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO; 810185377Ssam } 811185907Ssam return HAL_EINVAL; 812185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 813185377Ssam switch (capability) { 814185377Ssam case 0: /* hardware capability */ 815185377Ssam return pCap->halTkipMicTxRxKeySupport ? 816185377Ssam HAL_ENXIO : HAL_OK; 817185377Ssam case 1: /* current setting */ 818185377Ssam return (ahp->ah_miscMode & 819185377Ssam AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; 820185377Ssam } 821185377Ssam return HAL_EINVAL; 822185377Ssam case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ 823185377Ssam /* XXX move to capability bit */ 824185377Ssam return MACVERSION(ah) > AR_SREV_VERSION_VENICE || 825185377Ssam (MACVERSION(ah) == AR_SREV_VERSION_VENICE && 826185377Ssam AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; 827185377Ssam case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 828185377Ssam switch (capability) { 829185377Ssam case 0: /* hardware capability */ 830185377Ssam return HAL_OK; 831185377Ssam case 1: /* current setting */ 832185380Ssam return ahp->ah_diversity ? HAL_OK : HAL_ENXIO; 833185377Ssam } 834185377Ssam return HAL_EINVAL; 835185377Ssam case HAL_CAP_DIAG: 836185377Ssam *result = AH_PRIVATE(ah)->ah_diagreg; 837185377Ssam return HAL_OK; 838185377Ssam case HAL_CAP_TPC: 839185377Ssam switch (capability) { 840185377Ssam case 0: /* hardware capability */ 841185377Ssam return HAL_OK; 842185377Ssam case 1: 843185377Ssam return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; 844185377Ssam } 845185377Ssam return HAL_OK; 846185377Ssam case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ 847185377Ssam switch (capability) { 848185377Ssam case HAL_CAP_RADAR: 849185377Ssam return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? 850185377Ssam HAL_OK: HAL_ENXIO; 851185377Ssam case HAL_CAP_AR: 852185377Ssam return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || 853185377Ssam ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? 854185377Ssam HAL_OK: HAL_ENXIO; 855185377Ssam } 856185377Ssam return HAL_ENXIO; 857185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 858185377Ssam switch (capability) { 859185377Ssam case 0: /* hardware capability */ 860222027Sadrian return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENXIO; 861185377Ssam case 1: 862185377Ssam return (ahp->ah_staId1Defaults & 863185377Ssam AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; 864185377Ssam } 865185377Ssam return HAL_EINVAL; 866185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 867185377Ssam switch (capability) { 868185377Ssam case 0: /* hardware capability */ 869185377Ssam return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; 870185377Ssam case 1: 871185377Ssam return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? 872185377Ssam HAL_OK : HAL_ENXIO; 873185377Ssam } 874185377Ssam return HAL_EINVAL; 875185377Ssam case HAL_CAP_TPC_ACK: 876185377Ssam *result = MS(ahp->ah_macTPC, AR_TPC_ACK); 877185377Ssam return HAL_OK; 878185377Ssam case HAL_CAP_TPC_CTS: 879185377Ssam *result = MS(ahp->ah_macTPC, AR_TPC_CTS); 880185377Ssam return HAL_OK; 881185377Ssam case HAL_CAP_INTMIT: /* interference mitigation */ 882185377Ssam switch (capability) { 883185377Ssam case 0: /* hardware capability */ 884185377Ssam return HAL_OK; 885185377Ssam case 1: 886185377Ssam return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? 887185377Ssam HAL_OK : HAL_ENXIO; 888185377Ssam case 2: /* HAL_ANI_NOISE_IMMUNITY_LEVEL */ 889185377Ssam case 3: /* HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION */ 890185377Ssam case 4: /* HAL_ANI_CCK_WEAK_SIGNAL_THR */ 891185377Ssam case 5: /* HAL_ANI_FIRSTEP_LEVEL */ 892185377Ssam case 6: /* HAL_ANI_SPUR_IMMUNITY_LEVEL */ 893185377Ssam ani = ar5212AniGetCurrentState(ah); 894185377Ssam if (ani == AH_NULL) 895185377Ssam return HAL_ENXIO; 896185377Ssam switch (capability) { 897185377Ssam case 2: *result = ani->noiseImmunityLevel; break; 898185377Ssam case 3: *result = !ani->ofdmWeakSigDetectOff; break; 899185377Ssam case 4: *result = ani->cckWeakSigThreshold; break; 900185377Ssam case 5: *result = ani->firstepLevel; break; 901185377Ssam case 6: *result = ani->spurImmunityLevel; break; 902185377Ssam } 903185377Ssam return HAL_OK; 904185377Ssam } 905185377Ssam return HAL_EINVAL; 906185377Ssam default: 907185377Ssam return ath_hal_getcapability(ah, type, capability, result); 908185377Ssam } 909185377Ssam#undef MACVERSION 910185377Ssam} 911185377Ssam 912185377SsamHAL_BOOL 913185377Ssamar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 914185377Ssam uint32_t capability, uint32_t setting, HAL_STATUS *status) 915185377Ssam{ 916185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 917185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 918185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 919185377Ssam uint32_t v; 920185377Ssam 921185377Ssam switch (type) { 922185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 923185377Ssam if (setting) 924185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; 925185377Ssam else 926185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; 927185377Ssam return AH_TRUE; 928185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 929185377Ssam if (!pCap->halTkipMicTxRxKeySupport) 930185377Ssam return AH_FALSE; 931185377Ssam /* NB: true =>'s use split key cache layout */ 932185377Ssam if (setting) 933185377Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 934185377Ssam else 935185377Ssam ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 936185377Ssam /* NB: write here so keys can be setup w/o a reset */ 937219771Sadrian OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); 938185377Ssam return AH_TRUE; 939185377Ssam case HAL_CAP_DIVERSITY: 940185380Ssam if (ahp->ah_phyPowerOn) { 941185380Ssam v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 942185380Ssam if (setting) 943185380Ssam v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 944185380Ssam else 945185380Ssam v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 946185380Ssam OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); 947185380Ssam } 948185380Ssam ahp->ah_diversity = (setting != 0); 949185377Ssam return AH_TRUE; 950185377Ssam case HAL_CAP_DIAG: /* hardware diagnostic support */ 951185377Ssam /* 952185377Ssam * NB: could split this up into virtual capabilities, 953185377Ssam * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly 954185377Ssam * seems worth the additional complexity. 955185377Ssam */ 956185377Ssam AH_PRIVATE(ah)->ah_diagreg = setting; 957185377Ssam OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 958185377Ssam return AH_TRUE; 959185377Ssam case HAL_CAP_TPC: 960185377Ssam ahp->ah_tpcEnabled = (setting != 0); 961185377Ssam return AH_TRUE; 962185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 963185377Ssam if (setting) 964185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; 965185377Ssam else 966185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; 967185377Ssam return AH_TRUE; 968185377Ssam case HAL_CAP_TPC_ACK: 969185377Ssam case HAL_CAP_TPC_CTS: 970185377Ssam setting += ahp->ah_txPowerIndexOffset; 971185377Ssam if (setting > 63) 972185377Ssam setting = 63; 973185377Ssam if (type == HAL_CAP_TPC_ACK) { 974185377Ssam ahp->ah_macTPC &= AR_TPC_ACK; 975185377Ssam ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); 976185377Ssam } else { 977185377Ssam ahp->ah_macTPC &= AR_TPC_CTS; 978185377Ssam ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); 979185377Ssam } 980185377Ssam OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); 981185377Ssam return AH_TRUE; 982185377Ssam case HAL_CAP_INTMIT: { /* interference mitigation */ 983185377Ssam static const HAL_ANI_CMD cmds[] = { 984185377Ssam HAL_ANI_PRESENT, 985185377Ssam HAL_ANI_MODE, 986185377Ssam HAL_ANI_NOISE_IMMUNITY_LEVEL, 987185377Ssam HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 988185377Ssam HAL_ANI_CCK_WEAK_SIGNAL_THR, 989185377Ssam HAL_ANI_FIRSTEP_LEVEL, 990185377Ssam HAL_ANI_SPUR_IMMUNITY_LEVEL, 991185377Ssam }; 992185377Ssam return capability < N(cmds) ? 993185377Ssam ar5212AniControl(ah, cmds[capability], setting) : 994185377Ssam AH_FALSE; 995185377Ssam } 996185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 997185377Ssam if (pCap->halTsfAddSupport) { 998185377Ssam if (setting) 999185377Ssam ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; 1000185377Ssam else 1001185377Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; 1002185377Ssam return AH_TRUE; 1003185377Ssam } 1004185377Ssam /* fall thru... */ 1005185377Ssam default: 1006185377Ssam return ath_hal_setcapability(ah, type, capability, 1007185377Ssam setting, status); 1008185377Ssam } 1009185377Ssam#undef N 1010185377Ssam} 1011185377Ssam 1012185377SsamHAL_BOOL 1013185377Ssamar5212GetDiagState(struct ath_hal *ah, int request, 1014185377Ssam const void *args, uint32_t argsize, 1015185377Ssam void **result, uint32_t *resultsize) 1016185377Ssam{ 1017185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 1018185377Ssam 1019185377Ssam (void) ahp; 1020185377Ssam if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 1021185377Ssam return AH_TRUE; 1022185377Ssam switch (request) { 1023185377Ssam case HAL_DIAG_EEPROM: 1024185377Ssam case HAL_DIAG_EEPROM_EXP_11A: 1025185377Ssam case HAL_DIAG_EEPROM_EXP_11B: 1026185377Ssam case HAL_DIAG_EEPROM_EXP_11G: 1027185377Ssam case HAL_DIAG_RFGAIN: 1028185377Ssam return ath_hal_eepromDiag(ah, request, 1029185377Ssam args, argsize, result, resultsize); 1030185377Ssam case HAL_DIAG_RFGAIN_CURSTEP: 1031185377Ssam *result = __DECONST(void *, ahp->ah_gainValues.currStep); 1032185377Ssam *resultsize = (*result == AH_NULL) ? 1033185377Ssam 0 : sizeof(GAIN_OPTIMIZATION_STEP); 1034185377Ssam return AH_TRUE; 1035185377Ssam case HAL_DIAG_PCDAC: 1036185377Ssam *result = ahp->ah_pcdacTable; 1037185377Ssam *resultsize = ahp->ah_pcdacTableSize; 1038185377Ssam return AH_TRUE; 1039185377Ssam case HAL_DIAG_TXRATES: 1040185377Ssam *result = &ahp->ah_ratesArray[0]; 1041185377Ssam *resultsize = sizeof(ahp->ah_ratesArray); 1042185377Ssam return AH_TRUE; 1043185377Ssam case HAL_DIAG_ANI_CURRENT: 1044185377Ssam *result = ar5212AniGetCurrentState(ah); 1045185377Ssam *resultsize = (*result == AH_NULL) ? 1046185377Ssam 0 : sizeof(struct ar5212AniState); 1047185377Ssam return AH_TRUE; 1048185377Ssam case HAL_DIAG_ANI_STATS: 1049185377Ssam *result = ar5212AniGetCurrentStats(ah); 1050185377Ssam *resultsize = (*result == AH_NULL) ? 1051185377Ssam 0 : sizeof(struct ar5212Stats); 1052185377Ssam return AH_TRUE; 1053185377Ssam case HAL_DIAG_ANI_CMD: 1054185377Ssam if (argsize != 2*sizeof(uint32_t)) 1055185377Ssam return AH_FALSE; 1056185377Ssam ar5212AniControl(ah, ((const uint32_t *)args)[0], 1057185377Ssam ((const uint32_t *)args)[1]); 1058185377Ssam return AH_TRUE; 1059185377Ssam case HAL_DIAG_ANI_PARAMS: 1060185377Ssam /* 1061185377Ssam * NB: We assume struct ar5212AniParams is identical 1062185377Ssam * to HAL_ANI_PARAMS; if they diverge then we'll need 1063185377Ssam * to handle it here 1064185377Ssam */ 1065185377Ssam if (argsize == 0 && args == AH_NULL) { 1066185377Ssam struct ar5212AniState *aniState = 1067185377Ssam ar5212AniGetCurrentState(ah); 1068185377Ssam if (aniState == AH_NULL) 1069185377Ssam return AH_FALSE; 1070185377Ssam *result = __DECONST(void *, aniState->params); 1071185377Ssam *resultsize = sizeof(struct ar5212AniParams); 1072185377Ssam return AH_TRUE; 1073185377Ssam } else { 1074185377Ssam if (argsize != sizeof(struct ar5212AniParams)) 1075185377Ssam return AH_FALSE; 1076185377Ssam return ar5212AniSetParams(ah, args, args); 1077185377Ssam } 1078185377Ssam } 1079185377Ssam return AH_FALSE; 1080185377Ssam} 1081211206Sadrian 1082211206Sadrian/* 1083211206Sadrian * Check whether there's an in-progress NF completion. 1084211206Sadrian * 1085211206Sadrian * Returns AH_TRUE if there's a in-progress NF calibration, AH_FALSE 1086211206Sadrian * otherwise. 1087211206Sadrian */ 1088211206SadrianHAL_BOOL 1089211206Sadrianar5212IsNFCalInProgress(struct ath_hal *ah) 1090211206Sadrian{ 1091211206Sadrian if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) 1092211206Sadrian return AH_TRUE; 1093211206Sadrian return AH_FALSE; 1094211206Sadrian} 1095211206Sadrian 1096211206Sadrian/* 1097211206Sadrian * Wait for an in-progress NF calibration to complete. 1098211206Sadrian * 1099211206Sadrian * The completion function waits "i" times 10uS. 1100211206Sadrian * It returns AH_TRUE if the NF calibration completed (or was never 1101211206Sadrian * in progress); AH_FALSE if it was still in progress after "i" checks. 1102211206Sadrian */ 1103211206SadrianHAL_BOOL 1104211206Sadrianar5212WaitNFCalComplete(struct ath_hal *ah, int i) 1105211206Sadrian{ 1106211206Sadrian int j; 1107211206Sadrian if (i <= 0) 1108211206Sadrian i = 1; /* it should run at least once */ 1109211206Sadrian for (j = 0; j < i; j++) { 1110211206Sadrian if (! ar5212IsNFCalInProgress(ah)) 1111211206Sadrian return AH_TRUE; 1112211206Sadrian OS_DELAY(10); 1113211206Sadrian } 1114211206Sadrian return AH_FALSE; 1115211206Sadrian} 1116