ar5212_misc.c revision 187831
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 187831 2009-01-28 18:00:22Z sam $ 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 267185377Ssam/* 268185377Ssam * Reset the current hardware tsf for stamlme. 269185377Ssam */ 270185377Ssamvoid 271185377Ssamar5212ResetTsf(struct ath_hal *ah) 272185377Ssam{ 273185377Ssam 274185377Ssam uint32_t val = OS_REG_READ(ah, AR_BEACON); 275185377Ssam 276185377Ssam OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 277185377Ssam /* 278185377Ssam * When resetting the TSF, write twice to the 279185377Ssam * corresponding register; each write to the RESET_TSF bit toggles 280185377Ssam * the internal signal to cause a reset of the TSF - but if the signal 281185377Ssam * is left high, it will reset the TSF on the next chip reset also! 282185377Ssam * writing the bit an even number of times fixes this issue 283185377Ssam */ 284185377Ssam OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 285185377Ssam} 286185377Ssam 287185377Ssam/* 288185377Ssam * Set or clear hardware basic rate bit 289185377Ssam * Set hardware basic rate set if basic rate is found 290185377Ssam * and basic rate is equal or less than 2Mbps 291185377Ssam */ 292185377Ssamvoid 293185377Ssamar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs) 294185377Ssam{ 295187831Ssam const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 296185377Ssam uint32_t reg; 297185377Ssam uint8_t xset; 298185377Ssam int i; 299185377Ssam 300187831Ssam if (chan == AH_NULL || !IEEE80211_IS_CHAN_CCK(chan)) 301185377Ssam return; 302185377Ssam xset = 0; 303185377Ssam for (i = 0; i < rs->rs_count; i++) { 304185377Ssam uint8_t rset = rs->rs_rates[i]; 305185377Ssam /* Basic rate defined? */ 306185377Ssam if ((rset & 0x80) && (rset &= 0x7f) >= xset) 307185377Ssam xset = rset; 308185377Ssam } 309185377Ssam /* 310185377Ssam * Set the h/w bit to reflect whether or not the basic 311185377Ssam * rate is found to be equal or less than 2Mbps. 312185377Ssam */ 313185377Ssam reg = OS_REG_READ(ah, AR_STA_ID1); 314185377Ssam if (xset && xset/2 <= 2) 315185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B); 316185377Ssam else 317185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B); 318185377Ssam} 319185377Ssam 320185377Ssam/* 321185377Ssam * Grab a semi-random value from hardware registers - may not 322185377Ssam * change often 323185377Ssam */ 324185377Ssamuint32_t 325185377Ssamar5212GetRandomSeed(struct ath_hal *ah) 326185377Ssam{ 327185377Ssam uint32_t nf; 328185377Ssam 329185377Ssam nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; 330185377Ssam if (nf & 0x100) 331185377Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 332185377Ssam return (OS_REG_READ(ah, AR_TSF_U32) ^ 333185377Ssam OS_REG_READ(ah, AR_TSF_L32) ^ nf); 334185377Ssam} 335185377Ssam 336185377Ssam/* 337185377Ssam * Detect if our card is present 338185377Ssam */ 339185377SsamHAL_BOOL 340185377Ssamar5212DetectCardPresent(struct ath_hal *ah) 341185377Ssam{ 342185377Ssam uint16_t macVersion, macRev; 343185377Ssam uint32_t v; 344185377Ssam 345185377Ssam /* 346185377Ssam * Read the Silicon Revision register and compare that 347185377Ssam * to what we read at attach time. If the same, we say 348185377Ssam * a card/device is present. 349185377Ssam */ 350185377Ssam v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; 351185377Ssam macVersion = v >> AR_SREV_ID_S; 352185377Ssam macRev = v & AR_SREV_REVISION; 353185377Ssam return (AH_PRIVATE(ah)->ah_macVersion == macVersion && 354185377Ssam AH_PRIVATE(ah)->ah_macRev == macRev); 355185377Ssam} 356185377Ssam 357185377Ssamvoid 358185377Ssamar5212EnableMibCounters(struct ath_hal *ah) 359185377Ssam{ 360185377Ssam /* NB: this just resets the mib counter machinery */ 361185377Ssam OS_REG_WRITE(ah, AR_MIBC, 362185377Ssam ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 363185377Ssam} 364185377Ssam 365185377Ssamvoid 366185377Ssamar5212DisableMibCounters(struct ath_hal *ah) 367185377Ssam{ 368185377Ssam OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC); 369185377Ssam} 370185377Ssam 371185377Ssam/* 372185377Ssam * Update MIB Counters 373185377Ssam */ 374185377Ssamvoid 375185377Ssamar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats) 376185377Ssam{ 377185377Ssam stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); 378185377Ssam stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); 379185377Ssam stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); 380185377Ssam stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); 381185377Ssam stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); 382185377Ssam} 383185377Ssam 384185377Ssam/* 385185377Ssam * Detect if the HW supports spreading a CCK signal on channel 14 386185377Ssam */ 387185377SsamHAL_BOOL 388185377Ssamar5212IsJapanChannelSpreadSupported(struct ath_hal *ah) 389185377Ssam{ 390185377Ssam return AH_TRUE; 391185377Ssam} 392185377Ssam 393185377Ssam/* 394185377Ssam * Get the rssi of frame curently being received. 395185377Ssam */ 396185377Ssamuint32_t 397185377Ssamar5212GetCurRssi(struct ath_hal *ah) 398185377Ssam{ 399185377Ssam return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); 400185377Ssam} 401185377Ssam 402185377Ssamu_int 403185377Ssamar5212GetDefAntenna(struct ath_hal *ah) 404185377Ssam{ 405185377Ssam return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); 406185377Ssam} 407185377Ssam 408185377Ssamvoid 409185377Ssamar5212SetDefAntenna(struct ath_hal *ah, u_int antenna) 410185377Ssam{ 411185377Ssam OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); 412185377Ssam} 413185377Ssam 414185377SsamHAL_ANT_SETTING 415185377Ssamar5212GetAntennaSwitch(struct ath_hal *ah) 416185377Ssam{ 417185380Ssam return AH5212(ah)->ah_antControl; 418185377Ssam} 419185377Ssam 420185377SsamHAL_BOOL 421185380Ssamar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting) 422185377Ssam{ 423185380Ssam struct ath_hal_5212 *ahp = AH5212(ah); 424187831Ssam const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 425185377Ssam 426187831Ssam if (!ahp->ah_phyPowerOn || chan == AH_NULL) { 427185380Ssam /* PHY powered off, just stash settings */ 428185380Ssam ahp->ah_antControl = setting; 429185380Ssam ahp->ah_diversity = (setting == HAL_ANT_VARIABLE); 430185377Ssam return AH_TRUE; 431185377Ssam } 432187831Ssam return ar5212SetAntennaSwitchInternal(ah, setting, chan); 433185377Ssam} 434185377Ssam 435185377SsamHAL_BOOL 436185377Ssamar5212IsSleepAfterBeaconBroken(struct ath_hal *ah) 437185377Ssam{ 438185377Ssam return AH_TRUE; 439185377Ssam} 440185377Ssam 441185377SsamHAL_BOOL 442185377Ssamar5212SetSifsTime(struct ath_hal *ah, u_int us) 443185377Ssam{ 444185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 445185377Ssam 446185377Ssam if (us > ath_hal_mac_usec(ah, 0xffff)) { 447185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", 448185377Ssam __func__, us); 449185377Ssam ahp->ah_sifstime = (u_int) -1; /* restore default handling */ 450185377Ssam return AH_FALSE; 451185377Ssam } else { 452185377Ssam /* convert to system clocks */ 453185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us)); 454187831Ssam ahp->ah_slottime = us; 455185377Ssam return AH_TRUE; 456185377Ssam } 457185377Ssam} 458185377Ssam 459185377Ssamu_int 460185377Ssamar5212GetSifsTime(struct ath_hal *ah) 461185377Ssam{ 462185377Ssam u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; 463185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 464185377Ssam} 465185377Ssam 466185377SsamHAL_BOOL 467185377Ssamar5212SetSlotTime(struct ath_hal *ah, u_int us) 468185377Ssam{ 469185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 470185377Ssam 471185377Ssam if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) { 472185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", 473185377Ssam __func__, us); 474185377Ssam ahp->ah_slottime = (u_int) -1; /* restore default handling */ 475185377Ssam return AH_FALSE; 476185377Ssam } else { 477185377Ssam /* convert to system clocks */ 478185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); 479185377Ssam ahp->ah_slottime = us; 480185377Ssam return AH_TRUE; 481185377Ssam } 482185377Ssam} 483185377Ssam 484185377Ssamu_int 485185377Ssamar5212GetSlotTime(struct ath_hal *ah) 486185377Ssam{ 487185377Ssam u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; 488185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 489185377Ssam} 490185377Ssam 491185377SsamHAL_BOOL 492185377Ssamar5212SetAckTimeout(struct ath_hal *ah, u_int us) 493185377Ssam{ 494185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 495185377Ssam 496185377Ssam if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { 497185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", 498185377Ssam __func__, us); 499185377Ssam ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ 500185377Ssam return AH_FALSE; 501185377Ssam } else { 502185377Ssam /* convert to system clocks */ 503185377Ssam OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 504185377Ssam AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); 505185377Ssam ahp->ah_acktimeout = us; 506185377Ssam return AH_TRUE; 507185377Ssam } 508185377Ssam} 509185377Ssam 510185377Ssamu_int 511185377Ssamar5212GetAckTimeout(struct ath_hal *ah) 512185377Ssam{ 513185377Ssam u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); 514185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 515185377Ssam} 516185377Ssam 517185377Ssamu_int 518185377Ssamar5212GetAckCTSRate(struct ath_hal *ah) 519185377Ssam{ 520185377Ssam return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); 521185377Ssam} 522185377Ssam 523185377SsamHAL_BOOL 524185377Ssamar5212SetAckCTSRate(struct ath_hal *ah, u_int high) 525185377Ssam{ 526185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 527185377Ssam 528185377Ssam if (high) { 529185377Ssam OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 530185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; 531185377Ssam } else { 532185377Ssam OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 533185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; 534185377Ssam } 535185377Ssam return AH_TRUE; 536185377Ssam} 537185377Ssam 538185377SsamHAL_BOOL 539185377Ssamar5212SetCTSTimeout(struct ath_hal *ah, u_int us) 540185377Ssam{ 541185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 542185377Ssam 543185377Ssam if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { 544185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", 545185377Ssam __func__, us); 546185377Ssam ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ 547185377Ssam return AH_FALSE; 548185377Ssam } else { 549185377Ssam /* convert to system clocks */ 550185377Ssam OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 551185377Ssam AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); 552185377Ssam ahp->ah_ctstimeout = us; 553185377Ssam return AH_TRUE; 554185377Ssam } 555185377Ssam} 556185377Ssam 557185377Ssamu_int 558185377Ssamar5212GetCTSTimeout(struct ath_hal *ah) 559185377Ssam{ 560185377Ssam u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); 561185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 562185377Ssam} 563185377Ssam 564185377Ssam/* Setup decompression for given key index */ 565185377SsamHAL_BOOL 566185377Ssamar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 567185377Ssam{ 568185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 569185377Ssam 570185377Ssam if (keyidx >= HAL_DECOMP_MASK_SIZE) 571185377Ssam return HAL_EINVAL; 572185377Ssam OS_REG_WRITE(ah, AR_DCM_A, keyidx); 573185377Ssam OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0); 574185377Ssam ahp->ah_decompMask[keyidx] = en; 575185377Ssam 576185377Ssam return AH_TRUE; 577185377Ssam} 578185377Ssam 579185377Ssam/* Setup coverage class */ 580185377Ssamvoid 581185377Ssamar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 582185377Ssam{ 583185377Ssam uint32_t slot, timeout, eifs; 584185377Ssam u_int clkRate; 585185377Ssam 586185377Ssam AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 587185377Ssam 588185377Ssam if (now) { 589185377Ssam if (AH_PRIVATE(ah)->ah_coverageClass == 0) 590185377Ssam return; 591185377Ssam 592185377Ssam /* Don't apply coverage class to non A channels */ 593187831Ssam if (!IEEE80211_IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan)) 594185377Ssam return; 595185377Ssam 596185377Ssam /* Get core clock rate */ 597185377Ssam clkRate = ath_hal_mac_clks(ah, 1); 598185377Ssam 599185377Ssam /* Compute EIFS */ 600185377Ssam slot = coverageclass * 3 * clkRate; 601185377Ssam eifs = coverageclass * 6 * clkRate; 602187831Ssam if (IEEE80211_IS_CHAN_HALF(AH_PRIVATE(ah)->ah_curchan)) { 603185377Ssam slot += IFS_SLOT_HALF_RATE; 604185377Ssam eifs += IFS_EIFS_HALF_RATE; 605187831Ssam } else if (IEEE80211_IS_CHAN_QUARTER(AH_PRIVATE(ah)->ah_curchan)) { 606185377Ssam slot += IFS_SLOT_QUARTER_RATE; 607185377Ssam eifs += IFS_EIFS_QUARTER_RATE; 608185377Ssam } else { /* full rate */ 609185377Ssam slot += IFS_SLOT_FULL_RATE; 610185377Ssam eifs += IFS_EIFS_FULL_RATE; 611185377Ssam } 612185377Ssam 613185377Ssam /* 614185377Ssam * Add additional time for air propagation for ACK and CTS 615185377Ssam * timeouts. This value is in core clocks. 616185377Ssam */ 617185377Ssam timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate); 618185377Ssam 619185377Ssam /* 620185377Ssam * Write the values: slot, eifs, ack/cts timeouts. 621185377Ssam */ 622185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); 623185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); 624185377Ssam OS_REG_WRITE(ah, AR_TIME_OUT, 625185377Ssam SM(timeout, AR_TIME_OUT_CTS) 626185377Ssam | SM(timeout, AR_TIME_OUT_ACK)); 627185377Ssam } 628185377Ssam} 629185377Ssam 630185377Ssamvoid 631185377Ssamar5212SetPCUConfig(struct ath_hal *ah) 632185377Ssam{ 633185377Ssam ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); 634185377Ssam} 635185377Ssam 636185377Ssam/* 637185377Ssam * Return whether an external 32KHz crystal should be used 638185377Ssam * to reduce power consumption when sleeping. We do so if 639185377Ssam * the crystal is present (obtained from EEPROM) and if we 640185377Ssam * are not running as an AP and are configured to use it. 641185377Ssam */ 642185377SsamHAL_BOOL 643185377Ssamar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode) 644185377Ssam{ 645185377Ssam if (opmode != HAL_M_HOSTAP) { 646185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 647185377Ssam return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) && 648185377Ssam (ahp->ah_enable32kHzClock == USE_32KHZ || 649185377Ssam ahp->ah_enable32kHzClock == AUTO_32KHZ); 650185377Ssam } else 651185377Ssam return AH_FALSE; 652185377Ssam} 653185377Ssam 654185377Ssam/* 655185377Ssam * If 32KHz clock exists, use it to lower power consumption during sleep 656185377Ssam * 657185377Ssam * Note: If clock is set to 32 KHz, delays on accessing certain 658185377Ssam * baseband registers (27-31, 124-127) are required. 659185377Ssam */ 660185377Ssamvoid 661185377Ssamar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) 662185377Ssam{ 663185377Ssam if (ar5212Use32KHzclock(ah, opmode)) { 664185377Ssam /* 665185377Ssam * Enable clocks to be turned OFF in BB during sleep 666185377Ssam * and also enable turning OFF 32MHz/40MHz Refclk 667185377Ssam * from A2. 668185377Ssam */ 669185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 670185380Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 671185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 672185377Ssam OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); 673185377Ssam OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ 674185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1); 675185377Ssam 676185377Ssam if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) { 677185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26); 678185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d); 679185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07); 680185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f); 681185377Ssam /* # Set sleep clock rate to 32 KHz. */ 682185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2); 683185377Ssam } else { 684185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a); 685185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); 686185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); 687185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20); 688185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3); 689185377Ssam } 690185377Ssam } else { 691185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0); 692185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 693185377Ssam 694185377Ssam OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */ 695185377Ssam 696185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 697185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 698185377Ssam 699185377Ssam if (IS_2417(ah)) 700185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a); 701185377Ssam else if (IS_HB63(ah)) 702185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32); 703185377Ssam else 704185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 705185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 706185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 707185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 708185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18); 709185380Ssam OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 710185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 711185377Ssam } 712185377Ssam} 713185377Ssam 714185377Ssam/* 715185377Ssam * If 32KHz clock exists, turn it off and turn back on the 32Mhz 716185377Ssam */ 717185377Ssamvoid 718185377Ssamar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) 719185377Ssam{ 720185377Ssam if (ar5212Use32KHzclock(ah, opmode)) { 721185377Ssam /* # Set sleep clock rate back to 32 MHz. */ 722185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0); 723185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 724185377Ssam 725185377Ssam OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ 726185380Ssam OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 727185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 728185377Ssam 729185377Ssam /* 730185377Ssam * Restore BB registers to power-on defaults 731185377Ssam */ 732185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 733185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 734185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 735185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 736185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 737185380Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 738185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 739185377Ssam } 740185377Ssam} 741185377Ssam 742185377Ssam/* 743185377Ssam * Adjust NF based on statistical values for 5GHz frequencies. 744185377Ssam * Default method: this may be overridden by the rf backend. 745185377Ssam */ 746185377Ssamint16_t 747185377Ssamar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 748185377Ssam{ 749185377Ssam static const struct { 750185377Ssam uint16_t freqLow; 751185377Ssam int16_t adjust; 752185377Ssam } adjustDef[] = { 753185377Ssam { 5790, 11 }, /* NB: ordered high -> low */ 754185377Ssam { 5730, 10 }, 755185377Ssam { 5690, 9 }, 756185377Ssam { 5660, 8 }, 757185377Ssam { 5610, 7 }, 758185377Ssam { 5530, 5 }, 759185377Ssam { 5450, 4 }, 760185377Ssam { 5379, 2 }, 761185377Ssam { 5209, 0 }, 762185377Ssam { 3000, 1 }, 763185377Ssam { 0, 0 }, 764185377Ssam }; 765185377Ssam int i; 766185377Ssam 767185377Ssam for (i = 0; c->channel <= adjustDef[i].freqLow; i++) 768185377Ssam ; 769185377Ssam return adjustDef[i].adjust; 770185377Ssam} 771185377Ssam 772185377SsamHAL_STATUS 773185377Ssamar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 774185377Ssam uint32_t capability, uint32_t *result) 775185377Ssam{ 776185377Ssam#define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion 777185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 778185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 779185377Ssam const struct ar5212AniState *ani; 780185377Ssam 781185377Ssam switch (type) { 782185377Ssam case HAL_CAP_CIPHER: /* cipher handled in hardware */ 783185377Ssam switch (capability) { 784185377Ssam case HAL_CIPHER_AES_CCM: 785185377Ssam return pCap->halCipherAesCcmSupport ? 786185377Ssam HAL_OK : HAL_ENOTSUPP; 787185377Ssam case HAL_CIPHER_AES_OCB: 788185377Ssam case HAL_CIPHER_TKIP: 789185377Ssam case HAL_CIPHER_WEP: 790185377Ssam case HAL_CIPHER_MIC: 791185377Ssam case HAL_CIPHER_CLR: 792185377Ssam return HAL_OK; 793185377Ssam default: 794185377Ssam return HAL_ENOTSUPP; 795185377Ssam } 796185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 797185377Ssam switch (capability) { 798185377Ssam case 0: /* hardware capability */ 799185377Ssam return HAL_OK; 800185377Ssam case 1: 801185377Ssam return (ahp->ah_staId1Defaults & 802185377Ssam AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO; 803185377Ssam } 804185907Ssam return HAL_EINVAL; 805185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 806185377Ssam switch (capability) { 807185377Ssam case 0: /* hardware capability */ 808185377Ssam return pCap->halTkipMicTxRxKeySupport ? 809185377Ssam HAL_ENXIO : HAL_OK; 810185377Ssam case 1: /* current setting */ 811185377Ssam return (ahp->ah_miscMode & 812185377Ssam AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; 813185377Ssam } 814185377Ssam return HAL_EINVAL; 815185377Ssam case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ 816185377Ssam /* XXX move to capability bit */ 817185377Ssam return MACVERSION(ah) > AR_SREV_VERSION_VENICE || 818185377Ssam (MACVERSION(ah) == AR_SREV_VERSION_VENICE && 819185377Ssam AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; 820185377Ssam case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 821185377Ssam switch (capability) { 822185377Ssam case 0: /* hardware capability */ 823185377Ssam return HAL_OK; 824185377Ssam case 1: /* current setting */ 825185380Ssam return ahp->ah_diversity ? HAL_OK : HAL_ENXIO; 826185377Ssam } 827185377Ssam return HAL_EINVAL; 828185377Ssam case HAL_CAP_DIAG: 829185377Ssam *result = AH_PRIVATE(ah)->ah_diagreg; 830185377Ssam return HAL_OK; 831185377Ssam case HAL_CAP_TPC: 832185377Ssam switch (capability) { 833185377Ssam case 0: /* hardware capability */ 834185377Ssam return HAL_OK; 835185377Ssam case 1: 836185377Ssam return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; 837185377Ssam } 838185377Ssam return HAL_OK; 839185377Ssam case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ 840185377Ssam switch (capability) { 841185377Ssam case HAL_CAP_RADAR: 842185377Ssam return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? 843185377Ssam HAL_OK: HAL_ENXIO; 844185377Ssam case HAL_CAP_AR: 845185377Ssam return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || 846185377Ssam ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? 847185377Ssam HAL_OK: HAL_ENXIO; 848185377Ssam } 849185377Ssam return HAL_ENXIO; 850185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 851185377Ssam switch (capability) { 852185377Ssam case 0: /* hardware capability */ 853185377Ssam return HAL_OK; 854185377Ssam case 1: 855185377Ssam return (ahp->ah_staId1Defaults & 856185377Ssam AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; 857185377Ssam } 858185377Ssam return HAL_EINVAL; 859185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 860185377Ssam switch (capability) { 861185377Ssam case 0: /* hardware capability */ 862185377Ssam return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; 863185377Ssam case 1: 864185377Ssam return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? 865185377Ssam HAL_OK : HAL_ENXIO; 866185377Ssam } 867185377Ssam return HAL_EINVAL; 868185377Ssam case HAL_CAP_TPC_ACK: 869185377Ssam *result = MS(ahp->ah_macTPC, AR_TPC_ACK); 870185377Ssam return HAL_OK; 871185377Ssam case HAL_CAP_TPC_CTS: 872185377Ssam *result = MS(ahp->ah_macTPC, AR_TPC_CTS); 873185377Ssam return HAL_OK; 874185377Ssam case HAL_CAP_INTMIT: /* interference mitigation */ 875185377Ssam switch (capability) { 876185377Ssam case 0: /* hardware capability */ 877185377Ssam return HAL_OK; 878185377Ssam case 1: 879185377Ssam return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? 880185377Ssam HAL_OK : HAL_ENXIO; 881185377Ssam case 2: /* HAL_ANI_NOISE_IMMUNITY_LEVEL */ 882185377Ssam case 3: /* HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION */ 883185377Ssam case 4: /* HAL_ANI_CCK_WEAK_SIGNAL_THR */ 884185377Ssam case 5: /* HAL_ANI_FIRSTEP_LEVEL */ 885185377Ssam case 6: /* HAL_ANI_SPUR_IMMUNITY_LEVEL */ 886185377Ssam ani = ar5212AniGetCurrentState(ah); 887185377Ssam if (ani == AH_NULL) 888185377Ssam return HAL_ENXIO; 889185377Ssam switch (capability) { 890185377Ssam case 2: *result = ani->noiseImmunityLevel; break; 891185377Ssam case 3: *result = !ani->ofdmWeakSigDetectOff; break; 892185377Ssam case 4: *result = ani->cckWeakSigThreshold; break; 893185377Ssam case 5: *result = ani->firstepLevel; break; 894185377Ssam case 6: *result = ani->spurImmunityLevel; break; 895185377Ssam } 896185377Ssam return HAL_OK; 897185377Ssam } 898185377Ssam return HAL_EINVAL; 899185377Ssam default: 900185377Ssam return ath_hal_getcapability(ah, type, capability, result); 901185377Ssam } 902185377Ssam#undef MACVERSION 903185377Ssam} 904185377Ssam 905185377SsamHAL_BOOL 906185377Ssamar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 907185377Ssam uint32_t capability, uint32_t setting, HAL_STATUS *status) 908185377Ssam{ 909185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 910185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 911185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 912185377Ssam uint32_t v; 913185377Ssam 914185377Ssam switch (type) { 915185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 916185377Ssam if (setting) 917185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; 918185377Ssam else 919185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; 920185377Ssam return AH_TRUE; 921185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 922185377Ssam if (!pCap->halTkipMicTxRxKeySupport) 923185377Ssam return AH_FALSE; 924185377Ssam /* NB: true =>'s use split key cache layout */ 925185377Ssam if (setting) 926185377Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 927185377Ssam else 928185377Ssam ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 929185377Ssam /* NB: write here so keys can be setup w/o a reset */ 930185377Ssam OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); 931185377Ssam return AH_TRUE; 932185377Ssam case HAL_CAP_DIVERSITY: 933185380Ssam if (ahp->ah_phyPowerOn) { 934185380Ssam v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 935185380Ssam if (setting) 936185380Ssam v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 937185380Ssam else 938185380Ssam v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 939185380Ssam OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); 940185380Ssam } 941185380Ssam ahp->ah_diversity = (setting != 0); 942185377Ssam return AH_TRUE; 943185377Ssam case HAL_CAP_DIAG: /* hardware diagnostic support */ 944185377Ssam /* 945185377Ssam * NB: could split this up into virtual capabilities, 946185377Ssam * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly 947185377Ssam * seems worth the additional complexity. 948185377Ssam */ 949185377Ssam AH_PRIVATE(ah)->ah_diagreg = setting; 950185377Ssam OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 951185377Ssam return AH_TRUE; 952185377Ssam case HAL_CAP_TPC: 953185377Ssam ahp->ah_tpcEnabled = (setting != 0); 954185377Ssam return AH_TRUE; 955185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 956185377Ssam if (setting) 957185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; 958185377Ssam else 959185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; 960185377Ssam return AH_TRUE; 961185377Ssam case HAL_CAP_TPC_ACK: 962185377Ssam case HAL_CAP_TPC_CTS: 963185377Ssam setting += ahp->ah_txPowerIndexOffset; 964185377Ssam if (setting > 63) 965185377Ssam setting = 63; 966185377Ssam if (type == HAL_CAP_TPC_ACK) { 967185377Ssam ahp->ah_macTPC &= AR_TPC_ACK; 968185377Ssam ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); 969185377Ssam } else { 970185377Ssam ahp->ah_macTPC &= AR_TPC_CTS; 971185377Ssam ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); 972185377Ssam } 973185377Ssam OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); 974185377Ssam return AH_TRUE; 975185377Ssam case HAL_CAP_INTMIT: { /* interference mitigation */ 976185377Ssam static const HAL_ANI_CMD cmds[] = { 977185377Ssam HAL_ANI_PRESENT, 978185377Ssam HAL_ANI_MODE, 979185377Ssam HAL_ANI_NOISE_IMMUNITY_LEVEL, 980185377Ssam HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 981185377Ssam HAL_ANI_CCK_WEAK_SIGNAL_THR, 982185377Ssam HAL_ANI_FIRSTEP_LEVEL, 983185377Ssam HAL_ANI_SPUR_IMMUNITY_LEVEL, 984185377Ssam }; 985185377Ssam return capability < N(cmds) ? 986185377Ssam ar5212AniControl(ah, cmds[capability], setting) : 987185377Ssam AH_FALSE; 988185377Ssam } 989185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 990185377Ssam if (pCap->halTsfAddSupport) { 991185377Ssam if (setting) 992185377Ssam ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; 993185377Ssam else 994185377Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; 995185377Ssam return AH_TRUE; 996185377Ssam } 997185377Ssam /* fall thru... */ 998185377Ssam default: 999185377Ssam return ath_hal_setcapability(ah, type, capability, 1000185377Ssam setting, status); 1001185377Ssam } 1002185377Ssam#undef N 1003185377Ssam} 1004185377Ssam 1005185377SsamHAL_BOOL 1006185377Ssamar5212GetDiagState(struct ath_hal *ah, int request, 1007185377Ssam const void *args, uint32_t argsize, 1008185377Ssam void **result, uint32_t *resultsize) 1009185377Ssam{ 1010185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 1011185377Ssam 1012185377Ssam (void) ahp; 1013185377Ssam if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 1014185377Ssam return AH_TRUE; 1015185377Ssam switch (request) { 1016185377Ssam case HAL_DIAG_EEPROM: 1017185377Ssam case HAL_DIAG_EEPROM_EXP_11A: 1018185377Ssam case HAL_DIAG_EEPROM_EXP_11B: 1019185377Ssam case HAL_DIAG_EEPROM_EXP_11G: 1020185377Ssam case HAL_DIAG_RFGAIN: 1021185377Ssam return ath_hal_eepromDiag(ah, request, 1022185377Ssam args, argsize, result, resultsize); 1023185377Ssam case HAL_DIAG_RFGAIN_CURSTEP: 1024185377Ssam *result = __DECONST(void *, ahp->ah_gainValues.currStep); 1025185377Ssam *resultsize = (*result == AH_NULL) ? 1026185377Ssam 0 : sizeof(GAIN_OPTIMIZATION_STEP); 1027185377Ssam return AH_TRUE; 1028185377Ssam case HAL_DIAG_PCDAC: 1029185377Ssam *result = ahp->ah_pcdacTable; 1030185377Ssam *resultsize = ahp->ah_pcdacTableSize; 1031185377Ssam return AH_TRUE; 1032185377Ssam case HAL_DIAG_TXRATES: 1033185377Ssam *result = &ahp->ah_ratesArray[0]; 1034185377Ssam *resultsize = sizeof(ahp->ah_ratesArray); 1035185377Ssam return AH_TRUE; 1036185377Ssam case HAL_DIAG_ANI_CURRENT: 1037185377Ssam *result = ar5212AniGetCurrentState(ah); 1038185377Ssam *resultsize = (*result == AH_NULL) ? 1039185377Ssam 0 : sizeof(struct ar5212AniState); 1040185377Ssam return AH_TRUE; 1041185377Ssam case HAL_DIAG_ANI_STATS: 1042185377Ssam *result = ar5212AniGetCurrentStats(ah); 1043185377Ssam *resultsize = (*result == AH_NULL) ? 1044185377Ssam 0 : sizeof(struct ar5212Stats); 1045185377Ssam return AH_TRUE; 1046185377Ssam case HAL_DIAG_ANI_CMD: 1047185377Ssam if (argsize != 2*sizeof(uint32_t)) 1048185377Ssam return AH_FALSE; 1049185377Ssam ar5212AniControl(ah, ((const uint32_t *)args)[0], 1050185377Ssam ((const uint32_t *)args)[1]); 1051185377Ssam return AH_TRUE; 1052185377Ssam case HAL_DIAG_ANI_PARAMS: 1053185377Ssam /* 1054185377Ssam * NB: We assume struct ar5212AniParams is identical 1055185377Ssam * to HAL_ANI_PARAMS; if they diverge then we'll need 1056185377Ssam * to handle it here 1057185377Ssam */ 1058185377Ssam if (argsize == 0 && args == AH_NULL) { 1059185377Ssam struct ar5212AniState *aniState = 1060185377Ssam ar5212AniGetCurrentState(ah); 1061185377Ssam if (aniState == AH_NULL) 1062185377Ssam return AH_FALSE; 1063185377Ssam *result = __DECONST(void *, aniState->params); 1064185377Ssam *resultsize = sizeof(struct ar5212AniParams); 1065185377Ssam return AH_TRUE; 1066185377Ssam } else { 1067185377Ssam if (argsize != sizeof(struct ar5212AniParams)) 1068185377Ssam return AH_FALSE; 1069185377Ssam return ar5212AniSetParams(ah, args, args); 1070185377Ssam } 1071185377Ssam } 1072185377Ssam return AH_FALSE; 1073185377Ssam} 1074