diff options
Diffstat (limited to 'sys/dev/ath/ath_hal/ar5211')
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211.h | 331 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_attach.c | 556 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c | 184 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c | 160 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c | 177 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_misc.c | 756 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_phy.c | 103 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_power.c | 140 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_recv.c | 248 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_reset.c | 2120 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c | 699 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211desc.h | 132 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211phy.h | 93 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211reg.h | 863 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/boss.ini | 356 |
15 files changed, 6918 insertions, 0 deletions
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211.h b/sys/dev/ath/ath_hal/ar5211/ar5211.h new file mode 100644 index 000000000000..08396ed85dcb --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211.h @@ -0,0 +1,331 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _ATH_AR5211_H_ +#define _ATH_AR5211_H_ + +#include "ah_eeprom.h" + +#define AR5211_MAGIC 0x19570405 + +/* Classes for WME streams */ +#define AC_BK 0 +#define AC_BE 1 +#define AC_VI 2 +#define AC_VO 3 + +/* DCU Transmit Filter macros */ +#define CALC_MMR(dcu, idx) \ + ( (4 * dcu) + (idx < 32 ? 0 : (idx < 64 ? 1 : (idx < 96 ? 2 : 3))) ) +#define TXBLK_FROM_MMR(mmr) \ + (AR_D_TXBLK_BASE + ((mmr & 0x1f) << 6) + ((mmr & 0x20) >> 3)) +#define CALC_TXBLK_ADDR(dcu, idx) (TXBLK_FROM_MMR(CALC_MMR(dcu, idx))) +#define CALC_TXBLK_VALUE(idx) (1 << (idx & 0x1f)) + +/* MAC register values */ + +#define INIT_INTERRUPT_MASK \ + ( AR_IMR_TXERR | AR_IMR_TXOK | AR_IMR_RXORN | \ + AR_IMR_RXERR | AR_IMR_RXOK | AR_IMR_TXURN | \ + AR_IMR_HIUERR ) +#define INIT_BEACON_CONTROL \ + ( (INIT_RESET_TSF << 24) | (INIT_BEACON_EN << 23) | \ + (INIT_TIM_OFFSET << 16) | INIT_BEACON_PERIOD ) + +#define INIT_CONFIG_STATUS 0x00000000 +#define INIT_RSSI_THR 0x00000700 /* Missed beacon counter initialized to 0x7 (max is 0xff) */ +#define INIT_IQCAL_LOG_COUNT_MAX 0xF +#define INIT_BCON_CNTRL_REG 0x00000000 + +#define INIT_BEACON_PERIOD 0xffff +#define INIT_TIM_OFFSET 0 +#define INIT_BEACON_EN 0 /* this should be set by AP only when it's ready */ +#define INIT_RESET_TSF 0 + +/* + * Various fifo fill before Tx start, in 64-byte units + * i.e. put the frame in the air while still DMAing + */ +#define MIN_TX_FIFO_THRESHOLD 0x1 +#define MAX_TX_FIFO_THRESHOLD ((IEEE80211_MAX_LEN / 64) + 1) +#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD + +/* + * Gain support. + */ +typedef struct _gainOptStep { + int16_t paramVal[4]; + int32_t stepGain; + int8_t stepName[16]; +} GAIN_OPTIMIZATION_STEP; + +typedef struct { + uint32_t numStepsInLadder; + uint32_t defaultStepNum; + GAIN_OPTIMIZATION_STEP optStep[10]; +} GAIN_OPTIMIZATION_LADDER; + +typedef struct { + uint32_t currStepNum; + uint32_t currGain; + uint32_t targetGain; + uint32_t loTrig; + uint32_t hiTrig; + uint32_t active; + const GAIN_OPTIMIZATION_STEP *currStep; +} GAIN_VALUES; + +enum { + RFGAIN_INACTIVE, + RFGAIN_READ_REQUESTED, + RFGAIN_NEED_CHANGE +}; + +/* + * Header Info - general parameters and + * values set for each chipset board solution + * that are programmed every reset + */ +struct ath_hal_5211 { + struct ath_hal_private ah_priv; /* base class */ + + GAIN_VALUES ah_gainValues; + + uint8_t ah_macaddr[IEEE80211_ADDR_LEN]; + uint8_t ah_bssid[IEEE80211_ADDR_LEN]; + + /* + * Runtime state. + */ + uint32_t ah_maskReg; /* copy of AR_IMR */ + uint32_t ah_txOkInterruptMask; + uint32_t ah_txErrInterruptMask; + uint32_t ah_txDescInterruptMask; + uint32_t ah_txEolInterruptMask; + uint32_t ah_txUrnInterruptMask; + HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES]; + HAL_ANT_SETTING ah_diversityControl; /* antenna setting */ + uint32_t ah_calibrationTime; + HAL_BOOL ah_bIQCalibration; + int ah_rfgainState; + uint32_t ah_tx6PowerInHalfDbm; /* power output for 6Mb tx */ + uint32_t ah_staId1Defaults; /* STA_ID1 default settings */ + uint32_t ah_beaconInterval; + uint32_t ah_rssiThr; /* RSSI_THR settings */ + + u_int ah_sifstime; /* user-specified sifs time */ + u_int ah_slottime; /* user-specified slot time */ + u_int ah_acktimeout; /* user-specified ack timeout */ + u_int ah_ctstimeout; /* user-specified cts timeout */ + /* + * RF Silent handling. + */ + uint32_t ah_gpioSelect; /* GPIO pin to use */ + uint32_t ah_polarity; /* polarity to disable RF */ + uint32_t ah_gpioBit; /* after init, prev value */ +}; +#define AH5211(ah) ((struct ath_hal_5211 *)(ah)) + +struct ath_hal; + +extern void ar5211Detach(struct ath_hal *); + +extern HAL_BOOL ar5211Reset(struct ath_hal *, HAL_OPMODE, + struct ieee80211_channel *, HAL_BOOL bChannelChange, + HAL_RESET_TYPE, + HAL_STATUS *); +extern HAL_BOOL ar5211PhyDisable(struct ath_hal *); +extern HAL_BOOL ar5211Disable(struct ath_hal *); +extern HAL_BOOL ar5211ChipReset(struct ath_hal *, + const struct ieee80211_channel *); +extern HAL_BOOL ar5211PerCalibration(struct ath_hal *, struct ieee80211_channel *, HAL_BOOL *); +extern HAL_BOOL ar5211PerCalibrationN(struct ath_hal *ah, struct ieee80211_channel *chan, + u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone); +extern HAL_BOOL ar5211ResetCalValid(struct ath_hal *ah, const struct ieee80211_channel *); +extern HAL_BOOL ar5211SetTxPowerLimit(struct ath_hal *, uint32_t limit); +extern HAL_BOOL ar5211CalNoiseFloor(struct ath_hal *, + const struct ieee80211_channel *); +extern HAL_BOOL ar5211SetAntennaSwitchInternal(struct ath_hal *, + HAL_ANT_SETTING, const struct ieee80211_channel *); +extern int16_t ar5211GetNfAdjust(struct ath_hal *, + const HAL_CHANNEL_INTERNAL *); +extern HAL_BOOL ar5211ResetDma(struct ath_hal *, HAL_OPMODE); +extern void ar5211InitializeGainValues(struct ath_hal *); +extern HAL_RFGAIN ar5211GetRfgain(struct ath_hal *); +extern void ar5211SetPCUConfig(struct ath_hal *); + +extern HAL_BOOL ar5211SetTxQueueProps(struct ath_hal *ah, int q, + const HAL_TXQ_INFO *qInfo); +extern HAL_BOOL ar5211GetTxQueueProps(struct ath_hal *ah, int q, + HAL_TXQ_INFO *qInfo); +extern int ar5211SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, + const HAL_TXQ_INFO *qInfo); +extern HAL_BOOL ar5211ReleaseTxQueue(struct ath_hal *ah, u_int q); +extern HAL_BOOL ar5211ResetTxQueue(struct ath_hal *ah, u_int q); +extern uint32_t ar5211GetTxDP(struct ath_hal *, u_int); +extern HAL_BOOL ar5211SetTxDP(struct ath_hal *, u_int, uint32_t txdp); +extern HAL_BOOL ar5211UpdateTxTrigLevel(struct ath_hal *, HAL_BOOL); +extern HAL_BOOL ar5211StartTxDma(struct ath_hal *, u_int); +extern HAL_BOOL ar5211StopTxDma(struct ath_hal *, u_int); +extern uint32_t ar5211NumTxPending(struct ath_hal *, u_int qnum); +extern HAL_BOOL ar5211IsTxQueueStopped(struct ath_hal *, u_int); +extern HAL_BOOL ar5211GetTransmitFilterIndex(struct ath_hal *, uint32_t); +extern HAL_BOOL ar5211SetupTxDesc(struct ath_hal *, struct ath_desc *, + u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int txPower, + u_int txRate0, u_int txTries0, + u_int keyIx, u_int antMode, u_int flags, + u_int rtsctsRate, u_int rtsctsDuration, + u_int compicvLen, u_int compivLen, u_int comp); +extern HAL_BOOL ar5211SetupXTxDesc(struct ath_hal *, struct ath_desc *, + u_int txRate1, u_int txRetries1, + u_int txRate2, u_int txRetries2, + u_int txRate3, u_int txRetries3); +extern HAL_BOOL ar5211FillTxDesc(struct ath_hal *, struct ath_desc *, + HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, + u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0); +extern HAL_STATUS ar5211ProcTxDesc(struct ath_hal *, + struct ath_desc *, struct ath_tx_status *); +extern void ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *); +extern void ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *); +extern HAL_BOOL ar5211GetTxCompletionRates(struct ath_hal *ah, + const struct ath_desc *ds0, int *rates, int *tries); +extern void ar5211SetTxDescLink(struct ath_hal *ah, void *ds, + uint32_t link); +extern void ar5211GetTxDescLink(struct ath_hal *ah, void *ds, + uint32_t *link); +extern void ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds, + uint32_t **linkptr); + +extern uint32_t ar5211GetRxDP(struct ath_hal *, HAL_RX_QUEUE); +extern void ar5211SetRxDP(struct ath_hal *, uint32_t rxdp, HAL_RX_QUEUE); +extern void ar5211EnableReceive(struct ath_hal *); +extern HAL_BOOL ar5211StopDmaReceive(struct ath_hal *); +extern void ar5211StartPcuReceive(struct ath_hal *, HAL_BOOL); +extern void ar5211StopPcuReceive(struct ath_hal *); +extern void ar5211SetMulticastFilter(struct ath_hal *, + uint32_t filter0, uint32_t filter1); +extern HAL_BOOL ar5211ClrMulticastFilterIndex(struct ath_hal *, uint32_t); +extern HAL_BOOL ar5211SetMulticastFilterIndex(struct ath_hal *, uint32_t); +extern uint32_t ar5211GetRxFilter(struct ath_hal *); +extern void ar5211SetRxFilter(struct ath_hal *, uint32_t); +extern HAL_BOOL ar5211SetupRxDesc(struct ath_hal *, struct ath_desc *, + uint32_t, u_int flags); +extern HAL_STATUS ar5211ProcRxDesc(struct ath_hal *, struct ath_desc *, + uint32_t, struct ath_desc *, uint64_t, + struct ath_rx_status *); + +extern void ar5211GetMacAddress(struct ath_hal *, uint8_t *); +extern HAL_BOOL ar5211SetMacAddress(struct ath_hal *ah, const uint8_t *); +extern void ar5211GetBssIdMask(struct ath_hal *, uint8_t *); +extern HAL_BOOL ar5211SetBssIdMask(struct ath_hal *, const uint8_t *); +extern HAL_BOOL ar5211EepromRead(struct ath_hal *, u_int off, uint16_t *data); +extern HAL_BOOL ar5211EepromWrite(struct ath_hal *, u_int off, uint16_t data); +extern HAL_BOOL ar5211SetRegulatoryDomain(struct ath_hal *, + uint16_t, HAL_STATUS *); +extern u_int ar5211GetWirelessModes(struct ath_hal *); +extern void ar5211EnableRfKill(struct ath_hal *); +extern uint32_t ar5211GpioGet(struct ath_hal *, uint32_t gpio); +extern void ar5211GpioSetIntr(struct ath_hal *, u_int, uint32_t ilevel); +extern HAL_BOOL ar5211GpioCfgOutput(struct ath_hal *, uint32_t gpio, + HAL_GPIO_MUX_TYPE); +extern HAL_BOOL ar5211GpioCfgInput(struct ath_hal *, uint32_t gpio); +extern HAL_BOOL ar5211GpioSet(struct ath_hal *, uint32_t gpio, uint32_t val); +extern void ar5211SetLedState(struct ath_hal *, HAL_LED_STATE); +extern u_int ar5211AntennaGet(struct ath_hal *); +extern void ar5211WriteAssocid(struct ath_hal *, + const uint8_t *bssid, uint16_t assocId); +extern uint64_t ar5211GetTsf64(struct ath_hal *); +extern uint32_t ar5211GetTsf32(struct ath_hal *); +extern void ar5211ResetTsf(struct ath_hal *); +extern uint32_t ar5211GetMaxTurboRate(struct ath_hal *); +extern uint32_t ar5211GetRandomSeed(struct ath_hal *); +extern HAL_BOOL ar5211DetectCardPresent(struct ath_hal *); +extern void ar5211UpdateMibCounters(struct ath_hal *, HAL_MIB_STATS *); +extern void ar5211EnableHwEncryption(struct ath_hal *); +extern void ar5211DisableHwEncryption(struct ath_hal *); +extern HAL_BOOL ar5211SetSlotTime(struct ath_hal *, u_int); +extern u_int ar5211GetSlotTime(struct ath_hal *); +extern HAL_BOOL ar5211SetAckTimeout(struct ath_hal *, u_int); +extern u_int ar5211GetAckTimeout(struct ath_hal *); +extern HAL_BOOL ar5211SetAckCTSRate(struct ath_hal *, u_int); +extern u_int ar5211GetAckCTSRate(struct ath_hal *); +extern HAL_BOOL ar5211SetCTSTimeout(struct ath_hal *, u_int); +extern u_int ar5211GetCTSTimeout(struct ath_hal *); +extern HAL_BOOL ar5211SetSifsTime(struct ath_hal *, u_int); +extern u_int ar5211GetSifsTime(struct ath_hal *); +extern HAL_BOOL ar5211SetDecompMask(struct ath_hal *, uint16_t, int); +extern void ar5211SetCoverageClass(struct ath_hal *, uint8_t, int); +extern HAL_STATUS ar5211SetQuiet(struct ath_hal *, uint32_t, uint32_t, + uint32_t, HAL_QUIET_FLAG); +extern uint32_t ar5211GetCurRssi(struct ath_hal *); +extern u_int ar5211GetDefAntenna(struct ath_hal *); +extern void ar5211SetDefAntenna(struct ath_hal *ah, u_int antenna); +extern HAL_ANT_SETTING ar5211GetAntennaSwitch(struct ath_hal *); +extern HAL_BOOL ar5211SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); +extern HAL_STATUS ar5211GetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE, + uint32_t, uint32_t *); +extern HAL_BOOL ar5211SetCapability(struct ath_hal *, HAL_CAPABILITY_TYPE, + uint32_t, uint32_t, HAL_STATUS *); +extern HAL_BOOL ar5211GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize); +extern uint32_t ar5211Get11nExtBusy(struct ath_hal *); +extern HAL_BOOL ar5211GetMibCycleCounts(struct ath_hal *, + HAL_SURVEY_SAMPLE *); +extern void ar5211SetChainMasks(struct ath_hal *ah, uint32_t, uint32_t); +extern void ar5211SetNav(struct ath_hal *ah, u_int); +extern u_int ar5211GetNav(struct ath_hal *ah); + +extern void ar5211EnableDfs(struct ath_hal *, HAL_PHYERR_PARAM *); +extern void ar5211GetDfsThresh(struct ath_hal *, HAL_PHYERR_PARAM *); + +extern u_int ar5211GetKeyCacheSize(struct ath_hal *); +extern HAL_BOOL ar5211IsKeyCacheEntryValid(struct ath_hal *, uint16_t); +extern HAL_BOOL ar5211ResetKeyCacheEntry(struct ath_hal *, uint16_t entry); +extern HAL_BOOL ar5211SetKeyCacheEntry(struct ath_hal *, uint16_t entry, + const HAL_KEYVAL *, const uint8_t *mac, + int xorKey); +extern HAL_BOOL ar5211SetKeyCacheEntryMac(struct ath_hal *, + uint16_t, const uint8_t *); + +extern HAL_BOOL ar5211SetPowerMode(struct ath_hal *, HAL_POWER_MODE mode, + int setChip); +extern HAL_POWER_MODE ar5211GetPowerMode(struct ath_hal *); + +extern void ar5211SetBeaconTimers(struct ath_hal *, + const HAL_BEACON_TIMERS *); +extern void ar5211BeaconInit(struct ath_hal *, uint32_t, uint32_t); +extern void ar5211SetStaBeaconTimers(struct ath_hal *, + const HAL_BEACON_STATE *); +extern void ar5211ResetStaBeaconTimers(struct ath_hal *); +extern uint64_t ar5211GetNextTBTT(struct ath_hal *); + +extern HAL_BOOL ar5211IsInterruptPending(struct ath_hal *); +extern HAL_BOOL ar5211GetPendingInterrupts(struct ath_hal *, HAL_INT *); +extern HAL_INT ar5211GetInterrupts(struct ath_hal *); +extern HAL_INT ar5211SetInterrupts(struct ath_hal *, HAL_INT ints); + +extern const HAL_RATE_TABLE *ar5211GetRateTable(struct ath_hal *, u_int mode); + +extern HAL_BOOL ar5211AniControl(struct ath_hal *, HAL_ANI_CMD, int ); +extern void ar5211RxMonitor(struct ath_hal *, const HAL_NODE_STATS *, + const struct ieee80211_channel *); +extern void ar5211AniPoll(struct ath_hal *, const struct ieee80211_channel *); +extern void ar5211MibEvent(struct ath_hal *, const HAL_NODE_STATS *); +#endif /* _ATH_AR5211_H_ */ diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c new file mode 100644 index 000000000000..1b01f2a282b8 --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c @@ -0,0 +1,556 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211phy.h" + +#include "ah_eeprom_v3.h" + +static HAL_BOOL ar5211GetChannelEdges(struct ath_hal *ah, + uint16_t flags, uint16_t *low, uint16_t *high); +static HAL_BOOL ar5211GetChipPowerLimits(struct ath_hal *ah, + struct ieee80211_channel *chan); + +static void ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, + HAL_BOOL power_off); +static void ar5211DisablePCIE(struct ath_hal *ah); + +static const struct ath_hal_private ar5211hal = {{ + .ah_magic = AR5211_MAGIC, + + .ah_getRateTable = ar5211GetRateTable, + .ah_detach = ar5211Detach, + + /* Reset Functions */ + .ah_reset = ar5211Reset, + .ah_phyDisable = ar5211PhyDisable, + .ah_disable = ar5211Disable, + .ah_configPCIE = ar5211ConfigPCIE, + .ah_disablePCIE = ar5211DisablePCIE, + .ah_setPCUConfig = ar5211SetPCUConfig, + .ah_perCalibration = ar5211PerCalibration, + .ah_perCalibrationN = ar5211PerCalibrationN, + .ah_resetCalValid = ar5211ResetCalValid, + .ah_setTxPowerLimit = ar5211SetTxPowerLimit, + .ah_getChanNoise = ath_hal_getChanNoise, + + /* Transmit functions */ + .ah_updateTxTrigLevel = ar5211UpdateTxTrigLevel, + .ah_setupTxQueue = ar5211SetupTxQueue, + .ah_setTxQueueProps = ar5211SetTxQueueProps, + .ah_getTxQueueProps = ar5211GetTxQueueProps, + .ah_releaseTxQueue = ar5211ReleaseTxQueue, + .ah_resetTxQueue = ar5211ResetTxQueue, + .ah_getTxDP = ar5211GetTxDP, + .ah_setTxDP = ar5211SetTxDP, + .ah_numTxPending = ar5211NumTxPending, + .ah_startTxDma = ar5211StartTxDma, + .ah_stopTxDma = ar5211StopTxDma, + .ah_setupTxDesc = ar5211SetupTxDesc, + .ah_setupXTxDesc = ar5211SetupXTxDesc, + .ah_fillTxDesc = ar5211FillTxDesc, + .ah_procTxDesc = ar5211ProcTxDesc, + .ah_getTxIntrQueue = ar5211GetTxIntrQueue, + .ah_reqTxIntrDesc = ar5211IntrReqTxDesc, + .ah_getTxCompletionRates = ar5211GetTxCompletionRates, + .ah_setTxDescLink = ar5211SetTxDescLink, + .ah_getTxDescLink = ar5211GetTxDescLink, + .ah_getTxDescLinkPtr = ar5211GetTxDescLinkPtr, + + /* RX Functions */ + .ah_getRxDP = ar5211GetRxDP, + .ah_setRxDP = ar5211SetRxDP, + .ah_enableReceive = ar5211EnableReceive, + .ah_stopDmaReceive = ar5211StopDmaReceive, + .ah_startPcuReceive = ar5211StartPcuReceive, + .ah_stopPcuReceive = ar5211StopPcuReceive, + .ah_setMulticastFilter = ar5211SetMulticastFilter, + .ah_setMulticastFilterIndex = ar5211SetMulticastFilterIndex, + .ah_clrMulticastFilterIndex = ar5211ClrMulticastFilterIndex, + .ah_getRxFilter = ar5211GetRxFilter, + .ah_setRxFilter = ar5211SetRxFilter, + .ah_setupRxDesc = ar5211SetupRxDesc, + .ah_procRxDesc = ar5211ProcRxDesc, + .ah_rxMonitor = ar5211RxMonitor, + .ah_aniPoll = ar5211AniPoll, + .ah_procMibEvent = ar5211MibEvent, + + /* Misc Functions */ + .ah_getCapability = ar5211GetCapability, + .ah_setCapability = ar5211SetCapability, + .ah_getDiagState = ar5211GetDiagState, + .ah_getMacAddress = ar5211GetMacAddress, + .ah_setMacAddress = ar5211SetMacAddress, + .ah_getBssIdMask = ar5211GetBssIdMask, + .ah_setBssIdMask = ar5211SetBssIdMask, + .ah_setRegulatoryDomain = ar5211SetRegulatoryDomain, + .ah_setLedState = ar5211SetLedState, + .ah_writeAssocid = ar5211WriteAssocid, + .ah_gpioCfgInput = ar5211GpioCfgInput, + .ah_gpioCfgOutput = ar5211GpioCfgOutput, + .ah_gpioGet = ar5211GpioGet, + .ah_gpioSet = ar5211GpioSet, + .ah_gpioSetIntr = ar5211GpioSetIntr, + .ah_getTsf32 = ar5211GetTsf32, + .ah_getTsf64 = ar5211GetTsf64, + .ah_resetTsf = ar5211ResetTsf, + .ah_detectCardPresent = ar5211DetectCardPresent, + .ah_updateMibCounters = ar5211UpdateMibCounters, + .ah_getRfGain = ar5211GetRfgain, + .ah_getDefAntenna = ar5211GetDefAntenna, + .ah_setDefAntenna = ar5211SetDefAntenna, + .ah_getAntennaSwitch = ar5211GetAntennaSwitch, + .ah_setAntennaSwitch = ar5211SetAntennaSwitch, + .ah_setSifsTime = ar5211SetSifsTime, + .ah_getSifsTime = ar5211GetSifsTime, + .ah_setSlotTime = ar5211SetSlotTime, + .ah_getSlotTime = ar5211GetSlotTime, + .ah_setAckTimeout = ar5211SetAckTimeout, + .ah_getAckTimeout = ar5211GetAckTimeout, + .ah_setAckCTSRate = ar5211SetAckCTSRate, + .ah_getAckCTSRate = ar5211GetAckCTSRate, + .ah_setCTSTimeout = ar5211SetCTSTimeout, + .ah_getCTSTimeout = ar5211GetCTSTimeout, + .ah_setDecompMask = ar5211SetDecompMask, + .ah_setCoverageClass = ar5211SetCoverageClass, + .ah_setQuiet = ar5211SetQuiet, + .ah_get11nExtBusy = ar5211Get11nExtBusy, + .ah_getMibCycleCounts = ar5211GetMibCycleCounts, + .ah_setChainMasks = ar5211SetChainMasks, + .ah_enableDfs = ar5211EnableDfs, + .ah_getDfsThresh = ar5211GetDfsThresh, + /* XXX procRadarEvent */ + /* XXX isFastClockEnabled */ + .ah_setNav = ar5211SetNav, + .ah_getNav = ar5211GetNav, + + /* Key Cache Functions */ + .ah_getKeyCacheSize = ar5211GetKeyCacheSize, + .ah_resetKeyCacheEntry = ar5211ResetKeyCacheEntry, + .ah_isKeyCacheEntryValid = ar5211IsKeyCacheEntryValid, + .ah_setKeyCacheEntry = ar5211SetKeyCacheEntry, + .ah_setKeyCacheEntryMac = ar5211SetKeyCacheEntryMac, + + /* Power Management Functions */ + .ah_setPowerMode = ar5211SetPowerMode, + .ah_getPowerMode = ar5211GetPowerMode, + + /* Beacon Functions */ + .ah_setBeaconTimers = ar5211SetBeaconTimers, + .ah_beaconInit = ar5211BeaconInit, + .ah_setStationBeaconTimers = ar5211SetStaBeaconTimers, + .ah_resetStationBeaconTimers = ar5211ResetStaBeaconTimers, + .ah_getNextTBTT = ar5211GetNextTBTT, + + /* Interrupt Functions */ + .ah_isInterruptPending = ar5211IsInterruptPending, + .ah_getPendingInterrupts = ar5211GetPendingInterrupts, + .ah_getInterrupts = ar5211GetInterrupts, + .ah_setInterrupts = ar5211SetInterrupts }, + + .ah_getChannelEdges = ar5211GetChannelEdges, + .ah_getWirelessModes = ar5211GetWirelessModes, + .ah_eepromRead = ar5211EepromRead, +#ifdef AH_SUPPORT_WRITE_EEPROM + .ah_eepromWrite = ar5211EepromWrite, +#endif + .ah_getChipPowerLimits = ar5211GetChipPowerLimits, +}; + +static HAL_BOOL ar5211ChipTest(struct ath_hal *); +static HAL_BOOL ar5211FillCapabilityInfo(struct ath_hal *ah); + +/* + * Return the revsion id for the radio chip. This + * fetched via the PHY. + */ +static uint32_t +ar5211GetRadioRev(struct ath_hal *ah) +{ + uint32_t val; + int i; + + OS_REG_WRITE(ah, (AR_PHY_BASE + (0x34 << 2)), 0x00001c16); + for (i = 0; i < 8; i++) + OS_REG_WRITE(ah, (AR_PHY_BASE + (0x20 << 2)), 0x00010000); + val = (OS_REG_READ(ah, AR_PHY_BASE + (256 << 2)) >> 24) & 0xff; + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); + return ath_hal_reverseBits(val, 8); +} + +/* + * Attach for an AR5211 part. + */ +static struct ath_hal * +ar5211Attach(uint16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + struct ath_hal_5211 *ahp; + struct ath_hal *ah; + uint32_t val; + uint16_t eeval; + HAL_STATUS ecode; + + HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + __func__, sc, (void*) st, (void*) sh); + + /* NB: memory is returned zero'd */ + ahp = ath_hal_malloc(sizeof (struct ath_hal_5211)); + if (ahp == AH_NULL) { + HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + "%s: cannot allocate memory for state block\n", __func__); + ecode = HAL_ENOMEM; + goto bad; + } + ah = &ahp->ah_priv.h; + /* set initial values */ + OS_MEMCPY(&ahp->ah_priv, &ar5211hal, sizeof(struct ath_hal_private)); + ah->ah_sc = sc; + ah->ah_st = st; + ah->ah_sh = sh; + + ah->ah_devid = devid; /* NB: for AH_DEBUG_ALQ */ + AH_PRIVATE(ah)->ah_devid = devid; + AH_PRIVATE(ah)->ah_subvendorid = 0; /* XXX */ + + AH_PRIVATE(ah)->ah_powerLimit = MAX_RATE_POWER; + AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */ + + ahp->ah_diversityControl = HAL_ANT_VARIABLE; + ahp->ah_staId1Defaults = 0; + ahp->ah_rssiThr = INIT_RSSI_THR; + ahp->ah_sifstime = (u_int) -1; + ahp->ah_slottime = (u_int) -1; + ahp->ah_acktimeout = (u_int) -1; + ahp->ah_ctstimeout = (u_int) -1; + + if (!ar5211ChipReset(ah, AH_NULL)) { /* reset chip */ + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + ecode = HAL_EIO; + goto bad; + } + if (AH_PRIVATE(ah)->ah_devid == AR5211_FPGA11B) { + /* set it back to OFDM mode to be able to read analog rev id */ + OS_REG_WRITE(ah, AR5211_PHY_MODE, AR5211_PHY_MODE_OFDM); + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_44); + OS_DELAY(1000); + } + + /* Read Revisions from Chips */ + val = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID_M; + AH_PRIVATE(ah)->ah_macVersion = val >> AR_SREV_ID_S; + AH_PRIVATE(ah)->ah_macRev = val & AR_SREV_REVISION_M; + + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_MAUI_2 || + AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_OAHU) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: Mac Chip Rev 0x%x is not supported by this driver\n", + __func__, AH_PRIVATE(ah)->ah_macVersion); + ecode = HAL_ENOTSUPP; + goto bad; + } + + AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); + + if (!ar5211ChipTest(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", + __func__); + ecode = HAL_ESELFTEST; + goto bad; + } + + /* Set correct Baseband to analog shift setting to access analog chips. */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007); + } else { + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000047); + } + OS_DELAY(2000); + + /* Read Radio Chip Rev Extract */ + AH_PRIVATE(ah)->ah_analog5GhzRev = ar5211GetRadioRev(ah); + if ((AH_PRIVATE(ah)->ah_analog5GhzRev & 0xf0) != RAD5_SREV_MAJOR) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: 5G Radio Chip Rev 0x%02X is not supported by this " + "driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); + ecode = HAL_ENOTSUPP; + goto bad; + } + + val = (OS_REG_READ(ah, AR_PCICFG) & AR_PCICFG_EEPROM_SIZE_M) >> + AR_PCICFG_EEPROM_SIZE_S; + if (val != AR_PCICFG_EEPROM_SIZE_16K) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unsupported EEPROM size " + "%u (0x%x) found\n", __func__, val, val); + ecode = HAL_EESIZE; + goto bad; + } + ecode = ath_hal_legacyEepromAttach(ah); + if (ecode != HAL_OK) { + goto bad; + } + + /* If Bmode and AR5211, verify 2.4 analog exists */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU && + ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) { + /* Set correct Baseband to analog shift setting to access analog chips. */ + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00004007); + OS_DELAY(2000); + AH_PRIVATE(ah)->ah_analog2GhzRev = ar5211GetRadioRev(ah); + + /* Set baseband for 5GHz chip */ + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007); + OS_DELAY(2000); + if ((AH_PRIVATE(ah)->ah_analog2GhzRev & 0xF0) != RAD2_SREV_MAJOR) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: 2G Radio Chip Rev 0x%x is not supported by " + "this driver\n", __func__, + AH_PRIVATE(ah)->ah_analog2GhzRev); + ecode = HAL_ENOTSUPP; + goto bad; + } + } else { + ath_hal_eepromSet(ah, AR_EEP_BMODE, AH_FALSE); + } + + ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval); + if (ecode != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: cannot read regulatory domain from EEPROM\n", + __func__); + goto bad; + } + AH_PRIVATE(ah)->ah_currentRD = eeval; + AH_PRIVATE(ah)->ah_getNfAdjust = ar5211GetNfAdjust; + + /* + * Got everything we need now to setup the capabilities. + */ + (void) ar5211FillCapabilityInfo(ah); + + /* Initialize gain ladder thermal calibration structure */ + ar5211InitializeGainValues(ah); + + ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); + if (ecode != HAL_OK) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error getting mac address from EEPROM\n", __func__); + goto bad; + } + + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); + + return ah; +bad: + if (ahp) + ar5211Detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + return AH_NULL; +#undef N +} + +void +ar5211Detach(struct ath_hal *ah) +{ + HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__); + + HALASSERT(ah != AH_NULL); + HALASSERT(ah->ah_magic == AR5211_MAGIC); + + ath_hal_eepromDetach(ah); + ath_hal_free(ah); +} + +static HAL_BOOL +ar5211ChipTest(struct ath_hal *ah) +{ + uint32_t regAddr[2] = { AR_STA_ID0, AR_PHY_BASE+(8 << 2) }; + uint32_t regHold[2]; + uint32_t patternData[4] = + { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 }; + int i, j; + + /* Test PHY & MAC registers */ + for (i = 0; i < 2; i++) { + uint32_t addr = regAddr[i]; + uint32_t wrData, rdData; + + regHold[i] = OS_REG_READ(ah, addr); + for (j = 0; j < 0x100; j++) { + wrData = (j << 16) | j; + OS_REG_WRITE(ah, addr, wrData); + rdData = OS_REG_READ(ah, addr); + if (rdData != wrData) { + HALDEBUG(ah, HAL_DEBUG_ANY, +"%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + __func__, addr, wrData, rdData); + return AH_FALSE; + } + } + for (j = 0; j < 4; j++) { + wrData = patternData[j]; + OS_REG_WRITE(ah, addr, wrData); + rdData = OS_REG_READ(ah, addr); + if (wrData != rdData) { + HALDEBUG(ah, HAL_DEBUG_ANY, +"%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + __func__, addr, wrData, rdData); + return AH_FALSE; + } + } + OS_REG_WRITE(ah, regAddr[i], regHold[i]); + } + OS_DELAY(100); + return AH_TRUE; +} + +/* + * Store the channel edges for the requested operational mode + */ +static HAL_BOOL +ar5211GetChannelEdges(struct ath_hal *ah, + uint16_t flags, uint16_t *low, uint16_t *high) +{ + if (flags & IEEE80211_CHAN_5GHZ) { + *low = 4920; + *high = 6100; + return AH_TRUE; + } + if (flags & IEEE80211_CHAN_2GHZ && + ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) { + *low = 2312; + *high = 2732; + return AH_TRUE; + } + return AH_FALSE; +} + +static HAL_BOOL +ar5211GetChipPowerLimits(struct ath_hal *ah, struct ieee80211_channel *chan) +{ + /* XXX fill in, this is just a placeholder */ + HALDEBUG(ah, HAL_DEBUG_ATTACH, + "%s: no min/max power for %u/0x%x\n", + __func__, chan->ic_freq, chan->ic_flags); + chan->ic_maxpower = MAX_RATE_POWER; + chan->ic_minpower = 0; + return AH_TRUE; +} + +static void +ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off) +{ +} + +static void +ar5211DisablePCIE(struct ath_hal *ah) +{ +} + +/* + * Fill all software cached or static hardware state information. + */ +static HAL_BOOL +ar5211FillCapabilityInfo(struct ath_hal *ah) +{ + struct ath_hal_private *ahpriv = AH_PRIVATE(ah); + HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; + + /* Construct wireless mode from EEPROM */ + pCap->halWirelessModes = 0; + if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { + pCap->halWirelessModes |= HAL_MODE_11A; + if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) + pCap->halWirelessModes |= HAL_MODE_TURBO; + } + if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) + pCap->halWirelessModes |= HAL_MODE_11B; + + pCap->halLow2GhzChan = 2312; + pCap->halHigh2GhzChan = 2732; + pCap->halLow5GhzChan = 4920; + pCap->halHigh5GhzChan = 6100; + + pCap->halChanSpreadSupport = AH_TRUE; + pCap->halSleepAfterBeaconBroken = AH_TRUE; + pCap->halPSPollBroken = AH_TRUE; + pCap->halVEOLSupport = AH_TRUE; + pCap->halNumMRRetries = 1; /* No hardware MRR support */ + pCap->halNumTxMaps = 1; /* Single TX ptr per descr */ + + pCap->halTotalQueues = HAL_NUM_TX_QUEUES; + pCap->halKeyCacheSize = 128; + + /* XXX not needed */ + pCap->halChanHalfRate = AH_FALSE; + pCap->halChanQuarterRate = AH_FALSE; + + /* + * RSSI uses the combined field; some 11n NICs may use + * the control chain RSSI. + */ + pCap->halUseCombinedRadarRssi = AH_TRUE; + + if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) && + ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) { + /* NB: enabled by default */ + ahpriv->ah_rfkillEnabled = AH_TRUE; + pCap->halRfSilentSupport = AH_TRUE; + } + + pCap->halRxTstampPrecision = 13; + pCap->halTxTstampPrecision = 16; + pCap->halIntrMask = HAL_INT_COMMON + | HAL_INT_RX + | HAL_INT_TX + | HAL_INT_FATAL + | HAL_INT_BNR + | HAL_INT_TIM + ; + + pCap->hal4kbSplitTransSupport = AH_TRUE; + pCap->halHasRxSelfLinkedTail = AH_TRUE; + + /* XXX might be ok w/ some chip revs */ + ahpriv->ah_rxornIsFatal = AH_TRUE; + return AH_TRUE; +} + +static const char* +ar5211Probe(uint16_t vendorid, uint16_t devid) +{ + if (vendorid == ATHEROS_VENDOR_ID) { + if (devid == AR5211_DEVID || devid == AR5311_DEVID || + devid == AR5211_DEFAULT) + return "Atheros 5211"; + if (devid == AR5211_FPGA11B) + return "Atheros 5211 (FPGA)"; + } + return AH_NULL; +} +AH_CHIP(AR5211, ar5211Probe, ar5211Attach); diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c new file mode 100644 index 000000000000..06790b58f772 --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c @@ -0,0 +1,184 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211desc.h" + +/* + * Routines used to initialize and generated beacons for the AR5211/AR5311. + */ + +/* + * Return the hardware NextTBTT in TSF + */ +uint64_t +ar5211GetNextTBTT(struct ath_hal *ah) +{ +#define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10) + return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0)); +#undef TU_TO_TSF +} + +/* + * Initialize all of the hardware registers used to send beacons. + */ +void +ar5211SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) +{ + + OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt); + OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba); + OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba); + OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim); + /* + * Set the Beacon register after setting all timers. + */ + OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval); +} + +/* + * Legacy api to initialize all of the beacon registers. + */ +void +ar5211BeaconInit(struct ath_hal *ah, + uint32_t next_beacon, uint32_t beacon_period) +{ + HAL_BEACON_TIMERS bt; + + bt.bt_nexttbtt = next_beacon; + /* + * TIMER1: in AP/adhoc mode this controls the DMA beacon + * alert timer; otherwise it controls the next wakeup time. + * TIMER2: in AP mode, it controls the SBA beacon alert + * interrupt; otherwise it sets the start of the next CFP. + */ + switch (AH_PRIVATE(ah)->ah_opmode) { + case HAL_M_STA: + case HAL_M_MONITOR: + bt.bt_nextdba = 0xffff; + bt.bt_nextswba = 0x7ffff; + break; + case HAL_M_IBSS: + case HAL_M_HOSTAP: + bt.bt_nextdba = (next_beacon - + ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */ + bt.bt_nextswba = (next_beacon - + ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */ + break; + } + /* + * Set the ATIM window + * Our hardware does not support an ATIM window of 0 + * (beacons will not work). If the ATIM windows is 0, + * force it to 1. + */ + bt.bt_nextatim = next_beacon + 1; + bt.bt_intval = beacon_period & + (AR_BEACON_PERIOD | AR_BEACON_RESET_TSF | AR_BEACON_EN); + ar5211SetBeaconTimers(ah, &bt); +} + +void +ar5211ResetStaBeaconTimers(struct ath_hal *ah) +{ + uint32_t val; + + OS_REG_WRITE(ah, AR_TIMER0, 0); /* no beacons */ + val = OS_REG_READ(ah, AR_STA_ID1); + val |= AR_STA_ID1_PWR_SAV; /* XXX */ + /* tell the h/w that the associated AP is not PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + val & ~(AR_STA_ID1_DEFAULT_ANTENNA | AR_STA_ID1_PCF)); + OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_PERIOD); +} + +/* + * Set all the beacon related bits on the h/w for stations + * i.e. initializes the corresponding h/w timers; + * also tells the h/w whether to anticipate PCF beacons + */ +void +ar5211SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: setting beacon timers\n", __func__); + + HALASSERT(bs->bs_intval != 0); + /* if the AP will do PCF */ + if (bs->bs_cfpmaxduration != 0) { + /* tell the h/w that the associated AP is PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PCF); + + /* set CFP_PERIOD(1.024ms) register */ + OS_REG_WRITE(ah, AR_CFP_PERIOD, bs->bs_cfpperiod); + + /* set CFP_DUR(1.024ms) register to max cfp duration */ + OS_REG_WRITE(ah, AR_CFP_DUR, bs->bs_cfpmaxduration); + + /* set TIMER2(128us) to anticipated time of next CFP */ + OS_REG_WRITE(ah, AR_TIMER2, bs->bs_cfpnext << 3); + } else { + /* tell the h/w that the associated AP is not PCF capable */ + OS_REG_WRITE(ah, AR_STA_ID1, + OS_REG_READ(ah, AR_STA_ID1) &~ AR_STA_ID1_PCF); + } + + /* + * Set TIMER0(1.024ms) to the anticipated time of the next beacon. + */ + OS_REG_WRITE(ah, AR_TIMER0, bs->bs_nexttbtt); + + /* + * Start the beacon timers by setting the BEACON register + * to the beacon interval; also write the tim offset which + * we should know by now. The code, in ar5211WriteAssocid, + * also sets the tim offset once the AID is known which can + * be left as such for now. + */ + OS_REG_WRITE(ah, AR_BEACON, + (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_PERIOD|AR_BEACON_TIM)) + | SM(bs->bs_intval, AR_BEACON_PERIOD) + | SM(bs->bs_timoffset ? bs->bs_timoffset + 4 : 0, AR_BEACON_TIM) + ); + + /* + * Configure the BMISS interrupt. Note that we + * assume the caller blocks interrupts while enabling + * the threshold. + */ + HALASSERT(bs->bs_bmissthreshold <= MS(0xffffffff, AR_RSSI_THR_BM_THR)); + ahp->ah_rssiThr = (ahp->ah_rssiThr &~ AR_RSSI_THR_BM_THR) + | SM(bs->bs_bmissthreshold, AR_RSSI_THR_BM_THR); + OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); + + /* + * Set the sleep duration in 1/8 TU's. + */ +#define SLEEP_SLOP 3 + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLDUR, + (bs->bs_sleepduration - SLEEP_SLOP) << 3); +#undef SLEEP_SLOP +} diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c b/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c new file mode 100644 index 000000000000..8a4086b01d7e --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c @@ -0,0 +1,160 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" + +/* + * Checks to see if an interrupt is pending on our NIC + * + * Returns: TRUE if an interrupt is pending + * FALSE if not + */ +HAL_BOOL +ar5211IsInterruptPending(struct ath_hal *ah) +{ + return OS_REG_READ(ah, AR_INTPEND) != 0; +} + +/* + * Reads the Interrupt Status Register value from the NIC, thus deasserting + * the interrupt line, and returns both the masked and unmasked mapped ISR + * values. The value returned is mapped to abstract the hw-specific bit + * locations in the Interrupt Status Register. + * + * Returns: A hardware-abstracted bitmap of all non-masked-out + * interrupts pending, as well as an unmasked value + */ +HAL_BOOL +ar5211GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked) +{ + uint32_t isr; + + isr = OS_REG_READ(ah, AR_ISR_RAC); + if (isr == 0xffffffff) { + *masked = 0; + return AH_FALSE; + } + + *masked = isr & HAL_INT_COMMON; + + if (isr & AR_ISR_HIUERR) + *masked |= HAL_INT_FATAL; + if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) + *masked |= HAL_INT_RX; + if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL)) + *masked |= HAL_INT_TX; + /* + * Receive overrun is usually non-fatal on Oahu/Spirit. + * BUT on some parts rx could fail and the chip must be reset. + * So we force a hardware reset in all cases. + */ + if ((isr & AR_ISR_RXORN) && AH_PRIVATE(ah)->ah_rxornIsFatal) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: receive FIFO overrun interrupt\n", __func__); + *masked |= HAL_INT_FATAL; + } + + /* + * On fatal errors collect ISR state for debugging. + */ + if (*masked & HAL_INT_FATAL) { + AH_PRIVATE(ah)->ah_fatalState[0] = isr; + AH_PRIVATE(ah)->ah_fatalState[1] = OS_REG_READ(ah, AR_ISR_S0_S); + AH_PRIVATE(ah)->ah_fatalState[2] = OS_REG_READ(ah, AR_ISR_S1_S); + AH_PRIVATE(ah)->ah_fatalState[3] = OS_REG_READ(ah, AR_ISR_S2_S); + AH_PRIVATE(ah)->ah_fatalState[4] = OS_REG_READ(ah, AR_ISR_S3_S); + AH_PRIVATE(ah)->ah_fatalState[5] = OS_REG_READ(ah, AR_ISR_S4_S); + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: fatal error, ISR_RAC=0x%x ISR_S2_S=0x%x\n", + __func__, isr, AH_PRIVATE(ah)->ah_fatalState[3]); + } + return AH_TRUE; +} + +HAL_INT +ar5211GetInterrupts(struct ath_hal *ah) +{ + return AH5211(ah)->ah_maskReg; +} + +/* + * Atomically enables NIC interrupts. Interrupts are passed in + * via the enumerated bitmask in ints. + */ +HAL_INT +ar5211SetInterrupts(struct ath_hal *ah, HAL_INT ints) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + uint32_t omask = ahp->ah_maskReg; + uint32_t mask; + + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: 0x%x => 0x%x\n", + __func__, omask, ints); + + /* + * Disable interrupts here before reading & modifying + * the mask so that the ISR does not modify the mask + * out from under us. + */ + if (omask & HAL_INT_GLOBAL) { + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: disable IER\n", __func__); + OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); + /* XXX??? */ + (void) OS_REG_READ(ah, AR_IER); /* flush write to HW */ + } + + mask = ints & HAL_INT_COMMON; + if (ints & HAL_INT_TX) { + if (ahp->ah_txOkInterruptMask) + mask |= AR_IMR_TXOK; + if (ahp->ah_txErrInterruptMask) + mask |= AR_IMR_TXERR; + if (ahp->ah_txDescInterruptMask) + mask |= AR_IMR_TXDESC; + if (ahp->ah_txEolInterruptMask) + mask |= AR_IMR_TXEOL; + } + if (ints & HAL_INT_RX) + mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC; + if (ints & HAL_INT_FATAL) { + /* + * NB: ar5212Reset sets MCABT+SSERR+DPERR in AR_IMR_S2 + * so enabling HIUERR enables delivery. + */ + mask |= AR_IMR_HIUERR; + } + + /* Write the new IMR and store off our SW copy. */ + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); + OS_REG_WRITE(ah, AR_IMR, mask); + ahp->ah_maskReg = ints; + + /* Re-enable interrupts as appropriate. */ + if (ints & HAL_INT_GLOBAL) { + HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: enable IER\n", __func__); + OS_REG_WRITE(ah, AR_IER, AR_IER_ENABLE); + } + + return omask; +} diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c b/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c new file mode 100644 index 000000000000..19fb8770ef77 --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c @@ -0,0 +1,177 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" + +/* + * Chips-specific key cache routines. + */ + +#define AR_KEYTABLE_SIZE 128 +#define KEY_XOR 0xaa + +/* + * Return the size of the hardware key cache. + */ +uint32_t +ar5211GetKeyCacheSize(struct ath_hal *ah) +{ + return AR_KEYTABLE_SIZE; +} + +/* + * Return true if the specific key cache entry is valid. + */ +HAL_BOOL +ar5211IsKeyCacheEntryValid(struct ath_hal *ah, uint16_t entry) +{ + if (entry < AR_KEYTABLE_SIZE) { + uint32_t val = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry)); + if (val & AR_KEYTABLE_VALID) + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Clear the specified key cache entry + */ +HAL_BOOL +ar5211ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry) +{ + if (entry < AR_KEYTABLE_SIZE) { + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Sets the mac part of the specified key cache entry and mark it valid. + */ +HAL_BOOL +ar5211SetKeyCacheEntryMac(struct ath_hal *ah, uint16_t entry, const uint8_t *mac) +{ + uint32_t macHi, macLo; + + if (entry >= AR_KEYTABLE_SIZE) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n", + __func__, entry); + return AH_FALSE; + } + + /* + * Set MAC address -- shifted right by 1. MacLo is + * the 4 MSBs, and MacHi is the 2 LSBs. + */ + if (mac != AH_NULL) { + macHi = (mac[5] << 8) | mac[4]; + macLo = (mac[3] << 24)| (mac[2] << 16) + | (mac[1] << 8) | mac[0]; + macLo >>= 1; + macLo |= (macHi & 1) << 31; /* carry */ + macHi >>= 1; + } else { + macLo = macHi = 0; + } + + OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); + return AH_TRUE; +} + +/* + * Sets the contents of the specified key cache entry. + */ +HAL_BOOL +ar5211SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, + const HAL_KEYVAL *k, const uint8_t *mac, + int xorKey) +{ + uint32_t key0, key1, key2, key3, key4; + uint32_t keyType; + uint32_t xorMask= xorKey ? + (KEY_XOR << 24 | KEY_XOR << 16 | KEY_XOR << 8 | KEY_XOR) : 0; + + if (entry >= AR_KEYTABLE_SIZE) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n", + __func__, entry); + return AH_FALSE; + } + switch (k->kv_type) { + case HAL_CIPHER_AES_OCB: + keyType = AR_KEYTABLE_TYPE_AES; + break; + case HAL_CIPHER_WEP: + if (k->kv_len < 40 / NBBY) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: WEP key length %u too small\n", + __func__, k->kv_len); + return AH_FALSE; + } + if (k->kv_len <= 40 / NBBY) + keyType = AR_KEYTABLE_TYPE_40; + else if (k->kv_len <= 104 / NBBY) + keyType = AR_KEYTABLE_TYPE_104; + else + keyType = AR_KEYTABLE_TYPE_128; + break; + case HAL_CIPHER_CLR: + keyType = AR_KEYTABLE_TYPE_CLR; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cipher %u not supported\n", + __func__, k->kv_type); + return AH_FALSE; + } + + key0 = LE_READ_4(k->kv_val+0) ^ xorMask; + key1 = (LE_READ_2(k->kv_val+4) ^ xorMask) & 0xffff; + key2 = LE_READ_4(k->kv_val+6) ^ xorMask; + key3 = (LE_READ_2(k->kv_val+10) ^ xorMask) & 0xffff; + key4 = LE_READ_4(k->kv_val+12) ^ xorMask; + if (k->kv_len <= 104 / NBBY) + key4 &= 0xff; + + /* + * Note: WEP key cache hardware requires that each double-word + * pair be written in even/odd order (since the destination is + * a 64-bit register). Don't reorder these writes w/o + * understanding this! + */ + OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + return ar5211SetKeyCacheEntryMac(ah, entry, mac); +} diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c b/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c new file mode 100644 index 000000000000..4566d1b6f1cd --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c @@ -0,0 +1,756 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211phy.h" + +#include "ah_eeprom_v3.h" + +#define AR_NUM_GPIO 6 /* 6 GPIO bits */ +#define AR_GPIOD_MASK 0x2f /* 6-bit mask */ + +void +ar5211GetMacAddress(struct ath_hal *ah, uint8_t *mac) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); +} + +HAL_BOOL +ar5211SetMacAddress(struct ath_hal *ah, const uint8_t *mac) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); + return AH_TRUE; +} + +void +ar5211GetBssIdMask(struct ath_hal *ah, uint8_t *mask) +{ + static const uint8_t ones[IEEE80211_ADDR_LEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + OS_MEMCPY(mask, ones, IEEE80211_ADDR_LEN); +} + +HAL_BOOL +ar5211SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) +{ + return AH_FALSE; +} + +/* + * Read 16 bits of data from the specified EEPROM offset. + */ +HAL_BOOL +ar5211EepromRead(struct ath_hal *ah, u_int off, uint16_t *data) +{ + OS_REG_WRITE(ah, AR_EEPROM_ADDR, off); + OS_REG_WRITE(ah, AR_EEPROM_CMD, AR_EEPROM_CMD_READ); + + if (!ath_hal_wait(ah, AR_EEPROM_STS, + AR_EEPROM_STS_READ_COMPLETE | AR_EEPROM_STS_READ_ERROR, + AR_EEPROM_STS_READ_COMPLETE)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: read failed for entry 0x%x\n", __func__, off); + return AH_FALSE; + } + *data = OS_REG_READ(ah, AR_EEPROM_DATA) & 0xffff; + return AH_TRUE; +} + +#ifdef AH_SUPPORT_WRITE_EEPROM +/* + * Write 16 bits of data to the specified EEPROM offset. + */ +HAL_BOOL +ar5211EepromWrite(struct ath_hal *ah, u_int off, uint16_t data) +{ + return AH_FALSE; +} +#endif /* AH_SUPPORT_WRITE_EEPROM */ + +/* + * Attempt to change the cards operating regulatory domain to the given value + */ +HAL_BOOL +ar5211SetRegulatoryDomain(struct ath_hal *ah, + uint16_t regDomain, HAL_STATUS *status) +{ + HAL_STATUS ecode; + + if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { + ecode = HAL_EINVAL; + goto bad; + } + /* + * Check if EEPROM is configured to allow this; must + * be a proper version and the protection bits must + * permit re-writing that segment of the EEPROM. + */ + if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { + ecode = HAL_EEWRITE; + goto bad; + } +#ifdef AH_SUPPORT_WRITE_REGDOMAIN + if (ar5211EepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: set regulatory domain to %u (0x%x)\n", + __func__, regDomain, regDomain); + AH_PRIVATE(ah)->ah_currentRD = regDomain; + return AH_TRUE; + } +#endif + ecode = HAL_EIO; +bad: + if (status) + *status = ecode; + return AH_FALSE; +} + +/* + * Return the wireless modes (a,b,g,t) supported by hardware. + * + * This value is what is actually supported by the hardware + * and is unaffected by regulatory/country code settings. + * + */ +u_int +ar5211GetWirelessModes(struct ath_hal *ah) +{ + u_int mode = 0; + + if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { + mode = HAL_MODE_11A; + if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) + mode |= HAL_MODE_TURBO | HAL_MODE_108A; + } + if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) + mode |= HAL_MODE_11B; + return mode; +} + +#if 0 +HAL_BOOL +ar5211GetTurboDisable(struct ath_hal *ah) +{ + return (AH5211(ah)->ah_turboDisable != 0); +} +#endif + +/* + * Called if RfKill is supported (according to EEPROM). Set the interrupt and + * GPIO values so the ISR and can disable RF on a switch signal + */ +void +ar5211EnableRfKill(struct ath_hal *ah) +{ + uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; + int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); + int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); + + /* + * Configure the desired GPIO port for input + * and enable baseband rf silence. + */ + ar5211GpioCfgInput(ah, select); + OS_REG_SET_BIT(ah, AR_PHY_BASE, 0x00002000); + /* + * If radio disable switch connection to GPIO bit x is enabled + * program GPIO interrupt. + * If rfkill bit on eeprom is 1, setupeeprommap routine has already + * verified that it is a later version of eeprom, it has a place for + * rfkill bit and it is set to 1, indicating that GPIO bit x hardware + * connection is present. + */ + ar5211GpioSetIntr(ah, select, (ar5211GpioGet(ah, select) != polarity)); +} + +/* + * Configure GPIO Output lines + */ +HAL_BOOL +ar5211GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, AR_GPIOCR); + reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT)); + reg |= AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT); + + OS_REG_WRITE(ah, AR_GPIOCR, reg); + return AH_TRUE; +} + +/* + * Configure GPIO Input lines + */ +HAL_BOOL +ar5211GpioCfgInput(struct ath_hal *ah, uint32_t gpio) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, AR_GPIOCR); + reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT)); + reg |= AR_GPIOCR_0_CR_N << (gpio * AR_GPIOCR_CR_SHIFT); + + OS_REG_WRITE(ah, AR_GPIOCR, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - set output lines + */ +HAL_BOOL +ar5211GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) +{ + uint32_t reg; + + HALASSERT(gpio < AR_NUM_GPIO); + + reg = OS_REG_READ(ah, AR_GPIODO); + reg &= ~(1 << gpio); + reg |= (val&1) << gpio; + + OS_REG_WRITE(ah, AR_GPIODO, reg); + return AH_TRUE; +} + +/* + * Once configured for I/O - get input lines + */ +uint32_t +ar5211GpioGet(struct ath_hal *ah, uint32_t gpio) +{ + if (gpio < AR_NUM_GPIO) { + uint32_t val = OS_REG_READ(ah, AR_GPIODI); + val = ((val & AR_GPIOD_MASK) >> gpio) & 0x1; + return val; + } else { + return 0xffffffff; + } +} + +/* + * Set the GPIO 0 Interrupt (gpio is ignored) + */ +void +ar5211GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) +{ + uint32_t val = OS_REG_READ(ah, AR_GPIOCR); + + /* Clear the bits that we will modify. */ + val &= ~(AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_SELH | AR_GPIOCR_INT_ENA | + AR_GPIOCR_0_CR_A); + + val |= AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_ENA; + if (ilevel) + val |= AR_GPIOCR_INT_SELH; + + /* Don't need to change anything for low level interrupt. */ + OS_REG_WRITE(ah, AR_GPIOCR, val); + + /* Change the interrupt mask. */ + ar5211SetInterrupts(ah, AH5211(ah)->ah_maskReg | HAL_INT_GPIO); +} + +/* + * Change the LED blinking pattern to correspond to the connectivity + */ +void +ar5211SetLedState(struct ath_hal *ah, HAL_LED_STATE state) +{ + static const uint32_t ledbits[8] = { + AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_INIT */ + AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_SCAN */ + AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_AUTH */ + AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_ASSOC*/ + AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_RUN */ + AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND, + AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND, + AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND, + }; + OS_REG_WRITE(ah, AR_PCICFG, + (OS_REG_READ(ah, AR_PCICFG) &~ + (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE)) + | ledbits[state & 0x7] + ); +} + +/* + * Change association related fields programmed into the hardware. + * Writing a valid BSSID to the hardware effectively enables the hardware + * to synchronize its TSF to the correct beacons and receive frames coming + * from that BSSID. It is called by the SME JOIN operation. + */ +void +ar5211WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + /* XXX save bssid for possible re-use on reset */ + OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); + OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); + OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | + ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); +} + +/* + * Get the current hardware tsf for stamlme. + */ +uint64_t +ar5211GetTsf64(struct ath_hal *ah) +{ + uint32_t low1, low2, u32; + + /* sync multi-word read */ + low1 = OS_REG_READ(ah, AR_TSF_L32); + u32 = OS_REG_READ(ah, AR_TSF_U32); + low2 = OS_REG_READ(ah, AR_TSF_L32); + if (low2 < low1) { /* roll over */ + /* + * If we are not preempted this will work. If we are + * then we re-reading AR_TSF_U32 does no good as the + * low bits will be meaningless. Likewise reading + * L32, U32, U32, then comparing the last two reads + * to check for rollover doesn't help if preempted--so + * we take this approach as it costs one less PCI + * read which can be noticeable when doing things + * like timestamping packets in monitor mode. + */ + u32++; + } + return (((uint64_t) u32) << 32) | ((uint64_t) low2); +} + +/* + * Get the current hardware tsf for stamlme. + */ +uint32_t +ar5211GetTsf32(struct ath_hal *ah) +{ + return OS_REG_READ(ah, AR_TSF_L32); +} + +/* + * Reset the current hardware tsf for stamlme + */ +void +ar5211ResetTsf(struct ath_hal *ah) +{ + uint32_t val = OS_REG_READ(ah, AR_BEACON); + + OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); +} + +/* + * Grab a semi-random value from hardware registers - may not + * change often + */ +uint32_t +ar5211GetRandomSeed(struct ath_hal *ah) +{ + uint32_t nf; + + nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + return (OS_REG_READ(ah, AR_TSF_U32) ^ + OS_REG_READ(ah, AR_TSF_L32) ^ nf); +} + +/* + * Detect if our card is present + */ +HAL_BOOL +ar5211DetectCardPresent(struct ath_hal *ah) +{ + uint16_t macVersion, macRev; + uint32_t v; + + /* + * Read the Silicon Revision register and compare that + * to what we read at attach time. If the same, we say + * a card/device is present. + */ + v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID_M; + macVersion = v >> AR_SREV_ID_S; + macRev = v & AR_SREV_REVISION_M; + return (AH_PRIVATE(ah)->ah_macVersion == macVersion && + AH_PRIVATE(ah)->ah_macRev == macRev); +} + +/* + * Update MIB Counters + */ +void +ar5211UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS *stats) +{ + stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); + stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); + stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); + stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); + stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); +} + +HAL_BOOL +ar5211SetSifsTime(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (us > ath_hal_mac_usec(ah, 0xffff)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", + __func__, us); + ahp->ah_sifstime = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us)); + ahp->ah_slottime = us; + return AH_TRUE; + } +} + +u_int +ar5211GetSifsTime(struct ath_hal *ah) +{ + u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5211SetSlotTime(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (us < HAL_SLOT_TIME_9 || us > ath_hal_mac_usec(ah, 0xffff)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", + __func__, us); + ahp->ah_slottime = us; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); + ahp->ah_slottime = us; + return AH_TRUE; + } +} + +u_int +ar5211GetSlotTime(struct ath_hal *ah) +{ + u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5211SetAckTimeout(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", + __func__, us); + ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); + ahp->ah_acktimeout = us; + return AH_TRUE; + } +} + +u_int +ar5211GetAckTimeout(struct ath_hal *ah) +{ + u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +u_int +ar5211GetAckCTSRate(struct ath_hal *ah) +{ + return ((AH5211(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); +} + +HAL_BOOL +ar5211SetAckCTSRate(struct ath_hal *ah, u_int high) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (high) { + OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); + ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; + } else { + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); + ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; + } + return AH_TRUE; +} + +HAL_BOOL +ar5211SetCTSTimeout(struct ath_hal *ah, u_int us) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", + __func__, us); + ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ + return AH_FALSE; + } else { + /* convert to system clocks */ + OS_REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); + ahp->ah_ctstimeout = us; + return AH_TRUE; + } +} + +u_int +ar5211GetCTSTimeout(struct ath_hal *ah) +{ + u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} + +HAL_BOOL +ar5211SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) +{ + /* nothing to do */ + return AH_TRUE; +} + +void +ar5211SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) +{ +} + +HAL_STATUS +ar5211SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration, + uint32_t next_start, HAL_QUIET_FLAG flags) +{ + return HAL_OK; +} + +/* + * Control Adaptive Noise Immunity Parameters + */ +HAL_BOOL +ar5211AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) +{ + return AH_FALSE; +} + +void +ar5211AniPoll(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ +} + +void +ar5211RxMonitor(struct ath_hal *ah, const HAL_NODE_STATS *stats, + const struct ieee80211_channel *chan) +{ +} + +void +ar5211MibEvent(struct ath_hal *ah, const HAL_NODE_STATS *stats) +{ +} + +/* + * Get the rssi of frame curently being received. + */ +uint32_t +ar5211GetCurRssi(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); +} + +u_int +ar5211GetDefAntenna(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); +} + +void +ar5211SetDefAntenna(struct ath_hal *ah, u_int antenna) +{ + OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); +} + +HAL_ANT_SETTING +ar5211GetAntennaSwitch(struct ath_hal *ah) +{ + return AH5211(ah)->ah_diversityControl; +} + +HAL_BOOL +ar5211SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) +{ + const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; + + if (chan == AH_NULL) { + AH5211(ah)->ah_diversityControl = settings; + return AH_TRUE; + } + return ar5211SetAntennaSwitchInternal(ah, settings, chan); +} + +HAL_STATUS +ar5211GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t *result) +{ + + switch (type) { + case HAL_CAP_CIPHER: /* cipher handled in hardware */ + switch (capability) { + case HAL_CIPHER_AES_OCB: + case HAL_CIPHER_WEP: + case HAL_CIPHER_CLR: + return HAL_OK; + default: + return HAL_ENOTSUPP; + } + default: + return ath_hal_getcapability(ah, type, capability, result); + } +} + +HAL_BOOL +ar5211SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, + uint32_t capability, uint32_t setting, HAL_STATUS *status) +{ + switch (type) { + case HAL_CAP_DIAG: /* hardware diagnostic support */ + /* + * NB: could split this up into virtual capabilities, + * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly + * seems worth the additional complexity. + */ +#ifdef AH_DEBUG + AH_PRIVATE(ah)->ah_diagreg = setting; +#else + AH_PRIVATE(ah)->ah_diagreg = setting & 0x6; /* ACK+CTS */ +#endif + OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); + return AH_TRUE; + default: + return ath_hal_setcapability(ah, type, capability, + setting, status); + } +} + +HAL_BOOL +ar5211GetDiagState(struct ath_hal *ah, int request, + const void *args, uint32_t argsize, + void **result, uint32_t *resultsize) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + (void) ahp; + if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) + return AH_TRUE; + switch (request) { + case HAL_DIAG_EEPROM: + return ath_hal_eepromDiag(ah, request, + args, argsize, result, resultsize); + case HAL_DIAG_RFGAIN: + *result = &ahp->ah_gainValues; + *resultsize = sizeof(GAIN_VALUES); + return AH_TRUE; + case HAL_DIAG_RFGAIN_CURSTEP: + *result = __DECONST(void *, ahp->ah_gainValues.currStep); + *resultsize = (*result == AH_NULL) ? + 0 : sizeof(GAIN_OPTIMIZATION_STEP); + return AH_TRUE; + } + return AH_FALSE; +} + +/* + * Return what percentage of the extension channel is busy. + * This is always disabled for AR5211 series NICs. + */ +uint32_t +ar5211Get11nExtBusy(struct ath_hal *ah) +{ + return (0); +} + +/* + * There's no channel survey support for the AR5211. + */ +HAL_BOOL +ar5211GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample) +{ + + return (AH_FALSE); +} + +void +ar5211SetChainMasks(struct ath_hal *ah, uint32_t txchainmask, + uint32_t rxchainmask) +{ +} + +void +ar5211EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) +{ +} + +void +ar5211GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) +{ +} + +/* + * Get the current NAV value from the hardware. + */ +u_int +ar5211GetNav(struct ath_hal *ah) +{ + uint32_t reg; + + reg = OS_REG_READ(ah, AR_NAV); + return (reg); +} + +/* + * Set the current NAV value to the hardware. + */ +void +ar5211SetNav(struct ath_hal *ah, u_int val) +{ + + OS_REG_WRITE(ah, AR_NAV, val); +} + diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c b/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c new file mode 100644 index 000000000000..601584763058 --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c @@ -0,0 +1,103 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" + +/* shorthands to compact tables for readability */ +#define OFDM IEEE80211_T_OFDM +#define CCK IEEE80211_T_CCK +#define TURBO IEEE80211_T_TURBO + +HAL_RATE_TABLE ar5211_11a_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80|12), 0 }, +/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 }, +/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80|24), 2 }, +/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 }, +/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80|48), 4 }, +/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 }, +/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 }, +/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 } + }, +}; + +HAL_RATE_TABLE ar5211_turbo_table = { + 8, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 6 Mb */ { AH_TRUE, TURBO, 12000, 0x0b, 0x00, (0x80|12), 0 }, +/* 9 Mb */ { AH_TRUE, TURBO, 18000, 0x0f, 0x00, 18, 0 }, +/* 12 Mb */ { AH_TRUE, TURBO, 24000, 0x0a, 0x00, (0x80|24), 2 }, +/* 18 Mb */ { AH_TRUE, TURBO, 36000, 0x0e, 0x00, 36, 2 }, +/* 24 Mb */ { AH_TRUE, TURBO, 48000, 0x09, 0x00, (0x80|48), 4 }, +/* 36 Mb */ { AH_TRUE, TURBO, 72000, 0x0d, 0x00, 72, 4 }, +/* 48 Mb */ { AH_TRUE, TURBO, 96000, 0x08, 0x00, 96, 4 }, +/* 54 Mb */ { AH_TRUE, TURBO, 108000, 0x0c, 0x00, 108, 4 } + }, +}; + +HAL_RATE_TABLE ar5211_11b_table = { + 4, /* number of rates */ + { 0 }, + { +/* short ctrl */ +/* valid rateCode Preamble dot11Rate Rate */ +/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x0b, 0x00, (0x80| 2), 0 }, +/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x0a, 0x04, (0x80| 4), 1 }, +/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x09, 0x04, (0x80|11), 1 }, +/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x08, 0x04, (0x80|22), 1 } + }, +}; + +#undef OFDM +#undef CCK +#undef TURBO + +const HAL_RATE_TABLE * +ar5211GetRateTable(struct ath_hal *ah, u_int mode) +{ + HAL_RATE_TABLE *rt; + switch (mode) { + case HAL_MODE_11A: + rt = &ar5211_11a_table; + break; + case HAL_MODE_11B: + rt = &ar5211_11b_table; + break; + case HAL_MODE_TURBO: + rt = &ar5211_turbo_table; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid mode 0x%x\n", + __func__, mode); + return AH_NULL; + } + ath_hal_setupratetable(ah, rt); + return rt; +} diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_power.c b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c new file mode 100644 index 000000000000..4fa177b4522e --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c @@ -0,0 +1,140 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211desc.h" + +/* + * Notify Power Mgt is enabled in self-generated frames. + * If requested, force chip awake. + * + * Returns A_OK if chip is awake or successfully forced awake. + * + * WARNING WARNING WARNING + * There is a problem with the chip where sometimes it will not wake up. + */ +static HAL_BOOL +ar5211SetPowerModeAwake(struct ath_hal *ah, int setChip) +{ +#define POWER_UP_TIME 2000 + uint32_t val; + int i; + + if (setChip) { + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE); + OS_DELAY(10); /* Give chip the chance to awake */ + + for (i = POWER_UP_TIME / 200; i != 0; i--) { + val = OS_REG_READ(ah, AR_PCICFG); + if ((val & AR_PCICFG_SPWR_DN) == 0) + break; + OS_DELAY(200); + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, + AR_SCR_SLE_WAKE); + } + if (i == 0) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", + __func__, POWER_UP_TIME/20); +#endif + return AH_FALSE; + } + } + + OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + return AH_TRUE; +#undef POWER_UP_TIME +} + +/* + * Notify Power Mgt is disabled in self-generated frames. + * If requested, force chip to sleep. + */ +static void +ar5211SetPowerModeSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP); +} + +/* + * Notify Power Management is enabled in self-generating + * fames. If request, set power mode of chip to + * auto/normal. Duration in units of 128us (1/8 TU). + */ +static void +ar5211SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) +{ + OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) + OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_NORM); +} + +HAL_BOOL +ar5211SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) +{ +#ifdef AH_DEBUG + static const char* modes[] = { + "AWAKE", + "FULL-SLEEP", + "NETWORK SLEEP", + "UNDEFINED" + }; +#endif + int status = AH_TRUE; + + HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, + modes[ah->ah_powerMode], modes[mode], + setChip ? "set chip " : ""); + switch (mode) { + case HAL_PM_AWAKE: + if (setChip) + ah->ah_powerMode = mode; + status = ar5211SetPowerModeAwake(ah, setChip); + break; + case HAL_PM_FULL_SLEEP: + ar5211SetPowerModeSleep(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; + break; + case HAL_PM_NETWORK_SLEEP: + ar5211SetPowerModeNetworkSleep(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", + __func__, mode); + return AH_FALSE; + } + return status; +} + +HAL_POWER_MODE +ar5211GetPowerMode(struct ath_hal *ah) +{ + /* Just so happens the h/w maps directly to the abstracted value */ + return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE); +} diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c b/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c new file mode 100644 index 000000000000..874333e8e752 --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c @@ -0,0 +1,248 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_desc.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211desc.h" + +/* + * Get the RXDP. + */ +uint32_t +ar5211GetRxDP(struct ath_hal *ah, HAL_RX_QUEUE qtype) +{ + + HALASSERT(qtype == HAL_RX_QUEUE_HP); + return OS_REG_READ(ah, AR_RXDP); +} + +/* + * Set the RxDP. + */ +void +ar5211SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype) +{ + + HALASSERT(qtype == HAL_RX_QUEUE_HP); + OS_REG_WRITE(ah, AR_RXDP, rxdp); + HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp); +} + +/* + * Set Receive Enable bits. + */ +void +ar5211EnableReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_CR, AR_CR_RXE); +} + +/* + * Stop Receive at the DMA engine + */ +HAL_BOOL +ar5211StopDmaReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ + if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) { +#ifdef AH_DEBUG + ath_hal_printf(ah, "%s failed to stop in 10ms\n" + "AR_CR=0x%08X\nAR_DIAG_SW=0x%08X\n" + , __func__ + , OS_REG_READ(ah, AR_CR) + , OS_REG_READ(ah, AR_DIAG_SW) + ); +#endif + return AH_FALSE; + } else { + return AH_TRUE; + } +} + +/* + * Start Transmit at the PCU engine (unpause receive) + */ +void +ar5211StartPcuReceive(struct ath_hal *ah, HAL_BOOL is_scanning) +{ + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX)); +} + +/* + * Stop Transmit at the PCU engine (pause receive) + */ +void +ar5211StopPcuReceive(struct ath_hal *ah) +{ + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX); +} + +/* + * Set multicast filter 0 (lower 32-bits) + * filter 1 (upper 32-bits) + */ +void +ar5211SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1) +{ + OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0); + OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1); +} + +/* + * Clear multicast filter by index + */ +HAL_BOOL +ar5211ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) +{ + uint32_t val; + + if (ix >= 64) + return AH_FALSE; + if (ix >= 32) { + val = OS_REG_READ(ah, AR_MCAST_FIL1); + OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); + } else { + val = OS_REG_READ(ah, AR_MCAST_FIL0); + OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix))); + } + return AH_TRUE; +} + +/* + * Set multicast filter by index + */ +HAL_BOOL +ar5211SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) +{ + uint32_t val; + + if (ix >= 64) + return AH_FALSE; + if (ix >= 32) { + val = OS_REG_READ(ah, AR_MCAST_FIL1); + OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); + } else { + val = OS_REG_READ(ah, AR_MCAST_FIL0); + OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix))); + } + return AH_TRUE; +} + +/* + * Get receive filter. + */ +uint32_t +ar5211GetRxFilter(struct ath_hal *ah) +{ + return OS_REG_READ(ah, AR_RX_FILTER); +} + +/* + * Set receive filter. + */ +void +ar5211SetRxFilter(struct ath_hal *ah, uint32_t bits) +{ + OS_REG_WRITE(ah, AR_RX_FILTER, bits); +} + +/* + * Initialize RX descriptor, by clearing the status and clearing + * the size. This is not strictly HW dependent, but we want the + * control and status words to be opaque above the hal. + */ +HAL_BOOL +ar5211SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds, + uint32_t size, u_int flags) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + ads->ds_ctl0 = 0; + ads->ds_ctl1 = size & AR_BufLen; + if (ads->ds_ctl1 != size) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: buffer size %u too large\n", + __func__, size); + return AH_FALSE; + } + if (flags & HAL_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxInterReq; + ads->ds_status0 = ads->ds_status1 = 0; + + return AH_TRUE; +} + +/* + * Process an RX descriptor, and return the status to the caller. + * Copy some hardware specific items into the software portion + * of the descriptor. + * + * NB: the caller is responsible for validating the memory contents + * of the descriptor (e.g. flushing any cached copy). + */ +HAL_STATUS +ar5211ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, + uint32_t pa, struct ath_desc *nds, uint64_t tsf, + struct ath_rx_status *rs) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + struct ar5211_desc *ands = AR5211DESC(nds); + + if ((ads->ds_status1 & AR_Done) == 0) + return HAL_EINPROGRESS; + /* + * Given the use of a self-linked tail be very sure that the hw is + * done with this descriptor; the hw may have done this descriptor + * once and picked it up again...make sure the hw has moved on. + */ + if ((ands->ds_status1 & AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa) + return HAL_EINPROGRESS; + + rs->rs_datalen = ads->ds_status0 & AR_DataLen; + rs->rs_tstamp = MS(ads->ds_status1, AR_RcvTimestamp); + rs->rs_status = 0; + if ((ads->ds_status1 & AR_FrmRcvOK) == 0) { + if (ads->ds_status1 & AR_CRCErr) + rs->rs_status |= HAL_RXERR_CRC; + else if (ads->ds_status1 & AR_DecryptCRCErr) + rs->rs_status |= HAL_RXERR_DECRYPT; + else { + rs->rs_status |= HAL_RXERR_PHY; + rs->rs_phyerr = MS(ads->ds_status1, AR_PHYErr); + } + } + /* XXX what about KeyCacheMiss? */ + rs->rs_rssi = MS(ads->ds_status0, AR_RcvSigStrength); + if (ads->ds_status1 & AR_KeyIdxValid) + rs->rs_keyix = MS(ads->ds_status1, AR_KeyIdx); + else + rs->rs_keyix = HAL_RXKEYIX_INVALID; + /* NB: caller expected to do rate table mapping */ + rs->rs_rate = MS(ads->ds_status0, AR_RcvRate); + rs->rs_antenna = MS(ads->ds_status0, AR_RcvAntenna); + rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0; + + return HAL_OK; +} diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c b/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c new file mode 100644 index 000000000000..fa5293777f02 --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c @@ -0,0 +1,2120 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +/* + * Chips specific device attachment and device info collection + * Connects Init Reg Vectors, EEPROM Data, and device Functions. + */ +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211phy.h" + +#include "ah_eeprom_v3.h" + +/* Add static register initialization vectors */ +#include "ar5211/boss.ini" + +/* + * Structure to hold 11b tuning information for Beanie/Sombrero + * 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=12 + */ +typedef struct { + uint32_t refClkSel; /* reference clock, 1 for 16 MHz */ + uint32_t channelSelect; /* P[7:4]S[3:0] bits */ + uint16_t channel5111; /* 11a channel for 5111 */ +} CHAN_INFO_2GHZ; + +#define CI_2GHZ_INDEX_CORRECTION 19 +static const CHAN_INFO_2GHZ chan2GHzData[] = { + { 1, 0x46, 96 }, /* 2312 -19 */ + { 1, 0x46, 97 }, /* 2317 -18 */ + { 1, 0x46, 98 }, /* 2322 -17 */ + { 1, 0x46, 99 }, /* 2327 -16 */ + { 1, 0x46, 100 }, /* 2332 -15 */ + { 1, 0x46, 101 }, /* 2337 -14 */ + { 1, 0x46, 102 }, /* 2342 -13 */ + { 1, 0x46, 103 }, /* 2347 -12 */ + { 1, 0x46, 104 }, /* 2352 -11 */ + { 1, 0x46, 105 }, /* 2357 -10 */ + { 1, 0x46, 106 }, /* 2362 -9 */ + { 1, 0x46, 107 }, /* 2367 -8 */ + { 1, 0x46, 108 }, /* 2372 -7 */ + /* index -6 to 0 are pad to make this a nolookup table */ + { 1, 0x46, 116 }, /* -6 */ + { 1, 0x46, 116 }, /* -5 */ + { 1, 0x46, 116 }, /* -4 */ + { 1, 0x46, 116 }, /* -3 */ + { 1, 0x46, 116 }, /* -2 */ + { 1, 0x46, 116 }, /* -1 */ + { 1, 0x46, 116 }, /* 0 */ + { 1, 0x46, 116 }, /* 2412 1 */ + { 1, 0x46, 117 }, /* 2417 2 */ + { 1, 0x46, 118 }, /* 2422 3 */ + { 1, 0x46, 119 }, /* 2427 4 */ + { 1, 0x46, 120 }, /* 2432 5 */ + { 1, 0x46, 121 }, /* 2437 6 */ + { 1, 0x46, 122 }, /* 2442 7 */ + { 1, 0x46, 123 }, /* 2447 8 */ + { 1, 0x46, 124 }, /* 2452 9 */ + { 1, 0x46, 125 }, /* 2457 10 */ + { 1, 0x46, 126 }, /* 2462 11 */ + { 1, 0x46, 127 }, /* 2467 12 */ + { 1, 0x46, 128 }, /* 2472 13 */ + { 1, 0x44, 124 }, /* 2484 14 */ + { 1, 0x46, 136 }, /* 2512 15 */ + { 1, 0x46, 140 }, /* 2532 16 */ + { 1, 0x46, 144 }, /* 2552 17 */ + { 1, 0x46, 148 }, /* 2572 18 */ + { 1, 0x46, 152 }, /* 2592 19 */ + { 1, 0x46, 156 }, /* 2612 20 */ + { 1, 0x46, 160 }, /* 2632 21 */ + { 1, 0x46, 164 }, /* 2652 22 */ + { 1, 0x46, 168 }, /* 2672 23 */ + { 1, 0x46, 172 }, /* 2692 24 */ + { 1, 0x46, 176 }, /* 2712 25 */ + { 1, 0x46, 180 } /* 2732 26 */ +}; + +/* Power timeouts in usec to wait for chip to wake-up. */ +#define POWER_UP_TIME 2000 + +#define DELAY_PLL_SETTLE 300 /* 300 us */ +#define DELAY_BASE_ACTIVATE 100 /* 100 us */ + +#define NUM_RATES 8 + +static HAL_BOOL ar5211SetResetReg(struct ath_hal *ah, uint32_t resetMask); +static HAL_BOOL ar5211SetChannel(struct ath_hal *, + const struct ieee80211_channel *); +static int16_t ar5211RunNoiseFloor(struct ath_hal *, + uint8_t runTime, int16_t startingNF); +static HAL_BOOL ar5211IsNfGood(struct ath_hal *, + struct ieee80211_channel *chan); +static HAL_BOOL ar5211SetRf6and7(struct ath_hal *, + const struct ieee80211_channel *chan); +static HAL_BOOL ar5211SetBoardValues(struct ath_hal *, + const struct ieee80211_channel *chan); +static void ar5211SetPowerTable(struct ath_hal *, + PCDACS_EEPROM *pSrcStruct, uint16_t channel); +static HAL_BOOL ar5211SetTransmitPower(struct ath_hal *, + const struct ieee80211_channel *); +static void ar5211SetRateTable(struct ath_hal *, + RD_EDGES_POWER *pRdEdgesPower, TRGT_POWER_INFO *pPowerInfo, + uint16_t numChannels, const struct ieee80211_channel *chan); +static uint16_t ar5211GetScaledPower(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct); +static HAL_BOOL ar5211FindValueInList(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue); +static uint16_t ar5211GetInterpolatedValue(uint16_t target, + uint16_t srcLeft, uint16_t srcRight, + uint16_t targetLeft, uint16_t targetRight, HAL_BOOL scaleUp); +static void ar5211GetLowerUpperValues(uint16_t value, + const uint16_t *pList, uint16_t listSize, + uint16_t *pLowerValue, uint16_t *pUpperValue); +static void ar5211GetLowerUpperPcdacs(uint16_t pcdac, + uint16_t channel, const PCDACS_EEPROM *pSrcStruct, + uint16_t *pLowerPcdac, uint16_t *pUpperPcdac); + +static void ar5211SetRfgain(struct ath_hal *, const GAIN_VALUES *); +static void ar5211RequestRfgain(struct ath_hal *); +static HAL_BOOL ar5211InvalidGainReadback(struct ath_hal *, GAIN_VALUES *); +static HAL_BOOL ar5211IsGainAdjustNeeded(struct ath_hal *, const GAIN_VALUES *); +static int32_t ar5211AdjustGain(struct ath_hal *, GAIN_VALUES *); +static void ar5211SetOperatingMode(struct ath_hal *, int opmode); + +/* + * Places the device in and out of reset and then places sane + * values in the registers based on EEPROM config, initialization + * vectors (as determined by the mode), and station configuration + * + * bChannelChange is used to preserve DMA/PCU registers across + * a HW Reset during channel change. + */ +HAL_BOOL +ar5211Reset(struct ath_hal *ah, HAL_OPMODE opmode, + struct ieee80211_channel *chan, HAL_BOOL bChannelChange, + HAL_RESET_TYPE resetType, + HAL_STATUS *status) +{ +uint32_t softLedCfg, softLedState; +#define N(a) (sizeof (a) /sizeof (a[0])) +#define FAIL(_code) do { ecode = _code; goto bad; } while (0) + struct ath_hal_5211 *ahp = AH5211(ah); + HAL_CHANNEL_INTERNAL *ichan; + uint32_t i, ledstate; + HAL_STATUS ecode; + int q; + + uint32_t data, synthDelay; + uint32_t macStaId1; + uint16_t modesIndex = 0, freqIndex = 0; + uint32_t saveFrameSeqCount[AR_NUM_DCU]; + uint32_t saveTsfLow = 0, saveTsfHigh = 0; + uint32_t saveDefAntenna; + + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s: opmode %u channel %u/0x%x %s channel\n", + __func__, opmode, chan->ic_freq, chan->ic_flags, + bChannelChange ? "change" : "same"); + + OS_MARK(ah, AH_MARK_RESET, bChannelChange); + /* + * Map public channel to private. + */ + ichan = ath_hal_checkchannel(ah, chan); + if (ichan == AH_NULL) + FAIL(HAL_EINVAL); + switch (opmode) { + case HAL_M_STA: + case HAL_M_IBSS: + case HAL_M_HOSTAP: + case HAL_M_MONITOR: + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid operating mode %u\n", __func__, opmode); + FAIL(HAL_EINVAL); + break; + } + HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3); + + /* Preserve certain DMA hardware registers on a channel change */ + if (bChannelChange) { + /* + * Need to save/restore the TSF because of an issue + * that accelerates the TSF during a chip reset. + * + * We could use system timer routines to more + * accurately restore the TSF, but + * 1. Timer routines on certain platforms are + * not accurate enough (e.g. 1 ms resolution). + * 2. It would still not be accurate. + * + * The most important aspect of this workaround, + * is that, after reset, the TSF is behind + * other STAs TSFs. This will allow the STA to + * properly resynchronize its TSF in adhoc mode. + */ + saveTsfLow = OS_REG_READ(ah, AR_TSF_L32); + saveTsfHigh = OS_REG_READ(ah, AR_TSF_U32); + + /* Read frame sequence count */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + saveFrameSeqCount[0] = OS_REG_READ(ah, AR_D0_SEQNUM); + } else { + for (i = 0; i < AR_NUM_DCU; i++) + saveFrameSeqCount[i] = OS_REG_READ(ah, AR_DSEQNUM(i)); + } + if (!IEEE80211_IS_CHAN_DFS(chan)) + chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; + } + + /* + * Preserve the antenna on a channel change + */ + saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); + if (saveDefAntenna == 0) + saveDefAntenna = 1; + + /* Save hardware flag before chip reset clears the register */ + macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; + + /* Save led state from pci config register */ + ledstate = OS_REG_READ(ah, AR_PCICFG) & + (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | + AR_PCICFG_LEDSLOW); + softLedCfg = OS_REG_READ(ah, AR_GPIOCR); + softLedState = OS_REG_READ(ah, AR_GPIODO); + + if (!ar5211ChipReset(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); + FAIL(HAL_EIO); + } + + /* Setup the indices for the next set of register array writes */ + if (IEEE80211_IS_CHAN_5GHZ(chan)) { + freqIndex = 1; + if (IEEE80211_IS_CHAN_TURBO(chan)) + modesIndex = 2; + else if (IEEE80211_IS_CHAN_A(chan)) + modesIndex = 1; + else { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x\n", + __func__, chan->ic_freq, chan->ic_flags); + FAIL(HAL_EINVAL); + } + } else { + freqIndex = 2; + if (IEEE80211_IS_CHAN_B(chan)) + modesIndex = 3; + else if (IEEE80211_IS_CHAN_PUREG(chan)) + modesIndex = 4; + else { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x\n", + __func__, chan->ic_freq, chan->ic_flags); + FAIL(HAL_EINVAL); + } + } + + /* Set correct Baseband to analog shift setting to access analog chips. */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000007); + } else { + OS_REG_WRITE(ah, AR_PHY_BASE, 0x00000047); + } + + /* Write parameters specific to AR5211 */ + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + if (IEEE80211_IS_CHAN_2GHZ(chan) && + AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1) { + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + uint32_t ob2GHz, db2GHz; + + if (IEEE80211_IS_CHAN_CCK(chan)) { + ob2GHz = ee->ee_ob2GHz[0]; + db2GHz = ee->ee_db2GHz[0]; + } else { + ob2GHz = ee->ee_ob2GHz[1]; + db2GHz = ee->ee_db2GHz[1]; + } + ob2GHz = ath_hal_reverseBits(ob2GHz, 3); + db2GHz = ath_hal_reverseBits(db2GHz, 3); + ar5211Mode2_4[25][freqIndex] = + (ar5211Mode2_4[25][freqIndex] & ~0xC0) | + ((ob2GHz << 6) & 0xC0); + ar5211Mode2_4[26][freqIndex] = + (ar5211Mode2_4[26][freqIndex] & ~0x0F) | + (((ob2GHz >> 2) & 0x1) | + ((db2GHz << 1) & 0x0E)); + } + for (i = 0; i < N(ar5211Mode2_4); i++) + OS_REG_WRITE(ah, ar5211Mode2_4[i][0], + ar5211Mode2_4[i][freqIndex]); + } + + /* Write the analog registers 6 and 7 before other config */ + ar5211SetRf6and7(ah, chan); + + /* Write registers that vary across all modes */ + for (i = 0; i < N(ar5211Modes); i++) + OS_REG_WRITE(ah, ar5211Modes[i][0], ar5211Modes[i][modesIndex]); + + /* Write RFGain Parameters that differ between 2.4 and 5 GHz */ + for (i = 0; i < N(ar5211BB_RfGain); i++) + OS_REG_WRITE(ah, ar5211BB_RfGain[i][0], ar5211BB_RfGain[i][freqIndex]); + + /* Write Common Array Parameters */ + for (i = 0; i < N(ar5211Common); i++) { + uint32_t reg = ar5211Common[i][0]; + /* On channel change, don't reset the PCU registers */ + if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000))) + OS_REG_WRITE(ah, reg, ar5211Common[i][1]); + } + + /* Fix pre-AR5211 register values, this includes AR5311s. */ + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { + /* + * The TX and RX latency values have changed locations + * within the USEC register in AR5211. Since they're + * set via the .ini, for both AR5211 and AR5311, they + * are written properly here for AR5311. + */ + data = OS_REG_READ(ah, AR_USEC); + /* Must be 0 for proper write in AR5311 */ + HALASSERT((data & 0x00700000) == 0); + OS_REG_WRITE(ah, AR_USEC, + (data & (AR_USEC_M | AR_USEC_32_M | AR5311_USEC_TX_LAT_M)) | + ((29 << AR5311_USEC_RX_LAT_S) & AR5311_USEC_RX_LAT_M)); + /* The following registers exist only on AR5311. */ + OS_REG_WRITE(ah, AR5311_QDCLKGATE, 0); + + /* Set proper ADC & DAC delays for AR5311. */ + OS_REG_WRITE(ah, 0x00009878, 0x00000008); + + /* Enable the PCU FIFO corruption ECO on AR5311. */ + OS_REG_WRITE(ah, AR_DIAG_SW, + OS_REG_READ(ah, AR_DIAG_SW) | AR5311_DIAG_SW_USE_ECO); + } + + /* Restore certain DMA hardware registers on a channel change */ + if (bChannelChange) { + /* Restore TSF */ + OS_REG_WRITE(ah, AR_TSF_L32, saveTsfLow); + OS_REG_WRITE(ah, AR_TSF_U32, saveTsfHigh); + + if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_OAHU) { + OS_REG_WRITE(ah, AR_D0_SEQNUM, saveFrameSeqCount[0]); + } else { + for (i = 0; i < AR_NUM_DCU; i++) + OS_REG_WRITE(ah, AR_DSEQNUM(i), saveFrameSeqCount[i]); + } + } + + OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); + OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) + | macStaId1 + ); + ar5211SetOperatingMode(ah, opmode); + + /* Restore previous led state */ + OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate); + OS_REG_WRITE(ah, AR_GPIOCR, softLedCfg); + OS_REG_WRITE(ah, AR_GPIODO, softLedState); + + /* Restore previous antenna */ + OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); + + OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); + OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); + + /* Restore bmiss rssi & count thresholds */ + OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); + + OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ + + /* + * for pre-Production Oahu only. + * Disable clock gating in all DMA blocks. Helps when using + * 11B and AES but results in higher power consumption. + */ + if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_OAHU && + AH_PRIVATE(ah)->ah_macRev < AR_SREV_OAHU_PROD) { + OS_REG_WRITE(ah, AR_CFG, + OS_REG_READ(ah, AR_CFG) | AR_CFG_CLK_GATE_DIS); + } + + /* Setup the transmit power values. */ + if (!ar5211SetTransmitPower(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: error init'ing transmit power\n", __func__); + FAIL(HAL_EIO); + } + + /* + * Configurable OFDM spoofing for 11n compatibility; used + * only when operating in station mode. + */ + if (opmode != HAL_M_HOSTAP && + (AH_PRIVATE(ah)->ah_11nCompat & HAL_DIAG_11N_SERVICES) != 0) { + /* NB: override the .ini setting */ + OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, + AR_PHY_FRAME_CTL_ERR_SERV, + MS(AH_PRIVATE(ah)->ah_11nCompat, HAL_DIAG_11N_SERVICES)&1); + } + + /* Setup board specific options for EEPROM version 3 */ + ar5211SetBoardValues(ah, chan); + + if (!ar5211SetChannel(ah, chan)) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set channel\n", + __func__); + FAIL(HAL_EIO); + } + + /* Activate the PHY */ + if (AH_PRIVATE(ah)->ah_devid == AR5211_FPGA11B && + IEEE80211_IS_CHAN_2GHZ(chan)) + OS_REG_WRITE(ah, 0xd808, 0x502); /* required for FPGA */ + OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * Wait for the frequency synth to settle (synth goes on + * via AR_PHY_ACTIVE_EN). Read the phy active delay register. + * Value is in 100ns increments. + */ + data = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_M; + if (IEEE80211_IS_CHAN_CCK(chan)) { + synthDelay = (4 * data) / 22; + } else { + synthDelay = data / 10; + } + /* + * There is an issue if the AP starts the calibration before + * the baseband timeout completes. This could result in the + * rxclear false triggering. Add an extra delay to ensure this + * this does not happen. + */ + OS_DELAY(synthDelay + DELAY_BASE_ACTIVATE); + + /* Calibrate the AGC and wait for completion. */ + OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, + OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); + (void) ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0); + + /* Perform noise floor and set status */ + if (!ar5211CalNoiseFloor(ah, chan)) { + if (!IEEE80211_IS_CHAN_CCK(chan)) + chan->ic_state |= IEEE80211_CHANSTATE_CWINT; + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: noise floor calibration failed\n", __func__); + FAIL(HAL_EIO); + } + + /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ + if (ahp->ah_calibrationTime != 0) { + OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, + AR_PHY_TIMING_CTRL4_DO_IQCAL | (INIT_IQCAL_LOG_COUNT_MAX << AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S)); + ahp->ah_bIQCalibration = AH_TRUE; + } + + /* set 1:1 QCU to DCU mapping for all queues */ + for (q = 0; q < AR_NUM_DCU; q++) + OS_REG_WRITE(ah, AR_DQCUMASK(q), 1<<q); + + for (q = 0; q < HAL_NUM_TX_QUEUES; q++) + ar5211ResetTxQueue(ah, q); + + /* Setup QCU0 transmit interrupt masks (TX_ERR, TX_OK, TX_DESC, TX_URN) */ + OS_REG_WRITE(ah, AR_IMR_S0, + (AR_IMR_S0_QCU_TXOK & AR_QCU_0) | + (AR_IMR_S0_QCU_TXDESC & (AR_QCU_0<<AR_IMR_S0_QCU_TXDESC_S))); + OS_REG_WRITE(ah, AR_IMR_S1, (AR_IMR_S1_QCU_TXERR & AR_QCU_0)); + OS_REG_WRITE(ah, AR_IMR_S2, (AR_IMR_S2_QCU_TXURN & AR_QCU_0)); + + /* + * GBL_EIFS must always be written after writing + * to any QCUMASK register. + */ + OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, OS_REG_READ(ah, AR_D_GBL_IFS_EIFS)); + + /* Now set up the Interrupt Mask Register and save it for future use */ + OS_REG_WRITE(ah, AR_IMR, INIT_INTERRUPT_MASK); + ahp->ah_maskReg = INIT_INTERRUPT_MASK; + + /* Enable bus error interrupts */ + OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | + AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); + + /* Enable interrupts specific to AP */ + if (opmode == HAL_M_HOSTAP) { + OS_REG_WRITE(ah, AR_IMR, OS_REG_READ(ah, AR_IMR) | AR_IMR_MIB); + ahp->ah_maskReg |= AR_IMR_MIB; + } + + if (AH_PRIVATE(ah)->ah_rfkillEnabled) + ar5211EnableRfKill(ah); + + /* + * Writing to AR_BEACON will start timers. Hence it should + * be the last register to be written. Do not reset tsf, do + * not enable beacons at this point, but preserve other values + * like beaconInterval. + */ + OS_REG_WRITE(ah, AR_BEACON, + (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF))); + + /* Restore user-specified slot time and timeouts */ + if (ahp->ah_sifstime != (u_int) -1) + ar5211SetSifsTime(ah, ahp->ah_sifstime); + if (ahp->ah_slottime != (u_int) -1) + ar5211SetSlotTime(ah, ahp->ah_slottime); + if (ahp->ah_acktimeout != (u_int) -1) + ar5211SetAckTimeout(ah, ahp->ah_acktimeout); + if (ahp->ah_ctstimeout != (u_int) -1) + ar5211SetCTSTimeout(ah, ahp->ah_ctstimeout); + if (AH_PRIVATE(ah)->ah_diagreg != 0) + OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); + + AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ + + HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); + + return AH_TRUE; +bad: + if (status != AH_NULL) + *status = ecode; + return AH_FALSE; +#undef FAIL +#undef N +} + +/* + * Places the PHY and Radio chips into reset. A full reset + * must be called to leave this state. The PCI/MAC/PCU are + * not placed into reset as we must receive interrupt to + * re-enable the hardware. + */ +HAL_BOOL +ar5211PhyDisable(struct ath_hal *ah) +{ + return ar5211SetResetReg(ah, AR_RC_BB); +} + +/* + * Places all of hardware into reset + */ +HAL_BOOL +ar5211Disable(struct ath_hal *ah) +{ + if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + /* + * Reset the HW - PCI must be reset after the rest of the + * device has been reset. + */ + if (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI)) + return AH_FALSE; + OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ + + return AH_TRUE; +} + +/* + * Places the hardware into reset and then pulls it out of reset + * + * Only write the PLL if we're changing to or from CCK mode + * + * Attach calls with channelFlags = 0, as the coldreset should have + * us in the correct mode and we cannot check the hwchannel flags. + */ +HAL_BOOL +ar5211ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ + if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + + /* NB: called from attach with chan null */ + if (chan != AH_NULL) { + /* Set CCK and Turbo modes correctly */ + OS_REG_WRITE(ah, AR_PHY_TURBO, IEEE80211_IS_CHAN_TURBO(chan) ? + AR_PHY_FC_TURBO_MODE | AR_PHY_FC_TURBO_SHORT : 0); + if (IEEE80211_IS_CHAN_B(chan)) { + OS_REG_WRITE(ah, AR5211_PHY_MODE, + AR5211_PHY_MODE_CCK | AR5211_PHY_MODE_RF2GHZ); + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_44); + /* Wait for the PLL to settle */ + OS_DELAY(DELAY_PLL_SETTLE); + } else if (AH_PRIVATE(ah)->ah_devid == AR5211_DEVID) { + OS_REG_WRITE(ah, AR_PHY_PLL_CTL, AR_PHY_PLL_CTL_40); + OS_DELAY(DELAY_PLL_SETTLE); + OS_REG_WRITE(ah, AR5211_PHY_MODE, + AR5211_PHY_MODE_OFDM | (IEEE80211_IS_CHAN_2GHZ(chan) ? + AR5211_PHY_MODE_RF2GHZ : + AR5211_PHY_MODE_RF5GHZ)); + } + } + + /* + * Reset the HW - PCI must be reset after the rest of the + * device has been reset + */ + if (!ar5211SetResetReg(ah, AR_RC_MAC | AR_RC_BB | AR_RC_PCI)) + return AH_FALSE; + OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ + + /* Bring out of sleep mode (AGAIN) */ + if (!ar5211SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) + return AH_FALSE; + + /* Clear warm reset register */ + return ar5211SetResetReg(ah, 0); +} + +/* + * Recalibrate the lower PHY chips to account for temperature/environment + * changes. + */ +HAL_BOOL +ar5211PerCalibrationN(struct ath_hal *ah, struct ieee80211_channel *chan, + u_int chainMask, HAL_BOOL longCal, HAL_BOOL *isCalDone) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + HAL_CHANNEL_INTERNAL *ichan; + int32_t qCoff, qCoffDenom; + uint32_t data; + int32_t iqCorrMeas; + int32_t iCoff, iCoffDenom; + uint32_t powerMeasQ, powerMeasI; + + ichan = ath_hal_checkchannel(ah, chan); + if (ichan == AH_NULL) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->ic_freq, chan->ic_flags); + return AH_FALSE; + } + /* IQ calibration in progress. Check to see if it has finished. */ + if (ahp->ah_bIQCalibration && + !(OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & AR_PHY_TIMING_CTRL4_DO_IQCAL)) { + /* IQ Calibration has finished. */ + ahp->ah_bIQCalibration = AH_FALSE; + + /* Read calibration results. */ + powerMeasI = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_I); + powerMeasQ = OS_REG_READ(ah, AR_PHY_IQCAL_RES_PWR_MEAS_Q); + iqCorrMeas = OS_REG_READ(ah, AR_PHY_IQCAL_RES_IQ_CORR_MEAS); + + /* + * Prescale these values to remove 64-bit operation requirement at the loss + * of a little precision. + */ + iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; + qCoffDenom = powerMeasQ / 64; + + /* Protect against divide-by-0. */ + if (iCoffDenom != 0 && qCoffDenom != 0) { + iCoff = (-iqCorrMeas) / iCoffDenom; + /* IQCORR_Q_I_COFF is a signed 6 bit number */ + iCoff = iCoff & 0x3f; + + qCoff = ((int32_t)powerMeasI / qCoffDenom) - 64; + /* IQCORR_Q_Q_COFF is a signed 5 bit number */ + qCoff = qCoff & 0x1f; + + HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasI = 0x%08x\n", + powerMeasI); + HALDEBUG(ah, HAL_DEBUG_PERCAL, "powerMeasQ = 0x%08x\n", + powerMeasQ); + HALDEBUG(ah, HAL_DEBUG_PERCAL, "iqCorrMeas = 0x%08x\n", + iqCorrMeas); + HALDEBUG(ah, HAL_DEBUG_PERCAL, "iCoff = %d\n", + iCoff); + HALDEBUG(ah, HAL_DEBUG_PERCAL, "qCoff = %d\n", + qCoff); + + /* Write IQ */ + data = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) | + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE | + (((uint32_t)iCoff) << AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S) | + ((uint32_t)qCoff); + OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, data); + } + } + *isCalDone = !ahp->ah_bIQCalibration; + + if (longCal) { + /* Perform noise floor and set status */ + if (!ar5211IsNfGood(ah, chan)) { + /* report up and clear internal state */ + chan->ic_state |= IEEE80211_CHANSTATE_CWINT; + return AH_FALSE; + } + if (!ar5211CalNoiseFloor(ah, chan)) { + /* + * Delay 5ms before retrying the noise floor + * just to make sure, as we are in an error + * condition here. + */ + OS_DELAY(5000); + if (!ar5211CalNoiseFloor(ah, chan)) { + if (!IEEE80211_IS_CHAN_CCK(chan)) + chan->ic_state |= IEEE80211_CHANSTATE_CWINT; + return AH_FALSE; + } + } + ar5211RequestRfgain(ah); + } + return AH_TRUE; +} + +HAL_BOOL +ar5211PerCalibration(struct ath_hal *ah, struct ieee80211_channel *chan, + HAL_BOOL *isIQdone) +{ + return ar5211PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone); +} + +HAL_BOOL +ar5211ResetCalValid(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ + /* XXX */ + return AH_TRUE; +} + +/* + * Writes the given reset bit mask into the reset register + */ +static HAL_BOOL +ar5211SetResetReg(struct ath_hal *ah, uint32_t resetMask) +{ + uint32_t mask = resetMask ? resetMask : ~0; + HAL_BOOL rt; + + (void) OS_REG_READ(ah, AR_RXDP);/* flush any pending MMR writes */ + OS_REG_WRITE(ah, AR_RC, resetMask); + + /* need to wait at least 128 clocks when reseting PCI before read */ + OS_DELAY(15); + + resetMask &= AR_RC_MAC | AR_RC_BB; + mask &= AR_RC_MAC | AR_RC_BB; + rt = ath_hal_wait(ah, AR_RC, mask, resetMask); + if ((resetMask & AR_RC_MAC) == 0) { + if (isBigEndian()) { + /* + * Set CFG, little-endian for descriptor accesses. + */ + mask = INIT_CONFIG_STATUS | AR_CFG_SWTD | AR_CFG_SWRD; + OS_REG_WRITE(ah, AR_CFG, mask); + } else + OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS); + } + return rt; +} + +/* + * Takes the MHz channel value and sets the Channel value + * + * ASSUMES: Writes enabled to analog bus before AGC is active + * or by disabling the AGC. + */ +static HAL_BOOL +ar5211SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ + uint32_t refClk, reg32, data2111; + int16_t chan5111, chanIEEE; + + chanIEEE = chan->ic_ieee; + if (IEEE80211_IS_CHAN_2GHZ(chan)) { + const CHAN_INFO_2GHZ* ci = + &chan2GHzData[chanIEEE + CI_2GHZ_INDEX_CORRECTION]; + + data2111 = ((ath_hal_reverseBits(ci->channelSelect, 8) & 0xff) + << 5) + | (ci->refClkSel << 4); + chan5111 = ci->channel5111; + } else { + data2111 = 0; + chan5111 = chanIEEE; + } + + /* Rest of the code is common for 5 GHz and 2.4 GHz. */ + if (chan5111 >= 145 || (chan5111 & 0x1)) { + reg32 = ath_hal_reverseBits(chan5111 - 24, 8) & 0xFF; + refClk = 1; + } else { + reg32 = ath_hal_reverseBits(((chan5111 - 24) / 2), 8) & 0xFF; + refClk = 0; + } + + reg32 = (reg32 << 2) | (refClk << 1) | (1 << 10) | 0x1; + OS_REG_WRITE(ah, AR_PHY(0x27), ((data2111 & 0xff) << 8) | (reg32 & 0xff)); + reg32 >>= 8; + OS_REG_WRITE(ah, AR_PHY(0x34), (data2111 & 0xff00) | (reg32 & 0xff)); + + AH_PRIVATE(ah)->ah_curchan = chan; + return AH_TRUE; +} + +static int16_t +ar5211GetNoiseFloor(struct ath_hal *ah) +{ + int16_t nf; + + nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + return nf; +} + +/* + * Peform the noisefloor calibration for the length of time set + * in runTime (valid values 1 to 7) + * + * Returns: The NF value at the end of the given time (or 0 for failure) + */ +int16_t +ar5211RunNoiseFloor(struct ath_hal *ah, uint8_t runTime, int16_t startingNF) +{ + int i, searchTime; + + HALASSERT(runTime <= 7); + + /* Setup noise floor run time and starting value */ + OS_REG_WRITE(ah, AR_PHY(25), + (OS_REG_READ(ah, AR_PHY(25)) & ~0xFFF) | + ((runTime << 9) & 0xE00) | (startingNF & 0x1FF)); + /* Calibrate the noise floor */ + OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, + OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); + + /* Compute the required amount of searchTime needed to finish NF */ + if (runTime == 0) { + /* 8 search windows * 6.4us each */ + searchTime = 8 * 7; + } else { + /* 512 * runtime search windows * 6.4us each */ + searchTime = (runTime * 512) * 7; + } + + /* + * Do not read noise floor until it has been updated + * + * As a guesstimate - we may only get 1/60th the time on + * the air to see search windows in a heavily congested + * network (40 us every 2400 us of time) + */ + for (i = 0; i < 60; i++) { + if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) + break; + OS_DELAY(searchTime); + } + if (i >= 60) { + HALDEBUG(ah, HAL_DEBUG_NFCAL, + "NF with runTime %d failed to end on channel %d\n", + runTime, AH_PRIVATE(ah)->ah_curchan->ic_freq); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + " PHY NF Reg state: 0x%x\n", + OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); + HALDEBUG(ah, HAL_DEBUG_NFCAL, + " PHY Active Reg state: 0x%x\n", + OS_REG_READ(ah, AR_PHY_ACTIVE)); + return 0; + } + + return ar5211GetNoiseFloor(ah); +} + +static HAL_BOOL +getNoiseFloorThresh(struct ath_hal *ah, const struct ieee80211_channel *chan, + int16_t *nft) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + + switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) { + case IEEE80211_CHAN_A: + *nft = ee->ee_noiseFloorThresh[0]; + break; + case IEEE80211_CHAN_B: + *nft = ee->ee_noiseFloorThresh[1]; + break; + case IEEE80211_CHAN_PUREG: + *nft = ee->ee_noiseFloorThresh[2]; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->ic_flags); + return AH_FALSE; + } + return AH_TRUE; +} + +/* + * Read the NF and check it against the noise floor threshold + * + * Returns: TRUE if the NF is good + */ +static HAL_BOOL +ar5211IsNfGood(struct ath_hal *ah, struct ieee80211_channel *chan) +{ + HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); + int16_t nf, nfThresh; + + if (!getNoiseFloorThresh(ah, chan, &nfThresh)) + return AH_FALSE; + if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: NF did not complete in calibration window\n", __func__); + } + nf = ar5211GetNoiseFloor(ah); + if (nf > nfThresh) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: noise floor failed; detected %u, threshold %u\n", + __func__, nf, nfThresh); + /* + * NB: Don't discriminate 2.4 vs 5Ghz, if this + * happens it indicates a problem regardless + * of the band. + */ + chan->ic_state |= IEEE80211_CHANSTATE_CWINT; + } + ichan->rawNoiseFloor = nf; + return (nf <= nfThresh); +} + +/* + * Peform the noisefloor calibration and check for any constant channel + * interference. + * + * NOTE: preAR5211 have a lengthy carrier wave detection process - hence + * it is if'ed for MKK regulatory domain only. + * + * Returns: TRUE for a successful noise floor calibration; else FALSE + */ +HAL_BOOL +ar5211CalNoiseFloor(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ +#define N(a) (sizeof (a) / sizeof (a[0])) + /* Check for Carrier Wave interference in MKK regulatory zone */ + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU && + (chan->ic_flags & CHANNEL_NFCREQUIRED)) { + static const uint8_t runtime[3] = { 0, 2, 7 }; + HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); + int16_t nf, nfThresh; + int i; + + if (!getNoiseFloorThresh(ah, chan, &nfThresh)) + return AH_FALSE; + /* + * Run a quick noise floor that will hopefully + * complete (decrease delay time). + */ + for (i = 0; i < N(runtime); i++) { + nf = ar5211RunNoiseFloor(ah, runtime[i], 0); + if (nf > nfThresh) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: run failed with %u > threshold %u " + "(runtime %u)\n", __func__, + nf, nfThresh, runtime[i]); + ichan->rawNoiseFloor = 0; + } else + ichan->rawNoiseFloor = nf; + } + return (i <= N(runtime)); + } else { + /* Calibrate the noise floor */ + OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, + OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_NF); + } + return AH_TRUE; +#undef N +} + +/* + * Adjust NF based on statistical values for 5GHz frequencies. + */ +int16_t +ar5211GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) +{ + static const struct { + uint16_t freqLow; + int16_t adjust; + } adjust5111[] = { + { 5790, 11 }, /* NB: ordered high -> low */ + { 5730, 10 }, + { 5690, 9 }, + { 5660, 8 }, + { 5610, 7 }, + { 5530, 5 }, + { 5450, 4 }, + { 5379, 2 }, + { 5209, 0 }, /* XXX? bogus but doesn't matter */ + { 0, 1 }, + }; + int i; + + for (i = 0; c->channel <= adjust5111[i].freqLow; i++) + ; + /* NB: placeholder for 5111's less severe requirement */ + return adjust5111[i].adjust / 3; +} + +/* + * Reads EEPROM header info from device structure and programs + * analog registers 6 and 7 + * + * REQUIRES: Access to the analog device + */ +static HAL_BOOL +ar5211SetRf6and7(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ +#define N(a) (sizeof (a) / sizeof (a[0])) + uint16_t freq = ath_hal_gethwchannel(ah, chan); + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + struct ath_hal_5211 *ahp = AH5211(ah); + uint16_t rfXpdGain, rfPloSel, rfPwdXpd; + uint16_t tempOB, tempDB; + uint16_t freqIndex; + int i; + + freqIndex = IEEE80211_IS_CHAN_2GHZ(chan) ? 2 : 1; + + /* + * TODO: This array mode correspondes with the index used + * during the read. + * For readability, this should be changed to an enum or #define + */ + switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) { + case IEEE80211_CHAN_A: + if (freq > 4000 && freq < 5260) { + tempOB = ee->ee_ob1; + tempDB = ee->ee_db1; + } else if (freq >= 5260 && freq < 5500) { + tempOB = ee->ee_ob2; + tempDB = ee->ee_db2; + } else if (freq >= 5500 && freq < 5725) { + tempOB = ee->ee_ob3; + tempDB = ee->ee_db3; + } else if (freq >= 5725) { + tempOB = ee->ee_ob4; + tempDB = ee->ee_db4; + } else { + /* XXX panic?? */ + tempOB = tempDB = 0; + } + + rfXpdGain = ee->ee_xgain[0]; + rfPloSel = ee->ee_xpd[0]; + rfPwdXpd = !ee->ee_xpd[0]; + + ar5211Rf6n7[5][freqIndex] = + (ar5211Rf6n7[5][freqIndex] & ~0x10000000) | + (ee->ee_cornerCal.pd84<< 28); + ar5211Rf6n7[6][freqIndex] = + (ar5211Rf6n7[6][freqIndex] & ~0x04000000) | + (ee->ee_cornerCal.pd90 << 26); + ar5211Rf6n7[21][freqIndex] = + (ar5211Rf6n7[21][freqIndex] & ~0x08) | + (ee->ee_cornerCal.gSel << 3); + break; + case IEEE80211_CHAN_B: + tempOB = ee->ee_obFor24; + tempDB = ee->ee_dbFor24; + rfXpdGain = ee->ee_xgain[1]; + rfPloSel = ee->ee_xpd[1]; + rfPwdXpd = !ee->ee_xpd[1]; + break; + case IEEE80211_CHAN_PUREG: + tempOB = ee->ee_obFor24g; + tempDB = ee->ee_dbFor24g; + rfXpdGain = ee->ee_xgain[2]; + rfPloSel = ee->ee_xpd[2]; + rfPwdXpd = !ee->ee_xpd[2]; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->ic_flags); + return AH_FALSE; + } + + HALASSERT(1 <= tempOB && tempOB <= 5); + HALASSERT(1 <= tempDB && tempDB <= 5); + + /* Set rfXpdGain and rfPwdXpd */ + ar5211Rf6n7[11][freqIndex] = (ar5211Rf6n7[11][freqIndex] & ~0xC0) | + (((ath_hal_reverseBits(rfXpdGain, 4) << 7) | (rfPwdXpd << 6)) & 0xC0); + ar5211Rf6n7[12][freqIndex] = (ar5211Rf6n7[12][freqIndex] & ~0x07) | + ((ath_hal_reverseBits(rfXpdGain, 4) >> 1) & 0x07); + + /* Set OB */ + ar5211Rf6n7[12][freqIndex] = (ar5211Rf6n7[12][freqIndex] & ~0x80) | + ((ath_hal_reverseBits(tempOB, 3) << 7) & 0x80); + ar5211Rf6n7[13][freqIndex] = (ar5211Rf6n7[13][freqIndex] & ~0x03) | + ((ath_hal_reverseBits(tempOB, 3) >> 1) & 0x03); + + /* Set DB */ + ar5211Rf6n7[13][freqIndex] = (ar5211Rf6n7[13][freqIndex] & ~0x1C) | + ((ath_hal_reverseBits(tempDB, 3) << 2) & 0x1C); + + /* Set rfPloSel */ + ar5211Rf6n7[17][freqIndex] = (ar5211Rf6n7[17][freqIndex] & ~0x08) | + ((rfPloSel << 3) & 0x08); + + /* Write the Rf registers 6 & 7 */ + for (i = 0; i < N(ar5211Rf6n7); i++) + OS_REG_WRITE(ah, ar5211Rf6n7[i][0], ar5211Rf6n7[i][freqIndex]); + + /* Now that we have reprogrammed rfgain value, clear the flag. */ + ahp->ah_rfgainState = RFGAIN_INACTIVE; + + return AH_TRUE; +#undef N +} + +HAL_BOOL +ar5211SetAntennaSwitchInternal(struct ath_hal *ah, HAL_ANT_SETTING settings, + const struct ieee80211_channel *chan) +{ +#define ANT_SWITCH_TABLE1 0x9960 +#define ANT_SWITCH_TABLE2 0x9964 + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + struct ath_hal_5211 *ahp = AH5211(ah); + uint32_t antSwitchA, antSwitchB; + int ix; + + switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) { + case IEEE80211_CHAN_A: ix = 0; break; + case IEEE80211_CHAN_B: ix = 1; break; + case IEEE80211_CHAN_PUREG: ix = 2; break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->ic_flags); + return AH_FALSE; + } + + antSwitchA = ee->ee_antennaControl[1][ix] + | (ee->ee_antennaControl[2][ix] << 6) + | (ee->ee_antennaControl[3][ix] << 12) + | (ee->ee_antennaControl[4][ix] << 18) + | (ee->ee_antennaControl[5][ix] << 24) + ; + antSwitchB = ee->ee_antennaControl[6][ix] + | (ee->ee_antennaControl[7][ix] << 6) + | (ee->ee_antennaControl[8][ix] << 12) + | (ee->ee_antennaControl[9][ix] << 18) + | (ee->ee_antennaControl[10][ix] << 24) + ; + /* + * For fixed antenna, give the same setting for both switch banks + */ + switch (settings) { + case HAL_ANT_FIXED_A: + antSwitchB = antSwitchA; + break; + case HAL_ANT_FIXED_B: + antSwitchA = antSwitchB; + break; + case HAL_ANT_VARIABLE: + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad antenna setting %u\n", + __func__, settings); + return AH_FALSE; + } + ahp->ah_diversityControl = settings; + + OS_REG_WRITE(ah, ANT_SWITCH_TABLE1, antSwitchA); + OS_REG_WRITE(ah, ANT_SWITCH_TABLE2, antSwitchB); + + return AH_TRUE; +#undef ANT_SWITCH_TABLE1 +#undef ANT_SWITCH_TABLE2 +} + +/* + * Reads EEPROM header info and programs the device for correct operation + * given the channel value + */ +static HAL_BOOL +ar5211SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + struct ath_hal_5211 *ahp = AH5211(ah); + int arrayMode, falseDectectBackoff; + + switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) { + case IEEE80211_CHAN_A: + arrayMode = 0; + OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, + AR_PHY_FRAME_CTL_TX_CLIP, ee->ee_cornerCal.clip); + break; + case IEEE80211_CHAN_B: + arrayMode = 1; + break; + case IEEE80211_CHAN_PUREG: + arrayMode = 2; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->ic_flags); + return AH_FALSE; + } + + /* Set the antenna register(s) correctly for the chip revision */ + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { + OS_REG_WRITE(ah, AR_PHY(68), + (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) | 0x3); + } else { + OS_REG_WRITE(ah, AR_PHY(68), + (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFC06) | + (ee->ee_antennaControl[0][arrayMode] << 4) | 0x1); + + ar5211SetAntennaSwitchInternal(ah, + ahp->ah_diversityControl, chan); + + /* Set the Noise Floor Thresh on ar5211 devices */ + OS_REG_WRITE(ah, AR_PHY_BASE + (90 << 2), + (ee->ee_noiseFloorThresh[arrayMode] & 0x1FF) | (1<<9)); + } + OS_REG_WRITE(ah, AR_PHY_BASE + (17 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (17 << 2)) & 0xFFFFC07F) | + ((ee->ee_switchSettling[arrayMode] << 7) & 0x3F80)); + OS_REG_WRITE(ah, AR_PHY_BASE + (18 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (18 << 2)) & 0xFFFC0FFF) | + ((ee->ee_txrxAtten[arrayMode] << 12) & 0x3F000)); + OS_REG_WRITE(ah, AR_PHY_BASE + (20 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (20 << 2)) & 0xFFFF0000) | + ((ee->ee_pgaDesiredSize[arrayMode] << 8) & 0xFF00) | + (ee->ee_adcDesiredSize[arrayMode] & 0x00FF)); + OS_REG_WRITE(ah, AR_PHY_BASE + (13 << 2), + (ee->ee_txEndToXPAOff[arrayMode] << 24) | + (ee->ee_txEndToXPAOff[arrayMode] << 16) | + (ee->ee_txFrameToXPAOn[arrayMode] << 8) | + ee->ee_txFrameToXPAOn[arrayMode]); + OS_REG_WRITE(ah, AR_PHY_BASE + (10 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (10 << 2)) & 0xFFFF00FF) | + (ee->ee_txEndToXLNAOn[arrayMode] << 8)); + OS_REG_WRITE(ah, AR_PHY_BASE + (25 << 2), + (OS_REG_READ(ah, AR_PHY_BASE + (25 << 2)) & 0xFFF80FFF) | + ((ee->ee_thresh62[arrayMode] << 12) & 0x7F000)); + +#define NO_FALSE_DETECT_BACKOFF 2 +#define CB22_FALSE_DETECT_BACKOFF 6 + /* + * False detect backoff - suspected 32 MHz spur causes + * false detects in OFDM, causing Tx Hangs. Decrease + * weak signal sensitivity for this card. + */ + falseDectectBackoff = NO_FALSE_DETECT_BACKOFF; + if (AH_PRIVATE(ah)->ah_eeversion < AR_EEPROM_VER3_3) { + if (AH_PRIVATE(ah)->ah_subvendorid == 0x1022 && + IEEE80211_IS_CHAN_OFDM(chan)) + falseDectectBackoff += CB22_FALSE_DETECT_BACKOFF; + } else { + uint16_t freq = ath_hal_gethwchannel(ah, chan); + uint32_t remainder = freq % 32; + + if (remainder && (remainder < 10 || remainder > 22)) + falseDectectBackoff += ee->ee_falseDetectBackoff[arrayMode]; + } + OS_REG_WRITE(ah, 0x9924, + (OS_REG_READ(ah, 0x9924) & 0xFFFFFF01) + | ((falseDectectBackoff << 1) & 0xF7)); + + return AH_TRUE; +#undef NO_FALSE_DETECT_BACKOFF +#undef CB22_FALSE_DETECT_BACKOFF +} + +/* + * Set the limit on the overall output power. Used for dynamic + * transmit power control and the like. + * + * NOTE: The power is passed in is in units of 0.5 dBm. + */ +HAL_BOOL +ar5211SetTxPowerLimit(struct ath_hal *ah, uint32_t limit) +{ + + AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, limit); + return AH_TRUE; +} + +/* + * Sets the transmit power in the baseband for the given + * operating channel and mode. + */ +static HAL_BOOL +ar5211SetTransmitPower(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ + uint16_t freq = ath_hal_gethwchannel(ah, chan); + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + TRGT_POWER_INFO *pi; + RD_EDGES_POWER *rep; + PCDACS_EEPROM eepromPcdacs; + u_int nchan, cfgCtl; + int i; + + /* setup the pcdac struct to point to the correct info, based on mode */ + switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) { + case IEEE80211_CHAN_A: + eepromPcdacs.numChannels = ee->ee_numChannels11a; + eepromPcdacs.pChannelList= ee->ee_channels11a; + eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11a; + nchan = ee->ee_numTargetPwr_11a; + pi = ee->ee_trgtPwr_11a; + break; + case IEEE80211_CHAN_PUREG: + eepromPcdacs.numChannels = ee->ee_numChannels2_4; + eepromPcdacs.pChannelList= ee->ee_channels11g; + eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11g; + nchan = ee->ee_numTargetPwr_11g; + pi = ee->ee_trgtPwr_11g; + break; + case IEEE80211_CHAN_B: + eepromPcdacs.numChannels = ee->ee_numChannels2_4; + eepromPcdacs.pChannelList= ee->ee_channels11b; + eepromPcdacs.pDataPerChannel = ee->ee_dataPerChannel11b; + nchan = ee->ee_numTargetPwr_11b; + pi = ee->ee_trgtPwr_11b; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", + __func__, chan->ic_flags); + return AH_FALSE; + } + + ar5211SetPowerTable(ah, &eepromPcdacs, freq); + + rep = AH_NULL; + /* Match CTL to EEPROM value */ + cfgCtl = ath_hal_getctl(ah, chan); + for (i = 0; i < ee->ee_numCtls; i++) + if (ee->ee_ctl[i] != 0 && ee->ee_ctl[i] == cfgCtl) { + rep = &ee->ee_rdEdgesPower[i * NUM_EDGES]; + break; + } + ar5211SetRateTable(ah, rep, pi, nchan, chan); + + return AH_TRUE; +} + +/* + * Read the transmit power levels from the structures taken + * from EEPROM. Interpolate read transmit power values for + * this channel. Organize the transmit power values into a + * table for writing into the hardware. + */ +void +ar5211SetPowerTable(struct ath_hal *ah, PCDACS_EEPROM *pSrcStruct, + uint16_t channel) +{ + static FULL_PCDAC_STRUCT pcdacStruct; + static uint16_t pcdacTable[PWR_TABLE_SIZE]; + + uint16_t i, j; + uint16_t *pPcdacValues; + int16_t *pScaledUpDbm; + int16_t minScaledPwr; + int16_t maxScaledPwr; + int16_t pwr; + uint16_t pcdacMin = 0; + uint16_t pcdacMax = 63; + uint16_t pcdacTableIndex; + uint16_t scaledPcdac; + uint32_t addr; + uint32_t temp32; + + OS_MEMZERO(&pcdacStruct, sizeof(FULL_PCDAC_STRUCT)); + OS_MEMZERO(pcdacTable, sizeof(uint16_t) * PWR_TABLE_SIZE); + pPcdacValues = pcdacStruct.PcdacValues; + pScaledUpDbm = pcdacStruct.PwrValues; + + /* Initialize the pcdacs to dBM structs pcdacs to be 1 to 63 */ + for (i = PCDAC_START, j = 0; i <= PCDAC_STOP; i+= PCDAC_STEP, j++) + pPcdacValues[j] = i; + + pcdacStruct.numPcdacValues = j; + pcdacStruct.pcdacMin = PCDAC_START; + pcdacStruct.pcdacMax = PCDAC_STOP; + + /* Fill out the power values for this channel */ + for (j = 0; j < pcdacStruct.numPcdacValues; j++ ) + pScaledUpDbm[j] = ar5211GetScaledPower(channel, pPcdacValues[j], pSrcStruct); + + /* Now scale the pcdac values to fit in the 64 entry power table */ + minScaledPwr = pScaledUpDbm[0]; + maxScaledPwr = pScaledUpDbm[pcdacStruct.numPcdacValues - 1]; + + /* find minimum and make monotonic */ + for (j = 0; j < pcdacStruct.numPcdacValues; j++) { + if (minScaledPwr >= pScaledUpDbm[j]) { + minScaledPwr = pScaledUpDbm[j]; + pcdacMin = j; + } + /* + * Make the full_hsh monotonically increasing otherwise + * interpolation algorithm will get fooled gotta start + * working from the top, hence i = 63 - j. + */ + i = (uint16_t)(pcdacStruct.numPcdacValues - 1 - j); + if (i == 0) + break; + if (pScaledUpDbm[i-1] > pScaledUpDbm[i]) { + /* + * It could be a glitch, so make the power for + * this pcdac the same as the power from the + * next highest pcdac. + */ + pScaledUpDbm[i - 1] = pScaledUpDbm[i]; + } + } + + for (j = 0; j < pcdacStruct.numPcdacValues; j++) + if (maxScaledPwr < pScaledUpDbm[j]) { + maxScaledPwr = pScaledUpDbm[j]; + pcdacMax = j; + } + + /* Find the first power level with a pcdac */ + pwr = (uint16_t)(PWR_STEP * ((minScaledPwr - PWR_MIN + PWR_STEP / 2) / PWR_STEP) + PWR_MIN); + + /* Write all the first pcdac entries based off the pcdacMin */ + pcdacTableIndex = 0; + for (i = 0; i < (2 * (pwr - PWR_MIN) / EEP_SCALE + 1); i++) + pcdacTable[pcdacTableIndex++] = pcdacMin; + + i = 0; + while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1]) { + pwr += PWR_STEP; + /* stop if dbM > max_power_possible */ + while (pwr < pScaledUpDbm[pcdacStruct.numPcdacValues - 1] && + (pwr - pScaledUpDbm[i])*(pwr - pScaledUpDbm[i+1]) > 0) + i++; + /* scale by 2 and add 1 to enable round up or down as needed */ + scaledPcdac = (uint16_t)(ar5211GetInterpolatedValue(pwr, + pScaledUpDbm[i], pScaledUpDbm[i+1], + (uint16_t)(pPcdacValues[i] * 2), + (uint16_t)(pPcdacValues[i+1] * 2), 0) + 1); + + pcdacTable[pcdacTableIndex] = scaledPcdac / 2; + if (pcdacTable[pcdacTableIndex] > pcdacMax) + pcdacTable[pcdacTableIndex] = pcdacMax; + pcdacTableIndex++; + } + + /* Write all the last pcdac entries based off the last valid pcdac */ + while (pcdacTableIndex < PWR_TABLE_SIZE) { + pcdacTable[pcdacTableIndex] = pcdacTable[pcdacTableIndex - 1]; + pcdacTableIndex++; + } + + /* Finally, write the power values into the baseband power table */ + addr = AR_PHY_BASE + (608 << 2); + for (i = 0; i < 32; i++) { + temp32 = 0xffff & ((pcdacTable[2 * i + 1] << 8) | 0xff); + temp32 = (temp32 << 16) | (0xffff & ((pcdacTable[2 * i] << 8) | 0xff)); + OS_REG_WRITE(ah, addr, temp32); + addr += 4; + } + +} + +/* + * Set the transmit power in the baseband for the given + * operating channel and mode. + */ +static void +ar5211SetRateTable(struct ath_hal *ah, RD_EDGES_POWER *pRdEdgesPower, + TRGT_POWER_INFO *pPowerInfo, uint16_t numChannels, + const struct ieee80211_channel *chan) +{ + uint16_t freq = ath_hal_gethwchannel(ah, chan); + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + struct ath_hal_5211 *ahp = AH5211(ah); + static uint16_t ratesArray[NUM_RATES]; + static const uint16_t tpcScaleReductionTable[5] = + { 0, 3, 6, 9, MAX_RATE_POWER }; + + uint16_t *pRatesPower; + uint16_t lowerChannel, lowerIndex=0, lowerPower=0; + uint16_t upperChannel, upperIndex=0, upperPower=0; + uint16_t twiceMaxEdgePower=63; + uint16_t twicePower = 0; + uint16_t i, numEdges; + uint16_t tempChannelList[NUM_EDGES]; /* temp array for holding edge channels */ + uint16_t twiceMaxRDPower; + int16_t scaledPower = 0; /* for gcc -O2 */ + uint16_t mask = 0x3f; + HAL_BOOL paPreDEnable = 0; + int8_t twiceAntennaGain, twiceAntennaReduction = 0; + + pRatesPower = ratesArray; + twiceMaxRDPower = chan->ic_maxregpower * 2; + + if (IEEE80211_IS_CHAN_5GHZ(chan)) { + twiceAntennaGain = ee->ee_antennaGainMax[0]; + } else { + twiceAntennaGain = ee->ee_antennaGainMax[1]; + } + + twiceAntennaReduction = ath_hal_getantennareduction(ah, chan, twiceAntennaGain); + + if (pRdEdgesPower) { + /* Get the edge power */ + for (i = 0; i < NUM_EDGES; i++) { + if (pRdEdgesPower[i].rdEdge == 0) + break; + tempChannelList[i] = pRdEdgesPower[i].rdEdge; + } + numEdges = i; + + ar5211GetLowerUpperValues(freq, tempChannelList, + numEdges, &lowerChannel, &upperChannel); + /* Get the index for this channel */ + for (i = 0; i < numEdges; i++) + if (lowerChannel == tempChannelList[i]) + break; + HALASSERT(i != numEdges); + + if ((lowerChannel == upperChannel && + lowerChannel == freq) || + pRdEdgesPower[i].flag) { + twiceMaxEdgePower = pRdEdgesPower[i].twice_rdEdgePower; + HALASSERT(twiceMaxEdgePower > 0); + } + } + + /* extrapolate the power values for the test Groups */ + for (i = 0; i < numChannels; i++) + tempChannelList[i] = pPowerInfo[i].testChannel; + + ar5211GetLowerUpperValues(freq, tempChannelList, + numChannels, &lowerChannel, &upperChannel); + + /* get the index for the channel */ + for (i = 0; i < numChannels; i++) { + if (lowerChannel == tempChannelList[i]) + lowerIndex = i; + if (upperChannel == tempChannelList[i]) { + upperIndex = i; + break; + } + } + + for (i = 0; i < NUM_RATES; i++) { + if (IEEE80211_IS_CHAN_OFDM(chan)) { + /* power for rates 6,9,12,18,24 is all the same */ + if (i < 5) { + lowerPower = pPowerInfo[lowerIndex].twicePwr6_24; + upperPower = pPowerInfo[upperIndex].twicePwr6_24; + } else if (i == 5) { + lowerPower = pPowerInfo[lowerIndex].twicePwr36; + upperPower = pPowerInfo[upperIndex].twicePwr36; + } else if (i == 6) { + lowerPower = pPowerInfo[lowerIndex].twicePwr48; + upperPower = pPowerInfo[upperIndex].twicePwr48; + } else if (i == 7) { + lowerPower = pPowerInfo[lowerIndex].twicePwr54; + upperPower = pPowerInfo[upperIndex].twicePwr54; + } + } else { + switch (i) { + case 0: + case 1: + lowerPower = pPowerInfo[lowerIndex].twicePwr6_24; + upperPower = pPowerInfo[upperIndex].twicePwr6_24; + break; + case 2: + case 3: + lowerPower = pPowerInfo[lowerIndex].twicePwr36; + upperPower = pPowerInfo[upperIndex].twicePwr36; + break; + case 4: + case 5: + lowerPower = pPowerInfo[lowerIndex].twicePwr48; + upperPower = pPowerInfo[upperIndex].twicePwr48; + break; + case 6: + case 7: + lowerPower = pPowerInfo[lowerIndex].twicePwr54; + upperPower = pPowerInfo[upperIndex].twicePwr54; + break; + } + } + + twicePower = ar5211GetInterpolatedValue(freq, + lowerChannel, upperChannel, lowerPower, upperPower, 0); + + /* Reduce power by band edge restrictions */ + twicePower = AH_MIN(twicePower, twiceMaxEdgePower); + + /* + * If turbo is set, reduce power to keep power + * consumption under 2 Watts. Note that we always do + * this unless specially configured. Then we limit + * power only for non-AP operation. + */ + if (IEEE80211_IS_CHAN_TURBO(chan) && + AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1 +#ifdef AH_ENABLE_AP_SUPPORT + && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP +#endif + ) { + twicePower = AH_MIN(twicePower, ee->ee_turbo2WMaxPower5); + } + + /* Reduce power by max regulatory domain allowed restrictions */ + pRatesPower[i] = AH_MIN(twicePower, twiceMaxRDPower - twiceAntennaReduction); + + /* Use 6 Mb power level for transmit power scaling reduction */ + /* We don't want to reduce higher rates if its not needed */ + if (i == 0) { + scaledPower = pRatesPower[0] - + (tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2); + if (scaledPower < 1) + scaledPower = 1; + } + + pRatesPower[i] = AH_MIN(pRatesPower[i], scaledPower); + } + + /* Record txPower at Rate 6 for info gathering */ + ahp->ah_tx6PowerInHalfDbm = pRatesPower[0]; + +#ifdef AH_DEBUG + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s: final output power setting %d MHz:\n", + __func__, chan->ic_freq); + HALDEBUG(ah, HAL_DEBUG_RESET, + "6 Mb %d dBm, MaxRD: %d dBm, MaxEdge %d dBm\n", + scaledPower / 2, twiceMaxRDPower / 2, twiceMaxEdgePower / 2); + HALDEBUG(ah, HAL_DEBUG_RESET, "TPC Scale %d dBm - Ant Red %d dBm\n", + tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale] * 2, + twiceAntennaReduction / 2); + if (IEEE80211_IS_CHAN_TURBO(chan) && + AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER3_1) + HALDEBUG(ah, HAL_DEBUG_RESET, "Max Turbo %d dBm\n", + ee->ee_turbo2WMaxPower5); + HALDEBUG(ah, HAL_DEBUG_RESET, + " %2d | %2d | %2d | %2d | %2d | %2d | %2d | %2d dBm\n", + pRatesPower[0] / 2, pRatesPower[1] / 2, pRatesPower[2] / 2, + pRatesPower[3] / 2, pRatesPower[4] / 2, pRatesPower[5] / 2, + pRatesPower[6] / 2, pRatesPower[7] / 2); +#endif /* AH_DEBUG */ + + /* Write the power table into the hardware */ + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ((paPreDEnable & 1)<< 30) | ((pRatesPower[3] & mask) << 24) | + ((paPreDEnable & 1)<< 22) | ((pRatesPower[2] & mask) << 16) | + ((paPreDEnable & 1)<< 14) | ((pRatesPower[1] & mask) << 8) | + ((paPreDEnable & 1)<< 6 ) | (pRatesPower[0] & mask)); + OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ((paPreDEnable & 1)<< 30) | ((pRatesPower[7] & mask) << 24) | + ((paPreDEnable & 1)<< 22) | ((pRatesPower[6] & mask) << 16) | + ((paPreDEnable & 1)<< 14) | ((pRatesPower[5] & mask) << 8) | + ((paPreDEnable & 1)<< 6 ) | (pRatesPower[4] & mask)); + + /* set max power to the power value at rate 6 */ + ar5211SetTxPowerLimit(ah, pRatesPower[0]); + + AH_PRIVATE(ah)->ah_maxPowerLevel = pRatesPower[0]; +} + +/* + * Get or interpolate the pcdac value from the calibrated data + */ +uint16_t +ar5211GetScaledPower(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct) +{ + uint16_t powerValue; + uint16_t lFreq, rFreq; /* left and right frequency values */ + uint16_t llPcdac, ulPcdac; /* lower and upper left pcdac values */ + uint16_t lrPcdac, urPcdac; /* lower and upper right pcdac values */ + uint16_t lPwr, uPwr; /* lower and upper temp pwr values */ + uint16_t lScaledPwr, rScaledPwr; /* left and right scaled power */ + + if (ar5211FindValueInList(channel, pcdacValue, pSrcStruct, &powerValue)) + /* value was copied from srcStruct */ + return powerValue; + + ar5211GetLowerUpperValues(channel, pSrcStruct->pChannelList, + pSrcStruct->numChannels, &lFreq, &rFreq); + ar5211GetLowerUpperPcdacs(pcdacValue, lFreq, pSrcStruct, + &llPcdac, &ulPcdac); + ar5211GetLowerUpperPcdacs(pcdacValue, rFreq, pSrcStruct, + &lrPcdac, &urPcdac); + + /* get the power index for the pcdac value */ + ar5211FindValueInList(lFreq, llPcdac, pSrcStruct, &lPwr); + ar5211FindValueInList(lFreq, ulPcdac, pSrcStruct, &uPwr); + lScaledPwr = ar5211GetInterpolatedValue(pcdacValue, + llPcdac, ulPcdac, lPwr, uPwr, 0); + + ar5211FindValueInList(rFreq, lrPcdac, pSrcStruct, &lPwr); + ar5211FindValueInList(rFreq, urPcdac, pSrcStruct, &uPwr); + rScaledPwr = ar5211GetInterpolatedValue(pcdacValue, + lrPcdac, urPcdac, lPwr, uPwr, 0); + + return ar5211GetInterpolatedValue(channel, lFreq, rFreq, + lScaledPwr, rScaledPwr, 0); +} + +/* + * Find the value from the calibrated source data struct + */ +HAL_BOOL +ar5211FindValueInList(uint16_t channel, uint16_t pcdacValue, + const PCDACS_EEPROM *pSrcStruct, uint16_t *powerValue) +{ + const DATA_PER_CHANNEL *pChannelData; + const uint16_t *pPcdac; + uint16_t i, j; + + pChannelData = pSrcStruct->pDataPerChannel; + for (i = 0; i < pSrcStruct->numChannels; i++ ) { + if (pChannelData->channelValue == channel) { + pPcdac = pChannelData->PcdacValues; + for (j = 0; j < pChannelData->numPcdacValues; j++ ) { + if (*pPcdac == pcdacValue) { + *powerValue = pChannelData->PwrValues[j]; + return AH_TRUE; + } + pPcdac++; + } + } + pChannelData++; + } + return AH_FALSE; +} + +/* + * Returns interpolated or the scaled up interpolated value + */ +uint16_t +ar5211GetInterpolatedValue(uint16_t target, + uint16_t srcLeft, uint16_t srcRight, + uint16_t targetLeft, uint16_t targetRight, + HAL_BOOL scaleUp) +{ + uint16_t rv; + int16_t lRatio; + uint16_t scaleValue = EEP_SCALE; + + /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */ + if ((targetLeft * targetRight) == 0) + return 0; + if (scaleUp) + scaleValue = 1; + + if (srcRight != srcLeft) { + /* + * Note the ratio always need to be scaled, + * since it will be a fraction. + */ + lRatio = (target - srcLeft) * EEP_SCALE / (srcRight - srcLeft); + if (lRatio < 0) { + /* Return as Left target if value would be negative */ + rv = targetLeft * (scaleUp ? EEP_SCALE : 1); + } else if (lRatio > EEP_SCALE) { + /* Return as Right target if Ratio is greater than 100% (SCALE) */ + rv = targetRight * (scaleUp ? EEP_SCALE : 1); + } else { + rv = (lRatio * targetRight + (EEP_SCALE - lRatio) * + targetLeft) / scaleValue; + } + } else { + rv = targetLeft; + if (scaleUp) + rv *= EEP_SCALE; + } + return rv; +} + +/* + * Look for value being within 0.1 of the search values + * however, NDIS can't do float calculations, so multiply everything + * up by EEP_SCALE so can do integer arithmatic + * + * INPUT value -value to search for + * INPUT pList -ptr to the list to search + * INPUT listSize -number of entries in list + * OUTPUT pLowerValue -return the lower value + * OUTPUT pUpperValue -return the upper value + */ +void +ar5211GetLowerUpperValues(uint16_t value, + const uint16_t *pList, uint16_t listSize, + uint16_t *pLowerValue, uint16_t *pUpperValue) +{ + const uint16_t listEndValue = *(pList + listSize - 1); + uint32_t target = value * EEP_SCALE; + int i; + + /* + * See if value is lower than the first value in the list + * if so return first value + */ + if (target < (uint32_t)(*pList * EEP_SCALE - EEP_DELTA)) { + *pLowerValue = *pList; + *pUpperValue = *pList; + return; + } + + /* + * See if value is greater than last value in list + * if so return last value + */ + if (target > (uint32_t)(listEndValue * EEP_SCALE + EEP_DELTA)) { + *pLowerValue = listEndValue; + *pUpperValue = listEndValue; + return; + } + + /* look for value being near or between 2 values in list */ + for (i = 0; i < listSize; i++) { + /* + * If value is close to the current value of the list + * then target is not between values, it is one of the values + */ + if (abs(pList[i] * EEP_SCALE - (int32_t) target) < EEP_DELTA) { + *pLowerValue = pList[i]; + *pUpperValue = pList[i]; + return; + } + + /* + * Look for value being between current value and next value + * if so return these 2 values + */ + if (target < (uint32_t)(pList[i + 1] * EEP_SCALE - EEP_DELTA)) { + *pLowerValue = pList[i]; + *pUpperValue = pList[i + 1]; + return; + } + } +} + +/* + * Get the upper and lower pcdac given the channel and the pcdac + * used in the search + */ +void +ar5211GetLowerUpperPcdacs(uint16_t pcdac, uint16_t channel, + const PCDACS_EEPROM *pSrcStruct, + uint16_t *pLowerPcdac, uint16_t *pUpperPcdac) +{ + const DATA_PER_CHANNEL *pChannelData; + int i; + + /* Find the channel information */ + pChannelData = pSrcStruct->pDataPerChannel; + for (i = 0; i < pSrcStruct->numChannels; i++) { + if (pChannelData->channelValue == channel) + break; + pChannelData++; + } + ar5211GetLowerUpperValues(pcdac, pChannelData->PcdacValues, + pChannelData->numPcdacValues, pLowerPcdac, pUpperPcdac); +} + +#define DYN_ADJ_UP_MARGIN 15 +#define DYN_ADJ_LO_MARGIN 20 + +static const GAIN_OPTIMIZATION_LADDER gainLadder = { + 9, /* numStepsInLadder */ + 4, /* defaultStepNum */ + { { {4, 1, 1, 1}, 6, "FG8"}, + { {4, 0, 1, 1}, 4, "FG7"}, + { {3, 1, 1, 1}, 3, "FG6"}, + { {4, 0, 0, 1}, 1, "FG5"}, + { {4, 1, 1, 0}, 0, "FG4"}, /* noJack */ + { {4, 0, 1, 0}, -2, "FG3"}, /* halfJack */ + { {3, 1, 1, 0}, -3, "FG2"}, /* clip3 */ + { {4, 0, 0, 0}, -4, "FG1"}, /* noJack */ + { {2, 1, 1, 0}, -6, "FG0"} /* clip2 */ + } +}; + +/* + * Initialize the gain structure to good values + */ +void +ar5211InitializeGainValues(struct ath_hal *ah) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + GAIN_VALUES *gv = &ahp->ah_gainValues; + + /* initialize gain optimization values */ + gv->currStepNum = gainLadder.defaultStepNum; + gv->currStep = &gainLadder.optStep[gainLadder.defaultStepNum]; + gv->active = AH_TRUE; + gv->loTrig = 20; + gv->hiTrig = 35; +} + +static HAL_BOOL +ar5211InvalidGainReadback(struct ath_hal *ah, GAIN_VALUES *gv) +{ + const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; + uint32_t gStep, g; + uint32_t L1, L2, L3, L4; + + if (IEEE80211_IS_CHAN_CCK(chan)) { + gStep = 0x18; + L1 = 0; + L2 = gStep + 4; + L3 = 0x40; + L4 = L3 + 50; + + gv->loTrig = L1; + gv->hiTrig = L4+5; + } else { + gStep = 0x3f; + L1 = 0; + L2 = 50; + L3 = L1; + L4 = L3 + 50; + + gv->loTrig = L1 + DYN_ADJ_LO_MARGIN; + gv->hiTrig = L4 - DYN_ADJ_UP_MARGIN; + } + g = gv->currGain; + + return !((g >= L1 && g<= L2) || (g >= L3 && g <= L4)); +} + +/* + * Enable the probe gain check on the next packet + */ +static void +ar5211RequestRfgain(struct ath_hal *ah) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + /* Enable the gain readback probe */ + OS_REG_WRITE(ah, AR_PHY_PAPD_PROBE, + SM(ahp->ah_tx6PowerInHalfDbm, AR_PHY_PAPD_PROBE_POWERTX) + | AR_PHY_PAPD_PROBE_NEXT_TX); + + ahp->ah_rfgainState = HAL_RFGAIN_READ_REQUESTED; +} + +/* + * Exported call to check for a recent gain reading and return + * the current state of the thermal calibration gain engine. + */ +HAL_RFGAIN +ar5211GetRfgain(struct ath_hal *ah) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + GAIN_VALUES *gv = &ahp->ah_gainValues; + uint32_t rddata; + + if (!gv->active) + return HAL_RFGAIN_INACTIVE; + + if (ahp->ah_rfgainState == HAL_RFGAIN_READ_REQUESTED) { + /* Caller had asked to setup a new reading. Check it. */ + rddata = OS_REG_READ(ah, AR_PHY_PAPD_PROBE); + + if ((rddata & AR_PHY_PAPD_PROBE_NEXT_TX) == 0) { + /* bit got cleared, we have a new reading. */ + gv->currGain = rddata >> AR_PHY_PAPD_PROBE_GAINF_S; + /* inactive by default */ + ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; + + if (!ar5211InvalidGainReadback(ah, gv) && + ar5211IsGainAdjustNeeded(ah, gv) && + ar5211AdjustGain(ah, gv) > 0) { + /* + * Change needed. Copy ladder info + * into eeprom info. + */ + ar5211SetRfgain(ah, gv); + ahp->ah_rfgainState = HAL_RFGAIN_NEED_CHANGE; + } + } + } + return ahp->ah_rfgainState; +} + +/* + * Check to see if our readback gain level sits within the linear + * region of our current variable attenuation window + */ +static HAL_BOOL +ar5211IsGainAdjustNeeded(struct ath_hal *ah, const GAIN_VALUES *gv) +{ + return (gv->currGain <= gv->loTrig || gv->currGain >= gv->hiTrig); +} + +/* + * Move the rabbit ears in the correct direction. + */ +static int32_t +ar5211AdjustGain(struct ath_hal *ah, GAIN_VALUES *gv) +{ + /* return > 0 for valid adjustments. */ + if (!gv->active) + return -1; + + gv->currStep = &gainLadder.optStep[gv->currStepNum]; + if (gv->currGain >= gv->hiTrig) { + if (gv->currStepNum == 0) { + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Max gain limit.\n", __func__); + return -1; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Adding gain: currG=%d [%s] --> ", + __func__, gv->currGain, gv->currStep->stepName); + gv->targetGain = gv->currGain; + while (gv->targetGain >= gv->hiTrig && gv->currStepNum > 0) { + gv->targetGain -= 2 * (gainLadder.optStep[--(gv->currStepNum)].stepGain - + gv->currStep->stepGain); + gv->currStep = &gainLadder.optStep[gv->currStepNum]; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n", + gv->targetGain, gv->currStep->stepName); + return 1; + } + if (gv->currGain <= gv->loTrig) { + if (gv->currStepNum == gainLadder.numStepsInLadder-1) { + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Min gain limit.\n", __func__); + return -2; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, + "%s: Deducting gain: currG=%d [%s] --> ", + __func__, gv->currGain, gv->currStep->stepName); + gv->targetGain = gv->currGain; + while (gv->targetGain <= gv->loTrig && + gv->currStepNum < (gainLadder.numStepsInLadder - 1)) { + gv->targetGain -= 2 * + (gainLadder.optStep[++(gv->currStepNum)].stepGain - gv->currStep->stepGain); + gv->currStep = &gainLadder.optStep[gv->currStepNum]; + } + HALDEBUG(ah, HAL_DEBUG_RFPARAM, "targG=%d [%s]\n", + gv->targetGain, gv->currStep->stepName); + return 2; + } + return 0; /* caller didn't call needAdjGain first */ +} + +/* + * Adjust the 5GHz EEPROM information with the desired calibration values. + */ +static void +ar5211SetRfgain(struct ath_hal *ah, const GAIN_VALUES *gv) +{ + HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; + + if (!gv->active) + return; + ee->ee_cornerCal.clip = gv->currStep->paramVal[0]; /* bb_tx_clip */ + ee->ee_cornerCal.pd90 = gv->currStep->paramVal[1]; /* rf_pwd_90 */ + ee->ee_cornerCal.pd84 = gv->currStep->paramVal[2]; /* rf_pwd_84 */ + ee->ee_cornerCal.gSel = gv->currStep->paramVal[3]; /* rf_rfgainsel */ +} + +static void +ar5211SetOperatingMode(struct ath_hal *ah, int opmode) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + uint32_t val; + + val = OS_REG_READ(ah, AR_STA_ID1) & 0xffff; + switch (opmode) { + case HAL_M_HOSTAP: + OS_REG_WRITE(ah, AR_STA_ID1, val + | AR_STA_ID1_STA_AP + | AR_STA_ID1_RTS_USE_DEF + | ahp->ah_staId1Defaults); + break; + case HAL_M_IBSS: + OS_REG_WRITE(ah, AR_STA_ID1, val + | AR_STA_ID1_ADHOC + | AR_STA_ID1_DESC_ANTENNA + | ahp->ah_staId1Defaults); + break; + case HAL_M_STA: + case HAL_M_MONITOR: + OS_REG_WRITE(ah, AR_STA_ID1, val + | AR_STA_ID1_DEFAULT_ANTENNA + | ahp->ah_staId1Defaults); + break; + } +} + +void +ar5211SetPCUConfig(struct ath_hal *ah) +{ + ar5211SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); +} diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c new file mode 100644 index 000000000000..b2ad8fcb9f4b --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c @@ -0,0 +1,699 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_desc.h" + +#include "ar5211/ar5211.h" +#include "ar5211/ar5211reg.h" +#include "ar5211/ar5211desc.h" + +/* + * Update Tx FIFO trigger level. + * + * Set bIncTrigLevel to TRUE to increase the trigger level. + * Set bIncTrigLevel to FALSE to decrease the trigger level. + * + * Returns TRUE if the trigger level was updated + */ +HAL_BOOL +ar5211UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel) +{ + uint32_t curTrigLevel, txcfg; + HAL_INT ints = ar5211GetInterrupts(ah); + + /* + * Disable chip interrupts. This is because halUpdateTxTrigLevel + * is called from both ISR and non-ISR contexts. + */ + ar5211SetInterrupts(ah, ints &~ HAL_INT_GLOBAL); + txcfg = OS_REG_READ(ah, AR_TXCFG); + curTrigLevel = (txcfg & AR_TXCFG_FTRIG_M) >> AR_TXCFG_FTRIG_S; + if (bIncTrigLevel){ + /* increase the trigger level */ + curTrigLevel = curTrigLevel + + ((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2); + } else { + /* decrease the trigger level if not already at the minimum */ + if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) { + /* decrease the trigger level */ + curTrigLevel--; + } else { + /* no update to the trigger level */ + /* re-enable chip interrupts */ + ar5211SetInterrupts(ah, ints); + return AH_FALSE; + } + } + /* Update the trigger level */ + OS_REG_WRITE(ah, AR_TXCFG, (txcfg &~ AR_TXCFG_FTRIG_M) | + ((curTrigLevel << AR_TXCFG_FTRIG_S) & AR_TXCFG_FTRIG_M)); + /* re-enable chip interrupts */ + ar5211SetInterrupts(ah, ints); + return AH_TRUE; +} + +/* + * Set the properties of the tx queue with the parameters + * from qInfo. The queue must previously have been setup + * with a call to ar5211SetupTxQueue. + */ +HAL_BOOL +ar5211SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (q >= HAL_NUM_TX_QUEUES) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo); +} + +/* + * Return the properties for the specified tx queue. + */ +HAL_BOOL +ar5211GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + if (q >= HAL_NUM_TX_QUEUES) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]); +} + +/* + * Allocate and initialize a tx DCU/QCU combination. + */ +int +ar5211SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, + const HAL_TXQ_INFO *qInfo) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + HAL_TX_QUEUE_INFO *qi; + int q; + + switch (type) { + case HAL_TX_QUEUE_BEACON: + q = 9; + break; + case HAL_TX_QUEUE_CAB: + q = 8; + break; + case HAL_TX_QUEUE_DATA: + q = 0; + if (ahp->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE) + return q; + break; + default: + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n", + __func__, type); + return -1; + } + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n", + __func__, q); + return -1; + } + OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO)); + qi->tqi_type = type; + if (qInfo == AH_NULL) { + /* by default enable OK+ERR+DESC+URN interrupts */ + qi->tqi_qflags = + HAL_TXQ_TXOKINT_ENABLE + | HAL_TXQ_TXERRINT_ENABLE + | HAL_TXQ_TXDESCINT_ENABLE + | HAL_TXQ_TXURNINT_ENABLE + ; + qi->tqi_aifs = INIT_AIFS; + qi->tqi_cwmin = HAL_TXQ_USEDEFAULT; /* NB: do at reset */ + qi->tqi_cwmax = INIT_CWMAX; + qi->tqi_shretry = INIT_SH_RETRY; + qi->tqi_lgretry = INIT_LG_RETRY; + } else + (void) ar5211SetTxQueueProps(ah, q, qInfo); + return q; +} + +/* + * Update the h/w interrupt registers to reflect a tx q's configuration. + */ +static void +setTxQInterrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, + "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", __func__ + , ahp->ah_txOkInterruptMask + , ahp->ah_txErrInterruptMask + , ahp->ah_txDescInterruptMask + , ahp->ah_txEolInterruptMask + , ahp->ah_txUrnInterruptMask + ); + + OS_REG_WRITE(ah, AR_IMR_S0, + SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) + | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC) + ); + OS_REG_WRITE(ah, AR_IMR_S1, + SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) + | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL) + ); + OS_REG_RMW_FIELD(ah, AR_IMR_S2, + AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); +} + +/* + * Free a tx DCU/QCU combination. + */ +HAL_BOOL +ar5211ReleaseTxQueue(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + HAL_TX_QUEUE_INFO *qi; + + if (q >= HAL_NUM_TX_QUEUES) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", + __func__, q); + return AH_FALSE; + } + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q); + + qi->tqi_type = HAL_TX_QUEUE_INACTIVE; + ahp->ah_txOkInterruptMask &= ~(1 << q); + ahp->ah_txErrInterruptMask &= ~(1 << q); + ahp->ah_txDescInterruptMask &= ~(1 << q); + ahp->ah_txEolInterruptMask &= ~(1 << q); + ahp->ah_txUrnInterruptMask &= ~(1 << q); + setTxQInterrupts(ah, qi); + + return AH_TRUE; +} + +/* + * Set the retry, aifs, cwmin/max, readyTime regs for specified queue + */ +HAL_BOOL +ar5211ResetTxQueue(struct ath_hal *ah, u_int q) +{ + struct ath_hal_5211 *ahp = AH5211(ah); + const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; + HAL_TX_QUEUE_INFO *qi; + uint32_t cwMin, chanCwMin, value; + + if (q >= HAL_NUM_TX_QUEUES) { + HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", + __func__, q); + return AH_FALSE; + } + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", + __func__, q); + return AH_TRUE; /* XXX??? */ + } + + if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) { + /* + * Select cwmin according to channel type. + * NB: chan can be NULL during attach + */ + if (chan && IEEE80211_IS_CHAN_B(chan)) + chanCwMin = INIT_CWMIN_11B; + else + chanCwMin = INIT_CWMIN; + /* make sure that the CWmin is of the form (2^n - 1) */ + for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1) + ; + } else + cwMin = qi->tqi_cwmin; + + /* set cwMin/Max and AIFS values */ + OS_REG_WRITE(ah, AR_DLCL_IFS(q), + SM(cwMin, AR_D_LCL_IFS_CWMIN) + | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) + | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); + + /* Set retry limit values */ + OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q), + SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) + | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) + | SM(qi->tqi_lgretry, AR_D_RETRY_LIMIT_FR_LG) + | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH) + ); + + /* enable early termination on the QCU */ + OS_REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); + + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { + /* Configure DCU to use the global sequence count */ + OS_REG_WRITE(ah, AR_DMISC(q), AR5311_D_MISC_SEQ_NUM_CONTROL); + } + /* multiqueue support */ + if (qi->tqi_cbrPeriod) { + OS_REG_WRITE(ah, AR_QCBRCFG(q), + SM(qi->tqi_cbrPeriod,AR_Q_CBRCFG_CBR_INTERVAL) + | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_CBR_OVF_THRESH)); + OS_REG_WRITE(ah, AR_QMISC(q), + OS_REG_READ(ah, AR_QMISC(q)) | + AR_Q_MISC_FSP_CBR | + (qi->tqi_cbrOverflowLimit ? + AR_Q_MISC_CBR_EXP_CNTR_LIMIT : 0)); + } + if (qi->tqi_readyTime) { + OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), + SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) | + AR_Q_RDYTIMECFG_EN); + } + if (qi->tqi_burstTime) { + OS_REG_WRITE(ah, AR_DCHNTIME(q), + SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | + AR_D_CHNTIME_EN); + if (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE) { + OS_REG_WRITE(ah, AR_QMISC(q), + OS_REG_READ(ah, AR_QMISC(q)) | + AR_Q_MISC_RDYTIME_EXP_POLICY); + } + } + + if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE) { + OS_REG_WRITE(ah, AR_DMISC(q), + OS_REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE) { + OS_REG_WRITE(ah, AR_DMISC(q), + OS_REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_FRAG_BKOFF_EN); + } + switch (qi->tqi_type) { + case HAL_TX_QUEUE_BEACON: + /* Configure QCU for beacons */ + OS_REG_WRITE(ah, AR_QMISC(q), + OS_REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1); + /* Configure DCU for beacons */ + value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S) + | AR_D_MISC_BEACON_USE | AR_D_MISC_POST_FR_BKOFF_DIS; + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) + value |= AR5311_D_MISC_SEQ_NUM_CONTROL; + OS_REG_WRITE(ah, AR_DMISC(q), value); + break; + case HAL_TX_QUEUE_CAB: + /* Configure QCU for CAB (Crap After Beacon) frames */ + OS_REG_WRITE(ah, AR_QMISC(q), + OS_REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0 | AR_Q_MISC_RDYTIME_EXP_POLICY); + + value = (ahp->ah_beaconInterval + - (ah->ah_config.ah_sw_beacon_response_time + - ah->ah_config.ah_dma_beacon_response_time) + - ah->ah_config.ah_additional_swba_backoff) * 1024; + OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); + + /* Configure DCU for CAB */ + value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S); + if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) + value |= AR5311_D_MISC_SEQ_NUM_CONTROL; + OS_REG_WRITE(ah, AR_QMISC(q), value); + break; + default: + /* NB: silence compiler */ + break; + } + + /* + * Always update the secondary interrupt mask registers - this + * could be a new queue getting enabled in a running system or + * hw getting re-initialized during a reset! + * + * Since we don't differentiate between tx interrupts corresponding + * to individual queues - secondary tx mask regs are always unmasked; + * tx interrupts are enabled/disabled for all queues collectively + * using the primary mask reg + */ + if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) + ahp->ah_txOkInterruptMask |= 1 << q; + else + ahp->ah_txOkInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) + ahp->ah_txErrInterruptMask |= 1 << q; + else + ahp->ah_txErrInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) + ahp->ah_txDescInterruptMask |= 1 << q; + else + ahp->ah_txDescInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) + ahp->ah_txEolInterruptMask |= 1 << q; + else + ahp->ah_txEolInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) + ahp->ah_txUrnInterruptMask |= 1 << q; + else + ahp->ah_txUrnInterruptMask &= ~(1 << q); + setTxQInterrupts(ah, qi); + + return AH_TRUE; +} + +/* + * Get the TXDP for the specified data queue. + */ +uint32_t +ar5211GetTxDP(struct ath_hal *ah, u_int q) +{ + HALASSERT(q < HAL_NUM_TX_QUEUES); + return OS_REG_READ(ah, AR_QTXDP(q)); +} + +/* + * Set the TxDP for the specified tx queue. + */ +HAL_BOOL +ar5211SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp) +{ + HALASSERT(q < HAL_NUM_TX_QUEUES); + HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + /* + * Make sure that TXE is deasserted before setting the TXDP. If TXE + * is still asserted, setting TXDP will have no effect. + */ + HALASSERT((OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) == 0); + + OS_REG_WRITE(ah, AR_QTXDP(q), txdp); + + return AH_TRUE; +} + +/* + * Set Transmit Enable bits for the specified queues. + */ +HAL_BOOL +ar5211StartTxDma(struct ath_hal *ah, u_int q) +{ + HALASSERT(q < HAL_NUM_TX_QUEUES); + HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + /* Check that queue is not already active */ + HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1<<q)) == 0); + + HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); + + /* Check to be sure we're not enabling a q that has its TXD bit set. */ + HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1 << q)) == 0); + + OS_REG_WRITE(ah, AR_Q_TXE, 1 << q); + return AH_TRUE; +} + +/* + * Return the number of frames pending on the specified queue. + */ +uint32_t +ar5211NumTxPending(struct ath_hal *ah, u_int q) +{ + uint32_t n; + + HALASSERT(q < HAL_NUM_TX_QUEUES); + HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + n = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT_M; + /* + * Pending frame count (PFC) can momentarily go to zero + * while TXE remains asserted. In other words a PFC of + * zero is not sufficient to say that the queue has stopped. + */ + if (n == 0 && (OS_REG_READ(ah, AR_Q_TXE) & (1<<q))) + n = 1; /* arbitrarily pick 1 */ + return n; +} + +/* + * Stop transmit on the specified queue + */ +HAL_BOOL +ar5211StopTxDma(struct ath_hal *ah, u_int q) +{ + int i; + + HALASSERT(q < HAL_NUM_TX_QUEUES); + HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); + + OS_REG_WRITE(ah, AR_Q_TXD, 1<<q); + for (i = 0; i < 10000; i++) { + if (ar5211NumTxPending(ah, q) == 0) + break; + OS_DELAY(10); + } + OS_REG_WRITE(ah, AR_Q_TXD, 0); + + return (i < 10000); +} + +/* + * Descriptor Access Functions + */ + +#define VALID_PKT_TYPES \ + ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\ + (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\ + (1<<HAL_PKT_TYPE_BEACON)) +#define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES) +#define VALID_TX_RATES \ + ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\ + (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\ + (1<<0x1d)|(1<<0x18)|(1<<0x1c)) +#define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES) + +HAL_BOOL +ar5211SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int pktLen, + u_int hdrLen, + HAL_PKT_TYPE type, + u_int txPower, + u_int txRate0, u_int txTries0, + u_int keyIx, + u_int antMode, + u_int flags, + u_int rtsctsRate, + u_int rtsctsDuration, + u_int compicvLen, + u_int compivLen, + u_int comp) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + (void) hdrLen; + (void) txPower; + (void) rtsctsRate; (void) rtsctsDuration; + + HALASSERT(txTries0 != 0); + HALASSERT(isValidPktType(type)); + HALASSERT(isValidTxRate(txRate0)); + /* XXX validate antMode */ + + ads->ds_ctl0 = (pktLen & AR_FrameLen) + | (txRate0 << AR_XmitRate_S) + | (antMode << AR_AntModeXmit_S) + | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0) + | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0) + | (flags & HAL_TXDESC_RTSENA ? AR_RTSCTSEnable : 0) + | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0) + ; + ads->ds_ctl1 = (type << 26) + | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0) + ; + + if (keyIx != HAL_TXKEYIX_INVALID) { + ads->ds_ctl1 |= + (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx; + ads->ds_ctl0 |= AR_EncryptKeyValid; + } + return AH_TRUE; +#undef RATE +} + +HAL_BOOL +ar5211SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds, + u_int txRate1, u_int txTries1, + u_int txRate2, u_int txTries2, + u_int txRate3, u_int txTries3) +{ + (void) ah; (void) ds; + (void) txRate1; (void) txTries1; + (void) txRate2; (void) txTries2; + (void) txRate3; (void) txTries3; + return AH_FALSE; +} + +void +ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + ads->ds_ctl0 |= AR_TxInterReq; +} + +HAL_BOOL +ar5211FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, + HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId, + u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg, + const struct ath_desc *ds0) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + uint32_t segLen = segLenList[0]; + + ds->ds_data = bufAddrList[0]; + + HALASSERT((segLen &~ AR_BufLen) == 0); + + if (firstSeg) { + /* + * First descriptor, don't clobber xmit control data + * setup by ar5211SetupTxDesc. + */ + ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More); + } else if (lastSeg) { /* !firstSeg && lastSeg */ + /* + * Last descriptor in a multi-descriptor frame, + * copy the transmit parameters from the first + * frame for processing on completion. + */ + ads->ds_ctl0 = AR5211DESC_CONST(ds0)->ds_ctl0; + ads->ds_ctl1 = segLen; + } else { /* !firstSeg && !lastSeg */ + /* + * Intermediate descriptor in a multi-descriptor frame. + */ + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen | AR_More; + } + ads->ds_status0 = ads->ds_status1 = 0; + return AH_TRUE; +} + +/* + * Processing of HW TX descriptor. + */ +HAL_STATUS +ar5211ProcTxDesc(struct ath_hal *ah, + struct ath_desc *ds, struct ath_tx_status *ts) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + if ((ads->ds_status1 & AR_Done) == 0) + return HAL_EINPROGRESS; + + /* Update software copies of the HW status */ + ts->ts_seqnum = MS(ads->ds_status1, AR_SeqNum); + ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp); + ts->ts_status = 0; + if ((ads->ds_status0 & AR_FrmXmitOK) == 0) { + if (ads->ds_status0 & AR_ExcessiveRetries) + ts->ts_status |= HAL_TXERR_XRETRY; + if (ads->ds_status0 & AR_Filtered) + ts->ts_status |= HAL_TXERR_FILT; + if (ads->ds_status0 & AR_FIFOUnderrun) + ts->ts_status |= HAL_TXERR_FIFO; + } + ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate); + ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength); + ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt); + ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt); + ts->ts_virtcol = MS(ads->ds_status0, AR_VirtCollCnt); + ts->ts_antenna = 0; /* NB: don't know */ + ts->ts_finaltsi = 0; + /* + * NB: the number of retries is one less than it should be. + * Also, 0 retries and 1 retry are both reported as 0 retries. + */ + if (ts->ts_shortretry > 0) + ts->ts_shortretry++; + if (ts->ts_longretry > 0) + ts->ts_longretry++; + + return HAL_OK; +} + +/* + * Determine which tx queues need interrupt servicing. + * STUB. + */ +void +ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs) +{ + return; +} + +/* + * Retrieve the rate table from the given TX completion descriptor + */ +HAL_BOOL +ar5211GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries) +{ + return AH_FALSE; +} + +void +ar5211SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + ads->ds_link = link; +} + +void +ar5211GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + *link = ads->ds_link; +} + +void +ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr) +{ + struct ar5211_desc *ads = AR5211DESC(ds); + + *linkptr = &ads->ds_link; +} diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211desc.h b/sys/dev/ath/ath_hal/ar5211/ar5211desc.h new file mode 100644 index 000000000000..9d5a0b62f006 --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211desc.h @@ -0,0 +1,132 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _DEV_ATH_AR5211DESC_H +#define _DEV_ATH_AR5211DESC_H + +/* + * Defintions for the DMA descriptors used by the Atheros + * AR5211 and AR5110 Wireless Lan controller parts. + */ + +/* DMA descriptors */ +struct ar5211_desc { + uint32_t ds_link; /* link pointer */ + uint32_t ds_data; /* data buffer pointer */ + uint32_t ds_ctl0; /* DMA control 0 */ + uint32_t ds_ctl1; /* DMA control 1 */ + uint32_t ds_status0; /* DMA status 0 */ + uint32_t ds_status1; /* DMA status 1 */ +} __packed; +#define AR5211DESC(_ds) ((struct ar5211_desc *)(_ds)) +#define AR5211DESC_CONST(_ds) ((const struct ar5211_desc *)(_ds)) + +/* TX ds_ctl0 */ +#define AR_FrameLen 0x00000fff /* frame length */ +/* bits 12-17 are reserved */ +#define AR_XmitRate 0x003c0000 /* txrate */ +#define AR_XmitRate_S 18 +#define AR_RTSCTSEnable 0x00400000 /* RTS/CTS enable */ +#define AR_VEOL 0x00800000 /* virtual end-of-list */ +#define AR_ClearDestMask 0x01000000 /* Clear destination mask bit */ +#define AR_AntModeXmit 0x1e000000 /* TX antenna seslection */ +#define AR_AntModeXmit_S 25 +#define AR_TxInterReq 0x20000000 /* TX interrupt request */ +#define AR_EncryptKeyValid 0x40000000 /* EncryptKeyIdx is valid */ +/* bit 31 is reserved */ + +/* TX ds_ctl1 */ +#define AR_BufLen 0x00000fff /* data buffer length */ +#define AR_More 0x00001000 /* more desc in this frame */ +#define AR_EncryptKeyIdx 0x000fe000 /* ecnrypt key table index */ +#define AR_EncryptKeyIdx_S 13 +#define AR_FrmType 0x00700000 /* frame type indication */ +#define AR_FrmType_S 20 +#define AR_Frm_Normal 0x00000000 /* normal frame */ +#define AR_Frm_ATIM 0x00100000 /* ATIM frame */ +#define AR_Frm_PSPOLL 0x00200000 /* PS poll frame */ +#define AR_Frm_Beacon 0x00300000 /* Beacon frame */ +#define AR_Frm_ProbeResp 0x00400000 /* no delay data */ +#define AR_NoAck 0x00800000 /* No ACK flag */ +/* bits 24-31 are reserved */ + +/* RX ds_ctl1 */ +/* AR_BufLen 0x00000fff data buffer length */ +/* bit 12 is reserved */ +#define AR_RxInterReq 0x00002000 /* RX interrupt request */ +/* bits 14-31 are reserved */ + +/* TX ds_status0 */ +#define AR_FrmXmitOK 0x00000001 /* TX success */ +#define AR_ExcessiveRetries 0x00000002 /* excessive retries */ +#define AR_FIFOUnderrun 0x00000004 /* TX FIFO underrun */ +#define AR_Filtered 0x00000008 /* TX filter indication */ +/* NB: the spec has the Short+Long retry counts reversed */ +#define AR_LongRetryCnt 0x000000f0 /* long retry count */ +#define AR_LongRetryCnt_S 4 +#define AR_ShortRetryCnt 0x00000f00 /* short retry count */ +#define AR_ShortRetryCnt_S 8 +#define AR_VirtCollCnt 0x0000f000 /* virtual collision count */ +#define AR_VirtCollCnt_S 12 +#define AR_SendTimestamp 0xffff0000 /* TX timestamp */ +#define AR_SendTimestamp_S 16 + +/* RX ds_status0 */ +#define AR_DataLen 0x00000fff /* RX data length */ +/* AR_More 0x00001000 more desc in this frame */ +/* bits 13-14 are reserved */ +#define AR_RcvRate 0x00078000 /* reception rate */ +#define AR_RcvRate_S 15 +#define AR_RcvSigStrength 0x07f80000 /* receive signal strength */ +#define AR_RcvSigStrength_S 19 +#define AR_RcvAntenna 0x38000000 /* receive antenaa */ +#define AR_RcvAntenna_S 27 +/* bits 30-31 are reserved */ + +/* TX ds_status1 */ +#define AR_Done 0x00000001 /* descripter complete */ +#define AR_SeqNum 0x00001ffe /* TX sequence number */ +#define AR_SeqNum_S 1 +#define AR_AckSigStrength 0x001fe000 /* strength of ACK */ +#define AR_AckSigStrength_S 13 +/* bits 21-31 are reserved */ + +/* RX ds_status1 */ +/* AR_Done 0x00000001 descripter complete */ +#define AR_FrmRcvOK 0x00000002 /* frame reception success */ +#define AR_CRCErr 0x00000004 /* CRC error */ +/* bit 3 reserved */ +#define AR_DecryptCRCErr 0x00000010 /* Decryption CRC fiailure */ +#define AR_PHYErr 0x000000e0 /* PHY error */ +#define AR_PHYErr_S 5 +#define AR_PHYErr_Underrun 0x00000000 /* Transmit underrun */ +#define AR_PHYErr_Tim 0x00000020 /* Timing error */ +#define AR_PHYErr_Par 0x00000040 /* Parity error */ +#define AR_PHYErr_Rate 0x00000060 /* Illegal rate */ +#define AR_PHYErr_Len 0x00000080 /* Illegal length */ +#define AR_PHYErr_Radar 0x000000a0 /* Radar detect */ +#define AR_PHYErr_Srv 0x000000c0 /* Illegal service */ +#define AR_PHYErr_TOR 0x000000e0 /* Transmit override receive */ +#define AR_KeyIdxValid 0x00000100 /* decryption key index valid */ +#define AR_KeyIdx 0x00007e00 /* Decryption key index */ +#define AR_KeyIdx_S 9 +#define AR_RcvTimestamp 0x0fff8000 /* timestamp */ +#define AR_RcvTimestamp_S 15 +#define AR_KeyCacheMiss 0x10000000 /* key cache miss indication */ + +#endif /* _DEV_ATH_AR5211DESC_H_ */ diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211phy.h b/sys/dev/ath/ath_hal/ar5211/ar5211phy.h new file mode 100644 index 000000000000..6b833352eb82 --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211phy.h @@ -0,0 +1,93 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _DEV_ATH_AR5211PHY_H +#define _DEV_ATH_AR5211PHY_H + +/* + * Definitions for the PHY on the Atheros AR5211/5311 chipset. + */ + +/* PHY registers */ +#define AR_PHY_BASE 0x9800 /* PHY registers base address */ +#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) + +#define AR_PHY_TURBO 0x9804 /* PHY frame control register */ +#define AR_PHY_FC_TURBO_MODE 0x00000001 /* Set turbo mode bits */ +#define AR_PHY_FC_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode setting */ + +#define AR_PHY_CHIP_ID 0x9818 /* PHY chip revision ID */ + +#define AR_PHY_ACTIVE 0x981C /* PHY activation register */ +#define AR_PHY_ACTIVE_EN 0x00000001 /* Activate PHY chips */ +#define AR_PHY_ACTIVE_DIS 0x00000000 /* Deactivate PHY chips */ + +#define AR_PHY_AGC_CONTROL 0x9860 /* PHY chip calibration and noise floor setting */ +#define AR_PHY_AGC_CONTROL_CAL 0x00000001 /* Perform PHY chip internal calibration */ +#define AR_PHY_AGC_CONTROL_NF 0x00000002 /* Perform PHY chip noise-floor calculation */ + +#define AR_PHY_PLL_CTL 0x987c /* PLL control register */ +#define AR_PHY_PLL_CTL_44 0x19 /* 44 MHz for 11b channels and FPGA */ +#define AR_PHY_PLL_CTL_40 0x18 /* 40 MHz */ +#define AR_PHY_PLL_CTL_20 0x13 /* 20 MHz half rate 11a for emulation */ + +#define AR_PHY_RX_DELAY 0x9914 /* PHY analog_power_on_time, in 100ns increments */ +#define AR_PHY_RX_DELAY_M 0x00003FFF /* Mask for delay from active assertion (wake up) */ + /* to enable_receiver */ + +#define AR_PHY_TIMING_CTRL4 0x9920 /* PHY */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_M 0x0000001F /* Mask for kcos_theta-1 for q correction */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_M 0x000007E0 /* Mask for sin_theta for i correction */ +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5 /* Shift for sin_theta for i correction */ +#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x00000800 /* enable IQ correction */ +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_M 0x0000F000 /* Mask for max number of samples (logarithmic) */ +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12 /* Shift for max number of samples */ +#define AR_PHY_TIMING_CTRL4_DO_IQCAL 0x00010000 /* perform IQ calibration */ + +#define AR_PHY_PAPD_PROBE 0x9930 +#define AR_PHY_PAPD_PROBE_POWERTX 0x00007E00 +#define AR_PHY_PAPD_PROBE_POWERTX_S 9 +#define AR_PHY_PAPD_PROBE_NEXT_TX 0x00008000 /* command to take next reading */ +#define AR_PHY_PAPD_PROBE_GAINF 0xFE000000 +#define AR_PHY_PAPD_PROBE_GAINF_S 25 + +#define AR_PHY_POWER_TX_RATE1 0x9934 +#define AR_PHY_POWER_TX_RATE2 0x9938 +#define AR_PHY_POWER_TX_RATE_MAX 0x993c + +#define AR_PHY_FRAME_CTL 0x9944 +#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038 +#define AR_PHY_FRAME_CTL_TX_CLIP_S 3 +#define AR_PHY_FRAME_CTL_ERR_SERV 0x20000000 +#define AR_PHY_FRAME_CTL_ERR_SERV_S 29 + +#define AR_PHY_RADAR_0 0x9954 /* PHY radar detection settings */ +#define AR_PHY_RADAR_0_ENA 0x00000001 /* Enable radar detection */ + +#define AR_PHY_IQCAL_RES_PWR_MEAS_I 0x9c10 /*PHY IQ calibration results - power measurement for I */ +#define AR_PHY_IQCAL_RES_PWR_MEAS_Q 0x9c14 /*PHY IQ calibration results - power measurement for Q */ +#define AR_PHY_IQCAL_RES_IQ_CORR_MEAS 0x9c18 /*PHY IQ calibration results - IQ correlation measurement */ +#define AR_PHY_CURRENT_RSSI 0x9c1c /* rssi of current frame being received */ + +#define AR5211_PHY_MODE 0xA200 /* Mode register */ +#define AR5211_PHY_MODE_OFDM 0x0 /* bit 0 = 0 for OFDM */ +#define AR5211_PHY_MODE_CCK 0x1 /* bit 0 = 1 for CCK */ +#define AR5211_PHY_MODE_RF5GHZ 0x0 /* bit 1 = 0 for 5 GHz */ +#define AR5211_PHY_MODE_RF2GHZ 0x2 /* bit 1 = 1 for 2.4 GHz */ + +#endif /* _DEV_ATH_AR5211PHY_H */ diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211reg.h b/sys/dev/ath/ath_hal/ar5211/ar5211reg.h new file mode 100644 index 000000000000..54eab6aa9be2 --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/ar5211reg.h @@ -0,0 +1,863 @@ +/*- + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _DEV_ATH_AR5211REG_H +#define _DEV_ATH_AR5211REG_H + +/* + * Definitions for the Atheros AR5211/5311 chipset. + */ + +/* + * Maui2/Spirit specific registers/fields are indicated by AR5311. + * Oahu specific registers/fields are indicated by AR5211. + */ + +/* DMA Control and Interrupt Registers */ +#define AR_CR 0x0008 /* control register */ +#define AR_RXDP 0x000C /* receive queue descriptor pointer */ +#define AR_CFG 0x0014 /* configuration and status register */ +#define AR_IER 0x0024 /* Interrupt enable register */ +#define AR_RTSD0 0x0028 /* RTS Duration Parameters 0 */ +#define AR_RTSD1 0x002c /* RTS Duration Parameters 1 */ +#define AR_TXCFG 0x0030 /* tx DMA size config register */ +#define AR_RXCFG 0x0034 /* rx DMA size config register */ +#define AR5211_JUMBO_LAST 0x0038 /* Jumbo descriptor last address */ +#define AR_MIBC 0x0040 /* MIB control register */ +#define AR_TOPS 0x0044 /* timeout prescale count */ +#define AR_RXNPTO 0x0048 /* no frame received timeout */ +#define AR_TXNPTO 0x004C /* no frame trasmitted timeout */ +#define AR_RFGTO 0x0050 /* receive frame gap timeout */ +#define AR_RFCNT 0x0054 /* receive frame count limit */ +#define AR_MACMISC 0x0058 /* miscellaneous control/status */ +#define AR5311_QDCLKGATE 0x005c /* QCU/DCU clock gating control */ +#define AR_ISR 0x0080 /* Primary interrupt status register */ +#define AR_ISR_S0 0x0084 /* Secondary interrupt status reg 0 */ +#define AR_ISR_S1 0x0088 /* Secondary interrupt status reg 1 */ +#define AR_ISR_S2 0x008c /* Secondary interrupt status reg 2 */ +#define AR_ISR_S3 0x0090 /* Secondary interrupt status reg 3 */ +#define AR_ISR_S4 0x0094 /* Secondary interrupt status reg 4 */ +#define AR_IMR 0x00a0 /* Primary interrupt mask register */ +#define AR_IMR_S0 0x00a4 /* Secondary interrupt mask reg 0 */ +#define AR_IMR_S1 0x00a8 /* Secondary interrupt mask reg 1 */ +#define AR_IMR_S2 0x00ac /* Secondary interrupt mask reg 2 */ +#define AR_IMR_S3 0x00b0 /* Secondary interrupt mask reg 3 */ +#define AR_IMR_S4 0x00b4 /* Secondary interrupt mask reg 4 */ +#define AR_ISR_RAC 0x00c0 /* Primary interrupt status reg, */ +/* Shadow copies with read-and-clear access */ +#define AR_ISR_S0_S 0x00c4 /* Secondary interrupt status reg 0 */ +#define AR_ISR_S1_S 0x00c8 /* Secondary interrupt status reg 1 */ +#define AR_ISR_S2_S 0x00cc /* Secondary interrupt status reg 2 */ +#define AR_ISR_S3_S 0x00d0 /* Secondary interrupt status reg 3 */ +#define AR_ISR_S4_S 0x00d4 /* Secondary interrupt status reg 4 */ + +#define AR_Q0_TXDP 0x0800 /* Transmit Queue descriptor pointer */ +#define AR_Q1_TXDP 0x0804 /* Transmit Queue descriptor pointer */ +#define AR_Q2_TXDP 0x0808 /* Transmit Queue descriptor pointer */ +#define AR_Q3_TXDP 0x080c /* Transmit Queue descriptor pointer */ +#define AR_Q4_TXDP 0x0810 /* Transmit Queue descriptor pointer */ +#define AR_Q5_TXDP 0x0814 /* Transmit Queue descriptor pointer */ +#define AR_Q6_TXDP 0x0818 /* Transmit Queue descriptor pointer */ +#define AR_Q7_TXDP 0x081c /* Transmit Queue descriptor pointer */ +#define AR_Q8_TXDP 0x0820 /* Transmit Queue descriptor pointer */ +#define AR_Q9_TXDP 0x0824 /* Transmit Queue descriptor pointer */ +#define AR_QTXDP(i) (AR_Q0_TXDP + ((i)<<2)) + +#define AR_Q_TXE 0x0840 /* Transmit Queue enable */ +#define AR_Q_TXD 0x0880 /* Transmit Queue disable */ + +#define AR_Q0_CBRCFG 0x08c0 /* CBR configuration */ +#define AR_Q1_CBRCFG 0x08c4 /* CBR configuration */ +#define AR_Q2_CBRCFG 0x08c8 /* CBR configuration */ +#define AR_Q3_CBRCFG 0x08cc /* CBR configuration */ +#define AR_Q4_CBRCFG 0x08d0 /* CBR configuration */ +#define AR_Q5_CBRCFG 0x08d4 /* CBR configuration */ +#define AR_Q6_CBRCFG 0x08d8 /* CBR configuration */ +#define AR_Q7_CBRCFG 0x08dc /* CBR configuration */ +#define AR_Q8_CBRCFG 0x08e0 /* CBR configuration */ +#define AR_Q9_CBRCFG 0x08e4 /* CBR configuration */ +#define AR_QCBRCFG(i) (AR_Q0_CBRCFG + ((i)<<2)) + +#define AR_Q0_RDYTIMECFG 0x0900 /* ReadyTime configuration */ +#define AR_Q1_RDYTIMECFG 0x0904 /* ReadyTime configuration */ +#define AR_Q2_RDYTIMECFG 0x0908 /* ReadyTime configuration */ +#define AR_Q3_RDYTIMECFG 0x090c /* ReadyTime configuration */ +#define AR_Q4_RDYTIMECFG 0x0910 /* ReadyTime configuration */ +#define AR_Q5_RDYTIMECFG 0x0914 /* ReadyTime configuration */ +#define AR_Q6_RDYTIMECFG 0x0918 /* ReadyTime configuration */ +#define AR_Q7_RDYTIMECFG 0x091c /* ReadyTime configuration */ +#define AR_Q8_RDYTIMECFG 0x0920 /* ReadyTime configuration */ +#define AR_Q9_RDYTIMECFG 0x0924 /* ReadyTime configuration */ +#define AR_QRDYTIMECFG(i) (AR_Q0_RDYTIMECFG + ((i)<<2)) + +#define AR_Q_ONESHOTARM_SC 0x0940 /* OneShotArm set control */ +#define AR_Q_ONESHOTARM_CC 0x0980 /* OneShotArm clear control */ + +#define AR_Q0_MISC 0x09c0 /* Miscellaneous QCU settings */ +#define AR_Q1_MISC 0x09c4 /* Miscellaneous QCU settings */ +#define AR_Q2_MISC 0x09c8 /* Miscellaneous QCU settings */ +#define AR_Q3_MISC 0x09cc /* Miscellaneous QCU settings */ +#define AR_Q4_MISC 0x09d0 /* Miscellaneous QCU settings */ +#define AR_Q5_MISC 0x09d4 /* Miscellaneous QCU settings */ +#define AR_Q6_MISC 0x09d8 /* Miscellaneous QCU settings */ +#define AR_Q7_MISC 0x09dc /* Miscellaneous QCU settings */ +#define AR_Q8_MISC 0x09e0 /* Miscellaneous QCU settings */ +#define AR_Q9_MISC 0x09e4 /* Miscellaneous QCU settings */ +#define AR_QMISC(i) (AR_Q0_MISC + ((i)<<2)) + +#define AR_Q0_STS 0x0a00 /* Miscellaneous QCU status */ +#define AR_Q1_STS 0x0a04 /* Miscellaneous QCU status */ +#define AR_Q2_STS 0x0a08 /* Miscellaneous QCU status */ +#define AR_Q3_STS 0x0a0c /* Miscellaneous QCU status */ +#define AR_Q4_STS 0x0a10 /* Miscellaneous QCU status */ +#define AR_Q5_STS 0x0a14 /* Miscellaneous QCU status */ +#define AR_Q6_STS 0x0a18 /* Miscellaneous QCU status */ +#define AR_Q7_STS 0x0a1c /* Miscellaneous QCU status */ +#define AR_Q8_STS 0x0a20 /* Miscellaneous QCU status */ +#define AR_Q9_STS 0x0a24 /* Miscellaneous QCU status */ +#define AR_QSTS(i) (AR_Q0_STS + ((i)<<2)) + +#define AR_Q_RDYTIMESHDN 0x0a40 /* ReadyTimeShutdown status */ +#define AR_D0_QCUMASK 0x1000 /* QCU Mask */ +#define AR_D1_QCUMASK 0x1004 /* QCU Mask */ +#define AR_D2_QCUMASK 0x1008 /* QCU Mask */ +#define AR_D3_QCUMASK 0x100c /* QCU Mask */ +#define AR_D4_QCUMASK 0x1010 /* QCU Mask */ +#define AR_D5_QCUMASK 0x1014 /* QCU Mask */ +#define AR_D6_QCUMASK 0x1018 /* QCU Mask */ +#define AR_D7_QCUMASK 0x101c /* QCU Mask */ +#define AR_D8_QCUMASK 0x1020 /* QCU Mask */ +#define AR_D9_QCUMASK 0x1024 /* QCU Mask */ +#define AR_DQCUMASK(i) (AR_D0_QCUMASK + ((i)<<2)) + +#define AR_D0_LCL_IFS 0x1040 /* DCU-specific IFS settings */ +#define AR_D1_LCL_IFS 0x1044 /* DCU-specific IFS settings */ +#define AR_D2_LCL_IFS 0x1048 /* DCU-specific IFS settings */ +#define AR_D3_LCL_IFS 0x104c /* DCU-specific IFS settings */ +#define AR_D4_LCL_IFS 0x1050 /* DCU-specific IFS settings */ +#define AR_D5_LCL_IFS 0x1054 /* DCU-specific IFS settings */ +#define AR_D6_LCL_IFS 0x1058 /* DCU-specific IFS settings */ +#define AR_D7_LCL_IFS 0x105c /* DCU-specific IFS settings */ +#define AR_D8_LCL_IFS 0x1060 /* DCU-specific IFS settings */ +#define AR_D9_LCL_IFS 0x1064 /* DCU-specific IFS settings */ +#define AR_DLCL_IFS(i) (AR_D0_LCL_IFS + ((i)<<2)) + +#define AR_D0_RETRY_LIMIT 0x1080 /* Retry limits */ +#define AR_D1_RETRY_LIMIT 0x1084 /* Retry limits */ +#define AR_D2_RETRY_LIMIT 0x1088 /* Retry limits */ +#define AR_D3_RETRY_LIMIT 0x108c /* Retry limits */ +#define AR_D4_RETRY_LIMIT 0x1090 /* Retry limits */ +#define AR_D5_RETRY_LIMIT 0x1094 /* Retry limits */ +#define AR_D6_RETRY_LIMIT 0x1098 /* Retry limits */ +#define AR_D7_RETRY_LIMIT 0x109c /* Retry limits */ +#define AR_D8_RETRY_LIMIT 0x10a0 /* Retry limits */ +#define AR_D9_RETRY_LIMIT 0x10a4 /* Retry limits */ +#define AR_DRETRY_LIMIT(i) (AR_D0_RETRY_LIMIT + ((i)<<2)) + +#define AR_D0_CHNTIME 0x10c0 /* ChannelTime settings */ +#define AR_D1_CHNTIME 0x10c4 /* ChannelTime settings */ +#define AR_D2_CHNTIME 0x10c8 /* ChannelTime settings */ +#define AR_D3_CHNTIME 0x10cc /* ChannelTime settings */ +#define AR_D4_CHNTIME 0x10d0 /* ChannelTime settings */ +#define AR_D5_CHNTIME 0x10d4 /* ChannelTime settings */ +#define AR_D6_CHNTIME 0x10d8 /* ChannelTime settings */ +#define AR_D7_CHNTIME 0x10dc /* ChannelTime settings */ +#define AR_D8_CHNTIME 0x10e0 /* ChannelTime settings */ +#define AR_D9_CHNTIME 0x10e4 /* ChannelTime settings */ +#define AR_DCHNTIME(i) (AR_D0_CHNTIME + ((i)<<2)) + +#define AR_D0_MISC 0x1100 /* Misc DCU-specific settings */ +#define AR_D1_MISC 0x1104 /* Misc DCU-specific settings */ +#define AR_D2_MISC 0x1108 /* Misc DCU-specific settings */ +#define AR_D3_MISC 0x110c /* Misc DCU-specific settings */ +#define AR_D4_MISC 0x1110 /* Misc DCU-specific settings */ +#define AR_D5_MISC 0x1114 /* Misc DCU-specific settings */ +#define AR_D6_MISC 0x1118 /* Misc DCU-specific settings */ +#define AR_D7_MISC 0x111c /* Misc DCU-specific settings */ +#define AR_D8_MISC 0x1120 /* Misc DCU-specific settings */ +#define AR_D9_MISC 0x1124 /* Misc DCU-specific settings */ +#define AR_DMISC(i) (AR_D0_MISC + ((i)<<2)) + +#define AR_D0_SEQNUM 0x1140 /* Frame seqnum control/status */ +#define AR_D1_SEQNUM 0x1144 /* Frame seqnum control/status */ +#define AR_D2_SEQNUM 0x1148 /* Frame seqnum control/status */ +#define AR_D3_SEQNUM 0x114c /* Frame seqnum control/status */ +#define AR_D4_SEQNUM 0x1150 /* Frame seqnum control/status */ +#define AR_D5_SEQNUM 0x1154 /* Frame seqnum control/status */ +#define AR_D6_SEQNUM 0x1158 /* Frame seqnum control/status */ +#define AR_D7_SEQNUM 0x115c /* Frame seqnum control/status */ +#define AR_D8_SEQNUM 0x1160 /* Frame seqnum control/status */ +#define AR_D9_SEQNUM 0x1164 /* Frame seqnum control/status */ +#define AR_DSEQNUM(i) (AR_D0_SEQNUM + ((i<<2))) + +/* MAC DCU-global IFS settings */ +#define AR_D_GBL_IFS_SIFS 0x1030 /* DCU global SIFS settings */ +#define AR_D_GBL_IFS_SLOT 0x1070 /* DC global slot interval */ +#define AR_D_GBL_IFS_EIFS 0x10b0 /* DCU global EIFS setting */ +#define AR_D_GBL_IFS_MISC 0x10f0 /* DCU global misc. IFS settings */ +#define AR_D_FPCTL 0x1230 /* DCU frame prefetch settings */ +#define AR_D_TXPSE 0x1270 /* DCU transmit pause control/status */ +#define AR_D_TXBLK_CMD 0x1038 /* DCU transmit filter cmd (w/only) */ +#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i)) /* DCU transmit filter data */ +#define AR_D_TXBLK_CLR 0x143c /* DCU clear tx filter (w/only) */ +#define AR_D_TXBLK_SET 0x147c /* DCU set tx filter (w/only) */ + +#define AR_D_TXPSE 0x1270 /* DCU transmit pause control/status */ + +#define AR_RC 0x4000 /* Warm reset control register */ +#define AR_SCR 0x4004 /* Sleep control register */ +#define AR_INTPEND 0x4008 /* Interrupt Pending register */ +#define AR_SFR 0x400C /* Sleep force register */ +#define AR_PCICFG 0x4010 /* PCI configuration register */ +#define AR_GPIOCR 0x4014 /* GPIO control register */ +#define AR_GPIODO 0x4018 /* GPIO data output access register */ +#define AR_GPIODI 0x401C /* GPIO data input access register */ +#define AR_SREV 0x4020 /* Silicon Revision register */ + +#define AR_EEPROM_ADDR 0x6000 /* EEPROM address register (10 bit) */ +#define AR_EEPROM_DATA 0x6004 /* EEPROM data register (16 bit) */ +#define AR_EEPROM_CMD 0x6008 /* EEPROM command register */ +#define AR_EEPROM_STS 0x600c /* EEPROM status register */ +#define AR_EEPROM_CFG 0x6010 /* EEPROM configuration register */ + +#define AR_STA_ID0 0x8000 /* station ID0 - low 32 bits */ +#define AR_STA_ID1 0x8004 /* station ID1 - upper 16 bits */ +#define AR_BSS_ID0 0x8008 /* BSSID low 32 bits */ +#define AR_BSS_ID1 0x800C /* BSSID upper 16 bits / AID */ +#define AR_SLOT_TIME 0x8010 /* Time-out after a collision */ +#define AR_TIME_OUT 0x8014 /* ACK & CTS time-out */ +#define AR_RSSI_THR 0x8018 /* RSSI warning & missed beacon threshold */ +#define AR_USEC 0x801c /* transmit latency register */ +#define AR_BEACON 0x8020 /* beacon control value/mode bits */ +#define AR_CFP_PERIOD 0x8024 /* CFP Interval (TU/msec) */ +#define AR_TIMER0 0x8028 /* Next beacon time (TU/msec) */ +#define AR_TIMER1 0x802c /* DMA beacon alert time (1/8 TU) */ +#define AR_TIMER2 0x8030 /* Software beacon alert (1/8 TU) */ +#define AR_TIMER3 0x8034 /* ATIM window time */ +#define AR_CFP_DUR 0x8038 /* maximum CFP duration in TU */ +#define AR_RX_FILTER 0x803C /* receive filter register */ +#define AR_MCAST_FIL0 0x8040 /* multicast filter lower 32 bits */ +#define AR_MCAST_FIL1 0x8044 /* multicast filter upper 32 bits */ +#define AR_DIAG_SW 0x8048 /* PCU control register */ +#define AR_TSF_L32 0x804c /* local clock lower 32 bits */ +#define AR_TSF_U32 0x8050 /* local clock upper 32 bits */ +#define AR_TST_ADDAC 0x8054 /* ADDAC test register */ +#define AR_DEF_ANTENNA 0x8058 /* default antenna register */ + +#define AR_LAST_TSTP 0x8080 /* Time stamp of the last beacon rcvd */ +#define AR_NAV 0x8084 /* current NAV value */ +#define AR_RTS_OK 0x8088 /* RTS exchange success counter */ +#define AR_RTS_FAIL 0x808c /* RTS exchange failure counter */ +#define AR_ACK_FAIL 0x8090 /* ACK failure counter */ +#define AR_FCS_FAIL 0x8094 /* FCS check failure counter */ +#define AR_BEACON_CNT 0x8098 /* Valid beacon counter */ + +#define AR_KEYTABLE_0 0x8800 /* Encryption key table */ +#define AR_KEYTABLE(n) (AR_KEYTABLE_0 + ((n)*32)) + +#define AR_CR_RXE 0x00000004 /* Receive enable */ +#define AR_CR_RXD 0x00000020 /* Receive disable */ +#define AR_CR_SWI 0x00000040 /* One-shot software interrupt */ +#define AR_CR_BITS "\20\3RXE\6RXD\7SWI" + +#define AR_CFG_SWTD 0x00000001 /* byteswap tx descriptor words */ +#define AR_CFG_SWTB 0x00000002 /* byteswap tx data buffer words */ +#define AR_CFG_SWRD 0x00000004 /* byteswap rx descriptor words */ +#define AR_CFG_SWRB 0x00000008 /* byteswap rx data buffer words */ +#define AR_CFG_SWRG 0x00000010 /* byteswap register access data words */ +#define AR_CFG_AP_ADHOC_INDICATION 0x00000020 /* AP/adhoc indication (0-AP, 1-Adhoc) */ +#define AR_CFG_PHOK 0x00000100 /* PHY OK status */ +#define AR_CFG_EEBS 0x00000200 /* EEPROM busy */ +#define AR_CFG_CLK_GATE_DIS 0x00000400 /* Clock gating disable (Oahu only) */ +#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_M 0x00060000 /* Mask of PCI core master request queue full threshold */ +#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17 /* Shift for PCI core master request queue full threshold */ +#define AR_CFG_BITS \ + "\20\1SWTD\2SWTB\3SWRD\4SWRB\5SWRG\10PHYOK11EEBS" + +#define AR_IER_ENABLE 0x00000001 /* Global interrupt enable */ +#define AR_IER_DISABLE 0x00000000 /* Global interrupt disable */ +#define AR_IER_BITS "\20\1ENABLE" + +#define AR_RTSD0_RTS_DURATION_6_M 0x000000FF +#define AR_RTSD0_RTS_DURATION_6_S 0 +#define AR_RTSD0_RTS_DURATION_9_M 0x0000FF00 +#define AR_RTSD0_RTS_DURATION_9_S 8 +#define AR_RTSD0_RTS_DURATION_12_M 0x00FF0000 +#define AR_RTSD0_RTS_DURATION_12_S 16 +#define AR_RTSD0_RTS_DURATION_18_M 0xFF000000 +#define AR_RTSD0_RTS_DURATION_18_S 24 + +#define AR_RTSD0_RTS_DURATION_24_M 0x000000FF +#define AR_RTSD0_RTS_DURATION_24_S 0 +#define AR_RTSD0_RTS_DURATION_36_M 0x0000FF00 +#define AR_RTSD0_RTS_DURATION_36_S 8 +#define AR_RTSD0_RTS_DURATION_48_M 0x00FF0000 +#define AR_RTSD0_RTS_DURATION_48_S 16 +#define AR_RTSD0_RTS_DURATION_54_M 0xFF000000 +#define AR_RTSD0_RTS_DURATION_54_S 24 + +#define AR_DMASIZE_4B 0x00000000 /* DMA size 4 bytes (TXCFG + RXCFG) */ +#define AR_DMASIZE_8B 0x00000001 /* DMA size 8 bytes */ +#define AR_DMASIZE_16B 0x00000002 /* DMA size 16 bytes */ +#define AR_DMASIZE_32B 0x00000003 /* DMA size 32 bytes */ +#define AR_DMASIZE_64B 0x00000004 /* DMA size 64 bytes */ +#define AR_DMASIZE_128B 0x00000005 /* DMA size 128 bytes */ +#define AR_DMASIZE_256B 0x00000006 /* DMA size 256 bytes */ +#define AR_DMASIZE_512B 0x00000007 /* DMA size 512 bytes */ + +#define AR_TXCFG_FTRIG_M 0x000003F0 /* Mask for Frame trigger level */ +#define AR_TXCFG_FTRIG_S 4 /* Shift for Frame trigger level */ +#define AR_TXCFG_FTRIG_IMMED 0x00000000 /* bytes in PCU TX FIFO before air */ +#define AR_TXCFG_FTRIG_64B 0x00000010 /* default */ +#define AR_TXCFG_FTRIG_128B 0x00000020 +#define AR_TXCFG_FTRIG_192B 0x00000030 +#define AR_TXCFG_FTRIG_256B 0x00000040 /* 5 bits total */ +#define AR_TXCFG_BITS "\20" + +#define AR5311_RXCFG_DEF_RX_ANTENNA 0x00000008 /* Default Receive Antenna */ + /* Maui2/Spirit only - reserved on Oahu */ +#define AR_RXCFG_ZLFDMA 0x00000010 /* Enable DMA of zero-length frame */ +#define AR_RXCFG_EN_JUM 0x00000020 /* Enable jumbo rx descriptors */ +#define AR_RXCFG_WR_JUM 0x00000040 /* Wrap jumbo rx descriptors */ + +#define AR_MIBC_COW 0x00000001 /* counter overflow warning */ +#define AR_MIBC_FMC 0x00000002 /* freeze MIB counters */ +#define AR_MIBC_CMC 0x00000004 /* clear MIB counters */ +#define AR_MIBC_MCS 0x00000008 /* MIB counter strobe, increment all */ + +#define AR_TOPS_MASK 0x0000FFFF /* Mask for timeout prescale */ + +#define AR_RXNPTO_MASK 0x000003FF /* Mask for no frame received timeout */ + +#define AR_TXNPTO_MASK 0x000003FF /* Mask for no frame transmitted timeout */ +#define AR_TXNPTO_QCU_MASK 0x03FFFC00 /* Mask indicating the set of QCUs */ + /* for which frame completions will cause */ + /* a reset of the no frame transmitted timeout */ + +#define AR_RPGTO_MASK 0x000003FF /* Mask for receive frame gap timeout */ + +#define AR_RPCNT_MASK 0x0000001F /* Mask for receive frame count limit */ + +#define AR_MACMISC_DMA_OBS_M 0x000001E0 /* Mask for DMA observation bus mux select */ +#define AR_MACMISC_DMA_OBS_S 5 /* Shift for DMA observation bus mux select */ +#define AR_MACMISC_MISC_OBS_M 0x00000E00 /* Mask for MISC observation bus mux select */ +#define AR_MACMISC_MISC_OBS_S 9 /* Shift for MISC observation bus mux select */ +#define AR_MACMISC_MAC_OBS_BUS_LSB_M 0x00007000 /* Mask for MAC observation bus mux select (lsb) */ +#define AR_MACMISC_MAC_OBS_BUS_LSB_S 12 /* Shift for MAC observation bus mux select (lsb) */ +#define AR_MACMISC_MAC_OBS_BUS_MSB_M 0x00038000 /* Mask for MAC observation bus mux select (msb) */ +#define AR_MACMISC_MAC_OBS_BUS_MSB_S 15 /* Shift for MAC observation bus mux select (msb) */ + + /* Maui2/Spirit only. */ +#define AR5311_QDCLKGATE_QCU_M 0x0000FFFF /* Mask for QCU clock disable */ +#define AR5311_QDCLKGATE_DCU_M 0x07FF0000 /* Mask for DCU clock disable */ + + /* Interrupt Status Registers */ +#define AR_ISR_RXOK 0x00000001 /* At least one frame received sans errors */ +#define AR_ISR_RXDESC 0x00000002 /* Receive interrupt request */ +#define AR_ISR_RXERR 0x00000004 /* Receive error interrupt */ +#define AR_ISR_RXNOPKT 0x00000008 /* No frame received within timeout clock */ +#define AR_ISR_RXEOL 0x00000010 /* Received descriptor empty interrupt */ +#define AR_ISR_RXORN 0x00000020 /* Receive FIFO overrun interrupt */ +#define AR_ISR_TXOK 0x00000040 /* Transmit okay interrupt */ +#define AR_ISR_TXDESC 0x00000080 /* Transmit interrupt request */ +#define AR_ISR_TXERR 0x00000100 /* Transmit error interrupt */ +#define AR_ISR_TXNOPKT 0x00000200 /* No frame transmitted interrupt */ +#define AR_ISR_TXEOL 0x00000400 /* Transmit descriptor empty interrupt */ +#define AR_ISR_TXURN 0x00000800 /* Transmit FIFO underrun interrupt */ +#define AR_ISR_MIB 0x00001000 /* MIB interrupt - see MIBC */ +#define AR_ISR_SWI 0x00002000 /* Software interrupt */ +#define AR_ISR_RXPHY 0x00004000 /* PHY receive error interrupt */ +#define AR_ISR_RXKCM 0x00008000 /* Key-cache miss interrupt */ +#define AR_ISR_SWBA 0x00010000 /* Software beacon alert interrupt */ +#define AR_ISR_BRSSI 0x00020000 /* Beacon threshold interrupt */ +#define AR_ISR_BMISS 0x00040000 /* Beacon missed interrupt */ +#define AR_ISR_HIUERR 0x00080000 /* An unexpected bus error has occurred */ +#define AR_ISR_BNR 0x00100000 /* Beacon not ready interrupt */ +#define AR_ISR_TIM 0x00800000 /* TIM interrupt */ +#define AR_ISR_GPIO 0x01000000 /* GPIO Interrupt */ +#define AR_ISR_QCBROVF 0x02000000 /* QCU CBR overflow interrupt */ +#define AR_ISR_QCBRURN 0x04000000 /* QCU CBR underrun interrupt */ +#define AR_ISR_QTRIG 0x08000000 /* QCU scheduling trigger interrupt */ +#define AR_ISR_RESV0 0xF0000000 /* Reserved */ + +#define AR_ISR_S0_QCU_TXOK_M 0x000003FF /* Mask for TXOK (QCU 0-9) */ +#define AR_ISR_S0_QCU_TXDESC_M 0x03FF0000 /* Mask for TXDESC (QCU 0-9) */ + +#define AR_ISR_S1_QCU_TXERR_M 0x000003FF /* Mask for TXERR (QCU 0-9) */ +#define AR_ISR_S1_QCU_TXEOL_M 0x03FF0000 /* Mask for TXEOL (QCU 0-9) */ + +#define AR_ISR_S2_QCU_TXURN_M 0x000003FF /* Mask for TXURN (QCU 0-9) */ +#define AR_ISR_S2_MCABT 0x00010000 /* Master cycle abort interrupt */ +#define AR_ISR_S2_SSERR 0x00020000 /* SERR interrupt */ +#define AR_ISR_S2_DPERR 0x00040000 /* PCI bus parity error */ +#define AR_ISR_S2_RESV0 0xFFF80000 /* Reserved */ + +#define AR_ISR_S3_QCU_QCBROVF_M 0x000003FF /* Mask for QCBROVF (QCU 0-9) */ +#define AR_ISR_S3_QCU_QCBRURN_M 0x03FF0000 /* Mask for QCBRURN (QCU 0-9) */ + +#define AR_ISR_S4_QCU_QTRIG_M 0x000003FF /* Mask for QTRIG (QCU 0-9) */ +#define AR_ISR_S4_RESV0 0xFFFFFC00 /* Reserved */ + + /* Interrupt Mask Registers */ +#define AR_IMR_RXOK 0x00000001 /* At least one frame received sans errors */ +#define AR_IMR_RXDESC 0x00000002 /* Receive interrupt request */ +#define AR_IMR_RXERR 0x00000004 /* Receive error interrupt */ +#define AR_IMR_RXNOPKT 0x00000008 /* No frame received within timeout clock */ +#define AR_IMR_RXEOL 0x00000010 /* Received descriptor empty interrupt */ +#define AR_IMR_RXORN 0x00000020 /* Receive FIFO overrun interrupt */ +#define AR_IMR_TXOK 0x00000040 /* Transmit okay interrupt */ +#define AR_IMR_TXDESC 0x00000080 /* Transmit interrupt request */ +#define AR_IMR_TXERR 0x00000100 /* Transmit error interrupt */ +#define AR_IMR_TXNOPKT 0x00000200 /* No frame transmitted interrupt */ +#define AR_IMR_TXEOL 0x00000400 /* Transmit descriptor empty interrupt */ +#define AR_IMR_TXURN 0x00000800 /* Transmit FIFO underrun interrupt */ +#define AR_IMR_MIB 0x00001000 /* MIB interrupt - see MIBC */ +#define AR_IMR_SWI 0x00002000 /* Software interrupt */ +#define AR_IMR_RXPHY 0x00004000 /* PHY receive error interrupt */ +#define AR_IMR_RXKCM 0x00008000 /* Key-cache miss interrupt */ +#define AR_IMR_SWBA 0x00010000 /* Software beacon alert interrupt */ +#define AR_IMR_BRSSI 0x00020000 /* Beacon threshold interrupt */ +#define AR_IMR_BMISS 0x00040000 /* Beacon missed interrupt */ +#define AR_IMR_HIUERR 0x00080000 /* An unexpected bus error has occurred */ +#define AR_IMR_BNR 0x00100000 /* BNR interrupt */ +#define AR_IMR_TIM 0x00800000 /* TIM interrupt */ +#define AR_IMR_GPIO 0x01000000 /* GPIO Interrupt */ +#define AR_IMR_QCBROVF 0x02000000 /* QCU CBR overflow interrupt */ +#define AR_IMR_QCBRURN 0x04000000 /* QCU CBR underrun interrupt */ +#define AR_IMR_QTRIG 0x08000000 /* QCU scheduling trigger interrupt */ +#define AR_IMR_RESV0 0xF0000000 /* Reserved */ + +#define AR_IMR_S0_QCU_TXOK 0x000003FF /* Mask for TXOK (QCU 0-9) */ +#define AR_IMR_S0_QCU_TXOK_S 0 +#define AR_IMR_S0_QCU_TXDESC 0x03FF0000 /* Mask for TXDESC (QCU 0-9) */ +#define AR_IMR_S0_QCU_TXDESC_S 16 /* Shift for TXDESC (QCU 0-9) */ + +#define AR_IMR_S1_QCU_TXERR 0x000003FF /* Mask for TXERR (QCU 0-9) */ +#define AR_IMR_S1_QCU_TXERR_S 0 +#define AR_IMR_S1_QCU_TXEOL 0x03FF0000 /* Mask for TXEOL (QCU 0-9) */ +#define AR_IMR_S1_QCU_TXEOL_S 16 /* Shift for TXEOL (QCU 0-9) */ + +#define AR_IMR_S2_QCU_TXURN 0x000003FF /* Mask for TXURN (QCU 0-9) */ +#define AR_IMR_S2_QCU_TXURN_S 0 +#define AR_IMR_S2_MCABT 0x00010000 /* Master cycle abort interrupt */ +#define AR_IMR_S2_SSERR 0x00020000 /* SERR interrupt */ +#define AR_IMR_S2_DPERR 0x00040000 /* PCI bus parity error */ +#define AR_IMR_S2_RESV0 0xFFF80000 /* Reserved */ + +#define AR_IMR_S3_QCU_QCBROVF_M 0x000003FF /* Mask for QCBROVF (QCU 0-9) */ +#define AR_IMR_S3_QCU_QCBRURN_M 0x03FF0000 /* Mask for QCBRURN (QCU 0-9) */ +#define AR_IMR_S3_QCU_QCBRURN_S 16 /* Shift for QCBRURN (QCU 0-9) */ + +#define AR_IMR_S4_QCU_QTRIG_M 0x000003FF /* Mask for QTRIG (QCU 0-9) */ +#define AR_IMR_S4_RESV0 0xFFFFFC00 /* Reserved */ + + /* Interrupt status registers (read-and-clear access, secondary shadow copies) */ + + /* QCU registers */ +#define AR_NUM_QCU 10 /* Only use QCU 0-9 for forward QCU compatibility */ +#define AR_QCU_0 0x0001 +#define AR_QCU_1 0x0002 +#define AR_QCU_2 0x0004 +#define AR_QCU_3 0x0008 +#define AR_QCU_4 0x0010 +#define AR_QCU_5 0x0020 +#define AR_QCU_6 0x0040 +#define AR_QCU_7 0x0080 +#define AR_QCU_8 0x0100 +#define AR_QCU_9 0x0200 + +#define AR_Q_TXE_M 0x000003FF /* Mask for TXE (QCU 0-9) */ + +#define AR_Q_TXD_M 0x000003FF /* Mask for TXD (QCU 0-9) */ + +#define AR_Q_CBRCFG_CBR_INTERVAL 0x00FFFFFF /* Mask for CBR interval (us) */ +#define AR_Q_CBRCFG_CBR_INTERVAL_S 0 /* Shift for CBR interval */ +#define AR_Q_CBRCFG_CBR_OVF_THRESH 0xFF000000 /* Mask for CBR overflow threshold */ +#define AR_Q_CBRCFG_CBR_OVF_THRESH_S 24 /* Shift for " " " */ + +#define AR_Q_RDYTIMECFG_INT 0x00FFFFFF /* CBR interval (us) */ +#define AR_Q_RDYTIMECFG_INT_S 0 /* Shift for ReadyTime Interval (us) */ +#define AR_Q_RDYTIMECFG_DURATION_M 0x00FFFFFF /* Mask for CBR interval (us) */ +#define AR_Q_RDYTIMECFG_EN 0x01000000 /* ReadyTime enable */ +#define AR_Q_RDYTIMECFG_RESV0 0xFE000000 /* Reserved */ + +#define AR_Q_ONESHOTARM_SC_M 0x0000FFFF /* Mask for MAC_Q_ONESHOTARM_SC (QCU 0-15) */ +#define AR_Q_ONESHOTARM_SC_RESV0 0xFFFF0000 /* Reserved */ + +#define AR_Q_ONESHOTARM_CC_M 0x0000FFFF /* Mask for MAC_Q_ONESHOTARM_CC (QCU 0-15) */ +#define AR_Q_ONESHOTARM_CC_RESV0 0xFFFF0000 /* Reserved */ + +#define AR_Q_MISC_FSP_M 0x0000000F /* Mask for Frame Scheduling Policy */ +#define AR_Q_MISC_FSP_ASAP 0 /* ASAP */ +#define AR_Q_MISC_FSP_CBR 1 /* CBR */ +#define AR_Q_MISC_FSP_DBA_GATED 2 /* DMA Beacon Alert gated */ +#define AR_Q_MISC_FSP_TIM_GATED 3 /* TIM gated */ +#define AR_Q_MISC_FSP_BEACON_SENT_GATED 4 /* Beacon-sent-gated */ +#define AR_Q_MISC_ONE_SHOT_EN 0x00000010 /* OneShot enable */ +#define AR_Q_MISC_CBR_INCR_DIS1 0x00000020 /* Disable CBR expired counter + incr (empty q) */ +#define AR_Q_MISC_CBR_INCR_DIS0 0x00000040 /* Disable CBR expired counter + incr (empty beacon q) */ +#define AR_Q_MISC_BEACON_USE 0x00000080 /* Beacon use indication */ +#define AR_Q_MISC_CBR_EXP_CNTR_LIMIT 0x00000100 /* CBR expired counter limit enable */ +#define AR_Q_MISC_RDYTIME_EXP_POLICY 0x00000200 /* Enable TXE cleared on ReadyTime expired or VEOL */ +#define AR_Q_MISC_RESET_CBR_EXP_CTR 0x00000400 /* Reset CBR expired counter */ +#define AR_Q_MISC_DCU_EARLY_TERM_REQ 0x00000800 /* DCU frame early termination request control */ +#define AR_Q_MISC_RESV0 0xFFFFF000 /* Reserved */ + +#define AR_Q_STS_PEND_FR_CNT_M 0x00000003 /* Mask for Pending Frame Count */ +#define AR_Q_STS_RESV0 0x000000FC /* Reserved */ +#define AR_Q_STS_CBR_EXP_CNT_M 0x0000FF00 /* Mask for CBR expired counter */ +#define AR_Q_STS_RESV1 0xFFFF0000 /* Reserved */ + +#define AR_Q_RDYTIMESHDN_M 0x000003FF /* Mask for ReadyTimeShutdown status (QCU 0-9) */ + + /* DCU registers */ +#define AR_NUM_DCU 10 /* Only use 10 DCU's for forward QCU/DCU compatibility */ +#define AR_DCU_0 0x0001 +#define AR_DCU_1 0x0002 +#define AR_DCU_2 0x0004 +#define AR_DCU_3 0x0008 +#define AR_DCU_4 0x0010 +#define AR_DCU_5 0x0020 +#define AR_DCU_6 0x0040 +#define AR_DCU_7 0x0080 +#define AR_DCU_8 0x0100 +#define AR_DCU_9 0x0200 + +#define AR_D_QCUMASK_M 0x000003FF /* Mask for QCU Mask (QCU 0-9) */ +#define AR_D_QCUMASK_RESV0 0xFFFFFC00 /* Reserved */ + +#define AR_D_LCL_IFS_CWMIN 0x000003FF /* Mask for CW_MIN */ +#define AR_D_LCL_IFS_CWMIN_S 0 /* Shift for CW_MIN */ +#define AR_D_LCL_IFS_CWMAX 0x000FFC00 /* Mask for CW_MAX */ +#define AR_D_LCL_IFS_CWMAX_S 10 /* Shift for CW_MAX */ +#define AR_D_LCL_IFS_AIFS 0x0FF00000 /* Mask for AIFS */ +#define AR_D_LCL_IFS_AIFS_S 20 /* Shift for AIFS */ +#define AR_D_LCL_IFS_RESV0 0xF0000000 /* Reserved */ + +#define AR_D_RETRY_LIMIT_FR_SH 0x0000000F /* Mask for frame short retry limit */ +#define AR_D_RETRY_LIMIT_FR_SH_S 0 /* Shift for frame short retry limit */ +#define AR_D_RETRY_LIMIT_FR_LG 0x000000F0 /* Mask for frame long retry limit */ +#define AR_D_RETRY_LIMIT_FR_LG_S 4 /* Shift for frame long retry limit */ +#define AR_D_RETRY_LIMIT_STA_SH 0x00003F00 /* Mask for station short retry limit */ +#define AR_D_RETRY_LIMIT_STA_SH_S 8 /* Shift for station short retry limit */ +#define AR_D_RETRY_LIMIT_STA_LG 0x000FC000 /* Mask for station short retry limit */ +#define AR_D_RETRY_LIMIT_STA_LG_S 14 /* Shift for station short retry limit */ +#define AR_D_RETRY_LIMIT_RESV0 0xFFF00000 /* Reserved */ + +#define AR_D_CHNTIME_EN 0x00100000 /* ChannelTime enable */ +#define AR_D_CHNTIME_RESV0 0xFFE00000 /* Reserved */ +#define AR_D_CHNTIME_DUR 0x000FFFFF /* Mask for ChannelTime duration (us) */ +#define AR_D_CHNTIME_DUR_S 0 /* Shift for ChannelTime duration */ + +#define AR_D_MISC_BKOFF_THRESH_M 0x000007FF /* Mask for Backoff threshold setting */ +#define AR_D_MISC_FRAG_BKOFF_EN 0x00000200 /* Backoff during a frag burst */ +#define AR_D_MISC_HCF_POLL_EN 0x00000800 /* HFC poll enable */ +#define AR_D_MISC_BKOFF_PERSISTENCE 0x00001000 /* Backoff persistence factor setting */ +#define AR_D_MISC_FR_PREFETCH_EN 0x00002000 /* Frame prefetch enable */ +#define AR_D_MISC_VIR_COL_HANDLING_M 0x0000C000 /* Mask for Virtual collision handling policy */ +#define AR_D_MISC_VIR_COL_HANDLING_NORMAL 0 /* Normal */ +#define AR_D_MISC_VIR_COL_HANDLING_MODIFIED 1 /* Modified */ +#define AR_D_MISC_VIR_COL_HANDLING_IGNORE 2 /* Ignore */ +#define AR_D_MISC_BEACON_USE 0x00010000 /* Beacon use indication */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL 0x00060000 /* Mask for DCU arbiter lockout control */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_S 17 /* Shift for DCU arbiter lockout control */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_NONE 0 /* No lockout */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR 1 /* Intra-frame */ +#define AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL 2 /* Global */ +#define AR_D_MISC_ARB_LOCKOUT_IGNORE 0x00080000 /* DCU arbiter lockout ignore control */ +#define AR_D_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Sequence number increment disable */ +#define AR_D_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Post-frame backoff disable */ +#define AR_D_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual coll. handling policy */ +#define AR_D_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS handling policy */ +#define AR5311_D_MISC_SEQ_NUM_CONTROL 0x01000000 /* Sequence Number local or global */ + /* Maui2/Spirit only, reserved on Oahu */ +#define AR_D_MISC_RESV0 0xFE000000 /* Reserved */ + +#define AR_D_SEQNUM_M 0x00000FFF /* Mask for value of sequence number */ +#define AR_D_SEQNUM_RESV0 0xFFFFF000 /* Reserved */ + +#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 /* Mask forLFSR slice select */ +#define AR_D_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode indication */ +#define AR_D_GBL_IFS_MISC_SIFS_DURATION_USEC 0x000003F0 /* Mask for SIFS duration (us) */ +#define AR_D_GBL_IFS_MISC_USEC_DURATION 0x000FFC00 /* Mask for microsecond duration */ +#define AR_D_GBL_IFS_MISC_DCU_ARBITER_DLY 0x00300000 /* Mask for DCU arbiter delay */ +#define AR_D_GBL_IFS_MISC_RESV0 0xFFC00000 /* Reserved */ + +/* Oahu only */ +#define AR_D_TXPSE_CTRL_M 0x000003FF /* Mask of DCUs to pause (DCUs 0-9) */ +#define AR_D_TXPSE_RESV0 0x0000FC00 /* Reserved */ +#define AR_D_TXPSE_STATUS 0x00010000 /* Transmit pause status */ +#define AR_D_TXPSE_RESV1 0xFFFE0000 /* Reserved */ + + /* DMA & PCI Registers in PCI space (usable during sleep) */ +#define AR_RC_MAC 0x00000001 /* MAC reset */ +#define AR_RC_BB 0x00000002 /* Baseband reset */ +#define AR_RC_RESV0 0x00000004 /* Reserved */ +#define AR_RC_RESV1 0x00000008 /* Reserved */ +#define AR_RC_PCI 0x00000010 /* PCI-core reset */ +#define AR_RC_BITS "\20\1MAC\2BB\3RESV0\4RESV1\5RPCI" + +#define AR_SCR_SLDUR 0x0000ffff /* sleep duration mask, units of 128us */ +#define AR_SCR_SLDUR_S 0 +#define AR_SCR_SLE 0x00030000 /* sleep enable mask */ +#define AR_SCR_SLE_S 16 /* sleep enable bits shift */ +/* + * The previous values for the following three defines were: + * + * AR_SCR_SLE_WAKE 0x00000000 + * AR_SCR_SLE_SLP 0x00010000 + * AR_SCR_SLE_NORM 0x00020000 + * + * However, these have been pre-shifted with AR_SCR_SLE_S. The + * OS_REG_READ() macro would attempt to shift them again, effectively + * shifting out any of the set bits completely. + */ +#define AR_SCR_SLE_WAKE 0 /* force wake */ +#define AR_SCR_SLE_SLP 1 /* force sleep */ +#define AR_SCR_SLE_NORM 2 /* sleep logic normal operation */ +#define AR_SCR_SLE_UNITS 0x00000008 /* SCR units/TU */ +#define AR_SCR_BITS "\20\20SLE_SLP\21SLE" + +#define AR_INTPEND_TRUE 0x00000001 /* interrupt pending */ +#define AR_INTPEND_BITS "\20\1IP" + +#define AR_SFR_SLEEP 0x00000001 /* force sleep */ + +#define AR_PCICFG_CLKRUNEN 0x00000004 /* enable PCI CLKRUN function */ +#define AR_PCICFG_EEPROM_SIZE_M 0x00000018 /* Mask for EEPROM size */ +#define AR_PCICFG_EEPROM_SIZE_S 3 /* Mask for EEPROM size */ +#define AR_PCICFG_EEPROM_SIZE_4K 0 /* EEPROM size 4 Kbit */ +#define AR_PCICFG_EEPROM_SIZE_8K 1 /* EEPROM size 8 Kbit */ +#define AR_PCICFG_EEPROM_SIZE_16K 2 /* EEPROM size 16 Kbit */ +#define AR_PCICFG_EEPROM_SIZE_FAILED 3 /* Failure */ +#define AR_PCICFG_LEDCTL 0x00000060 /* LED control Status */ +#define AR_PCICFG_LEDCTL_NONE 0x00000000 /* STA is not associated or trying */ +#define AR_PCICFG_LEDCTL_PEND 0x00000020 /* STA is trying to associate */ +#define AR_PCICFG_LEDCTL_ASSOC 0x00000040 /* STA is associated */ +#define AR_PCICFG_PCI_BUS_SEL_M 0x00000380 /* Mask for PCI observation bus mux select */ +#define AR_PCICFG_DIS_CBE_FIX 0x00000400 /* Disable fix for bad PCI CBE# generation */ +#define AR_PCICFG_SL_INTEN 0x00000800 /* enable interrupt line assertion when asleep */ +#define AR_PCICFG_RESV0 0x00001000 /* Reserved */ +#define AR_PCICFG_SL_INPEN 0x00002000 /* Force asleep when an interrupt is pending */ +#define AR_PCICFG_RESV1 0x0000C000 /* Reserved */ +#define AR_PCICFG_SPWR_DN 0x00010000 /* mask for sleep/awake indication */ +#define AR_PCICFG_LEDMODE 0x000E0000 /* LED mode */ +#define AR_PCICFG_LEDMODE_PROP 0x00000000 /* Blink prop to filtered tx/rx */ +#define AR_PCICFG_LEDMODE_RPROP 0x00020000 /* Blink prop to unfiltered tx/rx */ +#define AR_PCICFG_LEDMODE_SPLIT 0x00040000 /* Blink power for tx/net for rx */ +#define AR_PCICFG_LEDMODE_RAND 0x00060000 /* Blink randomly */ +#define AR_PCICFG_LEDBLINK 0x00700000 /* LED blink threshold select */ +#define AR_PCICFG_LEDBLINK_S 20 +#define AR_PCICFG_LEDSLOW 0x00800000 /* LED slowest blink rate mode */ +#define AR_PCICFG_RESV2 0xFF000000 /* Reserved */ +#define AR_PCICFG_BITS "\20\3CLKRUNEN\13SL_INTEN" + +#define AR_GPIOCR_CR_SHIFT 2 /* Each CR is 2 bits */ +#define AR_GPIOCR_0_CR_N 0x00000000 /* Input only mode for GPIODO[0] */ +#define AR_GPIOCR_0_CR_0 0x00000001 /* Output only if GPIODO[0] = 0 */ +#define AR_GPIOCR_0_CR_1 0x00000002 /* Output only if GPIODO[0] = 1 */ +#define AR_GPIOCR_0_CR_A 0x00000003 /* Always output */ +#define AR_GPIOCR_1_CR_N 0x00000000 /* Input only mode for GPIODO[1] */ +#define AR_GPIOCR_1_CR_0 0x00000004 /* Output only if GPIODO[1] = 0 */ +#define AR_GPIOCR_1_CR_1 0x00000008 /* Output only if GPIODO[1] = 1 */ +#define AR_GPIOCR_1_CR_A 0x0000000C /* Always output */ +#define AR_GPIOCR_2_CR_N 0x00000000 /* Input only mode for GPIODO[2] */ +#define AR_GPIOCR_2_CR_0 0x00000010 /* Output only if GPIODO[2] = 0 */ +#define AR_GPIOCR_2_CR_1 0x00000020 /* Output only if GPIODO[2] = 1 */ +#define AR_GPIOCR_2_CR_A 0x00000030 /* Always output */ +#define AR_GPIOCR_3_CR_N 0x00000000 /* Input only mode for GPIODO[3] */ +#define AR_GPIOCR_3_CR_0 0x00000040 /* Output only if GPIODO[3] = 0 */ +#define AR_GPIOCR_3_CR_1 0x00000080 /* Output only if GPIODO[3] = 1 */ +#define AR_GPIOCR_3_CR_A 0x000000C0 /* Always output */ +#define AR_GPIOCR_4_CR_N 0x00000000 /* Input only mode for GPIODO[4] */ +#define AR_GPIOCR_4_CR_0 0x00000100 /* Output only if GPIODO[4] = 0 */ +#define AR_GPIOCR_4_CR_1 0x00000200 /* Output only if GPIODO[4] = 1 */ +#define AR_GPIOCR_4_CR_A 0x00000300 /* Always output */ +#define AR_GPIOCR_5_CR_N 0x00000000 /* Input only mode for GPIODO[5] */ +#define AR_GPIOCR_5_CR_0 0x00000400 /* Output only if GPIODO[5] = 0 */ +#define AR_GPIOCR_5_CR_1 0x00000800 /* Output only if GPIODO[5] = 1 */ +#define AR_GPIOCR_5_CR_A 0x00000C00 /* Always output */ +#define AR_GPIOCR_INT_SHIFT 12 /* Interrupt select field shifter */ +#define AR_GPIOCR_INT_MASK 0x00007000 /* Interrupt select field mask */ +#define AR_GPIOCR_INT_SEL0 0x00000000 /* Select Interrupt Pin GPIO_0 */ +#define AR_GPIOCR_INT_SEL1 0x00001000 /* Select Interrupt Pin GPIO_1 */ +#define AR_GPIOCR_INT_SEL2 0x00002000 /* Select Interrupt Pin GPIO_2 */ +#define AR_GPIOCR_INT_SEL3 0x00003000 /* Select Interrupt Pin GPIO_3 */ +#define AR_GPIOCR_INT_SEL4 0x00004000 /* Select Interrupt Pin GPIO_4 */ +#define AR_GPIOCR_INT_SEL5 0x00005000 /* Select Interrupt Pin GPIO_5 */ +#define AR_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO Interrupt */ +#define AR_GPIOCR_INT_SELL 0x00000000 /* Generate Interrupt if selected pin is low */ +#define AR_GPIOCR_INT_SELH 0x00010000 /* Generate Interrupt if selected pin is high */ + +#define AR_SREV_ID_M 0x000000FF /* Mask to read SREV info */ +#define AR_PCICFG_EEPROM_SIZE_16K 2 /* EEPROM size 16 Kbit */ +#define AR_SREV_ID_S 4 /* Major Rev Info */ +#define AR_SREV_REVISION_M 0x0000000F /* Chip revision level */ +#define AR_SREV_FPGA 1 +#define AR_SREV_D2PLUS 2 +#define AR_SREV_D2PLUS_MS 3 /* metal spin */ +#define AR_SREV_CRETE 4 +#define AR_SREV_CRETE_MS 5 /* FCS metal spin */ +#define AR_SREV_CRETE_MS23 7 /* 2.3 metal spin (6 skipped) */ +#define AR_SREV_CRETE_23 8 /* 2.3 full tape out */ +#define AR_SREV_VERSION_M 0x000000F0 /* Chip version indication */ +#define AR_SREV_VERSION_CRETE 0 +#define AR_SREV_VERSION_MAUI_1 1 +#define AR_SREV_VERSION_MAUI_2 2 +#define AR_SREV_VERSION_SPIRIT 3 +#define AR_SREV_VERSION_OAHU 4 +#define AR_SREV_OAHU_ES 0 /* Engineering Sample */ +#define AR_SREV_OAHU_PROD 2 /* Production */ + +#define RAD5_SREV_MAJOR 0x10 /* All current supported ar5211 5 GHz radios are rev 0x10 */ +#define RAD5_SREV_PROD 0x15 /* Current production level radios */ +#define RAD2_SREV_MAJOR 0x20 /* All current supported ar5211 2 GHz radios are rev 0x10 */ + + /* EEPROM Registers in the MAC */ +#define AR_EEPROM_CMD_READ 0x00000001 +#define AR_EEPROM_CMD_WRITE 0x00000002 +#define AR_EEPROM_CMD_RESET 0x00000004 + +#define AR_EEPROM_STS_READ_ERROR 0x00000001 +#define AR_EEPROM_STS_READ_COMPLETE 0x00000002 +#define AR_EEPROM_STS_WRITE_ERROR 0x00000004 +#define AR_EEPROM_STS_WRITE_COMPLETE 0x00000008 + +#define AR_EEPROM_CFG_SIZE_M 0x00000003 /* Mask for EEPROM size determination override */ +#define AR_EEPROM_CFG_SIZE_AUTO 0 +#define AR_EEPROM_CFG_SIZE_4KBIT 1 +#define AR_EEPROM_CFG_SIZE_8KBIT 2 +#define AR_EEPROM_CFG_SIZE_16KBIT 3 +#define AR_EEPROM_CFG_DIS_WAIT_WRITE_COMPL 0x00000004 /* Disable wait for write completion */ +#define AR_EEPROM_CFG_CLOCK_M 0x00000018 /* Mask for EEPROM clock rate control */ +#define AR_EEPROM_CFG_CLOCK_S 3 /* Shift for EEPROM clock rate control */ +#define AR_EEPROM_CFG_CLOCK_156KHZ 0 +#define AR_EEPROM_CFG_CLOCK_312KHZ 1 +#define AR_EEPROM_CFG_CLOCK_625KHZ 2 +#define AR_EEPROM_CFG_RESV0 0x000000E0 /* Reserved */ +#define AR_EEPROM_CFG_PROT_KEY_M 0x00FFFF00 /* Mask for EEPROM protection key */ +#define AR_EEPROM_CFG_PROT_KEY_S 8 /* Shift for EEPROM protection key */ +#define AR_EEPROM_CFG_EN_L 0x01000000 /* EPRM_EN_L setting */ + + /* MAC PCU Registers */ +#define AR_STA_ID1_SADH_MASK 0x0000FFFF /* Mask for upper 16 bits of MAC addr */ +#define AR_STA_ID1_STA_AP 0x00010000 /* Device is AP */ +#define AR_STA_ID1_ADHOC 0x00020000 /* Device is ad-hoc */ +#define AR_STA_ID1_PWR_SAV 0x00040000 /* Power save reporting in self-generated frames */ +#define AR_STA_ID1_KSRCHDIS 0x00080000 /* Key search disable */ +#define AR_STA_ID1_PCF 0x00100000 /* Observe PCF */ +#define AR_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ +#define AR_STA_ID1_DESC_ANTENNA 0x00400000 /* Update default antenna w/ TX antenna */ +#define AR_STA_ID1_RTS_USE_DEF 0x00800000 /* Use default antenna to send RTS */ +#define AR_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mb/s rate for ACK & CTS */ +#define AR_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK & CTS */ +#define AR_STA_ID1_BITS \ + "\20\20AP\21ADHOC\22PWR_SAV\23KSRCHDIS\25PCF" + +#define AR_BSS_ID1_U16_M 0x0000FFFF /* Mask for upper 16 bits of BSSID */ +#define AR_BSS_ID1_AID_M 0xFFFF0000 /* Mask for association ID */ +#define AR_BSS_ID1_AID_S 16 /* Shift for association ID */ + +#define AR_SLOT_TIME_MASK 0x000007FF /* Slot time mask */ + +#define AR_TIME_OUT_ACK 0x00001FFF /* Mask for ACK time-out */ +#define AR_TIME_OUT_ACK_S 0 /* Shift for ACK time-out */ +#define AR_TIME_OUT_CTS 0x1FFF0000 /* Mask for CTS time-out */ +#define AR_TIME_OUT_CTS_S 16 /* Shift for CTS time-out */ + +#define AR_RSSI_THR_MASK 0x000000FF /* Mask for Beacon RSSI warning threshold */ +#define AR_RSSI_THR_BM_THR 0x0000FF00 /* Mask for Missed beacon threshold */ +#define AR_RSSI_THR_BM_THR_S 8 /* Shift for Missed beacon threshold */ + +#define AR_USEC_M 0x0000007F /* Mask for clock cycles in 1 usec */ +#define AR_USEC_32_M 0x00003F80 /* Mask for number of 32MHz clock cycles in 1 usec */ +#define AR_USEC_32_S 7 /* Shift for number of 32MHz clock cycles in 1 usec */ +/* + * Tx/Rx latencies are to signal start and are in usecs. + * + * NOTE: AR5211/AR5311 difference: on Oahu, the TX latency field + * has increased from 6 bits to 9 bits. The RX latency field + * is unchanged, but is shifted over 3 bits. + */ +#define AR5311_USEC_TX_LAT_M 0x000FC000 /* Tx latency */ +#define AR5311_USEC_TX_LAT_S 14 +#define AR5311_USEC_RX_LAT_M 0x03F00000 /* Rx latency */ +#define AR5311_USEC_RX_LAT_S 20 + +#define AR5211_USEC_TX_LAT_M 0x007FC000 /* Tx latency */ +#define AR5211_USEC_TX_LAT_S 14 +#define AR5211_USEC_RX_LAT_M 0x1F800000 /* Rx latency */ +#define AR5211_USEC_RX_LAT_S 23 + +#define AR_BEACON_PERIOD 0x0000FFFF /* Beacon period in TU/msec */ +#define AR_BEACON_PERIOD_S 0 /* Byte offset of PERIOD start*/ +#define AR_BEACON_TIM 0x007F0000 /* Byte offset of TIM start */ +#define AR_BEACON_TIM_S 16 /* Byte offset of TIM start */ +#define AR_BEACON_EN 0x00800000 /* beacon enable */ +#define AR_BEACON_RESET_TSF 0x01000000 /* Clears TSF to 0 */ +#define AR_BEACON_BITS "\20\27ENABLE\30RESET_TSF" + +#define AR_RX_FILTER_ALL 0x00000000 /* Disallow all frames */ +#define AR_RX_UCAST 0x00000001 /* Allow unicast frames */ +#define AR_RX_MCAST 0x00000002 /* Allow multicast frames */ +#define AR_RX_BCAST 0x00000004 /* Allow broadcast frames */ +#define AR_RX_CONTROL 0x00000008 /* Allow control frames */ +#define AR_RX_BEACON 0x00000010 /* Allow beacon frames */ +#define AR_RX_PROM 0x00000020 /* Promiscuous mode */ +#define AR_RX_PHY_ERR 0x00000040 /* Allow all phy errors */ +#define AR_RX_PHY_RADAR 0x00000080 /* Allow radar phy errors */ +#define AR_RX_FILTER_BITS \ + "\20\1UCAST\2MCAST\3BCAST\4CONTROL\5BEACON\6PROMISC\7PHY_ERR\10PHY_RADAR" + +#define AR_DIAG_SW_CACHE_ACK 0x00000001 /* disable ACK if no valid key*/ +#define AR_DIAG_SW_DIS_ACK 0x00000002 /* disable ACK generation */ +#define AR_DIAG_SW_DIS_CTS 0x00000004 /* disable CTS generation */ +#define AR_DIAG_SW_DIS_ENCRYPT 0x00000008 /* disable encryption */ +#define AR_DIAG_SW_DIS_DECRYPT 0x00000010 /* disable decryption */ +#define AR_DIAG_SW_DIS_RX 0x00000020 /* disable receive */ +#define AR_DIAG_SW_CORR_FCS 0x00000080 /* corrupt FCS */ +#define AR_DIAG_SW_CHAN_INFO 0x00000100 /* dump channel info */ +#define AR_DIAG_SW_EN_SCRAMSD 0x00000200 /* enable fixed scrambler seed*/ +#define AR5311_DIAG_SW_USE_ECO 0x00000400 /* "super secret" use ECO enable bit */ +#define AR_DIAG_SW_SCRAM_SEED_M 0x0001FC00 /* Fixed scrambler seed mask */ +#define AR_DIAG_SW_SCRAM_SEED_S 10 /* Fixed scrambler seed shfit */ +#define AR_DIAG_SW_FRAME_NV0 0x00020000 /* accept frames of non-zero protocol version */ +#define AR_DIAG_SW_OBS_PT_SEL_M 0x000C0000 /* Observation point select */ +#define AR_DIAG_SW_OBS_PT_SEL_S 18 /* Observation point select */ +#define AR_DIAG_SW_BITS \ + "\20\1DIS_CACHE_ACK\2DIS_ACK\3DIS_CTS\4DIS_ENC\5DIS_DEC\6DIS_RX"\ + "\11CORR_FCS\12CHAN_INFO\13EN_SCRAM_SEED\14USE_ECO\24FRAME_NV0" + +#define AR_KEYTABLE_KEY0(n) (AR_KEYTABLE(n) + 0) /* key bit 0-31 */ +#define AR_KEYTABLE_KEY1(n) (AR_KEYTABLE(n) + 4) /* key bit 32-47 */ +#define AR_KEYTABLE_KEY2(n) (AR_KEYTABLE(n) + 8) /* key bit 48-79 */ +#define AR_KEYTABLE_KEY3(n) (AR_KEYTABLE(n) + 12) /* key bit 80-95 */ +#define AR_KEYTABLE_KEY4(n) (AR_KEYTABLE(n) + 16) /* key bit 96-127 */ +#define AR_KEYTABLE_TYPE(n) (AR_KEYTABLE(n) + 20) /* key type */ +#define AR_KEYTABLE_TYPE_40 0x00000000 /* WEP 40 bit key */ +#define AR_KEYTABLE_TYPE_104 0x00000001 /* WEP 104 bit key */ +#define AR_KEYTABLE_TYPE_128 0x00000003 /* WEP 128 bit key */ +#define AR_KEYTABLE_TYPE_AES 0x00000005 /* AES 128 bit key */ +#define AR_KEYTABLE_TYPE_CLR 0x00000007 /* no encryption */ +#define AR_KEYTABLE_MAC0(n) (AR_KEYTABLE(n) + 24) /* MAC address 1-32 */ +#define AR_KEYTABLE_MAC1(n) (AR_KEYTABLE(n) + 28) /* MAC address 33-47 */ +#define AR_KEYTABLE_VALID 0x00008000 /* key and MAC address valid */ + +#endif /* _DEV_ATH_AR5211REG_H */ diff --git a/sys/dev/ath/ath_hal/ar5211/boss.ini b/sys/dev/ath/ath_hal/ar5211/boss.ini new file mode 100644 index 000000000000..5619d01c4a4b --- /dev/null +++ b/sys/dev/ath/ath_hal/ar5211/boss.ini @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Atheros Communications, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* Auto Generated PCI Register Writes. Created: 09/12/02 */ + +static const uint32_t ar5211Modes[][5] = { + { 0x00000030, 0x00000015, 0x00000015, 0x0000001d, 0x00000015 }, + { 0x00001040, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f }, + { 0x00001070, 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 }, + { 0x00001030, 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 }, + { 0x000010b0, 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 }, + { 0x000010f0, 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 }, + { 0x00008014, 0x04000400, 0x08000800, 0x20003000, 0x04000400 }, + { 0x0000801c, 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 }, + { 0x00009804, 0x00000000, 0x00000003, 0x00000000, 0x00000000 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02010200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b }, + { 0x00009844, 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c }, + { 0x00009848, 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 }, + { 0x00009850, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 }, + { 0x00009858, 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e }, + { 0x0000985c, 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e }, + { 0x00009860, 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 }, + { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009914, 0x00002710, 0x00002710, 0x0000157c, 0x00002710 }, + { 0x00009918, 0x00000190, 0x00000190, 0x00000084, 0x00000190 }, + { 0x00009944, 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 }, + { 0x0000a180, 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff }, + { 0x000098d4, 0x00000010, 0x00000014, 0x00000010, 0x00000010 }, +}; + +static const uint32_t ar5211Common[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000028, 0x84849c9c }, + { 0x0000002c, 0x7c7c7c7c }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001230, 0x00000000 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000000 }, + { 0x00008024, 0x00000000 }, + { 0x00008028, 0x00000030 }, + { 0x0000802c, 0x0007ffff }, + { 0x00008030, 0x01ffffff }, + { 0x00008034, 0x00000031 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008040, 0x00000000 }, + { 0x00008044, 0x00000002 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0x2d849093 }, + { 0x00009810, 0x7d32e000 }, + { 0x00009814, 0x00000f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x00026ffe }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00020100 }, + { 0x00009840, 0x206a017a }, + { 0x0000984c, 0x1284613c }, + { 0x00009854, 0x00000859 }, + { 0x00009868, 0x409a4190 }, + { 0x0000986c, 0x050cb081 }, + { 0x00009870, 0x0000000f }, + { 0x00009874, 0x00000080 }, + { 0x00009878, 0x0000000c }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00800000 }, + { 0x00009910, 0x00000001 }, + { 0x0000991c, 0x0000092a }, + { 0x00009920, 0x00000000 }, + { 0x00009924, 0x00058a05 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000000 }, + { 0x00009930, 0x00000000 }, + { 0x00009934, 0x00000000 }, + { 0x00009938, 0x00000000 }, + { 0x0000993c, 0x0000003f }, + { 0x00009940, 0x00000004 }, + { 0x00009948, 0x00000000 }, + { 0x0000994c, 0x00000000 }, + { 0x00009950, 0x00000000 }, + { 0x00009954, 0x5d50f14c }, + { 0x00009958, 0x00000018 }, + { 0x0000995c, 0x004b6a8e }, + { 0x0000a184, 0x06ff05ff }, + { 0x0000a188, 0x07ff07ff }, + { 0x0000a18c, 0x08ff08ff }, + { 0x0000a190, 0x09ff09ff }, + { 0x0000a194, 0x0aff0aff }, + { 0x0000a198, 0x0bff0bff }, + { 0x0000a19c, 0x0cff0cff }, + { 0x0000a1a0, 0x0dff0dff }, + { 0x0000a1a4, 0x0fff0eff }, + { 0x0000a1a8, 0x12ff12ff }, + { 0x0000a1ac, 0x14ff13ff }, + { 0x0000a1b0, 0x16ff15ff }, + { 0x0000a1b4, 0x19ff17ff }, + { 0x0000a1b8, 0x1bff1aff }, + { 0x0000a1bc, 0x1eff1dff }, + { 0x0000a1c0, 0x23ff20ff }, + { 0x0000a1c4, 0x27ff25ff }, + { 0x0000a1c8, 0x2cff29ff }, + { 0x0000a1cc, 0x31ff2fff }, + { 0x0000a1d0, 0x37ff34ff }, + { 0x0000a1d4, 0x3aff3aff }, + { 0x0000a1d8, 0x3aff3aff }, + { 0x0000a1dc, 0x3aff3aff }, + { 0x0000a1e0, 0x3aff3aff }, + { 0x0000a1e4, 0x3aff3aff }, + { 0x0000a1e8, 0x3aff3aff }, + { 0x0000a1ec, 0x3aff3aff }, + { 0x0000a1f0, 0x3aff3aff }, + { 0x0000a1f4, 0x3aff3aff }, + { 0x0000a1f8, 0x3aff3aff }, + { 0x0000a1fc, 0x3aff3aff }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000020 }, + { 0x00009b08, 0x00000010 }, + { 0x00009b0c, 0x00000030 }, + { 0x00009b10, 0x00000008 }, + { 0x00009b14, 0x00000028 }, + { 0x00009b18, 0x00000004 }, + { 0x00009b1c, 0x00000024 }, + { 0x00009b20, 0x00000014 }, + { 0x00009b24, 0x00000034 }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000002c }, + { 0x00009b30, 0x00000002 }, + { 0x00009b34, 0x00000022 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000032 }, + { 0x00009b40, 0x0000000a }, + { 0x00009b44, 0x0000002a }, + { 0x00009b48, 0x00000006 }, + { 0x00009b4c, 0x00000026 }, + { 0x00009b50, 0x00000016 }, + { 0x00009b54, 0x00000036 }, + { 0x00009b58, 0x0000000e }, + { 0x00009b5c, 0x0000002e }, + { 0x00009b60, 0x00000001 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000011 }, + { 0x00009b6c, 0x00000031 }, + { 0x00009b70, 0x00000009 }, + { 0x00009b74, 0x00000029 }, + { 0x00009b78, 0x00000005 }, + { 0x00009b7c, 0x00000025 }, + { 0x00009b80, 0x00000015 }, + { 0x00009b84, 0x00000035 }, + { 0x00009b88, 0x0000000d }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000003 }, + { 0x00009b94, 0x00000023 }, + { 0x00009b98, 0x00000013 }, + { 0x00009b9c, 0x00000033 }, + { 0x00009ba0, 0x0000000b }, + { 0x00009ba4, 0x0000002b }, + { 0x00009ba8, 0x0000002b }, + { 0x00009bac, 0x0000002b }, + { 0x00009bb0, 0x0000002b }, + { 0x00009bb4, 0x0000002b }, + { 0x00009bb8, 0x0000002b }, + { 0x00009bbc, 0x0000002b }, + { 0x00009bc0, 0x0000002b }, + { 0x00009bc4, 0x0000002b }, + { 0x00009bc8, 0x0000002b }, + { 0x00009bcc, 0x0000002b }, + { 0x00009bd0, 0x0000002b }, + { 0x00009bd4, 0x0000002b }, + { 0x00009bd8, 0x0000002b }, + { 0x00009bdc, 0x0000002b }, + { 0x00009be0, 0x0000002b }, + { 0x00009be4, 0x0000002b }, + { 0x00009be8, 0x0000002b }, + { 0x00009bec, 0x0000002b }, + { 0x00009bf0, 0x0000002b }, + { 0x00009bf4, 0x0000002b }, + { 0x00009bf8, 0x00000002 }, + { 0x00009bfc, 0x00000016 }, + { 0x000098d4, 0x00000020 }, + { 0x000098d8, 0x00601068 }, +}; + +static uint32_t ar5211Mode2_4[][3] = { + { 0x0000a204, 0x00000000, 0x00000000 }, + { 0x0000a208, 0x503e4646, 0x503e4646 }, + { 0x0000a20c, 0x6480416c, 0x6480416c }, + { 0x0000a210, 0x0199a003, 0x0199a003 }, + { 0x0000a214, 0x044cd610, 0x044cd610 }, + { 0x0000a218, 0x13800040, 0x13800040 }, + { 0x0000a21c, 0x1be00060, 0x1be00060 }, + { 0x0000a220, 0x0c53800a, 0x0c53800a }, + { 0x0000a224, 0x0014df3b, 0x0014df3b }, + { 0x0000a228, 0x000001b5, 0x000001b5 }, + { 0x0000a22c, 0x00000020, 0x00000020 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00380000, 0x00380000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x000400f9, 0x000400f9 }, + { 0x000098d4, 0x00000000, 0x00000004 }, +}; + +static const uint32_t ar5211BB_RfGain[][3] = { + { 0x00009a00, 0x000001a9, 0x00000000 }, + { 0x00009a04, 0x000001e9, 0x00000040 }, + { 0x00009a08, 0x00000029, 0x00000080 }, + { 0x00009a0c, 0x00000069, 0x00000150 }, + { 0x00009a10, 0x00000199, 0x00000190 }, + { 0x00009a14, 0x000001d9, 0x000001d0 }, + { 0x00009a18, 0x00000019, 0x00000010 }, + { 0x00009a1c, 0x00000059, 0x00000044 }, + { 0x00009a20, 0x00000099, 0x00000084 }, + { 0x00009a24, 0x000001a5, 0x00000148 }, + { 0x00009a28, 0x000001e5, 0x00000188 }, + { 0x00009a2c, 0x00000025, 0x000001c8 }, + { 0x00009a30, 0x000001c8, 0x00000014 }, + { 0x00009a34, 0x00000008, 0x00000042 }, + { 0x00009a38, 0x00000048, 0x00000082 }, + { 0x00009a3c, 0x00000088, 0x00000178 }, + { 0x00009a40, 0x00000198, 0x000001b8 }, + { 0x00009a44, 0x000001d8, 0x000001f8 }, + { 0x00009a48, 0x00000018, 0x00000012 }, + { 0x00009a4c, 0x00000058, 0x00000052 }, + { 0x00009a50, 0x00000098, 0x00000092 }, + { 0x00009a54, 0x000001a4, 0x0000017c }, + { 0x00009a58, 0x000001e4, 0x000001bc }, + { 0x00009a5c, 0x00000024, 0x000001fc }, + { 0x00009a60, 0x00000064, 0x0000000a }, + { 0x00009a64, 0x000000a4, 0x0000004a }, + { 0x00009a68, 0x000000e4, 0x0000008a }, + { 0x00009a6c, 0x0000010a, 0x0000015a }, + { 0x00009a70, 0x0000014a, 0x0000019a }, + { 0x00009a74, 0x0000018a, 0x000001da }, + { 0x00009a78, 0x000001ca, 0x0000000e }, + { 0x00009a7c, 0x0000000a, 0x0000004e }, + { 0x00009a80, 0x0000004a, 0x0000008e }, + { 0x00009a84, 0x0000008a, 0x0000015e }, + { 0x00009a88, 0x000001ba, 0x0000019e }, + { 0x00009a8c, 0x000001fa, 0x000001de }, + { 0x00009a90, 0x0000003a, 0x00000009 }, + { 0x00009a94, 0x0000007a, 0x00000049 }, + { 0x00009a98, 0x00000186, 0x00000089 }, + { 0x00009a9c, 0x000001c6, 0x00000179 }, + { 0x00009aa0, 0x00000006, 0x000001b9 }, + { 0x00009aa4, 0x00000046, 0x000001f9 }, + { 0x00009aa8, 0x00000086, 0x00000039 }, + { 0x00009aac, 0x000000c6, 0x00000079 }, + { 0x00009ab0, 0x000000c6, 0x000000b9 }, + { 0x00009ab4, 0x000000c6, 0x000001bd }, + { 0x00009ab8, 0x000000c6, 0x000001fd }, + { 0x00009abc, 0x000000c6, 0x0000003d }, + { 0x00009ac0, 0x000000c6, 0x0000007d }, + { 0x00009ac4, 0x000000c6, 0x000000bd }, + { 0x00009ac8, 0x000000c6, 0x000000fd }, + { 0x00009acc, 0x000000c6, 0x000000fd }, + { 0x00009ad0, 0x000000c6, 0x000000fd }, + { 0x00009ad4, 0x000000c6, 0x000000fd }, + { 0x00009ad8, 0x000000c6, 0x000000fd }, + { 0x00009adc, 0x000000c6, 0x000000fd }, + { 0x00009ae0, 0x000000c6, 0x000000fd }, + { 0x00009ae4, 0x000000c6, 0x000000fd }, + { 0x00009ae8, 0x000000c6, 0x000000fd }, + { 0x00009aec, 0x000000c6, 0x000000fd }, + { 0x00009af0, 0x000000c6, 0x000000fd }, + { 0x00009af4, 0x000000c6, 0x000000fd }, + { 0x00009af8, 0x000000c6, 0x000000fd }, + { 0x00009afc, 0x000000c6, 0x000000fd }, +}; + +static uint32_t ar5211Rf6n7[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x10000000, 0x10000000 }, + { 0x0000989c, 0x04000000, 0x04000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x0a000000 }, + { 0x0000989c, 0x00380080, 0x02380080 }, + { 0x0000989c, 0x00020006, 0x00000006 }, + { 0x0000989c, 0x00000092, 0x00000092 }, + { 0x0000989c, 0x000000a0, 0x000000a0 }, + { 0x0000989c, 0x00040007, 0x00040007 }, + { 0x000098d4, 0x0000001a, 0x0000001a }, + { 0x0000989c, 0x00000048, 0x00000048 }, + { 0x0000989c, 0x00000010, 0x00000010 }, + { 0x0000989c, 0x00000008, 0x00000008 }, + { 0x0000989c, 0x0000000f, 0x0000000f }, + { 0x0000989c, 0x000000f2, 0x00000062 }, + { 0x0000989c, 0x0000904f, 0x0000904c }, + { 0x0000989c, 0x0000125a, 0x0000129a }, + { 0x000098cc, 0x0000000e, 0x0000000f }, +}; + |