ar5212_misc.c revision 222821
1327952Sdim/* 2212793Sdim * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3353358Sdim * Copyright (c) 2002-2008 Atheros Communications, Inc. 4353358Sdim * 5353358Sdim * Permission to use, copy, modify, and/or distribute this software for any 6212793Sdim * purpose with or without fee is hereby granted, provided that the above 7212793Sdim * copyright notice and this permission notice appear in all copies. 8212793Sdim * 9212793Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10212793Sdim * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11212793Sdim * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12212793Sdim * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13212793Sdim * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14212793Sdim * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15212793Sdim * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16321369Sdim * 17276479Sdim * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c 222821 2011-06-07 14:00:47Z adrian $ 18218893Sdim */ 19249423Sdim#include "opt_ah.h" 20276479Sdim 21276479Sdim#include "ah.h" 22249423Sdim#include "ah_internal.h" 23226633Sdim#include "ah_devid.h" 24321369Sdim#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 25327952Sdim 26321369Sdim#include "ar5212/ar5212.h" 27321369Sdim#include "ar5212/ar5212reg.h" 28321369Sdim#include "ar5212/ar5212phy.h" 29321369Sdim 30321369Sdim#include "ah_eeprom_v3.h" 31212793Sdim 32212793Sdim#define AR_NUM_GPIO 6 /* 6 GPIO pins */ 33321369Sdim#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ 34327952Sdim 35212793Sdimvoid 36212793Sdimar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac) 37327952Sdim{ 38321369Sdim struct ath_hal_5212 *ahp = AH5212(ah); 39249423Sdim 40218893Sdim OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); 41321369Sdim} 42212793Sdim 43321369SdimHAL_BOOL 44327952Sdimar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac) 45327952Sdim{ 46327952Sdim struct ath_hal_5212 *ahp = AH5212(ah); 47327952Sdim 48321369Sdim OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); 49321369Sdim return AH_TRUE; 50321369Sdim} 51276479Sdim 52249423Sdimvoid 53321369Sdimar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask) 54321369Sdim{ 55249423Sdim struct ath_hal_5212 *ahp = AH5212(ah); 56249423Sdim 57321369Sdim OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN); 58276479Sdim} 59321369Sdim 60249423SdimHAL_BOOL 61321369Sdimar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) 62321369Sdim{ 63249423Sdim struct ath_hal_5212 *ahp = AH5212(ah); 64249423Sdim 65327952Sdim /* save it since it must be rewritten on reset */ 66249423Sdim OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN); 67249423Sdim 68321369Sdim OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); 69321369Sdim OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); 70321369Sdim return AH_TRUE; 71321369Sdim} 72321369Sdim 73321369Sdim/* 74321369Sdim * Attempt to change the cards operating regulatory domain to the given value 75212793Sdim */ 76341825SdimHAL_BOOL 77321369Sdimar5212SetRegulatoryDomain(struct ath_hal *ah, 78212793Sdim uint16_t regDomain, HAL_STATUS *status) 79212793Sdim{ 80321369Sdim HAL_STATUS ecode; 81321369Sdim 82321369Sdim if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { 83321369Sdim ecode = HAL_EINVAL; 84212793Sdim goto bad; 85212793Sdim } 86212793Sdim if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { 87212793Sdim ecode = HAL_EEWRITE; 88218893Sdim goto bad; 89327952Sdim } 90218893Sdim#ifdef AH_SUPPORT_WRITE_REGDOMAIN 91218893Sdim if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { 92218893Sdim HALDEBUG(ah, HAL_DEBUG_ANY, 93321369Sdim "%s: set regulatory domain to %u (0x%x)\n", 94218893Sdim __func__, regDomain, regDomain); 95218893Sdim AH_PRIVATE(ah)->ah_currentRD = regDomain; 96218893Sdim return AH_TRUE; 97218893Sdim } 98218893Sdim#endif 99218893Sdim ecode = HAL_EIO; 100321369Sdimbad: 101218893Sdim if (status) 102218893Sdim *status = ecode; 103321369Sdim return AH_FALSE; 104321369Sdim} 105321369Sdim 106327952Sdim/* 107218893Sdim * Return the wireless modes (a,b,g,t) supported by hardware. 108276479Sdim * 109212793Sdim * This value is what is actually supported by the hardware 110212793Sdim * and is unaffected by regulatory/country code settings. 111212793Sdim */ 112276479Sdimu_int 113212793Sdimar5212GetWirelessModes(struct ath_hal *ah) 114212793Sdim{ 115212793Sdim u_int mode = 0; 116218893Sdim 117212793Sdim if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { 118218893Sdim mode = HAL_MODE_11A; 119234353Sdim if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) 120218893Sdim mode |= HAL_MODE_TURBO | HAL_MODE_108A; 121212793Sdim if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 122212793Sdim mode |= HAL_MODE_11A_HALF_RATE; 123239462Sdim if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 124239462Sdim mode |= HAL_MODE_11A_QUARTER_RATE; 125280031Sdim } 126288943Sdim if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) 127288943Sdim mode |= HAL_MODE_11B; 128280031Sdim if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && 129288943Sdim AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { 130288943Sdim mode |= HAL_MODE_11G; 131212793Sdim if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) 132234353Sdim mode |= HAL_MODE_108G; 133218893Sdim if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 134212793Sdim mode |= HAL_MODE_11G_HALF_RATE; 135212793Sdim if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 136321369Sdim mode |= HAL_MODE_11G_QUARTER_RATE; 137212793Sdim } 138321369Sdim return mode; 139280031Sdim} 140243830Sdim 141243830Sdim/* 142280031Sdim * Set the interrupt and GPIO values so the ISR can disable RF 143243830Sdim * on a switch signal. Assumes GPIO port and interrupt polarity 144243830Sdim * are set prior to call. 145243830Sdim */ 146280031Sdimvoid 147243830Sdimar5212EnableRfKill(struct ath_hal *ah) 148243830Sdim{ 149243830Sdim uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; 150280031Sdim int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); 151243830Sdim int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); 152243830Sdim 153221345Sdim /* 154212793Sdim * Configure the desired GPIO port for input 155321369Sdim * and enable baseband rf silence. 156280031Sdim */ 157280031Sdim ath_hal_gpioCfgInput(ah, select); 158280031Sdim OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000); 159276479Sdim /* 160276479Sdim * If radio disable switch connection to GPIO bit x is enabled 161280031Sdim * program GPIO interrupt. 162321369Sdim * If rfkill bit on eeprom is 1, setupeeprommap routine has already 163212793Sdim * verified that it is a later version of eeprom, it has a place for 164218893Sdim * rfkill bit and it is set to 1, indicating that GPIO bit x hardware 165212793Sdim * connection is present. 166321369Sdim */ 167218893Sdim ath_hal_gpioSetIntr(ah, select, 168218893Sdim (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity)); 169218893Sdim} 170234353Sdim 171218893Sdim/* 172218893Sdim * Change the LED blinking pattern to correspond to the connectivity 173218893Sdim */ 174234353Sdimvoid 175234353Sdimar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 176234353Sdim{ 177234353Sdim static const uint32_t ledbits[8] = { 178234353Sdim AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */ 179234353Sdim AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */ 180234353Sdim AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */ 181234353Sdim AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/ 182218893Sdim AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */ 183218893Sdim AR_PCICFG_LEDCTL_NONE, 184234353Sdim AR_PCICFG_LEDCTL_NONE, 185234353Sdim AR_PCICFG_LEDCTL_NONE, 186239462Sdim }; 187212793Sdim uint32_t bits; 188212793Sdim 189321369Sdim bits = OS_REG_READ(ah, AR_PCICFG); 190309124Sdim if (IS_2417(ah)) { 191226633Sdim /* 192226633Sdim * Enable LED for Nala. There is a bit marked reserved 193234353Sdim * that must be set and we also turn on the power led. 194360784Sdim * Because we mark s/w LED control setting the control 195360784Sdim * status bits below is meangless (the driver must flash 196234353Sdim * the LED(s) using the GPIO lines). 197234353Sdim */ 198249423Sdim bits = (bits &~ AR_PCICFG_LEDMODE) 199234353Sdim | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE) 200218893Sdim#if 0 201249423Sdim | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE) 202234353Sdim#endif 203249423Sdim | 0x08000000; 204249423Sdim } 205249423Sdim bits = (bits &~ AR_PCICFG_LEDCTL) 206249423Sdim | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL); 207249423Sdim OS_REG_WRITE(ah, AR_PCICFG, bits); 208249423Sdim} 209249423Sdim 210249423Sdim/* 211239462Sdim * Change association related fields programmed into the hardware. 212249423Sdim * Writing a valid BSSID to the hardware effectively enables the hardware 213218893Sdim * to synchronize its TSF to the correct beacons and receive frames coming 214288943Sdim * from that BSSID. It is called by the SME JOIN operation. 215276479Sdim */ 216218893Sdimvoid 217321369Sdimar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) 218239462Sdim{ 219239462Sdim struct ath_hal_5212 *ahp = AH5212(ah); 220239462Sdim 221218893Sdim /* XXX save bssid for possible re-use on reset */ 222360784Sdim OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); 223218893Sdim OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 224218893Sdim OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | 225360784Sdim ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); 226218893Sdim} 227239462Sdim 228239462Sdim/* 229239462Sdim * Get the current hardware tsf for stamlme 230360784Sdim */ 231218893Sdimuint64_t 232239462Sdimar5212GetTsf64(struct ath_hal *ah) 233218893Sdim{ 234218893Sdim uint32_t low1, low2, u32; 235218893Sdim 236321369Sdim /* sync multi-word read */ 237221345Sdim low1 = OS_REG_READ(ah, AR_TSF_L32); 238212793Sdim u32 = OS_REG_READ(ah, AR_TSF_U32); 239212793Sdim low2 = OS_REG_READ(ah, AR_TSF_L32); 240249423Sdim if (low2 < low1) { /* roll over */ 241223017Sdim /* 242309124Sdim * If we are not preempted this will work. If we are 243212793Sdim * then we re-reading AR_TSF_U32 does no good as the 244212793Sdim * low bits will be meaningless. Likewise reading 245212793Sdim * L32, U32, U32, then comparing the last two reads 246212793Sdim * to check for rollover doesn't help if preempted--so 247212793Sdim * we take this approach as it costs one less PCI read 248212793Sdim * which can be noticeable when doing things like 249212793Sdim * timestamping packets in monitor mode. 250212793Sdim */ 251234353Sdim u32++; 252212793Sdim } 253212793Sdim return (((uint64_t) u32) << 32) | ((uint64_t) low2); 254212793Sdim} 255321369Sdim 256212793Sdim/* 257212793Sdim * Get the current hardware tsf for stamlme 258212793Sdim */ 259212793Sdimuint32_t 260212793Sdimar5212GetTsf32(struct ath_hal *ah) 261212793Sdim{ 262212793Sdim return OS_REG_READ(ah, AR_TSF_L32); 263221345Sdim} 264224145Sdim 265221345Sdimvoid 266261991Sdimar5212SetTsf64(struct ath_hal *ah, uint64_t tsf64) 267224145Sdim{ 268221345Sdim OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); 269261991Sdim OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); 270221345Sdim} 271321369Sdim 272321369Sdim/* 273221345Sdim * Reset the current hardware tsf for stamlme. 274221345Sdim */ 275221345Sdimvoid 276221345Sdimar5212ResetTsf(struct ath_hal *ah) 277221345Sdim{ 278212793Sdim 279212793Sdim uint32_t val = OS_REG_READ(ah, AR_BEACON); 280218893Sdim 281218893Sdim OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 282218893Sdim /* 283212793Sdim * When resetting the TSF, write twice to the 284212793Sdim * corresponding register; each write to the RESET_TSF bit toggles 285212793Sdim * the internal signal to cause a reset of the TSF - but if the signal 286212793Sdim * is left high, it will reset the TSF on the next chip reset also! 287221345Sdim * writing the bit an even number of times fixes this issue 288221345Sdim */ 289221345Sdim OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 290261991Sdim} 291321369Sdim 292218893Sdim/* 293212793Sdim * Set or clear hardware basic rate bit 294212793Sdim * Set hardware basic rate set if basic rate is found 295212793Sdim * and basic rate is equal or less than 2Mbps 296321369Sdim */ 297321369Sdimvoid 298212793Sdimar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs) 299212793Sdim{ 300212793Sdim const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 301280031Sdim uint32_t reg; 302212793Sdim uint8_t xset; 303212793Sdim int i; 304360784Sdim 305224145Sdim if (chan == AH_NULL || !IEEE80211_IS_CHAN_CCK(chan)) 306212793Sdim return; 307261991Sdim xset = 0; 308261991Sdim for (i = 0; i < rs->rs_count; i++) { 309261991Sdim uint8_t rset = rs->rs_rates[i]; 310234353Sdim /* Basic rate defined? */ 311276479Sdim if ((rset & 0x80) && (rset &= 0x7f) >= xset) 312276479Sdim xset = rset; 313234353Sdim } 314276479Sdim /* 315212793Sdim * Set the h/w bit to reflect whether or not the basic 316276479Sdim * rate is found to be equal or less than 2Mbps. 317212793Sdim */ 318212793Sdim reg = OS_REG_READ(ah, AR_STA_ID1); 319212793Sdim if (xset && xset/2 <= 2) 320212793Sdim OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B); 321212793Sdim else 322212793Sdim OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B); 323280031Sdim} 324212793Sdim 325212793Sdim/* 326212793Sdim * Grab a semi-random value from hardware registers - may not 327212793Sdim * change often 328224145Sdim */ 329212793Sdimuint32_t 330261991Sdimar5212GetRandomSeed(struct ath_hal *ah) 331261991Sdim{ 332261991Sdim uint32_t nf; 333261991Sdim 334261991Sdim nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; 335234353Sdim if (nf & 0x100) 336276479Sdim nf = 0 - ((nf ^ 0x1ff) + 1); 337276479Sdim return (OS_REG_READ(ah, AR_TSF_U32) ^ 338276479Sdim OS_REG_READ(ah, AR_TSF_L32) ^ nf); 339276479Sdim} 340234353Sdim 341276479Sdim/* 342212793Sdim * Detect if our card is present 343212793Sdim */ 344276479SdimHAL_BOOL 345212793Sdimar5212DetectCardPresent(struct ath_hal *ah) 346212793Sdim{ 347212793Sdim uint16_t macVersion, macRev; 348212793Sdim uint32_t v; 349212793Sdim 350212793Sdim /* 351280031Sdim * Read the Silicon Revision register and compare that 352212793Sdim * to what we read at attach time. If the same, we say 353212793Sdim * a card/device is present. 354212793Sdim */ 355212793Sdim v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; 356224145Sdim macVersion = v >> AR_SREV_ID_S; 357212793Sdim macRev = v & AR_SREV_REVISION; 358261991Sdim return (AH_PRIVATE(ah)->ah_macVersion == macVersion && 359261991Sdim AH_PRIVATE(ah)->ah_macRev == macRev); 360261991Sdim} 361234353Sdim 362276479Sdimvoid 363276479Sdimar5212EnableMibCounters(struct ath_hal *ah) 364276479Sdim{ 365276479Sdim /* NB: this just resets the mib counter machinery */ 366234353Sdim OS_REG_WRITE(ah, AR_MIBC, 367276479Sdim ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 368212793Sdim} 369212793Sdim 370276479Sdimvoid 371212793Sdimar5212DisableMibCounters(struct ath_hal *ah) 372212793Sdim{ 373212793Sdim OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC); 374212793Sdim} 375212793Sdim 376212793Sdim/* 377280031Sdim * Update MIB Counters 378212793Sdim */ 379212793Sdimvoid 380212793Sdimar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats) 381224145Sdim{ 382218893Sdim stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); 383234353Sdim stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); 384276479Sdim stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); 385276479Sdim stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); 386234353Sdim stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); 387276479Sdim} 388212793Sdim 389276479Sdim/* 390212793Sdim * Detect if the HW supports spreading a CCK signal on channel 14 391212793Sdim */ 392212793SdimHAL_BOOL 393212793Sdimar5212IsJapanChannelSpreadSupported(struct ath_hal *ah) 394212793Sdim{ 395212793Sdim return AH_TRUE; 396218893Sdim} 397218893Sdim 398249423Sdim/* 399218893Sdim * Get the rssi of frame curently being received. 400212793Sdim */ 401218893Sdimuint32_t 402276479Sdimar5212GetCurRssi(struct ath_hal *ah) 403234353Sdim{ 404218893Sdim return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); 405218893Sdim} 406218893Sdim 407212793Sdimu_int 408249423Sdimar5212GetDefAntenna(struct ath_hal *ah) 409218893Sdim{ 410218893Sdim return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); 411218893Sdim} 412276479Sdim 413234353Sdimvoid 414218893Sdimar5212SetDefAntenna(struct ath_hal *ah, u_int antenna) 415218893Sdim{ 416218893Sdim OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); 417218893Sdim} 418218893Sdim 419218893SdimHAL_ANT_SETTING 420218893Sdimar5212GetAntennaSwitch(struct ath_hal *ah) 421249423Sdim{ 422218893Sdim return AH5212(ah)->ah_antControl; 423218893Sdim} 424218893Sdim 425218893SdimHAL_BOOL 426218893Sdimar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting) 427218893Sdim{ 428226633Sdim struct ath_hal_5212 *ahp = AH5212(ah); 429226633Sdim const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 430226633Sdim 431226633Sdim if (!ahp->ah_phyPowerOn || chan == AH_NULL) { 432226633Sdim /* PHY powered off, just stash settings */ 433226633Sdim ahp->ah_antControl = setting; 434226633Sdim ahp->ah_diversity = (setting == HAL_ANT_VARIABLE); 435226633Sdim return AH_TRUE; 436226633Sdim } 437218893Sdim return ar5212SetAntennaSwitchInternal(ah, setting, chan); 438276479Sdim} 439276479Sdim 440218893SdimHAL_BOOL 441218893Sdimar5212IsSleepAfterBeaconBroken(struct ath_hal *ah) 442218893Sdim{ 443218893Sdim return AH_TRUE; 444353358Sdim} 445218893Sdim 446212793SdimHAL_BOOL 447276479Sdimar5212SetSifsTime(struct ath_hal *ah, u_int us) 448218893Sdim{ 449218893Sdim struct ath_hal_5212 *ahp = AH5212(ah); 450276479Sdim 451218893Sdim if (us > ath_hal_mac_usec(ah, 0xffff)) { 452218893Sdim HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", 453218893Sdim __func__, us); 454218893Sdim ahp->ah_sifstime = (u_int) -1; /* restore default handling */ 455218893Sdim return AH_FALSE; 456218893Sdim } else { 457276479Sdim /* convert to system clocks */ 458276479Sdim OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us-2)); 459276479Sdim ahp->ah_sifstime = us; 460276479Sdim return AH_TRUE; 461218893Sdim } 462218893Sdim} 463218893Sdim 464249423Sdimu_int 465234353Sdimar5212GetSifsTime(struct ath_hal *ah) 466280031Sdim{ 467218893Sdim u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; 468218893Sdim return ath_hal_mac_usec(ah, clks)+2; /* convert from system clocks */ 469218893Sdim} 470218893Sdim 471234353SdimHAL_BOOL 472234353Sdimar5212SetSlotTime(struct ath_hal *ah, u_int us) 473249423Sdim{ 474249423Sdim struct ath_hal_5212 *ahp = AH5212(ah); 475249423Sdim 476276479Sdim if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) { 477234353Sdim HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", 478234353Sdim __func__, us); 479234353Sdim ahp->ah_slottime = (u_int) -1; /* restore default handling */ 480218893Sdim return AH_FALSE; 481218893Sdim } else { 482234353Sdim /* convert to system clocks */ 483234353Sdim OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); 484234353Sdim ahp->ah_slottime = us; 485234353Sdim return AH_TRUE; 486234353Sdim } 487234353Sdim} 488234353Sdim 489280031Sdimu_int 490280031Sdimar5212GetSlotTime(struct ath_hal *ah) 491280031Sdim{ 492276479Sdim u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; 493234353Sdim return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 494234353Sdim} 495234353Sdim 496234353SdimHAL_BOOL 497234353Sdimar5212SetAckTimeout(struct ath_hal *ah, u_int us) 498234353Sdim{ 499280031Sdim struct ath_hal_5212 *ahp = AH5212(ah); 500353358Sdim 501280031Sdim if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { 502280031Sdim HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", 503280031Sdim __func__, us); 504280031Sdim ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ 505280031Sdim return AH_FALSE; 506234353Sdim } else { 507234353Sdim /* convert to system clocks */ 508280031Sdim OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 509234353Sdim AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); 510218893Sdim ahp->ah_acktimeout = us; 511276479Sdim return AH_TRUE; 512212793Sdim } 513212793Sdim} 514276479Sdim 515212793Sdimu_int 516212793Sdimar5212GetAckTimeout(struct ath_hal *ah) 517280031Sdim{ 518234353Sdim u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); 519276479Sdim return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 520280031Sdim} 521280031Sdim 522276479Sdimu_int 523218893Sdimar5212GetAckCTSRate(struct ath_hal *ah) 524280031Sdim{ 525276479Sdim return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); 526280031Sdim} 527280031Sdim 528280031SdimHAL_BOOL 529276479Sdimar5212SetAckCTSRate(struct ath_hal *ah, u_int high) 530280031Sdim{ 531212793Sdim struct ath_hal_5212 *ahp = AH5212(ah); 532212793Sdim 533309124Sdim if (high) { 534309124Sdim OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 535309124Sdim ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; 536309124Sdim } else { 537249423Sdim OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 538218893Sdim ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; 539296417Sdim } 540218893Sdim return AH_TRUE; 541314564Sdim} 542314564Sdim 543314564SdimHAL_BOOL 544314564Sdimar5212SetCTSTimeout(struct ath_hal *ah, u_int us) 545309124Sdim{ 546280031Sdim struct ath_hal_5212 *ahp = AH5212(ah); 547280031Sdim 548243830Sdim if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { 549218893Sdim HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", 550276479Sdim __func__, us); 551261991Sdim ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ 552261991Sdim return AH_FALSE; 553276479Sdim } else { 554261991Sdim /* convert to system clocks */ 555309124Sdim OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 556234353Sdim AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); 557276479Sdim ahp->ah_ctstimeout = us; 558353358Sdim return AH_TRUE; 559309124Sdim } 560234353Sdim} 561276479Sdim 562276479Sdimu_int 563276479Sdimar5212GetCTSTimeout(struct ath_hal *ah) 564276479Sdim{ 565309124Sdim u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); 566234353Sdim return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 567309124Sdim} 568234353Sdim 569276479Sdim/* Setup decompression for given key index */ 570276479SdimHAL_BOOL 571234353Sdimar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 572234353Sdim{ 573276479Sdim struct ath_hal_5212 *ahp = AH5212(ah); 574234353Sdim 575234353Sdim if (keyidx >= HAL_DECOMP_MASK_SIZE) 576276479Sdim return HAL_EINVAL; 577234353Sdim OS_REG_WRITE(ah, AR_DCM_A, keyidx); 578218893Sdim OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0); 579309124Sdim ahp->ah_decompMask[keyidx] = en; 580243830Sdim 581243830Sdim return AH_TRUE; 582234353Sdim} 583309124Sdim 584234353Sdim/* Setup coverage class */ 585234353Sdimvoid 586234353Sdimar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 587234353Sdim{ 588234353Sdim uint32_t slot, timeout, eifs; 589234353Sdim u_int clkRate; 590234353Sdim 591234353Sdim AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 592234353Sdim 593309124Sdim if (now) { 594276479Sdim if (AH_PRIVATE(ah)->ah_coverageClass == 0) 595276479Sdim return; 596309124Sdim 597234353Sdim /* Don't apply coverage class to non A channels */ 598243830Sdim if (!IEEE80211_IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan)) 599234353Sdim return; 600234353Sdim 601261991Sdim /* Get core clock rate */ 602276479Sdim clkRate = ath_hal_mac_clks(ah, 1); 603276479Sdim 604276479Sdim /* Compute EIFS */ 605276479Sdim slot = coverageclass * 3 * clkRate; 606243830Sdim eifs = coverageclass * 6 * clkRate; 607243830Sdim if (IEEE80211_IS_CHAN_HALF(AH_PRIVATE(ah)->ah_curchan)) { 608309124Sdim slot += IFS_SLOT_HALF_RATE; 609243830Sdim eifs += IFS_EIFS_HALF_RATE; 610243830Sdim } else if (IEEE80211_IS_CHAN_QUARTER(AH_PRIVATE(ah)->ah_curchan)) { 611243830Sdim slot += IFS_SLOT_QUARTER_RATE; 612243830Sdim eifs += IFS_EIFS_QUARTER_RATE; 613276479Sdim } else { /* full rate */ 614243830Sdim slot += IFS_SLOT_FULL_RATE; 615243830Sdim eifs += IFS_EIFS_FULL_RATE; 616243830Sdim } 617243830Sdim 618243830Sdim /* 619234353Sdim * Add additional time for air propagation for ACK and CTS 620218893Sdim * timeouts. This value is in core clocks. 621223017Sdim */ 622243830Sdim timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate); 623234353Sdim 624223017Sdim /* 625234353Sdim * Write the values: slot, eifs, ack/cts timeouts. 626276479Sdim */ 627226633Sdim OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); 628223017Sdim OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); 629223017Sdim OS_REG_WRITE(ah, AR_TIME_OUT, 630223017Sdim SM(timeout, AR_TIME_OUT_CTS) 631276479Sdim | SM(timeout, AR_TIME_OUT_ACK)); 632276479Sdim } 633276479Sdim} 634276479Sdim 635223017SdimHAL_STATUS 636223017Sdimar5212SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration, 637223017Sdim uint32_t nextStart, HAL_QUIET_FLAG flag) 638223017Sdim{ 639218893Sdim OS_REG_WRITE(ah, AR_QUIET2, period | (duration << AR_QUIET2_QUIET_DUR_S)); 640218893Sdim if (flag & HAL_QUIET_ENABLE) { 641218893Sdim OS_REG_WRITE(ah, AR_QUIET1, nextStart | (1 << 16)); 642280031Sdim } 643288943Sdim else { 644218893Sdim OS_REG_WRITE(ah, AR_QUIET1, nextStart); 645212793Sdim } 646249423Sdim return HAL_OK; 647249423Sdim} 648218893Sdim 649218893Sdimvoid 650218893Sdimar5212SetPCUConfig(struct ath_hal *ah) 651218893Sdim{ 652218893Sdim ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); 653218893Sdim} 654218893Sdim 655218893Sdim/* 656218893Sdim * Return whether an external 32KHz crystal should be used 657218893Sdim * to reduce power consumption when sleeping. We do so if 658218893Sdim * the crystal is present (obtained from EEPROM) and if we 659234353Sdim * are not running as an AP and are configured to use it. 660234353Sdim */ 661280031SdimHAL_BOOL 662218893Sdimar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode) 663218893Sdim{ 664218893Sdim if (opmode != HAL_M_HOSTAP) { 665218893Sdim struct ath_hal_5212 *ahp = AH5212(ah); 666239462Sdim return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) && 667218893Sdim (ahp->ah_enable32kHzClock == USE_32KHZ || 668218893Sdim ahp->ah_enable32kHzClock == AUTO_32KHZ); 669218893Sdim } else 670218893Sdim return AH_FALSE; 671218893Sdim} 672218893Sdim 673218893Sdim/* 674276479Sdim * If 32KHz clock exists, use it to lower power consumption during sleep 675234353Sdim * 676218893Sdim * Note: If clock is set to 32 KHz, delays on accessing certain 677276479Sdim * baseband registers (27-31, 124-127) are required. 678276479Sdim */ 679276479Sdimvoid 680218893Sdimar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) 681218893Sdim{ 682218893Sdim if (ar5212Use32KHzclock(ah, opmode)) { 683218893Sdim /* 684218893Sdim * Enable clocks to be turned OFF in BB during sleep 685218893Sdim * and also enable turning OFF 32MHz/40MHz Refclk 686218893Sdim * from A2. 687218893Sdim */ 688218893Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 689226633Sdim OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 690288943Sdim IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 691218893Sdim OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); 692218893Sdim OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ 693218893Sdim OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1); 694218893Sdim 695218893Sdim if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) { 696212793Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26); 697212793Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d); 698212793Sdim OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07); 699212793Sdim OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f); 700212793Sdim /* # Set sleep clock rate to 32 KHz. */ 701226633Sdim OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2); 702212793Sdim } else { 703218893Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a); 704212793Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); 705212793Sdim OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); 706234353Sdim OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20); 707212793Sdim OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3); 708218893Sdim } 709212793Sdim } else { 710212793Sdim OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0); 711212793Sdim OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 712218893Sdim 713218893Sdim OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */ 714212793Sdim 715276479Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 716212793Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 717212793Sdim 718218893Sdim if (IS_2417(ah)) 719218893Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a); 720218893Sdim else if (IS_HB63(ah)) 721218893Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32); 722218893Sdim else 723218893Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 724218893Sdim OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 725212793Sdim OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 726212793Sdim OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 727212793Sdim IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18); 728212793Sdim OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 729212793Sdim IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 730226633Sdim } 731212793Sdim} 732212793Sdim 733212793Sdim/* 734212793Sdim * If 32KHz clock exists, turn it off and turn back on the 32Mhz 735218893Sdim */ 736212793Sdimvoid 737218893Sdimar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) 738212793Sdim{ 739261991Sdim if (ar5212Use32KHzclock(ah, opmode)) { 740218893Sdim /* # Set sleep clock rate back to 32 MHz. */ 741218893Sdim OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0); 742261991Sdim OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 743218893Sdim 744288943Sdim OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ 745288943Sdim OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 746218893Sdim IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 747218893Sdim 748261991Sdim /* 749218893Sdim * Restore BB registers to power-on defaults 750288943Sdim */ 751218893Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 752218893Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 753218893Sdim OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 754218893Sdim OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 755218893Sdim OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 756218893Sdim OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 757218893Sdim IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 758218893Sdim } 759218893Sdim} 760218893Sdim 761218893Sdim/* 762218893Sdim * Adjust NF based on statistical values for 5GHz frequencies. 763314564Sdim * Default method: this may be overridden by the rf backend. 764276479Sdim */ 765218893Sdimint16_t 766218893Sdimar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 767218893Sdim{ 768276479Sdim static const struct { 769321369Sdim uint16_t freqLow; 770218893Sdim int16_t adjust; 771218893Sdim } adjustDef[] = { 772218893Sdim { 5790, 11 }, /* NB: ordered high -> low */ 773221345Sdim { 5730, 10 }, 774221345Sdim { 5690, 9 }, 775261991Sdim { 5660, 8 }, 776261991Sdim { 5610, 7 }, 777218893Sdim { 5530, 5 }, 778221345Sdim { 5450, 4 }, 779218893Sdim { 5379, 2 }, 780221345Sdim { 5209, 0 }, 781221345Sdim { 3000, 1 }, 782221345Sdim { 0, 0 }, 783221345Sdim }; 784221345Sdim int i; 785221345Sdim 786221345Sdim for (i = 0; c->channel <= adjustDef[i].freqLow; i++) 787218893Sdim ; 788218893Sdim return adjustDef[i].adjust; 789218893Sdim} 790218893Sdim 791218893SdimHAL_STATUS 792218893Sdimar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 793218893Sdim uint32_t capability, uint32_t *result) 794218893Sdim{ 795218893Sdim#define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion 796218893Sdim struct ath_hal_5212 *ahp = AH5212(ah); 797218893Sdim const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 798218893Sdim const struct ar5212AniState *ani; 799218893Sdim 800212793Sdim switch (type) { 801218893Sdim case HAL_CAP_CIPHER: /* cipher handled in hardware */ 802218893Sdim switch (capability) { 803218893Sdim case HAL_CIPHER_AES_CCM: 804218893Sdim return pCap->halCipherAesCcmSupport ? 805218893Sdim HAL_OK : HAL_ENOTSUPP; 806218893Sdim case HAL_CIPHER_AES_OCB: 807218893Sdim case HAL_CIPHER_TKIP: 808218893Sdim case HAL_CIPHER_WEP: 809218893Sdim case HAL_CIPHER_MIC: 810212793Sdim case HAL_CIPHER_CLR: 811212793Sdim return HAL_OK; 812218893Sdim default: 813212793Sdim return HAL_ENOTSUPP; 814218893Sdim } 815218893Sdim case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 816218893Sdim switch (capability) { 817212793Sdim case 0: /* hardware capability */ 818249423Sdim return HAL_OK; 819218893Sdim case 1: 820249423Sdim return (ahp->ah_staId1Defaults & 821234353Sdim AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO; 822218893Sdim } 823218893Sdim return HAL_EINVAL; 824218893Sdim case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 825218893Sdim switch (capability) { 826234353Sdim case 0: /* hardware capability */ 827234353Sdim return pCap->halTkipMicTxRxKeySupport ? 828234353Sdim HAL_ENXIO : HAL_OK; 829234353Sdim case 1: /* current setting */ 830234353Sdim return (ahp->ah_miscMode & 831234353Sdim AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; 832234353Sdim } 833234353Sdim return HAL_EINVAL; 834234353Sdim case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ 835234353Sdim /* XXX move to capability bit */ 836234353Sdim return MACVERSION(ah) > AR_SREV_VERSION_VENICE || 837218893Sdim (MACVERSION(ah) == AR_SREV_VERSION_VENICE && 838218893Sdim AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; 839218893Sdim case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 840218893Sdim switch (capability) { 841218893Sdim case 0: /* hardware capability */ 842218893Sdim return HAL_OK; 843218893Sdim case 1: /* current setting */ 844218893Sdim return ahp->ah_diversity ? HAL_OK : HAL_ENXIO; 845218893Sdim } 846218893Sdim return HAL_EINVAL; 847218893Sdim case HAL_CAP_DIAG: 848218893Sdim *result = AH_PRIVATE(ah)->ah_diagreg; 849280031Sdim return HAL_OK; 850280031Sdim case HAL_CAP_TPC: 851218893Sdim switch (capability) { 852234353Sdim case 0: /* hardware capability */ 853276479Sdim return HAL_OK; 854218893Sdim case 1: 855218893Sdim return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; 856218893Sdim } 857218893Sdim return HAL_OK; 858218893Sdim case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ 859218893Sdim switch (capability) { 860218893Sdim case HAL_CAP_RADAR: 861218893Sdim return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? 862212793Sdim HAL_OK: HAL_ENXIO; 863218893Sdim case HAL_CAP_AR: 864280031Sdim return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || 865221345Sdim ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? 866218893Sdim HAL_OK: HAL_ENXIO; 867212793Sdim } 868212793Sdim return HAL_ENXIO; 869212793Sdim case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 870249423Sdim switch (capability) { 871223017Sdim case 0: /* hardware capability */ 872309124Sdim return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENXIO; 873309124Sdim case 1: 874218893Sdim return (ahp->ah_staId1Defaults & 875218893Sdim AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; 876249423Sdim } 877218893Sdim return HAL_EINVAL; 878221345Sdim case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 879218893Sdim switch (capability) { 880218893Sdim case 0: /* hardware capability */ 881218893Sdim return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; 882218893Sdim case 1: 883296417Sdim return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? 884296417Sdim HAL_OK : HAL_ENXIO; 885296417Sdim } 886218893Sdim return HAL_EINVAL; 887218893Sdim case HAL_CAP_TPC_ACK: 888212793Sdim *result = MS(ahp->ah_macTPC, AR_TPC_ACK); 889234353Sdim return HAL_OK; 890234353Sdim case HAL_CAP_TPC_CTS: 891234353Sdim *result = MS(ahp->ah_macTPC, AR_TPC_CTS); 892309124Sdim return HAL_OK; 893234353Sdim case HAL_CAP_INTMIT: /* interference mitigation */ 894234353Sdim switch (capability) { 895234353Sdim case HAL_CAP_INTMIT_PRESENT: /* hardware capability */ 896234353Sdim return HAL_OK; 897234353Sdim case HAL_CAP_INTMIT_ENABLE: 898218893Sdim return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? 899218893Sdim HAL_OK : HAL_ENXIO; 900218893Sdim case HAL_CAP_INTMIT_NOISE_IMMUNITY_LEVEL: 901218893Sdim case HAL_CAP_INTMIT_OFDM_WEAK_SIGNAL_LEVEL: 902221345Sdim case HAL_CAP_INTMIT_CCK_WEAK_SIGNAL_THR: 903234353Sdim case HAL_CAP_INTMIT_FIRSTEP_LEVEL: 904234353Sdim case HAL_CAP_INTMIT_SPUR_IMMUNITY_LEVEL: 905234353Sdim ani = ar5212AniGetCurrentState(ah); 906309124Sdim if (ani == AH_NULL) 907234353Sdim return HAL_ENXIO; 908234353Sdim switch (capability) { 909234353Sdim case 2: *result = ani->noiseImmunityLevel; break; 910234353Sdim case 3: *result = !ani->ofdmWeakSigDetectOff; break; 911234353Sdim case 4: *result = ani->cckWeakSigThreshold; break; 912212793Sdim case 5: *result = ani->firstepLevel; break; 913218893Sdim case 6: *result = ani->spurImmunityLevel; break; 914212793Sdim } 915212793Sdim return HAL_OK; 916360784Sdim } 917234353Sdim return HAL_EINVAL; 918212793Sdim default: 919234353Sdim return ath_hal_getcapability(ah, type, capability, result); 920234353Sdim } 921234353Sdim#undef MACVERSION 922249423Sdim} 923218893Sdim 924218893SdimHAL_BOOL 925234353Sdimar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 926234353Sdim uint32_t capability, uint32_t setting, HAL_STATUS *status) 927234353Sdim{ 928234353Sdim#define N(a) (sizeof(a)/sizeof(a[0])) 929234353Sdim struct ath_hal_5212 *ahp = AH5212(ah); 930234353Sdim const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 931234353Sdim uint32_t v; 932234353Sdim 933234353Sdim switch (type) { 934234353Sdim case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 935234353Sdim if (setting) 936234353Sdim ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; 937234353Sdim else 938234353Sdim ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; 939234353Sdim return AH_TRUE; 940261991Sdim case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 941212793Sdim if (!pCap->halTkipMicTxRxKeySupport) 942234353Sdim return AH_FALSE; 943243830Sdim /* NB: true =>'s use split key cache layout */ 944243830Sdim if (setting) 945243830Sdim ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 946234353Sdim else 947234353Sdim ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 948234353Sdim /* NB: write here so keys can be setup w/o a reset */ 949234353Sdim OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); 950234353Sdim return AH_TRUE; 951234353Sdim case HAL_CAP_DIVERSITY: 952234353Sdim if (ahp->ah_phyPowerOn) { 953234353Sdim v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 954234353Sdim if (setting) 955261991Sdim v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 956212793Sdim else 957212793Sdim v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 958243830Sdim OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); 959243830Sdim } 960243830Sdim ahp->ah_diversity = (setting != 0); 961234353Sdim return AH_TRUE; 962234353Sdim case HAL_CAP_DIAG: /* hardware diagnostic support */ 963234353Sdim /* 964234353Sdim * NB: could split this up into virtual capabilities, 965234353Sdim * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly 966234353Sdim * seems worth the additional complexity. 967234353Sdim */ 968234353Sdim AH_PRIVATE(ah)->ah_diagreg = setting; 969261991Sdim OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 970212793Sdim return AH_TRUE; 971218893Sdim case HAL_CAP_TPC: 972353358Sdim ahp->ah_tpcEnabled = (setting != 0); 973234353Sdim return AH_TRUE; 974234353Sdim case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 975234353Sdim if (setting) 976234353Sdim ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; 977234353Sdim else 978261991Sdim ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; 979234353Sdim return AH_TRUE; 980234353Sdim case HAL_CAP_TPC_ACK: 981234353Sdim case HAL_CAP_TPC_CTS: 982234353Sdim setting += ahp->ah_txPowerIndexOffset; 983218893Sdim if (setting > 63) 984218893Sdim setting = 63; 985353358Sdim if (type == HAL_CAP_TPC_ACK) { 986353358Sdim ahp->ah_macTPC &= AR_TPC_ACK; 987234353Sdim ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); 988234353Sdim } else { 989234353Sdim ahp->ah_macTPC &= AR_TPC_CTS; 990234353Sdim ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); 991234353Sdim } 992218893Sdim OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); 993218893Sdim return AH_TRUE; 994218893Sdim case HAL_CAP_INTMIT: { /* interference mitigation */ 995212793Sdim /* This maps the public ANI commands to the internal ANI commands */ 996218893Sdim /* Private: HAL_ANI_CMD; Public: HAL_CAP_INTMIT_CMD */ 997234353Sdim static const HAL_ANI_CMD cmds[] = { 998218893Sdim HAL_ANI_PRESENT, 999218893Sdim HAL_ANI_MODE, 1000234353Sdim HAL_ANI_NOISE_IMMUNITY_LEVEL, 1001234353Sdim HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 1002321369Sdim HAL_ANI_CCK_WEAK_SIGNAL_THR, 1003276479Sdim HAL_ANI_FIRSTEP_LEVEL, 1004218893Sdim HAL_ANI_SPUR_IMMUNITY_LEVEL, 1005234353Sdim }; 1006234353Sdim return capability < N(cmds) ? 1007234353Sdim AH5212(ah)->ah_aniControl(ah, cmds[capability], setting) : 1008234353Sdim AH_FALSE; 1009234353Sdim } 1010234353Sdim case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 1011276479Sdim if (pCap->halTsfAddSupport) { 1012234353Sdim if (setting) 1013234353Sdim ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; 1014234353Sdim else 1015234353Sdim ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; 1016212793Sdim return AH_TRUE; 1017212793Sdim } 1018212793Sdim /* fall thru... */ 1019218893Sdim default: 1020226633Sdim return ath_hal_setcapability(ah, type, capability, 1021226633Sdim setting, status); 1022226633Sdim } 1023226633Sdim#undef N 1024309124Sdim} 1025309124Sdim 1026309124SdimHAL_BOOL 1027309124Sdimar5212GetDiagState(struct ath_hal *ah, int request, 1028309124Sdim const void *args, uint32_t argsize, 1029309124Sdim void **result, uint32_t *resultsize) 1030309124Sdim{ 1031309124Sdim struct ath_hal_5212 *ahp = AH5212(ah); 1032309124Sdim 1033309124Sdim (void) ahp; 1034309124Sdim if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 1035309124Sdim return AH_TRUE; 1036309124Sdim switch (request) { 1037309124Sdim case HAL_DIAG_EEPROM: 1038309124Sdim case HAL_DIAG_EEPROM_EXP_11A: 1039218893Sdim case HAL_DIAG_EEPROM_EXP_11B: 1040218893Sdim case HAL_DIAG_EEPROM_EXP_11G: 1041218893Sdim case HAL_DIAG_RFGAIN: 1042218893Sdim return ath_hal_eepromDiag(ah, request, 1043212793Sdim args, argsize, result, resultsize); 1044218893Sdim case HAL_DIAG_RFGAIN_CURSTEP: 1045218893Sdim *result = __DECONST(void *, ahp->ah_gainValues.currStep); 1046218893Sdim *resultsize = (*result == AH_NULL) ? 1047212793Sdim 0 : sizeof(GAIN_OPTIMIZATION_STEP); 1048360784Sdim return AH_TRUE; 1049234353Sdim case HAL_DIAG_PCDAC: 1050234353Sdim *result = ahp->ah_pcdacTable; 1051280031Sdim *resultsize = ahp->ah_pcdacTableSize; 1052218893Sdim return AH_TRUE; 1053212793Sdim case HAL_DIAG_TXRATES: 1054212793Sdim *result = &ahp->ah_ratesArray[0]; 1055249423Sdim *resultsize = sizeof(ahp->ah_ratesArray); 1056234353Sdim return AH_TRUE; 1057212793Sdim case HAL_DIAG_ANI_CURRENT: 1058234353Sdim *result = ar5212AniGetCurrentState(ah); 1059249423Sdim *resultsize = (*result == AH_NULL) ? 1060218893Sdim 0 : sizeof(struct ar5212AniState); 1061212793Sdim return AH_TRUE; 1062218893Sdim case HAL_DIAG_ANI_STATS: 1063280031Sdim *result = ar5212AniGetCurrentStats(ah); 1064280031Sdim *resultsize = (*result == AH_NULL) ? 1065234353Sdim 0 : sizeof(struct ar5212Stats); 1066261991Sdim return AH_TRUE; 1067276479Sdim case HAL_DIAG_ANI_CMD: 1068218893Sdim if (argsize != 2*sizeof(uint32_t)) 1069218893Sdim return AH_FALSE; 1070218893Sdim AH5212(ah)->ah_aniControl(ah, ((const uint32_t *)args)[0], 1071314564Sdim ((const uint32_t *)args)[1]); 1072314564Sdim return AH_TRUE; 1073218893Sdim case HAL_DIAG_ANI_PARAMS: 1074234353Sdim /* 1075234353Sdim * NB: We assume struct ar5212AniParams is identical 1076234353Sdim * to HAL_ANI_PARAMS; if they diverge then we'll need 1077234353Sdim * to handle it here 1078234353Sdim */ 1079234353Sdim if (argsize == 0 && args == AH_NULL) { 1080234353Sdim struct ar5212AniState *aniState = 1081234353Sdim ar5212AniGetCurrentState(ah); 1082218893Sdim if (aniState == AH_NULL) 1083218893Sdim return AH_FALSE; 1084243830Sdim *result = __DECONST(void *, aniState->params); 1085243830Sdim *resultsize = sizeof(struct ar5212AniParams); 1086243830Sdim return AH_TRUE; 1087234353Sdim } else { 1088234353Sdim if (argsize != sizeof(struct ar5212AniParams)) 1089234353Sdim return AH_FALSE; 1090234353Sdim return ar5212AniSetParams(ah, args, args); 1091234353Sdim } 1092234353Sdim } 1093234353Sdim return AH_FALSE; 1094234353Sdim} 1095234353Sdim 1096218893Sdim/* 1097218893Sdim * Check whether there's an in-progress NF completion. 1098243830Sdim * 1099243830Sdim * Returns AH_TRUE if there's a in-progress NF calibration, AH_FALSE 1100243830Sdim * otherwise. 1101234353Sdim */ 1102234353SdimHAL_BOOL 1103234353Sdimar5212IsNFCalInProgress(struct ath_hal *ah) 1104234353Sdim{ 1105234353Sdim if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) 1106234353Sdim return AH_TRUE; 1107234353Sdim return AH_FALSE; 1108234353Sdim} 1109218893Sdim 1110212793Sdim/* 1111353358Sdim * Wait for an in-progress NF calibration to complete. 1112234353Sdim * 1113234353Sdim * The completion function waits "i" times 10uS. 1114234353Sdim * It returns AH_TRUE if the NF calibration completed (or was never 1115276479Sdim * in progress); AH_FALSE if it was still in progress after "i" checks. 1116234353Sdim */ 1117234353SdimHAL_BOOL 1118234353Sdimar5212WaitNFCalComplete(struct ath_hal *ah, int i) 1119234353Sdim{ 1120234353Sdim int j; 1121234353Sdim if (i <= 0) 1122234353Sdim i = 1; /* it should run at least once */ 1123234353Sdim for (j = 0; j < i; j++) { 1124212793Sdim if (! ar5212IsNFCalInProgress(ah)) 1125212793Sdim return AH_TRUE; 1126353358Sdim OS_DELAY(10); 1127353358Sdim } 1128234353Sdim return AH_FALSE; 1129234353Sdim} 1130234353Sdim 1131234353Sdimvoid 1132234353Sdimar5212EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 1133212793Sdim{ 1134212793Sdim uint32_t val; 1135212793Sdim val = OS_REG_READ(ah, AR_PHY_RADAR_0); 1136218893Sdim 1137234353Sdim if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) { 1138218893Sdim val &= ~AR_PHY_RADAR_0_FIRPWR; 1139218893Sdim val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR); 1140261991Sdim } 1141276479Sdim if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) { 1142218893Sdim val &= ~AR_PHY_RADAR_0_RRSSI; 1143234353Sdim val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI); 1144234353Sdim } 1145212793Sdim if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) { 1146212793Sdim val &= ~AR_PHY_RADAR_0_HEIGHT; 1147212793Sdim val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT); 1148218893Sdim } 1149212793Sdim if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) { 1150212793Sdim val &= ~AR_PHY_RADAR_0_PRSSI; 1151212793Sdim val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI); 1152226633Sdim } 1153226633Sdim if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) { 1154226633Sdim val &= ~AR_PHY_RADAR_0_INBAND; 1155226633Sdim val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND); 1156309124Sdim } 1157309124Sdim OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA); 1158309124Sdim} 1159309124Sdim 1160309124Sdimvoid 1161309124Sdimar5212GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 1162309124Sdim{ 1163309124Sdim uint32_t val,temp; 1164309124Sdim 1165309124Sdim val = OS_REG_READ(ah, AR_PHY_RADAR_0); 1166309124Sdim 1167309124Sdim temp = MS(val,AR_PHY_RADAR_0_FIRPWR); 1168309124Sdim temp |= 0xFFFFFF80; 1169309124Sdim pe->pe_firpwr = temp; 1170309124Sdim pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI); 1171218893Sdim pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT); 1172218893Sdim pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI); 1173212793Sdim pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND); 1174212793Sdim 1175212793Sdim pe->pe_relpwr = 0; 1176212793Sdim pe->pe_relstep = 0; 1177212793Sdim pe->pe_maxlen = 0; 1178218893Sdim pe->pe_extchannel = AH_FALSE; 1179218893Sdim} 1180218893Sdim 1181218893Sdim/* 1182218893Sdim * Process the radar phy error and extract the pulse duration. 1183212793Sdim */ 1184212793SdimHAL_BOOL 1185234353Sdimar5212ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs, 1186234353Sdim uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event) 1187212793Sdim{ 1188212793Sdim uint8_t dur; 1189212793Sdim uint8_t rssi; 1190218893Sdim 1191218893Sdim /* Check whether the given phy error is a radar event */ 1192218893Sdim if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) && 1193218893Sdim (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) 1194218893Sdim return AH_FALSE; 1195218893Sdim 1196218893Sdim /* 1197218893Sdim * The first byte is the pulse width - if there's 1198218893Sdim * no data, simply set the duration to 0 1199218893Sdim */ 1200218893Sdim if (rxs->rs_datalen >= 1) 1201218893Sdim /* The pulse width is byte 0 of the data */ 1202218893Sdim dur = ((uint8_t) buf[0]) & 0xff; 1203218893Sdim else 1204218893Sdim dur = 0; 1205218893Sdim 1206218893Sdim /* Pulse RSSI is the normal reported RSSI */ 1207218893Sdim rssi = (uint8_t) rxs->rs_rssi; 1208218893Sdim 1209218893Sdim /* 0 duration/rssi is not a valid radar event */ 1210218893Sdim if (dur == 0 && rssi == 0) 1211218893Sdim return AH_FALSE; 1212218893Sdim 1213218893Sdim HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", 1214218893Sdim __func__, rssi, dur); 1215218893Sdim 1216218893Sdim /* Record the event */ 1217218893Sdim event->re_full_ts = fulltsf; 1218218893Sdim event->re_ts = rxs->rs_tstamp; 1219218893Sdim event->re_rssi = rssi; 1220218893Sdim event->re_dur = dur; 1221218893Sdim event->re_flags = HAL_DFS_EVENT_PRICH; 1222218893Sdim 1223218893Sdim return AH_TRUE; 1224218893Sdim} 1225218893Sdim