2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2004 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.
21 #ifdef AH_SUPPORT_AR5210
24 #include "ah_internal.h"
26 #include "ar5210/ar5210.h"
27 #include "ar5210/ar5210reg.h"
28 #include "ar5210/ar5210phy.h"
30 static HAL_BOOL
ar5210GetChannelEdges(struct ath_hal
*,
31 uint16_t flags
, uint16_t *low
, uint16_t *high
);
32 static HAL_BOOL
ar5210GetChipPowerLimits(struct ath_hal
*ah
,
33 HAL_CHANNEL
*chans
, uint32_t nchans
);
35 static const struct ath_hal_private ar5210hal
= {{
36 .ah_magic
= AR5210_MAGIC
,
37 .ah_abi
= HAL_ABI_VERSION
,
38 .ah_countryCode
= CTRY_DEFAULT
,
40 .ah_getRateTable
= ar5210GetRateTable
,
41 .ah_detach
= ar5210Detach
,
44 .ah_reset
= ar5210Reset
,
45 .ah_phyDisable
= ar5210PhyDisable
,
46 .ah_disable
= ar5210Disable
,
47 .ah_setPCUConfig
= ar5210SetPCUConfig
,
48 .ah_perCalibration
= ar5210PerCalibration
,
49 .ah_setTxPowerLimit
= ar5210SetTxPowerLimit
,
50 .ah_getChanNoise
= ath_hal_getChanNoise
,
52 /* Transmit functions */
53 .ah_updateTxTrigLevel
= ar5210UpdateTxTrigLevel
,
54 .ah_setupTxQueue
= ar5210SetupTxQueue
,
55 .ah_setTxQueueProps
= ar5210SetTxQueueProps
,
56 .ah_getTxQueueProps
= ar5210GetTxQueueProps
,
57 .ah_releaseTxQueue
= ar5210ReleaseTxQueue
,
58 .ah_resetTxQueue
= ar5210ResetTxQueue
,
59 .ah_getTxDP
= ar5210GetTxDP
,
60 .ah_setTxDP
= ar5210SetTxDP
,
61 .ah_numTxPending
= ar5210NumTxPending
,
62 .ah_startTxDma
= ar5210StartTxDma
,
63 .ah_stopTxDma
= ar5210StopTxDma
,
64 .ah_setupTxDesc
= ar5210SetupTxDesc
,
65 .ah_setupXTxDesc
= ar5210SetupXTxDesc
,
66 .ah_fillTxDesc
= ar5210FillTxDesc
,
67 .ah_procTxDesc
= ar5210ProcTxDesc
,
68 .ah_getTxIntrQueue
= ar5210GetTxIntrQueue
,
69 .ah_reqTxIntrDesc
= ar5210IntrReqTxDesc
,
72 .ah_getRxDP
= ar5210GetRxDP
,
73 .ah_setRxDP
= ar5210SetRxDP
,
74 .ah_enableReceive
= ar5210EnableReceive
,
75 .ah_stopDmaReceive
= ar5210StopDmaReceive
,
76 .ah_startPcuReceive
= ar5210StartPcuReceive
,
77 .ah_stopPcuReceive
= ar5210StopPcuReceive
,
78 .ah_setMulticastFilter
= ar5210SetMulticastFilter
,
79 .ah_setMulticastFilterIndex
= ar5210SetMulticastFilterIndex
,
80 .ah_clrMulticastFilterIndex
= ar5210ClrMulticastFilterIndex
,
81 .ah_getRxFilter
= ar5210GetRxFilter
,
82 .ah_setRxFilter
= ar5210SetRxFilter
,
83 .ah_setupRxDesc
= ar5210SetupRxDesc
,
84 .ah_procRxDesc
= ar5210ProcRxDesc
,
85 .ah_rxMonitor
= ar5210AniPoll
,
86 .ah_procMibEvent
= ar5210MibEvent
,
89 .ah_getCapability
= ar5210GetCapability
,
90 .ah_setCapability
= ar5210SetCapability
,
91 .ah_getDiagState
= ar5210GetDiagState
,
92 .ah_getMacAddress
= ar5210GetMacAddress
,
93 .ah_setMacAddress
= ar5210SetMacAddress
,
94 .ah_getBssIdMask
= ar5210GetBssIdMask
,
95 .ah_setBssIdMask
= ar5210SetBssIdMask
,
96 .ah_setLedState
= ar5210SetLedState
,
97 .ah_writeAssocid
= ar5210WriteAssocid
,
98 .ah_gpioCfgInput
= ar5210GpioCfgInput
,
99 .ah_gpioCfgOutput
= ar5210GpioCfgOutput
,
100 .ah_gpioGet
= ar5210GpioGet
,
101 .ah_gpioSet
= ar5210GpioSet
,
102 .ah_gpioSetIntr
= ar5210Gpio0SetIntr
,
103 .ah_getTsf32
= ar5210GetTsf32
,
104 .ah_getTsf64
= ar5210GetTsf64
,
105 .ah_resetTsf
= ar5210ResetTsf
,
106 .ah_detectCardPresent
= ar5210DetectCardPresent
,
107 .ah_updateMibCounters
= ar5210UpdateMibCounters
,
108 .ah_getRfGain
= ar5210GetRfgain
,
109 .ah_getDefAntenna
= ar5210GetDefAntenna
,
110 .ah_setDefAntenna
= ar5210SetDefAntenna
,
111 .ah_getAntennaSwitch
= ar5210GetAntennaSwitch
,
112 .ah_setAntennaSwitch
= ar5210SetAntennaSwitch
,
113 .ah_setSifsTime
= ar5210SetSifsTime
,
114 .ah_getSifsTime
= ar5210GetSifsTime
,
115 .ah_setSlotTime
= ar5210SetSlotTime
,
116 .ah_getSlotTime
= ar5210GetSlotTime
,
117 .ah_setAckTimeout
= ar5210SetAckTimeout
,
118 .ah_getAckTimeout
= ar5210GetAckTimeout
,
119 .ah_setAckCTSRate
= ar5210SetAckCTSRate
,
120 .ah_getAckCTSRate
= ar5210GetAckCTSRate
,
121 .ah_setCTSTimeout
= ar5210SetCTSTimeout
,
122 .ah_getCTSTimeout
= ar5210GetCTSTimeout
,
123 .ah_setDecompMask
= ar5210SetDecompMask
,
124 .ah_setCoverageClass
= ar5210SetCoverageClass
,
126 /* Key Cache Functions */
127 .ah_getKeyCacheSize
= ar5210GetKeyCacheSize
,
128 .ah_resetKeyCacheEntry
= ar5210ResetKeyCacheEntry
,
129 .ah_isKeyCacheEntryValid
= ar5210IsKeyCacheEntryValid
,
130 .ah_setKeyCacheEntry
= ar5210SetKeyCacheEntry
,
131 .ah_setKeyCacheEntryMac
= ar5210SetKeyCacheEntryMac
,
133 /* Power Management Functions */
134 .ah_setPowerMode
= ar5210SetPowerMode
,
135 .ah_getPowerMode
= ar5210GetPowerMode
,
137 /* Beacon Functions */
138 .ah_setBeaconTimers
= ar5210SetBeaconTimers
,
139 .ah_beaconInit
= ar5210BeaconInit
,
140 .ah_setStationBeaconTimers
= ar5210SetStaBeaconTimers
,
141 .ah_resetStationBeaconTimers
= ar5210ResetStaBeaconTimers
,
143 /* Interrupt Functions */
144 .ah_isInterruptPending
= ar5210IsInterruptPending
,
145 .ah_getPendingInterrupts
= ar5210GetPendingInterrupts
,
146 .ah_getInterrupts
= ar5210GetInterrupts
,
147 .ah_setInterrupts
= ar5210SetInterrupts
},
149 .ah_getChannelEdges
= ar5210GetChannelEdges
,
150 .ah_getWirelessModes
= ar5210GetWirelessModes
,
151 .ah_eepromRead
= ar5210EepromRead
,
152 #ifdef AH_SUPPORT_WRITE_EEPROM
153 .ah_eepromWrite
= ar5210EepromWrite
,
155 .ah_gpioCfgInput
= ar5210GpioCfgInput
,
156 .ah_gpioCfgOutput
= ar5210GpioCfgOutput
,
157 .ah_gpioGet
= ar5210GpioGet
,
158 .ah_gpioSet
= ar5210GpioSet
,
159 .ah_gpioSetIntr
= ar5210Gpio0SetIntr
,
160 .ah_getChipPowerLimits
= ar5210GetChipPowerLimits
,
163 static HAL_BOOL
ar5210FillCapabilityInfo(struct ath_hal
*ah
);
166 * Attach for an AR5210 part.
169 ar5210Attach(uint16_t devid
, HAL_SOFTC sc
, HAL_BUS_TAG st
, HAL_BUS_HANDLE sh
, HAL_STATUS
*status
)
171 #define N(a) (sizeof(a)/sizeof(a[0]))
172 struct ath_hal_5210
*ahp
;
175 uint32_t revid
, pcicfg
, sum
;
176 uint16_t athvals
[AR_EEPROM_ATHEROS_MAX
], eeval
;
179 HALDEBUG(AH_NULL
, HAL_DEBUG_ATTACH
,
180 "%s: devid 0x%x sc %p st %p sh %p\n", __func__
, devid
,
181 sc
, (void*) st
, (void*) sh
);
183 /* NB: memory is returned zero'd */
184 ahp
= ath_hal_malloc(sizeof (struct ath_hal_5210
));
185 if (ahp
== AH_NULL
) {
186 HALDEBUG(AH_NULL
, HAL_DEBUG_ANY
,
187 "%s: no memory for state block\n", __func__
);
191 ah
= &ahp
->ah_priv
.h
;
192 /* set initial values */
193 OS_MEMCPY(&ahp
->ah_priv
, &ar5210hal
, sizeof(struct ath_hal_private
));
198 ah
->ah_devid
= devid
; /* NB: for AH_DEBUG_ALQ */
199 AH_PRIVATE(ah
)->ah_devid
= devid
;
200 AH_PRIVATE(ah
)->ah_subvendorid
= 0; /* XXX */
202 AH_PRIVATE(ah
)->ah_powerLimit
= MAX_RATE_POWER
;
203 AH_PRIVATE(ah
)->ah_tpScale
= HAL_TP_SCALE_MAX
; /* no scaling */
205 ahp
->ah_powerMode
= HAL_PM_UNDEFINED
;
206 ahp
->ah_staId1Defaults
= 0;
207 ahp
->ah_rssiThr
= INIT_RSSI_THR
;
208 ahp
->ah_sifstime
= (u_int
) -1;
209 ahp
->ah_slottime
= (u_int
) -1;
210 ahp
->ah_acktimeout
= (u_int
) -1;
211 ahp
->ah_ctstimeout
= (u_int
) -1;
213 if (!ar5210ChipReset(ah
, AH_NULL
)) { /* reset chip */
214 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: chip reset failed\n",
220 /* Read Revisions from Chips */
221 AH_PRIVATE(ah
)->ah_macVersion
= 1;
222 AH_PRIVATE(ah
)->ah_macRev
= OS_REG_READ(ah
, AR_SREV
) & 0xff;
223 AH_PRIVATE(ah
)->ah_phyRev
= OS_REG_READ(ah
, AR_PHY_CHIPID
);
224 AH_PRIVATE(ah
)->ah_analog2GhzRev
= 0;
226 /* Read Radio Chip Rev Extract */
227 OS_REG_WRITE(ah
, (AR_PHY_BASE
+ (0x34 << 2)), 0x00001c16);
228 for (i
= 0; i
< 4; i
++)
229 OS_REG_WRITE(ah
, (AR_PHY_BASE
+ (0x20 << 2)), 0x00010000);
230 revid
= (OS_REG_READ(ah
, AR_PHY_BASE
+ (256 << 2)) >> 28) & 0xf;
232 /* Chip labelling is 1 greater than revision register for AR5110 */
233 AH_PRIVATE(ah
)->ah_analog5GhzRev
= ath_hal_reverseBits(revid
, 4) + 1;
236 * Read all the settings from the EEPROM and stash
237 * ones we'll use later in our state block.
239 pcicfg
= OS_REG_READ(ah
, AR_PCICFG
);
240 OS_REG_WRITE(ah
, AR_PCICFG
, pcicfg
| AR_PCICFG_EEPROMSEL
);
242 if (!ar5210EepromRead(ah
, AR_EEPROM_MAGIC
, &eeval
)) {
243 HALDEBUG(ah
, HAL_DEBUG_ANY
,
244 "%s: cannot read EEPROM magic number\n", __func__
);
248 if (eeval
!= 0x5aa5) {
249 HALDEBUG(ah
, HAL_DEBUG_ANY
,
250 "%s: invalid EEPROM magic number 0x%x\n", __func__
, eeval
);
255 if (!ar5210EepromRead(ah
, AR_EEPROM_PROTECT
, &eeval
)) {
256 HALDEBUG(ah
, HAL_DEBUG_ANY
,
257 "%s: cannot read EEPROM protection bits; read locked?\n",
262 HALDEBUG(ah
, HAL_DEBUG_ATTACH
, "EEPROM protect 0x%x\n", eeval
);
263 ahp
->ah_eeprotect
= eeval
;
264 /* XXX check proper access before continuing */
266 if (!ar5210EepromRead(ah
, AR_EEPROM_VERSION
, &eeval
)) {
267 HALDEBUG(ah
, HAL_DEBUG_ANY
,
268 "%s: unable to read EEPROM version\n", __func__
);
272 ahp
->ah_eeversion
= (eeval
>>12) & 0xf;
273 if (ahp
->ah_eeversion
!= 1) {
275 * This driver only groks the version 1 EEPROM layout.
277 HALDEBUG(ah
, HAL_DEBUG_ANY
,
278 "%s: unsupported EEPROM version %u (0x%x) found\n",
279 __func__
, ahp
->ah_eeversion
, eeval
);
280 ecode
= HAL_EEVERSION
;
285 * Read the Atheros EEPROM entries and calculate the checksum.
288 for (i
= 0; i
< AR_EEPROM_ATHEROS_MAX
; i
++) {
289 if (!ar5210EepromRead(ah
, AR_EEPROM_ATHEROS(i
), &athvals
[i
])) {
296 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: bad EEPROM checksum 0x%x\n",
298 ecode
= HAL_EEBADSUM
;
303 * Valid checksum, fetch the regulatory domain and save values.
305 if (!ar5210EepromRead(ah
, AR_EEPROM_REG_DOMAIN
, &eeval
)) {
306 HALDEBUG(ah
, HAL_DEBUG_ANY
,
307 "%s: cannot read regdomain from EEPROM\n", __func__
);
312 AH_PRIVATE(ah
)->ah_currentRD
= eeval
& 0xff;
313 ahp
->ah_antenna
= athvals
[2];
314 ahp
->ah_biasCurrents
= athvals
[3];
315 ahp
->ah_thresh62
= athvals
[4] & 0xff;
316 ahp
->ah_xlnaOn
= (athvals
[4] >> 8) & 0xff;
317 ahp
->ah_xpaOn
= athvals
[5] & 0xff;
318 ahp
->ah_xpaOff
= (athvals
[5] >> 8) & 0xff;
319 ahp
->ah_regDomain
[0] = (athvals
[6] >> 8) & 0xff;
320 ahp
->ah_regDomain
[1] = athvals
[6] & 0xff;
321 ahp
->ah_regDomain
[2] = (athvals
[7] >> 8) & 0xff;
322 ahp
->ah_regDomain
[3] = athvals
[7] & 0xff;
323 ahp
->ah_rfKill
= athvals
[8] & 0x1;
324 ahp
->ah_devType
= (athvals
[8] >> 1) & 0x7;
325 AH_PRIVATE(ah
)->ah_getNfAdjust
= ar5210GetNfAdjust
;
327 for (i
= 0, loc
= AR_EEPROM_ATHEROS_TP_SETTINGS
; i
< AR_CHANNELS_MAX
; i
++, loc
+= AR_TP_SETTINGS_SIZE
) {
328 struct tpcMap
*chan
= &ahp
->ah_tpc
[i
];
330 /* Copy pcdac and gain_f values from EEPROM */
331 chan
->pcdac
[0] = (athvals
[loc
] >> 10) & 0x3F;
332 chan
->gainF
[0] = (athvals
[loc
] >> 4) & 0x3F;
333 chan
->pcdac
[1] = ((athvals
[loc
] << 2) & 0x3C)
334 | ((athvals
[loc
+1] >> 14) & 0x03);
335 chan
->gainF
[1] = (athvals
[loc
+1] >> 8) & 0x3F;
336 chan
->pcdac
[2] = (athvals
[loc
+1] >> 2) & 0x3F;
337 chan
->gainF
[2] = ((athvals
[loc
+1] << 4) & 0x30)
338 | ((athvals
[loc
+2] >> 12) & 0x0F);
339 chan
->pcdac
[3] = (athvals
[loc
+2] >> 6) & 0x3F;
340 chan
->gainF
[3] = athvals
[loc
+2] & 0x3F;
341 chan
->pcdac
[4] = (athvals
[loc
+3] >> 10) & 0x3F;
342 chan
->gainF
[4] = (athvals
[loc
+3] >> 4) & 0x3F;
343 chan
->pcdac
[5] = ((athvals
[loc
+3] << 2) & 0x3C)
344 | ((athvals
[loc
+4] >> 14) & 0x03);
345 chan
->gainF
[5] = (athvals
[loc
+4] >> 8) & 0x3F;
346 chan
->pcdac
[6] = (athvals
[loc
+4] >> 2) & 0x3F;
347 chan
->gainF
[6] = ((athvals
[loc
+4] << 4) & 0x30)
348 | ((athvals
[loc
+5] >> 12) & 0x0F);
349 chan
->pcdac
[7] = (athvals
[loc
+5] >> 6) & 0x3F;
350 chan
->gainF
[7] = athvals
[loc
+5] & 0x3F;
351 chan
->pcdac
[8] = (athvals
[loc
+6] >> 10) & 0x3F;
352 chan
->gainF
[8] = (athvals
[loc
+6] >> 4) & 0x3F;
353 chan
->pcdac
[9] = ((athvals
[loc
+6] << 2) & 0x3C)
354 | ((athvals
[loc
+7] >> 14) & 0x03);
355 chan
->gainF
[9] = (athvals
[loc
+7] >> 8) & 0x3F;
356 chan
->pcdac
[10] = (athvals
[loc
+7] >> 2) & 0x3F;
357 chan
->gainF
[10] = ((athvals
[loc
+7] << 4) & 0x30)
358 | ((athvals
[loc
+8] >> 12) & 0x0F);
360 /* Copy Regulatory Domain and Rate Information from EEPROM */
361 chan
->rate36
= (athvals
[loc
+8] >> 6) & 0x3F;
362 chan
->rate48
= athvals
[loc
+8] & 0x3F;
363 chan
->rate54
= (athvals
[loc
+9] >> 10) & 0x3F;
364 chan
->regdmn
[0] = (athvals
[loc
+9] >> 4) & 0x3F;
365 chan
->regdmn
[1] = ((athvals
[loc
+9] << 2) & 0x3C)
366 | ((athvals
[loc
+10] >> 14) & 0x03);
367 chan
->regdmn
[2] = (athvals
[loc
+10] >> 8) & 0x3F;
368 chan
->regdmn
[3] = (athvals
[loc
+10] >> 2) & 0x3F;
371 * Got everything we need now to setup the capabilities.
373 (void) ar5210FillCapabilityInfo(ah
);
376 for (i
= 0; i
< 3; i
++) {
377 if (!ar5210EepromRead(ah
, AR_EEPROM_MAC(i
), &eeval
)) {
378 HALDEBUG(ah
, HAL_DEBUG_ANY
,
379 "%s: cannot read EEPROM location %u\n", __func__
, i
);
384 ahp
->ah_macaddr
[2*i
+ 0] = eeval
>> 8;
385 ahp
->ah_macaddr
[2*i
+ 1] = eeval
& 0xff;
387 if (sum
== 0 || sum
== 0xffff*3) {
388 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: mac address read failed: %s\n",
389 __func__
, ath_hal_ether_sprintf(ahp
->ah_macaddr
));
390 ecode
= HAL_EEBADMAC
;
394 OS_REG_WRITE(ah
, AR_PCICFG
, pcicfg
); /* disable EEPROM access */
396 HALDEBUG(ah
, HAL_DEBUG_ATTACH
, "%s: return\n", __func__
);
401 OS_REG_WRITE(ah
, AR_PCICFG
, pcicfg
); /* disable EEPROM access */
412 ar5210Detach(struct ath_hal
*ah
)
414 HALDEBUG(ah
, HAL_DEBUG_ATTACH
, "%s:\n", __func__
);
416 HALASSERT(ah
!= AH_NULL
);
417 HALASSERT(ah
->ah_magic
== AR5210_MAGIC
);
423 * Store the channel edges for the requested operational mode
426 ar5210GetChannelEdges(struct ath_hal
*ah
,
427 uint16_t flags
, uint16_t *low
, uint16_t *high
)
429 if (flags
& CHANNEL_5GHZ
) {
439 ar5210GetChipPowerLimits(struct ath_hal
*ah
, HAL_CHANNEL
*chans
, uint32_t nchans
)
444 /* XXX fill in, this is just a placeholder */
445 for (i
= 0; i
< nchans
; i
++) {
447 HALDEBUG(ah
, HAL_DEBUG_ATTACH
,
448 "%s: no min/max power for %u/0x%x\n",
449 __func__
, chan
->channel
, chan
->channelFlags
);
450 chan
->maxTxPower
= MAX_RATE_POWER
;
451 chan
->minTxPower
= 0;
457 * Fill all software cached or static hardware state information.
460 ar5210FillCapabilityInfo(struct ath_hal
*ah
)
462 struct ath_hal_private
*ahpriv
= AH_PRIVATE(ah
);
463 HAL_CAPABILITIES
*pCap
= &ahpriv
->ah_caps
;
465 pCap
->halWirelessModes
|= HAL_MODE_11A
;
467 pCap
->halLow5GhzChan
= 5120;
468 pCap
->halHigh5GhzChan
= 5430;
470 pCap
->halSleepAfterBeaconBroken
= AH_TRUE
;
471 pCap
->halPSPollBroken
= AH_FALSE
;
473 pCap
->halTotalQueues
= HAL_NUM_TX_QUEUES
;
474 pCap
->halKeyCacheSize
= 64;
477 pCap
->halChanHalfRate
= AH_FALSE
;
478 pCap
->halChanQuarterRate
= AH_FALSE
;
480 if (AH5210(ah
)->ah_rfKill
) {
482 * Setup initial rfsilent settings based on the EEPROM
483 * contents. Pin 0, polarity 0 is fixed; record this
484 * using the EEPROM format found in later parts.
486 ahpriv
->ah_rfsilent
= SM(0, AR_EEPROM_RFSILENT_GPIO_SEL
)
487 | SM(0, AR_EEPROM_RFSILENT_POLARITY
);
488 ahpriv
->ah_rfkillEnabled
= AH_TRUE
;
489 pCap
->halRfSilentSupport
= AH_TRUE
;
492 pCap
->halTstampPrecision
= 15; /* NB: s/w extended from 13 */
494 ahpriv
->ah_rxornIsFatal
= AH_TRUE
;
497 #endif /* AH_SUPPORT_AR5210 */