16e778a7eSPedro F. Giffuni /*-
26e778a7eSPedro F. Giffuni * SPDX-License-Identifier: ISC
36e778a7eSPedro F. Giffuni *
459efa8b5SSam Leffler * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
514779705SSam Leffler * Copyright (c) 2002-2008 Atheros Communications, Inc.
614779705SSam Leffler *
714779705SSam Leffler * Permission to use, copy, modify, and/or distribute this software for any
814779705SSam Leffler * purpose with or without fee is hereby granted, provided that the above
914779705SSam Leffler * copyright notice and this permission notice appear in all copies.
1014779705SSam Leffler *
1114779705SSam Leffler * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1214779705SSam Leffler * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1314779705SSam Leffler * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1414779705SSam Leffler * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1514779705SSam Leffler * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1614779705SSam Leffler * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1714779705SSam Leffler * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1814779705SSam Leffler */
1914779705SSam Leffler #include "opt_ah.h"
2014779705SSam Leffler
2114779705SSam Leffler #include "ah.h"
2214779705SSam Leffler #include "ah_internal.h"
2314779705SSam Leffler #include "ah_devid.h"
2414779705SSam Leffler
2514779705SSam Leffler #include "ar5212/ar5212.h"
2614779705SSam Leffler #include "ar5212/ar5212reg.h"
2714779705SSam Leffler #include "ar5212/ar5212phy.h"
2814779705SSam Leffler
2914779705SSam Leffler #define AH_5212_COMMON
3014779705SSam Leffler #include "ar5212/ar5212.ini"
3114779705SSam Leffler
32ae2a0aa4SAdrian Chadd static void ar5212ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
33ae2a0aa4SAdrian Chadd HAL_BOOL power_off);
3444834ea4SSam Leffler static void ar5212DisablePCIE(struct ath_hal *ah);
3544834ea4SSam Leffler
3614779705SSam Leffler static const struct ath_hal_private ar5212hal = {{
3714779705SSam Leffler .ah_magic = AR5212_MAGIC,
3814779705SSam Leffler
3914779705SSam Leffler .ah_getRateTable = ar5212GetRateTable,
4014779705SSam Leffler .ah_detach = ar5212Detach,
4114779705SSam Leffler
4214779705SSam Leffler /* Reset Functions */
4314779705SSam Leffler .ah_reset = ar5212Reset,
4414779705SSam Leffler .ah_phyDisable = ar5212PhyDisable,
4514779705SSam Leffler .ah_disable = ar5212Disable,
4644834ea4SSam Leffler .ah_configPCIE = ar5212ConfigPCIE,
4744834ea4SSam Leffler .ah_disablePCIE = ar5212DisablePCIE,
4814779705SSam Leffler .ah_setPCUConfig = ar5212SetPCUConfig,
4914779705SSam Leffler .ah_perCalibration = ar5212PerCalibration,
5014779705SSam Leffler .ah_perCalibrationN = ar5212PerCalibrationN,
5114779705SSam Leffler .ah_resetCalValid = ar5212ResetCalValid,
5214779705SSam Leffler .ah_setTxPowerLimit = ar5212SetTxPowerLimit,
5314779705SSam Leffler .ah_getChanNoise = ath_hal_getChanNoise,
5414779705SSam Leffler
5514779705SSam Leffler /* Transmit functions */
5614779705SSam Leffler .ah_updateTxTrigLevel = ar5212UpdateTxTrigLevel,
5714779705SSam Leffler .ah_setupTxQueue = ar5212SetupTxQueue,
5814779705SSam Leffler .ah_setTxQueueProps = ar5212SetTxQueueProps,
5914779705SSam Leffler .ah_getTxQueueProps = ar5212GetTxQueueProps,
6014779705SSam Leffler .ah_releaseTxQueue = ar5212ReleaseTxQueue,
6114779705SSam Leffler .ah_resetTxQueue = ar5212ResetTxQueue,
6214779705SSam Leffler .ah_getTxDP = ar5212GetTxDP,
6314779705SSam Leffler .ah_setTxDP = ar5212SetTxDP,
6414779705SSam Leffler .ah_numTxPending = ar5212NumTxPending,
6514779705SSam Leffler .ah_startTxDma = ar5212StartTxDma,
6614779705SSam Leffler .ah_stopTxDma = ar5212StopTxDma,
6714779705SSam Leffler .ah_setupTxDesc = ar5212SetupTxDesc,
6814779705SSam Leffler .ah_setupXTxDesc = ar5212SetupXTxDesc,
6914779705SSam Leffler .ah_fillTxDesc = ar5212FillTxDesc,
7014779705SSam Leffler .ah_procTxDesc = ar5212ProcTxDesc,
7114779705SSam Leffler .ah_getTxIntrQueue = ar5212GetTxIntrQueue,
7214779705SSam Leffler .ah_reqTxIntrDesc = ar5212IntrReqTxDesc,
739ea46744SAdrian Chadd .ah_getTxCompletionRates = ar5212GetTxCompletionRates,
74ad3e6dcdSAdrian Chadd .ah_setTxDescLink = ar5212SetTxDescLink,
75ad3e6dcdSAdrian Chadd .ah_getTxDescLink = ar5212GetTxDescLink,
76ad3e6dcdSAdrian Chadd .ah_getTxDescLinkPtr = ar5212GetTxDescLinkPtr,
7714779705SSam Leffler
7814779705SSam Leffler /* RX Functions */
7914779705SSam Leffler .ah_getRxDP = ar5212GetRxDP,
8014779705SSam Leffler .ah_setRxDP = ar5212SetRxDP,
8114779705SSam Leffler .ah_enableReceive = ar5212EnableReceive,
8214779705SSam Leffler .ah_stopDmaReceive = ar5212StopDmaReceive,
8314779705SSam Leffler .ah_startPcuReceive = ar5212StartPcuReceive,
8414779705SSam Leffler .ah_stopPcuReceive = ar5212StopPcuReceive,
8514779705SSam Leffler .ah_setMulticastFilter = ar5212SetMulticastFilter,
8614779705SSam Leffler .ah_setMulticastFilterIndex = ar5212SetMulticastFilterIndex,
8714779705SSam Leffler .ah_clrMulticastFilterIndex = ar5212ClrMulticastFilterIndex,
8814779705SSam Leffler .ah_getRxFilter = ar5212GetRxFilter,
8914779705SSam Leffler .ah_setRxFilter = ar5212SetRxFilter,
9014779705SSam Leffler .ah_setupRxDesc = ar5212SetupRxDesc,
9114779705SSam Leffler .ah_procRxDesc = ar5212ProcRxDesc,
92a108ab63SAdrian Chadd .ah_rxMonitor = ar5212RxMonitor,
93a108ab63SAdrian Chadd .ah_aniPoll = ar5212AniPoll,
9414779705SSam Leffler .ah_procMibEvent = ar5212ProcessMibIntr,
9514779705SSam Leffler
9614779705SSam Leffler /* Misc Functions */
9714779705SSam Leffler .ah_getCapability = ar5212GetCapability,
9814779705SSam Leffler .ah_setCapability = ar5212SetCapability,
9914779705SSam Leffler .ah_getDiagState = ar5212GetDiagState,
10014779705SSam Leffler .ah_getMacAddress = ar5212GetMacAddress,
10114779705SSam Leffler .ah_setMacAddress = ar5212SetMacAddress,
10214779705SSam Leffler .ah_getBssIdMask = ar5212GetBssIdMask,
10314779705SSam Leffler .ah_setBssIdMask = ar5212SetBssIdMask,
10414779705SSam Leffler .ah_setRegulatoryDomain = ar5212SetRegulatoryDomain,
10514779705SSam Leffler .ah_setLedState = ar5212SetLedState,
10614779705SSam Leffler .ah_writeAssocid = ar5212WriteAssocid,
10714779705SSam Leffler .ah_gpioCfgInput = ar5212GpioCfgInput,
10814779705SSam Leffler .ah_gpioCfgOutput = ar5212GpioCfgOutput,
10914779705SSam Leffler .ah_gpioGet = ar5212GpioGet,
11014779705SSam Leffler .ah_gpioSet = ar5212GpioSet,
11114779705SSam Leffler .ah_gpioSetIntr = ar5212GpioSetIntr,
11214779705SSam Leffler .ah_getTsf32 = ar5212GetTsf32,
11314779705SSam Leffler .ah_getTsf64 = ar5212GetTsf64,
114c83ba0b9SAdrian Chadd .ah_setTsf64 = ar5212SetTsf64,
11514779705SSam Leffler .ah_resetTsf = ar5212ResetTsf,
11614779705SSam Leffler .ah_detectCardPresent = ar5212DetectCardPresent,
11714779705SSam Leffler .ah_updateMibCounters = ar5212UpdateMibCounters,
11814779705SSam Leffler .ah_getRfGain = ar5212GetRfgain,
11914779705SSam Leffler .ah_getDefAntenna = ar5212GetDefAntenna,
12014779705SSam Leffler .ah_setDefAntenna = ar5212SetDefAntenna,
12114779705SSam Leffler .ah_getAntennaSwitch = ar5212GetAntennaSwitch,
12214779705SSam Leffler .ah_setAntennaSwitch = ar5212SetAntennaSwitch,
12314779705SSam Leffler .ah_setSifsTime = ar5212SetSifsTime,
12414779705SSam Leffler .ah_getSifsTime = ar5212GetSifsTime,
12514779705SSam Leffler .ah_setSlotTime = ar5212SetSlotTime,
12614779705SSam Leffler .ah_getSlotTime = ar5212GetSlotTime,
12714779705SSam Leffler .ah_setAckTimeout = ar5212SetAckTimeout,
12814779705SSam Leffler .ah_getAckTimeout = ar5212GetAckTimeout,
12914779705SSam Leffler .ah_setAckCTSRate = ar5212SetAckCTSRate,
13014779705SSam Leffler .ah_getAckCTSRate = ar5212GetAckCTSRate,
13114779705SSam Leffler .ah_setCTSTimeout = ar5212SetCTSTimeout,
13214779705SSam Leffler .ah_getCTSTimeout = ar5212GetCTSTimeout,
13314779705SSam Leffler .ah_setDecompMask = ar5212SetDecompMask,
13414779705SSam Leffler .ah_setCoverageClass = ar5212SetCoverageClass,
13504d172dbSAdrian Chadd .ah_setQuiet = ar5212SetQuiet,
136352f07f6SAdrian Chadd .ah_getMibCycleCounts = ar5212GetMibCycleCounts,
137d2a72d67SAdrian Chadd .ah_setChainMasks = ar5212SetChainMasks,
138*bed90bf8SAdrian Chadd .ah_getNav = ar5212GetNav,
139*bed90bf8SAdrian Chadd .ah_setNav = ar5212SetNav,
14014779705SSam Leffler
1412cb5233bSAdrian Chadd /* DFS Functions */
1422cb5233bSAdrian Chadd .ah_enableDfs = ar5212EnableDfs,
1432cb5233bSAdrian Chadd .ah_getDfsThresh = ar5212GetDfsThresh,
14447152caeSAdrian Chadd .ah_getDfsDefaultThresh = ar5212GetDfsDefaultThresh,
1453d423111SAdrian Chadd .ah_procRadarEvent = ar5212ProcessRadarEvent,
14660829c48SAdrian Chadd .ah_isFastClockEnabled = ar5212IsFastClockEnabled,
1477f925de1SAdrian Chadd .ah_get11nExtBusy = ar5212Get11nExtBusy,
1482cb5233bSAdrian Chadd
14914779705SSam Leffler /* Key Cache Functions */
15014779705SSam Leffler .ah_getKeyCacheSize = ar5212GetKeyCacheSize,
15114779705SSam Leffler .ah_resetKeyCacheEntry = ar5212ResetKeyCacheEntry,
15214779705SSam Leffler .ah_isKeyCacheEntryValid = ar5212IsKeyCacheEntryValid,
15314779705SSam Leffler .ah_setKeyCacheEntry = ar5212SetKeyCacheEntry,
15414779705SSam Leffler .ah_setKeyCacheEntryMac = ar5212SetKeyCacheEntryMac,
15514779705SSam Leffler
15614779705SSam Leffler /* Power Management Functions */
15714779705SSam Leffler .ah_setPowerMode = ar5212SetPowerMode,
15814779705SSam Leffler .ah_getPowerMode = ar5212GetPowerMode,
15914779705SSam Leffler
16014779705SSam Leffler /* Beacon Functions */
16114779705SSam Leffler .ah_setBeaconTimers = ar5212SetBeaconTimers,
16214779705SSam Leffler .ah_beaconInit = ar5212BeaconInit,
16314779705SSam Leffler .ah_setStationBeaconTimers = ar5212SetStaBeaconTimers,
16414779705SSam Leffler .ah_resetStationBeaconTimers = ar5212ResetStaBeaconTimers,
165fc4de9b7SAdrian Chadd .ah_getNextTBTT = ar5212GetNextTBTT,
16614779705SSam Leffler
16714779705SSam Leffler /* Interrupt Functions */
16814779705SSam Leffler .ah_isInterruptPending = ar5212IsInterruptPending,
16914779705SSam Leffler .ah_getPendingInterrupts = ar5212GetPendingInterrupts,
17014779705SSam Leffler .ah_getInterrupts = ar5212GetInterrupts,
17114779705SSam Leffler .ah_setInterrupts = ar5212SetInterrupts },
17214779705SSam Leffler
17314779705SSam Leffler .ah_getChannelEdges = ar5212GetChannelEdges,
17414779705SSam Leffler .ah_getWirelessModes = ar5212GetWirelessModes,
17514779705SSam Leffler .ah_eepromRead = ar5212EepromRead,
17614779705SSam Leffler #ifdef AH_SUPPORT_WRITE_EEPROM
17714779705SSam Leffler .ah_eepromWrite = ar5212EepromWrite,
17814779705SSam Leffler #endif
17914779705SSam Leffler .ah_getChipPowerLimits = ar5212GetChipPowerLimits,
18014779705SSam Leffler };
18114779705SSam Leffler
18214779705SSam Leffler uint32_t
ar5212GetRadioRev(struct ath_hal * ah)18314779705SSam Leffler ar5212GetRadioRev(struct ath_hal *ah)
18414779705SSam Leffler {
18514779705SSam Leffler uint32_t val;
18614779705SSam Leffler int i;
18714779705SSam Leffler
18814779705SSam Leffler /* Read Radio Chip Rev Extract */
18914779705SSam Leffler OS_REG_WRITE(ah, AR_PHY(0x34), 0x00001c16);
19014779705SSam Leffler for (i = 0; i < 8; i++)
19114779705SSam Leffler OS_REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
19214779705SSam Leffler val = (OS_REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
19314779705SSam Leffler val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
19414779705SSam Leffler return ath_hal_reverseBits(val, 8);
19514779705SSam Leffler }
19614779705SSam Leffler
19714779705SSam Leffler static void
ar5212AniSetup(struct ath_hal * ah)19814779705SSam Leffler ar5212AniSetup(struct ath_hal *ah)
19914779705SSam Leffler {
20014779705SSam Leffler static const struct ar5212AniParams aniparams = {
20114779705SSam Leffler .maxNoiseImmunityLevel = 4, /* levels 0..4 */
20214779705SSam Leffler .totalSizeDesired = { -55, -55, -55, -55, -62 },
20314779705SSam Leffler .coarseHigh = { -14, -14, -14, -14, -12 },
20414779705SSam Leffler .coarseLow = { -64, -64, -64, -64, -70 },
20514779705SSam Leffler .firpwr = { -78, -78, -78, -78, -80 },
20614779705SSam Leffler .maxSpurImmunityLevel = 2, /* NB: depends on chip rev */
20714779705SSam Leffler .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 },
20814779705SSam Leffler .maxFirstepLevel = 2, /* levels 0..2 */
20914779705SSam Leffler .firstep = { 0, 4, 8 },
21014779705SSam Leffler .ofdmTrigHigh = 500,
21114779705SSam Leffler .ofdmTrigLow = 200,
21214779705SSam Leffler .cckTrigHigh = 200,
21314779705SSam Leffler .cckTrigLow = 100,
21414779705SSam Leffler .rssiThrHigh = 40,
21514779705SSam Leffler .rssiThrLow = 7,
21614779705SSam Leffler .period = 100,
21714779705SSam Leffler };
21814779705SSam Leffler if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_GRIFFIN) {
21914779705SSam Leffler struct ar5212AniParams tmp;
22014779705SSam Leffler OS_MEMCPY(&tmp, &aniparams, sizeof(struct ar5212AniParams));
22114779705SSam Leffler tmp.maxSpurImmunityLevel = 7; /* Venice and earlier */
22214779705SSam Leffler ar5212AniAttach(ah, &tmp, &tmp, AH_TRUE);
22314779705SSam Leffler } else
22414779705SSam Leffler ar5212AniAttach(ah, &aniparams, &aniparams, AH_TRUE);
2259f456336SAdrian Chadd
2269f456336SAdrian Chadd /* Set overridable ANI methods */
2279f456336SAdrian Chadd AH5212(ah)->ah_aniControl = ar5212AniControl;
22814779705SSam Leffler }
22914779705SSam Leffler
23014779705SSam Leffler /*
23114779705SSam Leffler * Attach for an AR5212 part.
23214779705SSam Leffler */
23314779705SSam Leffler void
ar5212InitState(struct ath_hal_5212 * ahp,uint16_t devid,HAL_SOFTC sc,HAL_BUS_TAG st,HAL_BUS_HANDLE sh,HAL_STATUS * status)23414779705SSam Leffler ar5212InitState(struct ath_hal_5212 *ahp, uint16_t devid, HAL_SOFTC sc,
23514779705SSam Leffler HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status)
23614779705SSam Leffler {
23714779705SSam Leffler #define N(a) (sizeof(a)/sizeof(a[0]))
23814779705SSam Leffler static const uint8_t defbssidmask[IEEE80211_ADDR_LEN] =
23914779705SSam Leffler { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
24014779705SSam Leffler struct ath_hal *ah;
24114779705SSam Leffler
24214779705SSam Leffler ah = &ahp->ah_priv.h;
24314779705SSam Leffler /* set initial values */
24414779705SSam Leffler OS_MEMCPY(&ahp->ah_priv, &ar5212hal, sizeof(struct ath_hal_private));
24514779705SSam Leffler ah->ah_sc = sc;
24614779705SSam Leffler ah->ah_st = st;
24714779705SSam Leffler ah->ah_sh = sh;
24814779705SSam Leffler
24914779705SSam Leffler ah->ah_devid = devid; /* NB: for alq */
25014779705SSam Leffler AH_PRIVATE(ah)->ah_devid = devid;
25114779705SSam Leffler AH_PRIVATE(ah)->ah_subvendorid = 0; /* XXX */
25214779705SSam Leffler
25314779705SSam Leffler AH_PRIVATE(ah)->ah_powerLimit = MAX_RATE_POWER;
25414779705SSam Leffler AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */
25514779705SSam Leffler
25614779705SSam Leffler ahp->ah_antControl = HAL_ANT_VARIABLE;
25714779705SSam Leffler ahp->ah_diversity = AH_TRUE;
25814779705SSam Leffler ahp->ah_bIQCalibration = AH_FALSE;
25914779705SSam Leffler /*
26014779705SSam Leffler * Enable MIC handling.
26114779705SSam Leffler */
26214779705SSam Leffler ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
26314779705SSam Leffler ahp->ah_rssiThr = INIT_RSSI_THR;
26414779705SSam Leffler ahp->ah_tpcEnabled = AH_FALSE; /* disabled by default */
26514779705SSam Leffler ahp->ah_phyPowerOn = AH_FALSE;
26614779705SSam Leffler ahp->ah_macTPC = SM(MAX_RATE_POWER, AR_TPC_ACK)
26714779705SSam Leffler | SM(MAX_RATE_POWER, AR_TPC_CTS)
26814779705SSam Leffler | SM(MAX_RATE_POWER, AR_TPC_CHIRP);
26914779705SSam Leffler ahp->ah_beaconInterval = 100; /* XXX [20..1000] */
27014779705SSam Leffler ahp->ah_enable32kHzClock = DONT_USE_32KHZ;/* XXX */
27114779705SSam Leffler ahp->ah_slottime = (u_int) -1;
27214779705SSam Leffler ahp->ah_acktimeout = (u_int) -1;
27314779705SSam Leffler ahp->ah_ctstimeout = (u_int) -1;
27414779705SSam Leffler ahp->ah_sifstime = (u_int) -1;
275f0be707dSPedro F. Giffuni ahp->ah_txTrigLev = INIT_TX_FIFO_THRESHOLD;
276f0be707dSPedro F. Giffuni ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD;
277256796dbSRui Paulo
27814779705SSam Leffler OS_MEMCPY(&ahp->ah_bssidmask, defbssidmask, IEEE80211_ADDR_LEN);
27914779705SSam Leffler #undef N
28014779705SSam Leffler }
28114779705SSam Leffler
28214779705SSam Leffler /*
28314779705SSam Leffler * Validate MAC version and revision.
28414779705SSam Leffler */
28514779705SSam Leffler static HAL_BOOL
ar5212IsMacSupported(uint8_t macVersion,uint8_t macRev)28614779705SSam Leffler ar5212IsMacSupported(uint8_t macVersion, uint8_t macRev)
28714779705SSam Leffler {
28814779705SSam Leffler #define N(a) (sizeof(a)/sizeof(a[0]))
28914779705SSam Leffler static const struct {
29014779705SSam Leffler uint8_t version;
29114779705SSam Leffler uint8_t revMin, revMax;
29214779705SSam Leffler } macs[] = {
29314779705SSam Leffler { AR_SREV_VERSION_VENICE,
29414779705SSam Leffler AR_SREV_D2PLUS, AR_SREV_REVISION_MAX },
29514779705SSam Leffler { AR_SREV_VERSION_GRIFFIN,
29614779705SSam Leffler AR_SREV_D2PLUS, AR_SREV_REVISION_MAX },
29714779705SSam Leffler { AR_SREV_5413,
29814779705SSam Leffler AR_SREV_REVISION_MIN, AR_SREV_REVISION_MAX },
29914779705SSam Leffler { AR_SREV_5424,
30014779705SSam Leffler AR_SREV_REVISION_MIN, AR_SREV_REVISION_MAX },
30114779705SSam Leffler { AR_SREV_2425,
30214779705SSam Leffler AR_SREV_REVISION_MIN, AR_SREV_REVISION_MAX },
30314779705SSam Leffler { AR_SREV_2417,
30414779705SSam Leffler AR_SREV_REVISION_MIN, AR_SREV_REVISION_MAX },
30514779705SSam Leffler };
30614779705SSam Leffler int i;
30714779705SSam Leffler
30814779705SSam Leffler for (i = 0; i < N(macs); i++)
30914779705SSam Leffler if (macs[i].version == macVersion &&
31014779705SSam Leffler macs[i].revMin <= macRev && macRev <= macs[i].revMax)
31114779705SSam Leffler return AH_TRUE;
31214779705SSam Leffler return AH_FALSE;
31314779705SSam Leffler #undef N
31414779705SSam Leffler }
31514779705SSam Leffler
31614779705SSam Leffler /*
31714779705SSam Leffler * Attach for an AR5212 part.
31814779705SSam Leffler */
31914779705SSam Leffler static struct ath_hal *
ar5212Attach(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)32014779705SSam Leffler ar5212Attach(uint16_t devid, HAL_SOFTC sc,
32188117a53SAdrian Chadd HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
3229389d5a9SAdrian Chadd HAL_OPS_CONFIG *ah_config, HAL_STATUS *status)
32314779705SSam Leffler {
32414779705SSam Leffler #define AH_EEPROM_PROTECT(ah) \
32544834ea4SSam Leffler (AH_PRIVATE(ah)->ah_ispcie)? AR_EEPROM_PROTECT_PCIE : AR_EEPROM_PROTECT)
32614779705SSam Leffler struct ath_hal_5212 *ahp;
32714779705SSam Leffler struct ath_hal *ah;
32814779705SSam Leffler struct ath_hal_rf *rf;
32914779705SSam Leffler uint32_t val;
33014779705SSam Leffler uint16_t eeval;
33114779705SSam Leffler HAL_STATUS ecode;
33214779705SSam Leffler
3330e56140aSAdrian Chadd HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
33414779705SSam Leffler __func__, sc, (void*) st, (void*) sh);
33514779705SSam Leffler
33614779705SSam Leffler /* NB: memory is returned zero'd */
33714779705SSam Leffler ahp = ath_hal_malloc(sizeof (struct ath_hal_5212));
33814779705SSam Leffler if (ahp == AH_NULL) {
3390e56140aSAdrian Chadd HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
34014779705SSam Leffler "%s: cannot allocate memory for state block\n", __func__);
34114779705SSam Leffler *status = HAL_ENOMEM;
34214779705SSam Leffler return AH_NULL;
34314779705SSam Leffler }
34414779705SSam Leffler ar5212InitState(ahp, devid, sc, st, sh, status);
34514779705SSam Leffler ah = &ahp->ah_priv.h;
34614779705SSam Leffler
34714779705SSam Leffler if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) {
34814779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n",
34914779705SSam Leffler __func__);
35014779705SSam Leffler ecode = HAL_EIO;
35114779705SSam Leffler goto bad;
35214779705SSam Leffler }
35314779705SSam Leffler /* Read Revisions from Chips before taking out of reset */
35414779705SSam Leffler val = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID;
35514779705SSam Leffler AH_PRIVATE(ah)->ah_macVersion = val >> AR_SREV_ID_S;
35614779705SSam Leffler AH_PRIVATE(ah)->ah_macRev = val & AR_SREV_REVISION;
35744834ea4SSam Leffler AH_PRIVATE(ah)->ah_ispcie = IS_5424(ah) || IS_2425(ah);
35814779705SSam Leffler
35914779705SSam Leffler if (!ar5212IsMacSupported(AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev)) {
36014779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
36114779705SSam Leffler "%s: Mac Chip Rev 0x%02x.%x not supported\n" ,
36214779705SSam Leffler __func__, AH_PRIVATE(ah)->ah_macVersion,
36314779705SSam Leffler AH_PRIVATE(ah)->ah_macRev);
36414779705SSam Leffler ecode = HAL_ENOTSUPP;
36514779705SSam Leffler goto bad;
36614779705SSam Leffler }
36714779705SSam Leffler
36814779705SSam Leffler /* setup common ini data; rf backends handle remainder */
36914779705SSam Leffler HAL_INI_INIT(&ahp->ah_ini_modes, ar5212Modes, 6);
37014779705SSam Leffler HAL_INI_INIT(&ahp->ah_ini_common, ar5212Common, 2);
37114779705SSam Leffler
37214779705SSam Leffler if (!ar5212ChipReset(ah, AH_NULL)) { /* reset chip */
37314779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__);
37414779705SSam Leffler ecode = HAL_EIO;
37514779705SSam Leffler goto bad;
37614779705SSam Leffler }
37714779705SSam Leffler
37814779705SSam Leffler AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID);
37914779705SSam Leffler
38044834ea4SSam Leffler if (AH_PRIVATE(ah)->ah_ispcie) {
38114779705SSam Leffler /* XXX: build flag to disable this? */
382ae2a0aa4SAdrian Chadd ath_hal_configPCIE(ah, AH_FALSE, AH_FALSE);
38314779705SSam Leffler }
38414779705SSam Leffler
38514779705SSam Leffler if (!ar5212ChipTest(ah)) {
38614779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n",
38714779705SSam Leffler __func__);
38814779705SSam Leffler ecode = HAL_ESELFTEST;
38914779705SSam Leffler goto bad;
39014779705SSam Leffler }
39114779705SSam Leffler
39214779705SSam Leffler /* Enable PCI core retry fix in software for Hainan and up */
39314779705SSam Leffler if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_VENICE)
39414779705SSam Leffler OS_REG_SET_BIT(ah, AR_PCICFG, AR_PCICFG_RETRYFIXEN);
39514779705SSam Leffler
39614779705SSam Leffler /*
39714779705SSam Leffler * Set correct Baseband to analog shift
39814779705SSam Leffler * setting to access analog chips.
39914779705SSam Leffler */
40014779705SSam Leffler OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
40114779705SSam Leffler
40214779705SSam Leffler /* Read Radio Chip Rev Extract */
40314779705SSam Leffler AH_PRIVATE(ah)->ah_analog5GhzRev = ar5212GetRadioRev(ah);
40414779705SSam Leffler
40514779705SSam Leffler rf = ath_hal_rfprobe(ah, &ecode);
40614779705SSam Leffler if (rf == AH_NULL)
40714779705SSam Leffler goto bad;
40814779705SSam Leffler
40914779705SSam Leffler /* NB: silently accept anything in release code per Atheros */
41014779705SSam Leffler switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
41114779705SSam Leffler case AR_RAD5111_SREV_MAJOR:
41214779705SSam Leffler case AR_RAD5112_SREV_MAJOR:
41314779705SSam Leffler case AR_RAD2112_SREV_MAJOR:
41414779705SSam Leffler case AR_RAD2111_SREV_MAJOR:
41514779705SSam Leffler case AR_RAD2413_SREV_MAJOR:
41614779705SSam Leffler case AR_RAD5413_SREV_MAJOR:
41714779705SSam Leffler case AR_RAD5424_SREV_MAJOR:
41814779705SSam Leffler break;
41914779705SSam Leffler default:
42014779705SSam Leffler if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) {
42114779705SSam Leffler /*
42214779705SSam Leffler * When RF_Silent is used, the
42314779705SSam Leffler * analog chip is reset. So when the system boots
42414779705SSam Leffler * up with the radio switch off we cannot determine
42514779705SSam Leffler * the RF chip rev. To workaround this check the
42614779705SSam Leffler * mac+phy revs and if Hainan, set the radio rev
42714779705SSam Leffler * to Derby.
42814779705SSam Leffler */
42914779705SSam Leffler if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE &&
43014779705SSam Leffler AH_PRIVATE(ah)->ah_macRev == AR_SREV_HAINAN &&
43114779705SSam Leffler AH_PRIVATE(ah)->ah_phyRev == AR_PHYREV_HAINAN) {
43214779705SSam Leffler AH_PRIVATE(ah)->ah_analog5GhzRev = AR_ANALOG5REV_HAINAN;
43314779705SSam Leffler break;
43414779705SSam Leffler }
43514779705SSam Leffler if (IS_2413(ah)) { /* Griffin */
43614779705SSam Leffler AH_PRIVATE(ah)->ah_analog5GhzRev =
43714779705SSam Leffler AR_RAD2413_SREV_MAJOR | 0x1;
43814779705SSam Leffler break;
43914779705SSam Leffler }
44014779705SSam Leffler if (IS_5413(ah)) { /* Eagle */
44114779705SSam Leffler AH_PRIVATE(ah)->ah_analog5GhzRev =
44214779705SSam Leffler AR_RAD5413_SREV_MAJOR | 0x2;
44314779705SSam Leffler break;
44414779705SSam Leffler }
44514779705SSam Leffler if (IS_2425(ah) || IS_2417(ah)) {/* Swan or Nala */
44614779705SSam Leffler AH_PRIVATE(ah)->ah_analog5GhzRev =
44714779705SSam Leffler AR_RAD5424_SREV_MAJOR | 0x2;
44814779705SSam Leffler break;
44914779705SSam Leffler }
45014779705SSam Leffler }
45114779705SSam Leffler #ifdef AH_DEBUG
45214779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
45314779705SSam Leffler "%s: 5G Radio Chip Rev 0x%02X is not supported by "
45414779705SSam Leffler "this driver\n",
45514779705SSam Leffler __func__, AH_PRIVATE(ah)->ah_analog5GhzRev);
45614779705SSam Leffler ecode = HAL_ENOTSUPP;
45714779705SSam Leffler goto bad;
45814779705SSam Leffler #endif
45914779705SSam Leffler }
46014779705SSam Leffler if (IS_RAD5112_REV1(ah)) {
46114779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
46214779705SSam Leffler "%s: 5112 Rev 1 is not supported by this "
46314779705SSam Leffler "driver (analog5GhzRev 0x%x)\n", __func__,
46414779705SSam Leffler AH_PRIVATE(ah)->ah_analog5GhzRev);
46514779705SSam Leffler ecode = HAL_ENOTSUPP;
46614779705SSam Leffler goto bad;
46714779705SSam Leffler }
46814779705SSam Leffler
46914779705SSam Leffler val = OS_REG_READ(ah, AR_PCICFG);
47014779705SSam Leffler val = MS(val, AR_PCICFG_EEPROM_SIZE);
47114779705SSam Leffler if (val == 0) {
47244834ea4SSam Leffler if (!AH_PRIVATE(ah)->ah_ispcie) {
47314779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
47414779705SSam Leffler "%s: unsupported EEPROM size %u (0x%x) found\n",
47514779705SSam Leffler __func__, val, val);
47614779705SSam Leffler ecode = HAL_EESIZE;
47714779705SSam Leffler goto bad;
47814779705SSam Leffler }
47914779705SSam Leffler /* XXX AH_PRIVATE(ah)->ah_isPciExpress = AH_TRUE; */
48014779705SSam Leffler } else if (val != AR_PCICFG_EEPROM_SIZE_16K) {
48114779705SSam Leffler if (AR_PCICFG_EEPROM_SIZE_FAILED == val) {
48214779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
48314779705SSam Leffler "%s: unsupported EEPROM size %u (0x%x) found\n",
48414779705SSam Leffler __func__, val, val);
48514779705SSam Leffler ecode = HAL_EESIZE;
48614779705SSam Leffler goto bad;
48714779705SSam Leffler }
48814779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
48914779705SSam Leffler "%s: EEPROM size = %d. Must be %d (16k).\n",
49014779705SSam Leffler __func__, val, AR_PCICFG_EEPROM_SIZE_16K);
49114779705SSam Leffler ecode = HAL_EESIZE;
49214779705SSam Leffler goto bad;
49314779705SSam Leffler }
49414779705SSam Leffler ecode = ath_hal_legacyEepromAttach(ah);
49514779705SSam Leffler if (ecode != HAL_OK) {
49614779705SSam Leffler goto bad;
49714779705SSam Leffler }
49814779705SSam Leffler ahp->ah_isHb63 = IS_2425(ah) && ath_hal_eepromGetFlag(ah, AR_EEP_ISTALON);
49914779705SSam Leffler
50014779705SSam Leffler /*
50114779705SSam Leffler * If Bmode and AR5212, verify 2.4 analog exists
50214779705SSam Leffler */
50314779705SSam Leffler if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE) &&
50414779705SSam Leffler (AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) == AR_RAD5111_SREV_MAJOR) {
50514779705SSam Leffler /*
50614779705SSam Leffler * Set correct Baseband to analog shift
50714779705SSam Leffler * setting to access analog chips.
50814779705SSam Leffler */
50914779705SSam Leffler OS_REG_WRITE(ah, AR_PHY(0), 0x00004007);
51014779705SSam Leffler OS_DELAY(2000);
51114779705SSam Leffler AH_PRIVATE(ah)->ah_analog2GhzRev = ar5212GetRadioRev(ah);
51214779705SSam Leffler
51314779705SSam Leffler /* Set baseband for 5GHz chip */
51414779705SSam Leffler OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
51514779705SSam Leffler OS_DELAY(2000);
51614779705SSam Leffler if ((AH_PRIVATE(ah)->ah_analog2GhzRev & 0xF0) != AR_RAD2111_SREV_MAJOR) {
51714779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
51814779705SSam Leffler "%s: 2G Radio Chip Rev 0x%02X is not "
51914779705SSam Leffler "supported by this driver\n", __func__,
52014779705SSam Leffler AH_PRIVATE(ah)->ah_analog2GhzRev);
52114779705SSam Leffler ecode = HAL_ENOTSUPP;
52214779705SSam Leffler goto bad;
52314779705SSam Leffler }
52414779705SSam Leffler }
52514779705SSam Leffler
52614779705SSam Leffler ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval);
52714779705SSam Leffler if (ecode != HAL_OK) {
52814779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
52914779705SSam Leffler "%s: cannot read regulatory domain from EEPROM\n",
53014779705SSam Leffler __func__);
53114779705SSam Leffler goto bad;
53214779705SSam Leffler }
53314779705SSam Leffler AH_PRIVATE(ah)->ah_currentRD = eeval;
53414779705SSam Leffler /* XXX record serial number */
53514779705SSam Leffler
53614779705SSam Leffler /*
53714779705SSam Leffler * Got everything we need now to setup the capabilities.
53814779705SSam Leffler */
53914779705SSam Leffler if (!ar5212FillCapabilityInfo(ah)) {
54014779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
54114779705SSam Leffler "%s: failed ar5212FillCapabilityInfo\n", __func__);
54214779705SSam Leffler ecode = HAL_EEREAD;
54314779705SSam Leffler goto bad;
54414779705SSam Leffler }
54514779705SSam Leffler
54614779705SSam Leffler if (!rf->attach(ah, &ecode)) {
54714779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n",
54814779705SSam Leffler __func__, ecode);
54914779705SSam Leffler goto bad;
55014779705SSam Leffler }
55114779705SSam Leffler /*
55214779705SSam Leffler * Set noise floor adjust method; we arrange a
55314779705SSam Leffler * direct call instead of thunking.
55414779705SSam Leffler */
55514779705SSam Leffler AH_PRIVATE(ah)->ah_getNfAdjust = ahp->ah_rfHal->getNfAdjust;
55614779705SSam Leffler
55714779705SSam Leffler /* Initialize gain ladder thermal calibration structure */
55814779705SSam Leffler ar5212InitializeGainValues(ah);
55914779705SSam Leffler
56014779705SSam Leffler ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr);
56114779705SSam Leffler if (ecode != HAL_OK) {
56214779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
56314779705SSam Leffler "%s: error getting mac address from EEPROM\n", __func__);
56414779705SSam Leffler goto bad;
56514779705SSam Leffler }
56614779705SSam Leffler
56714779705SSam Leffler ar5212AniSetup(ah);
56814779705SSam Leffler /* Setup of Radar/AR structures happens in ath_hal_initchannels*/
56914779705SSam Leffler ar5212InitNfCalHistBuffer(ah);
57014779705SSam Leffler
57114779705SSam Leffler /* XXX EAR stuff goes here */
57214779705SSam Leffler
57314779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__);
57414779705SSam Leffler
57514779705SSam Leffler return ah;
57614779705SSam Leffler
57714779705SSam Leffler bad:
57814779705SSam Leffler if (ahp)
57914779705SSam Leffler ar5212Detach((struct ath_hal *) ahp);
58014779705SSam Leffler if (status)
58114779705SSam Leffler *status = ecode;
58214779705SSam Leffler return AH_NULL;
58314779705SSam Leffler #undef AH_EEPROM_PROTECT
58414779705SSam Leffler }
58514779705SSam Leffler
58614779705SSam Leffler void
ar5212Detach(struct ath_hal * ah)58714779705SSam Leffler ar5212Detach(struct ath_hal *ah)
58814779705SSam Leffler {
58914779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n", __func__);
59014779705SSam Leffler
59114779705SSam Leffler HALASSERT(ah != AH_NULL);
59214779705SSam Leffler HALASSERT(ah->ah_magic == AR5212_MAGIC);
59314779705SSam Leffler
59414779705SSam Leffler ar5212AniDetach(ah);
59514779705SSam Leffler ar5212RfDetach(ah);
59614779705SSam Leffler ar5212Disable(ah);
59714779705SSam Leffler ar5212SetPowerMode(ah, HAL_PM_FULL_SLEEP, AH_TRUE);
59814779705SSam Leffler
59914779705SSam Leffler ath_hal_eepromDetach(ah);
60014779705SSam Leffler ath_hal_free(ah);
60114779705SSam Leffler }
60214779705SSam Leffler
60314779705SSam Leffler HAL_BOOL
ar5212ChipTest(struct ath_hal * ah)60414779705SSam Leffler ar5212ChipTest(struct ath_hal *ah)
60514779705SSam Leffler {
60614779705SSam Leffler uint32_t regAddr[2] = { AR_STA_ID0, AR_PHY_BASE+(8 << 2) };
60714779705SSam Leffler uint32_t regHold[2];
60814779705SSam Leffler uint32_t patternData[4] =
60914779705SSam Leffler { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 };
61014779705SSam Leffler int i, j;
61114779705SSam Leffler
61214779705SSam Leffler /* Test PHY & MAC registers */
61314779705SSam Leffler for (i = 0; i < 2; i++) {
61414779705SSam Leffler uint32_t addr = regAddr[i];
61514779705SSam Leffler uint32_t wrData, rdData;
61614779705SSam Leffler
61714779705SSam Leffler regHold[i] = OS_REG_READ(ah, addr);
61814779705SSam Leffler for (j = 0; j < 0x100; j++) {
61914779705SSam Leffler wrData = (j << 16) | j;
62014779705SSam Leffler OS_REG_WRITE(ah, addr, wrData);
62114779705SSam Leffler rdData = OS_REG_READ(ah, addr);
62214779705SSam Leffler if (rdData != wrData) {
62314779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
62414779705SSam Leffler "%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
62514779705SSam Leffler __func__, addr, wrData, rdData);
62614779705SSam Leffler return AH_FALSE;
62714779705SSam Leffler }
62814779705SSam Leffler }
62914779705SSam Leffler for (j = 0; j < 4; j++) {
63014779705SSam Leffler wrData = patternData[j];
63114779705SSam Leffler OS_REG_WRITE(ah, addr, wrData);
63214779705SSam Leffler rdData = OS_REG_READ(ah, addr);
63314779705SSam Leffler if (wrData != rdData) {
63414779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
63514779705SSam Leffler "%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
63614779705SSam Leffler __func__, addr, wrData, rdData);
63714779705SSam Leffler return AH_FALSE;
63814779705SSam Leffler }
63914779705SSam Leffler }
64014779705SSam Leffler OS_REG_WRITE(ah, regAddr[i], regHold[i]);
64114779705SSam Leffler }
64214779705SSam Leffler OS_DELAY(100);
64314779705SSam Leffler return AH_TRUE;
64414779705SSam Leffler }
64514779705SSam Leffler
64614779705SSam Leffler /*
64714779705SSam Leffler * Store the channel edges for the requested operational mode
64814779705SSam Leffler */
64914779705SSam Leffler HAL_BOOL
ar5212GetChannelEdges(struct ath_hal * ah,uint16_t flags,uint16_t * low,uint16_t * high)65014779705SSam Leffler ar5212GetChannelEdges(struct ath_hal *ah,
65114779705SSam Leffler uint16_t flags, uint16_t *low, uint16_t *high)
65214779705SSam Leffler {
65359efa8b5SSam Leffler if (flags & IEEE80211_CHAN_5GHZ) {
65414779705SSam Leffler *low = 4915;
65514779705SSam Leffler *high = 6100;
65614779705SSam Leffler return AH_TRUE;
65714779705SSam Leffler }
65859efa8b5SSam Leffler if ((flags & IEEE80211_CHAN_2GHZ) &&
65914779705SSam Leffler (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE) ||
66014779705SSam Leffler ath_hal_eepromGetFlag(ah, AR_EEP_GMODE))) {
66114779705SSam Leffler *low = 2312;
66214779705SSam Leffler *high = 2732;
66314779705SSam Leffler return AH_TRUE;
66414779705SSam Leffler }
66514779705SSam Leffler return AH_FALSE;
66614779705SSam Leffler }
66714779705SSam Leffler
66814779705SSam Leffler /*
66944834ea4SSam Leffler * Disable PLL when in L0s as well as receiver clock when in L1.
67044834ea4SSam Leffler * This power saving option must be enabled through the Serdes.
67144834ea4SSam Leffler *
67244834ea4SSam Leffler * Programming the Serdes must go through the same 288 bit serial shift
67344834ea4SSam Leffler * register as the other analog registers. Hence the 9 writes.
67444834ea4SSam Leffler *
67544834ea4SSam Leffler * XXX Clean up the magic numbers.
67644834ea4SSam Leffler */
67744834ea4SSam Leffler static void
ar5212ConfigPCIE(struct ath_hal * ah,HAL_BOOL restore,HAL_BOOL power_off)678ae2a0aa4SAdrian Chadd ar5212ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
67944834ea4SSam Leffler {
68044834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
68144834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
68244834ea4SSam Leffler
68344834ea4SSam Leffler /* RX shut off when elecidle is asserted */
68444834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
68544834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
68644834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
68744834ea4SSam Leffler
68844834ea4SSam Leffler /* Shut off PLL and CLKREQ active in L1 */
68944834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
69044834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
69144834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
69244834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
69344834ea4SSam Leffler
69444834ea4SSam Leffler /* Load the new settings */
69544834ea4SSam Leffler OS_REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
69644834ea4SSam Leffler }
69744834ea4SSam Leffler
69844834ea4SSam Leffler static void
ar5212DisablePCIE(struct ath_hal * ah)69944834ea4SSam Leffler ar5212DisablePCIE(struct ath_hal *ah)
70044834ea4SSam Leffler {
70144834ea4SSam Leffler /* NB: fill in for 9100 */
70244834ea4SSam Leffler }
70344834ea4SSam Leffler
70444834ea4SSam Leffler /*
70514779705SSam Leffler * Fill all software cached or static hardware state information.
70614779705SSam Leffler * Return failure if capabilities are to come from EEPROM and
70714779705SSam Leffler * cannot be read.
70814779705SSam Leffler */
70914779705SSam Leffler HAL_BOOL
ar5212FillCapabilityInfo(struct ath_hal * ah)71014779705SSam Leffler ar5212FillCapabilityInfo(struct ath_hal *ah)
71114779705SSam Leffler {
71214779705SSam Leffler #define AR_KEYTABLE_SIZE 128
71314779705SSam Leffler #define IS_GRIFFIN_LITE(ah) \
71414779705SSam Leffler (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_GRIFFIN && \
71514779705SSam Leffler AH_PRIVATE(ah)->ah_macRev == AR_SREV_GRIFFIN_LITE)
71614779705SSam Leffler #define IS_COBRA(ah) \
71714779705SSam Leffler (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_COBRA)
71814779705SSam Leffler #define IS_2112(ah) \
71914779705SSam Leffler ((AH_PRIVATE(ah)->ah_analog5GhzRev & 0xF0) == AR_RAD2112_SREV_MAJOR)
72014779705SSam Leffler
72114779705SSam Leffler struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
72214779705SSam Leffler HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
72314779705SSam Leffler uint16_t capField, val;
72414779705SSam Leffler
72514779705SSam Leffler /* Read the capability EEPROM location */
72614779705SSam Leffler if (ath_hal_eepromGet(ah, AR_EEP_OPCAP, &capField) != HAL_OK) {
72714779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY,
72814779705SSam Leffler "%s: unable to read caps from eeprom\n", __func__);
72914779705SSam Leffler return AH_FALSE;
73014779705SSam Leffler }
73114779705SSam Leffler if (IS_2112(ah))
73214779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_AMODE, AH_FALSE);
73314779705SSam Leffler if (capField == 0 && IS_GRIFFIN_LITE(ah)) {
73414779705SSam Leffler /*
73514779705SSam Leffler * For griffin-lite cards with unprogrammed capabilities.
73614779705SSam Leffler */
73714779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_COMPRESS, AH_FALSE);
73814779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_FASTFRAME, AH_FALSE);
73914779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_TURBO5DISABLE, AH_TRUE);
74014779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_TURBO2DISABLE, AH_TRUE);
74114779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ATTACH,
74214779705SSam Leffler "%s: override caps for griffin-lite, now 0x%x (+!turbo)\n",
74314779705SSam Leffler __func__, capField);
74414779705SSam Leffler }
74514779705SSam Leffler
74614779705SSam Leffler /* Modify reg domain on newer cards that need to work with older sw */
74714779705SSam Leffler if (ahpriv->ah_opmode != HAL_M_HOSTAP &&
74814779705SSam Leffler ahpriv->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
74914779705SSam Leffler if (ahpriv->ah_currentRD == 0x64 ||
75014779705SSam Leffler ahpriv->ah_currentRD == 0x65)
75114779705SSam Leffler ahpriv->ah_currentRD += 5;
75214779705SSam Leffler else if (ahpriv->ah_currentRD == 0x41)
75314779705SSam Leffler ahpriv->ah_currentRD = 0x43;
75414779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: regdomain mapped to 0x%x\n",
75514779705SSam Leffler __func__, ahpriv->ah_currentRD);
75614779705SSam Leffler }
75714779705SSam Leffler
75814779705SSam Leffler if (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_2417 ||
75914779705SSam Leffler AH_PRIVATE(ah)->ah_macVersion == AR_SREV_2425) {
76014779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ATTACH,
76114779705SSam Leffler "%s: enable Bmode and disable turbo for Swan/Nala\n",
76214779705SSam Leffler __func__);
76314779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_BMODE, AH_TRUE);
76414779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_COMPRESS, AH_FALSE);
76514779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_FASTFRAME, AH_FALSE);
76614779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_TURBO5DISABLE, AH_TRUE);
76714779705SSam Leffler ath_hal_eepromSet(ah, AR_EEP_TURBO2DISABLE, AH_TRUE);
76814779705SSam Leffler }
76914779705SSam Leffler
77014779705SSam Leffler /* Construct wireless mode from EEPROM */
77114779705SSam Leffler pCap->halWirelessModes = 0;
77214779705SSam Leffler if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) {
77314779705SSam Leffler pCap->halWirelessModes |= HAL_MODE_11A;
77414779705SSam Leffler if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE))
77514779705SSam Leffler pCap->halWirelessModes |= HAL_MODE_TURBO;
77614779705SSam Leffler }
77714779705SSam Leffler if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE))
77814779705SSam Leffler pCap->halWirelessModes |= HAL_MODE_11B;
77914779705SSam Leffler if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) &&
78014779705SSam Leffler ahpriv->ah_subvendorid != AR_SUBVENDOR_ID_NOG) {
78114779705SSam Leffler pCap->halWirelessModes |= HAL_MODE_11G;
78214779705SSam Leffler if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE))
78314779705SSam Leffler pCap->halWirelessModes |= HAL_MODE_108G;
78414779705SSam Leffler }
78514779705SSam Leffler
78614779705SSam Leffler pCap->halLow2GhzChan = 2312;
78714779705SSam Leffler /* XXX 2417 too? */
78814779705SSam Leffler if (IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2425(ah) || IS_2417(ah))
78914779705SSam Leffler pCap->halHigh2GhzChan = 2500;
79014779705SSam Leffler else
79114779705SSam Leffler pCap->halHigh2GhzChan = 2732;
79214779705SSam Leffler
793adadb607SAdrian Chadd /*
794adadb607SAdrian Chadd * For AR5111 version < 4, the lowest centre frequency supported is
795adadb607SAdrian Chadd * 5130MHz. For AR5111 version 4, the 4.9GHz channels are supported
796adadb607SAdrian Chadd * but only in 10MHz increments.
797adadb607SAdrian Chadd *
798adadb607SAdrian Chadd * In addition, the programming method is wrong - it uses the IEEE
799adadb607SAdrian Chadd * channel number to calculate the frequency, rather than the
800adadb607SAdrian Chadd * channel centre. Since half/quarter rates re-use some of the
801adadb607SAdrian Chadd * 5GHz channel IEEE numbers, this will result in a badly programmed
802adadb607SAdrian Chadd * synth.
803adadb607SAdrian Chadd *
804adadb607SAdrian Chadd * Until the relevant support is written, just limit lower frequency
805adadb607SAdrian Chadd * support for AR5111 so things aren't incorrectly programmed.
806adadb607SAdrian Chadd *
807adadb607SAdrian Chadd * XXX It's also possible this code doesn't correctly limit the
808adadb607SAdrian Chadd * centre frequencies of potential channels; this is very important
809adadb607SAdrian Chadd * for half/quarter rate!
810adadb607SAdrian Chadd */
811adadb607SAdrian Chadd if (AH_RADIO_MAJOR(ah) == AR_RAD5111_SREV_MAJOR) {
812adadb607SAdrian Chadd pCap->halLow5GhzChan = 5120; /* XXX lowest centre = 5130MHz */
813adadb607SAdrian Chadd } else {
81414779705SSam Leffler pCap->halLow5GhzChan = 4915;
815adadb607SAdrian Chadd }
81614779705SSam Leffler pCap->halHigh5GhzChan = 6100;
81714779705SSam Leffler
81814779705SSam Leffler pCap->halCipherCkipSupport = AH_FALSE;
81914779705SSam Leffler pCap->halCipherTkipSupport = AH_TRUE;
82014779705SSam Leffler pCap->halCipherAesCcmSupport =
82114779705SSam Leffler (ath_hal_eepromGetFlag(ah, AR_EEP_AES) &&
82214779705SSam Leffler ((AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE) ||
82314779705SSam Leffler ((AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE) &&
82414779705SSam Leffler (AH_PRIVATE(ah)->ah_macRev >= AR_SREV_VERSION_OAHU))));
82514779705SSam Leffler
82614779705SSam Leffler pCap->halMicCkipSupport = AH_FALSE;
82714779705SSam Leffler pCap->halMicTkipSupport = AH_TRUE;
82814779705SSam Leffler pCap->halMicAesCcmSupport = ath_hal_eepromGetFlag(ah, AR_EEP_AES);
82914779705SSam Leffler /*
83014779705SSam Leffler * Starting with Griffin TX+RX mic keys can be combined
83114779705SSam Leffler * in one key cache slot.
83214779705SSam Leffler */
83314779705SSam Leffler if (AH_PRIVATE(ah)->ah_macVersion >= AR_SREV_VERSION_GRIFFIN)
83414779705SSam Leffler pCap->halTkipMicTxRxKeySupport = AH_TRUE;
83514779705SSam Leffler else
83614779705SSam Leffler pCap->halTkipMicTxRxKeySupport = AH_FALSE;
83714779705SSam Leffler pCap->halChanSpreadSupport = AH_TRUE;
83814779705SSam Leffler pCap->halSleepAfterBeaconBroken = AH_TRUE;
83914779705SSam Leffler
84014779705SSam Leffler if (ahpriv->ah_macRev > 1 || IS_COBRA(ah)) {
84114779705SSam Leffler pCap->halCompressSupport =
84214779705SSam Leffler ath_hal_eepromGetFlag(ah, AR_EEP_COMPRESS) &&
84314779705SSam Leffler (pCap->halWirelessModes & (HAL_MODE_11A|HAL_MODE_11G)) != 0;
84414779705SSam Leffler pCap->halBurstSupport = ath_hal_eepromGetFlag(ah, AR_EEP_BURST);
84514779705SSam Leffler pCap->halFastFramesSupport =
84614779705SSam Leffler ath_hal_eepromGetFlag(ah, AR_EEP_FASTFRAME) &&
84714779705SSam Leffler (pCap->halWirelessModes & (HAL_MODE_11A|HAL_MODE_11G)) != 0;
84814779705SSam Leffler pCap->halChapTuningSupport = AH_TRUE;
84914779705SSam Leffler pCap->halTurboPrimeSupport = AH_TRUE;
85014779705SSam Leffler }
85114779705SSam Leffler pCap->halTurboGSupport = pCap->halWirelessModes & HAL_MODE_108G;
85214779705SSam Leffler
85314779705SSam Leffler pCap->halPSPollBroken = AH_TRUE; /* XXX fixed in later revs? */
854ee3e4df9SAdrian Chadd pCap->halNumMRRetries = 4; /* Hardware supports 4 MRR */
855217ad7d2SAdrian Chadd pCap->halNumTxMaps = 1; /* Single TX ptr per descr */
85614779705SSam Leffler pCap->halVEOLSupport = AH_TRUE;
85714779705SSam Leffler pCap->halBssIdMaskSupport = AH_TRUE;
85814779705SSam Leffler pCap->halMcastKeySrchSupport = AH_TRUE;
85914779705SSam Leffler if ((ahpriv->ah_macVersion == AR_SREV_VERSION_VENICE &&
86014779705SSam Leffler ahpriv->ah_macRev == 8) ||
86114779705SSam Leffler ahpriv->ah_macVersion > AR_SREV_VERSION_VENICE)
86214779705SSam Leffler pCap->halTsfAddSupport = AH_TRUE;
86314779705SSam Leffler
86414779705SSam Leffler if (ath_hal_eepromGet(ah, AR_EEP_MAXQCU, &val) == HAL_OK)
86514779705SSam Leffler pCap->halTotalQueues = val;
86614779705SSam Leffler else
86714779705SSam Leffler pCap->halTotalQueues = HAL_NUM_TX_QUEUES;
86814779705SSam Leffler
86914779705SSam Leffler if (ath_hal_eepromGet(ah, AR_EEP_KCENTRIES, &val) == HAL_OK)
87014779705SSam Leffler pCap->halKeyCacheSize = val;
87114779705SSam Leffler else
87214779705SSam Leffler pCap->halKeyCacheSize = AR_KEYTABLE_SIZE;
87314779705SSam Leffler
87414779705SSam Leffler pCap->halChanHalfRate = AH_TRUE;
87514779705SSam Leffler pCap->halChanQuarterRate = AH_TRUE;
87614779705SSam Leffler
8777f925de1SAdrian Chadd /*
8787f925de1SAdrian Chadd * RSSI uses the combined field; some 11n NICs may use
8797f925de1SAdrian Chadd * the control chain RSSI.
8807f925de1SAdrian Chadd */
8817f925de1SAdrian Chadd pCap->halUseCombinedRadarRssi = AH_TRUE;
8827f925de1SAdrian Chadd
88314779705SSam Leffler if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) &&
88414779705SSam Leffler ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) {
88514779705SSam Leffler /* NB: enabled by default */
88614779705SSam Leffler ahpriv->ah_rfkillEnabled = AH_TRUE;
88714779705SSam Leffler pCap->halRfSilentSupport = AH_TRUE;
88814779705SSam Leffler }
88914779705SSam Leffler
89014779705SSam Leffler /* NB: this is a guess, no one seems to know the answer */
89114779705SSam Leffler ahpriv->ah_rxornIsFatal =
89214779705SSam Leffler (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_VENICE);
89314779705SSam Leffler
8943c3e9d33SSam Leffler /* enable features that first appeared in Hainan */
8953c3e9d33SSam Leffler if ((AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE &&
89614779705SSam Leffler AH_PRIVATE(ah)->ah_macRev == AR_SREV_HAINAN) ||
8973c3e9d33SSam Leffler AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE) {
8983c3e9d33SSam Leffler /* h/w phy counters */
8993c3e9d33SSam Leffler pCap->halHwPhyCounterSupport = AH_TRUE;
9003c3e9d33SSam Leffler /* bssid match disable */
9013c3e9d33SSam Leffler pCap->halBssidMatchSupport = AH_TRUE;
9023c3e9d33SSam Leffler }
90314779705SSam Leffler
90451558243SAdrian Chadd pCap->halRxTstampPrecision = 15;
90551558243SAdrian Chadd pCap->halTxTstampPrecision = 16;
906683f3134SSam Leffler pCap->halIntrMask = HAL_INT_COMMON
907683f3134SSam Leffler | HAL_INT_RX
908683f3134SSam Leffler | HAL_INT_TX
909683f3134SSam Leffler | HAL_INT_FATAL
910683f3134SSam Leffler | HAL_INT_BNR
911683f3134SSam Leffler | HAL_INT_BMISC
912683f3134SSam Leffler ;
913210411e0SSam Leffler if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_GRIFFIN)
914210411e0SSam Leffler pCap->halIntrMask &= ~HAL_INT_TBTT;
91514779705SSam Leffler
916e0e5b8b4SAdrian Chadd pCap->hal4kbSplitTransSupport = AH_TRUE;
9178a2a6beeSAdrian Chadd pCap->halHasRxSelfLinkedTail = AH_TRUE;
918e0e5b8b4SAdrian Chadd
91914779705SSam Leffler return AH_TRUE;
92014779705SSam Leffler #undef IS_COBRA
92114779705SSam Leffler #undef IS_GRIFFIN_LITE
92214779705SSam Leffler #undef AR_KEYTABLE_SIZE
92314779705SSam Leffler }
92414779705SSam Leffler
92514779705SSam Leffler static const char*
ar5212Probe(uint16_t vendorid,uint16_t devid)92614779705SSam Leffler ar5212Probe(uint16_t vendorid, uint16_t devid)
92714779705SSam Leffler {
92814779705SSam Leffler if (vendorid == ATHEROS_VENDOR_ID ||
92914779705SSam Leffler vendorid == ATHEROS_3COM_VENDOR_ID ||
93014779705SSam Leffler vendorid == ATHEROS_3COM2_VENDOR_ID) {
93114779705SSam Leffler switch (devid) {
93214779705SSam Leffler case AR5212_FPGA:
93314779705SSam Leffler return "Atheros 5212 (FPGA)";
93414779705SSam Leffler case AR5212_DEVID:
93514779705SSam Leffler case AR5212_DEVID_IBM:
93614779705SSam Leffler case AR5212_DEFAULT:
93714779705SSam Leffler return "Atheros 5212";
93814779705SSam Leffler case AR5212_AR2413:
93914779705SSam Leffler return "Atheros 2413";
94014779705SSam Leffler case AR5212_AR2417:
94114779705SSam Leffler return "Atheros 2417";
94214779705SSam Leffler case AR5212_AR5413:
94314779705SSam Leffler return "Atheros 5413";
94414779705SSam Leffler case AR5212_AR5424:
94514779705SSam Leffler return "Atheros 5424/2424";
94614779705SSam Leffler }
94714779705SSam Leffler }
94814779705SSam Leffler return AH_NULL;
94914779705SSam Leffler }
95014779705SSam Leffler AH_CHIP(AR5212, ar5212Probe, ar5212Attach);
951