2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2006 Atheros Communications, Inc.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * $Id: ar5211_attach.c,v 1.1.1.1 2008/12/11 04:46:31 alc Exp $
22 #include "ah_internal.h"
25 #include "ar5211/ar5211.h"
26 #include "ar5211/ar5211reg.h"
27 #include "ar5211/ar5211phy.h"
29 #include "ah_eeprom_v3.h"
31 static HAL_BOOL
ar5211GetChannelEdges(struct ath_hal
*ah
,
32 uint16_t flags
, uint16_t *low
, uint16_t *high
);
33 static HAL_BOOL
ar5211GetChipPowerLimits(struct ath_hal
*ah
,
34 HAL_CHANNEL
*chans
, uint32_t nchans
);
36 static const struct ath_hal_private ar5211hal
= {{
37 .ah_magic
= AR5211_MAGIC
,
38 .ah_abi
= HAL_ABI_VERSION
,
39 .ah_countryCode
= CTRY_DEFAULT
,
41 .ah_getRateTable
= ar5211GetRateTable
,
42 .ah_detach
= ar5211Detach
,
45 .ah_reset
= ar5211Reset
,
46 .ah_phyDisable
= ar5211PhyDisable
,
47 .ah_disable
= ar5211Disable
,
48 .ah_setPCUConfig
= ar5211SetPCUConfig
,
49 .ah_perCalibration
= ar5211PerCalibration
,
50 .ah_perCalibrationN
= ar5211PerCalibrationN
,
51 .ah_resetCalValid
= ar5211ResetCalValid
,
52 .ah_setTxPowerLimit
= ar5211SetTxPowerLimit
,
53 .ah_getChanNoise
= ath_hal_getChanNoise
,
55 /* Transmit functions */
56 .ah_updateTxTrigLevel
= ar5211UpdateTxTrigLevel
,
57 .ah_setupTxQueue
= ar5211SetupTxQueue
,
58 .ah_setTxQueueProps
= ar5211SetTxQueueProps
,
59 .ah_getTxQueueProps
= ar5211GetTxQueueProps
,
60 .ah_releaseTxQueue
= ar5211ReleaseTxQueue
,
61 .ah_resetTxQueue
= ar5211ResetTxQueue
,
62 .ah_getTxDP
= ar5211GetTxDP
,
63 .ah_setTxDP
= ar5211SetTxDP
,
64 .ah_numTxPending
= ar5211NumTxPending
,
65 .ah_startTxDma
= ar5211StartTxDma
,
66 .ah_stopTxDma
= ar5211StopTxDma
,
67 .ah_setupTxDesc
= ar5211SetupTxDesc
,
68 .ah_setupXTxDesc
= ar5211SetupXTxDesc
,
69 .ah_fillTxDesc
= ar5211FillTxDesc
,
70 .ah_procTxDesc
= ar5211ProcTxDesc
,
71 .ah_getTxIntrQueue
= ar5211GetTxIntrQueue
,
72 .ah_reqTxIntrDesc
= ar5211IntrReqTxDesc
,
75 .ah_getRxDP
= ar5211GetRxDP
,
76 .ah_setRxDP
= ar5211SetRxDP
,
77 .ah_enableReceive
= ar5211EnableReceive
,
78 .ah_stopDmaReceive
= ar5211StopDmaReceive
,
79 .ah_startPcuReceive
= ar5211StartPcuReceive
,
80 .ah_stopPcuReceive
= ar5211StopPcuReceive
,
81 .ah_setMulticastFilter
= ar5211SetMulticastFilter
,
82 .ah_setMulticastFilterIndex
= ar5211SetMulticastFilterIndex
,
83 .ah_clrMulticastFilterIndex
= ar5211ClrMulticastFilterIndex
,
84 .ah_getRxFilter
= ar5211GetRxFilter
,
85 .ah_setRxFilter
= ar5211SetRxFilter
,
86 .ah_setupRxDesc
= ar5211SetupRxDesc
,
87 .ah_procRxDesc
= ar5211ProcRxDesc
,
88 .ah_rxMonitor
= ar5211AniPoll
,
89 .ah_procMibEvent
= ar5211MibEvent
,
92 .ah_getCapability
= ar5211GetCapability
,
93 .ah_setCapability
= ar5211SetCapability
,
94 .ah_getDiagState
= ar5211GetDiagState
,
95 .ah_getMacAddress
= ar5211GetMacAddress
,
96 .ah_setMacAddress
= ar5211SetMacAddress
,
97 .ah_getBssIdMask
= ar5211GetBssIdMask
,
98 .ah_setBssIdMask
= ar5211SetBssIdMask
,
99 .ah_setRegulatoryDomain
= ar5211SetRegulatoryDomain
,
100 .ah_setLedState
= ar5211SetLedState
,
101 .ah_writeAssocid
= ar5211WriteAssocid
,
102 .ah_gpioCfgInput
= ar5211GpioCfgInput
,
103 .ah_gpioCfgOutput
= ar5211GpioCfgOutput
,
104 .ah_gpioGet
= ar5211GpioGet
,
105 .ah_gpioSet
= ar5211GpioSet
,
106 .ah_gpioSetIntr
= ar5211GpioSetIntr
,
107 .ah_getTsf32
= ar5211GetTsf32
,
108 .ah_getTsf64
= ar5211GetTsf64
,
109 .ah_resetTsf
= ar5211ResetTsf
,
110 .ah_detectCardPresent
= ar5211DetectCardPresent
,
111 .ah_updateMibCounters
= ar5211UpdateMibCounters
,
112 .ah_getRfGain
= ar5211GetRfgain
,
113 .ah_getDefAntenna
= ar5211GetDefAntenna
,
114 .ah_setDefAntenna
= ar5211SetDefAntenna
,
115 .ah_getAntennaSwitch
= ar5211GetAntennaSwitch
,
116 .ah_setAntennaSwitch
= ar5211SetAntennaSwitch
,
117 .ah_setSifsTime
= ar5211SetSifsTime
,
118 .ah_getSifsTime
= ar5211GetSifsTime
,
119 .ah_setSlotTime
= ar5211SetSlotTime
,
120 .ah_getSlotTime
= ar5211GetSlotTime
,
121 .ah_setAckTimeout
= ar5211SetAckTimeout
,
122 .ah_getAckTimeout
= ar5211GetAckTimeout
,
123 .ah_setAckCTSRate
= ar5211SetAckCTSRate
,
124 .ah_getAckCTSRate
= ar5211GetAckCTSRate
,
125 .ah_setCTSTimeout
= ar5211SetCTSTimeout
,
126 .ah_getCTSTimeout
= ar5211GetCTSTimeout
,
127 .ah_setDecompMask
= ar5211SetDecompMask
,
128 .ah_setCoverageClass
= ar5211SetCoverageClass
,
130 /* Key Cache Functions */
131 .ah_getKeyCacheSize
= ar5211GetKeyCacheSize
,
132 .ah_resetKeyCacheEntry
= ar5211ResetKeyCacheEntry
,
133 .ah_isKeyCacheEntryValid
= ar5211IsKeyCacheEntryValid
,
134 .ah_setKeyCacheEntry
= ar5211SetKeyCacheEntry
,
135 .ah_setKeyCacheEntryMac
= ar5211SetKeyCacheEntryMac
,
137 /* Power Management Functions */
138 .ah_setPowerMode
= ar5211SetPowerMode
,
139 .ah_getPowerMode
= ar5211GetPowerMode
,
141 /* Beacon Functions */
142 .ah_setBeaconTimers
= ar5211SetBeaconTimers
,
143 .ah_beaconInit
= ar5211BeaconInit
,
144 .ah_setStationBeaconTimers
= ar5211SetStaBeaconTimers
,
145 .ah_resetStationBeaconTimers
= ar5211ResetStaBeaconTimers
,
147 /* Interrupt Functions */
148 .ah_isInterruptPending
= ar5211IsInterruptPending
,
149 .ah_getPendingInterrupts
= ar5211GetPendingInterrupts
,
150 .ah_getInterrupts
= ar5211GetInterrupts
,
151 .ah_setInterrupts
= ar5211SetInterrupts
},
153 .ah_getChannelEdges
= ar5211GetChannelEdges
,
154 .ah_getWirelessModes
= ar5211GetWirelessModes
,
155 .ah_eepromRead
= ar5211EepromRead
,
156 #ifdef AH_SUPPORT_WRITE_EEPROM
157 .ah_eepromWrite
= ar5211EepromWrite
,
159 .ah_gpioCfgInput
= ar5211GpioCfgInput
,
160 .ah_gpioCfgOutput
= ar5211GpioCfgOutput
,
161 .ah_gpioGet
= ar5211GpioGet
,
162 .ah_gpioSet
= ar5211GpioSet
,
163 .ah_gpioSetIntr
= ar5211GpioSetIntr
,
164 .ah_getChipPowerLimits
= ar5211GetChipPowerLimits
,
167 static HAL_BOOL
ar5211ChipTest(struct ath_hal
*);
168 static HAL_BOOL
ar5211FillCapabilityInfo(struct ath_hal
*ah
);
171 * Return the revsion id for the radio chip. This
172 * fetched via the PHY.
175 ar5211GetRadioRev(struct ath_hal
*ah
)
180 OS_REG_WRITE(ah
, (AR_PHY_BASE
+ (0x34 << 2)), 0x00001c16);
181 for (i
= 0; i
< 8; i
++)
182 OS_REG_WRITE(ah
, (AR_PHY_BASE
+ (0x20 << 2)), 0x00010000);
183 val
= (OS_REG_READ(ah
, AR_PHY_BASE
+ (256 << 2)) >> 24) & 0xff;
184 val
= ((val
& 0xf0) >> 4) | ((val
& 0x0f) << 4);
185 return ath_hal_reverseBits(val
, 8);
189 * Attach for an AR5211 part.
192 ar5211Attach(uint16_t devid
, HAL_SOFTC sc
,
193 HAL_BUS_TAG st
, HAL_BUS_HANDLE sh
, HAL_STATUS
*status
)
195 #define N(a) (sizeof(a)/sizeof(a[0]))
196 struct ath_hal_5211
*ahp
;
202 HALDEBUG(AH_NULL
, HAL_DEBUG_ATTACH
, "%s: sc %p st %p sh %p\n",
203 __func__
, sc
, (void*) st
, (void*) sh
);
205 /* NB: memory is returned zero'd */
206 ahp
= ath_hal_malloc(sizeof (struct ath_hal_5211
));
207 if (ahp
== AH_NULL
) {
208 HALDEBUG(AH_NULL
, HAL_DEBUG_ANY
,
209 "%s: cannot allocate memory for state block\n", __func__
);
213 ah
= &ahp
->ah_priv
.h
;
214 /* set initial values */
215 OS_MEMCPY(&ahp
->ah_priv
, &ar5211hal
, sizeof(struct ath_hal_private
));
220 ah
->ah_devid
= devid
; /* NB: for AH_DEBUG_ALQ */
221 AH_PRIVATE(ah
)->ah_devid
= devid
;
222 AH_PRIVATE(ah
)->ah_subvendorid
= 0; /* XXX */
224 AH_PRIVATE(ah
)->ah_powerLimit
= MAX_RATE_POWER
;
225 AH_PRIVATE(ah
)->ah_tpScale
= HAL_TP_SCALE_MAX
; /* no scaling */
227 ahp
->ah_diversityControl
= HAL_ANT_VARIABLE
;
228 ahp
->ah_staId1Defaults
= 0;
229 ahp
->ah_rssiThr
= INIT_RSSI_THR
;
230 ahp
->ah_sifstime
= (u_int
) -1;
231 ahp
->ah_slottime
= (u_int
) -1;
232 ahp
->ah_acktimeout
= (u_int
) -1;
233 ahp
->ah_ctstimeout
= (u_int
) -1;
235 if (!ar5211ChipReset(ah
, AH_FALSE
)) { /* reset chip */
236 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: chip reset failed\n", __func__
);
240 if (AH_PRIVATE(ah
)->ah_devid
== AR5211_FPGA11B
) {
241 /* set it back to OFDM mode to be able to read analog rev id */
242 OS_REG_WRITE(ah
, AR5211_PHY_MODE
, AR5211_PHY_MODE_OFDM
);
243 OS_REG_WRITE(ah
, AR_PHY_PLL_CTL
, AR_PHY_PLL_CTL_44
);
247 /* Read Revisions from Chips */
248 val
= OS_REG_READ(ah
, AR_SREV
) & AR_SREV_ID_M
;
249 AH_PRIVATE(ah
)->ah_macVersion
= val
>> AR_SREV_ID_S
;
250 AH_PRIVATE(ah
)->ah_macRev
= val
& AR_SREV_REVISION_M
;
252 if (AH_PRIVATE(ah
)->ah_macVersion
< AR_SREV_VERSION_MAUI_2
||
253 AH_PRIVATE(ah
)->ah_macVersion
> AR_SREV_VERSION_OAHU
) {
254 HALDEBUG(ah
, HAL_DEBUG_ANY
,
255 "%s: Mac Chip Rev 0x%x is not supported by this driver\n",
256 __func__
, AH_PRIVATE(ah
)->ah_macVersion
);
257 ecode
= HAL_ENOTSUPP
;
261 AH_PRIVATE(ah
)->ah_phyRev
= OS_REG_READ(ah
, AR_PHY_CHIP_ID
);
263 if (!ar5211ChipTest(ah
)) {
264 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: hardware self-test failed\n",
266 ecode
= HAL_ESELFTEST
;
270 /* Set correct Baseband to analog shift setting to access analog chips. */
271 if (AH_PRIVATE(ah
)->ah_macVersion
>= AR_SREV_VERSION_OAHU
) {
272 OS_REG_WRITE(ah
, AR_PHY_BASE
, 0x00000007);
274 OS_REG_WRITE(ah
, AR_PHY_BASE
, 0x00000047);
278 /* Read Radio Chip Rev Extract */
279 AH_PRIVATE(ah
)->ah_analog5GhzRev
= ar5211GetRadioRev(ah
);
280 if ((AH_PRIVATE(ah
)->ah_analog5GhzRev
& 0xf0) != RAD5_SREV_MAJOR
) {
281 HALDEBUG(ah
, HAL_DEBUG_ANY
,
282 "%s: 5G Radio Chip Rev 0x%02X is not supported by this "
283 "driver\n", __func__
, AH_PRIVATE(ah
)->ah_analog5GhzRev
);
284 ecode
= HAL_ENOTSUPP
;
288 val
= (OS_REG_READ(ah
, AR_PCICFG
) & AR_PCICFG_EEPROM_SIZE_M
) >>
289 AR_PCICFG_EEPROM_SIZE_S
;
290 if (val
!= AR_PCICFG_EEPROM_SIZE_16K
) {
291 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unsupported EEPROM size "
292 "%u (0x%x) found\n", __func__
, val
, val
);
296 ecode
= ath_hal_legacyEepromAttach(ah
);
297 if (ecode
!= HAL_OK
) {
301 /* If Bmode and AR5211, verify 2.4 analog exists */
302 if (AH_PRIVATE(ah
)->ah_macVersion
>= AR_SREV_VERSION_OAHU
&&
303 ath_hal_eepromGetFlag(ah
, AR_EEP_BMODE
)) {
304 /* Set correct Baseband to analog shift setting to access analog chips. */
305 OS_REG_WRITE(ah
, AR_PHY_BASE
, 0x00004007);
307 AH_PRIVATE(ah
)->ah_analog2GhzRev
= ar5211GetRadioRev(ah
);
309 /* Set baseband for 5GHz chip */
310 OS_REG_WRITE(ah
, AR_PHY_BASE
, 0x00000007);
312 if ((AH_PRIVATE(ah
)->ah_analog2GhzRev
& 0xF0) != RAD2_SREV_MAJOR
) {
313 HALDEBUG(ah
, HAL_DEBUG_ANY
,
314 "%s: 2G Radio Chip Rev 0x%x is not supported by "
315 "this driver\n", __func__
,
316 AH_PRIVATE(ah
)->ah_analog2GhzRev
);
317 ecode
= HAL_ENOTSUPP
;
321 ath_hal_eepromSet(ah
, AR_EEP_BMODE
, AH_FALSE
);
324 ecode
= ath_hal_eepromGet(ah
, AR_EEP_REGDMN_0
, &eeval
);
325 if (ecode
!= HAL_OK
) {
326 HALDEBUG(ah
, HAL_DEBUG_ANY
,
327 "%s: cannot read regulatory domain from EEPROM\n",
331 AH_PRIVATE(ah
)->ah_currentRD
= eeval
;
332 AH_PRIVATE(ah
)->ah_getNfAdjust
= ar5211GetNfAdjust
;
335 * Got everything we need now to setup the capabilities.
337 (void) ar5211FillCapabilityInfo(ah
);
339 /* Initialize gain ladder thermal calibration structure */
340 ar5211InitializeGainValues(ah
);
342 ecode
= ath_hal_eepromGet(ah
, AR_EEP_MACADDR
, ahp
->ah_macaddr
);
343 if (ecode
!= HAL_OK
) {
344 HALDEBUG(ah
, HAL_DEBUG_ANY
,
345 "%s: error getting mac address from EEPROM\n", __func__
);
349 HALDEBUG(ah
, HAL_DEBUG_ATTACH
, "%s: return\n", __func__
);
354 ar5211Detach((struct ath_hal
*) ahp
);
362 ar5211Detach(struct ath_hal
*ah
)
364 HALDEBUG(ah
, HAL_DEBUG_ATTACH
, "%s:\n", __func__
);
366 HALASSERT(ah
!= AH_NULL
);
367 HALASSERT(ah
->ah_magic
== AR5211_MAGIC
);
369 ath_hal_eepromDetach(ah
);
374 ar5211ChipTest(struct ath_hal
*ah
)
376 uint32_t regAddr
[2] = { AR_STA_ID0
, AR_PHY_BASE
+(8 << 2) };
378 uint32_t patternData
[4] =
379 { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 };
382 /* Test PHY & MAC registers */
383 for (i
= 0; i
< 2; i
++) {
384 uint32_t addr
= regAddr
[i
];
385 uint32_t wrData
, rdData
;
387 regHold
[i
] = OS_REG_READ(ah
, addr
);
388 for (j
= 0; j
< 0x100; j
++) {
389 wrData
= (j
<< 16) | j
;
390 OS_REG_WRITE(ah
, addr
, wrData
);
391 rdData
= OS_REG_READ(ah
, addr
);
392 if (rdData
!= wrData
) {
393 HALDEBUG(ah
, HAL_DEBUG_ANY
,
394 "%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
395 __func__
, addr
, wrData
, rdData
);
399 for (j
= 0; j
< 4; j
++) {
400 wrData
= patternData
[j
];
401 OS_REG_WRITE(ah
, addr
, wrData
);
402 rdData
= OS_REG_READ(ah
, addr
);
403 if (wrData
!= rdData
) {
404 HALDEBUG(ah
, HAL_DEBUG_ANY
,
405 "%s: address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
406 __func__
, addr
, wrData
, rdData
);
410 OS_REG_WRITE(ah
, regAddr
[i
], regHold
[i
]);
417 * Store the channel edges for the requested operational mode
420 ar5211GetChannelEdges(struct ath_hal
*ah
,
421 uint16_t flags
, uint16_t *low
, uint16_t *high
)
423 if (flags
& CHANNEL_5GHZ
) {
428 if (flags
& CHANNEL_2GHZ
&& ath_hal_eepromGetFlag(ah
, AR_EEP_BMODE
)) {
437 ar5211GetChipPowerLimits(struct ath_hal
*ah
, HAL_CHANNEL
*chans
, uint32_t nchans
)
442 /* XXX fill in, this is just a placeholder */
443 for (i
= 0; i
< nchans
; i
++) {
445 HALDEBUG(ah
, HAL_DEBUG_ATTACH
,
446 "%s: no min/max power for %u/0x%x\n",
447 __func__
, chan
->channel
, chan
->channelFlags
);
448 chan
->maxTxPower
= MAX_RATE_POWER
;
449 chan
->minTxPower
= 0;
455 * Fill all software cached or static hardware state information.
458 ar5211FillCapabilityInfo(struct ath_hal
*ah
)
460 struct ath_hal_private
*ahpriv
= AH_PRIVATE(ah
);
461 HAL_CAPABILITIES
*pCap
= &ahpriv
->ah_caps
;
463 /* Construct wireless mode from EEPROM */
464 pCap
->halWirelessModes
= 0;
465 if (ath_hal_eepromGetFlag(ah
, AR_EEP_AMODE
)) {
466 pCap
->halWirelessModes
|= HAL_MODE_11A
;
467 if (!ath_hal_eepromGetFlag(ah
, AR_EEP_TURBO5DISABLE
))
468 pCap
->halWirelessModes
|= HAL_MODE_TURBO
;
470 if (ath_hal_eepromGetFlag(ah
, AR_EEP_BMODE
))
471 pCap
->halWirelessModes
|= HAL_MODE_11B
;
473 pCap
->halLow2GhzChan
= 2312;
474 pCap
->halHigh2GhzChan
= 2732;
475 pCap
->halLow5GhzChan
= 4920;
476 pCap
->halHigh5GhzChan
= 6100;
478 pCap
->halChanSpreadSupport
= AH_TRUE
;
479 pCap
->halSleepAfterBeaconBroken
= AH_TRUE
;
480 pCap
->halPSPollBroken
= AH_TRUE
;
481 pCap
->halVEOLSupport
= AH_TRUE
;
483 pCap
->halTotalQueues
= HAL_NUM_TX_QUEUES
;
484 pCap
->halKeyCacheSize
= 128;
487 pCap
->halChanHalfRate
= AH_FALSE
;
488 pCap
->halChanQuarterRate
= AH_FALSE
;
490 if (ath_hal_eepromGetFlag(ah
, AR_EEP_RFKILL
) &&
491 ath_hal_eepromGet(ah
, AR_EEP_RFSILENT
, &ahpriv
->ah_rfsilent
) == HAL_OK
) {
492 /* NB: enabled by default */
493 ahpriv
->ah_rfkillEnabled
= AH_TRUE
;
494 pCap
->halRfSilentSupport
= AH_TRUE
;
497 pCap
->halTstampPrecision
= 13;
499 /* XXX might be ok w/ some chip revs */
500 ahpriv
->ah_rxornIsFatal
= AH_TRUE
;
505 ar5211Probe(uint16_t vendorid
, uint16_t devid
)
507 if (vendorid
== ATHEROS_VENDOR_ID
) {
508 if (devid
== AR5211_DEVID
|| devid
== AR5311_DEVID
||
509 devid
== AR5211_DEFAULT
)
510 return "Atheros 5211";
511 if (devid
== AR5211_FPGA11B
)
512 return "Atheros 5211 (FPGA)";
516 AH_CHIP(AR5211
, ar5211Probe
, ar5211Attach
);