summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2011-01-06 07:27:16 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2011-01-06 07:27:16 +0000
commitba355aa6b769afe9323f3dde64ea29663ca30c69 (patch)
treea8a0c6789c41167507568bb3c84a0a5c0ba9c88d /sys/dev/ic
parentb6be427901ab5d95acc12832f4e5da50c72e38fe (diff)
"athn* at uhub? port ?"
this adds preliminary support for the Atheros AR9271 chipset and probably the AR9280+AR7010 and AR9287+AR7010 too though those were not tested. scanning still takes a very long time (~1 sec per channel) but otherwise, operation in STA mode seems stable. will implement fast channel change soon. committed over the Ubiquiti WifiStation EXT (AR9271) on i386 with WPA. requires firmware (see man page for details) ok deraadt@ (who checked the .h files)
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/ar5008.c9
-rw-r--r--sys/dev/ic/ar9280.c12
-rw-r--r--sys/dev/ic/ar9285.c49
-rw-r--r--sys/dev/ic/ar9285reg.h6
-rw-r--r--sys/dev/ic/athn.c51
-rw-r--r--sys/dev/ic/athnreg.h17
-rw-r--r--sys/dev/ic/athnvar.h3
7 files changed, 111 insertions, 36 deletions
diff --git a/sys/dev/ic/ar5008.c b/sys/dev/ic/ar5008.c
index ae1e31ffa97..b2731c8c2e9 100644
--- a/sys/dev/ic/ar5008.c
+++ b/sys/dev/ic/ar5008.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar5008.c,v 1.18 2011/01/01 10:48:31 damien Exp $ */
+/* $OpenBSD: ar5008.c,v 1.19 2011/01/06 07:27:15 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -2297,6 +2297,12 @@ ar5008_hw_init(struct athn_softc *sc, struct ieee80211_channel *c,
if (sc->tx_gain != NULL)
ar9280_reset_tx_gain(sc, c);
+ if (AR_SREV_9271_10(sc)) {
+ AR_WRITE(sc, AR_PHY(68), 0x30002311);
+ AR_WRITE(sc, AR_PHY_RF_CTL3, 0x0a020001);
+ }
+ AR_WRITE_BARRIER(sc);
+
/* Second initialization step (common to all channels). */
DPRINTFN(4, ("writing common init vals\n"));
for (i = 0; i < ini->ncmregs; i++) {
@@ -2308,6 +2314,7 @@ ar5008_hw_init(struct athn_softc *sc, struct ieee80211_channel *c,
if ((i & 0x1f) == 0)
DELAY(1);
}
+ AR_WRITE_BARRIER(sc);
if (!AR_SINGLE_CHIP(sc))
ar5416_reset_bb_gain(sc, c);
diff --git a/sys/dev/ic/ar9280.c b/sys/dev/ic/ar9280.c
index 99a24551dae..1cc3ee62941 100644
--- a/sys/dev/ic/ar9280.c
+++ b/sys/dev/ic/ar9280.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar9280.c,v 1.16 2011/01/01 14:25:03 damien Exp $ */
+/* $OpenBSD: ar9280.c,v 1.17 2011/01/06 07:27:15 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -322,7 +322,15 @@ ar9280_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c,
DELAY(100);
}
reg = AR_READ(sc, AR_AN_TOP2);
- reg = RW(reg, AR_AN_TOP2_XPABIAS_LVL, modal->xpaBiasLvl);
+ if ((sc->flags & ATHN_FLAG_USB) && IEEE80211_IS_CHAN_5GHZ(c)) {
+ /*
+ * Hardcode the output voltage of x-PA bias LDO to the
+ * lowest value for UB94 such that the card doesn't get
+ * too hot.
+ */
+ reg = RW(reg, AR_AN_TOP2_XPABIAS_LVL, 0);
+ } else
+ reg = RW(reg, AR_AN_TOP2_XPABIAS_LVL, modal->xpaBiasLvl);
if (modal->flagBits & AR5416_EEP_FLAG_LOCALBIAS)
reg |= AR_AN_TOP2_LOCALBIAS;
else
diff --git a/sys/dev/ic/ar9285.c b/sys/dev/ic/ar9285.c
index 58ff14d922f..09bf591692e 100644
--- a/sys/dev/ic/ar9285.c
+++ b/sys/dev/ic/ar9285.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar9285.c,v 1.16 2011/01/01 14:25:03 damien Exp $ */
+/* $OpenBSD: ar9285.c,v 1.17 2011/01/06 07:27:15 damien Exp $ */
/*-
* Copyright (c) 2009-2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -22,6 +22,7 @@
* Routines for AR9285 and AR9271 chipsets.
*/
+#include "athn_usb.h"
#include "bpfilter.h"
#include <sys/param.h>
@@ -110,7 +111,7 @@ ar9285_attach(struct athn_softc *sc)
sc->eep_size = sizeof(struct ar9285_eeprom);
sc->def_nf = AR9285_PHY_CCA_MAX_GOOD_VALUE;
sc->ngpiopins = (sc->flags & ATHN_FLAG_USB) ? 16 : 12;
- sc->led_pin = 1;
+ sc->led_pin = (sc->flags & ATHN_FLAG_USB) ? 15 : 1;
sc->workaround = AR9285_WA_DEFAULT;
sc->ops.setup = ar9285_setup;
sc->ops.swap_rom = ar9285_swap_rom;
@@ -119,7 +120,12 @@ ar9285_attach(struct athn_softc *sc)
sc->ops.set_synth = ar9280_set_synth;
sc->ops.spur_mitigate = ar9280_spur_mitigate;
sc->ops.get_spur_chans = ar9285_get_spur_chans;
- sc->ini = &ar9285_1_2_ini;
+#if NATHN_USB > 0
+ if (AR_SREV_9271(sc))
+ sc->ini = &ar9271_ini;
+ else
+#endif
+ sc->ini = &ar9285_1_2_ini;
sc->serdes = ar9280_2_0_serdes;
return (ar5008_attach(sc));
@@ -134,12 +140,15 @@ ar9285_setup(struct athn_softc *sc)
/* Select initialization values based on ROM. */
type = eep->baseEepHeader.txGainType;
DPRINTF(("Tx gain type=0x%x\n", type));
+#if NATHN_USB > 0
if (AR_SREV_9271(sc)) {
if (type == AR_EEP_TXGAIN_HIGH_POWER)
sc->tx_gain = &ar9271_tx_gain_high_power;
else
sc->tx_gain = &ar9271_tx_gain;
- } else if ((AR_READ(sc, AR_AN_SYNTH9) & 0x7) == 0x1) { /* XE rev. */
+ } else
+#endif /* NATHN_USB */
+ if ((AR_READ(sc, AR_AN_SYNTH9) & 0x7) == 0x1) { /* XE rev. */
if (type == AR_EEP_TXGAIN_HIGH_POWER)
sc->tx_gain = &ar9285_2_0_tx_gain_high_power;
else
@@ -306,6 +315,7 @@ ar9285_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c,
db2[0] = modal->db1_01;
db2[1] = db2[2] = db2[3] = db2[4] = db2[0];
}
+#if NATHN_USB > 0
if (AR_SREV_9271(sc)) {
reg = AR_READ(sc, AR9285_AN_RF2G3);
reg = RW(reg, AR9271_AN_RF2G3_OB_CCK, ob [0]);
@@ -320,7 +330,9 @@ ar9285_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c,
AR_WRITE(sc, AR9285_AN_RF2G4, reg);
AR_WRITE_BARRIER(sc);
DELAY(100);
- } else {
+ } else
+#endif /* ATHN_USB */
+ {
reg = AR_READ(sc, AR9285_AN_RF2G3);
reg = RW(reg, AR9285_AN_RF2G3_OB_0, ob [0]);
reg = RW(reg, AR9285_AN_RF2G3_OB_1, ob [1]);
@@ -495,6 +507,7 @@ ar9285_pa_calib(struct athn_softc *sc)
void
ar9271_pa_calib(struct athn_softc *sc)
{
+#if NATHN_USB > 0
/* List of registers that need to be saved/restored. */
static const uint16_t regs[] = {
AR9285_AN_TOP3,
@@ -505,7 +518,7 @@ ar9271_pa_calib(struct athn_softc *sc)
AR9285_AN_RF2G8,
AR9285_AN_RF2G7
};
- uint32_t svg[7], reg, ccomp_svg;
+ uint32_t svg[7], reg, rf2g3_svg;
int i;
/* Save registers. */
@@ -535,9 +548,8 @@ ar9271_pa_calib(struct athn_softc *sc)
reg = RW(reg, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
AR_WRITE(sc, AR9285_AN_RF2G7, reg);
- reg = AR_READ(sc, AR9285_AN_RF2G3);
/* Save compensation capacitor value. */
- ccomp_svg = MS(reg, AR9271_AN_RF2G3_CCOMP);
+ reg = rf2g3_svg = AR_READ(sc, AR9285_AN_RF2G3);
/* Program compensation capacitor for dynamic PA. */
reg = RW(reg, AR9271_AN_RF2G3_CCOMP, 0xfff);
AR_WRITE(sc, AR9285_AN_RF2G3, reg);
@@ -550,16 +562,14 @@ ar9271_pa_calib(struct athn_softc *sc)
AR_CLRBITS(sc, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS_6_0);
/* Set offsets 6-1. */
for (i = 6; i >= 1; i--) {
- AR_SETBITS(sc, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS(i));
+ reg = AR_READ(sc, AR9285_AN_RF2G6);
+ reg |= AR9271_AN_RF2G6_OFFS(i);
+ AR_WRITE(sc, AR9285_AN_RF2G6, reg);
AR_WRITE_BARRIER(sc);
DELAY(1);
- if (AR_READ(sc, AR9285_AN_RF2G9) & AR9285_AN_RXTXBB1_SPARE9) {
- AR_SETBITS(sc, AR9285_AN_RF2G6,
- AR9271_AN_RF2G6_OFFS(i));
- } else {
- AR_CLRBITS(sc, AR9285_AN_RF2G6,
- AR9271_AN_RF2G6_OFFS(i));
- }
+ if (!(AR_READ(sc, AR9285_AN_RF2G9) & AR9285_AN_RXTXBB1_SPARE9))
+ reg &= ~AR9271_AN_RF2G6_OFFS(i);
+ AR_WRITE(sc, AR9285_AN_RF2G6, reg);
}
AR_WRITE_BARRIER(sc);
@@ -571,10 +581,9 @@ ar9271_pa_calib(struct athn_softc *sc)
AR_WRITE(sc, regs[i], svg[i]);
/* Restore compensation capacitor value. */
- reg = AR_READ(sc, AR9285_AN_RF2G3);
- reg = RW(reg, AR9271_AN_RF2G3_CCOMP, ccomp_svg);
- AR_WRITE(sc, AR9285_AN_RF2G3, reg);
+ AR_WRITE(sc, AR9285_AN_RF2G3, rf2g3_svg);
AR_WRITE_BARRIER(sc);
+#endif /* NATHN_USB */
}
/*
@@ -630,6 +639,7 @@ ar9285_cl_cal(struct athn_softc *sc, struct ieee80211_channel *c,
void
ar9271_load_ani(struct athn_softc *sc)
{
+#if NATHN_USB > 0
/* Write ANI registers. */
AR_WRITE(sc, AR_PHY_DESIRED_SZ, 0x6d4000e2);
AR_WRITE(sc, AR_PHY_AGC_CTL1, 0x3139605e);
@@ -640,6 +650,7 @@ ar9271_load_ani(struct athn_softc *sc)
AR_WRITE(sc, AR_PHY_TIMING5, 0xd00a8007);
AR_WRITE(sc, AR_PHY_SFCORR_EXT, 0x05eea6d4);
AR_WRITE_BARRIER(sc);
+#endif /* NATHN_USB */
}
int
diff --git a/sys/dev/ic/ar9285reg.h b/sys/dev/ic/ar9285reg.h
index a7bc6bf5615..708e3772180 100644
--- a/sys/dev/ic/ar9285reg.h
+++ b/sys/dev/ic/ar9285reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar9285reg.h,v 1.6 2010/12/31 17:17:14 damien Exp $ */
+/* $OpenBSD: ar9285reg.h,v 1.7 2011/01/06 07:27:15 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -599,6 +599,7 @@ static const struct athn_ini ar9285_1_2_ini = {
ar9285_1_2_cm_vals
};
+#if NATHN_USB > 0
/*
* AR9271 programming.
*/
@@ -945,6 +946,7 @@ static const struct athn_ini ar9271_ini = {
ar9271_cm_regs,
ar9271_cm_vals
};
+#endif /* NATHN_USB */
/*
* AR9285 1.2 Tx gains.
@@ -1035,6 +1037,7 @@ static const struct athn_gain ar9285_2_0_tx_gain_high_power = {
ar9285_2_0_tx_gain_high_power_vals_2g
};
+#if NATHN_USB > 0
/*
* AR9271 Tx gains.
*/
@@ -1081,3 +1084,4 @@ static const struct athn_gain ar9271_tx_gain_high_power = {
NULL, /* 2GHz only. */
ar9271_tx_gain_high_power_vals_2g
};
+#endif /* NATHN_USB */
diff --git a/sys/dev/ic/athn.c b/sys/dev/ic/athn.c
index 64cc4263f71..17755c6c1d7 100644
--- a/sys/dev/ic/athn.c
+++ b/sys/dev/ic/athn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: athn.c,v 1.68 2010/12/31 21:44:38 damien Exp $ */
+/* $OpenBSD: athn.c,v 1.69 2011/01/06 07:27:15 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -21,6 +21,7 @@
* Driver for Atheros 802.11a/g/n chipsets.
*/
+#include "athn_usb.h"
#include "bpfilter.h"
#include <sys/param.h>
@@ -120,7 +121,7 @@ void athn_enable_interrupts(struct athn_softc *);
void athn_disable_interrupts(struct athn_softc *);
void athn_init_qos(struct athn_softc *);
int athn_hw_reset(struct athn_softc *, struct ieee80211_channel *,
- struct ieee80211_channel *);
+ struct ieee80211_channel *, int);
struct ieee80211_node *athn_node_alloc(struct ieee80211com *);
void athn_newassoc(struct ieee80211com *, struct ieee80211_node *,
int);
@@ -191,8 +192,12 @@ athn_attach(struct athn_softc *sc)
error = ar5416_attach(sc);
else if (AR_SREV_9280(sc))
error = ar9280_attach(sc);
- else if (AR_SREV_9285(sc) || AR_SREV_9271(sc))
+ else if (AR_SREV_9285(sc))
+ error = ar9285_attach(sc);
+#if NATHN_USB > 0
+ else if (AR_SREV_9271(sc))
error = ar9285_attach(sc);
+#endif
else if (AR_SREV_9287(sc))
error = ar9287_attach(sc);
else if (AR_SREV_9380(sc) || AR_SREV_9485(sc))
@@ -893,7 +898,7 @@ athn_switch_chan(struct athn_softc *sc, struct ieee80211_channel *c,
if (error != 0) {
reset: /* Error found, try a full reset. */
DPRINTFN(3, ("needs a full reset\n"));
- error = athn_hw_reset(sc, c, extc);
+ error = athn_hw_reset(sc, c, extc, 0);
if (error != 0) /* Hopeless case. */
return (error);
}
@@ -1259,8 +1264,14 @@ athn_init_calib(struct athn_softc *sc, struct ieee80211_channel *c,
/* Support temperature compensation calibration. */
sc->sup_calib_mask |= ATHN_CAL_TEMP;
} else if (IEEE80211_IS_CHAN_5GHZ(c) || extc != NULL) {
- /* Support ADC gain calibration. */
- sc->sup_calib_mask |= ATHN_CAL_ADC_GAIN;
+ /*
+ * ADC gain calibration causes uplink throughput
+ * drops in HT40 mode on AR9287.
+ */
+ if (!AR_SREV_9287(sc)) {
+ /* Support ADC gain calibration. */
+ sc->sup_calib_mask |= ATHN_CAL_ADC_GAIN;
+ }
/* Support ADC DC offset calibration. */
sc->sup_calib_mask |= ATHN_CAL_ADC_DC;
}
@@ -1634,7 +1645,7 @@ athn_inc_tx_trigger_level(struct athn_softc *sc)
* NB: The AR9285 and all single-stream parts have an issue that
* limits the size of the PCU Tx FIFO to 2KB instead of 4KB.
*/
- if (ftrig == (AR_SREV_9285(sc) ? 0x1f : 0x3f))
+ if (ftrig == ((AR_SREV_9285(sc) || AR_SREV_9271(sc)) ? 0x1f : 0x3f))
return; /* Already at max. */
reg = RW(reg, AR_TXCFG_FTRIG, ftrig + 1);
AR_WRITE(sc, AR_TXCFG, reg);
@@ -2044,7 +2055,7 @@ athn_init_qos(struct athn_softc *sc)
int
athn_hw_reset(struct athn_softc *sc, struct ieee80211_channel *c,
- struct ieee80211_channel *extc)
+ struct ieee80211_channel *extc, int init)
{
struct ieee80211com *ic = &sc->sc_ic;
struct athn_ops *ops = &sc->ops;
@@ -2069,6 +2080,11 @@ athn_hw_reset(struct athn_softc *sc, struct ieee80211_channel *c,
/* Mark PHY as inactive. */
ops->disable_phy(sc);
+ if (init && AR_SREV_9271(sc)) {
+ AR_WRITE(sc, AR9271_RESET_POWER_DOWN_CONTROL,
+ AR9271_RADIO_RF_RST);
+ DELAY(50);
+ }
if (AR_SREV_9280(sc) && (sc->flags & ATHN_FLAG_OLPC)) {
/* Save TSF before it gets cleared. */
tsfhi = AR_READ(sc, AR_TSF_U32);
@@ -2104,6 +2120,11 @@ athn_hw_reset(struct athn_softc *sc, struct ieee80211_channel *c,
return (EPERM);
}
}
+ if (init && AR_SREV_9271(sc)) {
+ AR_WRITE(sc, AR9271_RESET_POWER_DOWN_CONTROL,
+ AR9271_GATE_MAC_CTL);
+ DELAY(50);
+ }
if (AR_SREV_9280(sc) && (sc->flags & ATHN_FLAG_OLPC)) {
/* Restore TSF if it got cleared. */
AR_WRITE(sc, AR_TSF_L32, tsflo);
@@ -2234,9 +2255,17 @@ athn_hw_reset(struct athn_softc *sc, struct ieee80211_channel *c,
AR_WRITE(sc, AR_CFG_LED, cfg_led | AR_CFG_SCLK_32KHZ);
+ if (sc->flags & ATHN_FLAG_USB) {
+ if (AR_SREV_9271(sc))
+ AR_WRITE(sc, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+ else
+ AR_WRITE(sc, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+ }
#if BYTE_ORDER == BIG_ENDIAN
- /* Default is little-endian, turn on swapping for big-endian. */
- AR_WRITE(sc, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+ else {
+ /* Default is LE, turn on swapping for BE. */
+ AR_WRITE(sc, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+ }
#endif
AR_WRITE_BARRIER(sc);
@@ -2707,7 +2736,7 @@ athn_init(struct ifnet *ifp)
if (sc->flags & ATHN_FLAG_RFSILENT)
ops->rfsilent_init(sc);
- if ((error = athn_hw_reset(sc, c, extc)) != 0) {
+ if ((error = athn_hw_reset(sc, c, extc, 1)) != 0) {
printf("%s: unable to reset hardware; reset status %d\n",
sc->sc_dev.dv_xname, error);
goto fail;
diff --git a/sys/dev/ic/athnreg.h b/sys/dev/ic/athnreg.h
index 3f17d1066af..cd16a644472 100644
--- a/sys/dev/ic/athnreg.h
+++ b/sys/dev/ic/athnreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: athnreg.h,v 1.16 2011/01/01 12:58:33 damien Exp $ */
+/* $OpenBSD: athnreg.h,v 1.17 2011/01/06 07:27:15 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -1273,6 +1273,18 @@
#define AR_KEYTABLE_ANT 0x00000008
#define AR_KEYTABLE_VALID 0x00008000
+/*
+ * AR9271 specific registers.
+ */
+#define AR9271_RESET_POWER_DOWN_CONTROL 0x050044
+#define AR9271_FIRMWARE 0x501000
+#define AR9271_FIRMWARE_TEXT 0x903000
+#define AR7010_FIRMWARE_TEXT 0x906000
+
+/* Bits for AR9271_RESET_POWER_DOWN_CONTROL. */
+#define AR9271_RADIO_RF_RST 0x00000020
+#define AR9271_GATE_MAC_CTL 0x00004000
+
#define AR_BASE_PHY_ACTIVE_DELAY 100
@@ -1363,6 +1375,9 @@
#define AR_SREV_9271(sc) \
((sc)->mac_ver == AR_SREV_VERSION_9271)
+#define AR_SREV_9271_10(sc) \
+ (AR_SREV_9271(sc) && \
+ (sc)->mac_rev == AR_SREV_REVISION_9271_10)
#define AR_SREV_9287(sc) \
((sc)->mac_ver == AR_SREV_VERSION_9287)
diff --git a/sys/dev/ic/athnvar.h b/sys/dev/ic/athnvar.h
index 38edda927db..239245c10f0 100644
--- a/sys/dev/ic/athnvar.h
+++ b/sys/dev/ic/athnvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: athnvar.h,v 1.28 2011/01/01 10:48:31 damien Exp $ */
+/* $OpenBSD: athnvar.h,v 1.29 2011/01/06 07:27:15 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -290,6 +290,7 @@ struct athn_node {
struct ieee80211_amrr_node amn;
uint8_t ridx[IEEE80211_RATE_MAXSIZE];
uint8_t fallback[IEEE80211_RATE_MAXSIZE];
+ uint8_t sta_index;
};
/*