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 #include "opt_wlan.h"
297453645fSAndriy Voskoboinyk
307453645fSAndriy Voskoboinyk #include <sys/param.h>
317453645fSAndriy Voskoboinyk #include <sys/lock.h>
327453645fSAndriy Voskoboinyk #include <sys/mutex.h>
337453645fSAndriy Voskoboinyk #include <sys/mbuf.h>
347453645fSAndriy Voskoboinyk #include <sys/kernel.h>
357453645fSAndriy Voskoboinyk #include <sys/socket.h>
367453645fSAndriy Voskoboinyk #include <sys/systm.h>
377453645fSAndriy Voskoboinyk #include <sys/malloc.h>
387453645fSAndriy Voskoboinyk #include <sys/queue.h>
397453645fSAndriy Voskoboinyk #include <sys/taskqueue.h>
407453645fSAndriy Voskoboinyk #include <sys/bus.h>
417453645fSAndriy Voskoboinyk #include <sys/endian.h>
427453645fSAndriy Voskoboinyk #include <sys/linker.h>
437453645fSAndriy Voskoboinyk
447453645fSAndriy Voskoboinyk #include <net/if.h>
457453645fSAndriy Voskoboinyk #include <net/ethernet.h>
467453645fSAndriy Voskoboinyk #include <net/if_media.h>
477453645fSAndriy Voskoboinyk
487453645fSAndriy Voskoboinyk #include <net80211/ieee80211_var.h>
497453645fSAndriy Voskoboinyk #include <net80211/ieee80211_radiotap.h>
507453645fSAndriy Voskoboinyk
517453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnreg.h>
527453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnvar.h>
537453645fSAndriy Voskoboinyk
547453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_debug.h>
557453645fSAndriy Voskoboinyk
567453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8188e/r88e.h>
577453645fSAndriy Voskoboinyk
587453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8812a/r12a.h>
597453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8812a/r12a_reg.h>
607453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8812a/r12a_var.h>
617453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8812a/r12a_fw_cmd.h>
627453645fSAndriy Voskoboinyk
637453645fSAndriy Voskoboinyk #ifndef RTWN_WITHOUT_UCODE
647453645fSAndriy Voskoboinyk void
r12a_fw_reset(struct rtwn_softc * sc,int reason)657453645fSAndriy Voskoboinyk r12a_fw_reset(struct rtwn_softc *sc, int reason)
667453645fSAndriy Voskoboinyk {
677453645fSAndriy Voskoboinyk /* Reset MCU IO wrapper. */
6860b9567dSKevin Lo rtwn_setbits_1(sc, R92C_RSV_CTRL, R92C_RSV_CTRL_WLOCK_00, 0);
697453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0x08, 0);
707453645fSAndriy Voskoboinyk
717453645fSAndriy Voskoboinyk rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
727453645fSAndriy Voskoboinyk R92C_SYS_FUNC_EN_CPUEN, 0, 1);
737453645fSAndriy Voskoboinyk
747453645fSAndriy Voskoboinyk /* Enable MCU IO wrapper. */
7560b9567dSKevin Lo rtwn_setbits_1(sc, R92C_RSV_CTRL, R92C_RSV_CTRL_WLOCK_00, 0);
767453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0, 0x08);
777453645fSAndriy Voskoboinyk
787453645fSAndriy Voskoboinyk rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
797453645fSAndriy Voskoboinyk 0, R92C_SYS_FUNC_EN_CPUEN, 1);
807453645fSAndriy Voskoboinyk }
817453645fSAndriy Voskoboinyk
827453645fSAndriy Voskoboinyk void
r12a_fw_download_enable(struct rtwn_softc * sc,int enable)837453645fSAndriy Voskoboinyk r12a_fw_download_enable(struct rtwn_softc *sc, int enable)
847453645fSAndriy Voskoboinyk {
857453645fSAndriy Voskoboinyk if (enable) {
867453645fSAndriy Voskoboinyk /* MCU firmware download enable. */
877453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN);
887453645fSAndriy Voskoboinyk /* 8051 reset. */
897453645fSAndriy Voskoboinyk rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN,
907453645fSAndriy Voskoboinyk 0, 2);
917453645fSAndriy Voskoboinyk } else {
927453645fSAndriy Voskoboinyk /* MCU download disable. */
937453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0);
947453645fSAndriy Voskoboinyk }
957453645fSAndriy Voskoboinyk }
967453645fSAndriy Voskoboinyk
977453645fSAndriy Voskoboinyk void
r12a_set_media_status(struct rtwn_softc * sc,int macid)987453645fSAndriy Voskoboinyk r12a_set_media_status(struct rtwn_softc *sc, int macid)
997453645fSAndriy Voskoboinyk {
1007453645fSAndriy Voskoboinyk struct r12a_fw_cmd_msrrpt status;
1017453645fSAndriy Voskoboinyk int error;
1027453645fSAndriy Voskoboinyk
1037453645fSAndriy Voskoboinyk if (macid & RTWN_MACID_VALID)
1047453645fSAndriy Voskoboinyk status.msrb0 = R12A_MSRRPT_B0_ASSOC;
1057453645fSAndriy Voskoboinyk else
1067453645fSAndriy Voskoboinyk status.msrb0 = R12A_MSRRPT_B0_DISASSOC;
1077453645fSAndriy Voskoboinyk
1087453645fSAndriy Voskoboinyk status.macid = (macid & ~RTWN_MACID_VALID);
1097453645fSAndriy Voskoboinyk status.macid_end = 0;
1107453645fSAndriy Voskoboinyk
1117453645fSAndriy Voskoboinyk error = r88e_fw_cmd(sc, R12A_CMD_MSR_RPT, &status, sizeof(status));
1127453645fSAndriy Voskoboinyk if (error != 0)
1137453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, "cannot change media status!\n");
1147453645fSAndriy Voskoboinyk }
1157453645fSAndriy Voskoboinyk
1167453645fSAndriy Voskoboinyk int
r12a_set_pwrmode(struct rtwn_softc * sc,struct ieee80211vap * vap,int off)1177453645fSAndriy Voskoboinyk r12a_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap,
1187453645fSAndriy Voskoboinyk int off)
1197453645fSAndriy Voskoboinyk {
1207453645fSAndriy Voskoboinyk struct r12a_fw_cmd_pwrmode mode;
1217453645fSAndriy Voskoboinyk int error;
1227453645fSAndriy Voskoboinyk
1237453645fSAndriy Voskoboinyk if (off && vap->iv_state == IEEE80211_S_RUN &&
1247453645fSAndriy Voskoboinyk (vap->iv_flags & IEEE80211_F_PMGTON)) {
1257453645fSAndriy Voskoboinyk mode.mode = R88E_PWRMODE_LEG;
1267453645fSAndriy Voskoboinyk /*
1277453645fSAndriy Voskoboinyk * TODO: switch to RFOFF state
1287453645fSAndriy Voskoboinyk * (something is missing here - Rx stops with it).
1297453645fSAndriy Voskoboinyk */
1307453645fSAndriy Voskoboinyk #ifdef RTWN_TODO
1317453645fSAndriy Voskoboinyk mode.pwr_state = R88E_PWRMODE_STATE_RFOFF;
1327453645fSAndriy Voskoboinyk #else
1337453645fSAndriy Voskoboinyk mode.pwr_state = R88E_PWRMODE_STATE_RFON;
1347453645fSAndriy Voskoboinyk #endif
1357453645fSAndriy Voskoboinyk } else {
1367453645fSAndriy Voskoboinyk mode.mode = R88E_PWRMODE_CAM;
1377453645fSAndriy Voskoboinyk mode.pwr_state = R88E_PWRMODE_STATE_ALLON;
1387453645fSAndriy Voskoboinyk }
1397453645fSAndriy Voskoboinyk mode.pwrb1 =
1407453645fSAndriy Voskoboinyk SM(R88E_PWRMODE_B1_SMART_PS, R88E_PWRMODE_B1_LEG_NULLDATA) |
1417453645fSAndriy Voskoboinyk SM(R88E_PWRMODE_B1_RLBM, R88E_PWRMODE_B1_MODE_MIN);
1427453645fSAndriy Voskoboinyk /* XXX ignored */
1437453645fSAndriy Voskoboinyk mode.bcn_pass = 0;
1447453645fSAndriy Voskoboinyk mode.queue_uapsd = 0;
1457453645fSAndriy Voskoboinyk mode.pwrb5 = R12A_PWRMODE_B5_NO_BTCOEX;
1467453645fSAndriy Voskoboinyk error = r88e_fw_cmd(sc, R12A_CMD_SET_PWRMODE, &mode, sizeof(mode));
1477453645fSAndriy Voskoboinyk if (error != 0) {
1487453645fSAndriy Voskoboinyk device_printf(sc->sc_dev,
1497453645fSAndriy Voskoboinyk "%s: CMD_SET_PWRMODE was not sent, error %d\n",
1507453645fSAndriy Voskoboinyk __func__, error);
1517453645fSAndriy Voskoboinyk }
1527453645fSAndriy Voskoboinyk
1537453645fSAndriy Voskoboinyk return (error);
1547453645fSAndriy Voskoboinyk }
1557453645fSAndriy Voskoboinyk
1567453645fSAndriy Voskoboinyk void
r12a_iq_calib_fw(struct rtwn_softc * sc)1577453645fSAndriy Voskoboinyk r12a_iq_calib_fw(struct rtwn_softc *sc)
1587453645fSAndriy Voskoboinyk {
1597453645fSAndriy Voskoboinyk struct r12a_softc *rs = sc->sc_priv;
1607453645fSAndriy Voskoboinyk struct ieee80211_channel *c = sc->sc_ic.ic_curchan;
1617453645fSAndriy Voskoboinyk struct r12a_fw_cmd_iq_calib cmd;
1627453645fSAndriy Voskoboinyk
1637453645fSAndriy Voskoboinyk if (rs->rs_flags & R12A_IQK_RUNNING)
1647453645fSAndriy Voskoboinyk return;
1657453645fSAndriy Voskoboinyk
1667453645fSAndriy Voskoboinyk RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "Starting IQ calibration (FW)\n");
1677453645fSAndriy Voskoboinyk
1687453645fSAndriy Voskoboinyk cmd.chan = rtwn_chan2centieee(c);
1697453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_5GHZ(c))
1707453645fSAndriy Voskoboinyk cmd.band_bw = RTWN_CMD_IQ_BAND_5GHZ;
1717453645fSAndriy Voskoboinyk else
1727453645fSAndriy Voskoboinyk cmd.band_bw = RTWN_CMD_IQ_BAND_2GHZ;
1737453645fSAndriy Voskoboinyk
174*4fa68495SAdrian Chadd /* TODO: 160MHz */
175*4fa68495SAdrian Chadd if (IEEE80211_IS_CHAN_VHT80(c))
176*4fa68495SAdrian Chadd cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_80;
177*4fa68495SAdrian Chadd else if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_VHT40(c))
1787453645fSAndriy Voskoboinyk cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_40;
1797453645fSAndriy Voskoboinyk else
1807453645fSAndriy Voskoboinyk cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_20;
1817453645fSAndriy Voskoboinyk
1827453645fSAndriy Voskoboinyk cmd.ext_5g_pa_lna = RTWN_CMD_IQ_EXT_PA_5G(rs->ext_pa_5g);
1837453645fSAndriy Voskoboinyk cmd.ext_5g_pa_lna |= RTWN_CMD_IQ_EXT_LNA_5G(rs->ext_lna_5g);
1847453645fSAndriy Voskoboinyk
1857453645fSAndriy Voskoboinyk if (r88e_fw_cmd(sc, R12A_CMD_IQ_CALIBRATE, &cmd, sizeof(cmd)) != 0) {
1867453645fSAndriy Voskoboinyk RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
1877453645fSAndriy Voskoboinyk "error while sending IQ calibration command to FW!\n");
1887453645fSAndriy Voskoboinyk return;
1897453645fSAndriy Voskoboinyk }
1907453645fSAndriy Voskoboinyk
1917453645fSAndriy Voskoboinyk rs->rs_flags |= R12A_IQK_RUNNING;
1927453645fSAndriy Voskoboinyk }
1937453645fSAndriy Voskoboinyk #endif
194