summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2016-06-05 20:11:42 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2016-06-05 20:11:42 +0000
commitd099dcc7fcb186dd994265f53566586657f089de (patch)
treef8cd733771572b476d8b15d28222c4682a335e7e /sys/dev
parentf623688fe1f4e9eef651c8ed946a65d8fe1b6354 (diff)
Continue preparing a future merge of urtwn(4) and rtwn(4).
This mostly copies r88e support code to ic/rtwn.c and moves some functions which are not trivial to merge with USB counterparts back to pci/if_rtwn.c. ok mpi@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/rtwn.c618
-rw-r--r--sys/dev/ic/rtwnvar.h17
-rw-r--r--sys/dev/pci/if_rtwn.c272
3 files changed, 612 insertions, 295 deletions
diff --git a/sys/dev/ic/rtwn.c b/sys/dev/ic/rtwn.c
index 01b8e0e81e2..ed562053ada 100644
--- a/sys/dev/ic/rtwn.c
+++ b/sys/dev/ic/rtwn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtwn.c,v 1.7 2016/04/13 10:49:26 mpi Exp $ */
+/* $OpenBSD: rtwn.c,v 1.8 2016/06/05 20:11:41 stsp Exp $ */
/*-
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -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 *, int, uint8_t);
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 *, struct ieee80211_node *,
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_softc *, int, uint16_t[]);
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 rtwn_softc *sc, uint32_t chip_type)
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_t id, const void *buf, int len)
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, enum ieee80211_state nstate, int arg)
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 rate, void *physt)
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 rate, void *physt)
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, caddr_t data)
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, int chain,
}
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, struct ieee80211_channel *c,
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. */
diff --git a/sys/dev/ic/rtwnvar.h b/sys/dev/ic/rtwnvar.h
index 8d47c37431b..d80855339ff 100644
--- a/sys/dev/ic/rtwnvar.h
+++ b/sys/dev/ic/rtwnvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtwnvar.h,v 1.5 2016/03/21 12:00:32 stsp Exp $ */
+/* $OpenBSD: rtwnvar.h,v 1.6 2016/06/05 20:11:41 stsp Exp $ */
/*-
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -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
@@ -75,6 +80,12 @@ struct rtwn_softc {
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];
};
diff --git a/sys/dev/pci/if_rtwn.c b/sys/dev/pci/if_rtwn.c
index daf71ed99dd..34b958964cf 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.20 2016/03/21 12:00:32 stsp Exp $ */
+/* $OpenBSD: if_rtwn.c,v 1.21 2016/06/05 20:11:41 stsp Exp $ */
/*-
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -229,9 +229,13 @@ void rtwn_tx_done(struct rtwn_pci_softc *, int);
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, struct device *self, void *aux)
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, struct ieee80211_node *ni)
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;
@@ -1309,6 +1455,128 @@ rtwn_dma_init(void *cookie)
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
rtwn_enable_intr(void *cookie)
{