summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2010-04-05 14:14:03 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2010-04-05 14:14:03 +0000
commita24f6b8d2cb85809726a671ba115b29f9e870e65 (patch)
tree661ceb0855857133418844cbafb97ea300329bb4 /sys/dev/ic
parent6eb896d0da489dc987d2a7fd77d081d650352535 (diff)
Initial bits for >=RT3090 support.
Probably not functionnal yet (but test reports are welcome). Update microcode for RT2860 while I'm here (remember to run make && make install under sys/dev/microcode/ral/).
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/rt2860.c680
-rw-r--r--sys/dev/ic/rt2860reg.h16
-rw-r--r--sys/dev/ic/rt2860var.h15
3 files changed, 599 insertions, 112 deletions
diff --git a/sys/dev/ic/rt2860.c b/sys/dev/ic/rt2860.c
index 01a16eb56ff..d439d2d293e 100644
--- a/sys/dev/ic/rt2860.c
+++ b/sys/dev/ic/rt2860.c
@@ -1,8 +1,7 @@
-/* $OpenBSD: rt2860.c,v 1.43 2010/04/04 08:07:50 damien Exp $ */
+/* $OpenBSD: rt2860.c,v 1.44 2010/04/05 14:14:02 damien Exp $ */
/*-
- * Copyright (c) 2007, 2008
- * Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +17,7 @@
*/
/*-
- * Ralink Technology RT2860 chipset driver
+ * Ralink Technology RT2860/RT3090/RT3390/RT3562 chipset driver
* http://www.ralinktech.com/
*/
@@ -100,7 +99,8 @@ void rt2860_newassoc(struct ieee80211com *, struct ieee80211_node *,
int);
int rt2860_newstate(struct ieee80211com *, enum ieee80211_state,
int);
-uint16_t rt2860_eeprom_read(struct rt2860_softc *, uint8_t);
+uint16_t rt3090_efuse_read_2(struct rt2860_softc *, uint16_t);
+uint16_t rt2860_eeprom_read_2(struct rt2860_softc *, uint16_t);
void rt2860_intr_coherent(struct rt2860_softc *);
void rt2860_drain_stats_fifo(struct rt2860_softc *);
void rt2860_tx_intr(struct rt2860_softc *, int);
@@ -115,13 +115,18 @@ int rt2860_ioctl(struct ifnet *, u_long, caddr_t);
void rt2860_mcu_bbp_write(struct rt2860_softc *, uint8_t, uint8_t);
uint8_t rt2860_mcu_bbp_read(struct rt2860_softc *, uint8_t);
void rt2860_rf_write(struct rt2860_softc *, uint8_t, uint32_t);
+uint8_t rt3090_rf_read(struct rt2860_softc *, uint8_t);
+void rt3090_rf_write(struct rt2860_softc *, uint8_t, uint8_t);
int rt2860_mcu_cmd(struct rt2860_softc *, uint8_t, uint16_t);
void rt2860_enable_mrr(struct rt2860_softc *);
void rt2860_set_txpreamble(struct rt2860_softc *);
void rt2860_set_basicrates(struct rt2860_softc *);
void rt2860_select_chan_group(struct rt2860_softc *, int);
-void rt2860_set_chan(struct rt2860_softc *,
- struct ieee80211_channel *);
+void rt2860_set_chan(struct rt2860_softc *, u_int);
+void rt3090_set_chan(struct rt2860_softc *, u_int);
+int rt3090_rf_init(struct rt2860_softc *);
+int rt3090_filter_calib(struct rt2860_softc *, uint8_t, uint8_t,
+ uint8_t *);
void rt2860_set_leds(struct rt2860_softc *, uint16_t);
void rt2860_set_gp_timer(struct rt2860_softc *, int);
void rt2860_set_bssid(struct rt2860_softc *, const uint8_t *);
@@ -144,6 +149,9 @@ int rt2860_init(struct ifnet *);
void rt2860_stop(struct ifnet *, int);
int rt2860_load_microcode(struct rt2860_softc *);
void rt2860_calib(struct rt2860_softc *);
+void rt3090_set_rx_antenna(struct rt2860_softc *, int);
+void rt2860_switch_chan(struct rt2860_softc *,
+ struct ieee80211_channel *);
#ifndef IEEE80211_STA_ONLY
int rt2860_setup_beacon(struct rt2860_softc *);
#endif
@@ -171,6 +179,19 @@ static const struct rfprog {
RT2860_RF2850
};
+struct {
+ uint8_t n, r, k;
+} rt3090_freqs[] = {
+ RT3070_RF3052
+};
+
+static const struct {
+ uint8_t reg;
+ uint8_t val;
+} rt3090_def_rf[] = {
+ RT3070_DEF_RF
+};
+
int
rt2860_attach(void *xsc, int id)
{
@@ -178,14 +199,15 @@ rt2860_attach(void *xsc, int id)
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
int i, qid, ntries, error;
+ uint32_t tmp;
sc->amrr.amrr_min_success_threshold = 1;
sc->amrr.amrr_max_success_threshold = 15;
/* wait for NIC to initialize */
for (ntries = 0; ntries < 100; ntries++) {
- sc->mac_rev = RAL_READ(sc, RT2860_ASIC_VER_ID);
- if (sc->mac_rev != 0 && sc->mac_rev != 0xffffffff)
+ tmp = RAL_READ(sc, RT2860_ASIC_VER_ID);
+ if (tmp != 0 && tmp != 0xffffffff)
break;
DELAY(10);
}
@@ -194,7 +216,10 @@ rt2860_attach(void *xsc, int id)
sc->sc_dev.dv_xname);
return ETIMEDOUT;
}
- if ((sc->mac_rev >> 16) != 0x2860 &&
+ sc->mac_ver = tmp >> 16;
+ sc->mac_rev = tmp & 0xffff;
+
+ if (sc->mac_ver != 0x2860 &&
(id == PCI_PRODUCT_RALINK_RT2890 ||
id == PCI_PRODUCT_RALINK_RT2790 ||
id == PCI_PRODUCT_AWT_RT2890))
@@ -204,7 +229,7 @@ rt2860_attach(void *xsc, int id)
rt2860_read_eeprom(sc);
printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
printf("%s: MAC/BBP RT%X (rev 0x%04X), RF %s (MIMO %dT%dR)\n",
- sc->sc_dev.dv_xname, sc->mac_rev >> 16, sc->mac_rev & 0xffff,
+ sc->sc_dev.dv_xname, sc->mac_ver, sc->mac_rev,
rt2860_get_rf(sc->rf_rev), sc->ntxchains, sc->nrxchains);
/*
@@ -231,7 +256,8 @@ rt2860_attach(void *xsc, int id)
}
/* mgmt ring is broken on RT2860C, use EDCA AC VO ring instead */
- sc->mgtqid = (sc->mac_rev == 0x28600100) ? EDCA_AC_VO : 5;
+ sc->mgtqid = (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) ?
+ EDCA_AC_VO : 5;
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
@@ -368,7 +394,7 @@ rt2860_alloc_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring)
/* Tx rings must be 4-DWORD aligned */
error = bus_dmamem_alloc(sc->sc_dmat, size, 16, 0, &ring->seg, 1,
- &nsegs, BUS_DMA_NOWAIT);
+ &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO);
if (error != 0) {
printf("%s: could not allocate DMA memory\n",
sc->sc_dev.dv_xname);
@@ -389,7 +415,6 @@ rt2860_alloc_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring)
goto fail;
}
- memset(ring->txd, 0, size);
bus_dmamap_sync(sc->sc_dmat, ring->map, 0, size, BUS_DMASYNC_PREWRITE);
ring->paddr = ring->map->dm_segs[0].ds_addr;
@@ -478,7 +503,7 @@ rt2860_alloc_tx_pool(struct rt2860_softc *sc)
}
error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0,
- &sc->txwi_seg, 1, &nsegs, BUS_DMA_NOWAIT);
+ &sc->txwi_seg, 1, &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO);
if (error != 0) {
printf("%s: could not allocate DMA memory\n",
sc->sc_dev.dv_xname);
@@ -499,7 +524,6 @@ rt2860_alloc_tx_pool(struct rt2860_softc *sc)
goto fail;
}
- memset(sc->txwi_vaddr, 0, size);
bus_dmamap_sync(sc->sc_dmat, sc->txwi_map, 0, size,
BUS_DMASYNC_PREWRITE);
@@ -568,7 +592,7 @@ rt2860_alloc_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
/* Rx ring must be 4-DWORD aligned */
error = bus_dmamem_alloc(sc->sc_dmat, size, 16, 0, &ring->seg, 1,
- &nsegs, BUS_DMA_NOWAIT);
+ &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO);
if (error != 0) {
printf("%s: could not allocate DMA memory\n",
sc->sc_dev.dv_xname);
@@ -589,7 +613,6 @@ rt2860_alloc_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
goto fail;
}
- memset(ring->rxd, 0, size);
ring->paddr = ring->map->dm_segs[0].ds_addr;
for (i = 0; i < RT2860_RX_RING_COUNT; i++) {
@@ -604,20 +627,13 @@ rt2860_alloc_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
goto fail;
}
- MGETHDR(data->m, M_DONTWAIT, MT_DATA);
+ data->m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES);
if (data->m == NULL) {
printf("%s: could not allocate Rx mbuf\n",
sc->sc_dev.dv_xname);
error = ENOBUFS;
goto fail;
}
- MCLGET(data->m, M_DONTWAIT);
- if (!(data->m->m_flags & M_EXT)) {
- printf("%s: could not allocate Rx mbuf cluster\n",
- sc->sc_dev.dv_xname);
- error = ENOBUFS;
- goto fail;
- }
error = bus_dmamap_load(sc->sc_dmat, data->map,
mtod(data->m, void *), MCLBYTES, NULL,
@@ -838,7 +854,7 @@ rt2860_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
break;
case IEEE80211_S_SCAN:
- rt2860_set_chan(sc, ic->ic_bss->ni_chan);
+ rt2860_switch_chan(sc, ic->ic_bss->ni_chan);
if (ostate != IEEE80211_S_SCAN)
rt2860_set_gp_timer(sc, 150);
break;
@@ -846,12 +862,12 @@ rt2860_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
rt2860_set_gp_timer(sc, 0);
- rt2860_set_chan(sc, ic->ic_bss->ni_chan);
+ rt2860_switch_chan(sc, ic->ic_bss->ni_chan);
break;
case IEEE80211_S_RUN:
rt2860_set_gp_timer(sc, 0);
- rt2860_set_chan(sc, ic->ic_bss->ni_chan);
+ rt2860_switch_chan(sc, ic->ic_bss->ni_chan);
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
rt2860_updateslot(ic);
@@ -887,12 +903,49 @@ rt2860_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
return sc->sc_newstate(ic, nstate, arg);
}
+/* Read 16-bit from eFUSE ROM (>=RT3090 only.) */
+uint16_t
+rt3090_efuse_read_2(struct rt2860_softc *sc, uint16_t addr)
+{
+ uint32_t tmp;
+ uint16_t reg;
+ int ntries;
+
+ /*-
+ * Read one 16-byte block into registers EFUSE_DATA[0-3]:
+ * DATA0: F E D C
+ * DATA1: B A 9 8
+ * DATA2: 7 6 5 4
+ * DATA3: 3 2 1 0
+ */
+ tmp = RAL_READ(sc, RT3070_EFUSE_CTRL);
+ tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
+ tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
+ RAL_WRITE(sc, RT3070_EFUSE_CTRL, tmp);
+ for (ntries = 0; ntries < 500; ntries++) {
+ if (!(RAL_READ(sc, RT3070_EFUSE_CTRL) & RT3070_EFSROM_KICK))
+ break;
+ DELAY(2);
+ }
+ if (ntries == 100)
+ return 0xffff;
+
+ if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK)
+ return 0xffff; /* address not found */
+
+ /* determine to which 32-bit register our 16-bit word belongs */
+ reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
+ tmp = RAL_READ(sc, reg);
+
+ return (addr & 2) ? tmp >> 16 : tmp & 0xffff;
+}
+
/*
* Read 16 bits at address 'addr' from the serial EEPROM (either 93C46,
* 93C66 or 93C86).
*/
uint16_t
-rt2860_eeprom_read(struct rt2860_softc *sc, uint8_t addr)
+rt2860_eeprom_read_2(struct rt2860_softc *sc, uint16_t addr)
{
uint32_t tmp;
uint16_t val;
@@ -945,6 +998,13 @@ rt2860_eeprom_read(struct rt2860_softc *sc, uint8_t addr)
return val;
}
+static __inline uint16_t
+rt2860_srom_read(struct rt2860_softc *sc, uint8_t addr)
+{
+ /* either eFUSE ROM or EEPROM */
+ return sc->sc_srom_read(sc, addr);
+}
+
void
rt2860_intr_coherent(struct rt2860_softc *sc)
{
@@ -1105,17 +1165,11 @@ rt2860_rx_intr(struct rt2860_softc *sc)
goto skip;
}
- MGETHDR(m1, M_DONTWAIT, MT_DATA);
+ m1 = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES);
if (__predict_false(m1 == NULL)) {
ifp->if_ierrors++;
goto skip;
}
- MCLGET(m1, M_DONTWAIT);
- if (__predict_false(!(m1->m_flags & M_EXT))) {
- m_freem(m1);
- ifp->if_ierrors++;
- goto skip;
- }
bus_dmamap_sync(sc->sc_dmat, data->map, 0,
data->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
@@ -1722,7 +1776,7 @@ rt2860_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ic->ic_opmode == IEEE80211_M_MONITOR) {
if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
(IFF_UP | IFF_RUNNING))
- rt2860_set_chan(sc, ic->ic_ibss_chan);
+ rt2860_switch_chan(sc, ic->ic_ibss_chan);
error = 0;
}
break;
@@ -1833,6 +1887,58 @@ rt2860_rf_write(struct rt2860_softc *sc, uint8_t reg, uint32_t val)
RAL_WRITE(sc, RT2860_RF_CSR_CFG0, tmp);
}
+uint8_t
+rt3090_rf_read(struct rt2860_softc *sc, uint8_t reg)
+{
+ uint32_t tmp;
+ int ntries;
+
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (!(RAL_READ(sc, RT3070_RF_CSR_CFG) & RT3070_RF_KICK))
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ printf("%s: could not read RF register\n",
+ sc->sc_dev.dv_xname);
+ return 0xff;
+ }
+ tmp = RT3070_RF_KICK | reg << 8;
+ RAL_WRITE(sc, RT3070_RF_CSR_CFG, tmp);
+
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (!(RAL_READ(sc, RT3070_RF_CSR_CFG) & RT3070_RF_KICK))
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ printf("%s: could not read RF register\n",
+ sc->sc_dev.dv_xname);
+ return 0xff;
+ }
+ return tmp & 0xff;
+}
+
+void
+rt3090_rf_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val)
+{
+ uint32_t tmp;
+ int ntries;
+
+ for (ntries = 0; ntries < 10; ntries++) {
+ if (!(RAL_READ(sc, RT3070_RF_CSR_CFG) & RT3070_RF_KICK))
+ break;
+ DELAY(10);
+ }
+ if (ntries == 10) {
+ printf("%s: could not write to RF\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
+ RAL_WRITE(sc, RT3070_RF_CSR_CFG, tmp);
+}
+
/*
* Send a command to the 8051 microcontroller unit.
*/
@@ -1911,6 +2017,7 @@ void
rt2860_select_chan_group(struct rt2860_softc *sc, int group)
{
uint32_t tmp;
+ uint8_t agc;
rt2860_mcu_bbp_write(sc, 62, 0x37 - sc->lna[group]);
rt2860_mcu_bbp_write(sc, 63, 0x37 - sc->lna[group]);
@@ -1946,36 +2053,61 @@ rt2860_select_chan_group(struct rt2860_softc *sc, int group)
tmp |= RT2860_PA_PE_G0_EN | RT2860_LNA_PE_G0_EN;
if (sc->ntxchains > 1)
tmp |= RT2860_PA_PE_G1_EN;
+ if (sc->mac_ver == 0x3593 && sc->ntxchains > 2)
+ tmp |= RT3593_PA_PE_G2_EN;
if (sc->nrxchains > 1)
tmp |= RT2860_LNA_PE_G1_EN;
+ if (sc->mac_ver == 0x3593 && sc->nrxchains > 2)
+ tmp |= RT3593_LNA_PE_G2_EN;
} else { /* 5GHz */
tmp |= RT2860_PA_PE_A0_EN | RT2860_LNA_PE_A0_EN;
if (sc->ntxchains > 1)
tmp |= RT2860_PA_PE_A1_EN;
+ if (sc->mac_ver == 0x3593 && sc->ntxchains > 2)
+ tmp |= RT3593_PA_PE_A2_EN;
if (sc->nrxchains > 1)
tmp |= RT2860_LNA_PE_A1_EN;
+ if (sc->mac_ver == 0x3593 && sc->nrxchains > 2)
+ tmp |= RT3593_LNA_PE_A2_EN;
}
RAL_WRITE(sc, RT2860_TX_PIN_CFG, tmp);
+ if (sc->mac_ver == 0x3593) {
+ tmp = RAL_READ(sc, RT2860_GPIO_CTRL);
+ if (sc->sc_flags & RT2860_PCIE) {
+ tmp &= ~0x01010000;
+ if (group == 0)
+ tmp |= 0x00010000;
+ } else {
+ tmp &= ~0x00008080;
+ if (group == 0)
+ tmp |= 0x00000080;
+ }
+ tmp = (tmp & ~0x00001000) | 0x00000010;
+ RAL_WRITE(sc, RT2860_GPIO_CTRL, tmp);
+ }
+
/* set initial AGC value */
- if (group == 0)
- rt2860_mcu_bbp_write(sc, 66, 0x2e + sc->lna[0]);
- else
- rt2860_mcu_bbp_write(sc, 66, 0x32 + (sc->lna[group] * 5) / 3);
+ if (group == 0) { /* 2GHz band */
+ if (sc->mac_rev >= 0x3090)
+ agc = 0x1c + sc->lna[0] * 2;
+ else
+ agc = 0x2e + sc->lna[0];
+ } else { /* 5GHz band */
+ agc = 0x32 + (sc->lna[group] * 5) / 3;
+ }
+ rt2860_mcu_bbp_write(sc, 66, agc);
+
+ DELAY(1000);
}
void
-rt2860_set_chan(struct rt2860_softc *sc, struct ieee80211_channel *c)
+rt2860_set_chan(struct rt2860_softc *sc, u_int chan)
{
- struct ieee80211com *ic = &sc->sc_ic;
const struct rfprog *rfprog = rt2860_rf2850;
uint32_t r2, r3, r4;
int8_t txpow1, txpow2;
- u_int i, chan, group;
-
- chan = ieee80211_chan2ieee(ic, c);
- if (chan == 0 || chan == IEEE80211_CHAN_ANY)
- return;
+ u_int i;
/* find the settings for this channel (we know it exists) */
for (i = 0; rfprog[i].chan != chan; i++);
@@ -1991,7 +2123,7 @@ rt2860_set_chan(struct rt2860_softc *sc, struct ieee80211_channel *c)
/* use Tx power values from EEPROM */
txpow1 = sc->txpow1[i];
txpow2 = sc->txpow2[i];
- if (IEEE80211_IS_CHAN_5GHZ(c)) {
+ if (chan > 14) {
if (txpow1 >= 0)
txpow1 = txpow1 << 1 | 1;
else
@@ -2022,21 +2154,243 @@ rt2860_set_chan(struct rt2860_softc *sc, struct ieee80211_channel *c)
rt2860_rf_write(sc, RT2860_RF2, r2);
rt2860_rf_write(sc, RT2860_RF3, r3);
rt2860_rf_write(sc, RT2860_RF4, r4);
+}
- /* determine channel group */
- if (chan <= 14)
- group = 0;
- else if (chan <= 64)
- group = 1;
- else if (chan <= 128)
- group = 2;
- else
- group = 3;
+void
+rt3090_set_chan(struct rt2860_softc *sc, u_int chan)
+{
+ int8_t txpow1, txpow2;
+ uint8_t rf;
+ int i;
- /* XXX necessary only when group has changed! */
- rt2860_select_chan_group(sc, group);
+ KASSERT(chan >= 1 && chan <= 14); /* RT3090 is 2GHz only */
+ /* find the settings for this channel (we know it exists) */
+ for (i = 0; rt2860_rf2850[i].chan != chan; i++);
+
+ /* use Tx power values from EEPROM */
+ txpow1 = sc->txpow1[i];
+ txpow2 = sc->txpow2[i];
+
+ rt3090_rf_write(sc, 2, rt3090_freqs[i].n);
+ rf = rt3090_rf_read(sc, 3);
+ rf = (rf & ~0x0f) | rt3090_freqs[i].k;
+ rt3090_rf_write(sc, 3, rf);
+ rf = rt3090_rf_read(sc, 6);
+ rf = (rf & ~0x03) | rt3090_freqs[i].r;
+ rt3090_rf_write(sc, 6, rf);
+
+ /* set Tx0 power */
+ rf = rt3090_rf_read(sc, 12);
+ rf = (rf & ~0x1f) | txpow1;
+ rt3090_rf_write(sc, 12, rf);
+
+ /* set Tx1 power */
+ rf = rt3090_rf_read(sc, 13);
+ rf = (rf & ~0x1f) | txpow2;
+ rt3090_rf_write(sc, 13, rf);
+
+ rf = rt3090_rf_read(sc, 1);
+ rf &= ~0xfc;
+ if (sc->ntxchains == 1)
+ rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */
+ else if (sc->ntxchains == 2)
+ rf |= 1 << 7; /* 2T: disable Tx chain 3 */
+ if (sc->nrxchains == 1)
+ rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */
+ else if (sc->nrxchains == 2)
+ rf |= 1 << 6; /* 2R: disable Rx chain 3 */
+ rt3090_rf_write(sc, 1, rf);
+
+ /* set RF offset */
+ rf = rt3090_rf_read(sc, 23);
+ rf = (rf & ~0x7f) | sc->freq;
+ rt3090_rf_write(sc, 23, rf);
+
+ /* program RF filter */
+ rf = rt3090_rf_read(sc, 24); /* Tx */
+ rf = (rf & ~0x3f) | sc->rf24_20mhz;
+ rt3090_rf_write(sc, 24, rf);
+ rf = rt3090_rf_read(sc, 31); /* Rx */
+ rf = (rf & ~0x3f) | sc->rf24_20mhz;
+ rt3090_rf_write(sc, 31, rf);
+
+ /* enable RF tuning */
+ rf = rt3090_rf_read(sc, 7);
+ rt3090_rf_write(sc, 7, rf | 0x01);
+}
+
+int
+rt3090_rf_init(struct rt2860_softc *sc)
+{
+ uint32_t tmp;
+ uint8_t rf, bbp;
+ int i;
+
+ rf = rt3090_rf_read(sc, 30);
+ /* toggle RF R30 bit 7 */
+ rt3090_rf_write(sc, 30, rf | 0x80);
DELAY(1000);
+ rt3090_rf_write(sc, 30, rf & ~0x80);
+
+ tmp = RAL_READ(sc, RT3070_LDO_CFG0);
+ tmp &= ~0x1f000000;
+ if (sc->patch_dac && sc->mac_rev < 0x0211)
+ tmp |= 0x0d000000; /* 1.35V */
+ else
+ tmp |= 0x01000000; /* 1.2V */
+ RAL_WRITE(sc, RT3070_LDO_CFG0, tmp);
+
+ /* patch LNA_PE_G1 */
+ tmp = RAL_READ(sc, RT3070_GPIO_SWITCH);
+ RAL_WRITE(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
+
+ /* initialize RF registers to default value */
+ for (i = 0; i < nitems(rt3090_def_rf); i++) {
+ rt3090_rf_write(sc, rt3090_def_rf[i].reg,
+ rt3090_def_rf[i].val);
+ }
+
+ /* select 20MHz bandwidth */
+ rt3090_rf_write(sc, 31, 0x14);
+
+ rf = rt3090_rf_read(sc, 6);
+ rt3090_rf_write(sc, 6, rf | 0x40);
+
+ if (sc->mac_ver != 0x3593) {
+ /* calibrate filter for 20MHz bandwidth */
+ sc->rf24_20mhz = 0x1f; /* default value */
+ rt3090_filter_calib(sc, 0x07, 0x16, &sc->rf24_20mhz);
+
+ /* select 40MHz bandwidth */
+ bbp = rt2860_mcu_bbp_read(sc, 4);
+ rt2860_mcu_bbp_write(sc, 4, (bbp & ~0x08) | 0x10);
+ rf = rt3090_rf_read(sc, 31);
+ rt3090_rf_write(sc, 31, rf | 0x20);
+
+ /* calibrate filter for 40MHz bandwidth */
+ sc->rf24_40mhz = 0x2f; /* default value */
+ rt3090_filter_calib(sc, 0x27, 0x19, &sc->rf24_40mhz);
+
+ /* go back to 20MHz bandwidth */
+ bbp = rt2860_mcu_bbp_read(sc, 4);
+ rt2860_mcu_bbp_write(sc, 4, bbp & ~0x18);
+ }
+ if (sc->mac_rev < 0x0211)
+ rt3090_rf_write(sc, 27, 0x03);
+
+ tmp = RAL_READ(sc, RT3070_OPT_14);
+ RAL_WRITE(sc, RT3070_OPT_14, tmp | 1);
+
+ if (sc->rf_rev == RT3070_RF_3020)
+ rt3090_set_rx_antenna(sc, 0);
+
+ bbp = rt2860_mcu_bbp_read(sc, 138);
+ if (sc->mac_ver == 0x3593) {
+ if (sc->ntxchains == 1)
+ bbp |= 0x60; /* turn off DAC1 and DAC2 */
+ else if (sc->ntxchains == 2)
+ bbp |= 0x40; /* turn off DAC2 */
+ if (sc->nrxchains == 1)
+ bbp &= ~0x06; /* turn off ADC1 and ADC2 */
+ else if (sc->nrxchains == 2)
+ bbp &= ~0x04; /* turn off ADC2 */
+ } else {
+ if (sc->ntxchains == 1)
+ bbp |= 0x20; /* turn off DAC1 */
+ if (sc->nrxchains == 1)
+ bbp &= ~0x02; /* turn off ADC1 */
+ }
+ rt2860_mcu_bbp_write(sc, 138, bbp);
+
+ rf = rt3090_rf_read(sc, 1);
+ rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
+ rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
+ rt3090_rf_write(sc, 1, rf);
+
+ rf = rt3090_rf_read(sc, 15);
+ rt3090_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
+
+ rf = rt3090_rf_read(sc, 17);
+ rf &= ~RT3070_TX_LO1;
+ if (sc->mac_rev >= 0x0211 && !sc->ext_2ghz_lna)
+ rf |= 0x20; /* fix for long range Rx issue */
+ if (sc->txmixgain_2ghz >= 2)
+ rf = (rf & ~0x7) | sc->txmixgain_2ghz;
+ rt3090_rf_write(sc, 17, rf);
+
+ rf = rt3090_rf_read(sc, 20);
+ rt3090_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
+
+ rf = rt3090_rf_read(sc, 21);
+ rt3090_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
+
+ return 0;
+}
+
+int
+rt3090_filter_calib(struct rt2860_softc *sc, uint8_t init, uint8_t target,
+ uint8_t *val)
+{
+ uint8_t rf22, rf24;
+ uint8_t bbp55_pb, bbp55_sb, delta;
+ int ntries;
+
+ /* program filter */
+ rf24 = rt3090_rf_read(sc, 24);
+ rf24 = (rf24 & 0xc0) | init; /* initial filter value */
+ rt3090_rf_write(sc, 24, rf24);
+
+ /* enable baseband loopback mode */
+ rf22 = rt3090_rf_read(sc, 22);
+ rt3090_rf_write(sc, 22, rf22 | 0x01);
+
+ /* set power and frequency of passband test tone */
+ rt2860_mcu_bbp_write(sc, 24, 0x00);
+ for (ntries = 0; ntries < 100; ntries++) {
+ /* transmit test tone */
+ rt2860_mcu_bbp_write(sc, 25, 0x90);
+ DELAY(1000);
+ /* read received power */
+ bbp55_pb = rt2860_mcu_bbp_read(sc, 55);
+ if (bbp55_pb != 0)
+ break;
+ }
+ if (ntries == 100)
+ return ETIMEDOUT;
+
+ /* set power and frequency of stopband test tone */
+ rt2860_mcu_bbp_write(sc, 24, 0x06);
+ for (ntries = 0; ntries < 100; ntries++) {
+ /* transmit test tone */
+ rt2860_mcu_bbp_write(sc, 25, 0x90);
+ DELAY(1000);
+ /* read received power */
+ bbp55_sb = rt2860_mcu_bbp_read(sc, 55);
+
+ delta = bbp55_pb - bbp55_sb;
+ if (delta > target)
+ break;
+
+ /* reprogram filter */
+ rf24++;
+ rt3090_rf_write(sc, 24, rf24);
+ }
+ if (ntries < 100) {
+ if (rf24 != init)
+ rf24--; /* backtrack */
+ *val = rf24;
+ rt3090_rf_write(sc, 24, rf24);
+ }
+
+ /* restore initial state */
+ rt2860_mcu_bbp_write(sc, 24, 0x00);
+
+ /* disable baseband loopback mode */
+ rf22 = rt3090_rf_read(sc, 22);
+ rt3090_rf_write(sc, 22, rf22 & ~0x01);
+
+ return 0;
}
void
@@ -2069,7 +2423,7 @@ rt2860_set_gp_timer(struct rt2860_softc *sc, int ms)
/* enable GP timer */
tmp = RAL_READ(sc, RT2860_INT_TIMER_EN);
- RAL_WRITE(sc, RT2860_INT_TIMER_EN, tmp | RT2860_GP_TIMER_EN);
+ RAL_WRITE(sc, RT2860_INT_TIMER_EN, tmp | RT2860_GP_TIMER_EN);
}
void
@@ -2346,6 +2700,13 @@ rt2860_get_rf(uint8_t rev)
case RT2860_RF_2850: return "RT2850";
case RT2860_RF_2720: return "RT2720";
case RT2860_RF_2750: return "RT2750";
+ case RT3070_RF_3020: return "RT3020";
+ case RT3070_RF_2020: return "RT2020";
+ case RT3070_RF_3021: return "RT3021";
+ case RT3070_RF_3022: return "RT3022";
+ case RT3070_RF_3052: return "RT3052";
+ case RT3070_RF_3320: return "RT3320";
+ case RT3070_RF_3053: return "RT3053";
default: return "unknown";
}
}
@@ -2354,47 +2715,57 @@ int
rt2860_read_eeprom(struct rt2860_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
- uint16_t val;
int8_t delta_2ghz, delta_5ghz;
+ uint32_t tmp;
+ uint16_t val;
int ridx, ant, i;
+ /* check whether the ROM is eFUSE ROM or EEPROM */
+ sc->sc_srom_read = rt2860_eeprom_read_2;
+ if (sc->mac_ver >= 0x3090) {
+ tmp = RAL_READ(sc, RT3070_EFUSE_CTRL);
+ DPRINTF(("EFUSE_CTRL=0x%08x\n", tmp));
+ if (tmp & RT3070_SEL_EFUSE)
+ sc->sc_srom_read = rt3090_efuse_read_2;
+ }
+
/* read EEPROM version */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_VERSION);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_VERSION);
DPRINTF(("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8));
/* read MAC address */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_MAC01);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_MAC01);
ic->ic_myaddr[0] = val & 0xff;
ic->ic_myaddr[1] = val >> 8;
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_MAC23);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_MAC23);
ic->ic_myaddr[2] = val & 0xff;
ic->ic_myaddr[3] = val >> 8;
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_MAC45);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_MAC45);
ic->ic_myaddr[4] = val & 0xff;
ic->ic_myaddr[5] = val >> 8;
/* read country code */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_COUNTRY);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_COUNTRY);
DPRINTF(("EEPROM region code=0x%04x\n", val));
/* read default BBP settings */
for (i = 0; i < 8; i++) {
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_BBP_BASE + i);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_BBP_BASE + i);
sc->bbp[i].val = val & 0xff;
sc->bbp[i].reg = val >> 8;
DPRINTF(("BBP%d=0x%02x\n", sc->bbp[i].reg, sc->bbp[i].val));
}
/* read RF frequency offset from EEPROM */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_FREQ_LEDS);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_FREQ_LEDS);
sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
DPRINTF(("EEPROM freq offset %d\n", sc->freq & 0xff));
-
- if ((sc->leds = val >> 8) != 0xff) {
+ if ((val >> 8) != 0xff) {
/* read LEDs operating mode */
- sc->led[0] = rt2860_eeprom_read(sc, RT2860_EEPROM_LED1);
- sc->led[1] = rt2860_eeprom_read(sc, RT2860_EEPROM_LED2);
- sc->led[2] = rt2860_eeprom_read(sc, RT2860_EEPROM_LED3);
+ sc->leds = val >> 8;
+ sc->led[0] = rt2860_srom_read(sc, RT2860_EEPROM_LED1);
+ sc->led[1] = rt2860_srom_read(sc, RT2860_EEPROM_LED2);
+ sc->led[2] = rt2860_srom_read(sc, RT2860_EEPROM_LED3);
} else {
/* broken EEPROM, use default settings */
sc->leds = 0x01;
@@ -2406,13 +2777,25 @@ rt2860_read_eeprom(struct rt2860_softc *sc)
sc->leds, sc->led[0], sc->led[1], sc->led[2]));
/* read RF information */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_ANTENNA);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_ANTENNA);
if (val == 0xffff) {
- /* broken EEPROM, default to RF2820 1T2R */
DPRINTF(("invalid EEPROM antenna info, using default\n"));
- sc->rf_rev = RT2860_RF_2820;
- sc->ntxchains = 1;
- sc->nrxchains = 2;
+ if (sc->mac_ver == 0x3593) {
+ /* default to RF3053 3T3R */
+ sc->rf_rev = RT3070_RF_3053;
+ sc->ntxchains = 3;
+ sc->nrxchains = 3;
+ } else if (sc->mac_ver >= 0x3090) {
+ /* default to RF3020 1T1R */
+ sc->rf_rev = RT3070_RF_3020;
+ sc->ntxchains = 1;
+ sc->nrxchains = 1;
+ } else {
+ /* default to RF2820 1T2R */
+ sc->rf_rev = RT2860_RF_2820;
+ sc->ntxchains = 1;
+ sc->nrxchains = 2;
+ }
} else {
sc->rf_rev = (val >> 8) & 0xf;
sc->ntxchains = (val >> 4) & 0xf;
@@ -2422,20 +2805,26 @@ rt2860_read_eeprom(struct rt2860_softc *sc)
sc->rf_rev, sc->ntxchains, sc->nrxchains));
/* check if RF supports automatic Tx access gain control */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_CONFIG);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_CONFIG);
DPRINTF(("EEPROM CFG 0x%04x\n", val));
+ /* check if driver should patch the DAC issue */
+ if ((val >> 8) != 0xff)
+ sc->patch_dac = (val >> 15) & 1;
if ((val & 0xff) != 0xff) {
sc->ext_5ghz_lna = (val >> 3) & 1;
sc->ext_2ghz_lna = (val >> 2) & 1;
+ /* check if RF supports automatic Tx access gain control */
sc->calib_2ghz = sc->calib_5ghz = 0; /* XXX (val >> 1) & 1 */;
+ /* check if we have a hardware radio switch */
+ sc->rfswitch = val & 1;
}
if (sc->sc_flags & RT2860_ADVANCED_PS) {
/* read PCIe power save level */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_PCIE_PSLEVEL);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_PCIE_PSLEVEL);
if ((val & 0xff) != 0xff) {
sc->pslevel = val & 0x3;
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_REV);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_REV);
if (val >> 8 != 0x92 || !(val & 0x80))
sc->pslevel = MIN(sc->pslevel, 1);
DPRINTF(("EEPROM PCIe PS Level=%d\n", sc->pslevel));
@@ -2443,12 +2832,12 @@ rt2860_read_eeprom(struct rt2860_softc *sc)
}
/* read power settings for 2GHz channels */
for (i = 0; i < 14; i += 2) {
- val = rt2860_eeprom_read(sc,
+ val = rt2860_srom_read(sc,
RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2);
sc->txpow1[i + 0] = (int8_t)(val & 0xff);
sc->txpow1[i + 1] = (int8_t)(val >> 8);
- val = rt2860_eeprom_read(sc,
+ val = rt2860_srom_read(sc,
RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2);
sc->txpow2[i + 0] = (int8_t)(val & 0xff);
sc->txpow2[i + 1] = (int8_t)(val >> 8);
@@ -2464,12 +2853,12 @@ rt2860_read_eeprom(struct rt2860_softc *sc)
}
/* read power settings for 5GHz channels */
for (i = 0; i < 40; i += 2) {
- val = rt2860_eeprom_read(sc,
+ val = rt2860_srom_read(sc,
RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2);
sc->txpow1[i + 14] = (int8_t)(val & 0xff);
sc->txpow1[i + 15] = (int8_t)(val >> 8);
- val = rt2860_eeprom_read(sc,
+ val = rt2860_srom_read(sc,
RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2);
sc->txpow2[i + 14] = (int8_t)(val & 0xff);
sc->txpow2[i + 15] = (int8_t)(val >> 8);
@@ -2486,7 +2875,7 @@ rt2860_read_eeprom(struct rt2860_softc *sc)
}
/* read Tx power compensation for each Tx rate */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_DELTAPWR);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_DELTAPWR);
delta_2ghz = delta_5ghz = 0;
if ((val & 0xff) != 0xff && (val & 0x80)) {
delta_2ghz = val & 0xf;
@@ -2505,9 +2894,9 @@ rt2860_read_eeprom(struct rt2860_softc *sc)
for (ridx = 0; ridx < 5; ridx++) {
uint32_t reg;
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_RPWR + ridx * 2);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2);
reg = val;
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1);
reg |= (uint32_t)val << 16;
sc->txpow20mhz[ridx] = reg;
@@ -2520,19 +2909,19 @@ rt2860_read_eeprom(struct rt2860_softc *sc)
}
/* read factory-calibrated samples for temperature compensation */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI1_2GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI1_2GHZ);
sc->tssi_2ghz[0] = val & 0xff; /* [-4] */
sc->tssi_2ghz[1] = val >> 8; /* [-3] */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI2_2GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI2_2GHZ);
sc->tssi_2ghz[2] = val & 0xff; /* [-2] */
sc->tssi_2ghz[3] = val >> 8; /* [-1] */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI3_2GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI3_2GHZ);
sc->tssi_2ghz[4] = val & 0xff; /* [+0] */
sc->tssi_2ghz[5] = val >> 8; /* [+1] */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI4_2GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI4_2GHZ);
sc->tssi_2ghz[6] = val & 0xff; /* [+2] */
sc->tssi_2ghz[7] = val >> 8; /* [+3] */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI5_2GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI5_2GHZ);
sc->tssi_2ghz[8] = val & 0xff; /* [+4] */
sc->step_2ghz = val >> 8;
DPRINTF(("TSSI 2GHz: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x "
@@ -2544,19 +2933,19 @@ rt2860_read_eeprom(struct rt2860_softc *sc)
if (sc->tssi_2ghz[4] == 0xff)
sc->calib_2ghz = 0;
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI1_5GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI1_5GHZ);
sc->tssi_5ghz[0] = val & 0xff; /* [-4] */
sc->tssi_5ghz[1] = val >> 8; /* [-3] */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI2_5GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI2_5GHZ);
sc->tssi_5ghz[2] = val & 0xff; /* [-2] */
sc->tssi_5ghz[3] = val >> 8; /* [-1] */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI3_5GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI3_5GHZ);
sc->tssi_5ghz[4] = val & 0xff; /* [+0] */
sc->tssi_5ghz[5] = val >> 8; /* [+1] */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI4_5GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI4_5GHZ);
sc->tssi_5ghz[6] = val & 0xff; /* [+2] */
sc->tssi_5ghz[7] = val >> 8; /* [+3] */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_TSSI5_5GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI5_5GHZ);
sc->tssi_5ghz[8] = val & 0xff; /* [+4] */
sc->step_5ghz = val >> 8;
DPRINTF(("TSSI 5GHz: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x "
@@ -2569,21 +2958,30 @@ rt2860_read_eeprom(struct rt2860_softc *sc)
sc->calib_5ghz = 0;
/* read RSSI offsets and LNA gains from EEPROM */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_RSSI1_2GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_RSSI1_2GHZ);
sc->rssi_2ghz[0] = val & 0xff; /* Ant A */
sc->rssi_2ghz[1] = val >> 8; /* Ant B */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_RSSI2_2GHZ);
- sc->rssi_2ghz[2] = val & 0xff; /* Ant C */
+ val = rt2860_srom_read(sc, RT2860_EEPROM_RSSI2_2GHZ);
+ if (sc->mac_ver >= 0x3090) {
+ /*
+ * On RT3090 chips (limited to 2 Rx chains), this ROM
+ * field contains the Tx mixer gain for the 2GHz band.
+ */
+ if ((val & 0xff) != 0xff)
+ sc->txmixgain_2ghz = val & 0x7;
+ DPRINTF(("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz));
+ } else
+ sc->rssi_2ghz[2] = val & 0xff; /* Ant C */
sc->lna[2] = val >> 8; /* channel group 2 */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_RSSI1_5GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_RSSI1_5GHZ);
sc->rssi_5ghz[0] = val & 0xff; /* Ant A */
sc->rssi_5ghz[1] = val >> 8; /* Ant B */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_RSSI2_5GHZ);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_RSSI2_5GHZ);
sc->rssi_5ghz[2] = val & 0xff; /* Ant C */
sc->lna[3] = val >> 8; /* channel group 3 */
- val = rt2860_eeprom_read(sc, RT2860_EEPROM_LNA);
+ val = rt2860_srom_read(sc, RT2860_EEPROM_LNA);
sc->lna[0] = val & 0xff; /* channel group 0 */
sc->lna[1] = val >> 8; /* channel group 1 */
@@ -2638,11 +3036,11 @@ rt2860_bbp_init(struct rt2860_softc *sc)
}
/* fix BBP84 for RT2860E */
- if ((sc->mac_rev & 0xffff) != 0x0101)
+ if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
rt2860_mcu_bbp_write(sc, 84, 0x19);
/* fix BBP69 and BBP73 for RT2860C */
- if (sc->mac_rev == 0x28600100) {
+ if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0100) {
rt2860_mcu_bbp_write(sc, 69, 0x16);
rt2860_mcu_bbp_write(sc, 73, 0x12);
}
@@ -2790,6 +3188,14 @@ rt2860_init(struct ifnet *ifp)
return ETIMEDOUT;
}
+ if (!(RAL_READ(sc, RT2860_PCI_CFG) & RT2860_PCI_CFG_PCI)) {
+ sc->sc_flags |= RT2860_PCIE;
+ /* PCIe has different clock cycle count than PCI */
+ tmp = RAL_READ(sc, RT2860_US_CYC_CNT);
+ tmp = (tmp & ~0xff) | 0x7d;
+ RAL_WRITE(sc, RT2860_US_CYC_CNT, tmp);
+ }
+
/* clear Host to MCU mailbox */
RAL_WRITE(sc, RT2860_H2M_BBPAGENT, 0);
RAL_WRITE(sc, RT2860_H2M_MAILBOX, 0);
@@ -2853,11 +3259,18 @@ rt2860_init(struct ifnet *ifp)
rt2860_mcu_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
}
+ /* select Main antenna for 1T1R devices */
+ if (sc->rf_rev == RT3070_RF_3020)
+ rt3090_set_rx_antenna(sc, 0);
+
/* send LEDs operating mode to microcontroller */
(void)rt2860_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
(void)rt2860_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
(void)rt2860_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
+ if (sc->mac_ver >= 0x3090)
+ rt3090_rf_init(sc);
+
/* disable non-existing Rx chains */
bbp3 = rt2860_mcu_bbp_read(sc, 3);
bbp3 &= ~(1 << 3 | 1 << 4);
@@ -2875,7 +3288,7 @@ rt2860_init(struct ifnet *ifp)
/* select default channel */
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
- rt2860_set_chan(sc, ic->ic_ibss_chan);
+ rt2860_switch_chan(sc, ic->ic_ibss_chan);
/* reset RF from MCU */
(void)rt2860_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0);
@@ -3060,6 +3473,55 @@ rt2860_calib(struct rt2860_softc *sc)
}
}
+void
+rt3090_set_rx_antenna(struct rt2860_softc *sc, int aux)
+{
+ uint32_t tmp;
+
+ if (aux) {
+ tmp = RAL_READ(sc, RT2860_PCI_EECTRL);
+ RAL_WRITE(sc, RT2860_PCI_EECTRL, tmp & ~RT2860_C);
+ tmp = RAL_READ(sc, RT2860_GPIO_CTRL);
+ RAL_WRITE(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
+ } else {
+ tmp = RAL_READ(sc, RT2860_PCI_EECTRL);
+ RAL_WRITE(sc, RT2860_PCI_EECTRL, tmp | RT2860_C);
+ tmp = RAL_READ(sc, RT2860_GPIO_CTRL);
+ RAL_WRITE(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
+ }
+}
+
+void
+rt2860_switch_chan(struct rt2860_softc *sc, struct ieee80211_channel *c)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ u_int chan, group;
+
+ chan = ieee80211_chan2ieee(ic, c);
+ if (chan == 0 || chan == IEEE80211_CHAN_ANY)
+ return;
+
+ if (sc->mac_ver >= 0x3090)
+ rt3090_set_chan(sc, chan);
+ else
+ rt2860_set_chan(sc, chan);
+
+ /* determine channel group */
+ if (chan <= 14)
+ group = 0;
+ else if (chan <= 64)
+ group = 1;
+ else if (chan <= 128)
+ group = 2;
+ else
+ group = 3;
+
+ /* XXX necessary only when group has changed! */
+ rt2860_select_chan_group(sc, group);
+
+ DELAY(1000);
+}
+
#ifndef IEEE80211_STA_ONLY
int
rt2860_setup_beacon(struct rt2860_softc *sc)
diff --git a/sys/dev/ic/rt2860reg.h b/sys/dev/ic/rt2860reg.h
index 1ee7f61180f..9229c89c068 100644
--- a/sys/dev/ic/rt2860reg.h
+++ b/sys/dev/ic/rt2860reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rt2860reg.h,v 1.26 2010/02/08 18:46:47 damien Exp $ */
+/* $OpenBSD: rt2860reg.h,v 1.27 2010/04/05 14:14:02 damien Exp $ */
/*-
* Copyright (c) 2007
@@ -205,6 +205,10 @@
#define RT2860_BCN_BASE(vap) (0x7800 + (vap) * 512)
+/* possible flags for RT2860_PCI_CFG */
+#define RT2860_PCI_CFG_USB (1 << 17)
+#define RT2860_PCI_CFG_PCI (1 << 16)
+
/* possible flags for register RT2860_PCI_EECTRL */
#define RT2860_C (1 << 0)
#define RT2860_S (1 << 1)
@@ -499,6 +503,14 @@
#define RT2860_WAKEUP_LEAD_TIME_SHIFT 0
/* possible flags for register TX_PIN_CFG */
+#define RT3593_LNA_PE_G2_POL (1 << 31)
+#define RT3593_LNA_PE_A2_POL (1 << 30)
+#define RT3593_LNA_PE_G2_EN (1 << 29)
+#define RT3593_LNA_PE_A2_EN (1 << 28)
+#define RT3593_PA_PE_G2_POL (1 << 27)
+#define RT3593_PA_PE_A2_POL (1 << 26)
+#define RT3593_PA_PE_G2_EN (1 << 25)
+#define RT3593_PA_PE_A2_EN (1 << 24)
#define RT2860_TRSW_POL (1 << 19)
#define RT2860_TRSW_EN (1 << 18)
#define RT2860_RFTR_POL (1 << 17)
@@ -838,6 +850,8 @@ struct rt2860_rxwi {
#define RT3070_RF_3021 7 /* 1T2R */
#define RT3070_RF_3022 8 /* 2T2R */
#define RT3070_RF_3052 9 /* dual-band 2T2R */
+#define RT3070_RF_3320 11 /* 1T1R */
+#define RT3070_RF_3053 13 /* dual-band 3T3R */
/* USB commands for RT2870 only */
#define RT2870_RESET 1
diff --git a/sys/dev/ic/rt2860var.h b/sys/dev/ic/rt2860var.h
index de22fb9b5db..8fccfd0366f 100644
--- a/sys/dev/ic/rt2860var.h
+++ b/sys/dev/ic/rt2860var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rt2860var.h,v 1.14 2010/02/08 18:46:47 damien Exp $ */
+/* $OpenBSD: rt2860var.h,v 1.15 2010/04/05 14:14:02 damien Exp $ */
/*-
* Copyright (c) 2007
@@ -117,10 +117,14 @@ struct rt2860_softc {
bus_space_tag_t sc_st;
bus_space_handle_t sc_sh;
+ uint16_t (*sc_srom_read)(struct rt2860_softc *,
+ uint16_t);
+
int sc_flags;
#define RT2860_ENABLED (1 << 0)
#define RT2860_FWLOADED (1 << 1)
#define RT2860_ADVANCED_PS (1 << 2)
+#define RT2860_PCIE (1 << 3)
uint32_t sc_ic_flags;
int fixed_ridx;
@@ -138,7 +142,8 @@ struct rt2860_softc {
int mgtqid;
uint8_t qfullmsk;
- uint32_t mac_rev;
+ uint16_t mac_ver;
+ uint16_t mac_rev;
uint8_t rf_rev;
uint8_t freq;
uint8_t ntxchains;
@@ -149,10 +154,16 @@ struct rt2860_softc {
int8_t rssi_2ghz[3];
int8_t rssi_5ghz[3];
uint8_t lna[4];
+ uint8_t rf24_20mhz;
+ uint8_t rf24_40mhz;
+ uint8_t patch_dac;
+ uint8_t rfswitch;
uint8_t ext_2ghz_lna;
uint8_t ext_5ghz_lna;
uint8_t calib_2ghz;
uint8_t calib_5ghz;
+ uint8_t txmixgain_2ghz;
+ uint8_t txmixgain_5ghz;
uint8_t tssi_2ghz[9];
uint8_t tssi_5ghz[9];
uint8_t step_2ghz;