1 | /* |
2 | * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting |
3 | * Copyright (c) 2002-2004 Atheros Communications, Inc. |
4 | * |
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. |
8 | * |
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. |
16 | * |
17 | * $Id: ar5210_attach.c,v 1.3 2011/03/07 11:25:42 cegger Exp $ |
18 | */ |
19 | #include "opt_ah.h" |
20 | |
21 | #include "ah.h" |
22 | #include "ah_internal.h" |
23 | #include "ah_devid.h" |
24 | |
25 | #include "ar5210/ar5210.h" |
26 | #include "ar5210/ar5210reg.h" |
27 | #include "ar5210/ar5210phy.h" |
28 | |
29 | #include "ah_eeprom_v1.h" |
30 | |
31 | static HAL_BOOL ar5210GetChannelEdges(struct ath_hal *, |
32 | uint16_t flags, uint16_t *low, uint16_t *high); |
33 | static HAL_BOOL ar5210GetChipPowerLimits(struct ath_hal *ah, |
34 | HAL_CHANNEL *chans, uint32_t nchans); |
35 | |
36 | static void ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore); |
37 | static void ar5210DisablePCIE(struct ath_hal *ah); |
38 | |
39 | static const struct ath_hal_private ar5210hal = {{ |
40 | .ah_magic = AR5210_MAGIC, |
41 | .ah_abi = HAL_ABI_VERSION, |
42 | .ah_countryCode = CTRY_DEFAULT, |
43 | |
44 | .ah_getRateTable = ar5210GetRateTable, |
45 | .ah_detach = ar5210Detach, |
46 | |
47 | /* Reset Functions */ |
48 | .ah_reset = ar5210Reset, |
49 | .ah_phyDisable = ar5210PhyDisable, |
50 | .ah_disable = ar5210Disable, |
51 | .ah_configPCIE = ar5210ConfigPCIE, |
52 | .ah_disablePCIE = ar5210DisablePCIE, |
53 | .ah_setPCUConfig = ar5210SetPCUConfig, |
54 | .ah_perCalibration = ar5210PerCalibration, |
55 | .ah_perCalibrationN = ar5210PerCalibrationN, |
56 | .ah_resetCalValid = ar5210ResetCalValid, |
57 | .ah_setTxPowerLimit = ar5210SetTxPowerLimit, |
58 | .ah_getChanNoise = ath_hal_getChanNoise, |
59 | |
60 | /* Transmit functions */ |
61 | .ah_updateTxTrigLevel = ar5210UpdateTxTrigLevel, |
62 | .ah_setupTxQueue = ar5210SetupTxQueue, |
63 | .ah_setTxQueueProps = ar5210SetTxQueueProps, |
64 | .ah_getTxQueueProps = ar5210GetTxQueueProps, |
65 | .ah_releaseTxQueue = ar5210ReleaseTxQueue, |
66 | .ah_resetTxQueue = ar5210ResetTxQueue, |
67 | .ah_getTxDP = ar5210GetTxDP, |
68 | .ah_setTxDP = ar5210SetTxDP, |
69 | .ah_numTxPending = ar5210NumTxPending, |
70 | .ah_startTxDma = ar5210StartTxDma, |
71 | .ah_stopTxDma = ar5210StopTxDma, |
72 | .ah_setupTxDesc = ar5210SetupTxDesc, |
73 | .ah_setupXTxDesc = ar5210SetupXTxDesc, |
74 | .ah_fillTxDesc = ar5210FillTxDesc, |
75 | .ah_procTxDesc = ar5210ProcTxDesc, |
76 | .ah_getTxIntrQueue = ar5210GetTxIntrQueue, |
77 | .ah_reqTxIntrDesc = ar5210IntrReqTxDesc, |
78 | |
79 | /* RX Functions */ |
80 | .ah_getRxDP = ar5210GetRxDP, |
81 | .ah_setRxDP = ar5210SetRxDP, |
82 | .ah_enableReceive = ar5210EnableReceive, |
83 | .ah_stopDmaReceive = ar5210StopDmaReceive, |
84 | .ah_startPcuReceive = ar5210StartPcuReceive, |
85 | .ah_stopPcuReceive = ar5210StopPcuReceive, |
86 | .ah_setMulticastFilter = ar5210SetMulticastFilter, |
87 | .ah_setMulticastFilterIndex = ar5210SetMulticastFilterIndex, |
88 | .ah_clrMulticastFilterIndex = ar5210ClrMulticastFilterIndex, |
89 | .ah_getRxFilter = ar5210GetRxFilter, |
90 | .ah_setRxFilter = ar5210SetRxFilter, |
91 | .ah_setupRxDesc = ar5210SetupRxDesc, |
92 | .ah_procRxDesc = ar5210ProcRxDesc, |
93 | .ah_rxMonitor = ar5210AniPoll, |
94 | .ah_procMibEvent = ar5210MibEvent, |
95 | |
96 | /* Misc Functions */ |
97 | .ah_getCapability = ar5210GetCapability, |
98 | .ah_setCapability = ar5210SetCapability, |
99 | .ah_getDiagState = ar5210GetDiagState, |
100 | .ah_getMacAddress = ar5210GetMacAddress, |
101 | .ah_setMacAddress = ar5210SetMacAddress, |
102 | .ah_getBssIdMask = ar5210GetBssIdMask, |
103 | .ah_setBssIdMask = ar5210SetBssIdMask, |
104 | .ah_setRegulatoryDomain = ar5210SetRegulatoryDomain, |
105 | .ah_setLedState = ar5210SetLedState, |
106 | .ah_writeAssocid = ar5210WriteAssocid, |
107 | .ah_gpioCfgInput = ar5210GpioCfgInput, |
108 | .ah_gpioCfgOutput = ar5210GpioCfgOutput, |
109 | .ah_gpioGet = ar5210GpioGet, |
110 | .ah_gpioSet = ar5210GpioSet, |
111 | .ah_gpioSetIntr = ar5210Gpio0SetIntr, |
112 | .ah_getTsf32 = ar5210GetTsf32, |
113 | .ah_getTsf64 = ar5210GetTsf64, |
114 | .ah_resetTsf = ar5210ResetTsf, |
115 | .ah_detectCardPresent = ar5210DetectCardPresent, |
116 | .ah_updateMibCounters = ar5210UpdateMibCounters, |
117 | .ah_getRfGain = ar5210GetRfgain, |
118 | .ah_getDefAntenna = ar5210GetDefAntenna, |
119 | .ah_setDefAntenna = ar5210SetDefAntenna, |
120 | .ah_getAntennaSwitch = ar5210GetAntennaSwitch, |
121 | .ah_setAntennaSwitch = ar5210SetAntennaSwitch, |
122 | .ah_setSifsTime = ar5210SetSifsTime, |
123 | .ah_getSifsTime = ar5210GetSifsTime, |
124 | .ah_setSlotTime = ar5210SetSlotTime, |
125 | .ah_getSlotTime = ar5210GetSlotTime, |
126 | .ah_setAckTimeout = ar5210SetAckTimeout, |
127 | .ah_getAckTimeout = ar5210GetAckTimeout, |
128 | .ah_setAckCTSRate = ar5210SetAckCTSRate, |
129 | .ah_getAckCTSRate = ar5210GetAckCTSRate, |
130 | .ah_setCTSTimeout = ar5210SetCTSTimeout, |
131 | .ah_getCTSTimeout = ar5210GetCTSTimeout, |
132 | .ah_setDecompMask = ar5210SetDecompMask, |
133 | .ah_setCoverageClass = ar5210SetCoverageClass, |
134 | |
135 | /* Key Cache Functions */ |
136 | .ah_getKeyCacheSize = ar5210GetKeyCacheSize, |
137 | .ah_resetKeyCacheEntry = ar5210ResetKeyCacheEntry, |
138 | .ah_isKeyCacheEntryValid = ar5210IsKeyCacheEntryValid, |
139 | .ah_setKeyCacheEntry = ar5210SetKeyCacheEntry, |
140 | .ah_setKeyCacheEntryMac = ar5210SetKeyCacheEntryMac, |
141 | |
142 | /* Power Management Functions */ |
143 | .ah_setPowerMode = ar5210SetPowerMode, |
144 | .ah_getPowerMode = ar5210GetPowerMode, |
145 | |
146 | /* Beacon Functions */ |
147 | .ah_setBeaconTimers = ar5210SetBeaconTimers, |
148 | .ah_beaconInit = ar5210BeaconInit, |
149 | .ah_setStationBeaconTimers = ar5210SetStaBeaconTimers, |
150 | .ah_resetStationBeaconTimers = ar5210ResetStaBeaconTimers, |
151 | |
152 | /* Interrupt Functions */ |
153 | .ah_isInterruptPending = ar5210IsInterruptPending, |
154 | .ah_getPendingInterrupts = ar5210GetPendingInterrupts, |
155 | .ah_getInterrupts = ar5210GetInterrupts, |
156 | .ah_setInterrupts = ar5210SetInterrupts }, |
157 | |
158 | .ah_getChannelEdges = ar5210GetChannelEdges, |
159 | .ah_getWirelessModes = ar5210GetWirelessModes, |
160 | .ah_eepromRead = ar5210EepromRead, |
161 | #ifdef AH_SUPPORT_WRITE_EEPROM |
162 | .ah_eepromWrite = ar5210EepromWrite, |
163 | #endif |
164 | .ah_gpioCfgInput = ar5210GpioCfgInput, |
165 | .ah_gpioCfgOutput = ar5210GpioCfgOutput, |
166 | .ah_gpioGet = ar5210GpioGet, |
167 | .ah_gpioSet = ar5210GpioSet, |
168 | .ah_gpioSetIntr = ar5210Gpio0SetIntr, |
169 | .ah_getChipPowerLimits = ar5210GetChipPowerLimits, |
170 | }; |
171 | |
172 | static HAL_BOOL ar5210FillCapabilityInfo(struct ath_hal *ah); |
173 | |
174 | /* |
175 | * Attach for an AR5210 part. |
176 | */ |
177 | static struct ath_hal * |
178 | ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, |
179 | HAL_STATUS *status) |
180 | { |
181 | #define N(a) (sizeof(a)/sizeof(a[0])) |
182 | struct ath_hal_5210 *ahp; |
183 | struct ath_hal *ah; |
184 | uint32_t revid, pcicfg; |
185 | uint16_t eeval; |
186 | HAL_STATUS ecode; |
187 | int i; |
188 | |
189 | HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, |
190 | "%s: devid 0x%x sc %p st %p sh %p\n" , __func__, devid, |
191 | sc, (void*) st, (void*) sh); |
192 | |
193 | /* NB: memory is returned zero'd */ |
194 | ahp = ath_hal_malloc(sizeof (struct ath_hal_5210)); |
195 | if (ahp == AH_NULL) { |
196 | HALDEBUG(AH_NULL, HAL_DEBUG_ANY, |
197 | "%s: no memory for state block\n" , __func__); |
198 | ecode = HAL_ENOMEM; |
199 | goto bad; |
200 | } |
201 | ah = &ahp->ah_priv.h; |
202 | /* set initial values */ |
203 | OS_MEMCPY(&ahp->ah_priv, &ar5210hal, sizeof(struct ath_hal_private)); |
204 | ah->ah_sc = sc; |
205 | ah->ah_st = st; |
206 | ah->ah_sh = sh; |
207 | |
208 | ah->ah_devid = devid; /* NB: for AH_DEBUG_ALQ */ |
209 | AH_PRIVATE(ah)->ah_devid = devid; |
210 | AH_PRIVATE(ah)->ah_subvendorid = 0; /* XXX */ |
211 | |
212 | AH_PRIVATE(ah)->ah_powerLimit = AR5210_MAX_RATE_POWER; |
213 | AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */ |
214 | |
215 | ahp->ah_powerMode = HAL_PM_UNDEFINED; |
216 | ahp->ah_staId1Defaults = 0; |
217 | ahp->ah_rssiThr = INIT_RSSI_THR; |
218 | ahp->ah_sifstime = (u_int) -1; |
219 | ahp->ah_slottime = (u_int) -1; |
220 | ahp->ah_acktimeout = (u_int) -1; |
221 | ahp->ah_ctstimeout = (u_int) -1; |
222 | |
223 | if (!ar5210ChipReset(ah, AH_NULL)) { /* reset chip */ |
224 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n" , |
225 | __func__); |
226 | ecode = HAL_EIO; |
227 | goto bad; |
228 | } |
229 | |
230 | /* Read Revisions from Chips */ |
231 | AH_PRIVATE(ah)->ah_macVersion = 1; |
232 | AH_PRIVATE(ah)->ah_macRev = OS_REG_READ(ah, AR_SREV) & 0xff; |
233 | AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIPID); |
234 | AH_PRIVATE(ah)->ah_analog2GhzRev = 0; |
235 | |
236 | /* Read Radio Chip Rev Extract */ |
237 | OS_REG_WRITE(ah, (AR_PHY_BASE + (0x34 << 2)), 0x00001c16); |
238 | for (i = 0; i < 4; i++) |
239 | OS_REG_WRITE(ah, (AR_PHY_BASE + (0x20 << 2)), 0x00010000); |
240 | revid = (OS_REG_READ(ah, AR_PHY_BASE + (256 << 2)) >> 28) & 0xf; |
241 | |
242 | /* Chip labelling is 1 greater than revision register for AR5110 */ |
243 | AH_PRIVATE(ah)->ah_analog5GhzRev = ath_hal_reverseBits(revid, 4) + 1; |
244 | |
245 | /* |
246 | * Read all the settings from the EEPROM and stash |
247 | * ones we'll use later. |
248 | */ |
249 | pcicfg = OS_REG_READ(ah, AR_PCICFG); |
250 | OS_REG_WRITE(ah, AR_PCICFG, pcicfg | AR_PCICFG_EEPROMSEL); |
251 | ecode = ath_hal_v1EepromAttach(ah); |
252 | if (ecode != HAL_OK) { |
253 | goto eebad; |
254 | } |
255 | ecode = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, &eeval); |
256 | if (ecode != HAL_OK) { |
257 | HALDEBUG(ah, HAL_DEBUG_ANY, |
258 | "%s: cannot read regulatory domain from EEPROM\n" , |
259 | __func__); |
260 | goto eebad; |
261 | } |
262 | AH_PRIVATE(ah)->ah_currentRD = eeval; |
263 | ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); |
264 | if (ecode != HAL_OK) { |
265 | HALDEBUG(ah, HAL_DEBUG_ANY, |
266 | "%s: error getting mac address from EEPROM\n" , __func__); |
267 | goto eebad; |
268 | } |
269 | OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */ |
270 | |
271 | AH_PRIVATE(ah)->ah_getNfAdjust = ar5210GetNfAdjust; |
272 | |
273 | /* |
274 | * Got everything we need now to setup the capabilities. |
275 | */ |
276 | (void) ar5210FillCapabilityInfo(ah); |
277 | |
278 | HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n" , __func__); |
279 | |
280 | return ah; |
281 | eebad: |
282 | OS_REG_WRITE(ah, AR_PCICFG, pcicfg); /* disable EEPROM access */ |
283 | bad: |
284 | if (ahp) |
285 | ath_hal_free(ahp); |
286 | if (status) |
287 | *status = ecode; |
288 | return AH_NULL; |
289 | #undef N |
290 | } |
291 | |
292 | void |
293 | ar5210Detach(struct ath_hal *ah) |
294 | { |
295 | HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s:\n" , __func__); |
296 | |
297 | HALASSERT(ah != AH_NULL); |
298 | HALASSERT(ah->ah_magic == AR5210_MAGIC); |
299 | |
300 | ath_hal_eepromDetach(ah); |
301 | ath_hal_free(ah); |
302 | } |
303 | |
304 | /* |
305 | * Store the channel edges for the requested operational mode |
306 | */ |
307 | static HAL_BOOL |
308 | ar5210GetChannelEdges(struct ath_hal *ah, |
309 | uint16_t flags, uint16_t *low, uint16_t *high) |
310 | { |
311 | if (flags & CHANNEL_5GHZ) { |
312 | *low = 5120; |
313 | *high = 5430; |
314 | return AH_TRUE; |
315 | } else { |
316 | return AH_FALSE; |
317 | } |
318 | } |
319 | |
320 | static HAL_BOOL |
321 | ar5210GetChipPowerLimits(struct ath_hal *ah, HAL_CHANNEL *chans, uint32_t nchans) |
322 | { |
323 | HAL_CHANNEL *chan; |
324 | int i; |
325 | |
326 | /* XXX fill in, this is just a placeholder */ |
327 | for (i = 0; i < nchans; i++) { |
328 | chan = &chans[i]; |
329 | HALDEBUG(ah, HAL_DEBUG_ATTACH, |
330 | "%s: no min/max power for %u/0x%x\n" , |
331 | __func__, chan->channel, chan->channelFlags); |
332 | chan->maxTxPower = AR5210_MAX_RATE_POWER; |
333 | chan->minTxPower = 0; |
334 | } |
335 | return AH_TRUE; |
336 | } |
337 | |
338 | static void |
339 | ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore) |
340 | { |
341 | } |
342 | |
343 | static void |
344 | ar5210DisablePCIE(struct ath_hal *ah) |
345 | { |
346 | } |
347 | |
348 | /* |
349 | * Fill all software cached or static hardware state information. |
350 | */ |
351 | static HAL_BOOL |
352 | ar5210FillCapabilityInfo(struct ath_hal *ah) |
353 | { |
354 | struct ath_hal_private *ahpriv = AH_PRIVATE(ah); |
355 | HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; |
356 | |
357 | pCap->halWirelessModes |= HAL_MODE_11A; |
358 | |
359 | pCap->halLow5GhzChan = 5120; |
360 | pCap->halHigh5GhzChan = 5430; |
361 | |
362 | pCap->halSleepAfterBeaconBroken = AH_TRUE; |
363 | pCap->halPSPollBroken = AH_FALSE; |
364 | |
365 | pCap->halTotalQueues = HAL_NUM_TX_QUEUES; |
366 | pCap->halKeyCacheSize = 64; |
367 | |
368 | /* XXX not needed */ |
369 | pCap->halChanHalfRate = AH_FALSE; |
370 | pCap->halChanQuarterRate = AH_FALSE; |
371 | |
372 | if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL)) { |
373 | /* |
374 | * Setup initial rfsilent settings based on the EEPROM |
375 | * contents. Pin 0, polarity 0 is fixed; record this |
376 | * using the EEPROM format found in later parts. |
377 | */ |
378 | ahpriv->ah_rfsilent = SM(0, AR_EEPROM_RFSILENT_GPIO_SEL) |
379 | | SM(0, AR_EEPROM_RFSILENT_POLARITY); |
380 | ahpriv->ah_rfkillEnabled = AH_TRUE; |
381 | pCap->halRfSilentSupport = AH_TRUE; |
382 | } |
383 | |
384 | pCap->halTstampPrecision = 15; /* NB: s/w extended from 13 */ |
385 | pCap->halIntrMask = (HAL_INT_COMMON - HAL_INT_BNR) |
386 | | HAL_INT_RX |
387 | | HAL_INT_TX |
388 | | HAL_INT_FATAL |
389 | ; |
390 | |
391 | ahpriv->ah_rxornIsFatal = AH_TRUE; |
392 | return AH_TRUE; |
393 | } |
394 | |
395 | static const char* |
396 | ar5210Probe(uint16_t vendorid, uint16_t devid) |
397 | { |
398 | if (vendorid == ATHEROS_VENDOR_ID && |
399 | (devid == AR5210_PROD || devid == AR5210_DEFAULT)) |
400 | return "Atheros 5210" ; |
401 | return AH_NULL; |
402 | } |
403 | AH_CHIP(AR5210, ar5210Probe, ar5210Attach); |
404 | |