Another step on the long road towards merging these drivers.

Copy r88e support code into ic/rtwn.c. This can't be tested until the
USB driver starts making use of the shared rtwn.c file, but it's pretty
straightforward.

It turns out some functions won't benefit a lot from merging, mostly
where register access patterns differ between PCI and USB drivers.
Put them back into the PCI part of the driver. There's still some
overlap that could be partly avoided, but let's deal with that later.

No regressions in rtwn(4) as far as I can see.

ok?

Index: ic/rtwn.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/rtwn.c,v
retrieving revision 1.7
diff -u -p -r1.7 rtwn.c
--- ic/rtwn.c   13 Apr 2016 10:49:26 -0000      1.7
+++ ic/rtwn.c   4 Jun 2016 17:32:12 -0000
@@ -51,10 +51,6 @@
 #include <net80211/ieee80211_var.h>
 #include <net80211/ieee80211_radiotap.h>
 
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pcidevs.h>
-
 #include <dev/ic/r92creg.h>
 #include <dev/ic/rtwnvar.h>
 
@@ -84,10 +80,16 @@ uint32_t    rtwn_rf_read(struct rtwn_softc 
 void           rtwn_cam_write(struct rtwn_softc *, uint32_t, uint32_t);
 uint8_t                rtwn_efuse_read_1(struct rtwn_softc *, uint16_t);
 void           rtwn_efuse_read(struct rtwn_softc *);
+void           rtwn_efuse_switch_power(struct rtwn_softc *);
 int            rtwn_read_chipid(struct rtwn_softc *, uint32_t);
 void           rtwn_read_rom(struct rtwn_softc *);
+void           rtwn_r88e_read_rom(struct rtwn_softc *);
 int            rtwn_media_change(struct ifnet *);
 int            rtwn_ra_init(struct rtwn_softc *);
+int            rtwn_r92c_ra_init(struct rtwn_softc *, u_int8_t, u_int32_t,
+                   int, uint32_t, int);
+int            rtwn_r88e_ra_init(struct rtwn_softc *, u_int8_t, u_int32_t,
+                   int, uint32_t, int);
 void           rtwn_tsf_sync_enable(struct rtwn_softc *);
 void           rtwn_set_led(struct rtwn_softc *, int, int);
 int            rtwn_newstate(struct ieee80211com *, enum ieee80211_state, int);
@@ -97,16 +99,14 @@ int         rtwn_set_key(struct ieee80211com *,
 void           rtwn_delete_key(struct ieee80211com *,
                    struct ieee80211_node *, struct ieee80211_key *);
 void           rtwn_update_avgrssi(struct rtwn_softc *, int, int8_t);
-int8_t         rtwn_get_rssi(struct rtwn_softc *, int, void *);
+int8_t         rtwn_r88e_get_rssi(struct rtwn_softc *, int, void *);
 void           rtwn_start(struct ifnet *);
 void           rtwn_watchdog(struct ifnet *);
 int            rtwn_ioctl(struct ifnet *, u_long, caddr_t);
-int            rtwn_power_on(struct rtwn_softc *);
 void           rtwn_fw_reset(struct rtwn_softc *);
+void           rtwn_r88e_fw_reset(struct rtwn_softc *);
 int            rtwn_fw_loadpage(struct rtwn_softc *, int, uint8_t *, int);
 int            rtwn_load_firmware(struct rtwn_softc *);
-void           rtwn_mac_init(struct rtwn_softc *);
-void           rtwn_bb_init(struct rtwn_softc *);
 void           rtwn_rf_init(struct rtwn_softc *);
 void           rtwn_cam_init(struct rtwn_softc *);
 void           rtwn_pa_bias_init(struct rtwn_softc *);
@@ -116,6 +116,9 @@ void                rtwn_write_txpower(struct rtwn_sof
 void           rtwn_get_txpower(struct rtwn_softc *, int,
                    struct ieee80211_channel *, struct ieee80211_channel *,
                    uint16_t[]);
+void           rtwn_r88e_get_txpower(struct rtwn_softc *, int,
+                   struct ieee80211_channel *,
+                   struct ieee80211_channel *, uint16_t[]);
 void           rtwn_set_txpower(struct rtwn_softc *,
                    struct ieee80211_channel *, struct ieee80211_channel *);
 void           rtwn_set_chan(struct rtwn_softc *,
@@ -168,11 +171,17 @@ rtwn_attach(struct device *pdev, struct 
                sc->ntxchains = 1;
                sc->nrxchains = 1;
        }
-       rtwn_read_rom(sc);
+
+       if (sc->chip & RTWN_CHIP_88E)
+               rtwn_r88e_read_rom(sc);
+       else
+               rtwn_read_rom(sc);
 
        printf("%s: MAC/BB RTL%s, RF 6052 %dT%dR, address %s\n",
            sc->sc_pdev->dv_xname,
-           (sc->chip & RTWN_CHIP_92C) ? "8192CE" : "8188CE",
+           (sc->chip & RTWN_CHIP_92C) ? "8192CE" :
+           (sc->chip & RTWN_CHIP_88E) ? "8188EE" :
+           "8188CE",
            sc->ntxchains, sc->nrxchains,
            ether_sprintf(ic->ic_myaddr));
 
@@ -358,9 +367,15 @@ rtwn_fw_cmd(struct rtwn_softc *sc, uint8
 void
 rtwn_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t val)
 {
+       uint32_t param_addr;
+
+       if (sc->chip & RTWN_CHIP_88E)
+               param_addr = SM(R88E_LSSI_PARAM_ADDR, addr);
+       else
+               param_addr = SM(R92C_LSSI_PARAM_ADDR, addr);
+
        rtwn_bb_write(sc, R92C_LSSI_PARAM(chain),
-           SM(R92C_LSSI_PARAM_ADDR, addr) |
-           SM(R92C_LSSI_PARAM_DATA, val));
+           param_addr | SM(R92C_LSSI_PARAM_DATA, val));
 }
 
 uint32_t
@@ -432,22 +447,8 @@ rtwn_efuse_read(struct rtwn_softc *sc)
        uint8_t off, msk;
        int i;
 
-       reg = rtwn_read_2(sc, R92C_SYS_ISO_CTRL);
-       if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) {
-               rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
-                   reg | R92C_SYS_ISO_CTRL_PWC_EV12V);
-       }
-       reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
-       if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
-               rtwn_write_2(sc, R92C_SYS_FUNC_EN,
-                   reg | R92C_SYS_FUNC_EN_ELDR);
-       }
-       reg = rtwn_read_2(sc, R92C_SYS_CLKR);
-       if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
-           (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
-               rtwn_write_2(sc, R92C_SYS_CLKR,
-                   reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
-       }
+       rtwn_efuse_switch_power(sc);
+
        memset(&sc->rom, 0xff, sizeof(sc->rom));
        while (addr < 512) {
                reg = rtwn_efuse_read_1(sc, addr);
@@ -478,11 +479,37 @@ rtwn_efuse_read(struct rtwn_softc *sc)
 #endif
 }
 
+void
+rtwn_efuse_switch_power(struct rtwn_softc *sc)
+{
+       uint16_t reg;
+
+       reg = rtwn_read_2(sc, R92C_SYS_ISO_CTRL);
+       if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) {
+               rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
+                   reg | R92C_SYS_ISO_CTRL_PWC_EV12V);
+       }
+       reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
+       if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
+               rtwn_write_2(sc, R92C_SYS_FUNC_EN,
+                   reg | R92C_SYS_FUNC_EN_ELDR);
+       }
+       reg = rtwn_read_2(sc, R92C_SYS_CLKR);
+       if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
+           (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
+               rtwn_write_2(sc, R92C_SYS_CLKR,
+                   reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
+       }
+}
+
 int
 rtwn_read_chipid(struct rtwn_softc *sc, uint32_t chip_type)
 {
        uint32_t reg;
 
+       if (sc->chip & RTWN_CHIP_88E)
+               return (0);
+
        reg = rtwn_read_4(sc, R92C_SYS_CFG);
        if (reg & R92C_SYS_CFG_TRP_VAUX_EN)
                /* Unsupported test chip. */
@@ -527,6 +554,7 @@ rtwn_read_rom(struct rtwn_softc *sc)
        DPRINTF(("PA setting=0x%x\n", sc->pa_setting));
 
        sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE);
+       DPRINTF(("board type=%d\n", sc->board_type));
 
        sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY);
        DPRINTF(("regulatory type=%d\n", sc->regulatory));
@@ -534,6 +562,66 @@ rtwn_read_rom(struct rtwn_softc *sc)
        IEEE80211_ADDR_COPY(ic->ic_myaddr, rom->macaddr);
 }
 
+void
+rtwn_r88e_read_rom(struct rtwn_softc *sc)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       uint8_t *rom = sc->r88e_rom;
+       uint16_t addr = 0;
+       uint32_t reg;
+       uint8_t off, msk, tmp;
+       int i;
+
+       off = 0;
+
+       rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON);
+       rtwn_efuse_switch_power(sc);
+
+       /* Read full ROM image. */
+       memset(&sc->r88e_rom, 0xff, sizeof(sc->r88e_rom));
+       while (addr < 512) {
+               reg = rtwn_efuse_read_1(sc, addr);
+               if (reg == 0xff)
+                       break;
+               addr++;
+               if ((reg & 0x1f) == 0x0f) {
+                       tmp = (reg & 0xe0) >> 5;
+                       reg = rtwn_efuse_read_1(sc, addr);
+                       if ((reg & 0x0f) != 0x0f)
+                               off = ((reg & 0xf0) >> 1) | tmp;
+                       addr++;
+               } else
+                       off = reg >> 4;
+               msk = reg & 0xf;
+               for (i = 0; i < 4; i++) {
+                       if (msk & (1 << i))
+                               continue;
+                       rom[off * 8 + i * 2 + 0] =
+                           rtwn_efuse_read_1(sc, addr);
+                       addr++;
+                       rom[off * 8 + i * 2 + 1] =
+                           rtwn_efuse_read_1(sc, addr);
+                       addr++;
+               }
+       }
+
+       rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF);
+
+       addr = 0x10;
+       for (i = 0; i < 6; i++)
+               sc->cck_tx_pwr[i] = sc->r88e_rom[addr++];
+       for (i = 0; i < 5; i++)
+               sc->ht40_tx_pwr[i] = sc->r88e_rom[addr++];
+       sc->bw20_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf0) >> 4;
+       if (sc->bw20_tx_pwr_diff & 0x08)
+               sc->bw20_tx_pwr_diff |= 0xf0;
+       sc->ofdm_tx_pwr_diff = (sc->r88e_rom[addr] & 0xf);
+       if (sc->ofdm_tx_pwr_diff & 0x08)
+               sc->ofdm_tx_pwr_diff |= 0xf0;
+       sc->regulatory = MS(sc->r88e_rom[0xc1], R92C_ROM_RF1_REGULATORY);
+       IEEE80211_ADDR_COPY(ic->ic_myaddr, &sc->r88e_rom[0xd7]);
+}
+
 int
 rtwn_media_change(struct ifnet *ifp)
 {
@@ -562,7 +650,6 @@ rtwn_ra_init(struct rtwn_softc *sc)
        struct ieee80211com *ic = &sc->sc_ic;
        struct ieee80211_node *ni = ic->ic_bss;
        struct ieee80211_rateset *rs = &ni->ni_rates;
-       struct r92c_fw_cmd_macid_cfg cmd;
        uint32_t rates, basicrates;
        uint8_t mode;
        int maxrate, maxbasicrate, error, i, j;
@@ -593,6 +680,33 @@ rtwn_ra_init(struct rtwn_softc *sc)
        DPRINTF(("mode=0x%x rates=0x%08x, basicrates=0x%08x\n",
            mode, rates, basicrates));
 
+       /* Configure Automatic Rate Fallback Register. */
+       if (ic->ic_curmode == IEEE80211_MODE_11B) {
+               if (rates & 0x0c)
+                       rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0d));
+               else
+                       rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0f));
+       } else
+               rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0ff5));
+
+       if (sc->chip & RTWN_CHIP_88E)
+               error = rtwn_r88e_ra_init(sc, mode, rates, maxrate,
+                   basicrates, maxbasicrate);
+       else
+               error = rtwn_r92c_ra_init(sc, mode, rates, maxrate,
+                   basicrates, maxbasicrate);
+
+       /* Indicate highest supported rate. */
+       ni->ni_txrate = rs->rs_nrates - 1;
+       return (error);
+}
+
+int rtwn_r92c_ra_init(struct rtwn_softc *sc, u_int8_t mode, u_int32_t rates,
+    int maxrate, uint32_t basicrates, int maxbasicrate)
+{
+       struct r92c_fw_cmd_macid_cfg cmd;
+       int error;
+
        /* Set rates mask for group addressed frames. */
        cmd.macid = R92C_MACID_BC | R92C_MACID_VALID;
        cmd.mask = htole32(mode << 28 | basicrates);
@@ -621,17 +735,28 @@ rtwn_ra_init(struct rtwn_softc *sc)
        rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(R92C_MACID_BSS),
            maxrate);
 
-       /* Configure Automatic Rate Fallback Register. */
-       if (ic->ic_curmode == IEEE80211_MODE_11B) {
-               if (rates & 0x0c)
-                       rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0d));
-               else
-                       rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0f));
-       } else
-               rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0ff5));
+       return (0);
+}
+
+int
+rtwn_r88e_ra_init(struct rtwn_softc *sc, u_int8_t mode, u_int32_t rates,
+    int maxrate, uint32_t basicrates, int maxbasicrate)
+{
+       u_int32_t reg;
+
+       rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, maxbasicrate);
+
+       reg = rtwn_read_4(sc, R92C_RRSR);
+       reg = RW(reg, R92C_RRSR_RATE_BITMAP, rates);
+       rtwn_write_4(sc, R92C_RRSR, reg);
+
+       /*
+        * Workaround for performance problems with firmware rate adaptation:
+        * If the AP only supports 11b rates, disable mixed B/G mode.
+        */
+       if (mode != R92C_RAID_11B && maxrate <= 3 /* 11M */)
+               sc->sc_flags |= RTWN_FLAG_FORCE_RAID_11B;
 
-       /* Indicate highest supported rate. */
-       ni->ni_txrate = rs->rs_nrates - 1;
        return (0);
 }
 
@@ -753,6 +878,9 @@ rtwn_newstate(struct ieee80211com *ic, e
                rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317);
                rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320);
                rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444);
+
+               /* Disable 11b-only AP workaround (see rtwn_r88e_ra_init). */
+               sc->sc_flags &= ~RTWN_FLAG_FORCE_RAID_11B;
        }
        switch (nstate) {
        case IEEE80211_S_INIT:
@@ -1023,6 +1151,9 @@ rtwn_get_rssi(struct rtwn_softc *sc, int
        uint8_t rpt;
        int8_t rssi;
 
+       if (sc->chip & RTWN_CHIP_88E)
+               return rtwn_r88e_get_rssi(sc, rate, physt);
+
        if (rate <= 3) {
                cck = (struct r92c_rx_cck *)physt;
                if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) {
@@ -1040,6 +1171,57 @@ rtwn_get_rssi(struct rtwn_softc *sc, int
        return (rssi);
 }
 
+int8_t
+rtwn_r88e_get_rssi(struct rtwn_softc *sc, int rate, void *physt)
+{
+       struct r92c_rx_phystat *phy;
+       struct r88e_rx_cck *cck;
+       uint8_t cck_agc_rpt, lna_idx, vga_idx;
+       int8_t rssi;
+
+       rssi = 0;
+       if (rate <= 3) {
+               cck = (struct r88e_rx_cck *)physt;
+               cck_agc_rpt = cck->agc_rpt;
+               lna_idx = (cck_agc_rpt & 0xe0) >> 5;
+               vga_idx = cck_agc_rpt & 0x1f; 
+               switch (lna_idx) {
+               case 7:
+                       if (vga_idx <= 27)
+                               rssi = -100 + 2* (27 - vga_idx);
+                       else
+                               rssi = -100;
+                       break;
+               case 6:
+                       rssi = -48 + 2 * (2 - vga_idx);
+                       break;
+               case 5:
+                       rssi = -42 + 2 * (7 - vga_idx);
+                       break;
+               case 4:
+                       rssi = -36 + 2 * (7 - vga_idx);
+                       break;
+               case 3:
+                       rssi = -24 + 2 * (7 - vga_idx);
+                       break;
+               case 2:
+                       rssi = -12 + 2 * (5 - vga_idx);
+                       break;
+               case 1:
+                       rssi = 8 - (2 * vga_idx);
+                       break;
+               case 0:
+                       rssi = 14 - (2 * vga_idx);
+                       break;
+               }
+               rssi += 6;
+       } else {        /* OFDM/HT. */
+               phy = (struct r92c_rx_phystat *)physt;
+               rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110;
+       }
+       return (rssi);
+}
+
 void
 rtwn_start(struct ifnet *ifp)
 {
@@ -1182,136 +1364,6 @@ rtwn_ioctl(struct ifnet *ifp, u_long cmd
        return (error);
 }
 
-int
-rtwn_power_on(struct rtwn_softc *sc)
-{
-       uint32_t reg;
-       int ntries;
-
-       /* Wait for autoload done bit. */
-       for (ntries = 0; ntries < 1000; ntries++) {
-               if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN)
-                       break;
-               DELAY(5);
-       }
-       if (ntries == 1000) {
-               printf("%s: timeout waiting for chip autoload\n",
-                   sc->sc_pdev->dv_xname);
-               return (ETIMEDOUT);
-       }
-
-       /* Unlock ISO/CLK/Power control register. */
-       rtwn_write_1(sc, R92C_RSV_CTRL, 0);
-
-       /* TODO: check if we need this for 8188CE */
-       if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
-               /* bt coex */
-               reg = rtwn_read_4(sc, R92C_APS_FSMCO);
-               reg |= (R92C_APS_FSMCO_SOP_ABG |
-                       R92C_APS_FSMCO_SOP_AMB |
-                       R92C_APS_FSMCO_XOP_BTCK);
-               rtwn_write_4(sc, R92C_APS_FSMCO, reg);
-       }
-
-       /* Move SPS into PWM mode. */
-       rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b);
-
-       /* Set low byte to 0x0f, leave others unchanged. */
-       rtwn_write_4(sc, R92C_AFE_XTAL_CTRL,
-           (rtwn_read_4(sc, R92C_AFE_XTAL_CTRL) & 0xffffff00) | 0x0f);
-
-       /* TODO: check if we need this for 8188CE */
-       if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
-               /* bt coex */
-               reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL);
-               reg &= (~0x00024800); /* XXX magic from linux */
-               rtwn_write_4(sc, R92C_AFE_XTAL_CTRL, reg);
-       }
-
-       rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
-         (rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & 0xff) |
-         R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR);
-       DELAY(200);
-
-       /* TODO: linux does additional btcoex stuff here */
-
-       /* Auto enable WLAN. */
-       rtwn_write_2(sc, R92C_APS_FSMCO,
-           rtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC);
-       for (ntries = 0; ntries < 1000; ntries++) {
-               if (!(rtwn_read_2(sc, R92C_APS_FSMCO) &
-                   R92C_APS_FSMCO_APFM_ONMAC))
-                       break;
-               DELAY(5);
-       }
-       if (ntries == 1000) {
-               printf("%s: timeout waiting for MAC auto ON\n",
-                   sc->sc_pdev->dv_xname);
-               return (ETIMEDOUT);
-       }
-
-       /* Enable radio, GPIO and LED functions. */
-       rtwn_write_2(sc, R92C_APS_FSMCO,
-           R92C_APS_FSMCO_AFSM_PCIE |
-           R92C_APS_FSMCO_PDN_EN |
-           R92C_APS_FSMCO_PFM_ALDN);
-       /* Release RF digital isolation. */
-       rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
-           rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR);
-
-       if (sc->chip & RTWN_CHIP_92C)
-               rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x77);
-       else
-               rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x22);
-
-       rtwn_write_4(sc, R92C_INT_MIG, 0);
-
-       if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
-               /* bt coex */
-               reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL + 2);
-               reg &= 0xfd; /* XXX magic from linux */
-               rtwn_write_4(sc, R92C_AFE_XTAL_CTRL + 2, reg);
-       }
-
-       rtwn_write_1(sc, R92C_GPIO_MUXCFG,
-           rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_RFKILL);
-
-       reg = rtwn_read_1(sc, R92C_GPIO_IO_SEL);
-       if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) {
-               printf("%s: radio is disabled by hardware switch\n",
-                   sc->sc_pdev->dv_xname);
-               return (EPERM); /* :-) */
-       }
-
-       /* Initialize MAC. */
-       reg = rtwn_read_1(sc, R92C_APSD_CTRL);
-       rtwn_write_1(sc, R92C_APSD_CTRL,
-           rtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF);
-       for (ntries = 0; ntries < 200; ntries++) {
-               if (!(rtwn_read_1(sc, R92C_APSD_CTRL) &
-                   R92C_APSD_CTRL_OFF_STATUS))
-                       break;
-               DELAY(500);
-       }
-       if (ntries == 200) {
-               printf("%s: timeout waiting for MAC initialization\n",
-                   sc->sc_pdev->dv_xname);
-               return (ETIMEDOUT);
-       }
-
-       /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
-       reg = rtwn_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_write_2(sc, R92C_CR, reg);
-
-       rtwn_write_1(sc, 0xfe10, 0x19);
-
-       return (0);
-}
-
 void
 rtwn_fw_reset(struct rtwn_softc *sc)
 {
@@ -1338,6 +1390,16 @@ sleep:
        tsleep(&reg, 0, "rtwnrst", hz);
 }
 
+void
+rtwn_r88e_fw_reset(struct rtwn_softc *sc)
+{
+       uint16_t reg;
+
+       reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
+       rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN);
+       rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg | R92C_SYS_FUNC_EN_CPUEN);
+}
+
 int
 rtwn_fw_loadpage(struct rtwn_softc *sc, int page, uint8_t *buf, int len)
 {
@@ -1371,23 +1433,15 @@ int
 rtwn_load_firmware(struct rtwn_softc *sc)
 {
        const struct r92c_fw_hdr *hdr;
-       const char *name;
        u_char *fw, *ptr;
        size_t len;
        uint32_t reg;
        int mlen, ntries, page, error;
 
        /* Read firmware image from the filesystem. */
-       if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) ==
-           RTWN_CHIP_UMC_A_CUT)
-               name = "rtwn-rtl8192cfwU";
-       else
-               name = "rtwn-rtl8192cfwU_B";
-       if ((error = loadfirmware(name, &fw, &len)) != 0) {
-               printf("%s: could not read firmware %s (error %d)\n",
-                   sc->sc_pdev->dv_xname, name, error);
+       error = sc->sc_ops.load_firmware(sc->sc_ops.cookie, &fw, &len);
+       if (error)
                return (error);
-       }
        if (len < sizeof(*hdr)) {
                printf("%s: firmware too short\n", sc->sc_pdev->dv_xname);
                error = EINVAL;
@@ -1397,6 +1451,7 @@ rtwn_load_firmware(struct rtwn_softc *sc
        hdr = (const struct r92c_fw_hdr *)ptr;
        /* Check if there is a valid FW header and skip it. */
        if ((letoh16(hdr->signature) >> 4) == 0x88c ||
+           (letoh16(hdr->signature) >> 4) == 0x88e ||
            (letoh16(hdr->signature) >> 4) == 0x92c) {
                DPRINTF(("FW V%d.%d %02d-%02d %02d:%02d\n",
                    letoh16(hdr->version), letoh16(hdr->subversion),
@@ -1405,13 +1460,19 @@ rtwn_load_firmware(struct rtwn_softc *sc
                len -= sizeof(*hdr);
        }
 
-       if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
-               rtwn_fw_reset(sc);
+       if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) {
+               if (sc->chip & RTWN_CHIP_88E)
+                       rtwn_r88e_fw_reset(sc);
+               else
+                       rtwn_fw_reset(sc);
+       }
 
        /* Enable FW download. */
-       rtwn_write_2(sc, R92C_SYS_FUNC_EN,
-           rtwn_read_2(sc, R92C_SYS_FUNC_EN) |
-           R92C_SYS_FUNC_EN_CPUEN);
+       if (!(sc->chip & RTWN_CHIP_88E))
+               rtwn_write_2(sc, R92C_SYS_FUNC_EN,
+                   rtwn_read_2(sc, R92C_SYS_FUNC_EN) |
+                   R92C_SYS_FUNC_EN_CPUEN);
+
        rtwn_write_1(sc, R92C_MCUFWDL,
            rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN);
        rtwn_write_1(sc, R92C_MCUFWDL + 2,
@@ -1454,11 +1515,13 @@ rtwn_load_firmware(struct rtwn_softc *sc
        reg = rtwn_read_4(sc, R92C_MCUFWDL);
        reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY;
        rtwn_write_4(sc, R92C_MCUFWDL, reg);
+       if (sc->chip & RTWN_CHIP_88E)
+               rtwn_r88e_fw_reset(sc);
        /* Wait for firmware readiness. */
        for (ntries = 0; ntries < 1000; ntries++) {
                if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY)
                        break;
-               DELAY(5);
+               DELAY(10);
        }
        if (ntries == 1000) {
                printf("%s: timeout waiting for firmware readiness\n",
@@ -1472,105 +1535,6 @@ rtwn_load_firmware(struct rtwn_softc *sc
 }
 
 void
-rtwn_mac_init(struct rtwn_softc *sc)
-{
-       int i;
-
-       /* Write MAC initialization values. */
-       for (i = 0; i < nitems(rtl8192ce_mac); i++)
-               rtwn_write_1(sc, rtl8192ce_mac[i].reg, rtl8192ce_mac[i].val);
-}
-
-void
-rtwn_bb_init(struct rtwn_softc *sc)
-{
-       const struct r92c_bb_prog *prog;
-       uint32_t reg;
-       int i;
-
-       /* Enable BB and RF. */
-       rtwn_write_2(sc, R92C_SYS_FUNC_EN,
-           rtwn_read_2(sc, R92C_SYS_FUNC_EN) |
-           R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST |
-           R92C_SYS_FUNC_EN_DIO_RF);
-
-       rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83);
-
-       rtwn_write_1(sc, R92C_RF_CTRL,
-           R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
-
-       rtwn_write_1(sc, R92C_SYS_FUNC_EN,
-           R92C_SYS_FUNC_EN_DIO_PCIE | R92C_SYS_FUNC_EN_PCIEA |
-           R92C_SYS_FUNC_EN_PPLL | R92C_SYS_FUNC_EN_BB_GLB_RST |
-           R92C_SYS_FUNC_EN_BBRSTB);
-
-       rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80);
-
-       rtwn_write_4(sc, R92C_LEDCFG0,
-           rtwn_read_4(sc, R92C_LEDCFG0) | 0x00800000);
-
-       /* Select BB programming. */ 
-       prog = (sc->chip & RTWN_CHIP_92C) ?
-           &rtl8192ce_bb_prog_2t : &rtl8192ce_bb_prog_1t;
-
-       /* Write BB initialization values. */
-       for (i = 0; i < prog->count; i++) {
-               rtwn_bb_write(sc, prog->regs[i], prog->vals[i]);
-               DELAY(1);
-       }
-
-       if (sc->chip & RTWN_CHIP_92C_1T2R) {
-               /* 8192C 1T only configuration. */
-               reg = rtwn_bb_read(sc, R92C_FPGA0_TXINFO);
-               reg = (reg & ~0x00000003) | 0x2;
-               rtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg);
-
-               reg = rtwn_bb_read(sc, R92C_FPGA1_TXINFO);
-               reg = (reg & ~0x00300033) | 0x00200022;
-               rtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg);
-
-               reg = rtwn_bb_read(sc, R92C_CCK0_AFESETTING);
-               reg = (reg & ~0xff000000) | 0x45 << 24;
-               rtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg);
-
-               reg = rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
-               reg = (reg & ~0x000000ff) | 0x23;
-               rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg);
-
-               reg = rtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1);
-               reg = (reg & ~0x00000030) | 1 << 4;
-               rtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg);
-
-               reg = rtwn_bb_read(sc, 0xe74);
-               reg = (reg & ~0x0c000000) | 2 << 26;
-               rtwn_bb_write(sc, 0xe74, reg);
-               reg = rtwn_bb_read(sc, 0xe78);
-               reg = (reg & ~0x0c000000) | 2 << 26;
-               rtwn_bb_write(sc, 0xe78, reg);
-               reg = rtwn_bb_read(sc, 0xe7c);
-               reg = (reg & ~0x0c000000) | 2 << 26;
-               rtwn_bb_write(sc, 0xe7c, reg);
-               reg = rtwn_bb_read(sc, 0xe80);
-               reg = (reg & ~0x0c000000) | 2 << 26;
-               rtwn_bb_write(sc, 0xe80, reg);
-               reg = rtwn_bb_read(sc, 0xe88);
-               reg = (reg & ~0x0c000000) | 2 << 26;
-               rtwn_bb_write(sc, 0xe88, reg);
-       }
-
-       /* Write AGC values. */
-       for (i = 0; i < prog->agccount; i++) {
-               rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE,
-                   prog->agcvals[i]);
-               DELAY(1);
-       }
-
-       if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) &
-           R92C_HSSI_PARAM2_CCK_HIPWR)
-               sc->sc_flags |= RTWN_FLAG_CCK_HIPWR;
-}
-
-void
 rtwn_rf_init(struct rtwn_softc *sc)
 {
        const struct r92c_rf_prog *prog;
@@ -1578,7 +1542,9 @@ rtwn_rf_init(struct rtwn_softc *sc)
        int i, j, idx, off;
 
        /* Select RF programming based on board type. */
-       if (!(sc->chip & RTWN_CHIP_92C)) {
+       if (sc->chip & RTWN_CHIP_88E)
+               prog = rtl8188eu_rf_prog;
+       else if (!(sc->chip & RTWN_CHIP_92C)) {
                if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
                        prog = rtl8188ce_rf_prog;
                else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
@@ -1869,6 +1835,75 @@ rtwn_get_txpower(struct rtwn_softc *sc, 
 }
 
 void
+rtwn_r88e_get_txpower(struct rtwn_softc *sc, int chain,
+    struct ieee80211_channel *c, struct ieee80211_channel *extc,
+    uint16_t power[RTWN_RIDX_COUNT])
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       uint16_t cckpow, ofdmpow, bw20pow, htpow;
+       const struct r88e_txpwr *base;
+       int ridx, chan, group;
+
+       /* Determine channel group. */
+       chan = ieee80211_chan2ieee(ic, c);      /* XXX center freq! */
+       if (chan <= 2)
+               group = 0;
+       else if (chan <= 5)
+               group = 1;
+       else if (chan <= 8)
+               group = 2;
+       else if (chan <= 11)
+               group = 3;
+       else if (chan <= 13)
+               group = 4;
+       else
+               group = 5;
+
+       /* Get original Tx power based on board type and RF chain. */
+       base = &rtl8188eu_txagc[chain];
+
+       memset(power, 0, RTWN_RIDX_COUNT * sizeof(power[0]));
+       if (sc->regulatory == 0) {
+               for (ridx = 0; ridx <= 3; ridx++)
+                       power[ridx] = base->pwr[0][ridx];
+       }
+       for (ridx = 4; ridx < RTWN_RIDX_COUNT; ridx++) {
+               if (sc->regulatory == 3)
+                       power[ridx] = base->pwr[0][ridx];
+               else if (sc->regulatory == 1) {
+                       if (extc == NULL)
+                               power[ridx] = base->pwr[group][ridx];
+               } else if (sc->regulatory != 2)
+                       power[ridx] = base->pwr[0][ridx];
+       }
+
+       /* Compute per-CCK rate Tx power. */
+       cckpow = sc->cck_tx_pwr[group];
+       for (ridx = 0; ridx <= 3; ridx++) {
+               power[ridx] += cckpow;
+               if (power[ridx] > R92C_MAX_TX_PWR)
+                       power[ridx] = R92C_MAX_TX_PWR;
+       }
+
+       htpow = sc->ht40_tx_pwr[group];
+
+       /* Compute per-OFDM rate Tx power. */
+       ofdmpow = htpow + sc->ofdm_tx_pwr_diff;
+       for (ridx = 4; ridx <= 11; ridx++) {
+               power[ridx] += ofdmpow;
+               if (power[ridx] > R92C_MAX_TX_PWR)
+                       power[ridx] = R92C_MAX_TX_PWR;
+       }
+
+       bw20pow = htpow + sc->bw20_tx_pwr_diff;
+       for (ridx = 12; ridx <= 27; ridx++) {
+               power[ridx] += bw20pow;
+               if (power[ridx] > R92C_MAX_TX_PWR)
+                       power[ridx] = R92C_MAX_TX_PWR;
+       }
+}
+
+void
 rtwn_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c,
     struct ieee80211_channel *extc)
 {
@@ -1877,7 +1912,10 @@ rtwn_set_txpower(struct rtwn_softc *sc, 
 
        for (i = 0; i < sc->ntxchains; i++) {
                /* Compute per-rate Tx power values. */
-               rtwn_get_txpower(sc, i, c, extc, power);
+               if (sc->chip & RTWN_CHIP_88E)
+                       rtwn_r88e_get_txpower(sc, i, c, extc, power);
+               else
+                       rtwn_get_txpower(sc, i, c, extc, power);
                /* Write per-rate Tx power values to hardware. */
                rtwn_write_txpower(sc, i, power);
        }
@@ -2382,7 +2420,7 @@ rtwn_init(struct ifnet *ifp)
        sc->fwcur = 0;
 
        /* Power on adapter. */
-       error = rtwn_power_on(sc);
+       error = sc->sc_ops.power_on(sc->sc_ops.cookie);
        if (error != 0) {
                printf("%s: could not power on adapter\n",
                    sc->sc_pdev->dv_xname);
@@ -2460,8 +2498,8 @@ rtwn_init(struct ifnet *ifp)
                goto fail;
 
        /* Initialize MAC/BB/RF blocks. */
-       rtwn_mac_init(sc);
-       rtwn_bb_init(sc);
+       sc->sc_ops.mac_init(sc->sc_ops.cookie);
+       sc->sc_ops.bb_init(sc->sc_ops.cookie);
        rtwn_rf_init(sc);
 
        /* Turn CCK and OFDM blocks on. */
Index: ic/rtwnvar.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/rtwnvar.h,v
retrieving revision 1.5
diff -u -p -r1.5 rtwnvar.h
--- ic/rtwnvar.h        21 Mar 2016 12:00:32 -0000      1.5
+++ ic/rtwnvar.h        4 Jun 2016 17:19:16 -0000
@@ -28,7 +28,11 @@ struct rtwn_ops {
        void            (*write_2)(void *, uint16_t, uint16_t);
        void            (*write_4)(void *, uint16_t, uint32_t);
        int             (*tx)(void *, struct mbuf *, struct ieee80211_node *);
+       int             (*power_on)(void *);
        int             (*dma_init)(void *);
+       int             (*load_firmware)(void *, u_char **fw, size_t *);
+       void            (*mac_init)(void *);
+       void            (*bb_init)(void *);
        void            (*enable_intr)(void *);
        void            (*disable_intr)(void *);
        void            (*stop)(void *);
@@ -50,8 +54,9 @@ struct rtwn_softc {
        struct task                     init_task;
        int                             ac2idx[EDCA_NUM_AC];
        uint32_t                        sc_flags;
-#define RTWN_FLAG_CCK_HIPWR    0x01
-#define RTWN_FLAG_BUSY         0x02
+#define RTWN_FLAG_CCK_HIPWR            0x01
+#define RTWN_FLAG_BUSY                 0x02
+#define RTWN_FLAG_FORCE_RAID_11B       0x04
 
        uint32_t                chip;
 #define RTWN_CHIP_92C          0x01
@@ -74,6 +79,12 @@ struct rtwn_softc {
        int                             sc_tx_timer;
        int                             fwcur;
        struct r92c_rom                 rom;
+
+       uint8_t                         r88e_rom[512];
+       uint8_t                         cck_tx_pwr[6];
+       uint8_t                         ht40_tx_pwr[5];
+       int8_t                          bw20_tx_pwr_diff;
+       int8_t                          ofdm_tx_pwr_diff;
 
        uint32_t                        rf_chnlbw[R92C_MAX_CHAINS];
 };
Index: pci/if_rtwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_rtwn.c,v
retrieving revision 1.20
diff -u -p -r1.20 if_rtwn.c
--- pci/if_rtwn.c       21 Mar 2016 12:00:32 -0000      1.20
+++ pci/if_rtwn.c       4 Jun 2016 17:20:56 -0000
@@ -229,9 +229,13 @@ void               rtwn_tx_done(struct rtwn_pci_softc
 void           rtwn_pci_stop(void *);
 int            rtwn_intr(void *);
 int            rtwn_is_oactive(void *);
+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_dma_init(void *);
+int            rtwn_pci_load_firmware(void *, u_char **, size_t *);
+void           rtwn_mac_init(void *);
+void           rtwn_bb_init(void *);
 void           rtwn_enable_intr(void *);
 void           rtwn_disable_intr(void *);
 void           rtwn_calib_to(void *);
@@ -241,6 +245,10 @@ void               rtwn_scan_to(void *);
 void           rtwn_pci_next_scan(void *);
 void           rtwn_cancel_scan(void *);
 
+/* Aliases. */
+#define        rtwn_bb_write   rtwn_pci_write_4
+#define rtwn_bb_read   rtwn_pci_read_4
+
 struct cfdriver rtwn_cd = {
        NULL, "rtwn", DV_IFNET
 };
@@ -341,7 +349,11 @@ rtwn_pci_attach(struct device *parent, s
        sc->sc_sc.sc_ops.read_2 = rtwn_pci_read_2;
        sc->sc_sc.sc_ops.read_4 = rtwn_pci_read_4;
        sc->sc_sc.sc_ops.tx = rtwn_tx;
+       sc->sc_sc.sc_ops.power_on = rtwn_power_on;
        sc->sc_sc.sc_ops.dma_init = rtwn_dma_init;
+       sc->sc_sc.sc_ops.load_firmware = rtwn_pci_load_firmware;
+       sc->sc_sc.sc_ops.mac_init = rtwn_mac_init;
+       sc->sc_sc.sc_ops.bb_init = rtwn_bb_init;
        sc->sc_sc.sc_ops.enable_intr = rtwn_enable_intr;
        sc->sc_sc.sc_ops.disable_intr = rtwn_disable_intr;
        sc->sc_sc.sc_ops.stop = rtwn_pci_stop;
@@ -963,7 +975,8 @@ rtwn_tx(void *cookie, struct mbuf *m, st
        txd->txdw5 = 0;
        if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
            type == IEEE80211_FC0_TYPE_DATA) {
-               if (ic->ic_curmode == IEEE80211_MODE_11B)
+               if (ic->ic_curmode == IEEE80211_MODE_11B ||
+                   (sc->sc_sc.sc_flags & RTWN_FLAG_FORCE_RAID_11B))
                        raid = R92C_RAID_11B;
                else
                        raid = R92C_RAID_11BG;
@@ -1241,6 +1254,139 @@ rtwn_llt_init(struct rtwn_pci_softc *sc)
 }
 
 int
+rtwn_power_on(void *cookie)
+{
+       struct rtwn_pci_softc *sc = cookie;
+       uint32_t reg;
+       int ntries;
+
+       /* Wait for autoload done bit. */
+       for (ntries = 0; ntries < 1000; ntries++) {
+               if (rtwn_pci_read_1(sc, R92C_APS_FSMCO) &
+                   R92C_APS_FSMCO_PFM_ALDN)
+                       break;
+               DELAY(5);
+       }
+       if (ntries == 1000) {
+               printf("%s: timeout waiting for chip autoload\n",
+                   sc->sc_dev.dv_xname);
+               return (ETIMEDOUT);
+       }
+
+       /* Unlock ISO/CLK/Power control register. */
+       rtwn_pci_write_1(sc, R92C_RSV_CTRL, 0);
+
+       /* TODO: check if we need this for 8188CE */
+       if (sc->sc_sc.board_type != R92C_BOARD_TYPE_DONGLE) {
+               /* bt coex */
+               reg = rtwn_pci_read_4(sc, R92C_APS_FSMCO);
+               reg |= (R92C_APS_FSMCO_SOP_ABG |
+                       R92C_APS_FSMCO_SOP_AMB |
+                       R92C_APS_FSMCO_XOP_BTCK);
+               rtwn_pci_write_4(sc, R92C_APS_FSMCO, reg);
+       }
+
+       /* Move SPS into PWM mode. */
+       rtwn_pci_write_1(sc, R92C_SPS0_CTRL, 0x2b);
+       DELAY(100);
+
+       /* Set low byte to 0x0f, leave others unchanged. */
+       rtwn_pci_write_4(sc, R92C_AFE_XTAL_CTRL,
+           (rtwn_pci_read_4(sc, R92C_AFE_XTAL_CTRL) & 0xffffff00) | 0x0f);
+
+       /* TODO: check if we need this for 8188CE */
+       if (sc->sc_sc.board_type != R92C_BOARD_TYPE_DONGLE) {
+               /* bt coex */
+               reg = rtwn_pci_read_4(sc, R92C_AFE_XTAL_CTRL);
+               reg &= (~0x00024800); /* XXX magic from linux */
+               rtwn_pci_write_4(sc, R92C_AFE_XTAL_CTRL, reg);
+       }
+
+       rtwn_pci_write_2(sc, R92C_SYS_ISO_CTRL,
+         (rtwn_pci_read_2(sc, R92C_SYS_ISO_CTRL) & 0xff) |
+         R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR);
+       DELAY(200);
+
+       /* TODO: linux does additional btcoex stuff here */
+
+       /* 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 < 1000; ntries++) {
+               if (!(rtwn_pci_read_2(sc, R92C_APS_FSMCO) &
+                   R92C_APS_FSMCO_APFM_ONMAC))
+                       break;
+               DELAY(5);
+       }
+       if (ntries == 1000) {
+               printf("%s: timeout waiting for MAC auto ON\n",
+                   sc->sc_dev.dv_xname);
+               return (ETIMEDOUT);
+       }
+
+       /* Enable radio, GPIO and LED functions. */
+       rtwn_pci_write_2(sc, R92C_APS_FSMCO,
+           R92C_APS_FSMCO_AFSM_PCIE |
+           R92C_APS_FSMCO_PDN_EN |
+           R92C_APS_FSMCO_PFM_ALDN);
+       /* Release RF digital isolation. */
+       rtwn_pci_write_2(sc, R92C_SYS_ISO_CTRL,
+           rtwn_pci_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR);
+
+       if (sc->sc_sc.chip & RTWN_CHIP_92C)
+               rtwn_pci_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x77);
+       else
+               rtwn_pci_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x22);
+
+       rtwn_pci_write_4(sc, R92C_INT_MIG, 0);
+
+       if (sc->sc_sc.board_type != R92C_BOARD_TYPE_DONGLE) {
+               /* bt coex */
+               reg = rtwn_pci_read_4(sc, R92C_AFE_XTAL_CTRL + 2);
+               reg &= 0xfd; /* XXX magic from linux */
+               rtwn_pci_write_4(sc, R92C_AFE_XTAL_CTRL + 2, reg);
+       }
+
+       rtwn_pci_write_1(sc, R92C_GPIO_MUXCFG,
+           rtwn_pci_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_RFKILL);
+
+       reg = rtwn_pci_read_1(sc, R92C_GPIO_IO_SEL);
+       if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) {
+               printf("%s: radio is disabled by hardware switch\n",
+                   sc->sc_dev.dv_xname);
+               return (EPERM); /* :-) */
+       }
+
+       /* Initialize MAC. */
+       reg = rtwn_pci_read_1(sc, R92C_APSD_CTRL);
+       rtwn_pci_write_1(sc, R92C_APSD_CTRL,
+           rtwn_pci_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF);
+       for (ntries = 0; ntries < 200; ntries++) {
+               if (!(rtwn_pci_read_1(sc, R92C_APSD_CTRL) &
+                   R92C_APSD_CTRL_OFF_STATUS))
+                       break;
+               DELAY(500);
+       }
+       if (ntries == 200) {
+               printf("%s: timeout waiting for MAC initialization\n",
+                   sc->sc_dev.dv_xname);
+               return (ETIMEDOUT);
+       }
+
+       /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
+       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, 0xfe10, 0x19);
+
+       return (0);
+}
+
+int
 rtwn_dma_init(void *cookie)
 {
        struct rtwn_pci_softc *sc = cookie;
@@ -1307,6 +1453,128 @@ rtwn_dma_init(void *cookie)
            SM(R92C_PBP_PSTX, R92C_PBP_128));
 
        return (0);
+}
+
+int
+rtwn_pci_load_firmware(void *cookie, u_char **fw, size_t *len)
+{
+       struct rtwn_pci_softc *sc = cookie;
+       const char *name;
+       int error;
+
+       if ((sc->sc_sc.chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) ==
+           RTWN_CHIP_UMC_A_CUT)
+               name = "rtwn-rtl8192cfwU";
+       else
+               name = "rtwn-rtl8192cfwU_B";
+
+       error = loadfirmware(name, fw, len);
+       if (error)
+               printf("%s: could not read firmware %s (error %d)\n",
+                   sc->sc_dev.dv_xname, name, error);
+       return (error);
+}
+
+void
+rtwn_mac_init(void *cookie)
+{
+       struct rtwn_pci_softc *sc = 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);
+}
+
+void
+rtwn_bb_init(void *cookie)
+{
+       struct rtwn_pci_softc *sc = cookie;
+       const struct r92c_bb_prog *prog;
+       uint32_t reg;
+       int i;
+
+       /* Enable BB and RF. */
+       rtwn_pci_write_2(sc, R92C_SYS_FUNC_EN,
+           rtwn_pci_read_2(sc, R92C_SYS_FUNC_EN) |
+           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);
+
+       rtwn_pci_write_1(sc, R92C_RF_CTRL,
+           R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
+
+       rtwn_pci_write_1(sc, R92C_SYS_FUNC_EN,
+           R92C_SYS_FUNC_EN_DIO_PCIE | R92C_SYS_FUNC_EN_PCIEA |
+           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);
+
+       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;
+
+       /* Write BB initialization values. */
+       for (i = 0; i < prog->count; i++) {
+               rtwn_bb_write(sc, prog->regs[i], prog->vals[i]);
+               DELAY(1);
+       }
+
+       if (sc->sc_sc.chip & RTWN_CHIP_92C_1T2R) {
+               /* 8192C 1T only configuration. */
+               reg = rtwn_bb_read(sc, R92C_FPGA0_TXINFO);
+               reg = (reg & ~0x00000003) | 0x2;
+               rtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg);
+
+               reg = rtwn_bb_read(sc, R92C_FPGA1_TXINFO);
+               reg = (reg & ~0x00300033) | 0x00200022;
+               rtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg);
+
+               reg = rtwn_bb_read(sc, R92C_CCK0_AFESETTING);
+               reg = (reg & ~0xff000000) | 0x45 << 24;
+               rtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg);
+
+               reg = rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
+               reg = (reg & ~0x000000ff) | 0x23;
+               rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg);
+
+               reg = rtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1);
+               reg = (reg & ~0x00000030) | 1 << 4;
+               rtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg);
+
+               reg = rtwn_bb_read(sc, 0xe74);
+               reg = (reg & ~0x0c000000) | 2 << 26;
+               rtwn_bb_write(sc, 0xe74, reg);
+               reg = rtwn_bb_read(sc, 0xe78);
+               reg = (reg & ~0x0c000000) | 2 << 26;
+               rtwn_bb_write(sc, 0xe78, reg);
+               reg = rtwn_bb_read(sc, 0xe7c);
+               reg = (reg & ~0x0c000000) | 2 << 26;
+               rtwn_bb_write(sc, 0xe7c, reg);
+               reg = rtwn_bb_read(sc, 0xe80);
+               reg = (reg & ~0x0c000000) | 2 << 26;
+               rtwn_bb_write(sc, 0xe80, reg);
+               reg = rtwn_bb_read(sc, 0xe88);
+               reg = (reg & ~0x0c000000) | 2 << 26;
+               rtwn_bb_write(sc, 0xe88, reg);
+       }
+
+       /* Write AGC values. */
+       for (i = 0; i < prog->agccount; i++) {
+               rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE,
+                   prog->agcvals[i]);
+               DELAY(1);
+       }
+
+       if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) &
+           R92C_HSSI_PARAM2_CCK_HIPWR)
+               sc->sc_sc.sc_flags |= RTWN_FLAG_CCK_HIPWR;
 }
 
 void

Reply via email to