diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2010-04-05 14:14:03 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2010-04-05 14:14:03 +0000 |
commit | a24f6b8d2cb85809726a671ba115b29f9e870e65 (patch) | |
tree | 661ceb0855857133418844cbafb97ea300329bb4 /sys/dev/ic | |
parent | 6eb896d0da489dc987d2a7fd77d081d650352535 (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.c | 680 | ||||
-rw-r--r-- | sys/dev/ic/rt2860reg.h | 16 | ||||
-rw-r--r-- | sys/dev/ic/rt2860var.h | 15 |
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; |