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
r12a_write_txpower_ht(struct rtwn_softc * sc,int chain,struct ieee80211_channel * c,uint8_t power[RTWN_RIDX_COUNT])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
r12a_write_txpower_vht(struct rtwn_softc * sc,int chain,struct ieee80211_channel * c,uint8_t power[RTWN_RIDX_COUNT])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
r12a_write_txpower_cck(struct rtwn_softc * sc,int chain,struct ieee80211_channel * c,uint8_t power[RTWN_RIDX_COUNT])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
r12a_write_txpower_ofdm(struct rtwn_softc * sc,int chain,struct ieee80211_channel * c,uint8_t power[RTWN_RIDX_COUNT])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
r12a_tx_power_training(struct rtwn_softc * sc,int chain,const struct ieee80211_channel * c,uint8_t power[RTWN_RIDX_COUNT])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
r12a_write_txpower(struct rtwn_softc * sc,int chain,struct ieee80211_channel * c,uint8_t power[RTWN_RIDX_COUNT])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
r12a_get_power_group(struct rtwn_softc * sc,struct ieee80211_channel * c)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
r12a_get_txpower(struct rtwn_softc * sc,int chain,struct ieee80211_channel * c,uint8_t power[RTWN_RIDX_COUNT])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
r12a_set_txpower(struct rtwn_softc * sc,struct ieee80211_channel * c)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
r12a_fix_spur(struct rtwn_softc * sc,struct ieee80211_channel * c)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
r12a_set_band(struct rtwn_softc * sc,struct ieee80211_channel * c)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
r12a_set_chan(struct rtwn_softc * sc,struct ieee80211_channel * c)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
r12a_set_band_2ghz(struct rtwn_softc * sc,uint32_t basicrates)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
r12a_set_band_5ghz(struct rtwn_softc * sc,uint32_t basicrates)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