17453645fSAndriy Voskoboinyk /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */
27453645fSAndriy Voskoboinyk
37453645fSAndriy Voskoboinyk /*-
47453645fSAndriy Voskoboinyk * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
57453645fSAndriy Voskoboinyk * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
67453645fSAndriy Voskoboinyk * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
77453645fSAndriy Voskoboinyk *
87453645fSAndriy Voskoboinyk * Permission to use, copy, modify, and distribute this software for any
97453645fSAndriy Voskoboinyk * purpose with or without fee is hereby granted, provided that the above
107453645fSAndriy Voskoboinyk * copyright notice and this permission notice appear in all copies.
117453645fSAndriy Voskoboinyk *
127453645fSAndriy Voskoboinyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
137453645fSAndriy Voskoboinyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
147453645fSAndriy Voskoboinyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
157453645fSAndriy Voskoboinyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
167453645fSAndriy Voskoboinyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
177453645fSAndriy Voskoboinyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
187453645fSAndriy Voskoboinyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
197453645fSAndriy Voskoboinyk */
207453645fSAndriy Voskoboinyk
217453645fSAndriy Voskoboinyk #include <sys/cdefs.h>
227453645fSAndriy Voskoboinyk #include "opt_wlan.h"
237453645fSAndriy Voskoboinyk
247453645fSAndriy Voskoboinyk #include <sys/param.h>
257453645fSAndriy Voskoboinyk #include <sys/lock.h>
267453645fSAndriy Voskoboinyk #include <sys/mutex.h>
277453645fSAndriy Voskoboinyk #include <sys/mbuf.h>
287453645fSAndriy Voskoboinyk #include <sys/kernel.h>
297453645fSAndriy Voskoboinyk #include <sys/socket.h>
307453645fSAndriy Voskoboinyk #include <sys/systm.h>
317453645fSAndriy Voskoboinyk #include <sys/malloc.h>
327453645fSAndriy Voskoboinyk #include <sys/queue.h>
337453645fSAndriy Voskoboinyk #include <sys/taskqueue.h>
347453645fSAndriy Voskoboinyk #include <sys/bus.h>
357453645fSAndriy Voskoboinyk #include <sys/endian.h>
367453645fSAndriy Voskoboinyk #include <sys/linker.h>
377453645fSAndriy Voskoboinyk
387453645fSAndriy Voskoboinyk #include <net/if.h>
397453645fSAndriy Voskoboinyk #include <net/ethernet.h>
407453645fSAndriy Voskoboinyk #include <net/if_media.h>
417453645fSAndriy Voskoboinyk
427453645fSAndriy Voskoboinyk #include <net80211/ieee80211_var.h>
437453645fSAndriy Voskoboinyk #include <net80211/ieee80211_radiotap.h>
447453645fSAndriy Voskoboinyk
457453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnreg.h>
467453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnvar.h>
477453645fSAndriy Voskoboinyk
487453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_debug.h>
497453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_ridx.h>
507453645fSAndriy Voskoboinyk
517453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8192c/r92c.h>
527453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8192c/r92c_priv.h>
537453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8192c/r92c_reg.h>
547453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8192c/r92c_var.h>
557453645fSAndriy Voskoboinyk
566858c6b1SAdrian Chadd void
r92c_dump_txpower(struct rtwn_softc * sc,int chain,uint8_t power[RTWN_RIDX_COUNT])576858c6b1SAdrian Chadd r92c_dump_txpower(struct rtwn_softc *sc, int chain,
586858c6b1SAdrian Chadd uint8_t power[RTWN_RIDX_COUNT])
596858c6b1SAdrian Chadd {
606858c6b1SAdrian Chadd
616858c6b1SAdrian Chadd #ifdef RTWN_DEBUG
626858c6b1SAdrian Chadd if (sc->sc_debug & RTWN_DEBUG_TXPWR) {
636858c6b1SAdrian Chadd int i;
646858c6b1SAdrian Chadd
656858c6b1SAdrian Chadd /* Print CCK */
666858c6b1SAdrian Chadd RTWN_DPRINTF(sc, RTWN_DEBUG_TXPWR,
676858c6b1SAdrian Chadd "TX [%d]: CCK: 1M: %d 2M: %d 5.5M: %d 11M: %d\n",
686858c6b1SAdrian Chadd chain,
696858c6b1SAdrian Chadd power[RTWN_RIDX_CCK1],
706858c6b1SAdrian Chadd power[RTWN_RIDX_CCK2],
716858c6b1SAdrian Chadd power[RTWN_RIDX_CCK55],
726858c6b1SAdrian Chadd power[RTWN_RIDX_CCK11]);
736858c6b1SAdrian Chadd /* Print OFDM */
746858c6b1SAdrian Chadd RTWN_DPRINTF(sc, RTWN_DEBUG_TXPWR,
756858c6b1SAdrian Chadd "TX [%d]: OFDM: 6M: %d 9M: %d 12M: %d 18M: %d 24M: %d "
766858c6b1SAdrian Chadd "36M: %d 48M: %d 54M: %d\n",
776858c6b1SAdrian Chadd chain,
786858c6b1SAdrian Chadd power[RTWN_RIDX_OFDM6],
796858c6b1SAdrian Chadd power[RTWN_RIDX_OFDM9],
806858c6b1SAdrian Chadd power[RTWN_RIDX_OFDM12],
816858c6b1SAdrian Chadd power[RTWN_RIDX_OFDM18],
826858c6b1SAdrian Chadd power[RTWN_RIDX_OFDM24],
836858c6b1SAdrian Chadd power[RTWN_RIDX_OFDM36],
846858c6b1SAdrian Chadd power[RTWN_RIDX_OFDM48],
856858c6b1SAdrian Chadd power[RTWN_RIDX_OFDM54]);
866858c6b1SAdrian Chadd /* Print HT, 1 and 2 stream */
876858c6b1SAdrian Chadd for (i = 0; i < sc->ntxchains; i++) {
886858c6b1SAdrian Chadd RTWN_DPRINTF(sc, RTWN_DEBUG_TXPWR,
896858c6b1SAdrian Chadd "TX [%d]: MCS%d-%d: %d %d %d %d %d %d %d %d\n",
906858c6b1SAdrian Chadd chain,
916858c6b1SAdrian Chadd i * 8,
926858c6b1SAdrian Chadd i * 8 + 7,
936858c6b1SAdrian Chadd power[RTWN_RIDX_HT_MCS(i * 8 + 0)],
946858c6b1SAdrian Chadd power[RTWN_RIDX_HT_MCS(i * 8 + 1)],
956858c6b1SAdrian Chadd power[RTWN_RIDX_HT_MCS(i * 8 + 2)],
966858c6b1SAdrian Chadd power[RTWN_RIDX_HT_MCS(i * 8 + 3)],
976858c6b1SAdrian Chadd power[RTWN_RIDX_HT_MCS(i * 8 + 4)],
986858c6b1SAdrian Chadd power[RTWN_RIDX_HT_MCS(i * 8 + 5)],
996858c6b1SAdrian Chadd power[RTWN_RIDX_HT_MCS(i * 8 + 6)],
1006858c6b1SAdrian Chadd power[RTWN_RIDX_HT_MCS(i * 8 + 7)]);
1016858c6b1SAdrian Chadd }
1026858c6b1SAdrian Chadd }
1036858c6b1SAdrian Chadd #endif
1046858c6b1SAdrian Chadd }
1056858c6b1SAdrian Chadd
1067453645fSAndriy Voskoboinyk static int
r92c_get_power_group(struct rtwn_softc * sc,struct ieee80211_channel * c)1077453645fSAndriy Voskoboinyk r92c_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c)
1087453645fSAndriy Voskoboinyk {
1097453645fSAndriy Voskoboinyk uint8_t chan;
1107453645fSAndriy Voskoboinyk int group;
1117453645fSAndriy Voskoboinyk
1127453645fSAndriy Voskoboinyk chan = rtwn_chan2centieee(c);
1137453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_2GHZ(c)) {
1147453645fSAndriy Voskoboinyk if (chan <= 3) group = 0;
1157453645fSAndriy Voskoboinyk else if (chan <= 9) group = 1;
1167453645fSAndriy Voskoboinyk else if (chan <= 14) group = 2;
1177453645fSAndriy Voskoboinyk else {
1187453645fSAndriy Voskoboinyk KASSERT(0, ("wrong 2GHz channel %d!\n", chan));
1197453645fSAndriy Voskoboinyk return (-1);
1207453645fSAndriy Voskoboinyk }
1217453645fSAndriy Voskoboinyk } else {
1227453645fSAndriy Voskoboinyk KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags));
1237453645fSAndriy Voskoboinyk return (-1);
1247453645fSAndriy Voskoboinyk }
1257453645fSAndriy Voskoboinyk
1267453645fSAndriy Voskoboinyk return (group);
1277453645fSAndriy Voskoboinyk }
1287453645fSAndriy Voskoboinyk
1297453645fSAndriy Voskoboinyk /* XXX recheck */
1307453645fSAndriy Voskoboinyk void
r92c_get_txpower(struct rtwn_softc * sc,int chain,struct ieee80211_channel * c,uint8_t power[RTWN_RIDX_COUNT])1317453645fSAndriy Voskoboinyk r92c_get_txpower(struct rtwn_softc *sc, int chain,
1325c7083ceSAndriy Voskoboinyk struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT])
1337453645fSAndriy Voskoboinyk {
134*0ea7f8caSAdrian Chadd const struct ieee80211com *ic = &sc->sc_ic;
1357453645fSAndriy Voskoboinyk struct r92c_softc *rs = sc->sc_priv;
1367453645fSAndriy Voskoboinyk struct rtwn_r92c_txpwr *rt = rs->rs_txpwr;
1377453645fSAndriy Voskoboinyk const struct rtwn_r92c_txagc *base = rs->rs_txagc;
1387453645fSAndriy Voskoboinyk uint8_t ofdmpow, htpow, diff, max;
1397453645fSAndriy Voskoboinyk int max_mcs, ridx, group;
1407453645fSAndriy Voskoboinyk
1417453645fSAndriy Voskoboinyk /* Determine channel group. */
1427453645fSAndriy Voskoboinyk group = r92c_get_power_group(sc, c);
1437453645fSAndriy Voskoboinyk if (group == -1) { /* shouldn't happen */
1447453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__);
1457453645fSAndriy Voskoboinyk return;
1467453645fSAndriy Voskoboinyk }
1477453645fSAndriy Voskoboinyk
148*0ea7f8caSAdrian Chadd /*
149*0ea7f8caSAdrian Chadd * Treat the entries in 1/2 dBm resolution where 0 = 0dBm.
150*0ea7f8caSAdrian Chadd * Apply the adjustments afterwards; assume that the vendor
151*0ea7f8caSAdrian Chadd * driver is applying offsets to make up for the actual
152*0ea7f8caSAdrian Chadd * target power in dBm.
153*0ea7f8caSAdrian Chadd */
1547453645fSAndriy Voskoboinyk
1550cc18edfSAndriy Voskoboinyk max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1);
1563d699261SAdrian Chadd KASSERT(max_mcs <= RTWN_RIDX_LEGACY_HT_COUNT, ("increase ridx limit\n"));
1577453645fSAndriy Voskoboinyk
1587453645fSAndriy Voskoboinyk if (rs->regulatory == 0) {
1597453645fSAndriy Voskoboinyk for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
1607453645fSAndriy Voskoboinyk power[ridx] = base[chain].pwr[0][ridx];
1617453645fSAndriy Voskoboinyk }
1623d699261SAdrian Chadd for (ridx = RTWN_RIDX_OFDM6; ridx < RTWN_RIDX_LEGACY_HT_COUNT; ridx++) {
1637453645fSAndriy Voskoboinyk if (rs->regulatory == 3) {
1647453645fSAndriy Voskoboinyk power[ridx] = base[chain].pwr[0][ridx];
1657453645fSAndriy Voskoboinyk /* Apply vendor limits. */
1667453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_HT40(c))
1677453645fSAndriy Voskoboinyk max = rt->ht40_max_pwr[chain][group];
1687453645fSAndriy Voskoboinyk else
1697453645fSAndriy Voskoboinyk max = rt->ht20_max_pwr[chain][group];
1707453645fSAndriy Voskoboinyk if (power[ridx] > max)
1717453645fSAndriy Voskoboinyk power[ridx] = max;
1727453645fSAndriy Voskoboinyk } else if (rs->regulatory == 1) {
1737453645fSAndriy Voskoboinyk if (!IEEE80211_IS_CHAN_HT40(c))
1747453645fSAndriy Voskoboinyk power[ridx] = base[chain].pwr[group][ridx];
1757453645fSAndriy Voskoboinyk } else if (rs->regulatory != 2)
1767453645fSAndriy Voskoboinyk power[ridx] = base[chain].pwr[0][ridx];
1777453645fSAndriy Voskoboinyk }
1787453645fSAndriy Voskoboinyk
1797453645fSAndriy Voskoboinyk /* Compute per-CCK rate Tx power. */
1807453645fSAndriy Voskoboinyk for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
1817453645fSAndriy Voskoboinyk power[ridx] += rt->cck_tx_pwr[chain][group];
1827453645fSAndriy Voskoboinyk
1837453645fSAndriy Voskoboinyk htpow = rt->ht40_1s_tx_pwr[chain][group];
1847453645fSAndriy Voskoboinyk if (sc->ntxchains > 1) {
1857453645fSAndriy Voskoboinyk /* Apply reduction for 2 spatial streams. */
1867453645fSAndriy Voskoboinyk diff = rt->ht40_2s_tx_pwr_diff[chain][group];
1877453645fSAndriy Voskoboinyk htpow = (htpow > diff) ? htpow - diff : 0;
1887453645fSAndriy Voskoboinyk }
1897453645fSAndriy Voskoboinyk
1907453645fSAndriy Voskoboinyk /* Compute per-OFDM rate Tx power. */
1917453645fSAndriy Voskoboinyk diff = rt->ofdm_tx_pwr_diff[chain][group];
1927453645fSAndriy Voskoboinyk ofdmpow = htpow + diff; /* HT->OFDM correction. */
1937453645fSAndriy Voskoboinyk for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++)
1947453645fSAndriy Voskoboinyk power[ridx] += ofdmpow;
1957453645fSAndriy Voskoboinyk
1967453645fSAndriy Voskoboinyk /* Compute per-MCS Tx power. */
1977453645fSAndriy Voskoboinyk if (!IEEE80211_IS_CHAN_HT40(c)) {
1987453645fSAndriy Voskoboinyk diff = rt->ht20_tx_pwr_diff[chain][group];
1997453645fSAndriy Voskoboinyk htpow += diff; /* HT40->HT20 correction. */
2007453645fSAndriy Voskoboinyk }
2010cc18edfSAndriy Voskoboinyk for (ridx = RTWN_RIDX_HT_MCS(0); ridx <= max_mcs; ridx++)
2027453645fSAndriy Voskoboinyk power[ridx] += htpow;
2037453645fSAndriy Voskoboinyk
2047453645fSAndriy Voskoboinyk /* Apply max limit. */
2057453645fSAndriy Voskoboinyk for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) {
2067453645fSAndriy Voskoboinyk if (power[ridx] > R92C_MAX_TX_PWR)
2077453645fSAndriy Voskoboinyk power[ridx] = R92C_MAX_TX_PWR;
208*0ea7f8caSAdrian Chadd /* Apply net80211 limits */
209*0ea7f8caSAdrian Chadd if (power[ridx] > ic->ic_txpowlimit)
210*0ea7f8caSAdrian Chadd power[ridx] = ic->ic_txpowlimit;
211*0ea7f8caSAdrian Chadd
2127453645fSAndriy Voskoboinyk }
2137453645fSAndriy Voskoboinyk }
2147453645fSAndriy Voskoboinyk
215ac1b5d81SAndriy Voskoboinyk void
r92c_write_txpower(struct rtwn_softc * sc,int chain,uint8_t power[RTWN_RIDX_COUNT])2167453645fSAndriy Voskoboinyk r92c_write_txpower(struct rtwn_softc *sc, int chain,
2175c7083ceSAndriy Voskoboinyk uint8_t power[RTWN_RIDX_COUNT])
2187453645fSAndriy Voskoboinyk {
2197453645fSAndriy Voskoboinyk uint32_t reg;
2207453645fSAndriy Voskoboinyk
2217453645fSAndriy Voskoboinyk /* Write per-CCK rate Tx power. */
2227453645fSAndriy Voskoboinyk if (chain == 0) {
2237453645fSAndriy Voskoboinyk reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32);
2247453645fSAndriy Voskoboinyk reg = RW(reg, R92C_TXAGC_A_CCK1, power[RTWN_RIDX_CCK1]);
2257453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg);
2267453645fSAndriy Voskoboinyk reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
2277453645fSAndriy Voskoboinyk reg = RW(reg, R92C_TXAGC_A_CCK2, power[RTWN_RIDX_CCK2]);
2287453645fSAndriy Voskoboinyk reg = RW(reg, R92C_TXAGC_A_CCK55, power[RTWN_RIDX_CCK55]);
2297453645fSAndriy Voskoboinyk reg = RW(reg, R92C_TXAGC_A_CCK11, power[RTWN_RIDX_CCK11]);
2307453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
2317453645fSAndriy Voskoboinyk } else {
2327453645fSAndriy Voskoboinyk reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32);
2337453645fSAndriy Voskoboinyk reg = RW(reg, R92C_TXAGC_B_CCK1, power[RTWN_RIDX_CCK1]);
2347453645fSAndriy Voskoboinyk reg = RW(reg, R92C_TXAGC_B_CCK2, power[RTWN_RIDX_CCK2]);
2357453645fSAndriy Voskoboinyk reg = RW(reg, R92C_TXAGC_B_CCK55, power[RTWN_RIDX_CCK55]);
2367453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg);
2377453645fSAndriy Voskoboinyk reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
2387453645fSAndriy Voskoboinyk reg = RW(reg, R92C_TXAGC_B_CCK11, power[RTWN_RIDX_CCK11]);
2397453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
2407453645fSAndriy Voskoboinyk }
2417453645fSAndriy Voskoboinyk /* Write per-OFDM rate Tx power. */
2427453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain),
2437453645fSAndriy Voskoboinyk SM(R92C_TXAGC_RATE06, power[RTWN_RIDX_OFDM6]) |
2447453645fSAndriy Voskoboinyk SM(R92C_TXAGC_RATE09, power[RTWN_RIDX_OFDM9]) |
2457453645fSAndriy Voskoboinyk SM(R92C_TXAGC_RATE12, power[RTWN_RIDX_OFDM12]) |
2467453645fSAndriy Voskoboinyk SM(R92C_TXAGC_RATE18, power[RTWN_RIDX_OFDM18]));
2477453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain),
2487453645fSAndriy Voskoboinyk SM(R92C_TXAGC_RATE24, power[RTWN_RIDX_OFDM24]) |
2497453645fSAndriy Voskoboinyk SM(R92C_TXAGC_RATE36, power[RTWN_RIDX_OFDM36]) |
2507453645fSAndriy Voskoboinyk SM(R92C_TXAGC_RATE48, power[RTWN_RIDX_OFDM48]) |
2517453645fSAndriy Voskoboinyk SM(R92C_TXAGC_RATE54, power[RTWN_RIDX_OFDM54]));
2527453645fSAndriy Voskoboinyk /* Write per-MCS Tx power. */
2537453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain),
2540cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS00, power[RTWN_RIDX_HT_MCS(0)]) |
2550cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS01, power[RTWN_RIDX_HT_MCS(1)]) |
2560cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS02, power[RTWN_RIDX_HT_MCS(2)]) |
2570cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS03, power[RTWN_RIDX_HT_MCS(3)]));
2587453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain),
2590cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS04, power[RTWN_RIDX_HT_MCS(4)]) |
2600cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS05, power[RTWN_RIDX_HT_MCS(5)]) |
2610cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS06, power[RTWN_RIDX_HT_MCS(6)]) |
2620cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS07, power[RTWN_RIDX_HT_MCS(7)]));
2637453645fSAndriy Voskoboinyk if (sc->ntxchains >= 2) {
2647453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain),
2650cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS08, power[RTWN_RIDX_HT_MCS(8)]) |
2660cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS09, power[RTWN_RIDX_HT_MCS(9)]) |
2670cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS10, power[RTWN_RIDX_HT_MCS(10)]) |
2680cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS11, power[RTWN_RIDX_HT_MCS(11)]));
2697453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain),
2700cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS12, power[RTWN_RIDX_HT_MCS(12)]) |
2710cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS13, power[RTWN_RIDX_HT_MCS(13)]) |
2720cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS14, power[RTWN_RIDX_HT_MCS(14)]) |
2730cc18edfSAndriy Voskoboinyk SM(R92C_TXAGC_MCS15, power[RTWN_RIDX_HT_MCS(15)]));
2747453645fSAndriy Voskoboinyk }
2757453645fSAndriy Voskoboinyk }
2767453645fSAndriy Voskoboinyk
2777453645fSAndriy Voskoboinyk static void
r92c_set_txpower(struct rtwn_softc * sc,struct ieee80211_channel * c)2787453645fSAndriy Voskoboinyk r92c_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c)
2797453645fSAndriy Voskoboinyk {
2805c7083ceSAndriy Voskoboinyk uint8_t power[RTWN_RIDX_COUNT];
2817453645fSAndriy Voskoboinyk int i;
2827453645fSAndriy Voskoboinyk
2837453645fSAndriy Voskoboinyk for (i = 0; i < sc->ntxchains; i++) {
2848f1ef22fSAndriy Voskoboinyk memset(power, 0, sizeof(power));
2857453645fSAndriy Voskoboinyk /* Compute per-rate Tx power values. */
2867453645fSAndriy Voskoboinyk rtwn_r92c_get_txpower(sc, i, c, power);
2876858c6b1SAdrian Chadd /* Optionally print out the power table */
2886858c6b1SAdrian Chadd r92c_dump_txpower(sc, i, power);
2897453645fSAndriy Voskoboinyk /* Write per-rate Tx power values to hardware. */
2907453645fSAndriy Voskoboinyk r92c_write_txpower(sc, i, power);
2917453645fSAndriy Voskoboinyk }
2927453645fSAndriy Voskoboinyk }
2937453645fSAndriy Voskoboinyk
294*0ea7f8caSAdrian Chadd /*
295*0ea7f8caSAdrian Chadd * Only reconfigure the transmit power if there's a valid BSS node and
296*0ea7f8caSAdrian Chadd * channel. Otherwise just let the next call to r92c_set_chan()
297*0ea7f8caSAdrian Chadd * configure the transmit power.
298*0ea7f8caSAdrian Chadd */
299*0ea7f8caSAdrian Chadd int
r92c_set_tx_power(struct rtwn_softc * sc,struct ieee80211vap * vap)300*0ea7f8caSAdrian Chadd r92c_set_tx_power(struct rtwn_softc *sc, struct ieee80211vap *vap)
301*0ea7f8caSAdrian Chadd {
302*0ea7f8caSAdrian Chadd if (vap->iv_bss == NULL)
303*0ea7f8caSAdrian Chadd return (EINVAL);
304*0ea7f8caSAdrian Chadd if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
305*0ea7f8caSAdrian Chadd return (EINVAL);
306*0ea7f8caSAdrian Chadd
307*0ea7f8caSAdrian Chadd /* Set it for the current channel */
308*0ea7f8caSAdrian Chadd r92c_set_txpower(sc, vap->iv_bss->ni_chan);
309*0ea7f8caSAdrian Chadd
310*0ea7f8caSAdrian Chadd return (0);
311*0ea7f8caSAdrian Chadd }
312*0ea7f8caSAdrian Chadd
3137453645fSAndriy Voskoboinyk static void
r92c_set_bw40(struct rtwn_softc * sc,uint8_t chan,int prichlo)3147453645fSAndriy Voskoboinyk r92c_set_bw40(struct rtwn_softc *sc, uint8_t chan, int prichlo)
3157453645fSAndriy Voskoboinyk {
3167453645fSAndriy Voskoboinyk struct r92c_softc *rs = sc->sc_priv;
3177453645fSAndriy Voskoboinyk
3187453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_BWOPMODE, R92C_BWOPMODE_20MHZ, 0);
3197453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_RRSR + 2, 0x6f, (prichlo ? 1 : 2) << 5);
3207453645fSAndriy Voskoboinyk
3217453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_40MHZ);
3227453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, 0, R92C_RFMOD_40MHZ);
3237453645fSAndriy Voskoboinyk
3247453645fSAndriy Voskoboinyk /* Set CCK side band. */
3257453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10,
3267453645fSAndriy Voskoboinyk (prichlo ? 0 : 1) << 4);
3277453645fSAndriy Voskoboinyk
3287453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_OFDM1_LSTF, 0x0c00,
3297453645fSAndriy Voskoboinyk (prichlo ? 1 : 2) << 10);
3307453645fSAndriy Voskoboinyk
3317453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2,
3327453645fSAndriy Voskoboinyk R92C_FPGA0_ANAPARAM2_CBW20, 0);
3337453645fSAndriy Voskoboinyk
33435e63136SAdrian Chadd rtwn_bb_setbits(sc, R92C_FPGA0_POWER_SAVE,
33535e63136SAdrian Chadd R92C_FPGA0_POWER_SAVE_PS_MASK, (prichlo ? 2 : 1) << 26);
3367453645fSAndriy Voskoboinyk
3377453645fSAndriy Voskoboinyk /* Select 40MHz bandwidth. */
3387453645fSAndriy Voskoboinyk rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
3397453645fSAndriy Voskoboinyk (rs->rf_chnlbw[0] & ~0xfff) | chan);
3407453645fSAndriy Voskoboinyk }
3417453645fSAndriy Voskoboinyk
3427453645fSAndriy Voskoboinyk void
r92c_set_bw20(struct rtwn_softc * sc,uint8_t chan)3437453645fSAndriy Voskoboinyk r92c_set_bw20(struct rtwn_softc *sc, uint8_t chan)
3447453645fSAndriy Voskoboinyk {
3457453645fSAndriy Voskoboinyk struct r92c_softc *rs = sc->sc_priv;
3467453645fSAndriy Voskoboinyk
3477453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R92C_BWOPMODE, 0, R92C_BWOPMODE_20MHZ);
3487453645fSAndriy Voskoboinyk
3497453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0);
3507453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0);
3517453645fSAndriy Voskoboinyk
3527453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2, 0,
3537453645fSAndriy Voskoboinyk R92C_FPGA0_ANAPARAM2_CBW20);
3547453645fSAndriy Voskoboinyk
3557453645fSAndriy Voskoboinyk /* Select 20MHz bandwidth. */
3567453645fSAndriy Voskoboinyk rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
3577453645fSAndriy Voskoboinyk (rs->rf_chnlbw[0] & ~0xfff) | chan | R92C_RF_CHNLBW_BW20);
3587453645fSAndriy Voskoboinyk }
3597453645fSAndriy Voskoboinyk
3607453645fSAndriy Voskoboinyk void
r92c_set_chan(struct rtwn_softc * sc,struct ieee80211_channel * c)3617453645fSAndriy Voskoboinyk r92c_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c)
3627453645fSAndriy Voskoboinyk {
3637453645fSAndriy Voskoboinyk struct r92c_softc *rs = sc->sc_priv;
3647453645fSAndriy Voskoboinyk u_int chan;
3657453645fSAndriy Voskoboinyk int i;
3667453645fSAndriy Voskoboinyk
3677453645fSAndriy Voskoboinyk chan = rtwn_chan2centieee(c);
3687453645fSAndriy Voskoboinyk
3697453645fSAndriy Voskoboinyk /* Set Tx power for this new channel. */
3707453645fSAndriy Voskoboinyk r92c_set_txpower(sc, c);
3717453645fSAndriy Voskoboinyk
3727453645fSAndriy Voskoboinyk for (i = 0; i < sc->nrxchains; i++) {
3737453645fSAndriy Voskoboinyk rtwn_rf_write(sc, i, R92C_RF_CHNLBW,
3747453645fSAndriy Voskoboinyk RW(rs->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan));
3757453645fSAndriy Voskoboinyk }
3767453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_HT40(c))
3777453645fSAndriy Voskoboinyk r92c_set_bw40(sc, chan, IEEE80211_IS_CHAN_HT40U(c));
3787453645fSAndriy Voskoboinyk else
3797453645fSAndriy Voskoboinyk rtwn_r92c_set_bw20(sc, chan);
3807453645fSAndriy Voskoboinyk }
3817453645fSAndriy Voskoboinyk
3827453645fSAndriy Voskoboinyk void
r92c_set_gain(struct rtwn_softc * sc,uint8_t gain)3837453645fSAndriy Voskoboinyk r92c_set_gain(struct rtwn_softc *sc, uint8_t gain)
3847453645fSAndriy Voskoboinyk {
3857453645fSAndriy Voskoboinyk
3867453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0),
3877453645fSAndriy Voskoboinyk R92C_OFDM0_AGCCORE1_GAIN_M, gain);
3887453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(1),
3897453645fSAndriy Voskoboinyk R92C_OFDM0_AGCCORE1_GAIN_M, gain);
3907453645fSAndriy Voskoboinyk }
3917453645fSAndriy Voskoboinyk
3927453645fSAndriy Voskoboinyk void
r92c_scan_start(struct ieee80211com * ic)3937453645fSAndriy Voskoboinyk r92c_scan_start(struct ieee80211com *ic)
3947453645fSAndriy Voskoboinyk {
3957453645fSAndriy Voskoboinyk struct rtwn_softc *sc = ic->ic_softc;
3967453645fSAndriy Voskoboinyk struct r92c_softc *rs = sc->sc_priv;
3977453645fSAndriy Voskoboinyk
3987453645fSAndriy Voskoboinyk RTWN_LOCK(sc);
3997453645fSAndriy Voskoboinyk /* Set gain for scanning. */
4007453645fSAndriy Voskoboinyk rtwn_r92c_set_gain(sc, 0x20);
4017453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc);
4027453645fSAndriy Voskoboinyk
4037453645fSAndriy Voskoboinyk rs->rs_scan_start(ic);
4047453645fSAndriy Voskoboinyk }
4057453645fSAndriy Voskoboinyk
4067453645fSAndriy Voskoboinyk void
r92c_scan_end(struct ieee80211com * ic)4077453645fSAndriy Voskoboinyk r92c_scan_end(struct ieee80211com *ic)
4087453645fSAndriy Voskoboinyk {
4097453645fSAndriy Voskoboinyk struct rtwn_softc *sc = ic->ic_softc;
4107453645fSAndriy Voskoboinyk struct r92c_softc *rs = sc->sc_priv;
4117453645fSAndriy Voskoboinyk
4127453645fSAndriy Voskoboinyk RTWN_LOCK(sc);
4137453645fSAndriy Voskoboinyk /* Set gain under link. */
4147453645fSAndriy Voskoboinyk rtwn_r92c_set_gain(sc, 0x32);
4157453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc);
4167453645fSAndriy Voskoboinyk
4177453645fSAndriy Voskoboinyk rs->rs_scan_end(ic);
4187453645fSAndriy Voskoboinyk }
419