diff --git a/freebsd/sys/dev/rtwn/if_rtwn.c b/freebsd/sys/dev/rtwn/if_rtwn.c new file mode 100644 index 00000000..a553814f --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn.c @@ -0,0 +1,2020 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU/RTL8812AU/RTL8821AU. + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +static void rtwn_radiotap_attach(struct rtwn_softc *); +static void rtwn_vap_decrement_counters(struct rtwn_softc *, + enum ieee80211_opmode, int); +static void rtwn_set_ic_opmode(struct rtwn_softc *); +static struct ieee80211vap *rtwn_vap_create(struct ieee80211com *, + const char [IFNAMSIZ], int, enum ieee80211_opmode, + int, const uint8_t [IEEE80211_ADDR_LEN], + const uint8_t [IEEE80211_ADDR_LEN]); +static void rtwn_vap_delete(struct ieee80211vap *); +static int rtwn_read_chipid(struct rtwn_softc *); +static int rtwn_ioctl_reset(struct ieee80211vap *, u_long); +#ifndef RTWN_WITHOUT_UCODE +static void rtwn_set_media_status(struct rtwn_softc *, + union sec_param *); +static int rtwn_tx_fwpkt_check(struct rtwn_softc *, + struct ieee80211vap *); +static int rtwn_construct_nulldata(struct rtwn_softc *, + struct ieee80211vap *, uint8_t *, int); +static int rtwn_push_nulldata(struct rtwn_softc *, + struct ieee80211vap *); +static void rtwn_pwrmode_init(void *); +static void rtwn_set_pwrmode_cb(struct rtwn_softc *, + union sec_param *); +#endif +static void rtwn_tsf_sync_adhoc(void *); +static void rtwn_tsf_sync_adhoc_task(void *, int); +static void rtwn_tsf_sync_enable(struct rtwn_softc *, + struct ieee80211vap *); +static void rtwn_set_ack_preamble(struct rtwn_softc *); +static void rtwn_set_mode(struct rtwn_softc *, uint8_t, int); +static int rtwn_monitor_newstate(struct ieee80211vap *, + enum ieee80211_state, int); +static int rtwn_newstate(struct ieee80211vap *, + enum ieee80211_state, int); +static void rtwn_calc_basicrates(struct rtwn_softc *); +static int rtwn_run(struct rtwn_softc *, + struct ieee80211vap *); +#ifndef D4054 +static void rtwn_watchdog(void *); +#endif +static void rtwn_parent(struct ieee80211com *); +static int rtwn_llt_write(struct rtwn_softc *, uint32_t, + uint32_t); +static int rtwn_llt_init(struct rtwn_softc *); +static int rtwn_dma_init(struct rtwn_softc *); +static int rtwn_mac_init(struct rtwn_softc *); +static void rtwn_mrr_init(struct rtwn_softc *); +static void rtwn_scan_start(struct ieee80211com *); +static void rtwn_scan_curchan(struct ieee80211_scan_state *, + unsigned long); +static void rtwn_scan_end(struct ieee80211com *); +static void rtwn_getradiocaps(struct ieee80211com *, int, int *, + struct ieee80211_channel[]); +static void rtwn_update_chw(struct ieee80211com *); +static void rtwn_set_channel(struct ieee80211com *); +static int rtwn_wme_update(struct ieee80211com *); +static void rtwn_update_slot(struct ieee80211com *); +static void rtwn_update_slot_cb(struct rtwn_softc *, + union sec_param *); +static void rtwn_update_aifs(struct rtwn_softc *, uint8_t); +static void rtwn_update_promisc(struct ieee80211com *); +static void rtwn_update_mcast(struct ieee80211com *); +static int rtwn_set_bssid(struct rtwn_softc *, + const uint8_t *, int); +static int rtwn_set_macaddr(struct rtwn_softc *, + const uint8_t *, int); +static struct ieee80211_node *rtwn_node_alloc(struct ieee80211vap *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static void rtwn_newassoc(struct ieee80211_node *, int); +static void rtwn_node_free(struct ieee80211_node *); +static void rtwn_init_beacon_reg(struct rtwn_softc *); +static int rtwn_init(struct rtwn_softc *); +static void rtwn_stop(struct rtwn_softc *); + +MALLOC_DEFINE(M_RTWN_PRIV, "rtwn_priv", "rtwn driver private state"); + +static const uint8_t rtwn_chan_2ghz[] = + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; + +static const uint16_t wme2reg[] = + { R92C_EDCA_BE_PARAM, R92C_EDCA_BK_PARAM, + R92C_EDCA_VI_PARAM, R92C_EDCA_VO_PARAM }; + +int +rtwn_attach(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + int error; + + sc->cur_bcnq_id = RTWN_VAP_ID_INVALID; + + RTWN_NT_LOCK_INIT(sc); + rtwn_cmdq_init(sc); +#ifndef D4054 + callout_init_mtx(&sc->sc_watchdog_to, &sc->sc_mtx, 0); +#endif + callout_init(&sc->sc_calib_to, 0); + callout_init(&sc->sc_pwrmode_init, 0); + mbufq_init(&sc->sc_snd, ifqmaxlen); + + RTWN_LOCK(sc); + error = rtwn_read_chipid(sc); + RTWN_UNLOCK(sc); + if (error != 0) { + device_printf(sc->sc_dev, "unsupported test chip\n"); + goto detach; + } + + error = rtwn_read_rom(sc); + if (error != 0) { + device_printf(sc->sc_dev, "%s: cannot read rom, error %d\n", + __func__, error); + goto detach; + } + + if (sc->macid_limit > RTWN_MACID_LIMIT) { + device_printf(sc->sc_dev, + "macid limit will be reduced from %d to %d\n", + sc->macid_limit, RTWN_MACID_LIMIT); + sc->macid_limit = RTWN_MACID_LIMIT; + } + if (sc->cam_entry_limit > RTWN_CAM_ENTRY_LIMIT) { + device_printf(sc->sc_dev, + "cam entry limit will be reduced from %d to %d\n", + sc->cam_entry_limit, RTWN_CAM_ENTRY_LIMIT); + sc->cam_entry_limit = RTWN_CAM_ENTRY_LIMIT; + } + if (sc->txdesc_len > RTWN_TX_DESC_SIZE) { + device_printf(sc->sc_dev, + "adjust size for Tx descriptor (current %d, needed %d)\n", + RTWN_TX_DESC_SIZE, sc->txdesc_len); + goto detach; + } + + device_printf(sc->sc_dev, "MAC/BB %s, RF 6052 %dT%dR\n", + sc->name, sc->ntxchains, sc->nrxchains); + + ic->ic_softc = sc; + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ + + /* set device capabilities */ + ic->ic_caps = + IEEE80211_C_STA /* station mode */ + | IEEE80211_C_MONITOR /* monitor mode */ + | IEEE80211_C_IBSS /* adhoc mode */ + | IEEE80211_C_HOSTAP /* hostap mode */ +#if 0 /* TODO: HRPWM register setup */ +#ifndef RTWN_WITHOUT_UCODE + | IEEE80211_C_PMGT /* Station-side power mgmt */ +#endif +#endif + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ + | IEEE80211_C_SHSLOT /* short slot time supported */ +#if 0 + | IEEE80211_C_BGSCAN /* capable of bg scanning */ +#endif + | IEEE80211_C_WPA /* 802.11i */ + | IEEE80211_C_WME /* 802.11e */ + | IEEE80211_C_SWAMSDUTX /* Do software A-MSDU TX */ + | IEEE80211_C_FF /* Atheros fast-frames */ + ; + + if (sc->sc_hwcrypto != RTWN_CRYPTO_SW) { + ic->ic_cryptocaps = + IEEE80211_CRYPTO_WEP | + IEEE80211_CRYPTO_TKIP | + IEEE80211_CRYPTO_AES_CCM; + } + + ic->ic_htcaps = + IEEE80211_HTCAP_SHORTGI20 /* short GI in 20MHz */ + | IEEE80211_HTCAP_MAXAMSDU_3839 /* max A-MSDU length */ + | IEEE80211_HTCAP_SMPS_OFF /* SM PS mode disabled */ + /* s/w capabilities */ + | IEEE80211_HTC_HT /* HT operation */ + | IEEE80211_HTC_AMPDU /* A-MPDU tx */ + | IEEE80211_HTC_AMSDU /* A-MSDU tx */ + ; + + if (sc->sc_ht40) { + ic->ic_htcaps |= + IEEE80211_HTCAP_CHWIDTH40 /* 40 MHz channel width */ + | IEEE80211_HTCAP_SHORTGI40 /* short GI in 40MHz */ + ; + } + + ic->ic_txstream = sc->ntxchains; + ic->ic_rxstream = sc->nrxchains; + + /* Enable TX watchdog */ +#ifdef D4054 + ic->ic_flags_ext |= IEEE80211_FEXT_WATCHDOG; +#endif + + /* Adjust capabilities. */ + rtwn_adj_devcaps(sc); + + rtwn_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, + ic->ic_channels); + + /* XXX TODO: setup regdomain if R92C_CHANNEL_PLAN_BY_HW bit is set. */ + + ieee80211_ifattach(ic); + ic->ic_raw_xmit = rtwn_raw_xmit; + ic->ic_scan_start = rtwn_scan_start; + sc->sc_scan_curchan = ic->ic_scan_curchan; + ic->ic_scan_curchan = rtwn_scan_curchan; + ic->ic_scan_end = rtwn_scan_end; + ic->ic_getradiocaps = rtwn_getradiocaps; + ic->ic_update_chw = rtwn_update_chw; + ic->ic_set_channel = rtwn_set_channel; + ic->ic_transmit = rtwn_transmit; + ic->ic_parent = rtwn_parent; + ic->ic_vap_create = rtwn_vap_create; + ic->ic_vap_delete = rtwn_vap_delete; + ic->ic_wme.wme_update = rtwn_wme_update; + ic->ic_updateslot = rtwn_update_slot; + ic->ic_update_promisc = rtwn_update_promisc; + ic->ic_update_mcast = rtwn_update_mcast; + ic->ic_node_alloc = rtwn_node_alloc; + ic->ic_newassoc = rtwn_newassoc; + sc->sc_node_free = ic->ic_node_free; + ic->ic_node_free = rtwn_node_free; + + rtwn_postattach(sc); + rtwn_radiotap_attach(sc); + + if (bootverbose) + ieee80211_announce(ic); + + return (0); + +detach: + return (ENXIO); /* failure */ +} + +static void +rtwn_radiotap_attach(struct rtwn_softc *sc) +{ + struct rtwn_rx_radiotap_header *rxtap = &sc->sc_rxtap; + struct rtwn_tx_radiotap_header *txtap = &sc->sc_txtap; + + ieee80211_radiotap_attach(&sc->sc_ic, + &txtap->wt_ihdr, sizeof(*txtap), RTWN_TX_RADIOTAP_PRESENT, + &rxtap->wr_ihdr, sizeof(*rxtap), RTWN_RX_RADIOTAP_PRESENT); +} + +void +rtwn_sysctlattach(struct rtwn_softc *sc) +{ + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); + struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); + +#if 1 + sc->sc_ht40 = 0; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "ht40", CTLFLAG_RDTUN, &sc->sc_ht40, + sc->sc_ht40, "Enable 40 MHz mode support"); +#endif + +#ifdef RTWN_DEBUG + SYSCTL_ADD_U32(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "debug", CTLFLAG_RWTUN, &sc->sc_debug, sc->sc_debug, + "Control debugging printfs"); +#endif + + sc->sc_hwcrypto = RTWN_CRYPTO_PAIR; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "hwcrypto", CTLFLAG_RDTUN, &sc->sc_hwcrypto, + sc->sc_hwcrypto, "Enable h/w crypto: " + "0 - disable, 1 - pairwise keys, 2 - all keys"); + if (sc->sc_hwcrypto >= RTWN_CRYPTO_MAX) + sc->sc_hwcrypto = RTWN_CRYPTO_FULL; + + sc->sc_ratectl_sysctl = RTWN_RATECTL_NET80211; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "ratectl", CTLFLAG_RDTUN, &sc->sc_ratectl_sysctl, + sc->sc_ratectl_sysctl, "Select rate control mechanism: " + "0 - disabled, 1 - via net80211, 2 - via firmware"); + if (sc->sc_ratectl_sysctl >= RTWN_RATECTL_MAX) + sc->sc_ratectl_sysctl = RTWN_RATECTL_FW; + + sc->sc_ratectl = sc->sc_ratectl_sysctl; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "ratectl_selected", CTLFLAG_RD, &sc->sc_ratectl, + sc->sc_ratectl, + "Currently selected rate control mechanism (by the driver)"); +} + +void +rtwn_detach(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_softc == sc) { + /* Stop command queue. */ + RTWN_CMDQ_LOCK(sc); + sc->sc_detached = 1; + RTWN_CMDQ_UNLOCK(sc); + + ieee80211_draintask(ic, &sc->cmdq_task); + ieee80211_ifdetach(ic); + } + + rtwn_cmdq_destroy(sc); + if (RTWN_NT_LOCK_INITIALIZED(sc)) + RTWN_NT_LOCK_DESTROY(sc); +} + +void +rtwn_suspend(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + ieee80211_suspend_all(ic); +} + +void +rtwn_resume(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + ieee80211_resume_all(ic); +} + +static void +rtwn_vap_decrement_counters(struct rtwn_softc *sc, + enum ieee80211_opmode opmode, int id) +{ + + RTWN_ASSERT_LOCKED(sc); + + if (id != RTWN_VAP_ID_INVALID) { + KASSERT(id == 0 || id == 1, ("wrong vap id %d!\n", id)); + KASSERT(sc->vaps[id] != NULL, ("vap pointer is NULL\n")); + sc->vaps[id] = NULL; + } + + switch (opmode) { + case IEEE80211_M_HOSTAP: + sc->ap_vaps--; + /* FALLTHROUGH */ + case IEEE80211_M_IBSS: + sc->bcn_vaps--; + /* FALLTHROUGH */ + case IEEE80211_M_STA: + sc->nvaps--; + break; + case IEEE80211_M_MONITOR: + sc->mon_vaps--; + break; + default: + KASSERT(0, ("wrong opmode %d\n", opmode)); + break; + } + + KASSERT(sc->vaps_running >= 0 && sc->monvaps_running >= 0, + ("number of running vaps is negative (vaps %d, monvaps %d)\n", + sc->vaps_running, sc->monvaps_running)); + KASSERT(sc->vaps_running - sc->monvaps_running <= RTWN_PORT_COUNT, + ("number of running vaps is too big (vaps %d, monvaps %d)\n", + sc->vaps_running, sc->monvaps_running)); + + KASSERT(sc->nvaps >= 0 && sc->nvaps <= RTWN_PORT_COUNT, + ("wrong value %d for nvaps\n", sc->nvaps)); + KASSERT(sc->mon_vaps >= 0, ("mon_vaps is negative (%d)\n", + sc->mon_vaps)); + KASSERT(sc->bcn_vaps >= 0 && ((RTWN_CHIP_HAS_BCNQ1(sc) && + sc->bcn_vaps <= RTWN_PORT_COUNT) || sc->bcn_vaps <= 1), + ("bcn_vaps value %d is wrong\n", sc->bcn_vaps)); + KASSERT(sc->ap_vaps >= 0 && ((RTWN_CHIP_HAS_BCNQ1(sc) && + sc->ap_vaps <= RTWN_PORT_COUNT) || sc->ap_vaps <= 1), + ("ap_vaps value %d is wrong\n", sc->ap_vaps)); +} + +static void +rtwn_set_ic_opmode(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + RTWN_ASSERT_LOCKED(sc); + + /* for ieee80211_reset_erp() */ + if (sc->bcn_vaps - sc->ap_vaps > 0) + ic->ic_opmode = IEEE80211_M_IBSS; + else if (sc->ap_vaps > 0) + ic->ic_opmode = IEEE80211_M_HOSTAP; + else if (sc->nvaps > 0) + ic->ic_opmode = IEEE80211_M_STA; + else + ic->ic_opmode = IEEE80211_M_MONITOR; +} + +static struct ieee80211vap * +rtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, + enum ieee80211_opmode opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct rtwn_vap *uvp; + struct ieee80211vap *vap; + int id = RTWN_VAP_ID_INVALID; + + RTWN_LOCK(sc); + KASSERT(sc->nvaps <= RTWN_PORT_COUNT, + ("nvaps overflow (%d > %d)\n", sc->nvaps, RTWN_PORT_COUNT)); + KASSERT(sc->ap_vaps <= RTWN_PORT_COUNT, + ("ap_vaps overflow (%d > %d)\n", sc->ap_vaps, RTWN_PORT_COUNT)); + KASSERT(sc->bcn_vaps <= RTWN_PORT_COUNT, + ("bcn_vaps overflow (%d > %d)\n", sc->bcn_vaps, RTWN_PORT_COUNT)); + + if (opmode != IEEE80211_M_MONITOR) { + switch (sc->nvaps) { + case 0: + id = 0; + break; + case 1: + if (sc->vaps[1] == NULL) + id = 1; + else if (sc->vaps[0] == NULL) + id = 0; + KASSERT(id != RTWN_VAP_ID_INVALID, + ("no free ports left\n")); + break; + case 2: + default: + goto fail; + } + + if (opmode == IEEE80211_M_IBSS || + opmode == IEEE80211_M_HOSTAP) { + if ((sc->bcn_vaps == 1 && !RTWN_CHIP_HAS_BCNQ1(sc)) || + sc->bcn_vaps == RTWN_PORT_COUNT) + goto fail; + } + } + + switch (opmode) { + case IEEE80211_M_HOSTAP: + sc->ap_vaps++; + /* FALLTHROUGH */ + case IEEE80211_M_IBSS: + sc->bcn_vaps++; + /* FALLTHROUGH */ + case IEEE80211_M_STA: + sc->nvaps++; + break; + case IEEE80211_M_MONITOR: + sc->mon_vaps++; + break; + default: + KASSERT(0, ("unknown opmode %d\n", opmode)); + goto fail; + } + RTWN_UNLOCK(sc); + + uvp = malloc(sizeof(struct rtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); + uvp->id = id; + if (id != RTWN_VAP_ID_INVALID) { + RTWN_LOCK(sc); + sc->vaps[id] = uvp; + RTWN_UNLOCK(sc); + } + vap = &uvp->vap; + /* enable s/w bmiss handling for sta mode */ + + if (ieee80211_vap_setup(ic, vap, name, unit, opmode, + flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { + /* out of memory */ + free(uvp, M_80211_VAP); + + RTWN_LOCK(sc); + rtwn_vap_decrement_counters(sc, opmode, id); + RTWN_UNLOCK(sc); + + return (NULL); + } + + rtwn_beacon_init(sc, &uvp->bcn_desc.txd[0], uvp->id); + rtwn_vap_preattach(sc, vap); + + /* override state transition machine */ + uvp->newstate = vap->iv_newstate; + if (opmode == IEEE80211_M_MONITOR) + vap->iv_newstate = rtwn_monitor_newstate; + else + vap->iv_newstate = rtwn_newstate; + vap->iv_update_beacon = rtwn_update_beacon; + vap->iv_reset = rtwn_ioctl_reset; + vap->iv_key_alloc = rtwn_key_alloc; + vap->iv_key_set = rtwn_key_set; + vap->iv_key_delete = rtwn_key_delete; + vap->iv_max_aid = sc->macid_limit; + + /* 802.11n parameters */ + vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_16; + vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K; + + TIMEOUT_TASK_INIT(taskqueue_thread, &uvp->tx_beacon_csa, 0, + rtwn_tx_beacon_csa, vap); + if (opmode == IEEE80211_M_IBSS) { + uvp->recv_mgmt = vap->iv_recv_mgmt; + vap->iv_recv_mgmt = rtwn_adhoc_recv_mgmt; + TASK_INIT(&uvp->tsf_sync_adhoc_task, 0, + rtwn_tsf_sync_adhoc_task, vap); + callout_init(&uvp->tsf_sync_adhoc, 0); + } + + /* + * NB: driver can select net80211 RA even when user requests + * another mechanism. + */ + ieee80211_ratectl_init(vap); + + /* complete setup */ + ieee80211_vap_attach(vap, ieee80211_media_change, + ieee80211_media_status, mac); + + RTWN_LOCK(sc); + rtwn_set_ic_opmode(sc); + if (sc->sc_flags & RTWN_RUNNING) { + if (uvp->id != RTWN_VAP_ID_INVALID) + rtwn_set_macaddr(sc, vap->iv_myaddr, uvp->id); + + rtwn_rxfilter_update(sc); + } + RTWN_UNLOCK(sc); + + return (vap); + +fail: + RTWN_UNLOCK(sc); + return (NULL); +} + +static void +rtwn_vap_delete(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_softc *sc = ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); + + /* Put vap into INIT state + stop device if needed. */ + ieee80211_stop(vap); + ieee80211_draintask(ic, &vap->iv_nstate_task); + ieee80211_draintask(ic, &ic->ic_parent_task); + + RTWN_LOCK(sc); + /* Cancel any unfinished Tx. */ + rtwn_reset_lists(sc, vap); + if (uvp->bcn_mbuf != NULL) + m_freem(uvp->bcn_mbuf); + rtwn_vap_decrement_counters(sc, vap->iv_opmode, uvp->id); + rtwn_set_ic_opmode(sc); + if (sc->sc_flags & RTWN_RUNNING) + rtwn_rxfilter_update(sc); + RTWN_UNLOCK(sc); + + if (vap->iv_opmode == IEEE80211_M_IBSS) { + ieee80211_draintask(ic, &uvp->tsf_sync_adhoc_task); + callout_drain(&uvp->tsf_sync_adhoc); + } + + ieee80211_ratectl_deinit(vap); + ieee80211_vap_detach(vap); + free(uvp, M_80211_VAP); +} + +static int +rtwn_read_chipid(struct rtwn_softc *sc) +{ + uint32_t reg; + + reg = rtwn_read_4(sc, R92C_SYS_CFG); + if (reg & R92C_SYS_CFG_TRP_VAUX_EN) /* test chip */ + return (EOPNOTSUPP); + + rtwn_read_chipid_vendor(sc, reg); + + return (0); +} + +static int +rtwn_ioctl_reset(struct ieee80211vap *vap, u_long cmd) +{ + int error; + + switch (cmd) { +#ifndef RTWN_WITHOUT_UCODE + case IEEE80211_IOC_POWERSAVE: + case IEEE80211_IOC_POWERSAVESLEEP: + { + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); + + if (vap->iv_opmode == IEEE80211_M_STA && uvp->id == 0) { + RTWN_LOCK(sc); + if (sc->sc_flags & RTWN_RUNNING) + error = rtwn_set_pwrmode(sc, vap, 1); + else + error = 0; + RTWN_UNLOCK(sc); + if (error != 0) + error = ENETRESET; + } else + error = EOPNOTSUPP; + break; + } +#endif + case IEEE80211_IOC_SHORTGI: + case IEEE80211_IOC_RTSTHRESHOLD: + case IEEE80211_IOC_PROTMODE: + case IEEE80211_IOC_HTPROTMODE: + error = 0; + break; + default: + error = ENETRESET; + break; + } + + return (error); +} + +#ifndef RTWN_WITHOUT_UCODE +static void +rtwn_set_media_status(struct rtwn_softc *sc, union sec_param *data) +{ + sc->sc_set_media_status(sc, data->macid); +} + +static int +rtwn_tx_fwpkt_check(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + int ntries, error; + + for (ntries = 0; ntries < 5; ntries++) { + error = rtwn_push_nulldata(sc, vap); + if (error == 0) + break; + } + if (ntries == 5) { + device_printf(sc->sc_dev, + "%s: cannot push f/w frames into chip, error %d!\n", + __func__, error); + return (error); + } + + return (0); +} + +static int +rtwn_construct_nulldata(struct rtwn_softc *sc, struct ieee80211vap *vap, + uint8_t *ptr, int qos) +{ + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211com *ic = &sc->sc_ic; + struct rtwn_tx_desc_common *txd; + struct ieee80211_frame *wh; + int pktlen; + + /* XXX obtain from net80211 */ + wh = (struct ieee80211_frame *)(ptr + sc->txdesc_len); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; + wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; + IEEE80211_ADDR_COPY(wh->i_addr1, vap->iv_bss->ni_bssid); + IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); + IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_macaddr); + + txd = (struct rtwn_tx_desc_common *)ptr; + txd->offset = sc->txdesc_len; + pktlen = sc->txdesc_len; + if (qos) { + struct ieee80211_qosframe *qwh; + const int tid = WME_AC_TO_TID(WME_AC_BE); + + qwh = (struct ieee80211_qosframe *)wh; + qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS_NULL; + qwh->i_qos[0] = tid & IEEE80211_QOS_TID; + + txd->pktlen = htole16(sizeof(struct ieee80211_qosframe)); + pktlen += sizeof(struct ieee80211_qosframe); + } else { + wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_NODATA; + + txd->pktlen = htole16(sizeof(struct ieee80211_frame)); + pktlen += sizeof(struct ieee80211_frame); + } + + rtwn_fill_tx_desc_null(sc, ptr, + ic->ic_curmode == IEEE80211_MODE_11B, qos, uvp->id); + + return (pktlen); +} + +static int +rtwn_push_nulldata(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_channel *c = ic->ic_curchan; + struct mbuf *m; + uint8_t *ptr; + int required_size, bcn_size, null_size, null_data, error; + + if (!(sc->sc_flags & RTWN_FW_LOADED)) + return (0); /* requires firmware */ + + KASSERT(sc->page_size > 0, ("page size was not set!\n")); + + /* Leave some space for beacon (multi-vap) */ + bcn_size = roundup(RTWN_BCN_MAX_SIZE, sc->page_size); + /* 1 page for Null Data + 1 page for Qos Null Data frames. */ + required_size = bcn_size + sc->page_size * 2; + + m = m_get2(required_size, M_NOWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) + return (ENOMEM); + + /* Setup beacon descriptor. */ + rtwn_beacon_set_rate(sc, &uvp->bcn_desc.txd[0], + IEEE80211_IS_CHAN_5GHZ(c)); + + ptr = mtod(m, uint8_t *); + memset(ptr, 0, required_size - sc->txdesc_len); + + /* Construct Null Data frame. */ + ptr += bcn_size - sc->txdesc_len; + null_size = rtwn_construct_nulldata(sc, vap, ptr, 0); + KASSERT(null_size < sc->page_size, + ("recalculate size for Null Data frame\n")); + + /* Construct Qos Null Data frame. */ + ptr += roundup(null_size, sc->page_size); + null_size = rtwn_construct_nulldata(sc, vap, ptr, 1); + KASSERT(null_size < sc->page_size, + ("recalculate size for Qos Null Data frame\n")); + + /* Do not try to detect a beacon here. */ + rtwn_setbits_1_shift(sc, R92C_CR, 0, R92C_CR_ENSWBCN, 1); + rtwn_setbits_1_shift(sc, R92C_FWHW_TXQ_CTRL, + R92C_FWHW_TXQ_CTRL_REAL_BEACON, 0, 2); + + if (uvp->bcn_mbuf != NULL) { + rtwn_beacon_unload(sc, uvp->id); + m_freem(uvp->bcn_mbuf); + } + + m->m_pkthdr.len = m->m_len = required_size - sc->txdesc_len; + uvp->bcn_mbuf = m; + + error = rtwn_tx_beacon_check(sc, uvp); + if (error != 0) { + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: frame was not recognized!\n", __func__); + goto fail; + } + + /* Setup addresses in firmware. */ + null_data = howmany(bcn_size, sc->page_size); + error = rtwn_set_rsvd_page(sc, 0, null_data, null_data + 1); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: CMD_RSVD_PAGE was not sent, error %d\n", + __func__, error); + goto fail; + } + +fail: + /* Re-enable beacon detection. */ + rtwn_setbits_1_shift(sc, R92C_FWHW_TXQ_CTRL, + 0, R92C_FWHW_TXQ_CTRL_REAL_BEACON, 2); + rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSWBCN, 0, 1); + + /* Restore beacon (if present). */ + if (sc->bcn_vaps > 0 && sc->vaps[!uvp->id] != NULL) { + struct rtwn_vap *uvp2 = sc->vaps[!uvp->id]; + + if (uvp2->curr_mode != R92C_MSR_NOLINK) + error = rtwn_tx_beacon_check(sc, uvp2); + } + + return (error); +} + +static void +rtwn_pwrmode_init(void *arg) +{ + struct rtwn_softc *sc = arg; + + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_set_pwrmode_cb); +} + +static void +rtwn_set_pwrmode_cb(struct rtwn_softc *sc, union sec_param *data) +{ + struct ieee80211vap *vap = &sc->vaps[0]->vap; + + if (vap != NULL) + rtwn_set_pwrmode(sc, vap, 1); +} +#endif + +static void +rtwn_tsf_sync_adhoc(void *arg) +{ + struct ieee80211vap *vap = arg; + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_vap *uvp = RTWN_VAP(vap); + + if (uvp->curr_mode != R92C_MSR_NOLINK) { + /* Do it in process context. */ + ieee80211_runtask(ic, &uvp->tsf_sync_adhoc_task); + } +} + +/* + * Workaround for TSF synchronization: + * when BSSID filter in IBSS mode is not set + * (and TSF synchronization is enabled), then any beacon may update it. + * This routine synchronizes it when BSSID matching is enabled (IBSS merge + * is not possible during this period). + * + * NOTE: there is no race with rtwn_newstate(), since it uses the same + * taskqueue. + */ +static void +rtwn_tsf_sync_adhoc_task(void *arg, int pending) +{ + struct ieee80211vap *vap = arg; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + struct ieee80211_node *ni; + + RTWN_LOCK(sc); + ni = ieee80211_ref_node(vap->iv_bss); + + /* Accept beacons with the same BSSID. */ + rtwn_set_rx_bssid_all(sc, 0); + + /* Deny RCR updates. */ + sc->sc_flags |= RTWN_RCR_LOCKED; + + /* Enable synchronization. */ + rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), + R92C_BCN_CTRL_DIS_TSF_UDT0, 0); + + /* Synchronize. */ + rtwn_delay(sc, ni->ni_intval * 5 * 1000); + + /* Disable synchronization. */ + rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), + 0, R92C_BCN_CTRL_DIS_TSF_UDT0); + + /* Accept all beacons. */ + sc->sc_flags &= ~RTWN_RCR_LOCKED; + rtwn_set_rx_bssid_all(sc, 1); + + /* Schedule next TSF synchronization. */ + callout_reset(&uvp->tsf_sync_adhoc, 60*hz, rtwn_tsf_sync_adhoc, vap); + + ieee80211_free_node(ni); + RTWN_UNLOCK(sc); +} + +static void +rtwn_tsf_sync_enable(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct rtwn_vap *uvp = RTWN_VAP(vap); + + /* Reset TSF. */ + rtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RESET(uvp->id)); + + switch (vap->iv_opmode) { + case IEEE80211_M_STA: + /* Enable TSF synchronization. */ + rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), + R92C_BCN_CTRL_DIS_TSF_UDT0, 0); + break; + case IEEE80211_M_IBSS: + ieee80211_runtask(ic, &uvp->tsf_sync_adhoc_task); + /* FALLTHROUGH */ + case IEEE80211_M_HOSTAP: + /* Enable beaconing. */ + rtwn_beacon_enable(sc, uvp->id, 1); + break; + default: + device_printf(sc->sc_dev, "undefined opmode %d\n", + vap->iv_opmode); + return; + } +} + +static void +rtwn_set_ack_preamble(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t reg; + + reg = rtwn_read_4(sc, R92C_WMAC_TRXPTCL_CTL); + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + reg |= R92C_WMAC_TRXPTCL_SHPRE; + else + reg &= ~R92C_WMAC_TRXPTCL_SHPRE; + rtwn_write_4(sc, R92C_WMAC_TRXPTCL_CTL, reg); +} + +static void +rtwn_set_mode(struct rtwn_softc *sc, uint8_t mode, int id) +{ + + rtwn_setbits_1(sc, R92C_MSR, R92C_MSR_MASK << id * 2, mode << id * 2); + if (sc->vaps[id] != NULL) + sc->vaps[id]->curr_mode = mode; +} + +static int +rtwn_monitor_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, + int arg) +{ + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_softc *sc = ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); + + RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s -> %s\n", + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[nstate]); + + if (vap->iv_state != nstate) { + IEEE80211_UNLOCK(ic); + RTWN_LOCK(sc); + + switch (nstate) { + case IEEE80211_S_INIT: + sc->vaps_running--; + sc->monvaps_running--; + + if (sc->vaps_running == 0) { + /* Turn link LED off. */ + rtwn_set_led(sc, RTWN_LED_LINK, 0); + } + break; + case IEEE80211_S_RUN: + sc->vaps_running++; + sc->monvaps_running++; + + if (sc->vaps_running == 1) { + /* Turn link LED on. */ + rtwn_set_led(sc, RTWN_LED_LINK, 1); + } + break; + default: + /* NOTREACHED */ + break; + } + + RTWN_UNLOCK(sc); + IEEE80211_LOCK(ic); + } + + return (uvp->newstate(vap, nstate, arg)); +} + +static int +rtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) +{ + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_softc *sc = ic->ic_softc; + enum ieee80211_state ostate; + int error, early_newstate; + + ostate = vap->iv_state; + RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s -> %s\n", + ieee80211_state_name[ostate], ieee80211_state_name[nstate]); + + if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC && + ostate == IEEE80211_S_INIT && nstate == IEEE80211_S_RUN) { + /* need to call iv_newstate() firstly */ + error = uvp->newstate(vap, nstate, arg); + if (error != 0) + return (error); + + early_newstate = 1; + } else + early_newstate = 0; + + if (ostate == IEEE80211_S_CSA) { + taskqueue_cancel_timeout(taskqueue_thread, + &uvp->tx_beacon_csa, NULL); + + /* + * In multi-vap case second counter may not be cleared + * properly. + */ + vap->iv_csa_count = 0; + } + IEEE80211_UNLOCK(ic); + RTWN_LOCK(sc); + + if (ostate == IEEE80211_S_CSA) { + /* Unblock all queues (multi-vap case). */ + rtwn_write_1(sc, R92C_TXPAUSE, 0); + } + + if ((ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_CSA) || + ostate == IEEE80211_S_CSA) { + sc->vaps_running--; + + /* Set media status to 'No Link'. */ + rtwn_set_mode(sc, R92C_MSR_NOLINK, uvp->id); + + if (vap->iv_opmode == IEEE80211_M_IBSS) { + /* Stop periodical TSF synchronization. */ + callout_stop(&uvp->tsf_sync_adhoc); + } + + /* Disable TSF synchronization / beaconing. */ + rtwn_beacon_enable(sc, uvp->id, 0); + rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), + 0, R92C_BCN_CTRL_DIS_TSF_UDT0); + + /* NB: monitor mode vaps are using port 0. */ + if (uvp->id != 0 || sc->monvaps_running == 0) { + /* Reset TSF. */ + rtwn_write_1(sc, R92C_DUAL_TSF_RST, + R92C_DUAL_TSF_RESET(uvp->id)); + } + +#ifndef RTWN_WITHOUT_UCODE + if ((ic->ic_caps & IEEE80211_C_PMGT) != 0 && uvp->id == 0) { + /* Disable power management. */ + callout_stop(&sc->sc_pwrmode_init); + rtwn_set_pwrmode(sc, vap, 0); + } +#endif + if (sc->vaps_running - sc->monvaps_running > 0) { + /* Recalculate basic rates bitmap. */ + rtwn_calc_basicrates(sc); + } + + if (sc->vaps_running == sc->monvaps_running) { + /* Stop calibration. */ + callout_stop(&sc->sc_calib_to); + + /* Stop Rx of data frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP2, 0); + + /* Reset EDCA parameters. */ + rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217); + 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); + + if (sc->vaps_running == 0) { + /* Turn link LED off. */ + rtwn_set_led(sc, RTWN_LED_LINK, 0); + } + } + } + + error = 0; + switch (nstate) { + case IEEE80211_S_SCAN: + /* Pause AC Tx queues. */ + if (sc->vaps_running == 0) + rtwn_setbits_1(sc, R92C_TXPAUSE, 0, R92C_TX_QUEUE_AC); + break; + case IEEE80211_S_RUN: + error = rtwn_run(sc, vap); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not move to RUN state\n", __func__); + break; + } + + sc->vaps_running++; + break; + case IEEE80211_S_CSA: + /* Block all Tx queues (except beacon queue). */ + rtwn_setbits_1(sc, R92C_TXPAUSE, 0, + R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH); + break; + default: + break; + } + + RTWN_UNLOCK(sc); + IEEE80211_LOCK(ic); + if (error != 0) + return (error); + + return (early_newstate ? 0 : uvp->newstate(vap, nstate, arg)); +} + +static void +rtwn_calc_basicrates(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t basicrates; + int i; + + RTWN_ASSERT_LOCKED(sc); + + if (ic->ic_flags & IEEE80211_F_SCAN) + return; /* will be done by rtwn_scan_end(). */ + + basicrates = 0; + for (i = 0; i < nitems(sc->vaps); i++) { + struct rtwn_vap *rvp; + struct ieee80211vap *vap; + struct ieee80211_node *ni; + uint32_t rates; + + rvp = sc->vaps[i]; + if (rvp == NULL || rvp->curr_mode == R92C_MSR_NOLINK) + continue; + + vap = &rvp->vap; + if (vap->iv_bss == NULL) + continue; + + ni = ieee80211_ref_node(vap->iv_bss); + rtwn_get_rates(sc, &ni->ni_rates, NULL, &rates, NULL, 1); + basicrates |= rates; + ieee80211_free_node(ni); + } + + if (basicrates == 0) + return; + + /* XXX initial RTS rate? */ + rtwn_set_basicrates(sc, basicrates); +} + +static int +rtwn_run(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_node *ni; + uint8_t mode; + int error; + + RTWN_ASSERT_LOCKED(sc); + + error = 0; + ni = ieee80211_ref_node(vap->iv_bss); + + if (ic->ic_bsschan == IEEE80211_CHAN_ANYC || + ni->ni_chan == IEEE80211_CHAN_ANYC) { + error = EINVAL; + goto fail; + } + + switch (vap->iv_opmode) { + case IEEE80211_M_STA: + mode = R92C_MSR_INFRA; + break; + case IEEE80211_M_IBSS: + mode = R92C_MSR_ADHOC; + break; + case IEEE80211_M_HOSTAP: + mode = R92C_MSR_AP; + break; + default: + KASSERT(0, ("undefined opmode %d\n", vap->iv_opmode)); + error = EINVAL; + goto fail; + } + + /* Set media status to 'Associated'. */ + rtwn_set_mode(sc, mode, uvp->id); + + /* Set AssocID. */ + /* XXX multi-vap? */ + rtwn_write_2(sc, R92C_BCN_PSR_RPT, + 0xc000 | IEEE80211_NODE_AID(ni)); + + /* Set BSSID. */ + rtwn_set_bssid(sc, ni->ni_bssid, uvp->id); + + /* Set beacon interval. */ + rtwn_write_2(sc, R92C_BCN_INTERVAL(uvp->id), ni->ni_intval); + + if (sc->vaps_running == sc->monvaps_running) { + /* Enable Rx of data frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); + + /* Flush all AC queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, 0); + } + +#ifndef RTWN_WITHOUT_UCODE + /* Upload (QoS) Null Data frame to firmware. */ + /* Note: do this for port 0 only. */ + if ((ic->ic_caps & IEEE80211_C_PMGT) != 0 && + vap->iv_opmode == IEEE80211_M_STA && uvp->id == 0) { + error = rtwn_tx_fwpkt_check(sc, vap); + if (error != 0) + goto fail; + + /* Setup power management. */ + /* + * NB: it will be enabled immediately - delay it, + * so 4-Way handshake will not be interrupted. + */ + callout_reset(&sc->sc_pwrmode_init, 5*hz, + rtwn_pwrmode_init, sc); + } +#endif + + /* Enable TSF synchronization. */ + rtwn_tsf_sync_enable(sc, vap); + + if (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS) { + error = rtwn_setup_beacon(sc, ni); + if (error != 0) { + device_printf(sc->sc_dev, + "unable to push beacon into the chip, " + "error %d\n", error); + goto fail; + } + } + + /* Set ACK preamble type. */ + rtwn_set_ack_preamble(sc); + + /* Set basic rates mask. */ + rtwn_calc_basicrates(sc); + +#ifdef RTWN_TODO + rtwn_write_1(sc, R92C_SIFS_CCK + 1, 10); + rtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10); + rtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10); + rtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10); + rtwn_write_1(sc, R92C_R2T_SIFS + 1, 10); + rtwn_write_1(sc, R92C_T2T_SIFS + 1, 10); +#endif + + if (sc->vaps_running == sc->monvaps_running) { + /* Reset temperature calibration state machine. */ + sc->sc_flags &= ~RTWN_TEMP_MEASURED; + sc->thcal_temp = sc->thermal_meter; + + /* Start periodic calibration. */ + callout_reset(&sc->sc_calib_to, 2*hz, rtwn_calib_to, + sc); + + if (sc->vaps_running == 0) { + /* Turn link LED on. */ + rtwn_set_led(sc, RTWN_LED_LINK, 1); + } + } + +fail: + ieee80211_free_node(ni); + + return (error); +} + +#ifndef D4054 +static void +rtwn_watchdog(void *arg) +{ + struct rtwn_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + + RTWN_ASSERT_LOCKED(sc); + + KASSERT(sc->sc_flags & RTWN_RUNNING, ("not running")); + + if (sc->sc_tx_timer != 0 && --sc->sc_tx_timer == 0) { + ic_printf(ic, "device timeout\n"); + ieee80211_restart_all(ic); + return; + } + callout_reset(&sc->sc_watchdog_to, hz, rtwn_watchdog, sc); +} +#endif + +static void +rtwn_parent(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct ieee80211vap *vap; + + if (ic->ic_nrunning > 0) { + if (rtwn_init(sc) != 0) { + IEEE80211_LOCK(ic); + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + ieee80211_stop_locked(vap); + IEEE80211_UNLOCK(ic); + } else + ieee80211_start_all(ic); + } else + rtwn_stop(sc); +} + + +static int +rtwn_llt_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data) +{ + int ntries, error; + + error = rtwn_write_4(sc, R92C_LLT_INIT, + SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) | + SM(R92C_LLT_INIT_ADDR, addr) | + SM(R92C_LLT_INIT_DATA, data)); + if (error != 0) + return (error); + /* Wait for write operation to complete. */ + for (ntries = 0; ntries < 20; ntries++) { + if (MS(rtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) == + R92C_LLT_INIT_OP_NO_ACTIVE) + return (0); + rtwn_delay(sc, 10); + } + return (ETIMEDOUT); +} + +static int +rtwn_llt_init(struct rtwn_softc *sc) +{ + int i, error; + + /* Reserve pages [0; page_count]. */ + for (i = 0; i < sc->page_count; i++) { + if ((error = rtwn_llt_write(sc, i, i + 1)) != 0) + return (error); + } + /* NB: 0xff indicates end-of-list. */ + if ((error = rtwn_llt_write(sc, i, 0xff)) != 0) + return (error); + /* + * Use pages [page_count + 1; pktbuf_count - 1] + * as ring buffer. + */ + for (++i; i < sc->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, sc->page_count + 1); + return (error); +} + +static int +rtwn_dma_init(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + uint16_t reg; + uint8_t tx_boundary; + int error; + + /* Initialize LLT table. */ + error = rtwn_llt_init(sc); + if (error != 0) + return (error); + + /* Set the number of pages for each queue. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "%s: pages per queue: high %d, normal %d, low %d, public %d\n", + __func__, sc->nhqpages, sc->nnqpages, sc->nlqpages, + sc->npubqpages); + + RTWN_CHK(rtwn_write_1(sc, R92C_RQPN_NPQ, sc->nnqpages)); + RTWN_CHK(rtwn_write_4(sc, R92C_RQPN, + /* Set number of pages for public queue. */ + SM(R92C_RQPN_PUBQ, sc->npubqpages) | + /* Set number of pages for high priority queue. */ + SM(R92C_RQPN_HPQ, sc->nhqpages) | + /* Set number of pages for low priority queue. */ + SM(R92C_RQPN_LPQ, sc->nlqpages) | + /* Load values. */ + R92C_RQPN_LD)); + + /* Initialize TX buffer boundary. */ + KASSERT(sc->page_count < 255 && sc->page_count > 0, + ("page_count is %d\n", sc->page_count)); + tx_boundary = sc->page_count + 1; + RTWN_CHK(rtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, tx_boundary)); + RTWN_CHK(rtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, tx_boundary)); + RTWN_CHK(rtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, tx_boundary)); + RTWN_CHK(rtwn_write_1(sc, R92C_TRXFF_BNDY, tx_boundary)); + RTWN_CHK(rtwn_write_1(sc, R92C_TDECTRL + 1, tx_boundary)); + + error = rtwn_init_bcnq1_boundary(sc); + if (error != 0) + return (error); + + /* Set queue to USB pipe mapping. */ + /* Note: PCIe devices are using some magic number here. */ + reg = rtwn_get_qmap(sc); + RTWN_CHK(rtwn_setbits_2(sc, R92C_TRXDMA_CTRL, + R92C_TRXDMA_CTRL_QMAP_M, reg)); + + /* Configure Tx/Rx DMA (PCIe). */ + rtwn_set_desc_addr(sc); + + /* Set Tx/Rx transfer page boundary. */ + RTWN_CHK(rtwn_write_2(sc, R92C_TRXFF_BNDY + 2, + sc->rx_dma_size - 1)); + + /* Set Tx/Rx transfer page size. */ + rtwn_set_page_size(sc); + + return (0); +} + +static int +rtwn_mac_init(struct rtwn_softc *sc) +{ + int i, error; + + /* Write MAC initialization values. */ + for (i = 0; i < sc->mac_size; i++) { + error = rtwn_write_1(sc, sc->mac_prog[i].reg, + sc->mac_prog[i].val); + if (error != 0) + return (error); + } + + return (0); +} + +static void +rtwn_mrr_init(struct rtwn_softc *sc) +{ + int i; + + /* Drop rate index by 1 per retry. */ + for (i = 0; i < R92C_DARFRC_SIZE; i++) { + rtwn_write_1(sc, R92C_DARFRC + i, i + 1); + rtwn_write_1(sc, R92C_RARFRC + i, i + 1); + } +} + +static void +rtwn_scan_start(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + + RTWN_LOCK(sc); + /* Pause beaconing. */ + rtwn_setbits_1(sc, R92C_TXPAUSE, 0, R92C_TX_QUEUE_BCN); + /* Receive beacons / probe responses from any BSSID. */ + if (sc->bcn_vaps == 0) + rtwn_set_rx_bssid_all(sc, 1); + RTWN_UNLOCK(sc); +} + +static void +rtwn_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) +{ + struct rtwn_softc *sc = ss->ss_ic->ic_softc; + + /* Make link LED blink during scan. */ + RTWN_LOCK(sc); + rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink); + RTWN_UNLOCK(sc); + + sc->sc_scan_curchan(ss, maxdwell); +} + +static void +rtwn_scan_end(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + + RTWN_LOCK(sc); + /* Restore limitations. */ + if (ic->ic_promisc == 0 && sc->bcn_vaps == 0) + rtwn_set_rx_bssid_all(sc, 0); + + /* Restore LED state. */ + rtwn_set_led(sc, RTWN_LED_LINK, (sc->vaps_running != 0)); + + /* Restore basic rates mask. */ + rtwn_calc_basicrates(sc); + + /* Resume beaconing. */ + rtwn_setbits_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_BCN, 0); + RTWN_UNLOCK(sc); +} + +static void +rtwn_getradiocaps(struct ieee80211com *ic, + int maxchans, int *nchans, struct ieee80211_channel chans[]) +{ + struct rtwn_softc *sc = ic->ic_softc; + uint8_t bands[IEEE80211_MODE_BYTES]; + int i; + + memset(bands, 0, sizeof(bands)); + setbit(bands, IEEE80211_MODE_11B); + setbit(bands, IEEE80211_MODE_11G); + setbit(bands, IEEE80211_MODE_11NG); + ieee80211_add_channel_list_2ghz(chans, maxchans, nchans, + rtwn_chan_2ghz, nitems(rtwn_chan_2ghz), bands, + !!(ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)); + + /* XXX workaround add_channel_list() limitations */ + setbit(bands, IEEE80211_MODE_11A); + setbit(bands, IEEE80211_MODE_11NA); + for (i = 0; i < nitems(sc->chan_num_5ghz); i++) { + if (sc->chan_num_5ghz[i] == 0) + continue; + + ieee80211_add_channel_list_5ghz(chans, maxchans, nchans, + sc->chan_list_5ghz[i], sc->chan_num_5ghz[i], bands, + !!(ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)); + } +} + +static void +rtwn_update_chw(struct ieee80211com *ic) +{ +} + +static void +rtwn_set_channel(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct ieee80211_channel *c = ic->ic_curchan; + + RTWN_LOCK(sc); + rtwn_set_chan(sc, c); + sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); + sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); + sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); + sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); + RTWN_UNLOCK(sc); +} + +static int +rtwn_wme_update(struct ieee80211com *ic) +{ + struct ieee80211_channel *c = ic->ic_curchan; + struct rtwn_softc *sc = ic->ic_softc; + struct wmeParams *wmep = sc->cap_wmeParams; + uint8_t aifs, acm, slottime; + int ac; + + /* Prevent possible races. */ + IEEE80211_LOCK(ic); /* XXX */ + RTWN_LOCK(sc); + memcpy(wmep, ic->ic_wme.wme_chanParams.cap_wmeParams, + sizeof(sc->cap_wmeParams)); + RTWN_UNLOCK(sc); + IEEE80211_UNLOCK(ic); + + acm = 0; + slottime = IEEE80211_GET_SLOTTIME(ic); + + RTWN_LOCK(sc); + for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) { + /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ + aifs = wmep[ac].wmep_aifsn * slottime + + (IEEE80211_IS_CHAN_5GHZ(c) ? + IEEE80211_DUR_OFDM_SIFS : IEEE80211_DUR_SIFS); + rtwn_write_4(sc, wme2reg[ac], + SM(R92C_EDCA_PARAM_TXOP, wmep[ac].wmep_txopLimit) | + SM(R92C_EDCA_PARAM_ECWMIN, wmep[ac].wmep_logcwmin) | + SM(R92C_EDCA_PARAM_ECWMAX, wmep[ac].wmep_logcwmax) | + SM(R92C_EDCA_PARAM_AIFS, aifs)); + if (ac != WME_AC_BE) + acm |= wmep[ac].wmep_acm << ac; + } + + if (acm != 0) + acm |= R92C_ACMHWCTRL_EN; + rtwn_setbits_1(sc, R92C_ACMHWCTRL, R92C_ACMHWCTRL_ACM_MASK, acm); + RTWN_UNLOCK(sc); + + return 0; +} + +static void +rtwn_update_slot(struct ieee80211com *ic) +{ + rtwn_cmd_sleepable(ic->ic_softc, NULL, 0, rtwn_update_slot_cb); +} + +static void +rtwn_update_slot_cb(struct rtwn_softc *sc, union sec_param *data) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint8_t slottime; + + slottime = IEEE80211_GET_SLOTTIME(ic); + + RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: setting slot time to %uus\n", + __func__, slottime); + + rtwn_write_1(sc, R92C_SLOT, slottime); + rtwn_update_aifs(sc, slottime); +} + +static void +rtwn_update_aifs(struct rtwn_softc *sc, uint8_t slottime) +{ + struct ieee80211_channel *c = sc->sc_ic.ic_curchan; + const struct wmeParams *wmep = sc->cap_wmeParams; + uint8_t aifs, ac; + + for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) { + /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ + aifs = wmep[ac].wmep_aifsn * slottime + + (IEEE80211_IS_CHAN_5GHZ(c) ? + IEEE80211_DUR_OFDM_SIFS : IEEE80211_DUR_SIFS); + rtwn_write_1(sc, wme2reg[ac], aifs); + } +} + +static void +rtwn_update_promisc(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + + RTWN_LOCK(sc); + if (sc->sc_flags & RTWN_RUNNING) + rtwn_set_promisc(sc); + RTWN_UNLOCK(sc); +} + +static void +rtwn_update_mcast(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + + RTWN_LOCK(sc); + if (sc->sc_flags & RTWN_RUNNING) + rtwn_set_multi(sc); + RTWN_UNLOCK(sc); +} + +static int +rtwn_set_bssid(struct rtwn_softc *sc, const uint8_t *bssid, int id) +{ + int error; + + error = rtwn_write_4(sc, R92C_BSSID(id), le32dec(&bssid[0])); + if (error != 0) + return (error); + error = rtwn_write_2(sc, R92C_BSSID(id) + 4, le16dec(&bssid[4])); + + return (error); +} + +static int +rtwn_set_macaddr(struct rtwn_softc *sc, const uint8_t *addr, int id) +{ + int error; + + error = rtwn_write_4(sc, R92C_MACID(id), le32dec(&addr[0])); + if (error != 0) + return (error); + error = rtwn_write_2(sc, R92C_MACID(id) + 4, le16dec(&addr[4])); + + return (error); +} + +static struct ieee80211_node * +rtwn_node_alloc(struct ieee80211vap *vap, + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct rtwn_node *un; + + un = malloc(sizeof (struct rtwn_node), M_80211_NODE, + M_NOWAIT | M_ZERO); + + if (un == NULL) + return NULL; + + un->id = RTWN_MACID_UNDEFINED; + un->avg_pwdb = -1; + + return &un->ni; +} + +static void +rtwn_newassoc(struct ieee80211_node *ni, int isnew) +{ + struct rtwn_softc *sc = ni->ni_ic->ic_softc; + struct rtwn_node *un = RTWN_NODE(ni); + int id; + + if (!isnew) + return; + + RTWN_NT_LOCK(sc); + for (id = 0; id <= sc->macid_limit; id++) { + if (id != RTWN_MACID_BC && sc->node_list[id] == NULL) { + un->id = id; + sc->node_list[id] = ni; + break; + } + } + RTWN_NT_UNLOCK(sc); + + if (id > sc->macid_limit) { + device_printf(sc->sc_dev, "%s: node table is full\n", + __func__); + return; + } + +#ifndef RTWN_WITHOUT_UCODE + /* Notify firmware. */ + id |= RTWN_MACID_VALID; + rtwn_cmd_sleepable(sc, &id, sizeof(id), rtwn_set_media_status); +#endif +} + +static void +rtwn_node_free(struct ieee80211_node *ni) +{ + struct rtwn_softc *sc = ni->ni_ic->ic_softc; + struct rtwn_node *un = RTWN_NODE(ni); + + RTWN_NT_LOCK(sc); + if (un->id != RTWN_MACID_UNDEFINED) { + sc->node_list[un->id] = NULL; +#ifndef RTWN_WITHOUT_UCODE + rtwn_cmd_sleepable(sc, &un->id, sizeof(un->id), + rtwn_set_media_status); +#endif + } + RTWN_NT_UNLOCK(sc); + + sc->sc_node_free(ni); +} + +static void +rtwn_init_beacon_reg(struct rtwn_softc *sc) +{ + rtwn_write_1(sc, R92C_BCN_CTRL(0), R92C_BCN_CTRL_DIS_TSF_UDT0); + rtwn_write_1(sc, R92C_BCN_CTRL(1), R92C_BCN_CTRL_DIS_TSF_UDT0); + rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404); + rtwn_write_1(sc, R92C_DRVERLYINT, 0x05); + rtwn_write_1(sc, R92C_BCNDMATIM, 0x02); + rtwn_write_2(sc, R92C_BCNTCFG, 0x660f); +} + +static int +rtwn_init(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + int i, error; + + RTWN_LOCK(sc); + if (sc->sc_flags & RTWN_RUNNING) { + RTWN_UNLOCK(sc); + return (0); + } + sc->sc_flags |= RTWN_STARTED; + + /* Power on adapter. */ + error = rtwn_power_on(sc); + if (error != 0) + goto fail; + +#ifndef RTWN_WITHOUT_UCODE + /* Load 8051 microcode. */ + error = rtwn_load_firmware(sc); + if (error == 0) + sc->sc_flags |= RTWN_FW_LOADED; + + /* Init firmware commands ring. */ + sc->fwcur = 0; +#endif + + /* Initialize MAC block. */ + error = rtwn_mac_init(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: error while initializing MAC block\n", __func__); + goto fail; + } + + /* Initialize DMA. */ + error = rtwn_dma_init(sc); + if (error != 0) + goto fail; + + /* Drop incorrect TX (USB). */ + rtwn_drop_incorrect_tx(sc); + + /* Set info size in Rx descriptors (in 64-bit words). */ + rtwn_write_1(sc, R92C_RX_DRVINFO_SZ, R92C_RX_DRVINFO_SZ_DEF); + + /* Init interrupts. */ + rtwn_init_intr(sc); + + for (i = 0; i < nitems(sc->vaps); i++) { + struct rtwn_vap *uvp = sc->vaps[i]; + + /* Set initial network type. */ + rtwn_set_mode(sc, R92C_MSR_NOLINK, i); + + if (uvp == NULL) + continue; + + /* Set MAC address. */ + error = rtwn_set_macaddr(sc, uvp->vap.iv_myaddr, uvp->id); + if (error != 0) + goto fail; + } + + /* Initialize Rx filter. */ + rtwn_rxfilter_init(sc); + + /* Set short/long retry limits. */ + rtwn_write_2(sc, R92C_RL, + SM(R92C_RL_SRL, 0x30) | SM(R92C_RL_LRL, 0x30)); + + /* Initialize EDCA parameters. */ + rtwn_init_edca(sc); + + rtwn_setbits_1(sc, R92C_FWHW_TXQ_CTRL, 0, + R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW); + /* Set ACK timeout. */ + rtwn_write_1(sc, R92C_ACKTO, sc->ackto); + + /* Setup aggregation. */ + /* Tx aggregation. */ + rtwn_init_tx_agg(sc); + rtwn_init_rx_agg(sc); + + /* Initialize beacon parameters. */ + rtwn_init_beacon_reg(sc); + + /* Init A-MPDU parameters. */ + rtwn_init_ampdu(sc); + + /* Init MACTXEN / MACRXEN after setting RxFF boundary. */ + rtwn_setbits_1(sc, R92C_CR, 0, R92C_CR_MACTXEN | R92C_CR_MACRXEN); + + /* Initialize BB/RF blocks. */ + rtwn_init_bb(sc); + rtwn_init_rf(sc); + + /* Initialize wireless band. */ + rtwn_set_chan(sc, ic->ic_curchan); + + /* Clear per-station keys table. */ + rtwn_init_cam(sc); + + /* Enable decryption / encryption. */ + rtwn_init_seccfg(sc); + + /* Install static keys (if any). */ + for (i = 0; i < nitems(sc->vaps); i++) { + if (sc->vaps[i] != NULL) { + error = rtwn_init_static_keys(sc, sc->vaps[i]); + if (error != 0) + goto fail; + } + } + + /* Initialize antenna selection. */ + rtwn_init_antsel(sc); + + /* Enable hardware sequence numbering. */ + rtwn_write_1(sc, R92C_HWSEQ_CTRL, R92C_TX_QUEUE_ALL); + + /* Disable BAR. */ + rtwn_write_4(sc, R92C_BAR_MODE_CTRL, 0x0201ffff); + + /* NAV limit. */ + rtwn_write_1(sc, R92C_NAV_UPPER, 0); + + /* Initialize GPIO setting. */ + rtwn_setbits_1(sc, R92C_GPIO_MUXCFG, R92C_GPIO_MUXCFG_ENBT, 0); + + /* Initialize MRR. */ + rtwn_mrr_init(sc); + + /* Device-specific post initialization. */ + rtwn_post_init(sc); + + rtwn_start_xfers(sc); + +#ifndef D4054 + callout_reset(&sc->sc_watchdog_to, hz, rtwn_watchdog, sc); +#endif + + sc->sc_flags |= RTWN_RUNNING; +fail: + RTWN_UNLOCK(sc); + + return (error); +} + +static void +rtwn_stop(struct rtwn_softc *sc) +{ + + RTWN_LOCK(sc); + if (!(sc->sc_flags & RTWN_STARTED)) { + RTWN_UNLOCK(sc); + return; + } + +#ifndef D4054 + callout_stop(&sc->sc_watchdog_to); + sc->sc_tx_timer = 0; +#endif + sc->sc_flags &= ~(RTWN_STARTED | RTWN_RUNNING | RTWN_FW_LOADED); + sc->sc_flags &= ~RTWN_TEMP_MEASURED; + sc->fwver = 0; + sc->thcal_temp = 0; + sc->cur_bcnq_id = RTWN_VAP_ID_INVALID; + +#ifdef D4054 + ieee80211_tx_watchdog_stop(&sc->sc_ic); +#endif + + rtwn_abort_xfers(sc); + rtwn_drain_mbufq(sc); + rtwn_power_off(sc); + rtwn_reset_lists(sc, NULL); + RTWN_UNLOCK(sc); +} + +MODULE_VERSION(rtwn, 2); +MODULE_DEPEND(rtwn, wlan, 1, 1, 1); +#ifndef RTWN_WITHOUT_UCODE +MODULE_DEPEND(rtwn, firmware, 1, 1, 1); +#endif diff --git a/freebsd/sys/dev/rtwn/if_rtwn_beacon.c b/freebsd/sys/dev/rtwn/if_rtwn_beacon.c new file mode 100644 index 00000000..a6a49f76 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_beacon.c @@ -0,0 +1,271 @@ +#include + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + + +static void +rtwn_reset_beacon_valid(struct rtwn_softc *sc, int id) +{ + + KASSERT (id == 0 || id == 1, ("wrong port id %d\n", id)); + + /* XXX cannot be cleared on RTL8188CE */ + rtwn_setbits_1_shift(sc, sc->bcn_status_reg[id], + R92C_TDECTRL_BCN_VALID, 0, 2); + + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: 'beacon valid' bit for vap %d was unset\n", + __func__, id); +} + +static int +rtwn_check_beacon_valid(struct rtwn_softc *sc, int id) +{ + uint16_t reg; + int ntries; + + if (id == RTWN_VAP_ID_INVALID) + return (0); + + reg = sc->bcn_status_reg[id]; + for (ntries = 0; ntries < 10; ntries++) { + if (rtwn_read_4(sc, reg) & R92C_TDECTRL_BCN_VALID) { + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: beacon for vap %d was recognized\n", + __func__, id); + break; + } + rtwn_delay(sc, sc->bcn_check_interval); + } + if (ntries == 10) + return (ETIMEDOUT); + + return (0); +} + +void +rtwn_switch_bcnq(struct rtwn_softc *sc, int id) +{ + + if (sc->cur_bcnq_id != id) { + /* Wait until any previous transmit completes. */ + (void) rtwn_check_beacon_valid(sc, sc->cur_bcnq_id); + + /* Change current port. */ + rtwn_beacon_select(sc, id); + sc->cur_bcnq_id = id; + } + + /* Reset 'beacon valid' bit. */ + rtwn_reset_beacon_valid(sc, id); +} + +int +rtwn_setup_beacon(struct rtwn_softc *sc, struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct mbuf *m; + + RTWN_ASSERT_LOCKED(sc); + + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return (EINVAL); + + m = ieee80211_beacon_alloc(ni); + if (m == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate beacon frame\n", __func__); + return (ENOMEM); + } + + if (uvp->bcn_mbuf != NULL) { + rtwn_beacon_unload(sc, uvp->id); + m_freem(uvp->bcn_mbuf); + } + + uvp->bcn_mbuf = m; + + rtwn_beacon_set_rate(sc, &uvp->bcn_desc.txd[0], + IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)); + + return (rtwn_tx_beacon_check(sc, uvp)); +} + +/* + * Push a beacon frame into the chip. Beacon will + * be repeated by the chip every R92C_BCN_INTERVAL. + */ +static int +rtwn_tx_beacon(struct rtwn_softc *sc, struct rtwn_vap *uvp) +{ + int error; + + RTWN_ASSERT_LOCKED(sc); + + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: sending beacon for vap %d\n", __func__, uvp->id); + + error = rtwn_tx_start(sc, NULL, uvp->bcn_mbuf, &uvp->bcn_desc.txd[0], + IEEE80211_FC0_TYPE_MGT, uvp->id); + + return (error); +} + +void +rtwn_update_beacon(struct ieee80211vap *vap, int item) +{ + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_softc *sc = ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; + struct ieee80211_node *ni = vap->iv_bss; + int mcast = 0; + + RTWN_LOCK(sc); + if (uvp->bcn_mbuf == NULL) { + uvp->bcn_mbuf = ieee80211_beacon_alloc(ni); + if (uvp->bcn_mbuf == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate beacon frame\n", __func__); + RTWN_UNLOCK(sc); + return; + } + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: vap id %d, iv_csa_count %d, ic_csa_count %d, item %d\n", + __func__, uvp->id, vap->iv_csa_count, ic->ic_csa_count, item); + + switch (item) { + case IEEE80211_BEACON_CSA: + if (vap->iv_csa_count != ic->ic_csa_count) { + /* + * XXX two APs with different beacon intervals + * are not handled properly. + */ + /* XXX check TBTT? */ + taskqueue_enqueue_timeout(taskqueue_thread, + &uvp->tx_beacon_csa, + msecs_to_ticks(ni->ni_intval)); + } + break; + case IEEE80211_BEACON_TIM: + mcast = 1; /* XXX */ + break; + default: + break; + } + + setbit(bo->bo_flags, item); + + rtwn_beacon_update_begin(sc, vap); + RTWN_UNLOCK(sc); + + ieee80211_beacon_update(ni, uvp->bcn_mbuf, mcast); + + /* XXX clear manually */ + clrbit(bo->bo_flags, IEEE80211_BEACON_CSA); + + RTWN_LOCK(sc); + rtwn_tx_beacon(sc, uvp); + rtwn_beacon_update_end(sc, vap); + RTWN_UNLOCK(sc); +} + +void +rtwn_tx_beacon_csa(void *arg, int npending __unused) +{ + struct ieee80211vap *vap = arg; + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_softc *sc = ic->ic_softc; + struct rtwn_vap *rvp = RTWN_VAP(vap); + + KASSERT (rvp->id == 0 || rvp->id == 1, + ("wrong port id %d\n", rvp->id)); + + IEEE80211_LOCK(ic); + if (ic->ic_flags & IEEE80211_F_CSAPENDING) { + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: vap id %d, iv_csa_count %d, ic_csa_count %d\n", + __func__, rvp->id, vap->iv_csa_count, ic->ic_csa_count); + + rtwn_update_beacon(vap, IEEE80211_BEACON_CSA); + } + IEEE80211_UNLOCK(ic); + + (void) rvp; +} + +int +rtwn_tx_beacon_check(struct rtwn_softc *sc, struct rtwn_vap *uvp) +{ + int ntries, error; + + for (ntries = 0; ntries < 5; ntries++) { + rtwn_reset_beacon_valid(sc, uvp->id); + + error = rtwn_tx_beacon(sc, uvp); + if (error != 0) + continue; + + error = rtwn_check_beacon_valid(sc, uvp->id); + if (error == 0) + break; + } + if (ntries == 5) { + device_printf(sc->sc_dev, + "%s: cannot push beacon into chip, error %d!\n", + __func__, error); + return (error); + } + + return (0); +} diff --git a/freebsd/sys/dev/rtwn/if_rtwn_beacon.h b/freebsd/sys/dev/rtwn/if_rtwn_beacon.h new file mode 100644 index 00000000..c38f7568 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_beacon.h @@ -0,0 +1,28 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_BEACON_H +#define IF_RTWN_BEACON_H + +void rtwn_switch_bcnq(struct rtwn_softc *, int); +int rtwn_setup_beacon(struct rtwn_softc *, struct ieee80211_node *); +void rtwn_update_beacon(struct ieee80211vap *, int); +void rtwn_tx_beacon_csa(void *arg, int); +int rtwn_tx_beacon_check(struct rtwn_softc *, struct rtwn_vap *); + +#endif /* IF_RTWN_BEACON_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_calib.c b/freebsd/sys/dev/rtwn/if_rtwn_calib.c new file mode 100644 index 00000000..8943b557 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_calib.c @@ -0,0 +1,130 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +static void +rtwn_temp_calib(struct rtwn_softc *sc) +{ + uint8_t temp; + + RTWN_ASSERT_LOCKED(sc); + + if (!(sc->sc_flags & RTWN_TEMP_MEASURED)) { + /* Start measuring temperature. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP, + "%s: start measuring temperature\n", __func__); + rtwn_temp_measure(sc); + sc->sc_flags |= RTWN_TEMP_MEASURED; + return; + } + sc->sc_flags &= ~RTWN_TEMP_MEASURED; + + /* Read measured temperature. */ + temp = rtwn_temp_read(sc); + if (temp == 0) { /* Read failed, skip. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP, + "%s: temperature read failed, skipping\n", __func__); + return; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP, + "temperature: previous %u, current %u\n", + sc->thcal_temp, temp); + + /* + * Redo LC/IQ calibration if temperature changed significantly since + * last calibration. + */ + if (sc->thcal_temp == 0xff) { + /* efuse value is absent; do LCK at initial status. */ + rtwn_lc_calib(sc); + + sc->thcal_temp = temp; + } else if (abs(temp - sc->thcal_temp) > sc->temp_delta) { + RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP, + "%s: LC/IQ calib triggered by temp: %u -> %u\n", + __func__, sc->thcal_temp, temp); + + rtwn_lc_calib(sc); + rtwn_iq_calib(sc); + + /* Record temperature of last calibration. */ + sc->thcal_temp = temp; + } +} + +static void +rtwn_calib_cb(struct rtwn_softc *sc, union sec_param *data) +{ + /* Do temperature compensation. */ + rtwn_temp_calib(sc); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_ratectl == RTWN_RATECTL_FW) { + /* Refresh per-node RSSI. */ + rtwn_set_rssi(sc); + } +#endif + + if (sc->vaps_running > sc->monvaps_running) + callout_reset(&sc->sc_calib_to, 2*hz, rtwn_calib_to, sc); +} + +void +rtwn_calib_to(void *arg) +{ + struct rtwn_softc *sc = arg; + + /* Do it in a process context. */ + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_calib_cb); +} diff --git a/freebsd/sys/dev/rtwn/if_rtwn_calib.h b/freebsd/sys/dev/rtwn/if_rtwn_calib.h new file mode 100644 index 00000000..ee50fd06 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_calib.h @@ -0,0 +1,24 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_CALIB_H +#define IF_RTWN_CALIB_H + +void rtwn_calib_to(void *); + +#endif /* IF_RTWN_CALIB_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_cam.c b/freebsd/sys/dev/rtwn/if_rtwn_cam.c new file mode 100644 index 00000000..2539bc70 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_cam.c @@ -0,0 +1,366 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include + + +void +rtwn_init_cam(struct rtwn_softc *sc) +{ + /* Invalidate all CAM entries. */ + rtwn_write_4(sc, R92C_CAMCMD, + R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR); +} + +static int +rtwn_cam_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data) +{ + int error; + + error = rtwn_write_4(sc, R92C_CAMWRITE, data); + if (error != 0) + return (error); + error = rtwn_write_4(sc, R92C_CAMCMD, + R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE | + SM(R92C_CAMCMD_ADDR, addr)); + + return (error); +} + +void +rtwn_init_seccfg(struct rtwn_softc *sc) +{ + uint16_t seccfg; + + /* Select decryption / encryption flags. */ + seccfg = 0; + switch (sc->sc_hwcrypto) { + case RTWN_CRYPTO_SW: + break; /* nothing to do */ + case RTWN_CRYPTO_PAIR: + /* NB: TXUCKEY_DEF / RXUCKEY_DEF are required for RTL8192C */ + seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF | + R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA | + R92C_SECCFG_MC_SRCH_DIS; + break; + case RTWN_CRYPTO_FULL: + seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF | + R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA | + R92C_SECCFG_TXBCKEY_DEF | R92C_SECCFG_RXBCKEY_DEF; + break; + default: + KASSERT(0, ("%s: case %d was not handled\n", __func__, + sc->sc_hwcrypto)); + break; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, "%s: seccfg %04X, hwcrypto %d\n", + __func__, seccfg, sc->sc_hwcrypto); + + rtwn_write_2(sc, R92C_SECCFG, seccfg); +} + +int +rtwn_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, + ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) +{ + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + int i, start; + + if (&vap->iv_nw_keys[0] <= k && + k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { +#if __FreeBSD_version > 1200018 + *keyix = ieee80211_crypto_get_key_wepidx(vap, k); +#else + *keyix = k - vap->iv_nw_keys; +#endif + if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) + k->wk_flags |= IEEE80211_KEY_SWCRYPT; + else { + RTWN_LOCK(sc); + if (isset(sc->keys_bmap, *keyix)) { + device_printf(sc->sc_dev, + "%s: group key slot %d is already used!\n", + __func__, *keyix); + /* XXX recover? */ + RTWN_UNLOCK(sc); + return (0); + } + + setbit(sc->keys_bmap, *keyix); + RTWN_UNLOCK(sc); + } + + goto end; + } + + start = sc->cam_entry_limit; + switch (sc->sc_hwcrypto) { + case RTWN_CRYPTO_SW: + k->wk_flags |= IEEE80211_KEY_SWCRYPT; + *keyix = 0; + goto end; + case RTWN_CRYPTO_PAIR: + /* all slots for pairwise keys. */ + start = 0; + RTWN_LOCK(sc); + if (sc->sc_flags & RTWN_FLAG_CAM_FIXED) + start = 4; + RTWN_UNLOCK(sc); + break; + case RTWN_CRYPTO_FULL: + /* first 4 - for group keys, others for pairwise. */ + start = 4; + break; + default: + KASSERT(0, ("%s: case %d was not handled!\n", + __func__, sc->sc_hwcrypto)); + break; + } + + RTWN_LOCK(sc); + for (i = start; i < sc->cam_entry_limit; i++) { + if (isclr(sc->keys_bmap, i)) { + setbit(sc->keys_bmap, i); + *keyix = i; + break; + } + } + RTWN_UNLOCK(sc); + if (i == sc->cam_entry_limit) { +#if __FreeBSD_version > 1200008 + /* XXX check and remove keys with the same MAC address */ + k->wk_flags |= IEEE80211_KEY_SWCRYPT; + *keyix = 0; +#else + device_printf(sc->sc_dev, + "%s: no free space in the key table\n", __func__); + return (0); +#endif + } + +end: + *rxkeyix = *keyix; + return (1); +} + +static int +rtwn_key_set_cb0(struct rtwn_softc *sc, const struct ieee80211_key *k) +{ + uint8_t algo, keyid; + int i, error; + + if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL && + k->wk_keyix < IEEE80211_WEP_NKID) + keyid = k->wk_keyix; + else + keyid = 0; + + /* Map net80211 cipher to HW crypto algorithm. */ + switch (k->wk_cipher->ic_cipher) { + case IEEE80211_CIPHER_WEP: + if (k->wk_keylen < 8) + algo = R92C_CAM_ALGO_WEP40; + else + algo = R92C_CAM_ALGO_WEP104; + break; + case IEEE80211_CIPHER_TKIP: + algo = R92C_CAM_ALGO_TKIP; + break; + case IEEE80211_CIPHER_AES_CCM: + algo = R92C_CAM_ALGO_AES; + break; + default: + device_printf(sc->sc_dev, "%s: unknown cipher %u\n", + __func__, k->wk_cipher->ic_cipher); + return (EINVAL); + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, + "%s: keyix %u, keyid %u, algo %u/%u, flags %04X, len %u, " + "macaddr %s\n", __func__, k->wk_keyix, keyid, + k->wk_cipher->ic_cipher, algo, k->wk_flags, k->wk_keylen, + ether_sprintf(k->wk_macaddr)); + + /* Clear high bits. */ + rtwn_cam_write(sc, R92C_CAM_CTL6(k->wk_keyix), 0); + rtwn_cam_write(sc, R92C_CAM_CTL7(k->wk_keyix), 0); + + /* Write key. */ + for (i = 0; i < 4; i++) { + error = rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), + le32dec(&k->wk_key[i * 4])); + if (error != 0) + goto fail; + } + + /* Write CTL0 last since that will validate the CAM entry. */ + error = rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), + le32dec(&k->wk_macaddr[2])); + if (error != 0) + goto fail; + error = rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), + SM(R92C_CAM_ALGO, algo) | + SM(R92C_CAM_KEYID, keyid) | + SM(R92C_CAM_MACLO, le16dec(&k->wk_macaddr[0])) | + R92C_CAM_VALID); + if (error != 0) + goto fail; + + return (0); + +fail: + device_printf(sc->sc_dev, "%s fails, error %d\n", __func__, error); + return (error); +} + +static void +rtwn_key_set_cb(struct rtwn_softc *sc, union sec_param *data) +{ + const struct ieee80211_key *k = &data->key; + + (void) rtwn_key_set_cb0(sc, k); +} + +int +rtwn_init_static_keys(struct rtwn_softc *sc, struct rtwn_vap *rvp) +{ + int i, error; + + if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) + return (0); /* nothing to do */ + + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + const struct ieee80211_key *k = rvp->keys[i]; + if (k != NULL) { + error = rtwn_key_set_cb0(sc, k); + if (error != 0) + return (error); + } + } + + return (0); +} + +static void +rtwn_key_del_cb(struct rtwn_softc *sc, union sec_param *data) +{ + struct ieee80211_key *k = &data->key; + int i; + + RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, + "%s: keyix %u, flags %04X, macaddr %s\n", __func__, + k->wk_keyix, k->wk_flags, ether_sprintf(k->wk_macaddr)); + + rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), 0); + rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), 0); + + /* Clear key. */ + for (i = 0; i < 4; i++) + rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), 0); + clrbit(sc->keys_bmap, k->wk_keyix); +} + +static int +rtwn_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k, + int set) +{ + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + + if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { + /* Not for us. */ + return (1); + } + + if (&vap->iv_nw_keys[0] <= k && + k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { +#if __FreeBSD_version <= 1200008 + struct ieee80211_key *k1 = &vap->iv_nw_keys[k->wk_keyix]; + + if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) { + k1->wk_flags |= IEEE80211_KEY_SWCRYPT; + return (k->wk_cipher->ic_setkey(k1)); + } else { +#else + if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL) { +#endif + struct rtwn_vap *rvp = RTWN_VAP(vap); + + RTWN_LOCK(sc); + rvp->keys[k->wk_keyix] = (set ? k : NULL); + if ((sc->sc_flags & RTWN_RUNNING) == 0) { + if (!set) + clrbit(sc->keys_bmap, k->wk_keyix); + RTWN_UNLOCK(sc); + return (1); + } + RTWN_UNLOCK(sc); + } + } + + return (!rtwn_cmd_sleepable(sc, k, sizeof(*k), + set ? rtwn_key_set_cb : rtwn_key_del_cb)); +} + +int +rtwn_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + return (rtwn_process_key(vap, k, 1)); +} + +int +rtwn_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + return (rtwn_process_key(vap, k, 0)); +} diff --git a/freebsd/sys/dev/rtwn/if_rtwn_cam.h b/freebsd/sys/dev/rtwn/if_rtwn_cam.h new file mode 100644 index 00000000..280509b9 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_cam.h @@ -0,0 +1,30 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_CAM_H +#define IF_RTWN_CAM_H + +void rtwn_init_cam(struct rtwn_softc *); +void rtwn_init_seccfg(struct rtwn_softc *); +int rtwn_key_alloc(struct ieee80211vap *, struct ieee80211_key *, + ieee80211_keyix *, ieee80211_keyix *); +int rtwn_key_set(struct ieee80211vap *, const struct ieee80211_key *); +int rtwn_init_static_keys(struct rtwn_softc *, struct rtwn_vap *); +int rtwn_key_delete(struct ieee80211vap *, const struct ieee80211_key *); + +#endif /* IF_RTWN_CAM_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_debug.h b/freebsd/sys/dev/rtwn/if_rtwn_debug.h new file mode 100644 index 00000000..1559ff57 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_debug.h @@ -0,0 +1,60 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_DEBUG_H +#define IF_RTWN_DEBUG_H + +#include + +#ifdef RTWN_DEBUG +enum { + RTWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ + RTWN_DEBUG_XMIT_DESC = 0x00000002, /* xmit descriptors */ + RTWN_DEBUG_RECV = 0x00000004, /* basic recv operation */ + RTWN_DEBUG_RECV_DESC = 0x00000008, /* recv descriptors */ + RTWN_DEBUG_STATE = 0x00000010, /* 802.11 state transitions */ + RTWN_DEBUG_RA = 0x00000020, /* f/w rate adaptation setup */ + RTWN_DEBUG_USB = 0x00000040, /* usb requests */ + RTWN_DEBUG_FIRMWARE = 0x00000080, /* firmware(9) loading debug */ + RTWN_DEBUG_BEACON = 0x00000100, /* beacon handling */ + RTWN_DEBUG_INTR = 0x00000200, /* ISR */ + RTWN_DEBUG_TEMP = 0x00000400, /* temperature calibration */ + RTWN_DEBUG_ROM = 0x00000800, /* various ROM info */ + RTWN_DEBUG_KEY = 0x00001000, /* crypto keys management */ + RTWN_DEBUG_TXPWR = 0x00002000, /* dump Tx power values */ + RTWN_DEBUG_RSSI = 0x00004000, /* dump RSSI lookups */ + RTWN_DEBUG_RESET = 0x00008000, /* initialization progress */ + RTWN_DEBUG_CALIB = 0x00010000, /* calibration progress */ + RTWN_DEBUG_RADAR = 0x00020000, /* radar detection status */ + RTWN_DEBUG_ANY = 0xffffffff +}; + +#define RTWN_DPRINTF(_sc, _m, ...) do { \ + if ((_sc)->sc_debug & (_m)) \ + device_printf((_sc)->sc_dev, __VA_ARGS__); \ +} while(0) + +#else +#define RTWN_DPRINTF(_sc, _m, ...) do { (void) _sc; } while (0) +#endif + +#endif /* IF_RTWN_DEBUG_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_efuse.c b/freebsd/sys/dev/rtwn/if_rtwn_efuse.c new file mode 100644 index 00000000..bdf28a5d --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_efuse.c @@ -0,0 +1,267 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + + +static int +rtwn_efuse_switch_power(struct rtwn_softc *sc) +{ + uint32_t reg; + int error; + + error = rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON); + if (error != 0) + return (error); + + reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN); + if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { + error = rtwn_write_2(sc, R92C_SYS_FUNC_EN, + reg | R92C_SYS_FUNC_EN_ELDR); + if (error != 0) + return (error); + } + 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)) { + error = rtwn_write_2(sc, R92C_SYS_CLKR, + reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); + if (error != 0) + return (error); + } + + return (0); +} + +int +rtwn_efuse_read_next(struct rtwn_softc *sc, uint8_t *val) +{ + uint32_t reg; + int ntries, error; + + if (sc->next_rom_addr >= sc->efuse_maxlen) + return (EFAULT); + + reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); + reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->next_rom_addr); + reg &= ~R92C_EFUSE_CTRL_VALID; + + error = rtwn_write_4(sc, R92C_EFUSE_CTRL, reg); + if (error != 0) + return (error); + /* Wait for read operation to complete. */ + for (ntries = 0; ntries < 100; ntries++) { + reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); + if (reg & R92C_EFUSE_CTRL_VALID) + break; + rtwn_delay(sc, 10); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "could not read efuse byte at address 0x%x\n", + sc->next_rom_addr); + return (ETIMEDOUT); + } + + *val = MS(reg, R92C_EFUSE_CTRL_DATA); + sc->next_rom_addr++; + + return (0); +} + +static int +rtwn_efuse_read_data(struct rtwn_softc *sc, uint8_t *rom, uint8_t off, + uint8_t msk) +{ + uint8_t reg; + int addr, i, error; + + for (i = 0; i < 4; i++) { + if (msk & (1 << i)) + continue; + + addr = off * 8 + i * 2; + if (addr + 1 >= sc->efuse_maplen) + return (EFAULT); + + error = rtwn_efuse_read_next(sc, ®); + if (error != 0) + return (error); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n", + addr, reg); + rom[addr] = reg; + + error = rtwn_efuse_read_next(sc, ®); + if (error != 0) + return (error); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n", + addr + 1, reg); + rom[addr + 1] = reg; + } + + return (0); +} + +#ifdef RTWN_DEBUG +static void +rtwn_dump_rom_contents(struct rtwn_softc *sc, uint8_t *rom, uint16_t size) +{ + int i; + + /* Dump ROM contents. */ + device_printf(sc->sc_dev, "%s:", __func__); + for (i = 0; i < size; i++) { + if (i % 32 == 0) + printf("\n%03X: ", i); + else if (i % 4 == 0) + printf(" "); + + printf("%02X", rom[i]); + } + printf("\n"); +} +#endif + +static int +rtwn_efuse_read(struct rtwn_softc *sc, uint8_t *rom, uint16_t size) +{ +#define RTWN_CHK(res) do { \ + if ((error = res) != 0) \ + goto end; \ +} while(0) + uint8_t msk, off, reg; + int error; + + /* Read full ROM image. */ + sc->next_rom_addr = 0; + memset(rom, 0xff, size); + + RTWN_CHK(rtwn_efuse_read_next(sc, ®)); + while (reg != 0xff) { + /* check for extended header */ + if ((sc->sc_flags & RTWN_FLAG_EXT_HDR) && + (reg & 0x1f) == 0x0f) { + off = reg >> 5; + RTWN_CHK(rtwn_efuse_read_next(sc, ®)); + + if ((reg & 0x0f) != 0x0f) + off = ((reg & 0xf0) >> 1) | off; + else + continue; + } else + off = reg >> 4; + msk = reg & 0xf; + + RTWN_CHK(rtwn_efuse_read_data(sc, rom, off, msk)); + RTWN_CHK(rtwn_efuse_read_next(sc, ®)); + } + +end: + +#ifdef RTWN_DEBUG + if (sc->sc_debug & RTWN_DEBUG_ROM) + rtwn_dump_rom_contents(sc, rom, size); +#endif + + /* Device-specific. */ + rtwn_efuse_postread(sc); + + if (error != 0) { + device_printf(sc->sc_dev, "%s: error while reading ROM\n", + __func__); + } + + return (error); +#undef RTWN_CHK +} + +static int +rtwn_efuse_read_prepare(struct rtwn_softc *sc, uint8_t *rom, uint16_t size) +{ + int error; + + error = rtwn_efuse_switch_power(sc); + if (error != 0) + goto fail; + + error = rtwn_efuse_read(sc, rom, size); + +fail: + rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF); + + return (error); +} + +int +rtwn_read_rom(struct rtwn_softc *sc) +{ + uint8_t *rom; + int error; + + rom = malloc(sc->efuse_maplen, M_TEMP, M_WAITOK); + + /* Read full ROM image. */ + RTWN_LOCK(sc); + error = rtwn_efuse_read_prepare(sc, rom, sc->efuse_maplen); + RTWN_UNLOCK(sc); + if (error != 0) + goto fail; + + /* Parse & save data in softc. */ + rtwn_parse_rom(sc, rom); + +fail: + free(rom, M_TEMP); + + return (error); +} diff --git a/freebsd/sys/dev/rtwn/if_rtwn_efuse.h b/freebsd/sys/dev/rtwn/if_rtwn_efuse.h new file mode 100644 index 00000000..62125c24 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_efuse.h @@ -0,0 +1,25 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_EFUSE_H +#define IF_RTWN_EFUSE_H + +int rtwn_efuse_read_next(struct rtwn_softc *, uint8_t *); +int rtwn_read_rom(struct rtwn_softc *); + +#endif /* IF_RTWN_EFUSE_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_fw.c b/freebsd/sys/dev/rtwn/if_rtwn_fw.c new file mode 100644 index 00000000..a4c9506e --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_fw.c @@ -0,0 +1,226 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + + +#ifndef RTWN_WITHOUT_UCODE +static int +rtwn_fw_loadpage(struct rtwn_softc *sc, int page, const uint8_t *buf, + int len) +{ + uint32_t reg; + uint16_t off; + int mlen, error; + + reg = rtwn_read_4(sc, R92C_MCUFWDL); + reg = RW(reg, R92C_MCUFWDL_PAGE, page); + rtwn_write_4(sc, R92C_MCUFWDL, reg); + + error = 0; + off = R92C_FW_START_ADDR; + while (len > 0) { + if (len > R92C_FW_MAX_BLOCK_SIZE) + mlen = R92C_FW_MAX_BLOCK_SIZE; + else if (len > 4) + mlen = 4; + else + mlen = 1; + error = rtwn_fw_write_block(sc, buf, off, mlen); + if (error != 0) + break; + off += mlen; + buf += mlen; + len -= mlen; + } + + if (error != 0) { + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, + "%s: could not load firmware page %d (offset %u)\n", + __func__, page, off); + } + + return (error); +} + +static int +rtwn_fw_checksum_report(struct rtwn_softc *sc) +{ + int ntries; + + for (ntries = 0; ntries < 25; ntries++) { + if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT) + break; + rtwn_delay(sc, 10000); + } + if (ntries == 25) { + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, + "timeout waiting for checksum report\n"); + return (ETIMEDOUT); + } + + return (0); +} + +int +rtwn_load_firmware(struct rtwn_softc *sc) +{ + const struct firmware *fw; + const struct r92c_fw_hdr *hdr; + const u_char *ptr; + size_t len; + int ntries, error; + + /* Read firmware image from the filesystem. */ + RTWN_UNLOCK(sc); + fw = firmware_get(sc->fwname); + RTWN_LOCK(sc); + if (fw == NULL) { + device_printf(sc->sc_dev, + "failed loadfirmware of file %s\n", sc->fwname); + return (ENOENT); + } + + len = fw->datasize; + if (len < sizeof(*hdr) || len > sc->fwsize_limit) { + device_printf(sc->sc_dev, "wrong firmware size (%zu)\n", len); + error = EINVAL; + goto fail; + } + ptr = fw->data; + hdr = (const struct r92c_fw_hdr *)ptr; + /* Check if there is a valid FW header and skip it. */ + if ((le16toh(hdr->signature) >> 4) == sc->fwsig) { + sc->fwver = le16toh(hdr->version); + + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, + "FW V%u.%u %02u-%02u %02u:%02u\n", + le16toh(hdr->version), le16toh(hdr->subversion), + hdr->month, hdr->date, hdr->hour, hdr->minute); + ptr += sizeof(*hdr); + len -= sizeof(*hdr); + } + + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) { + rtwn_write_1(sc, R92C_MCUFWDL, 0); + rtwn_fw_reset(sc, RTWN_FW_RESET_DOWNLOAD); + } + + /* Enable firmware download. */ + rtwn_fw_download_enable(sc, 1); + + error = 0; /* compiler warning */ + for (ntries = 0; ntries < 3; ntries++) { + const u_char *curr_ptr = ptr; + const int maxpages = len / R92C_FW_PAGE_SIZE; + int page; + + /* Reset the FWDL checksum. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_CHKSUM_RPT); + + for (page = 0; page < maxpages; page++) { + error = rtwn_fw_loadpage(sc, page, curr_ptr, + R92C_FW_PAGE_SIZE); + if (error != 0) + break; + curr_ptr += R92C_FW_PAGE_SIZE; + } + if (page != maxpages) + continue; + + if (len % R92C_FW_PAGE_SIZE != 0) { + error = rtwn_fw_loadpage(sc, page, curr_ptr, + len % R92C_FW_PAGE_SIZE); + if (error != 0) + continue; + } + + /* Wait for checksum report. */ + error = rtwn_fw_checksum_report(sc); + if (error == 0) + break; + } + if (ntries == 3) { + device_printf(sc->sc_dev, + "%s: failed to upload firmware %s (error %d)\n", + __func__, sc->fwname, error); + goto fail; + } + + /* Disable firmware download. */ + rtwn_fw_download_enable(sc, 0); + + rtwn_setbits_4(sc, R92C_MCUFWDL, R92C_MCUFWDL_WINTINI_RDY, + R92C_MCUFWDL_RDY); + + rtwn_fw_reset(sc, RTWN_FW_RESET_CHECKSUM); + + /* Wait for firmware readiness. */ + for (ntries = 0; ntries < 20; ntries++) { + if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY) + break; + rtwn_delay(sc, 10000); + } + if (ntries == 20) { + device_printf(sc->sc_dev, + "timeout waiting for firmware readiness\n"); + error = ETIMEDOUT; + goto fail; + } +fail: + firmware_put(fw, FIRMWARE_UNLOAD); + return (error); +} +#endif diff --git a/freebsd/sys/dev/rtwn/if_rtwn_fw.h b/freebsd/sys/dev/rtwn/if_rtwn_fw.h new file mode 100644 index 00000000..41e84ee8 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_fw.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef IF_RTWN_FW_H +#define IF_RTWN_FW_H + +/* + * Firmware base address. + */ +#define R92C_FW_START_ADDR 0x1000 +#define R92C_FW_PAGE_SIZE 4096 +#define R92C_FW_MAX_BLOCK_SIZE 196 + +/* + * Firmware image header. + */ +struct r92c_fw_hdr { + /* QWORD0 */ + uint16_t signature; + uint8_t category; + uint8_t function; + uint16_t version; + uint16_t subversion; + /* QWORD1 */ + uint8_t month; + uint8_t date; + uint8_t hour; + uint8_t minute; + uint16_t ramcodesize; + uint16_t reserved2; + /* QWORD2 */ + uint32_t svnidx; + uint32_t reserved3; + /* QWORD3 */ + uint32_t reserved4; + uint32_t reserved5; +} __packed; + + +int rtwn_load_firmware(struct rtwn_softc *); + +#endif /* IF_RTWN_FW_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_nop.h b/freebsd/sys/dev/rtwn/if_rtwn_nop.h new file mode 100644 index 00000000..2b8b3e1a --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_nop.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_NOP_H +#define IF_RTWN_NOP_H + +static __inline void +rtwn_nop_softc(struct rtwn_softc *sc) +{ +} + +static __inline int +rtwn_nop_int_softc(struct rtwn_softc *sc) +{ + return (0); +} + +static __inline int +rtwn_nop_int_softc_mbuf(struct rtwn_softc *sc, struct mbuf *m) +{ + return (0); +} + +static __inline void +rtwn_nop_softc_int(struct rtwn_softc *sc, int id) +{ +} + +static __inline void +rtwn_nop_softc_uint32(struct rtwn_softc *sc, uint32_t reg) +{ +} + +static __inline void +rtwn_nop_softc_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ +} + +static __inline void +rtwn_nop_softc_vap(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ +} + +static __inline void +rtwn_nop_softc_uint8_int(struct rtwn_softc *sc, uint8_t *buf, int len) +{ +} + +static __inline void +rtwn_nop_void_int(void *buf, int is5ghz) +{ +} + +#endif /* IF_RTWN_NOP_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_ridx.h b/freebsd/sys/dev/rtwn/if_rtwn_ridx.h new file mode 100644 index 00000000..eef43898 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_ridx.h @@ -0,0 +1,94 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_RIDX_H +#define IF_RTWN_RIDX_H + +/* HW rate indices. */ +#define RTWN_RIDX_CCK1 0 +#define RTWN_RIDX_CCK2 1 +#define RTWN_RIDX_CCK55 2 +#define RTWN_RIDX_CCK11 3 +#define RTWN_RIDX_OFDM6 4 +#define RTWN_RIDX_OFDM9 5 +#define RTWN_RIDX_OFDM12 6 +#define RTWN_RIDX_OFDM18 7 +#define RTWN_RIDX_OFDM24 8 +#define RTWN_RIDX_OFDM36 9 +#define RTWN_RIDX_OFDM48 10 +#define RTWN_RIDX_OFDM54 11 +#define RTWN_RIDX_MCS(i) (12 + (i)) + +#define RTWN_RIDX_COUNT 28 +#define RTWN_RIDX_UNKNOWN (uint8_t)-1 + +#define RTWN_RATE_IS_CCK(rate) ((rate) <= RTWN_RIDX_CCK11) +#define RTWN_RATE_IS_OFDM(rate) \ + ((rate) >= RTWN_RIDX_OFDM6 && (rate) != RTWN_RIDX_UNKNOWN) + + +static const uint8_t ridx2rate[] = + { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; + +static __inline uint8_t +rate2ridx(uint8_t rate) +{ + if (rate & IEEE80211_RATE_MCS) { + /* 11n rates start at idx 12 */ + return ((rate & 0xf) + 12); + } + switch (rate) { + /* 11g */ + case 12: return 4; + case 18: return 5; + case 24: return 6; + case 36: return 7; + case 48: return 8; + case 72: return 9; + case 96: return 10; + case 108: return 11; + /* 11b */ + case 2: return 0; + case 4: return 1; + case 11: return 2; + case 22: return 3; + default: return RTWN_RIDX_UNKNOWN; + } +} + +/* XXX move to net80211 */ +static __inline__ uint8_t +rtwn_ctl_mcsrate(const struct ieee80211_rate_table *rt, uint8_t ridx) +{ + uint8_t cix, rate; + + /* Check if we are using MCS rate. */ + KASSERT(ridx >= RTWN_RIDX_MCS(0) && ridx != RTWN_RIDX_UNKNOWN, + ("bad mcs rate index %d", ridx)); + + rate = (ridx - RTWN_RIDX_MCS(0)) | IEEE80211_RATE_MCS; + cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex; + KASSERT(cix != (uint8_t)-1, ("rate %d (%d) has no info", rate, ridx)); + return rt->info[cix].dot11Rate; +} + +#endif /* IF_RTWN_RIDX_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_rx.c b/freebsd/sys/dev/rtwn/if_rtwn_rx.c new file mode 100644 index 00000000..8d103dc7 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_rx.c @@ -0,0 +1,466 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + + +void +rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs, + const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p, + int *maxrate_p, int basic_rates) +{ + uint32_t rates; + uint8_t ridx; + int i, maxrate; + + /* Get rates mask. */ + rates = 0; + maxrate = 0; + + /* This is for 11bg */ + for (i = 0; i < rs->rs_nrates; i++) { + /* Convert 802.11 rate to HW rate index. */ + ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i])); + if (ridx == RTWN_RIDX_UNKNOWN) /* Unknown rate, skip. */ + continue; + if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) || + !basic_rates) { + rates |= 1 << ridx; + if (ridx > maxrate) + maxrate = ridx; + } + } + + /* If we're doing 11n, enable 11n rates */ + if (rs_ht != NULL && !basic_rates) { + for (i = 0; i < rs_ht->rs_nrates; i++) { + if ((rs_ht->rs_rates[i] & 0x7f) > 0xf) + continue; + /* 11n rates start at index 12 */ + ridx = RTWN_RIDX_MCS((rs_ht->rs_rates[i]) & 0xf); + rates |= (1 << ridx); + + /* Guard against the rate table being oddly ordered */ + if (ridx > maxrate) + maxrate = ridx; + } + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_RA, + "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate); + + if (rates_p != NULL) + *rates_p = rates; + if (maxrate_p != NULL) + *maxrate_p = maxrate; +} + +void +rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates) +{ + + RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates); + + rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates); +} + +static void +rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int rate) +{ + int pwdb; + + /* Convert antenna signal to percentage. */ + if (un->last_rssi <= -100 || un->last_rssi >= 20) + pwdb = 0; + else if (un->last_rssi >= 0) + pwdb = 100; + else + pwdb = 100 + un->last_rssi; + if (RTWN_RATE_IS_CCK(rate)) { + /* CCK gain is smaller than OFDM/MCS gain. */ + pwdb += 6; + if (pwdb > 100) + pwdb = 100; + if (pwdb <= 14) + pwdb -= 4; + else if (pwdb <= 26) + pwdb -= 8; + else if (pwdb <= 34) + pwdb -= 6; + else if (pwdb <= 42) + pwdb -= 2; + } + + if (un->avg_pwdb == -1) /* Init. */ + un->avg_pwdb = pwdb; + else if (un->avg_pwdb < pwdb) + un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20) + 1; + else + un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, + "MACID %d, PWDB %d, EMA %d\n", un->id, pwdb, un->avg_pwdb); +} + +static int8_t +rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt) +{ + int8_t rssi; + + if (RTWN_RATE_IS_CCK(rate)) + rssi = rtwn_get_rssi_cck(sc, physt); + else /* OFDM/HT. */ + rssi = rtwn_get_rssi_ofdm(sc, physt); + + return (rssi); +} + +static uint32_t +rtwn_get_tsf_low(struct rtwn_softc *sc, int id) +{ + return (rtwn_read_4(sc, R92C_TSFTR(id))); +} + +static uint32_t +rtwn_get_tsf_high(struct rtwn_softc *sc, int id) +{ + return (rtwn_read_4(sc, R92C_TSFTR(id) + 4)); +} + +static void +rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id) +{ + /* NB: we cannot read it at once. */ + *buf = rtwn_get_tsf_high(sc, id); + *buf <<= 32; + *buf += rtwn_get_tsf_low(sc, id); +} + +struct ieee80211_node * +rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc, + int8_t *rssi) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + struct ieee80211_frame_min *wh; + struct rtwn_node *un; + struct r92c_rx_stat *stat; + uint32_t rxdw0, rxdw3; + int cipher, infosz, pktlen, rate, shift; + + stat = desc; + rxdw0 = le32toh(stat->rxdw0); + rxdw3 = le32toh(stat->rxdw3); + + cipher = MS(rxdw0, R92C_RXDW0_CIPHER); + infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + shift = MS(rxdw0, R92C_RXDW0_SHIFT); + rate = MS(rxdw3, R92C_RXDW3_RATE); + + wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz)); + if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && + cipher != R92C_CAM_ALGO_NONE) + m->m_flags |= M_WEP; + + if (pktlen >= sizeof(*wh)) + ni = ieee80211_find_rxnode(ic, wh); + else + ni = NULL; + un = RTWN_NODE(ni); + + /* Get RSSI from PHY status descriptor if present. */ + if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { + *rssi = rtwn_get_rssi(sc, rate, mtod(m, void *)); + RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, ridx %d\n", + __func__, *rssi, rate); + + sc->last_rssi = *rssi; + if (un != NULL) { + un->last_rssi = *rssi; + + /* Update our average RSSI. */ + rtwn_update_avgrssi(sc, un, rate); + } + } else + *rssi = (un != NULL) ? un->last_rssi : sc->last_rssi; + + if (ieee80211_radiotap_active(ic)) { + struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap; + int id = RTWN_VAP_ID_INVALID; + + if (ni != NULL) + id = RTWN_VAP(ni->ni_vap)->id; + if (id == RTWN_VAP_ID_INVALID) + id = 0; + + tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc); + tap->wr_tsft = rtwn_get_tsf_high(sc, id); + if (le32toh(stat->tsf_low) > rtwn_get_tsf_low(sc, id)) + tap->wr_tsft--; + tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32; + tap->wr_tsft += stat->tsf_low; + + /* XXX 20/40? */ + + /* Map HW rate index to 802.11 rate. */ + if (rate < RTWN_RIDX_MCS(0)) + tap->wr_rate = ridx2rate[rate]; + else /* MCS0~15. */ + tap->wr_rate = IEEE80211_RATE_MCS | (rate - 12); + + tap->wr_dbm_antsignal = *rssi; + tap->wr_dbm_antnoise = RTWN_NOISE_FLOOR; + } + + /* Drop PHY descriptor. */ + m_adj(m, infosz + shift); + + return (ni); +} + +void +rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, + const struct ieee80211_rx_stats *rxs, + int rssi, int nf) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); + uint64_t ni_tstamp, curr_tstamp; + + uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf); + + if (vap->iv_state == IEEE80211_S_RUN && + (subtype == IEEE80211_FC0_SUBTYPE_BEACON || + subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { + ni_tstamp = le64toh(ni->ni_tstamp.tsf); + RTWN_LOCK(sc); + rtwn_get_tsf(sc, &curr_tstamp, uvp->id); + RTWN_UNLOCK(sc); + + if (ni_tstamp >= curr_tstamp) + (void) ieee80211_ibss_merge(ni); + } +} + +static uint8_t +rtwn_get_multi_pos(const uint8_t maddr[]) +{ + uint64_t mask = 0x00004d101df481b4; + uint8_t pos = 0x27; /* initial value */ + int i, j; + + for (i = 0; i < IEEE80211_ADDR_LEN; i++) + for (j = (i == 0) ? 1 : 0; j < 8; j++) + if ((maddr[i] >> j) & 1) + pos ^= (mask >> (i * 8 + j - 1)); + + pos &= 0x3f; + + return (pos); +} + +void +rtwn_set_multi(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t mfilt[2]; + + RTWN_ASSERT_LOCKED(sc); + + /* general structure was copied from ath(4). */ + if (ic->ic_allmulti == 0) { + struct ieee80211vap *vap; + struct ifnet *ifp; + struct ifmultiaddr *ifma; + + /* + * Merge multicast addresses to form the hardware filter. + */ + mfilt[0] = mfilt[1] = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + ifp = vap->iv_ifp; + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + caddr_t dl; + uint8_t pos; + + dl = LLADDR((struct sockaddr_dl *) + ifma->ifma_addr); + pos = rtwn_get_multi_pos(dl); + + mfilt[pos / 32] |= (1 << (pos % 32)); + } + if_maddr_runlock(ifp); + } + } else + mfilt[0] = mfilt[1] = ~0; + + + rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]); + rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]); + + RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n", + __func__, mfilt[0], mfilt[1]); +} + +static void +rtwn_rxfilter_update_mgt(struct rtwn_softc *sc) +{ + uint16_t filter; + + filter = 0x7f7f; + if (sc->bcn_vaps == 0) { /* STA and/or MONITOR mode vaps */ + filter &= ~( + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) | + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) | + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ)); + } + if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) { /* AP vaps only */ + filter &= ~( + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP)); + } + rtwn_write_2(sc, R92C_RXFLTMAP0, filter); +} + +void +rtwn_rxfilter_update(struct rtwn_softc *sc) +{ + + RTWN_ASSERT_LOCKED(sc); + + /* Filter for management frames. */ + rtwn_rxfilter_update_mgt(sc); + + /* Update Rx filter. */ + rtwn_set_promisc(sc); +} + +void +rtwn_rxfilter_init(struct rtwn_softc *sc) +{ + + RTWN_ASSERT_LOCKED(sc); + + /* Setup multicast filter. */ + rtwn_set_multi(sc); + + /* Reject all control frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); + + /* Reject all data frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000); + + /* Append generic Rx filter bits. */ + sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM | + R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | + R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; + + /* Update dynamic Rx filter parts. */ + rtwn_rxfilter_update(sc); +} + +void +rtwn_rxfilter_set(struct rtwn_softc *sc) +{ + if (!(sc->sc_flags & RTWN_RCR_LOCKED)) + rtwn_write_4(sc, R92C_RCR, sc->rcr); +} + +void +rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable) +{ + + if (enable) + sc->rcr &= ~R92C_RCR_CBSSID_BCN; + else + sc->rcr |= R92C_RCR_CBSSID_BCN; + rtwn_rxfilter_set(sc); +} + +void +rtwn_set_promisc(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t mask_all, mask_min; + + RTWN_ASSERT_LOCKED(sc); + + mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; + mask_min = R92C_RCR_APM; + + if (sc->bcn_vaps == 0) + mask_min |= R92C_RCR_CBSSID_BCN; + if (sc->ap_vaps == 0) + mask_min |= R92C_RCR_CBSSID_DATA; + + if (ic->ic_promisc == 0 && sc->mon_vaps == 0) { + if (sc->bcn_vaps != 0) + mask_all |= R92C_RCR_CBSSID_BCN; + if (sc->ap_vaps != 0) /* for Null data frames */ + mask_all |= R92C_RCR_CBSSID_DATA; + + sc->rcr &= ~mask_all; + sc->rcr |= mask_min; + } else { + sc->rcr &= ~mask_min; + sc->rcr |= mask_all; + } + rtwn_rxfilter_set(sc); +} diff --git a/freebsd/sys/dev/rtwn/if_rtwn_rx.h b/freebsd/sys/dev/rtwn/if_rtwn_rx.h new file mode 100644 index 00000000..dfdcc4bf --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_rx.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_RX_H +#define IF_RTWN_RX_H + +#define RTWN_NOISE_FLOOR -95 + + +void rtwn_get_rates(struct rtwn_softc *, const struct ieee80211_rateset *, + const struct ieee80211_htrateset *, uint32_t *, int *, int); +void rtwn_set_basicrates(struct rtwn_softc *, uint32_t); +struct ieee80211_node * rtwn_rx_common(struct rtwn_softc *, struct mbuf *, + void *, int8_t *); +void rtwn_adhoc_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, + const struct ieee80211_rx_stats *, int, int); +void rtwn_set_multi(struct rtwn_softc *); +void rtwn_rxfilter_update(struct rtwn_softc *); +void rtwn_rxfilter_init(struct rtwn_softc *); +void rtwn_rxfilter_set(struct rtwn_softc *); +void rtwn_set_rx_bssid_all(struct rtwn_softc *, int); +void rtwn_set_promisc(struct rtwn_softc *); + +#endif /* IF_RTWN_RX_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_task.c b/freebsd/sys/dev/rtwn/if_rtwn_task.c new file mode 100644 index 00000000..ecff85a5 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_task.c @@ -0,0 +1,124 @@ +#include + +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + + +static void +rtwn_cmdq_cb(void *arg, int pending) +{ + struct rtwn_softc *sc = arg; + struct rtwn_cmdq *item; + + /* + * Device must be powered on (via rtwn_power_on()) + * before any command may be sent. + */ + RTWN_LOCK(sc); + if (!(sc->sc_flags & RTWN_RUNNING)) { + RTWN_UNLOCK(sc); + return; + } + + RTWN_CMDQ_LOCK(sc); + while (sc->cmdq[sc->cmdq_first].func != NULL) { + item = &sc->cmdq[sc->cmdq_first]; + sc->cmdq_first = (sc->cmdq_first + 1) % RTWN_CMDQ_SIZE; + RTWN_CMDQ_UNLOCK(sc); + + item->func(sc, &item->data); + + RTWN_CMDQ_LOCK(sc); + memset(item, 0, sizeof (*item)); + } + RTWN_CMDQ_UNLOCK(sc); + RTWN_UNLOCK(sc); +} + +void +rtwn_cmdq_init(struct rtwn_softc *sc) +{ + RTWN_CMDQ_LOCK_INIT(sc); + TASK_INIT(&sc->cmdq_task, 0, rtwn_cmdq_cb, sc); +} + +void +rtwn_cmdq_destroy(struct rtwn_softc *sc) +{ + if (RTWN_CMDQ_LOCK_INITIALIZED(sc)) + RTWN_CMDQ_LOCK_DESTROY(sc); +} + +int +rtwn_cmd_sleepable(struct rtwn_softc *sc, const void *ptr, size_t len, + CMD_FUNC_PROTO) +{ + struct ieee80211com *ic = &sc->sc_ic; + + KASSERT(len <= sizeof(union sec_param), ("buffer overflow")); + + RTWN_CMDQ_LOCK(sc); + if (sc->sc_detached) { + RTWN_CMDQ_UNLOCK(sc); + return (ESHUTDOWN); + } + + if (sc->cmdq[sc->cmdq_last].func != NULL) { + device_printf(sc->sc_dev, "%s: cmdq overflow\n", __func__); + RTWN_CMDQ_UNLOCK(sc); + + return (EAGAIN); + } + + if (ptr != NULL) + memcpy(&sc->cmdq[sc->cmdq_last].data, ptr, len); + sc->cmdq[sc->cmdq_last].func = func; + sc->cmdq_last = (sc->cmdq_last + 1) % RTWN_CMDQ_SIZE; + RTWN_CMDQ_UNLOCK(sc); + + ieee80211_runtask(ic, &sc->cmdq_task); + + return (0); +} diff --git a/freebsd/sys/dev/rtwn/if_rtwn_task.h b/freebsd/sys/dev/rtwn/if_rtwn_task.h new file mode 100644 index 00000000..a9d60c20 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_task.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_TASK_H +#define IF_RTWN_TASK_H + +void rtwn_cmdq_init(struct rtwn_softc *); +void rtwn_cmdq_destroy(struct rtwn_softc *); +int rtwn_cmd_sleepable(struct rtwn_softc *, const void *, size_t, + CMD_FUNC_PROTO); + +#endif /* IF_RTWN_TASK_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_tx.c b/freebsd/sys/dev/rtwn/if_rtwn_tx.c new file mode 100644 index 00000000..1ea9a766 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_tx.c @@ -0,0 +1,348 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#ifdef IEEE80211_SUPPORT_SUPERG +#include +#endif + +#include +#include + +#include +#include +#include +#include + + +void +rtwn_drain_mbufq(struct rtwn_softc *sc) +{ + struct mbuf *m; + struct ieee80211_node *ni; + RTWN_ASSERT_LOCKED(sc); + while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + ieee80211_free_node(ni); + m_freem(m); + } +} + +#ifdef IEEE80211_SUPPORT_SUPERG +void +rtwn_ff_flush_all(struct rtwn_softc *sc, union sec_param *data) +{ + struct ieee80211com *ic = &sc->sc_ic; + + RTWN_UNLOCK(sc); + ieee80211_ff_flush_all(ic); + RTWN_LOCK(sc); +} +#endif + +static uint8_t +rtwn_get_cipher(u_int ic_cipher) +{ + uint8_t cipher; + + switch (ic_cipher) { + case IEEE80211_CIPHER_NONE: + cipher = RTWN_TXDW1_CIPHER_NONE; + break; + case IEEE80211_CIPHER_WEP: + case IEEE80211_CIPHER_TKIP: + cipher = RTWN_TXDW1_CIPHER_RC4; + break; + case IEEE80211_CIPHER_AES_CCM: + cipher = RTWN_TXDW1_CIPHER_AES; + break; + default: + KASSERT(0, ("%s: unknown cipher %d\n", __func__, + ic_cipher)); + return (RTWN_TXDW1_CIPHER_SM4); + } + + return (cipher); +} + +static int +rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m) +{ + const struct ieee80211_txparam *tp; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_key *k = NULL; + struct ieee80211_channel *chan; + struct ieee80211_frame *wh; + struct rtwn_tx_desc_common *txd; + struct rtwn_tx_buf buf; + uint8_t rate, ridx, type; + u_int cipher; + int ismcast, maxretry; + + RTWN_ASSERT_LOCKED(sc); + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? + ni->ni_chan : ic->ic_curchan; + tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; + maxretry = tp->maxretry; + + /* Choose a TX rate index. */ + if (type == IEEE80211_FC0_TYPE_MGT) + rate = tp->mgmtrate; + else if (ismcast) + rate = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + rate = tp->ucastrate; + else if (m->m_flags & M_EAPOL) + rate = tp->mgmtrate; + else { + if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { + /* XXX pass pktlen */ + (void) ieee80211_ratectl_rate(ni, NULL, 0); + rate = ni->ni_txrate; + } else { + if (ni->ni_flags & IEEE80211_NODE_HT) + rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */ + else if (ic->ic_curmode != IEEE80211_MODE_11B) + rate = ridx2rate[RTWN_RIDX_OFDM36]; + else + rate = ridx2rate[RTWN_RIDX_CCK55]; + } + } + + ridx = rate2ridx(rate); + + cipher = IEEE80211_CIPHER_NONE; + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + device_printf(sc->sc_dev, + "ieee80211_crypto_encap returns NULL.\n"); + return (ENOBUFS); + } + if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) + cipher = k->wk_cipher->ic_cipher; + + /* in case packet header moved, reset pointer */ + wh = mtod(m, struct ieee80211_frame *); + } + + /* Fill Tx descriptor. */ + txd = (struct rtwn_tx_desc_common *)&buf; + memset(txd, 0, sc->txdesc_len); + txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); + + rtwn_fill_tx_desc(sc, ni, m, txd, ridx, maxretry); + + if (ieee80211_radiotap_active_vap(vap)) { + struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); + if (k != NULL) + tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; + ieee80211_radiotap_tx(vap, m); + } + + return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); +} + +static int +rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, const struct ieee80211_bpf_params *params) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_key *k = NULL; + struct ieee80211_frame *wh; + struct rtwn_tx_desc_common *txd; + struct rtwn_tx_buf buf; + uint8_t type; + u_int cipher; + + /* Encrypt the frame if need be. */ + cipher = IEEE80211_CIPHER_NONE; + if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { + /* Retrieve key for TX. */ + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + device_printf(sc->sc_dev, + "ieee80211_crypto_encap returns NULL.\n"); + return (ENOBUFS); + } + if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) + cipher = k->wk_cipher->ic_cipher; + } + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + + /* Fill Tx descriptor. */ + txd = (struct rtwn_tx_desc_common *)&buf; + memset(txd, 0, sc->txdesc_len); + txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); + + rtwn_fill_tx_desc_raw(sc, ni, m, txd, params); + + if (ieee80211_radiotap_active_vap(vap)) { + struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); + if (k != NULL) + tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; + ieee80211_radiotap_tx(vap, m); + } + + return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); +} + +int +rtwn_transmit(struct ieee80211com *ic, struct mbuf *m) +{ + struct rtwn_softc *sc = ic->ic_softc; + int error; + + RTWN_LOCK(sc); + if ((sc->sc_flags & RTWN_RUNNING) == 0) { + RTWN_UNLOCK(sc); + return (ENXIO); + } + error = mbufq_enqueue(&sc->sc_snd, m); + if (error) { + RTWN_UNLOCK(sc); + return (error); + } + rtwn_start(sc); + RTWN_UNLOCK(sc); + + return (0); +} + +void +rtwn_start(struct rtwn_softc *sc) +{ + struct ieee80211_node *ni; + struct mbuf *m; + + RTWN_ASSERT_LOCKED(sc); + while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + if (sc->qfullmsk != 0) { + mbufq_prepend(&sc->sc_snd, m); + break; + } + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: called; m %p, ni %p\n", __func__, m, ni); + + if (rtwn_tx_data(sc, ni, m) != 0) { + if_inc_counter(ni->ni_vap->iv_ifp, + IFCOUNTER_OERRORS, 1); + m_freem(m); +#ifdef D4054 + ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0); +#endif + ieee80211_free_node(ni); + break; + } + } +} + +int +rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = ni->ni_ic; + struct rtwn_softc *sc = ic->ic_softc; + int error; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n", + __func__, m, ni); + + /* prevent management frames from being sent if we're not ready */ + RTWN_LOCK(sc); + if (!(sc->sc_flags & RTWN_RUNNING)) { + error = ENETDOWN; + goto end; + } + + if (sc->qfullmsk != 0) { + error = ENOBUFS; + goto end; + } + + if (params == NULL) { + /* + * Legacy path; interpret frame contents to decide + * precisely how to send the frame. + */ + error = rtwn_tx_data(sc, ni, m); + } else { + /* + * Caller supplied explicit parameters to use in + * sending the frame. + */ + error = rtwn_tx_raw(sc, ni, m, params); + } + +end: + if (error != 0) { + if (m->m_flags & M_TXCB) + ieee80211_process_callback(ni, m, 1); + m_freem(m); + } + + RTWN_UNLOCK(sc); + + return (error); +} diff --git a/freebsd/sys/dev/rtwn/if_rtwn_tx.h b/freebsd/sys/dev/rtwn/if_rtwn_tx.h new file mode 100644 index 00000000..e02fb564 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwn_tx.h @@ -0,0 +1,31 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_TX_H +#define IF_RTWN_TX_H + +void rtwn_drain_mbufq(struct rtwn_softc *); +#ifdef IEEE80211_SUPPORT_SUPERG +void rtwn_ff_flush_all(struct rtwn_softc *, union sec_param *); +#endif +int rtwn_transmit(struct ieee80211com *, struct mbuf *); +void rtwn_start(struct rtwn_softc *); +int rtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); + +#endif /* IF_RTWN_TX_H */ diff --git a/freebsd/sys/dev/rtwn/if_rtwnreg.h b/freebsd/sys/dev/rtwn/if_rtwnreg.h new file mode 100644 index 00000000..9dc830a2 --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwnreg.h @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#define R92C_MIN_TX_PWR 0x00 +#define R92C_MAX_TX_PWR 0x3f + +#define R92C_H2C_NBOX 4 + + +/* Common part of Tx descriptor (named only!). */ +struct rtwn_tx_desc_common { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; +#define RTWN_FLAGS0_OWN 0x80 + + uint32_t txdw1; +/* NB: qsel is shared too; however, it looks better at the lower level */ +#define RTWN_TXDW1_CIPHER_M 0x00c00000 +#define RTWN_TXDW1_CIPHER_S 22 +#define RTWN_TXDW1_CIPHER_NONE 0 +#define RTWN_TXDW1_CIPHER_RC4 1 +#define RTWN_TXDW1_CIPHER_SM4 2 +#define RTWN_TXDW1_CIPHER_AES 3 + + uint32_t reserved[5]; + + union txdw7_shared { + uint16_t usb_checksum; + uint16_t pci_txbufsize; + } txdw7; +} __packed __attribute__((aligned(4))); + +/* + * Macros to access subfields in registers. + */ +/* Mask and Shift (getter). */ +#define MS(val, field) \ + (((val) & field##_M) >> field##_S) + +/* Shift and Mask (setter). */ +#define SM(field, val) \ + (((val) << field##_S) & field##_M) + +/* Rewrite. */ +#define RW(var, field, val) \ + (((var) & ~field##_M) | SM(field, val)) + + +#define RTWN_MAX_CONDITIONS 3 + +/* + * Structure for MAC initialization values. + */ +struct rtwn_mac_prog { + uint16_t reg; + uint8_t val; +}; + +/* + * Structure for baseband initialization values. + */ +struct rtwn_bb_prog { + int count; + const uint16_t *reg; + const uint32_t *val; + const uint8_t cond[RTWN_MAX_CONDITIONS]; + const struct rtwn_bb_prog *next; +}; + +struct rtwn_agc_prog { + int count; + const uint32_t *val; + const uint8_t cond[RTWN_MAX_CONDITIONS]; + const struct rtwn_agc_prog *next; +}; + +/* + * Structure for RF initialization values. + */ +struct rtwn_rf_prog { + int count; + const uint8_t *reg; + const uint32_t *val; + const uint8_t cond[RTWN_MAX_CONDITIONS]; + const struct rtwn_rf_prog *next; +}; + + +/* XXX move to net80211. */ +static __inline int +rtwn_chan2centieee(const struct ieee80211_channel *c) +{ + int chan; + + chan = c->ic_ieee; + if (c->ic_extieee != 0) + chan = (chan + c->ic_extieee) / 2; + + return (chan); +} diff --git a/freebsd/sys/dev/rtwn/if_rtwnvar.h b/freebsd/sys/dev/rtwn/if_rtwnvar.h new file mode 100644 index 00000000..0c010adb --- /dev/null +++ b/freebsd/sys/dev/rtwn/if_rtwnvar.h @@ -0,0 +1,624 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef IF_RTWNVAR_H +#define IF_RTWNVAR_H + +#include + +#define RTWN_TX_DESC_SIZE 64 + +#define RTWN_TXBUFSZ (16 * 1024) + +#define RTWN_BCN_MAX_SIZE 512 +#define RTWN_CAM_ENTRY_LIMIT 64 + +#define RTWN_MACID_BC 1 /* Broadcast. */ +#define RTWN_MACID_UNDEFINED 0x7fff +#define RTWN_MACID_VALID 0x8000 +#define RTWN_MACID_LIMIT 128 + +#define RTWN_TX_TIMEOUT 5000 /* ms */ +#define RTWN_MAX_EPOUT 4 +#define RTWN_PORT_COUNT 2 + +#define RTWN_LED_LINK 0 +#define RTWN_LED_DATA 1 + +struct rtwn_rx_radiotap_header { + struct ieee80211_radiotap_header wr_ihdr; + uint64_t wr_tsft; + uint8_t wr_flags; + uint8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + int8_t wr_dbm_antsignal; + int8_t wr_dbm_antnoise; +} __packed __aligned(8); + +#define RTWN_RX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_TSFT | \ + 1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_RATE | \ + 1 << IEEE80211_RADIOTAP_CHANNEL | \ + 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL | \ + 1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) + +struct rtwn_tx_radiotap_header { + struct ieee80211_radiotap_header wt_ihdr; + uint8_t wt_flags; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; +} __packed __aligned(8); + +#define RTWN_TX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_CHANNEL) + +struct rtwn_tx_buf { + uint8_t txd[RTWN_TX_DESC_SIZE]; +} __attribute__((aligned(4))); + +struct rtwn_softc; + +union sec_param { + struct ieee80211_key key; + int macid; +}; + +#define CMD_FUNC_PROTO void (*func)(struct rtwn_softc *, \ + union sec_param *) + +struct rtwn_cmdq { + union sec_param data; + CMD_FUNC_PROTO; +}; +#define RTWN_CMDQ_SIZE 16 + +struct rtwn_node { + struct ieee80211_node ni; /* must be the first */ + int id; + int8_t last_rssi; + int avg_pwdb; +}; +#define RTWN_NODE(ni) ((struct rtwn_node *)(ni)) + +struct rtwn_vap { + struct ieee80211vap vap; + int id; +#define RTWN_VAP_ID_INVALID -1 + int curr_mode; + + struct rtwn_tx_buf bcn_desc; + struct mbuf *bcn_mbuf; + struct timeout_task tx_beacon_csa; + + struct callout tsf_sync_adhoc; + struct task tsf_sync_adhoc_task; + + const struct ieee80211_key *keys[IEEE80211_WEP_NKID]; + + int (*newstate)(struct ieee80211vap *, + enum ieee80211_state, int); + void (*recv_mgmt)(struct ieee80211_node *, + struct mbuf *, int, + const struct ieee80211_rx_stats *, + int, int); +}; +#define RTWN_VAP(vap) ((struct rtwn_vap *)(vap)) + +/* + * Rx data types. + */ +enum { + RTWN_RX_DATA, + RTWN_RX_TX_REPORT, + RTWN_RX_OTHER +}; + +/* + * Firmware reset reasons. + */ +enum { + RTWN_FW_RESET_DOWNLOAD, + RTWN_FW_RESET_CHECKSUM, + RTWN_FW_RESET_SHUTDOWN +}; + +/* + * Rate control algorithm selection. + */ +enum { + RTWN_RATECTL_NONE, + RTWN_RATECTL_NET80211, + RTWN_RATECTL_FW, + RTWN_RATECTL_MAX +}; + +/* + * Control h/w crypto usage. + */ +enum { + RTWN_CRYPTO_SW, + RTWN_CRYPTO_PAIR, + RTWN_CRYPTO_FULL, + RTWN_CRYPTO_MAX, +}; + +struct rtwn_softc { + struct ieee80211com sc_ic; + struct mbufq sc_snd; + device_t sc_dev; + +#if 1 + int sc_ht40; +#endif + uint32_t sc_debug; + int sc_hwcrypto; + int sc_ratectl_sysctl; + int sc_ratectl; + + uint8_t sc_detached; + uint8_t sc_flags; +/* Device flags */ +#define RTWN_FLAG_CCK_HIPWR 0x01 +#define RTWN_FLAG_EXT_HDR 0x02 +#define RTWN_FLAG_CAM_FIXED 0x04 +/* Driver state */ +#define RTWN_STARTED 0x08 +#define RTWN_RUNNING 0x10 +#define RTWN_FW_LOADED 0x20 +#define RTWN_TEMP_MEASURED 0x40 +#define RTWN_RCR_LOCKED 0x80 + +#define RTWN_CHIP_HAS_BCNQ1(_sc) \ + ((_sc)->bcn_status_reg[0] != (_sc)->bcn_status_reg[1]) + + void *sc_priv; + const char *name; + int sc_ant; + + int8_t last_rssi; + uint8_t thcal_temp; + int cur_bcnq_id; + + int nvaps; + int ap_vaps; + int bcn_vaps; + int mon_vaps; + + int vaps_running; + int monvaps_running; + + uint16_t next_rom_addr; + uint8_t keys_bmap[howmany(RTWN_CAM_ENTRY_LIMIT, NBBY)]; + + struct rtwn_vap *vaps[RTWN_PORT_COUNT]; + struct ieee80211_node *node_list[RTWN_MACID_LIMIT]; + struct mtx nt_mtx; + + struct callout sc_calib_to; + struct callout sc_pwrmode_init; +#ifndef D4054 + struct callout sc_watchdog_to; + int sc_tx_timer; +#endif + + struct mtx sc_mtx; + + struct rtwn_cmdq cmdq[RTWN_CMDQ_SIZE]; + struct mtx cmdq_mtx; + struct task cmdq_task; + uint8_t cmdq_first; + uint8_t cmdq_last; + + struct wmeParams cap_wmeParams[WME_NUM_AC]; + + struct rtwn_rx_radiotap_header sc_rxtap; + struct rtwn_tx_radiotap_header sc_txtap; + + int ntxchains; + int nrxchains; + + int ledlink; + uint8_t thermal_meter; + + int sc_tx_n_active; + uint8_t qfullmsk; + + /* Firmware-specific */ + const char *fwname; + uint16_t fwver; + uint16_t fwsig; + int fwcur; + + void (*sc_node_free)(struct ieee80211_node *); + void (*sc_scan_curchan)(struct ieee80211_scan_state *, + unsigned long); + + /* Interface-specific. */ + int (*sc_write_1)(struct rtwn_softc *, uint16_t, + uint8_t); + int (*sc_write_2)(struct rtwn_softc *, uint16_t, + uint16_t); + int (*sc_write_4)(struct rtwn_softc *, uint16_t, + uint32_t); + uint8_t (*sc_read_1)(struct rtwn_softc *, uint16_t); + uint16_t (*sc_read_2)(struct rtwn_softc *, uint16_t); + uint32_t (*sc_read_4)(struct rtwn_softc *, uint16_t); + /* XXX eliminate */ + void (*sc_delay)(struct rtwn_softc *, int); + int (*sc_tx_start)(struct rtwn_softc *, + struct ieee80211_node *, struct mbuf *, uint8_t *, + uint8_t, int); + void (*sc_start_xfers)(struct rtwn_softc *); + void (*sc_reset_lists)(struct rtwn_softc *, + struct ieee80211vap *); + void (*sc_abort_xfers)(struct rtwn_softc *); + int (*sc_fw_write_block)(struct rtwn_softc *, + const uint8_t *, uint16_t, int); + uint16_t (*sc_get_qmap)(struct rtwn_softc *); + void (*sc_set_desc_addr)(struct rtwn_softc *); + void (*sc_drop_incorrect_tx)(struct rtwn_softc *); + void (*sc_beacon_update_begin)(struct rtwn_softc *, + struct ieee80211vap *); + void (*sc_beacon_update_end)(struct rtwn_softc *, + struct ieee80211vap *); + void (*sc_beacon_unload)(struct rtwn_softc *, int); + + /* XXX drop checks for PCIe? */ + int bcn_check_interval; + + /* Device-specific. */ + uint32_t (*sc_rf_read)(struct rtwn_softc *, int, uint8_t); + void (*sc_rf_write)(struct rtwn_softc *, int, uint8_t, + uint32_t); + int (*sc_check_condition)(struct rtwn_softc *, + const uint8_t[]); + void (*sc_efuse_postread)(struct rtwn_softc *); + void (*sc_parse_rom)(struct rtwn_softc *, uint8_t *); + void (*sc_set_led)(struct rtwn_softc *, int, int); + int (*sc_power_on)(struct rtwn_softc *); + void (*sc_power_off)(struct rtwn_softc *); +#ifndef RTWN_WITHOUT_UCODE + void (*sc_fw_reset)(struct rtwn_softc *, int); + void (*sc_fw_download_enable)(struct rtwn_softc *, int); +#endif + int (*sc_set_page_size)(struct rtwn_softc *); + void (*sc_lc_calib)(struct rtwn_softc *); + void (*sc_iq_calib)(struct rtwn_softc *); + void (*sc_read_chipid_vendor)(struct rtwn_softc *, + uint32_t); + void (*sc_adj_devcaps)(struct rtwn_softc *); + void (*sc_vap_preattach)(struct rtwn_softc *, + struct ieee80211vap *); + void (*sc_postattach)(struct rtwn_softc *); + void (*sc_detach_private)(struct rtwn_softc *); + void (*sc_fill_tx_desc)(struct rtwn_softc *, + struct ieee80211_node *, struct mbuf *, + void *, uint8_t, int); + void (*sc_fill_tx_desc_raw)(struct rtwn_softc *, + struct ieee80211_node *, struct mbuf *, + void *, const struct ieee80211_bpf_params *); + void (*sc_fill_tx_desc_null)(struct rtwn_softc *, + void *, int, int, int); + void (*sc_dump_tx_desc)(struct rtwn_softc *, const void *); + uint8_t (*sc_tx_radiotap_flags)(const void *); + uint8_t (*sc_rx_radiotap_flags)(const void *); + void (*sc_beacon_init)(struct rtwn_softc *, void *, int); + void (*sc_beacon_enable)(struct rtwn_softc *, int, int); + void (*sc_beacon_set_rate)(void *, int); + void (*sc_beacon_select)(struct rtwn_softc *, int); + void (*sc_set_chan)(struct rtwn_softc *, + struct ieee80211_channel *); + void (*sc_set_media_status)(struct rtwn_softc *, int); +#ifndef RTWN_WITHOUT_UCODE + int (*sc_set_rsvd_page)(struct rtwn_softc *, int, int, + int); + int (*sc_set_pwrmode)(struct rtwn_softc *, + struct ieee80211vap *, int); + void (*sc_set_rssi)(struct rtwn_softc *); +#endif + int8_t (*sc_get_rssi_cck)(struct rtwn_softc *, void *); + int8_t (*sc_get_rssi_ofdm)(struct rtwn_softc *, void *); + int (*sc_classify_intr)(struct rtwn_softc *, void *, int); + void (*sc_handle_tx_report)(struct rtwn_softc *, uint8_t *, + int); + void (*sc_handle_c2h_report)(struct rtwn_softc *, + uint8_t *, int); + int (*sc_check_frame)(struct rtwn_softc *, struct mbuf *); + void (*sc_temp_measure)(struct rtwn_softc *); + uint8_t (*sc_temp_read)(struct rtwn_softc *); + void (*sc_init_tx_agg)(struct rtwn_softc *); + void (*sc_init_rx_agg)(struct rtwn_softc *); + void (*sc_init_intr)(struct rtwn_softc *); + void (*sc_init_ampdu)(struct rtwn_softc *); + void (*sc_init_edca)(struct rtwn_softc *); + void (*sc_init_bb)(struct rtwn_softc *); + void (*sc_init_rf)(struct rtwn_softc *); + void (*sc_init_antsel)(struct rtwn_softc *); + void (*sc_post_init)(struct rtwn_softc *); + int (*sc_init_bcnq1_boundary)(struct rtwn_softc *); + + const uint8_t *chan_list_5ghz[3]; + int chan_num_5ghz[3]; + + const struct rtwn_mac_prog *mac_prog; + int mac_size; + const struct rtwn_bb_prog *bb_prog; + int bb_size; + const struct rtwn_agc_prog *agc_prog; + int agc_size; + const struct rtwn_rf_prog *rf_prog; + + int page_count; + int pktbuf_count; + + int ackto; + + int npubqpages; + int nhqpages; + int nnqpages; + int nlqpages; + int page_size; + + int txdesc_len; + int efuse_maxlen; + int efuse_maplen; + + uint16_t rx_dma_size; + + int macid_limit; + int cam_entry_limit; + int fwsize_limit; + int temp_delta; + + uint16_t bcn_status_reg[RTWN_PORT_COUNT]; + uint32_t rcr; /* Rx filter */ +}; +MALLOC_DECLARE(M_RTWN_PRIV); + +#define RTWN_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define RTWN_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define RTWN_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) + +#define RTWN_CMDQ_LOCK_INIT(sc) \ + mtx_init(&(sc)->cmdq_mtx, "cmdq lock", NULL, MTX_DEF) +#define RTWN_CMDQ_LOCK(sc) mtx_lock(&(sc)->cmdq_mtx) +#define RTWN_CMDQ_UNLOCK(sc) mtx_unlock(&(sc)->cmdq_mtx) +#define RTWN_CMDQ_LOCK_INITIALIZED(sc) mtx_initialized(&(sc)->cmdq_mtx) +#define RTWN_CMDQ_LOCK_DESTROY(sc) mtx_destroy(&(sc)->cmdq_mtx) + +#define RTWN_NT_LOCK_INIT(sc) \ + mtx_init(&(sc)->nt_mtx, "node table lock", NULL, MTX_DEF) +#define RTWN_NT_LOCK(sc) mtx_lock(&(sc)->nt_mtx) +#define RTWN_NT_UNLOCK(sc) mtx_unlock(&(sc)->nt_mtx) +#define RTWN_NT_LOCK_INITIALIZED(sc) mtx_initialized(&(sc)->nt_mtx) +#define RTWN_NT_LOCK_DESTROY(sc) mtx_destroy(&(sc)->nt_mtx) + + +void rtwn_sysctlattach(struct rtwn_softc *); + +int rtwn_attach(struct rtwn_softc *); +void rtwn_detach(struct rtwn_softc *); +void rtwn_resume(struct rtwn_softc *); +void rtwn_suspend(struct rtwn_softc *); + + +/* Interface-specific. */ +#define rtwn_write_1(_sc, _addr, _val) \ + (((_sc)->sc_write_1)((_sc), (_addr), (_val))) +#define rtwn_write_2(_sc, _addr, _val) \ + (((_sc)->sc_write_2)((_sc), (_addr), (_val))) +#define rtwn_write_4(_sc, _addr, _val) \ + (((_sc)->sc_write_4)((_sc), (_addr), (_val))) +#define rtwn_read_1(_sc, _addr) \ + (((_sc)->sc_read_1)((_sc), (_addr))) +#define rtwn_read_2(_sc, _addr) \ + (((_sc)->sc_read_2)((_sc), (_addr))) +#define rtwn_read_4(_sc, _addr) \ + (((_sc)->sc_read_4)((_sc), (_addr))) +#define rtwn_delay(_sc, _usec) \ + (((_sc)->sc_delay)((_sc), (_usec))) +#define rtwn_tx_start(_sc, _ni, _m, _desc, _type, _id) \ + (((_sc)->sc_tx_start)((_sc), (_ni), (_m), (_desc), (_type), (_id))) +#define rtwn_start_xfers(_sc) \ + (((_sc)->sc_start_xfers)((_sc))) +#define rtwn_reset_lists(_sc, _vap) \ + (((_sc)->sc_reset_lists)((_sc), (_vap))) +#define rtwn_abort_xfers(_sc) \ + (((_sc)->sc_abort_xfers)((_sc))) +#define rtwn_fw_write_block(_sc, _buf, _reg, _len) \ + (((_sc)->sc_fw_write_block)((_sc), (_buf), (_reg), (_len))) +#define rtwn_get_qmap(_sc) \ + (((_sc)->sc_get_qmap)((_sc))) +#define rtwn_set_desc_addr(_sc) \ + (((_sc)->sc_set_desc_addr)((_sc))) +#define rtwn_drop_incorrect_tx(_sc) \ + (((_sc)->sc_drop_incorrect_tx)((_sc))) +#define rtwn_beacon_update_begin(_sc, _vap) \ + (((_sc)->sc_beacon_update_begin)((_sc), (_vap))) +#define rtwn_beacon_update_end(_sc, _vap) \ + (((_sc)->sc_beacon_update_end)((_sc), (_vap))) +#define rtwn_beacon_unload(_sc, _id) \ + (((_sc)->sc_beacon_unload)((_sc), (_id))) + +/* Aliases. */ +#define rtwn_bb_write rtwn_write_4 +#define rtwn_bb_read rtwn_read_4 +#define rtwn_bb_setbits rtwn_setbits_4 + +/* Device-specific. */ +#define rtwn_rf_read(_sc, _chain, _addr) \ + (((_sc)->sc_rf_read)((_sc), (_chain), (_addr))) +#define rtwn_rf_write(_sc, _chain, _addr, _val) \ + (((_sc)->sc_rf_write)((_sc), (_chain), (_addr), (_val))) +#define rtwn_check_condition(_sc, _cond) \ + (((_sc)->sc_check_condition)((_sc), (_cond))) +#define rtwn_efuse_postread(_sc) \ + (((_sc)->sc_efuse_postread)((_sc))) +#define rtwn_parse_rom(_sc, _rom) \ + (((_sc)->sc_parse_rom)((_sc), (_rom))) +#define rtwn_set_led(_sc, _led, _on) \ + (((_sc)->sc_set_led)((_sc), (_led), (_on))) +#define rtwn_get_rssi_cck(_sc, _physt) \ + (((_sc)->sc_get_rssi_cck)((_sc), (_physt))) +#define rtwn_get_rssi_ofdm(_sc, _physt) \ + (((_sc)->sc_get_rssi_ofdm)((_sc), (_physt))) +#define rtwn_power_on(_sc) \ + (((_sc)->sc_power_on)((_sc))) +#define rtwn_power_off(_sc) \ + (((_sc)->sc_power_off)((_sc))) +#ifndef RTWN_WITHOUT_UCODE +#define rtwn_fw_reset(_sc, _reason) \ + (((_sc)->sc_fw_reset)((_sc), (_reason))) +#define rtwn_fw_download_enable(_sc, _enable) \ + (((_sc)->sc_fw_download_enable)((_sc), (_enable))) +#endif +#define rtwn_set_page_size(_sc) \ + (((_sc)->sc_set_page_size)((_sc))) +#define rtwn_lc_calib(_sc) \ + (((_sc)->sc_lc_calib)((_sc))) +#define rtwn_iq_calib(_sc) \ + (((_sc)->sc_iq_calib)((_sc))) +#define rtwn_read_chipid_vendor(_sc, _reg) \ + (((_sc)->sc_read_chipid_vendor)((_sc), (_reg))) +#define rtwn_adj_devcaps(_sc) \ + (((_sc)->sc_adj_devcaps)((_sc))) +#define rtwn_vap_preattach(_sc, _vap) \ + (((_sc)->sc_vap_preattach)((_sc), (_vap))) +#define rtwn_postattach(_sc) \ + (((_sc)->sc_postattach)((_sc))) +#define rtwn_detach_private(_sc) \ + (((_sc)->sc_detach_private)((_sc))) +#define rtwn_fill_tx_desc(_sc, _ni, _m, \ + _buf, _ridx, _maxretry) \ + (((_sc)->sc_fill_tx_desc)((_sc), (_ni), \ + (_m), (_buf), (_ridx), (_maxretry))) +#define rtwn_fill_tx_desc_raw(_sc, _ni, _m, \ + _buf, _params) \ + (((_sc)->sc_fill_tx_desc_raw)((_sc), (_ni), \ + (_m), (_buf), (_params))) +#define rtwn_fill_tx_desc_null(_sc, _buf, _11b, _qos, _id) \ + (((_sc)->sc_fill_tx_desc_null)((_sc), \ + (_buf), (_11b), (_qos), (_id))) +#define rtwn_dump_tx_desc(_sc, _desc) \ + (((_sc)->sc_dump_tx_desc)((_sc), (_desc))) +#define rtwn_tx_radiotap_flags(_sc, _buf) \ + (((_sc)->sc_tx_radiotap_flags)((_buf))) +#define rtwn_rx_radiotap_flags(_sc, _buf) \ + (((_sc)->sc_rx_radiotap_flags)((_buf))) +#define rtwn_set_chan(_sc, _c) \ + (((_sc)->sc_set_chan)((_sc), (_c))) +#ifndef RTWN_WITHOUT_UCODE +#define rtwn_set_rsvd_page(_sc, _resp, _null, _qos_null) \ + (((_sc)->sc_set_rsvd_page)((_sc), \ + (_resp), (_null), (_qos_null))) +#define rtwn_set_pwrmode(_sc, _vap, _off) \ + (((_sc)->sc_set_pwrmode)((_sc), (_vap), (_off))) +#define rtwn_set_rssi(_sc) \ + (((_sc)->sc_set_rssi)((_sc))) +#endif +#define rtwn_classify_intr(_sc, _buf, _len) \ + (((_sc)->sc_classify_intr)((_sc), (_buf), (_len))) +#define rtwn_handle_tx_report(_sc, _buf, _len) \ + (((_sc)->sc_handle_tx_report)((_sc), (_buf), (_len))) +#define rtwn_handle_c2h_report(_sc, _buf, _len) \ + (((_sc)->sc_handle_c2h_report)((_sc), (_buf), (_len))) +#define rtwn_check_frame(_sc, _m) \ + (((_sc)->sc_check_frame)((_sc), (_m))) +#define rtwn_beacon_init(_sc, _buf, _id) \ + (((_sc)->sc_beacon_init)((_sc), (_buf), (_id))) +#define rtwn_beacon_enable(_sc, _id, _enable) \ + (((_sc)->sc_beacon_enable)((_sc), (_id), (_enable))) +#define rtwn_beacon_set_rate(_sc, _buf, _is5ghz) \ + (((_sc)->sc_beacon_set_rate)((_buf), (_is5ghz))) +#define rtwn_beacon_select(_sc, _id) \ + (((_sc)->sc_beacon_select)((_sc), (_id))) +#define rtwn_temp_measure(_sc) \ + (((_sc)->sc_temp_measure)((_sc))) +#define rtwn_temp_read(_sc) \ + (((_sc)->sc_temp_read)((_sc))) +#define rtwn_init_tx_agg(_sc) \ + (((_sc)->sc_init_tx_agg)((_sc))) +#define rtwn_init_rx_agg(_sc) \ + (((_sc)->sc_init_rx_agg)((_sc))) +#define rtwn_init_intr(_sc) \ + (((_sc)->sc_init_intr)((_sc))) +#define rtwn_init_ampdu(_sc) \ + (((_sc)->sc_init_ampdu)((_sc))) +#define rtwn_init_edca(_sc) \ + (((_sc)->sc_init_edca)((_sc))) +#define rtwn_init_bb(_sc) \ + (((_sc)->sc_init_bb)((_sc))) +#define rtwn_init_rf(_sc) \ + (((_sc)->sc_init_rf)((_sc))) +#define rtwn_init_antsel(_sc) \ + (((_sc)->sc_init_antsel)((_sc))) +#define rtwn_post_init(_sc) \ + (((_sc)->sc_post_init)((_sc))) +#define rtwn_init_bcnq1_boundary(_sc) \ + (((_sc)->sc_init_bcnq1_boundary)((_sc))) + + +/* + * Methods to access subfields in registers. + */ +static __inline int +rtwn_setbits_1(struct rtwn_softc *sc, uint16_t addr, uint8_t clr, + uint8_t set) +{ + return (rtwn_write_1(sc, addr, + (rtwn_read_1(sc, addr) & ~clr) | set)); +} + +static __inline int +rtwn_setbits_1_shift(struct rtwn_softc *sc, uint16_t addr, uint32_t clr, + uint32_t set, int shift) +{ + return (rtwn_setbits_1(sc, addr + shift, clr >> shift * NBBY, + set >> shift * NBBY)); +} + +static __inline int +rtwn_setbits_2(struct rtwn_softc *sc, uint16_t addr, uint16_t clr, + uint16_t set) +{ + return (rtwn_write_2(sc, addr, + (rtwn_read_2(sc, addr) & ~clr) | set)); +} + +static __inline int +rtwn_setbits_4(struct rtwn_softc *sc, uint16_t addr, uint32_t clr, + uint32_t set) +{ + return (rtwn_write_4(sc, addr, + (rtwn_read_4(sc, addr) & ~clr) | set)); +} + +static __inline void +rtwn_rf_setbits(struct rtwn_softc *sc, int chain, uint8_t addr, + uint32_t clr, uint32_t set) +{ + rtwn_rf_write(sc, chain, addr, + (rtwn_rf_read(sc, chain, addr) & ~clr) | set); +} + +#endif /* IF_RTWNVAR_H */ diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c new file mode 100644 index 00000000..5b28d27f --- /dev/null +++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c @@ -0,0 +1,784 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + + +static device_probe_t rtwn_pci_probe; +static device_attach_t rtwn_pci_attach; +static device_detach_t rtwn_pci_detach; +static device_shutdown_t rtwn_pci_shutdown; +static device_suspend_t rtwn_pci_suspend; +static device_resume_t rtwn_pci_resume; + +static int rtwn_pci_alloc_rx_list(struct rtwn_softc *); +static void rtwn_pci_reset_rx_list(struct rtwn_softc *); +static void rtwn_pci_free_rx_list(struct rtwn_softc *); +static int rtwn_pci_alloc_tx_list(struct rtwn_softc *, int); +static void rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *, int); +static void rtwn_pci_reset_beacon_ring(struct rtwn_softc *, int); +static void rtwn_pci_reset_tx_list(struct rtwn_softc *, + struct ieee80211vap *, int); +static void rtwn_pci_free_tx_list(struct rtwn_softc *, int); +static void rtwn_pci_reset_lists(struct rtwn_softc *, + struct ieee80211vap *); +static int rtwn_pci_fw_write_block(struct rtwn_softc *, + const uint8_t *, uint16_t, int); +static uint16_t rtwn_pci_get_qmap(struct rtwn_softc *); +static void rtwn_pci_set_desc_addr(struct rtwn_softc *); +static void rtwn_pci_beacon_update_begin(struct rtwn_softc *, + struct ieee80211vap *); +static void rtwn_pci_beacon_update_end(struct rtwn_softc *, + struct ieee80211vap *); +static void rtwn_pci_attach_methods(struct rtwn_softc *); + + +static int matched_chip = RTWN_CHIP_MAX_PCI; + +static int +rtwn_pci_probe(device_t dev) +{ + const struct rtwn_pci_ident *ident; + + for (ident = rtwn_pci_ident_table; ident->name != NULL; ident++) { + if (pci_get_vendor(dev) == ident->vendor && + pci_get_device(dev) == ident->device) { + matched_chip = ident->chip; + device_set_desc(dev, ident->name); + return (BUS_PROBE_DEFAULT); + } + } + return (ENXIO); +} + +static int +rtwn_pci_alloc_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *rx_ring = &pc->rx_ring; + struct rtwn_rx_data *rx_data; + bus_size_t size; + int i, error; + + /* Allocate Rx descriptors. */ + size = sizeof(struct r92ce_rx_stat) * RTWN_PCI_RX_LIST_COUNT; + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + size, 1, size, 0, NULL, NULL, &rx_ring->desc_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create rx desc DMA tag\n"); + goto fail; + } + + error = bus_dmamem_alloc(rx_ring->desc_dmat, (void **)&rx_ring->desc, + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, + &rx_ring->desc_map); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate rx desc\n"); + goto fail; + } + error = bus_dmamap_load(rx_ring->desc_dmat, rx_ring->desc_map, + rx_ring->desc, size, rtwn_pci_dma_map_addr, &rx_ring->paddr, 0); + if (error != 0) { + device_printf(sc->sc_dev, "could not load rx desc DMA map\n"); + goto fail; + } + bus_dmamap_sync(rx_ring->desc_dmat, rx_ring->desc_map, + BUS_DMASYNC_PREWRITE); + + /* Create RX buffer DMA tag. */ + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, NULL, NULL, &rx_ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create rx buf DMA tag\n"); + goto fail; + } + + /* Allocate Rx buffers. */ + for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) { + rx_data = &rx_ring->rx_data[i]; + error = bus_dmamap_create(rx_ring->data_dmat, 0, &rx_data->map); + if (error != 0) { + device_printf(sc->sc_dev, + "could not create rx buf DMA map\n"); + goto fail; + } + + rx_data->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, + MJUMPAGESIZE); + if (rx_data->m == NULL) { + device_printf(sc->sc_dev, + "could not allocate rx mbuf\n"); + error = ENOMEM; + goto fail; + } + + error = bus_dmamap_load(rx_ring->data_dmat, rx_data->map, + mtod(rx_data->m, void *), MJUMPAGESIZE, + rtwn_pci_dma_map_addr, &rx_data->paddr, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, + "could not load rx buf DMA map"); + goto fail; + } + + rtwn_pci_setup_rx_desc(pc, &rx_ring->desc[i], rx_data->paddr, + MJUMPAGESIZE, i); + } + rx_ring->cur = 0; + + return (0); + +fail: + rtwn_pci_free_rx_list(sc); + return (error); +} + +static void +rtwn_pci_reset_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *rx_ring = &pc->rx_ring; + struct rtwn_rx_data *rx_data; + int i; + + for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) { + rx_data = &rx_ring->rx_data[i]; + rtwn_pci_setup_rx_desc(pc, &rx_ring->desc[i], + rx_data->paddr, MJUMPAGESIZE, i); + } + rx_ring->cur = 0; +} + +static void +rtwn_pci_free_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *rx_ring = &pc->rx_ring; + struct rtwn_rx_data *rx_data; + int i; + + if (rx_ring->desc_dmat != NULL) { + if (rx_ring->desc != NULL) { + bus_dmamap_sync(rx_ring->desc_dmat, + rx_ring->desc_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(rx_ring->desc_dmat, + rx_ring->desc_map); + bus_dmamem_free(rx_ring->desc_dmat, rx_ring->desc, + rx_ring->desc_map); + rx_ring->desc = NULL; + } + bus_dma_tag_destroy(rx_ring->desc_dmat); + rx_ring->desc_dmat = NULL; + } + + for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) { + rx_data = &rx_ring->rx_data[i]; + + if (rx_data->m != NULL) { + bus_dmamap_sync(rx_ring->data_dmat, + rx_data->map, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rx_ring->data_dmat, rx_data->map); + m_freem(rx_data->m); + rx_data->m = NULL; + } + bus_dmamap_destroy(rx_ring->data_dmat, rx_data->map); + rx_data->map = NULL; + } + if (rx_ring->data_dmat != NULL) { + bus_dma_tag_destroy(rx_ring->data_dmat); + rx_ring->data_dmat = NULL; + } +} + +static int +rtwn_pci_alloc_tx_list(struct rtwn_softc *sc, int qid) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid]; + bus_size_t size; + int i, error; + + size = sc->txdesc_len * RTWN_PCI_TX_LIST_COUNT; + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + size, 1, size, 0, NULL, NULL, &tx_ring->desc_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create tx ring DMA tag\n"); + goto fail; + } + + error = bus_dmamem_alloc(tx_ring->desc_dmat, &tx_ring->desc, + BUS_DMA_NOWAIT | BUS_DMA_ZERO, &tx_ring->desc_map); + if (error != 0) { + device_printf(sc->sc_dev, "can't map tx ring DMA memory\n"); + goto fail; + } + error = bus_dmamap_load(tx_ring->desc_dmat, tx_ring->desc_map, + tx_ring->desc, size, rtwn_pci_dma_map_addr, &tx_ring->paddr, + BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, "could not load desc DMA map\n"); + goto fail; + } + bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, + BUS_DMASYNC_PREWRITE); + + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + MJUMPAGESIZE, 1, MJUMPAGESIZE, 0, NULL, NULL, &tx_ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create tx buf DMA tag\n"); + goto fail; + } + + for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { + struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i]; + void *tx_desc = (uint8_t *)tx_ring->desc + sc->txdesc_len * i; + uint32_t next_desc_addr = tx_ring->paddr + + sc->txdesc_len * ((i + 1) % RTWN_PCI_TX_LIST_COUNT); + + rtwn_pci_setup_tx_desc(pc, tx_desc, next_desc_addr); + + error = bus_dmamap_create(tx_ring->data_dmat, 0, &tx_data->map); + if (error != 0) { + device_printf(sc->sc_dev, + "could not create tx buf DMA map\n"); + return (error); + } + tx_data->m = NULL; + tx_data->ni = NULL; + } + return (0); + +fail: + rtwn_pci_free_tx_list(sc, qid); + return (error); +} + +static void +rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *sc, int qid) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; + int i; + + for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { + struct rtwn_tx_data *data = &ring->tx_data[i]; + void *desc = (uint8_t *)ring->desc + sc->txdesc_len * i; + + rtwn_pci_copy_tx_desc(pc, desc, NULL); + + if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + m_freem(data->m); + data->m = NULL; + } + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; + } + } + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, + BUS_DMASYNC_POSTWRITE); + + sc->qfullmsk &= ~(1 << qid); + ring->queued = 0; + ring->last = ring->cur = 0; +} + +/* + * Clear entry 0 (or 1) in the beacon queue (other are not used). + */ +static void +rtwn_pci_reset_beacon_ring(struct rtwn_softc *sc, int id) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring = &pc->tx_ring[RTWN_PCI_BEACON_QUEUE]; + struct rtwn_tx_data *data = &ring->tx_data[id]; + struct rtwn_tx_desc_common *txd = (struct rtwn_tx_desc_common *) + ((uint8_t *)ring->desc + id * sc->txdesc_len); + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); + if (txd->flags0 & RTWN_FLAGS0_OWN) { + /* Clear OWN bit. */ + txd->flags0 &= ~RTWN_FLAGS0_OWN; + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, + BUS_DMASYNC_PREWRITE); + + /* Unload mbuf. */ + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + } +} + +/* + * Drop stale entries from Tx ring before the vap will be deleted. + * In case if vap is NULL just free everything and reset cur / last pointers. + */ +static void +rtwn_pci_reset_tx_list(struct rtwn_softc *sc, struct ieee80211vap *vap, + int qid) +{ + int i; + + if (vap == NULL) { + if (qid != RTWN_PCI_BEACON_QUEUE) { + /* + * Device was stopped; just clear all entries. + */ + rtwn_pci_reset_tx_ring_stopped(sc, qid); + } else { + for (i = 0; i < RTWN_PORT_COUNT; i++) + rtwn_pci_reset_beacon_ring(sc, i); + } + } else if (qid == RTWN_PCI_BEACON_QUEUE && + (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS)) { + struct rtwn_vap *uvp = RTWN_VAP(vap); + + rtwn_pci_reset_beacon_ring(sc, uvp->id); + } else { + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; + + for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { + struct rtwn_tx_data *data = &ring->tx_data[i]; + if (data->ni != NULL && data->ni->ni_vap == vap) { + /* + * NB: if some vap is still running + * rtwn_pci_tx_done() will free the mbuf; + * otherwise, rtwn_stop() will reset all rings + * after device shutdown. + */ + ieee80211_free_node(data->ni); + data->ni = NULL; + } + } + } +} + +static void +rtwn_pci_free_tx_list(struct rtwn_softc *sc, int qid) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid]; + struct rtwn_tx_data *tx_data; + int i; + + if (tx_ring->desc_dmat != NULL) { + if (tx_ring->desc != NULL) { + bus_dmamap_sync(tx_ring->desc_dmat, + tx_ring->desc_map, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(tx_ring->desc_dmat, + tx_ring->desc_map); + bus_dmamem_free(tx_ring->desc_dmat, tx_ring->desc, + tx_ring->desc_map); + } + bus_dma_tag_destroy(tx_ring->desc_dmat); + } + + for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { + tx_data = &tx_ring->tx_data[i]; + + if (tx_data->m != NULL) { + bus_dmamap_sync(tx_ring->data_dmat, tx_data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(tx_ring->data_dmat, tx_data->map); + m_freem(tx_data->m); + tx_data->m = NULL; + } + } + if (tx_ring->data_dmat != NULL) { + bus_dma_tag_destroy(tx_ring->data_dmat); + tx_ring->data_dmat = NULL; + } + + sc->qfullmsk &= ~(1 << qid); + tx_ring->queued = 0; + tx_ring->last = tx_ring->cur = 0; +} + +static void +rtwn_pci_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + int i; + + for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) + rtwn_pci_reset_tx_list(sc, vap, i); + + if (vap == NULL) { + sc->qfullmsk = 0; + rtwn_pci_reset_rx_list(sc); + } +} + +static int +rtwn_pci_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, + uint16_t reg, int mlen) +{ + int i; + + for (i = 0; i < mlen; i++) + rtwn_pci_write_1(sc, reg++, buf[i]); + + /* NB: cannot fail */ + return (0); +} + +static uint16_t +rtwn_pci_get_qmap(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + KASSERT(pc->pc_qmap != 0, ("%s: qmap is not set!\n", __func__)); + + return (pc->pc_qmap); +} + +static void +rtwn_pci_set_desc_addr(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, "%s: addresses:\n" + "bk: %08jX, be: %08jX, vi: %08jX, vo: %08jX\n" + "bcn: %08jX, mgt: %08jX, high: %08jX, rx: %08jX\n", + __func__, (uintmax_t)pc->tx_ring[RTWN_PCI_BK_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_BE_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_VI_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_VO_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_BEACON_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_MGNT_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_HIGH_QUEUE].paddr, + (uintmax_t)pc->rx_ring.paddr); + + /* Set Tx Configuration Register. */ + rtwn_pci_write_4(sc, R92C_TCR, pc->tcr); + + /* Configure Tx DMA. */ + rtwn_pci_write_4(sc, R92C_BKQ_DESA, + pc->tx_ring[RTWN_PCI_BK_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_BEQ_DESA, + pc->tx_ring[RTWN_PCI_BE_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_VIQ_DESA, + pc->tx_ring[RTWN_PCI_VI_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_VOQ_DESA, + pc->tx_ring[RTWN_PCI_VO_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_BCNQ_DESA, + pc->tx_ring[RTWN_PCI_BEACON_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_MGQ_DESA, + pc->tx_ring[RTWN_PCI_MGNT_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_HQ_DESA, + pc->tx_ring[RTWN_PCI_HIGH_QUEUE].paddr); + + /* Configure Rx DMA. */ + rtwn_pci_write_4(sc, R92C_RX_DESA, pc->rx_ring.paddr); +} + +static void +rtwn_pci_beacon_update_begin(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct rtwn_vap *rvp = RTWN_VAP(vap); + + RTWN_ASSERT_LOCKED(sc); + + rtwn_beacon_enable(sc, rvp->id, 0); +} + +static void +rtwn_pci_beacon_update_end(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct rtwn_vap *rvp = RTWN_VAP(vap); + + RTWN_ASSERT_LOCKED(sc); + + if (rvp->curr_mode != R92C_MSR_NOLINK) + rtwn_beacon_enable(sc, rvp->id, 1); +} + +static void +rtwn_pci_attach_methods(struct rtwn_softc *sc) +{ + sc->sc_write_1 = rtwn_pci_write_1; + sc->sc_write_2 = rtwn_pci_write_2; + sc->sc_write_4 = rtwn_pci_write_4; + sc->sc_read_1 = rtwn_pci_read_1; + sc->sc_read_2 = rtwn_pci_read_2; + sc->sc_read_4 = rtwn_pci_read_4; + sc->sc_delay = rtwn_pci_delay; + sc->sc_tx_start = rtwn_pci_tx_start; + sc->sc_reset_lists = rtwn_pci_reset_lists; + sc->sc_abort_xfers = rtwn_nop_softc; + sc->sc_fw_write_block = rtwn_pci_fw_write_block; + sc->sc_get_qmap = rtwn_pci_get_qmap; + sc->sc_set_desc_addr = rtwn_pci_set_desc_addr; + sc->sc_drop_incorrect_tx = rtwn_nop_softc; + sc->sc_beacon_update_begin = rtwn_pci_beacon_update_begin; + sc->sc_beacon_update_end = rtwn_pci_beacon_update_end; + sc->sc_beacon_unload = rtwn_pci_reset_beacon_ring; + + sc->bcn_check_interval = 25000; +} + +static int +rtwn_pci_attach(device_t dev) +{ + struct rtwn_pci_softc *pc = device_get_softc(dev); + struct rtwn_softc *sc = &pc->pc_sc; + struct ieee80211com *ic = &sc->sc_ic; + uint32_t lcsr; + int cap_off, i, error, rid; + + if (matched_chip >= RTWN_CHIP_MAX_PCI) + return (ENXIO); + + /* + * Get the offset of the PCI Express Capability Structure in PCI + * Configuration Space. + */ + error = pci_find_cap(dev, PCIY_EXPRESS, &cap_off); + if (error != 0) { + device_printf(dev, "PCIe capability structure not found!\n"); + return (error); + } + + /* Enable bus-mastering. */ + pci_enable_busmaster(dev); + + rid = PCIR_BAR(2); + pc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (pc->mem == NULL) { + device_printf(dev, "can't map mem space\n"); + return (ENOMEM); + } + pc->pc_st = rman_get_bustag(pc->mem); + pc->pc_sh = rman_get_bushandle(pc->mem); + + /* Install interrupt handler. */ + rid = 1; + if (pci_alloc_msi(dev, &rid) == 0) + rid = 1; + else + rid = 0; + pc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | + (rid != 0 ? 0 : RF_SHAREABLE)); + if (pc->irq == NULL) { + device_printf(dev, "can't map interrupt\n"); + goto detach; + } + + /* Disable PCIe Active State Power Management (ASPM). */ + lcsr = pci_read_config(dev, cap_off + PCIER_LINK_CTL, 4); + lcsr &= ~PCIEM_LINK_CTL_ASPMC; + pci_write_config(dev, cap_off + PCIER_LINK_CTL, lcsr, 4); + + sc->sc_dev = dev; + ic->ic_name = device_get_nameunit(dev); + + /* Need to be initialized early. */ + rtwn_sysctlattach(sc); + mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); + + rtwn_pci_attach_methods(sc); + /* XXX something similar to USB_GET_DRIVER_INFO() */ + rtwn_pci_attach_private(pc, matched_chip); + + /* Allocate Tx/Rx buffers. */ + error = rtwn_pci_alloc_rx_list(sc); + if (error != 0) { + device_printf(dev, + "could not allocate Rx buffers, error %d\n", + error); + goto detach; + } + for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) { + error = rtwn_pci_alloc_tx_list(sc, i); + if (error != 0) { + device_printf(dev, + "could not allocate Tx buffers, error %d\n", + error); + goto detach; + } + } + + /* Generic attach. */ + error = rtwn_attach(sc); + if (error != 0) + goto detach; + + /* + * Hook our interrupt after all initialization is complete. + */ + error = bus_setup_intr(dev, pc->irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, rtwn_pci_intr, sc, &pc->pc_ih); + if (error != 0) { + device_printf(dev, "can't establish interrupt, error %d\n", + error); + goto detach; + } + + return (0); + +detach: + rtwn_pci_detach(dev); /* failure */ + return (ENXIO); +} + +static int +rtwn_pci_detach(device_t dev) +{ + struct rtwn_pci_softc *pc = device_get_softc(dev); + struct rtwn_softc *sc = &pc->pc_sc; + int i; + + /* Generic detach. */ + rtwn_detach(sc); + + /* Uninstall interrupt handler. */ + if (pc->irq != NULL) { + bus_teardown_intr(dev, pc->irq, pc->pc_ih); + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(pc->irq), + pc->irq); + pci_release_msi(dev); + } + + /* Free Tx/Rx buffers. */ + for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) + rtwn_pci_free_tx_list(sc, i); + rtwn_pci_free_rx_list(sc); + + if (pc->mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, + rman_get_rid(pc->mem), pc->mem); + + rtwn_detach_private(sc); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static int +rtwn_pci_shutdown(device_t self) +{ + struct rtwn_pci_softc *pc = device_get_softc(self); + + ieee80211_stop_all(&pc->pc_sc.sc_ic); + return (0); +} + +static int +rtwn_pci_suspend(device_t self) +{ + struct rtwn_pci_softc *pc = device_get_softc(self); + + rtwn_suspend(&pc->pc_sc); + + return (0); +} + +static int +rtwn_pci_resume(device_t self) +{ + struct rtwn_pci_softc *pc = device_get_softc(self); + + rtwn_resume(&pc->pc_sc); + + return (0); +} + +static device_method_t rtwn_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rtwn_pci_probe), + DEVMETHOD(device_attach, rtwn_pci_attach), + DEVMETHOD(device_detach, rtwn_pci_detach), + DEVMETHOD(device_shutdown, rtwn_pci_shutdown), + DEVMETHOD(device_suspend, rtwn_pci_suspend), + DEVMETHOD(device_resume, rtwn_pci_resume), + + DEVMETHOD_END +}; + +static driver_t rtwn_pci_driver = { + "rtwn", + rtwn_pci_methods, + sizeof(struct rtwn_pci_softc) +}; + +static devclass_t rtwn_pci_devclass; + +DRIVER_MODULE(rtwn_pci, pci, rtwn_pci_driver, rtwn_pci_devclass, NULL, NULL); +MODULE_VERSION(rtwn_pci, 1); +MODULE_DEPEND(rtwn_pci, pci, 1, 1, 1); +MODULE_DEPEND(rtwn_pci, wlan, 1, 1, 1); +MODULE_DEPEND(rtwn_pci, rtwn, 2, 2, 2); diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h new file mode 100644 index 00000000..6df5812e --- /dev/null +++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +void r92ce_attach(struct rtwn_pci_softc *); + +enum { + RTWN_CHIP_RTL8192CE, + RTWN_CHIP_MAX_PCI +}; + +struct rtwn_pci_ident { + uint16_t vendor; + uint16_t device; + const char *name; + int chip; +}; + +static const struct rtwn_pci_ident rtwn_pci_ident_table[] = { + { 0x10ec, 0x8176, "Realtek RTL8188CE", RTWN_CHIP_RTL8192CE }, + { 0, 0, NULL, RTWN_CHIP_MAX_PCI } +}; + +typedef void (*chip_pci_attach)(struct rtwn_pci_softc *); + +static const chip_pci_attach rtwn_chip_pci_attach[RTWN_CHIP_MAX_PCI] = { + [RTWN_CHIP_RTL8192CE] = r92ce_attach +}; + +static __inline void +rtwn_pci_attach_private(struct rtwn_pci_softc *pc, int chip) +{ + rtwn_chip_pci_attach[chip](pc); +} diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c new file mode 100644 index 00000000..3801f811 --- /dev/null +++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.c @@ -0,0 +1,125 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +int +rtwn_pci_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + bus_space_write_1(pc->pc_st, pc->pc_sh, addr, val); + + return (0); +} + +int +rtwn_pci_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + val = htole16(val); + bus_space_write_2(pc->pc_st, pc->pc_sh, addr, val); + + return (0); +} + +int +rtwn_pci_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + val = htole32(val); + bus_space_write_4(pc->pc_st, pc->pc_sh, addr, val); + + return (0); +} + +uint8_t +rtwn_pci_read_1(struct rtwn_softc *sc, uint16_t addr) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + return (bus_space_read_1(pc->pc_st, pc->pc_sh, addr)); +} + +uint16_t +rtwn_pci_read_2(struct rtwn_softc *sc, uint16_t addr) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + uint16_t val; + + val = bus_space_read_2(pc->pc_st, pc->pc_sh, addr); + return le16toh(val); +} + +uint32_t +rtwn_pci_read_4(struct rtwn_softc *sc, uint16_t addr) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + uint32_t val; + + val = bus_space_read_4(pc->pc_st, pc->pc_sh, addr); + return le32toh(val); +} + +void +rtwn_pci_delay(struct rtwn_softc *sc, int usec) +{ + if (usec < 1000) + DELAY(usec); + else { + (void) mtx_sleep(sc, &sc->sc_mtx, 0, "rtwn_pci", + MAX(msecs_to_ticks(usec / 1000), 1)); + } +} diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h new file mode 100644 index 00000000..7c900345 --- /dev/null +++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_reg.h @@ -0,0 +1,30 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_PCI_REG_H +#define RTWN_PCI_REG_H + +int rtwn_pci_write_1(struct rtwn_softc *, uint16_t, uint8_t); +int rtwn_pci_write_2(struct rtwn_softc *, uint16_t, uint16_t); +int rtwn_pci_write_4(struct rtwn_softc *, uint16_t, uint32_t); +uint8_t rtwn_pci_read_1(struct rtwn_softc *, uint16_t); +uint16_t rtwn_pci_read_2(struct rtwn_softc *, uint16_t); +uint32_t rtwn_pci_read_4(struct rtwn_softc *, uint16_t); +void rtwn_pci_delay(struct rtwn_softc *, int); + +#endif /* RTWN_PCI_REG_H */ diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c new file mode 100644 index 00000000..8da0061b --- /dev/null +++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c @@ -0,0 +1,329 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +void +rtwn_pci_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, + int error) +{ + + if (error != 0) + return; + KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); + *(bus_addr_t *)arg = segs[0].ds_addr; +} + +void +rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *pc, struct r92ce_rx_stat *desc, + bus_addr_t addr, size_t len, int idx) +{ + + memset(desc, 0, sizeof(*desc)); + desc->rxdw0 = htole32(SM(R92C_RXDW0_PKTLEN, len) | + ((idx == RTWN_PCI_RX_LIST_COUNT - 1) ? R92C_RXDW0_EOR : 0)); + desc->rxbufaddr = htole32(addr); + bus_space_barrier(pc->pc_st, pc->pc_sh, 0, pc->pc_mapsize, + BUS_SPACE_BARRIER_WRITE); + desc->rxdw0 |= htole32(R92C_RXDW0_OWN); +} + +static void +rtwn_pci_rx_frame(struct rtwn_softc *sc, struct r92ce_rx_stat *rx_desc, + int desc_idx) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *ring = &pc->rx_ring; + struct rtwn_rx_data *rx_data = &ring->rx_data[desc_idx]; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + uint32_t rxdw0; + struct mbuf *m, *m1; + int8_t rssi = 0, nf; + int infosz, pktlen, shift, error; + + /* Dump Rx descriptor. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC, + "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X, " + "addr: %08X (64: %08X)\n", + __func__, le32toh(rx_desc->rxdw0), le32toh(rx_desc->rxdw1), + le32toh(rx_desc->rxdw2), le32toh(rx_desc->rxdw3), + le32toh(rx_desc->rxdw4), le32toh(rx_desc->tsf_low), + le32toh(rx_desc->rxbufaddr), le32toh(rx_desc->rxbufaddr64)); + + rxdw0 = le32toh(rx_desc->rxdw0); + if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { + /* + * This should not happen since we setup our Rx filter + * to not receive these frames. + */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: RX flags error (%s)\n", __func__, + rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV"); + goto fail; + } + + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack) || + pktlen > MJUMPAGESIZE)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: frame is too short/long: %d\n", __func__, pktlen); + goto fail; + } + + infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; + shift = MS(rxdw0, R92C_RXDW0_SHIFT); + + m1 = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); + if (__predict_false(m1 == NULL)) { + device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n", + __func__); + goto fail; + } + bus_dmamap_sync(ring->data_dmat, rx_data->map, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(ring->data_dmat, rx_data->map); + + error = bus_dmamap_load(ring->data_dmat, rx_data->map, mtod(m1, void *), + MJUMPAGESIZE, rtwn_pci_dma_map_addr, &rx_data->paddr, 0); + if (error != 0) { + m_freem(m1); + + error = bus_dmamap_load(ring->data_dmat, rx_data->map, + mtod(rx_data->m, void *), MJUMPAGESIZE, + rtwn_pci_dma_map_addr, &rx_data->paddr, BUS_DMA_NOWAIT); + if (error != 0) + panic("%s: could not load old RX mbuf", + device_get_name(sc->sc_dev)); + + /* Physical address may have changed. */ + rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr, + MJUMPAGESIZE, desc_idx); + goto fail; + } + + /* Finalize mbuf. */ + m = rx_data->m; + rx_data->m = m1; + m->m_pkthdr.len = m->m_len = pktlen + infosz + shift; + + nf = RTWN_NOISE_FLOOR; + ni = rtwn_rx_common(sc, m, rx_desc, &rssi); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: Rx frame len %d, infosz %d, shift %d, rssi %d\n", + __func__, pktlen, infosz, shift, rssi); + + /* Update RX descriptor. */ + rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr, MJUMPAGESIZE, + desc_idx); + + /* Send the frame to the 802.11 layer. */ + RTWN_UNLOCK(sc); + if (ni != NULL) { + (void)ieee80211_input(ni, m, rssi - nf, nf); + /* Node is no longer needed. */ + ieee80211_free_node(ni); + } else + (void)ieee80211_input_all(ic, m, rssi - nf, nf); + + RTWN_LOCK(sc); + + return; + +fail: + counter_u64_add(ic->ic_ierrors, 1); +} + +static void +rtwn_pci_tx_done(struct rtwn_softc *sc, int qid) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; + struct rtwn_tx_desc_common *desc; + struct rtwn_tx_data *data; + + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: qid %d, last %d, cur %d\n", + __func__, qid, ring->last, ring->cur); + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); + + while(ring->last != ring->cur) { + data = &ring->tx_data[ring->last]; + desc = (struct rtwn_tx_desc_common *) + ((uint8_t *)ring->desc + sc->txdesc_len * ring->last); + + KASSERT(data->m != NULL, ("no mbuf")); + + if (desc->flags0 & RTWN_FLAGS0_OWN) + break; + + /* Unmap and free mbuf. */ + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + + if (data->ni != NULL) { /* not a beacon frame */ + ieee80211_tx_complete(data->ni, data->m, 0); + + data->ni = NULL; + ring->queued--; + KASSERT(ring->queued >= 0, + ("ring->queued (qid %d) underflow!\n", qid)); + } else + m_freem(data->m); + + data->m = NULL; + ring->last = (ring->last + 1) % RTWN_PCI_TX_LIST_COUNT; +#ifndef D4054 + if (ring->queued > 0) + sc->sc_tx_timer = 5; + else + sc->sc_tx_timer = 0; +#endif + } + + if ((sc->qfullmsk & (1 << qid)) != 0 && + ring->queued < (RTWN_PCI_TX_LIST_COUNT - 1)) { + sc->qfullmsk &= ~(1 << qid); + rtwn_start(sc); + } + +#ifdef IEEE80211_SUPPORT_SUPERG + /* + * If the TX active queue drops below a certain + * threshold, ensure we age fast-frames out so they're + * transmitted. + */ + if (sc->sc_ratectl != RTWN_RATECTL_NET80211 && ring->queued <= 1) { + /* + * XXX TODO: just make this a callout timer schedule + * so we can flush the FF staging queue if we're + * approaching idle. + */ + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); + } +#endif +} + +static void +rtwn_pci_rx_done(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *ring = &pc->rx_ring; + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); + + for (;;) { + struct r92ce_rx_stat *rx_desc = &ring->desc[ring->cur]; + + if (le32toh(rx_desc->rxdw0) & R92C_RXDW0_OWN) + break; + + rtwn_pci_rx_frame(sc, rx_desc, ring->cur); + + if (!(sc->sc_flags & RTWN_RUNNING)) + return; + + ring->cur = (ring->cur + 1) % RTWN_PCI_RX_LIST_COUNT; + } + + /* Finished receive; age anything left on the FF queue by a little bump */ + /* + * XXX TODO: just make this a callout timer schedule so we can + * flush the FF staging queue if we're approaching idle. + */ +#ifdef IEEE80211_SUPPORT_SUPERG + if (!(sc->sc_flags & RTWN_FW_LOADED) || + sc->sc_ratectl != RTWN_RATECTL_NET80211) + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); +#endif +} + +void +rtwn_pci_intr(void *arg) +{ + struct rtwn_softc *sc = arg; + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + int i, status, tx_rings; + + RTWN_LOCK(sc); + status = rtwn_classify_intr(sc, &tx_rings, 0); + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: status %08X, tx_rings %08X\n", + __func__, status, tx_rings); + if (status == 0 && tx_rings == 0) + goto unlock; + + if (status & RTWN_PCI_INTR_RX) { + rtwn_pci_rx_done(sc); + if (!(sc->sc_flags & RTWN_RUNNING)) + goto unlock; + } + + if (tx_rings != 0) + for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) + if (tx_rings & (1 << i)) + rtwn_pci_tx_done(sc, i); + + if (sc->sc_flags & RTWN_RUNNING) + rtwn_pci_enable_intr(pc); +unlock: + RTWN_UNLOCK(sc); +} diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h new file mode 100644 index 00000000..265d32d8 --- /dev/null +++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_PCI_RX_H +#define RTWN_PCI_RX_H + +void rtwn_pci_dma_map_addr(void *, bus_dma_segment_t *, int, int); +void rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *, + struct r92ce_rx_stat *, bus_addr_t, size_t, int); +void rtwn_pci_intr(void *); + +#endif /* RTWN_PCI_RX_H */ diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c new file mode 100644 index 00000000..a2f4221c --- /dev/null +++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.c @@ -0,0 +1,274 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + + +static struct mbuf * +rtwn_mbuf_defrag(struct mbuf *m0, int how) +{ + struct mbuf *m = NULL; + + KASSERT(m0->m_flags & M_PKTHDR, + ("M_PKTHDR flag is absent (m %p)!", m0)); + + /* NB: we need _exactly_ one mbuf (no less, no more). */ + if (m0->m_pkthdr.len > MJUMPAGESIZE) { + /* XXX MJUM9BYTES? */ + return (NULL); + } else if (m0->m_pkthdr.len > MCLBYTES) { + m = m_getjcl(how, MT_DATA, M_PKTHDR, MJUMPAGESIZE); + if (m == NULL) + return (NULL); + + if (m_dup_pkthdr(m, m0, how) == 0) { + m_freem(m); + return (NULL); + } + + m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t)); + m->m_len = m->m_pkthdr.len; + m_freem(m0); + + return (m); + } else + return (m_defrag(m0, how)); +} + +static int +rtwn_pci_tx_start_frame(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, uint8_t *tx_desc, uint8_t type) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring; + struct rtwn_tx_data *data; + struct rtwn_tx_desc_common *txd; + bus_dma_segment_t segs[1]; + uint8_t qid; + int nsegs, error; + + RTWN_ASSERT_LOCKED(sc); + + switch (type) { + case IEEE80211_FC0_TYPE_CTL: + case IEEE80211_FC0_TYPE_MGT: + qid = RTWN_PCI_MGNT_QUEUE; + break; + default: + qid = M_WME_GETAC(m); + break; + } + + ring = &pc->tx_ring[qid]; + data = &ring->tx_data[ring->cur]; + if (data->m != NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: ring #%u is full (m %p)\n", __func__, qid, data->m); + return (ENOBUFS); + } + + txd = (struct rtwn_tx_desc_common *) + ((uint8_t *)ring->desc + sc->txdesc_len * ring->cur); + if (txd->flags0 & RTWN_FLAGS0_OWN) { + device_printf(sc->sc_dev, + "%s: OWN bit is set (tx desc %d, ring %u)!\n", + __func__, ring->cur, qid); + return (ENOBUFS); + } + + /* Copy Tx descriptor. */ + rtwn_pci_copy_tx_desc(pc, txd, tx_desc); + txd->pktlen = htole16(m->m_pkthdr.len); + txd->offset = sc->txdesc_len; + + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, + &nsegs, BUS_DMA_NOWAIT); + if (error != 0 && error != EFBIG) { + device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", + error); + return (error); + } + if (error != 0) { + struct mbuf *mnew; + + mnew = rtwn_mbuf_defrag(m, M_NOWAIT); + if (mnew == NULL) { + device_printf(sc->sc_dev, "can't defragment mbuf\n"); + return (ENOBUFS); + } + m = mnew; + + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, + segs, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, + "can't map mbuf (error %d)\n", error); + if (ni != NULL) { + if_inc_counter(ni->ni_vap->iv_ifp, + IFCOUNTER_OERRORS, 1); + ieee80211_free_node(ni); + } + m_freem(m); + return (0); /* XXX */ + } + } + + rtwn_pci_tx_postsetup(pc, txd, segs); + txd->flags0 |= RTWN_FLAGS0_OWN; + + /* Dump Tx descriptor. */ + rtwn_dump_tx_desc(sc, txd); + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); + + data->m = m; + data->ni = ni; + + ring->cur = (ring->cur + 1) % RTWN_PCI_TX_LIST_COUNT; + + ring->queued++; + if (ring->queued >= (RTWN_PCI_TX_LIST_COUNT - 1)) + sc->qfullmsk |= (1 << qid); + +#ifndef D4054 + sc->sc_tx_timer = 5; +#endif + + /* Kick TX. */ + rtwn_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid)); + + return (0); +} + +static int +rtwn_pci_tx_start_beacon(struct rtwn_softc *sc, struct mbuf *m, + uint8_t *tx_desc, int id) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring; + struct rtwn_tx_data *data; + struct rtwn_tx_desc_common *txd; + bus_dma_segment_t segs[1]; + int nsegs, error, own; + + RTWN_ASSERT_LOCKED(sc); + + KASSERT(id == 0 || id == 1, ("bogus vap id %d\n", id)); + + ring = &pc->tx_ring[RTWN_PCI_BEACON_QUEUE]; + data = &ring->tx_data[id]; + txd = (struct rtwn_tx_desc_common *) + ((uint8_t *)ring->desc + id * sc->txdesc_len); + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, + BUS_DMASYNC_POSTREAD); + own = !!(txd->flags0 & RTWN_FLAGS0_OWN); + error = 0; + if (!own || txd->pktlen != htole16(m->m_pkthdr.len)) { + if (!own) { + /* Copy Tx descriptor. */ + rtwn_pci_copy_tx_desc(pc, txd, tx_desc); + txd->offset = sc->txdesc_len; + } else { + /* Reload mbuf. */ + bus_dmamap_unload(ring->data_dmat, data->map); + } + + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, + data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, + "can't map beacon (error %d)\n", error); + txd->flags0 &= ~RTWN_FLAGS0_OWN; + goto end; + } + + txd->pktlen = htole16(m->m_pkthdr.len); + rtwn_pci_tx_postsetup(pc, txd, segs); + txd->flags0 |= RTWN_FLAGS0_OWN; +end: + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, + BUS_DMASYNC_PREWRITE); + } + + /* Dump Tx descriptor. */ + rtwn_dump_tx_desc(sc, txd); + + bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); + + return (0); +} + +int +rtwn_pci_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id) +{ + int error = 0; + + RTWN_ASSERT_LOCKED(sc); + + if (ni == NULL) /* beacon frame */ + error = rtwn_pci_tx_start_beacon(sc, m, tx_desc, id); + else + error = rtwn_pci_tx_start_frame(sc, ni, m, tx_desc, type); + + return (error); +} diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h new file mode 100644 index 00000000..9b9d2e33 --- /dev/null +++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_tx.h @@ -0,0 +1,25 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_PCI_TX_H +#define RTWN_PCI_TX_H + +int rtwn_pci_tx_start(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, uint8_t *, uint8_t, int); + +#endif /* RTWN_PCI_TX_H */ diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h new file mode 100644 index 00000000..5a9e64e7 --- /dev/null +++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h @@ -0,0 +1,140 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_PCI_VAR_H +#define RTWN_PCI_VAR_H + +#include + + +#define RTWN_PCI_RX_LIST_COUNT 256 +#define RTWN_PCI_TX_LIST_COUNT 256 + +struct rtwn_rx_data { + bus_dmamap_t map; + struct mbuf *m; + bus_addr_t paddr; +}; + +struct rtwn_rx_ring { + struct r92ce_rx_stat *desc; + bus_addr_t paddr; + bus_dma_tag_t desc_dmat; + bus_dmamap_t desc_map; + bus_dma_tag_t data_dmat; + bus_dma_segment_t seg; + struct rtwn_rx_data rx_data[RTWN_PCI_RX_LIST_COUNT]; + int cur; +}; + +struct rtwn_tx_data { + bus_dmamap_t map; + struct mbuf *m; + struct ieee80211_node *ni; +}; + +struct rtwn_tx_ring { + bus_addr_t paddr; + bus_dma_tag_t desc_dmat; + bus_dmamap_t desc_map; + bus_dma_tag_t data_dmat; + bus_dma_segment_t seg; + void *desc; + struct rtwn_tx_data tx_data[RTWN_PCI_TX_LIST_COUNT]; + int queued; + int cur; + int last; +}; + +/* + * TX queue indices. + */ +enum { + RTWN_PCI_BK_QUEUE, + RTWN_PCI_BE_QUEUE, + RTWN_PCI_VI_QUEUE, + RTWN_PCI_VO_QUEUE, + RTWN_PCI_BEACON_QUEUE, + RTWN_PCI_TXCMD_QUEUE, + RTWN_PCI_MGNT_QUEUE, + RTWN_PCI_HIGH_QUEUE, + RTWN_PCI_HCCA_QUEUE, + RTWN_PCI_NTXQUEUES +}; + +/* + * Interrupt events. + */ +enum { + RTWN_PCI_INTR_RX_ERROR = 0x00000001, + RTWN_PCI_INTR_RX_OVERFLOW = 0x00000002, + RTWN_PCI_INTR_RX_DESC_UNAVAIL = 0x00000004, + RTWN_PCI_INTR_RX_DONE = 0x00000008, + RTWN_PCI_INTR_TX_ERROR = 0x00000010, + RTWN_PCI_INTR_TX_OVERFLOW = 0x00000020, + RTWN_PCI_INTR_TX_REPORT = 0x00000040, + RTWN_PCI_INTR_PS_TIMEOUT = 0x00000080 +}; + +/* Shortcuts */ +/* Vendor driver treats RX errors like ROK... */ +#define RTWN_PCI_INTR_RX \ + (RTWN_PCI_INTR_RX_OVERFLOW | RTWN_PCI_INTR_RX_DESC_UNAVAIL | \ + RTWN_PCI_INTR_RX_DONE) + + +struct rtwn_pci_softc { + struct rtwn_softc pc_sc; /* must be the first */ + + struct resource *irq; + struct resource *mem; + bus_space_tag_t pc_st; + bus_space_handle_t pc_sh; + void *pc_ih; + bus_size_t pc_mapsize; + + struct rtwn_rx_ring rx_ring; + struct rtwn_tx_ring tx_ring[RTWN_PCI_NTXQUEUES]; + + /* must be set by the driver. */ + uint16_t pc_qmap; + uint32_t tcr; + + void (*pc_setup_tx_desc)(struct rtwn_pci_softc *, + void *, uint32_t); + void (*pc_tx_postsetup)(struct rtwn_pci_softc *, + void *, bus_dma_segment_t *); + void (*pc_copy_tx_desc)(void *, const void *); + void (*pc_enable_intr)(struct rtwn_pci_softc *); +}; +#define RTWN_PCI_SOFTC(sc) ((struct rtwn_pci_softc *)(sc)) + +#define rtwn_pci_setup_tx_desc(_pc, _desc, _addr) \ + (((_pc)->pc_setup_tx_desc)((_pc), (_desc), (_addr))) +#define rtwn_pci_tx_postsetup(_pc, _txd, _segs) \ + (((_pc)->pc_tx_postsetup)((_pc), (_txd), (_segs))) +#define rtwn_pci_copy_tx_desc(_pc, _dest, _src) \ + (((_pc)->pc_copy_tx_desc)((_dest), (_src))) +#define rtwn_pci_enable_intr(_pc) \ + (((_pc)->pc_enable_intr)((_pc))) + +#endif /* RTWN_PCI_VAR_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e.h new file mode 100644 index 00000000..999ab400 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTL8188E_H +#define RTL8188E_H + +/* + * Global definitions. + */ +#define R88E_PUBQ_NPAGES 142 +#define R88E_TXPKTBUF_COUNT 177 +#define R88E_TX_PAGE_COUNT 169 + +#define R88E_MACID_MAX 63 +#define R88E_RX_DMA_BUFFER_SIZE 0x2400 + +#define R88E_INTR_MSG_LEN 60 + +#define R88E_CALIB_THRESHOLD 4 + + +/* + * Function declarations. + */ +/* r88e_beacon.c */ +void r88e_beacon_enable(struct rtwn_softc *, int, int); + +/* r88e_calib.c */ +void r88e_iq_calib(struct rtwn_softc *); +void r88e_temp_measure(struct rtwn_softc *); +uint8_t r88e_temp_read(struct rtwn_softc *); + +/* r88e_chan.c */ +void r88e_get_txpower(struct rtwn_softc *, int, + struct ieee80211_channel *, uint16_t[]); +void r88e_set_bw20(struct rtwn_softc *, uint8_t); +void r88e_set_gain(struct rtwn_softc *, uint8_t); + +/* r88e_fw.c */ +#ifndef RTWN_WITHOUT_UCODE +int r88e_fw_cmd(struct rtwn_softc *, uint8_t, const void *, int); +void r88e_fw_reset(struct rtwn_softc *, int); +void r88e_fw_download_enable(struct rtwn_softc *, int); +#endif +void r88e_macid_enable_link(struct rtwn_softc *, int, int); +void r88e_set_media_status(struct rtwn_softc *, int); +#ifndef RTWN_WITHOUT_UCODE +int r88e_set_rsvd_page(struct rtwn_softc *, int, int, int); +int r88e_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, int); +#endif + +/* r88e_init.c */ +void r88e_init_bb(struct rtwn_softc *); +void r88e_init_rf(struct rtwn_softc *); +int r88e_power_on(struct rtwn_softc *); + +/* r88e_led.c */ +void r88e_set_led(struct rtwn_softc *, int, int); + +/* r88e_rf.c */ +void r88e_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); + +/* r88e_rom.c */ +void r88e_parse_rom(struct rtwn_softc *, uint8_t *); + +/* r88e_rx.c */ +void r88e_ratectl_tx_complete(struct rtwn_softc *, uint8_t *, int); +void r88e_handle_c2h_report(struct rtwn_softc *, uint8_t *, int); +int8_t r88e_get_rssi_cck(struct rtwn_softc *, void *); +int8_t r88e_get_rssi_ofdm(struct rtwn_softc *, void *); + +/* r88e_tx.c */ +void r88e_tx_enable_ampdu(void *, int); +void r88e_tx_setup_hwseq(void *); +void r88e_tx_setup_macid(void *, int); + +#endif /* RTL8188E_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c new file mode 100644 index 00000000..752b29dd --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_beacon.c @@ -0,0 +1,64 @@ +#include + +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r88e_beacon_enable(struct rtwn_softc *sc, int id, int enable) +{ + + if (enable) { + rtwn_setbits_1(sc, R92C_MBID_NUM, 0, R88E_MBID_TXBCN_RPT(id)); + rtwn_setbits_1(sc, R92C_BCN_CTRL(id), + 0, R92C_BCN_CTRL_EN_BCN); + } else { + rtwn_setbits_1(sc, R92C_MBID_NUM, R88E_MBID_TXBCN_RPT(id), 0); + rtwn_setbits_1(sc, R92C_BCN_CTRL(id), + R92C_BCN_CTRL_EN_BCN, 0); + } +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c new file mode 100644 index 00000000..c996749a --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c @@ -0,0 +1,69 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88e_iq_calib(struct rtwn_softc *sc) +{ + /* XXX TODO */ +} + +void +r88e_temp_measure(struct rtwn_softc *sc) +{ + rtwn_rf_write(sc, 0, R88E_RF_T_METER, R88E_RF_T_METER_START); +} + +uint8_t +r88e_temp_read(struct rtwn_softc *sc) +{ + return (MS(rtwn_rf_read(sc, 0, R88E_RF_T_METER), + R88E_RF_T_METER_VAL)); +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c new file mode 100644 index 00000000..405edb2b --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c @@ -0,0 +1,169 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +static int +r88e_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint8_t chan; + int group; + + chan = rtwn_chan2centieee(c); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + 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 if (chan <= 14) group = 5; + else { + KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); + return (-1); + } + } else { + KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); + return (-1); + } + + return (group); +} + +void +r88e_get_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT]) +{ + struct r92c_softc *rs = sc->sc_priv; + const struct rtwn_r88e_txpwr *rt = rs->rs_txpwr; + const struct rtwn_r88e_txagc *base = rs->rs_txagc; + uint16_t cckpow, ofdmpow, bw20pow, htpow; + int max_mcs, ridx, group; + + /* Determine channel group. */ + group = r88e_get_power_group(sc, c); + if (group == -1) { /* shouldn't happen */ + device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); + return; + } + + /* XXX net80211 regulatory */ + + max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n")); + + memset(power, 0, max_mcs * sizeof(power[0])); + if (rs->regulatory == 0) { + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] = base->pwr[0][ridx]; + } + for (ridx = RTWN_RIDX_OFDM6; ridx < RTWN_RIDX_COUNT; ridx++) { + if (rs->regulatory == 3) + power[ridx] = base->pwr[0][ridx]; + else if (rs->regulatory == 1) { + if (!IEEE80211_IS_CHAN_HT40(c)) + power[ridx] = base->pwr[group][ridx]; + } else if (rs->regulatory != 2) + power[ridx] = base->pwr[0][ridx]; + } + + /* Compute per-CCK rate Tx power. */ + cckpow = rt->cck_tx_pwr[group]; + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] += cckpow; + + htpow = rt->ht40_tx_pwr[group]; + + /* Compute per-OFDM rate Tx power. */ + ofdmpow = htpow + rt->ofdm_tx_pwr_diff; + for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) + power[ridx] += ofdmpow; + + bw20pow = htpow + rt->bw20_tx_pwr_diff; + for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++) + power[ridx] += bw20pow; + + /* Apply max limit. */ + for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } +} + +void +r88e_set_bw20(struct rtwn_softc *sc, uint8_t chan) +{ + struct r92c_softc *rs = sc->sc_priv; + + rtwn_setbits_1(sc, R92C_BWOPMODE, 0, R92C_BWOPMODE_20MHZ); + + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0); + rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0); + + /* Select 20MHz bandwidth. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + (rs->rf_chnlbw[0] & ~0xfff) | chan | R88E_RF_CHNLBW_BW20); +} + +void +r88e_set_gain(struct rtwn_softc *sc, uint8_t gain) +{ + + rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0), + R92C_OFDM0_AGCCORE1_GAIN_M, gain); +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c new file mode 100644 index 00000000..409084f6 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw.c @@ -0,0 +1,227 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +int +r88e_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len) +{ + struct r88e_fw_cmd cmd; + int ntries, error; + + if (!(sc->sc_flags & RTWN_FW_LOADED)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware " + "was not loaded; command (id %d) will be discarded\n", + __func__, id); + return (0); + } + + /* Wait for current FW box to be empty. */ + for (ntries = 0; ntries < 50; ntries++) { + if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) + break; + rtwn_delay(sc, 2000); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "could not send firmware command\n"); + return (ETIMEDOUT); + } + memset(&cmd, 0, sizeof(cmd)); + cmd.id = id; + KASSERT(len <= sizeof(cmd.msg), + ("%s: firmware command too long (%d > %zu)\n", + __func__, len, sizeof(cmd.msg))); + memcpy(cmd.msg, buf, len); + + /* Write the first word last since that will trigger the FW. */ + if (len > 3) { + error = rtwn_write_4(sc, R88E_HMEBOX_EXT(sc->fwcur), + *(uint32_t *)((uint8_t *)&cmd + 4)); + if (error != 0) + return (error); + } + error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *(uint32_t *)&cmd); + if (error != 0) + return (error); + + sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; + + return (0); +} + +void +r88e_fw_reset(struct rtwn_softc *sc, int reason) +{ + 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); +} + +void +r88e_fw_download_enable(struct rtwn_softc *sc, int enable) +{ + if (enable) { + /* MCU firmware download enable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN); + /* 8051 reset. */ + rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN, + 0, 2); + } else { + /* MCU download disable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0); + /* Reserved for f/w extension. */ + rtwn_write_1(sc, R92C_MCUFWDL + 1, 0); + } +} +#endif + +void +r88e_macid_enable_link(struct rtwn_softc *sc, int id, int enable) +{ + uint32_t reg; + + reg = R88E_MACID_NO_LINK; + if (id > 32) + reg += 4; + + if (enable) + rtwn_setbits_4(sc, reg, 1 << (id % 32), 0); + else + rtwn_setbits_4(sc, reg, 0, 1 << (id % 32)); + + /* XXX max macid for tx reports */ +} + +void +r88e_set_media_status(struct rtwn_softc *sc, int macid) +{ + struct r88e_fw_cmd_msrrpt status; + + if (macid & RTWN_MACID_VALID) + status.msrb0 = R88E_MSRRPT_B0_ASSOC; + else + status.msrb0 = R88E_MSRRPT_B0_DISASSOC; + status.macid = (macid & ~RTWN_MACID_VALID); + + r88e_macid_enable_link(sc, status.macid, + (macid & RTWN_MACID_VALID) != 0); + +#ifndef RTWN_WITHOUT_UCODE + if (r88e_fw_cmd(sc, R88E_CMD_MSR_RPT, &status, sizeof(status)) != 0) { + device_printf(sc->sc_dev, "%s: cannot change media status!\n", + __func__); + } +#endif +} + +#ifndef RTWN_WITHOUT_UCODE +int +r88e_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null, + int qos_null) +{ + struct r88e_fw_cmd_rsvdpage rsvd; + + rsvd.probe_resp = probe_resp; + rsvd.ps_poll = 0; + rsvd.null_data = null; + rsvd.null_data_qos = qos_null; + rsvd.null_data_qos_bt = 0; + return (r88e_fw_cmd(sc, R88E_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd))); +} + +int +r88e_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap, + int off) +{ + struct r88e_fw_cmd_pwrmode mode; + int error; + + if (off && vap->iv_state == IEEE80211_S_RUN && + (vap->iv_flags & IEEE80211_F_PMGTON)) { + mode.mode = R88E_PWRMODE_LEG; + /* + * TODO: switch to RFOFF state + * (something is missing here - Rx stops with it). + */ +#ifdef RTWN_TODO + mode.pwr_state = R88E_PWRMODE_STATE_RFOFF; +#else + mode.pwr_state = R88E_PWRMODE_STATE_RFON; +#endif + } else { + mode.mode = R88E_PWRMODE_CAM; + mode.pwr_state = R88E_PWRMODE_STATE_ALLON; + } + mode.pwrb1 = + SM(R88E_PWRMODE_B1_SMART_PS, R88E_PWRMODE_B1_LEG_NULLDATA) | + SM(R88E_PWRMODE_B1_RLBM, R88E_PWRMODE_B1_MODE_MIN); + /* XXX ignored */ + mode.bcn_pass = 0; + mode.queue_uapsd = 0; + error = r88e_fw_cmd(sc, R88E_CMD_SET_PWRMODE, &mode, sizeof(mode)); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: CMD_SET_PWRMODE was not sent, error %d\n", + __func__, error); + } + + return (error); +} +#endif diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h new file mode 100644 index 00000000..c152729c --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2015 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_FW_CMD_H +#define R88E_FW_CMD_H + +/* + * Host to firmware commands. + */ +struct r88e_fw_cmd { + uint8_t id; +#define R88E_CMD_RSVD_PAGE 0x00 +#define R88E_CMD_MSR_RPT 0x01 +#define R88E_CMD_SET_PWRMODE 0x20 + + uint8_t msg[7]; +} __packed __attribute__((aligned(4))); + +/* Structure for R88E_CMD_RSVD_PAGE. */ +struct r88e_fw_cmd_rsvdpage { + uint8_t probe_resp; + uint8_t ps_poll; + uint8_t null_data; + uint8_t null_data_qos; + uint8_t null_data_qos_bt; +} __packed; + +/* Structure for R88E_CMD_MSR_RPT. */ +struct r88e_fw_cmd_msrrpt { + uint8_t msrb0; +#define R88E_MSRRPT_B0_DISASSOC 0x00 +#define R88E_MSRRPT_B0_ASSOC 0x01 + + uint8_t macid; +} __packed; + +/* Structure for R88E_CMD_SET_PWRMODE. */ +struct r88e_fw_cmd_pwrmode { + uint8_t mode; +#define R88E_PWRMODE_CAM 0 +#define R88E_PWRMODE_LEG 1 +#define R88E_PWRMODE_UAPSD 2 + + uint8_t pwrb1; +#define R88E_PWRMODE_B1_RLBM_M 0x0f +#define R88E_PWRMODE_B1_RLBM_S 0 +#define R88E_PWRMODE_B1_MODE_MIN 0 +#define R88E_PWRMODE_B1_MODE_MAX 1 +#define R88E_PWRMODE_B1_MODE_DTIM 2 + +#define R88E_PWRMODE_B1_SMART_PS_M 0xf0 +#define R88E_PWRMODE_B1_SMART_PS_S 4 +#define R88E_PWRMODE_B1_LEG_PSPOLL0 0 +#define R88E_PWRMODE_B1_LEG_PSPOLL1 1 +#define R88E_PWRMODE_B1_LEG_NULLDATA 2 +#define R88E_PWRMODE_B1_WMM_PSPOLL 0 +#define R88E_PWRMODE_B1_WMM_NULLDATA 1 + + uint8_t bcn_pass; + uint8_t queue_uapsd; + uint8_t pwr_state; +#define R88E_PWRMODE_STATE_RFOFF 0x00 +#define R88E_PWRMODE_STATE_RFON 0x04 +#define R88E_PWRMODE_STATE_ALLON 0x0c +} __packed; + +#endif /* R88E_FW_CMD_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c new file mode 100644 index 00000000..62e5463b --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_init.c @@ -0,0 +1,160 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include + + +static void +r88e_crystalcap_write(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg; + uint8_t val; + + val = rs->crystalcap & 0x3f; + reg = rtwn_bb_read(sc, R92C_AFE_XTAL_CTRL); + rtwn_bb_write(sc, R92C_AFE_XTAL_CTRL, + RW(reg, R92C_AFE_XTAL_CTRL_ADDR, val | val << 6)); +} + +void +r88e_init_bb(struct rtwn_softc *sc) +{ + + /* Enable BB and RF. */ + rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0, + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | + R92C_SYS_FUNC_EN_DIO_RF); + + 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_USBA | R92C_SYS_FUNC_EN_USBD | + R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); + + r92c_init_bb_common(sc); + + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553422); + rtwn_delay(sc, 1); + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553420); + rtwn_delay(sc, 1); + + r88e_crystalcap_write(sc); +} + +int +r88e_power_on(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + int ntries; + + /* Wait for power ready bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for chip power up\n"); + return (ETIMEDOUT); + } + + /* Reset BB. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST, 0)); + + RTWN_CHK(rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0, 0x80)); + + /* Disable HWPDN. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APDM_HPDN, 0, 1)); + + /* Disable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0, 1)); + + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + 0, R92C_APS_FSMCO_APFM_ONMAC, 1)); + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) + return (ETIMEDOUT); + + /* Enable LDO normal mode. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_LPLDO_CTRL, + R92C_LPLDO_CTRL_SLEEP, 0)); + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0)); + RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN | + R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) | + R92C_CR_CALTMR_EN)); + + return (0); +#undef RTWN_CHK +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c new file mode 100644 index 00000000..02ec644a --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_led.c @@ -0,0 +1,70 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r88e_set_led(struct rtwn_softc *sc, int led, int on) +{ + + if (led == RTWN_LED_LINK) { + if (!on) { + rtwn_setbits_1(sc, R92C_LEDCFG2, 0x6f, + R92C_LEDCFG0_DIS); + rtwn_setbits_1(sc, R92C_MAC_PINMUX_CFG, 0x01, 0); + } else + rtwn_setbits_1(sc, R92C_LEDCFG2, 0x0f, 0x60); + sc->ledlink = on; /* Save LED state. */ + } + + /* XXX led #1? */ +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h new file mode 100644 index 00000000..cb4f7edb --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h @@ -0,0 +1,273 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_PRIV_H +#define R88E_PRIV_H + +#include + +/* + * Parsed Tx power (diff) values. + */ +struct rtwn_r88e_txpwr { + uint8_t cck_tx_pwr[R88E_GROUP_2G]; + uint8_t ht40_tx_pwr[R88E_GROUP_2G - 1]; + int8_t ofdm_tx_pwr_diff; + int8_t bw20_tx_pwr_diff; +}; + + +/* + * MAC initialization values. + */ +static const struct rtwn_mac_prog rtl8188eu_mac[] = { + { 0x026, 0x41 }, { 0x027, 0x35 }, { 0x040, 0x00 }, { 0x428, 0x0a }, + { 0x429, 0x10 }, { 0x430, 0x00 }, { 0x431, 0x01 }, { 0x432, 0x02 }, + { 0x433, 0x04 }, { 0x434, 0x05 }, { 0x435, 0x06 }, { 0x436, 0x07 }, + { 0x437, 0x08 }, { 0x438, 0x00 }, { 0x439, 0x00 }, { 0x43a, 0x01 }, + { 0x43b, 0x02 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, { 0x43e, 0x06 }, + { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, { 0x442, 0x00 }, + { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, { 0x447, 0x00 }, + { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, { 0x45b, 0xb9 }, + { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x480, 0x08 }, { 0x4c8, 0xff }, + { 0x4c9, 0x08 }, { 0x4cc, 0xff }, { 0x4cd, 0xff }, { 0x4ce, 0x01 }, + { 0x4d3, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, { 0x502, 0x2f }, + { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, { 0x506, 0x5e }, + { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, { 0x50a, 0x5e }, + { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, { 0x50e, 0x00 }, + { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, { 0x516, 0x0a }, + { 0x525, 0x4f }, { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, + { 0x55d, 0xff }, { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a }, + { 0x620, 0xff }, { 0x621, 0xff }, { 0x622, 0xff }, { 0x623, 0xff }, + { 0x624, 0xff }, { 0x625, 0xff }, { 0x626, 0xff }, { 0x627, 0xff }, + { 0x652, 0x20 }, { 0x63c, 0x0a }, { 0x63d, 0x0a }, { 0x63e, 0x0e }, + { 0x63f, 0x0e }, { 0x640, 0x40 }, { 0x66e, 0x05 }, { 0x700, 0x21 }, + { 0x701, 0x43 }, { 0x702, 0x65 }, { 0x703, 0x87 }, { 0x708, 0x21 }, + { 0x709, 0x43 }, { 0x70a, 0x65 }, { 0x70b, 0x87 } +}; + +/* + * Baseband initialization values. + */ +static const uint16_t rtl8188eu_bb_regs[] = { + 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x81c, + 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, + 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, + 0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, + 0x880, 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, + 0x900, 0x904, 0x908, 0x90c, 0x910, 0x914, 0xa00, 0xa04, + 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24, + 0xa28, 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xb2c, + 0xc00, 0xc04, 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, + 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, + 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, 0xc5c, + 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, + 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, 0xc98, 0xc9c, + 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, 0xcbc, + 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, + 0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, + 0xd10, 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, + 0xd40, 0xd44, 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, + 0xd60, 0xd64, 0xd68, 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, + 0xe04, 0xe08, 0xe10, 0xe14, 0xe18, 0xe1c, 0xe28, 0xe30, + 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, + 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xee8, 0xeec, 0xf14, 0xf4c, 0xf00 +}; + +static const uint32_t rtl8188eu_bb_vals[] = { + 0x80040000, 0x00000003, 0x0000fc00, 0x0000000a, 0x10001331, + 0x020c3d10, 0x02200385, 0x00000000, 0x01000100, 0x00390204, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00010000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x569a11a9, 0x01000014, 0x66f60110, + 0x061f0649, 0x00000000, 0x27272700, 0x07000760, 0x25004000, + 0x00000808, 0x00000000, 0xb0000c1c, 0x00000001, 0x00000000, + 0xccc000c0, 0x00000800, 0xfffffffe, 0x40302010, 0x00706050, + 0x00000000, 0x00000023, 0x00000000, 0x81121111, 0x00000002, + 0x00000201, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e7f120f, + 0x9500bb78, 0x1114d028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x00000900, 0x225b0606, 0x218075b1, 0x80000000, 0x48071d40, + 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, 0x40000100, + 0x08800000, 0x40000100, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x69e9ac47, 0x469652af, 0x49795994, 0x0a97971c, + 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, 0x69553420, + 0x43bc0094, 0x00013169, 0x00250492, 0x00000000, 0x7112848b, + 0x47c00bff, 0x00000036, 0x2c7f000d, 0x020610db, 0x0000001f, + 0x00b91612, 0x390000e4, 0x20f60000, 0x40000100, 0x20200000, + 0x00091521, 0x00000000, 0x00121820, 0x00007f7f, 0x00000000, + 0x000300a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x28000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x64b22427, 0x00766932, + 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, 0x00000740, + 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, 0x3333bc43, + 0x7a8f5b6f, 0xcc979975, 0x00000000, 0x80608000, 0x00000000, + 0x00127353, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x6437140a, 0x00000000, 0x00000282, 0x30032064, 0x4653de68, + 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220, + 0x000e3c24, 0x2d2d2d2d, 0x2d2d2d2d, 0x0390272d, 0x2d2d2d2d, + 0x2d2d2d2d, 0x2d2d2d2d, 0x2d2d2d2d, 0x00000000, 0x1000dc1f, + 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, 0x01004800, + 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102, + 0x28160d05, 0x00000008, 0x001b25a4, 0x00c00014, 0x00c00014, + 0x01000014, 0x01000014, 0x01000014, 0x01000014, 0x00c00014, + 0x01000014, 0x00c00014, 0x00c00014, 0x00c00014, 0x00c00014, + 0x00000014, 0x00000014, 0x21555448, 0x01c00014, 0x00000003, + 0x00000000, 0x00000300 +}; + +static const struct rtwn_bb_prog rtl8188eu_bb[] = { + { + nitems(rtl8188eu_bb_regs), + rtl8188eu_bb_regs, + rtl8188eu_bb_vals, + { 0 }, + NULL + } +}; + +static const uint32_t rtl8188eu_agc_vals[] = { + 0xfb000001, 0xfb010001, 0xfb020001, 0xfb030001, 0xfb040001, + 0xfb050001, 0xfa060001, 0xf9070001, 0xf8080001, 0xf7090001, + 0xf60a0001, 0xf50b0001, 0xf40c0001, 0xf30d0001, 0xf20e0001, + 0xf10f0001, 0xf0100001, 0xef110001, 0xee120001, 0xed130001, + 0xec140001, 0xeb150001, 0xea160001, 0xe9170001, 0xe8180001, + 0xe7190001, 0xe61a0001, 0xe51b0001, 0xe41c0001, 0xe31d0001, + 0xe21e0001, 0xe11f0001, 0x8a200001, 0x89210001, 0x88220001, + 0x87230001, 0x86240001, 0x85250001, 0x84260001, 0x83270001, + 0x82280001, 0x6b290001, 0x6a2a0001, 0x692b0001, 0x682c0001, + 0x672d0001, 0x662e0001, 0x652f0001, 0x64300001, 0x63310001, + 0x62320001, 0x61330001, 0x46340001, 0x45350001, 0x44360001, + 0x43370001, 0x42380001, 0x41390001, 0x403a0001, 0x403b0001, + 0x403c0001, 0x403d0001, 0x403e0001, 0x403f0001, 0xfb400001, + 0xfb410001, 0xfb420001, 0xfb430001, 0xfb440001, 0xfb450001, + 0xfb460001, 0xfb470001, 0xfb480001, 0xfa490001, 0xf94a0001, + 0xf84B0001, 0xf74c0001, 0xf64d0001, 0xf54e0001, 0xf44f0001, + 0xf3500001, 0xf2510001, 0xf1520001, 0xf0530001, 0xef540001, + 0xee550001, 0xed560001, 0xec570001, 0xeb580001, 0xea590001, + 0xe95a0001, 0xe85b0001, 0xe75c0001, 0xe65d0001, 0xe55e0001, + 0xe45f0001, 0xe3600001, 0xe2610001, 0xc3620001, 0xc2630001, + 0xc1640001, 0x8b650001, 0x8a660001, 0x89670001, 0x88680001, + 0x87690001, 0x866a0001, 0x856b0001, 0x846c0001, 0x676d0001, + 0x666e0001, 0x656f0001, 0x64700001, 0x63710001, 0x62720001, + 0x61730001, 0x60740001, 0x46750001, 0x45760001, 0x44770001, + 0x43780001, 0x42790001, 0x417a0001, 0x407b0001, 0x407c0001, + 0x407d0001, 0x407e0001, 0x407f0001 +}; + +static const struct rtwn_agc_prog rtl8188eu_agc[] = { + { + nitems(rtl8188eu_agc_vals), + rtl8188eu_agc_vals, + { 0 }, + NULL + } +}; + +/* + * RF initialization values. + */ +static const uint8_t rtl8188eu_rf_regs[] = { + 0x00, 0x08, 0x18, 0x19, 0x1e, 0x1f, 0x2f, 0x3f, 0x42, 0x57, + 0x58, 0x67, 0x83, 0xb0, 0xb1, 0xb2, 0xb4, 0xb6, 0xb7, 0xb8, + 0xb9, 0xba, 0xbb, 0xbf, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xdf, 0xef, 0x51, 0x52, 0x53, 0x56, + 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xb6, 0x18, 0x5a, + 0x19, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x00, 0x84, 0x86, 0x87, 0x8e, 0x8f, 0xef, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0x00, 0x18, 0xfe, 0xfe, + 0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00 +}; + +static const uint32_t rtl8188eu_rf_vals[] = { + 0x30000, 0x84000, 0x00407, 0x00012, 0x80009, 0x00880, 0x1a060, + 0x00000, 0x060c0, 0xd0000, 0xbe180, 0x01552, 0x00000, 0xff8fc, + 0x54400, 0xccc19, 0x43003, 0x4953e, 0x1c718, 0x060ff, 0x80001, + 0x40000, 0x00400, 0xc0000, 0x02400, 0x00009, 0x40c91, 0x99999, + 0x000a3, 0x88820, 0x76c06, 0x00000, 0x80000, 0x00180, 0x001a0, + 0x6b27d, 0x7e49d, 0x00073, 0x51ff3, 0x00086, 0x00186, + 0x00286, 0x01c25, 0x09c25, 0x11c25, 0x19c25, 0x48538, 0x00c07, + 0x4bd00, 0x739d0, 0x0adf3, 0x09df0, 0x08ded, 0x07dea, 0x06de7, + 0x054ee, 0x044eb, 0x034e8, 0x0246b, 0x01468, 0x0006d, 0x30159, + 0x68200, 0x000ce, 0x48a00, 0x65540, 0x88000, 0x020a0, 0xf02b0, + 0xef7b0, 0xd4fb0, 0xcf060, 0xb0090, 0xa0080, 0x90080, 0x8f780, + 0x722b0, 0x6f7b0, 0x54fb0, 0x4f060, 0x30090, 0x20080, 0x10080, + 0x0f780, 0x000a0, 0x10159, 0x0f407, 0x0c350, 0x0c350, 0x80003, + 0x0c350, 0x0c350, 0x00001, 0x80000, 0x33e60 +}; + +static const struct rtwn_rf_prog rtl8188eu_rf[] = { + { + nitems(rtl8188eu_rf_regs), + rtl8188eu_rf_regs, + rtl8188eu_rf_vals, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL } +}; + + +struct rtwn_r88e_txagc { + uint8_t pwr[R88E_GROUP_2G][20]; /* RTWN_RIDX_MCS(7) + 1 */ +}; + +/* + * Per RF chain/group/rate Tx gain values. + */ +static const struct rtwn_r88e_txagc r88e_txagc[] = { + { { /* Chain 0. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 3. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 4. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 5. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + } + } } +}; + +#endif /* R88E_PRIV_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h new file mode 100644 index 00000000..f6f26fa4 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_reg.h @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_REG_H +#define R88E_REG_H + +#include + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R88E_BB_PAD_CTRL 0x064 +#define R88E_HIMR 0x0b0 +#define R88E_HISR 0x0b4 +#define R88E_HIMRE 0x0b8 +#define R88E_HISRE 0x0bc +/* MAC General Configuration. */ +#define R88E_32K_CTRL 0x194 +#define R88E_HMEBOX_EXT(idx) (0x1f0 + (idx) * 4) +/* Protocol Configuration. */ +#define R88E_TXPKTBUF_BCNQ1_BDNY 0x457 +#define R88E_MACID_NO_LINK 0x484 +#define R88E_TX_RPT_CTRL 0x4ec +#define R88E_TX_RPT_MACID_MAX 0x4ed +#define R88E_TX_RPT_TIME 0x4f0 +#define R88E_SCH_TXCMD 0x5f8 + + +/* Bits for R88E_HIMR. */ +#define R88E_HIMR_CPWM 0x00000100 +#define R88E_HIMR_CPWM2 0x00000200 +#define R88E_HIMR_TBDER 0x04000000 +#define R88E_HIMR_PSTIMEOUT 0x20000000 + +/* Bits for R88E_HIMRE.*/ +#define R88E_HIMRE_RXFOVW 0x00000100 +#define R88E_HIMRE_TXFOVW 0x00000200 +#define R88E_HIMRE_RXERR 0x00000400 +#define R88E_HIMRE_TXERR 0x00000800 + +/* Bits for R88E_TX_RPT_CTRL. */ +#define R88E_TX_RPT1_ENA 0x01 +#define R88E_TX_RPT2_ENA 0x02 + +/* Bits for R92C_MBID_NUM. */ +#define R88E_MBID_TXBCN_RPT(id) (0x08 << (id)) + +/* Bits for R92C_SECCFG. */ +#define R88E_SECCFG_CHK_KEYID 0x0100 + + +/* + * Baseband registers. + */ +/* Bits for R92C_LSSI_PARAM(i). */ +#define R88E_LSSI_PARAM_ADDR_M 0x0ff00000 +#define R88E_LSSI_PARAM_ADDR_S 20 + + +/* + * RF (6052) registers. + */ +#define R88E_RF_T_METER 0x42 + +/* Bits for R92C_RF_CHNLBW. */ +#define R88E_RF_CHNLBW_BW20 0x00c00 + +/* Bits for R88E_RF_T_METER. */ +#define R88E_RF_T_METER_VAL_M 0x0fc00 +#define R88E_RF_T_METER_VAL_S 10 +#define R88E_RF_T_METER_START 0x30000 + +#endif /* R88E_REG_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c new file mode 100644 index 00000000..18991ba8 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rf.c @@ -0,0 +1,62 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88e_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t val) +{ + rtwn_bb_write(sc, R92C_LSSI_PARAM(chain), + SM(R88E_LSSI_PARAM_ADDR, addr) | + SM(R92C_LSSI_PARAM_DATA, val)); +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c new file mode 100644 index 00000000..9fc7c4c4 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom.c @@ -0,0 +1,87 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +void +r88e_parse_rom(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r92c_softc *rs = sc->sc_priv; + struct rtwn_r88e_txpwr *rt = rs->rs_txpwr; + struct r88e_rom *rom = (struct r88e_rom *)buf; + int i; + + rt->bw20_tx_pwr_diff = RTWN_SIGN4TO8(MS(rom->tx_pwr_diff, HIGH_PART)); + rt->ofdm_tx_pwr_diff = RTWN_SIGN4TO8(MS(rom->tx_pwr_diff, LOW_PART)); + for (i = 0; i < nitems(rom->cck_tx_pwr); i++) + rt->cck_tx_pwr[i] = rom->cck_tx_pwr[i]; + for (i = 0; i < nitems(rom->ht40_tx_pwr); i++) + rt->ht40_tx_pwr[i] = rom->ht40_tx_pwr[i]; + + rs->crystalcap = RTWN_GET_ROM_VAR(rom->crystalcap, + R88E_ROM_CRYSTALCAP_DEF); + rs->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY); + rs->board_type = + MS(RTWN_GET_ROM_VAR(rom->rf_board_opt, R92C_BOARD_TYPE_DONGLE), + R92C_ROM_RF1_BOARD_TYPE); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type %d\n", + __func__,rs->regulatory); + + sc->thermal_meter = rom->thermal_meter; + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h new file mode 100644 index 00000000..5734246f --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R88E_ROM_DEFS_H +#define R88E_ROM_DEFS_H + +#include + +#define R88E_GROUP_2G 6 + +#define R88E_EFUSE_MAX_LEN 512 +#define R88E_EFUSE_MAP_LEN 512 + +#endif /* R88E_ROM_DEFS_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h new file mode 100644 index 00000000..c80028e0 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_image.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R88E_ROM_IMAGE_H +#define R88E_ROM_IMAGE_H + +#include + +/* + * RTL8188EU ROM image. + */ +struct r88e_rom { + uint8_t reserved1[16]; + uint8_t cck_tx_pwr[R88E_GROUP_2G]; + uint8_t ht40_tx_pwr[R88E_GROUP_2G - 1]; + uint8_t tx_pwr_diff; + uint8_t reserved2[156]; + uint8_t channel_plan; + uint8_t crystalcap; +#define R88E_ROM_CRYSTALCAP_DEF 0x20 + + uint8_t thermal_meter; + uint8_t reserved3[6]; + uint8_t rf_board_opt; + uint8_t rf_feature_opt; + uint8_t rf_bt_opt; + uint8_t version; + uint8_t customer_id; + uint8_t reserved4[3]; + uint8_t rf_ant_opt; + uint8_t reserved5[6]; + uint16_t vid; + uint16_t pid; + uint8_t usb_opt; + uint8_t reserved6[2]; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint8_t reserved7[2]; + uint8_t string[33]; /* "realtek 802.11n NIC" */ + uint8_t reserved8[256]; +} __packed; + +_Static_assert(sizeof(struct r88e_rom) == R88E_EFUSE_MAP_LEN, + "R88E_EFUSE_MAP_LEN must be equal to sizeof(struct r88e_rom)!"); + +#endif /* R88E_ROM_IMAGE_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c new file mode 100644 index 00000000..464542b4 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c @@ -0,0 +1,213 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88e_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ +#if __FreeBSD_version >= 1200012 + struct ieee80211_ratectl_tx_status txs; +#endif + struct r88e_tx_rpt_ccx *rpt; + struct ieee80211_node *ni; + uint8_t macid; + int ntries; + + /* Skip Rx descriptor. */ + buf += sizeof(struct r92c_rx_stat); + len -= sizeof(struct r92c_rx_stat); + + rpt = (struct r88e_tx_rpt_ccx *)buf; + if (len != sizeof(*rpt)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: wrong report size (%d, must be %zu)\n", + __func__, len, sizeof(*rpt)); + return; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: ccx report dump: 0: %02X, 1: %02X, 2: %02X, queue time: " + "low %02X, high %02X, final ridx: %02X, 6: %02X, 7: %02X\n", + __func__, rpt->rptb0, rpt->rptb1, rpt->rptb2, rpt->queue_time_low, + rpt->queue_time_high, rpt->final_rate, rpt->rptb6, rpt->rptb7); + + macid = MS(rpt->rptb1, R88E_RPTB1_MACID); + if (macid > sc->macid_limit) { + device_printf(sc->sc_dev, + "macid %u is too big; increase MACID_MAX limit\n", + macid); + return; + } + + ntries = MS(rpt->rptb2, R88E_RPTB2_RETRY_CNT); + + ni = sc->node_list[macid]; + if (ni != NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was" + "%s sent (%d retries)\n", __func__, macid, + (rpt->rptb1 & R88E_RPTB1_PKT_OK) ? "" : " not", + ntries); + +#if __FreeBSD_version >= 1200012 + txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | + IEEE80211_RATECTL_STATUS_FINAL_RATE; + txs.long_retries = ntries; + if (rpt->final_rate > RTWN_RIDX_OFDM54) { /* MCS */ + txs.final_rate = + (rpt->final_rate - 12) | IEEE80211_RATE_MCS; + } else + txs.final_rate = ridx2rate[rpt->final_rate]; + if (rpt->rptb1 & R88E_RPTB1_PKT_OK) + txs.status = IEEE80211_RATECTL_TX_SUCCESS; + else if (rpt->rptb2 & R88E_RPTB2_RETRY_OVER) + txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; + else if (rpt->rptb2 & R88E_RPTB2_LIFE_EXPIRE) + txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; + else + txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED; + ieee80211_ratectl_tx_complete(ni, &txs); +#else + struct ieee80211vap *vap = ni->ni_vap; + if (rpt->rptb1 & R88E_RPTB1_PKT_OK) { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); + } else { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); + } +#endif + } else { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n", + __func__, macid); + } +} + +void +r88e_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + + /* Skip Rx descriptor. */ + buf += sizeof(struct r92c_rx_stat); + len -= sizeof(struct r92c_rx_stat); + + if (len != R88E_INTR_MSG_LEN) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: wrong interrupt message size (%d, must be %d)\n", + __func__, len, R88E_INTR_MSG_LEN); + return; + } + + /* XXX TODO */ +} + +int8_t +r88e_get_rssi_cck(struct rtwn_softc *sc, void *physt) +{ + struct r88e_rx_phystat *phy = (struct r88e_rx_phystat *)physt; + int8_t lna_idx, vga_idx, rssi; + + lna_idx = (phy->agc_rpt & 0xe0) >> 5; + vga_idx = (phy->agc_rpt & 0x1f); + rssi = 6 - 2 * vga_idx; + + switch (lna_idx) { + case 7: + if (vga_idx > 27) + rssi = -100 + 6; + else + rssi += -100 + 2 * 27; + break; + case 6: + rssi += -48 + 2 * 2; + break; + case 5: + rssi += -42 + 2 * 7; + break; + case 4: + rssi += -36 + 2 * 7; + break; + case 3: + rssi += -24 + 2 * 7; + break; + case 2: + rssi += -6 + 2 * 5; + if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) + rssi -= 6; + break; + case 1: + rssi += 8; + break; + case 0: + rssi += 14; + break; + } + + return (rssi); +} + +int8_t +r88e_get_rssi_ofdm(struct rtwn_softc *sc, void *physt) +{ + struct r88e_rx_phystat *phy = (struct r88e_rx_phystat *)physt; + int rssi; + + /* Get average RSSI. */ + rssi = ((phy->sig_qual >> 1) & 0x7f) - 110; + + return (rssi); +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h new file mode 100644 index 00000000..2b72f3dd --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_RX_DESC_H +#define R88E_RX_DESC_H + +#include + +/* Rx MAC descriptor defines (chip-specific). */ +/* Rx dword 3 */ +#define R88E_RXDW3_RPT_M 0x0000c000 +#define R88E_RXDW3_RPT_S 14 +#define R88E_RXDW3_RPT_RX 0 +#define R88E_RXDW3_RPT_TX1 1 +#define R88E_RXDW3_RPT_TX2 2 +#define R88E_RXDW3_RPT_HIS 3 + +/* Rx PHY descriptor. */ +struct r88e_rx_phystat { + uint8_t path_agc[2]; + uint8_t chan; + uint8_t reserved1; + uint8_t sig_qual; + uint8_t agc_rpt; + uint8_t rpt_b; + uint8_t reserved2; + uint8_t noise_power; + uint8_t path_cfotail[2]; + uint8_t pcts_mask[2]; + uint8_t stream_rxevm[2]; + uint8_t path_rxsnr[2]; + uint8_t noise_power_db_lsb; + uint8_t reserved3[3]; + uint8_t stream_csi[2]; + uint8_t stream_target_csi[2]; + uint8_t sig_evm; +} __packed; + +/* Tx report (type 1). */ +struct r88e_tx_rpt_ccx { + uint8_t rptb0; +#define R88E_RPTB6_PKT_NUM_M 0x0e +#define R88E_RPTB6_PKT_NUM_S 1 +#define R88E_RPTB0_INT_CCX 0x80 + + uint8_t rptb1; +#define R88E_RPTB1_MACID_M 0x3f +#define R88E_RPTB1_MACID_S 0 +#define R88E_RPTB1_PKT_OK 0x40 +#define R88E_RPTB1_BMC 0x80 + + uint8_t rptb2; +#define R88E_RPTB2_RETRY_CNT_M 0x3f +#define R88E_RPTB2_RETRY_CNT_S 0 +#define R88E_RPTB2_LIFE_EXPIRE 0x40 +#define R88E_RPTB2_RETRY_OVER 0x80 + + uint8_t queue_time_low; + uint8_t queue_time_high; + uint8_t final_rate; + uint8_t rptb6; +#define R88E_RPTB6_QSEL_M 0xf0 +#define R88E_RPTB6_QSEL_S 4 + + uint8_t rptb7; +} __packed; + +/* Interrupt message format. */ +/* XXX recheck */ +struct r88e_intr_msg { + uint8_t c2h_id; + uint8_t c2h_seq; + uint8_t c2h_evt; + uint8_t reserved1[13]; + uint8_t cpwm1; + uint8_t reserved2[3]; + uint8_t cpwm2; + uint8_t reserved3[27]; + uint32_t hisr; + uint32_t hisr_ex; +}; + +#endif /* R88E_RX_DESC_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c new file mode 100644 index 00000000..4f70e61c --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx.c @@ -0,0 +1,81 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88e_tx_enable_ampdu(void *buf, int enable) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + if (enable) + txd->txdw2 |= htole32(R88E_TXDW2_AGGEN); + else + txd->txdw2 |= htole32(R88E_TXDW2_AGGBK); +} + +void +r88e_tx_setup_hwseq(void *buf) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->txdseq |= htole16(R88E_TXDSEQ_HWSEQ_EN); +} + +void +r88e_tx_setup_macid(void *buf, int id) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, id)); +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h new file mode 100644 index 00000000..98338fb7 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_TX_DESC_H +#define R88E_TX_DESC_H + +#include + +/* Tx MAC descriptor defines (chip-specific). */ +/* Tx dword 1. */ +#define R88E_TXDW1_MACID_M 0x0000003f +#define R88E_TXDW1_MACID_S 0 + +/* Tx dword 2. */ +#define R88E_TXDW2_AGGEN 0x00001000 +#define R88E_TXDW2_AGGBK 0x00010000 + +/* Tx dword 3. */ +#define R88E_TXDSEQ_HWSEQ_EN 0x8000 + +#endif /* R88E_TX_DESC_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h new file mode 100644 index 00000000..85b637cb --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTL8188EU_H +#define RTL8188EU_H + +#include + + +/* + * Function declarations. + */ +/* r88eu_init.c */ +void r88eu_power_off(struct rtwn_softc *); +void r88eu_init_intr(struct rtwn_softc *); +void r88eu_init_rx_agg(struct rtwn_softc *); +void r88eu_post_init(struct rtwn_softc *); + +/* r88eu_rx.c */ +int r88eu_classify_intr(struct rtwn_softc *, void *, int); + +#endif /* RTL8188EU_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c new file mode 100644 index 00000000..4d5452be --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c @@ -0,0 +1,218 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include + + +static struct rtwn_r88e_txpwr r88e_txpwr; + +void r88eu_attach(struct rtwn_usb_softc *); + +static void +r88e_postattach(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + struct ieee80211com *ic = &sc->sc_ic; + + rs->rs_scan_start = ic->ic_scan_start; + ic->ic_scan_start = r92c_scan_start; + rs->rs_scan_end = ic->ic_scan_end; + ic->ic_scan_end = r92c_scan_end; +} + +static void +r88eu_attach_private(struct rtwn_softc *sc) +{ + struct r92c_softc *rs; + + rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_txpwr = &r88e_txpwr; + rs->rs_txagc = &r88e_txagc; + + rs->rs_set_bw20 = r88e_set_bw20; + rs->rs_get_txpower = r88e_get_txpower; + rs->rs_set_gain = r88e_set_gain; + rs->rs_tx_enable_ampdu = r88e_tx_enable_ampdu; + rs->rs_tx_setup_hwseq = r88e_tx_setup_hwseq; + rs->rs_tx_setup_macid = r88e_tx_setup_macid; + rs->rs_set_name = rtwn_nop_softc; /* not used */ + + rs->rf_read_delay[0] = 10; + rs->rf_read_delay[1] = 100; + rs->rf_read_delay[2] = 10; + + sc->sc_priv = rs; +} + +static void +r88eu_adj_devcaps(struct rtwn_softc *sc) +{ + /* XXX TODO? */ +} + +void +r88eu_attach(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + /* USB part. */ + uc->uc_align_rx = r92cu_align_rx; + uc->tx_agg_desc_num = 6; + + /* Common part. */ + sc->sc_flags = RTWN_FLAG_EXT_HDR; + + sc->sc_set_chan = r92c_set_chan; + sc->sc_fill_tx_desc = r92c_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r92c_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r92c_fill_tx_desc_null; + sc->sc_dump_tx_desc = r92cu_dump_tx_desc; + sc->sc_tx_radiotap_flags = r92c_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r92c_rx_radiotap_flags; + sc->sc_get_rssi_cck = r88e_get_rssi_cck; + sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm; + sc->sc_classify_intr = r88eu_classify_intr; + sc->sc_handle_tx_report = r88e_ratectl_tx_complete; + sc->sc_handle_c2h_report = r88e_handle_c2h_report; + sc->sc_check_frame = rtwn_nop_int_softc_mbuf; + sc->sc_rf_read = r92c_rf_read; + sc->sc_rf_write = r88e_rf_write; + sc->sc_check_condition = r92c_check_condition; + sc->sc_efuse_postread = rtwn_nop_softc; + sc->sc_parse_rom = r88e_parse_rom; + sc->sc_set_led = r88e_set_led; + sc->sc_power_on = r88e_power_on; + sc->sc_power_off = r88eu_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r88e_fw_reset; + sc->sc_fw_download_enable = r88e_fw_download_enable; +#endif + sc->sc_set_page_size = r92c_set_page_size; + sc->sc_lc_calib = r92c_lc_calib; + sc->sc_iq_calib = r88e_iq_calib; /* XXX TODO */ + sc->sc_read_chipid_vendor = rtwn_nop_softc_uint32; + sc->sc_adj_devcaps = r88eu_adj_devcaps; + sc->sc_vap_preattach = rtwn_nop_softc_vap; + sc->sc_postattach = r88e_postattach; + sc->sc_detach_private = r92c_detach_private; + sc->sc_set_media_status = r88e_set_media_status; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_rsvd_page = r88e_set_rsvd_page; + sc->sc_set_pwrmode = r88e_set_pwrmode; + sc->sc_set_rssi = rtwn_nop_softc; /* XXX TODO? */ +#endif + sc->sc_beacon_init = r92c_beacon_init; + sc->sc_beacon_enable = r88e_beacon_enable; + sc->sc_beacon_set_rate = rtwn_nop_void_int; + sc->sc_beacon_select = rtwn_nop_softc_int; + sc->sc_temp_measure = r88e_temp_measure; + sc->sc_temp_read = r88e_temp_read; + sc->sc_init_tx_agg = r92cu_init_tx_agg; + sc->sc_init_rx_agg = r88eu_init_rx_agg; + sc->sc_init_ampdu = rtwn_nop_softc; + sc->sc_init_intr = r88eu_init_intr; + sc->sc_init_edca = r92c_init_edca; + sc->sc_init_bb = r88e_init_bb; + sc->sc_init_rf = r92c_init_rf; + sc->sc_init_antsel = rtwn_nop_softc; + sc->sc_post_init = r88eu_post_init; + sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc; + + sc->mac_prog = &rtl8188eu_mac[0]; + sc->mac_size = nitems(rtl8188eu_mac); + sc->bb_prog = &rtl8188eu_bb[0]; + sc->bb_size = nitems(rtl8188eu_bb); + sc->agc_prog = &rtl8188eu_agc[0]; + sc->agc_size = nitems(rtl8188eu_agc); + sc->rf_prog = &rtl8188eu_rf[0]; + + sc->name = "RTL8188EU"; + sc->fwname = "rtwn-rtl8188eufw"; + sc->fwsig = 0x88e; + + sc->page_count = R88E_TX_PAGE_COUNT; + sc->pktbuf_count = R88E_TXPKTBUF_COUNT; + + sc->ackto = 0x40; + sc->npubqpages = R88E_PUBQ_NPAGES; + sc->page_size = R92C_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r92cu_tx_desc); + sc->efuse_maxlen = R88E_EFUSE_MAX_LEN; + sc->efuse_maplen = R88E_EFUSE_MAP_LEN; + sc->rx_dma_size = R88E_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R88E_MACID_MAX + 1; + sc->cam_entry_limit = R92C_CAM_ENTRY_COUNT; + sc->fwsize_limit = R92C_MAX_FW_SIZE; + sc->temp_delta = R88E_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R92C_TDECTRL; + sc->rcr = 0; + + sc->ntxchains = 1; + sc->nrxchains = 1; + + r88eu_attach_private(sc); +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c new file mode 100644 index 00000000..3f9ae320 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c @@ -0,0 +1,226 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88eu_power_off(struct rtwn_softc *sc) +{ + uint8_t reg; + int error, ntries; + + /* Disable any kind of TX reports. */ + error = rtwn_setbits_1(sc, R88E_TX_RPT_CTRL, + R88E_TX_RPT1_ENA | R88E_TX_RPT2_ENA, 0); + if (error == ENXIO) /* hardware gone */ + return; + + /* Stop Rx. */ + rtwn_write_1(sc, R92C_CR, 0); + + /* Move card to Low Power State. */ + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + + for (ntries = 0; ntries < 10; ntries++) { + /* Should be zero if no packet is transmitting. */ + if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: failed to block Tx queues\n", + __func__); + return; + } + + /* CCK and OFDM are disabled, and clock are gated. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0); + + rtwn_delay(sc, 1); + + /* Reset MAC TRX */ + rtwn_write_1(sc, R92C_CR, + 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); + + /* check if removed later */ + rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1); + + /* Respond TxOK to scheduler */ + rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, 0x20); + + /* If firmware in ram code, do reset. */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY) + r88e_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); +#endif + + /* Reset MCU ready status. */ + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* Disable 32k. */ + rtwn_setbits_1(sc, R88E_32K_CTRL, 0x01, 0); + + /* Move card to Disabled state. */ + /* Turn off RF. */ + rtwn_write_1(sc, R92C_RF_CTRL, 0); + + /* LDO Sleep mode. */ + rtwn_setbits_1(sc, R92C_LPLDO_CTRL, 0, R92C_LPLDO_CTRL_SLEEP); + + /* Turn off MAC by HW state machine */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_APFM_OFF, 1); + + for (ntries = 0; ntries < 10; ntries++) { + /* Wait until it will be disabled. */ + if ((rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_OFF) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: could not turn off MAC\n", + __func__); + return; + } + + /* schmit trigger */ + rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0, 0x80); + + /* Enable WL suspend. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_PCIE, R92C_APS_FSMCO_AFSM_HSUS, 1); + + /* Enable bandgap mbias in suspend. */ + rtwn_write_1(sc, R92C_APS_FSMCO + 3, 0); + + /* Clear SIC_EN register. */ + rtwn_setbits_1(sc, R92C_GPIO_MUXCFG + 1, 0x10, 0); + + /* Set USB suspend enable local register */ + rtwn_setbits_1(sc, R92C_USB_SUSPEND, 0, 0x10); + + /* Reset MCU IO Wrapper. */ + reg = rtwn_read_1(sc, R92C_RSV_CTRL + 1); + rtwn_write_1(sc, R92C_RSV_CTRL + 1, reg & ~0x08); + rtwn_write_1(sc, R92C_RSV_CTRL + 1, reg | 0x08); + + /* marked as 'For Power Consumption' code. */ + rtwn_write_1(sc, R92C_GPIO_OUT, rtwn_read_1(sc, R92C_GPIO_IN)); + rtwn_write_1(sc, R92C_GPIO_IOSEL, 0xff); + + rtwn_write_1(sc, R92C_GPIO_IO_SEL, + rtwn_read_1(sc, R92C_GPIO_IO_SEL) << 4); + rtwn_setbits_1(sc, R92C_GPIO_MOD, 0, 0x0f); + + /* Set LNA, TRSW, EX_PA Pin to output mode. */ + rtwn_write_4(sc, R88E_BB_PAD_CTRL, 0x00080808); +} + +void +r88eu_init_intr(struct rtwn_softc *sc) +{ + /* TODO: adjust */ + 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); + rtwn_setbits_1(sc, R92C_USB_SPECIAL_OPTION, 0, + R92C_USB_SPECIAL_OPTION_INT_BULK_SEL); +} + +void +r88eu_init_rx_agg(struct rtwn_softc *sc) +{ + /* XXX merge? */ + rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0, + R92C_TRXDMA_CTRL_RXDMA_AGG_EN); + /* XXX dehardcode */ + rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48); + rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH + 1, 4); +} + +void +r88eu_post_init(struct rtwn_softc *sc) +{ + + /* Enable per-packet TX report. */ + rtwn_setbits_1(sc, R88E_TX_RPT_CTRL, 0, R88E_TX_RPT1_ENA); + + /* Disable Tx if MACID is not associated. */ + rtwn_write_4(sc, R88E_MACID_NO_LINK, 0xffffffff); + rtwn_write_4(sc, R88E_MACID_NO_LINK + 4, 0xffffffff); + r88e_macid_enable_link(sc, RTWN_MACID_BC, 1); + + /* Perform LO and IQ calibrations. */ + r88e_iq_calib(sc); + /* Perform LC calibration. */ + r92c_lc_calib(sc); + + rtwn_write_1(sc, R92C_USB_HRPWM, 0); + + if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { + /* No support (yet?) for f/w rate adaptation. */ + sc->sc_ratectl = RTWN_RATECTL_NET80211; + } else + sc->sc_ratectl = sc->sc_ratectl_sysctl; +} diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h new file mode 100644 index 00000000..fc61eaae --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88EU_REG_H +#define R88EU_REG_H + +#include +#include + +#endif /* R88EU_REG_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c new file mode 100644 index 00000000..3c2671c7 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c @@ -0,0 +1,76 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + + +int +r88eu_classify_intr(struct rtwn_softc *sc, void *buf, int len) +{ + struct r92c_rx_stat *stat = buf; + int report_sel = MS(le32toh(stat->rxdw3), R88E_RXDW3_RPT); + + switch (report_sel) { + case R88E_RXDW3_RPT_RX: + return (RTWN_RX_DATA); + case R88E_RXDW3_RPT_TX1: /* per-packet Tx report */ + case R88E_RXDW3_RPT_TX2: /* periodical Tx report */ + return (RTWN_RX_TX_REPORT); + case R88E_RXDW3_RPT_HIS: + return (RTWN_RX_OTHER); + default: /* shut up the compiler */ + return (RTWN_RX_DATA); + } +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h new file mode 100644 index 00000000..93379f8b --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce.h @@ -0,0 +1,74 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTL8192CE_H +#define RTL8192CE_H + +#include + + +/* + * Global definitions. + */ +#define R92CE_PUBQ_NPAGES 176 +#define R92CE_HPQ_NPAGES 41 +#define R92CE_LPQ_NPAGES 28 +#define R92CE_TX_PAGE_COUNT \ + (R92CE_PUBQ_NPAGES + R92CE_HPQ_NPAGES + R92CE_LPQ_NPAGES) + + +/* + * Function declarations. + */ +/* r92ce_calib.c */ +void r92ce_iq_calib(struct rtwn_softc *); + +/* r92ce_fw.c */ +#ifndef RTWN_WITHOUT_UCODE +void r92ce_fw_reset(struct rtwn_softc *, int); +#endif + +/* r92ce_init.c */ +void r92ce_init_intr(struct rtwn_softc *); +void r92ce_init_edca(struct rtwn_softc *); +void r92ce_init_bb(struct rtwn_softc *); +int r92ce_power_on(struct rtwn_softc *); +void r92ce_power_off(struct rtwn_softc *); +void r92ce_init_ampdu(struct rtwn_softc *); +void r92ce_post_init(struct rtwn_softc *); + +/* r92ce_led.c */ +void r92ce_set_led(struct rtwn_softc *, int, int); + +/* r92ce_rx.c */ +int r92ce_classify_intr(struct rtwn_softc *, void *, int); +void r92ce_enable_intr(struct rtwn_pci_softc *); +void r92ce_start_xfers(struct rtwn_softc *); + +/* r92ce_tx.c */ +void r92ce_setup_tx_desc(struct rtwn_pci_softc *, void *, uint32_t); +void r92ce_tx_postsetup(struct rtwn_pci_softc *, void *, + bus_dma_segment_t[]); +void r92ce_copy_tx_desc(void *, const void *); +void r92ce_dump_tx_desc(struct rtwn_softc *, const void *); + +#endif /* RTL8192CE_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c new file mode 100644 index 00000000..d53dbf98 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c @@ -0,0 +1,265 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + + +static struct rtwn_r92c_txpwr r92c_txpwr; + +void r92ce_attach(struct rtwn_pci_softc *); + +static void +r92ce_postattach(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + struct ieee80211com *ic = &sc->sc_ic; + + if (!(rs->chip & R92C_CHIP_92C) && + rs->board_type == R92C_BOARD_TYPE_HIGHPA) + rs->rs_txagc = &rtl8188ru_txagc[0]; + else + rs->rs_txagc = &rtl8192cu_txagc[0]; + + if ((rs->chip & (R92C_CHIP_UMC_A_CUT | R92C_CHIP_92C)) == + R92C_CHIP_UMC_A_CUT) + sc->fwname = "rtwn-rtl8192cfwE"; + else + sc->fwname = "rtwn-rtl8192cfwE_B"; + sc->fwsig = 0x88c; + + rs->rs_scan_start = ic->ic_scan_start; + ic->ic_scan_start = r92c_scan_start; + rs->rs_scan_end = ic->ic_scan_end; + ic->ic_scan_end = r92c_scan_end; +} + +static void +r92ce_set_name(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + if (rs->chip & R92C_CHIP_92C) + sc->name = "RTL8192CE"; + else + sc->name = "RTL8188CE"; +} + +static void +r92ce_attach_private(struct rtwn_softc *sc) +{ + struct r92c_softc *rs; + + rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_txpwr = &r92c_txpwr; + + rs->rs_set_bw20 = r92c_set_bw20; + rs->rs_get_txpower = r92c_get_txpower; + rs->rs_set_gain = r92c_set_gain; + rs->rs_tx_enable_ampdu = r92c_tx_enable_ampdu; + rs->rs_tx_setup_hwseq = r92c_tx_setup_hwseq; + rs->rs_tx_setup_macid = r92c_tx_setup_macid; + rs->rs_set_name = r92ce_set_name; + + /* XXX TODO: test with net80211 ratectl! */ +#ifndef RTWN_WITHOUT_UCODE + rs->rs_c2h_timeout = hz; + + callout_init_mtx(&rs->rs_c2h_report, &sc->sc_mtx, 0); +#endif + + rs->rf_read_delay[0] = 1000; + rs->rf_read_delay[1] = 1000; + rs->rf_read_delay[2] = 1000; + + sc->sc_priv = rs; +} + +static void +r92ce_adj_devcaps(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + /* + * XXX do NOT enable PMGT until RSVD_PAGE command + * will not be tested / fixed + HRPWM register must be set too. + */ + ic->ic_caps &= ~IEEE80211_C_PMGT; +} + +void +r92ce_attach(struct rtwn_pci_softc *pc) +{ + struct rtwn_softc *sc = &pc->pc_sc; + + /* PCIe part. */ + pc->pc_setup_tx_desc = r92ce_setup_tx_desc; + pc->pc_tx_postsetup = r92ce_tx_postsetup; + pc->pc_copy_tx_desc = r92ce_copy_tx_desc; + pc->pc_enable_intr = r92ce_enable_intr; + + pc->pc_qmap = 0xf771; + pc->tcr = + R92C_TCR_CFENDFORM | (1 << 12) | (1 << 13); + + /* Common part. */ + /* RTL8192C* cannot use pairwise keys from first 4 slots */ + sc->sc_flags = RTWN_FLAG_CAM_FIXED; + + sc->sc_start_xfers = r92ce_start_xfers; + sc->sc_set_chan = r92c_set_chan; + sc->sc_fill_tx_desc = r92c_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r92c_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r92c_fill_tx_desc_null; /* XXX recheck */ + sc->sc_dump_tx_desc = r92ce_dump_tx_desc; + sc->sc_tx_radiotap_flags = r92c_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r92c_rx_radiotap_flags; + sc->sc_get_rssi_cck = r92c_get_rssi_cck; + sc->sc_get_rssi_ofdm = r92c_get_rssi_ofdm; + sc->sc_classify_intr = r92ce_classify_intr; + sc->sc_handle_tx_report = rtwn_nop_softc_uint8_int; + sc->sc_handle_c2h_report = rtwn_nop_softc_uint8_int; + sc->sc_check_frame = rtwn_nop_int_softc_mbuf; + sc->sc_rf_read = r92c_rf_read; + sc->sc_rf_write = r92c_rf_write; + sc->sc_check_condition = r92c_check_condition; + sc->sc_efuse_postread = r92c_efuse_postread; + sc->sc_parse_rom = r92c_parse_rom; + sc->sc_set_led = r92ce_set_led; + sc->sc_power_on = r92ce_power_on; + sc->sc_power_off = r92ce_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r92ce_fw_reset; + sc->sc_fw_download_enable = r92c_fw_download_enable; +#endif + sc->sc_set_page_size = r92c_set_page_size; + sc->sc_lc_calib = r92c_lc_calib; + sc->sc_iq_calib = r92ce_iq_calib; + sc->sc_read_chipid_vendor = r92c_read_chipid_vendor; + sc->sc_adj_devcaps = r92ce_adj_devcaps; + sc->sc_vap_preattach = rtwn_nop_softc_vap; + sc->sc_postattach = r92ce_postattach; + sc->sc_detach_private = r92c_detach_private; + sc->sc_set_media_status = r92c_joinbss_rpt; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_rsvd_page = r92c_set_rsvd_page; + sc->sc_set_pwrmode = r92c_set_pwrmode; + sc->sc_set_rssi = r92c_set_rssi; +#endif + sc->sc_beacon_init = r92c_beacon_init; + sc->sc_beacon_enable = r92c_beacon_enable; + sc->sc_beacon_set_rate = rtwn_nop_void_int; + sc->sc_beacon_select = rtwn_nop_softc_int; + sc->sc_temp_measure = r92c_temp_measure; + sc->sc_temp_read = r92c_temp_read; + sc->sc_init_tx_agg = rtwn_nop_softc; + sc->sc_init_rx_agg = rtwn_nop_softc; + sc->sc_init_ampdu = r92ce_init_ampdu; + sc->sc_init_intr = r92ce_init_intr; + sc->sc_init_edca = r92ce_init_edca; + sc->sc_init_bb = r92ce_init_bb; + sc->sc_init_rf = r92c_init_rf; + sc->sc_init_antsel = rtwn_nop_softc; + sc->sc_post_init = r92ce_post_init; + sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc; + + sc->mac_prog = &rtl8192ce_mac[0]; + sc->mac_size = nitems(rtl8192ce_mac); + sc->bb_prog = &rtl8192ce_bb[0]; + sc->bb_size = nitems(rtl8192ce_bb); + sc->agc_prog = &rtl8192ce_agc[0]; + sc->agc_size = nitems(rtl8192ce_agc); + sc->rf_prog = &rtl8192c_rf[0]; + + sc->page_count = R92CE_TX_PAGE_COUNT; + sc->pktbuf_count = R92C_TXPKTBUF_COUNT; + + sc->ackto = 0x40; + sc->npubqpages = R92CE_PUBQ_NPAGES; + sc->nhqpages = R92CE_HPQ_NPAGES; + sc->nnqpages = 0; + sc->nlqpages = R92CE_LPQ_NPAGES; + sc->page_size = R92C_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r92ce_tx_desc); + sc->efuse_maxlen = R92C_EFUSE_MAX_LEN; + sc->efuse_maplen = R92C_EFUSE_MAP_LEN; + sc->rx_dma_size = R92C_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R92C_MACID_MAX + 1; + sc->cam_entry_limit = R92C_CAM_ENTRY_COUNT; + sc->fwsize_limit = R92C_MAX_FW_SIZE; + sc->temp_delta = R92C_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + /* + * TODO: some additional setup is required + * to maintain few beacons at the same time. + * + * XXX BCNQ1 mechanism is not needed here; move it to the USB module. + */ + sc->bcn_status_reg[1] = R92C_TDECTRL; + sc->rcr = 0; + + r92ce_attach_private(sc); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c new file mode 100644 index 00000000..e1b4f507 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c @@ -0,0 +1,388 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + + +/* Registers to save and restore during IQ calibration. */ +struct r92ce_iq_cal_reg_vals { + uint32_t adda[16]; + uint8_t txpause; + uint8_t bcn_ctrl[2]; + uint32_t gpio_muxcfg; + uint32_t ofdm0_trxpathena; + uint32_t ofdm0_trmuxpar; + uint32_t fpga0_rfifacesw1; +}; + +/* XXX 92CU? */ +static int +r92ce_iq_calib_chain(struct rtwn_softc *sc, int chain, uint16_t tx[2], + uint16_t rx[2]) +{ + uint32_t status; + int offset = chain * 0x20; + + if (chain == 0) { /* IQ calibration for chain 0. */ + /* IQ calibration settings for chain 0. */ + rtwn_bb_write(sc, 0xe30, 0x10008c1f); + rtwn_bb_write(sc, 0xe34, 0x10008c1f); + rtwn_bb_write(sc, 0xe38, 0x82140102); + + if (sc->ntxchains > 1) { + rtwn_bb_write(sc, 0xe3c, 0x28160202); /* 2T */ + /* IQ calibration settings for chain 1. */ + rtwn_bb_write(sc, 0xe50, 0x10008c22); + rtwn_bb_write(sc, 0xe54, 0x10008c22); + rtwn_bb_write(sc, 0xe58, 0x82140102); + rtwn_bb_write(sc, 0xe5c, 0x28160202); + } else + rtwn_bb_write(sc, 0xe3c, 0x28160502); /* 1T */ + + /* LO calibration settings. */ + rtwn_bb_write(sc, 0xe4c, 0x001028d1); + /* We're doing LO and IQ calibration in one shot. */ + rtwn_bb_write(sc, 0xe48, 0xf9000000); + rtwn_bb_write(sc, 0xe48, 0xf8000000); + + } else { /* IQ calibration for chain 1. */ + /* We're doing LO and IQ calibration in one shot. */ + rtwn_bb_write(sc, 0xe60, 0x00000002); + rtwn_bb_write(sc, 0xe60, 0x00000000); + } + + /* Give LO and IQ calibrations the time to complete. */ + rtwn_delay(sc, 1000); + + /* Read IQ calibration status. */ + status = rtwn_bb_read(sc, 0xeac); + + if (status & (1 << (28 + chain * 3))) + return (0); /* Tx failed. */ + /* Read Tx IQ calibration results. */ + tx[0] = (rtwn_bb_read(sc, 0xe94 + offset) >> 16) & 0x3ff; + tx[1] = (rtwn_bb_read(sc, 0xe9c + offset) >> 16) & 0x3ff; + if (tx[0] == 0x142 || tx[1] == 0x042) + return (0); /* Tx failed. */ + + if (status & (1 << (27 + chain * 3))) + return (1); /* Rx failed. */ + /* Read Rx IQ calibration results. */ + rx[0] = (rtwn_bb_read(sc, 0xea4 + offset) >> 16) & 0x3ff; + rx[1] = (rtwn_bb_read(sc, 0xeac + offset) >> 16) & 0x3ff; + if (rx[0] == 0x132 || rx[1] == 0x036) + return (1); /* Rx failed. */ + + return (3); /* Both Tx and Rx succeeded. */ +} + +static void +r92ce_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2][2], + uint16_t rx[2][2], struct r92ce_iq_cal_reg_vals *vals) +{ + /* Registers to save and restore during IQ calibration. */ + static const uint16_t reg_adda[16] = { + 0x85c, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec + }; + int i, chain; + uint32_t hssi_param1; + + if (n == 0) { + for (i = 0; i < nitems(reg_adda); i++) + vals->adda[i] = rtwn_bb_read(sc, reg_adda[i]); + + vals->txpause = rtwn_read_1(sc, R92C_TXPAUSE); + vals->bcn_ctrl[0] = rtwn_read_1(sc, R92C_BCN_CTRL(0)); + vals->bcn_ctrl[1] = rtwn_read_1(sc, R92C_BCN_CTRL(1)); + vals->gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG); + } + + if (sc->ntxchains == 1) { + rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0); + for (i = 1; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0); + } else { + for (i = 0; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], 0x04db25a4); + } + + hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0)); + if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) { + rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), + hssi_param1 | R92C_HSSI_PARAM1_PI); + rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), + hssi_param1 | R92C_HSSI_PARAM1_PI); + } + + if (n == 0) { + vals->ofdm0_trxpathena = + rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA); + vals->ofdm0_trmuxpar = rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR); + vals->fpga0_rfifacesw1 = + rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1)); + } + + rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600); + rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4); + rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000); + if (sc->ntxchains > 1) { + rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000); + rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00010000); + } + + rtwn_write_1(sc, R92C_TXPAUSE, + R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH); + rtwn_write_1(sc, R92C_BCN_CTRL(0), + vals->bcn_ctrl[0] & ~R92C_BCN_CTRL_EN_BCN); + rtwn_write_1(sc, R92C_BCN_CTRL(1), + vals->bcn_ctrl[1] & ~R92C_BCN_CTRL_EN_BCN); + rtwn_write_1(sc, R92C_GPIO_MUXCFG, + vals->gpio_muxcfg & ~R92C_GPIO_MUXCFG_ENBT); + + rtwn_bb_write(sc, 0x0b68, 0x00080000); + if (sc->ntxchains > 1) + rtwn_bb_write(sc, 0x0b6c, 0x00080000); + + rtwn_bb_write(sc, 0x0e28, 0x80800000); + rtwn_bb_write(sc, 0x0e40, 0x01007c00); + rtwn_bb_write(sc, 0x0e44, 0x01004800); + + rtwn_bb_write(sc, 0x0b68, 0x00080000); + + for (chain = 0; chain < sc->ntxchains; chain++) { + if (chain > 0) { + /* Put chain 0 on standby. */ + rtwn_bb_write(sc, 0x0e28, 0x00); + rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000); + rtwn_bb_write(sc, 0x0e28, 0x80800000); + + /* Enable chain 1. */ + for (i = 0; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], 0x0b1b25a4); + } + + /* Run IQ calibration twice. */ + for (i = 0; i < 2; i++) { + int ret; + + ret = r92ce_iq_calib_chain(sc, chain, + tx[chain], rx[chain]); + if (ret == 0) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: chain %d: Tx failed.\n", + __func__, chain); + tx[chain][0] = 0xff; + tx[chain][1] = 0xff; + rx[chain][0] = 0xff; + rx[chain][1] = 0xff; + } else if (ret == 1) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: chain %d: Rx failed.\n", + __func__, chain); + rx[chain][0] = 0xff; + rx[chain][1] = 0xff; + } else if (ret == 3) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: chain %d: Both Tx and Rx " + "succeeded.\n", __func__, chain); + } + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: results for run %d chain %d: tx[0] 0x%x, " + "tx[1] 0x%x, rx[0] 0x%x, rx[1] 0x%x\n", __func__, n, chain, + tx[chain][0], tx[chain][1], rx[chain][0], rx[chain][1]); + } + + rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, + vals->ofdm0_trxpathena); + rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), + vals->fpga0_rfifacesw1); + rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, vals->ofdm0_trmuxpar); + + rtwn_bb_write(sc, 0x0e28, 0x00); + rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3); + if (sc->ntxchains > 1) + rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00032ed3); + + if (n != 0) { + if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) { + rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1); + rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1); + } + + for (i = 0; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], vals->adda[i]); + + rtwn_write_1(sc, R92C_TXPAUSE, vals->txpause); + rtwn_write_1(sc, R92C_BCN_CTRL(0), vals->bcn_ctrl[0]); + rtwn_write_1(sc, R92C_BCN_CTRL(1), vals->bcn_ctrl[1]); + rtwn_write_4(sc, R92C_GPIO_MUXCFG, vals->gpio_muxcfg); + } +} + +#define RTWN_IQ_CAL_MAX_TOLERANCE 5 +static int +r92ce_iq_calib_compare_results(struct rtwn_softc *sc, uint16_t tx1[2][2], + uint16_t rx1[2][2], uint16_t tx2[2][2], uint16_t rx2[2][2]) +{ + int chain, i, tx_ok[2], rx_ok[2]; + + tx_ok[0] = tx_ok[1] = rx_ok[0] = rx_ok[1] = 0; + for (chain = 0; chain < sc->ntxchains; chain++) { + for (i = 0; i < 2; i++) { + if (tx1[chain][i] == 0xff || tx2[chain][i] == 0xff || + rx1[chain][i] == 0xff || rx2[chain][i] == 0xff) + continue; + + tx_ok[chain] = (abs(tx1[chain][i] - tx2[chain][i]) <= + RTWN_IQ_CAL_MAX_TOLERANCE); + + rx_ok[chain] = (abs(rx1[chain][i] - rx2[chain][i]) <= + RTWN_IQ_CAL_MAX_TOLERANCE); + } + } + + if (sc->ntxchains > 1) + return (tx_ok[0] && tx_ok[1] && rx_ok[0] && rx_ok[1]); + else + return (tx_ok[0] && rx_ok[0]); +} +#undef RTWN_IQ_CAL_MAX_TOLERANCE + +static void +r92ce_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2], + uint16_t rx[2], int chain) +{ + uint32_t reg, val, x; + long y, tx_c; + + if (tx[0] == 0xff || tx[1] == 0xff) + return; + + reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain)); + val = ((reg >> 22) & 0x3ff); + x = tx[0]; + if (x & 0x00000200) + x |= 0xfffffc00; + reg = (((x * val) >> 8) & 0x3ff); + rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(chain), 0x3ff, reg); + rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x80000000, + ((x * val) & 0x80) << 24); + + y = tx[1]; + if (y & 0x00000200) + y |= 0xfffffc00; + tx_c = (y * val) >> 8; + rtwn_bb_setbits(sc, R92C_OFDM0_TXAFE(chain), 0xf0000000, + (tx_c & 0x3c0) << 22); + rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(chain), 0x003f0000, + (tx_c & 0x3f) << 16); + rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x20000000, + ((y * val) & 0x80) << 22); + + if (rx[0] == 0xff || rx[1] == 0xff) + return; + + rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(chain), 0x3ff, + rx[0] & 0x3ff); + rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(chain), 0xfc00, + (rx[1] & 0x3f) << 10); + + if (chain == 0) { + rtwn_bb_setbits(sc, R92C_OFDM0_RXIQEXTANTA, 0xf0000000, + (rx[1] & 0x3c0) << 22); + } else { + rtwn_bb_setbits(sc, R92C_OFDM0_AGCRSSITABLE, 0xf000, + (rx[1] & 0x3c0) << 6); + } +} + +#define RTWN_IQ_CAL_NRUN 3 +void +r92ce_iq_calib(struct rtwn_softc *sc) +{ + struct r92ce_iq_cal_reg_vals vals; + uint16_t tx[RTWN_IQ_CAL_NRUN][2][2], rx[RTWN_IQ_CAL_NRUN][2][2]; + int n, valid; + + valid = 0; + for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) { + r92ce_iq_calib_run(sc, n, tx[n], rx[n], &vals); + + if (n == 0) + continue; + + /* Valid results remain stable after consecutive runs. */ + valid = r92ce_iq_calib_compare_results(sc, tx[n - 1], + rx[n - 1], tx[n], rx[n]); + if (valid) + break; + } + + if (valid) { + r92ce_iq_calib_write_results(sc, tx[n][0], rx[n][0], 0); + if (sc->ntxchains > 1) + r92ce_iq_calib_write_results(sc, tx[n][1], rx[n][1], 1); + } +} +#undef RTWN_IQ_CAL_NRUN diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c new file mode 100644 index 00000000..c4905429 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c @@ -0,0 +1,77 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + + +#ifndef RTWN_WITHOUT_UCODE +void +r92ce_fw_reset(struct rtwn_softc *sc, int reason) +{ + + if (reason == RTWN_FW_RESET_CHECKSUM) + return; + + r92c_fw_reset(sc, reason); + + /* + * We must sleep for one second to let the firmware settle. + * Accessing registers too early will hang the whole system. + */ + if (reason == RTWN_FW_RESET_DOWNLOAD) + rtwn_delay(sc, 1000 * 1000); +} +#endif diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c new file mode 100644 index 00000000..e7ec8bfd --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c @@ -0,0 +1,325 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include +#include + + +void +r92ce_init_intr(struct rtwn_softc *sc) +{ + /* Disable interrupts. */ + rtwn_write_4(sc, R92C_HISR, 0x00000000); + rtwn_write_4(sc, R92C_HIMR, 0x00000000); +} + +void +r92ce_init_edca(struct rtwn_softc *sc) +{ + /* SIFS */ + rtwn_write_2(sc, R92C_SPEC_SIFS, 0x1010); + rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x1010); + rtwn_write_2(sc, R92C_SIFS_CCK, 0x1010); + rtwn_write_2(sc, R92C_SIFS_OFDM, 0x0e0e); + /* TXOP */ + rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b); + rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f); + rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4322); + rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3222); +} + +void +r92ce_init_bb(struct rtwn_softc *sc) +{ + + /* Enable BB and RF. */ + rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0, + 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_setbits_4(sc, R92C_LEDCFG0, 0, 0x00800000); + + r92c_init_bb_common(sc); +} + +int +r92ce_power_on(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + 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) { + device_printf(sc->sc_dev, + "timeout waiting for chip autoload\n"); + return (ETIMEDOUT); + } + + /* Unlock ISO/CLK/Power control register. */ + rtwn_write_1(sc, R92C_RSV_CTRL, 0); + + if (rs->board_type != R92C_BOARD_TYPE_DONGLE) { + /* bt coex */ + rtwn_setbits_4(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_SOP_ABG | + R92C_APS_FSMCO_SOP_AMB | + R92C_APS_FSMCO_XOP_BTCK); + } + + /* Move SPS into PWM mode. */ + rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b); + + /* Set low byte to 0x0f, leave others unchanged. */ + rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0f); + + /* TODO: check if we need this for 8188CE */ + if (rs->board_type != R92C_BOARD_TYPE_DONGLE) { + /* bt coex */ + /* XXX magic from linux */ + rtwn_setbits_4(sc, R92C_AFE_XTAL_CTRL, 0x024800, 0); + } + + rtwn_setbits_2(sc, R92C_SYS_ISO_CTRL, 0xff00, + R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR); + + DELAY(200); + + /* TODO: linux does additional btcoex stuff here */ + + /* Auto enable WLAN. */ + rtwn_setbits_2(sc, R92C_APS_FSMCO, 0, 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) { + device_printf(sc->sc_dev, "timeout waiting for MAC auto ON\n"); + 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_setbits_2(sc, R92C_SYS_ISO_CTRL, R92C_SYS_ISO_CTRL_DIOR, 0); + + if (rs->chip & R92C_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 (rs->board_type != R92C_BOARD_TYPE_DONGLE) { + /* bt coex */ + /* XXX magic from linux */ + rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0x02, 0); + } + + rtwn_setbits_1(sc, R92C_GPIO_MUXCFG, R92C_GPIO_MUXCFG_RFKILL, 0); + + reg = rtwn_read_1(sc, R92C_GPIO_IO_SEL); + if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) { + device_printf(sc->sc_dev, + "radio is disabled by hardware switch\n"); + /* XXX how driver will know when radio will be enabled? */ + return (EPERM); + } + + /* Initialize MAC. */ + rtwn_setbits_1(sc, R92C_APSD_CTRL, R92C_APSD_CTRL_OFF, 0); + 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) { + device_printf(sc->sc_dev, + "timeout waiting for MAC initialization\n"); + return (ETIMEDOUT); + } + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + rtwn_setbits_2(sc, R92C_CR, 0, + 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 | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0)); + + rtwn_write_4(sc, R92C_MCUTST_1, 0x0); + + return (0); +} + +void +r92ce_power_off(struct rtwn_softc *sc) +{ +#ifndef RTWN_WITHOUT_UCODE + struct r92c_softc *rs = sc->sc_priv; + + /* Deinit C2H event handler. */ + callout_stop(&rs->rs_c2h_report); + rs->rs_c2h_paused = 0; + rs->rs_c2h_pending = 0; + rs->rs_c2h_timeout = hz; +#endif + + /* Stop hardware. */ + /* Disable interrupts. */ + rtwn_write_4(sc, R92C_HISR, 0); + rtwn_write_4(sc, R92C_HIMR, 0); + + /* Stop hardware. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + + /* Turn off RF. */ + rtwn_write_1(sc, R92C_RF_CTRL, 0); + + /* Reset BB state machine */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, 0, R92C_SYS_FUNC_EN_BB_GLB_RST); + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0); + + /* Disable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + rtwn_setbits_2(sc, R92C_CR, + 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, + 0); + + /* If firmware in ram code, do reset. */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) + r92ce_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); +#endif + + /* TODO: linux does additional btcoex stuff here */ + rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0x80); /* linux magic number */ + rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); /* ditto */ + rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0e); /* different with btcoex */ + rtwn_write_1(sc, R92C_RSV_CTRL, 0x0e); + rtwn_write_1(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_PDN_EN); +} + +void +r92ce_init_ampdu(struct rtwn_softc *sc) +{ + + /* Setup AMPDU aggregation. */ + rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */ + rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16); +} + +void +r92ce_post_init(struct rtwn_softc *sc) +{ + rtwn_write_2(sc, R92C_FWHW_TXQ_CTRL, + 0x1f00 | R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW); + + rtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff); + + /* Perform LO and IQ calibrations. */ + r92ce_iq_calib(sc); + /* Perform LC calibration. */ + r92c_lc_calib(sc); + + r92c_pa_bias_init(sc); + + /* Fix for lower temperature. */ + rtwn_write_1(sc, 0x15, 0xe9); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_flags & RTWN_FW_LOADED) { + struct r92c_softc *rs = sc->sc_priv; + + if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { + /* XXX TODO: fix (see comment in r92cu_init.c) */ + sc->sc_ratectl = RTWN_RATECTL_NET80211; + } else + sc->sc_ratectl = sc->sc_ratectl_sysctl; + + /* Start C2H event handling. */ + callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout, + r92c_handle_c2h_report, sc); + } else +#endif + sc->sc_ratectl = RTWN_RATECTL_NONE; +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c new file mode 100644 index 00000000..28273a38 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c @@ -0,0 +1,69 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include + +void +r92ce_set_led(struct rtwn_softc *sc, int led, int on) +{ + + if (led == RTWN_LED_LINK) { + rtwn_setbits_1(sc, R92C_LEDCFG2, 0x0f, + on ? R92C_LEDCFG2_EN : R92C_LEDCFG2_DIS); + sc->ledlink = on; /* Save LED state. */ + } +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h new file mode 100644 index 00000000..7416516c --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h @@ -0,0 +1,182 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R92CE_PRIV_H +#define R92CE_PRIV_H + +#include + + +/* + * MAC initialization values. + */ +static const struct rtwn_mac_prog rtl8192ce_mac[] = { + { 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 }, + { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, + { 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 }, + { 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, + { 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, + { 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, + { 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, + { 0x45b, 0xb9 }, { 0x460, 0x88 }, { 0x461, 0x88 }, { 0x462, 0x06 }, + { 0x463, 0x03 }, { 0x4c8, 0x04 }, { 0x4c9, 0x08 }, { 0x4cc, 0x02 }, + { 0x4cd, 0x28 }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, + { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, + { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, + { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, + { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, + { 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 }, + { 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x20 }, { 0x547, 0x00 }, + { 0x559, 0x02 }, { 0x55a, 0x02 }, { 0x55d, 0xff }, { 0x605, 0x30 }, + { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x652, 0x20 }, { 0x63c, 0x0a }, + { 0x63d, 0x0e }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, + { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, + { 0x70b, 0x87 } +}; + + +/* + * Baseband initialization values. + */ +static const uint16_t rtl8192ce_bb_regs0[] = { + 0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, + 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, + 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, + 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884, + 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908, + 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, + 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04 +}, rtl8192ce_bb_regs1[] = { + 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, + 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, + 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, + 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, + 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, + 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, + 0xce0, 0xce4, 0xce8, 0xcec, 0xd00 +}; + +static const uint32_t rtl8192ce_bb_vals0_2t[] = { + 0x0011800f, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, + 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, + 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, + 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, + 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05633 +}, rtl8192ce_bb_vals0_1t[] = { + 0x0011800f, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, + 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, + 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05611 +}, rtl8192ce_bb_vals1[] = { + 0x000000e4, 0x6c6c6c6c, 0x08800000, 0x40000100, 0x08800000, + 0x40000100, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x69e9ac44, 0x469652cf, 0x49795994, 0x0a97971c, 0x1f7c403f, + 0x000100b7, 0xec020107, 0x007f037f, 0x69543420, 0x43bc0094, + 0x69543420, 0x433c0094, 0x00000000, 0x5116848b, 0x47c00bff, + 0x00000036, 0x2c7f000d, 0x018610db, 0x0000001f, 0x00b91612, + 0x40000100, 0x20f60000, 0x40000100, 0x20200000, 0x00121820, + 0x00000000, 0x00121820, 0x00007f7f, 0x00000000, 0x00000080, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x28000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x64b22427, 0x00766932, 0x00222222, + 0x00000000, 0x37644302, 0x2f97d40c, 0x00080740 +}, rtl8192ce_bb_vals4_1t[] = { + 0x00000010, 0x001b25a4, 0x631b25a0, 0x631b25a0, 0x081b25a0, + 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x631b25a0, 0x081b25a0, + 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x001b25a0, + 0x001b25a0, 0x6b1b25a0, 0x00000003, 0x00000000, 0x00000300 +}; + +static const struct rtwn_bb_prog rtl8192ce_bb[] = { + { + nitems(rtl8192ce_bb_regs0), + rtl8192ce_bb_regs0, + rtl8192ce_bb_vals0_2t, + { R92C_COND_RTL8192C }, + &(const struct rtwn_bb_prog){ + nitems(rtl8192ce_bb_regs0), + rtl8192ce_bb_regs0, + rtl8192ce_bb_vals0_1t, + { 0 }, + NULL + } + }, + { + nitems(rtl8192ce_bb_regs1), + rtl8192ce_bb_regs1, + rtl8192ce_bb_vals1, + { 0 }, + NULL + }, + { + nitems(rtl8192c_bb_regs3), + rtl8192c_bb_regs3, + rtl8192c_bb_vals3_92ce_92cu, + { R92C_COND_RTL8192C }, + &(const struct rtwn_bb_prog){ + nitems(rtl8192c_bb_regs3), + rtl8192c_bb_regs3, + rtl8192c_bb_vals3_88cu_88ru, + { 0 }, + NULL + } + }, + { + nitems(rtl8192c_bb_regs4), + rtl8192c_bb_regs4, + rtl8192c_bb_vals4, + { 0 }, + NULL + }, + { + nitems(rtl8192c_bb_regs5), + rtl8192c_bb_regs5, + rtl8192c_bb_vals5_92ce_92cu, + { R92C_COND_RTL8192C }, + &(const struct rtwn_bb_prog){ + nitems(rtl8192c_bb_regs5), + rtl8192c_bb_regs5, + rtl8192ce_bb_vals4_1t, + { 0 }, + NULL + } + } +}; + +#endif /* R92CE_PRIV_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h new file mode 100644 index 00000000..355d8f46 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h @@ -0,0 +1,103 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R92CE_REG_H +#define R92CE_REG_H + +#include + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R92C_PCIE_MIO_INTF 0x0e4 +#define R92C_PCIE_MIO_INTD 0x0e8 +/* PCIe Configuration. */ +#define R92C_PCIE_CTRL_REG 0x300 +#define R92C_INT_MIG 0x304 +#define R92C_BCNQ_DESA 0x308 +#define R92C_HQ_DESA 0x310 +#define R92C_MGQ_DESA 0x318 +#define R92C_VOQ_DESA 0x320 +#define R92C_VIQ_DESA 0x328 +#define R92C_BEQ_DESA 0x330 +#define R92C_BKQ_DESA 0x338 +#define R92C_RX_DESA 0x340 +#define R92C_DBI 0x348 +#define R92C_MDIO 0x354 +#define R92C_DBG_SEL 0x360 +#define R92C_PCIE_HRPWM 0x361 +#define R92C_PCIE_HCPWM 0x363 +#define R92C_UART_CTRL 0x364 +#define R92C_UART_TX_DES 0x370 +#define R92C_UART_RX_DES 0x378 + + +/* Bits for R92C_GPIO_MUXCFG. */ +#define R92C_GPIO_MUXCFG_RFKILL 0x0008 + +/* Bits for R92C_GPIO_IO_SEL. */ +#define R92C_GPIO_IO_SEL_RFKILL 0x0008 + +/* Bits for R92C_LEDCFG2. */ +#define R92C_LEDCFG2_EN 0x60 +#define R92C_LEDCFG2_DIS 0x68 + +/* Bits for R92C_HIMR. */ +#define R92C_IMR_ROK 0x00000001 /* receive DMA OK */ +#define R92C_IMR_VODOK 0x00000002 /* AC_VO DMA OK */ +#define R92C_IMR_VIDOK 0x00000004 /* AC_VI DMA OK */ +#define R92C_IMR_BEDOK 0x00000008 /* AC_BE DMA OK */ +#define R92C_IMR_BKDOK 0x00000010 /* AC_BK DMA OK */ +#define R92C_IMR_TXBDER 0x00000020 /* beacon transmit error */ +#define R92C_IMR_MGNTDOK 0x00000040 /* management queue DMA OK */ +#define R92C_IMR_TBDOK 0x00000080 /* beacon transmit OK */ +#define R92C_IMR_HIGHDOK 0x00000100 /* high queue DMA OK */ +#define R92C_IMR_BDOK 0x00000200 /* beacon queue DMA OK */ +#define R92C_IMR_ATIMEND 0x00000400 /* ATIM window end interrupt */ +#define R92C_IMR_RDU 0x00000800 /* Rx descriptor unavailable */ +#define R92C_IMR_RXFOVW 0x00001000 /* receive FIFO overflow */ +#define R92C_IMR_BCNINT 0x00002000 /* beacon DMA interrupt 0 */ +#define R92C_IMR_PSTIMEOUT 0x00004000 /* powersave timeout */ +#define R92C_IMR_TXFOVW 0x00008000 /* transmit FIFO overflow */ +#define R92C_IMR_TIMEOUT1 0x00010000 /* timeout interrupt 1 */ +#define R92C_IMR_TIMEOUT2 0x00020000 /* timeout interrupt 2 */ +#define R92C_IMR_BCNDOK1 0x00040000 /* beacon queue DMA OK (1) */ +#define R92C_IMR_BCNDOK2 0x00080000 /* beacon queue DMA OK (2) */ +#define R92C_IMR_BCNDOK3 0x00100000 /* beacon queue DMA OK (3) */ +#define R92C_IMR_BCNDOK4 0x00200000 /* beacon queue DMA OK (4) */ +#define R92C_IMR_BCNDOK5 0x00400000 /* beacon queue DMA OK (5) */ +#define R92C_IMR_BCNDOK6 0x00800000 /* beacon queue DMA OK (6) */ +#define R92C_IMR_BCNDOK7 0x01000000 /* beacon queue DMA OK (7) */ +#define R92C_IMR_BCNDOK8 0x02000000 /* beacon queue DMA OK (8) */ +#define R92C_IMR_BCNDMAINT1 0x04000000 /* beacon DMA interrupt 1 */ +#define R92C_IMR_BCNDMAINT2 0x08000000 /* beacon DMA interrupt 2 */ +#define R92C_IMR_BCNDMAINT3 0x10000000 /* beacon DMA interrupt 3 */ +#define R92C_IMR_BCNDMAINT4 0x20000000 /* beacon DMA interrupt 4 */ +#define R92C_IMR_BCNDMAINT5 0x40000000 /* beacon DMA interrupt 5 */ +#define R92C_IMR_BCNDMAINT6 0x80000000 /* beacon DMA interrupt 6 */ + +/* Shortcut. */ +#define R92C_IBSS_INT_MASK \ + (R92C_IMR_BCNINT | R92C_IMR_TBDOK | R92C_IMR_TBDER) + +#endif /* R92CE_REG_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c new file mode 100644 index 00000000..d496e7b8 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c @@ -0,0 +1,134 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + + +int +r92ce_classify_intr(struct rtwn_softc *sc, void *arg, int len __unused) +{ + uint32_t status; + int *rings = arg; + int ret; + + *rings = 0; + status = rtwn_read_4(sc, R92C_HISR); + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: HISR %08X, HISRE %04X\n", + __func__, status, rtwn_read_2(sc, R92C_HISRE)); + if (status == 0 || status == 0xffffffff) + return (0); + + /* Disable interrupts. */ + rtwn_write_4(sc, R92C_HIMR, 0); + + /* Ack interrupts. */ + rtwn_write_4(sc, R92C_HISR, status); + + if (status & R92C_IMR_BDOK) + *rings |= (1 << RTWN_PCI_BEACON_QUEUE); + if (status & R92C_IMR_HIGHDOK) + *rings |= (1 << RTWN_PCI_HIGH_QUEUE); + if (status & R92C_IMR_MGNTDOK) + *rings |= (1 << RTWN_PCI_MGNT_QUEUE); + if (status & R92C_IMR_BKDOK) + *rings |= (1 << RTWN_PCI_BK_QUEUE); + if (status & R92C_IMR_BEDOK) + *rings |= (1 << RTWN_PCI_BE_QUEUE); + if (status & R92C_IMR_VIDOK) + *rings |= (1 << RTWN_PCI_VI_QUEUE); + if (status & R92C_IMR_VODOK) + *rings |= (1 << RTWN_PCI_VO_QUEUE); + + ret = 0; + if (status & R92C_IMR_RXFOVW) + ret |= RTWN_PCI_INTR_RX_OVERFLOW; + if (status & R92C_IMR_RDU) + ret |= RTWN_PCI_INTR_RX_DESC_UNAVAIL; + if (status & R92C_IMR_ROK) + ret |= RTWN_PCI_INTR_RX_DONE; + if (status & R92C_IMR_TXFOVW) + ret |= RTWN_PCI_INTR_TX_OVERFLOW; + if (status & R92C_IMR_PSTIMEOUT) + ret |= RTWN_PCI_INTR_PS_TIMEOUT; + + return (ret); +} + +#define R92C_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) +void +r92ce_enable_intr(struct rtwn_pci_softc *pc) +{ + struct rtwn_softc *sc = &pc->pc_sc; + + /* Enable interrupts. */ + rtwn_write_4(sc, R92C_HIMR, R92C_INT_ENABLE); +} + +void +r92ce_start_xfers(struct rtwn_softc *sc) +{ + /* Clear pending interrupts. */ + rtwn_write_4(sc, R92C_HISR, 0xffffffff); + + /* Enable interrupts. */ + rtwn_write_4(sc, R92C_HIMR, R92C_INT_ENABLE); +} +#undef R92C_INT_ENABLE diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h new file mode 100644 index 00000000..476a9e88 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h @@ -0,0 +1,41 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R92CE_RX_DESC_H +#define R92CE_RX_DESC_H + +#include + +/* Rx MAC descriptor (PCIe). */ +struct r92ce_rx_stat { + uint32_t rxdw0; + uint32_t rxdw1; + uint32_t rxdw2; + uint32_t rxdw3; + uint32_t rxdw4; + uint32_t tsf_low; + + uint32_t rxbufaddr; + uint32_t rxbufaddr64; +} __packed __attribute__((aligned(4))); + +#endif /* R92CE_RX_DESC_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c new file mode 100644 index 00000000..31d621bd --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c @@ -0,0 +1,117 @@ +#include + +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r92ce_setup_tx_desc(struct rtwn_pci_softc *pc, void *desc, + uint32_t next_desc_addr) +{ + struct r92ce_tx_desc *txd = desc; + + /* setup tx desc */ + txd->nextdescaddr = htole32(next_desc_addr); +} + +void +r92ce_tx_postsetup(struct rtwn_pci_softc *pc, void *desc, + bus_dma_segment_t segs[]) +{ + struct r92ce_tx_desc *txd = desc; + + txd->txbufaddr = htole32(segs[0].ds_addr); + txd->txbufsize = txd->pktlen; + bus_space_barrier(pc->pc_st, pc->pc_sh, 0, pc->pc_mapsize, + BUS_SPACE_BARRIER_WRITE); +} + +void +r92ce_copy_tx_desc(void *dest, const void *src) +{ + struct r92ce_tx_desc *txd = dest; + size_t len = sizeof(struct r92c_tx_desc) + + sizeof(txd->txbufsize) + sizeof(txd->pad); + + if (src != NULL) + memcpy(dest, src, len); + else + memset(dest, 0, len); +} + +void +r92ce_dump_tx_desc(struct rtwn_softc *sc, const void *desc) +{ +#ifdef RTWN_DEBUG + const struct r92ce_tx_desc *txd = desc; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT_DESC, + "%s: len %d, off %d, flags0 %02X, dw: 1 %08X, 2 %08X, 3 %04X " + "(seq %04X), 4 %08X, 5 %08X, 6 %08X, size %04X, pad %04X, " + "addr: %08X (64: %08X), next: %08X (64: %08X), " + "rsvd: %08X %08X %08X %08X\n", + __func__, le16toh(txd->pktlen), txd->offset, txd->flags0, + le32toh(txd->txdw1), le32toh(txd->txdw2), le16toh(txd->txdw3), + le16toh(txd->txdseq), le32toh(txd->txdw4), le32toh(txd->txdw5), + le32toh(txd->txdw6), le16toh(txd->txbufsize), le16toh(txd->pad), + le32toh(txd->txbufaddr), le32toh(txd->txbufaddr64), + le32toh(txd->nextdescaddr), le32toh(txd->nextdescaddr64), + le32toh(txd->reserved[0]), le32toh(txd->reserved[1]), + le32toh(txd->reserved[2]), le32toh(txd->reserved[3])); +#endif +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h new file mode 100644 index 00000000..4153710a --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h @@ -0,0 +1,55 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R92CE_TX_DESC_H +#define R92CE_TX_DESC_H + +#include + +/* Tx MAC descriptor (PCIe). */ +struct r92ce_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; + + uint32_t txdw1; + uint32_t txdw2; + uint16_t txdw3; + uint16_t txdseq; + + uint32_t txdw4; + uint32_t txdw5; + uint32_t txdw6; + + uint16_t txbufsize; + uint16_t pad; + + uint32_t txbufaddr; + uint32_t txbufaddr64; + + uint32_t nextdescaddr; + uint32_t nextdescaddr64; + + uint32_t reserved[4]; +} __packed __attribute__((aligned(4))); + +#endif /* R92CE_TX_DESC_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c.h new file mode 100644 index 00000000..2b63179e --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c.h @@ -0,0 +1,114 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTL8192C_H +#define RTL8192C_H + +/* + * Global definitions. + */ +#define R92C_TXPKTBUF_COUNT 256 + +#define R92C_TX_PAGE_SIZE 128 +#define R92C_RX_DMA_BUFFER_SIZE 0x2800 + +#define R92C_MAX_FW_SIZE 0x4000 +#define R92C_MACID_MAX 31 +#define R92C_CAM_ENTRY_COUNT 32 + +#define R92C_CALIB_THRESHOLD 2 + + +/* + * Function declarations. + */ +/* r92c_attach.c */ +void r92c_detach_private(struct rtwn_softc *); +void r92c_read_chipid_vendor(struct rtwn_softc *, uint32_t); + +/* r92c_beacon.c */ +void r92c_beacon_init(struct rtwn_softc *, void *, int); +void r92c_beacon_enable(struct rtwn_softc *, int, int); + +/* r92c_calib.c */ +void r92c_iq_calib(struct rtwn_softc *); +void r92c_lc_calib(struct rtwn_softc *); +void r92c_temp_measure(struct rtwn_softc *); +uint8_t r92c_temp_read(struct rtwn_softc *); + +/* r92c_chan.c */ +void r92c_get_txpower(struct rtwn_softc *, int, + struct ieee80211_channel *, uint16_t[]); +void r92c_set_bw20(struct rtwn_softc *, uint8_t); +void r92c_set_chan(struct rtwn_softc *, struct ieee80211_channel *); +void r92c_set_gain(struct rtwn_softc *, uint8_t); +void r92c_scan_start(struct ieee80211com *); +void r92c_scan_end(struct ieee80211com *); + +/* r92c_fw.c */ +#ifndef RTWN_WITHOUT_UCODE +void r92c_fw_reset(struct rtwn_softc *, int); +void r92c_fw_download_enable(struct rtwn_softc *, int); +#endif +void r92c_joinbss_rpt(struct rtwn_softc *, int); +#ifndef RTWN_WITHOUT_UCODE +int r92c_set_rsvd_page(struct rtwn_softc *, int, int, int); +int r92c_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, int); +void r92c_set_rssi(struct rtwn_softc *); +void r92c_handle_c2h_report(void *); +#endif + +/* r92c_init.c */ +int r92c_check_condition(struct rtwn_softc *, const uint8_t[]); +int r92c_set_page_size(struct rtwn_softc *); +void r92c_init_bb_common(struct rtwn_softc *); +int r92c_init_rf_chain(struct rtwn_softc *, + const struct rtwn_rf_prog *, int); +void r92c_init_rf(struct rtwn_softc *); +void r92c_init_edca(struct rtwn_softc *); +void r92c_init_ampdu(struct rtwn_softc *); +void r92c_init_antsel(struct rtwn_softc *); +void r92c_pa_bias_init(struct rtwn_softc *); + +/* r92c_rf.c */ +uint32_t r92c_rf_read(struct rtwn_softc *, int, uint8_t); +void r92c_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); + +/* r92c_rom.c */ +void r92c_efuse_postread(struct rtwn_softc *); +void r92c_parse_rom(struct rtwn_softc *, uint8_t *); + +/* r92c_rx.c */ +int8_t r92c_get_rssi_cck(struct rtwn_softc *, void *); +int8_t r92c_get_rssi_ofdm(struct rtwn_softc *, void *); +uint8_t r92c_rx_radiotap_flags(const void *); + +/* r92c_tx.c */ +void r92c_tx_enable_ampdu(void *, int); +void r92c_tx_setup_hwseq(void *); +void r92c_tx_setup_macid(void *, int); +void r92c_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, void *, uint8_t, int); +void r92c_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, void *, const struct ieee80211_bpf_params *); +void r92c_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); +uint8_t r92c_tx_radiotap_flags(const void *); + +#endif /* RTL8192C_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c new file mode 100644 index 00000000..cfb76acc --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_attach.c @@ -0,0 +1,82 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + + +void +r92c_detach_private(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + free(rs, M_RTWN_PRIV); +} + +void +r92c_read_chipid_vendor(struct rtwn_softc *sc, uint32_t reg_sys_cfg) +{ + struct r92c_softc *rs = sc->sc_priv; + + if (reg_sys_cfg & R92C_SYS_CFG_TYPE_92C) { + rs->chip |= R92C_CHIP_92C; + /* Check if it is a castrated 8192C. */ + if (MS(rtwn_read_4(sc, R92C_HPON_FSM), + R92C_HPON_FSM_CHIP_BONDING_ID) == + R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R) + rs->chip |= R92C_CHIP_92C_1T2R; + } + if (reg_sys_cfg & R92C_SYS_CFG_VENDOR_UMC) { + if (MS(reg_sys_cfg, R92C_SYS_CFG_CHIP_VER_RTL) == 0) + rs->chip |= R92C_CHIP_UMC_A_CUT; + } +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c new file mode 100644 index 00000000..fc106a47 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_beacon.c @@ -0,0 +1,88 @@ +#include + +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + + +void +r92c_beacon_init(struct rtwn_softc *sc, void *buf, int id) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + /* + * NB: there is no need to setup HWSEQ_EN bit; + * QSEL_BEACON already implies it. + */ + txd->flags0 |= R92C_FLAGS0_BMCAST | R92C_FLAGS0_FSG | R92C_FLAGS0_LSG; + txd->txdw1 |= htole32( + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BEACON) | + SM(R92C_TXDW1_RAID, R92C_RAID_11B)); + + rtwn_r92c_tx_setup_macid(sc, buf, id); + txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); + txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id)); + txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id)); + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, RTWN_RIDX_CCK1)); +} + +void +r92c_beacon_enable(struct rtwn_softc *sc, int id, int enable) +{ + + if (enable) { + rtwn_setbits_1(sc, R92C_BCN_CTRL(id), + 0, R92C_BCN_CTRL_EN_BCN); + } else { + rtwn_setbits_1(sc, R92C_BCN_CTRL(id), + R92C_BCN_CTRL_EN_BCN, 0); + } +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c new file mode 100644 index 00000000..e7706b8d --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_calib.c @@ -0,0 +1,115 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r92c_iq_calib(struct rtwn_softc *sc) +{ + /* XXX TODO */ +} + +void +r92c_lc_calib(struct rtwn_softc *sc) +{ + uint32_t rf_ac[2]; + uint8_t txmode; + int i; + + txmode = rtwn_read_1(sc, R92C_OFDM1_LSTF + 3); + if ((txmode & 0x70) != 0) { + /* Disable all continuous Tx. */ + rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70); + + /* Set RF mode to standby mode. */ + for (i = 0; i < sc->nrxchains; i++) { + rf_ac[i] = rtwn_rf_read(sc, i, R92C_RF_AC); + rtwn_rf_write(sc, i, R92C_RF_AC, + RW(rf_ac[i], R92C_RF_AC_MODE, + R92C_RF_AC_MODE_STANDBY)); + } + } else { + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + } + /* Start calibration. */ + rtwn_rf_setbits(sc, 0, R92C_RF_CHNLBW, 0, R92C_RF_CHNLBW_LCSTART); + + /* Give calibration the time to complete. */ + rtwn_delay(sc, 100000); /* 100ms */ + + /* Restore configuration. */ + if ((txmode & 0x70) != 0) { + /* Restore Tx mode. */ + rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode); + /* Restore RF mode. */ + for (i = 0; i < sc->nrxchains; i++) + rtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]); + } else { + /* Unblock all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, 0x00); + } +} + +void +r92c_temp_measure(struct rtwn_softc *sc) +{ + rtwn_rf_write(sc, 0, R92C_RF_T_METER, R92C_RF_T_METER_START); +} + +uint8_t +r92c_temp_read(struct rtwn_softc *sc) +{ + return (MS(rtwn_rf_read(sc, 0, R92C_RF_T_METER), + R92C_RF_T_METER_VAL)); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c new file mode 100644 index 00000000..a4ba2766 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c @@ -0,0 +1,353 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +static int +r92c_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint8_t chan; + int group; + + chan = rtwn_chan2centieee(c); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + if (chan <= 3) group = 0; + else if (chan <= 9) group = 1; + else if (chan <= 14) group = 2; + else { + KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); + return (-1); + } + } else { + KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); + return (-1); + } + + return (group); +} + +/* XXX recheck */ +void +r92c_get_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT]) +{ + struct r92c_softc *rs = sc->sc_priv; + struct rtwn_r92c_txpwr *rt = rs->rs_txpwr; + const struct rtwn_r92c_txagc *base = rs->rs_txagc; + uint8_t ofdmpow, htpow, diff, max; + int max_mcs, ridx, group; + + /* Determine channel group. */ + group = r92c_get_power_group(sc, c); + if (group == -1) { /* shouldn't happen */ + device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); + return; + } + + /* XXX net80211 regulatory */ + + max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n")); + + memset(power, 0, max_mcs * sizeof(power[0])); + if (rs->regulatory == 0) { + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] = base[chain].pwr[0][ridx]; + } + for (ridx = RTWN_RIDX_OFDM6; ridx < RTWN_RIDX_COUNT; ridx++) { + if (rs->regulatory == 3) { + power[ridx] = base[chain].pwr[0][ridx]; + /* Apply vendor limits. */ + if (IEEE80211_IS_CHAN_HT40(c)) + max = rt->ht40_max_pwr[chain][group]; + else + max = rt->ht20_max_pwr[chain][group]; + if (power[ridx] > max) + power[ridx] = max; + } else if (rs->regulatory == 1) { + if (!IEEE80211_IS_CHAN_HT40(c)) + power[ridx] = base[chain].pwr[group][ridx]; + } else if (rs->regulatory != 2) + power[ridx] = base[chain].pwr[0][ridx]; + } + + /* Compute per-CCK rate Tx power. */ + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] += rt->cck_tx_pwr[chain][group]; + + htpow = rt->ht40_1s_tx_pwr[chain][group]; + if (sc->ntxchains > 1) { + /* Apply reduction for 2 spatial streams. */ + diff = rt->ht40_2s_tx_pwr_diff[chain][group]; + htpow = (htpow > diff) ? htpow - diff : 0; + } + + /* Compute per-OFDM rate Tx power. */ + diff = rt->ofdm_tx_pwr_diff[chain][group]; + ofdmpow = htpow + diff; /* HT->OFDM correction. */ + for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) + power[ridx] += ofdmpow; + + /* Compute per-MCS Tx power. */ + if (!IEEE80211_IS_CHAN_HT40(c)) { + diff = rt->ht20_tx_pwr_diff[chain][group]; + htpow += diff; /* HT40->HT20 correction. */ + } + for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++) + power[ridx] += htpow; + + /* Apply max limit. */ + for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } +} + +static void +r92c_write_txpower(struct rtwn_softc *sc, int chain, + uint16_t power[RTWN_RIDX_COUNT]) +{ + uint32_t reg; + + /* Write per-CCK rate Tx power. */ + if (chain == 0) { + reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32); + reg = RW(reg, R92C_TXAGC_A_CCK1, power[RTWN_RIDX_CCK1]); + rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); + reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); + reg = RW(reg, R92C_TXAGC_A_CCK2, power[RTWN_RIDX_CCK2]); + reg = RW(reg, R92C_TXAGC_A_CCK55, power[RTWN_RIDX_CCK55]); + reg = RW(reg, R92C_TXAGC_A_CCK11, power[RTWN_RIDX_CCK11]); + rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); + } else { + reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); + reg = RW(reg, R92C_TXAGC_B_CCK1, power[RTWN_RIDX_CCK1]); + reg = RW(reg, R92C_TXAGC_B_CCK2, power[RTWN_RIDX_CCK2]); + reg = RW(reg, R92C_TXAGC_B_CCK55, power[RTWN_RIDX_CCK55]); + rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); + reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); + reg = RW(reg, R92C_TXAGC_B_CCK11, power[RTWN_RIDX_CCK11]); + rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); + } + /* Write per-OFDM rate Tx power. */ + rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain), + SM(R92C_TXAGC_RATE06, power[RTWN_RIDX_OFDM6]) | + SM(R92C_TXAGC_RATE09, power[RTWN_RIDX_OFDM9]) | + SM(R92C_TXAGC_RATE12, power[RTWN_RIDX_OFDM12]) | + SM(R92C_TXAGC_RATE18, power[RTWN_RIDX_OFDM18])); + rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain), + SM(R92C_TXAGC_RATE24, power[RTWN_RIDX_OFDM24]) | + SM(R92C_TXAGC_RATE36, power[RTWN_RIDX_OFDM36]) | + SM(R92C_TXAGC_RATE48, power[RTWN_RIDX_OFDM48]) | + SM(R92C_TXAGC_RATE54, power[RTWN_RIDX_OFDM54])); + /* Write per-MCS Tx power. */ + rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), + SM(R92C_TXAGC_MCS00, power[RTWN_RIDX_MCS(0)]) | + SM(R92C_TXAGC_MCS01, power[RTWN_RIDX_MCS(1)]) | + SM(R92C_TXAGC_MCS02, power[RTWN_RIDX_MCS(2)]) | + SM(R92C_TXAGC_MCS03, power[RTWN_RIDX_MCS(3)])); + rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), + SM(R92C_TXAGC_MCS04, power[RTWN_RIDX_MCS(4)]) | + SM(R92C_TXAGC_MCS05, power[RTWN_RIDX_MCS(5)]) | + SM(R92C_TXAGC_MCS06, power[RTWN_RIDX_MCS(6)]) | + SM(R92C_TXAGC_MCS07, power[RTWN_RIDX_MCS(7)])); + if (sc->ntxchains >= 2) { + rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), + SM(R92C_TXAGC_MCS08, power[RTWN_RIDX_MCS(8)]) | + SM(R92C_TXAGC_MCS09, power[RTWN_RIDX_MCS(9)]) | + SM(R92C_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) | + SM(R92C_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)])); + rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), + SM(R92C_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) | + SM(R92C_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) | + SM(R92C_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) | + SM(R92C_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)])); + } +} + +static void +r92c_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint16_t power[RTWN_RIDX_COUNT]; + int i; + + for (i = 0; i < sc->ntxchains; i++) { + /* Compute per-rate Tx power values. */ + rtwn_r92c_get_txpower(sc, i, c, power); +#ifdef RTWN_DEBUG + if (sc->sc_debug & RTWN_DEBUG_TXPWR) { + int ridx; + + /* Dump per-rate Tx power values. */ + printf("Tx power for chain %d:\n", i); + for (ridx = RTWN_RIDX_CCK1; + ridx < RTWN_RIDX_COUNT; + ridx++) + printf("Rate %d = %u\n", ridx, power[ridx]); + } +#endif + /* Write per-rate Tx power values to hardware. */ + r92c_write_txpower(sc, i, power); + } +} + +static void +r92c_set_bw40(struct rtwn_softc *sc, uint8_t chan, int prichlo) +{ + struct r92c_softc *rs = sc->sc_priv; + + rtwn_setbits_1(sc, R92C_BWOPMODE, R92C_BWOPMODE_20MHZ, 0); + rtwn_setbits_1(sc, R92C_RRSR + 2, 0x6f, (prichlo ? 1 : 2) << 5); + + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_40MHZ); + rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, 0, R92C_RFMOD_40MHZ); + + /* Set CCK side band. */ + rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10, + (prichlo ? 0 : 1) << 4); + + rtwn_bb_setbits(sc, R92C_OFDM1_LSTF, 0x0c00, + (prichlo ? 1 : 2) << 10); + + rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2, + R92C_FPGA0_ANAPARAM2_CBW20, 0); + + rtwn_bb_setbits(sc, 0x818, 0x0c000000, (prichlo ? 2 : 1) << 26); + + /* Select 40MHz bandwidth. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + (rs->rf_chnlbw[0] & ~0xfff) | chan); +} + +void +r92c_set_bw20(struct rtwn_softc *sc, uint8_t chan) +{ + struct r92c_softc *rs = sc->sc_priv; + + rtwn_setbits_1(sc, R92C_BWOPMODE, 0, R92C_BWOPMODE_20MHZ); + + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0); + rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0); + + rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2, 0, + R92C_FPGA0_ANAPARAM2_CBW20); + + /* Select 20MHz bandwidth. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + (rs->rf_chnlbw[0] & ~0xfff) | chan | R92C_RF_CHNLBW_BW20); +} + +void +r92c_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + struct r92c_softc *rs = sc->sc_priv; + u_int chan; + int i; + + chan = rtwn_chan2centieee(c); + + /* Set Tx power for this new channel. */ + r92c_set_txpower(sc, c); + + for (i = 0; i < sc->nrxchains; i++) { + rtwn_rf_write(sc, i, R92C_RF_CHNLBW, + RW(rs->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan)); + } + if (IEEE80211_IS_CHAN_HT40(c)) + r92c_set_bw40(sc, chan, IEEE80211_IS_CHAN_HT40U(c)); + else + rtwn_r92c_set_bw20(sc, chan); +} + +void +r92c_set_gain(struct rtwn_softc *sc, uint8_t gain) +{ + + rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0), + R92C_OFDM0_AGCCORE1_GAIN_M, gain); + rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(1), + R92C_OFDM0_AGCCORE1_GAIN_M, gain); +} + +void +r92c_scan_start(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct r92c_softc *rs = sc->sc_priv; + + RTWN_LOCK(sc); + /* Set gain for scanning. */ + rtwn_r92c_set_gain(sc, 0x20); + RTWN_UNLOCK(sc); + + rs->rs_scan_start(ic); +} + +void +r92c_scan_end(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct r92c_softc *rs = sc->sc_priv; + + RTWN_LOCK(sc); + /* Set gain under link. */ + rtwn_r92c_set_gain(sc, 0x32); + RTWN_UNLOCK(sc); + + rs->rs_scan_end(ic); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c new file mode 100644 index 00000000..74c7d205 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c @@ -0,0 +1,522 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +static int +r92c_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len) +{ + struct r92c_fw_cmd cmd; + int ntries, error; + + KASSERT(len <= sizeof(cmd.msg), + ("%s: firmware command too long (%d > %zu)\n", + __func__, len, sizeof(cmd.msg))); + + if (!(sc->sc_flags & RTWN_FW_LOADED)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware " + "was not loaded; command (id %u) will be discarded\n", + __func__, id); + return (0); + } + + /* Wait for current FW box to be empty. */ + for (ntries = 0; ntries < 50; ntries++) { + if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) + break; + rtwn_delay(sc, 2000); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "could not send firmware command\n"); + return (ETIMEDOUT); + } + memset(&cmd, 0, sizeof(cmd)); + cmd.id = id; + if (len > 3) { + /* Ext command: [id : byte2 : byte3 : byte4 : byte0 : byte1] */ + cmd.id |= R92C_CMD_FLAG_EXT; + memcpy(cmd.msg, (const uint8_t *)buf + 2, len - 2); + memcpy(cmd.msg + 3, buf, 2); + } else + memcpy(cmd.msg, buf, len); + + /* Write the first word last since that will trigger the FW. */ + if (len > 3) { + error = rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur), + *(uint16_t *)((uint8_t *)&cmd + 4)); + if (error != 0) + return (error); + } + error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), + *(uint32_t *)&cmd); + if (error != 0) + return (error); + + sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; + + return (0); +} + +void +r92c_fw_reset(struct rtwn_softc *sc, int reason) +{ + int ntries; + + if (reason == RTWN_FW_RESET_CHECKSUM) + return; + + /* Tell 8051 to reset itself. */ + rtwn_write_1(sc, R92C_HMETFR + 3, 0x20); + + /* Wait until 8051 resets by itself. */ + for (ntries = 0; ntries < 100; ntries++) { + if ((rtwn_read_2(sc, R92C_SYS_FUNC_EN) & + R92C_SYS_FUNC_EN_CPUEN) == 0) + return; + rtwn_delay(sc, 50); + } + /* Force 8051 reset. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_CPUEN, 0, 1); +} + +void +r92c_fw_download_enable(struct rtwn_softc *sc, int enable) +{ + if (enable) { + /* 8051 enable. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, 0, + R92C_SYS_FUNC_EN_CPUEN, 1); + /* MCU firmware download enable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN); + /* 8051 reset. */ + rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN, + 0, 2); + } else { + /* MCU download disable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0); + /* Reserved for f/w extension. */ + rtwn_write_1(sc, R92C_MCUFWDL + 1, 0); + } +} +#endif + +/* + * Initialize firmware rate adaptation. + */ +#ifndef RTWN_WITHOUT_UCODE +static int +r92c_send_ra_cmd(struct rtwn_softc *sc, int macid, uint32_t rates, + int maxrate) +{ + struct r92c_fw_cmd_macid_cfg cmd; + uint8_t mode; + int error = 0; + + /* XXX should be called directly from iv_newstate() for MACID_BC */ + /* XXX joinbss, not send_ra_cmd() */ +#ifdef RTWN_TODO + /* NB: group addressed frames are done at 11bg rates for now */ + if (ic->ic_curmode == IEEE80211_MODE_11B) + mode = R92C_RAID_11B; + else + mode = R92C_RAID_11BG; + /* XXX misleading 'mode' value here for unicast frames */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RA, + "%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__, + mode, rates, basicrates); + + /* Set rates mask for group addressed frames. */ + cmd.macid = RTWN_MACID_BC | R92C_CMD_MACID_VALID; + cmd.mask = htole32(mode << 28 | basicrates); + error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); + if (error != 0) { + device_printf(sc->sc_dev, + "could not set RA mask for broadcast station\n"); + return (error); + } +#endif + + /* Set rates mask for unicast frames. */ + if (maxrate >= RTWN_RIDX_MCS(0)) + mode = R92C_RAID_11GN; + else if (maxrate >= RTWN_RIDX_OFDM6) + mode = R92C_RAID_11BG; + else + mode = R92C_RAID_11B; + cmd.macid = macid | R92C_CMD_MACID_VALID; + cmd.mask = htole32(mode << 28 | rates); + error = r92c_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not set RA mask for %d station\n", + __func__, macid); + return (error); + } + + return (0); +} +#endif + +static void +r92c_init_ra(struct rtwn_softc *sc, int macid) +{ + struct ieee80211_htrateset *rs_ht; + struct ieee80211_node *ni; + uint32_t rates; + int maxrate; + + RTWN_NT_LOCK(sc); + if (sc->node_list[macid] == NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: macid %d, ni is NULL\n", + __func__, macid); + RTWN_NT_UNLOCK(sc); + return; + } + + ni = ieee80211_ref_node(sc->node_list[macid]); + if (ni->ni_flags & IEEE80211_NODE_HT) + rs_ht = &ni->ni_htrates; + else + rs_ht = NULL; + /* XXX MACID_BC */ + rtwn_get_rates(sc, &ni->ni_rates, rs_ht, &rates, &maxrate, 0); + RTWN_NT_UNLOCK(sc); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_ratectl == RTWN_RATECTL_FW) { + r92c_send_ra_cmd(sc, macid, rates, maxrate); + } +#endif + + rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(macid), maxrate); + + ieee80211_free_node(ni); +} + +void +r92c_joinbss_rpt(struct rtwn_softc *sc, int macid) +{ +#ifndef RTWN_WITHOUT_UCODE + struct r92c_softc *rs = sc->sc_priv; + struct ieee80211vap *vap; + struct r92c_fw_cmd_joinbss_rpt cmd; + + if (sc->vaps[0] == NULL) /* XXX fix */ + goto end; + + vap = &sc->vaps[0]->vap; + if ((vap->iv_state == IEEE80211_S_RUN) ^ + !(rs->rs_flags & R92C_FLAG_ASSOCIATED)) + goto end; + + if (rs->rs_flags & R92C_FLAG_ASSOCIATED) { + cmd.mstatus = R92C_MSTATUS_DISASSOC; + rs->rs_flags &= ~R92C_FLAG_ASSOCIATED; + } else { + cmd.mstatus = R92C_MSTATUS_ASSOC; + rs->rs_flags |= R92C_FLAG_ASSOCIATED; + } + + if (r92c_fw_cmd(sc, R92C_CMD_JOINBSS_RPT, &cmd, sizeof(cmd)) != 0) { + device_printf(sc->sc_dev, "%s: cannot change media status!\n", + __func__); + } + +end: +#endif + + /* TODO: init rates for RTWN_MACID_BC. */ + if (macid & RTWN_MACID_VALID) + r92c_init_ra(sc, macid & ~RTWN_MACID_VALID); +} + +#ifndef RTWN_WITHOUT_UCODE +int +r92c_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null, + int qos_null) +{ + struct r92c_fw_cmd_rsvdpage rsvd; + + rsvd.probe_resp = probe_resp; + rsvd.ps_poll = 0; + rsvd.null_data = null; + + return (r92c_fw_cmd(sc, R92C_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd))); +} + +int +r92c_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap, + int off) +{ + struct r92c_fw_cmd_pwrmode mode; + int error; + + /* XXX dm_RF_saving */ + + if (off && vap->iv_state == IEEE80211_S_RUN && + (vap->iv_flags & IEEE80211_F_PMGTON)) + mode.mode = R92C_PWRMODE_MIN; + else + mode.mode = R92C_PWRMODE_CAM; + mode.smart_ps = R92C_PWRMODE_SMARTPS_NULLDATA; + mode.bcn_pass = 1; /* XXX */ + error = r92c_fw_cmd(sc, R92C_CMD_SET_PWRMODE, &mode, sizeof(mode)); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: CMD_SET_PWRMODE was not sent, error %d\n", + __func__, error); + } + + return (error); +} + +void +r92c_set_rssi(struct rtwn_softc *sc) +{ + struct ieee80211_node *ni; + struct rtwn_node *rn; + struct r92c_fw_cmd_rssi cmd; + int i; + + cmd.reserved = 0; + + RTWN_NT_LOCK(sc); + for (i = 0; i < sc->macid_limit; i++) { + /* XXX optimize? */ + ni = sc->node_list[i]; + if (ni == NULL) + continue; + + rn = RTWN_NODE(ni); + cmd.macid = i; + cmd.pwdb = rn->avg_pwdb; + RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, + "%s: sending RSSI command (macid %d, rssi %d)\n", + __func__, i, rn->avg_pwdb); + + RTWN_NT_UNLOCK(sc); + r92c_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd)); + RTWN_NT_LOCK(sc); + } + RTWN_NT_UNLOCK(sc); +} + +static void +r92c_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ +#if __FreeBSD_version >= 1200012 + struct ieee80211_ratectl_tx_status txs; +#endif + struct r92c_c2h_tx_rpt *rpt; + struct ieee80211_node *ni; + uint8_t macid; + int ntries; + + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) { + /* shouldn't happen */ + device_printf(sc->sc_dev, "%s called while ratectl = %d!\n", + __func__, sc->sc_ratectl); + return; + } + + rpt = (struct r92c_c2h_tx_rpt *)buf; + if (len != sizeof(*rpt)) { + device_printf(sc->sc_dev, + "%s: wrong report size (%d, must be %zu)\n", + __func__, len, sizeof(*rpt)); + return; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: ccx report dump: 0: %02X, 1: %02X, queue time: " + "low %02X, high %02X, 4: %02X, 5: %02X, 6: %02X, 7: %02X\n", + __func__, rpt->rptb0, rpt->rptb1, rpt->queue_time_low, + rpt->queue_time_high, rpt->rptb4, rpt->rptb5, rpt->rptb6, + rpt->rptb7); + + macid = MS(rpt->rptb5, R92C_RPTB5_MACID); + if (macid > sc->macid_limit) { + device_printf(sc->sc_dev, + "macid %u is too big; increase MACID_MAX limit\n", + macid); + return; + } + + ntries = MS(rpt->rptb0, R92C_RPTB0_RETRY_CNT); + + RTWN_NT_LOCK(sc); + ni = sc->node_list[macid]; + if (ni != NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was" + "%s sent (%d retries)\n", __func__, macid, + (rpt->rptb7 & R92C_RPTB7_PKT_OK) ? "" : " not", + ntries); + +#if __FreeBSD_version >= 1200012 + txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY; + txs.long_retries = ntries; + if (rpt->rptb7 & R92C_RPTB7_PKT_OK) + txs.status = IEEE80211_RATECTL_TX_SUCCESS; + else if (rpt->rptb6 & R92C_RPTB6_RETRY_OVER) + txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; /* XXX */ + else if (rpt->rptb6 & R92C_RPTB6_LIFE_EXPIRE) + txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; + else + txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED; + ieee80211_ratectl_tx_complete(ni, &txs); +#else + struct ieee80211vap *vap = ni->ni_vap; + if (rpt->rptb7 & R92C_RPTB7_PKT_OK) { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); + } else { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); + } +#endif + } else { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n", + __func__, macid); + } + RTWN_NT_UNLOCK(sc); + +#ifdef IEEE80211_SUPPORT_SUPERG + if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1) + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); +#endif +} + +static void +r92c_handle_c2h_task(struct rtwn_softc *sc, union sec_param *data) +{ + const uint16_t off = R92C_C2H_EVT_MSG + sizeof(struct r92c_c2h_evt); + struct r92c_softc *rs = sc->sc_priv; + uint16_t buf[R92C_C2H_MSG_MAX_LEN / 2 + 1]; + uint8_t id, len, status; + int i; + + /* Do not reschedule the task if device is not running. */ + if (!(sc->sc_flags & RTWN_RUNNING)) + return; + + /* Read current status. */ + status = rtwn_read_1(sc, R92C_C2H_EVT_CLEAR); + if (status == R92C_C2H_EVT_HOST_CLOSE) + goto end; /* nothing to do */ + else if (status == R92C_C2H_EVT_FW_CLOSE) { + len = rtwn_read_1(sc, R92C_C2H_EVT_MSG); + id = MS(len, R92C_C2H_EVTB0_ID); + len = MS(len, R92C_C2H_EVTB0_LEN); + + memset(buf, 0, sizeof(buf)); + /* Try to optimize event reads. */ + for (i = 0; i < len; i += 2) + buf[i / 2] = rtwn_read_2(sc, off + i); + KASSERT(i < sizeof(buf), ("%s: buffer overrun (%d >= %zu)!", + __func__, i, sizeof(buf))); + + switch (id) { + case R92C_C2H_EVT_TX_REPORT: + r92c_ratectl_tx_complete(sc, (uint8_t *)buf, len); + break; + default: + device_printf(sc->sc_dev, + "%s: C2H report %u (len %u) was not handled\n", + __func__, id, len); + break; + } + } + + /* Prepare for next event. */ + rtwn_write_1(sc, R92C_C2H_EVT_CLEAR, R92C_C2H_EVT_HOST_CLOSE); + +end: + /* Adjust timeout for next call. */ + if (rs->rs_c2h_pending != 0) { + rs->rs_c2h_pending = 0; + rs->rs_c2h_paused = 0; + } else + rs->rs_c2h_paused++; + + if (rs->rs_c2h_paused > R92C_TX_PAUSED_THRESHOLD) + rs->rs_c2h_timeout = hz; + else + rs->rs_c2h_timeout = MAX(hz / 100, 1); + + /* Reschedule the task. */ + callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout, + r92c_handle_c2h_report, sc); +} + +void +r92c_handle_c2h_report(void *arg) +{ + struct rtwn_softc *sc = arg; + + rtwn_cmd_sleepable(sc, NULL, 0, r92c_handle_c2h_task); +} + +#endif /* RTWN_WITHOUT_UCODE */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h new file mode 100644 index 00000000..998a7805 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h @@ -0,0 +1,148 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_FW_CMD_H +#define R92C_FW_CMD_H + +/* + * Host to firmware commands. + */ +struct r92c_fw_cmd { + uint8_t id; +#define R92C_CMD_SET_PWRMODE 1 +#define R92C_CMD_JOINBSS_RPT 2 +#define R92C_CMD_RSVD_PAGE 3 +#define R92C_CMD_RSSI_SETTING 5 +#define R92C_CMD_MACID_CONFIG 6 + +#define R92C_CMD_FLAG_EXT 0x80 + + uint8_t msg[5]; +} __packed __attribute__((aligned(4))); + +/* Structure for R92C_CMD_JOINBSS_RPT. */ +struct r92c_fw_cmd_joinbss_rpt { + uint8_t mstatus; +#define R92C_MSTATUS_DISASSOC 0x00 +#define R92C_MSTATUS_ASSOC 0x01 +} __packed; + +/* Structure for R92C_CMD_SET_PWRMODE. */ +struct r92c_fw_cmd_pwrmode { + uint8_t mode; +#define R92C_PWRMODE_CAM 0 +#define R92C_PWRMODE_MIN 1 +#define R92C_PWRMODE_MAX 2 +#define R92C_PWRMODE_DTIM 3 +#define R92C_PWRMODE_UAPSD_WMM 5 +#define R92C_PWRMODE_UAPSD 6 +#define R92C_PWRMODE_IBSS 7 + + uint8_t smart_ps; +/* XXX undocumented */ +#define R92C_PWRMODE_SMARTPS_NULLDATA 2 + + uint8_t bcn_pass; /* unit: beacon interval */ +} __packed; + +/* Structure for R92C_CMD_RSVD_PAGE. */ +struct r92c_fw_cmd_rsvdpage { + uint8_t probe_resp; + uint8_t ps_poll; + uint8_t null_data; +} __packed; + +/* Structure for R92C_CMD_RSSI_SETTING. */ +struct r92c_fw_cmd_rssi { + uint8_t macid; + uint8_t reserved; + uint8_t pwdb; +} __packed; + +/* Structure for R92C_CMD_MACID_CONFIG. */ +struct r92c_fw_cmd_macid_cfg { + uint32_t mask; + uint8_t macid; +#define R92C_CMD_MACID_VALID 0x80 +} __packed; + +/* + * C2H event structure. + */ +/* Bigger value is used to prevent buffer overrun. */ +#define R92C_C2H_MSG_MAX_LEN 16 + +struct r92c_c2h_evt { + uint8_t evtb0; +#define R92C_C2H_EVTB0_ID_M 0x0f +#define R92C_C2H_EVTB0_ID_S 0 +#define R92C_C2H_EVTB0_LEN_M 0xf0 +#define R92C_C2H_EVTB0_LEN_S 4 + + uint8_t seq; + + /* Followed by payload (see below). */ +} __packed; + +/* + * C2H event types. + */ +#define R92C_C2H_EVT_DEBUG 0 +#define R92C_C2H_EVT_TX_REPORT 3 +#define R92C_C2H_EVT_EXT_RA_RPT 6 + +/* Structure for R92C_C2H_EVT_TX_REPORT event. */ +struct r92c_c2h_tx_rpt { + uint8_t rptb0; +#define R92C_RPTB0_RETRY_CNT_M 0x3f +#define R92C_RPTB0_RETRY_CNT_S 0 + + uint8_t rptb1; /* XXX junk */ +#define R92C_RPTB1_RTS_RETRY_CNT_M 0x3f +#define R92C_RPTB1_RTS_RETRY_CNT_S 0 + + uint8_t queue_time_low; + uint8_t queue_time_high; + uint8_t rptb4; +#define R92C_RPTB4_MISSED_PKT_NUM_M 0x1f +#define R92C_RPTB4_MISSED_PKT_NUM_S 0 + + uint8_t rptb5; +#define R92C_RPTB5_MACID_M 0x1f +#define R92C_RPTB5_MACID_S 0 +#define R92C_RPTB5_DES1_FRAGSSN_M 0xe0 +#define R92C_RPTB5_DES1_FRAGSSN_S 5 + + uint8_t rptb6; +#define R92C_RPTB6_RPT_PKT_NUM_M 0x1f +#define R92C_RPTB6_RPT_PKT_NUM_S 0 +#define R92C_RPTB6_PKT_DROP 0x20 +#define R92C_RPTB6_LIFE_EXPIRE 0x40 +#define R92C_RPTB6_RETRY_OVER 0x80 + + uint8_t rptb7; +#define R92C_RPTB7_EDCA_M 0x0f +#define R92C_RPTB7_EDCA_S 0 +#define R92C_RPTB7_BMC 0x20 +#define R92C_RPTB7_PKT_OK 0x40 +#define R92C_RPTB7_INT_CCX 0x80 +} __packed; + +#endif /* R92C_FW_CMD_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c new file mode 100644 index 00000000..d8db0286 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_init.c @@ -0,0 +1,319 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +int +r92c_check_condition(struct rtwn_softc *sc, const uint8_t cond[]) +{ + struct r92c_softc *rs = sc->sc_priv; + uint8_t mask; + int i; + + if (cond[0] == 0) + return (1); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "%s: condition byte 0: %02X; chip %02X, board %02X\n", + __func__, cond[0], rs->chip, rs->board_type); + + if (!(rs->chip & R92C_CHIP_92C)) { + if (rs->board_type == R92C_BOARD_TYPE_HIGHPA) + mask = R92C_COND_RTL8188RU; + else if (rs->board_type == R92C_BOARD_TYPE_MINICARD) + mask = R92C_COND_RTL8188CE; + else + mask = R92C_COND_RTL8188CU; + } else { + if (rs->board_type == R92C_BOARD_TYPE_MINICARD) + mask = R92C_COND_RTL8192CE; + else + mask = R92C_COND_RTL8192CU; + } + + for (i = 0; i < RTWN_MAX_CONDITIONS && cond[i] != 0; i++) + if ((cond[i] & mask) == mask) + return (1); + + return (0); +} + +int +r92c_set_page_size(struct rtwn_softc *sc) +{ + return (rtwn_write_1(sc, R92C_PBP, SM(R92C_PBP_PSRX, R92C_PBP_128) | + SM(R92C_PBP_PSTX, R92C_PBP_128)) == 0); +} + +void +r92c_init_bb_common(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + int i, j; + + /* Write BB initialization values. */ + for (i = 0; i < sc->bb_size; i++) { + const struct rtwn_bb_prog *bb_prog = &sc->bb_prog[i]; + + while (!rtwn_check_condition(sc, bb_prog->cond)) { + KASSERT(bb_prog->next != NULL, + ("%s: wrong condition value (i %d)\n", + __func__, i)); + bb_prog = bb_prog->next; + } + + for (j = 0; j < bb_prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "BB: reg 0x%03x, val 0x%08x\n", + bb_prog->reg[j], bb_prog->val[j]); + + rtwn_bb_write(sc, bb_prog->reg[j], bb_prog->val[j]); + rtwn_delay(sc, 1); + } + } + + if (rs->chip & R92C_CHIP_92C_1T2R) { + /* 8192C 1T only configuration. */ + rtwn_bb_setbits(sc, R92C_FPGA0_TXINFO, 0x03, 0x02); + rtwn_bb_setbits(sc, R92C_FPGA1_TXINFO, 0x300033, 0x200022); + rtwn_bb_setbits(sc, R92C_CCK0_AFESETTING, 0xff000000, + 0x45000000); + rtwn_bb_setbits(sc, R92C_OFDM0_TRXPATHENA, 0xff, 0x23); + rtwn_bb_setbits(sc, R92C_OFDM0_AGCPARAM1, 0x30, 0x10); + + rtwn_bb_setbits(sc, 0xe74, 0x0c000000, 0x08000000); + rtwn_bb_setbits(sc, 0xe78, 0x0c000000, 0x08000000); + rtwn_bb_setbits(sc, 0xe7c, 0x0c000000, 0x08000000); + rtwn_bb_setbits(sc, 0xe80, 0x0c000000, 0x08000000); + rtwn_bb_setbits(sc, 0xe88, 0x0c000000, 0x08000000); + } + + /* Write AGC values. */ + for (i = 0; i < sc->agc_size; i++) { + const struct rtwn_agc_prog *agc_prog = &sc->agc_prog[i]; + + while (!rtwn_check_condition(sc, agc_prog->cond)) { + KASSERT(agc_prog->next != NULL, + ("%s: wrong condition value (2) (i %d)\n", + __func__, i)); + agc_prog = agc_prog->next; + } + + for (j = 0; j < agc_prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "AGC: val 0x%08x\n", agc_prog->val[j]); + + rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, + agc_prog->val[j]); + rtwn_delay(sc, 1); + } + } + + if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & R92C_HSSI_PARAM2_CCK_HIPWR) + sc->sc_flags |= RTWN_FLAG_CCK_HIPWR; +} + +int +r92c_init_rf_chain(struct rtwn_softc *sc, + const struct rtwn_rf_prog *rf_prog, int chain) +{ + int i, j; + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, "%s: chain %d\n", + __func__, chain); + + for (i = 0; rf_prog[i].reg != NULL; i++) { + const struct rtwn_rf_prog *prog = &rf_prog[i]; + + while (!rtwn_check_condition(sc, prog->cond)) { + KASSERT(prog->next != NULL, + ("%s: wrong condition value (i %d)\n", + __func__, i)); + prog = prog->next; + } + + for (j = 0; j < prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "RF: reg 0x%02x, val 0x%05x\n", + prog->reg[j], prog->val[j]); + + /* + * These are fake RF registers offsets that + * indicate a delay is required. + */ + /* NB: we are using 'value' to store required delay. */ + if (prog->reg[j] > 0xf8) { + rtwn_delay(sc, prog->val[j]); + continue; + } + + rtwn_rf_write(sc, chain, prog->reg[j], prog->val[j]); + rtwn_delay(sc, 1); + } + } + + return (i); +} + +void +r92c_init_rf(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg, type; + int i, chain, idx, off; + + for (chain = 0, i = 0; chain < sc->nrxchains; chain++, i++) { + /* Save RF_ENV control type. */ + idx = chain / 2; + off = (chain % 2) * 16; + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); + type = (reg >> off) & 0x10; + + /* Set RF_ENV enable. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(chain), + 0, 0x100000); + rtwn_delay(sc, 1); + /* Set RF_ENV output high. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(chain), + 0, 0x10); + rtwn_delay(sc, 1); + /* Set address and data lengths of RF registers. */ + rtwn_bb_setbits(sc, R92C_HSSI_PARAM2(chain), + R92C_HSSI_PARAM2_ADDR_LENGTH, 0); + rtwn_delay(sc, 1); + rtwn_bb_setbits(sc, R92C_HSSI_PARAM2(chain), + R92C_HSSI_PARAM2_DATA_LENGTH, 0); + rtwn_delay(sc, 1); + + /* Write RF initialization values for this chain. */ + i += r92c_init_rf_chain(sc, &sc->rf_prog[i], chain); + + /* Restore RF_ENV control type. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACESW(idx), + 0x10 << off, type << off); + + /* Cache RF register CHNLBW. */ + rs->rf_chnlbw[chain] = rtwn_rf_read(sc, chain, + R92C_RF_CHNLBW); + } + + if ((rs->chip & (R92C_CHIP_UMC_A_CUT | R92C_CHIP_92C)) == + R92C_CHIP_UMC_A_CUT) { + rtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255); + rtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00); + } + + /* Turn CCK and OFDM blocks on. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_CCK_EN); + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_OFDM_EN); +} + +void +r92c_init_edca(struct rtwn_softc *sc) +{ + /* SIFS */ + rtwn_write_2(sc, R92C_SPEC_SIFS, 0x100a); + rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x100a); + rtwn_write_2(sc, R92C_SIFS_CCK, 0x100a); + rtwn_write_2(sc, R92C_SIFS_OFDM, 0x100a); + /* TXOP */ + rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b); + rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f); + rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005ea324); + rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002fa226); +} + +void +r92c_init_ampdu(struct rtwn_softc *sc) +{ + + /* Setup AMPDU aggregation. */ + rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */ + rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16); + rtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x0708); +} + +void +r92c_init_antsel(struct rtwn_softc *sc) +{ + uint32_t reg; + + if (sc->ntxchains != 1 || sc->nrxchains != 1) + return; + + rtwn_setbits_1(sc, R92C_LEDCFG2, 0, 0x80); + rtwn_bb_setbits(sc, R92C_FPGA0_RFPARAM(0), 0, 0x2000); + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(0)); + sc->sc_ant = MS(reg, R92C_FPGA0_RFIFACEOE0_ANT); /* XXX */ +} + +void +r92c_pa_bias_init(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + int i; + + for (i = 0; i < sc->nrxchains; i++) { + if (rs->pa_setting & (1 << i)) + continue; + r92c_rf_write(sc, i, R92C_RF_IPA, 0x0f406); + r92c_rf_write(sc, i, R92C_RF_IPA, 0x4f406); + r92c_rf_write(sc, i, R92C_RF_IPA, 0x8f406); + r92c_rf_write(sc, i, R92C_RF_IPA, 0xcf406); + } + if (!(rs->pa_setting & 0x10)) + rtwn_setbits_1(sc, 0x16, 0xf0, 0x90); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h new file mode 100644 index 00000000..13c38fb2 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h @@ -0,0 +1,408 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_PRIV_H +#define R92C_PRIV_H + +#include + +/* + * Parsed Tx power (diff) values. + */ +struct rtwn_r92c_txpwr { + uint8_t cck_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + uint8_t ht40_1s_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ht40_2s_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ht20_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ofdm_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ht40_max_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ht20_max_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; +}; + + +/* + * Baseband initialization values (shared parts). + */ +#define R92C_COND_RTL8188CE 0x01 +#define R92C_COND_RTL8188CU 0x02 +#define R92C_COND_RTL8188RU 0x04 +#define R92C_COND_RTL8192CE 0x08 +#define R92C_COND_RTL8192CU 0x10 + +/* Shortcut. */ +#define R92C_COND_RTL8192C (R92C_COND_RTL8192CE | R92C_COND_RTL8192CU) + +static const uint16_t rtl8192c_bb_regs3[] = { + 0xd04 +}, rtl8192c_bb_regs4[] = { + 0xd08, 0xd0c, 0xd10, 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, + 0xd3c, 0xd40, 0xd44, 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, + 0xd60, 0xd64, 0xd68, 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, + 0xe08, 0xe10, 0xe14, 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, + 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c +}, rtl8192c_bb_regs5[] = { + 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xf14, + 0xf4c, 0xf00 +}; + +static const uint32_t rtl8192c_bb_vals3_88cu_88ru[] = { + 0x00020401 +}, rtl8192c_bb_vals3_92ce_92cu[] = { + 0x00020403 +}, rtl8192c_bb_vals4[] = { + 0x0000907f, 0x20010201, 0xa0633333, 0x3333bc43, 0x7a8f5b6b, + 0xcc979975, 0x00000000, 0x80608000, 0x00000000, 0x00027293, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6437140a, + 0x00000000, 0x00000000, 0x30032064, 0x4653de68, 0x04518a3c, + 0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220, 0x000e3c24, + 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, 0x2a2a2a2a, 0x2a2a2a2a, + 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, 0x1000dc1f, 0x10008c1f, + 0x02140102, 0x681604c2, 0x01007c00, 0x01004800, 0xfb000000, + 0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102, 0x28160d05 +},rtl8192c_bb_vals5_92ce_92cu[] = { + 0x00000010, 0x001b25a4, 0x63db25a4, 0x63db25a4, 0x0c1b25a4, + 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x63db25a4, 0x0c1b25a4, + 0x63db25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, 0x001b25a4, + 0x001b25a4, 0x6fdb25a4, 0x00000003, 0x00000000, 0x00000300 +}; + +/* + * RTL8192CU and RTL8192CE-VAU. + */ + +static const uint32_t rtl8192ce_agc_vals[] = { + 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, + 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001, + 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001, + 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001, + 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001, + 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001, + 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001, + 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, + 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, + 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, + 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, + 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, + 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, + 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, + 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001, + 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001, + 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001, + 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001, + 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001, + 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001, + 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, + 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, + 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, + 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, + 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, + 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, + 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, + 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, + 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, + 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, + 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, + 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e +}; + +static const struct rtwn_agc_prog rtl8192ce_agc[] = { + { + nitems(rtl8192ce_agc_vals), + rtl8192ce_agc_vals, + { 0 }, + NULL + } +}; + + +/* + * RF initialization values. + */ +static const uint8_t rtl8192c_rf0_regs0[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21 +}, rtl8192c_rf0_regs1[] = { + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28 +}, rtl8192c_rf0_regs2[] = { + 0x29, 0x2a, 0x2b, 0x2a, 0x2b, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, + 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, + 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, + 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, + 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, + 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x10, 0x11, 0x10, 0x11, + 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11 +}, rtl8192c_rf0_regs3[] = { + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13 +}, rtl8192c_rf0_regs4[] = { + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15 +}, rtl8192c_rf0_regs5[] = { + 0x16, 0x16, 0x16, 0x16, 0x00, 0x18, 0xfe, 0xfe, 0x1f, 0xfe, 0xfe, + 0x1e, 0x1f, 0x00 +}; + +static const uint32_t rtl8192c_rf0_vals0_88ce_88cu_92ce[] = { + 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, + 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, + 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000 +}, rtl8192c_rf0_vals0_88ru[] = { + 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb0, + 0x54867, 0x8992e, 0x0e529, 0x39ce7, 0x00451, 0x00000, 0x00255, + 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000 +}, rtl8192c_rf0_vals1_88ru[] = { + 0x0083c, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x977c0 +}, rtl8192c_rf0_vals1_88ce[] = { + 0x00000, 0x01558, 0x00060, 0x00483, 0x4f200, 0xec7d9, 0x577c0 +}, rtl8192c_rf0_vals1_88cu_92ce[] = { + 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0 +}, rtl8192c_rf0_vals2[] = { + 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, + 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, + 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, + 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, + 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, + 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, + 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, + 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, + 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, + 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, + 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100 +}, rtl8192c_rf0_vals3_88ru[] = { + 0xd8000, 0x90000, 0x51000, 0x12000, 0x28fb4, 0x24fa8, 0x207a4, + 0x1c798, 0x183a4, 0x14398, 0x101a4, 0x0c198, 0x080a4, 0x04098, + 0x00014 +}, rtl8192c_rf0_vals3_92ce[] = { + 0x32000, 0x71000, 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, + 0x1c49f, 0x18493, 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, + 0x0001c +}, rtl8192c_rf0_vals3_88cu_88ce[] = { + 0x32000, 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, + 0x1c49f, 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, + 0x00020 +}, rtl8192c_rf0_vals4_92ce_88ce[] = { + 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, + 0xcf424 +}, rtl8192c_rf0_vals4_88cu_88ru[] = { + 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405, + 0xcf405 +}, rtl8192c_rf0_vals5[] = { + 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, 0x0c350, + 0x0c350, 0x80003, 0x0c350, 0x0c350, 0x44457, 0x80000, 0x30159 +}; + +static const struct rtwn_rf_prog rtl8192c_rf[] = { + /* RF chain 0 */ + /* RTL8188RU. */ + { + nitems(rtl8192c_rf0_regs0), + rtl8192c_rf0_regs0, + rtl8192c_rf0_vals0_88ru, + { R92C_COND_RTL8188RU }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs0), + rtl8192c_rf0_regs0, + rtl8192c_rf0_vals0_88ce_88cu_92ce, + { 0 }, + NULL + } + }, + /* RTL8188RU. */ + { + nitems(rtl8192c_rf0_regs1), + rtl8192c_rf0_regs1, + rtl8192c_rf0_vals1_88ru, + { R92C_COND_RTL8188RU }, + /* RTL8188CE. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs1), + rtl8192c_rf0_regs1, + rtl8192c_rf0_vals1_88ce, + { R92C_COND_RTL8188CE }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs1), + rtl8192c_rf0_regs1, + rtl8192c_rf0_vals1_88cu_92ce, + { 0 }, + NULL + } + } + }, + { + nitems(rtl8192c_rf0_regs2), + rtl8192c_rf0_regs2, + rtl8192c_rf0_vals2, + { 0 }, + NULL + }, + /* RTL8188RU. */ + { + nitems(rtl8192c_rf0_regs3), + rtl8192c_rf0_regs3, + rtl8192c_rf0_vals3_88ru, + { R92C_COND_RTL8188RU }, + /* RTL8192C. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs3), + rtl8192c_rf0_regs3, + rtl8192c_rf0_vals3_92ce, + { R92C_COND_RTL8192C }, + /* Others. */ + &(struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs3), + rtl8192c_rf0_regs3, + rtl8192c_rf0_vals3_88cu_88ce, + { 0 }, + NULL + } + } + }, + /* RTL8188CE / RTL8192C. */ + { + nitems(rtl8192c_rf0_regs4), + rtl8192c_rf0_regs4, + rtl8192c_rf0_vals4_92ce_88ce, + { R92C_COND_RTL8188CE | R92C_COND_RTL8192C }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs4), + rtl8192c_rf0_regs4, + rtl8192c_rf0_vals4_88cu_88ru, + { 0 }, + NULL + } + }, + { + nitems(rtl8192c_rf0_regs5), + rtl8192c_rf0_regs5, + rtl8192c_rf0_vals5, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL }, + /* RF chain 1 (RTL8192C). */ + { + 12, /* 0x00 - 0x0f */ + rtl8192c_rf0_regs0, + rtl8192c_rf0_vals0_88ce_88cu_92ce, + { 0 }, + NULL + }, + { + nitems(rtl8192c_rf0_regs3), /* 0x12 - 0x13 */ + rtl8192c_rf0_regs3, + rtl8192c_rf0_vals3_92ce, + { 0 }, + NULL + }, + { + nitems(rtl8192c_rf0_regs4), /* 0x14 - 0x15 */ + rtl8192c_rf0_regs4, + rtl8192c_rf0_vals4_92ce_88ce, + { 0 }, + NULL + }, + { + 4, /* 0x16 */ + rtl8192c_rf0_regs5, + rtl8192c_rf0_vals5, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL } +}; + + +struct rtwn_r92c_txagc { + uint8_t pwr[R92C_GROUP_2G][28]; /* RTWN_RIDX_MCS(15) + 1 */ +}; + +/* + * Per RF chain/group/rate Tx gain values. + */ +static const struct rtwn_r92c_txagc rtl8192cu_txagc[] = { + { { /* Chain 0. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x0c, 0x0c, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* OFDM6~54. */ + 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* MCS0~7. */ + 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02 /* MCS8~15. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + } + } }, + { { /* Chain 1. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + } + } } +}; + +static const struct rtwn_r92c_txagc rtl8188ru_txagc[] = { + { { /* Chain 0. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x08, 0x08, 0x08, 0x06, 0x06, 0x04, 0x04, 0x00, /* OFDM6~54. */ + 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00, /* MCS0~7. */ + 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00 /* MCS8~15. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + } + } } +}; + +#endif /* R92C_PRIV_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h new file mode 100644 index 00000000..ff03d191 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_reg.h @@ -0,0 +1,855 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_REG_H +#define R92C_REG_H + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R92C_SYS_ISO_CTRL 0x000 +#define R92C_SYS_FUNC_EN 0x002 +#define R92C_APS_FSMCO 0x004 +#define R92C_SYS_CLKR 0x008 +#define R92C_AFE_MISC 0x010 +#define R92C_SPS0_CTRL 0x011 +#define R92C_SPS_OCP_CFG 0x018 +#define R92C_RSV_CTRL 0x01c +#define R92C_RF_CTRL 0x01f +#define R92C_LDOA15_CTRL 0x020 +#define R92C_LDOV12D_CTRL 0x021 +#define R92C_LDOHCI12_CTRL 0x022 +#define R92C_LPLDO_CTRL 0x023 +#define R92C_AFE_XTAL_CTRL 0x024 +#define R92C_AFE_PLL_CTRL 0x028 +#define R92C_APE_PLL_CTRL_EXT 0x02c +#define R92C_MAC_PHY_CTRL R92C_APE_PLL_CTRL_EXT +#define R92C_EFUSE_CTRL 0x030 +#define R92C_EFUSE_TEST 0x034 +#define R92C_PWR_DATA 0x038 +#define R92C_CAL_TIMER 0x03c +#define R92C_ACLK_MON 0x03e +#define R92C_GPIO_MUXCFG 0x040 +#define R92C_GPIO_IO_SEL 0x042 +#define R92C_MAC_PINMUX_CFG 0x043 +#define R92C_GPIO_PIN_CTRL 0x044 +#define R92C_GPIO_IN 0x044 +#define R92C_GPIO_OUT 0x045 +#define R92C_GPIO_IOSEL 0x046 +#define R92C_GPIO_MOD 0x047 +#define R92C_GPIO_INTM 0x048 +#define R92C_LEDCFG0 0x04c +#define R92C_LEDCFG1 0x04d +#define R92C_LEDCFG2 0x04e +#define R92C_LEDCFG3 0x04f +#define R92C_FSIMR 0x050 +#define R92C_FSISR 0x054 +#define R92C_HSIMR 0x058 +#define R92C_HSISR 0x05c +#define R92C_MULTI_FUNC_CTRL 0x068 +#define R92C_MCUFWDL 0x080 +#define R92C_HMEBOX_EXT(idx) (0x088 + (idx) * 2) +#define R92C_EFUSE_ACCESS 0x0cf +#define R92C_BIST_SCAN 0x0d0 +#define R92C_BIST_RPT 0x0d4 +#define R92C_BIST_ROM_RPT 0x0d8 +#define R92C_HPON_FSM 0x0ec +#define R92C_SYS_CFG 0x0f0 +#define R92C_TYPE_ID 0x0fc +/* MAC General Configuration. */ +#define R92C_CR 0x100 +#define R92C_MSR 0x102 +#define R92C_PBP 0x104 +#define R92C_TRXDMA_CTRL 0x10c +#define R92C_TRXFF_BNDY 0x114 +#define R92C_TRXFF_STATUS 0x118 +#define R92C_RXFF_PTR 0x11c +#define R92C_HIMR 0x120 +#define R92C_HISR 0x124 +#define R92C_HIMRE 0x128 +#define R92C_HISRE 0x12c +#define R92C_CPWM 0x12f +#define R92C_FWIMR 0x130 +#define R92C_FWISR 0x134 +#define R92C_PKTBUF_DBG_CTRL 0x140 +#define R92C_PKTBUF_DBG_DATA_L 0x144 +#define R92C_PKTBUF_DBG_DATA_H 0x148 +#define R92C_TC0_CTRL(i) (0x150 + (i) * 4) +#define R92C_TCUNIT_BASE 0x164 +#define R92C_MBIST_START 0x174 +#define R92C_MBIST_DONE 0x178 +#define R92C_MBIST_FAIL 0x17c +#define R92C_C2H_EVT_MSG 0x1a0 +#define R92C_C2H_EVT_CLEAR 0x1af +#define R92C_C2H_EVT_MSG_TEST 0x1b8 +#define R92C_MCUTST_1 0x1c0 +#define R92C_FMETHR 0x1c8 +#define R92C_HMETFR 0x1cc +#define R92C_HMEBOX(idx) (0x1d0 + (idx) * 4) +#define R92C_LLT_INIT 0x1e0 +#define R92C_BB_ACCESS_CTRL 0x1e8 +#define R92C_BB_ACCESS_DATA 0x1ec +/* Tx DMA Configuration. */ +#define R92C_RQPN 0x200 +#define R92C_FIFOPAGE 0x204 +#define R92C_TDECTRL 0x208 +#define R92C_TXDMA_OFFSET_CHK 0x20c +#define R92C_TXDMA_STATUS 0x210 +#define R92C_RQPN_NPQ 0x214 +/* Rx DMA Configuration. */ +#define R92C_RXDMA_AGG_PG_TH 0x280 +#define R92C_RXPKT_NUM 0x284 +#define R92C_RXDMA_STATUS 0x288 +/* Protocol Configuration. */ +#define R92C_VOQ_INFORMATION 0x400 +#define R92C_VIQ_INFORMATION 0x404 +#define R92C_BEQ_INFORMATION 0x408 +#define R92C_BKQ_INFORMATION 0x40c +#define R92C_MGQ_INFORMATION 0x410 +#define R92C_HGQ_INFORMATION 0x414 +#define R92C_BCNQ_INFORMATION 0x418 +#define R92C_CPU_MGQ_INFORMATION 0x41c +#define R92C_FWHW_TXQ_CTRL 0x420 +#define R92C_HWSEQ_CTRL 0x423 +#define R92C_TXPKTBUF_BCNQ_BDNY 0x424 +#define R92C_TXPKTBUF_MGQ_BDNY 0x425 +#define R92C_SPEC_SIFS 0x428 +#define R92C_RL 0x42a +#define R92C_DARFRC 0x430 +#define R92C_RARFRC 0x438 +#define R92C_RRSR 0x440 +#define R92C_ARFR(i) (0x444 + (i) * 4) +#define R92C_AGGLEN_LMT 0x458 +#define R92C_AMPDU_MIN_SPACE 0x45c +#define R92C_TXPKTBUF_WMAC_LBK_BF_HD 0x45d +#define R92C_FAST_EDCA_CTRL 0x460 +#define R92C_RD_RESP_PKT_TH 0x463 +#define R92C_INIRTS_RATE_SEL 0x480 +#define R92C_INIDATA_RATE_SEL(macid) (0x484 + (macid)) +#define R92C_QUEUE_CTRL 0x4c6 +#define R92C_MAX_AGGR_NUM 0x4ca +#define R92C_BAR_MODE_CTRL 0x4cc +/* EDCA Configuration. */ +#define R92C_EDCA_VO_PARAM 0x500 +#define R92C_EDCA_VI_PARAM 0x504 +#define R92C_EDCA_BE_PARAM 0x508 +#define R92C_EDCA_BK_PARAM 0x50c +#define R92C_BCNTCFG 0x510 +#define R92C_PIFS 0x512 +#define R92C_RDG_PIFS 0x513 +#define R92C_SIFS_CCK 0x514 +#define R92C_SIFS_OFDM 0x516 +#define R92C_AGGR_BREAK_TIME 0x51a +#define R92C_SLOT 0x51b +#define R92C_TX_PTCL_CTRL 0x520 +#define R92C_TXPAUSE 0x522 +#define R92C_DIS_TXREQ_CLR 0x523 +#define R92C_RD_CTRL 0x524 +#define R92C_TBTT_PROHIBIT 0x540 +#define R92C_RD_NAV_NXT 0x544 +#define R92C_NAV_PROT_LEN 0x546 +#define R92C_BCN_CTRL(id) ((id) + 0x550) +/* WARNING: R92C_USTIME_TSF == 0x55c, not 0x551 */ +#define R92C_MBID_NUM 0x552 +#define R92C_DUAL_TSF_RST 0x553 +#define R92C_BCN_INTERVAL(id) (0x554 + (id) * 2) +#define R92C_DRVERLYINT 0x558 +#define R92C_BCNDMATIM 0x559 +#define R92C_ATIMWND 0x55a +#define R92C_USTIME_TSF 0x55c +#define R92C_BCN_MAX_ERR 0x55d +#define R92C_RXTSF_OFFSET_CCK 0x55e +#define R92C_RXTSF_OFFSET_OFDM 0x55f +#define R92C_TSFTR(i) (0x560 + (i) * 8) +#define R92C_PSTIMER 0x580 +#define R92C_TIMER0 0x584 +#define R92C_TIMER1 0x588 +#define R92C_ACMHWCTRL 0x5c0 +#define R92C_ACMRSTCTRL 0x5c1 +#define R92C_ACMAVG 0x5c2 +#define R92C_VO_ADMTIME 0x5c4 +#define R92C_VI_ADMTIME 0x5c6 +#define R92C_BE_ADMTIME 0x5c8 +#define R92C_EDCA_RANDOM_GEN 0x5cc +#define R92C_SCH_TXCMD 0x5d0 +/* WMAC Configuration. */ +#define R92C_APSD_CTRL 0x600 +#define R92C_BWOPMODE 0x603 +#define R92C_TCR 0x604 +#define R92C_RCR 0x608 +#define R92C_RX_PKT_LIMIT 0x60c +#define R92C_RX_DRVINFO_SZ 0x60f +#define R92C_MACID0 0x610 +#define R92C_BSSID0 0x618 +#define R92C_MAR 0x620 +#define R92C_USTIME_EDCA 0x638 +#define R92C_MAC_SPEC_SIFS 0x63a +#define R92C_R2T_SIFS 0x63c +#define R92C_T2T_SIFS 0x63e +#define R92C_ACKTO 0x640 +#define R92C_NAV_UPPER 0x652 +#define R92C_WMAC_TRXPTCL_CTL 0x668 +#define R92C_CAMCMD 0x670 +#define R92C_CAMWRITE 0x674 +#define R92C_CAMREAD 0x678 +#define R92C_CAMDBG 0x67c +#define R92C_SECCFG 0x680 +#define R92C_RXFLTMAP0 0x6a0 +#define R92C_RXFLTMAP1 0x6a2 +#define R92C_RXFLTMAP2 0x6a4 +#define R92C_BCN_PSR_RPT 0x6a8 +#define R92C_MACID1 0x700 +#define R92C_BSSID1 0x708 + + +#define R92C_MACID(id) ((id) == 0 ? R92C_MACID0 : R92C_MACID1) +#define R92C_BSSID(id) ((id) == 0 ? R92C_BSSID0 : R92C_BSSID1) + +/* Bits for R92C_SYS_ISO_CTRL. */ +#define R92C_SYS_ISO_CTRL_MD2PP 0x0001 +#define R92C_SYS_ISO_CTRL_UA2USB 0x0002 +#define R92C_SYS_ISO_CTRL_UD2CORE 0x0004 +#define R92C_SYS_ISO_CTRL_PA2PCIE 0x0008 +#define R92C_SYS_ISO_CTRL_PD2CORE 0x0010 +#define R92C_SYS_ISO_CTRL_IP2MAC 0x0020 +#define R92C_SYS_ISO_CTRL_DIOP 0x0040 +#define R92C_SYS_ISO_CTRL_DIOE 0x0080 +#define R92C_SYS_ISO_CTRL_EB2CORE 0x0100 +#define R92C_SYS_ISO_CTRL_DIOR 0x0200 +#define R92C_SYS_ISO_CTRL_PWC_EV25V 0x4000 +#define R92C_SYS_ISO_CTRL_PWC_EV12V 0x8000 + +/* Bits for R92C_SYS_FUNC_EN. */ +#define R92C_SYS_FUNC_EN_BBRSTB 0x0001 +#define R92C_SYS_FUNC_EN_BB_GLB_RST 0x0002 +#define R92C_SYS_FUNC_EN_USBA 0x0004 +#define R92C_SYS_FUNC_EN_UPLL 0x0008 +#define R92C_SYS_FUNC_EN_USBD 0x0010 +#define R92C_SYS_FUNC_EN_DIO_PCIE 0x0020 +#define R92C_SYS_FUNC_EN_PCIEA 0x0040 +#define R92C_SYS_FUNC_EN_PPLL 0x0080 +#define R92C_SYS_FUNC_EN_PCIED 0x0100 +#define R92C_SYS_FUNC_EN_DIOE 0x0200 +#define R92C_SYS_FUNC_EN_CPUEN 0x0400 +#define R92C_SYS_FUNC_EN_DCORE 0x0800 +#define R92C_SYS_FUNC_EN_ELDR 0x1000 +#define R92C_SYS_FUNC_EN_DIO_RF 0x2000 +#define R92C_SYS_FUNC_EN_HWPDN 0x4000 +#define R92C_SYS_FUNC_EN_MREGEN 0x8000 + +/* Bits for R92C_APS_FSMCO. */ +#define R92C_APS_FSMCO_PFM_LDALL 0x00000001 +#define R92C_APS_FSMCO_PFM_ALDN 0x00000002 +#define R92C_APS_FSMCO_PFM_LDKP 0x00000004 +#define R92C_APS_FSMCO_PFM_WOWL 0x00000008 +#define R92C_APS_FSMCO_PDN_EN 0x00000010 +#define R92C_APS_FSMCO_PDN_PL 0x00000020 +#define R92C_APS_FSMCO_APFM_ONMAC 0x00000100 +#define R92C_APS_FSMCO_APFM_OFF 0x00000200 +#define R92C_APS_FSMCO_APFM_RSM 0x00000400 +#define R92C_APS_FSMCO_AFSM_HSUS 0x00000800 +#define R92C_APS_FSMCO_AFSM_PCIE 0x00001000 +#define R92C_APS_FSMCO_APDM_MAC 0x00002000 +#define R92C_APS_FSMCO_APDM_HOST 0x00004000 +#define R92C_APS_FSMCO_APDM_HPDN 0x00008000 +#define R92C_APS_FSMCO_RDY_MACON 0x00010000 +#define R92C_APS_FSMCO_SUS_HOST 0x00020000 +#define R92C_APS_FSMCO_ROP_ALD 0x00100000 +#define R92C_APS_FSMCO_ROP_PWR 0x00200000 +#define R92C_APS_FSMCO_ROP_SPS 0x00400000 +#define R92C_APS_FSMCO_SOP_MRST 0x02000000 +#define R92C_APS_FSMCO_SOP_FUSE 0x04000000 +#define R92C_APS_FSMCO_SOP_ABG 0x08000000 +#define R92C_APS_FSMCO_SOP_AMB 0x10000000 +#define R92C_APS_FSMCO_SOP_RCK 0x20000000 +#define R92C_APS_FSMCO_SOP_A8M 0x40000000 +#define R92C_APS_FSMCO_XOP_BTCK 0x80000000 + +/* Bits for R92C_SYS_CLKR. */ +#define R92C_SYS_CLKR_ANAD16V_EN 0x00000001 +#define R92C_SYS_CLKR_ANA8M 0x00000002 +#define R92C_SYS_CLKR_MACSLP 0x00000010 +#define R92C_SYS_CLKR_LOADER_EN 0x00000020 +#define R92C_SYS_CLKR_80M_SSC_DIS 0x00000080 +#define R92C_SYS_CLKR_80M_SSC_EN_HO 0x00000100 +#define R92C_SYS_CLKR_PHY_SSC_RSTB 0x00000200 +#define R92C_SYS_CLKR_SEC_EN 0x00000400 +#define R92C_SYS_CLKR_MAC_EN 0x00000800 +#define R92C_SYS_CLKR_SYS_EN 0x00001000 +#define R92C_SYS_CLKR_RING_EN 0x00002000 + +/* Bits for R92C_RF_CTRL. */ +#define R92C_RF_CTRL_EN 0x01 +#define R92C_RF_CTRL_RSTB 0x02 +#define R92C_RF_CTRL_SDMRSTB 0x04 + +/* Bits for R92C_LDOA15_CTRL. */ +#define R92C_LDOA15_CTRL_EN 0x01 +#define R92C_LDOA15_CTRL_STBY 0x02 +#define R92C_LDOA15_CTRL_OBUF 0x04 +#define R92C_LDOA15_CTRL_REG_VOS 0x08 + +/* Bits for R92C_LDOV12D_CTRL. */ +#define R92C_LDOV12D_CTRL_LDV12_EN 0x01 + +/* Bits for R92C_LPLDO_CTRL. */ +#define R92C_LPLDO_CTRL_SLEEP 0x10 + +/* Bits for R92C_AFE_XTAL_CTRL. */ +#define R92C_AFE_XTAL_CTRL_ADDR_M 0x007ff800 +#define R92C_AFE_XTAL_CTRL_ADDR_S 11 + +/* Bits for R92C_AFE_PLL_CTRL. */ +#define R92C_AFE_PLL_CTRL_EN 0x0001 +#define R92C_AFE_PLL_CTRL_320_EN 0x0002 +#define R92C_AFE_PLL_CTRL_FREF_SEL 0x0004 +#define R92C_AFE_PLL_CTRL_EDGE_SEL 0x0008 +#define R92C_AFE_PLL_CTRL_WDOGB 0x0010 +#define R92C_AFE_PLL_CTRL_LPFEN 0x0020 + +/* Bits for R92C_EFUSE_CTRL. */ +#define R92C_EFUSE_CTRL_DATA_M 0x000000ff +#define R92C_EFUSE_CTRL_DATA_S 0 +#define R92C_EFUSE_CTRL_ADDR_M 0x0003ff00 +#define R92C_EFUSE_CTRL_ADDR_S 8 +#define R92C_EFUSE_CTRL_VALID 0x80000000 + +/* Bits for R92C_GPIO_MUXCFG. */ +#define R92C_GPIO_MUXCFG_ENBT 0x0020 + +/* Bits for R92C_LEDCFG0. */ +#define R92C_LEDCFG0_DIS 0x08 + +/* Bits for R92C_MULTI_FUNC_CTRL. */ +#define R92C_MULTI_BT_FUNC_EN 0x00040000 + +/* Bits for R92C_MCUFWDL. */ +#define R92C_MCUFWDL_EN 0x00000001 +#define R92C_MCUFWDL_RDY 0x00000002 +#define R92C_MCUFWDL_CHKSUM_RPT 0x00000004 +#define R92C_MCUFWDL_MACINI_RDY 0x00000008 +#define R92C_MCUFWDL_BBINI_RDY 0x00000010 +#define R92C_MCUFWDL_RFINI_RDY 0x00000020 +#define R92C_MCUFWDL_WINTINI_RDY 0x00000040 +#define R92C_MCUFWDL_RAM_DL_SEL 0x00000080 /* 1: RAM, 0: ROM */ +#define R92C_MCUFWDL_PAGE_M 0x00070000 +#define R92C_MCUFWDL_PAGE_S 16 +#define R92C_MCUFWDL_ROM_DLEN 0x00080000 +#define R92C_MCUFWDL_CPRST 0x00800000 + +/* Bits for R92C_EFUSE_ACCESS. */ +#define R92C_EFUSE_ACCESS_OFF 0x00 +#define R92C_EFUSE_ACCESS_ON 0x69 + +/* Bits for R92C_HPON_FSM. */ +#define R92C_HPON_FSM_CHIP_BONDING_ID_S 22 +#define R92C_HPON_FSM_CHIP_BONDING_ID_M 0x00c00000 +#define R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R 1 + +/* Bits for R92C_SYS_CFG. */ +#define R92C_SYS_CFG_XCLK_VLD 0x00000001 +#define R92C_SYS_CFG_ACLK_VLD 0x00000002 +#define R92C_SYS_CFG_UCLK_VLD 0x00000004 +#define R92C_SYS_CFG_PCLK_VLD 0x00000008 +#define R92C_SYS_CFG_PCIRSTB 0x00000010 +#define R92C_SYS_CFG_V15_VLD 0x00000020 +#define R92C_SYS_CFG_TRP_B15V_EN 0x00000080 +#define R92C_SYS_CFG_SIC_IDLE 0x00000100 +#define R92C_SYS_CFG_BD_MAC2 0x00000200 +#define R92C_SYS_CFG_BD_MAC1 0x00000400 +#define R92C_SYS_CFG_IC_MACPHY_MODE 0x00000800 +#define R92C_SYS_CFG_CHIP_VER_RTL_M 0x0000f000 +#define R92C_SYS_CFG_CHIP_VER_RTL_S 12 +#define R92C_SYS_CFG_BT_FUNC 0x00010000 +#define R92C_SYS_CFG_VENDOR_UMC 0x00080000 +#define R92C_SYS_CFG_PAD_HWPD_IDN 0x00400000 +#define R92C_SYS_CFG_TRP_VAUX_EN 0x00800000 +#define R92C_SYS_CFG_TRP_BT_EN 0x01000000 +#define R92C_SYS_CFG_BD_PKG_SEL 0x02000000 +#define R92C_SYS_CFG_BD_HCI_SEL 0x04000000 +#define R92C_SYS_CFG_TYPE_92C 0x08000000 + +/* Bits for R92C_CR. */ +#define R92C_CR_HCI_TXDMA_EN 0x0001 +#define R92C_CR_HCI_RXDMA_EN 0x0002 +#define R92C_CR_TXDMA_EN 0x0004 +#define R92C_CR_RXDMA_EN 0x0008 +#define R92C_CR_PROTOCOL_EN 0x0010 +#define R92C_CR_SCHEDULE_EN 0x0020 +#define R92C_CR_MACTXEN 0x0040 +#define R92C_CR_MACRXEN 0x0080 +#define R92C_CR_ENSWBCN 0x0100 +#define R92C_CR_ENSEC 0x0200 +#define R92C_CR_CALTMR_EN 0x0400 + +/* Bits for R92C_MSR. */ +#define R92C_MSR_NOLINK 0x00 +#define R92C_MSR_ADHOC 0x01 +#define R92C_MSR_INFRA 0x02 +#define R92C_MSR_AP 0x03 +#define R92C_MSR_MASK (R92C_MSR_AP) + +/* Bits for R92C_PBP. */ +#define R92C_PBP_PSRX_M 0x0f +#define R92C_PBP_PSRX_S 0 +#define R92C_PBP_PSTX_M 0xf0 +#define R92C_PBP_PSTX_S 4 +#define R92C_PBP_64 0 +#define R92C_PBP_128 1 +#define R92C_PBP_256 2 +#define R92C_PBP_512 3 +#define R92C_PBP_1024 4 + +/* Bits for R92C_TRXDMA_CTRL. */ +#define R92C_TRXDMA_CTRL_RXDMA_AGG_EN 0x0004 +#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_M 0x0030 +#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_S 4 +#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_M 0x00c0 +#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_S 6 +#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_M 0x0300 +#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_S 8 +#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_M 0x0c00 +#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_S 10 +#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_M 0x3000 +#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_S 12 +#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_M 0xc000 +#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_S 14 +#define R92C_TRXDMA_CTRL_QUEUE_LOW 1 +#define R92C_TRXDMA_CTRL_QUEUE_NORMAL 2 +#define R92C_TRXDMA_CTRL_QUEUE_HIGH 3 +#define R92C_TRXDMA_CTRL_QMAP_M 0xfff0 +/* Shortcuts. */ +#define R92C_TRXDMA_CTRL_QMAP_3EP 0xf5b0 +#define R92C_TRXDMA_CTRL_QMAP_HQ_LQ 0xf5f0 +#define R92C_TRXDMA_CTRL_QMAP_HQ_NQ 0xfaf0 +#define R92C_TRXDMA_CTRL_QMAP_LQ 0x5550 +#define R92C_TRXDMA_CTRL_QMAP_NQ 0xaaa0 +#define R92C_TRXDMA_CTRL_QMAP_HQ 0xfff0 + +/* Bits for R92C_C2H_EVT_CLEAR. */ +#define R92C_C2H_EVT_HOST_CLOSE 0x00 +#define R92C_C2H_EVT_FW_CLOSE 0xff + +/* Bits for R92C_LLT_INIT. */ +#define R92C_LLT_INIT_DATA_M 0x000000ff +#define R92C_LLT_INIT_DATA_S 0 +#define R92C_LLT_INIT_ADDR_M 0x0000ff00 +#define R92C_LLT_INIT_ADDR_S 8 +#define R92C_LLT_INIT_OP_M 0xc0000000 +#define R92C_LLT_INIT_OP_S 30 +#define R92C_LLT_INIT_OP_NO_ACTIVE 0 +#define R92C_LLT_INIT_OP_WRITE 1 + +/* Bits for R92C_RQPN. */ +#define R92C_RQPN_HPQ_M 0x000000ff +#define R92C_RQPN_HPQ_S 0 +#define R92C_RQPN_LPQ_M 0x0000ff00 +#define R92C_RQPN_LPQ_S 8 +#define R92C_RQPN_PUBQ_M 0x00ff0000 +#define R92C_RQPN_PUBQ_S 16 +#define R92C_RQPN_LD 0x80000000 + +/* Bits for R92C_TDECTRL. */ +#define R92C_TDECTRL_BLK_DESC_NUM_M 0x000000f0 +#define R92C_TDECTRL_BLK_DESC_NUM_S 4 +#define R92C_TDECTRL_BCN_VALID 0x00010000 + +/* Bits for R92C_TXDMA_OFFSET_CHK. */ +#define R92C_TXDMA_OFFSET_DROP_DATA_EN 0x00000200 + +/* Bits for R92C_FWHW_TXQ_CTRL. */ +#define R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW 0x80 +#define R92C_FWHW_TXQ_CTRL_REAL_BEACON 0x400000 + +/* Bits for R92C_SPEC_SIFS. */ +#define R92C_SPEC_SIFS_CCK_M 0x00ff +#define R92C_SPEC_SIFS_CCK_S 0 +#define R92C_SPEC_SIFS_OFDM_M 0xff00 +#define R92C_SPEC_SIFS_OFDM_S 8 + +/* Bits for R92C_RL. */ +#define R92C_RL_LRL_M 0x003f +#define R92C_RL_LRL_S 0 +#define R92C_RL_SRL_M 0x3f00 +#define R92C_RL_SRL_S 8 + +/* Size of R92C_DARFRC. */ +#define R92C_DARFRC_SIZE 8 + +/* Bits for R92C_RRSR. */ +#define R92C_RRSR_RATE_BITMAP_M 0x000fffff +#define R92C_RRSR_RATE_BITMAP_S 0 +#define R92C_RRSR_RATE_CCK_ONLY_1M 0xffff1 +#define R92C_RRSR_RATE_ALL 0xfffff +#define R92C_RRSR_RSC_LOWSUBCHNL 0x00200000 +#define R92C_RRSR_RSC_UPSUBCHNL 0x00400000 +#define R92C_RRSR_SHORT 0x00800000 + +/* Bits for R92C_EDCA_XX_PARAM. */ +#define R92C_EDCA_PARAM_AIFS_M 0x000000ff +#define R92C_EDCA_PARAM_AIFS_S 0 +#define R92C_EDCA_PARAM_ECWMIN_M 0x00000f00 +#define R92C_EDCA_PARAM_ECWMIN_S 8 +#define R92C_EDCA_PARAM_ECWMAX_M 0x0000f000 +#define R92C_EDCA_PARAM_ECWMAX_S 12 +#define R92C_EDCA_PARAM_TXOP_M 0xffff0000 +#define R92C_EDCA_PARAM_TXOP_S 16 + +/* Bits for R92C_HWSEQ_CTRL / R92C_TXPAUSE. */ +#define R92C_TX_QUEUE_VO 0x01 +#define R92C_TX_QUEUE_VI 0x02 +#define R92C_TX_QUEUE_BE 0x04 +#define R92C_TX_QUEUE_BK 0x08 +#define R92C_TX_QUEUE_MGT 0x10 +#define R92C_TX_QUEUE_HIGH 0x20 +#define R92C_TX_QUEUE_BCN 0x40 + +/* Shortcuts. */ +#define R92C_TX_QUEUE_AC \ + (R92C_TX_QUEUE_VO | R92C_TX_QUEUE_VI | \ + R92C_TX_QUEUE_BE | R92C_TX_QUEUE_BK) + +#define R92C_TX_QUEUE_ALL \ + (R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | \ + R92C_TX_QUEUE_HIGH | R92C_TX_QUEUE_BCN | 0x80) /* XXX */ + +/* Bits for R92C_BCN_CTRL. */ +#define R92C_BCN_CTRL_EN_MBSSID 0x02 +#define R92C_BCN_CTRL_TXBCN_RPT 0x04 +#define R92C_BCN_CTRL_EN_BCN 0x08 +#define R92C_BCN_CTRL_DIS_TSF_UDT0 0x10 + +/* Bits for R92C_DUAL_TSF_RST. */ +#define R92C_DUAL_TSF_RESET(id) (0x01 << (id)) +#define R92C_DUAL_TSF_RST_TXOK 0x20 + +/* Bits for R92C_ACMHWCTRL. */ +#define R92C_ACMHWCTRL_EN 0x01 +#define R92C_ACMHWCTRL_BE 0x02 +#define R92C_ACMHWCTRL_VI 0x04 +#define R92C_ACMHWCTRL_VO 0x08 +#define R92C_ACMHWCTRL_ACM_MASK 0x0f + +/* Bits for R92C_APSD_CTRL. */ +#define R92C_APSD_CTRL_OFF 0x40 +#define R92C_APSD_CTRL_OFF_STATUS 0x80 + +/* Bits for R92C_BWOPMODE. */ +#define R92C_BWOPMODE_11J 0x01 +#define R92C_BWOPMODE_5G 0x02 +#define R92C_BWOPMODE_20MHZ 0x04 + +/* Bits for R92C_TCR. */ +#define R92C_TCR_TSFRST 0x00000001 +#define R92C_TCR_DIS_GCLK 0x00000002 +#define R92C_TCR_PAD_SEL 0x00000004 +#define R92C_TCR_PWR_ST 0x00000040 +#define R92C_TCR_PWRBIT_OW_EN 0x00000080 +#define R92C_TCR_ACRC 0x00000100 +#define R92C_TCR_CFENDFORM 0x00000200 +#define R92C_TCR_ICV 0x00000400 + +/* Bits for R92C_RCR. */ +#define R92C_RCR_AAP 0x00000001 +#define R92C_RCR_APM 0x00000002 +#define R92C_RCR_AM 0x00000004 +#define R92C_RCR_AB 0x00000008 +#define R92C_RCR_ADD3 0x00000010 +#define R92C_RCR_APWRMGT 0x00000020 +#define R92C_RCR_CBSSID_DATA 0x00000040 +#define R92C_RCR_CBSSID_BCN 0x00000080 +#define R92C_RCR_ACRC32 0x00000100 +#define R92C_RCR_AICV 0x00000200 +#define R92C_RCR_ADF 0x00000800 +#define R92C_RCR_ACF 0x00001000 +#define R92C_RCR_AMF 0x00002000 +#define R92C_RCR_HTC_LOC_CTRL 0x00004000 +#define R92C_RCR_MFBEN 0x00400000 +#define R92C_RCR_LSIGEN 0x00800000 +#define R92C_RCR_ENMBID 0x01000000 +#define R92C_RCR_APP_BA_SSN 0x08000000 +#define R92C_RCR_APP_PHYSTS 0x10000000 +#define R92C_RCR_APP_ICV 0x20000000 +#define R92C_RCR_APP_MIC 0x40000000 +#define R92C_RCR_APPFCS 0x80000000 + +/* Bits for R92C_RX_DRVINFO_SZ. */ +#define R92C_RX_DRVINFO_SZ_DEF 4 /* XXX other values will not work */ + +/* Bits for R92C_WMAC_TRXPTCL_CTL. */ +#define R92C_WMAC_TRXPTCL_SHPRE 0x00020000 + +/* Bits for R92C_CAMCMD. */ +#define R92C_CAMCMD_ADDR_M 0x0000ffff +#define R92C_CAMCMD_ADDR_S 0 +#define R92C_CAMCMD_WRITE 0x00010000 +#define R92C_CAMCMD_CLR 0x40000000 +#define R92C_CAMCMD_POLLING 0x80000000 + + +/* + * CAM entries. + */ +#define R92C_CAM_CTL0(entry) ((entry) * 8 + 0) +#define R92C_CAM_CTL1(entry) ((entry) * 8 + 1) +#define R92C_CAM_KEY(entry, i) ((entry) * 8 + 2 + (i)) +#define R92C_CAM_CTL6(entry) ((entry) * 8 + 6) +#define R92C_CAM_CTL7(entry) ((entry) * 8 + 7) + +/* Bits for R92C_CAM_CTL0(i). */ +#define R92C_CAM_KEYID_M 0x00000003 +#define R92C_CAM_KEYID_S 0 +#define R92C_CAM_ALGO_M 0x0000001c +#define R92C_CAM_ALGO_S 2 +#define R92C_CAM_ALGO_NONE 0 +#define R92C_CAM_ALGO_WEP40 1 +#define R92C_CAM_ALGO_TKIP 2 +#define R92C_CAM_ALGO_AES 4 +#define R92C_CAM_ALGO_WEP104 5 +#define R92C_CAM_VALID 0x00008000 +#define R92C_CAM_MACLO_M 0xffff0000 +#define R92C_CAM_MACLO_S 16 + +/* Bits for R92C_SECCFG. */ +#define R92C_SECCFG_TXUCKEY_DEF 0x0001 +#define R92C_SECCFG_RXUCKEY_DEF 0x0002 +#define R92C_SECCFG_TXENC_ENA 0x0004 +#define R92C_SECCFG_RXDEC_ENA 0x0008 +#define R92C_SECCFG_CMP_A2 0x0010 +#define R92C_SECCFG_MC_SRCH_DIS 0x0020 +#define R92C_SECCFG_TXBCKEY_DEF 0x0040 +#define R92C_SECCFG_RXBCKEY_DEF 0x0080 + +/* Bits for R92C_RXFLTMAP*. */ +#define R92C_RXFLTMAP_SUBTYPE(subtype) \ + (1 << ((subtype) >> IEEE80211_FC0_SUBTYPE_SHIFT)) + + +/* + * Baseband registers. + */ +#define R92C_FPGA0_RFMOD 0x800 +#define R92C_FPGA0_TXINFO 0x804 +#define R92C_HSSI_PARAM1(chain) (0x820 + (chain) * 8) +#define R92C_HSSI_PARAM2(chain) (0x824 + (chain) * 8) +#define R92C_TXAGC_RATE18_06(i) (((i) == 0) ? 0xe00 : 0x830) +#define R92C_TXAGC_RATE54_24(i) (((i) == 0) ? 0xe04 : 0x834) +#define R92C_TXAGC_A_CCK1_MCS32 0xe08 +#define R92C_TXAGC_B_CCK1_55_MCS32 0x838 +#define R92C_TXAGC_B_CCK11_A_CCK2_11 0x86c +#define R92C_TXAGC_MCS03_MCS00(i) (((i) == 0) ? 0xe10 : 0x83c) +#define R92C_TXAGC_MCS07_MCS04(i) (((i) == 0) ? 0xe14 : 0x848) +#define R92C_TXAGC_MCS11_MCS08(i) (((i) == 0) ? 0xe18 : 0x84c) +#define R92C_TXAGC_MCS15_MCS12(i) (((i) == 0) ? 0xe1c : 0x868) +#define R92C_LSSI_PARAM(chain) (0x840 + (chain) * 4) +#define R92C_FPGA0_RFIFACEOE(chain) (0x860 + (chain) * 4) +#define R92C_FPGA0_RFIFACESW(idx) (0x870 + (idx) * 4) +#define R92C_FPGA0_RFPARAM(idx) (0x878 + (idx) * 4) +#define R92C_FPGA0_ANAPARAM2 0x884 +#define R92C_LSSI_READBACK(chain) (0x8a0 + (chain) * 4) +#define R92C_HSPI_READBACK(chain) (0x8b8 + (chain) * 4) +#define R92C_FPGA1_RFMOD 0x900 +#define R92C_FPGA1_TXINFO 0x90c +#define R92C_CCK0_SYSTEM 0xa00 +#define R92C_CCK0_AFESETTING 0xa04 +#define R92C_OFDM0_TRXPATHENA 0xc04 +#define R92C_OFDM0_TRMUXPAR 0xc08 +#define R92C_OFDM0_RXIQIMBALANCE(chain) (0xc14 + (chain) * 8) +#define R92C_OFDM0_ECCATHRESHOLD 0xc4c +#define R92C_OFDM0_AGCCORE1(chain) (0xc50 + (chain) * 8) +#define R92C_OFDM0_AGCPARAM1 0xc70 +#define R92C_OFDM0_AGCRSSITABLE 0xc78 +#define R92C_OFDM0_TXIQIMBALANCE(chain) (0xc80 + (chain) * 8) +#define R92C_OFDM0_TXAFE(chain) (0xc94 + (chain) * 8) +#define R92C_OFDM0_RXIQEXTANTA 0xca0 +#define R92C_OFDM1_LSTF 0xd00 + +/* Bits for R92C_FPGA[01]_RFMOD. */ +#define R92C_RFMOD_40MHZ 0x00000001 +#define R92C_RFMOD_JAPAN 0x00000002 +#define R92C_RFMOD_CCK_TXSC 0x00000030 +#define R92C_RFMOD_CCK_EN 0x01000000 +#define R92C_RFMOD_OFDM_EN 0x02000000 + +/* Bits for R92C_HSSI_PARAM1(i). */ +#define R92C_HSSI_PARAM1_PI 0x00000100 + +/* Bits for R92C_HSSI_PARAM2(i). */ +#define R92C_HSSI_PARAM2_CCK_HIPWR 0x00000200 +#define R92C_HSSI_PARAM2_ADDR_LENGTH 0x00000400 +#define R92C_HSSI_PARAM2_DATA_LENGTH 0x00000800 +#define R92C_HSSI_PARAM2_READ_ADDR_M 0x7f800000 +#define R92C_HSSI_PARAM2_READ_ADDR_S 23 +#define R92C_HSSI_PARAM2_READ_EDGE 0x80000000 + +/* Bits for R92C_TXAGC_A_CCK1_MCS32. */ +#define R92C_TXAGC_A_CCK1_M 0x0000ff00 +#define R92C_TXAGC_A_CCK1_S 8 + +/* Bits for R92C_TXAGC_B_CCK11_A_CCK2_11. */ +#define R92C_TXAGC_B_CCK11_M 0x000000ff +#define R92C_TXAGC_B_CCK11_S 0 +#define R92C_TXAGC_A_CCK2_M 0x0000ff00 +#define R92C_TXAGC_A_CCK2_S 8 +#define R92C_TXAGC_A_CCK55_M 0x00ff0000 +#define R92C_TXAGC_A_CCK55_S 16 +#define R92C_TXAGC_A_CCK11_M 0xff000000 +#define R92C_TXAGC_A_CCK11_S 24 + +/* Bits for R92C_TXAGC_B_CCK1_55_MCS32. */ +#define R92C_TXAGC_B_CCK1_M 0x0000ff00 +#define R92C_TXAGC_B_CCK1_S 8 +#define R92C_TXAGC_B_CCK2_M 0x00ff0000 +#define R92C_TXAGC_B_CCK2_S 16 +#define R92C_TXAGC_B_CCK55_M 0xff000000 +#define R92C_TXAGC_B_CCK55_S 24 + +/* Bits for R92C_TXAGC_RATE18_06(x). */ +#define R92C_TXAGC_RATE06_M 0x000000ff +#define R92C_TXAGC_RATE06_S 0 +#define R92C_TXAGC_RATE09_M 0x0000ff00 +#define R92C_TXAGC_RATE09_S 8 +#define R92C_TXAGC_RATE12_M 0x00ff0000 +#define R92C_TXAGC_RATE12_S 16 +#define R92C_TXAGC_RATE18_M 0xff000000 +#define R92C_TXAGC_RATE18_S 24 + +/* Bits for R92C_TXAGC_RATE54_24(x). */ +#define R92C_TXAGC_RATE24_M 0x000000ff +#define R92C_TXAGC_RATE24_S 0 +#define R92C_TXAGC_RATE36_M 0x0000ff00 +#define R92C_TXAGC_RATE36_S 8 +#define R92C_TXAGC_RATE48_M 0x00ff0000 +#define R92C_TXAGC_RATE48_S 16 +#define R92C_TXAGC_RATE54_M 0xff000000 +#define R92C_TXAGC_RATE54_S 24 + +/* Bits for R92C_TXAGC_MCS03_MCS00(x). */ +#define R92C_TXAGC_MCS00_M 0x000000ff +#define R92C_TXAGC_MCS00_S 0 +#define R92C_TXAGC_MCS01_M 0x0000ff00 +#define R92C_TXAGC_MCS01_S 8 +#define R92C_TXAGC_MCS02_M 0x00ff0000 +#define R92C_TXAGC_MCS02_S 16 +#define R92C_TXAGC_MCS03_M 0xff000000 +#define R92C_TXAGC_MCS03_S 24 + +/* Bits for R92C_TXAGC_MCS07_MCS04(x). */ +#define R92C_TXAGC_MCS04_M 0x000000ff +#define R92C_TXAGC_MCS04_S 0 +#define R92C_TXAGC_MCS05_M 0x0000ff00 +#define R92C_TXAGC_MCS05_S 8 +#define R92C_TXAGC_MCS06_M 0x00ff0000 +#define R92C_TXAGC_MCS06_S 16 +#define R92C_TXAGC_MCS07_M 0xff000000 +#define R92C_TXAGC_MCS07_S 24 + +/* Bits for R92C_TXAGC_MCS11_MCS08(x). */ +#define R92C_TXAGC_MCS08_M 0x000000ff +#define R92C_TXAGC_MCS08_S 0 +#define R92C_TXAGC_MCS09_M 0x0000ff00 +#define R92C_TXAGC_MCS09_S 8 +#define R92C_TXAGC_MCS10_M 0x00ff0000 +#define R92C_TXAGC_MCS10_S 16 +#define R92C_TXAGC_MCS11_M 0xff000000 +#define R92C_TXAGC_MCS11_S 24 + +/* Bits for R92C_TXAGC_MCS15_MCS12(x). */ +#define R92C_TXAGC_MCS12_M 0x000000ff +#define R92C_TXAGC_MCS12_S 0 +#define R92C_TXAGC_MCS13_M 0x0000ff00 +#define R92C_TXAGC_MCS13_S 8 +#define R92C_TXAGC_MCS14_M 0x00ff0000 +#define R92C_TXAGC_MCS14_S 16 +#define R92C_TXAGC_MCS15_M 0xff000000 +#define R92C_TXAGC_MCS15_S 24 + +/* Bits for R92C_LSSI_PARAM(i). */ +#define R92C_LSSI_PARAM_DATA_M 0x000fffff +#define R92C_LSSI_PARAM_DATA_S 0 +#define R92C_LSSI_PARAM_ADDR_M 0x03f00000 +#define R92C_LSSI_PARAM_ADDR_S 20 + +/* Bits for R92C_FPGA0_RFIFACEOE(0). */ +#define R92C_FPGA0_RFIFACEOE0_ANT_M 0x00000300 +#define R92C_FPGA0_RFIFACEOE0_ANT_S 8 + +/* Bits for R92C_FPGA0_ANAPARAM2. */ +#define R92C_FPGA0_ANAPARAM2_CBW20 0x00000400 + +/* Bits for R92C_LSSI_READBACK(i). */ +#define R92C_LSSI_READBACK_DATA_M 0x000fffff +#define R92C_LSSI_READBACK_DATA_S 0 + +/* Bits for R92C_OFDM0_AGCCORE1(i). */ +#define R92C_OFDM0_AGCCORE1_GAIN_M 0x0000007f +#define R92C_OFDM0_AGCCORE1_GAIN_S 0 + + +/* + * RF (6052) registers. + */ +#define R92C_RF_AC 0x00 +#define R92C_RF_IQADJ_G(i) (0x01 + (i)) +#define R92C_RF_POW_TRSW 0x05 +#define R92C_RF_GAIN_RX 0x06 +#define R92C_RF_GAIN_TX 0x07 +#define R92C_RF_TXM_IDAC 0x08 +#define R92C_RF_BS_IQGEN 0x0f +#define R92C_RF_MODE1 0x10 +#define R92C_RF_MODE2 0x11 +#define R92C_RF_RX_AGC_HP 0x12 +#define R92C_RF_TX_AGC 0x13 +#define R92C_RF_BIAS 0x14 +#define R92C_RF_IPA 0x15 +#define R92C_RF_POW_ABILITY 0x17 +#define R92C_RF_CHNLBW 0x18 +#define R92C_RF_RX_G1 0x1a +#define R92C_RF_RX_G2 0x1b +#define R92C_RF_RX_BB2 0x1c +#define R92C_RF_RX_BB1 0x1d +#define R92C_RF_RCK1 0x1e +#define R92C_RF_RCK2 0x1f +#define R92C_RF_TX_G(i) (0x20 + (i)) +#define R92C_RF_TX_BB1 0x23 +#define R92C_RF_T_METER 0x24 +#define R92C_RF_SYN_G(i) (0x25 + (i)) +#define R92C_RF_RCK_OS 0x30 +#define R92C_RF_TXPA_G(i) (0x31 + (i)) + +/* Bits for R92C_RF_AC. */ +#define R92C_RF_AC_MODE_M 0x70000 +#define R92C_RF_AC_MODE_S 16 +#define R92C_RF_AC_MODE_STANDBY 1 + +/* Bits for R92C_RF_CHNLBW. */ +#define R92C_RF_CHNLBW_CHNL_M 0x003ff +#define R92C_RF_CHNLBW_CHNL_S 0 +#define R92C_RF_CHNLBW_BW20 0x00400 +#define R92C_RF_CHNLBW_LCSTART 0x08000 + +/* Bits for R92C_RF_T_METER. */ +#define R92C_RF_T_METER_START 0x60 +#define R92C_RF_T_METER_VAL_M 0x1f +#define R92C_RF_T_METER_VAL_S 0 + +#endif /* R92C_REG_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c new file mode 100644 index 00000000..22507e6c --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rf.c @@ -0,0 +1,95 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +uint32_t +r92c_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg[R92C_MAX_CHAINS], val; + + reg[0] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)); + if (chain != 0) + reg[chain] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(chain)); + + rtwn_bb_write(sc, R92C_HSSI_PARAM2(0), + reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE); + rtwn_delay(sc, rs->rf_read_delay[0]); + + rtwn_bb_write(sc, R92C_HSSI_PARAM2(chain), + RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) | + R92C_HSSI_PARAM2_READ_EDGE); + rtwn_delay(sc, rs->rf_read_delay[1]); + + rtwn_bb_write(sc, R92C_HSSI_PARAM2(0), + reg[0] | R92C_HSSI_PARAM2_READ_EDGE); + rtwn_delay(sc, rs->rf_read_delay[2]); + + if (rtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI) + val = rtwn_bb_read(sc, R92C_HSPI_READBACK(chain)); + else + val = rtwn_bb_read(sc, R92C_LSSI_READBACK(chain)); + return (MS(val, R92C_LSSI_READBACK_DATA)); +} + +void +r92c_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, + uint32_t val) +{ + rtwn_bb_write(sc, R92C_LSSI_PARAM(chain), + SM(R92C_LSSI_PARAM_ADDR, addr) | + SM(R92C_LSSI_PARAM_DATA, val)); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c new file mode 100644 index 00000000..1c1595fc --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom.c @@ -0,0 +1,141 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +static void +r92c_set_chains(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + if (rs->chip & R92C_CHIP_92C) { + sc->ntxchains = (rs->chip & R92C_CHIP_92C_1T2R) ? 1 : 2; + sc->nrxchains = 2; + } else { + sc->ntxchains = 1; + sc->nrxchains = 1; + } +} + +void +r92c_efuse_postread(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + /* XXX Weird but this is what the vendor driver does. */ + sc->next_rom_addr = 0x1fa; + (void) rtwn_efuse_read_next(sc, &rs->pa_setting); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: PA setting=0x%x\n", __func__, + rs->pa_setting); +} + +void +r92c_parse_rom(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r92c_softc *rs = sc->sc_priv; + struct rtwn_r92c_txpwr *rt = rs->rs_txpwr; + struct r92c_rom *rom = (struct r92c_rom *)buf; + int i, j; + + rs->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); + rs->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type=%d\n", + __func__, rs->regulatory); + + /* Need to be set before postinit() (but after preinit()). */ + rtwn_r92c_set_name(sc); + r92c_set_chains(sc); + + for (j = 0; j < R92C_GROUP_2G; j++) { + for (i = 0; i < sc->ntxchains; i++) { + rt->cck_tx_pwr[i][j] = rom->cck_tx_pwr[i][j]; + rt->ht40_1s_tx_pwr[i][j] = rom->ht40_1s_tx_pwr[i][j]; + } + + rt->ht40_2s_tx_pwr_diff[0][j] = + MS(rom->ht40_2s_tx_pwr_diff[j], LOW_PART); + rt->ht20_tx_pwr_diff[0][j] = + RTWN_SIGN4TO8(MS(rom->ht20_tx_pwr_diff[j], + LOW_PART)); + rt->ofdm_tx_pwr_diff[0][j] = + MS(rom->ofdm_tx_pwr_diff[j], LOW_PART); + rt->ht40_max_pwr[0][j] = + MS(rom->ht40_max_pwr[j], LOW_PART); + rt->ht20_max_pwr[0][j] = + MS(rom->ht20_max_pwr[j], LOW_PART); + + if (sc->ntxchains > 1) { + rt->ht40_2s_tx_pwr_diff[1][j] = + MS(rom->ht40_2s_tx_pwr_diff[j], HIGH_PART); + rt->ht20_tx_pwr_diff[1][j] = + RTWN_SIGN4TO8(MS(rom->ht20_tx_pwr_diff[j], + HIGH_PART)); + rt->ofdm_tx_pwr_diff[1][j] = + MS(rom->ofdm_tx_pwr_diff[j], HIGH_PART); + rt->ht40_max_pwr[1][j] = + MS(rom->ht40_max_pwr[j], HIGH_PART); + rt->ht20_max_pwr[1][j] = + MS(rom->ht20_max_pwr[j], HIGH_PART); + } + } + + sc->thermal_meter = MS(rom->thermal_meter, R92C_ROM_THERMAL_METER); + if (sc->thermal_meter == R92C_ROM_THERMAL_METER_M) + sc->thermal_meter = 0xff; + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h new file mode 100644 index 00000000..35fc42df --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_ROM_DEFS_H +#define R92C_ROM_DEFS_H + +#define R92C_MAX_CHAINS 2 +#define R92C_GROUP_2G 3 + +#define R92C_EFUSE_MAX_LEN 512 +#define R92C_EFUSE_MAP_LEN 128 + +/* + * Some generic rom parsing macros. + */ +#define RTWN_GET_ROM_VAR(var, def) (((var) != 0xff) ? (var) : (def)) +#define RTWN_SIGN4TO8(val) (((val) & 0x08) ? (val) | 0xf0 : (val)) + +#define LOW_PART_M 0x0f +#define LOW_PART_S 0 +#define HIGH_PART_M 0xf0 +#define HIGH_PART_S 4 + +/* Bits for rf_board_opt (rf_opt1) field. */ +#define R92C_ROM_RF1_REGULATORY_M 0x07 +#define R92C_ROM_RF1_REGULATORY_S 0 +#define R92C_ROM_RF1_BOARD_TYPE_M 0xe0 +#define R92C_ROM_RF1_BOARD_TYPE_S 5 + +/* Generic board types. */ +#define R92C_BOARD_TYPE_DONGLE 0 +#define R92C_BOARD_TYPE_HIGHPA 1 +#define R92C_BOARD_TYPE_MINICARD 2 +#define R92C_BOARD_TYPE_SOLO 3 +#define R92C_BOARD_TYPE_COMBO 4 + +/* Bits for channel_plan field. */ +#define R92C_CHANNEL_PLAN_BY_HW 0x80 + +#endif /* R92C_ROM_DEFS_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h new file mode 100644 index 00000000..304324e6 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_ROM_IMAGE_H +#define R92C_ROM_IMAGE_H + +#include + +/* + * RTL8192CU ROM image. + */ +struct r92c_rom { + uint16_t id; /* 0x8192 */ + uint8_t reserved1[5]; + uint8_t dbg_sel; + uint16_t reserved2; + uint16_t vid; + uint16_t pid; + uint8_t usb_opt; + uint8_t ep_setting; + uint16_t reserved3; + uint8_t usb_phy; + uint8_t reserved4[3]; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint8_t string[61]; /* "Realtek" */ + uint8_t subcustomer_id; + uint8_t cck_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + uint8_t ht40_1s_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + uint8_t ht40_2s_tx_pwr_diff[R92C_GROUP_2G]; + uint8_t ht20_tx_pwr_diff[R92C_GROUP_2G]; + uint8_t ofdm_tx_pwr_diff[R92C_GROUP_2G]; + uint8_t ht40_max_pwr[R92C_GROUP_2G]; + uint8_t ht20_max_pwr[R92C_GROUP_2G]; + uint8_t xtal_calib; + uint8_t tssi[R92C_MAX_CHAINS]; + uint8_t thermal_meter; +#define R92C_ROM_THERMAL_METER_M 0x1f +#define R92C_ROM_THERMAL_METER_S 0 + + uint8_t rf_opt1; + uint8_t rf_opt2; + uint8_t rf_opt3; + uint8_t rf_opt4; + uint8_t channel_plan; +#define R92C_CHANNEL_PLAN_BY_HW 0x80 + + uint8_t version; + uint8_t customer_id; +} __packed; + +_Static_assert(sizeof(struct r92c_rom) == R92C_EFUSE_MAP_LEN, + "R92C_EFUSE_MAP_LEN must be equal to sizeof(struct r92c_rom)!"); + +#endif /* R92C_ROM_IMAGE_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c new file mode 100644 index 00000000..b77c76f6 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c @@ -0,0 +1,104 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + + +int8_t +r92c_get_rssi_cck(struct rtwn_softc *sc, void *physt) +{ + static const int8_t cckoff[] = { 16, -12, -26, -46 }; + struct r92c_rx_cck *cck = (struct r92c_rx_cck *)physt; + uint8_t rpt; + int8_t rssi; + + if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) { + rpt = (cck->agc_rpt >> 5) & 0x03; + rssi = (cck->agc_rpt & 0x1f) << 1; + } else { + rpt = (cck->agc_rpt >> 6) & 0x03; + rssi = cck->agc_rpt & 0x3e; + } + rssi = cckoff[rpt] - rssi; + + return (rssi); +} + +int8_t +r92c_get_rssi_ofdm(struct rtwn_softc *sc, void *physt) +{ + struct r92c_rx_phystat *phy = (struct r92c_rx_phystat *)physt; + int rssi; + + /* Get average RSSI. */ + rssi = ((phy->pwdb_all >> 1) & 0x7f) - 110; + + return (rssi); +} + +uint8_t +r92c_rx_radiotap_flags(const void *buf) +{ + const struct r92c_rx_stat *stat = buf; + uint8_t flags, rate; + + if (!(stat->rxdw3 & htole32(R92C_RXDW3_SPLCP))) + return (0); + + rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE); + if (RTWN_RATE_IS_CCK(rate)) + flags = IEEE80211_RADIOTAP_F_SHORTPRE; + else + flags = IEEE80211_RADIOTAP_F_SHORTGI; + return (flags); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h new file mode 100644 index 00000000..7fec70be --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_RX_DESC_H +#define R92C_RX_DESC_H + +/* Rx MAC descriptor (common parts / USB). */ +struct r92c_rx_stat { + uint32_t rxdw0; +#define R92C_RXDW0_PKTLEN_M 0x00003fff +#define R92C_RXDW0_PKTLEN_S 0 +#define R92C_RXDW0_CRCERR 0x00004000 +#define R92C_RXDW0_ICVERR 0x00008000 +#define R92C_RXDW0_INFOSZ_M 0x000f0000 +#define R92C_RXDW0_INFOSZ_S 16 +#define R92C_RXDW0_CIPHER_M 0x00700000 +#define R92C_RXDW0_CIPHER_S 20 +#define R92C_RXDW0_QOS 0x00800000 +#define R92C_RXDW0_SHIFT_M 0x03000000 +#define R92C_RXDW0_SHIFT_S 24 +#define R92C_RXDW0_PHYST 0x04000000 +#define R92C_RXDW0_SWDEC 0x08000000 +#define R92C_RXDW0_LS 0x10000000 +#define R92C_RXDW0_FS 0x20000000 +#define R92C_RXDW0_EOR 0x40000000 +#define R92C_RXDW0_OWN 0x80000000 + + uint32_t rxdw1; +#define R92C_RXDW1_MACID_M 0x0000001f +#define R92C_RXDW1_MACID_S 0 +#define R92C_RXDW1_MC 0x40000000 +#define R92C_RXDW1_BC 0x80000000 + + uint32_t rxdw2; + uint32_t rxdw3; +#define R92C_RXDW3_RATE_M 0x0000003f +#define R92C_RXDW3_RATE_S 0 +#define R92C_RXDW3_HT 0x00000040 +#define R92C_RXDW3_SPLCP 0x00000100 +#define R92C_RXDW3_HT40 0x00000200 +#define R92C_RXDW3_HTC 0x00000400 + + uint32_t rxdw4; + uint32_t tsf_low; +} __packed __attribute__((aligned(4))); + +/* Rx PHY CCK descriptor. */ +struct r92c_rx_cck { + uint8_t adc_pwdb[4]; + uint8_t sq_rpt; + uint8_t agc_rpt; +} __packed; + +/* Rx PHY descriptor. */ +struct r92c_rx_phystat { + uint8_t trsw_gain[4]; + uint8_t pwdb_all; + uint8_t cfosho[4]; + uint8_t cfotail[4]; + uint8_t rxevm[2]; + uint8_t rxsnr[4]; + uint8_t pdsnr[2]; + uint8_t csi_current[2]; + uint8_t csi_target[2]; + uint8_t sigevm; + uint8_t max_ex_pwr; + uint8_t phy_byte28; +#define R92C_PHY_BYTE28_ANTSEL 0x01 +#define R92C_PHY_BYTE28_ANTSEL_B 0x02 +#define R92C_PHY_BYTE28_ANT_TRAIN_EN 0x04 +#define R92C_PHY_BYTE28_IDLE_LONG 0x08 +#define R92C_PHY_BYTE28_RXSC_M 0x30 +#define R92C_PHY_BYTE28_RXSC_S 4 +#define R92C_PHY_BYTE28_SGI_EN 0x40 +#define R92C_PHY_BYTE28_EX_INTF_FLG 0x80 +} __packed; + +#endif /* R92C_RX_DESC_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c new file mode 100644 index 00000000..0e3c408d --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c @@ -0,0 +1,438 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + + +static int +r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + if (IEEE80211_IS_CHAN_HT40U(c)) + return (R92C_TXDW4_SCO_SCA); + else + return (R92C_TXDW4_SCO_SCB); +} + +static void +r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + if (ni->ni_chan != IEEE80211_CHAN_ANYC && + IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { + int extc_offset; + + extc_offset = r92c_tx_get_sco(sc, ni->ni_chan); + txd->txdw4 |= htole32(R92C_TXDW4_DATA_BW40); + txd->txdw4 |= htole32(SM(R92C_TXDW4_DATA_SCO, extc_offset)); + } +} + +static void +r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, + enum ieee80211_protmode mode, uint8_t ridx) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint8_t rate; + + switch (mode) { + case IEEE80211_PROT_CTSONLY: + txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF); + break; + case IEEE80211_PROT_RTSCTS: + txd->txdw4 |= htole32(R92C_TXDW4_RTSEN); + break; + default: + break; + } + + if (mode == IEEE80211_PROT_CTSONLY || + mode == IEEE80211_PROT_RTSCTS) { + if (ridx >= RTWN_RIDX_MCS(0)) + rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); + else + rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); + ridx = rate2ridx(rate); + + txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx)); + /* RTS rate fallback limit (max). */ + txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf)); + + if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT); + } +} + +static void +r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd, + struct ieee80211_node *ni, int ismcast) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_channel *chan; + enum ieee80211_phymode mode; + uint8_t raid; + + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? + ni->ni_chan : ic->ic_curchan; + mode = ieee80211_chan2mode(chan); + + /* NB: group addressed frames are done at 11bg rates for now */ + if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { + switch (mode) { + case IEEE80211_MODE_11B: + case IEEE80211_MODE_11G: + break; + case IEEE80211_MODE_11NG: + mode = IEEE80211_MODE_11G; + break; + default: + device_printf(sc->sc_dev, "unknown mode(1) %d!\n", + ic->ic_curmode); + return; + } + } + + switch (mode) { + case IEEE80211_MODE_11B: + raid = R92C_RAID_11B; + break; + case IEEE80211_MODE_11G: + if (vap->iv_flags & IEEE80211_F_PUREG) + raid = R92C_RAID_11G; + else + raid = R92C_RAID_11BG; + break; + case IEEE80211_MODE_11NG: + if (vap->iv_flags_ht & IEEE80211_FHT_PUREN) + raid = R92C_RAID_11N; + else + raid = R92C_RAID_11BGN; + break; + default: + device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); + return; + } + + txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid)); +} + +/* XXX move to device-independent layer */ +static void +r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + struct ieee80211vap *vap = ni->ni_vap; + + if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) + txd->txdw5 |= htole32(R92C_TXDW5_SGI); + else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ + IEEE80211_IS_CHAN_HT40(ni->ni_chan) && + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && + (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) + txd->txdw5 |= htole32(R92C_TXDW5_SGI); +} + +void +r92c_tx_enable_ampdu(void *buf, int enable) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + if (enable) + txd->txdw1 |= htole32(R92C_TXDW1_AGGEN); + else + txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); +} + +void +r92c_tx_setup_hwseq(void *buf) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); +} + +void +r92c_tx_setup_macid(void *buf, int id) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id)); +} + +void +r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, void *buf, uint8_t ridx, int maxretry) +{ +#ifndef RTWN_WITHOUT_UCODE + struct r92c_softc *rs = sc->sc_priv; +#endif + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_frame *wh; + struct r92c_tx_desc *txd; + enum ieee80211_protmode prot; + uint8_t type, tid, qos, qsel; + int hasqos, ismcast, macid; + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + hasqos = IEEE80211_QOS_HAS_SEQ(wh); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + + /* Select TX ring for this frame. */ + if (hasqos) { + qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; + tid = qos & IEEE80211_QOS_TID; + } else { + qos = 0; + tid = 0; + } + + /* Fill Tx descriptor. */ + txd = (struct r92c_tx_desc *)buf; + txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; + if (ismcast) + txd->flags0 |= R92C_FLAGS0_BMCAST; + + if (!ismcast) { + /* Unicast frame, check if an ACK is expected. */ + if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != + IEEE80211_QOS_ACKPOLICY_NOACK) { + txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); + txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, + maxretry)); + } + + struct rtwn_node *un = RTWN_NODE(ni); + macid = un->id; + + if (type == IEEE80211_FC0_TYPE_DATA) { + qsel = tid % RTWN_MAX_TID; + + rtwn_r92c_tx_enable_ampdu(sc, buf, + (m->m_flags & M_AMPDU_MPDU) != 0); + if (m->m_flags & M_AMPDU_MPDU) { + txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN, + vap->iv_ampdu_density)); + txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG, + 0x1f)); /* XXX */ + } + if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { + txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); + sc->sc_tx_n_active++; +#ifndef RTWN_WITHOUT_UCODE + rs->rs_c2h_pending++; +#endif + } + + if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); + + prot = IEEE80211_PROT_NONE; + if (ridx >= RTWN_RIDX_MCS(0)) { + r92c_tx_set_ht40(sc, txd, ni); + r92c_tx_set_sgi(sc, txd, ni); + prot = ic->ic_htprotmode; + } else if (ic->ic_flags & IEEE80211_F_USEPROT) + prot = ic->ic_protmode; + + /* XXX fix last comparison for A-MSDU (in net80211) */ + /* XXX A-MPDU? */ + if (m->m_pkthdr.len + IEEE80211_CRC_LEN > + vap->iv_rtsthreshold && + vap->iv_rtsthreshold != IEEE80211_RTS_MAX) + prot = IEEE80211_PROT_RTSCTS; + + /* NB: checks for ht40 / short bits (set above). */ + if (prot != IEEE80211_PROT_NONE) + r92c_tx_protection(sc, txd, prot, ridx); + } else /* IEEE80211_FC0_TYPE_MGT */ + qsel = R92C_TXDW1_QSEL_MGNT; + } else { + macid = RTWN_MACID_BC; + qsel = R92C_TXDW1_QSEL_MGNT; + } + + txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel)); + + rtwn_r92c_tx_setup_macid(sc, txd, macid); + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); + /* Data rate fallback limit (max). */ + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); + txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); + r92c_tx_raid(sc, txd, ni, ismcast); + + /* Force this rate if needed. */ + if (sc->sc_ratectl != RTWN_RATECTL_FW) + txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); + + if (!hasqos) { + /* Use HW sequence numbering for non-QoS frames. */ + rtwn_r92c_tx_setup_hwseq(sc, txd); + txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); + } else { + uint16_t seqno; + + if (m->m_flags & M_AMPDU_MPDU) { + seqno = ni->ni_txseqs[tid]; + /* NB: clear Fragment Number field. */ + *(uint16_t *)wh->i_seq = 0; + ni->ni_txseqs[tid]++; + } else + seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; + + /* Set sequence number. */ + txd->txdseq = htole16(seqno); + } +} + +void +r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_frame *wh; + struct r92c_tx_desc *txd; + uint8_t ridx; + int ismcast; + + /* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */ + + wh = mtod(m, struct ieee80211_frame *); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + ridx = rate2ridx(params->ibp_rate0); + + /* Fill Tx descriptor. */ + txd = (struct r92c_tx_desc *)buf; + txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; + if (ismcast) + txd->flags0 |= R92C_FLAGS0_BMCAST; + + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { + txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); + txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, + params->ibp_try0)); + } + if (params->ibp_flags & IEEE80211_BPF_RTS) + r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); + if (params->ibp_flags & IEEE80211_BPF_CTS) + r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); + + rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC); + txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); + + /* Set TX rate index. */ + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); + txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); + txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); + r92c_tx_raid(sc, txd, ni, ismcast); + + if (!IEEE80211_QOS_HAS_SEQ(wh)) { + /* Use HW sequence numbering for non-QoS frames. */ + rtwn_r92c_tx_setup_hwseq(sc, txd); + txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); + } else { + /* Set sequence number. */ + txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); + } +} + +void +r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, + int qos, int id) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN; + txd->txdw1 = htole32( + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); + + txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); + txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id)); + if (is11b) { + txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, + RTWN_RIDX_CCK1)); + } else { + txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, + RTWN_RIDX_OFDM6)); + } + + if (!qos) { + rtwn_r92c_tx_setup_hwseq(sc, txd); + txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id)); + } +} + +uint8_t +r92c_tx_radiotap_flags(const void *buf) +{ + const struct r92c_tx_desc *txd = buf; + uint8_t flags; + + flags = 0; + if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE)) + flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + if (txd->txdw5 & htole32(R92C_TXDW5_SGI)) + flags |= IEEE80211_RADIOTAP_F_SHORTGI; + return (flags); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h new file mode 100644 index 00000000..037ac0e2 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_TX_DESC_H +#define R92C_TX_DESC_H + +/* Tx MAC descriptor (common part). */ +struct r92c_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; +#define R92C_FLAGS0_BMCAST 0x01 +#define R92C_FLAGS0_LSG 0x04 +#define R92C_FLAGS0_FSG 0x08 +#define R92C_FLAGS0_OWN 0x80 + + uint32_t txdw1; +#define R92C_TXDW1_MACID_M 0x0000001f +#define R92C_TXDW1_MACID_S 0 +#define R92C_TXDW1_AGGEN 0x00000020 +#define R92C_TXDW1_AGGBK 0x00000040 + +#define R92C_TXDW1_QSEL_M 0x00001f00 +#define R92C_TXDW1_QSEL_S 8 + +#define R92C_TXDW1_QSEL_BE 0x00 /* or 0x03 */ +#define R92C_TXDW1_QSEL_BK 0x01 /* or 0x02 */ +#define R92C_TXDW1_QSEL_VI 0x04 /* or 0x05 */ +#define R92C_TXDW1_QSEL_VO 0x06 /* or 0x07 */ +#define RTWN_MAX_TID 8 + +#define R92C_TXDW1_QSEL_BEACON 0x10 +#define R92C_TXDW1_QSEL_MGNT 0x12 + +#define R92C_TXDW1_RAID_M 0x000f0000 +#define R92C_TXDW1_RAID_S 16 +#define R92C_TXDW1_CIPHER_M 0x00c00000 +#define R92C_TXDW1_CIPHER_S 22 +#define R92C_TXDW1_CIPHER_NONE 0 +#define R92C_TXDW1_CIPHER_RC4 1 +#define R92C_TXDW1_CIPHER_AES 3 +#define R92C_TXDW1_PKTOFF_M 0x7c000000 +#define R92C_TXDW1_PKTOFF_S 26 + + uint32_t txdw2; +#define R92C_TXDW2_CCX_RPT 0x00080000 +#define R92C_TXDW2_AMPDU_DEN_M 0x00700000 +#define R92C_TXDW2_AMPDU_DEN_S 20 + + uint16_t txdw3; + uint16_t txdseq; + + uint32_t txdw4; +#define R92C_TXDW4_RTSRATE_M 0x0000003f +#define R92C_TXDW4_RTSRATE_S 0 +#define R92C_TXDW4_SEQ_SEL_M 0x00000040 +#define R92C_TXDW4_SEQ_SEL_S 6 +#define R92C_TXDW4_HWSEQ_EN 0x00000080 +#define R92C_TXDW4_DRVRATE 0x00000100 +#define R92C_TXDW4_CTS2SELF 0x00000800 +#define R92C_TXDW4_RTSEN 0x00001000 +#define R92C_TXDW4_HWRTSEN 0x00002000 +#define R92C_TXDW4_PORT_ID_M 0x00004000 +#define R92C_TXDW4_PORT_ID_S 14 +#define R92C_TXDW4_DATA_SCO_M 0x00300000 +#define R92C_TXDW4_DATA_SCO_S 20 +#define R92C_TXDW4_SCO_SCA 1 +#define R92C_TXDW4_SCO_SCB 2 +#define R92C_TXDW4_DATA_SHPRE 0x01000000 +#define R92C_TXDW4_DATA_BW40 0x02000000 +#define R92C_TXDW4_RTS_SHORT 0x04000000 +#define R92C_TXDW4_RTS_BW40 0x08000000 +#define R92C_TXDW4_RTS_SCO_M 0x30000000 +#define R92C_TXDW4_RTS_SCO_S 28 + + uint32_t txdw5; +#define R92C_TXDW5_DATARATE_M 0x0000003f +#define R92C_TXDW5_DATARATE_S 0 +#define R92C_TXDW5_SGI 0x00000040 +#define R92C_TXDW5_DATARATE_FB_LMT_M 0x00001f00 +#define R92C_TXDW5_DATARATE_FB_LMT_S 8 +#define R92C_TXDW5_RTSRATE_FB_LMT_M 0x0001e000 +#define R92C_TXDW5_RTSRATE_FB_LMT_S 13 +#define R92C_TXDW5_RTY_LMT_ENA 0x00020000 +#define R92C_TXDW5_RTY_LMT_M 0x00fc0000 +#define R92C_TXDW5_RTY_LMT_S 18 +#define R92C_TXDW5_AGGNUM_M 0xff000000 +#define R92C_TXDW5_AGGNUM_S 24 + + uint32_t txdw6; +#define R92C_TXDW6_MAX_AGG_M 0x0000f800 +#define R92C_TXDW6_MAX_AGG_S 11 +} __packed __attribute__((aligned(4))); + + +/* Rate adaptation modes. */ +#define R92C_RAID_11BGN 0 +#define R92C_RAID_11GN 1 +#define R92C_RAID_11BN 2 +#define R92C_RAID_11N 3 +#define R92C_RAID_11BG 4 +#define R92C_RAID_11G 5 /* "pure" 11g */ +#define R92C_RAID_11B 6 + +#endif /* R92C_TX_DESC_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h new file mode 100644 index 00000000..c48318d9 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_VAR_H +#define R92C_VAR_H + +#include + +struct r92c_softc { + uint8_t rs_flags; +#define R92C_FLAG_ASSOCIATED 0x01 + + uint8_t chip; +#define R92C_CHIP_92C 0x01 +#define R92C_CHIP_92C_1T2R 0x02 +#define R92C_CHIP_UMC_A_CUT 0x04 + +#ifndef RTWN_WITHOUT_UCODE + struct callout rs_c2h_report; + int rs_c2h_timeout; + int rs_c2h_pending; + int rs_c2h_paused; +#endif +#define R92C_TX_PAUSED_THRESHOLD 20 + + void *rs_txpwr; + const void *rs_txagc; + + uint8_t board_type; + uint8_t regulatory; + uint8_t crystalcap; + uint8_t pa_setting; + + void (*rs_scan_start)(struct ieee80211com *); + void (*rs_scan_end)(struct ieee80211com *); + + void (*rs_set_bw20)(struct rtwn_softc *, uint8_t); + void (*rs_get_txpower)(struct rtwn_softc *, int, + struct ieee80211_channel *, uint16_t[]); + void (*rs_set_gain)(struct rtwn_softc *, uint8_t); + void (*rs_tx_enable_ampdu)(void *, int); + void (*rs_tx_setup_hwseq)(void *); + void (*rs_tx_setup_macid)(void *, int); + void (*rs_set_name)(struct rtwn_softc *); + + int rf_read_delay[3]; + uint32_t rf_chnlbw[R92C_MAX_CHAINS]; +}; +#define R92C_SOFTC(_sc) ((struct r92c_softc *)((_sc)->sc_priv)) + +#define rtwn_r92c_set_bw20(_sc, _chan) \ + ((R92C_SOFTC(_sc)->rs_set_bw20)((_sc), (_chan))) +#define rtwn_r92c_get_txpower(_sc, _chain, _c, _power) \ + ((R92C_SOFTC(_sc)->rs_get_txpower)((_sc), (_chain), (_c), (_power))) +#define rtwn_r92c_set_gain(_sc, _gain) \ + ((R92C_SOFTC(_sc)->rs_set_gain)((_sc), (_gain))) +#define rtwn_r92c_tx_enable_ampdu(_sc, _buf, _enable) \ + ((R92C_SOFTC(_sc)->rs_tx_enable_ampdu)((_buf), (_enable))) +#define rtwn_r92c_tx_setup_hwseq(_sc, _buf) \ + ((R92C_SOFTC(_sc)->rs_tx_setup_hwseq)((_buf))) +#define rtwn_r92c_tx_setup_macid(_sc, _buf, _id) \ + ((R92C_SOFTC(_sc)->rs_tx_setup_macid)((_buf), (_id))) +#define rtwn_r92c_set_name(_sc) \ + ((R92C_SOFTC(_sc)->rs_set_name)((_sc))) + +#endif /* R92C_VAR_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h new file mode 100644 index 00000000..2486d7fa --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTL8192CU_H +#define RTL8192CU_H + +#include + + +/* + * Global definitions. + */ +#define R92CU_PUBQ_NPAGES 231 +#define R92CU_TX_PAGE_COUNT 248 + + +/* + * Function declarations. + */ +/* r92cu_init.c */ +void r92cu_init_bb(struct rtwn_softc *); +int r92cu_power_on(struct rtwn_softc *); +void r92cu_power_off(struct rtwn_softc *); +void r92cu_init_intr(struct rtwn_softc *); +void r92cu_init_tx_agg(struct rtwn_softc *); +void r92cu_init_rx_agg(struct rtwn_softc *); +void r92cu_post_init(struct rtwn_softc *); + +/* r92cu_led.c */ +void r92cu_set_led(struct rtwn_softc *, int, int); + +/* r92cu_rx.c */ +int r92cu_classify_intr(struct rtwn_softc *, void *, int); +int r92cu_align_rx(int, int); + +/* r92cu_tx.c */ +void r92cu_dump_tx_desc(struct rtwn_softc *, const void *); + +#endif /* RTL8192CU_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c new file mode 100644 index 00000000..ce3f7a1a --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c @@ -0,0 +1,247 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + + +static struct rtwn_r92c_txpwr r92c_txpwr; + +void r92cu_attach(struct rtwn_usb_softc *); + +static void +r92cu_postattach(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + struct ieee80211com *ic = &sc->sc_ic; + + if (!(rs->chip & R92C_CHIP_92C) && + rs->board_type == R92C_BOARD_TYPE_HIGHPA) { + sc->agc_prog = &rtl8188ru_agc[0]; + sc->agc_size = nitems(rtl8188ru_agc); + rs->rs_txagc = &rtl8188ru_txagc[0]; + } else { + sc->agc_prog = &rtl8192ce_agc[0]; + sc->agc_size = nitems(rtl8192ce_agc); + rs->rs_txagc = &rtl8192cu_txagc[0]; + } + + if ((rs->chip & (R92C_CHIP_UMC_A_CUT | R92C_CHIP_92C)) == + R92C_CHIP_UMC_A_CUT) { + sc->fwname = "rtwn-rtl8192cfwU"; + } else { + sc->fwname = "rtwn-rtl8192cfwT"; + } + sc->fwsig = 0x88c; + + rs->rs_scan_start = ic->ic_scan_start; + ic->ic_scan_start = r92c_scan_start; + rs->rs_scan_end = ic->ic_scan_end; + ic->ic_scan_end = r92c_scan_end; +} + +static void +r92cu_set_name(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + if (!(rs->chip & R92C_CHIP_92C)) { + if (rs->board_type == R92C_BOARD_TYPE_HIGHPA) + sc->name = "RTL8188RU"; + else if (rs->board_type == R92C_BOARD_TYPE_MINICARD) + sc->name = "RTL8188CU-VAU"; + else + sc->name = "RTL8188CUS"; + } else + sc->name = "RTL8192CU"; +} + +static void +r92cu_attach_private(struct rtwn_softc *sc) +{ + struct r92c_softc *rs; + + rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_txpwr = &r92c_txpwr; + + rs->rs_set_bw20 = r92c_set_bw20; + rs->rs_get_txpower = r92c_get_txpower; + rs->rs_set_gain = r92c_set_gain; + rs->rs_tx_enable_ampdu = r92c_tx_enable_ampdu; + rs->rs_tx_setup_hwseq = r92c_tx_setup_hwseq; + rs->rs_tx_setup_macid = r92c_tx_setup_macid; + rs->rs_set_name = r92cu_set_name; + +#ifndef RTWN_WITHOUT_UCODE + rs->rs_c2h_timeout = hz; + + callout_init_mtx(&rs->rs_c2h_report, &sc->sc_mtx, 0); +#endif + + rs->rf_read_delay[0] = 10; + rs->rf_read_delay[1] = 100; + rs->rf_read_delay[2] = 10; + + sc->sc_priv = rs; +} + +static void +r92cu_adj_devcaps(struct rtwn_softc *sc) +{ + /* XXX Currently broken / incomplete. */ + sc->sc_ic.ic_caps &= ~IEEE80211_C_PMGT; +} + +void +r92cu_attach(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + /* USB part. */ + uc->uc_align_rx = r92cu_align_rx; + uc->tx_agg_desc_num = 6; + + /* Common part. */ + sc->sc_flags = RTWN_FLAG_CAM_FIXED; + + sc->sc_set_chan = r92c_set_chan; + sc->sc_fill_tx_desc = r92c_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r92c_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r92c_fill_tx_desc_null; + sc->sc_dump_tx_desc = r92cu_dump_tx_desc; + sc->sc_tx_radiotap_flags = r92c_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r92c_rx_radiotap_flags; + sc->sc_get_rssi_cck = r92c_get_rssi_cck; + sc->sc_get_rssi_ofdm = r92c_get_rssi_ofdm; + sc->sc_classify_intr = r92cu_classify_intr; + sc->sc_handle_tx_report = rtwn_nop_softc_uint8_int; + sc->sc_handle_c2h_report = rtwn_nop_softc_uint8_int; + sc->sc_check_frame = rtwn_nop_int_softc_mbuf; + sc->sc_rf_read = r92c_rf_read; + sc->sc_rf_write = r92c_rf_write; + sc->sc_check_condition = r92c_check_condition; + sc->sc_efuse_postread = r92c_efuse_postread; + sc->sc_parse_rom = r92c_parse_rom; + sc->sc_set_led = r92cu_set_led; + sc->sc_power_on = r92cu_power_on; + sc->sc_power_off = r92cu_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r92c_fw_reset; + sc->sc_fw_download_enable = r92c_fw_download_enable; +#endif + sc->sc_set_page_size = r92c_set_page_size; + sc->sc_lc_calib = r92c_lc_calib; + sc->sc_iq_calib = r92c_iq_calib; /* XXX TODO */ + sc->sc_read_chipid_vendor = r92c_read_chipid_vendor; + sc->sc_adj_devcaps = r92cu_adj_devcaps; + sc->sc_vap_preattach = rtwn_nop_softc_vap; + sc->sc_postattach = r92cu_postattach; + sc->sc_detach_private = r92c_detach_private; + sc->sc_set_media_status = r92c_joinbss_rpt; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_rsvd_page = r92c_set_rsvd_page; + sc->sc_set_pwrmode = r92c_set_pwrmode; + sc->sc_set_rssi = r92c_set_rssi; +#endif + sc->sc_beacon_init = r92c_beacon_init; + sc->sc_beacon_enable = r92c_beacon_enable; + sc->sc_beacon_set_rate = rtwn_nop_void_int; + sc->sc_beacon_select = rtwn_nop_softc_int; + sc->sc_temp_measure = r92c_temp_measure; + sc->sc_temp_read = r92c_temp_read; + sc->sc_init_tx_agg = r92cu_init_tx_agg; + sc->sc_init_rx_agg = r92cu_init_rx_agg; + sc->sc_init_ampdu = r92c_init_ampdu; + sc->sc_init_intr = r92cu_init_intr; + sc->sc_init_edca = r92c_init_edca; + sc->sc_init_bb = r92cu_init_bb; + sc->sc_init_rf = r92c_init_rf; + sc->sc_init_antsel = r92c_init_antsel; + sc->sc_post_init = r92cu_post_init; + sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc; + + sc->mac_prog = &rtl8192cu_mac[0]; + sc->mac_size = nitems(rtl8192cu_mac); + sc->bb_prog = &rtl8192cu_bb[0]; + sc->bb_size = nitems(rtl8192cu_bb); + sc->rf_prog = &rtl8192c_rf[0]; + + sc->page_count = R92CU_TX_PAGE_COUNT; + sc->pktbuf_count = R92C_TXPKTBUF_COUNT; + + sc->ackto = 0x40; + sc->npubqpages = R92CU_PUBQ_NPAGES; + sc->page_size = R92C_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r92cu_tx_desc); + sc->efuse_maxlen = R92C_EFUSE_MAX_LEN; + sc->efuse_maplen = R92C_EFUSE_MAP_LEN; + sc->rx_dma_size = R92C_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R92C_MACID_MAX + 1; + sc->cam_entry_limit = R92C_CAM_ENTRY_COUNT; + sc->fwsize_limit = R92C_MAX_FW_SIZE; + sc->temp_delta = R92C_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R92C_TDECTRL; + sc->rcr = 0; + + r92cu_attach_private(sc); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c new file mode 100644 index 00000000..44b3a509 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c @@ -0,0 +1,393 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include + + +void +r92cu_init_bb(struct rtwn_softc *sc) +{ + + /* Enable BB and RF. */ + rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0, + 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_USBA | R92C_SYS_FUNC_EN_USBD | + R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); + + rtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f); + rtwn_write_1(sc, 0x15, 0xe9); + rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); + + r92c_init_bb_common(sc); +} + +int +r92cu_power_on(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + uint32_t reg; + int ntries; + + /* Wait for autoload done bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for chip autoload\n"); + return (ETIMEDOUT); + } + + /* Unlock ISO/CLK/Power control register. */ + RTWN_CHK(rtwn_write_1(sc, R92C_RSV_CTRL, 0)); + + /* Move SPS into PWM mode. */ + RTWN_CHK(rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b)); + + /* just in case if power_off() was not properly executed. */ + rtwn_delay(sc, 100); + + reg = rtwn_read_1(sc, R92C_LDOV12D_CTRL); + if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) { + RTWN_CHK(rtwn_write_1(sc, R92C_LDOV12D_CTRL, + reg | R92C_LDOV12D_CTRL_LDV12_EN)); + + rtwn_delay(sc, 100); + + RTWN_CHK(rtwn_setbits_1(sc, R92C_SYS_ISO_CTRL, + R92C_SYS_ISO_CTRL_MD2PP, 0)); + } + + /* Auto enable WLAN. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_APFM_ONMAC, 1)); + + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for MAC auto ON\n"); + return (ETIMEDOUT); + } + + /* Enable radio, GPIO and LED functions. */ + RTWN_CHK(rtwn_write_2(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | + R92C_APS_FSMCO_PDN_EN | + R92C_APS_FSMCO_PFM_ALDN)); + + /* Release RF digital isolation. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_SYS_ISO_CTRL, + R92C_SYS_ISO_CTRL_DIOR, 0, 1)); + + /* Initialize MAC. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_APSD_CTRL, + R92C_APSD_CTRL_OFF, 0)); + for (ntries = 0; ntries < 1000; ntries++) { + if (!(rtwn_read_1(sc, R92C_APSD_CTRL) & + R92C_APSD_CTRL_OFF_STATUS)) + break; + rtwn_delay(sc, 50); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, + "timeout waiting for MAC initialization\n"); + return (ETIMEDOUT); + } + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN | + R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) | + R92C_CR_CALTMR_EN)); + + RTWN_CHK(rtwn_write_1(sc, 0xfe10, 0x19)); + + return (0); +#undef RTWN_CHK +} + +void +r92cu_power_off(struct rtwn_softc *sc) +{ +#ifndef RTWN_WITHOUT_UCODE + struct r92c_softc *rs = sc->sc_priv; +#endif + uint32_t reg; + int error; + + /* Deinit C2H event handler. */ +#ifndef RTWN_WITHOUT_UCODE + callout_stop(&rs->rs_c2h_report); + rs->rs_c2h_paused = 0; + rs->rs_c2h_pending = 0; + rs->rs_c2h_timeout = hz; +#endif + + /* Block all Tx queues. */ + error = rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + if (error == ENXIO) /* hardware gone */ + return; + + /* Disable RF */ + rtwn_rf_write(sc, 0, 0, 0); + + rtwn_write_1(sc, R92C_APSD_CTRL, R92C_APSD_CTRL_OFF); + + /* Reset BB state machine */ + rtwn_write_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA | + R92C_SYS_FUNC_EN_BB_GLB_RST); + rtwn_write_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA); + + /* + * Reset digital sequence + */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY) { + /* Reset MCU ready status */ + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* If firmware in ram code, do reset */ + r92c_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); + } +#endif + + /* Reset MAC and Enable 8051 */ + rtwn_write_1(sc, R92C_SYS_FUNC_EN + 1, + (R92C_SYS_FUNC_EN_CPUEN | + R92C_SYS_FUNC_EN_ELDR | + R92C_SYS_FUNC_EN_HWPDN) >> 8); + + /* Reset MCU ready status */ + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* Disable MAC clock */ + rtwn_write_2(sc, R92C_SYS_CLKR, + R92C_SYS_CLKR_ANAD16V_EN | + R92C_SYS_CLKR_ANA8M | + R92C_SYS_CLKR_LOADER_EN | + R92C_SYS_CLKR_80M_SSC_DIS | + R92C_SYS_CLKR_SYS_EN | + R92C_SYS_CLKR_RING_EN | + 0x4000); + + /* Disable AFE PLL */ + rtwn_write_1(sc, R92C_AFE_PLL_CTRL, 0x80); + + /* Gated AFE DIG_CLOCK */ + rtwn_write_2(sc, R92C_AFE_XTAL_CTRL, 0x880F); + + /* Isolated digital to PON */ + rtwn_write_1(sc, R92C_SYS_ISO_CTRL, + R92C_SYS_ISO_CTRL_MD2PP | + R92C_SYS_ISO_CTRL_PA2PCIE | + R92C_SYS_ISO_CTRL_PD2CORE | + R92C_SYS_ISO_CTRL_IP2MAC | + R92C_SYS_ISO_CTRL_DIOP | + R92C_SYS_ISO_CTRL_DIOE); + + /* + * Pull GPIO PIN to balance level and LED control + */ + /* 1. Disable GPIO[7:0] */ + rtwn_write_2(sc, R92C_GPIO_IOSEL, 0x0000); + + reg = rtwn_read_4(sc, R92C_GPIO_PIN_CTRL) & ~0x0000ff00; + reg |= ((reg << 8) & 0x0000ff00) | 0x00ff0000; + rtwn_write_4(sc, R92C_GPIO_PIN_CTRL, reg); + + /* Disable GPIO[10:8] */ + rtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0x00); + + reg = rtwn_read_2(sc, R92C_GPIO_IO_SEL) & ~0x00f0; + reg |= (((reg & 0x000f) << 4) | 0x0780); + rtwn_write_2(sc, R92C_GPIO_IO_SEL, reg); + + /* Disable LED0 & 1 */ + rtwn_write_2(sc, R92C_LEDCFG0, 0x8080); + + /* + * Reset digital sequence + */ + /* Disable ELDR clock */ + rtwn_write_2(sc, R92C_SYS_CLKR, + R92C_SYS_CLKR_ANAD16V_EN | + R92C_SYS_CLKR_ANA8M | + R92C_SYS_CLKR_LOADER_EN | + R92C_SYS_CLKR_80M_SSC_DIS | + R92C_SYS_CLKR_SYS_EN | + R92C_SYS_CLKR_RING_EN | + 0x4000); + + /* Isolated ELDR to PON */ + rtwn_write_1(sc, R92C_SYS_ISO_CTRL + 1, + (R92C_SYS_ISO_CTRL_DIOR | + R92C_SYS_ISO_CTRL_PWC_EV12V) >> 8); + + /* + * Disable analog sequence + */ + /* Disable A15 power */ + rtwn_write_1(sc, R92C_LDOA15_CTRL, R92C_LDOA15_CTRL_OBUF); + /* Disable digital core power */ + rtwn_setbits_1(sc, R92C_LDOV12D_CTRL, + R92C_LDOV12D_CTRL_LDV12_EN, 0); + + /* Enter PFM mode */ + rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); + + /* Set USB suspend */ + rtwn_write_2(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APDM_HOST | + R92C_APS_FSMCO_AFSM_HSUS | + R92C_APS_FSMCO_PFM_ALDN); + + /* Lock ISO/CLK/Power control register. */ + rtwn_write_1(sc, R92C_RSV_CTRL, 0x0E); +} + +void +r92cu_init_intr(struct rtwn_softc *sc) +{ + rtwn_write_4(sc, R92C_HISR, 0xffffffff); + rtwn_write_4(sc, R92C_HIMR, 0xffffffff); +} + +void +r92cu_init_tx_agg(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + uint32_t reg; + + reg = rtwn_read_4(sc, R92C_TDECTRL); + reg = RW(reg, R92C_TDECTRL_BLK_DESC_NUM, uc->tx_agg_desc_num); + rtwn_write_4(sc, R92C_TDECTRL, reg); +} + +void +r92cu_init_rx_agg(struct rtwn_softc *sc) +{ + + /* Rx aggregation (DMA & USB). */ + rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0, + R92C_TRXDMA_CTRL_RXDMA_AGG_EN); + rtwn_setbits_1(sc, R92C_USB_SPECIAL_OPTION, 0, + R92C_USB_SPECIAL_OPTION_AGG_EN); + + /* XXX dehardcode */ + rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48); + rtwn_write_1(sc, R92C_USB_DMA_AGG_TO, 4); + rtwn_write_1(sc, R92C_USB_AGG_TH, 8); + rtwn_write_1(sc, R92C_USB_AGG_TO, 6); +} + +void +r92cu_post_init(struct rtwn_softc *sc) +{ + + /* Perform LO and IQ calibrations. */ + r92c_iq_calib(sc); + /* Perform LC calibration. */ + r92c_lc_calib(sc); + + /* Fix USB interference issue. */ + rtwn_write_1(sc, 0xfe40, 0xe0); + rtwn_write_1(sc, 0xfe41, 0x8d); + rtwn_write_1(sc, 0xfe42, 0x80); + + r92c_pa_bias_init(sc); + + /* Fix for lower temperature. */ + rtwn_write_1(sc, 0x15, 0xe9); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_flags & RTWN_FW_LOADED) { + struct r92c_softc *rs = sc->sc_priv; + + if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { + /* XXX firmware RA does not work yet */ + sc->sc_ratectl = RTWN_RATECTL_NET80211; + } else + sc->sc_ratectl = sc->sc_ratectl_sysctl; + + /* Start C2H event handling. */ + callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout, + r92c_handle_c2h_report, sc); + } else +#endif + sc->sc_ratectl = RTWN_RATECTL_NONE; +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c new file mode 100644 index 00000000..4db6b167 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c @@ -0,0 +1,68 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + + +void +r92cu_set_led(struct rtwn_softc *sc, int led, int on) +{ + uint8_t reg; + + if (led == RTWN_LED_LINK) { + reg = rtwn_read_1(sc, R92C_LEDCFG0) & 0x70; + if (!on) + reg |= R92C_LEDCFG0_DIS; + rtwn_write_1(sc, R92C_LEDCFG0, reg); + sc->ledlink = on; /* Save LED state. */ + } +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h new file mode 100644 index 00000000..8e3203f0 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h @@ -0,0 +1,322 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92CU_PRIV_H +#define R92CU_PRIV_H + +#include + + +/* + * MAC initialization values. + */ +static const struct rtwn_mac_prog rtl8192cu_mac[] = { + { 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 }, + { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, + { 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 }, + { 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, + { 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, + { 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, + { 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, + { 0x45b, 0xb9 }, { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x462, 0x08 }, + { 0x463, 0x03 }, { 0x4c8, 0xff }, { 0x4c9, 0x08 }, { 0x4cc, 0xff }, + { 0x4cd, 0xff }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, + { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, + { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, + { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, + { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, + { 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 }, + { 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x40 }, { 0x547, 0x00 }, + { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, { 0x55a, 0x02 }, + { 0x55d, 0xff }, { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a }, + { 0x652, 0x20 }, { 0x63c, 0x0a }, { 0x63d, 0x0e }, { 0x63e, 0x0a }, + { 0x63f, 0x0e }, { 0x66e, 0x05 }, { 0x700, 0x21 }, { 0x701, 0x43 }, + { 0x702, 0x65 }, { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, + { 0x70a, 0x65 }, { 0x70b, 0x87 } +}; + + +/* + * Baseband initialization values. + */ +static const uint16_t rtl8192cu_bb_regs0_88ru[] = { + 0x024, 0x028, 0x040, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, + 0x818, 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, + 0x83c, 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, + 0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, + 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, + 0x908, 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, + 0xa1c, 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, + 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, + 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, + 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70 +}, rtl8192cu_bb_regs0[] = { + 0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, + 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, + 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, + 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884, + 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908, + 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, + 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, 0xc08, + 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, + 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, + 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70 +}, rtl8192cu_bb_regs1[] = { + 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88 +}, rtl8192cu_bb_regs2[] = { + 0xc8c, 0xc90, 0xc94, 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, + 0xcb0, 0xcb4, 0xcb8, 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, + 0xcd4, 0xcd8, 0xcdc, 0xce0, 0xce4, 0xce8, 0xcec, 0xd00 +}, rtl8192cu_bb_regs5_88ru[] = { + 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xee8, + 0xf14, 0xf4c, 0xf00 +}; + +static const uint32_t rtl8192cu_bb_vals0_88cu[] = { + 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, + 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, + 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, + 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, + 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, + 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, + 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d +}, rtl8192cu_bb_vals0_88ru[] = { + 0x0011800d, 0x00ffdb83, 0x000c0004, 0x80040000, 0x00000001, + 0x0000fc00, 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, + 0x00000000, 0x01000100, 0x00390204, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x569a569a, 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, + 0x32323200, 0x03000300, 0x22004000, 0x00000808, 0x00ffc3f1, + 0xc0083070, 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, + 0xfffffffe, 0x40302010, 0x00706050, 0x00000000, 0x00000023, + 0x00000000, 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, + 0x2e68120f, 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, + 0x15160000, 0x070b0f12, 0x00000104, 0x00d30000, 0x101fbf00, + 0x00000007, 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, + 0x08800000, 0x40000100, 0x08800000, 0x40000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, + 0x49795994, 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, + 0x007f037f, 0x6954342e, 0x43bc0094, 0x6954342f, 0x433c0094, + 0x00000000, 0x5116848b, 0x47c00bff, 0x00000036, 0x2c56000d +}, rtl8192cu_bb_vals0_92ce_92cu[] = { + 0x0011800d, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, + 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, + 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, + 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, + 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000, + 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, + 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, + 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, + 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d +}, rtl8192cu_bb_vals1_88ru[] = { + 0x018610db, 0x0000001f, 0x00b91612, 0x24000090, 0x20f60000, + 0x24000090 +}, rtl8192cu_bb_vals1_92cu[] = { + 0x0186115b, 0x0000001f, 0x00b99612, 0x40000100, 0x20f60000, + 0x40000100 +}, rtl8192cu_bb_vals1_88cu_92ce[] = { + 0x018610db, 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, + 0x40000100 +}, rtl8192cu_bb_vals2[] = { + 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, + 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, + 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, + 0x00080740 +}, rtl8192cu_bb_vals5_88cu[] = { + 0x00000008, 0x001b25a4, 0x631b25a0, 0x631b25a0, 0x081b25a0, + 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x631b25a0, 0x081b25a0, + 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x001b25a0, + 0x001b25a0, 0x6b1b25a0, 0x00000003, 0x00000000, 0x00000300 +}, rtl8192cu_bb_vals5_88ru[] = { + 0x00000010, 0x001b25a4, 0x631b25a0, 0x631b25a0, 0x081b25a0, + 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x631b25a0, 0x081b25a0, + 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x001b25a0, + 0x001b25a0, 0x6b1b25a0, 0x31555448, 0x00000003, 0x00000000, + 0x00000300 +}; + +static const struct rtwn_bb_prog rtl8192cu_bb[] = { + /* RTL8188CE / RTL8188CU. */ + { + nitems(rtl8192cu_bb_regs0), + rtl8192cu_bb_regs0, + rtl8192cu_bb_vals0_88cu, + { R92C_COND_RTL8188CU | R92C_COND_RTL8188CE }, + /* RTL8188RU. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs0_88ru), + rtl8192cu_bb_regs0_88ru, + rtl8192cu_bb_vals0_88ru, + { R92C_COND_RTL8188RU }, + /* Others. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs0), + rtl8192cu_bb_regs0, + rtl8192cu_bb_vals0_92ce_92cu, + { 0 }, + NULL + } + } + }, + /* RTL8188RU. */ + { + nitems(rtl8192cu_bb_regs1), + rtl8192cu_bb_regs1, + rtl8192cu_bb_vals1_88ru, + { R92C_COND_RTL8188RU }, + /* RTL8192CU. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs1), + rtl8192cu_bb_regs1, + rtl8192cu_bb_vals1_92cu, + { R92C_COND_RTL8192CU }, + /* Others. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs1), + rtl8192cu_bb_regs1, + rtl8192cu_bb_vals1_88cu_92ce, + { 0 }, + NULL + } + } + }, + { + nitems(rtl8192cu_bb_regs2), + rtl8192cu_bb_regs2, + rtl8192cu_bb_vals2, + { 0 }, + NULL + }, + /* RTL8192CE / RTL8192CU. */ + { + nitems(rtl8192c_bb_regs3), + rtl8192c_bb_regs3, + rtl8192c_bb_vals3_92ce_92cu, + { R92C_COND_RTL8192C }, + /* Others. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192c_bb_regs3), + rtl8192c_bb_regs3, + rtl8192c_bb_vals3_88cu_88ru, + { 0 }, + NULL + } + }, + { + nitems(rtl8192c_bb_regs4), + rtl8192c_bb_regs4, + rtl8192c_bb_vals4, + { 0 }, + NULL + }, + /* RTL8188CE / RTL8188CU. */ + { + nitems(rtl8192c_bb_regs5), + rtl8192c_bb_regs5, + rtl8192cu_bb_vals5_88cu, + { R92C_COND_RTL8188CU | R92C_COND_RTL8188CE }, + /* RTL8188RU. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs5_88ru), + rtl8192cu_bb_regs5_88ru, + rtl8192cu_bb_vals5_88ru, + { R92C_COND_RTL8188RU }, + /* Others. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192c_bb_regs5), + rtl8192c_bb_regs5, + rtl8192c_bb_vals5_92ce_92cu, + { 0 }, + NULL + } + } + } +}; + + +static const uint32_t rtl8188ru_agc_vals[] = { + 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, + 0x7b050001, 0x7b060001, 0x7b070001, 0x7b080001, 0x7a090001, + 0x790a0001, 0x780b0001, 0x770c0001, 0x760d0001, 0x750e0001, + 0x740f0001, 0x73100001, 0x72110001, 0x71120001, 0x70130001, + 0x6f140001, 0x6e150001, 0x6d160001, 0x6c170001, 0x6b180001, + 0x6a190001, 0x691a0001, 0x681b0001, 0x671c0001, 0x661d0001, + 0x651e0001, 0x641f0001, 0x63200001, 0x62210001, 0x61220001, + 0x60230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, + 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, + 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, + 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, + 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, + 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, + 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, + 0x7b460001, 0x7b470001, 0x7b480001, 0x7a490001, 0x794a0001, + 0x784b0001, 0x774c0001, 0x764d0001, 0x754e0001, 0x744f0001, + 0x73500001, 0x72510001, 0x71520001, 0x70530001, 0x6f540001, + 0x6e550001, 0x6d560001, 0x6c570001, 0x6b580001, 0x6a590001, + 0x695a0001, 0x685b0001, 0x675c0001, 0x665d0001, 0x655e0001, + 0x645f0001, 0x63600001, 0x62610001, 0x61620001, 0x60630001, + 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, + 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, + 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, + 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, + 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, + 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, + 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, + 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, + 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, + 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, + 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, + 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e +}; + +static const struct rtwn_agc_prog rtl8188ru_agc[] = { + { + nitems(rtl8188ru_agc_vals), + rtl8188ru_agc_vals, + { 0 }, + NULL + } +}; + +#endif /* R92CU_PRIV_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h new file mode 100644 index 00000000..a9db29cc --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92CU_REG_H +#define R92CU_REG_H + +#include + + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R92C_USB_SIE_INTF 0x0e0 + + +/* + * USB registers. + */ +#define R92C_USB_SUSPEND 0xfe10 +#define R92C_USB_INFO 0xfe17 +#define R92C_USB_SPECIAL_OPTION 0xfe55 +#define R92C_USB_HCPWM 0xfe57 +#define R92C_USB_HRPWM 0xfe58 +#define R92C_USB_DMA_AGG_TO 0xfe5b +#define R92C_USB_AGG_TO 0xfe5c +#define R92C_USB_AGG_TH 0xfe5d +#define R92C_USB_VID 0xfe60 +#define R92C_USB_PID 0xfe62 +#define R92C_USB_OPTIONAL 0xfe64 +#define R92C_USB_EP 0xfe65 +#define R92C_USB_PHY 0xfe68 +#define R92C_USB_MAC_ADDR 0xfe70 +#define R92C_USB_STRING 0xfe80 + +/* Bits for R92C_USB_SPECIAL_OPTION. */ +#define R92C_USB_SPECIAL_OPTION_AGG_EN 0x08 +#define R92C_USB_SPECIAL_OPTION_INT_BULK_SEL 0x10 + +/* Bits for R92C_USB_EP. */ +#define R92C_USB_EP_HQ_M 0x000f +#define R92C_USB_EP_HQ_S 0 +#define R92C_USB_EP_NQ_M 0x00f0 +#define R92C_USB_EP_NQ_S 4 +#define R92C_USB_EP_LQ_M 0x0f00 +#define R92C_USB_EP_LQ_S 8 + +#endif /* R92CU_REG_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c new file mode 100644 index 00000000..ec55da6d --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c @@ -0,0 +1,65 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + + +int +r92cu_classify_intr(struct rtwn_softc *sc, void *buf, int len) +{ + /* NB: reports are fetched from C2H_MSG register. */ + return (RTWN_RX_DATA); +} + +int +r92cu_align_rx(int totlen, int len) +{ + return (roundup2(totlen, 128)); +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c new file mode 100644 index 00000000..0954316d --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c @@ -0,0 +1,66 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r92cu_dump_tx_desc(struct rtwn_softc *sc, const void *desc) +{ +#ifdef RTWN_DEBUG + const struct r92cu_tx_desc *txd = desc; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT_DESC, + "%s: len %d, off %d, flags0 %02X, dw: 1 %08X, 2 %08X, 3 %04X " + "(seq %04X), 4 %08X, 5 %08X, 6 %08X, sum %04X, pad %04X\n", + __func__, le16toh(txd->pktlen), txd->offset, txd->flags0, + le32toh(txd->txdw1), le32toh(txd->txdw2), le16toh(txd->txdw3), + le16toh(txd->txdseq), le32toh(txd->txdw4), le32toh(txd->txdw5), + le32toh(txd->txdw6), le16toh(txd->txdsum), le16toh(txd->pad)); +#endif +} diff --git a/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h new file mode 100644 index 00000000..16c2d058 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92CU_TX_DESC_H +#define R92CU_TX_DESC_H + +#include + +/* Tx MAC descriptor (USB). */ +struct r92cu_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; + + uint32_t txdw1; + uint32_t txdw2; + uint16_t txdw3; + uint16_t txdseq; + + uint32_t txdw4; + uint32_t txdw5; + uint32_t txdw6; + + uint16_t txdsum; + uint16_t pad; +} __packed __attribute__((aligned(4))); + +#endif /* R92CU_TX_DESC_H */ \ No newline at end of file diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a.h new file mode 100644 index 00000000..ec1d61e1 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a.h @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef RTL8812A_H +#define RTL8812A_H + +/* + * Global definitions. + */ +#define R12A_PUBQ_NPAGES 219 +#define R12A_TXPKTBUF_COUNT 255 +#define R12A_TX_PAGE_COUNT 248 + +#define R12A_TX_PAGE_SIZE 512 +#define R12A_RX_DMA_BUFFER_SIZE 0x3e80 + +#define R12A_MAX_FW_SIZE 0x8000 +#define R12A_MACID_MAX 127 +#define R12A_CAM_ENTRY_COUNT 64 + +#define R12A_INTR_MSG_LEN 60 + +static const uint8_t r12a_chan_5ghz_0[] = + { 36, 40, 44, 48, 52, 56, 60, 64 }; +static const uint8_t r12a_chan_5ghz_1[] = + { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144 }; +static const uint8_t r12a_chan_5ghz_2[] = + { 149, 153, 157, 161, 165, 169, 173, 177 }; + + +/* + * Function declarations. + */ +/* r12a_attach.c */ +void r12a_vap_preattach(struct rtwn_softc *, struct ieee80211vap *); +void r12a_detach_private(struct rtwn_softc *); + +/* r12a_beacon.c */ +void r12a_beacon_init(struct rtwn_softc *, void *, int); +void r12a_beacon_set_rate(void *, int); + +/* r12a_calib.c */ +void r12a_save_bb_afe_vals(struct rtwn_softc *, uint32_t[], + const uint16_t[], int); +void r12a_restore_bb_afe_vals(struct rtwn_softc *, uint32_t[], + const uint16_t[], int); +void r12a_save_rf_vals(struct rtwn_softc *, uint32_t[], + const uint8_t[], int); +void r12a_restore_rf_vals(struct rtwn_softc *, uint32_t[], + const uint8_t[], int); +void r12a_lc_calib(struct rtwn_softc *); +#ifndef RTWN_WITHOUT_UCODE +int r12a_iq_calib_fw_supported(struct rtwn_softc *); +#endif +void r12a_iq_calib_sw(struct rtwn_softc *); +void r12a_iq_calib(struct rtwn_softc *); + +/* r12a_caps.c */ +int r12a_ioctl_net(struct ieee80211com *, u_long, void *); + +/* r12a_chan.c */ +void r12a_fix_spur(struct rtwn_softc *, struct ieee80211_channel *); +void r12a_set_chan(struct rtwn_softc *, struct ieee80211_channel *); +void r12a_set_band_2ghz(struct rtwn_softc *, uint32_t); +void r12a_set_band_5ghz(struct rtwn_softc *, uint32_t); + +/* r12a_fw.c */ +#ifndef RTWN_WITHOUT_UCODE +void r12a_fw_reset(struct rtwn_softc *, int); +void r12a_fw_download_enable(struct rtwn_softc *, int); +void r12a_set_media_status(struct rtwn_softc *, int); +int r12a_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, + int); +void r12a_iq_calib_fw(struct rtwn_softc *); +#endif + +/* r12a_init.c */ +int r12a_check_condition(struct rtwn_softc *, const uint8_t[]); +int r12a_set_page_size(struct rtwn_softc *); +void r12a_init_edca(struct rtwn_softc *); +void r12a_init_bb(struct rtwn_softc *); +void r12a_init_rf(struct rtwn_softc *); +void r12a_crystalcap_write(struct rtwn_softc *); +int r12a_power_on(struct rtwn_softc *); +void r12a_power_off(struct rtwn_softc *); +void r12a_init_intr(struct rtwn_softc *); +void r12a_init_antsel(struct rtwn_softc *); + +/* r12a_led.c */ +void r12a_set_led(struct rtwn_softc *, int, int); + +/* r12a_rf.c */ +uint32_t r12a_rf_read(struct rtwn_softc *, int, uint8_t); +uint32_t r12a_c_cut_rf_read(struct rtwn_softc *, int, uint8_t); +void r12a_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); + +/* r12a_rom.c */ +void r12a_parse_rom_common(struct rtwn_softc *, uint8_t *); +void r12a_parse_rom(struct rtwn_softc *, uint8_t *); + +/* r12a_rx.c */ +void r12a_ratectl_tx_complete(struct rtwn_softc *, uint8_t *, int); +void r12a_handle_c2h_report(struct rtwn_softc *, uint8_t *, int); +int r12a_check_frame_checksum(struct rtwn_softc *, struct mbuf *); +uint8_t r12a_rx_radiotap_flags(const void *); + +/* r12a_tx.c */ +void r12a_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, void *, uint8_t, int); +void r12a_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, void *, const struct ieee80211_bpf_params *); +void r12a_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); +uint8_t r12a_tx_radiotap_flags(const void *); + +#endif /* RTL8812A_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c new file mode 100644 index 00000000..37b1a183 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_beacon.c @@ -0,0 +1,96 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +void +r12a_beacon_init(struct rtwn_softc *sc, void *buf, int id) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + txd->flags0 = R12A_FLAGS0_LSG | R12A_FLAGS0_FSG | R12A_FLAGS0_BMCAST; + + /* + * NB: there is no need to setup HWSEQ_EN bit; + * QSEL_BEACON already implies it. + */ + txd->txdw1 = htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_BEACON)); + txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC)); + + txd->txdw3 = htole32(R12A_TXDW3_DRVRATE); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id)); + + txd->txdw6 = htole32(SM(R21A_TXDW6_MBSSID, id)); +} + +void +r12a_beacon_set_rate(void *buf, int is5ghz) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + txd->txdw4 &= ~htole32(R12A_TXDW4_DATARATE_M); + if (is5ghz) { + txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, + RTWN_RIDX_OFDM6)); + } else + txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, RTWN_RIDX_CCK1)); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c new file mode 100644 index 00000000..73f1df0f --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_calib.c @@ -0,0 +1,288 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + + +void +r12a_lc_calib(struct rtwn_softc *sc) +{ + uint32_t chnlbw; + uint8_t txmode; + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: LC calibration started\n", __func__); + + txmode = rtwn_read_1(sc, R12A_SINGLETONE_CONT_TX + 2); + + if ((txmode & 0x07) != 0) { + /* Disable all continuous Tx. */ + /* + * Skipped because BB turns off continuous Tx until + * next packet comes in. + */ + } else { + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + } + + /* Enter LCK mode. */ + rtwn_rf_setbits(sc, 0, R12A_RF_LCK, 0, R12A_RF_LCK_MODE); + + /* Start calibration. */ + chnlbw = rtwn_rf_read(sc, 0, R92C_RF_CHNLBW); + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, chnlbw | R92C_RF_CHNLBW_LCSTART); + + /* Give calibration the time to complete. */ + rtwn_delay(sc, 150000); /* 150 ms */ + + /* Leave LCK mode. */ + rtwn_rf_setbits(sc, 0, R12A_RF_LCK, R12A_RF_LCK_MODE, 0); + + /* Restore configuration. */ + if ((txmode & 0x07) != 0) { + /* Continuous Tx case. */ + /* + * Skipped because BB turns off continuous Tx until + * next packet comes in. + */ + } else { + /* Unblock all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, 0); + } + + /* Recover channel number. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, chnlbw); + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: LC calibration finished\n", __func__); +} + +#ifndef RTWN_WITHOUT_UCODE +int +r12a_iq_calib_fw_supported(struct rtwn_softc *sc) +{ + if (sc->fwver == 0x19) + return (1); + + return (0); +} +#endif + +void +r12a_save_bb_afe_vals(struct rtwn_softc *sc, uint32_t vals[], + const uint16_t regs[], int size) +{ + int i; + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + + for (i = 0; i < size; i++) + vals[i] = rtwn_bb_read(sc, regs[i]); +} + +void +r12a_restore_bb_afe_vals(struct rtwn_softc *sc, uint32_t vals[], + const uint16_t regs[], int size) +{ + int i; + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + + for (i = 0; i < size; i++) + rtwn_bb_write(sc, regs[i], vals[i]); +} + +void +r12a_save_rf_vals(struct rtwn_softc *sc, uint32_t vals[], + const uint8_t regs[], int size) +{ + int c, i; + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + + for (c = 0; c < sc->nrxchains; c++) + for (i = 0; i < size; i++) + vals[c * size + i] = rtwn_rf_read(sc, c, regs[i]); +} + +void +r12a_restore_rf_vals(struct rtwn_softc *sc, uint32_t vals[], + const uint8_t regs[], int size) +{ + int c, i; + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + + for (c = 0; c < sc->nrxchains; c++) + for (i = 0; i < size; i++) + rtwn_rf_write(sc, c, regs[i], vals[c * size + i]); +} + +#ifdef RTWN_TODO +static void +r12a_iq_tx(struct rtwn_softc *sc) +{ + /* TODO */ +} + +static void +r12a_iq_config_mac(struct rtwn_softc *sc) +{ + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + rtwn_write_1(sc, R92C_TXPAUSE, + R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH); + /* BCN_CTRL & BCN_CTRL1 */ + rtwn_setbits_1(sc, R92C_BCN_CTRL(0), R92C_BCN_CTRL_EN_BCN, 0); + rtwn_setbits_1(sc, R92C_BCN_CTRL(1), R92C_BCN_CTRL_EN_BCN, 0); + /* Rx ant off */ + rtwn_write_1(sc, R12A_OFDMCCK_EN, 0); + /* CCA off */ + rtwn_bb_setbits(sc, R12A_CCA_ON_SEC, 0x03, 0x0c); + /* CCK RX Path off */ + rtwn_write_1(sc, R12A_CCK_RX_PATH + 3, 0x0f); +} +#endif + +void +r12a_iq_calib_sw(struct rtwn_softc *sc) +{ +#define R12A_MAX_NRXCHAINS 2 + uint32_t bb_vals[nitems(r12a_iq_bb_regs)]; + uint32_t afe_vals[nitems(r12a_iq_afe_regs)]; + uint32_t rf_vals[nitems(r12a_iq_rf_regs) * R12A_MAX_NRXCHAINS]; + uint32_t rfe[2]; + + KASSERT(sc->nrxchains <= R12A_MAX_NRXCHAINS, + ("nrxchains > %d (%d)\n", R12A_MAX_NRXCHAINS, sc->nrxchains)); + + /* Save registers. */ + r12a_save_bb_afe_vals(sc, bb_vals, r12a_iq_bb_regs, + nitems(r12a_iq_bb_regs)); + + /* Select page C1. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0, 0x80000000); + rfe[0] = rtwn_bb_read(sc, R12A_RFE(0)); + rfe[1] = rtwn_bb_read(sc, R12A_RFE(1)); + + r12a_save_bb_afe_vals(sc, afe_vals, r12a_iq_afe_regs, + nitems(r12a_iq_afe_regs)); + r12a_save_rf_vals(sc, rf_vals, r12a_iq_rf_regs, + nitems(r12a_iq_rf_regs)); + +#ifdef RTWN_TODO + /* Configure MAC. */ + rtwn_iq_config_mac(sc); + rtwn_iq_tx(sc); +#endif + + r12a_restore_rf_vals(sc, rf_vals, r12a_iq_rf_regs, + nitems(r12a_iq_rf_regs)); + r12a_restore_bb_afe_vals(sc, afe_vals, r12a_iq_afe_regs, + nitems(r12a_iq_afe_regs)); + + /* Select page C1. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0, 0x80000000); + + /* Chain 0. */ + rtwn_bb_write(sc, R12A_SLEEP_NAV(0), 0); + rtwn_bb_write(sc, R12A_PMPD(0), 0); + rtwn_bb_write(sc, 0xc88, 0); + rtwn_bb_write(sc, 0xc8c, 0x3c000000); + rtwn_bb_setbits(sc, 0xc90, 0, 0x00000080); + rtwn_bb_setbits(sc, 0xcc4, 0, 0x20040000); + rtwn_bb_setbits(sc, 0xcc8, 0, 0x20000000); + + /* Chain 1. */ + rtwn_bb_write(sc, R12A_SLEEP_NAV(1), 0); + rtwn_bb_write(sc, R12A_PMPD(1), 0); + rtwn_bb_write(sc, 0xe88, 0); + rtwn_bb_write(sc, 0xe8c, 0x3c000000); + rtwn_bb_setbits(sc, 0xe90, 0, 0x00000080); + rtwn_bb_setbits(sc, 0xec4, 0, 0x20040000); + rtwn_bb_setbits(sc, 0xec8, 0, 0x20000000); + + rtwn_bb_write(sc, R12A_RFE(0), rfe[0]); + rtwn_bb_write(sc, R12A_RFE(1), rfe[1]); + + r12a_restore_bb_afe_vals(sc, bb_vals, r12a_iq_bb_regs, + nitems(r12a_iq_bb_regs)); +#undef R12A_MAX_NRXCHAINS +} + +void +r12a_iq_calib(struct rtwn_softc *sc) +{ +#ifndef RTWN_WITHOUT_UCODE + if ((sc->sc_flags & RTWN_FW_LOADED) && + rtwn_r12a_iq_calib_fw_supported(sc)) + r12a_iq_calib_fw(sc); + else +#endif + rtwn_r12a_iq_calib_sw(sc); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c new file mode 100644 index 00000000..fc022e91 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_caps.c @@ -0,0 +1,122 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + + +int +r12a_ioctl_net(struct ieee80211com *ic, u_long cmd, void *data) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct r12a_softc *rs = sc->sc_priv; + struct ifreq *ifr = (struct ifreq *)data; + int error; + + error = 0; + switch (cmd) { + case SIOCSIFCAP: + { + struct ieee80211vap *vap; + int changed, rxmask; + + rxmask = ifr->ifr_reqcap & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); + + RTWN_LOCK(sc); + changed = 0; + if (!(rs->rs_flags & R12A_RXCKSUM_EN) ^ + !(ifr->ifr_reqcap & IFCAP_RXCSUM)) { + rs->rs_flags ^= R12A_RXCKSUM_EN; + changed = 1; + } + if (!(rs->rs_flags & R12A_RXCKSUM6_EN) ^ + !(ifr->ifr_reqcap & IFCAP_RXCSUM_IPV6)) { + rs->rs_flags ^= R12A_RXCKSUM6_EN; + changed = 1; + } + if (changed) { + if (rxmask == 0) + sc->rcr &= ~R12A_RCR_TCP_OFFLD_EN; + else + sc->rcr |= R12A_RCR_TCP_OFFLD_EN; + + if (sc->sc_flags & RTWN_RUNNING) + rtwn_rxfilter_set(sc); + } + RTWN_UNLOCK(sc); + + IEEE80211_LOCK(ic); /* XXX */ + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + struct ifnet *ifp = vap->iv_ifp; + + ifp->if_capenable &= + ~(IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); + ifp->if_capenable |= rxmask; + } + IEEE80211_UNLOCK(ic); + break; + } + default: + error = ENOTTY; /* for net80211 */ + break; + } + + return (error); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c new file mode 100644 index 00000000..11db1a5d --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c @@ -0,0 +1,603 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + + +static void +r12a_write_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) +{ + + if (IEEE80211_IS_CHAN_2GHZ(c)) { + /* Write per-CCK rate Tx power. */ + rtwn_bb_write(sc, R12A_TXAGC_CCK11_1(chain), + SM(R12A_TXAGC_CCK1, power[RTWN_RIDX_CCK1]) | + SM(R12A_TXAGC_CCK2, power[RTWN_RIDX_CCK2]) | + SM(R12A_TXAGC_CCK55, power[RTWN_RIDX_CCK55]) | + SM(R12A_TXAGC_CCK11, power[RTWN_RIDX_CCK11])); + } + + /* Write per-OFDM rate Tx power. */ + rtwn_bb_write(sc, R12A_TXAGC_OFDM18_6(chain), + SM(R12A_TXAGC_OFDM06, power[RTWN_RIDX_OFDM6]) | + SM(R12A_TXAGC_OFDM09, power[RTWN_RIDX_OFDM9]) | + SM(R12A_TXAGC_OFDM12, power[RTWN_RIDX_OFDM12]) | + SM(R12A_TXAGC_OFDM18, power[RTWN_RIDX_OFDM18])); + rtwn_bb_write(sc, R12A_TXAGC_OFDM54_24(chain), + SM(R12A_TXAGC_OFDM24, power[RTWN_RIDX_OFDM24]) | + SM(R12A_TXAGC_OFDM36, power[RTWN_RIDX_OFDM36]) | + SM(R12A_TXAGC_OFDM48, power[RTWN_RIDX_OFDM48]) | + SM(R12A_TXAGC_OFDM54, power[RTWN_RIDX_OFDM54])); + /* Write per-MCS Tx power. */ + rtwn_bb_write(sc, R12A_TXAGC_MCS3_0(chain), + SM(R12A_TXAGC_MCS0, power[RTWN_RIDX_MCS(0)]) | + SM(R12A_TXAGC_MCS1, power[RTWN_RIDX_MCS(1)]) | + SM(R12A_TXAGC_MCS2, power[RTWN_RIDX_MCS(2)]) | + SM(R12A_TXAGC_MCS3, power[RTWN_RIDX_MCS(3)])); + rtwn_bb_write(sc, R12A_TXAGC_MCS7_4(chain), + SM(R12A_TXAGC_MCS4, power[RTWN_RIDX_MCS(4)]) | + SM(R12A_TXAGC_MCS5, power[RTWN_RIDX_MCS(5)]) | + SM(R12A_TXAGC_MCS6, power[RTWN_RIDX_MCS(6)]) | + SM(R12A_TXAGC_MCS7, power[RTWN_RIDX_MCS(7)])); + if (sc->ntxchains >= 2) { + rtwn_bb_write(sc, R12A_TXAGC_MCS11_8(chain), + SM(R12A_TXAGC_MCS8, power[RTWN_RIDX_MCS(8)]) | + SM(R12A_TXAGC_MCS9, power[RTWN_RIDX_MCS(9)]) | + SM(R12A_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) | + SM(R12A_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)])); + rtwn_bb_write(sc, R12A_TXAGC_MCS15_12(chain), + SM(R12A_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) | + SM(R12A_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) | + SM(R12A_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) | + SM(R12A_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)])); + } + + /* TODO: VHT rates */ +} + +static int +r12a_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint8_t chan; + int group; + + chan = rtwn_chan2centieee(c); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + 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 <= 14) group = 4; + else { + KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); + return (-1); + } + } else if (IEEE80211_IS_CHAN_5GHZ(c)) { + if (chan < 36) + return (-1); + + if (chan <= 42) group = 0; + else if (chan <= 48) group = 1; + else if (chan <= 58) group = 2; + else if (chan <= 64) group = 3; + else if (chan <= 106) group = 4; + else if (chan <= 114) group = 5; + else if (chan <= 122) group = 6; + else if (chan <= 130) group = 7; + else if (chan <= 138) group = 8; + else if (chan <= 144) group = 9; + else if (chan <= 155) group = 10; + else if (chan <= 161) group = 11; + else if (chan <= 171) group = 12; + else if (chan <= 177) group = 13; + else { + KASSERT(0, ("wrong 5GHz channel %d!\n", chan)); + return (-1); + } + } else { + KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); + return (-1); + } + + return (group); +} + +static void +r12a_get_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) +{ + struct r12a_softc *rs = sc->sc_priv; + int i, ridx, group, max_mcs; + + /* Determine channel group. */ + group = r12a_get_power_group(sc, c); + if (group == -1) { /* shouldn't happen */ + device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); + return; + } + + /* TODO: VHT rates. */ + max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + + /* XXX regulatory */ + /* XXX net80211 regulatory */ + + if (IEEE80211_IS_CHAN_2GHZ(c)) { + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] = rs->cck_tx_pwr[chain][group]; + for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) + power[ridx] = rs->ht40_tx_pwr_2g[chain][group]; + + for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) + power[ridx] += rs->ofdm_tx_pwr_diff_2g[chain][0]; + + for (i = 0; i < sc->ntxchains; i++) { + uint8_t min_mcs; + uint8_t pwr_diff; + +#ifdef notyet + if (IEEE80211_IS_CHAN_HT80(c)) { + /* Vendor driver uses HT40 values here. */ + pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i]; + } else +#endif + if (IEEE80211_IS_CHAN_HT40(c)) + pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i]; + else + pwr_diff = rs->bw20_tx_pwr_diff_2g[chain][i]; + + min_mcs = RTWN_RIDX_MCS(i * 8); + for (ridx = min_mcs; ridx <= max_mcs; ridx++) + power[ridx] += pwr_diff; + } + } else { /* 5GHz */ + for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) + power[ridx] = rs->ht40_tx_pwr_5g[chain][group]; + + for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) + power[ridx] += rs->ofdm_tx_pwr_diff_5g[chain][0]; + + for (i = 0; i < sc->ntxchains; i++) { + uint8_t min_mcs; + uint8_t pwr_diff; + +#ifdef notyet + if (IEEE80211_IS_CHAN_HT80(c)) { + /* TODO: calculate base value. */ + pwr_diff = rs->bw80_tx_pwr_diff_5g[chain][i]; + } else +#endif + if (IEEE80211_IS_CHAN_HT40(c)) + pwr_diff = rs->bw40_tx_pwr_diff_5g[chain][i]; + else + pwr_diff = rs->bw20_tx_pwr_diff_5g[chain][i]; + + min_mcs = RTWN_RIDX_MCS(i * 8); + for (ridx = min_mcs; ridx <= max_mcs; ridx++) + power[ridx] += pwr_diff; + } + } + + /* Apply max limit. */ + for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } + +#ifdef RTWN_DEBUG + if (sc->sc_debug & RTWN_DEBUG_TXPWR) { + /* Dump per-rate Tx power values. */ + printf("Tx power for chain %d:\n", chain); + for (ridx = RTWN_RIDX_CCK1; ridx < RTWN_RIDX_COUNT; ridx++) + printf("Rate %d = %u\n", ridx, power[ridx]); + } +#endif +} + +static void +r12a_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint8_t power[RTWN_RIDX_COUNT]; + int i; + + for (i = 0; i < sc->ntxchains; i++) { + memset(power, 0, sizeof(power)); + /* Compute per-rate Tx power values. */ + r12a_get_txpower(sc, i, c, power); + /* Write per-rate Tx power values to hardware. */ + r12a_write_txpower(sc, i, c, power); + } +} + +void +r12a_fix_spur(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + struct r12a_softc *rs = sc->sc_priv; + uint16_t chan = rtwn_chan2centieee(c); + + if (rs->chip & R12A_CHIP_C_CUT) { + if (IEEE80211_IS_CHAN_HT40(c) && chan == 11) { + rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0xc00); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0, 0x40000000); + } else { + rtwn_bb_setbits(sc, R12A_RFMOD, 0x400, 0x800); + + if (!IEEE80211_IS_CHAN_HT40(c) && /* 20 MHz */ + (chan == 13 || chan == 14)) { + rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, + 0, 0x40000000); + } else { /* !80 Mhz */ + rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, + 0x40000000, 0); + } + } + } else { + /* Set ADC clock to 160M to resolve 2480 MHz spur. */ + if (!IEEE80211_IS_CHAN_HT40(c) && /* 20 MHz */ + (chan == 13 || chan == 14)) + rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300); + else if (IEEE80211_IS_CHAN_2GHZ(c)) + rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200); + } +} + +static void +r12a_set_band(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct r12a_softc *rs = sc->sc_priv; + uint32_t basicrates; + uint8_t swing; + int i; + + /* Check if band was changed. */ + if ((sc->sc_flags & (RTWN_STARTED | RTWN_RUNNING)) != + RTWN_STARTED && IEEE80211_IS_CHAN_5GHZ(c) ^ + !(rtwn_read_1(sc, R12A_CCK_CHECK) & R12A_CCK_CHECK_5GHZ)) + return; + + rtwn_get_rates(sc, ieee80211_get_suprates(ic, c), NULL, &basicrates, + NULL, 1); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + rtwn_r12a_set_band_2ghz(sc, basicrates); + swing = rs->tx_bbswing_2g; + } else if (IEEE80211_IS_CHAN_5GHZ(c)) { + rtwn_r12a_set_band_5ghz(sc, basicrates); + swing = rs->tx_bbswing_5g; + } else { + KASSERT(0, ("wrong channel flags %08X\n", c->ic_flags)); + return; + } + + /* XXX PATH_B is set by vendor driver. */ + for (i = 0; i < 2; i++) { + uint16_t val = 0; + + switch ((swing >> i * 2) & 0x3) { + case 0: + val = 0x200; /* 0 dB */ + break; + case 1: + val = 0x16a; /* -3 dB */ + break; + case 2: + val = 0x101; /* -6 dB */ + break; + case 3: + val = 0xb6; /* -9 dB */ + break; + } + + rtwn_bb_setbits(sc, R12A_TX_SCALE(i), R12A_TX_SCALE_SWING_M, + val << R12A_TX_SCALE_SWING_S); + } +} + +void +r12a_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint32_t val; + uint16_t chan; + int i; + + r12a_set_band(sc, c); + + chan = rtwn_chan2centieee(c); + if (36 <= chan && chan <= 48) + val = 0x09280000; + else if (50 <= chan && chan <= 64) + val = 0x08a60000; + else if (100 <= chan && chan <= 116) + val = 0x08a40000; + else if (118 <= chan) + val = 0x08240000; + else + val = 0x12d40000; + + rtwn_bb_setbits(sc, R12A_FC_AREA, 0x1ffe0000, val); + + for (i = 0; i < sc->nrxchains; i++) { + if (36 <= chan && chan <= 64) + val = 0x10100; + else if (100 <= chan && chan <= 140) + val = 0x30100; + else if (140 < chan) + val = 0x50100; + else + val = 0x00000; + + rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0x70300, val); + + /* RTL8812AU-specific */ + rtwn_r12a_fix_spur(sc, c); + + KASSERT(chan <= 0xff, ("%s: chan %d\n", __func__, chan)); + rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xff, chan); + } + +#ifdef notyet + if (IEEE80211_IS_CHAN_HT80(c)) { /* 80 MHz */ + rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x80, 0x100); + + /* TODO */ + + val = 0x0; + } else +#endif + if (IEEE80211_IS_CHAN_HT40(c)) { /* 40 MHz */ + uint8_t ext_chan; + + if (IEEE80211_IS_CHAN_HT40U(c)) + ext_chan = R12A_DATA_SEC_PRIM_DOWN_20; + else + ext_chan = R12A_DATA_SEC_PRIM_UP_20; + + rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x100, 0x80); + rtwn_write_1(sc, R12A_DATA_SEC, ext_chan); + + rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300201); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0); + + /* discard high 4 bits */ + val = rtwn_bb_read(sc, R12A_RFMOD); + val = RW(val, R12A_RFMOD_EXT_CHAN, ext_chan); + rtwn_bb_write(sc, R12A_RFMOD, val); + + val = rtwn_bb_read(sc, R12A_CCA_ON_SEC); + val = RW(val, R12A_CCA_ON_SEC_EXT_CHAN, ext_chan); + rtwn_bb_write(sc, R12A_CCA_ON_SEC, val); + + if (rtwn_read_1(sc, 0x837) & 0x04) + val = 0x01800000; + else if (sc->nrxchains == 2 && sc->ntxchains == 2) + val = 0x01c00000; + else + val = 0x02000000; + + rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val); + + if (IEEE80211_IS_CHAN_HT40U(c)) + rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10, 0); + else + rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0, 0x10); + + val = 0x400; + } else { /* 20 MHz */ + rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x180, 0); + rtwn_write_1(sc, R12A_DATA_SEC, R12A_DATA_SEC_NO_EXT); + + rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300200); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0); + + if (sc->nrxchains == 2 && sc->ntxchains == 2) + val = 0x01c00000; + else + val = 0x02000000; + + rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val); + + val = 0xc00; + } + + /* RTL8812AU-specific */ + rtwn_r12a_fix_spur(sc, c); + + for (i = 0; i < sc->nrxchains; i++) + rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xc00, val); + + /* Set Tx power for this new channel. */ + r12a_set_txpower(sc, c); +} + +void +r12a_set_band_2ghz(struct rtwn_softc *sc, uint32_t basicrates) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Enable CCK / OFDM. */ + rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, + 0, R12A_OFDMCCK_EN_CCK | R12A_OFDMCCK_EN_OFDM); + + rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x02, 0x01); + rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2e000); + + /* Select AGC table. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0); + + switch (rs->rfe_type) { + case 0: + case 1: + case 2: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); + break; + case 3: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337770); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337770); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01); + break; + case 4: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x00100000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x00100000); + break; + case 5: + rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x77); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); + rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0x01, 0); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); + break; + default: + break; + } + + rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0x10); + rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0x0f000000, 0x01000000); + + /* Write basic rates. */ + rtwn_set_basicrates(sc, basicrates); + + rtwn_write_1(sc, R12A_CCK_CHECK, 0); +} + +void +r12a_set_band_5ghz(struct rtwn_softc *sc, uint32_t basicrates) +{ + struct r12a_softc *rs = sc->sc_priv; + int ntries; + + rtwn_write_1(sc, R12A_CCK_CHECK, R12A_CCK_CHECK_5GHZ); + + for (ntries = 0; ntries < 100; ntries++) { + if ((rtwn_read_2(sc, R12A_TXPKT_EMPTY) & 0x30) == 0x30) + break; + + rtwn_delay(sc, 25); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "%s: TXPKT_EMPTY check failed (%04X)\n", + __func__, rtwn_read_2(sc, R12A_TXPKT_EMPTY)); + } + + /* Enable OFDM. */ + rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, R12A_OFDMCCK_EN_CCK, + R12A_OFDMCCK_EN_OFDM); + + rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x01, 0x02); + rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2a000); + + /* Select AGC table. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0x01); + + switch (rs->rfe_type) { + case 0: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + break; + case 1: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); + break; + case 2: + case 4: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337777); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + break; + case 3: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337717); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337717); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01); + break; + case 5: + rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x33); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777); + rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0, 0x01); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + break; + default: + break; + } + + rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0); + rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0, 0x0f000000); + + /* Write basic rates. */ + rtwn_set_basicrates(sc, basicrates); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c new file mode 100644 index 00000000..12a3d855 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw.c @@ -0,0 +1,196 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +void +r12a_fw_reset(struct rtwn_softc *sc, int reason) +{ + /* Reset MCU IO wrapper. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0); + rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0x08, 0); + + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_CPUEN, 0, 1); + + /* Enable MCU IO wrapper. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0); + rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0, 0x08); + + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + 0, R92C_SYS_FUNC_EN_CPUEN, 1); +} + +void +r12a_fw_download_enable(struct rtwn_softc *sc, int enable) +{ + if (enable) { + /* MCU firmware download enable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN); + /* 8051 reset. */ + rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN, + 0, 2); + } else { + /* MCU download disable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0); + } +} + +void +r12a_set_media_status(struct rtwn_softc *sc, int macid) +{ + struct r12a_fw_cmd_msrrpt status; + int error; + + if (macid & RTWN_MACID_VALID) + status.msrb0 = R12A_MSRRPT_B0_ASSOC; + else + status.msrb0 = R12A_MSRRPT_B0_DISASSOC; + + status.macid = (macid & ~RTWN_MACID_VALID); + status.macid_end = 0; + + error = r88e_fw_cmd(sc, R12A_CMD_MSR_RPT, &status, sizeof(status)); + if (error != 0) + device_printf(sc->sc_dev, "cannot change media status!\n"); +} + +int +r12a_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap, + int off) +{ + struct r12a_fw_cmd_pwrmode mode; + int error; + + if (off && vap->iv_state == IEEE80211_S_RUN && + (vap->iv_flags & IEEE80211_F_PMGTON)) { + mode.mode = R88E_PWRMODE_LEG; + /* + * TODO: switch to RFOFF state + * (something is missing here - Rx stops with it). + */ +#ifdef RTWN_TODO + mode.pwr_state = R88E_PWRMODE_STATE_RFOFF; +#else + mode.pwr_state = R88E_PWRMODE_STATE_RFON; +#endif + } else { + mode.mode = R88E_PWRMODE_CAM; + mode.pwr_state = R88E_PWRMODE_STATE_ALLON; + } + mode.pwrb1 = + SM(R88E_PWRMODE_B1_SMART_PS, R88E_PWRMODE_B1_LEG_NULLDATA) | + SM(R88E_PWRMODE_B1_RLBM, R88E_PWRMODE_B1_MODE_MIN); + /* XXX ignored */ + mode.bcn_pass = 0; + mode.queue_uapsd = 0; + mode.pwrb5 = R12A_PWRMODE_B5_NO_BTCOEX; + error = r88e_fw_cmd(sc, R12A_CMD_SET_PWRMODE, &mode, sizeof(mode)); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: CMD_SET_PWRMODE was not sent, error %d\n", + __func__, error); + } + + return (error); +} + +void +r12a_iq_calib_fw(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + struct ieee80211_channel *c = sc->sc_ic.ic_curchan; + struct r12a_fw_cmd_iq_calib cmd; + + if (rs->rs_flags & R12A_IQK_RUNNING) + return; + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "Starting IQ calibration (FW)\n"); + + cmd.chan = rtwn_chan2centieee(c); + if (IEEE80211_IS_CHAN_5GHZ(c)) + cmd.band_bw = RTWN_CMD_IQ_BAND_5GHZ; + else + cmd.band_bw = RTWN_CMD_IQ_BAND_2GHZ; + + /* TODO: 80/160 MHz. */ + if (IEEE80211_IS_CHAN_HT40(c)) + cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_40; + else + cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_20; + + cmd.ext_5g_pa_lna = RTWN_CMD_IQ_EXT_PA_5G(rs->ext_pa_5g); + cmd.ext_5g_pa_lna |= RTWN_CMD_IQ_EXT_LNA_5G(rs->ext_lna_5g); + + if (r88e_fw_cmd(sc, R12A_CMD_IQ_CALIBRATE, &cmd, sizeof(cmd)) != 0) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "error while sending IQ calibration command to FW!\n"); + return; + } + + rs->rs_flags |= R12A_IQK_RUNNING; +} +#endif diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h new file mode 100644 index 00000000..58b82ed1 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h @@ -0,0 +1,123 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12A_FW_CMD_H +#define R12A_FW_CMD_H + +#include + +/* + * Host to firmware commands. + */ +/* Note: some parts are shared with RTL8188EU. */ +#define R12A_CMD_MSR_RPT 0x01 +#define R12A_CMD_SET_PWRMODE 0x20 +#define R12A_CMD_IQ_CALIBRATE 0x45 + +/* Structure for R12A_CMD_MSR_RPT. */ +struct r12a_fw_cmd_msrrpt { + uint8_t msrb0; +#define R12A_MSRRPT_B0_DISASSOC 0x00 +#define R12A_MSRRPT_B0_ASSOC 0x01 +#define R12A_MSRRPT_B0_MACID_IND 0x02 + + uint8_t macid; + uint8_t macid_end; +} __packed; + +/* Structure for R12A_CMD_SET_PWRMODE. */ +struct r12a_fw_cmd_pwrmode { + uint8_t mode; + uint8_t pwrb1; + uint8_t bcn_pass; + uint8_t queue_uapsd; + uint8_t pwr_state; + uint8_t pwrb5; +#define R12A_PWRMODE_B5_NO_BTCOEX 0x40 +} __packed; + +/* Structure for R12A_CMD_IQ_CALIBRATE. */ +struct r12a_fw_cmd_iq_calib { + uint8_t chan; + uint8_t band_bw; +#define RTWN_CMD_IQ_CHAN_WIDTH_20 0x01 +#define RTWN_CMD_IQ_CHAN_WIDTH_40 0x02 +#define RTWN_CMD_IQ_CHAN_WIDTH_80 0x04 +#define RTWN_CMD_IQ_CHAN_WIDTH_160 0x08 +#define RTWN_CMD_IQ_BAND_2GHZ 0x10 +#define RTWN_CMD_IQ_BAND_5GHZ 0x20 + + uint8_t ext_5g_pa_lna; +#define RTWN_CMD_IQ_EXT_PA_5G(pa) (pa) +#define RTWN_CMD_IQ_EXT_LNA_5G(lna) ((lna) << 1) +} __packed; + + +/* + * C2H event types. + */ +#define R12A_C2H_DEBUG 0x00 +#define R12A_C2H_TX_REPORT 0x03 +#define R12A_C2H_BT_INFO 0x09 +#define R12A_C2H_RA_REPORT 0x0c +#define R12A_C2H_IQK_FINISHED 0x11 + +/* Structure for R12A_C2H_TX_REPORT event. */ +struct r12a_c2h_tx_rpt { + uint8_t txrptb0; +#define R12A_TXRPTB0_QSEL_M 0x1f +#define R12A_TXRPTB0_QSEL_S 0 +#define R12A_TXRPTB0_BC 0x20 +#define R12A_TXRPTB0_LIFE_EXPIRE 0x40 +#define R12A_TXRPTB0_RETRY_OVER 0x80 + + uint8_t macid; + uint8_t txrptb2; +#define R12A_TXRPTB2_RETRY_CNT_M 0x3f +#define R12A_TXRPTB2_RETRY_CNT_S 0 + + uint8_t queue_time_low; /* 256 msec unit */ + uint8_t queue_time_high; + uint8_t final_rate; + uint16_t reserved; +} __packed; + +/* Structure for R12A_C2H_RA_REPORT event. */ +struct r12a_c2h_ra_report { + uint8_t rarptb0; +#define R12A_RARPTB0_RATE_M 0x3f +#define R12A_RARPTB0_RATE_S 0 + + uint8_t macid; + uint8_t rarptb2; +#define R12A_RARPTB0_LDPC 0x01 +#define R12A_RARPTB0_TXBF 0x02 +#define R12A_RARPTB0_NOISE 0x04 +} __packed; + +#endif /* R12A_FW_CMD_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c new file mode 100644 index 00000000..4835966e --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_init.c @@ -0,0 +1,488 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include + + +int +r12a_check_condition(struct rtwn_softc *sc, const uint8_t cond[]) +{ + struct r12a_softc *rs = sc->sc_priv; + uint8_t mask[4]; + int i, j, nmasks; + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "%s: condition byte 0: %02X; ext PA/LNA: %d/%d (2 GHz), " + "%d/%d (5 GHz)\n", __func__, cond[0], rs->ext_pa_2g, + rs->ext_lna_2g, rs->ext_pa_5g, rs->ext_lna_5g); + + if (cond[0] == 0) + return (1); + + if (!rs->ext_pa_2g && !rs->ext_lna_2g && + !rs->ext_pa_5g && !rs->ext_lna_5g) + return (0); + + nmasks = 0; + if (rs->ext_pa_2g) { + mask[nmasks] = R12A_COND_GPA; + mask[nmasks] |= R12A_COND_TYPE(rs->type_pa_2g); + nmasks++; + } + if (rs->ext_pa_5g) { + mask[nmasks] = R12A_COND_APA; + mask[nmasks] |= R12A_COND_TYPE(rs->type_pa_5g); + nmasks++; + } + if (rs->ext_lna_2g) { + mask[nmasks] = R12A_COND_GLNA; + mask[nmasks] |= R12A_COND_TYPE(rs->type_lna_2g); + nmasks++; + } + if (rs->ext_lna_5g) { + mask[nmasks] = R12A_COND_ALNA; + mask[nmasks] |= R12A_COND_TYPE(rs->type_lna_5g); + nmasks++; + } + + for (i = 0; i < RTWN_MAX_CONDITIONS && cond[i] != 0; i++) + for (j = 0; j < nmasks; j++) + if ((cond[i] & mask[j]) == mask[j]) + return (1); + + return (0); +} + +int +r12a_set_page_size(struct rtwn_softc *sc) +{ + return (rtwn_setbits_1(sc, R92C_PBP, R92C_PBP_PSTX_M, + R92C_PBP_512 << R92C_PBP_PSTX_S) == 0); +} + +void +r12a_init_edca(struct rtwn_softc *sc) +{ + r92c_init_edca(sc); + + /* 80 MHz clock */ + rtwn_write_1(sc, R92C_USTIME_TSF, 0x50); + rtwn_write_1(sc, R92C_USTIME_EDCA, 0x50); +} + +void +r12a_init_bb(struct rtwn_softc *sc) +{ + int i, j; + + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, 0, R92C_SYS_FUNC_EN_USBA); + + /* Enable BB and RF. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, 0, + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST); + + /* PathA RF Power On. */ + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + + /* PathB RF Power On. */ + rtwn_write_1(sc, R12A_RF_B_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + + /* Write BB initialization values. */ + for (i = 0; i < sc->bb_size; i++) { + const struct rtwn_bb_prog *bb_prog = &sc->bb_prog[i]; + + while (!rtwn_check_condition(sc, bb_prog->cond)) { + KASSERT(bb_prog->next != NULL, + ("%s: wrong condition value (i %d)\n", + __func__, i)); + bb_prog = bb_prog->next; + } + + for (j = 0; j < bb_prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "BB: reg 0x%03x, val 0x%08x\n", + bb_prog->reg[j], bb_prog->val[j]); + + rtwn_bb_write(sc, bb_prog->reg[j], bb_prog->val[j]); + rtwn_delay(sc, 1); + } + } + + /* XXX meshpoint mode? */ + + /* Write AGC values. */ + for (i = 0; i < sc->agc_size; i++) { + const struct rtwn_agc_prog *agc_prog = &sc->agc_prog[i]; + + while (!rtwn_check_condition(sc, agc_prog->cond)) { + KASSERT(agc_prog->next != NULL, + ("%s: wrong condition value (2) (i %d)\n", + __func__, i)); + agc_prog = agc_prog->next; + } + + for (j = 0; j < agc_prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "AGC: val 0x%08x\n", agc_prog->val[j]); + + rtwn_bb_write(sc, 0x81c, agc_prog->val[j]); + rtwn_delay(sc, 1); + } + } + + for (i = 0; i < sc->nrxchains; i++) { + rtwn_bb_write(sc, R12A_INITIAL_GAIN(i), 0x22); + rtwn_delay(sc, 1); + rtwn_bb_write(sc, R12A_INITIAL_GAIN(i), 0x20); + rtwn_delay(sc, 1); + } + + rtwn_r12a_crystalcap_write(sc); + + if (rtwn_bb_read(sc, R12A_CCK_RPT_FORMAT) & R12A_CCK_RPT_FORMAT_HIPWR) + sc->sc_flags |= RTWN_FLAG_CCK_HIPWR; +} + +void +r12a_init_rf(struct rtwn_softc *sc) +{ + int chain, i; + + for (chain = 0, i = 0; chain < sc->nrxchains; chain++, i++) { + /* Write RF initialization values for this chain. */ + i += r92c_init_rf_chain(sc, &sc->rf_prog[i], chain); + } +} + +void +r12a_crystalcap_write(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + uint32_t reg; + uint8_t val; + + val = rs->crystalcap & 0x3f; + reg = rtwn_bb_read(sc, R92C_MAC_PHY_CTRL); + reg = RW(reg, R12A_MAC_PHY_CRYSTALCAP, val | (val << 6)); + rtwn_bb_write(sc, R92C_MAC_PHY_CTRL, reg); +} + +static void +r12a_rf_init_workaround(struct rtwn_softc *sc) +{ + + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_SDMRSTB); + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | + R92C_RF_CTRL_SDMRSTB); + rtwn_write_1(sc, R12A_RF_B_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_SDMRSTB); + rtwn_write_1(sc, R12A_RF_B_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | + R92C_RF_CTRL_SDMRSTB); +} + +int +r12a_power_on(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + int ntries; + + r12a_rf_init_workaround(sc); + + /* Force PWM mode. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_SPS0_CTRL + 1, 0, 0x01)); + + /* Turn off ZCD. */ + RTWN_CHK(rtwn_setbits_2(sc, 0x014, 0x0180, 0)); + + /* Enable LDO normal mode. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_LPLDO_CTRL, R92C_LPLDO_CTRL_SLEEP, + 0)); + + /* GPIO 0...7 input mode. */ + RTWN_CHK(rtwn_write_1(sc, R92C_GPIO_IOSEL, 0)); + + /* GPIO 11...8 input mode. */ + RTWN_CHK(rtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0)); + + /* Enable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS, 0, 1)); + + /* Enable 8051. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + 0, R92C_SYS_FUNC_EN_CPUEN, 1)); + + /* Disable SW LPS. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APFM_RSM, 0, 1)); + + /* Wait for power ready bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for chip power up\n"); + return (ETIMEDOUT); + } + + /* Disable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS, 0, 1)); + + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_APFM_ONMAC, 1)); + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) + return (ETIMEDOUT); + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0x0000)); + RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN | + R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) | + R92C_CR_CALTMR_EN)); + + return (0); +} + +void +r12a_power_off(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + int error, ntries; + + /* Stop Rx. */ + error = rtwn_write_1(sc, R92C_CR, 0); + if (error == ENXIO) /* hardware gone */ + return; + + /* Move card to Low Power state. */ + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + + for (ntries = 0; ntries < 10; ntries++) { + /* Should be zero if no packet is transmitting. */ + if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: failed to block Tx queues\n", + __func__); + return; + } + + /* Turn off 3-wire. */ + rtwn_write_1(sc, R12A_HSSI_PARAM1(0), 0x04); + rtwn_write_1(sc, R12A_HSSI_PARAM1(1), 0x04); + + /* CCK and OFDM are disabled, and clock are gated. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0); + + rtwn_delay(sc, 1); + + /* Reset whole BB. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0); + + /* Reset MAC TRX. */ + rtwn_write_1(sc, R92C_CR, + R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN); + + /* check if removed later. (?) */ + rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1); + + /* Respond TxOK to scheduler */ + rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, R92C_DUAL_TSF_RST_TXOK); + + /* If firmware in ram code, do reset. */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) + r12a_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); +#endif + + /* Reset MCU. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN, + 0, 1); + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* Move card to Disabled state. */ + /* Turn off 3-wire. */ + rtwn_write_1(sc, R12A_HSSI_PARAM1(0), 0x04); + rtwn_write_1(sc, R12A_HSSI_PARAM1(1), 0x04); + + /* Reset BB, close RF. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0); + + rtwn_delay(sc, 1); + + /* SPS PWM mode. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0xff, + R92C_APS_FSMCO_SOP_RCK | R92C_APS_FSMCO_SOP_ABG, 3); + + /* ANA clock = 500k. */ + rtwn_setbits_1(sc, R92C_SYS_CLKR, R92C_SYS_CLKR_ANA8M, 0); + + /* Turn off MAC by HW state machine */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_APFM_OFF, + 1); + for (ntries = 0; ntries < 10; ntries++) { + /* Wait until it will be disabled. */ + if ((rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_OFF) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: could not turn off MAC\n", + __func__); + return; + } + + /* Reset 8051. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN, + 0, 1); + + /* Fill the default value of host_CPU handshake field. */ + rtwn_write_1(sc, R92C_MCUFWDL, + R92C_MCUFWDL_EN | R92C_MCUFWDL_CHKSUM_RPT); + + rtwn_setbits_1(sc, R92C_GPIO_IO_SEL, 0xf0, 0xc0); + + /* GPIO 11 input mode, 10...8 output mode. */ + rtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0x07); + + /* GPIO 7...0, output = input */ + rtwn_write_1(sc, R92C_GPIO_OUT, 0); + + /* GPIO 7...0 output mode. */ + rtwn_write_1(sc, R92C_GPIO_IOSEL, 0xff); + + rtwn_write_1(sc, R92C_GPIO_MOD, 0); + + /* Turn on ZCD. */ + rtwn_setbits_2(sc, 0x014, 0, 0x0180); + + /* Force PFM mode. */ + rtwn_setbits_1(sc, R92C_SPS0_CTRL + 1, 0x01, 0); + + /* LDO sleep mode. */ + rtwn_setbits_1(sc, R92C_LPLDO_CTRL, 0, R92C_LPLDO_CTRL_SLEEP); + + /* ANA clock = 500k. */ + rtwn_setbits_1(sc, R92C_SYS_CLKR, R92C_SYS_CLKR_ANA8M, 0); + + /* SOP option to disable BG/MB. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0xff, + R92C_APS_FSMCO_SOP_RCK, 3); + + /* Disable RFC_0. */ + rtwn_setbits_1(sc, R92C_RF_CTRL, R92C_RF_CTRL_RSTB, 0); + + /* Disable RFC_1. */ + rtwn_setbits_1(sc, R12A_RF_B_CTRL, R92C_RF_CTRL_RSTB, 0); + + /* Enable WL suspend. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_AFSM_HSUS, + 1); + + rs->rs_flags &= ~R12A_IQK_RUNNING; +} + +void +r12a_init_intr(struct rtwn_softc *sc) +{ + rtwn_write_4(sc, R88E_HIMR, 0); + rtwn_write_4(sc, R88E_HIMRE, 0); +} + +void +r12a_init_antsel(struct rtwn_softc *sc) +{ + uint32_t reg; + + rtwn_write_1(sc, R92C_LEDCFG2, 0x82); + rtwn_bb_setbits(sc, R92C_FPGA0_RFPARAM(0), 0, 0x2000); + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(0)); + sc->sc_ant = MS(reg, R92C_FPGA0_RFIFACEOE0_ANT); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c new file mode 100644 index 00000000..e38dbd44 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_led.c @@ -0,0 +1,74 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r12a_set_led(struct rtwn_softc *sc, int led, int on) +{ + /* XXX assume led #0 == LED_LINK */ + /* XXX antenna diversity */ + + if (led == RTWN_LED_LINK) { + rtwn_setbits_1(sc, R92C_LEDCFG0, 0x8f, + R12A_LEDCFG2_ENA | (on ? 0 : R92C_LEDCFG0_DIS)); + sc->ledlink = on; /* Save LED state. */ + } + + /* XXX leds #1/#2 ? */ +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h new file mode 100644 index 00000000..e75e32fc --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_priv.h @@ -0,0 +1,852 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12A_PRIV_H +#define R12A_PRIV_H + +/* + * MAC initialization values. + */ +#define RTL8812AU_MAC_PROG_START \ + { 0x010, 0x0c }, + +#define RTL8812AU_MAC_PROG_END \ + { 0x025, 0x0f }, { 0x072, 0x00 }, { 0x420, 0x80 }, { 0x428, 0x0a }, \ + { 0x429, 0x10 }, { 0x430, 0x00 }, { 0x431, 0x00 }, { 0x432, 0x00 }, \ + { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, { 0x436, 0x07 }, \ + { 0x437, 0x08 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, { 0x43e, 0x07 }, \ + { 0x43f, 0x08 }, { 0x440, 0x5d }, { 0x441, 0x01 }, { 0x442, 0x00 }, \ + { 0x444, 0x10 }, { 0x445, 0x00 }, { 0x446, 0x00 }, { 0x447, 0x00 }, \ + { 0x448, 0x00 }, { 0x449, 0xf0 }, { 0x44a, 0x0f }, { 0x44b, 0x3e }, \ + { 0x44c, 0x10 }, { 0x44d, 0x00 }, { 0x44e, 0x00 }, { 0x44f, 0x00 }, \ + { 0x450, 0x00 }, { 0x451, 0xf0 }, { 0x452, 0x0f }, { 0x453, 0x00 }, \ + { 0x45b, 0x80 }, { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x4c8, 0xff }, \ + { 0x4c9, 0x08 }, { 0x4cc, 0xff }, { 0x4cd, 0xff }, { 0x4ce, 0x01 }, \ + { 0x500, 0x26 }, { 0x501, 0xa2 }, { 0x502, 0x2f }, { 0x503, 0x00 }, \ + { 0x504, 0x28 }, { 0x505, 0xa3 }, { 0x506, 0x5e }, { 0x507, 0x00 }, \ + { 0x508, 0x2b }, { 0x509, 0xa4 }, { 0x50a, 0x5e }, { 0x50b, 0x00 }, \ + { 0x50c, 0x4f }, { 0x50d, 0xa4 }, { 0x50e, 0x00 }, { 0x50f, 0x00 }, \ + { 0x512, 0x1c }, { 0x514, 0x0a }, { 0x516, 0x0a }, { 0x525, 0x4f }, \ + { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, { 0x55c, 0x50 }, \ + { 0x55d, 0xff }, { 0x604, 0x09 }, { 0x605, 0x30 }, { 0x607, 0x03 }, \ + { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x620, 0xff }, { 0x621, 0xff }, \ + { 0x622, 0xff }, { 0x623, 0xff }, { 0x624, 0xff }, { 0x625, 0xff }, \ + { 0x626, 0xff }, { 0x627, 0xff }, { 0x638, 0x50 }, { 0x63c, 0x0a }, \ + { 0x63d, 0x0a }, { 0x63e, 0x0e }, { 0x63f, 0x0e }, { 0x640, 0x80 }, \ + { 0x642, 0x40 }, { 0x643, 0x00 }, { 0x652, 0xc8 }, { 0x66e, 0x05 }, \ + { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, { 0x703, 0x87 }, \ + { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, { 0x70b, 0x87 }, \ + { 0x718, 0x40 } + +static const struct rtwn_mac_prog rtl8812au_mac_no_ext_pa_lna[] = { + RTL8812AU_MAC_PROG_START + { 0x11, 0x66 }, + RTL8812AU_MAC_PROG_END +}, rtl8812au_mac[] = { + RTL8812AU_MAC_PROG_START + { 0x11, 0x5a }, + RTL8812AU_MAC_PROG_END +}; + + +/* + * Baseband initialization values. + */ +#define R12A_COND_GPA 0x01 +#define R12A_COND_APA 0x02 +#define R12A_COND_GLNA 0x04 +#define R12A_COND_ALNA 0x08 +#define R12A_COND_TYPE(t) ((t) << 4) + +static const uint16_t rtl8812au_bb_regs0[] = { + 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x820, 0x824, + 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, 0x840, 0x844, 0x848, + 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, 0x864, 0x868, 0x86c, + 0x870, 0x874, 0x878, 0x87c, 0x8a0, 0x8a4, 0x8a8, 0x8ac, 0x8b0, + 0x8b4, 0x8b8, 0x8bc, 0x8c0, 0x8c4, 0x8c8, 0x8cc, 0x8d0, 0x8dc, + 0x8d4, 0x8d8, 0x8f8, 0x8fc, 0x900, 0x90c, 0x910, 0x914, 0x918, + 0x91c, 0x920, 0x924, 0x928, 0x92c, 0x930, 0x934, 0x960, 0x964, + 0x968, 0x96c, 0x970, 0x978, 0x97c, 0x980, 0x984, 0x988, 0x990, + 0x994, 0x998, 0x99c, 0x9a0, 0x9a4, 0x9a8, 0x9ac, 0x9b0, 0x9b4, + 0x9b8, 0x9bc, 0x9d0, 0x9d4, 0x9d8, 0x9dc, 0x9e4, 0x9e8, 0xa00, + 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24, + 0xa28, 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xa84, 0xb00, + 0xb04, 0xb08, 0xb0c, 0xb10, 0xb14, 0xb18, 0xb1c, 0xb20, 0xb24, + 0xb28, 0xb2c, 0xb30, 0xb34, 0xb38, 0xb3c, 0xb40, 0xb44, 0xb48, + 0xb4c, 0xb50, 0xb54, 0xb58, 0xb5c, 0xc00, 0xc04, 0xc08, 0xc0c, + 0xc10, 0xc14, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, + 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, + 0xc5c, 0xc60, 0xc64 +}, rtl8812au_bb_regs1[] = { + 0xc68 +}, rtl8812au_bb_regs2[] = { + 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc94, 0xc98, + 0xc9c, 0xca0, 0xca4, 0xca8, 0xcb0, 0xcb4, 0xcb8, 0xe00, 0xe04, + 0xe08, 0xe0c, 0xe10, 0xe14, 0xe1c, 0xe20, 0xe24, 0xe28, 0xe2c, + 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, + 0xe54, 0xe58, 0xe5c, 0xe60, 0xe64, 0xe68, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, 0xe94, 0xe98, 0xe9c, 0xea0, 0xea4, + 0xea8, 0xeb0, 0xeb4, 0xeb8 +}; + +static const uint32_t rtl8812au_bb_vals0[] = { + 0x8020d010, 0x080112e0, 0x0e028233, 0x12131113, 0x20101263, + 0x020c3d10, 0x03a00385, 0x00000000, 0x00030fe0, 0x00000000, + 0x002083dd, 0x2eaaeeb8, 0x0037a706, 0x06c89b44, 0x0000095b, + 0xc0000001, 0x40003cde, 0x6210ff8b, 0x6cfdffb8, 0x28874706, + 0x0001520c, 0x8060e000, 0x74210168, 0x6929c321, 0x79727432, + 0x8ca7a314, 0x338c2878, 0x03333333, 0x31602c2e, 0x00003152, + 0x000fc000, 0x00000013, 0x7f7f7f7f, 0xa202033e, 0x0ff0fa0a, + 0x00000600, 0x000fc080, 0x6c0057ff, 0x4ca520a3, 0x27f00020, + 0x00000000, 0x00012d69, 0x08248492, 0x0000b800, 0x00000000, + 0x940008a0, 0x290b5612, 0x400002c0, 0x00000000, 0x00000701, + 0x00000000, 0x0000fc00, 0x00000404, 0x1c1028c0, 0x64b11a1c, + 0xe0767233, 0x055aa500, 0x00000004, 0xfffe0000, 0xfffffffe, + 0x001fffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x801fffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x27100000, 0xffff0100, 0xffffff5c, 0xffffffff, + 0x000000ff, 0x00080080, 0x00000000, 0x00000000, 0x81081008, + 0x00000000, 0x01081008, 0x01081008, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000003, 0x000002d5, 0x00d047c8, + 0x01ff000c, 0x8c838300, 0x2e7f000f, 0x9500bb78, 0x11144028, + 0x00881117, 0x89140f00, 0x1a1b0000, 0x090e1217, 0x00000305, + 0x00900000, 0x101fff00, 0x00000008, 0x00000900, 0x225b0606, + 0x218075b2, 0x001f8c80, 0x03100000, 0x0000b000, 0xae0201eb, + 0x01003207, 0x00009807, 0x01000000, 0x00000002, 0x00000002, + 0x0000001f, 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, + 0x13121110, 0x17161514, 0x0000003a, 0x00000000, 0x00000000, + 0x13000032, 0x48080000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000007, 0x00042020, 0x80410231, 0x00000000, + 0x00000100, 0x01000000, 0x40000003, 0x12121212, 0x12121212, + 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, + 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, + 0x00000020, 0x0008121c, 0x30000c1c, 0x00000058, 0x34344443, + 0x07003333 +}, rtl8812au_bb_vals1_ext_pa_lna[] = { + 0x59791979 +}, rtl8812au_bb_vals1[] = { + 0x59799979 +}, rtl8812au_bb_vals2[] = { + 0x59795979, 0x19795979, 0x19795979, 0x19791979, 0x19791979, + 0x19791979, 0x19791979, 0x0100005c, 0x00000000, 0x00000000, + 0x00000029, 0x08040201, 0x80402010, 0x77547777, 0x00000077, + 0x00508242, 0x00000007, 0x00042020, 0x80410231, 0x00000000, + 0x00000100, 0x01000000, 0x40000003, 0x12121212, 0x12121212, + 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, + 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, + 0x00000020, 0x0008121c, 0x30000c1c, 0x00000058, 0x34344443, + 0x07003333, 0x59791979, 0x59795979, 0x19795979, 0x19795979, + 0x19791979, 0x19791979, 0x19791979, 0x19791979, 0x0100005c, + 0x00000000, 0x00000000, 0x00000029, 0x08040201, 0x80402010, + 0x77547777, 0x00000077, 0x00508242 +}; + +static const struct rtwn_bb_prog rtl8812au_bb[] = { + { + nitems(rtl8812au_bb_regs0), + rtl8812au_bb_regs0, + rtl8812au_bb_vals0, + { 0 }, + NULL + }, + /* + * Devices with: + * * External 2GHz PA, type 0; + * * External 5GHz PA, type 0 or 5; + * * External 2GHz LNA, type 0 or 5; + * * External 5GHz LNA, type 0; + */ + { + nitems(rtl8812au_bb_regs1), + rtl8812au_bb_regs1, + rtl8812au_bb_vals1_ext_pa_lna, + { + R12A_COND_GPA | R12A_COND_GLNA | + R12A_COND_APA | R12A_COND_ALNA | + R12A_COND_TYPE(0x0), + R12A_COND_APA | R12A_COND_GLNA | + R12A_COND_TYPE(0x5), 0 + }, + /* + * Others. + */ + &(const struct rtwn_bb_prog){ + nitems(rtl8812au_bb_regs1), + rtl8812au_bb_regs1, + rtl8812au_bb_vals1, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_bb_regs2), + rtl8812au_bb_regs2, + rtl8812au_bb_vals2, + { 0 }, + NULL + } +}; + + +static const uint32_t rtl8812au_agc_vals0_lna_g0[] = { + 0xfc000001, 0xfb020001, 0xfa040001, 0xf9060001, 0xf8080001, + 0xf70a0001, 0xf60c0001, 0xf50e0001, 0xf4100001, 0xf3120001, + 0xf2140001, 0xf1160001, 0xf0180001, 0xef1a0001, 0xee1c0001, + 0xed1e0001, 0xec200001, 0xeb220001, 0xea240001, 0xcd260001, + 0xcc280001, 0xcb2a0001, 0xca2c0001, 0xc92e0001, 0xc8300001, + 0xa6320001, 0xa5340001, 0xa4360001, 0xa3380001, 0xa23a0001, + 0x883c0001, 0x873e0001, 0x86400001, 0x85420001, 0x84440001, + 0x83460001, 0x82480001, 0x814a0001, 0x484c0001, 0x474e0001, + 0x46500001, 0x45520001, 0x44540001, 0x43560001, 0x42580001, + 0x415a0001, 0x255c0001, 0x245e0001, 0x23600001, 0x22620001, + 0x21640001, 0x21660001, 0x21680001, 0x216a0001, 0x216c0001, + 0x216e0001, 0x21700001, 0x21720001, 0x21740001, 0x21760001, + 0x21780001, 0x217a0001, 0x217c0001, 0x217e0001 +}, rtl8812au_agc_vals0_lna_g5[] = { + 0xf9000001, 0xf8020001, 0xf7040001, 0xf6060001, 0xf5080001, + 0xf40a0001, 0xf30c0001, 0xf20e0001, 0xf1100001, 0xf0120001, + 0xef140001, 0xee160001, 0xed180001, 0xec1a0001, 0xeb1c0001, + 0xea1e0001, 0xcd200001, 0xcc220001, 0xcb240001, 0xca260001, + 0xc9280001, 0xc82a0001, 0xc72c0001, 0xc62e0001, 0xa5300001, + 0xa4320001, 0xa3340001, 0xa2360001, 0x88380001, 0x873a0001, + 0x863c0001, 0x853e0001, 0x84400001, 0x83420001, 0x82440001, + 0x81460001, 0x48480001, 0x474a0001, 0x464c0001, 0x454e0001, + 0x44500001, 0x43520001, 0x42540001, 0x41560001, 0x25580001, + 0x245a0001, 0x235c0001, 0x225e0001, 0x21600001, 0x21620001, + 0x21640001, 0x21660001, 0x21680001, 0x216a0001, 0x236c0001, + 0x226e0001, 0x21700001, 0x21720001, 0x21740001, 0x21760001, + 0x21780001, 0x217a0001, 0x217c0001, 0x217e0001 +}, rtl8812au_agc_vals0[] = { + 0xff000001, 0xff020001, 0xff040001, 0xff060001, 0xff080001, + 0xfe0a0001, 0xfd0c0001, 0xfc0e0001, 0xfb100001, 0xfa120001, + 0xf9140001, 0xf8160001, 0xf7180001, 0xf61a0001, 0xf51c0001, + 0xf41e0001, 0xf3200001, 0xf2220001, 0xf1240001, 0xf0260001, + 0xef280001, 0xee2a0001, 0xed2c0001, 0xec2e0001, 0xeb300001, + 0xea320001, 0xe9340001, 0xe8360001, 0xe7380001, 0xe63a0001, + 0xe53c0001, 0xc73e0001, 0xc6400001, 0xc5420001, 0xc4440001, + 0xc3460001, 0xc2480001, 0xc14a0001, 0xa74c0001, 0xa64e0001, + 0xa5500001, 0xa4520001, 0xa3540001, 0xa2560001, 0xa1580001, + 0x675a0001, 0x665c0001, 0x655e0001, 0x64600001, 0x63620001, + 0x48640001, 0x47660001, 0x46680001, 0x456a0001, 0x446c0001, + 0x436e0001, 0x42700001, 0x41720001, 0x41740001, 0x41760001, + 0x41780001, 0x417a0001, 0x417c0001, 0x417e0001 +}, rtl8812au_agc_vals1_lna_a0[] = { + 0xfc800001, 0xfb820001, 0xfa840001, 0xf9860001, 0xf8880001, + 0xf78a0001, 0xf68c0001, 0xf58e0001, 0xf4900001, 0xf3920001, + 0xf2940001, 0xf1960001, 0xf0980001, 0xef9a0001, 0xee9c0001, + 0xed9e0001, 0xeca00001, 0xeba20001, 0xeaa40001, 0xe9a60001, + 0xe8a80001, 0xe7aa0001, 0xe6ac0001, 0xe5ae0001, 0xe4b00001, + 0xe3b20001, 0xa8b40001, 0xa7b60001, 0xa6b80001, 0xa5ba0001, + 0xa4bc0001, 0xa3be0001, 0xa2c00001, 0xa1c20001, 0x68c40001, + 0x67c60001, 0x66c80001, 0x65ca0001, 0x64cc0001, 0x47ce0001, + 0x46d00001, 0x45d20001, 0x44d40001, 0x43d60001, 0x42d80001, + 0x08da0001, 0x07dc0001, 0x06de0001, 0x05e00001, 0x04e20001, + 0x03e40001, 0x02e60001, 0x01e80001, 0x01ea0001, 0x01ec0001, + 0x01ee0001, 0x01f00001, 0x01f20001, 0x01f40001, 0x01f60001, + 0x01f80001, 0x01fa0001, 0x01fc0001, 0x01fe0001 +}, rtl8812au_agc_vals1[] = { + 0xff800001, 0xff820001, 0xff840001, 0xfe860001, 0xfd880001, + 0xfc8a0001, 0xfb8c0001, 0xfa8e0001, 0xf9900001, 0xf8920001, + 0xf7940001, 0xf6960001, 0xf5980001, 0xf49a0001, 0xf39c0001, + 0xf29e0001, 0xf1a00001, 0xf0a20001, 0xefa40001, 0xeea60001, + 0xeda80001, 0xecaa0001, 0xebac0001, 0xeaae0001, 0xe9b00001, + 0xe8b20001, 0xe7b40001, 0xe6b60001, 0xe5b80001, 0xe4ba0001, + 0xe3bc0001, 0xa8be0001, 0xa7c00001, 0xa6c20001, 0xa5c40001, + 0xa4c60001, 0xa3c80001, 0xa2ca0001, 0xa1cc0001, 0x68ce0001, + 0x67d00001, 0x66d20001, 0x65d40001, 0x64d60001, 0x47d80001, + 0x46da0001, 0x45dc0001, 0x44de0001, 0x43e00001, 0x42e20001, + 0x08e40001, 0x07e60001, 0x06e80001, 0x05ea0001, 0x04ec0001, + 0x03ee0001, 0x02f00001, 0x01f20001, 0x01f40001, 0x01f60001, + 0x01f80001, 0x01fa0001, 0x01fc0001, 0x01fe0001 +}; + +static const struct rtwn_agc_prog rtl8812au_agc[] = { + /* + * External 2GHz LNA (type 0). + */ + { + nitems(rtl8812au_agc_vals0_lna_g0), + rtl8812au_agc_vals0_lna_g0, + { R12A_COND_GLNA | R12A_COND_TYPE(0x0), 0 }, + /* + * External 2GHz LNA (type 5). + */ + &(const struct rtwn_agc_prog){ + nitems(rtl8812au_agc_vals0_lna_g5), + rtl8812au_agc_vals0_lna_g5, + { R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 }, + /* + * Others. + */ + &(const struct rtwn_agc_prog){ + nitems(rtl8812au_agc_vals0), + rtl8812au_agc_vals0, + { 0 }, + NULL + } + } + }, + /* + * External 5GHz LNA (type 0). + */ + { + nitems(rtl8812au_agc_vals1_lna_a0), + rtl8812au_agc_vals1_lna_a0, + { R12A_COND_ALNA | R12A_COND_TYPE(0x0), 0 }, + /* + * Others. + */ + &(const struct rtwn_agc_prog){ + nitems(rtl8812au_agc_vals1), + rtl8812au_agc_vals1, + { 0 }, + NULL + } + } +}; + +/* + * RF initialization values. + */ +static const uint8_t rtl8812au_rf0_regs0[] = { + 0x00, 0x18, 0x56, 0x66, 0x1e, 0x89 +}, rtl8812au_rf0_regs1[] = { + 0x86 +}, rtl8812au_rf0_regs2[] = { + 0x8b +}, rtl8812au_rf0_regs3[] = { + 0xb1, 0xb3, 0xb4, 0xba, 0x18, 0xef +}, rtl8812au_rf0_regs4[] = { + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b +}, rtl8812au_rf0_regs5[] = { + 0xef, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34 +}, rtl8812au_rf0_regs6[] = { + 0xef, 0xef, 0xdf, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xef, + 0x51, 0x52, 0x53, 0x54, 0xef, 0x08, 0x18, 0xef, 0x3a, 0x3b, 0x3c, + 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, + 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, + 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, + 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, + 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, + 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, + 0x3a, 0x3b, 0x3c, 0xef +}, rtl8812au_rf0_regs7[] = { + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 +}, rtl8812au_rf0_regs8[] = { + 0xef, 0x18, 0xef, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0xef, 0x18, 0xef, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xef, 0xef, 0x3c, 0x3c, 0x3c, +}, rtl8812au_rf0_regs9[] = { + 0xef, 0x18, 0xef, 0xdf, 0x1f +}, rtl8812au_rf0_regs10[] = { + 0x61, 0x62, 0x63, 0x64, 0x65 +}, rtl8812au_rf0_regs11[] = { + 0x08, 0x1c, 0xb4, 0x18, 0xfe, 0xfe, 0xfe, 0xfe, 0xb4, 0x18 +}, rtl8812au_rf1_regs0[] = { + 0x56, 0x66, 0x89 +}, rtl8812au_rf1_regs3[] = { + 0xb1, 0xb3, 0xb4, 0xba, 0x18, 0xef +}; + +static const uint32_t rtl8812au_rf0_vals0[] = { + 0x10000, 0x1712a, 0x51cf2, 0x40000, 0x80000, 0x00080 +}, rtl8812au_rf0_vals1_lna_g0_g5[] = { + 0x14b3a +}, rtl8812au_rf0_vals1[] = { + 0x14b38 +}, rtl8812au_rf0_vals2_lna_a0[] = { + 0x80180 +}, rtl8812au_rf0_vals2[] = { + 0x87180 +}, rtl8812au_rf0_vals3[] = { + 0x1fc1a, 0xf0810, 0x1a78d, 0x86180, 0x00006, 0x02000 +}, rtl8812au_rf0_vals4_lna_g0_g5[] = { + 0x3f218, 0x30a58, 0x2fa58, 0x22590, 0x1fa50, 0x10248, 0x08240 +}, rtl8812au_rf0_vals4[] = { + 0x38a58, 0x37a58, 0x2a590, 0x27a50, 0x18248, 0x10240, 0x08240 +}, rtl8812au_rf0_vals5_pa_g0[] = { + 0x00100, 0x0a4ee, 0x09076, 0x08073, 0x07070, 0x0606d, 0x0506a, + 0x04049, 0x03046, 0x02028, 0x01025, 0x00022 +}, rtl8812au_rf0_vals5[] = { + 0x00100, 0x0adf4, 0x09df1, 0x08dee, 0x07deb, 0x06de8, 0x05de5, + 0x04de2, 0x03ce6, 0x024e7, 0x014e4, 0x004e1 +}, rtl8812au_rf0_vals6[] = { + 0x00000, 0x020a2, 0x00080, 0x00192, 0x08192, 0x10192, 0x00024, + 0x08024, 0x10024, 0x18024, 0x00000, 0x00c21, 0x006d9, 0xfc649, + 0x0017e, 0x00002, 0x08400, 0x1712a, 0x01000, 0x00080, 0x3a02c, + 0x04000, 0x00400, 0x3202c, 0x10000, 0x000a0, 0x2b064, 0x04000, + 0x000d8, 0x23070, 0x04000, 0x00468, 0x1b870, 0x10000, 0x00098, + 0x12085, 0xe4000, 0x00418, 0x0a080, 0xf0000, 0x00418, 0x02080, + 0x10000, 0x00080, 0x7a02c, 0x04000, 0x00400, 0x7202c, 0x10000, + 0x000a0, 0x6b064, 0x04000, 0x000d8, 0x63070, 0x04000, 0x00468, + 0x5b870, 0x10000, 0x00098, 0x52085, 0xe4000, 0x00418, 0x4a080, + 0xf0000, 0x00418, 0x42080, 0x10000, 0x00080, 0xba02c, 0x04000, + 0x00400, 0xb202c, 0x10000, 0x000a0, 0xab064, 0x04000, 0x000d8, + 0xa3070, 0x04000, 0x00468, 0x9b870, 0x10000, 0x00098, 0x92085, + 0xe4000, 0x00418, 0x8a080, 0xf0000, 0x00418, 0x82080, 0x10000, + 0x01100 +}, rtl8812au_rf0_vals7_pa_a0[] = { + 0x4a0b2, 0x490af, 0x48070, 0x4706d, 0x46050, 0x4504d, 0x4404a, + 0x43047, 0x4200a, 0x41007, 0x40004, 0x2a0b2, 0x290af, 0x28070, + 0x2706d, 0x26050, 0x2504d, 0x2404a, 0x23047, 0x2200a, 0x21007, + 0x20004, 0x0a0b2, 0x090af, 0x08070, 0x0706d, 0x06050, 0x0504d, + 0x0404a, 0x03047, 0x0200a, 0x01007, 0x00004 +}, rtl8812au_rf0_vals7_pa_a5[] = { + 0x4a0b2, 0x490af, 0x48070, 0x4706d, 0x4604d, 0x4504a, 0x44047, + 0x43044, 0x42007, 0x41004, 0x40001, 0x2a0b4, 0x290b1, 0x28072, + 0x2706f, 0x2604f, 0x2504c, 0x24049, 0x23046, 0x22009, 0x21006, + 0x20003, 0x0a0b2, 0x090af, 0x08070, 0x0706d, 0x0604d, 0x0504a, + 0x04047, 0x03044, 0x02007, 0x01004, 0x00001 +}, rtl8812au_rf0_vals7[] = { + 0x4adf5, 0x49df2, 0x48def, 0x47dec, 0x46de9, 0x45de6, 0x44de3, + 0x438c8, 0x428c5, 0x418c2, 0x408c0, 0x2adf5, 0x29df2, 0x28def, + 0x27dec, 0x26de9, 0x25de6, 0x24de3, 0x238c8, 0x228c5, 0x218c2, + 0x208c0, 0x0aff7, 0x09df7, 0x08df4, 0x07df1, 0x06dee, 0x05deb, + 0x04de8, 0x038cc, 0x028c9, 0x018c6, 0x008c3 +}, rtl8812au_rf0_vals8_pa_a0_a5[] = { + 0x00000, 0x1712a, 0x00040, 0x001d4, 0x081d4, 0x101d4, 0x201b4, + 0x281b4, 0x301b4, 0x401b4, 0x481b4, 0x501b4, 0x00000, 0x1712a, + 0x00010, 0x04bfb, 0x0cbfb, 0x14bfb, 0x1cbfb, 0x24f4b, 0x2cf4b, + 0x34f4b, 0x3cf4b, 0x44f4b, 0x4cf4b, 0x54f4b, 0x5cf4b, 0x00000, + 0x00008, 0x002cc, 0x00522, 0x00902 +}, rtl8812au_rf0_vals8[] = { + 0x00000, 0x1712a, 0x00040, 0x00188, 0x08147, 0x10147, 0x201d7, + 0x281d7, 0x301d7, 0x401d8, 0x481d8, 0x501d8, 0x00000, 0x1712a, + 0x00010, 0x84eb4, 0x8cc35, 0x94c35, 0x9cc35, 0xa4c35, 0xacc35, + 0xb4c35, 0xbcc35, 0xc4c34, 0xccc35, 0xd4c35, 0xdcc35, 0x00000, + 0x00008, 0x002a8, 0x005a2, 0x00880 +}, rtl8812au_rf0_vals9[] = { + 0x00000, 0x1712a, 0x00002, 0x00080, 0x00064 +}, rtl8812au_rf0_vals10_pa_a0[] = { + 0xfdd43, 0x38f4b, 0x32117, 0x194ac, 0x931d1 +}, rtl8812au_rf0_vals10_pa_a5[] = { + 0xfdd43, 0x38f4b, 0x32117, 0x194ac, 0x931d2 +}, rtl8812au_rf0_vals10[] = { + 0xe5d53, 0x38fcd, 0x114eb, 0x196ac, 0x911d7 +}, rtl8812au_rf0_vals11[] = { + 0x08400, 0x739d2, 0x1e78d, 0x1f12a, 0x0c350, 0x0c350, 0x0c350, + 0x0c350, 0x1a78d, 0x1712a +}, rtl8812au_rf1_vals0[] = { + 0x51cf2, 0x40000, 0x00080 +}, rtl8812au_rf1_vals3[] = { + 0x1fc1a, 0xf0810, 0x1a78d, 0x86180, 0x00006, 0x02000 +}, rtl8812au_rf1_vals6[] = { + 0x00000, 0x020a2, 0x00080, 0x00192, 0x08192, 0x10192, 0x00024, + 0x08024, 0x10024, 0x18024, 0x00000, 0x00c21, 0x006d9, 0xfc649, + 0x0017e, 0x00002, 0x08400, 0x1712a, 0x01000, 0x00080, 0x3a02c, + 0x04000, 0x00400, 0x3202c, 0x10000, 0x000a0, 0x2b064, 0x04000, + 0x000d8, 0x23070, 0x04000, 0x00468, 0x1b870, 0x10000, 0x00098, + 0x12085, 0xe4000, 0x00418, 0x0a080, 0xf0000, 0x00418, 0x02080, + 0x10000, 0x00080, 0x7a02c, 0x04000, 0x00400, 0x7202c, 0x10000, + 0x000a0, 0x6b064, 0x04000, 0x000d8, 0x63070, 0x04000, 0x00468, + 0x5b870, 0x10000, 0x00098, 0x52085, 0xe4000, 0x00418, 0x4a080, + 0xf0000, 0x00418, 0x42080, 0x10000, 0x00080, 0xba02c, 0x04000, + 0x00400, 0xb202c, 0x10000, 0x000a0, 0xab064, 0x04000, 0x000d8, + 0xa3070, 0x04000, 0x00468, 0x9b870, 0x10000, 0x00098, 0x92085, + 0xe4000, 0x00418, 0x8a080, 0xf0000, 0x00418, 0x82080, 0x10000, + 0x01100 +}, rtl8812au_rf1_vals7_pa_a5[] = { + 0x4a0b1, 0x490ae, 0x4806f, 0x4706c, 0x4604c, 0x45049, 0x44046, + 0x43043, 0x42006, 0x41003, 0x40000, 0x2a0b3, 0x290b0, 0x28071, + 0x2706e, 0x2604e, 0x2504b, 0x24048, 0x23045, 0x22008, 0x21005, + 0x20002, 0x0a0b3, 0x090b0, 0x08070, 0x0706d, 0x0604d, 0x0504a, + 0x04047, 0x03044, 0x02007, 0x01004, 0x00001 +}, rtl8812au_rf1_vals8_pa_a0_a5[] = { + 0x00000, 0x1712a, 0x00040, 0x001c5, 0x081c5, 0x101c5, 0x20174, + 0x28174, 0x30174, 0x40185, 0x48185, 0x50185, 0x00000, 0x1712a, + 0x00010, 0x05b8b, 0x0db8b, 0x15b8b, 0x1db8b, 0x262db, 0x2e2db, + 0x362db, 0x3e2db, 0x4553b, 0x4d53b, 0x5553b, 0x5d53b, 0x00000, + 0x00008, 0x002dc, 0x00524, 0x00902 +}, rtl8812au_rf1_vals10_pa_g0_a0[] = { + 0xeac43, 0x38f47, 0x31157, 0x1c4ac, 0x931d1 +}, rtl8812au_rf1_vals10_pa_a5[] = { + 0xeac43, 0x38f47, 0x31157, 0x1c4ac, 0x931d2 +}; + +static const struct rtwn_rf_prog rtl8812au_rf[] = { + /* RF chain 0. */ + { + nitems(rtl8812au_rf0_regs0), + rtl8812au_rf0_regs0, + rtl8812au_rf0_vals0, + { 0 }, + NULL + }, + /* External 2GHz LNA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs1), + rtl8812au_rf0_regs1, + rtl8812au_rf0_vals1_lna_g0_g5, + { + R12A_COND_GLNA | R12A_COND_TYPE(0x0), + R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 + }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs1), + rtl8812au_rf0_regs1, + rtl8812au_rf0_vals1, + { 0 }, + NULL + } + }, + /* External 5GHz LNA, type 0. */ + { + nitems(rtl8812au_rf0_regs2), + rtl8812au_rf0_regs2, + rtl8812au_rf0_vals2_lna_a0, + { R12A_COND_ALNA | R12A_COND_TYPE(0x0), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs2), + rtl8812au_rf0_regs2, + rtl8812au_rf0_vals2, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs3), + rtl8812au_rf0_regs3, + rtl8812au_rf0_vals3, + { 0 }, + NULL + }, + /* External 2GHz LNA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs4), + rtl8812au_rf0_regs4, + rtl8812au_rf0_vals4_lna_g0_g5, + { + R12A_COND_GLNA | R12A_COND_TYPE(0x0), + R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 + }, + /* Others */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs4), + rtl8812au_rf0_regs4, + rtl8812au_rf0_vals4, + { 0 }, + NULL + } + }, + /* External 2GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs5), + rtl8812au_rf0_regs5, + rtl8812au_rf0_vals5_pa_g0, + { R12A_COND_GPA | R12A_COND_TYPE(0x0), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs5), + rtl8812au_rf0_regs5, + rtl8812au_rf0_vals5, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs6), + rtl8812au_rf0_regs6, + rtl8812au_rf0_vals6, + { 0 }, + NULL + }, + /* External 5GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7_pa_a0, + { R12A_COND_APA | R12A_COND_TYPE(0x0), 0 }, + /* External 5GHz PA, type 5. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7_pa_a5, + { R12A_COND_APA | R12A_COND_TYPE(0x5), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7, + { 0 }, + NULL + } + } + }, + /* External 5GHz PA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs8), + rtl8812au_rf0_regs8, + rtl8812au_rf0_vals8_pa_a0_a5, + { + R12A_COND_APA | R12A_COND_TYPE(0x0), + R12A_COND_APA | R12A_COND_TYPE(0x5), 0 + }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs8), + rtl8812au_rf0_regs8, + rtl8812au_rf0_vals8, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs9), + rtl8812au_rf0_regs9, + rtl8812au_rf0_vals9, + { 0 }, + NULL + }, + /* External 5GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf0_vals10_pa_a0, + { R12A_COND_APA | R12A_COND_TYPE(0x0), 0 }, + /* External 5GHz PA, type 5. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf0_vals10_pa_a5, + { R12A_COND_APA | R12A_COND_TYPE(0x5), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf0_vals10, + { 0 }, + NULL + } + } + }, + { + nitems(rtl8812au_rf0_regs11), + rtl8812au_rf0_regs11, + rtl8812au_rf0_vals11, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL }, + /* RF chain 1. */ + { + nitems(rtl8812au_rf1_regs0), + rtl8812au_rf1_regs0, + rtl8812au_rf1_vals0, + { 0 }, + NULL + }, + /* rtl8812au_rf[1] */ + /* External 2GHz LNA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs1), + rtl8812au_rf0_regs1, + rtl8812au_rf0_vals1_lna_g0_g5, + { + R12A_COND_GLNA | R12A_COND_TYPE(0x0), + R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 + }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs1), + rtl8812au_rf0_regs1, + rtl8812au_rf0_vals1, + { 0 }, + NULL + } + }, + /* rtl8812au_rf[2] */ + /* External 5GHz LNA, type 0. */ + { + nitems(rtl8812au_rf0_regs2), + rtl8812au_rf0_regs2, + rtl8812au_rf0_vals2_lna_a0, + { R12A_COND_ALNA | R12A_COND_TYPE(0x0), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs2), + rtl8812au_rf0_regs2, + rtl8812au_rf0_vals2, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf1_regs3), + rtl8812au_rf1_regs3, + rtl8812au_rf1_vals3, + { 0 }, + NULL + }, + /* rtl8812au_rf[4] */ + /* External 2GHz LNA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs4), + rtl8812au_rf0_regs4, + rtl8812au_rf0_vals4_lna_g0_g5, + { + R12A_COND_GLNA | R12A_COND_TYPE(0x0), + R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 + }, + /* Others */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs4), + rtl8812au_rf0_regs4, + rtl8812au_rf0_vals4, + { 0 }, + NULL + } + }, + /* rtl8812au_rf[5] */ + /* External 2GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs5), + rtl8812au_rf0_regs5, + rtl8812au_rf0_vals5_pa_g0, + { R12A_COND_GPA | R12A_COND_TYPE(0x0), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs5), + rtl8812au_rf0_regs5, + rtl8812au_rf0_vals5, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs6), + rtl8812au_rf0_regs6, + rtl8812au_rf1_vals6, + { 0 }, + NULL + }, + /* External 5GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7_pa_a0, + { R12A_COND_APA | R12A_COND_TYPE(0x0), 0 }, + /* External 5GHz PA, type 5. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf1_vals7_pa_a5, + { R12A_COND_APA | R12A_COND_TYPE(0x5), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7, + { 0 }, + NULL + } + } + }, + /* External 5GHz PA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs8), + rtl8812au_rf0_regs8, + rtl8812au_rf1_vals8_pa_a0_a5, + { + R12A_COND_APA | R12A_COND_TYPE(0x0), + R12A_COND_APA | R12A_COND_TYPE(0x5), 0 + }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs8), + rtl8812au_rf0_regs8, + rtl8812au_rf0_vals8, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs9) - 1, + rtl8812au_rf0_regs9, + rtl8812au_rf0_vals9, + { 0 }, + NULL + }, + + /* External 2GHz or 5GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf1_vals10_pa_g0_a0, + { + R12A_COND_GPA | R12A_COND_TYPE(0x0), + R12A_COND_APA | R12A_COND_TYPE(0x0), 0 + }, + /* External 5GHz PA, type 5. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf1_vals10_pa_a5, + { R12A_COND_APA | R12A_COND_TYPE(0x5), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf0_vals10, + { 0 }, + NULL + } + } + }, + { + 1, + rtl8812au_rf0_regs11, + rtl8812au_rf0_vals11, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL } +}; + + +/* + * Registers to save before IQ calibration. + */ +static const uint16_t r12a_iq_bb_regs[] = { + 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0xe00, 0x838, 0x82c +}; + +static const uint16_t r12a_iq_afe_regs[] = { + 0xc5c, 0xc60, 0xc64, 0xc68, 0xcb0, 0xcb4, 0xe5c, 0xe60, 0xe64, + 0xe68, 0xeb0, 0xeb4 +}; + +static const uint8_t r12a_iq_rf_regs[] = { + 0x65, 0x8f, 0x0 +}; + +#endif /* R12A_PRIV_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h new file mode 100644 index 00000000..41cc160f --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_reg.h @@ -0,0 +1,236 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12A_REG_H +#define R12A_REG_H + +#include + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R12A_SDIO_CTRL 0x070 +#define R12A_RF_B_CTRL 0x076 +/* Rx DMA Configuration. */ +#define R12A_RXDMA_PRO 0x290 +#define R12A_EARLY_MODE_CONTROL 0x2bc +/* Protocol Configuration. */ +#define R12A_TXPKT_EMPTY 0x41a +#define R12A_ARFR_5G(i) (0x444 + (i) * 8) +#define R12A_CCK_CHECK 0x454 +#define R12A_AMPDU_MAX_TIME 0x456 +#define R12A_AMPDU_MAX_LENGTH R92C_AGGLEN_LMT +#define R12A_DATA_SEC 0x483 +#define R12A_ARFR_2G(i) (0x48c + (i) * 8) +#define R12A_HT_SINGLE_AMPDU 0x4c7 + + +/* Bits for R92C_MAC_PHY_CTRL. */ +#define R12A_MAC_PHY_CRYSTALCAP_M 0x7ff80000 +#define R12A_MAC_PHY_CRYSTALCAP_S 19 + +/* Bits for R92C_LEDCFG2. */ +#define R12A_LEDCFG2_ENA 0x20 + +/* Bits for R12A_CCK_CHECK. */ +#define R12A_CCK_CHECK_BCN1 0x20 +#define R12A_CCK_CHECK_5GHZ 0x80 + +/* Bits for R12A_DATA_SEC. */ +#define R12A_DATA_SEC_NO_EXT 0x00 +#define R12A_DATA_SEC_PRIM_UP_20 0x01 +#define R12A_DATA_SEC_PRIM_DOWN_20 0x02 +#define R12A_DATA_SEC_PRIM_UPPER_20 0x03 +#define R12A_DATA_SEC_PRIM_LOWER_20 0x04 +#define R12A_DATA_SEC_PRIM_UP_40 0x90 +#define R12A_DATA_SEC_PRIM_DOWN_40 0xa0 + +/* Bits for R12A_HT_SINGLE_AMPDU. */ +#define R12A_HT_SINGLE_AMPDU_PKT_ENA 0x80 + +/* Bits for R92C_RCR. */ +#define R12A_RCR_DIS_CHK_14 0x00200000 +#define R12A_RCR_TCP_OFFLD_EN 0x02000000 +#define R12A_RCR_VHT_ACK 0x04000000 + + +/* + * Baseband registers. + */ +#define R12A_CCK_RPT_FORMAT 0x804 +#define R12A_OFDMCCK_EN 0x808 +#define R12A_RX_PATH R12A_OFDMCCK_EN +#define R12A_TX_PATH 0x80c +#define R12A_TXAGC_TABLE_SELECT 0x82c +#define R12A_PWED_TH 0x830 +#define R12A_BW_INDICATION 0x834 +#define R12A_CCA_ON_SEC 0x838 +#define R12A_L1_PEAK_TH 0x848 +#define R12A_FC_AREA 0x860 +#define R12A_RFMOD 0x8ac +#define R12A_HSSI_PARAM2 0x8b0 +#define R12A_ADC_BUF_CLK 0x8c4 +#define R12A_ANTSEL_SW 0x900 +#define R12A_SINGLETONE_CONT_TX 0x914 +#define R12A_CCK_RX_PATH 0xa04 +#define R12A_HSSI_PARAM1(chain) (0xc00 + (chain) * 0x200) +#define R12A_TX_SCALE(chain) (0xc1c + (chain) * 0x200) +#define R12A_TXAGC_CCK11_1(chain) (0xc20 + (chain) * 0x200) +#define R12A_TXAGC_OFDM18_6(chain) (0xc24 + (chain) * 0x200) +#define R12A_TXAGC_OFDM54_24(chain) (0xc28 + (chain) * 0x200) +#define R12A_TXAGC_MCS3_0(chain) (0xc2c + (chain) * 0x200) +#define R12A_TXAGC_MCS7_4(chain) (0xc30 + (chain) * 0x200) +#define R12A_TXAGC_MCS11_8(chain) (0xc34 + (chain) * 0x200) +#define R12A_TXAGC_MCS15_12(chain) (0xc38 + (chain) * 0x200) +#define R12A_TXAGC_NSS1IX3_1IX0(chain) (0xc3c + (chain) * 0x200) +#define R12A_TXAGC_NSS1IX7_1IX4(chain) (0xc40 + (chain) * 0x200) +#define R12A_TXAGC_NSS2IX1_1IX8(chain) (0xc44 + (chain) * 0x200) +#define R12A_TXAGC_NSS2IX5_2IX2(chain) (0xc48 + (chain) * 0x200) +#define R12A_TXAGC_NSS2IX9_2IX6(chain) (0xc4c + (chain) * 0x200) +#define R12A_INITIAL_GAIN(chain) (0xc50 + (chain) * 0x200) +#define R12A_AFE_POWER_1(chain) (0xc60 + (chain) * 0x200) +#define R12A_AFE_POWER_2(chain) (0xc64 + (chain) * 0x200) +#define R12A_SLEEP_NAV(chain) (0xc80 + (chain) * 0x200) +#define R12A_PMPD(chain) (0xc84 + (chain) * 0x200) +#define R12A_LSSI_PARAM(chain) (0xc90 + (chain) * 0x200) +#define R12A_RFE_PINMUX(chain) (0xcb0 + (chain) * 0x200) +#define R12A_RFE_INV(chain) (0xcb4 + (chain) * 0x200) +#define R12A_RFE(chain) (0xcb8 + (chain) * 0x200) +#define R12A_HSPI_READBACK(chain) (0xd04 + (chain) * 0x40) +#define R12A_LSSI_READBACK(chain) (0xd08 + (chain) * 0x40) + +/* Bits for R12A_CCK_RPT_FORMAT. */ +#define R12A_CCK_RPT_FORMAT_HIPWR 0x00010000 + +/* Bits for R12A_OFDMCCK_EN. */ +#define R12A_OFDMCCK_EN_CCK 0x10000000 +#define R12A_OFDMCCK_EN_OFDM 0x20000000 + +/* Bits for R12A_CCA_ON_SEC. */ +#define R12A_CCA_ON_SEC_EXT_CHAN_M 0xf0000000 +#define R12A_CCA_ON_SEC_EXT_CHAN_S 28 + +/* Bits for R12A_RFE_PINMUX(i). */ +#define R12A_RFE_PINMUX_PA_A_MASK 0x000000f0 +#define R12A_RFE_PINMUX_LNA_MASK 0x0000f000 + +/* Bits for R12A_RFMOD. */ +#define R12A_RFMOD_EXT_CHAN_M 0x3C +#define R12A_RFMOD_EXT_CHAN_S 2 + +/* Bits for R12A_HSSI_PARAM2. */ +#define R12A_HSSI_PARAM2_READ_ADDR_MASK 0xff + +/* Bits for R12A_HSSI_PARAM1(i). */ +#define R12A_HSSI_PARAM1_PI 0x00000004 + +/* Bits for R12A_TX_SCALE(i). */ +#define R12A_TX_SCALE_SWING_M 0xffe00000 +#define R12A_TX_SCALE_SWING_S 21 + +/* Bits for R12A_TXAGC_CCK11_1(i). */ +#define R12A_TXAGC_CCK1_M 0x000000ff +#define R12A_TXAGC_CCK1_S 0 +#define R12A_TXAGC_CCK2_M 0x0000ff00 +#define R12A_TXAGC_CCK2_S 8 +#define R12A_TXAGC_CCK55_M 0x00ff0000 +#define R12A_TXAGC_CCK55_S 16 +#define R12A_TXAGC_CCK11_M 0xff000000 +#define R12A_TXAGC_CCK11_S 24 + +/* Bits for R12A_TXAGC_OFDM18_6(i). */ +#define R12A_TXAGC_OFDM06_M 0x000000ff +#define R12A_TXAGC_OFDM06_S 0 +#define R12A_TXAGC_OFDM09_M 0x0000ff00 +#define R12A_TXAGC_OFDM09_S 8 +#define R12A_TXAGC_OFDM12_M 0x00ff0000 +#define R12A_TXAGC_OFDM12_S 16 +#define R12A_TXAGC_OFDM18_M 0xff000000 +#define R12A_TXAGC_OFDM18_S 24 + +/* Bits for R12A_TXAGC_OFDM54_24(i). */ +#define R12A_TXAGC_OFDM24_M 0x000000ff +#define R12A_TXAGC_OFDM24_S 0 +#define R12A_TXAGC_OFDM36_M 0x0000ff00 +#define R12A_TXAGC_OFDM36_S 8 +#define R12A_TXAGC_OFDM48_M 0x00ff0000 +#define R12A_TXAGC_OFDM48_S 16 +#define R12A_TXAGC_OFDM54_M 0xff000000 +#define R12A_TXAGC_OFDM54_S 24 + +/* Bits for R12A_TXAGC_MCS3_0(i). */ +#define R12A_TXAGC_MCS0_M 0x000000ff +#define R12A_TXAGC_MCS0_S 0 +#define R12A_TXAGC_MCS1_M 0x0000ff00 +#define R12A_TXAGC_MCS1_S 8 +#define R12A_TXAGC_MCS2_M 0x00ff0000 +#define R12A_TXAGC_MCS2_S 16 +#define R12A_TXAGC_MCS3_M 0xff000000 +#define R12A_TXAGC_MCS3_S 24 + +/* Bits for R12A_TXAGC_MCS7_4(i). */ +#define R12A_TXAGC_MCS4_M 0x000000ff +#define R12A_TXAGC_MCS4_S 0 +#define R12A_TXAGC_MCS5_M 0x0000ff00 +#define R12A_TXAGC_MCS5_S 8 +#define R12A_TXAGC_MCS6_M 0x00ff0000 +#define R12A_TXAGC_MCS6_S 16 +#define R12A_TXAGC_MCS7_M 0xff000000 +#define R12A_TXAGC_MCS7_S 24 + +/* Bits for R12A_TXAGC_MCS11_8(i). */ +#define R12A_TXAGC_MCS8_M 0x000000ff +#define R12A_TXAGC_MCS8_S 0 +#define R12A_TXAGC_MCS9_M 0x0000ff00 +#define R12A_TXAGC_MCS9_S 8 +#define R12A_TXAGC_MCS10_M 0x00ff0000 +#define R12A_TXAGC_MCS10_S 16 +#define R12A_TXAGC_MCS11_M 0xff000000 +#define R12A_TXAGC_MCS11_S 24 + +/* Bits for R12A_TXAGC_MCS15_12(i). */ +#define R12A_TXAGC_MCS12_M 0x000000ff +#define R12A_TXAGC_MCS12_S 0 +#define R12A_TXAGC_MCS13_M 0x0000ff00 +#define R12A_TXAGC_MCS13_S 8 +#define R12A_TXAGC_MCS14_M 0x00ff0000 +#define R12A_TXAGC_MCS14_S 16 +#define R12A_TXAGC_MCS15_M 0xff000000 +#define R12A_TXAGC_MCS15_S 24 + + +/* + * RF (6052) registers. + */ +#define R12A_RF_LCK 0xb4 + +/* Bits for R12A_RF_LCK. */ +#define R12A_RF_LCK_MODE 0x4000 + +#endif /* R12A_REG_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c new file mode 100644 index 00000000..29922ba2 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rf.c @@ -0,0 +1,112 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +uint32_t +r12a_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr) +{ + uint32_t pi_mode, val; + + /* Turn off CCA (avoids reading the wrong value). */ + if (addr != R92C_RF_AC) + rtwn_bb_setbits(sc, R12A_CCA_ON_SEC, 0, 0x08); + + val = rtwn_bb_read(sc, R12A_HSSI_PARAM1(chain)); + pi_mode = (val & R12A_HSSI_PARAM1_PI) ? 1 : 0; + + rtwn_bb_setbits(sc, R12A_HSSI_PARAM2, + R12A_HSSI_PARAM2_READ_ADDR_MASK, addr); + + val = rtwn_bb_read(sc, pi_mode ? R12A_HSPI_READBACK(chain) : + R12A_LSSI_READBACK(chain)); + + /* Turn on CCA (when exiting). */ + if (addr != R92C_RF_AC) + rtwn_bb_setbits(sc, R12A_CCA_ON_SEC, 0x08, 0); + + return (MS(val, R92C_LSSI_READBACK_DATA)); +} + +uint32_t +r12a_c_cut_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr) +{ + uint32_t pi_mode, val; + + val = rtwn_bb_read(sc, R12A_HSSI_PARAM1(chain)); + pi_mode = (val & R12A_HSSI_PARAM1_PI) ? 1 : 0; + + rtwn_bb_setbits(sc, R12A_HSSI_PARAM2, + R12A_HSSI_PARAM2_READ_ADDR_MASK, addr); + rtwn_delay(sc, 20); + + val = rtwn_bb_read(sc, pi_mode ? R12A_HSPI_READBACK(chain) : + R12A_LSSI_READBACK(chain)); + + return (MS(val, R92C_LSSI_READBACK_DATA)); +} + +void +r12a_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, + uint32_t val) +{ + rtwn_bb_write(sc, R12A_LSSI_PARAM(chain), + SM(R88E_LSSI_PARAM_ADDR, addr) | + SM(R92C_LSSI_PARAM_DATA, val)); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c new file mode 100644 index 00000000..a6a0b8c1 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom.c @@ -0,0 +1,224 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +void +r12a_parse_rom_common(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r12a_softc *rs = sc->sc_priv; + struct r12a_rom *rom = (struct r12a_rom *)buf; + int i, j, k; + + sc->thermal_meter = rom->thermal_meter; + rs->crystalcap = RTWN_GET_ROM_VAR(rom->crystalcap, + R12A_ROM_CRYSTALCAP_DEF); + rs->tx_bbswing_2g = RTWN_GET_ROM_VAR(rom->tx_bbswing_2g, 0); + rs->tx_bbswing_5g = RTWN_GET_ROM_VAR(rom->tx_bbswing_5g, 0); + + for (i = 0; i < sc->ntxchains; i++) { + struct r12a_tx_pwr_2g *pwr_2g = &rom->tx_pwr[i].pwr_2g; + struct r12a_tx_pwr_5g *pwr_5g = &rom->tx_pwr[i].pwr_5g; + struct r12a_tx_pwr_diff_2g *pwr_diff_2g = + &rom->tx_pwr[i].pwr_diff_2g; + struct r12a_tx_pwr_diff_5g *pwr_diff_5g = + &rom->tx_pwr[i].pwr_diff_5g; + + for (j = 0; j < R12A_GROUP_2G - 1; j++) { + rs->cck_tx_pwr[i][j] = + RTWN_GET_ROM_VAR(pwr_2g->cck[j], + R12A_DEF_TX_PWR_2G); + rs->ht40_tx_pwr_2g[i][j] = + RTWN_GET_ROM_VAR(pwr_2g->ht40[j], + R12A_DEF_TX_PWR_2G); + } + rs->cck_tx_pwr[i][j] = RTWN_GET_ROM_VAR(pwr_2g->cck[j], + R12A_DEF_TX_PWR_2G); + + rs->cck_tx_pwr_diff_2g[i][0] = 0; + rs->ofdm_tx_pwr_diff_2g[i][0] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->ht20_ofdm, LOW_PART)); + rs->bw20_tx_pwr_diff_2g[i][0] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->ht20_ofdm, HIGH_PART)); + rs->bw40_tx_pwr_diff_2g[i][0] = 0; + + for (j = 1, k = 0; k < nitems(pwr_diff_2g->diff123); j++, k++) { + rs->cck_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->diff123[k].ofdm_cck, LOW_PART)); + rs->ofdm_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->diff123[k].ofdm_cck, HIGH_PART)); + rs->bw20_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->diff123[k].ht40_ht20, LOW_PART)); + rs->bw40_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->diff123[k].ht40_ht20, HIGH_PART)); + } + + for (j = 0; j < R12A_GROUP_5G; j++) { + rs->ht40_tx_pwr_5g[i][j] = + RTWN_GET_ROM_VAR(pwr_5g->ht40[j], + R12A_DEF_TX_PWR_5G); + } + + rs->ofdm_tx_pwr_diff_5g[i][0] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht20_ofdm, LOW_PART)); + rs->ofdm_tx_pwr_diff_5g[i][1] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ofdm_ofdm[0], HIGH_PART)); + rs->ofdm_tx_pwr_diff_5g[i][2] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ofdm_ofdm[0], LOW_PART)); + rs->ofdm_tx_pwr_diff_5g[i][3] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ofdm_ofdm[1], LOW_PART)); + + rs->bw20_tx_pwr_diff_5g[i][0] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht20_ofdm, HIGH_PART)); + rs->bw40_tx_pwr_diff_5g[i][0] = 0; + for (j = 1, k = 0; k < nitems(pwr_diff_5g->ht40_ht20); + j++, k++) { + rs->bw20_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht40_ht20[k], LOW_PART)); + rs->bw40_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht40_ht20[k], HIGH_PART)); + } + + for (j = 0; j < nitems(pwr_diff_5g->ht80_ht160); j++) { + rs->bw80_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht80_ht160[j], HIGH_PART)); + rs->bw160_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht80_ht160[j], LOW_PART)); + } + } + + rs->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY); + rs->board_type = + MS(RTWN_GET_ROM_VAR(rom->rf_board_opt, R92C_BOARD_TYPE_DONGLE), + R92C_ROM_RF1_BOARD_TYPE); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type=%d\n", + __func__, rs->regulatory); +} + +void +r12a_parse_rom(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r12a_softc *rs = sc->sc_priv; + struct r12a_rom *rom = (struct r12a_rom *)buf; + uint8_t pa_type, lna_type_2g, lna_type_5g; + + /* Read PA/LNA types. */ + pa_type = RTWN_GET_ROM_VAR(rom->pa_type, 0); + lna_type_2g = RTWN_GET_ROM_VAR(rom->lna_type_2g, 0); + lna_type_5g = RTWN_GET_ROM_VAR(rom->lna_type_5g, 0); + + rs->ext_pa_2g = R12A_ROM_IS_PA_EXT_2GHZ(pa_type); + rs->ext_pa_5g = R12A_ROM_IS_PA_EXT_5GHZ(pa_type); + rs->ext_lna_2g = R21A_ROM_IS_LNA_EXT(lna_type_2g); + rs->ext_lna_5g = R21A_ROM_IS_LNA_EXT(lna_type_5g); + rs->bt_coex = (MS(rom->rf_board_opt, R92C_ROM_RF1_BOARD_TYPE) == + R92C_BOARD_TYPE_HIGHPA); + rs->bt_ant_num = (rom->rf_bt_opt & R12A_RF_BT_OPT_ANT_NUM); + + if (rs->ext_pa_2g) { + rs->type_pa_2g = + R12A_GET_ROM_PA_TYPE(lna_type_2g, 0) | + (R12A_GET_ROM_PA_TYPE(lna_type_2g, 1) << 2); + } + if (rs->ext_pa_5g) { + rs->type_pa_5g = + R12A_GET_ROM_PA_TYPE(lna_type_5g, 0) | + (R12A_GET_ROM_PA_TYPE(lna_type_5g, 1) << 2); + } + if (rs->ext_lna_2g) { + rs->type_lna_2g = + R12A_GET_ROM_LNA_TYPE(lna_type_2g, 0) | + (R12A_GET_ROM_LNA_TYPE(lna_type_2g, 1) << 2); + } + if (rs->ext_lna_5g) { + rs->type_lna_5g = + R12A_GET_ROM_LNA_TYPE(lna_type_5g, 0) | + (R12A_GET_ROM_LNA_TYPE(lna_type_5g, 1) << 2); + } + + if (rom->rfe_option & 0x80) { + if (rs->ext_lna_5g) { + if (rs->ext_pa_5g) { + if (rs->ext_pa_2g && rs->ext_lna_2g) + rs->rfe_type = 3; + else + rs->rfe_type = 0; + } else + rs->rfe_type = 2; + } else + rs->rfe_type = 4; + } else { + rs->rfe_type = rom->rfe_option & 0x3f; + + /* workaround for incorrect EFUSE map */ + if (rs->rfe_type == 4 && + rs->ext_pa_2g && rs->ext_lna_2g && + rs->ext_pa_5g && rs->ext_lna_5g) + rs->rfe_type = 0; + } + + /* Read MAC address. */ + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr_12a); + + /* Execute common part of initialization. */ + r12a_parse_rom_common(sc, buf); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h new file mode 100644 index 00000000..4cdb8b54 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12A_ROM_DEFS_H +#define R12A_ROM_DEFS_H + +#include + +#define R12A_GROUP_2G 6 +#define R12A_GROUP_5G 14 + +#define R12A_MAX_TX_COUNT 4 +#define R12A_MAX_RF_PATH 4 + +#define R12A_EFUSE_MAX_LEN 512 +#define R12A_EFUSE_MAP_LEN 512 + +#endif /* R12A_ROM_DEFS_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h new file mode 100644 index 00000000..1f992e1e --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rom_image.h @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12A_ROM_IMAGE_H +#define R12A_ROM_IMAGE_H + +#include + +#define R12A_DEF_TX_PWR_2G 0x2d +#define R12A_DEF_TX_PWR_5G 0xfe + +struct r12a_tx_pwr_2g { + uint8_t cck[R12A_GROUP_2G]; + uint8_t ht40[R12A_GROUP_2G - 1]; +} __packed; + +struct r12a_tx_pwr_diff_2g { + uint8_t ht20_ofdm; + struct { + uint8_t ht40_ht20; + uint8_t ofdm_cck; + } __packed diff123[R12A_MAX_TX_COUNT - 1]; +} __packed; + +struct r12a_tx_pwr_5g { + uint8_t ht40[R12A_GROUP_5G]; +} __packed; + +struct r12a_tx_pwr_diff_5g { + uint8_t ht20_ofdm; + uint8_t ht40_ht20[R12A_MAX_TX_COUNT - 1]; + uint8_t ofdm_ofdm[2]; + uint8_t ht80_ht160[R12A_MAX_TX_COUNT]; +} __packed; + +struct r12a_tx_pwr { + struct r12a_tx_pwr_2g pwr_2g; + struct r12a_tx_pwr_diff_2g pwr_diff_2g; + struct r12a_tx_pwr_5g pwr_5g; + struct r12a_tx_pwr_diff_5g pwr_diff_5g; +} __packed; + +/* + * RTL8812AU/RTL8821AU ROM image. + */ +struct r12a_rom { + uint8_t reserved1[16]; + struct r12a_tx_pwr tx_pwr[R12A_MAX_RF_PATH]; + uint8_t channel_plan; + uint8_t crystalcap; +#define R12A_ROM_CRYSTALCAP_DEF 0x20 + + uint8_t thermal_meter; + uint8_t iqk_lck; + uint8_t pa_type; +#define R12A_ROM_IS_PA_EXT_2GHZ(pa_type) (((pa_type) & 0x30) == 0x30) +#define R12A_ROM_IS_PA_EXT_5GHZ(pa_type) (((pa_type) & 0x03) == 0x03) +#define R21A_ROM_IS_PA_EXT_2GHZ(pa_type) (((pa_type) & 0x10) == 0x10) +#define R21A_ROM_IS_PA_EXT_5GHZ(pa_type) (((pa_type) & 0x01) == 0x01) + + uint8_t lna_type_2g; +#define R12A_ROM_IS_LNA_EXT(lna_type) (((lna_type) & 0x88) == 0x88) +#define R21A_ROM_IS_LNA_EXT(lna_type) (((lna_type) & 0x08) == 0x08) + +#define R12A_GET_ROM_PA_TYPE(lna_type, chain) \ + (((lna_type) >> ((chain) * 4 + 2)) & 0x01) +#define R12A_GET_ROM_LNA_TYPE(lna_type, chain) \ + (((lna_type) >> ((chain) * 4)) & 0x03) + + uint8_t reserved2; + uint8_t lna_type_5g; + uint8_t reserved3; + uint8_t rf_board_opt; +#define R12A_BOARD_TYPE_COMBO_MF 5 + + uint8_t rf_feature_opt; + uint8_t rf_bt_opt; +#define R12A_RF_BT_OPT_ANT_NUM 0x01 + + uint8_t version; + uint8_t customer_id; + uint8_t tx_bbswing_2g; + uint8_t tx_bbswing_5g; + uint8_t tx_pwr_calib_rate; + uint8_t rf_ant_opt; + uint8_t rfe_option; + uint8_t reserved4[5]; + uint16_t vid_12a; + uint16_t pid_12a; + uint8_t reserved5[3]; + uint8_t macaddr_12a[IEEE80211_ADDR_LEN]; + uint8_t reserved6[2]; + uint8_t string_12a[8]; /* "Realtek " */ + uint8_t reserved7[25]; + uint16_t vid_21a; + uint16_t pid_21a; + uint8_t reserved8[3]; + uint8_t macaddr_21a[IEEE80211_ADDR_LEN]; + uint8_t reserved9[2]; + uint8_t string_21a[8]; /* "Realtek " */ + uint8_t reserved10[2]; + uint8_t string_ven[23]; /* XXX variable length? */ + uint8_t reserved11[208]; +} __packed; + +_Static_assert(sizeof(struct r12a_rom) == R12A_EFUSE_MAP_LEN, + "R12A_EFUSE_MAP_LEN must be equal to sizeof(struct r12a_rom)!"); + +#endif /* R12A_ROM_IMAGE_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c new file mode 100644 index 00000000..049717a4 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c @@ -0,0 +1,240 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +void +r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ +#if __FreeBSD_version >= 1200012 + struct ieee80211_ratectl_tx_status txs; +#endif + struct r12a_c2h_tx_rpt *rpt; + struct ieee80211_node *ni; + int ntries; + + /* Skip Rx descriptor / report id / sequence fields. */ + buf += sizeof(struct r92c_rx_stat) + 2; + len -= sizeof(struct r92c_rx_stat) + 2; + + rpt = (struct r12a_c2h_tx_rpt *)buf; + if (len != sizeof(*rpt)) { + device_printf(sc->sc_dev, + "%s: wrong report size (%d, must be %zu)\n", + __func__, len, sizeof(*rpt)); + return; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: " + "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n", + __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2, + rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate, + rpt->reserved); + + if (rpt->macid > sc->macid_limit) { + device_printf(sc->sc_dev, + "macid %u is too big; increase MACID_MAX limit\n", + rpt->macid); + return; + } + + ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT); + + ni = sc->node_list[rpt->macid]; + if (ni != NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was" + "%s sent (%d retries)\n", __func__, rpt->macid, + (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER | + R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries); + +#if __FreeBSD_version >= 1200012 + txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | + IEEE80211_RATECTL_STATUS_FINAL_RATE; + txs.long_retries = ntries; + if (rpt->final_rate > RTWN_RIDX_OFDM54) { /* MCS */ + txs.final_rate = + (rpt->final_rate - 12) | IEEE80211_RATE_MCS; + } else + txs.final_rate = ridx2rate[rpt->final_rate]; + if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) + txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; + else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE) + txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; + else + txs.status = IEEE80211_RATECTL_TX_SUCCESS; + ieee80211_ratectl_tx_complete(ni, &txs); +#else + struct ieee80211vap *vap = ni->ni_vap; + if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); + } else { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); + } +#endif + } else { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: macid %u, ni is NULL\n", __func__, rpt->macid); + } +} + +void +r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Skip Rx descriptor. */ + buf += sizeof(struct r92c_rx_stat); + len -= sizeof(struct r92c_rx_stat); + + if (len < 2) { + device_printf(sc->sc_dev, "C2H report too short (len %d)\n", + len); + return; + } + len -= 2; + + switch (buf[0]) { /* command id */ + case R12A_C2H_TX_REPORT: + /* NOTREACHED */ + KASSERT(0, ("use handle_tx_report() instead of %s\n", + __func__)); + break; + case R12A_C2H_IQK_FINISHED: + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "FW IQ calibration finished\n"); + rs->rs_flags &= ~R12A_IQK_RUNNING; + break; + default: + device_printf(sc->sc_dev, + "%s: C2H report %u was not handled\n", + __func__, buf[0]); + } +} +#else +void +r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + /* Should not happen. */ + device_printf(sc->sc_dev, "%s: called\n", __func__); +} + +void +r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + /* Should not happen. */ + device_printf(sc->sc_dev, "%s: called\n", __func__); +} +#endif + +int +r12a_check_frame_checksum(struct rtwn_softc *sc, struct mbuf *m) +{ + struct r12a_softc *rs = sc->sc_priv; + struct r92c_rx_stat *stat; + uint32_t rxdw1; + + stat = mtod(m, struct r92c_rx_stat *); + rxdw1 = le32toh(stat->rxdw1); + if (rxdw1 & R12A_RXDW1_CKSUM) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: %s/%s checksum is %s\n", __func__, + (rxdw1 & R12A_RXDW1_UDP) ? "UDP" : "TCP", + (rxdw1 & R12A_RXDW1_IPV6) ? "IPv6" : "IP", + (rxdw1 & R12A_RXDW1_CKSUM_ERR) ? "invalid" : "valid"); + + if (rxdw1 & R12A_RXDW1_CKSUM_ERR) + return (-1); + + if ((rxdw1 & R12A_RXDW1_IPV6) ? + (rs->rs_flags & R12A_RXCKSUM6_EN) : + (rs->rs_flags & R12A_RXCKSUM_EN)) { + m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | + CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } + } + + return (0); +} + +uint8_t +r12a_rx_radiotap_flags(const void *buf) +{ + const struct r92c_rx_stat *stat = buf; + uint8_t flags, rate; + + if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP))) + return (0); + rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE); + if (RTWN_RATE_IS_CCK(rate)) + flags = IEEE80211_RADIOTAP_F_SHORTPRE; + else + flags = IEEE80211_RADIOTAP_F_SHORTGI; + return (flags); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h new file mode 100644 index 00000000..8642ca85 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12A_RX_DESC_H +#define R12A_RX_DESC_H + +#include + +/* Rx MAC descriptor defines (chip-specific). */ +/* Rx dword 1 */ +#define R12A_RXDW1_AMSDU 0x00002000 +#define R12A_RXDW1_CKSUM_ERR 0x00100000 +#define R12A_RXDW1_IPV6 0x00200000 +#define R12A_RXDW1_UDP 0x00400000 +#define R12A_RXDW1_CKSUM 0x00800000 +/* Rx dword 2 */ +#define R12A_RXDW2_RPT_C2H 0x10000000 +/* Rx dword 4 */ +#define R12A_RXDW4_SPLCP 0x00000001 +#define R12A_RXDW4_LDPC 0x00000002 +#define R12A_RXDW4_STBC 0x00000004 +#define R12A_RXDW4_BW_M 0x00000030 +#define R12A_RXDW4_BW_S 4 + +/* Rx PHY descriptor. */ +struct r12a_rx_phystat { + uint8_t gain_trsw[2]; + uint16_t phyw1; +#define R12A_PHYW1_CHAN_M 0x03ff +#define R12A_PHYW1_CHAN_S 0 +#define R12A_PHYW1_CHAN_EXT_M 0x3c00 +#define R12A_PHYW1_CHAN_EXT_S 10 +#define R12A_PHYW1_RFMOD_M 0xc000 +#define R12A_PHYW1_RFMOD_S 14 + + uint8_t pwdb_all; + uint8_t cfosho[4]; + uint8_t cfotail[4]; + uint8_t rxevm[2]; + uint8_t rxsnr[2]; + uint8_t pcts_msk_rpt[2]; + uint8_t pdsnr[2]; + uint8_t csi_current[2]; + uint8_t rx_gain_c; + uint8_t rx_gain_d; + uint8_t sigevm; + uint16_t phyw13; +#define R12A_PHYW13_ANTIDX_A_M 0x0700 +#define R12A_PHYW13_ANTIDX_A_S 8 +#define R12A_PHYW13_ANTIDX_B_M 0x3800 +#define R12A_PHYW13_ANTIDX_B_S 11 +} __packed; + +#endif /* R12A_RX_DESC_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c new file mode 100644 index 00000000..f7bd3a8e --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c @@ -0,0 +1,438 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + + +static int +r12a_get_primary_channel(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + /* XXX 80 MHz */ + if (IEEE80211_IS_CHAN_HT40U(c)) + return (R12A_TXDW5_PRIM_CHAN_20_80_2); + else + return (R12A_TXDW5_PRIM_CHAN_20_80_3); +} + +static void +r12a_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + /* XXX 80 Mhz */ + if (ni->ni_chan != IEEE80211_CHAN_ANYC && + IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { + int prim_chan; + + prim_chan = r12a_get_primary_channel(sc, ni->ni_chan); + txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW, + R12A_TXDW5_DATA_BW40)); + txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN, + prim_chan)); + } +} + +static void +r12a_tx_protection(struct rtwn_softc *sc, struct r12a_tx_desc *txd, + enum ieee80211_protmode mode, uint8_t ridx) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint8_t rate; + + switch (mode) { + case IEEE80211_PROT_CTSONLY: + txd->txdw3 |= htole32(R12A_TXDW3_CTS2SELF); + break; + case IEEE80211_PROT_RTSCTS: + txd->txdw3 |= htole32(R12A_TXDW3_RTSEN); + break; + default: + break; + } + + if (mode == IEEE80211_PROT_CTSONLY || + mode == IEEE80211_PROT_RTSCTS) { + if (ridx >= RTWN_RIDX_MCS(0)) + rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); + else + rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); + ridx = rate2ridx(rate); + + txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE, ridx)); + /* RTS rate fallback limit (max). */ + txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE_FB_LMT, 0xf)); + + if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + txd->txdw5 |= htole32(R12A_TXDW5_RTS_SHORT); + } +} + +static void +r12a_tx_raid(struct rtwn_softc *sc, struct r12a_tx_desc *txd, + struct ieee80211_node *ni, int ismcast) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_channel *chan; + enum ieee80211_phymode mode; + uint8_t raid; + + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? + ni->ni_chan : ic->ic_curchan; + mode = ieee80211_chan2mode(chan); + + /* NB: group addressed frames are done at 11bg rates for now */ + if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { + switch (mode) { + case IEEE80211_MODE_11A: + case IEEE80211_MODE_11B: + case IEEE80211_MODE_11G: + break; + case IEEE80211_MODE_11NA: + mode = IEEE80211_MODE_11A; + break; + case IEEE80211_MODE_11NG: + mode = IEEE80211_MODE_11G; + break; + default: + device_printf(sc->sc_dev, "unknown mode(1) %d!\n", + ic->ic_curmode); + return; + } + } + + switch (mode) { + case IEEE80211_MODE_11A: + raid = R12A_RAID_11G; + break; + case IEEE80211_MODE_11B: + raid = R12A_RAID_11B; + break; + case IEEE80211_MODE_11G: + if (vap->iv_flags & IEEE80211_F_PUREG) + raid = R12A_RAID_11G; + else + raid = R12A_RAID_11BG; + break; + case IEEE80211_MODE_11NA: + if (sc->ntxchains == 1) + raid = R12A_RAID_11GN_1; + else + raid = R12A_RAID_11GN_2; + break; + case IEEE80211_MODE_11NG: + if (sc->ntxchains == 1) { + if (IEEE80211_IS_CHAN_HT40(chan)) + raid = R12A_RAID_11BGN_1_40; + else + raid = R12A_RAID_11BGN_1; + } else { + if (IEEE80211_IS_CHAN_HT40(chan)) + raid = R12A_RAID_11BGN_2_40; + else + raid = R12A_RAID_11BGN_2; + } + break; + default: + /* TODO: 80 MHz / 11ac */ + device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); + return; + } + + txd->txdw1 |= htole32(SM(R12A_TXDW1_RAID, raid)); +} + +static void +r12a_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + struct ieee80211vap *vap = ni->ni_vap; + + if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) + txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); + else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ + IEEE80211_IS_CHAN_HT40(ni->ni_chan) && + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && + (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) + txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); +} + +void +r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, void *buf, uint8_t ridx, int maxretry) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_frame *wh; + struct r12a_tx_desc *txd; + enum ieee80211_protmode prot; + uint8_t type, tid, qos, qsel; + int hasqos, ismcast, macid; + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + hasqos = IEEE80211_QOS_HAS_SEQ(wh); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + + /* Select TX ring for this frame. */ + if (hasqos) { + qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; + tid = qos & IEEE80211_QOS_TID; + } else { + qos = 0; + tid = 0; + } + + /* Fill Tx descriptor. */ + txd = (struct r12a_tx_desc *)buf; + txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG; + if (ismcast) + txd->flags0 |= R12A_FLAGS0_BMCAST; + + if (!ismcast) { + /* Unicast frame, check if an ACK is expected. */ + if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != + IEEE80211_QOS_ACKPOLICY_NOACK) { + txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA); + txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT, + maxretry)); + } + + struct rtwn_node *un = RTWN_NODE(ni); + macid = un->id; + + if (type == IEEE80211_FC0_TYPE_DATA) { + qsel = tid % RTWN_MAX_TID; + + if (m->m_flags & M_AMPDU_MPDU) { + txd->txdw2 |= htole32(R12A_TXDW2_AGGEN); + txd->txdw2 |= htole32(SM(R12A_TXDW2_AMPDU_DEN, + vap->iv_ampdu_density)); + txd->txdw3 |= htole32(SM(R12A_TXDW3_MAX_AGG, + 0x1f)); /* XXX */ + } else + txd->txdw2 |= htole32(R12A_TXDW2_AGGBK); + + if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { + txd->txdw2 |= htole32(R12A_TXDW2_SPE_RPT); + sc->sc_tx_n_active++; + } + + if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); + + prot = IEEE80211_PROT_NONE; + if (ridx >= RTWN_RIDX_MCS(0)) { + r12a_tx_set_ht40(sc, txd, ni); + r12a_tx_set_sgi(sc, txd, ni); + prot = ic->ic_htprotmode; + } else if (ic->ic_flags & IEEE80211_F_USEPROT) + prot = ic->ic_protmode; + + /* XXX fix last comparison for A-MSDU (in net80211) */ + /* XXX A-MPDU? */ + if (m->m_pkthdr.len + IEEE80211_CRC_LEN > + vap->iv_rtsthreshold && + vap->iv_rtsthreshold != IEEE80211_RTS_MAX) + prot = IEEE80211_PROT_RTSCTS; + + if (prot != IEEE80211_PROT_NONE) + r12a_tx_protection(sc, txd, prot, ridx); + } else /* IEEE80211_FC0_TYPE_MGT */ + qsel = R12A_TXDW1_QSEL_MGNT; + } else { + macid = RTWN_MACID_BC; + qsel = R12A_TXDW1_QSEL_MGNT; + } + + txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, qsel)); + txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, macid)); + txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx)); + /* Data rate fallback limit (max). */ + txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f)); + /* XXX recheck for non-21au */ + txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id)); + r12a_tx_raid(sc, txd, ni, ismcast); + + /* Force this rate if needed. */ + if (sc->sc_ratectl != RTWN_RATECTL_FW) + txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE); + + if (!hasqos) { + /* Use HW sequence numbering for non-QoS frames. */ + txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id)); + } else { + uint16_t seqno; + + if (m->m_flags & M_AMPDU_MPDU) { + seqno = ni->ni_txseqs[tid]; + /* NB: clear Fragment Number field. */ + *(uint16_t *)wh->i_seq = 0; + ni->ni_txseqs[tid]++; + } else + seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; + + /* Set sequence number. */ + txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, seqno)); + } +} + +void +r12a_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_frame *wh; + struct r12a_tx_desc *txd; + uint8_t ridx; + int ismcast; + + /* XXX TODO: 11n checks, matching rtwn_fill_tx_desc() */ + + wh = mtod(m, struct ieee80211_frame *); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + ridx = rate2ridx(params->ibp_rate0); + + /* Fill Tx descriptor. */ + txd = (struct r12a_tx_desc *)buf; + txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG; + if (ismcast) + txd->flags0 |= R12A_FLAGS0_BMCAST; + + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { + txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA); + txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT, + params->ibp_try0)); + } + if (params->ibp_flags & IEEE80211_BPF_RTS) + r12a_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); + if (params->ibp_flags & IEEE80211_BPF_CTS) + r12a_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); + + txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC)); + txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT)); + + /* Set TX rate index. */ + txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx)); + txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f)); + txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id)); + txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE); + r12a_tx_raid(sc, txd, ni, ismcast); + + if (!IEEE80211_QOS_HAS_SEQ(wh)) { + /* Use HW sequence numbering for non-QoS frames. */ + txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id)); + } else { + /* Set sequence number. */ + txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, + M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE)); + } +} + +void +r12a_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, int qos, + int id) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + txd->flags0 = R12A_FLAGS0_FSG | R12A_FLAGS0_LSG | R12A_FLAGS0_OWN; + txd->txdw1 = htole32( + SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT)); + + txd->txdw3 = htole32(R12A_TXDW3_DRVRATE); + txd->txdw6 = htole32(SM(R21A_TXDW6_MBSSID, id)); + if (is11b) { + txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, + RTWN_RIDX_CCK1)); + } else { + txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, + RTWN_RIDX_OFDM6)); + } + + if (!qos) { + txd->txdw8 = htole32(R12A_TXDW8_HWSEQ_EN); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id)); + + } +} + +uint8_t +r12a_tx_radiotap_flags(const void *buf) +{ + const struct r12a_tx_desc *txd = buf; + uint8_t flags, rate; + + if (!(txd->txdw5 & htole32(R12A_TXDW5_DATA_SHORT))) + return (0); + + rate = MS(le32toh(txd->txdw4), R12A_TXDW4_DATARATE); + if (RTWN_RATE_IS_CCK(rate)) + flags = IEEE80211_RADIOTAP_F_SHORTPRE; + else + flags = IEEE80211_RADIOTAP_F_SHORTGI; + return (flags); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h new file mode 100644 index 00000000..9d3ad8b1 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h @@ -0,0 +1,149 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12A_TX_DESC_H +#define R12A_TX_DESC_H + +/* Tx MAC descriptor (common part). */ +struct r12a_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; +#define R12A_FLAGS0_BMCAST 0x01 +#define R12A_FLAGS0_LSG 0x04 +#define R12A_FLAGS0_FSG 0x08 +#define R12A_FLAGS0_OWN 0x80 + + uint32_t txdw1; +#define R12A_TXDW1_MACID_M 0x0000003f +#define R12A_TXDW1_MACID_S 0 +#define R12A_TXDW1_QSEL_M 0x00001f00 +#define R12A_TXDW1_QSEL_S 8 + +#define R12A_TXDW1_QSEL_BE 0x00 /* or 0x03 */ +#define R12A_TXDW1_QSEL_BK 0x01 /* or 0x02 */ +#define R12A_TXDW1_QSEL_VI 0x04 /* or 0x05 */ +#define R12A_TXDW1_QSEL_VO 0x06 /* or 0x07 */ +#define RTWN_MAX_TID 8 + +#define R12A_TXDW1_QSEL_BEACON 0x10 +#define R12A_TXDW1_QSEL_MGNT 0x12 + +#define R12A_TXDW1_RAID_M 0x001f0000 +#define R12A_TXDW1_RAID_S 16 +#define R12A_TXDW1_CIPHER_M 0x00c00000 +#define R12A_TXDW1_CIPHER_S 22 +#define R12A_TXDW1_CIPHER_NONE 0 +#define R12A_TXDW1_CIPHER_RC4 1 +#define R12A_TXDW1_CIPHER_SM4 2 +#define R12A_TXDW1_CIPHER_AES 3 +#define R12A_TXDW1_PKTOFF_M 0x1f000000 +#define R12A_TXDW1_PKTOFF_S 24 + + uint32_t txdw2; +#define R12A_TXDW2_AGGEN 0x00001000 +#define R12A_TXDW2_AGGBK 0x00010000 +#define R12A_TXDW2_MOREFRAG 0x00020000 +#define R12A_TXDW2_SPE_RPT 0x00080000 +#define R12A_TXDW2_AMPDU_DEN_M 0x00700000 +#define R12A_TXDW2_AMPDU_DEN_S 20 + + uint32_t txdw3; +#define R12A_TXDW3_SEQ_SEL_M 0x000000c0 +#define R12A_TXDW3_SEQ_SEL_S 6 +#define R12A_TXDW3_DRVRATE 0x00000100 +#define R12A_TXDW3_DISRTSFB 0x00000200 +#define R12A_TXDW3_DISDATAFB 0x00000400 +#define R12A_TXDW3_CTS2SELF 0x00000800 +#define R12A_TXDW3_RTSEN 0x00001000 +#define R12A_TXDW3_HWRTSEN 0x00002000 +#define R12A_TXDW3_MAX_AGG_M 0x003e0000 +#define R12A_TXDW3_MAX_AGG_S 17 + + uint32_t txdw4; +#define R12A_TXDW4_DATARATE_M 0x0000007f +#define R12A_TXDW4_DATARATE_S 0 +#define R12A_TXDW4_DATARATE_FB_LMT_M 0x00001f00 +#define R12A_TXDW4_DATARATE_FB_LMT_S 8 +#define R12A_TXDW4_RTSRATE_FB_LMT_M 0x0001e000 +#define R12A_TXDW4_RTSRATE_FB_LMT_S 13 +#define R12A_TXDW4_RETRY_LMT_ENA 0x00020000 +#define R12A_TXDW4_RETRY_LMT_M 0x00fc0000 +#define R12A_TXDW4_RETRY_LMT_S 18 +#define R12A_TXDW4_RTSRATE_M 0x1f000000 +#define R12A_TXDW4_RTSRATE_S 24 + + uint32_t txdw5; +#define R12A_TXDW5_DATA_PRIM_CHAN_M 0x0000000f +#define R12A_TXDW5_DATA_PRIM_CHAN_S 0 +#define R12A_TXDW5_PRIM_CHAN_20_80_3 1 +#define R12A_TXDW5_PRIM_CHAN_20_80_2 2 +#define R12A_TXDW5_PRIM_CHAN_20_80_4 3 +#define R12A_TXDW5_PRIM_CHAN_20_80_1 4 +#define R12A_TXDW5_PRIM_CHAN_40_80_1 9 +#define R12A_TXDW5_PRIM_CHAN_40_80_2 10 +#define R12A_TXDW5_DATA_SHORT 0x00000010 +#define R12A_TXDW5_DATA_BW_M 0x00000060 +#define R12A_TXDW5_DATA_BW_S 5 +#define R12A_TXDW5_DATA_BW40 1 +#define R12A_TXDW5_DATA_BW80 2 +#define R12A_TXDW5_DATA_LDPC 0x00000080 +#define R12A_TXDW5_RTS_SHORT 0x00001000 +#define R12A_TXDW5_RTS_PRIM_CHAN_M 0x0001e000 +#define R12A_TXDW5_RTS_PRIM_CHAN_S 13 + + uint32_t txdw6; +#define R21A_TXDW6_MBSSID_M 0x0000f000 +#define R21A_TXDW6_MBSSID_S 12 + + uint32_t reserved; + uint32_t txdw8; +#define R12A_TXDW8_HWSEQ_EN 0x00008000 + + uint32_t txdw9; +#define R12A_TXDW9_SEQ_M 0x00fff000 +#define R12A_TXDW9_SEQ_S 12 +} __packed __attribute__((aligned(4))); + + +/* Rate adaptation modes. */ +#define R12A_RAID_11BGN_2_40 0 +#define R12A_RAID_11BGN_1_40 1 +#define R12A_RAID_11BGN_2 2 +#define R12A_RAID_11BGN_1 3 +#define R12A_RAID_11GN_2 4 +#define R12A_RAID_11GN_1 5 +#define R12A_RAID_11BG 6 +#define R12A_RAID_11G 7 /* "pure" 11g */ +#define R12A_RAID_11B 8 +#define R12A_RAID_11AC_2_80 9 +#define R12A_RAID_11AC_1_80 10 +#define R12A_RAID_11AC_1 11 +#define R12A_RAID_11AC_2 12 + +#endif /* R12A_TX_DESC_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h b/freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h new file mode 100644 index 00000000..0092fb67 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_var.h @@ -0,0 +1,126 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12A_VAR_H +#define R12A_VAR_H + +#include + +struct r12a_softc { + uint8_t chip; +#define R12A_CHIP_C_CUT 0x01 + + uint8_t rs_flags; +#define R12A_RXCKSUM_EN 0x01 +#define R12A_RXCKSUM6_EN 0x02 +#define R12A_IQK_RUNNING 0x04 +#define R12A_RADAR_ENABLED 0x08 + + int rs_radar; + struct timeout_task rs_chan_check; + + /* ROM variables */ + int ext_pa_2g:1, + ext_pa_5g:1, + ext_lna_2g:1, + ext_lna_5g:1, + type_pa_2g:4, + type_pa_5g:4, + type_lna_2g:4, + type_lna_5g:4, + bt_coex:1, + bt_ant_num:1; + + uint8_t board_type; + uint8_t regulatory; + uint8_t crystalcap; + + uint8_t rfe_type; + uint8_t tx_bbswing_2g; + uint8_t tx_bbswing_5g; + + uint8_t cck_tx_pwr[R12A_MAX_RF_PATH][R12A_GROUP_2G]; + uint8_t ht40_tx_pwr_2g[R12A_MAX_RF_PATH][R12A_GROUP_2G]; + uint8_t ht40_tx_pwr_5g[R12A_MAX_RF_PATH][R12A_GROUP_5G]; + + int8_t cck_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + int8_t ofdm_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + int8_t bw20_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + int8_t bw40_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + + int8_t ofdm_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + int8_t bw20_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + int8_t bw40_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + int8_t bw80_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + int8_t bw160_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + + int sc_ant; + + int (*rs_newstate[RTWN_PORT_COUNT])(struct ieee80211vap *, + enum ieee80211_state, int); + void (*rs_scan_start)(struct ieee80211com *); + void (*rs_scan_end)(struct ieee80211com *); + + void (*rs_crystalcap_write)(struct rtwn_softc *); + void (*rs_fix_spur)(struct rtwn_softc *, + struct ieee80211_channel *); + void (*rs_set_band_2ghz)(struct rtwn_softc *, uint32_t); + void (*rs_set_band_5ghz)(struct rtwn_softc *, uint32_t); + void (*rs_init_burstlen)(struct rtwn_softc *); + void (*rs_init_ampdu_fwhw)(struct rtwn_softc *); +#ifndef RTWN_WITHOUT_UCODE + int (*rs_iq_calib_fw_supported)(struct rtwn_softc *); +#endif + void (*rs_iq_calib_sw)(struct rtwn_softc *); + + int ac_usb_dma_size; + int ac_usb_dma_time; + int ampdu_max_time; +}; +#define R12A_SOFTC(_sc) ((struct r12a_softc *)((_sc)->sc_priv)) + +#define rtwn_r12a_fix_spur(_sc, _c) \ + ((R12A_SOFTC(_sc)->rs_fix_spur)((_sc), (_c))) +#define rtwn_r12a_set_band_2ghz(_sc, _rates) \ + ((R12A_SOFTC(_sc)->rs_set_band_2ghz)((_sc), (_rates))) +#define rtwn_r12a_set_band_5ghz(_sc, _rates) \ + ((R12A_SOFTC(_sc)->rs_set_band_5ghz)((_sc), (_rates))) +#define rtwn_r12a_init_burstlen(_sc) \ + ((R12A_SOFTC(_sc)->rs_init_burstlen)((_sc))) +#define rtwn_r12a_init_ampdu_fwhw(_sc) \ + ((R12A_SOFTC(_sc)->rs_init_ampdu_fwhw)((_sc))) +#define rtwn_r12a_crystalcap_write(_sc) \ + ((R12A_SOFTC(_sc)->rs_crystalcap_write)((_sc))) +#ifndef RTWN_WITHOUT_UCODE +#define rtwn_r12a_iq_calib_fw_supported(_sc) \ + ((R12A_SOFTC(_sc)->rs_iq_calib_fw_supported)((_sc))) +#endif +#define rtwn_r12a_iq_calib_sw(_sc) \ + ((R12A_SOFTC(_sc)->rs_iq_calib_sw)((_sc))) + +#endif /* R12A_VAR_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h new file mode 100644 index 00000000..55d132c7 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef RTL8812AU_H +#define RTL8812AU_H + +#include + + +/* + * Function declarations. + */ +/* r12au_init.c */ +void r12au_init_rx_agg(struct rtwn_softc *); +void r12au_init_burstlen(struct rtwn_softc *); +void r12au_init_ampdu_fwhw(struct rtwn_softc *); +void r12au_init_ampdu(struct rtwn_softc *); +void r12au_post_init(struct rtwn_softc *); + +/* r12au_rx.c */ +int r12au_classify_intr(struct rtwn_softc *, void *, int); +int r12au_align_rx(int, int); + +/* r12au_tx.c */ +void r12au_dump_tx_desc(struct rtwn_softc *, const void *); + +#endif /* RTL8812AU_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c new file mode 100644 index 00000000..684076eb --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c @@ -0,0 +1,290 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +#include +#include + + +void r12au_attach(struct rtwn_usb_softc *); + +static void +r12au_postattach(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + struct r12a_softc *rs = sc->sc_priv; + + if (usbd_get_speed(uc->uc_udev) == USB_SPEED_SUPER) { + rs->ac_usb_dma_size = 0x07; + rs->ac_usb_dma_time = 0x1a; + } else { + rs->ac_usb_dma_size = 0x01; + rs->ac_usb_dma_time = 0x10; + } + + if (rs->chip & R12A_CHIP_C_CUT) + sc->sc_rf_read = r12a_c_cut_rf_read; + else + sc->sc_rf_read = r12a_rf_read; + + if (rs->board_type == R92C_BOARD_TYPE_MINICARD || + rs->board_type == R92C_BOARD_TYPE_SOLO || + rs->board_type == R92C_BOARD_TYPE_COMBO) + sc->sc_set_led = r88e_set_led; + else + sc->sc_set_led = r12a_set_led; + + if (!(rs->ext_pa_2g || rs->ext_lna_2g || + rs->ext_pa_5g || rs->ext_lna_5g)) + sc->mac_prog = &rtl8812au_mac_no_ext_pa_lna[0]; + + sc->sc_ic.ic_ioctl = r12a_ioctl_net; +} + +void +r12a_vap_preattach(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct r12a_softc *rs = sc->sc_priv; + struct ifnet *ifp = vap->iv_ifp; + + ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6; + RTWN_LOCK(sc); + if (rs->rs_flags & R12A_RXCKSUM_EN) + ifp->if_capenable |= IFCAP_RXCSUM; + if (rs->rs_flags & R12A_RXCKSUM6_EN) + ifp->if_capenable |= IFCAP_RXCSUM_IPV6; + RTWN_UNLOCK(sc); +} + +static void +r12a_attach_private(struct rtwn_softc *sc) +{ + struct r12a_softc *rs; + + rs = malloc(sizeof(struct r12a_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_flags = R12A_RXCKSUM_EN | R12A_RXCKSUM6_EN; + + rs->rs_fix_spur = r12a_fix_spur; + rs->rs_set_band_2ghz = r12a_set_band_2ghz; + rs->rs_set_band_5ghz = r12a_set_band_5ghz; + rs->rs_init_burstlen = r12au_init_burstlen; + rs->rs_init_ampdu_fwhw = r12au_init_ampdu_fwhw; + rs->rs_crystalcap_write = r12a_crystalcap_write; +#ifndef RTWN_WITHOUT_UCODE + rs->rs_iq_calib_fw_supported = r12a_iq_calib_fw_supported; +#endif + rs->rs_iq_calib_sw = r12a_iq_calib_sw; + + rs->ampdu_max_time = 0x70; + + sc->sc_priv = rs; +} + +void +r12a_detach_private(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + + free(rs, M_RTWN_PRIV); +} + +static void +r12a_read_chipid_vendor(struct rtwn_softc *sc, uint32_t reg_sys_cfg) +{ + struct r12a_softc *rs = sc->sc_priv; + + if (MS(reg_sys_cfg, R92C_SYS_CFG_CHIP_VER_RTL) == 1) + rs->chip |= R12A_CHIP_C_CUT; +} + +static void +r12au_adj_devcaps(struct rtwn_softc *sc) +{ + /* TODO: LDPC, STBC etc */ +} + +void +r12au_attach(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + /* USB part. */ + uc->uc_align_rx = r12au_align_rx; + uc->tx_agg_desc_num = 1; + + /* Common part. */ + sc->sc_flags = RTWN_FLAG_EXT_HDR; + + sc->sc_set_chan = r12a_set_chan; + sc->sc_fill_tx_desc = r12a_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r12a_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r12a_fill_tx_desc_null; + sc->sc_dump_tx_desc = r12au_dump_tx_desc; + sc->sc_tx_radiotap_flags = r12a_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r12a_rx_radiotap_flags; + sc->sc_get_rssi_cck = r88e_get_rssi_cck; + sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm; + sc->sc_classify_intr = r12au_classify_intr; + sc->sc_handle_tx_report = r12a_ratectl_tx_complete; + sc->sc_handle_c2h_report = r12a_handle_c2h_report; + sc->sc_check_frame = r12a_check_frame_checksum; + sc->sc_rf_write = r12a_rf_write; + sc->sc_check_condition = r12a_check_condition; + sc->sc_efuse_postread = rtwn_nop_softc; + sc->sc_parse_rom = r12a_parse_rom; + sc->sc_power_on = r12a_power_on; + sc->sc_power_off = r12a_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r12a_fw_reset; + sc->sc_fw_download_enable = r12a_fw_download_enable; +#endif + sc->sc_set_page_size = r12a_set_page_size; + sc->sc_lc_calib = r12a_lc_calib; + sc->sc_iq_calib = r12a_iq_calib; + sc->sc_read_chipid_vendor = r12a_read_chipid_vendor; + sc->sc_adj_devcaps = r12au_adj_devcaps; + sc->sc_vap_preattach = r12a_vap_preattach; + sc->sc_postattach = r12au_postattach; + sc->sc_detach_private = r12a_detach_private; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_media_status = r12a_set_media_status; + sc->sc_set_rsvd_page = r88e_set_rsvd_page; + sc->sc_set_pwrmode = r12a_set_pwrmode; + sc->sc_set_rssi = rtwn_nop_softc; /* XXX TODO */ +#else + sc->sc_set_media_status = rtwn_nop_softc_int; +#endif + sc->sc_beacon_init = r12a_beacon_init; + sc->sc_beacon_enable = r92c_beacon_enable; + sc->sc_beacon_set_rate = r12a_beacon_set_rate; + sc->sc_beacon_select = rtwn_nop_softc_int; + sc->sc_temp_measure = r88e_temp_measure; + sc->sc_temp_read = r88e_temp_read; + sc->sc_init_tx_agg = r92cu_init_tx_agg; + sc->sc_init_rx_agg = r12au_init_rx_agg; + sc->sc_init_ampdu = r12au_init_ampdu; + sc->sc_init_intr = r12a_init_intr; + sc->sc_init_edca = r12a_init_edca; + sc->sc_init_bb = r12a_init_bb; + sc->sc_init_rf = r12a_init_rf; + sc->sc_init_antsel = r12a_init_antsel; + sc->sc_post_init = r12au_post_init; + sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc; + + sc->chan_list_5ghz[0] = r12a_chan_5ghz_0; + sc->chan_list_5ghz[1] = r12a_chan_5ghz_1; + sc->chan_list_5ghz[2] = r12a_chan_5ghz_2; + sc->chan_num_5ghz[0] = nitems(r12a_chan_5ghz_0); + sc->chan_num_5ghz[1] = nitems(r12a_chan_5ghz_1); + sc->chan_num_5ghz[2] = nitems(r12a_chan_5ghz_2); + + sc->mac_prog = &rtl8812au_mac[0]; + sc->mac_size = nitems(rtl8812au_mac); + sc->bb_prog = &rtl8812au_bb[0]; + sc->bb_size = nitems(rtl8812au_bb); + sc->agc_prog = &rtl8812au_agc[0]; + sc->agc_size = nitems(rtl8812au_agc); + sc->rf_prog = &rtl8812au_rf[0]; + + sc->name = "RTL8812AU"; + sc->fwname = "rtwn-rtl8812aufw"; + sc->fwsig = 0x950; + + sc->page_count = R12A_TX_PAGE_COUNT; + sc->pktbuf_count = R12A_TXPKTBUF_COUNT; + + sc->ackto = 0x80; + sc->npubqpages = R12A_PUBQ_NPAGES; + sc->page_size = R12A_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r12au_tx_desc); + sc->efuse_maxlen = R12A_EFUSE_MAX_LEN; + sc->efuse_maplen = R12A_EFUSE_MAP_LEN; + sc->rx_dma_size = R12A_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R12A_MACID_MAX + 1; + sc->cam_entry_limit = R12A_CAM_ENTRY_COUNT; + sc->fwsize_limit = R12A_MAX_FW_SIZE; + sc->temp_delta = R88E_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R92C_TDECTRL; + sc->rcr = R12A_RCR_DIS_CHK_14 | + R12A_RCR_VHT_ACK | + R12A_RCR_TCP_OFFLD_EN; + + sc->ntxchains = 2; + sc->nrxchains = 2; + + r12a_attach_private(sc); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c new file mode 100644 index 00000000..f55ecb81 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_init.c @@ -0,0 +1,189 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r12au_init_rx_agg(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Rx aggregation (USB). */ + rtwn_write_2(sc, R92C_RXDMA_AGG_PG_TH, + rs->ac_usb_dma_size | (rs->ac_usb_dma_time << 8)); + rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0, + R92C_TRXDMA_CTRL_RXDMA_AGG_EN); +} + +void +r12au_init_burstlen(struct rtwn_softc *sc) +{ + if (rtwn_read_1(sc, R92C_TYPE_ID + 3) & 0x80) { + if ((rtwn_read_1(sc, R92C_USB_INFO) & 0x30) == 0) { + /* Set burst packet length to 512 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x20, 0x1e); + } else { + /* Set burst packet length to 64 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x10, 0x2e); + } + } else { /* USB 3.0 */ + /* Set burst packet length to 1 KB. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x30, 0x0e); + + rtwn_setbits_1(sc, 0xf008, 0x18, 0); + } +} + +static void +r12au_arfb_init(struct rtwn_softc *sc) +{ + /* ARFB table 9 for 11ac 5G 2SS. */ + rtwn_write_4(sc, R12A_ARFR_5G(0), 0x00000010); + rtwn_write_4(sc, R12A_ARFR_5G(0) + 4, 0xfffff000); + + /* ARFB table 10 for 11ac 5G 1SS. */ + rtwn_write_4(sc, R12A_ARFR_5G(1), 0x00000010); + rtwn_write_4(sc, R12A_ARFR_5G(1) + 4, 0x003ff000); + + /* ARFB table 11 for 11ac 2G 1SS. */ + rtwn_write_4(sc, R12A_ARFR_2G(0), 0x00000015); + rtwn_write_4(sc, R12A_ARFR_2G(0) + 4, 0x003ff000); + + /* ARFB table 12 for 11ac 2G 2SS. */ + rtwn_write_4(sc, R12A_ARFR_2G(1), 0x00000015); + rtwn_write_4(sc, R12A_ARFR_2G(1) + 4, 0xffcff000); +} + +void +r12au_init_ampdu_fwhw(struct rtwn_softc *sc) +{ + rtwn_setbits_1(sc, R92C_FWHW_TXQ_CTRL, + R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW, 0); +} + +void +r12au_init_ampdu(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Rx interval (USB3). */ + rtwn_write_1(sc, 0xf050, 0x01); + + /* burst length = 4 */ + rtwn_write_2(sc, R92C_RXDMA_STATUS, 0x7400); + + rtwn_write_1(sc, R92C_RXDMA_STATUS + 1, 0xf5); + + /* Setup AMPDU aggregation. */ + rtwn_write_1(sc, R12A_AMPDU_MAX_TIME, rs->ampdu_max_time); + rtwn_write_4(sc, R12A_AMPDU_MAX_LENGTH, 0xffffffff); + + /* 80 MHz clock (again?) */ + rtwn_write_1(sc, R92C_USTIME_TSF, 0x50); + rtwn_write_1(sc, R92C_USTIME_EDCA, 0x50); + + rtwn_r12a_init_burstlen(sc); + + /* Enable single packet AMPDU. */ + rtwn_setbits_1(sc, R12A_HT_SINGLE_AMPDU, 0, + R12A_HT_SINGLE_AMPDU_PKT_ENA); + + /* 11K packet length for VHT. */ + rtwn_write_1(sc, R92C_RX_PKT_LIMIT, 0x18); + + rtwn_write_1(sc, R92C_PIFS, 0); + + rtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x1f1f); + + rtwn_r12a_init_ampdu_fwhw(sc); + + /* Do not reset MAC. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0, 0x60); + + r12au_arfb_init(sc); +} + +void +r12au_post_init(struct rtwn_softc *sc) +{ + + /* Setup RTS BW (equal to data BW). */ + rtwn_setbits_1(sc, R92C_QUEUE_CTRL, 0x08, 0); + + rtwn_write_1(sc, R12A_EARLY_MODE_CONTROL + 3, 0x01); + + /* Reset USB mode switch setting. */ + rtwn_write_1(sc, R12A_SDIO_CTRL, 0); + rtwn_write_1(sc, R92C_ACLK_MON, 0); + + rtwn_write_1(sc, R92C_USB_HRPWM, 0); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_flags & RTWN_FW_LOADED) { + if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { + /* TODO: implement */ + sc->sc_ratectl = RTWN_RATECTL_NET80211; + } else + sc->sc_ratectl = sc->sc_ratectl_sysctl; + } else +#endif + sc->sc_ratectl = RTWN_RATECTL_NONE; +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h new file mode 100644 index 00000000..f768c262 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12AU_REG_H +#define R12AU_REG_H + +#include +#include + +#endif /* R12AU_REG_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c new file mode 100644 index 00000000..9015631a --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c @@ -0,0 +1,91 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include + + +int +r12au_classify_intr(struct rtwn_softc *sc, void *buf, int len) +{ + struct r92c_rx_stat *stat = buf; + uint32_t rxdw2 = le32toh(stat->rxdw2); + + if (rxdw2 & R12A_RXDW2_RPT_C2H) { + int pos = sizeof(struct r92c_rx_stat); + /* Check if Rx descriptor + command id/sequence fits. */ + if (len < pos + 2) /* unknown, skip */ + return (RTWN_RX_DATA); + + if (((uint8_t *)buf)[pos] == R12A_C2H_TX_REPORT) + return (RTWN_RX_TX_REPORT); + else + return (RTWN_RX_OTHER); + } else + return (RTWN_RX_DATA); +} + +int +r12au_align_rx(int totlen, int len) +{ + if (totlen < len) + return (roundup2(totlen, 8)); + + return (totlen); +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c new file mode 100644 index 00000000..20f13f93 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c @@ -0,0 +1,77 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r12au_dump_tx_desc(struct rtwn_softc *sc, const void *desc) +{ +#ifdef RTWN_DEBUG + const struct r12au_tx_desc *txd = desc; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT_DESC, + "%s: len %d, off %d, flags0 %02X, dw: 1 %08X, 2 %08X, 3 %08X, " + "4 %08X, 5 %08X, 6 %08X, sum %04X, flags7 %04X, 8 %08X, 9 %08X\n", + __func__, le16toh(txd->pktlen), txd->offset, txd->flags0, + le32toh(txd->txdw1), le32toh(txd->txdw2), le32toh(txd->txdw3), + le32toh(txd->txdw4), le32toh(txd->txdw5), le32toh(txd->txdw6), + le16toh(txd->txdsum), le16toh(txd->flags7), le32toh(txd->txdw8), + le32toh(txd->txdw9)); +#endif +} diff --git a/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h new file mode 100644 index 00000000..b7613f2b --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R12AU_TX_DESC_H +#define R12AU_TX_DESC_H + +#include + +/* Tx MAC descriptor (USB). */ +struct r12au_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; + + uint32_t txdw1; + uint32_t txdw2; + uint32_t txdw3; + uint32_t txdw4; + uint32_t txdw5; + uint32_t txdw6; + + uint16_t txdsum; + uint16_t flags7; +#define R12AU_FLAGS7_AGGNUM_M 0xff00 +#define R12AU_FLAGS7_AGGNUM_S 8 + + uint32_t txdw8; + uint32_t txdw9; +} __packed __attribute__((aligned(4))); + +#endif /* R12AU_TX_DESC_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a.h b/freebsd/sys/dev/rtwn/rtl8821a/r21a.h new file mode 100644 index 00000000..cfc99cb9 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a.h @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef RTL8821A_H +#define RTL8821A_H + +/* + * Global definitions. + */ +#define R21A_TX_PAGE_COUNT 243 +#define R21A_BCNQ0_PAGE_COUNT 8 +#define R21A_BCNQ0_BOUNDARY \ + (R21A_TX_PAGE_COUNT + R21A_BCNQ0_PAGE_COUNT + 1) + +#define R21A_TX_PAGE_SIZE 256 + + +/* + * Function declarations. + */ +/* r21a_beacon.c */ +void r21a_beacon_init(struct rtwn_softc *, void *, int); +void r21a_beacon_select(struct rtwn_softc *, int); + +/* r21a_calib.c */ +#ifndef RTWN_WITHOUT_UCODE +int r21a_iq_calib_fw_supported(struct rtwn_softc *); +#endif +void r21a_iq_calib_sw(struct rtwn_softc *); + +/* r21a_chan.c */ +void r21a_set_band_2ghz(struct rtwn_softc *, uint32_t); +void r21a_set_band_5ghz(struct rtwn_softc *, uint32_t); + +/* r21a_fw.c */ +void r21a_fw_reset(struct rtwn_softc *, int); + +/* r21a_init.c */ +int r21a_power_on(struct rtwn_softc *); +void r21a_power_off(struct rtwn_softc *); +int r21a_check_condition(struct rtwn_softc *, const uint8_t[]); +void r21a_crystalcap_write(struct rtwn_softc *); +int r21a_init_bcnq1_boundary(struct rtwn_softc *); +void r21a_init_ampdu_fwhw(struct rtwn_softc *); + +/* r21a_led.c */ +void r21a_set_led(struct rtwn_softc *, int, int); + +/* r21a_rom.c */ +void r21a_parse_rom(struct rtwn_softc *, uint8_t *); + +/* r21a_rx.c */ +int8_t r21a_get_rssi_cck(struct rtwn_softc *, void *); + +#endif /* RTL8821A_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c new file mode 100644 index 00000000..e60b777c --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_beacon.c @@ -0,0 +1,95 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r21a_beacon_init(struct rtwn_softc *sc, void *buf, int id) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + r12a_beacon_init(sc, buf, id); + + /* XXX sequence number for beacon 1 is not stable. */ + txd->txdw3 &= ~htole32(R12A_TXDW3_SEQ_SEL_M); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id * 2)); +} + +void +r21a_beacon_select(struct rtwn_softc *sc, int id) +{ + switch (id) { + case 0: + /* Switch to port 0 beacon. */ + rtwn_setbits_1_shift(sc, R21A_DWBCN1_CTRL, + R21A_DWBCN1_CTRL_SEL_BCN1, 0, 2); + break; + case 1: + /* Switch to port 1 beacon. */ + rtwn_setbits_1_shift(sc, R21A_DWBCN1_CTRL, + 0, R21A_DWBCN1_CTRL_SEL_BCN1, 2); + break; + default: + KASSERT(0, ("wrong port id %d\n", id)); + break; + } +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c new file mode 100644 index 00000000..d4679bc0 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_calib.c @@ -0,0 +1,128 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +int +r21a_iq_calib_fw_supported(struct rtwn_softc *sc) +{ + if (sc->fwver == 0x16) + return (1); + + return (0); +} +#endif + +void +r21a_iq_calib_sw(struct rtwn_softc *sc) +{ +#define R21A_MAX_NRXCHAINS 2 + uint32_t saved_bb_vals[nitems(r21a_iq_bb_regs)]; + uint32_t saved_afe_vals[nitems(r21a_iq_afe_regs)]; + uint32_t saved_rf_vals[nitems(r21a_iq_rf_regs) * R21A_MAX_NRXCHAINS]; + + KASSERT(sc->nrxchains <= R21A_MAX_NRXCHAINS, + ("nrxchains > %d (%d)\n", R21A_MAX_NRXCHAINS, sc->nrxchains)); + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: SW IQ calibration: TODO\n", + __func__); + + /* Save registers. */ + r12a_save_bb_afe_vals(sc, saved_bb_vals, r21a_iq_bb_regs, + nitems(r21a_iq_bb_regs)); + r12a_save_bb_afe_vals(sc, saved_afe_vals, r21a_iq_afe_regs, + nitems(r21a_iq_afe_regs)); + r12a_save_rf_vals(sc, saved_rf_vals, r21a_iq_rf_regs, + nitems(r21a_iq_rf_regs)); + +#ifdef RTWN_TODO + /* Configure MAC. */ + r12a_iq_config_mac(sc); + r21a_iq_tx(sc); +#endif + + /* Restore registers. */ + r12a_restore_rf_vals(sc, saved_rf_vals, r21a_iq_rf_regs, + nitems(r21a_iq_rf_regs)); + r12a_restore_bb_afe_vals(sc, saved_afe_vals, r21a_iq_afe_regs, + nitems(r21a_iq_afe_regs)); + + /* Select page C1. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0, 0x80000000); + + rtwn_bb_write(sc, R12A_SLEEP_NAV(0), 0); + rtwn_bb_write(sc, R12A_PMPD(0), 0); + rtwn_bb_write(sc, 0xc88, 0); + rtwn_bb_write(sc, 0xc8c, 0x3c000000); + rtwn_bb_write(sc, 0xc90, 0x80); + rtwn_bb_write(sc, 0xc94, 0); + rtwn_bb_write(sc, 0xcc4, 0x20040000); + rtwn_bb_write(sc, 0xcc8, 0x20000000); + rtwn_bb_write(sc, 0xcb8, 0); + + r12a_restore_bb_afe_vals(sc, saved_bb_vals, r21a_iq_bb_regs, + nitems(r21a_iq_bb_regs)); +#undef R21A_MAX_NRXCHAINS +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c new file mode 100644 index 00000000..9277b6af --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_chan.c @@ -0,0 +1,155 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include + + +static void +r21a_bypass_ext_lna_2ghz(struct rtwn_softc *sc) +{ + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x00100000, 0); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x00400000, 0); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0, 0x07); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0, 0x0700); +} + +void +r21a_set_band_2ghz(struct rtwn_softc *sc, uint32_t basicrates) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Enable CCK / OFDM. */ + rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, + 0, R12A_OFDMCCK_EN_CCK | R12A_OFDMCCK_EN_OFDM); + + /* Turn off RF PA and LNA. */ + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), + R12A_RFE_PINMUX_LNA_MASK, 0x7000); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), + R12A_RFE_PINMUX_PA_A_MASK, 0x70); + + if (rs->ext_lna_2g) { + /* Turn on 2.4 GHz external LNA. */ + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0, 0x00100000); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x00400000, 0); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0x05, 0x02); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0x0500, 0x0200); + } else { + /* Bypass 2.4 GHz external LNA. */ + r21a_bypass_ext_lna_2ghz(sc); + } + + /* Select AGC table. */ + rtwn_bb_setbits(sc, R12A_TX_SCALE(0), 0x0f00, 0); + + rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0x10); + rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0x0f000000, 0x01000000); + + /* Write basic rates. */ + rtwn_set_basicrates(sc, basicrates); + + rtwn_write_1(sc, R12A_CCK_CHECK, 0); +} + +void +r21a_set_band_5ghz(struct rtwn_softc *sc, uint32_t basicrates) +{ + struct r12a_softc *rs = sc->sc_priv; + int ntries; + + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), + R12A_RFE_PINMUX_LNA_MASK, 0x5000); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), + R12A_RFE_PINMUX_PA_A_MASK, 0x40); + + if (rs->ext_lna_2g) { + /* Bypass 2.4 GHz external LNA. */ + r21a_bypass_ext_lna_2ghz(sc); + } + + rtwn_write_1(sc, R12A_CCK_CHECK, R12A_CCK_CHECK_5GHZ); + + for (ntries = 0; ntries < 100; ntries++) { + if ((rtwn_read_2(sc, R12A_TXPKT_EMPTY) & 0x30) == 0x30) + break; + + rtwn_delay(sc, 25); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "%s: TXPKT_EMPTY check failed (%04X)\n", + __func__, rtwn_read_2(sc, R12A_TXPKT_EMPTY)); + } + + /* Enable OFDM. */ + rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, R12A_OFDMCCK_EN_CCK, + R12A_OFDMCCK_EN_OFDM); + + /* Select AGC table. */ + rtwn_bb_setbits(sc, R12A_TX_SCALE(0), 0x0f00, 0x0100); + + rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0); + rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0, 0x0f000000); + + /* Write basic rates. */ + rtwn_set_basicrates(sc, basicrates); +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c new file mode 100644 index 00000000..dad74ed1 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_fw.c @@ -0,0 +1,80 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +void +r21a_fw_reset(struct rtwn_softc *sc, int reason) +{ + + /* Reset MCU IO wrapper. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0); + rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0x01, 0); + + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_CPUEN, 0, 1); + + /* Enable MCU IO wrapper. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0); + rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0, 0x01); + + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + 0, R92C_SYS_FUNC_EN_CPUEN, 1); +} +#endif diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c new file mode 100644 index 00000000..a3bcde77 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_init.c @@ -0,0 +1,360 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +int +r21a_power_on(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + int ntries; + + /* Clear suspend and power down bits.*/ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_APDM_HPDN, 0, 1)); + + /* Disable GPIO9 as EXT WAKEUP. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_GPIO_INTM + 2, 0x01, 0)); + + /* Enable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0, 1)); + + /* Enable LDOA12 MACRO block for all interfaces. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_LDOA15_CTRL, 0, R92C_LDOA15_CTRL_EN)); + + /* Disable BT_GPS_SEL pins. */ + RTWN_CHK(rtwn_setbits_1(sc, 0x067, 0x10, 0)); + + /* 1 ms delay. */ + rtwn_delay(sc, 1000); + + /* Release analog Ips to digital isolation. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_SYS_ISO_CTRL, + R92C_SYS_ISO_CTRL_IP2MAC, 0)); + + /* Disable SW LPS and WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APFM_RSM | + R92C_APS_FSMCO_AFSM_HSUS | + R92C_APS_FSMCO_AFSM_PCIE, 0, 1)); + + /* Wait for power ready bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for chip power up\n"); + return (ETIMEDOUT); + } + + /* Release WLON reset. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_RDY_MACON, 2)); + + /* Disable HWPDN. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APDM_HPDN, 0, 1)); + + /* Disable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0, 1)); + + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_APFM_ONMAC, 1)); + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) + return (ETIMEDOUT); + + /* Switch DPDT_SEL_P output from WL BB. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_LEDCFG3, 0, 0x01)); + + /* switch for PAPE_G/PAPE_A from WL BB; switch LNAON from WL BB. */ + RTWN_CHK(rtwn_setbits_1(sc, 0x067, 0, 0x30)); + + RTWN_CHK(rtwn_setbits_1(sc, 0x025, 0x40, 0)); + + /* Enable falling edge triggering interrupt. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_GPIO_INTM + 1, 0, 0x02)); + + /* Enable GPIO9 interrupt mode. */ + RTWN_CHK(rtwn_setbits_1(sc, 0x063, 0, 0x02)); + + /* Enable GPIO9 input mode. */ + RTWN_CHK(rtwn_setbits_1(sc, 0x062, 0x02, 0)); + + /* Enable HSISR GPIO interrupt. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_HSIMR, 0, 0x01)); + + /* Enable HSISR GPIO9 interrupt. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_HSIMR + 2, 0, 0x02)); + + /* XTAL trim. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_APE_PLL_CTRL_EXT + 2, 0xFF, 0x82)); + + RTWN_CHK(rtwn_setbits_1(sc, R92C_AFE_MISC, 0, 0x40)); + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0x0000)); + RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN | + R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) | + R92C_CR_CALTMR_EN)); + + if (rtwn_read_4(sc, R92C_SYS_CFG) & R92C_SYS_CFG_TRP_BT_EN) + RTWN_CHK(rtwn_setbits_1(sc, 0x07C, 0, 0x40)); + + return (0); +#undef RTWN_CHK +} + +void +r21a_power_off(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + int error, ntries; + + /* Stop Rx. */ + error = rtwn_write_1(sc, R92C_CR, 0); + if (error == ENXIO) /* hardware gone */ + return; + + /* Move card to Low Power state. */ + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + + for (ntries = 0; ntries < 10; ntries++) { + /* Should be zero if no packet is transmitting. */ + if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: failed to block Tx queues\n", + __func__); + return; + } + + /* CCK and OFDM are disabled, and clock are gated. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0); + + rtwn_delay(sc, 1); + + /* Reset whole BB. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0); + + /* Reset MAC TRX. */ + rtwn_write_1(sc, R92C_CR, + R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN); + + /* check if removed later. (?) */ + rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1); + + /* Respond TxOK to scheduler */ + rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, R92C_DUAL_TSF_RST_TXOK); + + /* If firmware in ram code, do reset. */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) + r21a_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); +#endif + + /* Reset MCU. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN, + 0, 1); + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* Move card to Disabled state. */ + /* Turn off RF. */ + rtwn_write_1(sc, R92C_RF_CTRL, 0); + + rtwn_setbits_1(sc, R92C_LEDCFG3, 0x01, 0); + + /* Enable rising edge triggering interrupt. */ + rtwn_setbits_1(sc, R92C_GPIO_INTM + 1, 0x02, 0); + + /* Release WLON reset. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_RDY_MACON, 2); + + /* Turn off MAC by HW state machine */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_APFM_OFF, + 1); + for (ntries = 0; ntries < 10; ntries++) { + /* Wait until it will be disabled. */ + if ((rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_OFF) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: could not turn off MAC\n", + __func__); + return; + } + + /* Analog Ips to digital isolation. */ + rtwn_setbits_1(sc, R92C_SYS_ISO_CTRL, 0, R92C_SYS_ISO_CTRL_IP2MAC); + + /* Disable LDOA12 MACRO block. */ + rtwn_setbits_1(sc, R92C_LDOA15_CTRL, R92C_LDOA15_CTRL_EN, 0); + + /* Enable WL suspend. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_AFSM_PCIE, + R92C_APS_FSMCO_AFSM_HSUS, 1); + + /* Enable GPIO9 as EXT WAKEUP. */ + rtwn_setbits_1(sc, R92C_GPIO_INTM + 2, 0, 0x01); + + rs->rs_flags &= ~(R12A_IQK_RUNNING | R12A_RADAR_ENABLED); +} + +int +r21a_check_condition(struct rtwn_softc *sc, const uint8_t cond[]) +{ + struct r12a_softc *rs = sc->sc_priv; + uint8_t mask; + int i; + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "%s: condition byte 0: %02X; ext 5ghz pa/lna %d/%d\n", + __func__, cond[0], rs->ext_pa_5g, rs->ext_lna_5g); + + if (cond[0] == 0) + return (1); + + mask = 0; + if (rs->ext_pa_5g) + mask |= R21A_COND_EXT_PA_5G; + if (rs->ext_lna_5g) + mask |= R21A_COND_EXT_LNA_5G; + if (rs->bt_coex) + mask |= R21A_COND_BT; + if (!rs->ext_pa_2g && !rs->ext_lna_2g && + !rs->ext_pa_5g && !rs->ext_lna_5g && !rs->bt_coex) + mask = R21A_COND_BOARD_DEF; + + if (mask == 0) + return (0); + + for (i = 0; i < RTWN_MAX_CONDITIONS && cond[i] != 0; i++) + if (cond[i] == mask) + return (1); + + return (0); +} + +void +r21a_crystalcap_write(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + uint32_t reg; + uint8_t val; + + val = rs->crystalcap & 0x3f; + reg = rtwn_bb_read(sc, R92C_MAC_PHY_CTRL); + reg = RW(reg, R21A_MAC_PHY_CRYSTALCAP, val | (val << 6)); + rtwn_bb_write(sc, R92C_MAC_PHY_CTRL, reg); +} + +int +r21a_init_bcnq1_boundary(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + RTWN_CHK(rtwn_write_1(sc, R88E_TXPKTBUF_BCNQ1_BDNY, + R21A_BCNQ0_BOUNDARY)); + RTWN_CHK(rtwn_write_1(sc, R21A_DWBCN1_CTRL + 1, + R21A_BCNQ0_BOUNDARY)); + RTWN_CHK(rtwn_setbits_1_shift(sc, R21A_DWBCN1_CTRL, 0, + R21A_DWBCN1_CTRL_SEL_EN, 2)); + + return (0); +#undef RTWN_CHK +} + +void +r21a_init_ampdu_fwhw(struct rtwn_softc *sc) +{ + rtwn_write_1(sc, R92C_FWHW_TXQ_CTRL, + R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW); + rtwn_write_4(sc, R92C_FAST_EDCA_CTRL, 0x03087777); +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c new file mode 100644 index 00000000..83d67c67 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_led.c @@ -0,0 +1,69 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r21a_set_led(struct rtwn_softc *sc, int led, int on) +{ + if (led == RTWN_LED_LINK) { + rtwn_write_1(sc, R92C_LEDCFG2, + R12A_LEDCFG2_ENA | (on ? 0 : R92C_LEDCFG0_DIS)); + sc->ledlink = on; /* Save LED state. */ + } +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h b/freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h new file mode 100644 index 00000000..d4cfa46a --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_priv.h @@ -0,0 +1,464 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R21A_PRIV_H +#define R21A_PRIV_H + +/* + * MAC initialization values. + */ +static const struct rtwn_mac_prog rtl8821au_mac[] = { + { 0x421, 0x0f }, { 0x428, 0x0a }, { 0x429, 0x10 }, { 0x430, 0x00 }, + { 0x431, 0x00 }, { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, + { 0x435, 0x05 }, { 0x436, 0x07 }, { 0x437, 0x08 }, { 0x43c, 0x04 }, + { 0x43d, 0x05 }, { 0x43e, 0x07 }, { 0x43f, 0x08 }, { 0x440, 0x5d }, + { 0x441, 0x01 }, { 0x442, 0x00 }, { 0x444, 0x10 }, { 0x445, 0x00 }, + { 0x446, 0x00 }, { 0x447, 0x00 }, { 0x448, 0x00 }, { 0x449, 0xf0 }, + { 0x44a, 0x0f }, { 0x44b, 0x3e }, { 0x44c, 0x10 }, { 0x44d, 0x00 }, + { 0x44e, 0x00 }, { 0x44f, 0x00 }, { 0x450, 0x00 }, { 0x451, 0xf0 }, + { 0x452, 0x0f }, { 0x453, 0x00 }, { 0x456, 0x5e }, { 0x460, 0x66 }, + { 0x461, 0x66 }, { 0x4c8, 0x3f }, { 0x4c9, 0xff }, { 0x4cc, 0xff }, + { 0x4cd, 0xff }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, + { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, + { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, + { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, + { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, + { 0x516, 0x0a }, { 0x525, 0x4f }, { 0x550, 0x10 }, { 0x551, 0x10 }, + { 0x559, 0x02 }, { 0x55c, 0x50 }, { 0x55d, 0xff }, { 0x605, 0x30 }, + { 0x607, 0x07 }, { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x620, 0xff }, + { 0x621, 0xff }, { 0x622, 0xff }, { 0x623, 0xff }, { 0x624, 0xff }, + { 0x625, 0xff }, { 0x626, 0xff }, { 0x627, 0xff }, { 0x638, 0x50 }, + { 0x63c, 0x0a }, { 0x63d, 0x0a }, { 0x63e, 0x0e }, { 0x63f, 0x0e }, + { 0x640, 0x40 }, { 0x642, 0x40 }, { 0x643, 0x00 }, { 0x652, 0xc8 }, + { 0x66e, 0x05 }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, + { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, + { 0x70b, 0x87 }, { 0x718, 0x40 } +}; + + +/* + * Baseband initialization values. + */ +#define R21A_COND_EXT_PA_5G 0x01 +#define R21A_COND_EXT_LNA_5G 0x02 +#define R21A_COND_BOARD_DEF 0x04 +#define R21A_COND_BT 0x08 + +static const uint16_t rtl8821au_bb_regs[] = { + 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x820, 0x824, + 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, 0x840, 0x844, 0x848, + 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, 0x864, 0x868, 0x86c, + 0x870, 0x874, 0x878, 0x87c, 0x8a0, 0x8a4, 0x8a8, 0x8ac, 0x8b4, + 0x8b8, 0x8bc, 0x8c0, 0x8c4, 0x8c8, 0x8cc, 0x8d4, 0x8d8, 0x8f8, + 0x8fc, 0x900, 0x90c, 0x910, 0x914, 0x918, 0x91c, 0x920, 0x924, + 0x928, 0x92c, 0x930, 0x934, 0x960, 0x964, 0x968, 0x96c, 0x970, + 0x974, 0x978, 0x97c, 0x980, 0x984, 0x988, 0x990, 0x994, 0x998, + 0x99c, 0x9a0, 0x9a4, 0x9a8, 0x9ac, 0x9b0, 0x9b4, 0x9b8, 0x9bc, + 0x9d0, 0x9d4, 0x9d8, 0x9dc, 0x9e0, 0x9e4, 0x9e8, 0xa00, 0xa04, + 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24, 0xa28, + 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xa84, 0xb00, 0xb04, + 0xb08, 0xb0c, 0xb10, 0xb14, 0xb18, 0xb1c, 0xb20, 0xb24, 0xb28, + 0xb2c, 0xb30, 0xb34, 0xb38, 0xb3c, 0xb40, 0xb44, 0xb48, 0xb4c, + 0xb50, 0xb54, 0xb58, 0xb5c, 0xc00, 0xc04, 0xc08, 0xc0c, 0xc10, + 0xc14, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, 0xc38, + 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, 0xc5c, + 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, 0xc80, + 0xc84, 0xc94, 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcb0, 0xcb4, + 0xcb8 +}; + +static const uint32_t rtl8821au_bb_vals[] = { + 0x0020d090, 0x080112e0, 0x0e028211, 0x92131111, 0x20101261, + 0x020c3d10, 0x03a00385, 0x00000000, 0x00030fe0, 0x00000000, + 0x002081dd, 0x2aaaeec8, 0x0037a706, 0x06489b44, 0x0000095b, + 0xc0000001, 0x40003cde, 0x62103f8b, 0x6cfdffb8, 0x28874706, + 0x0001520c, 0x8060e000, 0x74210168, 0x6929c321, 0x79727432, + 0x8ca7a314, 0x888c2878, 0x08888888, 0x31612c2e, 0x00000152, + 0x000fd000, 0x00000013, 0x7f7f7f7f, 0xa2000338, 0x0ff0fa0a, + 0x000fc080, 0x6c10d7ff, 0x0ca52090, 0x1bf00020, 0x00000000, + 0x00013169, 0x08248492, 0x940008a0, 0x290b5612, 0x400002c0, + 0x00000000, 0x00000700, 0x00000000, 0x0000fc00, 0x00000404, + 0x1c1028c0, 0x64b11a1c, 0xe0767233, 0x055aa500, 0x00000004, + 0xfffe0000, 0xfffffffe, 0x001fffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x801fffff, 0x000003ff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x27100000, + 0xffff0100, 0xffffff5c, 0xffffffff, 0x000000ff, 0x00480080, + 0x00000000, 0x00000000, 0x81081008, 0x01081008, 0x01081008, + 0x01081008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00005d00, 0x00000003, 0x00000001, 0x00d047c8, 0x01ff800c, + 0x8c8a8300, 0x2e68000f, 0x9500bb78, 0x11144028, 0x00881117, + 0x89140f00, 0x1a1b0000, 0x090e1317, 0x00000204, 0x00900000, + 0x101fff00, 0x00000008, 0x00000900, 0x225b0606, 0x21805490, + 0x001f0000, 0x03100040, 0x0000b000, 0xae0201eb, 0x01003207, + 0x00009807, 0x01000000, 0x00000002, 0x00000002, 0x0000001f, + 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, 0x13121110, + 0x17161514, 0x0000003a, 0x00000000, 0x00000000, 0x13000032, + 0x48080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000007, 0x00042020, 0x80410231, 0x00000000, 0x00000100, + 0x01000000, 0x40000003, 0x2c2c2c2c, 0x30303030, 0x30303030, + 0x2c2c2c2c, 0x2c2c2c2c, 0x2c2c2c2c, 0x2c2c2c2c, 0x2a2a2a2a, + 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000020, + 0x001c1208, 0x30000c1c, 0x00000058, 0x34344443, 0x07003333, + 0x19791979, 0x19791979, 0x19791979, 0x19791979, 0x19791979, + 0x19791979, 0x19791979, 0x19791979, 0x0100005c, 0x00000000, + 0x00000000, 0x00000029, 0x08040201, 0x80402010, 0x77775747, + 0x10000077, 0x00508240 +}; + +static const struct rtwn_bb_prog rtl8821au_bb[] = { + { + nitems(rtl8821au_bb_regs), + rtl8821au_bb_regs, + rtl8821au_bb_vals, + { 0 }, + NULL + } +}; + +static const uint32_t rtl8821au_agc_vals0[] = { + 0xbf000001, 0xbf020001, 0xbf040001, 0xbf060001, 0xbe080001, + 0xbd0a0001, 0xbc0c0001, 0xba0e0001, 0xb9100001, 0xb8120001, + 0xb7140001, 0xb6160001, 0xb5180001, 0xb41a0001, 0xb31c0001, + 0xb21e0001, 0xb1200001, 0xb0220001, 0xaf240001, 0xae260001, + 0xad280001, 0xac2a0001, 0xab2c0001, 0xaa2e0001, 0xa9300001, + 0xa8320001, 0xa7340001, 0xa6360001, 0xa5380001, 0xa43a0001, + 0x683c0001, 0x673e0001, 0x66400001, 0x65420001, 0x64440001, + 0x63460001, 0x62480001, 0x614a0001, 0x474c0001, 0x464e0001, + 0x45500001, 0x44520001, 0x43540001, 0x42560001, 0x41580001, + 0x285a0001, 0x275c0001, 0x265e0001, 0x25600001, 0x24620001, + 0x0a640001, 0x09660001, 0x08680001, 0x076a0001, 0x066c0001, + 0x056e0001, 0x04700001, 0x03720001, 0x02740001, 0x01760001, + 0x01780001, 0x017a0001, 0x017c0001, 0x017e0001 +}, rtl8821au_agc_vals1_pa_lna_5g[] = { + 0xfb000101, 0xfa020101, 0xf9040101, 0xf8060101, 0xf7080101, + 0xf60a0101, 0xf50c0101, 0xf40e0101, 0xf3100101, 0xf2120101, + 0xf1140101, 0xf0160101, 0xef180101, 0xee1a0101, 0xed1c0101, + 0xec1e0101, 0xeb200101, 0xea220101, 0xe9240101, 0xe8260101, + 0xe7280101, 0xe62a0101, 0xe52c0101, 0xe42e0101, 0xe3300101, + 0xa5320101, 0xa4340101, 0xa3360101, 0x87380101, 0x863a0101, + 0x853c0101, 0x843e0101, 0x69400101, 0x68420101, 0x67440101, + 0x66460101, 0x49480101, 0x484a0101, 0x474c0101, 0x2a4e0101, + 0x29500101, 0x28520101, 0x27540101, 0x26560101, 0x25580101, + 0x245a0101, 0x235c0101, 0x055e0101, 0x04600101, 0x03620101, + 0x02640101, 0x01660101, 0x01680101, 0x016a0101, 0x016c0101, + 0x016e0101, 0x01700101, 0x01720101 +}, rtl8821au_agc_vals1[] = { + 0xff000101, 0xff020101, 0xfe040101, 0xfd060101, 0xfc080101, + 0xfd0a0101, 0xfc0c0101, 0xfb0e0101, 0xfa100101, 0xf9120101, + 0xf8140101, 0xf7160101, 0xf6180101, 0xf51a0101, 0xf41c0101, + 0xf31e0101, 0xf2200101, 0xf1220101, 0xf0240101, 0xef260101, + 0xee280101, 0xed2a0101, 0xec2c0101, 0xeb2e0101, 0xea300101, + 0xe9320101, 0xe8340101, 0xe7360101, 0xe6380101, 0xe53a0101, + 0xe43c0101, 0xe33e0101, 0xa5400101, 0xa4420101, 0xa3440101, + 0x87460101, 0x86480101, 0x854a0101, 0x844c0101, 0x694e0101, + 0x68500101, 0x67520101, 0x66540101, 0x49560101, 0x48580101, + 0x475a0101, 0x2a5c0101, 0x295e0101, 0x28600101, 0x27620101, + 0x26640101, 0x25660101, 0x24680101, 0x236a0101, 0x056c0101, + 0x046e0101, 0x03700101, 0x02720101 +}, rtl8821au_agc_vals2[] = { + 0x01740101, 0x01760101, 0x01780101, 0x017a0101, 0x017c0101, + 0x017e0101 +}; + +static const struct rtwn_agc_prog rtl8821au_agc[] = { + { + nitems(rtl8821au_agc_vals0), + rtl8821au_agc_vals0, + { 0 }, + NULL + }, + /* + * For devices with external 5GHz PA / LNA. + */ + { + nitems(rtl8821au_agc_vals1_pa_lna_5g), + rtl8821au_agc_vals1_pa_lna_5g, + { R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 }, + /* + * Others. + */ + &(const struct rtwn_agc_prog){ + nitems(rtl8821au_agc_vals1), + rtl8821au_agc_vals1, + { 0 }, + NULL + } + }, + { + nitems(rtl8821au_agc_vals2), + rtl8821au_agc_vals2, + { 0 }, + NULL + } +}; + + +/* + * RF initialization values. + */ +static const uint8_t rtl8821au_rf_regs0[] = { + 0x18, 0x56, 0x66, 0x00, 0x1e, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xef, 0x3e, 0x3f, + 0x3e, 0x3f, 0x3e, 0x3f, 0x3e, 0x3f, 0xef, 0x18, 0x89, 0x8b, 0xef, + 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, + 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, + 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, + 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, + 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, + 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0xef, 0xef +}, rtl8821au_rf_regs1[] = { + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34 +}, rtl8821au_rf_regs2[] = { + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0xef, 0x18, + 0xef +}, rtl8821au_rf_regs3[] = { + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0xef, 0x18, + 0xef, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xef, 0xef, 0x3c, 0x3c +}, rtl8821au_rf_regs4[] = { + 0x3c, 0xef, 0x18, 0xef, 0x08, 0xef, 0xdf, 0x1f, 0x58, 0x59, 0x61, + 0x62, 0x63, 0x64, 0x65 +}, rtl8821au_rf_regs5[] = { + 0x18, 0xef, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0xef, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0xef, 0xed, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0xed, 0xed, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xed, + 0xef, 0xdf, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xef, 0x51, + 0x52, 0x53, 0x54, 0x56, 0x51, 0x52, 0x53, 0x70, 0x71, 0x72, 0x74, + 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xed, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0xdf, 0xb3, 0xb4, 0xb7, 0x1c, 0xc4, 0x18, + 0xfe, 0xfe, 0x18, +}; + +static const uint32_t rtl8821au_rf_vals0[] = { + 0x1712a, 0x51cf2, 0x40000, 0x10000, 0x80000, 0x00830, 0x21800, + 0x28000, 0x48000, 0x94838, 0x44980, 0x48000, 0x0d480, 0x42240, + 0xf0380, 0x90000, 0x22852, 0x65540, 0x88001, 0x20000, 0x00380, + 0x90018, 0x20380, 0xa0018, 0x40308, 0xa0018, 0x60018, 0xa0018, + 0x00000, 0x1712a, 0x00080, 0x80180, 0x01000, 0x00244, 0x38027, + 0x82000, 0x00244, 0x30113, 0x82000, 0x0014c, 0x28027, 0x82000, + 0x000cc, 0x27027, 0x42000, 0x0014c, 0x1f913, 0x42000, 0x0010c, + 0x17f10, 0x12000, 0x000d0, 0x08027, 0xca000, 0x00244, 0x78027, + 0x82000, 0x00244, 0x70113, 0x82000, 0x0014c, 0x68027, 0x82000, + 0x000cc, 0x67027, 0x42000, 0x0014c, 0x5f913, 0x42000, 0x0010c, + 0x57f10, 0x12000, 0x000d0, 0x48027, 0xca000, 0x00244, 0xb8027, + 0x82000, 0x00244, 0xb0113, 0x82000, 0x0014c, 0xa8027, 0x82000, + 0x000cc, 0xa7027, 0x42000, 0x0014c, 0x9f913, 0x42000, 0x0010c, + 0x97f10, 0x12000, 0x000d0, 0x88027, 0xca000, 0x00000, 0x01100 +}, rtl8821au_rf_vals1_def_or_bt[] = { + 0x4adf5, 0x49df2, 0x48def, 0x47dec, 0x46de9, 0x45ccb, 0x4488d, + 0x4348d, 0x4248a, 0x4108d, 0x4008a, 0x2adf4, 0x29df1 +}, rtl8821au_rf_vals1_ext_5g[] = { + 0x4a0f3, 0x490b1, 0x480ae, 0x470ab, 0x4608b, 0x45069, 0x44048, + 0x43045, 0x42026, 0x41023, 0x40002, 0x2a0f3, 0x290f0 +}, rtl8821au_rf_vals1[] = { + 0x4adf7, 0x49df3, 0x48def, 0x47dec, 0x46de9, 0x45ccb, 0x4488d, + 0x4348d, 0x4248a, 0x4108d, 0x4008a, 0x2adf7, 0x29df2 +}, rtl8821au_rf_vals2_ext_5g[] = { + 0x280af, 0x270ac, 0x2608b, 0x25069, 0x24048, 0x23045, 0x22026, + 0x21023, 0x20002, 0x0a0d7, 0x090d3, 0x080b1, 0x070ae, 0x0608d, + 0x0506b, 0x0404a, 0x03047, 0x02044, 0x01025, 0x00004, 0x00000, + 0x1712a, 0x00040 +}, rtl8821au_rf_vals2[] = { + 0x28dee, 0x27deb, 0x26ccd, 0x25cca, 0x2488c, 0x2384c, 0x22849, + 0x21449, 0x2004d, 0x0adf7, 0x09df4, 0x08df1, 0x07dee, 0x06dcd, + 0x05ccd, 0x04cca, 0x0388c, 0x02888, 0x01488, 0x00486, 0x00000, + 0x1712a, 0x00040 +}, rtl8821au_rf_vals3_def_or_bt[] = { + 0x00128, 0x08128, 0x10128, 0x201c8, 0x281c8, 0x301c8, 0x401c8, + 0x481c8, 0x501c8, 0x00000, 0x1712a, 0x00010, 0x063b5, 0x0e3b5, + 0x163b5, 0x1e3b5, 0x263b5, 0x2e3b5, 0x363b5, 0x3e3b5, 0x463b5, + 0x4e3b5, 0x563b5, 0x5e3b5, 0x00000, 0x00008, 0x001b6, 0x00492 +}, rtl8821au_rf_vals3[] = { + 0x00145, 0x08145, 0x10145, 0x20196, 0x28196, 0x30196, 0x401c7, + 0x481c7, 0x501c7, 0x00000, 0x1712a, 0x00010, 0x056b3, 0x0d6b3, + 0x156b3, 0x1d6b3, 0x26634, 0x2e634, 0x36634, 0x3e634, 0x467b4, + 0x4e7b4, 0x567b4, 0x5e7b4, 0x00000, 0x00008, 0x0022a, 0x00594 +}, rtl8821au_rf_vals4_def_or_bt[] = { + 0x00800, 0x00000, 0x1712a, 0x00002, 0x02000, 0x00000, 0x000c0, + 0x00064, 0x81184, 0x6016c, 0xefd83, 0x93fcc, 0x110eb, 0x1c27c, + 0x93016 +}, rtl8821au_rf_vals4_ext_5g[] = { + 0x00820, 0x00000, 0x1712a, 0x00002, 0x02000, 0x00000, 0x000c0, + 0x00064, 0x81184, 0x6016c, 0xead53, 0x93bc4, 0x110e9, 0x1c67c, + 0x93015 +}, rtl8821au_rf_vals4[] = { + 0x00900, 0x00000, 0x1712a, 0x00002, 0x02000, 0x00000, 0x000c0, + 0x00064, 0x81184, 0x6016c, 0xead53, 0x93bc4, 0x714e9, 0x1c67c, + 0x91016 +}, rtl8821au_rf_vals5[] = { + 0x00006, 0x02000, 0x3824b, 0x3024b, 0x2844b, 0x20f4b, 0x18f4b, + 0x104b2, 0x08049, 0x00148, 0x7824b, 0x7024b, 0x6824b, 0x60f4b, + 0x58f4b, 0x504b2, 0x48049, 0x40148, 0x00000, 0x00100, 0x0adf3, + 0x09df0, 0x08d70, 0x07d6d, 0x06cee, 0x05ccc, 0x044ec, 0x034ac, + 0x0246d, 0x0106f, 0x0006c, 0x00000, 0x00010, 0x0adf2, 0x09def, + 0x08dec, 0x07de9, 0x06cec, 0x05ce9, 0x044ec, 0x034e9, 0x0246c, + 0x01469, 0x0006c, 0x00000, 0x00001, 0x38da7, 0x300c2, 0x288e2, + 0x200b8, 0x188a5, 0x10fbc, 0x08f71, 0x00240, 0x00000, 0x020a2, + 0x00080, 0x00120, 0x08120, 0x10120, 0x00085, 0x08085, 0x10085, + 0x18085, 0x00000, 0x00c31, 0x00622, 0xfc70b, 0x0017e, 0x51df3, + 0x00c01, 0x006d6, 0xfc649, 0x49661, 0x7843e, 0x00382, 0x51400, + 0x00160, 0x08160, 0x10160, 0x00124, 0x08124, 0x10124, 0x18124, + 0x0000c, 0x00140, 0x08140, 0x10140, 0x00124, 0x08124, 0x10124, + 0x18124, 0x00088, 0xf0e18, 0x1214c, 0x3000c, 0x539d2, 0xafe00, + 0x1f12a, 0x0c350, 0x0c350, 0x1712a, +}; + +static const struct rtwn_rf_prog rtl8821au_rf[] = { + /* RF chain 0. */ + { + nitems(rtl8821au_rf_regs0), + rtl8821au_rf_regs0, + rtl8821au_rf_vals0, + { 0 }, + NULL + }, + /* + * No external PA/LNA; with or without BT. + */ + { + nitems(rtl8821au_rf_regs1), + rtl8821au_rf_regs1, + rtl8821au_rf_vals1_def_or_bt, + { R21A_COND_BOARD_DEF, R21A_COND_BT, 0 }, + /* + * With external 5GHz PA and LNA. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs1), + rtl8821au_rf_regs1, + rtl8821au_rf_vals1_ext_5g, + { R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 }, + /* + * Others. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs1), + rtl8821au_rf_regs1, + rtl8821au_rf_vals1, + { 0 }, + NULL + } + } + }, + /* + * With external 5GHz PA and LNA. + */ + { + nitems(rtl8821au_rf_regs2), + rtl8821au_rf_regs2, + rtl8821au_rf_vals2_ext_5g, + { R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 }, + /* + * Others. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs2), + rtl8821au_rf_regs2, + rtl8821au_rf_vals2, + { 0 }, + NULL + } + }, + /* + * No external PA/LNA; with or without BT. + */ + { + nitems(rtl8821au_rf_regs3), + rtl8821au_rf_regs3, + rtl8821au_rf_vals3_def_or_bt, + { R21A_COND_BOARD_DEF, R21A_COND_BT, 0 }, + /* + * Others. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs3), + rtl8821au_rf_regs3, + rtl8821au_rf_vals3, + { 0 }, + NULL + } + }, + /* + * No external PA/LNA; with or without BT. + */ + { + nitems(rtl8821au_rf_regs4), + rtl8821au_rf_regs4, + rtl8821au_rf_vals4_def_or_bt, + { R21A_COND_BOARD_DEF, R21A_COND_BT, 0 }, + /* + * With external 5GHz PA and LNA. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs4), + rtl8821au_rf_regs4, + rtl8821au_rf_vals4_ext_5g, + { R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 }, + /* + * Others. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs4), + rtl8821au_rf_regs4, + rtl8821au_rf_vals4, + { 0 }, + NULL + } + } + }, + { + nitems(rtl8821au_rf_regs5), + rtl8821au_rf_regs5, + rtl8821au_rf_vals5, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL } +}; + + +/* + * Registers to save before IQ calibration. + */ +static const uint16_t r21a_iq_bb_regs[] = { + 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0x838, 0x82c +}; + +static const uint16_t r21a_iq_afe_regs[] = { + 0xc5c, 0xc60, 0xc64, 0xc68 +}; + +static const uint8_t r21a_iq_rf_regs[] = { + 0x65, 0x8f, 0x0 +}; + +#endif /* R21A_PRIV_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h b/freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h new file mode 100644 index 00000000..d13872d5 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_reg.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R21A_REG_H +#define R21A_REG_H + +#include + +/* + * MAC registers. + */ +/* Tx DMA Configuration. */ +#define R21A_DWBCN0_CTRL R92C_TDECTRL +#define R21A_DWBCN1_CTRL 0x228 + + +/* Bits for R92C_MAC_PHY_CTRL. */ +#define R21A_MAC_PHY_CRYSTALCAP_M 0x00fff000 +#define R21A_MAC_PHY_CRYSTALCAP_S 12 + +/* Bits for R21A_DWBCN1_CTRL. */ +#define R21A_DWBCN1_CTRL_SEL_EN 0x00020000 +#define R21A_DWBCN1_CTRL_SEL_BCN1 0x00100000 + +#endif /* R21A_REG_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c new file mode 100644 index 00000000..be64a064 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_rom.c @@ -0,0 +1,93 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + + +void +r21a_parse_rom(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r12a_softc *rs = sc->sc_priv; + struct r12a_rom *rom = (struct r12a_rom *)buf; + uint8_t pa_type, lna_type_2g, lna_type_5g; + + /* Read PA/LNA types. */ + pa_type = RTWN_GET_ROM_VAR(rom->pa_type, 0); + lna_type_2g = RTWN_GET_ROM_VAR(rom->lna_type_2g, 0); + lna_type_5g = RTWN_GET_ROM_VAR(rom->lna_type_5g, 0); + + rs->ext_pa_2g = R21A_ROM_IS_PA_EXT_2GHZ(pa_type); + rs->ext_pa_5g = R21A_ROM_IS_PA_EXT_5GHZ(pa_type); + rs->ext_lna_2g = R21A_ROM_IS_LNA_EXT(lna_type_2g); + rs->ext_lna_5g = R21A_ROM_IS_LNA_EXT(lna_type_5g); + + RTWN_LOCK(sc); + rs->bt_coex = + !!(rtwn_read_4(sc, R92C_MULTI_FUNC_CTRL) & R92C_MULTI_BT_FUNC_EN); + RTWN_UNLOCK(sc); + rs->bt_ant_num = (rom->rf_bt_opt & R12A_RF_BT_OPT_ANT_NUM); + + /* Read MAC address. */ + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr_21a); + + /* Execute common part of initialization. */ + r12a_parse_rom_common(sc, buf); +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c b/freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c new file mode 100644 index 00000000..498d2423 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/r21a_rx.c @@ -0,0 +1,90 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + + +int8_t +r21a_get_rssi_cck(struct rtwn_softc *sc, void *physt) +{ + struct r12a_rx_phystat *stat = (struct r12a_rx_phystat *)physt; + int8_t lna_idx, rssi; + + lna_idx = (stat->cfosho[0] & 0xe0) >> 5; + rssi = -6 - 2*(stat->cfosho[0] & 0x1f); /* Pout - (2 * VGA_idx) */ + + switch (lna_idx) { + case 5: + rssi -= 32; + break; + case 4: + rssi -= 24; + break; + case 2: + rssi -= 11; + break; + case 1: + rssi += 5; + break; + case 0: + rssi += 21; + break; + } + + return (rssi); +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h new file mode 100644 index 00000000..60aa476c --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef RTL8821AU_H +#define RTL8821AU_H + +#include + + +/* + * Function declarations. + */ +/* r21au_init.c */ +void r21au_init_tx_agg(struct rtwn_softc *); +void r21au_init_burstlen(struct rtwn_softc *); + +/* r21au_dfs.c */ +void r21au_chan_check(void *, int); +int r21au_newstate(struct ieee80211vap *, enum ieee80211_state, int); +void r21au_scan_start(struct ieee80211com *); +void r21au_scan_end(struct ieee80211com *); + +#endif /* RTL8821AU_H */ diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c new file mode 100644 index 00000000..6f7129f8 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c @@ -0,0 +1,283 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#include + +#include +#include + +#include +#include + +#include + + +void r21au_attach(struct rtwn_usb_softc *); + +static void +r21a_postattach(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct r12a_softc *rs = sc->sc_priv; + + if (rs->board_type == R92C_BOARD_TYPE_MINICARD || + rs->board_type == R92C_BOARD_TYPE_SOLO || + rs->board_type == R92C_BOARD_TYPE_COMBO) + sc->sc_set_led = r88e_set_led; + else + sc->sc_set_led = r21a_set_led; + + TIMEOUT_TASK_INIT(taskqueue_thread, &rs->rs_chan_check, 0, + r21au_chan_check, sc); + + /* RXCKSUM */ + ic->ic_ioctl = r12a_ioctl_net; + /* DFS */ + rs->rs_scan_start = ic->ic_scan_start; + ic->ic_scan_start = r21au_scan_start; + rs->rs_scan_end = ic->ic_scan_end; + ic->ic_scan_end = r21au_scan_end; +} + +static void +r21au_vap_preattach(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct rtwn_vap *rvp = RTWN_VAP(vap); + struct r12a_softc *rs = sc->sc_priv; + + r12a_vap_preattach(sc, vap); + + /* Install DFS newstate handler (non-monitor vaps only). */ + if (rvp->id != RTWN_VAP_ID_INVALID) { + KASSERT(rvp->id >= 0 && rvp->id <= nitems(rs->rs_newstate), + ("%s: wrong vap id %d\n", __func__, rvp->id)); + + rs->rs_newstate[rvp->id] = vap->iv_newstate; + vap->iv_newstate = r21au_newstate; + } +} + +static void +r21a_attach_private(struct rtwn_softc *sc) +{ + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); + struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); + struct r12a_softc *rs; + + rs = malloc(sizeof(struct r12a_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_flags = R12A_RXCKSUM_EN | R12A_RXCKSUM6_EN; + + rs->rs_radar = 0; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "radar_detection", CTLFLAG_RDTUN, &rs->rs_radar, + rs->rs_radar, "Enable radar detection (untested)"); + + rs->rs_fix_spur = rtwn_nop_softc_chan; + rs->rs_set_band_2ghz = r21a_set_band_2ghz; + rs->rs_set_band_5ghz = r21a_set_band_5ghz; + rs->rs_init_burstlen = r21au_init_burstlen; + rs->rs_init_ampdu_fwhw = r21a_init_ampdu_fwhw; + rs->rs_crystalcap_write = r21a_crystalcap_write; +#ifndef RTWN_WITHOUT_UCODE + rs->rs_iq_calib_fw_supported = r21a_iq_calib_fw_supported; +#endif + rs->rs_iq_calib_sw = r21a_iq_calib_sw; + + rs->ampdu_max_time = 0x5e; + + rs->ac_usb_dma_size = 0x01; + rs->ac_usb_dma_time = 0x10; + + sc->sc_priv = rs; +} + +static void +r21au_adj_devcaps(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct r12a_softc *rs = sc->sc_priv; + + if (rs->rs_radar != 0) + ic->ic_caps |= IEEE80211_C_DFS; + + /* TODO: LDPC etc */ +} + +void +r21au_attach(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + /* USB part. */ + uc->uc_align_rx = r12au_align_rx; + uc->tx_agg_desc_num = 6; + + /* Common part. */ + sc->sc_flags = RTWN_FLAG_EXT_HDR; + + sc->sc_set_chan = r12a_set_chan; + sc->sc_fill_tx_desc = r12a_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r12a_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r12a_fill_tx_desc_null; + sc->sc_dump_tx_desc = r12au_dump_tx_desc; + sc->sc_tx_radiotap_flags = r12a_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r12a_rx_radiotap_flags; + sc->sc_get_rssi_cck = r21a_get_rssi_cck; + sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm; + sc->sc_classify_intr = r12au_classify_intr; + sc->sc_handle_tx_report = r12a_ratectl_tx_complete; + sc->sc_handle_c2h_report = r12a_handle_c2h_report; + sc->sc_check_frame = r12a_check_frame_checksum; + sc->sc_rf_read = r12a_c_cut_rf_read; + sc->sc_rf_write = r12a_rf_write; + sc->sc_check_condition = r21a_check_condition; + sc->sc_efuse_postread = rtwn_nop_softc; + sc->sc_parse_rom = r21a_parse_rom; + sc->sc_power_on = r21a_power_on; + sc->sc_power_off = r21a_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r21a_fw_reset; + sc->sc_fw_download_enable = r12a_fw_download_enable; +#endif + sc->sc_set_page_size = rtwn_nop_int_softc; + sc->sc_lc_calib = rtwn_nop_softc; /* XXX not used */ + sc->sc_iq_calib = r12a_iq_calib; + sc->sc_read_chipid_vendor = rtwn_nop_softc_uint32; + sc->sc_adj_devcaps = r21au_adj_devcaps; + sc->sc_vap_preattach = r21au_vap_preattach; + sc->sc_postattach = r21a_postattach; + sc->sc_detach_private = r12a_detach_private; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_media_status = r12a_set_media_status; + sc->sc_set_rsvd_page = r88e_set_rsvd_page; + sc->sc_set_pwrmode = r12a_set_pwrmode; + sc->sc_set_rssi = rtwn_nop_softc; /* XXX TODO */ +#else + sc->sc_set_media_status = rtwn_nop_softc_int; +#endif + sc->sc_beacon_init = r21a_beacon_init; + sc->sc_beacon_enable = r92c_beacon_enable; + sc->sc_beacon_set_rate = r12a_beacon_set_rate; + sc->sc_beacon_select = r21a_beacon_select; + sc->sc_temp_measure = r88e_temp_measure; + sc->sc_temp_read = r88e_temp_read; + sc->sc_init_tx_agg = r21au_init_tx_agg; + sc->sc_init_rx_agg = r12au_init_rx_agg; + sc->sc_init_ampdu = r12au_init_ampdu; + sc->sc_init_intr = r12a_init_intr; + sc->sc_init_edca = r12a_init_edca; + sc->sc_init_bb = r12a_init_bb; + sc->sc_init_rf = r12a_init_rf; + sc->sc_init_antsel = r12a_init_antsel; + sc->sc_post_init = r12au_post_init; + sc->sc_init_bcnq1_boundary = r21a_init_bcnq1_boundary; + + sc->chan_list_5ghz[0] = r12a_chan_5ghz_0; + sc->chan_list_5ghz[1] = r12a_chan_5ghz_1; + sc->chan_list_5ghz[2] = r12a_chan_5ghz_2; + sc->chan_num_5ghz[0] = nitems(r12a_chan_5ghz_0); + sc->chan_num_5ghz[1] = nitems(r12a_chan_5ghz_1); + sc->chan_num_5ghz[2] = nitems(r12a_chan_5ghz_2); + + sc->mac_prog = &rtl8821au_mac[0]; + sc->mac_size = nitems(rtl8821au_mac); + sc->bb_prog = &rtl8821au_bb[0]; + sc->bb_size = nitems(rtl8821au_bb); + sc->agc_prog = &rtl8821au_agc[0]; + sc->agc_size = nitems(rtl8821au_agc); + sc->rf_prog = &rtl8821au_rf[0]; + + sc->name = "RTL8821AU"; + sc->fwname = "rtwn-rtl8821aufw"; + sc->fwsig = 0x210; + + sc->page_count = R21A_TX_PAGE_COUNT; + sc->pktbuf_count = R12A_TXPKTBUF_COUNT; + + sc->ackto = 0x80; + sc->npubqpages = R12A_PUBQ_NPAGES; + sc->page_size = R21A_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r12au_tx_desc); + sc->efuse_maxlen = R12A_EFUSE_MAX_LEN; + sc->efuse_maplen = R12A_EFUSE_MAP_LEN; + sc->rx_dma_size = R12A_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R12A_MACID_MAX + 1; + sc->cam_entry_limit = R12A_CAM_ENTRY_COUNT; + sc->fwsize_limit = R12A_MAX_FW_SIZE; + sc->temp_delta = R88E_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R21A_DWBCN1_CTRL; + sc->rcr = R12A_RCR_DIS_CHK_14 | + R12A_RCR_VHT_ACK | + R12A_RCR_TCP_OFFLD_EN; + + sc->ntxchains = 1; + sc->nrxchains = 1; + + r21a_attach_private(sc); +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c new file mode 100644 index 00000000..796ce6e0 --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_dfs.c @@ -0,0 +1,282 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include + + +#define R21AU_RADAR_CHECK_PERIOD (2 * hz) + +static void +r21au_dfs_radar_disable(struct rtwn_softc *sc) +{ + rtwn_bb_setbits(sc, 0x924, 0x00008000, 0); +} + +static int +r21au_dfs_radar_is_enabled(struct rtwn_softc *sc) +{ + return !!(rtwn_bb_read(sc, 0x924) & 0x00008000); +} + +static int +r21au_dfs_radar_reset(struct rtwn_softc *sc) +{ + int error; + + error = rtwn_bb_setbits(sc, 0x924, 0x00008000, 0); + if (error != 0) + return (error); + + return (rtwn_bb_setbits(sc, 0x924, 0, 0x00008000)); +} + +static int +r21au_dfs_radar_enable(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + + RTWN_ASSERT_LOCKED(sc); + + RTWN_CHK(rtwn_bb_setbits(sc, 0x814, 0x3fffffff, 0x04cc4d10)); + RTWN_CHK(rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0xff, 0x06)); + RTWN_CHK(rtwn_bb_write(sc, 0x918, 0x1c16ecdf)); + RTWN_CHK(rtwn_bb_write(sc, 0x924, 0x0152a400)); + RTWN_CHK(rtwn_bb_write(sc, 0x91c, 0x0fa21a20)); + RTWN_CHK(rtwn_bb_write(sc, 0x920, 0xe0f57204)); + + return (r21au_dfs_radar_reset(sc)); + +#undef RTWN_CHK +} + +static int +r21au_dfs_radar_is_detected(struct rtwn_softc *sc) +{ + return !!(rtwn_bb_read(sc, 0xf98) & 0x00020000); +} + +void +r21au_chan_check(void *arg, int npending __unused) +{ + struct rtwn_softc *sc = arg; + struct r12a_softc *rs = sc->sc_priv; + struct ieee80211com *ic = &sc->sc_ic; + + RTWN_LOCK(sc); +#ifdef DIAGNOSTIC + RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, + "%s: periodical radar detection task\n", __func__); +#endif + + if (!r21au_dfs_radar_is_enabled(sc)) { + if (rs->rs_flags & R12A_RADAR_ENABLED) { + /* should not happen */ + device_printf(sc->sc_dev, + "%s: radar detection was turned off " + "unexpectedly, resetting...\n", __func__); + + /* XXX something more appropriate? */ + ieee80211_restart_all(ic); + } + RTWN_UNLOCK(sc); + return; + } + + if (r21au_dfs_radar_is_detected(sc)) { + r21au_dfs_radar_reset(sc); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR, "%s: got radar event\n", + __func__); + + RTWN_UNLOCK(sc); + IEEE80211_LOCK(ic); + + ieee80211_dfs_notify_radar(ic, ic->ic_curchan); + + IEEE80211_UNLOCK(ic); + RTWN_LOCK(sc); + } + + if (rs->rs_flags & R12A_RADAR_ENABLED) { + taskqueue_enqueue_timeout(taskqueue_thread, + &rs->rs_chan_check, R21AU_RADAR_CHECK_PERIOD); + } + RTWN_UNLOCK(sc); +} + +int +r21au_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) +{ + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_softc *sc = ic->ic_softc; + struct rtwn_vap *rvp = RTWN_VAP(vap); + struct r12a_softc *rs = sc->sc_priv; + int error; + + KASSERT(rvp->id == 0 || rvp->id == 1, + ("%s: unexpected vap id %d\n", __func__, rvp->id)); + + IEEE80211_UNLOCK(ic); + RTWN_LOCK(sc); + + error = 0; + if (nstate == IEEE80211_S_CAC && + !(rs->rs_flags & R12A_RADAR_ENABLED)) { + error = r21au_dfs_radar_enable(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: cannot enable radar detection\n", __func__); + goto fail; + } + rs->rs_flags |= R12A_RADAR_ENABLED; + + RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR, + "%s: radar detection was enabled\n", __func__); + + taskqueue_enqueue_timeout(taskqueue_thread, + &rs->rs_chan_check, R21AU_RADAR_CHECK_PERIOD); + } + + if ((nstate < IEEE80211_S_CAC || nstate == IEEE80211_S_CSA) && + (rs->rs_flags & R12A_RADAR_ENABLED) && + (sc->vaps[!rvp->id] == NULL || + sc->vaps[!rvp->id]->vap.iv_state < IEEE80211_S_CAC || + sc->vaps[!rvp->id]->vap.iv_state == IEEE80211_S_CSA)) { + taskqueue_cancel_timeout(taskqueue_thread, &rs->rs_chan_check, + NULL); + + rs->rs_flags &= ~R12A_RADAR_ENABLED; + r21au_dfs_radar_disable(sc); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR, + "%s: radar detection was disabled\n", __func__); + } + +fail: + RTWN_UNLOCK(sc); + IEEE80211_LOCK(ic); + + if (error != 0) + return (error); + + return (rs->rs_newstate[rvp->id](vap, nstate, arg)); +} + +void +r21au_scan_start(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct r12a_softc *rs = sc->sc_priv; + + RTWN_LOCK(sc); + if (rs->rs_flags & R12A_RADAR_ENABLED) { + RTWN_UNLOCK(sc); + while (taskqueue_cancel_timeout(taskqueue_thread, + &rs->rs_chan_check, NULL) != 0) { + taskqueue_drain_timeout(taskqueue_thread, + &rs->rs_chan_check); + } + RTWN_LOCK(sc); + + r21au_dfs_radar_disable(sc); + RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR, + "%s: radar detection was (temporarily) disabled\n", + __func__); + } + RTWN_UNLOCK(sc); + + rs->rs_scan_start(ic); +} + +void +r21au_scan_end(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct r12a_softc *rs = sc->sc_priv; + int error; + + RTWN_LOCK(sc); + if (rs->rs_flags & R12A_RADAR_ENABLED) { + error = r21au_dfs_radar_enable(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: cannot re-enable radar detection\n", + __func__); + + /* XXX */ + ieee80211_restart_all(ic); + RTWN_UNLOCK(sc); + return; + } + RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR, + "%s: radar detection was re-enabled\n", __func__); + + taskqueue_enqueue_timeout(taskqueue_thread, + &rs->rs_chan_check, R21AU_RADAR_CHECK_PERIOD); + } + RTWN_UNLOCK(sc); + + rs->rs_scan_end(ic); +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c new file mode 100644 index 00000000..484d2dad --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_init.c @@ -0,0 +1,85 @@ +#include + +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include +#include + + +void +r21au_init_tx_agg(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + r92cu_init_tx_agg(sc); + + rtwn_write_1(sc, R21A_DWBCN1_CTRL, uc->tx_agg_desc_num << 1); +} + +void +r21au_init_burstlen(struct rtwn_softc *sc) +{ + if ((rtwn_read_1(sc, R92C_USB_INFO) & 0x30) == 0) { + /* Set burst packet length to 512 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x20, 0x1e); + } else { + /* Set burst packet length to 64 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x10, 0x2e); + } +} diff --git a/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h new file mode 100644 index 00000000..cd0deb5f --- /dev/null +++ b/freebsd/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef R21AU_REG_H +#define R21AU_REG_H + +#include +#include + +#endif /* R21AU_REG_H */ diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c new file mode 100644 index 00000000..f378ca3c --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c @@ -0,0 +1,444 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include + +static device_probe_t rtwn_usb_match; +static device_attach_t rtwn_usb_attach; +static device_detach_t rtwn_usb_detach; +static device_suspend_t rtwn_usb_suspend; +static device_resume_t rtwn_usb_resume; + +static int rtwn_usb_alloc_list(struct rtwn_softc *, + struct rtwn_data[], int, int); +static int rtwn_usb_alloc_rx_list(struct rtwn_softc *); +static int rtwn_usb_alloc_tx_list(struct rtwn_softc *); +static void rtwn_usb_free_list(struct rtwn_softc *, + struct rtwn_data data[], int); +static void rtwn_usb_free_rx_list(struct rtwn_softc *); +static void rtwn_usb_free_tx_list(struct rtwn_softc *); +static void rtwn_usb_reset_lists(struct rtwn_softc *, + struct ieee80211vap *); +static void rtwn_usb_reset_tx_list(struct rtwn_usb_softc *, + rtwn_datahead *, struct ieee80211vap *); +static void rtwn_usb_start_xfers(struct rtwn_softc *); +static void rtwn_usb_abort_xfers(struct rtwn_softc *); +static int rtwn_usb_fw_write_block(struct rtwn_softc *, + const uint8_t *, uint16_t, int); +static void rtwn_usb_drop_incorrect_tx(struct rtwn_softc *); +static void rtwn_usb_attach_methods(struct rtwn_softc *); + +#define RTWN_CONFIG_INDEX 0 + + +static int +rtwn_usb_match(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + + if (uaa->usb_mode != USB_MODE_HOST) + return (ENXIO); + if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX) + return (ENXIO); + if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa)); +} + +static int +rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[], + int ndata, int maxsz) +{ + int i, error; + + for (i = 0; i < ndata; i++) { + struct rtwn_data *dp = &data[i]; + dp->m = NULL; + dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); + if (dp->buf == NULL) { + device_printf(sc->sc_dev, + "could not allocate buffer\n"); + error = ENOMEM; + goto fail; + } + dp->ni = NULL; + } + + return (0); +fail: + rtwn_usb_free_list(sc, data, ndata); + return (error); +} + +static int +rtwn_usb_alloc_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int error, i; + + /* XXX recheck */ + error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT, + sc->rx_dma_size + 1024); + if (error != 0) + return (error); + + STAILQ_INIT(&uc->uc_rx_active); + STAILQ_INIT(&uc->uc_rx_inactive); + + for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) + STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next); + + return (0); +} + +static int +rtwn_usb_alloc_tx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int error, i; + + error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT, + RTWN_TXBUFSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&uc->uc_tx_active); + STAILQ_INIT(&uc->uc_tx_inactive); + STAILQ_INIT(&uc->uc_tx_pending); + + for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++) + STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next); + + return (0); +} + +static void +rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata) +{ + int i; + + for (i = 0; i < ndata; i++) { + struct rtwn_data *dp = &data[i]; + + if (dp->buf != NULL) { + free(dp->buf, M_USBDEV); + dp->buf = NULL; + } + if (dp->ni != NULL) { + ieee80211_free_node(dp->ni); + dp->ni = NULL; + } + if (dp->m != NULL) { + m_freem(dp->m); + dp->m = NULL; + } + } +} + +static void +rtwn_usb_free_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT); + + STAILQ_INIT(&uc->uc_rx_active); + STAILQ_INIT(&uc->uc_rx_inactive); +} + +static void +rtwn_usb_free_tx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT); + + STAILQ_INIT(&uc->uc_tx_active); + STAILQ_INIT(&uc->uc_tx_inactive); + STAILQ_INIT(&uc->uc_tx_pending); +} + +static void +rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + RTWN_ASSERT_LOCKED(sc); + + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap); + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap); + if (vap == NULL) + sc->qfullmsk = 0; +} + +static void +rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc, + rtwn_datahead *head, struct ieee80211vap *vap) +{ + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct rtwn_data *dp, *tmp; + int id; + + id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); + + STAILQ_FOREACH_SAFE(dp, head, next, tmp) { + if (vap == NULL || (dp->ni == NULL && + (dp->id == id || id == RTWN_VAP_ID_INVALID)) || + (dp->ni != NULL && dp->ni->ni_vap == vap)) { + if (dp->ni != NULL) { + ieee80211_free_node(dp->ni); + dp->ni = NULL; + } + + if (dp->m != NULL) { + m_freem(dp->m); + dp->m = NULL; + } + + STAILQ_REMOVE(head, dp, rtwn_data, next); + STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next); + } + } +} + +static void +rtwn_usb_start_xfers(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]); +} + +static void +rtwn_usb_abort_xfers(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int i; + + RTWN_ASSERT_LOCKED(sc); + + /* abort any pending transfers */ + RTWN_UNLOCK(sc); + for (i = 0; i < RTWN_N_TRANSFER; i++) + usbd_transfer_drain(uc->uc_xfer[i]); + RTWN_LOCK(sc); +} + +static int +rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, + uint16_t reg, int mlen) +{ + int error; + + /* XXX fix this deconst */ + error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf), + mlen); + + return (error); +} + +static void +rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc) +{ + + rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0, + R92C_TXDMA_OFFSET_DROP_DATA_EN, 1); +} + +static void +rtwn_usb_attach_methods(struct rtwn_softc *sc) +{ + sc->sc_write_1 = rtwn_usb_write_1; + sc->sc_write_2 = rtwn_usb_write_2; + sc->sc_write_4 = rtwn_usb_write_4; + sc->sc_read_1 = rtwn_usb_read_1; + sc->sc_read_2 = rtwn_usb_read_2; + sc->sc_read_4 = rtwn_usb_read_4; + sc->sc_delay = rtwn_usb_delay; + sc->sc_tx_start = rtwn_usb_tx_start; + sc->sc_start_xfers = rtwn_usb_start_xfers; + sc->sc_reset_lists = rtwn_usb_reset_lists; + sc->sc_abort_xfers = rtwn_usb_abort_xfers; + sc->sc_fw_write_block = rtwn_usb_fw_write_block; + sc->sc_get_qmap = rtwn_usb_get_qmap; + sc->sc_set_desc_addr = rtwn_nop_softc; + sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx; + sc->sc_beacon_update_begin = rtwn_nop_softc_vap; + sc->sc_beacon_update_end = rtwn_nop_softc_vap; + sc->sc_beacon_unload = rtwn_nop_softc_int; + + sc->bcn_check_interval = 100; +} + +static int +rtwn_usb_attach(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + struct rtwn_usb_softc *uc = device_get_softc(self); + struct rtwn_softc *sc = &uc->uc_sc; + struct ieee80211com *ic = &sc->sc_ic; + int error; + + device_set_usb_desc(self); + uc->uc_udev = uaa->device; + sc->sc_dev = self; + ic->ic_name = device_get_nameunit(self); + + /* Need to be initialized early. */ + rtwn_sysctlattach(sc); + mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); + + rtwn_usb_attach_methods(sc); + rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa)); + + error = rtwn_usb_setup_endpoints(uc); + if (error != 0) + goto detach; + + /* Allocate Tx/Rx buffers. */ + error = rtwn_usb_alloc_rx_list(sc); + if (error != 0) + goto detach; + + error = rtwn_usb_alloc_tx_list(sc); + if (error != 0) + goto detach; + + /* Generic attach. */ + error = rtwn_attach(sc); + if (error != 0) + goto detach; + + return (0); + +detach: + rtwn_usb_detach(self); /* failure */ + return (ENXIO); +} + +static int +rtwn_usb_detach(device_t self) +{ + struct rtwn_usb_softc *uc = device_get_softc(self); + struct rtwn_softc *sc = &uc->uc_sc; + + /* Generic detach. */ + rtwn_detach(sc); + + /* Free Tx/Rx buffers. */ + rtwn_usb_free_tx_list(sc); + rtwn_usb_free_rx_list(sc); + + /* Detach all USB transfers. */ + usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER); + + rtwn_detach_private(sc); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static int +rtwn_usb_suspend(device_t self) +{ + struct rtwn_usb_softc *uc = device_get_softc(self); + + rtwn_suspend(&uc->uc_sc); + + return (0); +} + +static int +rtwn_usb_resume(device_t self) +{ + struct rtwn_usb_softc *uc = device_get_softc(self); + + rtwn_resume(&uc->uc_sc); + + return (0); +} + +static device_method_t rtwn_usb_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rtwn_usb_match), + DEVMETHOD(device_attach, rtwn_usb_attach), + DEVMETHOD(device_detach, rtwn_usb_detach), + DEVMETHOD(device_suspend, rtwn_usb_suspend), + DEVMETHOD(device_resume, rtwn_usb_resume), + + DEVMETHOD_END +}; + +static driver_t rtwn_usb_driver = { + "rtwn", + rtwn_usb_methods, + sizeof(struct rtwn_usb_softc) +}; + +static devclass_t rtwn_usb_devclass; + +DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, rtwn_usb_devclass, NULL, NULL); +MODULE_VERSION(rtwn_usb, 1); +MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1); +MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1); +MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2); +USB_PNP_HOST_INFO(rtwn_devs); diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h new file mode 100644 index 00000000..48a4d6e5 --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.h @@ -0,0 +1,160 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +void r92cu_attach(struct rtwn_usb_softc *); +void r88eu_attach(struct rtwn_usb_softc *); +void r12au_attach(struct rtwn_usb_softc *); +void r21au_attach(struct rtwn_usb_softc *); + +enum { + RTWN_CHIP_RTL8192CU, + RTWN_CHIP_RTL8188EU, + RTWN_CHIP_RTL8812AU, + RTWN_CHIP_RTL8821AU, + RTWN_CHIP_MAX_USB +}; + +/* various supported device vendors/products */ +static const STRUCT_USB_HOST_ID rtwn_devs[] = { + /* RTL8188CE-VAU/RTL8188CUS/RTL8188RU/RTL8192CU */ +#define RTWN_RTL8192CU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8192CU) } + RTWN_RTL8192CU_DEV(ABOCOM, RTL8188CU_1), + RTWN_RTL8192CU_DEV(ABOCOM, RTL8188CU_2), + RTWN_RTL8192CU_DEV(ABOCOM, RTL8192CU), + RTWN_RTL8192CU_DEV(ASUS, RTL8192CU), + RTWN_RTL8192CU_DEV(ASUS, USBN10NANO), + RTWN_RTL8192CU_DEV(AZUREWAVE, RTL8188CE_1), + RTWN_RTL8192CU_DEV(AZUREWAVE, RTL8188CE_2), + RTWN_RTL8192CU_DEV(AZUREWAVE, RTL8188CU), + RTWN_RTL8192CU_DEV(BELKIN, F7D2102), + RTWN_RTL8192CU_DEV(BELKIN, RTL8188CU), + RTWN_RTL8192CU_DEV(BELKIN, RTL8192CU), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_1), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_2), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_3), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_4), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_5), + RTWN_RTL8192CU_DEV(COREGA, RTL8192CU), + RTWN_RTL8192CU_DEV(DLINK, RTL8188CU), + RTWN_RTL8192CU_DEV(DLINK, RTL8192CU_1), + RTWN_RTL8192CU_DEV(DLINK, RTL8192CU_2), + RTWN_RTL8192CU_DEV(DLINK, RTL8192CU_3), + RTWN_RTL8192CU_DEV(DLINK, DWA131B), + RTWN_RTL8192CU_DEV(EDIMAX, EW7811UN), + RTWN_RTL8192CU_DEV(EDIMAX, RTL8192CU), + RTWN_RTL8192CU_DEV(FEIXUN, RTL8188CU), + RTWN_RTL8192CU_DEV(FEIXUN, RTL8192CU), + RTWN_RTL8192CU_DEV(GUILLEMOT, HWNUP150), + RTWN_RTL8192CU_DEV(HAWKING, RTL8192CU), + RTWN_RTL8192CU_DEV(HP3, RTL8188CU), + RTWN_RTL8192CU_DEV(NETGEAR, WNA1000M), + RTWN_RTL8192CU_DEV(NETGEAR, RTL8192CU), + RTWN_RTL8192CU_DEV(NETGEAR4, RTL8188CU), + RTWN_RTL8192CU_DEV(NOVATECH, RTL8188CU), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_1), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_2), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_3), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_4), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CUS), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8192CU), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CE_0), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CE_1), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CTV), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_0), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_1), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_2), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_3), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_COMBO), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CUS), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188RU_1), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188RU_2), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188RU_3), + RTWN_RTL8192CU_DEV(REALTEK, RTL8191CU), + RTWN_RTL8192CU_DEV(REALTEK, RTL8192CE), + RTWN_RTL8192CU_DEV(REALTEK, RTL8192CU), + RTWN_RTL8192CU_DEV(REALTEK, RTL8192CU_1), + RTWN_RTL8192CU_DEV(SITECOMEU, RTL8188CU_1), + RTWN_RTL8192CU_DEV(SITECOMEU, RTL8188CU_2), + RTWN_RTL8192CU_DEV(SITECOMEU, RTL8192CU), + RTWN_RTL8192CU_DEV(TRENDNET, RTL8188CU), + RTWN_RTL8192CU_DEV(TRENDNET, RTL8192CU), + RTWN_RTL8192CU_DEV(ZYXEL, RTL8192CU), +#undef RTWN_RTL8192CU_DEV + + /* RTL8188EU */ +#define RTWN_RTL8188EU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8188EU) } + RTWN_RTL8188EU_DEV(ABOCOM, RTL8188EU), + RTWN_RTL8188EU_DEV(DLINK, DWA123D1), + RTWN_RTL8188EU_DEV(DLINK, DWA125D1), + RTWN_RTL8188EU_DEV(ELECOM, WDC150SU2M), + RTWN_RTL8188EU_DEV(REALTEK, RTL8188ETV), + RTWN_RTL8188EU_DEV(REALTEK, RTL8188EU), +#undef RTWN_RTL8188EU_DEV + + /* RTL8812AU */ +#define RTWN_RTL8812AU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8812AU) } + RTWN_RTL8812AU_DEV(ASUS, USBAC56), + RTWN_RTL8812AU_DEV(CISCOLINKSYS, WUSB6300), + RTWN_RTL8812AU_DEV(DLINK, DWA182C1), + RTWN_RTL8812AU_DEV(DLINK, DWA180A1), + RTWN_RTL8812AU_DEV(EDIMAX, EW7822UAC), + RTWN_RTL8812AU_DEV(IODATA, WNAC867U), + RTWN_RTL8812AU_DEV(MELCO, WIU3866D), + RTWN_RTL8812AU_DEV(NEC, WL900U), + RTWN_RTL8812AU_DEV(PLANEX2, GW900D), + RTWN_RTL8812AU_DEV(SENAO, EUB1200AC), + RTWN_RTL8812AU_DEV(SITECOMEU, WLA7100), + RTWN_RTL8812AU_DEV(TPLINK, T4U), + RTWN_RTL8812AU_DEV(TRENDNET, TEW805UB), + RTWN_RTL8812AU_DEV(ZYXEL, NWD6605), +#undef RTWN_RTL8812AU_DEV + + /* RTL8821AU */ +#define RTWN_RTL8821AU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8821AU) } + RTWN_RTL8821AU_DEV(DLINK, DWA171A1), + RTWN_RTL8821AU_DEV(DLINK, DWA172A1), + RTWN_RTL8821AU_DEV(EDIMAX, EW7811UTC_1), + RTWN_RTL8821AU_DEV(EDIMAX, EW7811UTC_2), + RTWN_RTL8821AU_DEV(HAWKING, HD65U), + RTWN_RTL8821AU_DEV(MELCO, WIU2433DM), + RTWN_RTL8821AU_DEV(NETGEAR, A6100) +#undef RTWN_RTL8821AU_DEV +}; + +typedef void (*chip_usb_attach)(struct rtwn_usb_softc *); + +static const chip_usb_attach rtwn_chip_usb_attach[RTWN_CHIP_MAX_USB] = { + [RTWN_CHIP_RTL8192CU] = r92cu_attach, + [RTWN_CHIP_RTL8188EU] = r88eu_attach, + [RTWN_CHIP_RTL8812AU] = r12au_attach, + [RTWN_CHIP_RTL8821AU] = r21au_attach +}; + +static __inline void +rtwn_usb_attach_private(struct rtwn_usb_softc *uc, int chip) +{ + rtwn_chip_usb_attach[chip](uc); +} diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c new file mode 100644 index 00000000..a1fafb46 --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c @@ -0,0 +1,255 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include + + +static struct usb_config rtwn_config[RTWN_N_TRANSFER] = { + [RTWN_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .flags = { + .pipe_bof = 1, + .short_xfer_ok = 1 + }, + .callback = rtwn_bulk_rx_callback, + }, + [RTWN_BULK_TX_BE] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1, + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, + [RTWN_BULK_TX_BK] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1, + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, + [RTWN_BULK_TX_VI] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, + [RTWN_BULK_TX_VO] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, +}; + +static void +rtwn_usb_setup_queues(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + int hasnq, haslq, nqueues, nqpages, nrempages; + + /* Get Tx queues to USB endpoints mapping. */ + hasnq = haslq = 0; + switch (uc->ntx) { + case 4: + case 3: + haslq = 1; + /* FALLTHROUGH */ + case 2: + hasnq = 1; + /* FALLTHROUGH */ + default: + break; + } + nqueues = 1 + hasnq + haslq; + + /* Get the number of pages for each queue. */ + nqpages = (sc->page_count - sc->npubqpages) / nqueues; + + /* + * The remaining pages are assigned to the high priority + * queue. + */ + nrempages = (sc->page_count - sc->npubqpages) % nqueues; + + sc->nhqpages = nqpages + nrempages; + sc->nnqpages = (hasnq ? nqpages : 0); + sc->nlqpages = (haslq ? nqpages : 0); +} + +int +rtwn_usb_setup_endpoints(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + const uint8_t iface_index = RTWN_IFACE_INDEX; + struct usb_endpoint *ep, *ep_end; + uint8_t addr[RTWN_MAX_EPOUT]; + int error; + + /* Determine the number of bulk-out pipes. */ + uc->ntx = 0; + ep = uc->uc_udev->endpoints; + ep_end = uc->uc_udev->endpoints + uc->uc_udev->endpoints_max; + for (; ep != ep_end; ep++) { + uint8_t eaddr; + + if ((ep->edesc == NULL) || (ep->iface_index != iface_index)) + continue; + + eaddr = ep->edesc->bEndpointAddress; + RTWN_DPRINTF(sc, RTWN_DEBUG_USB, + "%s: endpoint: addr %u, direction %s\n", __func__, + UE_GET_ADDR(eaddr), UE_GET_DIR(eaddr) == UE_DIR_OUT ? + "output" : "input"); + + if (UE_GET_DIR(eaddr) == UE_DIR_OUT) { + if (uc->ntx == RTWN_MAX_EPOUT) + break; + + addr[uc->ntx++] = UE_GET_ADDR(eaddr); + } + } + if (uc->ntx == 0 || uc->ntx > RTWN_MAX_EPOUT) { + device_printf(sc->sc_dev, + "%s: invalid number of Tx bulk pipes (%d)\n", __func__, + uc->ntx); + return (EINVAL); + } + + /* NB: keep in sync with rtwn_dma_init(). */ + rtwn_config[RTWN_BULK_TX_VO].endpoint = addr[0]; + switch (uc->ntx) { + case 4: + case 3: + rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[2]; + rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[2]; + rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[1]; + break; + case 2: + rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[1]; + rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[1]; + rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + break; + case 1: + rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[0]; + rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[0]; + rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + break; + default: + KASSERT(0, ("unhandled number of endpoints %d\n", uc->ntx)); + break; + } + + rtwn_config[RTWN_BULK_RX].bufsize = sc->rx_dma_size + 1024; + error = usbd_transfer_setup(uc->uc_udev, &iface_index, + uc->uc_xfer, rtwn_config, RTWN_N_TRANSFER, uc, &sc->sc_mtx); + if (error) { + device_printf(sc->sc_dev, "could not allocate USB transfers, " + "err=%s\n", usbd_errstr(error)); + return (error); + } + + /* Assign pages for each queue (if not done). */ + if (sc->nhqpages == 0 && sc->nnqpages == 0 && sc->nlqpages == 0) + rtwn_usb_setup_queues(uc); + + return (0); +} + +uint16_t +rtwn_usb_get_qmap(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + switch (uc->ntx) { + case 1: + return (R92C_TRXDMA_CTRL_QMAP_HQ); + case 2: + return (R92C_TRXDMA_CTRL_QMAP_HQ_NQ); + default: + return (R92C_TRXDMA_CTRL_QMAP_3EP); + } +} diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h new file mode 100644 index 00000000..0cdd738e --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.h @@ -0,0 +1,25 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_EP_H +#define IF_RTWN_EP_H + +int rtwn_usb_setup_endpoints(struct rtwn_usb_softc *); +uint16_t rtwn_usb_get_qmap(struct rtwn_softc *); + +#endif /* IF_RTWN_EP_H */ diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c new file mode 100644 index 00000000..1461205b --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.c @@ -0,0 +1,181 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +static int rtwn_do_request(struct rtwn_softc *, + struct usb_device_request *, void *); +static int rtwn_usb_read_region_1(struct rtwn_softc *, + uint16_t, uint8_t *, int); + +/* USB Requests. */ +#define R92C_REQ_REGS 0x05 + + +static int +rtwn_do_request(struct rtwn_softc *sc, struct usb_device_request *req, + void *data) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + usb_error_t err; + int ntries = 10; + + RTWN_ASSERT_LOCKED(sc); + + while (ntries--) { + err = usbd_do_request_flags(uc->uc_udev, &sc->sc_mtx, + req, data, 0, NULL, 250 /* ms */); + if (err == USB_ERR_NORMAL_COMPLETION) + return (0); + + RTWN_DPRINTF(sc, RTWN_DEBUG_USB, + "%s: control request failed, %s (retries left: %d)\n", + __func__, usbd_errstr(err), ntries); + if (err == USB_ERR_NOT_CONFIGURED) + return (ENXIO); + + usb_pause_mtx(&sc->sc_mtx, hz / 100); + } + return (EIO); +} + +/* export for rtwn_fw_write_block() */ +int +rtwn_usb_write_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf, + int len) +{ + usb_device_request_t req; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = R92C_REQ_REGS; + USETW(req.wValue, addr); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + return (rtwn_do_request(sc, &req, buf)); +} + +int +rtwn_usb_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val) +{ + return (rtwn_usb_write_region_1(sc, addr, &val, sizeof(val))); +} + +int +rtwn_usb_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val) +{ + val = htole16(val); + return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); +} + +int +rtwn_usb_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val) +{ + val = htole32(val); + return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); +} + +static int +rtwn_usb_read_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf, + int len) +{ + usb_device_request_t req; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = R92C_REQ_REGS; + USETW(req.wValue, addr); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + return (rtwn_do_request(sc, &req, buf)); +} + +uint8_t +rtwn_usb_read_1(struct rtwn_softc *sc, uint16_t addr) +{ + uint8_t val; + + if (rtwn_usb_read_region_1(sc, addr, &val, 1) != 0) + return (0xff); + return (val); +} + +uint16_t +rtwn_usb_read_2(struct rtwn_softc *sc, uint16_t addr) +{ + uint16_t val; + + if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0) + return (0xffff); + return (le16toh(val)); +} + +uint32_t +rtwn_usb_read_4(struct rtwn_softc *sc, uint16_t addr) +{ + uint32_t val; + + if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0) + return (0xffffffff); + return (le32toh(val)); +} + +void +rtwn_usb_delay(struct rtwn_softc *sc, int usec) +{ + + /* 1ms delay as default is too big. */ + if (usec < 1000) + DELAY(usec); + else { + usb_pause_mtx(&sc->sc_mtx, + MAX(msecs_to_ticks(usec / 1000), 1)); + } +} diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h new file mode 100644 index 00000000..1149248d --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_reg.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_USB_REG_H +#define RTWN_USB_REG_H + +static __inline uint16_t +rtwn_usb_calc_tx_checksum(void *buf) +{ + uint16_t sum = 0; + int i; + + /* NB: checksum calculation takes into account only first 32 bytes. */ + for (i = 0; i < 32 / 2; i++) + sum ^= ((uint16_t *)buf)[i]; + + return (sum); /* NB: already little endian. */ +} + +int rtwn_usb_write_region_1(struct rtwn_softc *, uint16_t, + uint8_t *, int); +int rtwn_usb_write_1(struct rtwn_softc *, uint16_t, uint8_t); +int rtwn_usb_write_2(struct rtwn_softc *, uint16_t, uint16_t); +int rtwn_usb_write_4(struct rtwn_softc *, uint16_t, uint32_t); +uint8_t rtwn_usb_read_1(struct rtwn_softc *, uint16_t); +uint16_t rtwn_usb_read_2(struct rtwn_softc *, uint16_t); +uint32_t rtwn_usb_read_4(struct rtwn_softc *, uint16_t); +void rtwn_usb_delay(struct rtwn_softc *, int); + +#endif /* RTWN_USB_REG_H */ diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c new file mode 100644 index 00000000..8795e16d --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c @@ -0,0 +1,342 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#ifdef IEEE80211_SUPPORT_SUPERG +#include +#endif + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include /* for CAM_ALGO_NONE */ +#include + + +static struct mbuf * +rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct r92c_rx_stat *stat, + int totlen) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct mbuf *m; + uint32_t rxdw0; + int pktlen; + + RTWN_ASSERT_LOCKED(sc); + + /* Dump Rx descriptor. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC, + "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X\n", + __func__, le32toh(stat->rxdw0), le32toh(stat->rxdw1), + le32toh(stat->rxdw2), le32toh(stat->rxdw3), le32toh(stat->rxdw4), + le32toh(stat->tsf_low)); + + /* + * don't pass packets to the ieee80211 framework if the driver isn't + * RUNNING. + */ + if (!(sc->sc_flags & RTWN_RUNNING)) + return (NULL); + + rxdw0 = le32toh(stat->rxdw0); + if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { + /* + * This should not happen since we setup our Rx filter + * to not receive these frames. + */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: RX flags error (%s)\n", __func__, + rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV"); + goto fail; + } + + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack))) { + /* + * Should not happen (because of Rx filter setup). + */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: frame is too short: %d\n", __func__, pktlen); + goto fail; + } + + m = m_get2(totlen, M_NOWAIT, MT_DATA, M_PKTHDR); + if (__predict_false(m == NULL)) { + device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n", + __func__); + goto fail; + } + + /* Finalize mbuf. */ + memcpy(mtod(m, uint8_t *), (uint8_t *)stat, totlen); + m->m_pkthdr.len = m->m_len = totlen; + + if (rtwn_check_frame(sc, m) != 0) { + m_freem(m); + goto fail; + } + + return (m); +fail: + counter_u64_add(ic->ic_ierrors, 1); + return (NULL); +} + +static struct mbuf * +rtwn_rxeof(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + struct r92c_rx_stat *stat; + struct mbuf *m, *m0 = NULL; + uint32_t rxdw0; + int totlen, pktlen, infosz; + + /* Process packets. */ + while (len >= sizeof(*stat)) { + stat = (struct r92c_rx_stat *)buf; + rxdw0 = le32toh(stat->rxdw0); + + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + if (__predict_false(pktlen == 0)) + break; + + infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; + + /* Make sure everything fits in xfer. */ + totlen = sizeof(*stat) + infosz + pktlen; + if (totlen > len) { + device_printf(sc->sc_dev, + "%s: totlen (%d) > len (%d)!\n", + __func__, totlen, len); + break; + } + + if (m0 == NULL) + m0 = m = rtwn_rx_copy_to_mbuf(sc, stat, totlen); + else { + m->m_next = rtwn_rx_copy_to_mbuf(sc, stat, totlen); + if (m->m_next != NULL) + m = m->m_next; + } + + /* Align next frame. */ + totlen = rtwn_usb_align_rx(uc, totlen, len); + buf += totlen; + len -= totlen; + } + + return (m0); +} + +static struct mbuf * +rtwn_report_intr(struct rtwn_usb_softc *uc, struct usb_xfer *xfer, + struct rtwn_data *data) +{ + struct rtwn_softc *sc = &uc->uc_sc; + struct ieee80211com *ic = &sc->sc_ic; + uint8_t *buf; + int len; + + usbd_xfer_status(xfer, &len, NULL, NULL, NULL); + + if (__predict_false(len < sizeof(struct r92c_rx_stat))) { + counter_u64_add(ic->ic_ierrors, 1); + return (NULL); + } + + buf = data->buf; + switch (rtwn_classify_intr(sc, buf, len)) { + case RTWN_RX_DATA: + return (rtwn_rxeof(sc, buf, len)); + case RTWN_RX_TX_REPORT: + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) { + /* shouldn't happen */ + device_printf(sc->sc_dev, + "%s called while ratectl = %d!\n", + __func__, sc->sc_ratectl); + break; + } + + RTWN_NT_LOCK(sc); + rtwn_handle_tx_report(sc, buf, len); + RTWN_NT_UNLOCK(sc); + +#ifdef IEEE80211_SUPPORT_SUPERG + /* + * NB: this will executed only when 'report' bit is set. + */ + if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1) + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); +#endif + break; + case RTWN_RX_OTHER: + rtwn_handle_c2h_report(sc, buf, len); + break; + default: + /* NOTREACHED */ + KASSERT(0, ("unknown Rx classification code")); + break; + } + + return (NULL); +} + +static struct ieee80211_node * +rtwn_rx_frame(struct rtwn_softc *sc, struct mbuf *m, int8_t *rssi) +{ + struct r92c_rx_stat stat; + + /* Imitate PCIe layout. */ + m_copydata(m, 0, sizeof(struct r92c_rx_stat), (caddr_t)&stat); + m_adj(m, sizeof(struct r92c_rx_stat)); + + return (rtwn_rx_common(sc, m, &stat, rssi)); +} + +void +rtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer); + struct rtwn_softc *sc = &uc->uc_sc; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + struct mbuf *m = NULL, *next; + struct rtwn_data *data; + int8_t nf, rssi; + + RTWN_ASSERT_LOCKED(sc); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + data = STAILQ_FIRST(&uc->uc_rx_active); + if (data == NULL) + goto tr_setup; + STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next); + m = rtwn_report_intr(uc, xfer, data); + STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + data = STAILQ_FIRST(&uc->uc_rx_inactive); + if (data == NULL) { + KASSERT(m == NULL, ("mbuf isn't NULL")); + goto finish; + } + STAILQ_REMOVE_HEAD(&uc->uc_rx_inactive, next); + STAILQ_INSERT_TAIL(&uc->uc_rx_active, data, next); + usbd_xfer_set_frame_data(xfer, 0, data->buf, + usbd_xfer_max_len(xfer)); + usbd_transfer_submit(xfer); + + /* + * To avoid LOR we should unlock our private mutex here to call + * ieee80211_input() because here is at the end of a USB + * callback and safe to unlock. + */ + while (m != NULL) { + next = m->m_next; + m->m_next = NULL; + + ni = rtwn_rx_frame(sc, m, &rssi); + + RTWN_UNLOCK(sc); + + nf = RTWN_NOISE_FLOOR; + if (ni != NULL) { + if (ni->ni_flags & IEEE80211_NODE_HT) + m->m_flags |= M_AMPDU; + (void)ieee80211_input(ni, m, rssi - nf, nf); + ieee80211_free_node(ni); + } else { + (void)ieee80211_input_all(ic, m, + rssi - nf, nf); + } + RTWN_LOCK(sc); + m = next; + } + break; + default: + /* needs it to the inactive queue due to a error. */ + data = STAILQ_FIRST(&uc->uc_rx_active); + if (data != NULL) { + STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next); + STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next); + } + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + counter_u64_add(ic->ic_ierrors, 1); + goto tr_setup; + } + break; + } +finish: + /* Finished receive; age anything left on the FF queue by a little bump */ + /* + * XXX TODO: just make this a callout timer schedule so we can + * flush the FF staging queue if we're approaching idle. + */ +#ifdef IEEE80211_SUPPORT_SUPERG + if (!(sc->sc_flags & RTWN_FW_LOADED) || + sc->sc_ratectl != RTWN_RATECTL_NET80211) + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); +#endif + + /* Kick-start more transmit in case we stalled */ + rtwn_start(sc); +} diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h new file mode 100644 index 00000000..e3708169 --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.h @@ -0,0 +1,24 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_USB_RX_H +#define RTWN_USB_RX_H + +void rtwn_bulk_rx_callback(struct usb_xfer *, usb_error_t); + +#endif /* RTWN_USB_RX_H */ diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c new file mode 100644 index 00000000..9ae41d28 --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c @@ -0,0 +1,284 @@ +#include + +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +static struct rtwn_data * _rtwn_usb_getbuf(struct rtwn_usb_softc *); +static struct rtwn_data * rtwn_usb_getbuf(struct rtwn_usb_softc *); +static void rtwn_usb_txeof(struct rtwn_usb_softc *, + struct rtwn_data *, int); + + +static const uint8_t wme2qid[] = + { RTWN_BULK_TX_BE, RTWN_BULK_TX_BK, + RTWN_BULK_TX_VI, RTWN_BULK_TX_VO }; + + +static struct rtwn_data * +_rtwn_usb_getbuf(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + struct rtwn_data *bf; + + bf = STAILQ_FIRST(&uc->uc_tx_inactive); + if (bf != NULL) + STAILQ_REMOVE_HEAD(&uc->uc_tx_inactive, next); + else { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: out of xmit buffers\n", __func__); + } + return (bf); +} + +static struct rtwn_data * +rtwn_usb_getbuf(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + struct rtwn_data *bf; + + RTWN_ASSERT_LOCKED(sc); + + bf = _rtwn_usb_getbuf(uc); + if (bf == NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: stop queue\n", + __func__); + } + return (bf); +} + +static void +rtwn_usb_txeof(struct rtwn_usb_softc *uc, struct rtwn_data *data, int status) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + RTWN_ASSERT_LOCKED(sc); + + if (data->ni != NULL) /* not a beacon frame */ + ieee80211_tx_complete(data->ni, data->m, status); + + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) + if (sc->sc_tx_n_active > 0) + sc->sc_tx_n_active--; + + data->ni = NULL; + data->m = NULL; + + STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, data, next); + sc->qfullmsk = 0; +#ifndef D4054 + if (STAILQ_EMPTY(&uc->uc_tx_active) && STAILQ_EMPTY(&uc->uc_tx_pending)) + sc->sc_tx_timer = 0; + else + sc->sc_tx_timer = 5; +#endif +} + +void +rtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer); + struct rtwn_softc *sc = &uc->uc_sc; + struct rtwn_data *data; + + RTWN_ASSERT_LOCKED(sc); + + switch (USB_GET_STATE(xfer)){ + case USB_ST_TRANSFERRED: + data = STAILQ_FIRST(&uc->uc_tx_active); + if (data == NULL) + goto tr_setup; + STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + rtwn_usb_txeof(uc, data, 0); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + data = STAILQ_FIRST(&uc->uc_tx_pending); + if (data == NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: empty pending queue\n", __func__); + sc->sc_tx_n_active = 0; + goto finish; + } + STAILQ_REMOVE_HEAD(&uc->uc_tx_pending, next); + STAILQ_INSERT_TAIL(&uc->uc_tx_active, data, next); + + /* + * Note: if this is a beacon frame, ensure that it will go + * into appropriate queue. + */ + if (data->ni == NULL && RTWN_CHIP_HAS_BCNQ1(sc)) + rtwn_switch_bcnq(sc, data->id); + usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); + usbd_transfer_submit(xfer); + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) + sc->sc_tx_n_active++; + break; + default: + data = STAILQ_FIRST(&uc->uc_tx_active); + if (data == NULL) + goto tr_setup; + STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + rtwn_usb_txeof(uc, data, 1); + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +finish: +#ifdef IEEE80211_SUPPORT_SUPERG + /* + * If the TX active queue drops below a certain + * threshold, ensure we age fast-frames out so they're + * transmitted. + */ + if (sc->sc_ratectl != RTWN_RATECTL_NET80211 && + sc->sc_tx_n_active <= 1) { + /* XXX ew - net80211 should defer this for us! */ + + /* + * Note: this sc_tx_n_active currently tracks + * the number of pending transmit submissions + * and not the actual depth of the TX frames + * pending to the hardware. That means that + * we're going to end up with some sub-optimal + * aggregation behaviour. + */ + /* + * XXX TODO: just make this a callout timer schedule so we can + * flush the FF staging queue if we're approaching idle. + */ + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); + } +#endif + /* Kick-start more transmit */ + rtwn_start(sc); +} + +static void +rtwn_usb_tx_checksum(struct rtwn_tx_desc_common *txd) +{ + txd->txdw7.usb_checksum = 0; + txd->txdw7.usb_checksum = rtwn_usb_calc_tx_checksum(txd); +} + +int +rtwn_usb_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + struct rtwn_tx_desc_common *txd; + struct rtwn_data *data; + struct usb_xfer *xfer; + uint16_t ac; + + RTWN_ASSERT_LOCKED(sc); + + data = rtwn_usb_getbuf(uc); + if (data == NULL) + return (ENOBUFS); + + ac = M_WME_GETAC(m); + + switch (type) { + case IEEE80211_FC0_TYPE_CTL: + case IEEE80211_FC0_TYPE_MGT: + xfer = uc->uc_xfer[RTWN_BULK_TX_VO]; + break; + default: + xfer = uc->uc_xfer[wme2qid[ac]]; + break; + } + + txd = (struct rtwn_tx_desc_common *)tx_desc; + txd->pktlen = htole16(m->m_pkthdr.len); + txd->offset = sc->txdesc_len; + txd->flags0 |= RTWN_FLAGS0_OWN; + rtwn_usb_tx_checksum(txd); + + /* Dump Tx descriptor. */ + rtwn_dump_tx_desc(sc, tx_desc); + + memcpy(data->buf, tx_desc, sc->txdesc_len); + m_copydata(m, 0, m->m_pkthdr.len, + (caddr_t)(data->buf + sc->txdesc_len)); + + data->buflen = m->m_pkthdr.len + sc->txdesc_len; + data->id = id; + data->ni = ni; + if (data->ni != NULL) { + data->m = m; +#ifndef D4054 + sc->sc_tx_timer = 5; +#endif + } + + STAILQ_INSERT_TAIL(&uc->uc_tx_pending, data, next); + if (STAILQ_EMPTY(&uc->uc_tx_inactive)) + sc->qfullmsk = 1; + + usbd_transfer_start(xfer); + + return (0); +} diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h new file mode 100644 index 00000000..01527080 --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.h @@ -0,0 +1,26 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_USB_TX_H +#define RTWN_USB_TX_H + +void rtwn_bulk_tx_callback(struct usb_xfer *, usb_error_t); +int rtwn_usb_tx_start(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, uint8_t *, uint8_t, int); + +#endif /* RTWN_USB_TX_H */ diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h new file mode 100644 index 00000000..be7f8f19 --- /dev/null +++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTWN_USBVAR_H +#define RTWN_USBVAR_H + +#define RTWN_IFACE_INDEX 0 + +#define RTWN_USB_RX_LIST_COUNT 1 +#define RTWN_USB_TX_LIST_COUNT 16 + +struct rtwn_data { + uint8_t *buf; + /* 'id' is meaningful for beacons only */ + int id; + uint16_t buflen; + struct mbuf *m; + struct ieee80211_node *ni; + STAILQ_ENTRY(rtwn_data) next; +}; +typedef STAILQ_HEAD(, rtwn_data) rtwn_datahead; + +enum { + RTWN_BULK_RX, + RTWN_BULK_TX_BE, /* = WME_AC_BE */ + RTWN_BULK_TX_BK, /* = WME_AC_BK */ + RTWN_BULK_TX_VI, /* = WME_AC_VI */ + RTWN_BULK_TX_VO, /* = WME_AC_VO */ + RTWN_N_TRANSFER = 5, +}; + +#define RTWN_EP_QUEUES RTWN_BULK_RX + +struct rtwn_usb_softc { + struct rtwn_softc uc_sc; /* must be the first */ + struct usb_device *uc_udev; + struct usb_xfer *uc_xfer[RTWN_N_TRANSFER]; + + struct rtwn_data uc_rx[RTWN_USB_RX_LIST_COUNT]; + rtwn_datahead uc_rx_active; + rtwn_datahead uc_rx_inactive; + struct rtwn_data uc_tx[RTWN_USB_TX_LIST_COUNT]; + rtwn_datahead uc_tx_active; + rtwn_datahead uc_tx_inactive; + rtwn_datahead uc_tx_pending; + + int (*uc_align_rx)(int, int); + + int ntx; + int tx_agg_desc_num; +}; +#define RTWN_USB_SOFTC(sc) ((struct rtwn_usb_softc *)(sc)) + +#define rtwn_usb_align_rx(_uc, _totlen, _len) \ + (((_uc)->uc_align_rx)((_totlen), (_len))) + +#endif /* RTWN_USBVAR_H */ diff --git a/libbsd.txt b/libbsd.txt index ed8bbe29..f6690815 100644 --- a/libbsd.txt +++ b/libbsd.txt @@ -778,8 +778,6 @@ detail and debug level information from the command. . *, trunk, 2017-01-09, 1f8e4a995a6ede4bdb24e6d335ccda2bdb0175ab. -== How to import code from FreeBSD - . In case you import files from a special FreeBSD version, then update the list above. . Run `git status` and make sure your working directory is clean. . Run `./freebsd-to-rtems.py -R`