xref: /freebsd-src/sys/dev/rtwn/rtl8812a/r12a_chan.c (revision 745a85824748e06b9b2ca4e9639ba13bbf9c08ca)
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