summaryrefslogtreecommitdiff
path: root/sys/dev/usb/if_urtwn.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/if_urtwn.c')
-rw-r--r--sys/dev/usb/if_urtwn.c397
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];