Added two wireless drivers: atheros5000.device and realtek8180.device.
[AROS.git] / workbench / devs / networks / atheros5000 / hal / ar5211 / ar5211_misc.c
blob581cd2e9bfaef4fe9d825ef996d719baaaa60991
1 /*
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$
19 #include "opt_ah.h"
21 #ifdef AH_SUPPORT_AR5211
23 #include "ah.h"
24 #include "ah_internal.h"
26 #include "ar5211/ar5211.h"
27 #include "ar5211/ar5211reg.h"
28 #include "ar5211/ar5211phy.h"
30 #include "ah_eeprom_v3.h"
32 #define AR_NUM_GPIO 6 /* 6 GPIO bits */
33 #define AR_GPIOD_MASK 0x2f /* 6-bit mask */
35 void
36 ar5211GetMacAddress(struct ath_hal *ah, uint8_t *mac)
38 struct ath_hal_5211 *ahp = AH5211(ah);
40 OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN);
43 HAL_BOOL
44 ar5211SetMacAddress(struct ath_hal *ah, const uint8_t *mac)
46 struct ath_hal_5211 *ahp = AH5211(ah);
48 OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN);
49 return AH_TRUE;
52 void
53 ar5211GetBssIdMask(struct ath_hal *ah, uint8_t *mask)
55 static const uint8_t ones[IEEE80211_ADDR_LEN] =
56 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
57 OS_MEMCPY(mask, ones, IEEE80211_ADDR_LEN);
60 HAL_BOOL
61 ar5211SetBssIdMask(struct ath_hal *ah, const uint8_t *mask)
63 return AH_FALSE;
67 * Read 16 bits of data from the specified EEPROM offset.
69 HAL_BOOL
70 ar5211EepromRead(struct ath_hal *ah, u_int off, uint16_t *data)
72 OS_REG_WRITE(ah, AR_EEPROM_ADDR, off);
73 OS_REG_WRITE(ah, AR_EEPROM_CMD, AR_EEPROM_CMD_READ);
75 if (!ath_hal_wait(ah, AR_EEPROM_STS,
76 AR_EEPROM_STS_READ_COMPLETE | AR_EEPROM_STS_READ_ERROR,
77 AR_EEPROM_STS_READ_COMPLETE)) {
78 HALDEBUG(ah, HAL_DEBUG_ANY,
79 "%s: read failed for entry 0x%x\n", __func__, off);
80 return AH_FALSE;
82 *data = OS_REG_READ(ah, AR_EEPROM_DATA) & 0xffff;
83 return AH_TRUE;
87 * Return the wireless modes (a,b,g,t) supported by hardware.
89 * This value is what is actually supported by the hardware
90 * and is unaffected by regulatory/country code settings.
93 u_int
94 ar5211GetWirelessModes(struct ath_hal *ah)
96 u_int mode = 0;
98 if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) {
99 mode = HAL_MODE_11A;
100 if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE))
101 mode |= HAL_MODE_TURBO | HAL_MODE_108A;
103 if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE))
104 mode |= HAL_MODE_11B;
105 return mode;
108 #if 0
109 HAL_BOOL
110 ar5211GetTurboDisable(struct ath_hal *ah)
112 return (AH5211(ah)->ah_turboDisable != 0);
114 #endif
117 * Called if RfKill is supported (according to EEPROM). Set the interrupt and
118 * GPIO values so the ISR and can disable RF on a switch signal
120 void
121 ar5211EnableRfKill(struct ath_hal *ah)
123 uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent;
124 int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL);
125 int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY);
128 * Configure the desired GPIO port for input
129 * and enable baseband rf silence.
131 ar5211GpioCfgInput(ah, select);
132 OS_REG_SET_BIT(ah, AR_PHY_BASE, 0x00002000);
134 * If radio disable switch connection to GPIO bit x is enabled
135 * program GPIO interrupt.
136 * If rfkill bit on eeprom is 1, setupeeprommap routine has already
137 * verified that it is a later version of eeprom, it has a place for
138 * rfkill bit and it is set to 1, indicating that GPIO bit x hardware
139 * connection is present.
141 ar5211GpioSetIntr(ah, select, (ar5211GpioGet(ah, select) != polarity));
145 * Configure GPIO Output lines
147 HAL_BOOL
148 ar5211GpioCfgOutput(struct ath_hal *ah, uint32_t gpio)
150 uint32_t reg;
152 HALASSERT(gpio < AR_NUM_GPIO);
154 reg = OS_REG_READ(ah, AR_GPIOCR);
155 reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT));
156 reg |= AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT);
158 OS_REG_WRITE(ah, AR_GPIOCR, reg);
159 return AH_TRUE;
163 * Configure GPIO Input lines
165 HAL_BOOL
166 ar5211GpioCfgInput(struct ath_hal *ah, uint32_t gpio)
168 uint32_t reg;
170 HALASSERT(gpio < AR_NUM_GPIO);
172 reg = OS_REG_READ(ah, AR_GPIOCR);
173 reg &= ~(AR_GPIOCR_0_CR_A << (gpio * AR_GPIOCR_CR_SHIFT));
174 reg |= AR_GPIOCR_0_CR_N << (gpio * AR_GPIOCR_CR_SHIFT);
176 OS_REG_WRITE(ah, AR_GPIOCR, reg);
177 return AH_TRUE;
181 * Once configured for I/O - set output lines
183 HAL_BOOL
184 ar5211GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val)
186 uint32_t reg;
188 HALASSERT(gpio < AR_NUM_GPIO);
190 reg = OS_REG_READ(ah, AR_GPIODO);
191 reg &= ~(1 << gpio);
192 reg |= (val&1) << gpio;
194 OS_REG_WRITE(ah, AR_GPIODO, reg);
195 return AH_TRUE;
199 * Once configured for I/O - get input lines
201 uint32_t
202 ar5211GpioGet(struct ath_hal *ah, uint32_t gpio)
204 if (gpio < AR_NUM_GPIO) {
205 uint32_t val = OS_REG_READ(ah, AR_GPIODI);
206 val = ((val & AR_GPIOD_MASK) >> gpio) & 0x1;
207 return val;
208 } else {
209 return 0xffffffff;
214 * Set the GPIO 0 Interrupt (gpio is ignored)
216 void
217 ar5211GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel)
219 uint32_t val = OS_REG_READ(ah, AR_GPIOCR);
221 /* Clear the bits that we will modify. */
222 val &= ~(AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_SELH | AR_GPIOCR_INT_ENA |
223 AR_GPIOCR_0_CR_A);
225 val |= AR_GPIOCR_INT_SEL0 | AR_GPIOCR_INT_ENA;
226 if (ilevel)
227 val |= AR_GPIOCR_INT_SELH;
229 /* Don't need to change anything for low level interrupt. */
230 OS_REG_WRITE(ah, AR_GPIOCR, val);
232 /* Change the interrupt mask. */
233 ar5211SetInterrupts(ah, AH5211(ah)->ah_maskReg | HAL_INT_GPIO);
237 * Change the LED blinking pattern to correspond to the connectivity
239 void
240 ar5211SetLedState(struct ath_hal *ah, HAL_LED_STATE state)
242 static const uint32_t ledbits[8] = {
243 AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_INIT */
244 AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_SCAN */
245 AR_PCICFG_LEDCTL_PEND|AR_PCICFG_LEDMODE_PROP, /* HAL_LED_AUTH */
246 AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_ASSOC*/
247 AR_PCICFG_LEDCTL_ASSOC|AR_PCICFG_LEDMODE_PROP,/* HAL_LED_RUN */
248 AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND,
249 AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND,
250 AR_PCICFG_LEDCTL_NONE|AR_PCICFG_LEDMODE_RAND,
252 OS_REG_WRITE(ah, AR_PCICFG,
253 (OS_REG_READ(ah, AR_PCICFG) &~
254 (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE))
255 | ledbits[state & 0x7]
260 * Change association related fields programmed into the hardware.
261 * Writing a valid BSSID to the hardware effectively enables the hardware
262 * to synchronize its TSF to the correct beacons and receive frames coming
263 * from that BSSID. It is called by the SME JOIN operation.
265 void
266 ar5211WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId)
268 struct ath_hal_5211 *ahp = AH5211(ah);
270 /* XXX save bssid for possible re-use on reset */
271 OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);
272 OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
273 OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) |
274 ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S));
278 * Get the current hardware tsf for stamlme.
280 uint64_t
281 ar5211GetTsf64(struct ath_hal *ah)
283 uint32_t low1, low2, u32;
285 /* sync multi-word read */
286 low1 = OS_REG_READ(ah, AR_TSF_L32);
287 u32 = OS_REG_READ(ah, AR_TSF_U32);
288 low2 = OS_REG_READ(ah, AR_TSF_L32);
289 if (low2 < low1) { /* roll over */
291 * If we are not preempted this will work. If we are
292 * then we re-reading AR_TSF_U32 does no good as the
293 * low bits will be meaningless. Likewise reading
294 * L32, U32, U32, then comparing the last two reads
295 * to check for rollover
296 * doesn't help if preempted--so we take this approach
297 * as it costs one less PCI read which can be noticeable
298 * when doing things like timestamping packets in
299 * monitor mode.
301 u32++;
303 return (((uint64_t) u32) << 32) | ((uint64_t) low2);
307 * Get the current hardware tsf for stamlme.
309 uint32_t
310 ar5211GetTsf32(struct ath_hal *ah)
312 return OS_REG_READ(ah, AR_TSF_L32);
316 * Reset the current hardware tsf for stamlme
318 void
319 ar5211ResetTsf(struct ath_hal *ah)
321 uint32_t val = OS_REG_READ(ah, AR_BEACON);
323 OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF);
327 * Grab a semi-random value from hardware registers - may not
328 * change often
330 uint32_t
331 ar5211GetRandomSeed(struct ath_hal *ah)
333 uint32_t nf;
335 nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff;
336 if (nf & 0x100)
337 nf = 0 - ((nf ^ 0x1ff) + 1);
338 return (OS_REG_READ(ah, AR_TSF_U32) ^
339 OS_REG_READ(ah, AR_TSF_L32) ^ nf);
343 * Detect if our card is present
345 HAL_BOOL
346 ar5211DetectCardPresent(struct ath_hal *ah)
348 uint16_t macVersion, macRev;
349 uint32_t v;
352 * Read the Silicon Revision register and compare that
353 * to what we read at attach time. If the same, we say
354 * a card/device is present.
356 v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID_M;
357 macVersion = v >> AR_SREV_ID_S;
358 macRev = v & AR_SREV_REVISION_M;
359 return (AH_PRIVATE(ah)->ah_macVersion == macVersion &&
360 AH_PRIVATE(ah)->ah_macRev == macRev);
364 * Update MIB Counters
366 void
367 ar5211UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS *stats)
369 stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL);
370 stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL);
371 stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL);
372 stats->rts_good += OS_REG_READ(ah, AR_RTS_OK);
373 stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT);
376 HAL_BOOL
377 ar5211SetSifsTime(struct ath_hal *ah, u_int us)
379 struct ath_hal_5211 *ahp = AH5211(ah);
381 if (us > ath_hal_mac_usec(ah, 0xffff)) {
382 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n",
383 __func__, us);
384 ahp->ah_sifstime = (u_int) -1; /* restore default handling */
385 return AH_FALSE;
386 } else {
387 /* convert to system clocks */
388 OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us));
389 ahp->ah_slottime = us;
390 return AH_TRUE;
394 u_int
395 ar5211GetSifsTime(struct ath_hal *ah)
397 u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff;
398 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
401 HAL_BOOL
402 ar5211SetSlotTime(struct ath_hal *ah, u_int us)
404 struct ath_hal_5211 *ahp = AH5211(ah);
406 if (us < HAL_SLOT_TIME_9 || us > ath_hal_mac_usec(ah, 0xffff)) {
407 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n",
408 __func__, us);
409 ahp->ah_slottime = us; /* restore default handling */
410 return AH_FALSE;
411 } else {
412 /* convert to system clocks */
413 OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us));
414 ahp->ah_slottime = us;
415 return AH_TRUE;
419 u_int
420 ar5211GetSlotTime(struct ath_hal *ah)
422 u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff;
423 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
426 HAL_BOOL
427 ar5211SetAckTimeout(struct ath_hal *ah, u_int us)
429 struct ath_hal_5211 *ahp = AH5211(ah);
431 if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
432 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n",
433 __func__, us);
434 ahp->ah_acktimeout = (u_int) -1; /* restore default handling */
435 return AH_FALSE;
436 } else {
437 /* convert to system clocks */
438 OS_REG_RMW_FIELD(ah, AR_TIME_OUT,
439 AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us));
440 ahp->ah_acktimeout = us;
441 return AH_TRUE;
445 u_int
446 ar5211GetAckTimeout(struct ath_hal *ah)
448 u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK);
449 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
452 u_int
453 ar5211GetAckCTSRate(struct ath_hal *ah)
455 return ((AH5211(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0);
458 HAL_BOOL
459 ar5211SetAckCTSRate(struct ath_hal *ah, u_int high)
461 struct ath_hal_5211 *ahp = AH5211(ah);
463 if (high) {
464 OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);
465 ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB;
466 } else {
467 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB);
468 ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB;
470 return AH_TRUE;
473 HAL_BOOL
474 ar5211SetCTSTimeout(struct ath_hal *ah, u_int us)
476 struct ath_hal_5211 *ahp = AH5211(ah);
478 if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
479 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n",
480 __func__, us);
481 ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */
482 return AH_FALSE;
483 } else {
484 /* convert to system clocks */
485 OS_REG_RMW_FIELD(ah, AR_TIME_OUT,
486 AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us));
487 ahp->ah_ctstimeout = us;
488 return AH_TRUE;
492 u_int
493 ar5211GetCTSTimeout(struct ath_hal *ah)
495 u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS);
496 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */
499 HAL_BOOL
500 ar5211SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)
502 /* nothing to do */
503 return AH_TRUE;
506 void
507 ar5211SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
512 * Control Adaptive Noise Immunity Parameters
514 HAL_BOOL
515 ar5211AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
517 return AH_FALSE;
520 void
521 ar5211AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats, HAL_CHANNEL *chan)
525 void
526 ar5211MibEvent(struct ath_hal *ah, const HAL_NODE_STATS *stats)
531 * Get the rssi of frame curently being received.
533 uint32_t
534 ar5211GetCurRssi(struct ath_hal *ah)
536 return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff);
539 u_int
540 ar5211GetDefAntenna(struct ath_hal *ah)
542 return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7);
545 void
546 ar5211SetDefAntenna(struct ath_hal *ah, u_int antenna)
548 OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
551 HAL_ANT_SETTING
552 ar5211GetAntennaSwitch(struct ath_hal *ah)
554 return AH5211(ah)->ah_diversityControl;
557 HAL_BOOL
558 ar5211SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
560 const HAL_CHANNEL *chan =
561 (const HAL_CHANNEL *) AH_PRIVATE(ah)->ah_curchan;
563 if (chan == AH_NULL) {
564 AH5211(ah)->ah_diversityControl = settings;
565 return AH_TRUE;
567 return ar5211SetAntennaSwitchInternal(ah, settings, chan);
570 HAL_STATUS
571 ar5211GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
572 uint32_t capability, uint32_t *result)
575 switch (type) {
576 case HAL_CAP_CIPHER: /* cipher handled in hardware */
577 switch (capability) {
578 case HAL_CIPHER_AES_OCB:
579 case HAL_CIPHER_WEP:
580 case HAL_CIPHER_CLR:
581 return HAL_OK;
582 default:
583 return HAL_ENOTSUPP;
585 default:
586 return ath_hal_getcapability(ah, type, capability, result);
590 HAL_BOOL
591 ar5211SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
592 uint32_t capability, uint32_t setting, HAL_STATUS *status)
594 switch (type) {
595 case HAL_CAP_DIAG: /* hardware diagnostic support */
597 * NB: could split this up into virtual capabilities,
598 * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly
599 * seems worth the additional complexity.
601 #ifdef AH_DEBUG
602 AH_PRIVATE(ah)->ah_diagreg = setting;
603 #else
604 AH_PRIVATE(ah)->ah_diagreg = setting & 0x6; /* ACK+CTS */
605 #endif
606 OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
607 return AH_TRUE;
608 default:
609 return ath_hal_setcapability(ah, type, capability,
610 setting, status);
614 HAL_BOOL
615 ar5211GetDiagState(struct ath_hal *ah, int request,
616 const void *args, uint32_t argsize,
617 void **result, uint32_t *resultsize)
619 struct ath_hal_5211 *ahp = AH5211(ah);
621 (void) ahp;
622 if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
623 return AH_TRUE;
624 switch (request) {
625 case HAL_DIAG_EEPROM:
626 return ath_hal_eepromDiag(ah, request,
627 args, argsize, result, resultsize);
628 case HAL_DIAG_RFGAIN:
629 *result = &ahp->ah_gainValues;
630 *resultsize = sizeof(GAIN_VALUES);
631 return AH_TRUE;
632 case HAL_DIAG_RFGAIN_CURSTEP:
633 *result = __DECONST(void *, ahp->ah_gainValues.currStep);
634 *resultsize = (*result == AH_NULL) ?
635 0 : sizeof(GAIN_OPTIMIZATION_STEP);
636 return AH_TRUE;
638 return AH_FALSE;
640 #endif /* AH_SUPPORT_AR5211 */