ar5212_misc.c revision 185380
1185377Ssam/* 2185377Ssam * Copyright (c) 2002-2008 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 * 17185380Ssam * $Id: ar5212_misc.c,v 1.12 2008/11/27 22:30:00 sam Exp $ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#ifdef AH_SUPPORT_AR5212 22185377Ssam 23185377Ssam#include "ah.h" 24185377Ssam#include "ah_internal.h" 25185377Ssam#include "ah_devid.h" 26185377Ssam#ifdef AH_DEBUG 27185377Ssam#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 28185377Ssam#endif 29185377Ssam 30185377Ssam#include "ar5212/ar5212.h" 31185377Ssam#include "ar5212/ar5212reg.h" 32185377Ssam#include "ar5212/ar5212phy.h" 33185377Ssam#ifdef AH_SUPPORT_AR5311 34185377Ssam#include "ar5212/ar5311reg.h" 35185377Ssam#endif 36185377Ssam 37185377Ssam#include "ah_eeprom_v3.h" 38185377Ssam 39185377Ssam#define AR_NUM_GPIO 6 /* 6 GPIO pins */ 40185377Ssam#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ 41185377Ssam 42185377Ssamextern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *); 43185377Ssam 44185377Ssamvoid 45185377Ssamar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac) 46185377Ssam{ 47185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 48185377Ssam 49185377Ssam OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); 50185377Ssam} 51185377Ssam 52185377SsamHAL_BOOL 53185377Ssamar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac) 54185377Ssam{ 55185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 56185377Ssam 57185377Ssam OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); 58185377Ssam return AH_TRUE; 59185377Ssam} 60185377Ssam 61185377Ssamvoid 62185377Ssamar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask) 63185377Ssam{ 64185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 65185377Ssam 66185377Ssam OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN); 67185377Ssam} 68185377Ssam 69185377SsamHAL_BOOL 70185377Ssamar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) 71185377Ssam{ 72185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 73185377Ssam 74185377Ssam /* save it since it must be rewritten on reset */ 75185377Ssam OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN); 76185377Ssam 77185377Ssam OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); 78185377Ssam OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); 79185377Ssam return AH_TRUE; 80185377Ssam} 81185377Ssam 82185377Ssam/* 83185380Ssam * Attempt to change the cards operating regulatory domain to the given value 84185380Ssam */ 85185380SsamHAL_BOOL 86185380Ssamar5212SetRegulatoryDomain(struct ath_hal *ah, 87185380Ssam uint16_t regDomain, HAL_STATUS *status) 88185380Ssam{ 89185380Ssam HAL_STATUS ecode; 90185380Ssam 91185380Ssam if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { 92185380Ssam ecode = HAL_EINVAL; 93185380Ssam goto bad; 94185380Ssam } 95185380Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { 96185380Ssam ecode = HAL_EEWRITE; 97185380Ssam goto bad; 98185380Ssam } 99185380Ssam#ifdef AH_SUPPORT_WRITE_REGDOMAIN 100185380Ssam if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { 101185380Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 102185380Ssam "%s: set regulatory domain to %u (0x%x)\n", 103185380Ssam __func__, regDomain, regDomain); 104185380Ssam AH_PRIVATE(ah)->ah_currentRD = regDomain; 105185380Ssam return AH_TRUE; 106185380Ssam } 107185380Ssam#endif 108185380Ssam ecode = HAL_EIO; 109185380Ssambad: 110185380Ssam if (status) 111185380Ssam *status = ecode; 112185380Ssam return AH_FALSE; 113185380Ssam} 114185380Ssam 115185380Ssam/* 116185377Ssam * Return the wireless modes (a,b,g,t) supported by hardware. 117185377Ssam * 118185377Ssam * This value is what is actually supported by the hardware 119185377Ssam * and is unaffected by regulatory/country code settings. 120185377Ssam */ 121185377Ssamu_int 122185377Ssamar5212GetWirelessModes(struct ath_hal *ah) 123185377Ssam{ 124185377Ssam u_int mode = 0; 125185377Ssam 126185377Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { 127185377Ssam mode = HAL_MODE_11A; 128185377Ssam if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) 129185377Ssam mode |= HAL_MODE_TURBO | HAL_MODE_108A; 130185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 131185380Ssam mode |= HAL_MODE_11A_HALF_RATE; 132185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 133185380Ssam mode |= HAL_MODE_11A_QUARTER_RATE; 134185377Ssam } 135185377Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) 136185377Ssam mode |= HAL_MODE_11B; 137185377Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && 138185377Ssam AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { 139185377Ssam mode |= HAL_MODE_11G; 140185377Ssam if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) 141185377Ssam mode |= HAL_MODE_108G; 142185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 143185380Ssam mode |= HAL_MODE_11G_HALF_RATE; 144185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 145185380Ssam mode |= HAL_MODE_11G_QUARTER_RATE; 146185377Ssam } 147185377Ssam return mode; 148185377Ssam} 149185377Ssam 150185377Ssam/* 151185377Ssam * Set the interrupt and GPIO values so the ISR can disable RF 152185377Ssam * on a switch signal. Assumes GPIO port and interrupt polarity 153185377Ssam * are set prior to call. 154185377Ssam */ 155185377Ssamvoid 156185377Ssamar5212EnableRfKill(struct ath_hal *ah) 157185377Ssam{ 158185377Ssam uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; 159185377Ssam int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); 160185377Ssam int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); 161185377Ssam 162185377Ssam /* 163185377Ssam * Configure the desired GPIO port for input 164185377Ssam * and enable baseband rf silence. 165185377Ssam */ 166185377Ssam ath_hal_gpioCfgInput(ah, select); 167185377Ssam OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000); 168185377Ssam /* 169185377Ssam * If radio disable switch connection to GPIO bit x is enabled 170185377Ssam * program GPIO interrupt. 171185377Ssam * If rfkill bit on eeprom is 1, setupeeprommap routine has already 172185377Ssam * verified that it is a later version of eeprom, it has a place for 173185377Ssam * rfkill bit and it is set to 1, indicating that GPIO bit x hardware 174185377Ssam * connection is present. 175185377Ssam */ 176185377Ssam ath_hal_gpioSetIntr(ah, select, 177185377Ssam (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity)); 178185377Ssam} 179185377Ssam 180185377Ssam/* 181185377Ssam * Change the LED blinking pattern to correspond to the connectivity 182185377Ssam */ 183185377Ssamvoid 184185377Ssamar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 185185377Ssam{ 186185377Ssam static const uint32_t ledbits[8] = { 187185377Ssam AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */ 188185377Ssam AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */ 189185377Ssam AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */ 190185377Ssam AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/ 191185377Ssam AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */ 192185377Ssam AR_PCICFG_LEDCTL_NONE, 193185377Ssam AR_PCICFG_LEDCTL_NONE, 194185377Ssam AR_PCICFG_LEDCTL_NONE, 195185377Ssam }; 196185377Ssam uint32_t bits; 197185377Ssam 198185377Ssam bits = OS_REG_READ(ah, AR_PCICFG); 199185377Ssam if (IS_2417(ah)) { 200185377Ssam /* 201185377Ssam * Enable LED for Nala. There is a bit marked reserved 202185377Ssam * that must be set and we also turn on the power led. 203185377Ssam * Because we mark s/w LED control setting the control 204185377Ssam * status bits below is meangless (the driver must flash 205185377Ssam * the LED(s) using the GPIO lines). 206185377Ssam */ 207185377Ssam bits = (bits &~ AR_PCICFG_LEDMODE) 208185377Ssam | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE) 209185377Ssam#if 0 210185377Ssam | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE) 211185377Ssam#endif 212185377Ssam | 0x08000000; 213185377Ssam } 214185377Ssam bits = (bits &~ AR_PCICFG_LEDCTL) 215185377Ssam | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL); 216185377Ssam OS_REG_WRITE(ah, AR_PCICFG, bits); 217185377Ssam} 218185377Ssam 219185377Ssam/* 220185377Ssam * Change association related fields programmed into the hardware. 221185377Ssam * Writing a valid BSSID to the hardware effectively enables the hardware 222185377Ssam * to synchronize its TSF to the correct beacons and receive frames coming 223185377Ssam * from that BSSID. It is called by the SME JOIN operation. 224185377Ssam */ 225185377Ssamvoid 226185377Ssamar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) 227185377Ssam{ 228185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 229185377Ssam 230185377Ssam /* XXX save bssid for possible re-use on reset */ 231185377Ssam OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); 232185377Ssam OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 233185377Ssam OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | 234185377Ssam ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); 235185377Ssam} 236185377Ssam 237185377Ssam/* 238185377Ssam * Get the current hardware tsf for stamlme 239185377Ssam */ 240185377Ssamuint64_t 241185377Ssamar5212GetTsf64(struct ath_hal *ah) 242185377Ssam{ 243185377Ssam uint32_t low1, low2, u32; 244185377Ssam 245185377Ssam /* sync multi-word read */ 246185377Ssam low1 = OS_REG_READ(ah, AR_TSF_L32); 247185377Ssam u32 = OS_REG_READ(ah, AR_TSF_U32); 248185377Ssam low2 = OS_REG_READ(ah, AR_TSF_L32); 249185377Ssam if (low2 < low1) { /* roll over */ 250185377Ssam /* 251185377Ssam * If we are not preempted this will work. If we are 252185377Ssam * then we re-reading AR_TSF_U32 does no good as the 253185377Ssam * low bits will be meaningless. Likewise reading 254185377Ssam * L32, U32, U32, then comparing the last two reads 255185380Ssam * to check for rollover doesn't help if preempted--so 256185380Ssam * we take this approach as it costs one less PCI read 257185380Ssam * which can be noticeable when doing things like 258185380Ssam * timestamping packets in monitor mode. 259185377Ssam */ 260185377Ssam u32++; 261185377Ssam } 262185377Ssam return (((uint64_t) u32) << 32) | ((uint64_t) low2); 263185377Ssam} 264185377Ssam 265185377Ssam/* 266185377Ssam * Get the current hardware tsf for stamlme 267185377Ssam */ 268185377Ssamuint32_t 269185377Ssamar5212GetTsf32(struct ath_hal *ah) 270185377Ssam{ 271185377Ssam return OS_REG_READ(ah, AR_TSF_L32); 272185377Ssam} 273185377Ssam 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{ 302185377Ssam HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 303185377Ssam uint32_t reg; 304185377Ssam uint8_t xset; 305185377Ssam int i; 306185377Ssam 307185377Ssam if (chan == AH_NULL || !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); 431185380Ssam const HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan; 432185377Ssam 433185380Ssam if (!ahp->ah_phyPowerOn || ichan == 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 } 439185380Ssam return ar5212SetAntennaSwitchInternal(ah, setting, ichan); 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 */ 460185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us)); 461185377Ssam ahp->ah_slottime = 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; 470185377Ssam return ath_hal_mac_usec(ah, clks); /* 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 */ 600185377Ssam if (!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; 609185377Ssam if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { 610185377Ssam slot += IFS_SLOT_HALF_RATE; 611185377Ssam eifs += IFS_EIFS_HALF_RATE; 612185377Ssam } else if (IS_CHAN_QUARTER_RATE(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 } 811185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 812185377Ssam switch (capability) { 813185377Ssam case 0: /* hardware capability */ 814185377Ssam return pCap->halTkipMicTxRxKeySupport ? 815185377Ssam HAL_ENXIO : HAL_OK; 816185377Ssam case 1: /* current setting */ 817185377Ssam return (ahp->ah_miscMode & 818185377Ssam AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; 819185377Ssam } 820185377Ssam return HAL_EINVAL; 821185377Ssam case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ 822185377Ssam /* XXX move to capability bit */ 823185377Ssam return MACVERSION(ah) > AR_SREV_VERSION_VENICE || 824185377Ssam (MACVERSION(ah) == AR_SREV_VERSION_VENICE && 825185377Ssam AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; 826185377Ssam case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 827185377Ssam switch (capability) { 828185377Ssam case 0: /* hardware capability */ 829185377Ssam return HAL_OK; 830185377Ssam case 1: /* current setting */ 831185380Ssam return ahp->ah_diversity ? HAL_OK : HAL_ENXIO; 832185377Ssam } 833185377Ssam return HAL_EINVAL; 834185377Ssam case HAL_CAP_DIAG: 835185377Ssam *result = AH_PRIVATE(ah)->ah_diagreg; 836185377Ssam return HAL_OK; 837185377Ssam case HAL_CAP_TPC: 838185377Ssam switch (capability) { 839185377Ssam case 0: /* hardware capability */ 840185377Ssam return HAL_OK; 841185377Ssam case 1: 842185377Ssam return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; 843185377Ssam } 844185377Ssam return HAL_OK; 845185377Ssam case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ 846185377Ssam switch (capability) { 847185377Ssam case HAL_CAP_RADAR: 848185377Ssam return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? 849185377Ssam HAL_OK: HAL_ENXIO; 850185377Ssam case HAL_CAP_AR: 851185377Ssam return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || 852185377Ssam ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? 853185377Ssam HAL_OK: HAL_ENXIO; 854185377Ssam } 855185377Ssam return HAL_ENXIO; 856185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 857185377Ssam switch (capability) { 858185377Ssam case 0: /* hardware capability */ 859185377Ssam return HAL_OK; 860185377Ssam case 1: 861185377Ssam return (ahp->ah_staId1Defaults & 862185377Ssam AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; 863185377Ssam } 864185377Ssam return HAL_EINVAL; 865185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 866185377Ssam switch (capability) { 867185377Ssam case 0: /* hardware capability */ 868185377Ssam return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; 869185377Ssam case 1: 870185377Ssam return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? 871185377Ssam HAL_OK : HAL_ENXIO; 872185377Ssam } 873185377Ssam return HAL_EINVAL; 874185377Ssam case HAL_CAP_TPC_ACK: 875185377Ssam *result = MS(ahp->ah_macTPC, AR_TPC_ACK); 876185377Ssam return HAL_OK; 877185377Ssam case HAL_CAP_TPC_CTS: 878185377Ssam *result = MS(ahp->ah_macTPC, AR_TPC_CTS); 879185377Ssam return HAL_OK; 880185377Ssam case HAL_CAP_INTMIT: /* interference mitigation */ 881185377Ssam switch (capability) { 882185377Ssam case 0: /* hardware capability */ 883185377Ssam return HAL_OK; 884185377Ssam case 1: 885185377Ssam return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? 886185377Ssam HAL_OK : HAL_ENXIO; 887185377Ssam case 2: /* HAL_ANI_NOISE_IMMUNITY_LEVEL */ 888185377Ssam case 3: /* HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION */ 889185377Ssam case 4: /* HAL_ANI_CCK_WEAK_SIGNAL_THR */ 890185377Ssam case 5: /* HAL_ANI_FIRSTEP_LEVEL */ 891185377Ssam case 6: /* HAL_ANI_SPUR_IMMUNITY_LEVEL */ 892185377Ssam ani = ar5212AniGetCurrentState(ah); 893185377Ssam if (ani == AH_NULL) 894185377Ssam return HAL_ENXIO; 895185377Ssam switch (capability) { 896185377Ssam case 2: *result = ani->noiseImmunityLevel; break; 897185377Ssam case 3: *result = !ani->ofdmWeakSigDetectOff; break; 898185377Ssam case 4: *result = ani->cckWeakSigThreshold; break; 899185377Ssam case 5: *result = ani->firstepLevel; break; 900185377Ssam case 6: *result = ani->spurImmunityLevel; break; 901185377Ssam } 902185377Ssam return HAL_OK; 903185377Ssam } 904185377Ssam return HAL_EINVAL; 905185377Ssam default: 906185377Ssam return ath_hal_getcapability(ah, type, capability, result); 907185377Ssam } 908185377Ssam#undef MACVERSION 909185377Ssam} 910185377Ssam 911185377SsamHAL_BOOL 912185377Ssamar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 913185377Ssam uint32_t capability, uint32_t setting, HAL_STATUS *status) 914185377Ssam{ 915185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 916185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 917185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 918185377Ssam uint32_t v; 919185377Ssam 920185377Ssam switch (type) { 921185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 922185377Ssam if (setting) 923185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; 924185377Ssam else 925185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; 926185377Ssam return AH_TRUE; 927185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 928185377Ssam if (!pCap->halTkipMicTxRxKeySupport) 929185377Ssam return AH_FALSE; 930185377Ssam /* NB: true =>'s use split key cache layout */ 931185377Ssam if (setting) 932185377Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 933185377Ssam else 934185377Ssam ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 935185377Ssam /* NB: write here so keys can be setup w/o a reset */ 936185377Ssam OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); 937185377Ssam return AH_TRUE; 938185377Ssam case HAL_CAP_DIVERSITY: 939185380Ssam if (ahp->ah_phyPowerOn) { 940185380Ssam v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 941185380Ssam if (setting) 942185380Ssam v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 943185380Ssam else 944185380Ssam v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 945185380Ssam OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); 946185380Ssam } 947185380Ssam ahp->ah_diversity = (setting != 0); 948185377Ssam return AH_TRUE; 949185377Ssam case HAL_CAP_DIAG: /* hardware diagnostic support */ 950185377Ssam /* 951185377Ssam * NB: could split this up into virtual capabilities, 952185377Ssam * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly 953185377Ssam * seems worth the additional complexity. 954185377Ssam */ 955185377Ssam AH_PRIVATE(ah)->ah_diagreg = setting; 956185377Ssam OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 957185377Ssam return AH_TRUE; 958185377Ssam case HAL_CAP_TPC: 959185377Ssam ahp->ah_tpcEnabled = (setting != 0); 960185377Ssam return AH_TRUE; 961185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 962185377Ssam if (setting) 963185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; 964185377Ssam else 965185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; 966185377Ssam return AH_TRUE; 967185377Ssam case HAL_CAP_TPC_ACK: 968185377Ssam case HAL_CAP_TPC_CTS: 969185377Ssam setting += ahp->ah_txPowerIndexOffset; 970185377Ssam if (setting > 63) 971185377Ssam setting = 63; 972185377Ssam if (type == HAL_CAP_TPC_ACK) { 973185377Ssam ahp->ah_macTPC &= AR_TPC_ACK; 974185377Ssam ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); 975185377Ssam } else { 976185377Ssam ahp->ah_macTPC &= AR_TPC_CTS; 977185377Ssam ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); 978185377Ssam } 979185377Ssam OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); 980185377Ssam return AH_TRUE; 981185377Ssam case HAL_CAP_INTMIT: { /* interference mitigation */ 982185377Ssam static const HAL_ANI_CMD cmds[] = { 983185377Ssam HAL_ANI_PRESENT, 984185377Ssam HAL_ANI_MODE, 985185377Ssam HAL_ANI_NOISE_IMMUNITY_LEVEL, 986185377Ssam HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 987185377Ssam HAL_ANI_CCK_WEAK_SIGNAL_THR, 988185377Ssam HAL_ANI_FIRSTEP_LEVEL, 989185377Ssam HAL_ANI_SPUR_IMMUNITY_LEVEL, 990185377Ssam }; 991185377Ssam return capability < N(cmds) ? 992185377Ssam ar5212AniControl(ah, cmds[capability], setting) : 993185377Ssam AH_FALSE; 994185377Ssam } 995185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 996185377Ssam if (pCap->halTsfAddSupport) { 997185377Ssam if (setting) 998185377Ssam ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; 999185377Ssam else 1000185377Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; 1001185377Ssam return AH_TRUE; 1002185377Ssam } 1003185377Ssam /* fall thru... */ 1004185377Ssam default: 1005185377Ssam return ath_hal_setcapability(ah, type, capability, 1006185377Ssam setting, status); 1007185377Ssam } 1008185377Ssam#undef N 1009185377Ssam} 1010185377Ssam 1011185377SsamHAL_BOOL 1012185377Ssamar5212GetDiagState(struct ath_hal *ah, int request, 1013185377Ssam const void *args, uint32_t argsize, 1014185377Ssam void **result, uint32_t *resultsize) 1015185377Ssam{ 1016185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 1017185377Ssam 1018185377Ssam (void) ahp; 1019185377Ssam if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 1020185377Ssam return AH_TRUE; 1021185377Ssam switch (request) { 1022185377Ssam case HAL_DIAG_EEPROM: 1023185377Ssam case HAL_DIAG_EEPROM_EXP_11A: 1024185377Ssam case HAL_DIAG_EEPROM_EXP_11B: 1025185377Ssam case HAL_DIAG_EEPROM_EXP_11G: 1026185377Ssam case HAL_DIAG_RFGAIN: 1027185377Ssam return ath_hal_eepromDiag(ah, request, 1028185377Ssam args, argsize, result, resultsize); 1029185377Ssam case HAL_DIAG_RFGAIN_CURSTEP: 1030185377Ssam *result = __DECONST(void *, ahp->ah_gainValues.currStep); 1031185377Ssam *resultsize = (*result == AH_NULL) ? 1032185377Ssam 0 : sizeof(GAIN_OPTIMIZATION_STEP); 1033185377Ssam return AH_TRUE; 1034185377Ssam case HAL_DIAG_PCDAC: 1035185377Ssam *result = ahp->ah_pcdacTable; 1036185377Ssam *resultsize = ahp->ah_pcdacTableSize; 1037185377Ssam return AH_TRUE; 1038185377Ssam case HAL_DIAG_TXRATES: 1039185377Ssam *result = &ahp->ah_ratesArray[0]; 1040185377Ssam *resultsize = sizeof(ahp->ah_ratesArray); 1041185377Ssam return AH_TRUE; 1042185377Ssam case HAL_DIAG_ANI_CURRENT: 1043185377Ssam *result = ar5212AniGetCurrentState(ah); 1044185377Ssam *resultsize = (*result == AH_NULL) ? 1045185377Ssam 0 : sizeof(struct ar5212AniState); 1046185377Ssam return AH_TRUE; 1047185377Ssam case HAL_DIAG_ANI_STATS: 1048185377Ssam *result = ar5212AniGetCurrentStats(ah); 1049185377Ssam *resultsize = (*result == AH_NULL) ? 1050185377Ssam 0 : sizeof(struct ar5212Stats); 1051185377Ssam return AH_TRUE; 1052185377Ssam case HAL_DIAG_ANI_CMD: 1053185377Ssam if (argsize != 2*sizeof(uint32_t)) 1054185377Ssam return AH_FALSE; 1055185377Ssam ar5212AniControl(ah, ((const uint32_t *)args)[0], 1056185377Ssam ((const uint32_t *)args)[1]); 1057185377Ssam return AH_TRUE; 1058185377Ssam case HAL_DIAG_ANI_PARAMS: 1059185377Ssam /* 1060185377Ssam * NB: We assume struct ar5212AniParams is identical 1061185377Ssam * to HAL_ANI_PARAMS; if they diverge then we'll need 1062185377Ssam * to handle it here 1063185377Ssam */ 1064185377Ssam if (argsize == 0 && args == AH_NULL) { 1065185377Ssam struct ar5212AniState *aniState = 1066185377Ssam ar5212AniGetCurrentState(ah); 1067185377Ssam if (aniState == AH_NULL) 1068185377Ssam return AH_FALSE; 1069185377Ssam *result = __DECONST(void *, aniState->params); 1070185377Ssam *resultsize = sizeof(struct ar5212AniParams); 1071185377Ssam return AH_TRUE; 1072185377Ssam } else { 1073185377Ssam if (argsize != sizeof(struct ar5212AniParams)) 1074185377Ssam return AH_FALSE; 1075185377Ssam return ar5212AniSetParams(ah, args, args); 1076185377Ssam } 1077185377Ssam } 1078185377Ssam return AH_FALSE; 1079185377Ssam} 1080185377Ssam#endif /* AH_SUPPORT_AR5212 */ 1081