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 #include <dev/rtwn/if_rtwn_ridx.h> 567453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_rx.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 627453645fSAndriy Voskoboinyk static void 63468cd606SAdrian Chadd r12a_write_txpower_ht(struct rtwn_softc *sc, int chain, 640351824fSKevin Lo struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) 657453645fSAndriy Voskoboinyk { 667453645fSAndriy Voskoboinyk 677453645fSAndriy Voskoboinyk /* Write per-MCS Tx power. */ 687453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_TXAGC_MCS3_0(chain), 690cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS0, power[RTWN_RIDX_HT_MCS(0)]) | 700cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS1, power[RTWN_RIDX_HT_MCS(1)]) | 710cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS2, power[RTWN_RIDX_HT_MCS(2)]) | 720cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS3, power[RTWN_RIDX_HT_MCS(3)])); 737453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_TXAGC_MCS7_4(chain), 740cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS4, power[RTWN_RIDX_HT_MCS(4)]) | 750cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS5, power[RTWN_RIDX_HT_MCS(5)]) | 760cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS6, power[RTWN_RIDX_HT_MCS(6)]) | 770cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS7, power[RTWN_RIDX_HT_MCS(7)])); 787453645fSAndriy Voskoboinyk if (sc->ntxchains >= 2) { 797453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_TXAGC_MCS11_8(chain), 800cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS8, power[RTWN_RIDX_HT_MCS(8)]) | 810cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS9, power[RTWN_RIDX_HT_MCS(9)]) | 820cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS10, power[RTWN_RIDX_HT_MCS(10)]) | 830cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS11, power[RTWN_RIDX_HT_MCS(11)])); 847453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_TXAGC_MCS15_12(chain), 850cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS12, power[RTWN_RIDX_HT_MCS(12)]) | 860cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS13, power[RTWN_RIDX_HT_MCS(13)]) | 870cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS14, power[RTWN_RIDX_HT_MCS(14)]) | 880cc18edfSAndriy Voskoboinyk SM(R12A_TXAGC_MCS15, power[RTWN_RIDX_HT_MCS(15)])); 897453645fSAndriy Voskoboinyk } 907453645fSAndriy Voskoboinyk 91468cd606SAdrian Chadd /* TODO: HT MCS 16 -> 31 */ 92468cd606SAdrian Chadd } 93468cd606SAdrian Chadd 94468cd606SAdrian Chadd static void 95b811e5a5SAdrian Chadd r12a_write_txpower_vht(struct rtwn_softc *sc, int chain, 96b811e5a5SAdrian Chadd struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) 97b811e5a5SAdrian Chadd { 98b811e5a5SAdrian Chadd 99b811e5a5SAdrian Chadd /* 1SS, MCS 0..3 */ 100b811e5a5SAdrian Chadd rtwn_bb_write(sc, R12A_TXAGC_NSS1IX3_1IX0(chain), 101b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS0, power[RTWN_RIDX_VHT_MCS(0, 0)]) | 102b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS1, power[RTWN_RIDX_VHT_MCS(0, 1)]) | 103b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS2, power[RTWN_RIDX_VHT_MCS(0, 2)]) | 104b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS3, power[RTWN_RIDX_VHT_MCS(0, 3)])); 105b811e5a5SAdrian Chadd 106b811e5a5SAdrian Chadd /* 1SS, MCS 4..7 */ 107b811e5a5SAdrian Chadd rtwn_bb_write(sc, R12A_TXAGC_NSS1IX7_1IX4(chain), 108b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS4, power[RTWN_RIDX_VHT_MCS(0, 4)]) | 109b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS5, power[RTWN_RIDX_VHT_MCS(0, 5)]) | 110b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS6, power[RTWN_RIDX_VHT_MCS(0, 6)]) | 111b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS7, power[RTWN_RIDX_VHT_MCS(0, 7)])); 112b811e5a5SAdrian Chadd 113b811e5a5SAdrian Chadd /* 1SS, MCS 8,9 ; 2SS MCS0, 1 */ 114b811e5a5SAdrian Chadd if (sc->ntxchains == 1) { 115b811e5a5SAdrian Chadd rtwn_bb_write(sc, R12A_TXAGC_NSS2IX1_1IX8(chain), 116b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS8, power[RTWN_RIDX_VHT_MCS(0, 8)]) | 117b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS9, power[RTWN_RIDX_VHT_MCS(0, 9)]) | 118b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS0, 0) | 119b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS1, 0)); 120b811e5a5SAdrian Chadd } else { 121b811e5a5SAdrian Chadd rtwn_bb_write(sc, R12A_TXAGC_NSS2IX1_1IX8(chain), 122b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS8, power[RTWN_RIDX_VHT_MCS(0, 8)]) | 123b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS1_MCS9, power[RTWN_RIDX_VHT_MCS(0, 9)]) | 124b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS0, power[RTWN_RIDX_VHT_MCS(1, 0)]) | 125b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS1, power[RTWN_RIDX_VHT_MCS(1, 1)])); 126b811e5a5SAdrian Chadd } 127b811e5a5SAdrian Chadd 128b811e5a5SAdrian Chadd /* 2SS MCS 2..5 */ 129b811e5a5SAdrian Chadd if (sc->ntxchains > 1) { 130b811e5a5SAdrian Chadd rtwn_bb_write(sc, R12A_TXAGC_NSS2IX5_2IX2(chain), 131b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS2, power[RTWN_RIDX_VHT_MCS(1, 2)]) | 132b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS3, power[RTWN_RIDX_VHT_MCS(1, 3)]) | 133b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS4, power[RTWN_RIDX_VHT_MCS(1, 4)]) | 134b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS5, power[RTWN_RIDX_VHT_MCS(1, 5)])); 135b811e5a5SAdrian Chadd } 136b811e5a5SAdrian Chadd 137b811e5a5SAdrian Chadd /* 2SS MCS 6..9 */ 138b811e5a5SAdrian Chadd if (sc->ntxchains > 1) { 139b811e5a5SAdrian Chadd rtwn_bb_write(sc, R12A_TXAGC_NSS2IX9_2IX6(chain), 140b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS2, power[RTWN_RIDX_VHT_MCS(1, 6)]) | 141b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS3, power[RTWN_RIDX_VHT_MCS(1, 7)]) | 142b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS4, power[RTWN_RIDX_VHT_MCS(1, 8)]) | 143b811e5a5SAdrian Chadd SM(R12A_TXAGC_NSS2_MCS5, power[RTWN_RIDX_VHT_MCS(1, 9)])); 144b811e5a5SAdrian Chadd } 145b811e5a5SAdrian Chadd 146b811e5a5SAdrian Chadd /* TODO: 3SS, 4SS VHT rates */ 147b811e5a5SAdrian Chadd } 148b811e5a5SAdrian Chadd 149b811e5a5SAdrian Chadd 150b811e5a5SAdrian Chadd static void 151468cd606SAdrian Chadd r12a_write_txpower_cck(struct rtwn_softc *sc, int chain, 152468cd606SAdrian Chadd struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) 153468cd606SAdrian Chadd { 154468cd606SAdrian Chadd 155468cd606SAdrian Chadd if (IEEE80211_IS_CHAN_2GHZ(c)) { 156468cd606SAdrian Chadd /* Write per-CCK rate Tx power. */ 157468cd606SAdrian Chadd rtwn_bb_write(sc, R12A_TXAGC_CCK11_1(chain), 158468cd606SAdrian Chadd SM(R12A_TXAGC_CCK1, power[RTWN_RIDX_CCK1]) | 159468cd606SAdrian Chadd SM(R12A_TXAGC_CCK2, power[RTWN_RIDX_CCK2]) | 160468cd606SAdrian Chadd SM(R12A_TXAGC_CCK55, power[RTWN_RIDX_CCK55]) | 161468cd606SAdrian Chadd SM(R12A_TXAGC_CCK11, power[RTWN_RIDX_CCK11])); 162468cd606SAdrian Chadd } 163468cd606SAdrian Chadd } 164468cd606SAdrian Chadd 165468cd606SAdrian Chadd static void 166468cd606SAdrian Chadd r12a_write_txpower_ofdm(struct rtwn_softc *sc, int chain, 167468cd606SAdrian Chadd struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) 168468cd606SAdrian Chadd { 169468cd606SAdrian Chadd 170468cd606SAdrian Chadd /* Write per-OFDM rate Tx power. */ 171468cd606SAdrian Chadd rtwn_bb_write(sc, R12A_TXAGC_OFDM18_6(chain), 172468cd606SAdrian Chadd SM(R12A_TXAGC_OFDM06, power[RTWN_RIDX_OFDM6]) | 173468cd606SAdrian Chadd SM(R12A_TXAGC_OFDM09, power[RTWN_RIDX_OFDM9]) | 174468cd606SAdrian Chadd SM(R12A_TXAGC_OFDM12, power[RTWN_RIDX_OFDM12]) | 175468cd606SAdrian Chadd SM(R12A_TXAGC_OFDM18, power[RTWN_RIDX_OFDM18])); 176468cd606SAdrian Chadd rtwn_bb_write(sc, R12A_TXAGC_OFDM54_24(chain), 177468cd606SAdrian Chadd SM(R12A_TXAGC_OFDM24, power[RTWN_RIDX_OFDM24]) | 178468cd606SAdrian Chadd SM(R12A_TXAGC_OFDM36, power[RTWN_RIDX_OFDM36]) | 179468cd606SAdrian Chadd SM(R12A_TXAGC_OFDM48, power[RTWN_RIDX_OFDM48]) | 180468cd606SAdrian Chadd SM(R12A_TXAGC_OFDM54, power[RTWN_RIDX_OFDM54])); 181468cd606SAdrian Chadd } 182468cd606SAdrian Chadd 183468cd606SAdrian Chadd static void 184cf6b389fSAdrian Chadd r12a_tx_power_training(struct rtwn_softc *sc, int chain, 185cf6b389fSAdrian Chadd const struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) 186cf6b389fSAdrian Chadd { 187cf6b389fSAdrian Chadd uint32_t write_data; 188cf6b389fSAdrian Chadd int32_t power_level; 189cf6b389fSAdrian Chadd int i; 190cf6b389fSAdrian Chadd 191cf6b389fSAdrian Chadd write_data = 0; 192cf6b389fSAdrian Chadd 193cf6b389fSAdrian Chadd power_level = (int32_t) power[RTWN_RIDX_HT_MCS(7)]; 194cf6b389fSAdrian Chadd for (i = 0; i < 3; i++) { 195cf6b389fSAdrian Chadd if (i == 0) 196cf6b389fSAdrian Chadd power_level -= 10; 197cf6b389fSAdrian Chadd else if (i == 1) 198cf6b389fSAdrian Chadd power_level -= 8; 199cf6b389fSAdrian Chadd else 200cf6b389fSAdrian Chadd power_level -= 6; 201cf6b389fSAdrian Chadd 202cf6b389fSAdrian Chadd /* Handle underflow and the minimum value (2) */ 203cf6b389fSAdrian Chadd if (power_level < 2) 204cf6b389fSAdrian Chadd power_level = 2; 205cf6b389fSAdrian Chadd 206cf6b389fSAdrian Chadd write_data |= ((power_level & 0xff) << (i * 8)); 207cf6b389fSAdrian Chadd } 208cf6b389fSAdrian Chadd 209cf6b389fSAdrian Chadd rtwn_bb_setbits(sc, R12A_TX_PWR_TRAINING(chain), 210cf6b389fSAdrian Chadd 0x00ffffff, write_data); 211cf6b389fSAdrian Chadd } 212cf6b389fSAdrian Chadd 213cf6b389fSAdrian Chadd static void 214468cd606SAdrian Chadd r12a_write_txpower(struct rtwn_softc *sc, int chain, 215468cd606SAdrian Chadd struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) 216468cd606SAdrian Chadd { 217468cd606SAdrian Chadd 218468cd606SAdrian Chadd r12a_write_txpower_cck(sc, chain, c, power); 219468cd606SAdrian Chadd r12a_write_txpower_ofdm(sc, chain, c, power); 220468cd606SAdrian Chadd r12a_write_txpower_ht(sc, chain, c, power); 221b811e5a5SAdrian Chadd r12a_write_txpower_vht(sc, chain, c, power); 222cf6b389fSAdrian Chadd 223cf6b389fSAdrian Chadd r12a_tx_power_training(sc, chain, c, power); 2247453645fSAndriy Voskoboinyk } 2257453645fSAndriy Voskoboinyk 2267453645fSAndriy Voskoboinyk static int 2277453645fSAndriy Voskoboinyk r12a_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) 2287453645fSAndriy Voskoboinyk { 2297453645fSAndriy Voskoboinyk uint8_t chan; 2307453645fSAndriy Voskoboinyk int group; 2317453645fSAndriy Voskoboinyk 2327453645fSAndriy Voskoboinyk chan = rtwn_chan2centieee(c); 2337453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_2GHZ(c)) { 2347453645fSAndriy Voskoboinyk if (chan <= 2) group = 0; 2357453645fSAndriy Voskoboinyk else if (chan <= 5) group = 1; 2367453645fSAndriy Voskoboinyk else if (chan <= 8) group = 2; 2377453645fSAndriy Voskoboinyk else if (chan <= 11) group = 3; 2387453645fSAndriy Voskoboinyk else if (chan <= 14) group = 4; 2397453645fSAndriy Voskoboinyk else { 2407453645fSAndriy Voskoboinyk KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); 2417453645fSAndriy Voskoboinyk return (-1); 2427453645fSAndriy Voskoboinyk } 2437453645fSAndriy Voskoboinyk } else if (IEEE80211_IS_CHAN_5GHZ(c)) { 2447453645fSAndriy Voskoboinyk if (chan < 36) 2457453645fSAndriy Voskoboinyk return (-1); 2467453645fSAndriy Voskoboinyk 2477453645fSAndriy Voskoboinyk if (chan <= 42) group = 0; 2487453645fSAndriy Voskoboinyk else if (chan <= 48) group = 1; 2497453645fSAndriy Voskoboinyk else if (chan <= 58) group = 2; 2507453645fSAndriy Voskoboinyk else if (chan <= 64) group = 3; 2517453645fSAndriy Voskoboinyk else if (chan <= 106) group = 4; 2527453645fSAndriy Voskoboinyk else if (chan <= 114) group = 5; 2537453645fSAndriy Voskoboinyk else if (chan <= 122) group = 6; 2547453645fSAndriy Voskoboinyk else if (chan <= 130) group = 7; 2557453645fSAndriy Voskoboinyk else if (chan <= 138) group = 8; 2567453645fSAndriy Voskoboinyk else if (chan <= 144) group = 9; 2577453645fSAndriy Voskoboinyk else if (chan <= 155) group = 10; 2587453645fSAndriy Voskoboinyk else if (chan <= 161) group = 11; 2597453645fSAndriy Voskoboinyk else if (chan <= 171) group = 12; 2607453645fSAndriy Voskoboinyk else if (chan <= 177) group = 13; 2617453645fSAndriy Voskoboinyk else { 2627453645fSAndriy Voskoboinyk KASSERT(0, ("wrong 5GHz channel %d!\n", chan)); 2637453645fSAndriy Voskoboinyk return (-1); 2647453645fSAndriy Voskoboinyk } 2657453645fSAndriy Voskoboinyk } else { 2667453645fSAndriy Voskoboinyk KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); 2677453645fSAndriy Voskoboinyk return (-1); 2687453645fSAndriy Voskoboinyk } 2697453645fSAndriy Voskoboinyk 2707453645fSAndriy Voskoboinyk return (group); 2717453645fSAndriy Voskoboinyk } 2727453645fSAndriy Voskoboinyk 2737453645fSAndriy Voskoboinyk static void 2747453645fSAndriy Voskoboinyk r12a_get_txpower(struct rtwn_softc *sc, int chain, 2750351824fSKevin Lo struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) 2767453645fSAndriy Voskoboinyk { 2777453645fSAndriy Voskoboinyk struct r12a_softc *rs = sc->sc_priv; 278b4980d8aSAdrian Chadd int i, ridx, group, max_mcs, max_vht_mcs; 2797453645fSAndriy Voskoboinyk 2807453645fSAndriy Voskoboinyk /* Determine channel group. */ 2817453645fSAndriy Voskoboinyk group = r12a_get_power_group(sc, c); 2827453645fSAndriy Voskoboinyk if (group == -1) { /* shouldn't happen */ 2837453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); 2847453645fSAndriy Voskoboinyk return; 2857453645fSAndriy Voskoboinyk } 2867453645fSAndriy Voskoboinyk 2870cc18edfSAndriy Voskoboinyk max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); 288b4980d8aSAdrian Chadd max_vht_mcs = RTWN_RIDX_VHT_MCS(sc->ntxchains, 9) - 1; 2897453645fSAndriy Voskoboinyk 2907453645fSAndriy Voskoboinyk /* XXX regulatory */ 2917453645fSAndriy Voskoboinyk /* XXX net80211 regulatory */ 2927453645fSAndriy Voskoboinyk 2937453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_2GHZ(c)) { 2947453645fSAndriy Voskoboinyk for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) 2957453645fSAndriy Voskoboinyk power[ridx] = rs->cck_tx_pwr[chain][group]; 2967453645fSAndriy Voskoboinyk for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) 2977453645fSAndriy Voskoboinyk power[ridx] = rs->ht40_tx_pwr_2g[chain][group]; 2987453645fSAndriy Voskoboinyk 2990351824fSKevin Lo for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) 3000351824fSKevin Lo power[ridx] += rs->ofdm_tx_pwr_diff_2g[chain][0]; 3017453645fSAndriy Voskoboinyk 3027453645fSAndriy Voskoboinyk for (i = 0; i < sc->ntxchains; i++) { 3037453645fSAndriy Voskoboinyk uint8_t min_mcs; 3047453645fSAndriy Voskoboinyk uint8_t pwr_diff; 3057453645fSAndriy Voskoboinyk 306b4980d8aSAdrian Chadd if (IEEE80211_IS_CHAN_VHT80(c)) { 3077453645fSAndriy Voskoboinyk /* Vendor driver uses HT40 values here. */ 3087453645fSAndriy Voskoboinyk pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i]; 3097453645fSAndriy Voskoboinyk } else 310b4980d8aSAdrian Chadd if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_VHT40(c)) 3117453645fSAndriy Voskoboinyk pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i]; 3127453645fSAndriy Voskoboinyk else 3137453645fSAndriy Voskoboinyk pwr_diff = rs->bw20_tx_pwr_diff_2g[chain][i]; 3147453645fSAndriy Voskoboinyk 3150cc18edfSAndriy Voskoboinyk min_mcs = RTWN_RIDX_HT_MCS(i * 8); 3167453645fSAndriy Voskoboinyk for (ridx = min_mcs; ridx <= max_mcs; ridx++) 3177453645fSAndriy Voskoboinyk power[ridx] += pwr_diff; 3187453645fSAndriy Voskoboinyk } 3197453645fSAndriy Voskoboinyk } else { /* 5GHz */ 320b4980d8aSAdrian Chadd /* OFDM + HT */ 3217453645fSAndriy Voskoboinyk for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) 3227453645fSAndriy Voskoboinyk power[ridx] = rs->ht40_tx_pwr_5g[chain][group]; 323b4980d8aSAdrian Chadd /* VHT */ 324b4980d8aSAdrian Chadd for (ridx = RTWN_RIDX_VHT_MCS_SHIFT; ridx <= max_vht_mcs; ridx++) 325b4980d8aSAdrian Chadd power[ridx] = rs->ht40_tx_pwr_5g[chain][group]; 3267453645fSAndriy Voskoboinyk 327b4980d8aSAdrian Chadd /* Add power for OFDM rates */ 3280351824fSKevin Lo for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) 3290351824fSKevin Lo power[ridx] += rs->ofdm_tx_pwr_diff_5g[chain][0]; 3300351824fSKevin Lo 3317453645fSAndriy Voskoboinyk for (i = 0; i < sc->ntxchains; i++) { 3327453645fSAndriy Voskoboinyk uint8_t min_mcs; 3337453645fSAndriy Voskoboinyk uint8_t pwr_diff; 3347453645fSAndriy Voskoboinyk 335b4980d8aSAdrian Chadd if (IEEE80211_IS_CHAN_VHT80(c)) { 3367453645fSAndriy Voskoboinyk /* TODO: calculate base value. */ 3377453645fSAndriy Voskoboinyk pwr_diff = rs->bw80_tx_pwr_diff_5g[chain][i]; 3387453645fSAndriy Voskoboinyk } else 339b4980d8aSAdrian Chadd if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_VHT40(c)) 3407453645fSAndriy Voskoboinyk pwr_diff = rs->bw40_tx_pwr_diff_5g[chain][i]; 3417453645fSAndriy Voskoboinyk else 3427453645fSAndriy Voskoboinyk pwr_diff = rs->bw20_tx_pwr_diff_5g[chain][i]; 3437453645fSAndriy Voskoboinyk 344b4980d8aSAdrian Chadd /* Adjust HT rates */ 3450cc18edfSAndriy Voskoboinyk min_mcs = RTWN_RIDX_HT_MCS(i * 8); 3467453645fSAndriy Voskoboinyk for (ridx = min_mcs; ridx <= max_mcs; ridx++) 3477453645fSAndriy Voskoboinyk power[ridx] += pwr_diff; 348b4980d8aSAdrian Chadd 349b4980d8aSAdrian Chadd /* Adjust VHT rates */ 350b4980d8aSAdrian Chadd for (ridx = RTWN_RIDX_VHT_MCS(i, 0); 351b4980d8aSAdrian Chadd ridx <= RTWN_RIDX_VHT_MCS(i, 9); 352b4980d8aSAdrian Chadd ridx++) 353b4980d8aSAdrian Chadd power[ridx] += pwr_diff; 354b4980d8aSAdrian Chadd 3557453645fSAndriy Voskoboinyk } 3567453645fSAndriy Voskoboinyk } 3577453645fSAndriy Voskoboinyk 3587453645fSAndriy Voskoboinyk /* Apply max limit. */ 3597453645fSAndriy Voskoboinyk for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { 3607453645fSAndriy Voskoboinyk if (power[ridx] > R92C_MAX_TX_PWR) 3617453645fSAndriy Voskoboinyk power[ridx] = R92C_MAX_TX_PWR; 3627453645fSAndriy Voskoboinyk } 363b4980d8aSAdrian Chadd for (ridx = RTWN_RIDX_VHT_MCS(0, 0); 364b4980d8aSAdrian Chadd ridx <= RTWN_RIDX_VHT_MCS(3, 9); 365b4980d8aSAdrian Chadd ridx++) { 366b4980d8aSAdrian Chadd if (power[ridx] > R92C_MAX_TX_PWR) 367b4980d8aSAdrian Chadd power[ridx] = R92C_MAX_TX_PWR; 368b4980d8aSAdrian Chadd } 3697453645fSAndriy Voskoboinyk 3707453645fSAndriy Voskoboinyk #ifdef RTWN_DEBUG 3717453645fSAndriy Voskoboinyk if (sc->sc_debug & RTWN_DEBUG_TXPWR) { 3727453645fSAndriy Voskoboinyk /* Dump per-rate Tx power values. */ 3737453645fSAndriy Voskoboinyk printf("Tx power for chain %d:\n", chain); 3746b322760SAndriy Voskoboinyk for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) 3757453645fSAndriy Voskoboinyk printf("Rate %d = %u\n", ridx, power[ridx]); 376b4980d8aSAdrian Chadd /* TODO: dump VHT 0..9 for each spatial stream */ 3777453645fSAndriy Voskoboinyk } 3787453645fSAndriy Voskoboinyk #endif 3797453645fSAndriy Voskoboinyk } 3807453645fSAndriy Voskoboinyk 3817453645fSAndriy Voskoboinyk static void 3827453645fSAndriy Voskoboinyk r12a_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) 3837453645fSAndriy Voskoboinyk { 3840351824fSKevin Lo uint8_t power[RTWN_RIDX_COUNT]; 3857453645fSAndriy Voskoboinyk int i; 3867453645fSAndriy Voskoboinyk 3877453645fSAndriy Voskoboinyk for (i = 0; i < sc->ntxchains; i++) { 3887453645fSAndriy Voskoboinyk memset(power, 0, sizeof(power)); 3897453645fSAndriy Voskoboinyk /* Compute per-rate Tx power values. */ 3907453645fSAndriy Voskoboinyk r12a_get_txpower(sc, i, c, power); 3917453645fSAndriy Voskoboinyk /* Write per-rate Tx power values to hardware. */ 3927453645fSAndriy Voskoboinyk r12a_write_txpower(sc, i, c, power); 3937453645fSAndriy Voskoboinyk } 3947453645fSAndriy Voskoboinyk } 3957453645fSAndriy Voskoboinyk 3967453645fSAndriy Voskoboinyk void 3977453645fSAndriy Voskoboinyk r12a_fix_spur(struct rtwn_softc *sc, struct ieee80211_channel *c) 3987453645fSAndriy Voskoboinyk { 3997453645fSAndriy Voskoboinyk struct r12a_softc *rs = sc->sc_priv; 4007453645fSAndriy Voskoboinyk uint16_t chan = rtwn_chan2centieee(c); 4017453645fSAndriy Voskoboinyk 4027453645fSAndriy Voskoboinyk if (rs->chip & R12A_CHIP_C_CUT) { 4037453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_HT40(c) && chan == 11) { 4047453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0xc00); 4057453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0, 0x40000000); 4067453645fSAndriy Voskoboinyk } else { 4077453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFMOD, 0x400, 0x800); 4087453645fSAndriy Voskoboinyk 4097722d5e2SAdrian Chadd if ((IEEE80211_IS_CHAN_B(c) || 4107722d5e2SAdrian Chadd IEEE80211_IS_CHAN_ANYG(c) || 4117722d5e2SAdrian Chadd IEEE80211_IS_CHAN_HT20(c)) && /* 2GHz, 20 MHz */ 4127453645fSAndriy Voskoboinyk (chan == 13 || chan == 14)) { 4137453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300); 4147453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 4157453645fSAndriy Voskoboinyk 0, 0x40000000); 4167722d5e2SAdrian Chadd } else if (IEEE80211_IS_CHAN_HT40(c) || 4177722d5e2SAdrian Chadd IEEE80211_IS_CHAN_VHT40(c)) { 4187722d5e2SAdrian Chadd /* XXX double check! */ 4197722d5e2SAdrian Chadd rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 4207722d5e2SAdrian Chadd 0, 0x40000000); 4217722d5e2SAdrian Chadd } else if (IEEE80211_IS_CHAN_VHT80(c)) { 4227722d5e2SAdrian Chadd /* XXX double check! */ 4237453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200); 4247453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 4257453645fSAndriy Voskoboinyk 0x40000000, 0); 4267453645fSAndriy Voskoboinyk } 4277453645fSAndriy Voskoboinyk } 4287453645fSAndriy Voskoboinyk } else { 4297453645fSAndriy Voskoboinyk /* Set ADC clock to 160M to resolve 2480 MHz spur. */ 4307722d5e2SAdrian Chadd if ((IEEE80211_IS_CHAN_B(c) || 4317722d5e2SAdrian Chadd IEEE80211_IS_CHAN_ANYG(c) || 4327722d5e2SAdrian Chadd IEEE80211_IS_CHAN_HT20(c)) && /* 2GHz, 20 MHz */ 4337453645fSAndriy Voskoboinyk (chan == 13 || chan == 14)) 4347453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300); 4357453645fSAndriy Voskoboinyk else if (IEEE80211_IS_CHAN_2GHZ(c)) 4367453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200); 4377453645fSAndriy Voskoboinyk } 4387453645fSAndriy Voskoboinyk } 4397453645fSAndriy Voskoboinyk 4407453645fSAndriy Voskoboinyk static void 4417453645fSAndriy Voskoboinyk r12a_set_band(struct rtwn_softc *sc, struct ieee80211_channel *c) 4427453645fSAndriy Voskoboinyk { 4437453645fSAndriy Voskoboinyk struct ieee80211com *ic = &sc->sc_ic; 4447453645fSAndriy Voskoboinyk struct r12a_softc *rs = sc->sc_priv; 4457453645fSAndriy Voskoboinyk uint32_t basicrates; 4467453645fSAndriy Voskoboinyk uint8_t swing; 4477453645fSAndriy Voskoboinyk int i; 4487453645fSAndriy Voskoboinyk 4497453645fSAndriy Voskoboinyk /* Check if band was changed. */ 4507453645fSAndriy Voskoboinyk if ((sc->sc_flags & (RTWN_STARTED | RTWN_RUNNING)) != 4517453645fSAndriy Voskoboinyk RTWN_STARTED && IEEE80211_IS_CHAN_5GHZ(c) ^ 4527453645fSAndriy Voskoboinyk !(rtwn_read_1(sc, R12A_CCK_CHECK) & R12A_CCK_CHECK_5GHZ)) 4537453645fSAndriy Voskoboinyk return; 4547453645fSAndriy Voskoboinyk 455*745a8582SAdrian Chadd /* Note: this only fetches the basic rates, not the full rateset */ 4567453645fSAndriy Voskoboinyk rtwn_get_rates(sc, ieee80211_get_suprates(ic, c), NULL, &basicrates, 457*745a8582SAdrian Chadd NULL, NULL, 1); 4587453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_2GHZ(c)) { 4597453645fSAndriy Voskoboinyk rtwn_r12a_set_band_2ghz(sc, basicrates); 4607453645fSAndriy Voskoboinyk swing = rs->tx_bbswing_2g; 4617453645fSAndriy Voskoboinyk } else if (IEEE80211_IS_CHAN_5GHZ(c)) { 4627453645fSAndriy Voskoboinyk rtwn_r12a_set_band_5ghz(sc, basicrates); 4637453645fSAndriy Voskoboinyk swing = rs->tx_bbswing_5g; 4647453645fSAndriy Voskoboinyk } else { 4657453645fSAndriy Voskoboinyk KASSERT(0, ("wrong channel flags %08X\n", c->ic_flags)); 4667453645fSAndriy Voskoboinyk return; 4677453645fSAndriy Voskoboinyk } 4687453645fSAndriy Voskoboinyk 4697453645fSAndriy Voskoboinyk /* XXX PATH_B is set by vendor driver. */ 4707453645fSAndriy Voskoboinyk for (i = 0; i < 2; i++) { 4710ea682ebSAndriy Voskoboinyk uint16_t val = 0; 4727453645fSAndriy Voskoboinyk 4737453645fSAndriy Voskoboinyk switch ((swing >> i * 2) & 0x3) { 4747453645fSAndriy Voskoboinyk case 0: 4757453645fSAndriy Voskoboinyk val = 0x200; /* 0 dB */ 4767453645fSAndriy Voskoboinyk break; 4777453645fSAndriy Voskoboinyk case 1: 4787453645fSAndriy Voskoboinyk val = 0x16a; /* -3 dB */ 4797453645fSAndriy Voskoboinyk break; 4807453645fSAndriy Voskoboinyk case 2: 4817453645fSAndriy Voskoboinyk val = 0x101; /* -6 dB */ 4827453645fSAndriy Voskoboinyk break; 4837453645fSAndriy Voskoboinyk case 3: 4847453645fSAndriy Voskoboinyk val = 0xb6; /* -9 dB */ 4857453645fSAndriy Voskoboinyk break; 4867453645fSAndriy Voskoboinyk } 4877453645fSAndriy Voskoboinyk 4887453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_TX_SCALE(i), R12A_TX_SCALE_SWING_M, 4897453645fSAndriy Voskoboinyk val << R12A_TX_SCALE_SWING_S); 4907453645fSAndriy Voskoboinyk } 4917453645fSAndriy Voskoboinyk } 4927453645fSAndriy Voskoboinyk 4937453645fSAndriy Voskoboinyk void 4947453645fSAndriy Voskoboinyk r12a_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) 4957453645fSAndriy Voskoboinyk { 4967453645fSAndriy Voskoboinyk uint32_t val; 4977453645fSAndriy Voskoboinyk uint16_t chan; 4987453645fSAndriy Voskoboinyk int i; 4997453645fSAndriy Voskoboinyk 5007453645fSAndriy Voskoboinyk r12a_set_band(sc, c); 5017453645fSAndriy Voskoboinyk 5027453645fSAndriy Voskoboinyk chan = rtwn_chan2centieee(c); 5037453645fSAndriy Voskoboinyk if (36 <= chan && chan <= 48) 5047453645fSAndriy Voskoboinyk val = 0x09280000; 5057453645fSAndriy Voskoboinyk else if (50 <= chan && chan <= 64) 5067453645fSAndriy Voskoboinyk val = 0x08a60000; 5077453645fSAndriy Voskoboinyk else if (100 <= chan && chan <= 116) 5087453645fSAndriy Voskoboinyk val = 0x08a40000; 5097453645fSAndriy Voskoboinyk else if (118 <= chan) 5107453645fSAndriy Voskoboinyk val = 0x08240000; 5117453645fSAndriy Voskoboinyk else 5127453645fSAndriy Voskoboinyk val = 0x12d40000; 5137453645fSAndriy Voskoboinyk 5147453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_FC_AREA, 0x1ffe0000, val); 5157453645fSAndriy Voskoboinyk 5167453645fSAndriy Voskoboinyk for (i = 0; i < sc->nrxchains; i++) { 5177453645fSAndriy Voskoboinyk if (36 <= chan && chan <= 64) 5187453645fSAndriy Voskoboinyk val = 0x10100; 5197453645fSAndriy Voskoboinyk else if (100 <= chan && chan <= 140) 5207453645fSAndriy Voskoboinyk val = 0x30100; 5217453645fSAndriy Voskoboinyk else if (140 < chan) 5227453645fSAndriy Voskoboinyk val = 0x50100; 5237453645fSAndriy Voskoboinyk else 5247453645fSAndriy Voskoboinyk val = 0x00000; 5257453645fSAndriy Voskoboinyk 5267453645fSAndriy Voskoboinyk rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0x70300, val); 5277453645fSAndriy Voskoboinyk 5287453645fSAndriy Voskoboinyk /* RTL8812AU-specific */ 5297453645fSAndriy Voskoboinyk rtwn_r12a_fix_spur(sc, c); 5307453645fSAndriy Voskoboinyk 5317453645fSAndriy Voskoboinyk KASSERT(chan <= 0xff, ("%s: chan %d\n", __func__, chan)); 5327453645fSAndriy Voskoboinyk rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xff, chan); 5337453645fSAndriy Voskoboinyk } 5347453645fSAndriy Voskoboinyk 5357722d5e2SAdrian Chadd if (IEEE80211_IS_CHAN_VHT80(c)) { /* 80 MHz */ 5367722d5e2SAdrian Chadd uint8_t ext20 = 0, ext40 = 0; 5377722d5e2SAdrian Chadd uint8_t txsc; 5387722d5e2SAdrian Chadd /* calculate ext20/ext40 */ 5397722d5e2SAdrian Chadd if (c->ic_ieee > c->ic_vht_ch_freq1) { 5407722d5e2SAdrian Chadd if (c->ic_ieee - c->ic_vht_ch_freq1 == 2) { 5417722d5e2SAdrian Chadd ext20 = R12A_DATA_SEC_PRIM_UP_20; 5427722d5e2SAdrian Chadd ext40 = R12A_DATA_SEC_PRIM_UP_40; 5437722d5e2SAdrian Chadd } else { 5447722d5e2SAdrian Chadd ext20 = R12A_DATA_SEC_PRIM_UPPER_20; 5457722d5e2SAdrian Chadd ext40 = R12A_DATA_SEC_PRIM_UP_40; 5467722d5e2SAdrian Chadd } 5477722d5e2SAdrian Chadd } else { 5487722d5e2SAdrian Chadd if (c->ic_vht_ch_freq1 - c->ic_ieee == 2) { 5497722d5e2SAdrian Chadd ext20 = R12A_DATA_SEC_PRIM_DOWN_20; 5507722d5e2SAdrian Chadd ext40 = R12A_DATA_SEC_PRIM_DOWN_40; 5517722d5e2SAdrian Chadd } else { 5527722d5e2SAdrian Chadd ext20 = R12A_DATA_SEC_PRIM_LOWER_20; 5537722d5e2SAdrian Chadd ext40 = R12A_DATA_SEC_PRIM_DOWN_40; 5547722d5e2SAdrian Chadd } 5557722d5e2SAdrian Chadd } 5567722d5e2SAdrian Chadd /* Form txsc from sec20/sec40 config */ 5577722d5e2SAdrian Chadd txsc = SM(R12A_DATA_SEC_TXSC_20M, ext20); 5587722d5e2SAdrian Chadd txsc |= SM(R12A_DATA_SEC_TXSC_40M, ext40); 5597453645fSAndriy Voskoboinyk 5607722d5e2SAdrian Chadd rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x180, 0x100); 5617453645fSAndriy Voskoboinyk 5627722d5e2SAdrian Chadd /* DATA_SEC, for ext20/ext40 */ 5637722d5e2SAdrian Chadd rtwn_write_1(sc, R12A_DATA_SEC, txsc); 5647722d5e2SAdrian Chadd 5657722d5e2SAdrian Chadd /* ADCCLK */ 5667722d5e2SAdrian Chadd rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300202); 5677722d5e2SAdrian Chadd 5687722d5e2SAdrian Chadd /* ADC160 - Set bit 30 */ 5697722d5e2SAdrian Chadd rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0, 0x40000000); 5707722d5e2SAdrian Chadd 5717722d5e2SAdrian Chadd /* ADCCLK, ext20 */ 5727722d5e2SAdrian Chadd /* discard high 4 bits */ 5737722d5e2SAdrian Chadd val = rtwn_bb_read(sc, R12A_RFMOD); 5747722d5e2SAdrian Chadd val = RW(val, R12A_RFMOD_EXT_CHAN, ext20); 5757722d5e2SAdrian Chadd rtwn_bb_write(sc, R12A_RFMOD, val); 5767722d5e2SAdrian Chadd 5777722d5e2SAdrian Chadd /* CCA2ND, ext20 */ 5787722d5e2SAdrian Chadd val = rtwn_bb_read(sc, R12A_CCA_ON_SEC); 5797722d5e2SAdrian Chadd val = RW(val, R12A_CCA_ON_SEC_EXT_CHAN, ext20); 5807722d5e2SAdrian Chadd rtwn_bb_write(sc, R12A_CCA_ON_SEC, val); 5817722d5e2SAdrian Chadd 5827722d5e2SAdrian Chadd /* PEAK_TH */ 5837722d5e2SAdrian Chadd if (rtwn_read_1(sc, 0x837) & 0x04) 5847722d5e2SAdrian Chadd val = 0x01400000; 5857722d5e2SAdrian Chadd else if (sc->nrxchains == 2 && sc->ntxchains == 2) 5867722d5e2SAdrian Chadd val = 0x01800000; 5877722d5e2SAdrian Chadd else 5887722d5e2SAdrian Chadd val = 0x01c00000; 5897722d5e2SAdrian Chadd 5907722d5e2SAdrian Chadd rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val); 5917722d5e2SAdrian Chadd /* BWMASK */ 5927453645fSAndriy Voskoboinyk val = 0x0; 5937722d5e2SAdrian Chadd 5947722d5e2SAdrian Chadd } else if (IEEE80211_IS_CHAN_HT40(c) || 5957722d5e2SAdrian Chadd IEEE80211_IS_CHAN_VHT40(c)) { /* 40 MHz */ 5967453645fSAndriy Voskoboinyk uint8_t ext_chan; 5977453645fSAndriy Voskoboinyk 5987453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_HT40U(c)) 5997453645fSAndriy Voskoboinyk ext_chan = R12A_DATA_SEC_PRIM_DOWN_20; 6007453645fSAndriy Voskoboinyk else 6017453645fSAndriy Voskoboinyk ext_chan = R12A_DATA_SEC_PRIM_UP_20; 6027453645fSAndriy Voskoboinyk 6037453645fSAndriy Voskoboinyk rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x100, 0x80); 6047453645fSAndriy Voskoboinyk rtwn_write_1(sc, R12A_DATA_SEC, ext_chan); 6057453645fSAndriy Voskoboinyk 6067453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300201); 6077453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0); 6087453645fSAndriy Voskoboinyk 6097453645fSAndriy Voskoboinyk /* discard high 4 bits */ 6107453645fSAndriy Voskoboinyk val = rtwn_bb_read(sc, R12A_RFMOD); 6117453645fSAndriy Voskoboinyk val = RW(val, R12A_RFMOD_EXT_CHAN, ext_chan); 6127453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFMOD, val); 6137453645fSAndriy Voskoboinyk 6147453645fSAndriy Voskoboinyk val = rtwn_bb_read(sc, R12A_CCA_ON_SEC); 6157453645fSAndriy Voskoboinyk val = RW(val, R12A_CCA_ON_SEC_EXT_CHAN, ext_chan); 6167453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_CCA_ON_SEC, val); 6177453645fSAndriy Voskoboinyk 6187453645fSAndriy Voskoboinyk if (rtwn_read_1(sc, 0x837) & 0x04) 6197453645fSAndriy Voskoboinyk val = 0x01800000; 6207453645fSAndriy Voskoboinyk else if (sc->nrxchains == 2 && sc->ntxchains == 2) 6217453645fSAndriy Voskoboinyk val = 0x01c00000; 6227453645fSAndriy Voskoboinyk else 6237453645fSAndriy Voskoboinyk val = 0x02000000; 6247453645fSAndriy Voskoboinyk 6257453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val); 6267453645fSAndriy Voskoboinyk 6277453645fSAndriy Voskoboinyk if (IEEE80211_IS_CHAN_HT40U(c)) 6287453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10, 0); 6297453645fSAndriy Voskoboinyk else 6307453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0, 0x10); 6317453645fSAndriy Voskoboinyk 6327453645fSAndriy Voskoboinyk val = 0x400; 6337453645fSAndriy Voskoboinyk } else { /* 20 MHz */ 6347453645fSAndriy Voskoboinyk rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x180, 0); 6357453645fSAndriy Voskoboinyk rtwn_write_1(sc, R12A_DATA_SEC, R12A_DATA_SEC_NO_EXT); 6367453645fSAndriy Voskoboinyk 6377453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300200); 6387453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0); 6397453645fSAndriy Voskoboinyk 6407453645fSAndriy Voskoboinyk if (sc->nrxchains == 2 && sc->ntxchains == 2) 6417453645fSAndriy Voskoboinyk val = 0x01c00000; 6427453645fSAndriy Voskoboinyk else 6437453645fSAndriy Voskoboinyk val = 0x02000000; 6447453645fSAndriy Voskoboinyk 6457453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val); 6467453645fSAndriy Voskoboinyk 6477453645fSAndriy Voskoboinyk val = 0xc00; 6487453645fSAndriy Voskoboinyk } 6497453645fSAndriy Voskoboinyk 6507453645fSAndriy Voskoboinyk /* RTL8812AU-specific */ 6517453645fSAndriy Voskoboinyk rtwn_r12a_fix_spur(sc, c); 6527453645fSAndriy Voskoboinyk 6530351824fSKevin Lo for (i = 0; i < sc->nrxchains; i++) 6547453645fSAndriy Voskoboinyk rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xc00, val); 6557453645fSAndriy Voskoboinyk 6567453645fSAndriy Voskoboinyk /* Set Tx power for this new channel. */ 6577453645fSAndriy Voskoboinyk r12a_set_txpower(sc, c); 6587453645fSAndriy Voskoboinyk } 6597453645fSAndriy Voskoboinyk 6607453645fSAndriy Voskoboinyk void 6617453645fSAndriy Voskoboinyk r12a_set_band_2ghz(struct rtwn_softc *sc, uint32_t basicrates) 6627453645fSAndriy Voskoboinyk { 6637453645fSAndriy Voskoboinyk struct r12a_softc *rs = sc->sc_priv; 6647453645fSAndriy Voskoboinyk 6657453645fSAndriy Voskoboinyk /* Enable CCK / OFDM. */ 6667453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, 6677453645fSAndriy Voskoboinyk 0, R12A_OFDMCCK_EN_CCK | R12A_OFDMCCK_EN_OFDM); 6687453645fSAndriy Voskoboinyk 6697453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x02, 0x01); 6707453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2e000); 6717453645fSAndriy Voskoboinyk 6727453645fSAndriy Voskoboinyk /* Select AGC table. */ 6737453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0); 6747453645fSAndriy Voskoboinyk 6757453645fSAndriy Voskoboinyk switch (rs->rfe_type) { 6767453645fSAndriy Voskoboinyk case 0: 6777453645fSAndriy Voskoboinyk case 1: 6787453645fSAndriy Voskoboinyk case 2: 6797453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777); 6807453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); 6817453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0); 6827453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); 6837453645fSAndriy Voskoboinyk break; 6847453645fSAndriy Voskoboinyk case 3: 6857453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337770); 6867453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337770); 6877453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); 6887453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); 6897453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01); 6907453645fSAndriy Voskoboinyk break; 6917453645fSAndriy Voskoboinyk case 4: 6927453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777); 6937453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); 6947453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x00100000); 6957453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x00100000); 6967453645fSAndriy Voskoboinyk break; 6977453645fSAndriy Voskoboinyk case 5: 6987453645fSAndriy Voskoboinyk rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x77); 6997453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); 7007453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0x01, 0); 7017453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); 7027453645fSAndriy Voskoboinyk break; 7037453645fSAndriy Voskoboinyk default: 7047453645fSAndriy Voskoboinyk break; 7057453645fSAndriy Voskoboinyk } 7067453645fSAndriy Voskoboinyk 7077453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0x10); 7087453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0x0f000000, 0x01000000); 7097453645fSAndriy Voskoboinyk 7107453645fSAndriy Voskoboinyk /* Write basic rates. */ 7117453645fSAndriy Voskoboinyk rtwn_set_basicrates(sc, basicrates); 7127453645fSAndriy Voskoboinyk 7137453645fSAndriy Voskoboinyk rtwn_write_1(sc, R12A_CCK_CHECK, 0); 7147453645fSAndriy Voskoboinyk } 7157453645fSAndriy Voskoboinyk 7167453645fSAndriy Voskoboinyk void 7177453645fSAndriy Voskoboinyk r12a_set_band_5ghz(struct rtwn_softc *sc, uint32_t basicrates) 7187453645fSAndriy Voskoboinyk { 7197453645fSAndriy Voskoboinyk struct r12a_softc *rs = sc->sc_priv; 7207453645fSAndriy Voskoboinyk int ntries; 7217453645fSAndriy Voskoboinyk 7227453645fSAndriy Voskoboinyk rtwn_write_1(sc, R12A_CCK_CHECK, R12A_CCK_CHECK_5GHZ); 7237453645fSAndriy Voskoboinyk 7247453645fSAndriy Voskoboinyk for (ntries = 0; ntries < 100; ntries++) { 7257453645fSAndriy Voskoboinyk if ((rtwn_read_2(sc, R12A_TXPKT_EMPTY) & 0x30) == 0x30) 7267453645fSAndriy Voskoboinyk break; 7277453645fSAndriy Voskoboinyk 7287453645fSAndriy Voskoboinyk rtwn_delay(sc, 25); 7297453645fSAndriy Voskoboinyk } 7307453645fSAndriy Voskoboinyk if (ntries == 100) { 7317453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, 7327453645fSAndriy Voskoboinyk "%s: TXPKT_EMPTY check failed (%04X)\n", 7337453645fSAndriy Voskoboinyk __func__, rtwn_read_2(sc, R12A_TXPKT_EMPTY)); 7347453645fSAndriy Voskoboinyk } 7357453645fSAndriy Voskoboinyk 7367453645fSAndriy Voskoboinyk /* Enable OFDM. */ 7377453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, R12A_OFDMCCK_EN_CCK, 7387453645fSAndriy Voskoboinyk R12A_OFDMCCK_EN_OFDM); 7397453645fSAndriy Voskoboinyk 7407453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x01, 0x02); 7417453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2a000); 7427453645fSAndriy Voskoboinyk 7437453645fSAndriy Voskoboinyk /* Select AGC table. */ 7447453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0x01); 7457453645fSAndriy Voskoboinyk 7467453645fSAndriy Voskoboinyk switch (rs->rfe_type) { 7477453645fSAndriy Voskoboinyk case 0: 7487453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717); 7497453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717); 7507453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); 7517453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); 7527453645fSAndriy Voskoboinyk break; 7537453645fSAndriy Voskoboinyk case 1: 7547453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717); 7557453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717); 7567453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0); 7577453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); 7587453645fSAndriy Voskoboinyk break; 7597453645fSAndriy Voskoboinyk case 2: 7607453645fSAndriy Voskoboinyk case 4: 7617453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337777); 7627453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777); 7637453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); 7647453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); 7657453645fSAndriy Voskoboinyk break; 7667453645fSAndriy Voskoboinyk case 3: 7677453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337717); 7687453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337717); 7697453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); 7707453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); 7717453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01); 7727453645fSAndriy Voskoboinyk break; 7737453645fSAndriy Voskoboinyk case 5: 7747453645fSAndriy Voskoboinyk rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x33); 7757453645fSAndriy Voskoboinyk rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777); 7767453645fSAndriy Voskoboinyk rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0, 0x01); 7777453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); 7787453645fSAndriy Voskoboinyk break; 7797453645fSAndriy Voskoboinyk default: 7807453645fSAndriy Voskoboinyk break; 7817453645fSAndriy Voskoboinyk } 7827453645fSAndriy Voskoboinyk 7837453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0); 7847453645fSAndriy Voskoboinyk rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0, 0x0f000000); 7857453645fSAndriy Voskoboinyk 7867453645fSAndriy Voskoboinyk /* Write basic rates. */ 7877453645fSAndriy Voskoboinyk rtwn_set_basicrates(sc, basicrates); 7887453645fSAndriy Voskoboinyk } 789