diff options
author | Jonathan Matthew <jmatthew@cvs.openbsd.org> | 2018-09-21 01:45:54 +0000 |
---|---|---|
committer | Jonathan Matthew <jmatthew@cvs.openbsd.org> | 2018-09-21 01:45:54 +0000 |
commit | 84b9575109bad934f45fdafeac6b98b2fbc1faff (patch) | |
tree | e6b8b3a642788aa7a131605a60a66ff8a4437a86 | |
parent | 34e0fdd2259803fff4a8402b7ed5f2c3c7592f36 (diff) |
Add support for RTL8188EE.
This needs a new firmware image, which should be added to the rtwn
firmware package shortly.
testing and lots of help from kevlo@
ok kevlo@ stsp@
-rw-r--r-- | sys/dev/ic/r92creg.h | 54 | ||||
-rw-r--r-- | sys/dev/ic/rtwn.c | 54 | ||||
-rw-r--r-- | sys/dev/ic/rtwnvar.h | 20 | ||||
-rw-r--r-- | sys/dev/pci/if_rtwn.c | 462 |
4 files changed, 529 insertions, 61 deletions
diff --git a/sys/dev/ic/r92creg.h b/sys/dev/ic/r92creg.h index c2be8db4696..8dbf64c72c6 100644 --- a/sys/dev/ic/r92creg.h +++ b/sys/dev/ic/r92creg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: r92creg.h,v 1.17 2018/09/13 09:28:07 kevlo Exp $ */ +/* $OpenBSD: r92creg.h,v 1.18 2018/09/21 01:45:53 jmatthew Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> @@ -58,6 +58,8 @@ #define R92C_FSISR 0x054 #define R92C_HSIMR 0x058 #define R92C_HSISR 0x05c +#define R92C_AFE_XTAL_CTRL_EXT 0x078 +#define R88E_XCK_OUT_CTRL 0x07c #define R92C_MCUFWDL 0x080 #define R92C_HMEBOX_EXT(idx) (0x088 + (idx) * 2) #define R88E_HIMR 0x0b0 @@ -96,6 +98,7 @@ #define R92C_MBIST_START 0x174 #define R92C_MBIST_DONE 0x178 #define R92C_MBIST_FAIL 0x17c +#define R88E_32K_CTRL 0x194 #define R92C_C2HEVT_MSG 0x1a0 #define R92C_C2HEVT_CLEAR 0x1af #define R92C_C2HEVT_MSG_TEST 0x1b8 @@ -117,6 +120,7 @@ /* Rx DMA Configuration. */ #define R92C_RXDMA_AGG_PG_TH 0x280 #define R92C_RXPKT_NUM 0x284 +#define R88E_RXDMA_CTRL 0x286 #define R92C_RXDMA_STATUS 0x288 #define R92C_PCIE_CTRL_REG 0x300 @@ -165,8 +169,9 @@ #define R92C_RD_RESP_PKT_TH 0x463 #define R92C_INIRTS_RATE_SEL 0x480 #define R92C_INIDATA_RATE_SEL(macid) (0x484 + (macid)) -#define R88E_TX_RPT_CTRL 0x4ec #define R92C_MAX_AGGR_NUM 0x4ca +#define R88E_TX_RPT_CTRL 0x4ec +#define R88E_TX_RPT_TIME 0x4f0 /* EDCA Configuration. */ #define R92C_EDCA_VO_PARAM 0x500 #define R92C_EDCA_VI_PARAM 0x504 @@ -329,6 +334,9 @@ #define R92C_AFE_XTAL_CTRL_ADDR_M 0x007ff800 #define R92C_AFE_XTAL_CTRL_ADDR_S 11 +/* Bits for R88E_XCK_OUT_CTRL. */ +#define R88E_XCK_OUT_CTRL_EN 1 + /* Bits for R92C_EFUSE_CTRL. */ #define R92C_EFUSE_CTRL_DATA_M 0x000000ff #define R92C_EFUSE_CTRL_DATA_S 0 @@ -339,6 +347,7 @@ /* Bits for R92C_GPIO_MUXCFG. */ #define R92C_GPIO_MUXCFG_RFKILL 0x0008 #define R92C_GPIO_MUXCFG_ENBT 0x0020 +#define R92C_GPIO_MUXCFG_ENSIC 0x1000 /* Bits for R92C_GPIO_IO_SEL. */ #define R92C_GPIO_IO_SEL_RFKILL 0x0008 @@ -365,10 +374,30 @@ #define R92C_MCUFWDL_CPRST 0x00800000 /* Bits for R88E_HIMR. */ +#define R88E_HIMR_ROK 0x00000001 +#define R88E_HIMR_RDU 0x00000002 +#define R88E_HIMR_VODOK 0x00000004 +#define R88E_HIMR_VIDOK 0x00000008 +#define R88E_HIMR_BEDOK 0x00000010 +#define R88E_HIMR_BKDOK 0x00000020 +#define R88E_HIMR_MGNTDOK 0x00000040 +#define R88E_HIMR_HIGHDOK 0x00000080 #define R88E_HIMR_CPWM 0x00000100 #define R88E_HIMR_CPWM2 0x00000200 +#define R88E_HIMR_C2HCMD 0x00000400 +#define R88E_HIMR_HISR1_IND_INT 0x00000800 +#define R88E_HIMR_ATIMEND 0x00001000 +#define R88E_HIMR_BCNDMAINT_E 0x00004000 +#define R88E_HIMR_HSISR_IND_ON_INT 0x00008000 +#define R88E_HIMR_BCNDOK0 0x00010000 +#define R88E_HIMR_BCNDMAINT0 0x00100000 +#define R88E_HIMR_TSF_BIT32_TOGGLE 0x01000000 +#define R88E_HIMR_TBDOK 0x02000000 #define R88E_HIMR_TBDER 0x04000000 +#define R88E_HIMR_GTINT3 0x08000000 +#define R88E_HIMR_GTINT4 0x10000000 #define R88E_HIMR_PSTIMEOUT 0x20000000 +#define R88E_HIMR_TXCCK 0x40000000 /* Bits for R88E_HIMRE.*/ #define R88E_HIMRE_RXFOVW 0x00000100 @@ -376,6 +405,13 @@ #define R88E_HIMRE_RXERR 0x00000400 #define R88E_HIMRE_TXERR 0x00000800 +/* Bits for R88E_HSIMR */ +#define R88E_HSIMR_GPIO12_0_INT_EN 0x00000001 +#define R88E_HSIMR_SPS_OCP_INT_EN 0x00000020 +#define R88E_HSIMR_RON_INT_EN 0x00000040 +#define R88E_HSIMR_PDN_INT_EN 0x00000080 +#define R88E_HSIMR_GPIO9_INT_EN 0x02000000 + /* Bits for R92C_EFUSE_ACCESS. */ #define R92C_EFUSE_ACCESS_OFF 0x00 #define R92C_EFUSE_ACCESS_ON 0x69 @@ -1100,7 +1136,7 @@ struct r88e_tx_pwr { } __packed; /* - * RTL8188EU ROM image. + * RTL8188E ROM images. */ struct r88e_rom { uint16_t id; @@ -1119,6 +1155,18 @@ struct r88e_rom { uint8_t reserved4[3]; uint8_t rf_ant_opt; uint8_t reserved5[6]; +} __packed; + +struct r88e_pci_rom { + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint16_t vid; + uint16_t did; + uint16_t svid; + uint16_t smid; + uint8_t reserved[290]; +} __packed; + +struct r88e_usb_rom { uint16_t vid; uint16_t pid; uint8_t usb_opt; diff --git a/sys/dev/ic/rtwn.c b/sys/dev/ic/rtwn.c index 01aca68667f..8ede63992db 100644 --- a/sys/dev/ic/rtwn.c +++ b/sys/dev/ic/rtwn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtwn.c,v 1.37 2018/09/13 09:28:07 kevlo Exp $ */ +/* $OpenBSD: rtwn.c,v 1.38 2018/09/21 01:45:53 jmatthew Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> @@ -637,18 +637,29 @@ rtwn_r88e_read_rom(struct rtwn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct r88e_rom *rom = &sc->sc_r88e_rom; + struct r88e_pci_rom *pcirom = &sc->sc_r88e_pci_rom; + struct r88e_usb_rom *usbrom = &sc->sc_r88e_usb_rom; + int romsize; + + if (sc->chip & RTWN_CHIP_PCI) + romsize = sizeof(struct r88e_pci_rom); + else + romsize = sizeof(struct r88e_usb_rom); /* Read full ROM image. */ rtwn_efuse_read(sc, (uint8_t *)&sc->sc_r88e_rom, - sizeof(sc->sc_r88e_rom)); + sizeof(sc->sc_r88e_rom) + romsize); - sc->crystal_cap = rom->xtal; + sc->crystal_cap = (sc->chip & RTWN_CHIP_PCI) ? 0x20 : rom->xtal; DPRINTF(("Crystal cap=0x%x\n", sc->crystal_cap)); sc->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY); DPRINTF(("regulatory type=%d\n", sc->regulatory)); - IEEE80211_ADDR_COPY(ic->ic_myaddr, rom->macaddr); + if (sc->chip & RTWN_CHIP_PCI) + IEEE80211_ADDR_COPY(ic->ic_myaddr, pcirom->macaddr); + else + IEEE80211_ADDR_COPY(ic->ic_myaddr, usbrom->macaddr); } int @@ -1729,6 +1740,13 @@ rtwn_rf_init(struct rtwn_softc *sc) sc->rf_chnlbw[i] = rtwn_rf_read(sc, i, R92C_RF_CHNLBW); } + /* magic value for HP 8188EEs */ + if (sc->chip == (RTWN_CHIP_88E | RTWN_CHIP_PCI)) { + struct r88e_pci_rom *pcirom = &sc->sc_r88e_pci_rom; + if ((pcirom->svid == 0x103c) && (pcirom->smid == 0x197d)) + rtwn_rf_write(sc, 0, 0x52, 0x7e4bd); + } + if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) == RTWN_CHIP_UMC_A_CUT) { rtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255); @@ -2186,6 +2204,9 @@ rtwn_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c, ((sc->chip & RTWN_CHIP_88E) ? R88E_RF_CHNLBW_BW20 : R92C_RF_CHNLBW_BW20)); } + + if (sc->chip == (RTWN_CHIP_88E | RTWN_CHIP_PCI)) + DELAY(25000); } int @@ -2609,12 +2630,23 @@ rtwn_enable_intr(struct rtwn_softc *sc) { if (sc->chip & RTWN_CHIP_88E) { rtwn_write_4(sc, R88E_HISR, 0xffffffff); - rtwn_write_4(sc, R88E_HIMR, R88E_HIMR_CPWM | - R88E_HIMR_CPWM2 | R88E_HIMR_TBDER | - R88E_HIMR_PSTIMEOUT); - rtwn_write_4(sc, R88E_HIMRE, R88E_HIMRE_RXFOVW | - R88E_HIMRE_TXFOVW | R88E_HIMRE_RXERR | - R88E_HIMRE_TXERR); + if (sc->chip & RTWN_CHIP_USB) { + rtwn_write_4(sc, R88E_HIMR, R88E_HIMR_CPWM | + R88E_HIMR_CPWM2 | R88E_HIMR_TBDER | + R88E_HIMR_PSTIMEOUT); + rtwn_write_4(sc, R88E_HIMRE, R88E_HIMRE_RXFOVW | + R88E_HIMRE_TXFOVW | R88E_HIMRE_RXERR | + R88E_HIMRE_TXERR); + } else { + rtwn_write_4(sc, R88E_HIMR, + RTWN_88E_INT_ENABLE); + rtwn_write_4(sc, R88E_HIMRE, + R88E_HIMRE_RXFOVW); + rtwn_write_1(sc, R92C_C2HEVT_CLEAR, 0); + rtwn_write_4(sc, R92C_HSIMR, + R88E_HSIMR_PDN_INT_EN | R88E_HSIMR_RON_INT_EN); + } + if (sc->chip & RTWN_CHIP_USB) { rtwn_write_1(sc, R92C_USB_SPECIAL_OPTION, rtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) | @@ -2626,7 +2658,7 @@ rtwn_enable_intr(struct rtwn_softc *sc) if (sc->chip & RTWN_CHIP_USB) imask = 0xffffffff; else if (sc->chip & RTWN_CHIP_PCI) - imask = RTWN_INT_ENABLE; + imask = RTWN_92C_INT_ENABLE; else panic("unknown chip type 0x%x", sc->chip); diff --git a/sys/dev/ic/rtwnvar.h b/sys/dev/ic/rtwnvar.h index a5a3c674c6e..698c76a2b78 100644 --- a/sys/dev/ic/rtwnvar.h +++ b/sys/dev/ic/rtwnvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rtwnvar.h,v 1.10 2017/07/08 14:26:23 kevlo Exp $ */ +/* $OpenBSD: rtwnvar.h,v 1.11 2018/09/21 01:45:53 jmatthew Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> @@ -48,10 +48,14 @@ struct rtwn_ops { #define RTWN_LED_LINK 0 #define RTWN_LED_DATA 1 -#define RTWN_INT_ENABLE (R92C_IMR_ROK | R92C_IMR_VODOK | R92C_IMR_VIDOK | \ +#define RTWN_92C_INT_ENABLE (R92C_IMR_ROK | R92C_IMR_VODOK | R92C_IMR_VIDOK | \ R92C_IMR_BEDOK | R92C_IMR_BKDOK | R92C_IMR_MGNTDOK | \ R92C_IMR_HIGHDOK | R92C_IMR_BDOK | R92C_IMR_RDU | \ R92C_IMR_RXFOVW) +#define RTWN_88E_INT_ENABLE (R88E_HIMR_PSTIMEOUT | R88E_HIMR_HSISR_IND_ON_INT | \ + R88E_HIMR_C2HCMD | R88E_HIMR_ROK | R88E_HIMR_VODOK | \ + R88E_HIMR_VIDOK | R88E_HIMR_BEDOK | R88E_HIMR_BKDOK | \ + R88E_HIMR_MGNTDOK | R88E_HIMR_HIGHDOK | R88E_HIMR_RDU) struct rtwn_softc { /* sc_ops must be initialized by the attachment driver! */ @@ -95,10 +99,18 @@ struct rtwn_softc { int fwcur; union { struct r92c_rom r92c_rom; - struct r88e_rom r88e_rom; + struct { + struct r88e_rom r88e_rom; + union { + struct r88e_pci_rom pci; + struct r88e_usb_rom usb; + } u; + } __packed _88e; } u; #define sc_r92c_rom u.r92c_rom -#define sc_r88e_rom u.r88e_rom +#define sc_r88e_rom u._88e.r88e_rom +#define sc_r88e_pci_rom u._88e.u.pci +#define sc_r88e_usb_rom u._88e.u.usb uint32_t rf_chnlbw[R92C_MAX_CHAINS]; }; diff --git a/sys/dev/pci/if_rtwn.c b/sys/dev/pci/if_rtwn.c index c146cee5877..f9a713bb9a4 100644 --- a/sys/dev/pci/if_rtwn.c +++ b/sys/dev/pci/if_rtwn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_rtwn.c,v 1.32 2018/09/13 09:28:07 kevlo Exp $ */ +/* $OpenBSD: if_rtwn.c,v 1.33 2018/09/21 01:45:53 jmatthew Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> @@ -19,7 +19,7 @@ */ /* - * PCI front-end for Realtek RTL8188CE/RTL8192CE driver. + * PCI front-end for Realtek RTL8188CE/RTL8188EE/RTL8192CE driver. */ #include "bpfilter.h" @@ -64,6 +64,7 @@ * Driver definitions. */ +#define R92C_NPQ_NPAGES 0 #define R92C_PUBQ_NPAGES 176 #define R92C_HPQ_NPAGES 41 #define R92C_LPQ_NPAGES 28 @@ -71,6 +72,17 @@ #define R92C_TX_PAGE_COUNT \ (R92C_PUBQ_NPAGES + R92C_HPQ_NPAGES + R92C_LPQ_NPAGES) #define R92C_TX_PAGE_BOUNDARY (R92C_TX_PAGE_COUNT + 1) +#define R92C_MAX_RX_DMA_SIZE 0x2800 + +#define R88E_NPQ_NPAGES 0 +#define R88E_PUBQ_NPAGES 116 +#define R88E_HPQ_NPAGES 41 +#define R88E_LPQ_NPAGES 13 +#define R88E_TXPKTBUF_COUNT 176 +#define R88E_TX_PAGE_COUNT \ + (R88E_PUBQ_NPAGES + R88E_HPQ_NPAGES + R88E_LPQ_NPAGES) +#define R88E_TX_PAGE_BOUNDARY (R88E_TX_PAGE_COUNT + 1) +#define R88E_MAX_RX_DMA_SIZE 0x2600 #define RTWN_NTXQUEUES 9 #define RTWN_RX_LIST_COUNT 256 @@ -202,6 +214,7 @@ extern int rtwn_debug; static const struct pci_matchid rtwn_pci_devices[] = { { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTL8188CE }, + { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTL8188EE }, { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTL8192CE } }; @@ -229,12 +242,15 @@ int rtwn_tx(void *, struct mbuf *, struct ieee80211_node *); void rtwn_tx_done(struct rtwn_pci_softc *, int); int rtwn_alloc_buffers(void *); int rtwn_pci_init(void *); +void rtwn_pci_88e_stop(struct rtwn_pci_softc *); void rtwn_pci_stop(void *); int rtwn_intr(void *); int rtwn_is_oactive(void *); +int rtwn_92c_power_on(struct rtwn_pci_softc *); +int rtwn_88e_power_on(struct rtwn_pci_softc *); int rtwn_power_on(void *); int rtwn_llt_write(struct rtwn_pci_softc *, uint32_t, uint32_t); -int rtwn_llt_init(struct rtwn_pci_softc *); +int rtwn_llt_init(struct rtwn_pci_softc *, int); int rtwn_dma_init(void *); int rtwn_fw_loadpage(void *, int, uint8_t *, int); int rtwn_pci_load_firmware(void *, u_char **, size_t *); @@ -373,7 +389,16 @@ rtwn_pci_attach(struct device *parent, struct device *self, void *aux) sc->sc_sc.sc_ops.cancel_scan = rtwn_cancel_scan; sc->sc_sc.sc_ops.wait_async = rtwn_wait_async; - sc->sc_sc.chip = RTWN_CHIP_88C | RTWN_CHIP_92C | RTWN_CHIP_PCI; + sc->sc_sc.chip = RTWN_CHIP_PCI; + switch (PCI_PRODUCT(pa->pa_id)) { + case PCI_PRODUCT_REALTEK_RTL8188CE: + case PCI_PRODUCT_REALTEK_RTL8192CE: + sc->sc_sc.chip |= RTWN_CHIP_88C | RTWN_CHIP_92C; + break; + case PCI_PRODUCT_REALTEK_RTL8188EE: + sc->sc_sc.chip |= RTWN_CHIP_88E; + break; + } error = rtwn_attach(&sc->sc_dev, &sc->sc_sc); if (error != 0) { @@ -790,6 +815,30 @@ rtwn_rx_frame(struct rtwn_pci_softc *sc, struct r92c_rx_desc_pci *rx_desc, rxdw0 = letoh32(rx_desc->rxdw0); rxdw3 = letoh32(rx_desc->rxdw3); + if (sc->sc_sc.chip & RTWN_CHIP_88E) { + int ntries, type; + struct r88e_tx_rpt_ccx *rxstat; + + type = MS(rxdw3, R88E_RXDW3_RPT); + if (type == R88E_RXDW3_RPT_TX1) { + uint32_t rptb1, rptb2; + + rxstat = mtod(rx_data->m, struct r88e_tx_rpt_ccx *); + rptb1 = letoh32(rxstat->rptb1); + rptb2 = letoh32(rxstat->rptb2); + ntries = MS(rptb2, R88E_RPTB2_RETRY_CNT); + if (rptb1 & R88E_RPTB1_PKT_OK) + sc->amn.amn_txcnt++; + if (ntries > 0) + sc->amn.amn_retrycnt++; + + rtwn_setup_rx_desc(sc, rx_desc, + rx_data->map->dm_segs[0].ds_addr, MCLBYTES, + desc_idx); + return; + } + } + if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { /* * This should not happen since we setup our Rx filter @@ -996,11 +1045,20 @@ rtwn_tx(void *cookie, struct mbuf *m, struct ieee80211_node *ni) raid = R92C_RAID_11B; else raid = R92C_RAID_11BG; - txd->txdw1 |= htole32( - SM(R92C_TXDW1_MACID, R92C_MACID_BSS) | - SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) | - SM(R92C_TXDW1_RAID, raid) | - R92C_TXDW1_AGGBK); + + if (sc->sc_sc.chip & RTWN_CHIP_88E) { + txd->txdw1 |= htole32( + SM(R88E_TXDW1_MACID, R92C_MACID_BSS) | + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) | + SM(R92C_TXDW1_RAID, raid)); + txd->txdw2 |= htole32(R88E_TXDW2_AGGBK); + } else { + txd->txdw1 |= htole32( + SM(R92C_TXDW1_MACID, R92C_MACID_BSS) | + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) | + SM(R92C_TXDW1_RAID, raid) | + R92C_TXDW1_AGGBK); + } /* Request TX status report for AMRR. */ txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); @@ -1178,23 +1236,133 @@ rtwn_pci_init(void *cookie) { struct rtwn_pci_softc *sc = cookie; ieee80211_amrr_node_init(&sc->amrr, &sc->amn); + + /* Enable TX reports for AMRR */ + if (sc->sc_sc.chip & RTWN_CHIP_88E) { + rtwn_pci_write_1(sc, R88E_TX_RPT_CTRL, + (rtwn_pci_read_1(sc, R88E_TX_RPT_CTRL) & ~0) | + R88E_TX_RPT_CTRL_EN); + rtwn_pci_write_1(sc, R88E_TX_RPT_CTRL + 1, 0x02); + + rtwn_pci_write_2(sc, R88E_TX_RPT_TIME, 0xcdf0); + } + return (0); } void +rtwn_pci_88e_stop(struct rtwn_pci_softc *sc) +{ + int i, s; + uint16_t reg; + + s = splnet(); + + /* Disable interrupts. */ + rtwn_pci_write_4(sc, R88E_HIMR, 0x00000000); + + /* Stop hardware. */ + rtwn_pci_write_1(sc, R88E_TX_RPT_CTRL, + rtwn_pci_read_1(sc, R88E_TX_RPT_CTRL) & + ~(R88E_TX_RPT_CTRL_EN)); + + for (i = 0; i < 100; i++) { + if (rtwn_pci_read_1(sc, R88E_RXDMA_CTRL) & 0x02) + break; + DELAY(10); + } + if (i == 100) + DPRINTF(("rxdma ctrl didn't go off, %x\n", rtwn_pci_read_1(sc, R88E_RXDMA_CTRL))); + + rtwn_pci_write_1(sc, R92C_PCIE_CTRL_REG + 1, 0xff); + + rtwn_pci_write_1(sc, R92C_TXPAUSE, R92C_TXPAUSE_ALL); + + /* ensure transmission has stopped */ + for (i = 0; i < 100; i++) { + if (rtwn_pci_read_4(sc, 0x5f8) == 0) + break; + DELAY(10); + } + if (i == 100) + DPRINTF(("tx didn't stop\n")); + + rtwn_pci_write_1(sc, R92C_SYS_FUNC_EN, + rtwn_pci_read_1(sc, R92C_SYS_FUNC_EN) & + ~(R92C_SYS_FUNC_EN_BBRSTB)); + DELAY(1); + reg = rtwn_pci_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_MACTXEN | R92C_CR_MACRXEN | + R92C_CR_ENSEC); + rtwn_pci_write_2(sc, R92C_CR, reg); + rtwn_pci_write_1(sc, R92C_DUAL_TSF_RST, + rtwn_pci_read_1(sc, R92C_DUAL_TSF_RST) | 0x20); + + rtwn_pci_write_1(sc, R92C_RF_CTRL, 0x00); + if (rtwn_pci_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) + rtwn_fw_reset(&sc->sc_sc); + + rtwn_pci_write_1(sc, R92C_SYS_FUNC_EN + 1, + rtwn_pci_read_1(sc, R92C_SYS_FUNC_EN + 1) & ~0x02); + rtwn_pci_write_1(sc, R92C_MCUFWDL, 0); + + rtwn_pci_write_1(sc, R88E_32K_CTRL, + rtwn_pci_read_1(sc, R88E_32K_CTRL) & ~(0x01)); + + /* transition to cardemu state */ + rtwn_pci_write_1(sc, R92C_RF_CTRL, 0); + rtwn_pci_write_1(sc, R92C_LPLDO_CTRL, + rtwn_pci_read_1(sc, R92C_LPLDO_CTRL) | 0x10); + rtwn_pci_write_2(sc, R92C_APS_FSMCO, + rtwn_pci_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_OFF); + for (i = 0; i < 100; i++) { + if ((rtwn_pci_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_OFF) == 0) + break; + DELAY(10); + } + if (i == 100) + DPRINTF(("apfm off didn't go off\n")); + + /* transition to card disabled state */ + rtwn_pci_write_1(sc, R92C_AFE_XTAL_CTRL + 2, + rtwn_pci_read_1(sc, R92C_AFE_XTAL_CTRL + 2) | 0x80); + + rtwn_pci_write_1(sc, R92C_RSV_CTRL + 1, + rtwn_pci_read_1(sc, R92C_RSV_CTRL + 1) & ~(0x08)); + rtwn_pci_write_1(sc, R92C_RSV_CTRL + 1, + rtwn_pci_read_1(sc, R92C_RSV_CTRL + 1) | 0x08); + + rtwn_pci_write_1(sc, R92C_RSV_CTRL, 0x0e); + + for (i = 0; i < RTWN_NTXQUEUES; i++) + rtwn_reset_tx_list(sc, i); + rtwn_reset_rx_list(sc); + + splx(s); +} + +void rtwn_pci_stop(void *cookie) { struct rtwn_pci_softc *sc = cookie; uint16_t reg; int i, s; + if (sc->sc_sc.chip & RTWN_CHIP_88E) { + rtwn_pci_88e_stop(sc); + return; + } + s = splnet(); /* Disable interrupts. */ rtwn_pci_write_4(sc, R92C_HIMR, 0x00000000); /* Stop hardware. */ - rtwn_pci_write_1(sc, R92C_TXPAUSE, 0xff); + rtwn_pci_write_1(sc, R92C_TXPAUSE, R92C_TXPAUSE_ALL); rtwn_pci_write_1(sc, R92C_RF_CTRL, 0x00); reg = rtwn_pci_read_1(sc, R92C_SYS_FUNC_EN); reg |= R92C_SYS_FUNC_EN_BB_GLB_RST; @@ -1224,12 +1392,77 @@ rtwn_pci_stop(void *cookie) } int +rtwn_88e_intr(struct rtwn_pci_softc *sc) +{ + u_int32_t status, estatus; + int i; + + status = rtwn_pci_read_4(sc, R88E_HISR); + if (status == 0 || status == 0xffffffff) + return (0); + + estatus = rtwn_pci_read_4(sc, R88E_HISRE); + + status &= RTWN_88E_INT_ENABLE; + estatus &= R88E_HIMRE_RXFOVW; + + rtwn_pci_write_4(sc, R88E_HIMR, 0); + rtwn_pci_write_4(sc, R88E_HIMRE, 0); + rtwn_pci_write_4(sc, R88E_HISR, status); + rtwn_pci_write_4(sc, R88E_HISRE, estatus); + + if (status & R88E_HIMR_HIGHDOK) + rtwn_tx_done(sc, RTWN_HIGH_QUEUE); + if (status & R88E_HIMR_MGNTDOK) + rtwn_tx_done(sc, RTWN_MGNT_QUEUE); + if (status & R88E_HIMR_BKDOK) + rtwn_tx_done(sc, RTWN_BK_QUEUE); + if (status & R88E_HIMR_BEDOK) + rtwn_tx_done(sc, RTWN_BE_QUEUE); + if (status & R88E_HIMR_VIDOK) + rtwn_tx_done(sc, RTWN_VI_QUEUE); + if (status & R88E_HIMR_VODOK) + rtwn_tx_done(sc, RTWN_VO_QUEUE); + if ((status & (R88E_HIMR_ROK | R88E_HIMR_RDU)) || + (estatus & R88E_HIMRE_RXFOVW)) { + bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0, + sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT, + BUS_DMASYNC_POSTREAD); + + for (i = 0; i < RTWN_RX_LIST_COUNT; i++) { + struct r92c_rx_desc_pci *rx_desc = &sc->rx_ring.desc[i]; + struct rtwn_rx_data *rx_data = &sc->rx_ring.rx_data[i]; + + if (letoh32(rx_desc->rxdw0) & R92C_RXDW0_OWN) + continue; + + rtwn_rx_frame(sc, rx_desc, rx_data, i); + } + } + + if (status & R88E_HIMR_HSISR_IND_ON_INT) { + rtwn_pci_write_1(sc, R92C_HSISR, + rtwn_pci_read_1(sc, R92C_HSISR) | + R88E_HSIMR_PDN_INT_EN | R88E_HSIMR_RON_INT_EN); + } + + /* Enable interrupts. */ + rtwn_pci_write_4(sc, R88E_HIMR, RTWN_88E_INT_ENABLE); + rtwn_pci_write_4(sc, R88E_HIMRE, R88E_HIMRE_RXFOVW); + + return (1); +} + +int rtwn_intr(void *xsc) { struct rtwn_pci_softc *sc = xsc; u_int32_t status; int i; + if (sc->sc_sc.chip & RTWN_CHIP_88E) + return (rtwn_88e_intr(sc)); + status = rtwn_pci_read_4(sc, R92C_HISR); if (status == 0 || status == 0xffffffff) return (0); @@ -1273,7 +1506,7 @@ rtwn_intr(void *xsc) rtwn_tx_done(sc, RTWN_VO_QUEUE); /* Enable interrupts. */ - rtwn_pci_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE); + rtwn_pci_write_4(sc, R92C_HIMR, RTWN_92C_INT_ENABLE); return (1); } @@ -1306,12 +1539,15 @@ rtwn_llt_write(struct rtwn_pci_softc *sc, uint32_t addr, uint32_t data) } int -rtwn_llt_init(struct rtwn_pci_softc *sc) +rtwn_llt_init(struct rtwn_pci_softc *sc, int page_count) { - int i, error; + int i, error, pktbuf_count; - /* Reserve pages [0; R92C_TX_PAGE_COUNT]. */ - for (i = 0; i < R92C_TX_PAGE_COUNT; i++) { + pktbuf_count = (sc->sc_sc.chip & RTWN_CHIP_88E) ? + R88E_TXPKTBUF_COUNT : R92C_TXPKTBUF_COUNT; + + /* Reserve pages [0; page_count]. */ + for (i = 0; i < page_count; i++) { if ((error = rtwn_llt_write(sc, i, i + 1)) != 0) return (error); } @@ -1319,22 +1555,21 @@ rtwn_llt_init(struct rtwn_pci_softc *sc) if ((error = rtwn_llt_write(sc, i, 0xff)) != 0) return (error); /* - * Use pages [R92C_TX_PAGE_COUNT + 1; R92C_TXPKTBUF_COUNT - 1] + * Use pages [page_count + 1; pktbuf_count - 1] * as ring buffer. */ - for (++i; i < R92C_TXPKTBUF_COUNT - 1; i++) { + for (++i; i < pktbuf_count - 1; i++) { if ((error = rtwn_llt_write(sc, i, i + 1)) != 0) return (error); } /* Make the last page point to the beginning of the ring buffer. */ - error = rtwn_llt_write(sc, i, R92C_TX_PAGE_COUNT + 1); + error = rtwn_llt_write(sc, i, pktbuf_count + 1); return (error); } int -rtwn_power_on(void *cookie) +rtwn_92c_power_on(struct rtwn_pci_softc *sc) { - struct rtwn_pci_softc *sc = cookie; uint32_t reg; int ntries; @@ -1464,43 +1699,164 @@ rtwn_power_on(void *cookie) } int +rtwn_88e_power_on(struct rtwn_pci_softc *sc) +{ + uint32_t reg; + int ntries; + + /* Disable XTAL output for power saving. */ + rtwn_pci_write_1(sc, R88E_XCK_OUT_CTRL, + rtwn_pci_read_1(sc, R88E_XCK_OUT_CTRL) & ~R88E_XCK_OUT_CTRL_EN); + + rtwn_pci_write_2(sc, R92C_APS_FSMCO, + rtwn_pci_read_2(sc, R92C_APS_FSMCO) & (~R92C_APS_FSMCO_APDM_HPDN)); + rtwn_pci_write_1(sc, R92C_RSV_CTRL, 0); + + /* Wait for power ready bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_pci_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); + } + + /* Reset BB. */ + rtwn_pci_write_1(sc, R92C_SYS_FUNC_EN, + rtwn_pci_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB | + R92C_SYS_FUNC_EN_BB_GLB_RST)); + + rtwn_pci_write_1(sc, R92C_AFE_XTAL_CTRL + 2, + rtwn_pci_read_1(sc, R92C_AFE_XTAL_CTRL + 2) | 0x80); + + /* Disable HWPDN. */ + rtwn_pci_write_2(sc, R92C_APS_FSMCO, + rtwn_pci_read_2(sc, R92C_APS_FSMCO) & ~R92C_APS_FSMCO_APDM_HPDN); + /* Disable WL suspend. */ + rtwn_pci_write_2(sc, R92C_APS_FSMCO, + rtwn_pci_read_2(sc, R92C_APS_FSMCO) & + ~(R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE)); + + /* Auto enable WLAN. */ + rtwn_pci_write_2(sc, R92C_APS_FSMCO, + rtwn_pci_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_pci_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 LDO normal mode. */ + rtwn_pci_write_1(sc, R92C_LPLDO_CTRL, + rtwn_pci_read_1(sc, R92C_LPLDO_CTRL) & ~0x10); + + rtwn_pci_write_1(sc, R92C_APS_FSMCO, + rtwn_pci_read_1(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_PDN_EN); + rtwn_pci_write_1(sc, R92C_PCIE_CTRL_REG + 2, + rtwn_pci_read_1(sc, R92C_PCIE_CTRL_REG + 2) | 0x04); + + rtwn_pci_write_1(sc, R92C_AFE_XTAL_CTRL_EXT + 1, + rtwn_pci_read_1(sc, R92C_AFE_XTAL_CTRL_EXT + 1) | 0x02); + + rtwn_pci_write_1(sc, R92C_SYS_CLKR, + rtwn_pci_read_1(sc, R92C_SYS_CLKR) | 0x08); + + rtwn_pci_write_2(sc, R92C_GPIO_MUXCFG, + rtwn_pci_read_2(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENSIC); + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + rtwn_pci_write_2(sc, R92C_CR, 0); + reg = rtwn_pci_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_MACTXEN | R92C_CR_MACRXEN | + R92C_CR_ENSEC | R92C_CR_CALTMR_EN; + rtwn_pci_write_2(sc, R92C_CR, reg); + + rtwn_pci_write_1(sc, R92C_MSR, 0); + return (0); +} + +int +rtwn_power_on(void *cookie) +{ + struct rtwn_pci_softc *sc = cookie; + + if (sc->sc_sc.chip & RTWN_CHIP_88E) + return (rtwn_88e_power_on(sc)); + else + return (rtwn_92c_power_on(sc)); +} + +int rtwn_dma_init(void *cookie) { struct rtwn_pci_softc *sc = cookie; uint32_t reg; + uint16_t dmasize; + int hqpages, lqpages, nqpages, pagecnt, boundary, trxdma, tcr; int error; + if (sc->sc_sc.chip & RTWN_CHIP_88E) { + nqpages = R88E_NPQ_NPAGES; + hqpages = R88E_HPQ_NPAGES; + lqpages = R88E_LPQ_NPAGES; + pagecnt = R88E_TX_PAGE_COUNT; + boundary = R88E_TX_PAGE_BOUNDARY; + dmasize = R88E_MAX_RX_DMA_SIZE; + tcr = R92C_TCR_CFENDFORM | R92C_TCR_ERRSTEN3; + trxdma = 0xe771; + } else { + nqpages = R92C_NPQ_NPAGES; + hqpages = R92C_HPQ_NPAGES; + lqpages = R92C_LPQ_NPAGES; + pagecnt = R92C_TX_PAGE_COUNT; + boundary = R92C_TX_PAGE_BOUNDARY; + dmasize = R92C_MAX_RX_DMA_SIZE; + tcr = R92C_TCR_CFENDFORM | R92C_TCR_ERRSTEN0 | + R92C_TCR_ERRSTEN1; + trxdma = 0xf771; + } + /* Initialize LLT table. */ - error = rtwn_llt_init(sc); + error = rtwn_llt_init(sc, pagecnt); if (error != 0) return error; /* Set number of pages for normal priority queue. */ - rtwn_pci_write_2(sc, R92C_RQPN_NPQ, 0); + rtwn_pci_write_2(sc, R92C_RQPN_NPQ, nqpages); rtwn_pci_write_4(sc, R92C_RQPN, /* Set number of pages for public queue. */ - SM(R92C_RQPN_PUBQ, R92C_PUBQ_NPAGES) | + SM(R92C_RQPN_PUBQ, pagecnt) | /* Set number of pages for high priority queue. */ - SM(R92C_RQPN_HPQ, R92C_HPQ_NPAGES) | + SM(R92C_RQPN_HPQ, hqpages) | /* Set number of pages for low priority queue. */ - SM(R92C_RQPN_LPQ, R92C_LPQ_NPAGES) | + SM(R92C_RQPN_LPQ, lqpages) | /* Load values. */ R92C_RQPN_LD); - rtwn_pci_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R92C_TX_PAGE_BOUNDARY); - rtwn_pci_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R92C_TX_PAGE_BOUNDARY); + rtwn_pci_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, boundary); + rtwn_pci_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, boundary); rtwn_pci_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, - R92C_TX_PAGE_BOUNDARY); - rtwn_pci_write_1(sc, R92C_TRXFF_BNDY, R92C_TX_PAGE_BOUNDARY); - rtwn_pci_write_1(sc, R92C_TDECTRL + 1, R92C_TX_PAGE_BOUNDARY); + boundary); + rtwn_pci_write_1(sc, R92C_TRXFF_BNDY, boundary); + rtwn_pci_write_1(sc, R92C_TDECTRL + 1, boundary); reg = rtwn_pci_read_2(sc, R92C_TRXDMA_CTRL); reg &= ~R92C_TRXDMA_CTRL_QMAP_M; - reg |= 0xF771; + reg |= trxdma; rtwn_pci_write_2(sc, R92C_TRXDMA_CTRL, reg); - rtwn_pci_write_4(sc, R92C_TCR, - R92C_TCR_CFENDFORM | R92C_TCR_ERRSTEN0 | R92C_TCR_ERRSTEN1); + rtwn_pci_write_4(sc, R92C_TCR, tcr); /* Configure Tx DMA. */ rtwn_pci_write_4(sc, R92C_BKQ_DESA, @@ -1520,9 +1876,10 @@ rtwn_dma_init(void *cookie) /* Configure Rx DMA. */ rtwn_pci_write_4(sc, R92C_RX_DESA, sc->rx_ring.map->dm_segs[0].ds_addr); + rtwn_pci_write_1(sc, R92C_PCIE_CTRL_REG+1, 0); /* Set Tx/Rx transfer page boundary. */ - rtwn_pci_write_2(sc, R92C_TRXFF_BNDY + 2, 0x27ff); + rtwn_pci_write_2(sc, R92C_TRXFF_BNDY + 2, dmasize - 1); /* Set Tx/Rx transfer page size. */ rtwn_pci_write_1(sc, R92C_PBP, @@ -1569,7 +1926,9 @@ rtwn_pci_load_firmware(void *cookie, u_char **fw, size_t *len) const char *name; int error; - if ((sc->sc_sc.chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) == + if (sc->sc_sc.chip & RTWN_CHIP_88E) + name = "rtwn-rtl8188efw"; + else if ((sc->sc_sc.chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) == RTWN_CHIP_UMC_A_CUT) name = "rtwn-rtl8192cfwU"; else @@ -1589,9 +1948,19 @@ rtwn_mac_init(void *cookie) int i; /* Write MAC initialization values. */ - for (i = 0; i < nitems(rtl8192ce_mac); i++) - rtwn_pci_write_1(sc, rtl8192ce_mac[i].reg, - rtl8192ce_mac[i].val); + if (sc->sc_sc.chip & RTWN_CHIP_88E) { + for (i = 0; i < nitems(rtl8188eu_mac); i++) { + if (rtl8188eu_mac[i].reg == R92C_GPIO_MUXCFG) + continue; + rtwn_pci_write_1(sc, rtl8188eu_mac[i].reg, + rtl8188eu_mac[i].val); + } + rtwn_pci_write_1(sc, R92C_MAX_AGGR_NUM, 0x07); + } else { + for (i = 0; i < nitems(rtl8192ce_mac); i++) + rtwn_pci_write_1(sc, rtl8192ce_mac[i].reg, + rtl8192ce_mac[i].val); + } } void @@ -1608,7 +1977,8 @@ rtwn_bb_init(void *cookie) R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_DIO_RF); - rtwn_pci_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); + if (!(sc->sc_sc.chip & RTWN_CHIP_88E)) + rtwn_pci_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); rtwn_pci_write_1(sc, R92C_RF_CTRL, R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); @@ -1618,14 +1988,20 @@ rtwn_bb_init(void *cookie) R92C_SYS_FUNC_EN_PPLL | R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); - rtwn_pci_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); + if (!(sc->sc_sc.chip & RTWN_CHIP_88E)) { + rtwn_pci_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); + } rtwn_pci_write_4(sc, R92C_LEDCFG0, rtwn_pci_read_4(sc, R92C_LEDCFG0) | 0x00800000); - /* Select BB programming. */ - prog = (sc->sc_sc.chip & RTWN_CHIP_92C) ? - &rtl8192ce_bb_prog_2t : &rtl8192ce_bb_prog_1t; + /* Select BB programming. */ + if (sc->sc_sc.chip & RTWN_CHIP_88E) + prog = &rtl8188eu_bb_prog; + else if (!(sc->sc_sc.chip & RTWN_CHIP_92C)) + prog = &rtl8192ce_bb_prog_1t; + else + prog = &rtl8192ce_bb_prog_2t; /* Write BB initialization values. */ for (i = 0; i < prog->count; i++) { |