17453645fSAndriy Voskoboinyk /*- 27453645fSAndriy Voskoboinyk * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org> 37453645fSAndriy Voskoboinyk * All rights reserved. 47453645fSAndriy Voskoboinyk * 57453645fSAndriy Voskoboinyk * Redistribution and use in source and binary forms, with or without 67453645fSAndriy Voskoboinyk * modification, are permitted provided that the following conditions 77453645fSAndriy Voskoboinyk * are met: 87453645fSAndriy Voskoboinyk * 1. Redistributions of source code must retain the above copyright 97453645fSAndriy Voskoboinyk * notice, this list of conditions and the following disclaimer. 107453645fSAndriy Voskoboinyk * 2. Redistributions in binary form must reproduce the above copyright 117453645fSAndriy Voskoboinyk * notice, this list of conditions and the following disclaimer in the 127453645fSAndriy Voskoboinyk * documentation and/or other materials provided with the distribution. 137453645fSAndriy Voskoboinyk * 147453645fSAndriy Voskoboinyk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 157453645fSAndriy Voskoboinyk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 167453645fSAndriy Voskoboinyk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 177453645fSAndriy Voskoboinyk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 187453645fSAndriy Voskoboinyk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 197453645fSAndriy Voskoboinyk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 207453645fSAndriy Voskoboinyk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 217453645fSAndriy Voskoboinyk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 227453645fSAndriy Voskoboinyk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 237453645fSAndriy Voskoboinyk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 247453645fSAndriy Voskoboinyk * SUCH DAMAGE. 257453645fSAndriy Voskoboinyk */ 267453645fSAndriy Voskoboinyk 277453645fSAndriy Voskoboinyk #include <sys/cdefs.h> 287453645fSAndriy Voskoboinyk __FBSDID("$FreeBSD$"); 297453645fSAndriy Voskoboinyk 307453645fSAndriy Voskoboinyk #include "opt_wlan.h" 317453645fSAndriy Voskoboinyk 327453645fSAndriy Voskoboinyk #include <sys/param.h> 337453645fSAndriy Voskoboinyk #include <sys/lock.h> 347453645fSAndriy Voskoboinyk #include <sys/mutex.h> 357453645fSAndriy Voskoboinyk #include <sys/mbuf.h> 367453645fSAndriy Voskoboinyk #include <sys/kernel.h> 377453645fSAndriy Voskoboinyk #include <sys/socket.h> 387453645fSAndriy Voskoboinyk #include <sys/systm.h> 397453645fSAndriy Voskoboinyk #include <sys/malloc.h> 407453645fSAndriy Voskoboinyk #include <sys/queue.h> 417453645fSAndriy Voskoboinyk #include <sys/taskqueue.h> 427453645fSAndriy Voskoboinyk #include <sys/bus.h> 437453645fSAndriy Voskoboinyk #include <sys/endian.h> 447453645fSAndriy Voskoboinyk #include <sys/linker.h> 457453645fSAndriy Voskoboinyk 467453645fSAndriy Voskoboinyk #include <net/if.h> 477453645fSAndriy Voskoboinyk #include <net/ethernet.h> 487453645fSAndriy Voskoboinyk #include <net/if_media.h> 497453645fSAndriy Voskoboinyk 507453645fSAndriy Voskoboinyk #include <net80211/ieee80211_var.h> 517453645fSAndriy Voskoboinyk #include <net80211/ieee80211_radiotap.h> 527453645fSAndriy Voskoboinyk 537453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnreg.h> 547453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnvar.h> 557453645fSAndriy Voskoboinyk 567453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_debug.h> 577453645fSAndriy Voskoboinyk 587453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8188e/r88e.h> 597453645fSAndriy Voskoboinyk 607453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8812a/r12a.h> 617453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8812a/r12a_reg.h> 627453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8812a/r12a_var.h> 637453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8812a/r12a_fw_cmd.h> 647453645fSAndriy Voskoboinyk 657453645fSAndriy Voskoboinyk 667453645fSAndriy Voskoboinyk #ifndef RTWN_WITHOUT_UCODE 677453645fSAndriy Voskoboinyk void 687453645fSAndriy Voskoboinyk r12a_fw_reset(struct rtwn_softc *sc, int reason) 697453645fSAndriy Voskoboinyk { 707453645fSAndriy Voskoboinyk /* Reset MCU IO wrapper. */ 71*60b9567dSKevin Lo rtwn_setbits_1(sc, R92C_RSV_CTRL, R92C_RSV_CTRL_WLOCK_00, 0); 727453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0x08, 0); 737453645fSAndriy Voskoboinyk 747453645fSAndriy Voskoboinyk rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, 757453645fSAndriy Voskoboinyk R92C_SYS_FUNC_EN_CPUEN, 0, 1); 767453645fSAndriy Voskoboinyk 777453645fSAndriy Voskoboinyk /* Enable MCU IO wrapper. */ 78*60b9567dSKevin Lo rtwn_setbits_1(sc, R92C_RSV_CTRL, R92C_RSV_CTRL_WLOCK_00, 0); 797453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0, 0x08); 807453645fSAndriy Voskoboinyk 817453645fSAndriy Voskoboinyk rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, 827453645fSAndriy Voskoboinyk 0, R92C_SYS_FUNC_EN_CPUEN, 1); 837453645fSAndriy Voskoboinyk } 847453645fSAndriy Voskoboinyk 857453645fSAndriy Voskoboinyk void 867453645fSAndriy Voskoboinyk r12a_fw_download_enable(struct rtwn_softc *sc, int enable) 877453645fSAndriy Voskoboinyk { 887453645fSAndriy Voskoboinyk if (enable) { 897453645fSAndriy Voskoboinyk /* MCU firmware download enable. */ 907453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN); 917453645fSAndriy Voskoboinyk /* 8051 reset. */ 927453645fSAndriy Voskoboinyk rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN, 937453645fSAndriy Voskoboinyk 0, 2); 947453645fSAndriy Voskoboinyk } else { 957453645fSAndriy Voskoboinyk /* MCU download disable. */ 967453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0); 977453645fSAndriy Voskoboinyk } 987453645fSAndriy Voskoboinyk } 997453645fSAndriy Voskoboinyk 1007453645fSAndriy Voskoboinyk void 1017453645fSAndriy Voskoboinyk r12a_set_media_status(struct rtwn_softc *sc, int macid) 1027453645fSAndriy Voskoboinyk { 1037453645fSAndriy Voskoboinyk struct r12a_fw_cmd_msrrpt status; 1047453645fSAndriy Voskoboinyk int error; 1057453645fSAndriy Voskoboinyk 1067453645fSAndriy Voskoboinyk if (macid & RTWN_MACID_VALID) 1077453645fSAndriy Voskoboinyk status.msrb0 = R12A_MSRRPT_B0_ASSOC; 1087453645fSAndriy Voskoboinyk else 1097453645fSAndriy Voskoboinyk status.msrb0 = R12A_MSRRPT_B0_DISASSOC; 1107453645fSAndriy Voskoboinyk 1117453645fSAndriy Voskoboinyk status.macid = (macid & ~RTWN_MACID_VALID); 1127453645fSAndriy Voskoboinyk status.macid_end = 0; 1137453645fSAndriy Voskoboinyk 1147453645fSAndriy Voskoboinyk error = r88e_fw_cmd(sc, R12A_CMD_MSR_RPT, &status, sizeof(status)); 1157453645fSAndriy Voskoboinyk if (error != 0) 1167453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, "cannot change media status!\n"); 1177453645fSAndriy Voskoboinyk } 1187453645fSAndriy Voskoboinyk 1197453645fSAndriy Voskoboinyk int 1207453645fSAndriy Voskoboinyk r12a_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap, 1217453645fSAndriy Voskoboinyk int off) 1227453645fSAndriy Voskoboinyk { 1237453645fSAndriy Voskoboinyk struct r12a_fw_cmd_pwrmode mode; 1247453645fSAndriy Voskoboinyk int error; 1257453645fSAndriy Voskoboinyk 1267453645fSAndriy Voskoboinyk if (off && vap->iv_state == IEEE80211_S_RUN && 1277453645fSAndriy Voskoboinyk (vap->iv_flags & IEEE80211_F_PMGTON)) { 1287453645fSAndriy Voskoboinyk mode.mode = R88E_PWRMODE_LEG; 1297453645fSAndriy Voskoboinyk /* 1307453645fSAndriy Voskoboinyk * TODO: switch to RFOFF state 1317453645fSAndriy Voskoboinyk * (something is missing here - Rx stops with it). 1327453645fSAndriy Voskoboinyk */ 1337453645fSAndriy Voskoboinyk #ifdef RTWN_TODO 1347453645fSAndriy Voskoboinyk mode.pwr_state = R88E_PWRMODE_STATE_RFOFF; 1357453645fSAndriy Voskoboinyk #else 1367453645fSAndriy Voskoboinyk mode.pwr_state = R88E_PWRMODE_STATE_RFON; 1377453645fSAndriy Voskoboinyk #endif 1387453645fSAndriy Voskoboinyk } else { 1397453645fSAndriy Voskoboinyk mode.mode = R88E_PWRMODE_CAM; 1407453645fSAndriy Voskoboinyk mode.pwr_state = R88E_PWRMODE_STATE_ALLON; 1417453645fSAndriy Voskoboinyk } 1427453645fSAndriy Voskoboinyk mode.pwrb1 = 1437453645fSAndriy Voskoboinyk SM(R88E_PWRMODE_B1_SMART_PS, R88E_PWRMODE_B1_LEG_NULLDATA) | 1447453645fSAndriy Voskoboinyk SM(R88E_PWRMODE_B1_RLBM, R88E_PWRMODE_B1_MODE_MIN); 1457453645fSAndriy Voskoboinyk /* XXX ignored */ 1467453645fSAndriy Voskoboinyk mode.bcn_pass = 0; 1477453645fSAndriy Voskoboinyk mode.queue_uapsd = 0; 1487453645fSAndriy Voskoboinyk mode.pwrb5 = R12A_PWRMODE_B5_NO_BTCOEX; 1497453645fSAndriy Voskoboinyk error = r88e_fw_cmd(sc, R12A_CMD_SET_PWRMODE, &mode, sizeof(mode)); 1507453645fSAndriy Voskoboinyk if (error != 0) { 1517453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, 1527453645fSAndriy Voskoboinyk "%s: CMD_SET_PWRMODE was not sent, error %d\n", 1537453645fSAndriy Voskoboinyk __func__, error); 1547453645fSAndriy Voskoboinyk } 1557453645fSAndriy Voskoboinyk 1567453645fSAndriy Voskoboinyk return (error); 1577453645fSAndriy Voskoboinyk } 1587453645fSAndriy Voskoboinyk 1597453645fSAndriy Voskoboinyk void 1607453645fSAndriy Voskoboinyk r12a_iq_calib_fw(struct rtwn_softc *sc) 1617453645fSAndriy Voskoboinyk { 1627453645fSAndriy Voskoboinyk struct r12a_softc *rs = sc->sc_priv; 1637453645fSAndriy Voskoboinyk struct ieee80211_channel *c = sc->sc_ic.ic_curchan; 1647453645fSAndriy Voskoboinyk struct r12a_fw_cmd_iq_calib cmd; 1657453645fSAndriy Voskoboinyk 1667453645fSAndriy Voskoboinyk if (rs->rs_flags & R12A_IQK_RUNNING) 1677453645fSAndriy Voskoboinyk return; 1687453645fSAndriy Voskoboinyk 1697453645fSAndriy Voskoboinyk RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "Starting IQ calibration (FW)\n"); 1707453645fSAndriy Voskoboinyk 1717453645fSAndriy Voskoboinyk cmd.chan = rtwn_chan2centieee(c); 1727453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_5GHZ(c)) 1737453645fSAndriy Voskoboinyk cmd.band_bw = RTWN_CMD_IQ_BAND_5GHZ; 1747453645fSAndriy Voskoboinyk else 1757453645fSAndriy Voskoboinyk cmd.band_bw = RTWN_CMD_IQ_BAND_2GHZ; 1767453645fSAndriy Voskoboinyk 1777453645fSAndriy Voskoboinyk /* TODO: 80/160 MHz. */ 1787453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_HT40(c)) 1797453645fSAndriy Voskoboinyk cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_40; 1807453645fSAndriy Voskoboinyk else 1817453645fSAndriy Voskoboinyk cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_20; 1827453645fSAndriy Voskoboinyk 1837453645fSAndriy Voskoboinyk cmd.ext_5g_pa_lna = RTWN_CMD_IQ_EXT_PA_5G(rs->ext_pa_5g); 1847453645fSAndriy Voskoboinyk cmd.ext_5g_pa_lna |= RTWN_CMD_IQ_EXT_LNA_5G(rs->ext_lna_5g); 1857453645fSAndriy Voskoboinyk 1867453645fSAndriy Voskoboinyk if (r88e_fw_cmd(sc, R12A_CMD_IQ_CALIBRATE, &cmd, sizeof(cmd)) != 0) { 1877453645fSAndriy Voskoboinyk RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, 1887453645fSAndriy Voskoboinyk "error while sending IQ calibration command to FW!\n"); 1897453645fSAndriy Voskoboinyk return; 1907453645fSAndriy Voskoboinyk } 1917453645fSAndriy Voskoboinyk 1927453645fSAndriy Voskoboinyk rs->rs_flags |= R12A_IQK_RUNNING; 1937453645fSAndriy Voskoboinyk } 1947453645fSAndriy Voskoboinyk #endif 195