diff options
Diffstat (limited to 'sys/dev/usb/if_urtwn.c')
-rw-r--r-- | sys/dev/usb/if_urtwn.c | 397 |
1 files changed, 336 insertions, 61 deletions
diff --git a/sys/dev/usb/if_urtwn.c b/sys/dev/usb/if_urtwn.c index 325edba3fd9..43d924c69c9 100644 --- a/sys/dev/usb/if_urtwn.c +++ b/sys/dev/usb/if_urtwn.c @@ -1,8 +1,9 @@ -/* $OpenBSD: if_urtwn.c,v 1.79 2018/10/01 11:03:46 jmatthew Exp $ */ +/* $OpenBSD: if_urtwn.c,v 1.80 2018/12/04 10:47:32 jmatthew Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> + * Copyright (c) 2016 Nathanial Sloss <nathanialsloss@yahoo.com.au> * * 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 +19,8 @@ */ /* - * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU. + * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU/ + * RTL8192EU. */ #include "bpfilter.h" @@ -34,6 +36,7 @@ #include <sys/device.h> #include <sys/endian.h> +#include <machine/bus.h> #include <machine/intr.h> #if NBPFILTER > 0 @@ -52,6 +55,7 @@ #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> +#include <dev/usb/usbdivar.h> #include <dev/usb/usbdi_util.h> #include <dev/usb/usbdevs.h> @@ -68,6 +72,7 @@ #define R92C_TX_PAGE_COUNT 248 #define R92C_TX_PAGE_BOUNDARY (R92C_TX_PAGE_COUNT + 1) #define R92C_MAX_RX_DMA_SIZE 0x2800 + #define R88E_HQ_NPAGES 0 #define R88E_LQ_NPAGES 9 #define R88E_NQ_NPAGES 0 @@ -76,6 +81,16 @@ #define R88E_TX_PAGE_BOUNDARY (R88E_TX_PAGE_COUNT + 1) #define R88E_MAX_RX_DMA_SIZE 0x2400 +#define R92E_HQ_NPAGES 16 +#define R92E_LQ_NPAGES 16 +#define R92E_NQ_NPAGES 16 +#define R92E_TX_PAGE_COUNT 248 +#define R92E_TX_PAGE_BOUNDARY (R92E_TX_PAGE_COUNT + 1) +#define R92E_MAX_RX_DMA_SIZE 0x3fc0 + +#define R92C_TXDESC_SUMSIZE 32 +#define R92C_TXDESC_SUMOFFSET 14 + /* USB Requests. */ #define R92C_REQ_REGS 0x05 @@ -87,7 +102,7 @@ #define URTWN_HOST_CMD_RING_COUNT 32 #define URTWN_RXBUFSZ (16 * 1024) -#define URTWN_TXBUFSZ (sizeof(struct r92c_tx_desc_usb) + IEEE80211_MAX_LEN) +#define URTWN_TXBUFSZ (sizeof(struct r92e_tx_desc_usb) + IEEE80211_MAX_LEN) #define URTWN_RIDX_COUNT 28 @@ -219,6 +234,7 @@ int urtwn_debug = 4; { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, (f) | RTWN_CHIP_USB } #define URTWN_DEV_8192CU(v, p) URTWN_DEV(v, p, RTWN_CHIP_92C | RTWN_CHIP_88C) #define URTWN_DEV_8188EU(v, p) URTWN_DEV(v, p, RTWN_CHIP_88E) +#define URTWN_DEV_8192EU(v, p) URTWN_DEV(v, p, RTWN_CHIP_92E) static const struct urtwn_type { struct usb_devno dev; uint32_t chip; @@ -312,7 +328,10 @@ static const struct urtwn_type { URTWN_DEV_8188EU(ELECOM, WDC150SU2M), URTWN_DEV_8188EU(REALTEK, RTL8188ETV), URTWN_DEV_8188EU(REALTEK, RTL8188EU), - URTWN_DEV_8188EU(TPLINK, RTL8188EUS) + URTWN_DEV_8188EU(TPLINK, RTL8188EUS), + /* URTWN_RTL8192EU */ + URTWN_DEV_8192EU(REALTEK, RTL8192EU), + URTWN_DEV_8192EU(DLINK, DWA131E1) }; #define urtwn_lookup(v, p) \ @@ -370,6 +389,7 @@ int urtwn_ioctl(struct ifnet *, u_long, caddr_t); int urtwn_power_on(void *); int urtwn_alloc_buffers(void *); int urtwn_r92c_power_on(struct urtwn_softc *); +int urtwn_r92e_power_on(struct urtwn_softc *); int urtwn_r88e_power_on(struct urtwn_softc *); int urtwn_llt_init(struct urtwn_softc *, int); int urtwn_fw_loadpage(void *, int, uint8_t *, int); @@ -1185,7 +1205,7 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv, struct r92c_rx_desc_usb *rxd; uint32_t rxdw0; uint8_t *buf; - int len, totlen, pktlen, infosz, npkts, error; + int len, totlen, pktlen, infosz, npkts, error, align; if (__predict_false(status != USBD_NORMAL_COMPLETION)) { DPRINTF(("RX status=%d\n", status)); @@ -1227,8 +1247,34 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv, goto resubmit; } + } else if (sc->sc_sc.chip & RTWN_CHIP_92E) { + int type; + struct r92e_c2h_tx_rpt *txrpt; + + if (letoh32(rxd->rxdw2) & R92E_RXDW2_RPT_C2H) { + if (len < sizeof(struct r92c_rx_desc_usb) + 2) + goto resubmit; + + type = buf[sizeof(struct r92c_rx_desc_usb)]; + switch (type) { + case R92C_C2HEVT_TX_REPORT: + buf += sizeof(struct r92c_rx_desc_usb) + 2; + txrpt = (struct r92e_c2h_tx_rpt *)buf; + if (MS(txrpt->rptb2, R92E_RPTB2_RETRY_CNT) > 0) + sc->amn.amn_retrycnt++; + if ((txrpt->rptb0 & (R92E_RPTB0_RETRY_OVER | + R92E_RPTB0_LIFE_EXPIRE)) == 0) + sc->amn.amn_txcnt++; + break; + default: + break; + } + goto resubmit; + } } + align = (sc->sc_sc.chip & RTWN_CHIP_92E ? 7 : 127); + /* Process all of them. */ while (npkts-- > 0) { if (__predict_false(len < sizeof(*rxd))) @@ -1250,8 +1296,8 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv, /* Process 802.11 frame. */ urtwn_rx_frame(sc, buf, pktlen); - /* Next chunk is 128-byte aligned. */ - totlen = (totlen + 127) & ~127; + /* Handle chunk alignment. */ + totlen = (totlen + align) & ~align; buf += totlen; len -= totlen; } @@ -1296,51 +1342,21 @@ urtwn_txeof(struct usbd_xfer *xfer, void *priv, splx(s); } -int -urtwn_tx(void *cookie, struct mbuf *m, struct ieee80211_node *ni) +void +urtwn_tx_fill_desc(struct urtwn_softc *sc, uint8_t **txdp, struct mbuf *m, + struct ieee80211_frame *wh, struct ieee80211_key *k, + struct ieee80211_node *ni) { - struct urtwn_softc *sc = cookie; - struct ieee80211com *ic = &sc->sc_sc.sc_ic; - struct ieee80211_frame *wh; - struct ieee80211_key *k = NULL; - struct urtwn_tx_data *data; struct r92c_tx_desc_usb *txd; - struct usbd_pipe *pipe; - uint16_t qos, sum; - uint8_t raid, type, tid, qid; - int i, hasqos, xferlen, error; - - wh = mtod(m, struct ieee80211_frame *); - type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; - - if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { - k = ieee80211_get_txkey(ic, wh, ni); - if ((m = ieee80211_encrypt(ic, m, k)) == NULL) - return (ENOBUFS); - wh = mtod(m, struct ieee80211_frame *); - } - - if ((hasqos = ieee80211_has_qos(wh))) { - qos = ieee80211_get_qos(wh); - tid = qos & IEEE80211_QOS_TID; - qid = ieee80211_up_to_ac(ic, tid); - } else if (type != IEEE80211_FC0_TYPE_DATA) { - /* Use AC VO for management frames. */ - qid = EDCA_AC_VO; - } else - qid = EDCA_AC_BE; - - /* Get the USB pipe to use for this AC. */ - pipe = sc->tx_pipe[sc->ac2idx[qid]]; - - /* Grab a Tx buffer from our free list. */ - data = TAILQ_FIRST(&sc->tx_free_list); - TAILQ_REMOVE(&sc->tx_free_list, data, next); + struct ieee80211com *ic = &sc->sc_sc.sc_ic; + uint8_t raid, type; - /* Fill Tx descriptor. */ - txd = (struct r92c_tx_desc_usb *)data->buf; + txd = (struct r92c_tx_desc_usb *)*txdp; + (*txdp) += sizeof(*txd); memset(txd, 0, sizeof(*txd)); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + txd->txdw0 |= htole32( SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) | SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | @@ -1426,18 +1442,145 @@ urtwn_tx(void *cookie, struct mbuf *m, struct ieee80211_node *ni) /* Set sequence number (already little endian). */ txd->txdseq |= (*(uint16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT; - if (!hasqos) { + if (!ieee80211_has_qos(wh)) { /* Use HW sequence numbering for non-QoS frames. */ txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ); txd->txdseq |= htole16(R92C_TXDW3_HWSEQEN); } else txd->txdw4 |= htole32(R92C_TXDW4_QOS); +} + +void +urtwn_tx_fill_desc_gen2(struct urtwn_softc *sc, uint8_t **txdp, struct mbuf *m, + struct ieee80211_frame *wh, struct ieee80211_key *k, + struct ieee80211_node *ni) +{ + struct r92e_tx_desc_usb *txd; + struct ieee80211com *ic = &sc->sc_sc.sc_ic; + uint8_t raid, type; + + txd = (struct r92e_tx_desc_usb *)*txdp; + (*txdp) += sizeof(*txd); + memset(txd, 0, sizeof(*txd)); + + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + + txd->txdw0 |= htole32( + SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) | + SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | + R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); + +#ifdef notyet + /* cipher */ +#endif + + if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && + type == IEEE80211_FC0_TYPE_DATA) { + if (ic->ic_curmode == IEEE80211_MODE_11B || + (sc->sc_sc.sc_flags & RTWN_FLAG_FORCE_RAID_11B)) + raid = R92E_RAID_11B; + else + raid = R92E_RAID_11BG; + txd->txdw1 |= htole32( + SM(R92E_TXDW1_MACID, R92C_MACID_BSS) | + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) | + SM(R92C_TXDW1_RAID, raid)); + /* Request TX status report for AMRR */ + txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT | R88E_TXDW2_AGGBK); + + if (m->m_pkthdr.len + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) { + txd->txdw4 |= htole32(R92C_TXDW4_RTSEN | + R92C_TXDW4_HWRTSEN); + } else if (ic->ic_flags & IEEE80211_F_USEPROT) { + if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) { + txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF | + R92C_TXDW4_HWRTSEN); + } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) { + txd->txdw4 |= htole32(R92C_TXDW4_RTSEN | + R92C_TXDW4_HWRTSEN); + } + } + txd->txdw5 |= htole32(0x0001ff00); + + /* Use AMRR */ + txd->txdw3 |= htole32(R92E_TXDW3_DRVRATE); + txd->txdw4 |= htole32(SM(R92E_TXDW4_RTSRATE, ni->ni_txrate)); + txd->txdw4 |= htole32(SM(R92E_TXDW4_DATARATE, ni->ni_txrate)); + } else { + txd->txdw1 |= htole32( + SM(R92E_TXDW1_MACID, 0) | + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) | + SM(R92C_TXDW1_RAID, R92E_RAID_11B)); + + /* Force CCK1. */ + txd->txdw3 |= htole32(R92E_TXDW3_DRVRATE); + txd->txdw4 |= htole32(SM(R92E_TXDW4_DATARATE, 0)); + } + txd->txdw4 |= htole32(SM(R92E_TXDW4_DATARATEFB, 0x1f)); + + txd->txdseq2 |= htole16(SM(R92E_TXDSEQ2_HWSEQ, *(uint16_t *)wh->i_seq)); + + if (!ieee80211_has_qos(wh)) { + /* Use HW sequence numbering for non-QoS frames. */ + txd->txdw7 |= htole16(R92C_TXDW3_HWSEQEN); + } +} + +int +urtwn_tx(void *cookie, struct mbuf *m, struct ieee80211_node *ni) +{ + struct urtwn_softc *sc = cookie; + struct ieee80211com *ic = &sc->sc_sc.sc_ic; + struct ieee80211_frame *wh; + struct ieee80211_key *k = NULL; + struct urtwn_tx_data *data; + struct usbd_pipe *pipe; + uint16_t qos, sum; + uint8_t tid, qid; + int i, xferlen, error; + uint8_t *txdp; + + wh = mtod(m, struct ieee80211_frame *); + + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + k = ieee80211_get_txkey(ic, wh, ni); + if ((m = ieee80211_encrypt(ic, m, k)) == NULL) + return (ENOBUFS); + wh = mtod(m, struct ieee80211_frame *); + } + + if (ieee80211_has_qos(wh)) { + qos = ieee80211_get_qos(wh); + tid = qos & IEEE80211_QOS_TID; + qid = ieee80211_up_to_ac(ic, tid); + } else if ((wh->i_fc[1] & IEEE80211_FC0_TYPE_MASK) + != IEEE80211_FC0_TYPE_DATA) { + /* Use AC VO for management frames. */ + qid = EDCA_AC_VO; + } else + qid = EDCA_AC_BE; + + /* Get the USB pipe to use for this AC. */ + pipe = sc->tx_pipe[sc->ac2idx[qid]]; + + /* Grab a Tx buffer from our free list. */ + data = TAILQ_FIRST(&sc->tx_free_list); + TAILQ_REMOVE(&sc->tx_free_list, data, next); + + /* Fill Tx descriptor. */ + txdp = data->buf; + if (sc->sc_sc.chip & RTWN_CHIP_92E) + urtwn_tx_fill_desc_gen2(sc, &txdp, m, wh, k, ni); + else + urtwn_tx_fill_desc(sc, &txdp, m, wh, k, ni); /* Compute Tx descriptor checksum. */ sum = 0; - for (i = 0; i < sizeof(*txd) / 2; i++) - sum ^= ((uint16_t *)txd)[i]; - txd->txdsum = sum; /* NB: already little endian. */ + for (i = 0; i < R92C_TXDESC_SUMSIZE / 2; i++) + sum ^= ((uint16_t *)data->buf)[i]; + ((uint16_t *)data->buf)[R92C_TXDESC_SUMOFFSET] = sum; #if NBPFILTER > 0 if (__predict_false(sc->sc_drvbpf != NULL)) { @@ -1458,8 +1601,8 @@ urtwn_tx(void *cookie, struct mbuf *m, struct ieee80211_node *ni) } #endif - xferlen = sizeof(*txd) + m->m_pkthdr.len; - m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txd[1]); + xferlen = (txdp - data->buf) + m->m_pkthdr.len; + m_copydata(m, 0, m->m_pkthdr.len, txdp); m_freem(m); data->pipe = pipe; @@ -1580,6 +1723,80 @@ urtwn_r92c_power_on(struct urtwn_softc *sc) } int +urtwn_r92e_power_on(struct urtwn_softc *sc) +{ + uint32_t reg; + int ntries; + + if (urtwn_read_4(sc, R92C_SYS_CFG) & R92E_SYS_CFG_SPSLDO_SEL) { + /* LDO. */ + urtwn_write_1(sc, R92E_LDO_SWR_CTRL, 0xc3); + } else { + reg = urtwn_read_4(sc, R92C_SYS_SWR_CTRL2); + reg &= 0xff0fffff; + reg |= 0x00500000; + urtwn_write_4(sc, R92C_SYS_SWR_CTRL2, reg); + urtwn_write_1(sc, R92E_LDO_SWR_CTRL, 0x83); + } + + /* 40MHz crystal source */ + urtwn_write_1(sc, R92C_AFE_PLL_CTRL, + urtwn_read_1(sc, R92C_AFE_PLL_CTRL) & 0xfb); + urtwn_write_4(sc, R92C_AFE_XTAL_CTRL_EXT, + urtwn_read_4(sc, R92C_AFE_XTAL_CTRL_EXT) & 0xfffffc7f); + + urtwn_write_1(sc, R92C_AFE_PLL_CTRL, + urtwn_read_1(sc, R92C_AFE_PLL_CTRL) & 0xbf); + urtwn_write_4(sc, R92C_AFE_XTAL_CTRL_EXT, + urtwn_read_4(sc, R92C_AFE_XTAL_CTRL_EXT) & 0xffdfffff); + + /* Disable HWPDN. */ + urtwn_write_2(sc, R92C_APS_FSMCO, + urtwn_read_2(sc, R92C_APS_FSMCO) & ~R92C_APS_FSMCO_APDM_HPDN); + for (ntries = 0; ntries < 5000; ntries++) { + if (urtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) + break; + DELAY(10); + } + if (ntries == 5000) { + printf("%s: timeout waiting for chip power up\n", + sc->sc_dev.dv_xname); + return (ETIMEDOUT); + } + + /* Disable WL suspend. */ + urtwn_write_2(sc, R92C_APS_FSMCO, + urtwn_read_2(sc, R92C_APS_FSMCO) & + ~(R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE)); + + /* Auto enable WLAN. */ + urtwn_write_4(sc, R92C_APS_FSMCO, + urtwn_read_4(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_RDY_MACON); + urtwn_write_2(sc, R92C_APS_FSMCO, + urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); + for (ntries = 0; ntries < 5000; ntries++) { + if (!(urtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + DELAY(10); + } + if (ntries == 5000) { + printf("%s: timeout waiting for MAC auto ON\n", + sc->sc_dev.dv_xname); + return (ETIMEDOUT); + } + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + urtwn_write_2(sc, R92C_CR, 0); + reg = urtwn_read_2(sc, R92C_CR); + reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | + R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | + R92C_CR_SCHEDULE_EN | R92C_CR_ENSEC | R92C_CR_CALTMR_EN; + urtwn_write_2(sc, R92C_CR, reg); + return (0); +} + +int urtwn_r88e_power_on(struct urtwn_softc *sc) { uint32_t reg; @@ -1672,6 +1889,22 @@ urtwn_llt_init(struct urtwn_softc *sc, int page_count) } int +urtwn_auto_llt_init(struct urtwn_softc *sc) +{ + int ntries; + + urtwn_write_4(sc, R92E_AUTO_LLT, urtwn_read_4(sc, + R92E_AUTO_LLT) | R92E_AUTO_LLT_EN); + for (ntries = 0; ntries < 1000; ntries++) { + if (!(urtwn_read_4(sc, R92E_AUTO_LLT) & R92E_AUTO_LLT_EN)) + return (0); + DELAY(2); + } + + return (ETIMEDOUT); +} + +int urtwn_fw_loadpage(void *cookie, int page, uint8_t *buf, int len) { struct urtwn_softc *sc = cookie; @@ -1707,7 +1940,9 @@ urtwn_load_firmware(void *cookie, u_char **fw, size_t *len) const char *name; int error; - if (sc->sc_sc.chip & RTWN_CHIP_88E) + if (sc->sc_sc.chip & RTWN_CHIP_92E) + name = "urtwn-rtl8192eu_nic"; + else if (sc->sc_sc.chip & RTWN_CHIP_88E) name = "urtwn-rtl8188eufw"; else if ((sc->sc_sc.chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) == RTWN_CHIP_UMC_A_CUT) @@ -1739,6 +1974,13 @@ urtwn_dma_init(void *cookie) pagecnt = R88E_TX_PAGE_COUNT; boundary = R88E_TX_PAGE_BOUNDARY; dmasize = R88E_MAX_RX_DMA_SIZE; + } else if (sc->sc_sc.chip & RTWN_CHIP_92E) { + hqpages = R92E_HQ_NPAGES; + lqpages = R92E_LQ_NPAGES; + nqpages = R92E_NQ_NPAGES; + pagecnt = R92E_TX_PAGE_COUNT; + boundary = R92E_TX_PAGE_BOUNDARY; + dmasize = R92E_MAX_RX_DMA_SIZE; } else { hqpages = R92C_HQ_NPAGES; lqpages = R92C_LQ_NPAGES; @@ -1749,7 +1991,11 @@ urtwn_dma_init(void *cookie) } /* Initialize LLT table. */ - error = urtwn_llt_init(sc, pagecnt); + if (sc->sc_sc.chip & RTWN_CHIP_92E) { + error = urtwn_auto_llt_init(sc); + } else { + error = urtwn_llt_init(sc, pagecnt); + } if (error != 0) return (error); @@ -1804,10 +2050,12 @@ urtwn_dma_init(void *cookie) /* Set Tx/Rx transfer page boundary. */ urtwn_write_2(sc, R92C_TRXFF_BNDY + 2, dmasize - 1); - /* Set Tx/Rx transfer page size. */ - urtwn_write_1(sc, R92C_PBP, - SM(R92C_PBP_PSRX, R92C_PBP_128) | - SM(R92C_PBP_PSTX, R92C_PBP_128)); + if (!(sc->sc_sc.chip & RTWN_CHIP_92E)) { + /* Set Tx/Rx transfer page size. */ + urtwn_write_1(sc, R92C_PBP, + SM(R92C_PBP_PSRX, R92C_PBP_128) | + SM(R92C_PBP_PSTX, R92C_PBP_128)); + } return (error); } @@ -1824,6 +2072,11 @@ urtwn_mac_init(void *cookie) rtl8188eu_mac[i].val); } urtwn_write_1(sc, R92C_MAX_AGGR_NUM, 0x07); + } else if (sc->sc_sc.chip & RTWN_CHIP_92E) { + for (i = 0; i < nitems(rtl8192eu_mac); i++) { + urtwn_write_1(sc, rtl8192eu_mac[i].reg, + rtl8192eu_mac[i].val); + } } else { for (i = 0; i < nitems(rtl8192cu_mac); i++) urtwn_write_1(sc, rtl8192cu_mac[i].reg, @@ -1846,7 +2099,7 @@ urtwn_bb_init(void *cookie) R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_DIO_RF); - if (!(sc->sc_sc.chip & RTWN_CHIP_88E)) + if (!(sc->sc_sc.chip & (RTWN_CHIP_88E | RTWN_CHIP_92E))) urtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); urtwn_write_1(sc, R92C_RF_CTRL, @@ -1855,7 +2108,7 @@ urtwn_bb_init(void *cookie) R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); - if (!(sc->sc_sc.chip & RTWN_CHIP_88E)) { + if (!(sc->sc_sc.chip & (RTWN_CHIP_88E | RTWN_CHIP_92E))) { urtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f); urtwn_write_1(sc, 0x15, 0xe9); urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); @@ -1864,6 +2117,8 @@ urtwn_bb_init(void *cookie) /* Select BB programming based on board type. */ if (sc->sc_sc.chip & RTWN_CHIP_88E) prog = &rtl8188eu_bb_prog; + else if (sc->sc_sc.chip & RTWN_CHIP_92E) + prog = &rtl8192eu_bb_prog; else if (!(sc->sc_sc.chip & RTWN_CHIP_92C)) { if (sc->sc_sc.board_type == R92C_BOARD_TYPE_MINICARD) prog = &rtl8188ce_bb_prog; @@ -1934,11 +2189,26 @@ urtwn_bb_init(void *cookie) DELAY(1); urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553420); DELAY(1); + } else if (sc->sc_sc.chip & RTWN_CHIP_92E) { + urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x00040022); + DELAY(1); + urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x00040020); + DELAY(1); + } + if (sc->sc_sc.chip & RTWN_CHIP_88E) { xtal = sc->sc_sc.crystal_cap & 0x3f; reg = urtwn_bb_read(sc, R92C_AFE_XTAL_CTRL); urtwn_bb_write(sc, R92C_AFE_XTAL_CTRL, RW(reg, R92C_AFE_XTAL_CTRL_ADDR, xtal | xtal << 6)); + } else if (sc->sc_sc.chip & RTWN_CHIP_92E) { + xtal = sc->sc_sc.crystal_cap & 0x3f; + reg = urtwn_read_4(sc, R92C_AFE_CTRL3); + reg &= 0xff000fff; + reg |= (xtal | (xtal << 6)) << 12; + urtwn_write_4(sc, R92C_AFE_CTRL3, reg); + + urtwn_write_4(sc, R92C_AFE_XTAL_CTRL, 0x000f81fb); } if (urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & R92C_HSSI_PARAM2_CCK_HIPWR) @@ -1952,6 +2222,8 @@ urtwn_power_on(void *cookie) if (sc->sc_sc.chip & RTWN_CHIP_88E) return (urtwn_r88e_power_on(sc)); + else if (sc->sc_sc.chip & RTWN_CHIP_92E) + return (urtwn_r92e_power_on(sc)); return (urtwn_r92c_power_on(sc)); } @@ -1988,6 +2260,9 @@ urtwn_init(void *cookie) struct urtwn_softc *sc = cookie; int i, error; + if (sc->sc_sc.chip & RTWN_CHIP_92E) + urtwn_write_1(sc, R92C_ACLK_MON, 0); + /* Queue Rx xfers. */ for (i = 0; i < URTWN_RX_LIST_COUNT; i++) { struct urtwn_rx_data *data = &sc->rx_data[i]; |