ar5212_misc.c revision 185377
1/* 2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $Id: ar5212_misc.c,v 1.8 2008/11/10 04:08:03 sam Exp $ 18 */ 19#include "opt_ah.h" 20 21#ifdef AH_SUPPORT_AR5212 22 23#include "ah.h" 24#include "ah_internal.h" 25#include "ah_devid.h" 26#ifdef AH_DEBUG 27#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 28#endif 29 30#include "ar5212/ar5212.h" 31#include "ar5212/ar5212reg.h" 32#include "ar5212/ar5212phy.h" 33#ifdef AH_SUPPORT_AR5311 34#include "ar5212/ar5311reg.h" 35#endif 36 37#include "ah_eeprom_v3.h" 38 39#define AR_NUM_GPIO 6 /* 6 GPIO pins */ 40#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ 41 42extern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *); 43 44void 45ar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac) 46{ 47 struct ath_hal_5212 *ahp = AH5212(ah); 48 49 OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); 50} 51 52HAL_BOOL 53ar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac) 54{ 55 struct ath_hal_5212 *ahp = AH5212(ah); 56 57 OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); 58 return AH_TRUE; 59} 60 61void 62ar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask) 63{ 64 struct ath_hal_5212 *ahp = AH5212(ah); 65 66 OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN); 67} 68 69HAL_BOOL 70ar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) 71{ 72 struct ath_hal_5212 *ahp = AH5212(ah); 73 74 /* save it since it must be rewritten on reset */ 75 OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN); 76 77 OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); 78 OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); 79 return AH_TRUE; 80} 81 82/* 83 * Return the wireless modes (a,b,g,t) supported by hardware. 84 * 85 * This value is what is actually supported by the hardware 86 * and is unaffected by regulatory/country code settings. 87 * 88 */ 89u_int 90ar5212GetWirelessModes(struct ath_hal *ah) 91{ 92 u_int mode = 0; 93 94 if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { 95 mode = HAL_MODE_11A; 96 if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) 97 mode |= HAL_MODE_TURBO | HAL_MODE_108A; 98 } 99 if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) 100 mode |= HAL_MODE_11B; 101 if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && 102 AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { 103 mode |= HAL_MODE_11G; 104 if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) 105 mode |= HAL_MODE_108G; 106 } 107 return mode; 108} 109 110/* 111 * Set the interrupt and GPIO values so the ISR can disable RF 112 * on a switch signal. Assumes GPIO port and interrupt polarity 113 * are set prior to call. 114 */ 115void 116ar5212EnableRfKill(struct ath_hal *ah) 117{ 118 uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; 119 int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); 120 int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); 121 122 /* 123 * Configure the desired GPIO port for input 124 * and enable baseband rf silence. 125 */ 126 ath_hal_gpioCfgInput(ah, select); 127 OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000); 128 /* 129 * If radio disable switch connection to GPIO bit x is enabled 130 * program GPIO interrupt. 131 * If rfkill bit on eeprom is 1, setupeeprommap routine has already 132 * verified that it is a later version of eeprom, it has a place for 133 * rfkill bit and it is set to 1, indicating that GPIO bit x hardware 134 * connection is present. 135 */ 136 ath_hal_gpioSetIntr(ah, select, 137 (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity)); 138} 139 140/* 141 * Change the LED blinking pattern to correspond to the connectivity 142 */ 143void 144ar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 145{ 146 static const uint32_t ledbits[8] = { 147 AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */ 148 AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */ 149 AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */ 150 AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/ 151 AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */ 152 AR_PCICFG_LEDCTL_NONE, 153 AR_PCICFG_LEDCTL_NONE, 154 AR_PCICFG_LEDCTL_NONE, 155 }; 156 uint32_t bits; 157 158 bits = OS_REG_READ(ah, AR_PCICFG); 159 if (IS_2417(ah)) { 160 /* 161 * Enable LED for Nala. There is a bit marked reserved 162 * that must be set and we also turn on the power led. 163 * Because we mark s/w LED control setting the control 164 * status bits below is meangless (the driver must flash 165 * the LED(s) using the GPIO lines). 166 */ 167 bits = (bits &~ AR_PCICFG_LEDMODE) 168 | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE) 169#if 0 170 | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE) 171#endif 172 | 0x08000000; 173 } 174 bits = (bits &~ AR_PCICFG_LEDCTL) 175 | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL); 176 OS_REG_WRITE(ah, AR_PCICFG, bits); 177} 178 179/* 180 * Change association related fields programmed into the hardware. 181 * Writing a valid BSSID to the hardware effectively enables the hardware 182 * to synchronize its TSF to the correct beacons and receive frames coming 183 * from that BSSID. It is called by the SME JOIN operation. 184 */ 185void 186ar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) 187{ 188 struct ath_hal_5212 *ahp = AH5212(ah); 189 190 /* XXX save bssid for possible re-use on reset */ 191 OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); 192 OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 193 OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | 194 ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); 195} 196 197/* 198 * Get the current hardware tsf for stamlme 199 */ 200uint64_t 201ar5212GetTsf64(struct ath_hal *ah) 202{ 203 uint32_t low1, low2, u32; 204 205 /* sync multi-word read */ 206 low1 = OS_REG_READ(ah, AR_TSF_L32); 207 u32 = OS_REG_READ(ah, AR_TSF_U32); 208 low2 = OS_REG_READ(ah, AR_TSF_L32); 209 if (low2 < low1) { /* roll over */ 210 /* 211 * If we are not preempted this will work. If we are 212 * then we re-reading AR_TSF_U32 does no good as the 213 * low bits will be meaningless. Likewise reading 214 * L32, U32, U32, then comparing the last two reads 215 * to check for rollover 216 * doesn't help if preempted--so we take this approach 217 * as it costs one less PCI read which can be noticeable 218 * when doing things like timestamping packets in 219 * monitor mode. 220 */ 221 u32++; 222 } 223 return (((uint64_t) u32) << 32) | ((uint64_t) low2); 224} 225 226/* 227 * Get the current hardware tsf for stamlme 228 */ 229uint32_t 230ar5212GetTsf32(struct ath_hal *ah) 231{ 232 return OS_REG_READ(ah, AR_TSF_L32); 233} 234 235/* 236 * Reset the current hardware tsf for stamlme. 237 */ 238void 239ar5212ResetTsf(struct ath_hal *ah) 240{ 241 242 uint32_t val = OS_REG_READ(ah, AR_BEACON); 243 244 OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 245 /* 246 * When resetting the TSF, write twice to the 247 * corresponding register; each write to the RESET_TSF bit toggles 248 * the internal signal to cause a reset of the TSF - but if the signal 249 * is left high, it will reset the TSF on the next chip reset also! 250 * writing the bit an even number of times fixes this issue 251 */ 252 OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 253} 254 255/* 256 * Set or clear hardware basic rate bit 257 * Set hardware basic rate set if basic rate is found 258 * and basic rate is equal or less than 2Mbps 259 */ 260void 261ar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs) 262{ 263 HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 264 uint32_t reg; 265 uint8_t xset; 266 int i; 267 268 if (chan == AH_NULL || !IS_CHAN_CCK(chan)) 269 return; 270 xset = 0; 271 for (i = 0; i < rs->rs_count; i++) { 272 uint8_t rset = rs->rs_rates[i]; 273 /* Basic rate defined? */ 274 if ((rset & 0x80) && (rset &= 0x7f) >= xset) 275 xset = rset; 276 } 277 /* 278 * Set the h/w bit to reflect whether or not the basic 279 * rate is found to be equal or less than 2Mbps. 280 */ 281 reg = OS_REG_READ(ah, AR_STA_ID1); 282 if (xset && xset/2 <= 2) 283 OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B); 284 else 285 OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B); 286} 287 288/* 289 * Grab a semi-random value from hardware registers - may not 290 * change often 291 */ 292uint32_t 293ar5212GetRandomSeed(struct ath_hal *ah) 294{ 295 uint32_t nf; 296 297 nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; 298 if (nf & 0x100) 299 nf = 0 - ((nf ^ 0x1ff) + 1); 300 return (OS_REG_READ(ah, AR_TSF_U32) ^ 301 OS_REG_READ(ah, AR_TSF_L32) ^ nf); 302} 303 304/* 305 * Detect if our card is present 306 */ 307HAL_BOOL 308ar5212DetectCardPresent(struct ath_hal *ah) 309{ 310 uint16_t macVersion, macRev; 311 uint32_t v; 312 313 /* 314 * Read the Silicon Revision register and compare that 315 * to what we read at attach time. If the same, we say 316 * a card/device is present. 317 */ 318 v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; 319 macVersion = v >> AR_SREV_ID_S; 320 macRev = v & AR_SREV_REVISION; 321 return (AH_PRIVATE(ah)->ah_macVersion == macVersion && 322 AH_PRIVATE(ah)->ah_macRev == macRev); 323} 324 325void 326ar5212EnableMibCounters(struct ath_hal *ah) 327{ 328 /* NB: this just resets the mib counter machinery */ 329 OS_REG_WRITE(ah, AR_MIBC, 330 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 331} 332 333void 334ar5212DisableMibCounters(struct ath_hal *ah) 335{ 336 OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC); 337} 338 339/* 340 * Update MIB Counters 341 */ 342void 343ar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats) 344{ 345 stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); 346 stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); 347 stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); 348 stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); 349 stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); 350} 351 352/* 353 * Detect if the HW supports spreading a CCK signal on channel 14 354 */ 355HAL_BOOL 356ar5212IsJapanChannelSpreadSupported(struct ath_hal *ah) 357{ 358 return AH_TRUE; 359} 360 361/* 362 * Get the rssi of frame curently being received. 363 */ 364uint32_t 365ar5212GetCurRssi(struct ath_hal *ah) 366{ 367 return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); 368} 369 370u_int 371ar5212GetDefAntenna(struct ath_hal *ah) 372{ 373 return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); 374} 375 376void 377ar5212SetDefAntenna(struct ath_hal *ah, u_int antenna) 378{ 379 OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); 380} 381 382HAL_ANT_SETTING 383ar5212GetAntennaSwitch(struct ath_hal *ah) 384{ 385 return AH5212(ah)->ah_diversityControl; 386} 387 388HAL_BOOL 389ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 390{ 391 const HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 392 393 if (chan == AH_NULL) { 394 AH5212(ah)->ah_diversityControl = settings; 395 return AH_TRUE; 396 } 397 return ar5212SetAntennaSwitchInternal(ah, settings, chan); 398} 399 400HAL_BOOL 401ar5212IsSleepAfterBeaconBroken(struct ath_hal *ah) 402{ 403 return AH_TRUE; 404} 405 406HAL_BOOL 407ar5212SetSifsTime(struct ath_hal *ah, u_int us) 408{ 409 struct ath_hal_5212 *ahp = AH5212(ah); 410 411 if (us > ath_hal_mac_usec(ah, 0xffff)) { 412 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", 413 __func__, us); 414 ahp->ah_sifstime = (u_int) -1; /* restore default handling */ 415 return AH_FALSE; 416 } else { 417 /* convert to system clocks */ 418 OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us)); 419 ahp->ah_slottime = us; 420 return AH_TRUE; 421 } 422} 423 424u_int 425ar5212GetSifsTime(struct ath_hal *ah) 426{ 427 u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; 428 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 429} 430 431HAL_BOOL 432ar5212SetSlotTime(struct ath_hal *ah, u_int us) 433{ 434 struct ath_hal_5212 *ahp = AH5212(ah); 435 436 if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) { 437 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", 438 __func__, us); 439 ahp->ah_slottime = (u_int) -1; /* restore default handling */ 440 return AH_FALSE; 441 } else { 442 /* convert to system clocks */ 443 OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); 444 ahp->ah_slottime = us; 445 return AH_TRUE; 446 } 447} 448 449u_int 450ar5212GetSlotTime(struct ath_hal *ah) 451{ 452 u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; 453 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 454} 455 456HAL_BOOL 457ar5212SetAckTimeout(struct ath_hal *ah, u_int us) 458{ 459 struct ath_hal_5212 *ahp = AH5212(ah); 460 461 if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { 462 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", 463 __func__, us); 464 ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ 465 return AH_FALSE; 466 } else { 467 /* convert to system clocks */ 468 OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 469 AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); 470 ahp->ah_acktimeout = us; 471 return AH_TRUE; 472 } 473} 474 475u_int 476ar5212GetAckTimeout(struct ath_hal *ah) 477{ 478 u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); 479 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 480} 481 482u_int 483ar5212GetAckCTSRate(struct ath_hal *ah) 484{ 485 return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); 486} 487 488HAL_BOOL 489ar5212SetAckCTSRate(struct ath_hal *ah, u_int high) 490{ 491 struct ath_hal_5212 *ahp = AH5212(ah); 492 493 if (high) { 494 OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 495 ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; 496 } else { 497 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 498 ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; 499 } 500 return AH_TRUE; 501} 502 503HAL_BOOL 504ar5212SetCTSTimeout(struct ath_hal *ah, u_int us) 505{ 506 struct ath_hal_5212 *ahp = AH5212(ah); 507 508 if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { 509 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", 510 __func__, us); 511 ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ 512 return AH_FALSE; 513 } else { 514 /* convert to system clocks */ 515 OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 516 AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); 517 ahp->ah_ctstimeout = us; 518 return AH_TRUE; 519 } 520} 521 522u_int 523ar5212GetCTSTimeout(struct ath_hal *ah) 524{ 525 u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); 526 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 527} 528 529/* Setup decompression for given key index */ 530HAL_BOOL 531ar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 532{ 533 struct ath_hal_5212 *ahp = AH5212(ah); 534 535 if (keyidx >= HAL_DECOMP_MASK_SIZE) 536 return HAL_EINVAL; 537 OS_REG_WRITE(ah, AR_DCM_A, keyidx); 538 OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0); 539 ahp->ah_decompMask[keyidx] = en; 540 541 return AH_TRUE; 542} 543 544/* Setup coverage class */ 545void 546ar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 547{ 548 uint32_t slot, timeout, eifs; 549 u_int clkRate; 550 551 AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 552 553 if (now) { 554 if (AH_PRIVATE(ah)->ah_coverageClass == 0) 555 return; 556 557 /* Don't apply coverage class to non A channels */ 558 if (!IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan)) 559 return; 560 561 /* Get core clock rate */ 562 clkRate = ath_hal_mac_clks(ah, 1); 563 564 /* Compute EIFS */ 565 slot = coverageclass * 3 * clkRate; 566 eifs = coverageclass * 6 * clkRate; 567 if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { 568 slot += IFS_SLOT_HALF_RATE; 569 eifs += IFS_EIFS_HALF_RATE; 570 } else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { 571 slot += IFS_SLOT_QUARTER_RATE; 572 eifs += IFS_EIFS_QUARTER_RATE; 573 } else { /* full rate */ 574 slot += IFS_SLOT_FULL_RATE; 575 eifs += IFS_EIFS_FULL_RATE; 576 } 577 578 /* 579 * Add additional time for air propagation for ACK and CTS 580 * timeouts. This value is in core clocks. 581 */ 582 timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate); 583 584 /* 585 * Write the values: slot, eifs, ack/cts timeouts. 586 */ 587 OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); 588 OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); 589 OS_REG_WRITE(ah, AR_TIME_OUT, 590 SM(timeout, AR_TIME_OUT_CTS) 591 | SM(timeout, AR_TIME_OUT_ACK)); 592 } 593} 594 595void 596ar5212SetPCUConfig(struct ath_hal *ah) 597{ 598 ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); 599} 600 601/* 602 * Return whether an external 32KHz crystal should be used 603 * to reduce power consumption when sleeping. We do so if 604 * the crystal is present (obtained from EEPROM) and if we 605 * are not running as an AP and are configured to use it. 606 */ 607HAL_BOOL 608ar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode) 609{ 610 if (opmode != HAL_M_HOSTAP) { 611 struct ath_hal_5212 *ahp = AH5212(ah); 612 return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) && 613 (ahp->ah_enable32kHzClock == USE_32KHZ || 614 ahp->ah_enable32kHzClock == AUTO_32KHZ); 615 } else 616 return AH_FALSE; 617} 618 619/* 620 * If 32KHz clock exists, use it to lower power consumption during sleep 621 * 622 * Note: If clock is set to 32 KHz, delays on accessing certain 623 * baseband registers (27-31, 124-127) are required. 624 */ 625void 626ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) 627{ 628 if (ar5212Use32KHzclock(ah, opmode)) { 629 /* 630 * Enable clocks to be turned OFF in BB during sleep 631 * and also enable turning OFF 32MHz/40MHz Refclk 632 * from A2. 633 */ 634 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 635 OS_REG_WRITE(ah, AR_PHY_REFCLKPD, IS_5112(ah) ? 0x14 : 0x18); 636 OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); 637 OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ 638 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1); 639 640 if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) { 641 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26); 642 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d); 643 OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07); 644 OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f); 645 /* # Set sleep clock rate to 32 KHz. */ 646 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2); 647 } else { 648 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a); 649 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); 650 OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); 651 OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20); 652 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3); 653 } 654 } else { 655 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0); 656 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 657 658 OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */ 659 660 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 661 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 662 663 if (IS_2417(ah)) 664 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a); 665 else if (IS_HB63(ah)) 666 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32); 667 else 668 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 669 OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 670 OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 671 OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 672 IS_5112(ah) || IS_2417(ah) ? 0x14 : 0x18); 673 OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, IS_5112(ah) ? 39 : 31); 674 } 675} 676 677/* 678 * If 32KHz clock exists, turn it off and turn back on the 32Mhz 679 */ 680void 681ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) 682{ 683 if (ar5212Use32KHzclock(ah, opmode)) { 684 /* # Set sleep clock rate back to 32 MHz. */ 685 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0); 686 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 687 688 OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ 689 OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, IS_5112(ah) ? 39 : 31); 690 691 /* 692 * Restore BB registers to power-on defaults 693 */ 694 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 695 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 696 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 697 OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 698 OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 699 OS_REG_WRITE(ah, AR_PHY_REFCLKPD, IS_5112(ah) ? 0x14 : 0x18); 700 } 701} 702 703/* 704 * Adjust NF based on statistical values for 5GHz frequencies. 705 * Default method: this may be overridden by the rf backend. 706 */ 707int16_t 708ar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 709{ 710 static const struct { 711 uint16_t freqLow; 712 int16_t adjust; 713 } adjustDef[] = { 714 { 5790, 11 }, /* NB: ordered high -> low */ 715 { 5730, 10 }, 716 { 5690, 9 }, 717 { 5660, 8 }, 718 { 5610, 7 }, 719 { 5530, 5 }, 720 { 5450, 4 }, 721 { 5379, 2 }, 722 { 5209, 0 }, 723 { 3000, 1 }, 724 { 0, 0 }, 725 }; 726 int i; 727 728 for (i = 0; c->channel <= adjustDef[i].freqLow; i++) 729 ; 730 return adjustDef[i].adjust; 731} 732 733HAL_STATUS 734ar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 735 uint32_t capability, uint32_t *result) 736{ 737#define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion 738 struct ath_hal_5212 *ahp = AH5212(ah); 739 const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 740 const struct ar5212AniState *ani; 741 742 switch (type) { 743 case HAL_CAP_CIPHER: /* cipher handled in hardware */ 744 switch (capability) { 745 case HAL_CIPHER_AES_CCM: 746 return pCap->halCipherAesCcmSupport ? 747 HAL_OK : HAL_ENOTSUPP; 748 case HAL_CIPHER_AES_OCB: 749 case HAL_CIPHER_TKIP: 750 case HAL_CIPHER_WEP: 751 case HAL_CIPHER_MIC: 752 case HAL_CIPHER_CLR: 753 return HAL_OK; 754 default: 755 return HAL_ENOTSUPP; 756 } 757 case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 758 switch (capability) { 759 case 0: /* hardware capability */ 760 return HAL_OK; 761 case 1: 762 return (ahp->ah_staId1Defaults & 763 AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO; 764 } 765 case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 766 switch (capability) { 767 case 0: /* hardware capability */ 768 return pCap->halTkipMicTxRxKeySupport ? 769 HAL_ENXIO : HAL_OK; 770 case 1: /* current setting */ 771 return (ahp->ah_miscMode & 772 AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; 773 } 774 return HAL_EINVAL; 775 case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ 776 /* XXX move to capability bit */ 777 return MACVERSION(ah) > AR_SREV_VERSION_VENICE || 778 (MACVERSION(ah) == AR_SREV_VERSION_VENICE && 779 AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; 780 case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 781 switch (capability) { 782 case 0: /* hardware capability */ 783 return HAL_OK; 784 case 1: /* current setting */ 785 return (OS_REG_READ(ah, AR_PHY_CCK_DETECT) & 786 AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? 787 HAL_OK : HAL_ENXIO; 788 } 789 return HAL_EINVAL; 790 case HAL_CAP_DIAG: 791 *result = AH_PRIVATE(ah)->ah_diagreg; 792 return HAL_OK; 793 case HAL_CAP_TPC: 794 switch (capability) { 795 case 0: /* hardware capability */ 796 return HAL_OK; 797 case 1: 798 return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; 799 } 800 return HAL_OK; 801 case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ 802 switch (capability) { 803 case HAL_CAP_RADAR: 804 return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? 805 HAL_OK: HAL_ENXIO; 806 case HAL_CAP_AR: 807 return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || 808 ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? 809 HAL_OK: HAL_ENXIO; 810 } 811 return HAL_ENXIO; 812 case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 813 switch (capability) { 814 case 0: /* hardware capability */ 815 return HAL_OK; 816 case 1: 817 return (ahp->ah_staId1Defaults & 818 AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; 819 } 820 return HAL_EINVAL; 821 case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 822 switch (capability) { 823 case 0: /* hardware capability */ 824 return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; 825 case 1: 826 return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? 827 HAL_OK : HAL_ENXIO; 828 } 829 return HAL_EINVAL; 830 case HAL_CAP_TPC_ACK: 831 *result = MS(ahp->ah_macTPC, AR_TPC_ACK); 832 return HAL_OK; 833 case HAL_CAP_TPC_CTS: 834 *result = MS(ahp->ah_macTPC, AR_TPC_CTS); 835 return HAL_OK; 836 case HAL_CAP_INTMIT: /* interference mitigation */ 837 switch (capability) { 838 case 0: /* hardware capability */ 839 return HAL_OK; 840 case 1: 841 return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? 842 HAL_OK : HAL_ENXIO; 843 case 2: /* HAL_ANI_NOISE_IMMUNITY_LEVEL */ 844 case 3: /* HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION */ 845 case 4: /* HAL_ANI_CCK_WEAK_SIGNAL_THR */ 846 case 5: /* HAL_ANI_FIRSTEP_LEVEL */ 847 case 6: /* HAL_ANI_SPUR_IMMUNITY_LEVEL */ 848 ani = ar5212AniGetCurrentState(ah); 849 if (ani == AH_NULL) 850 return HAL_ENXIO; 851 switch (capability) { 852 case 2: *result = ani->noiseImmunityLevel; break; 853 case 3: *result = !ani->ofdmWeakSigDetectOff; break; 854 case 4: *result = ani->cckWeakSigThreshold; break; 855 case 5: *result = ani->firstepLevel; break; 856 case 6: *result = ani->spurImmunityLevel; break; 857 } 858 return HAL_OK; 859 } 860 return HAL_EINVAL; 861 default: 862 return ath_hal_getcapability(ah, type, capability, result); 863 } 864#undef MACVERSION 865} 866 867HAL_BOOL 868ar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 869 uint32_t capability, uint32_t setting, HAL_STATUS *status) 870{ 871#define N(a) (sizeof(a)/sizeof(a[0])) 872 struct ath_hal_5212 *ahp = AH5212(ah); 873 const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 874 uint32_t v; 875 876 switch (type) { 877 case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 878 if (setting) 879 ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; 880 else 881 ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; 882 return AH_TRUE; 883 case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 884 if (!pCap->halTkipMicTxRxKeySupport) 885 return AH_FALSE; 886 /* NB: true =>'s use split key cache layout */ 887 if (setting) 888 ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 889 else 890 ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 891 /* NB: write here so keys can be setup w/o a reset */ 892 OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); 893 return AH_TRUE; 894 case HAL_CAP_DIVERSITY: 895 v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 896 if (setting) 897 v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 898 else 899 v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 900 OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); 901 return AH_TRUE; 902 case HAL_CAP_DIAG: /* hardware diagnostic support */ 903 /* 904 * NB: could split this up into virtual capabilities, 905 * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly 906 * seems worth the additional complexity. 907 */ 908 AH_PRIVATE(ah)->ah_diagreg = setting; 909 OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 910 return AH_TRUE; 911 case HAL_CAP_TPC: 912 ahp->ah_tpcEnabled = (setting != 0); 913 return AH_TRUE; 914 case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 915 if (setting) 916 ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; 917 else 918 ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; 919 return AH_TRUE; 920 case HAL_CAP_TPC_ACK: 921 case HAL_CAP_TPC_CTS: 922 setting += ahp->ah_txPowerIndexOffset; 923 if (setting > 63) 924 setting = 63; 925 if (type == HAL_CAP_TPC_ACK) { 926 ahp->ah_macTPC &= AR_TPC_ACK; 927 ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); 928 } else { 929 ahp->ah_macTPC &= AR_TPC_CTS; 930 ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); 931 } 932 OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); 933 return AH_TRUE; 934 case HAL_CAP_INTMIT: { /* interference mitigation */ 935 static const HAL_ANI_CMD cmds[] = { 936 HAL_ANI_PRESENT, 937 HAL_ANI_MODE, 938 HAL_ANI_NOISE_IMMUNITY_LEVEL, 939 HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 940 HAL_ANI_CCK_WEAK_SIGNAL_THR, 941 HAL_ANI_FIRSTEP_LEVEL, 942 HAL_ANI_SPUR_IMMUNITY_LEVEL, 943 }; 944 return capability < N(cmds) ? 945 ar5212AniControl(ah, cmds[capability], setting) : 946 AH_FALSE; 947 } 948 case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 949 if (pCap->halTsfAddSupport) { 950 if (setting) 951 ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; 952 else 953 ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; 954 return AH_TRUE; 955 } 956 /* fall thru... */ 957 default: 958 return ath_hal_setcapability(ah, type, capability, 959 setting, status); 960 } 961#undef N 962} 963 964HAL_BOOL 965ar5212GetDiagState(struct ath_hal *ah, int request, 966 const void *args, uint32_t argsize, 967 void **result, uint32_t *resultsize) 968{ 969 struct ath_hal_5212 *ahp = AH5212(ah); 970 971 (void) ahp; 972 if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 973 return AH_TRUE; 974 switch (request) { 975 case HAL_DIAG_EEPROM: 976 case HAL_DIAG_EEPROM_EXP_11A: 977 case HAL_DIAG_EEPROM_EXP_11B: 978 case HAL_DIAG_EEPROM_EXP_11G: 979 case HAL_DIAG_RFGAIN: 980 return ath_hal_eepromDiag(ah, request, 981 args, argsize, result, resultsize); 982 case HAL_DIAG_RFGAIN_CURSTEP: 983 *result = __DECONST(void *, ahp->ah_gainValues.currStep); 984 *resultsize = (*result == AH_NULL) ? 985 0 : sizeof(GAIN_OPTIMIZATION_STEP); 986 return AH_TRUE; 987 case HAL_DIAG_PCDAC: 988 *result = ahp->ah_pcdacTable; 989 *resultsize = ahp->ah_pcdacTableSize; 990 return AH_TRUE; 991 case HAL_DIAG_TXRATES: 992 *result = &ahp->ah_ratesArray[0]; 993 *resultsize = sizeof(ahp->ah_ratesArray); 994 return AH_TRUE; 995 case HAL_DIAG_ANI_CURRENT: 996 *result = ar5212AniGetCurrentState(ah); 997 *resultsize = (*result == AH_NULL) ? 998 0 : sizeof(struct ar5212AniState); 999 return AH_TRUE; 1000 case HAL_DIAG_ANI_STATS: 1001 *result = ar5212AniGetCurrentStats(ah); 1002 *resultsize = (*result == AH_NULL) ? 1003 0 : sizeof(struct ar5212Stats); 1004 return AH_TRUE; 1005 case HAL_DIAG_ANI_CMD: 1006 if (argsize != 2*sizeof(uint32_t)) 1007 return AH_FALSE; 1008 ar5212AniControl(ah, ((const uint32_t *)args)[0], 1009 ((const uint32_t *)args)[1]); 1010 return AH_TRUE; 1011 case HAL_DIAG_ANI_PARAMS: 1012 /* 1013 * NB: We assume struct ar5212AniParams is identical 1014 * to HAL_ANI_PARAMS; if they diverge then we'll need 1015 * to handle it here 1016 */ 1017 if (argsize == 0 && args == AH_NULL) { 1018 struct ar5212AniState *aniState = 1019 ar5212AniGetCurrentState(ah); 1020 if (aniState == AH_NULL) 1021 return AH_FALSE; 1022 *result = __DECONST(void *, aniState->params); 1023 *resultsize = sizeof(struct ar5212AniParams); 1024 return AH_TRUE; 1025 } else { 1026 if (argsize != sizeof(struct ar5212AniParams)) 1027 return AH_FALSE; 1028 return ar5212AniSetParams(ah, args, args); 1029 } 1030 } 1031 return AH_FALSE; 1032} 1033#endif /* AH_SUPPORT_AR5212 */ 1034