Path: blob/main/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2008 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"22#include "ah_devid.h"23#include "ah_desc.h" /* NB: for HAL_PHYERR* */2425#include "ar5212/ar5212.h"26#include "ar5212/ar5212reg.h"27#include "ar5212/ar5212phy.h"2829#include "ah_eeprom_v3.h"3031#define AR_NUM_GPIO 6 /* 6 GPIO pins */32#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */3334void35ar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac)36{37struct ath_hal_5212 *ahp = AH5212(ah);3839OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN);40}4142HAL_BOOL43ar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac)44{45struct ath_hal_5212 *ahp = AH5212(ah);4647OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN);48return AH_TRUE;49}5051void52ar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask)53{54struct ath_hal_5212 *ahp = AH5212(ah);5556OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN);57}5859HAL_BOOL60ar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask)61{62struct ath_hal_5212 *ahp = AH5212(ah);6364/* save it since it must be rewritten on reset */65OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN);6667OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask));68OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4));69return AH_TRUE;70}7172/*73* Attempt to change the cards operating regulatory domain to the given value74*/75HAL_BOOL76ar5212SetRegulatoryDomain(struct ath_hal *ah,77uint16_t regDomain, HAL_STATUS *status)78{79HAL_STATUS ecode;8081if (AH_PRIVATE(ah)->ah_currentRD == regDomain) {82ecode = HAL_EINVAL;83goto bad;84}85if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) {86ecode = HAL_EEWRITE;87goto bad;88}89#ifdef AH_SUPPORT_WRITE_REGDOMAIN90if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) {91HALDEBUG(ah, HAL_DEBUG_ANY,92"%s: set regulatory domain to %u (0x%x)\n",93__func__, regDomain, regDomain);94AH_PRIVATE(ah)->ah_currentRD = regDomain;95return AH_TRUE;96}97#endif98ecode = HAL_EIO;99bad:100if (status)101*status = ecode;102return AH_FALSE;103}104105/*106* Return the wireless modes (a,b,g,t) supported by hardware.107*108* This value is what is actually supported by the hardware109* and is unaffected by regulatory/country code settings.110*/111u_int112ar5212GetWirelessModes(struct ath_hal *ah)113{114u_int mode = 0;115116if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) {117mode = HAL_MODE_11A;118if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE))119mode |= HAL_MODE_TURBO | HAL_MODE_108A;120if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate)121mode |= HAL_MODE_11A_HALF_RATE;122if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate)123mode |= HAL_MODE_11A_QUARTER_RATE;124}125if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE))126mode |= HAL_MODE_11B;127if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) &&128AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) {129mode |= HAL_MODE_11G;130if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE))131mode |= HAL_MODE_108G;132if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate)133mode |= HAL_MODE_11G_HALF_RATE;134if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate)135mode |= HAL_MODE_11G_QUARTER_RATE;136}137return mode;138}139140/*141* Set the interrupt and GPIO values so the ISR can disable RF142* on a switch signal. Assumes GPIO port and interrupt polarity143* are set prior to call.144*/145void146ar5212EnableRfKill(struct ath_hal *ah)147{148uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent;149int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL);150int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY);151152/*153* Configure the desired GPIO port for input154* and enable baseband rf silence.155*/156ath_hal_gpioCfgInput(ah, select);157OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000);158/*159* If radio disable switch connection to GPIO bit x is enabled160* program GPIO interrupt.161* If rfkill bit on eeprom is 1, setupeeprommap routine has already162* verified that it is a later version of eeprom, it has a place for163* rfkill bit and it is set to 1, indicating that GPIO bit x hardware164* connection is present.165*/166ath_hal_gpioSetIntr(ah, select,167(ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity));168}169170/*171* Change the LED blinking pattern to correspond to the connectivity172*/173void174ar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state)175{176static const uint32_t ledbits[8] = {177AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */178AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */179AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */180AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/181AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */182AR_PCICFG_LEDCTL_NONE,183AR_PCICFG_LEDCTL_NONE,184AR_PCICFG_LEDCTL_NONE,185};186uint32_t bits;187188bits = OS_REG_READ(ah, AR_PCICFG);189if (IS_2417(ah)) {190/*191* Enable LED for Nala. There is a bit marked reserved192* that must be set and we also turn on the power led.193* Because we mark s/w LED control setting the control194* status bits below is meangless (the driver must flash195* the LED(s) using the GPIO lines).196*/197bits = (bits &~ AR_PCICFG_LEDMODE)198| SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE)199#if 0200| SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE)201#endif202| 0x08000000;203}204bits = (bits &~ AR_PCICFG_LEDCTL)205| SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL);206OS_REG_WRITE(ah, AR_PCICFG, bits);207}208209/*210* Change association related fields programmed into the hardware.211* Writing a valid BSSID to the hardware effectively enables the hardware212* to synchronize its TSF to the correct beacons and receive frames coming213* from that BSSID. It is called by the SME JOIN operation.214*/215void216ar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId)217{218struct ath_hal_5212 *ahp = AH5212(ah);219220/* save bssid for possible re-use on reset */221OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);222ahp->ah_assocId = assocId;223OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));224OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) |225((assocId & 0x3fff)<<AR_BSS_ID1_AID_S));226}227228/*229* Get the current hardware tsf for stamlme230*/231uint64_t232ar5212GetTsf64(struct ath_hal *ah)233{234uint32_t low1, low2, u32;235236/* sync multi-word read */237low1 = OS_REG_READ(ah, AR_TSF_L32);238u32 = OS_REG_READ(ah, AR_TSF_U32);239low2 = OS_REG_READ(ah, AR_TSF_L32);240if (low2 < low1) { /* roll over */241/*242* If we are not preempted this will work. If we are243* then we re-reading AR_TSF_U32 does no good as the244* low bits will be meaningless. Likewise reading245* L32, U32, U32, then comparing the last two reads246* to check for rollover doesn't help if preempted--so247* we take this approach as it costs one less PCI read248* which can be noticeable when doing things like249* timestamping packets in monitor mode.250*/251u32++;252}253return (((uint64_t) u32) << 32) | ((uint64_t) low2);254}255256/*257* Get the current hardware tsf for stamlme258*/259uint32_t260ar5212GetTsf32(struct ath_hal *ah)261{262return OS_REG_READ(ah, AR_TSF_L32);263}264265void266ar5212SetTsf64(struct ath_hal *ah, uint64_t tsf64)267{268OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);269OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);270}271272/*273* Reset the current hardware tsf for stamlme.274*/275void276ar5212ResetTsf(struct ath_hal *ah)277{278279uint32_t val = OS_REG_READ(ah, AR_BEACON);280281OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);282/*283* When resetting the TSF, write twice to the284* corresponding register; each write to the RESET_TSF bit toggles285* the internal signal to cause a reset of the TSF - but if the signal286* is left high, it will reset the TSF on the next chip reset also!287* writing the bit an even number of times fixes this issue288*/289OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);290}291292/*293* Set or clear hardware basic rate bit294* Set hardware basic rate set if basic rate is found295* and basic rate is equal or less than 2Mbps296*/297void298ar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs)299{300const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;301uint32_t reg;302uint8_t xset;303int i;304305if (chan == AH_NULL || !IEEE80211_IS_CHAN_CCK(chan))306return;307xset = 0;308for (i = 0; i < rs->rs_count; i++) {309uint8_t rset = rs->rs_rates[i];310/* Basic rate defined? */311if ((rset & 0x80) && (rset &= 0x7f) >= xset)312xset = rset;313}314/*315* Set the h/w bit to reflect whether or not the basic316* rate is found to be equal or less than 2Mbps.317*/318reg = OS_REG_READ(ah, AR_STA_ID1);319if (xset && xset/2 <= 2)320OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B);321else322OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B);323}324325/*326* Grab a semi-random value from hardware registers - may not327* change often328*/329uint32_t330ar5212GetRandomSeed(struct ath_hal *ah)331{332uint32_t nf;333334nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff;335if (nf & 0x100)336nf = 0 - ((nf ^ 0x1ff) + 1);337return (OS_REG_READ(ah, AR_TSF_U32) ^338OS_REG_READ(ah, AR_TSF_L32) ^ nf);339}340341/*342* Detect if our card is present343*/344HAL_BOOL345ar5212DetectCardPresent(struct ath_hal *ah)346{347uint16_t macVersion, macRev;348uint32_t v;349350/*351* Read the Silicon Revision register and compare that352* to what we read at attach time. If the same, we say353* a card/device is present.354*/355v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID;356macVersion = v >> AR_SREV_ID_S;357macRev = v & AR_SREV_REVISION;358return (AH_PRIVATE(ah)->ah_macVersion == macVersion &&359AH_PRIVATE(ah)->ah_macRev == macRev);360}361362void363ar5212EnableMibCounters(struct ath_hal *ah)364{365/* NB: this just resets the mib counter machinery */366OS_REG_WRITE(ah, AR_MIBC,367~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f);368}369370void371ar5212DisableMibCounters(struct ath_hal *ah)372{373OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC);374}375376/*377* Update MIB Counters378*/379void380ar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats)381{382stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL);383stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL);384stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL);385stats->rts_good += OS_REG_READ(ah, AR_RTS_OK);386stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT);387}388389/*390* Detect if the HW supports spreading a CCK signal on channel 14391*/392HAL_BOOL393ar5212IsJapanChannelSpreadSupported(struct ath_hal *ah)394{395return AH_TRUE;396}397398/*399* Get the rssi of frame curently being received.400*/401uint32_t402ar5212GetCurRssi(struct ath_hal *ah)403{404return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff);405}406407u_int408ar5212GetDefAntenna(struct ath_hal *ah)409{410return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7);411}412413void414ar5212SetDefAntenna(struct ath_hal *ah, u_int antenna)415{416OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));417}418419HAL_ANT_SETTING420ar5212GetAntennaSwitch(struct ath_hal *ah)421{422return AH5212(ah)->ah_antControl;423}424425HAL_BOOL426ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting)427{428struct ath_hal_5212 *ahp = AH5212(ah);429const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;430431if (!ahp->ah_phyPowerOn || chan == AH_NULL) {432/* PHY powered off, just stash settings */433ahp->ah_antControl = setting;434ahp->ah_diversity = (setting == HAL_ANT_VARIABLE);435return AH_TRUE;436}437return ar5212SetAntennaSwitchInternal(ah, setting, chan);438}439440HAL_BOOL441ar5212IsSleepAfterBeaconBroken(struct ath_hal *ah)442{443return AH_TRUE;444}445446HAL_BOOL447ar5212SetSifsTime(struct ath_hal *ah, u_int us)448{449struct ath_hal_5212 *ahp = AH5212(ah);450451if (us > ath_hal_mac_usec(ah, 0xffff)) {452HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n",453__func__, us);454ahp->ah_sifstime = (u_int) -1; /* restore default handling */455return AH_FALSE;456} else {457/* convert to system clocks */458OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us-2));459ahp->ah_sifstime = us;460return AH_TRUE;461}462}463464u_int465ar5212GetSifsTime(struct ath_hal *ah)466{467u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff;468return ath_hal_mac_usec(ah, clks)+2; /* convert from system clocks */469}470471HAL_BOOL472ar5212SetSlotTime(struct ath_hal *ah, u_int us)473{474struct ath_hal_5212 *ahp = AH5212(ah);475476if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) {477HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n",478__func__, us);479ahp->ah_slottime = (u_int) -1; /* restore default handling */480return AH_FALSE;481} else {482/* convert to system clocks */483OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us));484ahp->ah_slottime = us;485return AH_TRUE;486}487}488489u_int490ar5212GetSlotTime(struct ath_hal *ah)491{492u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff;493return ath_hal_mac_usec(ah, clks); /* convert from system clocks */494}495496HAL_BOOL497ar5212SetAckTimeout(struct ath_hal *ah, u_int us)498{499struct ath_hal_5212 *ahp = AH5212(ah);500501if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {502HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n",503__func__, us);504ahp->ah_acktimeout = (u_int) -1; /* restore default handling */505return AH_FALSE;506} else {507/* convert to system clocks */508OS_REG_RMW_FIELD(ah, AR_TIME_OUT,509AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us));510ahp->ah_acktimeout = us;511return AH_TRUE;512}513}514515u_int516ar5212GetAckTimeout(struct ath_hal *ah)517{518u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK);519return ath_hal_mac_usec(ah, clks); /* convert from system clocks */520}521522u_int523ar5212GetAckCTSRate(struct ath_hal *ah)524{525return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0);526}527528HAL_BOOL529ar5212SetAckCTSRate(struct ath_hal *ah, u_int high)530{531struct ath_hal_5212 *ahp = AH5212(ah);532533if (high) {534OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);535ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB;536} else {537OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);538ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB;539}540return AH_TRUE;541}542543HAL_BOOL544ar5212SetCTSTimeout(struct ath_hal *ah, u_int us)545{546struct ath_hal_5212 *ahp = AH5212(ah);547548if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {549HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n",550__func__, us);551ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */552return AH_FALSE;553} else {554/* convert to system clocks */555OS_REG_RMW_FIELD(ah, AR_TIME_OUT,556AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us));557ahp->ah_ctstimeout = us;558return AH_TRUE;559}560}561562u_int563ar5212GetCTSTimeout(struct ath_hal *ah)564{565u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS);566return ath_hal_mac_usec(ah, clks); /* convert from system clocks */567}568569/* Setup decompression for given key index */570HAL_BOOL571ar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)572{573struct ath_hal_5212 *ahp = AH5212(ah);574575if (keyidx >= HAL_DECOMP_MASK_SIZE)576return AH_FALSE;577OS_REG_WRITE(ah, AR_DCM_A, keyidx);578OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0);579ahp->ah_decompMask[keyidx] = en;580581return AH_TRUE;582}583584/* Setup coverage class */585void586ar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)587{588uint32_t slot, timeout, eifs;589u_int clkRate;590591AH_PRIVATE(ah)->ah_coverageClass = coverageclass;592593if (now) {594if (AH_PRIVATE(ah)->ah_coverageClass == 0)595return;596597/* Don't apply coverage class to non A channels */598if (!IEEE80211_IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan))599return;600601/* Get core clock rate */602clkRate = ath_hal_mac_clks(ah, 1);603604/* Compute EIFS */605slot = coverageclass * 3 * clkRate;606eifs = coverageclass * 6 * clkRate;607if (IEEE80211_IS_CHAN_HALF(AH_PRIVATE(ah)->ah_curchan)) {608slot += IFS_SLOT_HALF_RATE;609eifs += IFS_EIFS_HALF_RATE;610} else if (IEEE80211_IS_CHAN_QUARTER(AH_PRIVATE(ah)->ah_curchan)) {611slot += IFS_SLOT_QUARTER_RATE;612eifs += IFS_EIFS_QUARTER_RATE;613} else { /* full rate */614slot += IFS_SLOT_FULL_RATE;615eifs += IFS_EIFS_FULL_RATE;616}617618/*619* Add additional time for air propagation for ACK and CTS620* timeouts. This value is in core clocks.621*/622timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate);623624/*625* Write the values: slot, eifs, ack/cts timeouts.626*/627OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot);628OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);629OS_REG_WRITE(ah, AR_TIME_OUT,630SM(timeout, AR_TIME_OUT_CTS)631| SM(timeout, AR_TIME_OUT_ACK));632}633}634635HAL_STATUS636ar5212SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration,637uint32_t nextStart, HAL_QUIET_FLAG flag)638{639OS_REG_WRITE(ah, AR_QUIET2, period | (duration << AR_QUIET2_QUIET_DUR_S));640if (flag & HAL_QUIET_ENABLE) {641OS_REG_WRITE(ah, AR_QUIET1, nextStart | (1 << 16));642}643else {644OS_REG_WRITE(ah, AR_QUIET1, nextStart);645}646return HAL_OK;647}648649void650ar5212SetPCUConfig(struct ath_hal *ah)651{652ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode);653}654655/*656* Return whether an external 32KHz crystal should be used657* to reduce power consumption when sleeping. We do so if658* the crystal is present (obtained from EEPROM) and if we659* are not running as an AP and are configured to use it.660*/661HAL_BOOL662ar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode)663{664if (opmode != HAL_M_HOSTAP) {665struct ath_hal_5212 *ahp = AH5212(ah);666return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) &&667(ahp->ah_enable32kHzClock == USE_32KHZ ||668ahp->ah_enable32kHzClock == AUTO_32KHZ);669} else670return AH_FALSE;671}672673/*674* If 32KHz clock exists, use it to lower power consumption during sleep675*676* Note: If clock is set to 32 KHz, delays on accessing certain677* baseband registers (27-31, 124-127) are required.678*/679void680ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode)681{682if (ar5212Use32KHzclock(ah, opmode)) {683/*684* Enable clocks to be turned OFF in BB during sleep685* and also enable turning OFF 32MHz/40MHz Refclk686* from A2.687*/688OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);689OS_REG_WRITE(ah, AR_PHY_REFCLKPD,690IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18);691OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1);692OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */693OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1);694695if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) {696OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26);697OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d);698OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07);699OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f);700/* # Set sleep clock rate to 32 KHz. */701OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2);702} else {703OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a);704OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c);705OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03);706OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20);707OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3);708}709} else {710OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0);711OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0);712713OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */714715OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);716OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f);717718if (IS_2417(ah))719OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a);720else if (IS_HB63(ah))721OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32);722else723OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);724OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);725OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);726OS_REG_WRITE(ah, AR_PHY_REFCLKPD,727IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18);728OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,729IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31);730}731}732733/*734* If 32KHz clock exists, turn it off and turn back on the 32Mhz735*/736void737ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode)738{739if (ar5212Use32KHzclock(ah, opmode)) {740/* # Set sleep clock rate back to 32 MHz. */741OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0);742OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0);743744OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */745OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32,746IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31);747748/*749* Restore BB registers to power-on defaults750*/751OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f);752OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f);753OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e);754OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c);755OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff);756OS_REG_WRITE(ah, AR_PHY_REFCLKPD,757IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18);758}759}760761/*762* Adjust NF based on statistical values for 5GHz frequencies.763* Default method: this may be overridden by the rf backend.764*/765int16_t766ar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c)767{768static const struct {769uint16_t freqLow;770int16_t adjust;771} adjustDef[] = {772{ 5790, 11 }, /* NB: ordered high -> low */773{ 5730, 10 },774{ 5690, 9 },775{ 5660, 8 },776{ 5610, 7 },777{ 5530, 5 },778{ 5450, 4 },779{ 5379, 2 },780{ 5209, 0 },781{ 3000, 1 },782{ 0, 0 },783};784int i;785786for (i = 0; c->channel <= adjustDef[i].freqLow; i++)787;788return adjustDef[i].adjust;789}790791HAL_STATUS792ar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,793uint32_t capability, uint32_t *result)794{795#define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion796struct ath_hal_5212 *ahp = AH5212(ah);797const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;798const struct ar5212AniState *ani;799800switch (type) {801case HAL_CAP_CIPHER: /* cipher handled in hardware */802switch (capability) {803case HAL_CIPHER_AES_CCM:804return pCap->halCipherAesCcmSupport ?805HAL_OK : HAL_ENOTSUPP;806case HAL_CIPHER_AES_OCB:807case HAL_CIPHER_TKIP:808case HAL_CIPHER_WEP:809case HAL_CIPHER_MIC:810case HAL_CIPHER_CLR:811return HAL_OK;812default:813return HAL_ENOTSUPP;814}815case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */816switch (capability) {817case 0: /* hardware capability */818return HAL_OK;819case 1:820return (ahp->ah_staId1Defaults &821AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO;822}823return HAL_EINVAL;824case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */825switch (capability) {826case 0: /* hardware capability */827return pCap->halTkipMicTxRxKeySupport ?828HAL_ENXIO : HAL_OK;829case 1: /* current setting */830return (ahp->ah_miscMode &831AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK;832}833return HAL_EINVAL;834case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */835/* XXX move to capability bit */836return MACVERSION(ah) > AR_SREV_VERSION_VENICE ||837(MACVERSION(ah) == AR_SREV_VERSION_VENICE &&838AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP;839case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */840switch (capability) {841case 0: /* hardware capability */842return HAL_OK;843case 1: /* current setting */844return ahp->ah_diversity ? HAL_OK : HAL_ENXIO;845case HAL_CAP_STRONG_DIV:846*result = OS_REG_READ(ah, AR_PHY_RESTART);847*result = MS(*result, AR_PHY_RESTART_DIV_GC);848return HAL_OK;849}850return HAL_EINVAL;851case HAL_CAP_DIAG:852*result = AH_PRIVATE(ah)->ah_diagreg;853return HAL_OK;854case HAL_CAP_TPC:855switch (capability) {856case 0: /* hardware capability */857return HAL_OK;858case 1:859return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO;860}861return HAL_OK;862case HAL_CAP_PHYDIAG: /* radar pulse detection capability */863switch (capability) {864case HAL_CAP_RADAR:865return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ?866HAL_OK: HAL_ENXIO;867case HAL_CAP_AR:868return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) ||869ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ?870HAL_OK: HAL_ENXIO;871}872return HAL_ENXIO;873case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */874switch (capability) {875case 0: /* hardware capability */876return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENXIO;877case 1:878return (ahp->ah_staId1Defaults &879AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO;880}881return HAL_EINVAL;882case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */883switch (capability) {884case 0: /* hardware capability */885return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP;886case 1:887return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ?888HAL_OK : HAL_ENXIO;889}890return HAL_EINVAL;891case HAL_CAP_TPC_ACK:892*result = MS(ahp->ah_macTPC, AR_TPC_ACK);893return HAL_OK;894case HAL_CAP_TPC_CTS:895*result = MS(ahp->ah_macTPC, AR_TPC_CTS);896return HAL_OK;897case HAL_CAP_INTMIT: /* interference mitigation */898switch (capability) {899case HAL_CAP_INTMIT_PRESENT: /* hardware capability */900return HAL_OK;901case HAL_CAP_INTMIT_ENABLE:902return (ahp->ah_procPhyErr & HAL_ANI_ENA) ?903HAL_OK : HAL_ENXIO;904case HAL_CAP_INTMIT_NOISE_IMMUNITY_LEVEL:905case HAL_CAP_INTMIT_OFDM_WEAK_SIGNAL_LEVEL:906case HAL_CAP_INTMIT_CCK_WEAK_SIGNAL_THR:907case HAL_CAP_INTMIT_FIRSTEP_LEVEL:908case HAL_CAP_INTMIT_SPUR_IMMUNITY_LEVEL:909ani = ar5212AniGetCurrentState(ah);910if (ani == AH_NULL)911return HAL_ENXIO;912switch (capability) {913case 2: *result = ani->noiseImmunityLevel; break;914case 3: *result = !ani->ofdmWeakSigDetectOff; break;915case 4: *result = ani->cckWeakSigThreshold; break;916case 5: *result = ani->firstepLevel; break;917case 6: *result = ani->spurImmunityLevel; break;918}919return HAL_OK;920}921return HAL_EINVAL;922default:923return ath_hal_getcapability(ah, type, capability, result);924}925#undef MACVERSION926}927928HAL_BOOL929ar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,930uint32_t capability, uint32_t setting, HAL_STATUS *status)931{932#define N(a) (sizeof(a)/sizeof(a[0]))933struct ath_hal_5212 *ahp = AH5212(ah);934const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;935uint32_t v;936937switch (type) {938case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */939if (setting)940ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE;941else942ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE;943return AH_TRUE;944case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */945if (!pCap->halTkipMicTxRxKeySupport)946return AH_FALSE;947/* NB: true =>'s use split key cache layout */948if (setting)949ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE;950else951ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE;952/* NB: write here so keys can be setup w/o a reset */953OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode);954return AH_TRUE;955case HAL_CAP_DIVERSITY:956switch (capability) {957case 0:958return AH_FALSE;959case 1: /* setting */960if (ahp->ah_phyPowerOn) {961if (capability == HAL_CAP_STRONG_DIV) {962v = OS_REG_READ(ah, AR_PHY_CCK_DETECT);963if (setting)964v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;965else966v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;967OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v);968}969}970ahp->ah_diversity = (setting != 0);971return AH_TRUE;972973case HAL_CAP_STRONG_DIV:974if (! ahp->ah_phyPowerOn)975return AH_FALSE;976v = OS_REG_READ(ah, AR_PHY_RESTART);977v &= ~AR_PHY_RESTART_DIV_GC;978v |= SM(setting, AR_PHY_RESTART_DIV_GC);979OS_REG_WRITE(ah, AR_PHY_RESTART, v);980return AH_TRUE;981default:982return AH_FALSE;983}984case HAL_CAP_DIAG: /* hardware diagnostic support */985/*986* NB: could split this up into virtual capabilities,987* (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly988* seems worth the additional complexity.989*/990AH_PRIVATE(ah)->ah_diagreg = setting;991OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);992return AH_TRUE;993case HAL_CAP_TPC:994ahp->ah_tpcEnabled = (setting != 0);995return AH_TRUE;996case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */997if (setting)998ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;999else1000ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;1001return AH_TRUE;1002case HAL_CAP_TPC_ACK:1003case HAL_CAP_TPC_CTS:1004setting += ahp->ah_txPowerIndexOffset;1005if (setting > 63)1006setting = 63;1007if (type == HAL_CAP_TPC_ACK) {1008ahp->ah_macTPC &= AR_TPC_ACK;1009ahp->ah_macTPC |= MS(setting, AR_TPC_ACK);1010} else {1011ahp->ah_macTPC &= AR_TPC_CTS;1012ahp->ah_macTPC |= MS(setting, AR_TPC_CTS);1013}1014OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC);1015return AH_TRUE;1016case HAL_CAP_INTMIT: { /* interference mitigation */1017/* This maps the public ANI commands to the internal ANI commands */1018/* Private: HAL_ANI_CMD; Public: HAL_CAP_INTMIT_CMD */1019static const HAL_ANI_CMD cmds[] = {1020HAL_ANI_PRESENT,1021HAL_ANI_MODE,1022HAL_ANI_NOISE_IMMUNITY_LEVEL,1023HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,1024HAL_ANI_CCK_WEAK_SIGNAL_THR,1025HAL_ANI_FIRSTEP_LEVEL,1026HAL_ANI_SPUR_IMMUNITY_LEVEL,1027};1028return capability < N(cmds) ?1029AH5212(ah)->ah_aniControl(ah, cmds[capability], setting) :1030AH_FALSE;1031}1032case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */1033if (pCap->halTsfAddSupport) {1034if (setting)1035ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF;1036else1037ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF;1038return AH_TRUE;1039}1040/* fall thru... */1041default:1042return ath_hal_setcapability(ah, type, capability,1043setting, status);1044}1045#undef N1046}10471048HAL_BOOL1049ar5212GetDiagState(struct ath_hal *ah, int request,1050const void *args, uint32_t argsize,1051void **result, uint32_t *resultsize)1052{1053struct ath_hal_5212 *ahp = AH5212(ah);1054HAL_ANI_STATS *astats;10551056(void) ahp;1057if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))1058return AH_TRUE;1059switch (request) {1060case HAL_DIAG_EEPROM:1061case HAL_DIAG_EEPROM_EXP_11A:1062case HAL_DIAG_EEPROM_EXP_11B:1063case HAL_DIAG_EEPROM_EXP_11G:1064case HAL_DIAG_RFGAIN:1065return ath_hal_eepromDiag(ah, request,1066args, argsize, result, resultsize);1067case HAL_DIAG_RFGAIN_CURSTEP:1068*result = __DECONST(void *, ahp->ah_gainValues.currStep);1069*resultsize = (*result == AH_NULL) ?10700 : sizeof(GAIN_OPTIMIZATION_STEP);1071return AH_TRUE;1072case HAL_DIAG_PCDAC:1073*result = ahp->ah_pcdacTable;1074*resultsize = ahp->ah_pcdacTableSize;1075return AH_TRUE;1076case HAL_DIAG_TXRATES:1077*result = &ahp->ah_ratesArray[0];1078*resultsize = sizeof(ahp->ah_ratesArray);1079return AH_TRUE;1080case HAL_DIAG_ANI_CURRENT:1081*result = ar5212AniGetCurrentState(ah);1082*resultsize = (*result == AH_NULL) ?10830 : sizeof(struct ar5212AniState);1084return AH_TRUE;1085case HAL_DIAG_ANI_STATS:1086OS_MEMZERO(&ahp->ext_ani_stats, sizeof(ahp->ext_ani_stats));1087astats = ar5212AniGetCurrentStats(ah);1088if (astats == NULL) {1089*result = NULL;1090*resultsize = 0;1091} else {1092OS_MEMCPY(&ahp->ext_ani_stats, astats, sizeof(HAL_ANI_STATS));1093*result = &ahp->ext_ani_stats;1094*resultsize = sizeof(ahp->ext_ani_stats);1095}1096return AH_TRUE;1097case HAL_DIAG_ANI_CMD:1098if (argsize != 2*sizeof(uint32_t))1099return AH_FALSE;1100AH5212(ah)->ah_aniControl(ah, ((const uint32_t *)args)[0],1101((const uint32_t *)args)[1]);1102return AH_TRUE;1103case HAL_DIAG_ANI_PARAMS:1104/*1105* NB: We assume struct ar5212AniParams is identical1106* to HAL_ANI_PARAMS; if they diverge then we'll need1107* to handle it here1108*/1109if (argsize == 0 && args == AH_NULL) {1110struct ar5212AniState *aniState =1111ar5212AniGetCurrentState(ah);1112if (aniState == AH_NULL)1113return AH_FALSE;1114*result = __DECONST(void *, aniState->params);1115*resultsize = sizeof(struct ar5212AniParams);1116return AH_TRUE;1117} else {1118if (argsize != sizeof(struct ar5212AniParams))1119return AH_FALSE;1120return ar5212AniSetParams(ah, args, args);1121}1122break;1123}1124return AH_FALSE;1125}11261127/*1128* Check whether there's an in-progress NF completion.1129*1130* Returns AH_TRUE if there's a in-progress NF calibration, AH_FALSE1131* otherwise.1132*/1133HAL_BOOL1134ar5212IsNFCalInProgress(struct ath_hal *ah)1135{1136if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF)1137return AH_TRUE;1138return AH_FALSE;1139}11401141/*1142* Wait for an in-progress NF calibration to complete.1143*1144* The completion function waits "i" times 10uS.1145* It returns AH_TRUE if the NF calibration completed (or was never1146* in progress); AH_FALSE if it was still in progress after "i" checks.1147*/1148HAL_BOOL1149ar5212WaitNFCalComplete(struct ath_hal *ah, int i)1150{1151int j;1152if (i <= 0)1153i = 1; /* it should run at least once */1154for (j = 0; j < i; j++) {1155if (! ar5212IsNFCalInProgress(ah))1156return AH_TRUE;1157OS_DELAY(10);1158}1159return AH_FALSE;1160}11611162void1163ar5212EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)1164{1165uint32_t val;1166val = OS_REG_READ(ah, AR_PHY_RADAR_0);11671168if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {1169val &= ~AR_PHY_RADAR_0_FIRPWR;1170val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);1171}1172if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {1173val &= ~AR_PHY_RADAR_0_RRSSI;1174val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);1175}1176if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {1177val &= ~AR_PHY_RADAR_0_HEIGHT;1178val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);1179}1180if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {1181val &= ~AR_PHY_RADAR_0_PRSSI;1182val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);1183}1184if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {1185val &= ~AR_PHY_RADAR_0_INBAND;1186val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);1187}1188if (pe->pe_enabled)1189val |= AR_PHY_RADAR_0_ENA;1190else1191val &= ~ AR_PHY_RADAR_0_ENA;11921193if (IS_5413(ah)) {1194if (pe->pe_blockradar == 1)1195OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,1196AR_PHY_RADAR_2_BLOCKOFDMWEAK);1197else1198OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,1199AR_PHY_RADAR_2_BLOCKOFDMWEAK);12001201if (pe->pe_en_relstep_check == 1)1202OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,1203AR_PHY_RADAR_2_ENRELSTEPCHK);1204else1205OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,1206AR_PHY_RADAR_2_ENRELSTEPCHK);12071208if (pe->pe_usefir128 == 1)1209OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,1210AR_PHY_RADAR_2_USEFIR128);1211else1212OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,1213AR_PHY_RADAR_2_USEFIR128);12141215if (pe->pe_enmaxrssi == 1)1216OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,1217AR_PHY_RADAR_2_ENMAXRSSI);1218else1219OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,1220AR_PHY_RADAR_2_ENMAXRSSI);12211222if (pe->pe_enrelpwr == 1)1223OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,1224AR_PHY_RADAR_2_ENRELPWRCHK);1225else1226OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,1227AR_PHY_RADAR_2_ENRELPWRCHK);12281229if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL)1230OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_2,1231AR_PHY_RADAR_2_RELPWR, pe->pe_relpwr);12321233if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL)1234OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_2,1235AR_PHY_RADAR_2_RELSTEP, pe->pe_relstep);12361237if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL)1238OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_2,1239AR_PHY_RADAR_2_MAXLEN, pe->pe_maxlen);1240}12411242OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);1243}12441245/*1246* Parameters for the AR5212 PHY.1247*/1248#define AR5212_DFS_FIRPWR -351249#define AR5212_DFS_RRSSI 201250#define AR5212_DFS_HEIGHT 141251#define AR5212_DFS_PRSSI 61252#define AR5212_DFS_INBAND 412531254/*1255* Default parameters for the AR5413 PHY.1256*/1257#define AR5413_DFS_FIRPWR -341258#define AR5413_DFS_RRSSI 201259#define AR5413_DFS_HEIGHT 101260#define AR5413_DFS_PRSSI 151261#define AR5413_DFS_INBAND 61262#define AR5413_DFS_RELPWR 81263#define AR5413_DFS_RELSTEP 311264#define AR5413_DFS_MAXLEN 25512651266HAL_BOOL1267ar5212GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)1268{12691270if (IS_5413(ah)) {1271pe->pe_firpwr = AR5413_DFS_FIRPWR;1272pe->pe_rrssi = AR5413_DFS_RRSSI;1273pe->pe_height = AR5413_DFS_HEIGHT;1274pe->pe_prssi = AR5413_DFS_PRSSI;1275pe->pe_inband = AR5413_DFS_INBAND;1276pe->pe_relpwr = AR5413_DFS_RELPWR;1277pe->pe_relstep = AR5413_DFS_RELSTEP;1278pe->pe_maxlen = AR5413_DFS_MAXLEN;1279pe->pe_usefir128 = 0;1280pe->pe_blockradar = 1;1281pe->pe_enmaxrssi = 1;1282pe->pe_enrelpwr = 1;1283pe->pe_en_relstep_check = 0;1284} else {1285pe->pe_firpwr = AR5212_DFS_FIRPWR;1286pe->pe_rrssi = AR5212_DFS_RRSSI;1287pe->pe_height = AR5212_DFS_HEIGHT;1288pe->pe_prssi = AR5212_DFS_PRSSI;1289pe->pe_inband = AR5212_DFS_INBAND;1290pe->pe_relpwr = 0;1291pe->pe_relstep = 0;1292pe->pe_maxlen = 0;1293pe->pe_usefir128 = 0;1294pe->pe_blockradar = 0;1295pe->pe_enmaxrssi = 0;1296pe->pe_enrelpwr = 0;1297pe->pe_en_relstep_check = 0;1298}12991300return (AH_TRUE);1301}13021303void1304ar5212GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)1305{1306uint32_t val,temp;13071308val = OS_REG_READ(ah, AR_PHY_RADAR_0);13091310temp = MS(val,AR_PHY_RADAR_0_FIRPWR);1311temp |= 0xFFFFFF80;1312pe->pe_firpwr = temp;1313pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);1314pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT);1315pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);1316pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);1317pe->pe_enabled = !! (val & AR_PHY_RADAR_0_ENA);13181319pe->pe_relpwr = 0;1320pe->pe_relstep = 0;1321pe->pe_maxlen = 0;1322pe->pe_usefir128 = 0;1323pe->pe_blockradar = 0;1324pe->pe_enmaxrssi = 0;1325pe->pe_enrelpwr = 0;1326pe->pe_en_relstep_check = 0;1327pe->pe_extchannel = AH_FALSE;13281329if (IS_5413(ah)) {1330val = OS_REG_READ(ah, AR_PHY_RADAR_2);1331pe->pe_relpwr = !! MS(val, AR_PHY_RADAR_2_RELPWR);1332pe->pe_relstep = !! MS(val, AR_PHY_RADAR_2_RELSTEP);1333pe->pe_maxlen = !! MS(val, AR_PHY_RADAR_2_MAXLEN);13341335pe->pe_usefir128 = !! (val & AR_PHY_RADAR_2_USEFIR128);1336pe->pe_blockradar = !! (val & AR_PHY_RADAR_2_BLOCKOFDMWEAK);1337pe->pe_enmaxrssi = !! (val & AR_PHY_RADAR_2_ENMAXRSSI);1338pe->pe_enrelpwr = !! (val & AR_PHY_RADAR_2_ENRELPWRCHK);1339pe->pe_en_relstep_check =1340!! (val & AR_PHY_RADAR_2_ENRELSTEPCHK);1341}1342}13431344/*1345* Process the radar phy error and extract the pulse duration.1346*/1347HAL_BOOL1348ar5212ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,1349uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)1350{1351uint8_t dur;1352uint8_t rssi;13531354/* Check whether the given phy error is a radar event */1355if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&1356(rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT))1357return AH_FALSE;13581359/*1360* The first byte is the pulse width - if there's1361* no data, simply set the duration to 01362*/1363if (rxs->rs_datalen >= 1)1364/* The pulse width is byte 0 of the data */1365dur = ((uint8_t) buf[0]) & 0xff;1366else1367dur = 0;13681369/* Pulse RSSI is the normal reported RSSI */1370rssi = (uint8_t) rxs->rs_rssi;13711372/* 0 duration/rssi is not a valid radar event */1373if (dur == 0 && rssi == 0)1374return AH_FALSE;13751376HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n",1377__func__, rssi, dur);13781379/* Record the event */1380event->re_full_ts = fulltsf;1381event->re_ts = rxs->rs_tstamp;1382event->re_rssi = rssi;1383event->re_dur = dur;1384event->re_flags = HAL_DFS_EVENT_PRICH;13851386return AH_TRUE;1387}13881389/*1390* Return whether 5GHz fast-clock (44MHz) is enabled.1391* It's always disabled for AR5212 series NICs.1392*/1393HAL_BOOL1394ar5212IsFastClockEnabled(struct ath_hal *ah)1395{1396return AH_FALSE;1397}13981399/*1400* Return what percentage of the extension channel is busy.1401* This is always disabled for AR5212 series NICs.1402*/1403uint32_t1404ar5212Get11nExtBusy(struct ath_hal *ah)1405{1406return 0;1407}14081409/*1410* Channel survey support.1411*/1412HAL_BOOL1413ar5212GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)1414{1415struct ath_hal_5212 *ahp = AH5212(ah);1416u_int32_t good = AH_TRUE;14171418/* XXX freeze/unfreeze mib counters */1419uint32_t rc = OS_REG_READ(ah, AR_RCCNT);1420uint32_t rf = OS_REG_READ(ah, AR_RFCNT);1421uint32_t tf = OS_REG_READ(ah, AR_TFCNT);1422uint32_t cc = OS_REG_READ(ah, AR_CCCNT); /* read cycles last */14231424if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cc) {1425/*1426* Cycle counter wrap (or initial call); it's not possible1427* to accurately calculate a value because the registers1428* right shift rather than wrap--so punt and return 0.1429*/1430HALDEBUG(ah, HAL_DEBUG_ANY,1431"%s: cycle counter wrap. ExtBusy = 0\n", __func__);1432good = AH_FALSE;1433} else {1434hsample->cycle_count = cc - ahp->ah_cycleCount;1435hsample->chan_busy = rc - ahp->ah_ctlBusy;1436hsample->ext_chan_busy = 0;1437hsample->rx_busy = rf - ahp->ah_rxBusy;1438hsample->tx_busy = tf - ahp->ah_txBusy;1439}14401441/*1442* Keep a copy of the MIB results so the next sample has something1443* to work from.1444*/1445ahp->ah_cycleCount = cc;1446ahp->ah_rxBusy = rf;1447ahp->ah_ctlBusy = rc;1448ahp->ah_txBusy = tf;14491450return (good);1451}14521453void1454ar5212SetChainMasks(struct ath_hal *ah, uint32_t tx_chainmask,1455uint32_t rx_chainmask)1456{1457}14581459/*1460* Get the current NAV value from the hardware.1461*1462* 0xdeadbeef indicates the hardware is currently powered off.1463*/1464u_int1465ar5212GetNav(struct ath_hal *ah)1466{1467uint32_t reg;14681469reg = OS_REG_READ(ah, AR_NAV);14701471if (reg == 0xdeadbeef)1472return (0);1473return (reg);1474}14751476/*1477* Set the current NAV value to the hardware.1478*/1479void1480ar5212SetNav(struct ath_hal *ah, u_int val)1481{14821483OS_REG_WRITE(ah, AR_NAV, val);1484}148514861487