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$ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam#include "ah_devid.h" 24185377Ssam#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 25185377Ssam 26185377Ssam#include "ar5212/ar5212.h" 27185377Ssam#include "ar5212/ar5212reg.h" 28185377Ssam#include "ar5212/ar5212phy.h" 29185377Ssam 30185377Ssam#include "ah_eeprom_v3.h" 31185377Ssam 32185377Ssam#define AR_NUM_GPIO 6 /* 6 GPIO pins */ 33185377Ssam#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ 34185377Ssam 35185377Ssamvoid 36185377Ssamar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac) 37185377Ssam{ 38185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 39185377Ssam 40185377Ssam OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); 41185377Ssam} 42185377Ssam 43185377SsamHAL_BOOL 44185377Ssamar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac) 45185377Ssam{ 46185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 47185377Ssam 48185377Ssam OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); 49185377Ssam return AH_TRUE; 50185377Ssam} 51185377Ssam 52185377Ssamvoid 53185377Ssamar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask) 54185377Ssam{ 55185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 56185377Ssam 57185377Ssam OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN); 58185377Ssam} 59185377Ssam 60185377SsamHAL_BOOL 61185377Ssamar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) 62185377Ssam{ 63185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 64185377Ssam 65185377Ssam /* save it since it must be rewritten on reset */ 66185377Ssam OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN); 67185377Ssam 68185377Ssam OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); 69185377Ssam OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); 70185377Ssam return AH_TRUE; 71185377Ssam} 72185377Ssam 73185377Ssam/* 74185380Ssam * Attempt to change the cards operating regulatory domain to the given value 75185380Ssam */ 76185380SsamHAL_BOOL 77185380Ssamar5212SetRegulatoryDomain(struct ath_hal *ah, 78185380Ssam uint16_t regDomain, HAL_STATUS *status) 79185380Ssam{ 80185380Ssam HAL_STATUS ecode; 81185380Ssam 82185380Ssam if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { 83185380Ssam ecode = HAL_EINVAL; 84185380Ssam goto bad; 85185380Ssam } 86185380Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { 87185380Ssam ecode = HAL_EEWRITE; 88185380Ssam goto bad; 89185380Ssam } 90185380Ssam#ifdef AH_SUPPORT_WRITE_REGDOMAIN 91185380Ssam if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { 92185380Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 93185380Ssam "%s: set regulatory domain to %u (0x%x)\n", 94185380Ssam __func__, regDomain, regDomain); 95185380Ssam AH_PRIVATE(ah)->ah_currentRD = regDomain; 96185380Ssam return AH_TRUE; 97185380Ssam } 98185380Ssam#endif 99185380Ssam ecode = HAL_EIO; 100185380Ssambad: 101185380Ssam if (status) 102185380Ssam *status = ecode; 103185380Ssam return AH_FALSE; 104185380Ssam} 105185380Ssam 106185380Ssam/* 107185377Ssam * Return the wireless modes (a,b,g,t) supported by hardware. 108185377Ssam * 109185377Ssam * This value is what is actually supported by the hardware 110185377Ssam * and is unaffected by regulatory/country code settings. 111185377Ssam */ 112185377Ssamu_int 113185377Ssamar5212GetWirelessModes(struct ath_hal *ah) 114185377Ssam{ 115185377Ssam u_int mode = 0; 116185377Ssam 117185377Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { 118185377Ssam mode = HAL_MODE_11A; 119185377Ssam if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) 120185377Ssam mode |= HAL_MODE_TURBO | HAL_MODE_108A; 121185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 122185380Ssam mode |= HAL_MODE_11A_HALF_RATE; 123185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 124185380Ssam mode |= HAL_MODE_11A_QUARTER_RATE; 125185377Ssam } 126185377Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) 127185377Ssam mode |= HAL_MODE_11B; 128185377Ssam if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && 129185377Ssam AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { 130185377Ssam mode |= HAL_MODE_11G; 131185377Ssam if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) 132185377Ssam mode |= HAL_MODE_108G; 133185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 134185380Ssam mode |= HAL_MODE_11G_HALF_RATE; 135185380Ssam if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 136185380Ssam mode |= HAL_MODE_11G_QUARTER_RATE; 137185377Ssam } 138185377Ssam return mode; 139185377Ssam} 140185377Ssam 141185377Ssam/* 142185377Ssam * Set the interrupt and GPIO values so the ISR can disable RF 143185377Ssam * on a switch signal. Assumes GPIO port and interrupt polarity 144185377Ssam * are set prior to call. 145185377Ssam */ 146185377Ssamvoid 147185377Ssamar5212EnableRfKill(struct ath_hal *ah) 148185377Ssam{ 149185377Ssam uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; 150185377Ssam int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); 151185377Ssam int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); 152185377Ssam 153185377Ssam /* 154185377Ssam * Configure the desired GPIO port for input 155185377Ssam * and enable baseband rf silence. 156185377Ssam */ 157185377Ssam ath_hal_gpioCfgInput(ah, select); 158185377Ssam OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000); 159185377Ssam /* 160185377Ssam * If radio disable switch connection to GPIO bit x is enabled 161185377Ssam * program GPIO interrupt. 162185377Ssam * If rfkill bit on eeprom is 1, setupeeprommap routine has already 163185377Ssam * verified that it is a later version of eeprom, it has a place for 164185377Ssam * rfkill bit and it is set to 1, indicating that GPIO bit x hardware 165185377Ssam * connection is present. 166185377Ssam */ 167185377Ssam ath_hal_gpioSetIntr(ah, select, 168185377Ssam (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity)); 169185377Ssam} 170185377Ssam 171185377Ssam/* 172185377Ssam * Change the LED blinking pattern to correspond to the connectivity 173185377Ssam */ 174185377Ssamvoid 175185377Ssamar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 176185377Ssam{ 177185377Ssam static const uint32_t ledbits[8] = { 178185377Ssam AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */ 179185377Ssam AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */ 180185377Ssam AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */ 181185377Ssam AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/ 182185377Ssam AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */ 183185377Ssam AR_PCICFG_LEDCTL_NONE, 184185377Ssam AR_PCICFG_LEDCTL_NONE, 185185377Ssam AR_PCICFG_LEDCTL_NONE, 186185377Ssam }; 187185377Ssam uint32_t bits; 188185377Ssam 189185377Ssam bits = OS_REG_READ(ah, AR_PCICFG); 190185377Ssam if (IS_2417(ah)) { 191185377Ssam /* 192185377Ssam * Enable LED for Nala. There is a bit marked reserved 193185377Ssam * that must be set and we also turn on the power led. 194185377Ssam * Because we mark s/w LED control setting the control 195185377Ssam * status bits below is meangless (the driver must flash 196185377Ssam * the LED(s) using the GPIO lines). 197185377Ssam */ 198185377Ssam bits = (bits &~ AR_PCICFG_LEDMODE) 199185377Ssam | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE) 200185377Ssam#if 0 201185377Ssam | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE) 202185377Ssam#endif 203185377Ssam | 0x08000000; 204185377Ssam } 205185377Ssam bits = (bits &~ AR_PCICFG_LEDCTL) 206185377Ssam | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL); 207185377Ssam OS_REG_WRITE(ah, AR_PCICFG, bits); 208185377Ssam} 209185377Ssam 210185377Ssam/* 211185377Ssam * Change association related fields programmed into the hardware. 212185377Ssam * Writing a valid BSSID to the hardware effectively enables the hardware 213185377Ssam * to synchronize its TSF to the correct beacons and receive frames coming 214185377Ssam * from that BSSID. It is called by the SME JOIN operation. 215185377Ssam */ 216185377Ssamvoid 217185377Ssamar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) 218185377Ssam{ 219185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 220185377Ssam 221185377Ssam /* XXX save bssid for possible re-use on reset */ 222185377Ssam OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); 223185377Ssam OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 224185377Ssam OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | 225185377Ssam ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); 226185377Ssam} 227185377Ssam 228185377Ssam/* 229185377Ssam * Get the current hardware tsf for stamlme 230185377Ssam */ 231185377Ssamuint64_t 232185377Ssamar5212GetTsf64(struct ath_hal *ah) 233185377Ssam{ 234185377Ssam uint32_t low1, low2, u32; 235185377Ssam 236185377Ssam /* sync multi-word read */ 237185377Ssam low1 = OS_REG_READ(ah, AR_TSF_L32); 238185377Ssam u32 = OS_REG_READ(ah, AR_TSF_U32); 239185377Ssam low2 = OS_REG_READ(ah, AR_TSF_L32); 240185377Ssam if (low2 < low1) { /* roll over */ 241185377Ssam /* 242185377Ssam * If we are not preempted this will work. If we are 243185377Ssam * then we re-reading AR_TSF_U32 does no good as the 244185377Ssam * low bits will be meaningless. Likewise reading 245185377Ssam * L32, U32, U32, then comparing the last two reads 246185380Ssam * to check for rollover doesn't help if preempted--so 247185380Ssam * we take this approach as it costs one less PCI read 248185380Ssam * which can be noticeable when doing things like 249185380Ssam * timestamping packets in monitor mode. 250185377Ssam */ 251185377Ssam u32++; 252185377Ssam } 253185377Ssam return (((uint64_t) u32) << 32) | ((uint64_t) low2); 254185377Ssam} 255185377Ssam 256185377Ssam/* 257185377Ssam * Get the current hardware tsf for stamlme 258185377Ssam */ 259185377Ssamuint32_t 260185377Ssamar5212GetTsf32(struct ath_hal *ah) 261185377Ssam{ 262185377Ssam return OS_REG_READ(ah, AR_TSF_L32); 263185377Ssam} 264185377Ssam 265219419Sadrianvoid 266219419Sadrianar5212SetTsf64(struct ath_hal *ah, uint64_t tsf64) 267219419Sadrian{ 268219419Sadrian OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); 269219419Sadrian OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); 270219419Sadrian} 271219419Sadrian 272185377Ssam/* 273185377Ssam * Reset the current hardware tsf for stamlme. 274185377Ssam */ 275185377Ssamvoid 276185377Ssamar5212ResetTsf(struct ath_hal *ah) 277185377Ssam{ 278185377Ssam 279185377Ssam uint32_t val = OS_REG_READ(ah, AR_BEACON); 280185377Ssam 281185377Ssam OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 282185377Ssam /* 283185377Ssam * When resetting the TSF, write twice to the 284185377Ssam * corresponding register; each write to the RESET_TSF bit toggles 285185377Ssam * the internal signal to cause a reset of the TSF - but if the signal 286185377Ssam * is left high, it will reset the TSF on the next chip reset also! 287185377Ssam * writing the bit an even number of times fixes this issue 288185377Ssam */ 289185377Ssam OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 290185377Ssam} 291185377Ssam 292185377Ssam/* 293185377Ssam * Set or clear hardware basic rate bit 294185377Ssam * Set hardware basic rate set if basic rate is found 295185377Ssam * and basic rate is equal or less than 2Mbps 296185377Ssam */ 297185377Ssamvoid 298185377Ssamar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs) 299185377Ssam{ 300187831Ssam const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 301185377Ssam uint32_t reg; 302185377Ssam uint8_t xset; 303185377Ssam int i; 304185377Ssam 305187831Ssam if (chan == AH_NULL || !IEEE80211_IS_CHAN_CCK(chan)) 306185377Ssam return; 307185377Ssam xset = 0; 308185377Ssam for (i = 0; i < rs->rs_count; i++) { 309185377Ssam uint8_t rset = rs->rs_rates[i]; 310185377Ssam /* Basic rate defined? */ 311185377Ssam if ((rset & 0x80) && (rset &= 0x7f) >= xset) 312185377Ssam xset = rset; 313185377Ssam } 314185377Ssam /* 315185377Ssam * Set the h/w bit to reflect whether or not the basic 316185377Ssam * rate is found to be equal or less than 2Mbps. 317185377Ssam */ 318185377Ssam reg = OS_REG_READ(ah, AR_STA_ID1); 319185377Ssam if (xset && xset/2 <= 2) 320185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B); 321185377Ssam else 322185377Ssam OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B); 323185377Ssam} 324185377Ssam 325185377Ssam/* 326185377Ssam * Grab a semi-random value from hardware registers - may not 327185377Ssam * change often 328185377Ssam */ 329185377Ssamuint32_t 330185377Ssamar5212GetRandomSeed(struct ath_hal *ah) 331185377Ssam{ 332185377Ssam uint32_t nf; 333185377Ssam 334185377Ssam nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; 335185377Ssam if (nf & 0x100) 336185377Ssam nf = 0 - ((nf ^ 0x1ff) + 1); 337185377Ssam return (OS_REG_READ(ah, AR_TSF_U32) ^ 338185377Ssam OS_REG_READ(ah, AR_TSF_L32) ^ nf); 339185377Ssam} 340185377Ssam 341185377Ssam/* 342185377Ssam * Detect if our card is present 343185377Ssam */ 344185377SsamHAL_BOOL 345185377Ssamar5212DetectCardPresent(struct ath_hal *ah) 346185377Ssam{ 347185377Ssam uint16_t macVersion, macRev; 348185377Ssam uint32_t v; 349185377Ssam 350185377Ssam /* 351185377Ssam * Read the Silicon Revision register and compare that 352185377Ssam * to what we read at attach time. If the same, we say 353185377Ssam * a card/device is present. 354185377Ssam */ 355185377Ssam v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; 356185377Ssam macVersion = v >> AR_SREV_ID_S; 357185377Ssam macRev = v & AR_SREV_REVISION; 358185377Ssam return (AH_PRIVATE(ah)->ah_macVersion == macVersion && 359185377Ssam AH_PRIVATE(ah)->ah_macRev == macRev); 360185377Ssam} 361185377Ssam 362185377Ssamvoid 363185377Ssamar5212EnableMibCounters(struct ath_hal *ah) 364185377Ssam{ 365185377Ssam /* NB: this just resets the mib counter machinery */ 366185377Ssam OS_REG_WRITE(ah, AR_MIBC, 367185377Ssam ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 368185377Ssam} 369185377Ssam 370185377Ssamvoid 371185377Ssamar5212DisableMibCounters(struct ath_hal *ah) 372185377Ssam{ 373185377Ssam OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC); 374185377Ssam} 375185377Ssam 376185377Ssam/* 377185377Ssam * Update MIB Counters 378185377Ssam */ 379185377Ssamvoid 380185377Ssamar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats) 381185377Ssam{ 382185377Ssam stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); 383185377Ssam stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); 384185377Ssam stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); 385185377Ssam stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); 386185377Ssam stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); 387185377Ssam} 388185377Ssam 389185377Ssam/* 390185377Ssam * Detect if the HW supports spreading a CCK signal on channel 14 391185377Ssam */ 392185377SsamHAL_BOOL 393185377Ssamar5212IsJapanChannelSpreadSupported(struct ath_hal *ah) 394185377Ssam{ 395185377Ssam return AH_TRUE; 396185377Ssam} 397185377Ssam 398185377Ssam/* 399185377Ssam * Get the rssi of frame curently being received. 400185377Ssam */ 401185377Ssamuint32_t 402185377Ssamar5212GetCurRssi(struct ath_hal *ah) 403185377Ssam{ 404185377Ssam return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); 405185377Ssam} 406185377Ssam 407185377Ssamu_int 408185377Ssamar5212GetDefAntenna(struct ath_hal *ah) 409185377Ssam{ 410185377Ssam return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); 411185377Ssam} 412185377Ssam 413185377Ssamvoid 414185377Ssamar5212SetDefAntenna(struct ath_hal *ah, u_int antenna) 415185377Ssam{ 416185377Ssam OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); 417185377Ssam} 418185377Ssam 419185377SsamHAL_ANT_SETTING 420185377Ssamar5212GetAntennaSwitch(struct ath_hal *ah) 421185377Ssam{ 422185380Ssam return AH5212(ah)->ah_antControl; 423185377Ssam} 424185377Ssam 425185377SsamHAL_BOOL 426185380Ssamar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting) 427185377Ssam{ 428185380Ssam struct ath_hal_5212 *ahp = AH5212(ah); 429187831Ssam const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 430185377Ssam 431187831Ssam if (!ahp->ah_phyPowerOn || chan == AH_NULL) { 432185380Ssam /* PHY powered off, just stash settings */ 433185380Ssam ahp->ah_antControl = setting; 434185380Ssam ahp->ah_diversity = (setting == HAL_ANT_VARIABLE); 435185377Ssam return AH_TRUE; 436185377Ssam } 437187831Ssam return ar5212SetAntennaSwitchInternal(ah, setting, chan); 438185377Ssam} 439185377Ssam 440185377SsamHAL_BOOL 441185377Ssamar5212IsSleepAfterBeaconBroken(struct ath_hal *ah) 442185377Ssam{ 443185377Ssam return AH_TRUE; 444185377Ssam} 445185377Ssam 446185377SsamHAL_BOOL 447185377Ssamar5212SetSifsTime(struct ath_hal *ah, u_int us) 448185377Ssam{ 449185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 450185377Ssam 451185377Ssam if (us > ath_hal_mac_usec(ah, 0xffff)) { 452185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", 453185377Ssam __func__, us); 454185377Ssam ahp->ah_sifstime = (u_int) -1; /* restore default handling */ 455185377Ssam return AH_FALSE; 456185377Ssam } else { 457185377Ssam /* convert to system clocks */ 458188866Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us-2)); 459218409Sadrian ahp->ah_sifstime = us; 460185377Ssam return AH_TRUE; 461185377Ssam } 462185377Ssam} 463185377Ssam 464185377Ssamu_int 465185377Ssamar5212GetSifsTime(struct ath_hal *ah) 466185377Ssam{ 467185377Ssam u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; 468188866Ssam return ath_hal_mac_usec(ah, clks)+2; /* convert from system clocks */ 469185377Ssam} 470185377Ssam 471185377SsamHAL_BOOL 472185377Ssamar5212SetSlotTime(struct ath_hal *ah, u_int us) 473185377Ssam{ 474185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 475185377Ssam 476185377Ssam if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) { 477185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", 478185377Ssam __func__, us); 479185377Ssam ahp->ah_slottime = (u_int) -1; /* restore default handling */ 480185377Ssam return AH_FALSE; 481185377Ssam } else { 482185377Ssam /* convert to system clocks */ 483185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); 484185377Ssam ahp->ah_slottime = us; 485185377Ssam return AH_TRUE; 486185377Ssam } 487185377Ssam} 488185377Ssam 489185377Ssamu_int 490185377Ssamar5212GetSlotTime(struct ath_hal *ah) 491185377Ssam{ 492185377Ssam u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; 493185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 494185377Ssam} 495185377Ssam 496185377SsamHAL_BOOL 497185377Ssamar5212SetAckTimeout(struct ath_hal *ah, u_int us) 498185377Ssam{ 499185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 500185377Ssam 501185377Ssam if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { 502185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", 503185377Ssam __func__, us); 504185377Ssam ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ 505185377Ssam return AH_FALSE; 506185377Ssam } else { 507185377Ssam /* convert to system clocks */ 508185377Ssam OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 509185377Ssam AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); 510185377Ssam ahp->ah_acktimeout = us; 511185377Ssam return AH_TRUE; 512185377Ssam } 513185377Ssam} 514185377Ssam 515185377Ssamu_int 516185377Ssamar5212GetAckTimeout(struct ath_hal *ah) 517185377Ssam{ 518185377Ssam u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); 519185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 520185377Ssam} 521185377Ssam 522185377Ssamu_int 523185377Ssamar5212GetAckCTSRate(struct ath_hal *ah) 524185377Ssam{ 525185377Ssam return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); 526185377Ssam} 527185377Ssam 528185377SsamHAL_BOOL 529185377Ssamar5212SetAckCTSRate(struct ath_hal *ah, u_int high) 530185377Ssam{ 531185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 532185377Ssam 533185377Ssam if (high) { 534185377Ssam OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 535185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; 536185377Ssam } else { 537185377Ssam OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 538185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; 539185377Ssam } 540185377Ssam return AH_TRUE; 541185377Ssam} 542185377Ssam 543185377SsamHAL_BOOL 544185377Ssamar5212SetCTSTimeout(struct ath_hal *ah, u_int us) 545185377Ssam{ 546185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 547185377Ssam 548185377Ssam if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { 549185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", 550185377Ssam __func__, us); 551185377Ssam ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ 552185377Ssam return AH_FALSE; 553185377Ssam } else { 554185377Ssam /* convert to system clocks */ 555185377Ssam OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 556185377Ssam AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); 557185377Ssam ahp->ah_ctstimeout = us; 558185377Ssam return AH_TRUE; 559185377Ssam } 560185377Ssam} 561185377Ssam 562185377Ssamu_int 563185377Ssamar5212GetCTSTimeout(struct ath_hal *ah) 564185377Ssam{ 565185377Ssam u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); 566185377Ssam return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 567185377Ssam} 568185377Ssam 569185377Ssam/* Setup decompression for given key index */ 570185377SsamHAL_BOOL 571185377Ssamar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 572185377Ssam{ 573185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 574185377Ssam 575185377Ssam if (keyidx >= HAL_DECOMP_MASK_SIZE) 576229740Sdim return AH_FALSE; 577185377Ssam OS_REG_WRITE(ah, AR_DCM_A, keyidx); 578185377Ssam OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0); 579185377Ssam ahp->ah_decompMask[keyidx] = en; 580185377Ssam 581185377Ssam return AH_TRUE; 582185377Ssam} 583185377Ssam 584185377Ssam/* Setup coverage class */ 585185377Ssamvoid 586185377Ssamar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 587185377Ssam{ 588185377Ssam uint32_t slot, timeout, eifs; 589185377Ssam u_int clkRate; 590185377Ssam 591185377Ssam AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 592185377Ssam 593185377Ssam if (now) { 594185377Ssam if (AH_PRIVATE(ah)->ah_coverageClass == 0) 595185377Ssam return; 596185377Ssam 597185377Ssam /* Don't apply coverage class to non A channels */ 598187831Ssam if (!IEEE80211_IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan)) 599185377Ssam return; 600185377Ssam 601185377Ssam /* Get core clock rate */ 602185377Ssam clkRate = ath_hal_mac_clks(ah, 1); 603185377Ssam 604185377Ssam /* Compute EIFS */ 605185377Ssam slot = coverageclass * 3 * clkRate; 606185377Ssam eifs = coverageclass * 6 * clkRate; 607187831Ssam if (IEEE80211_IS_CHAN_HALF(AH_PRIVATE(ah)->ah_curchan)) { 608185377Ssam slot += IFS_SLOT_HALF_RATE; 609185377Ssam eifs += IFS_EIFS_HALF_RATE; 610187831Ssam } else if (IEEE80211_IS_CHAN_QUARTER(AH_PRIVATE(ah)->ah_curchan)) { 611185377Ssam slot += IFS_SLOT_QUARTER_RATE; 612185377Ssam eifs += IFS_EIFS_QUARTER_RATE; 613185377Ssam } else { /* full rate */ 614185377Ssam slot += IFS_SLOT_FULL_RATE; 615185377Ssam eifs += IFS_EIFS_FULL_RATE; 616185377Ssam } 617185377Ssam 618185377Ssam /* 619185377Ssam * Add additional time for air propagation for ACK and CTS 620185377Ssam * timeouts. This value is in core clocks. 621185377Ssam */ 622185377Ssam timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate); 623185377Ssam 624185377Ssam /* 625185377Ssam * Write the values: slot, eifs, ack/cts timeouts. 626185377Ssam */ 627185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); 628185377Ssam OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); 629185377Ssam OS_REG_WRITE(ah, AR_TIME_OUT, 630185377Ssam SM(timeout, AR_TIME_OUT_CTS) 631185377Ssam | SM(timeout, AR_TIME_OUT_ACK)); 632185377Ssam } 633185377Ssam} 634185377Ssam 635222644SadrianHAL_STATUS 636222644Sadrianar5212SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration, 637222644Sadrian uint32_t nextStart, HAL_QUIET_FLAG flag) 638222644Sadrian{ 639222644Sadrian OS_REG_WRITE(ah, AR_QUIET2, period | (duration << AR_QUIET2_QUIET_DUR_S)); 640222644Sadrian if (flag & HAL_QUIET_ENABLE) { 641222644Sadrian OS_REG_WRITE(ah, AR_QUIET1, nextStart | (1 << 16)); 642222644Sadrian } 643222644Sadrian else { 644222644Sadrian OS_REG_WRITE(ah, AR_QUIET1, nextStart); 645222644Sadrian } 646222644Sadrian return HAL_OK; 647222644Sadrian} 648222644Sadrian 649185377Ssamvoid 650185377Ssamar5212SetPCUConfig(struct ath_hal *ah) 651185377Ssam{ 652185377Ssam ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); 653185377Ssam} 654185377Ssam 655185377Ssam/* 656185377Ssam * Return whether an external 32KHz crystal should be used 657185377Ssam * to reduce power consumption when sleeping. We do so if 658185377Ssam * the crystal is present (obtained from EEPROM) and if we 659185377Ssam * are not running as an AP and are configured to use it. 660185377Ssam */ 661185377SsamHAL_BOOL 662185377Ssamar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode) 663185377Ssam{ 664185377Ssam if (opmode != HAL_M_HOSTAP) { 665185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 666185377Ssam return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) && 667185377Ssam (ahp->ah_enable32kHzClock == USE_32KHZ || 668185377Ssam ahp->ah_enable32kHzClock == AUTO_32KHZ); 669185377Ssam } else 670185377Ssam return AH_FALSE; 671185377Ssam} 672185377Ssam 673185377Ssam/* 674185377Ssam * If 32KHz clock exists, use it to lower power consumption during sleep 675185377Ssam * 676185377Ssam * Note: If clock is set to 32 KHz, delays on accessing certain 677185377Ssam * baseband registers (27-31, 124-127) are required. 678185377Ssam */ 679185377Ssamvoid 680185377Ssamar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) 681185377Ssam{ 682185377Ssam if (ar5212Use32KHzclock(ah, opmode)) { 683185377Ssam /* 684185377Ssam * Enable clocks to be turned OFF in BB during sleep 685185377Ssam * and also enable turning OFF 32MHz/40MHz Refclk 686185377Ssam * from A2. 687185377Ssam */ 688185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 689185380Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 690185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 691185377Ssam OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); 692185377Ssam OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ 693185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1); 694185377Ssam 695185377Ssam if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) { 696185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26); 697185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d); 698185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07); 699185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f); 700185377Ssam /* # Set sleep clock rate to 32 KHz. */ 701185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2); 702185377Ssam } else { 703185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a); 704185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); 705185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); 706185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20); 707185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3); 708185377Ssam } 709185377Ssam } else { 710185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0); 711185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 712185377Ssam 713185377Ssam OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */ 714185377Ssam 715185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 716185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 717185377Ssam 718185377Ssam if (IS_2417(ah)) 719185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a); 720185377Ssam else if (IS_HB63(ah)) 721185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32); 722185377Ssam else 723185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 724185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 725185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 726185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 727185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18); 728185380Ssam OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 729185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 730185377Ssam } 731185377Ssam} 732185377Ssam 733185377Ssam/* 734185377Ssam * If 32KHz clock exists, turn it off and turn back on the 32Mhz 735185377Ssam */ 736185377Ssamvoid 737185377Ssamar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) 738185377Ssam{ 739185377Ssam if (ar5212Use32KHzclock(ah, opmode)) { 740185377Ssam /* # Set sleep clock rate back to 32 MHz. */ 741185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0); 742185377Ssam OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 743185377Ssam 744185377Ssam OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ 745185380Ssam OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 746185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 747185377Ssam 748185377Ssam /* 749185377Ssam * Restore BB registers to power-on defaults 750185377Ssam */ 751185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 752185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 753185377Ssam OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 754185377Ssam OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 755185377Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 756185380Ssam OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 757185380Ssam IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 758185377Ssam } 759185377Ssam} 760185377Ssam 761185377Ssam/* 762185377Ssam * Adjust NF based on statistical values for 5GHz frequencies. 763185377Ssam * Default method: this may be overridden by the rf backend. 764185377Ssam */ 765185377Ssamint16_t 766185377Ssamar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 767185377Ssam{ 768185377Ssam static const struct { 769185377Ssam uint16_t freqLow; 770185377Ssam int16_t adjust; 771185377Ssam } adjustDef[] = { 772185377Ssam { 5790, 11 }, /* NB: ordered high -> low */ 773185377Ssam { 5730, 10 }, 774185377Ssam { 5690, 9 }, 775185377Ssam { 5660, 8 }, 776185377Ssam { 5610, 7 }, 777185377Ssam { 5530, 5 }, 778185377Ssam { 5450, 4 }, 779185377Ssam { 5379, 2 }, 780185377Ssam { 5209, 0 }, 781185377Ssam { 3000, 1 }, 782185377Ssam { 0, 0 }, 783185377Ssam }; 784185377Ssam int i; 785185377Ssam 786185377Ssam for (i = 0; c->channel <= adjustDef[i].freqLow; i++) 787185377Ssam ; 788185377Ssam return adjustDef[i].adjust; 789185377Ssam} 790185377Ssam 791185377SsamHAL_STATUS 792185377Ssamar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 793185377Ssam uint32_t capability, uint32_t *result) 794185377Ssam{ 795185377Ssam#define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion 796185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 797185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 798185377Ssam const struct ar5212AniState *ani; 799185377Ssam 800185377Ssam switch (type) { 801185377Ssam case HAL_CAP_CIPHER: /* cipher handled in hardware */ 802185377Ssam switch (capability) { 803185377Ssam case HAL_CIPHER_AES_CCM: 804185377Ssam return pCap->halCipherAesCcmSupport ? 805185377Ssam HAL_OK : HAL_ENOTSUPP; 806185377Ssam case HAL_CIPHER_AES_OCB: 807185377Ssam case HAL_CIPHER_TKIP: 808185377Ssam case HAL_CIPHER_WEP: 809185377Ssam case HAL_CIPHER_MIC: 810185377Ssam case HAL_CIPHER_CLR: 811185377Ssam return HAL_OK; 812185377Ssam default: 813185377Ssam return HAL_ENOTSUPP; 814185377Ssam } 815185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 816185377Ssam switch (capability) { 817185377Ssam case 0: /* hardware capability */ 818185377Ssam return HAL_OK; 819185377Ssam case 1: 820185377Ssam return (ahp->ah_staId1Defaults & 821185377Ssam AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO; 822185377Ssam } 823185907Ssam return HAL_EINVAL; 824185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 825185377Ssam switch (capability) { 826185377Ssam case 0: /* hardware capability */ 827185377Ssam return pCap->halTkipMicTxRxKeySupport ? 828185377Ssam HAL_ENXIO : HAL_OK; 829185377Ssam case 1: /* current setting */ 830185377Ssam return (ahp->ah_miscMode & 831185377Ssam AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; 832185377Ssam } 833185377Ssam return HAL_EINVAL; 834185377Ssam case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ 835185377Ssam /* XXX move to capability bit */ 836185377Ssam return MACVERSION(ah) > AR_SREV_VERSION_VENICE || 837185377Ssam (MACVERSION(ah) == AR_SREV_VERSION_VENICE && 838185377Ssam AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; 839185377Ssam case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 840185377Ssam switch (capability) { 841185377Ssam case 0: /* hardware capability */ 842185377Ssam return HAL_OK; 843185377Ssam case 1: /* current setting */ 844185380Ssam return ahp->ah_diversity ? HAL_OK : HAL_ENXIO; 845185377Ssam } 846185377Ssam return HAL_EINVAL; 847185377Ssam case HAL_CAP_DIAG: 848185377Ssam *result = AH_PRIVATE(ah)->ah_diagreg; 849185377Ssam return HAL_OK; 850185377Ssam case HAL_CAP_TPC: 851185377Ssam switch (capability) { 852185377Ssam case 0: /* hardware capability */ 853185377Ssam return HAL_OK; 854185377Ssam case 1: 855185377Ssam return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; 856185377Ssam } 857185377Ssam return HAL_OK; 858185377Ssam case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ 859185377Ssam switch (capability) { 860185377Ssam case HAL_CAP_RADAR: 861185377Ssam return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? 862185377Ssam HAL_OK: HAL_ENXIO; 863185377Ssam case HAL_CAP_AR: 864185377Ssam return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || 865185377Ssam ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? 866185377Ssam HAL_OK: HAL_ENXIO; 867185377Ssam } 868185377Ssam return HAL_ENXIO; 869185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 870185377Ssam switch (capability) { 871185377Ssam case 0: /* hardware capability */ 872222027Sadrian return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENXIO; 873185377Ssam case 1: 874185377Ssam return (ahp->ah_staId1Defaults & 875185377Ssam AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; 876185377Ssam } 877185377Ssam return HAL_EINVAL; 878185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 879185377Ssam switch (capability) { 880185377Ssam case 0: /* hardware capability */ 881185377Ssam return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; 882185377Ssam case 1: 883185377Ssam return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? 884185377Ssam HAL_OK : HAL_ENXIO; 885185377Ssam } 886185377Ssam return HAL_EINVAL; 887185377Ssam case HAL_CAP_TPC_ACK: 888185377Ssam *result = MS(ahp->ah_macTPC, AR_TPC_ACK); 889185377Ssam return HAL_OK; 890185377Ssam case HAL_CAP_TPC_CTS: 891185377Ssam *result = MS(ahp->ah_macTPC, AR_TPC_CTS); 892185377Ssam return HAL_OK; 893185377Ssam case HAL_CAP_INTMIT: /* interference mitigation */ 894185377Ssam switch (capability) { 895222277Sadrian case HAL_CAP_INTMIT_PRESENT: /* hardware capability */ 896185377Ssam return HAL_OK; 897222277Sadrian case HAL_CAP_INTMIT_ENABLE: 898185377Ssam return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? 899185377Ssam HAL_OK : HAL_ENXIO; 900222277Sadrian case HAL_CAP_INTMIT_NOISE_IMMUNITY_LEVEL: 901222277Sadrian case HAL_CAP_INTMIT_OFDM_WEAK_SIGNAL_LEVEL: 902222277Sadrian case HAL_CAP_INTMIT_CCK_WEAK_SIGNAL_THR: 903222277Sadrian case HAL_CAP_INTMIT_FIRSTEP_LEVEL: 904222277Sadrian case HAL_CAP_INTMIT_SPUR_IMMUNITY_LEVEL: 905185377Ssam ani = ar5212AniGetCurrentState(ah); 906185377Ssam if (ani == AH_NULL) 907185377Ssam return HAL_ENXIO; 908185377Ssam switch (capability) { 909185377Ssam case 2: *result = ani->noiseImmunityLevel; break; 910185377Ssam case 3: *result = !ani->ofdmWeakSigDetectOff; break; 911185377Ssam case 4: *result = ani->cckWeakSigThreshold; break; 912185377Ssam case 5: *result = ani->firstepLevel; break; 913185377Ssam case 6: *result = ani->spurImmunityLevel; break; 914185377Ssam } 915185377Ssam return HAL_OK; 916185377Ssam } 917185377Ssam return HAL_EINVAL; 918185377Ssam default: 919185377Ssam return ath_hal_getcapability(ah, type, capability, result); 920185377Ssam } 921185377Ssam#undef MACVERSION 922185377Ssam} 923185377Ssam 924185377SsamHAL_BOOL 925185377Ssamar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 926185377Ssam uint32_t capability, uint32_t setting, HAL_STATUS *status) 927185377Ssam{ 928185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 929185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 930185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 931185377Ssam uint32_t v; 932185377Ssam 933185377Ssam switch (type) { 934185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 935185377Ssam if (setting) 936185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; 937185377Ssam else 938185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; 939185377Ssam return AH_TRUE; 940185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 941185377Ssam if (!pCap->halTkipMicTxRxKeySupport) 942185377Ssam return AH_FALSE; 943185377Ssam /* NB: true =>'s use split key cache layout */ 944185377Ssam if (setting) 945185377Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 946185377Ssam else 947185377Ssam ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 948185377Ssam /* NB: write here so keys can be setup w/o a reset */ 949219771Sadrian OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); 950185377Ssam return AH_TRUE; 951185377Ssam case HAL_CAP_DIVERSITY: 952185380Ssam if (ahp->ah_phyPowerOn) { 953185380Ssam v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 954185380Ssam if (setting) 955185380Ssam v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 956185380Ssam else 957185380Ssam v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 958185380Ssam OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); 959185380Ssam } 960185380Ssam ahp->ah_diversity = (setting != 0); 961185377Ssam return AH_TRUE; 962185377Ssam case HAL_CAP_DIAG: /* hardware diagnostic support */ 963185377Ssam /* 964185377Ssam * NB: could split this up into virtual capabilities, 965185377Ssam * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly 966185377Ssam * seems worth the additional complexity. 967185377Ssam */ 968185377Ssam AH_PRIVATE(ah)->ah_diagreg = setting; 969185377Ssam OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 970185377Ssam return AH_TRUE; 971185377Ssam case HAL_CAP_TPC: 972185377Ssam ahp->ah_tpcEnabled = (setting != 0); 973185377Ssam return AH_TRUE; 974185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 975185377Ssam if (setting) 976185377Ssam ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; 977185377Ssam else 978185377Ssam ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; 979185377Ssam return AH_TRUE; 980185377Ssam case HAL_CAP_TPC_ACK: 981185377Ssam case HAL_CAP_TPC_CTS: 982185377Ssam setting += ahp->ah_txPowerIndexOffset; 983185377Ssam if (setting > 63) 984185377Ssam setting = 63; 985185377Ssam if (type == HAL_CAP_TPC_ACK) { 986185377Ssam ahp->ah_macTPC &= AR_TPC_ACK; 987185377Ssam ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); 988185377Ssam } else { 989185377Ssam ahp->ah_macTPC &= AR_TPC_CTS; 990185377Ssam ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); 991185377Ssam } 992185377Ssam OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); 993185377Ssam return AH_TRUE; 994185377Ssam case HAL_CAP_INTMIT: { /* interference mitigation */ 995222277Sadrian /* This maps the public ANI commands to the internal ANI commands */ 996222277Sadrian /* Private: HAL_ANI_CMD; Public: HAL_CAP_INTMIT_CMD */ 997185377Ssam static const HAL_ANI_CMD cmds[] = { 998185377Ssam HAL_ANI_PRESENT, 999185377Ssam HAL_ANI_MODE, 1000185377Ssam HAL_ANI_NOISE_IMMUNITY_LEVEL, 1001185377Ssam HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 1002185377Ssam HAL_ANI_CCK_WEAK_SIGNAL_THR, 1003185377Ssam HAL_ANI_FIRSTEP_LEVEL, 1004185377Ssam HAL_ANI_SPUR_IMMUNITY_LEVEL, 1005185377Ssam }; 1006185377Ssam return capability < N(cmds) ? 1007222265Sadrian AH5212(ah)->ah_aniControl(ah, cmds[capability], setting) : 1008185377Ssam AH_FALSE; 1009185377Ssam } 1010185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 1011185377Ssam if (pCap->halTsfAddSupport) { 1012185377Ssam if (setting) 1013185377Ssam ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; 1014185377Ssam else 1015185377Ssam ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; 1016185377Ssam return AH_TRUE; 1017185377Ssam } 1018185377Ssam /* fall thru... */ 1019185377Ssam default: 1020185377Ssam return ath_hal_setcapability(ah, type, capability, 1021185377Ssam setting, status); 1022185377Ssam } 1023185377Ssam#undef N 1024185377Ssam} 1025185377Ssam 1026185377SsamHAL_BOOL 1027185377Ssamar5212GetDiagState(struct ath_hal *ah, int request, 1028185377Ssam const void *args, uint32_t argsize, 1029185377Ssam void **result, uint32_t *resultsize) 1030185377Ssam{ 1031185377Ssam struct ath_hal_5212 *ahp = AH5212(ah); 1032185377Ssam 1033185377Ssam (void) ahp; 1034185377Ssam if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 1035185377Ssam return AH_TRUE; 1036185377Ssam switch (request) { 1037185377Ssam case HAL_DIAG_EEPROM: 1038185377Ssam case HAL_DIAG_EEPROM_EXP_11A: 1039185377Ssam case HAL_DIAG_EEPROM_EXP_11B: 1040185377Ssam case HAL_DIAG_EEPROM_EXP_11G: 1041185377Ssam case HAL_DIAG_RFGAIN: 1042185377Ssam return ath_hal_eepromDiag(ah, request, 1043185377Ssam args, argsize, result, resultsize); 1044185377Ssam case HAL_DIAG_RFGAIN_CURSTEP: 1045185377Ssam *result = __DECONST(void *, ahp->ah_gainValues.currStep); 1046185377Ssam *resultsize = (*result == AH_NULL) ? 1047185377Ssam 0 : sizeof(GAIN_OPTIMIZATION_STEP); 1048185377Ssam return AH_TRUE; 1049185377Ssam case HAL_DIAG_PCDAC: 1050185377Ssam *result = ahp->ah_pcdacTable; 1051185377Ssam *resultsize = ahp->ah_pcdacTableSize; 1052185377Ssam return AH_TRUE; 1053185377Ssam case HAL_DIAG_TXRATES: 1054185377Ssam *result = &ahp->ah_ratesArray[0]; 1055185377Ssam *resultsize = sizeof(ahp->ah_ratesArray); 1056185377Ssam return AH_TRUE; 1057185377Ssam case HAL_DIAG_ANI_CURRENT: 1058185377Ssam *result = ar5212AniGetCurrentState(ah); 1059185377Ssam *resultsize = (*result == AH_NULL) ? 1060185377Ssam 0 : sizeof(struct ar5212AniState); 1061185377Ssam return AH_TRUE; 1062185377Ssam case HAL_DIAG_ANI_STATS: 1063185377Ssam *result = ar5212AniGetCurrentStats(ah); 1064185377Ssam *resultsize = (*result == AH_NULL) ? 1065185377Ssam 0 : sizeof(struct ar5212Stats); 1066185377Ssam return AH_TRUE; 1067185377Ssam case HAL_DIAG_ANI_CMD: 1068185377Ssam if (argsize != 2*sizeof(uint32_t)) 1069185377Ssam return AH_FALSE; 1070222265Sadrian AH5212(ah)->ah_aniControl(ah, ((const uint32_t *)args)[0], 1071185377Ssam ((const uint32_t *)args)[1]); 1072185377Ssam return AH_TRUE; 1073185377Ssam case HAL_DIAG_ANI_PARAMS: 1074185377Ssam /* 1075185377Ssam * NB: We assume struct ar5212AniParams is identical 1076185377Ssam * to HAL_ANI_PARAMS; if they diverge then we'll need 1077185377Ssam * to handle it here 1078185377Ssam */ 1079185377Ssam if (argsize == 0 && args == AH_NULL) { 1080185377Ssam struct ar5212AniState *aniState = 1081185377Ssam ar5212AniGetCurrentState(ah); 1082185377Ssam if (aniState == AH_NULL) 1083185377Ssam return AH_FALSE; 1084185377Ssam *result = __DECONST(void *, aniState->params); 1085185377Ssam *resultsize = sizeof(struct ar5212AniParams); 1086185377Ssam return AH_TRUE; 1087185377Ssam } else { 1088185377Ssam if (argsize != sizeof(struct ar5212AniParams)) 1089185377Ssam return AH_FALSE; 1090185377Ssam return ar5212AniSetParams(ah, args, args); 1091185377Ssam } 1092185377Ssam } 1093185377Ssam return AH_FALSE; 1094185377Ssam} 1095211206Sadrian 1096211206Sadrian/* 1097211206Sadrian * Check whether there's an in-progress NF completion. 1098211206Sadrian * 1099211206Sadrian * Returns AH_TRUE if there's a in-progress NF calibration, AH_FALSE 1100211206Sadrian * otherwise. 1101211206Sadrian */ 1102211206SadrianHAL_BOOL 1103211206Sadrianar5212IsNFCalInProgress(struct ath_hal *ah) 1104211206Sadrian{ 1105211206Sadrian if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) 1106211206Sadrian return AH_TRUE; 1107211206Sadrian return AH_FALSE; 1108211206Sadrian} 1109211206Sadrian 1110211206Sadrian/* 1111211206Sadrian * Wait for an in-progress NF calibration to complete. 1112211206Sadrian * 1113211206Sadrian * The completion function waits "i" times 10uS. 1114211206Sadrian * It returns AH_TRUE if the NF calibration completed (or was never 1115211206Sadrian * in progress); AH_FALSE if it was still in progress after "i" checks. 1116211206Sadrian */ 1117211206SadrianHAL_BOOL 1118211206Sadrianar5212WaitNFCalComplete(struct ath_hal *ah, int i) 1119211206Sadrian{ 1120211206Sadrian int j; 1121211206Sadrian if (i <= 0) 1122211206Sadrian i = 1; /* it should run at least once */ 1123211206Sadrian for (j = 0; j < i; j++) { 1124211206Sadrian if (! ar5212IsNFCalInProgress(ah)) 1125211206Sadrian return AH_TRUE; 1126211206Sadrian OS_DELAY(10); 1127211206Sadrian } 1128211206Sadrian return AH_FALSE; 1129211206Sadrian} 1130222584Sadrian 1131222584Sadrianvoid 1132222584Sadrianar5212EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 1133222584Sadrian{ 1134222584Sadrian uint32_t val; 1135222584Sadrian val = OS_REG_READ(ah, AR_PHY_RADAR_0); 1136222584Sadrian 1137222584Sadrian if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) { 1138222584Sadrian val &= ~AR_PHY_RADAR_0_FIRPWR; 1139222584Sadrian val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR); 1140222584Sadrian } 1141222584Sadrian if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) { 1142222584Sadrian val &= ~AR_PHY_RADAR_0_RRSSI; 1143222584Sadrian val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI); 1144222584Sadrian } 1145222584Sadrian if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) { 1146222584Sadrian val &= ~AR_PHY_RADAR_0_HEIGHT; 1147222584Sadrian val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT); 1148222584Sadrian } 1149222584Sadrian if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) { 1150222584Sadrian val &= ~AR_PHY_RADAR_0_PRSSI; 1151222584Sadrian val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI); 1152222584Sadrian } 1153222584Sadrian if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) { 1154222584Sadrian val &= ~AR_PHY_RADAR_0_INBAND; 1155222584Sadrian val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND); 1156222584Sadrian } 1157222584Sadrian OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA); 1158222584Sadrian} 1159222584Sadrian 1160222584Sadrianvoid 1161222584Sadrianar5212GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 1162222584Sadrian{ 1163222584Sadrian uint32_t val,temp; 1164222584Sadrian 1165222584Sadrian val = OS_REG_READ(ah, AR_PHY_RADAR_0); 1166222584Sadrian 1167222584Sadrian temp = MS(val,AR_PHY_RADAR_0_FIRPWR); 1168222584Sadrian temp |= 0xFFFFFF80; 1169222584Sadrian pe->pe_firpwr = temp; 1170222584Sadrian pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI); 1171222584Sadrian pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT); 1172222584Sadrian pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI); 1173222584Sadrian pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND); 1174222584Sadrian 1175222584Sadrian pe->pe_relpwr = 0; 1176222584Sadrian pe->pe_relstep = 0; 1177222584Sadrian pe->pe_maxlen = 0; 1178222584Sadrian pe->pe_extchannel = AH_FALSE; 1179222584Sadrian} 1180222584Sadrian 1181222815Sadrian/* 1182222815Sadrian * Process the radar phy error and extract the pulse duration. 1183222815Sadrian */ 1184222815SadrianHAL_BOOL 1185222815Sadrianar5212ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs, 1186222815Sadrian uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event) 1187222815Sadrian{ 1188222815Sadrian uint8_t dur; 1189222815Sadrian uint8_t rssi; 1190222815Sadrian 1191222815Sadrian /* Check whether the given phy error is a radar event */ 1192222815Sadrian if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) && 1193222815Sadrian (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) 1194222815Sadrian return AH_FALSE; 1195222815Sadrian 1196222815Sadrian /* 1197222815Sadrian * The first byte is the pulse width - if there's 1198222815Sadrian * no data, simply set the duration to 0 1199222815Sadrian */ 1200222815Sadrian if (rxs->rs_datalen >= 1) 1201222815Sadrian /* The pulse width is byte 0 of the data */ 1202222815Sadrian dur = ((uint8_t) buf[0]) & 0xff; 1203222815Sadrian else 1204222815Sadrian dur = 0; 1205222815Sadrian 1206222815Sadrian /* Pulse RSSI is the normal reported RSSI */ 1207222815Sadrian rssi = (uint8_t) rxs->rs_rssi; 1208222815Sadrian 1209222815Sadrian /* 0 duration/rssi is not a valid radar event */ 1210222815Sadrian if (dur == 0 && rssi == 0) 1211222815Sadrian return AH_FALSE; 1212222815Sadrian 1213222815Sadrian HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", 1214222815Sadrian __func__, rssi, dur); 1215222815Sadrian 1216222815Sadrian /* Record the event */ 1217222815Sadrian event->re_full_ts = fulltsf; 1218222815Sadrian event->re_ts = rxs->rs_tstamp; 1219222815Sadrian event->re_rssi = rssi; 1220222815Sadrian event->re_dur = dur; 1221222815Sadrian event->re_flags = HAL_DFS_EVENT_PRICH; 1222222815Sadrian 1223222815Sadrian return AH_TRUE; 1224222815Sadrian} 1225224709Sadrian 1226224709Sadrian/* 1227224709Sadrian * Return whether 5GHz fast-clock (44MHz) is enabled. 1228224709Sadrian * It's always disabled for AR5212 series NICs. 1229224709Sadrian */ 1230224709SadrianHAL_BOOL 1231224709Sadrianar5212IsFastClockEnabled(struct ath_hal *ah) 1232224709Sadrian{ 1233224709Sadrian return AH_FALSE; 1234224709Sadrian} 1235