xref: /freebsd/sys/dev/bwn/if_bwn_phy_g.c (revision d546e47aa0b57d0fe2370217df91aa5a921e6932)
1*d546e47aSAdrian Chadd /*-
2*d546e47aSAdrian Chadd  * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
3*d546e47aSAdrian Chadd  * All rights reserved.
4*d546e47aSAdrian Chadd  *
5*d546e47aSAdrian Chadd  * Redistribution and use in source and binary forms, with or without
6*d546e47aSAdrian Chadd  * modification, are permitted provided that the following conditions
7*d546e47aSAdrian Chadd  * are met:
8*d546e47aSAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
9*d546e47aSAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
10*d546e47aSAdrian Chadd  *    without modification.
11*d546e47aSAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12*d546e47aSAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13*d546e47aSAdrian Chadd  *    redistribution must be conditioned upon including a substantially
14*d546e47aSAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
15*d546e47aSAdrian Chadd  *
16*d546e47aSAdrian Chadd  * NO WARRANTY
17*d546e47aSAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*d546e47aSAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*d546e47aSAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20*d546e47aSAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21*d546e47aSAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22*d546e47aSAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*d546e47aSAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*d546e47aSAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*d546e47aSAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*d546e47aSAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27*d546e47aSAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
28*d546e47aSAdrian Chadd  */
29*d546e47aSAdrian Chadd 
30*d546e47aSAdrian Chadd #include <sys/cdefs.h>
31*d546e47aSAdrian Chadd __FBSDID("$FreeBSD$");
32*d546e47aSAdrian Chadd 
33*d546e47aSAdrian Chadd /*
34*d546e47aSAdrian Chadd  * The Broadcom Wireless LAN controller driver.
35*d546e47aSAdrian Chadd  */
36*d546e47aSAdrian Chadd 
37*d546e47aSAdrian Chadd #include <sys/param.h>
38*d546e47aSAdrian Chadd #include <sys/systm.h>
39*d546e47aSAdrian Chadd #include <sys/kernel.h>
40*d546e47aSAdrian Chadd #include <sys/malloc.h>
41*d546e47aSAdrian Chadd #include <sys/module.h>
42*d546e47aSAdrian Chadd #include <sys/endian.h>
43*d546e47aSAdrian Chadd #include <sys/errno.h>
44*d546e47aSAdrian Chadd #include <sys/firmware.h>
45*d546e47aSAdrian Chadd #include <sys/lock.h>
46*d546e47aSAdrian Chadd #include <sys/mutex.h>
47*d546e47aSAdrian Chadd #include <machine/bus.h>
48*d546e47aSAdrian Chadd #include <machine/resource.h>
49*d546e47aSAdrian Chadd #include <sys/bus.h>
50*d546e47aSAdrian Chadd #include <sys/rman.h>
51*d546e47aSAdrian Chadd #include <sys/socket.h>
52*d546e47aSAdrian Chadd #include <sys/sockio.h>
53*d546e47aSAdrian Chadd 
54*d546e47aSAdrian Chadd #include <net/ethernet.h>
55*d546e47aSAdrian Chadd #include <net/if.h>
56*d546e47aSAdrian Chadd #include <net/if_var.h>
57*d546e47aSAdrian Chadd #include <net/if_arp.h>
58*d546e47aSAdrian Chadd #include <net/if_dl.h>
59*d546e47aSAdrian Chadd #include <net/if_llc.h>
60*d546e47aSAdrian Chadd #include <net/if_media.h>
61*d546e47aSAdrian Chadd #include <net/if_types.h>
62*d546e47aSAdrian Chadd 
63*d546e47aSAdrian Chadd #include <dev/pci/pcivar.h>
64*d546e47aSAdrian Chadd #include <dev/pci/pcireg.h>
65*d546e47aSAdrian Chadd #include <dev/siba/siba_ids.h>
66*d546e47aSAdrian Chadd #include <dev/siba/sibareg.h>
67*d546e47aSAdrian Chadd #include <dev/siba/sibavar.h>
68*d546e47aSAdrian Chadd 
69*d546e47aSAdrian Chadd #include <net80211/ieee80211_var.h>
70*d546e47aSAdrian Chadd #include <net80211/ieee80211_radiotap.h>
71*d546e47aSAdrian Chadd #include <net80211/ieee80211_regdomain.h>
72*d546e47aSAdrian Chadd #include <net80211/ieee80211_phy.h>
73*d546e47aSAdrian Chadd #include <net80211/ieee80211_ratectl.h>
74*d546e47aSAdrian Chadd 
75*d546e47aSAdrian Chadd #include <dev/bwn/if_bwnreg.h>
76*d546e47aSAdrian Chadd #include <dev/bwn/if_bwnvar.h>
77*d546e47aSAdrian Chadd 
78*d546e47aSAdrian Chadd #include <dev/bwn/if_bwn_debug.h>
79*d546e47aSAdrian Chadd #include <dev/bwn/if_bwn_misc.h>
80*d546e47aSAdrian Chadd #include <dev/bwn/if_bwn_phy_g.h>
81*d546e47aSAdrian Chadd 
82*d546e47aSAdrian Chadd static void	bwn_phy_g_init_sub(struct bwn_mac *);
83*d546e47aSAdrian Chadd static uint8_t	bwn_has_hwpctl(struct bwn_mac *);
84*d546e47aSAdrian Chadd static void	bwn_phy_init_b5(struct bwn_mac *);
85*d546e47aSAdrian Chadd static void	bwn_phy_init_b6(struct bwn_mac *);
86*d546e47aSAdrian Chadd static void	bwn_phy_init_a(struct bwn_mac *);
87*d546e47aSAdrian Chadd static void	bwn_loopback_calcgain(struct bwn_mac *);
88*d546e47aSAdrian Chadd static uint16_t	bwn_rf_init_bcm2050(struct bwn_mac *);
89*d546e47aSAdrian Chadd static void	bwn_lo_g_init(struct bwn_mac *);
90*d546e47aSAdrian Chadd static void	bwn_lo_g_adjust(struct bwn_mac *);
91*d546e47aSAdrian Chadd static void	bwn_lo_get_powervector(struct bwn_mac *);
92*d546e47aSAdrian Chadd static struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
93*d546e47aSAdrian Chadd 		    const struct bwn_bbatt *, const struct bwn_rfatt *);
94*d546e47aSAdrian Chadd static void	bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
95*d546e47aSAdrian Chadd static void	bwn_phy_hwpctl_init(struct bwn_mac *);
96*d546e47aSAdrian Chadd static void	bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
97*d546e47aSAdrian Chadd static void	bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
98*d546e47aSAdrian Chadd 		    const struct bwn_bbatt *, const struct bwn_rfatt *,
99*d546e47aSAdrian Chadd 		    uint8_t);
100*d546e47aSAdrian Chadd static void	bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
101*d546e47aSAdrian Chadd static uint16_t	bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
102*d546e47aSAdrian Chadd static void	bwn_spu_workaround(struct bwn_mac *, uint8_t);
103*d546e47aSAdrian Chadd static void	bwn_wa_init(struct bwn_mac *);
104*d546e47aSAdrian Chadd static void	bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
105*d546e47aSAdrian Chadd 		    uint16_t);
106*d546e47aSAdrian Chadd static void	bwn_dummy_transmission(struct bwn_mac *, int, int);
107*d546e47aSAdrian Chadd static void	bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
108*d546e47aSAdrian Chadd 		    uint32_t);
109*d546e47aSAdrian Chadd static void	bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
110*d546e47aSAdrian Chadd 		    uint16_t);
111*d546e47aSAdrian Chadd static int16_t	bwn_nrssi_read(struct bwn_mac *, uint16_t);
112*d546e47aSAdrian Chadd static void	bwn_nrssi_offset(struct bwn_mac *);
113*d546e47aSAdrian Chadd static void	bwn_nrssi_threshold(struct bwn_mac *);
114*d546e47aSAdrian Chadd static void	bwn_nrssi_slope_11g(struct bwn_mac *);
115*d546e47aSAdrian Chadd static void	bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
116*d546e47aSAdrian Chadd 		    int16_t);
117*d546e47aSAdrian Chadd static void	bwn_set_original_gains(struct bwn_mac *);
118*d546e47aSAdrian Chadd static void	bwn_hwpctl_early_init(struct bwn_mac *);
119*d546e47aSAdrian Chadd static void	bwn_hwpctl_init_gphy(struct bwn_mac *);
120*d546e47aSAdrian Chadd static uint16_t	bwn_phy_g_chan2freq(uint8_t);
121*d546e47aSAdrian Chadd static void	bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
122*d546e47aSAdrian Chadd 
123*d546e47aSAdrian Chadd /* Stuff we need */
124*d546e47aSAdrian Chadd 
125*d546e47aSAdrian Chadd static uint16_t	bwn_phy_g_txctl(struct bwn_mac *mac);
126*d546e47aSAdrian Chadd static int	bwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset);
127*d546e47aSAdrian Chadd static void	bwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp);
128*d546e47aSAdrian Chadd static void	bwn_phy_lock(struct bwn_mac *mac);
129*d546e47aSAdrian Chadd static void	bwn_phy_unlock(struct bwn_mac *mac);
130*d546e47aSAdrian Chadd static void	bwn_rf_lock(struct bwn_mac *mac);
131*d546e47aSAdrian Chadd static void	bwn_rf_unlock(struct bwn_mac *mac);
132*d546e47aSAdrian Chadd 
133*d546e47aSAdrian Chadd static const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
134*d546e47aSAdrian Chadd static const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
135*d546e47aSAdrian Chadd static const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
136*d546e47aSAdrian Chadd static const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
137*d546e47aSAdrian Chadd static const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
138*d546e47aSAdrian Chadd const uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
139*d546e47aSAdrian Chadd 
140*d546e47aSAdrian Chadd static uint8_t
141*d546e47aSAdrian Chadd bwn_has_hwpctl(struct bwn_mac *mac)
142*d546e47aSAdrian Chadd {
143*d546e47aSAdrian Chadd 
144*d546e47aSAdrian Chadd 	if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
145*d546e47aSAdrian Chadd 		return (0);
146*d546e47aSAdrian Chadd 	return (mac->mac_phy.use_hwpctl(mac));
147*d546e47aSAdrian Chadd }
148*d546e47aSAdrian Chadd 
149*d546e47aSAdrian Chadd int
150*d546e47aSAdrian Chadd bwn_phy_g_attach(struct bwn_mac *mac)
151*d546e47aSAdrian Chadd {
152*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
153*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
154*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
155*d546e47aSAdrian Chadd 	unsigned int i;
156*d546e47aSAdrian Chadd 	int16_t pab0, pab1, pab2;
157*d546e47aSAdrian Chadd 	static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
158*d546e47aSAdrian Chadd 	int8_t bg;
159*d546e47aSAdrian Chadd 
160*d546e47aSAdrian Chadd 	bg = (int8_t)siba_sprom_get_tssi_bg(sc->sc_dev);
161*d546e47aSAdrian Chadd 	pab0 = (int16_t)siba_sprom_get_pa0b0(sc->sc_dev);
162*d546e47aSAdrian Chadd 	pab1 = (int16_t)siba_sprom_get_pa0b1(sc->sc_dev);
163*d546e47aSAdrian Chadd 	pab2 = (int16_t)siba_sprom_get_pa0b2(sc->sc_dev);
164*d546e47aSAdrian Chadd 
165*d546e47aSAdrian Chadd 	if ((siba_get_chipid(sc->sc_dev) == 0x4301) && (phy->rf_ver != 0x2050))
166*d546e47aSAdrian Chadd 		device_printf(sc->sc_dev, "not supported anymore\n");
167*d546e47aSAdrian Chadd 
168*d546e47aSAdrian Chadd 	pg->pg_flags = 0;
169*d546e47aSAdrian Chadd 	if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
170*d546e47aSAdrian Chadd 	    pab2 == -1) {
171*d546e47aSAdrian Chadd 		pg->pg_idletssi = 52;
172*d546e47aSAdrian Chadd 		pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
173*d546e47aSAdrian Chadd 		return (0);
174*d546e47aSAdrian Chadd 	}
175*d546e47aSAdrian Chadd 
176*d546e47aSAdrian Chadd 	pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
177*d546e47aSAdrian Chadd 	pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
178*d546e47aSAdrian Chadd 	if (pg->pg_tssi2dbm == NULL) {
179*d546e47aSAdrian Chadd 		device_printf(sc->sc_dev, "failed to allocate buffer\n");
180*d546e47aSAdrian Chadd 		return (ENOMEM);
181*d546e47aSAdrian Chadd 	}
182*d546e47aSAdrian Chadd 	for (i = 0; i < 64; i++) {
183*d546e47aSAdrian Chadd 		int32_t m1, m2, f, q, delta;
184*d546e47aSAdrian Chadd 		int8_t j = 0;
185*d546e47aSAdrian Chadd 
186*d546e47aSAdrian Chadd 		m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
187*d546e47aSAdrian Chadd 		m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
188*d546e47aSAdrian Chadd 		f = 256;
189*d546e47aSAdrian Chadd 
190*d546e47aSAdrian Chadd 		do {
191*d546e47aSAdrian Chadd 			if (j > 15) {
192*d546e47aSAdrian Chadd 				device_printf(sc->sc_dev,
193*d546e47aSAdrian Chadd 				    "failed to generate tssi2dBm\n");
194*d546e47aSAdrian Chadd 				free(pg->pg_tssi2dbm, M_DEVBUF);
195*d546e47aSAdrian Chadd 				return (ENOMEM);
196*d546e47aSAdrian Chadd 			}
197*d546e47aSAdrian Chadd 			q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
198*d546e47aSAdrian Chadd 			    f, 2048);
199*d546e47aSAdrian Chadd 			delta = abs(q - f);
200*d546e47aSAdrian Chadd 			f = q;
201*d546e47aSAdrian Chadd 			j++;
202*d546e47aSAdrian Chadd 		} while (delta >= 2);
203*d546e47aSAdrian Chadd 
204*d546e47aSAdrian Chadd 		pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
205*d546e47aSAdrian Chadd 		    128);
206*d546e47aSAdrian Chadd 	}
207*d546e47aSAdrian Chadd 
208*d546e47aSAdrian Chadd 	pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
209*d546e47aSAdrian Chadd 	return (0);
210*d546e47aSAdrian Chadd }
211*d546e47aSAdrian Chadd 
212*d546e47aSAdrian Chadd void
213*d546e47aSAdrian Chadd bwn_phy_g_detach(struct bwn_mac *mac)
214*d546e47aSAdrian Chadd {
215*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
216*d546e47aSAdrian Chadd 
217*d546e47aSAdrian Chadd 	if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
218*d546e47aSAdrian Chadd 		free(pg->pg_tssi2dbm, M_DEVBUF);
219*d546e47aSAdrian Chadd 		pg->pg_tssi2dbm = NULL;
220*d546e47aSAdrian Chadd 	}
221*d546e47aSAdrian Chadd 	pg->pg_flags = 0;
222*d546e47aSAdrian Chadd }
223*d546e47aSAdrian Chadd 
224*d546e47aSAdrian Chadd void
225*d546e47aSAdrian Chadd bwn_phy_g_init_pre(struct bwn_mac *mac)
226*d546e47aSAdrian Chadd {
227*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
228*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
229*d546e47aSAdrian Chadd 	void *tssi2dbm;
230*d546e47aSAdrian Chadd 	int idletssi;
231*d546e47aSAdrian Chadd 	unsigned int i;
232*d546e47aSAdrian Chadd 
233*d546e47aSAdrian Chadd 	tssi2dbm = pg->pg_tssi2dbm;
234*d546e47aSAdrian Chadd 	idletssi = pg->pg_idletssi;
235*d546e47aSAdrian Chadd 
236*d546e47aSAdrian Chadd 	memset(pg, 0, sizeof(*pg));
237*d546e47aSAdrian Chadd 
238*d546e47aSAdrian Chadd 	pg->pg_tssi2dbm = tssi2dbm;
239*d546e47aSAdrian Chadd 	pg->pg_idletssi = idletssi;
240*d546e47aSAdrian Chadd 
241*d546e47aSAdrian Chadd 	memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
242*d546e47aSAdrian Chadd 
243*d546e47aSAdrian Chadd 	for (i = 0; i < N(pg->pg_nrssi); i++)
244*d546e47aSAdrian Chadd 		pg->pg_nrssi[i] = -1000;
245*d546e47aSAdrian Chadd 	for (i = 0; i < N(pg->pg_nrssi_lt); i++)
246*d546e47aSAdrian Chadd 		pg->pg_nrssi_lt[i] = i;
247*d546e47aSAdrian Chadd 	pg->pg_lofcal = 0xffff;
248*d546e47aSAdrian Chadd 	pg->pg_initval = 0xffff;
249*d546e47aSAdrian Chadd 	pg->pg_immode = BWN_IMMODE_NONE;
250*d546e47aSAdrian Chadd 	pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
251*d546e47aSAdrian Chadd 	pg->pg_avgtssi = 0xff;
252*d546e47aSAdrian Chadd 
253*d546e47aSAdrian Chadd 	pg->pg_loctl.tx_bias = 0xff;
254*d546e47aSAdrian Chadd 	TAILQ_INIT(&pg->pg_loctl.calib_list);
255*d546e47aSAdrian Chadd }
256*d546e47aSAdrian Chadd 
257*d546e47aSAdrian Chadd int
258*d546e47aSAdrian Chadd bwn_phy_g_prepare_hw(struct bwn_mac *mac)
259*d546e47aSAdrian Chadd {
260*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
261*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
262*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
263*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
264*d546e47aSAdrian Chadd 	static const struct bwn_rfatt rfatt0[] = {
265*d546e47aSAdrian Chadd 		{ 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 },	{ 9, 0 }, { 2, 0 },
266*d546e47aSAdrian Chadd 		{ 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
267*d546e47aSAdrian Chadd 		{ 3, 1 }, { 4, 1 }
268*d546e47aSAdrian Chadd 	};
269*d546e47aSAdrian Chadd 	static const struct bwn_rfatt rfatt1[] = {
270*d546e47aSAdrian Chadd 		{ 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
271*d546e47aSAdrian Chadd 		{ 14, 1 }
272*d546e47aSAdrian Chadd 	};
273*d546e47aSAdrian Chadd 	static const struct bwn_rfatt rfatt2[] = {
274*d546e47aSAdrian Chadd 		{ 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
275*d546e47aSAdrian Chadd 		{ 9, 1 }
276*d546e47aSAdrian Chadd 	};
277*d546e47aSAdrian Chadd 	static const struct bwn_bbatt bbatt_0[] = {
278*d546e47aSAdrian Chadd 		{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
279*d546e47aSAdrian Chadd 	};
280*d546e47aSAdrian Chadd 
281*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
282*d546e47aSAdrian Chadd 
283*d546e47aSAdrian Chadd 	if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
284*d546e47aSAdrian Chadd 		pg->pg_bbatt.att = 0;
285*d546e47aSAdrian Chadd 	else
286*d546e47aSAdrian Chadd 		pg->pg_bbatt.att = 2;
287*d546e47aSAdrian Chadd 
288*d546e47aSAdrian Chadd 	/* prepare Radio Attenuation */
289*d546e47aSAdrian Chadd 	pg->pg_rfatt.padmix = 0;
290*d546e47aSAdrian Chadd 
291*d546e47aSAdrian Chadd 	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
292*d546e47aSAdrian Chadd 	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BCM4309G) {
293*d546e47aSAdrian Chadd 		if (siba_get_pci_revid(sc->sc_dev) < 0x43) {
294*d546e47aSAdrian Chadd 			pg->pg_rfatt.att = 2;
295*d546e47aSAdrian Chadd 			goto done;
296*d546e47aSAdrian Chadd 		} else if (siba_get_pci_revid(sc->sc_dev) < 0x51) {
297*d546e47aSAdrian Chadd 			pg->pg_rfatt.att = 3;
298*d546e47aSAdrian Chadd 			goto done;
299*d546e47aSAdrian Chadd 		}
300*d546e47aSAdrian Chadd 	}
301*d546e47aSAdrian Chadd 
302*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_A) {
303*d546e47aSAdrian Chadd 		pg->pg_rfatt.att = 0x60;
304*d546e47aSAdrian Chadd 		goto done;
305*d546e47aSAdrian Chadd 	}
306*d546e47aSAdrian Chadd 
307*d546e47aSAdrian Chadd 	switch (phy->rf_ver) {
308*d546e47aSAdrian Chadd 	case 0x2050:
309*d546e47aSAdrian Chadd 		switch (phy->rf_rev) {
310*d546e47aSAdrian Chadd 		case 0:
311*d546e47aSAdrian Chadd 			pg->pg_rfatt.att = 5;
312*d546e47aSAdrian Chadd 			goto done;
313*d546e47aSAdrian Chadd 		case 1:
314*d546e47aSAdrian Chadd 			if (phy->type == BWN_PHYTYPE_G) {
315*d546e47aSAdrian Chadd 				if (siba_get_pci_subvendor(sc->sc_dev) ==
316*d546e47aSAdrian Chadd 				    SIBA_BOARDVENDOR_BCM &&
317*d546e47aSAdrian Chadd 				    siba_get_pci_subdevice(sc->sc_dev) ==
318*d546e47aSAdrian Chadd 				    SIBA_BOARD_BCM4309G &&
319*d546e47aSAdrian Chadd 				    siba_get_pci_revid(sc->sc_dev) >= 30)
320*d546e47aSAdrian Chadd 					pg->pg_rfatt.att = 3;
321*d546e47aSAdrian Chadd 				else if (siba_get_pci_subvendor(sc->sc_dev) ==
322*d546e47aSAdrian Chadd 				    SIBA_BOARDVENDOR_BCM &&
323*d546e47aSAdrian Chadd 				    siba_get_pci_subdevice(sc->sc_dev) ==
324*d546e47aSAdrian Chadd 				    SIBA_BOARD_BU4306)
325*d546e47aSAdrian Chadd 					pg->pg_rfatt.att = 3;
326*d546e47aSAdrian Chadd 				else
327*d546e47aSAdrian Chadd 					pg->pg_rfatt.att = 1;
328*d546e47aSAdrian Chadd 			} else {
329*d546e47aSAdrian Chadd 				if (siba_get_pci_subvendor(sc->sc_dev) ==
330*d546e47aSAdrian Chadd 				    SIBA_BOARDVENDOR_BCM &&
331*d546e47aSAdrian Chadd 				    siba_get_pci_subdevice(sc->sc_dev) ==
332*d546e47aSAdrian Chadd 				    SIBA_BOARD_BCM4309G &&
333*d546e47aSAdrian Chadd 				    siba_get_pci_revid(sc->sc_dev) >= 30)
334*d546e47aSAdrian Chadd 					pg->pg_rfatt.att = 7;
335*d546e47aSAdrian Chadd 				else
336*d546e47aSAdrian Chadd 					pg->pg_rfatt.att = 6;
337*d546e47aSAdrian Chadd 			}
338*d546e47aSAdrian Chadd 			goto done;
339*d546e47aSAdrian Chadd 		case 2:
340*d546e47aSAdrian Chadd 			if (phy->type == BWN_PHYTYPE_G) {
341*d546e47aSAdrian Chadd 				if (siba_get_pci_subvendor(sc->sc_dev) ==
342*d546e47aSAdrian Chadd 				    SIBA_BOARDVENDOR_BCM &&
343*d546e47aSAdrian Chadd 				    siba_get_pci_subdevice(sc->sc_dev) ==
344*d546e47aSAdrian Chadd 				    SIBA_BOARD_BCM4309G &&
345*d546e47aSAdrian Chadd 				    siba_get_pci_revid(sc->sc_dev) >= 30)
346*d546e47aSAdrian Chadd 					pg->pg_rfatt.att = 3;
347*d546e47aSAdrian Chadd 				else if (siba_get_pci_subvendor(sc->sc_dev) ==
348*d546e47aSAdrian Chadd 				    SIBA_BOARDVENDOR_BCM &&
349*d546e47aSAdrian Chadd 				    siba_get_pci_subdevice(sc->sc_dev) ==
350*d546e47aSAdrian Chadd 				    SIBA_BOARD_BU4306)
351*d546e47aSAdrian Chadd 					pg->pg_rfatt.att = 5;
352*d546e47aSAdrian Chadd 				else if (siba_get_chipid(sc->sc_dev) == 0x4320)
353*d546e47aSAdrian Chadd 					pg->pg_rfatt.att = 4;
354*d546e47aSAdrian Chadd 				else
355*d546e47aSAdrian Chadd 					pg->pg_rfatt.att = 3;
356*d546e47aSAdrian Chadd 			} else
357*d546e47aSAdrian Chadd 				pg->pg_rfatt.att = 6;
358*d546e47aSAdrian Chadd 			goto done;
359*d546e47aSAdrian Chadd 		case 3:
360*d546e47aSAdrian Chadd 			pg->pg_rfatt.att = 5;
361*d546e47aSAdrian Chadd 			goto done;
362*d546e47aSAdrian Chadd 		case 4:
363*d546e47aSAdrian Chadd 		case 5:
364*d546e47aSAdrian Chadd 			pg->pg_rfatt.att = 1;
365*d546e47aSAdrian Chadd 			goto done;
366*d546e47aSAdrian Chadd 		case 6:
367*d546e47aSAdrian Chadd 		case 7:
368*d546e47aSAdrian Chadd 			pg->pg_rfatt.att = 5;
369*d546e47aSAdrian Chadd 			goto done;
370*d546e47aSAdrian Chadd 		case 8:
371*d546e47aSAdrian Chadd 			pg->pg_rfatt.att = 0xa;
372*d546e47aSAdrian Chadd 			pg->pg_rfatt.padmix = 1;
373*d546e47aSAdrian Chadd 			goto done;
374*d546e47aSAdrian Chadd 		case 9:
375*d546e47aSAdrian Chadd 		default:
376*d546e47aSAdrian Chadd 			pg->pg_rfatt.att = 5;
377*d546e47aSAdrian Chadd 			goto done;
378*d546e47aSAdrian Chadd 		}
379*d546e47aSAdrian Chadd 		break;
380*d546e47aSAdrian Chadd 	case 0x2053:
381*d546e47aSAdrian Chadd 		switch (phy->rf_rev) {
382*d546e47aSAdrian Chadd 		case 1:
383*d546e47aSAdrian Chadd 			pg->pg_rfatt.att = 6;
384*d546e47aSAdrian Chadd 			goto done;
385*d546e47aSAdrian Chadd 		}
386*d546e47aSAdrian Chadd 		break;
387*d546e47aSAdrian Chadd 	}
388*d546e47aSAdrian Chadd 	pg->pg_rfatt.att = 5;
389*d546e47aSAdrian Chadd done:
390*d546e47aSAdrian Chadd 	pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
391*d546e47aSAdrian Chadd 
392*d546e47aSAdrian Chadd 	if (!bwn_has_hwpctl(mac)) {
393*d546e47aSAdrian Chadd 		lo->rfatt.array = rfatt0;
394*d546e47aSAdrian Chadd 		lo->rfatt.len = N(rfatt0);
395*d546e47aSAdrian Chadd 		lo->rfatt.min = 0;
396*d546e47aSAdrian Chadd 		lo->rfatt.max = 9;
397*d546e47aSAdrian Chadd 		goto genbbatt;
398*d546e47aSAdrian Chadd 	}
399*d546e47aSAdrian Chadd 	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
400*d546e47aSAdrian Chadd 		lo->rfatt.array = rfatt1;
401*d546e47aSAdrian Chadd 		lo->rfatt.len = N(rfatt1);
402*d546e47aSAdrian Chadd 		lo->rfatt.min = 0;
403*d546e47aSAdrian Chadd 		lo->rfatt.max = 14;
404*d546e47aSAdrian Chadd 		goto genbbatt;
405*d546e47aSAdrian Chadd 	}
406*d546e47aSAdrian Chadd 	lo->rfatt.array = rfatt2;
407*d546e47aSAdrian Chadd 	lo->rfatt.len = N(rfatt2);
408*d546e47aSAdrian Chadd 	lo->rfatt.min = 0;
409*d546e47aSAdrian Chadd 	lo->rfatt.max = 9;
410*d546e47aSAdrian Chadd genbbatt:
411*d546e47aSAdrian Chadd 	lo->bbatt.array = bbatt_0;
412*d546e47aSAdrian Chadd 	lo->bbatt.len = N(bbatt_0);
413*d546e47aSAdrian Chadd 	lo->bbatt.min = 0;
414*d546e47aSAdrian Chadd 	lo->bbatt.max = 8;
415*d546e47aSAdrian Chadd 
416*d546e47aSAdrian Chadd 	BWN_READ_4(mac, BWN_MACCTL);
417*d546e47aSAdrian Chadd 	if (phy->rev == 1) {
418*d546e47aSAdrian Chadd 		phy->gmode = 0;
419*d546e47aSAdrian Chadd 		bwn_reset_core(mac, 0);
420*d546e47aSAdrian Chadd 		bwn_phy_g_init_sub(mac);
421*d546e47aSAdrian Chadd 		phy->gmode = 1;
422*d546e47aSAdrian Chadd 		bwn_reset_core(mac, BWN_TGSLOW_SUPPORT_G);
423*d546e47aSAdrian Chadd 	}
424*d546e47aSAdrian Chadd 	return (0);
425*d546e47aSAdrian Chadd }
426*d546e47aSAdrian Chadd 
427*d546e47aSAdrian Chadd static uint16_t
428*d546e47aSAdrian Chadd bwn_phy_g_txctl(struct bwn_mac *mac)
429*d546e47aSAdrian Chadd {
430*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
431*d546e47aSAdrian Chadd 
432*d546e47aSAdrian Chadd 	if (phy->rf_ver != 0x2050)
433*d546e47aSAdrian Chadd 		return (0);
434*d546e47aSAdrian Chadd 	if (phy->rf_rev == 1)
435*d546e47aSAdrian Chadd 		return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
436*d546e47aSAdrian Chadd 	if (phy->rf_rev < 6)
437*d546e47aSAdrian Chadd 		return (BWN_TXCTL_PA2DB);
438*d546e47aSAdrian Chadd 	if (phy->rf_rev == 8)
439*d546e47aSAdrian Chadd 		return (BWN_TXCTL_TXMIX);
440*d546e47aSAdrian Chadd 	return (0);
441*d546e47aSAdrian Chadd }
442*d546e47aSAdrian Chadd 
443*d546e47aSAdrian Chadd int
444*d546e47aSAdrian Chadd bwn_phy_g_init(struct bwn_mac *mac)
445*d546e47aSAdrian Chadd {
446*d546e47aSAdrian Chadd 
447*d546e47aSAdrian Chadd 	bwn_phy_g_init_sub(mac);
448*d546e47aSAdrian Chadd 	return (0);
449*d546e47aSAdrian Chadd }
450*d546e47aSAdrian Chadd 
451*d546e47aSAdrian Chadd void
452*d546e47aSAdrian Chadd bwn_phy_g_exit(struct bwn_mac *mac)
453*d546e47aSAdrian Chadd {
454*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
455*d546e47aSAdrian Chadd 	struct bwn_lo_calib *cal, *tmp;
456*d546e47aSAdrian Chadd 
457*d546e47aSAdrian Chadd 	if (lo == NULL)
458*d546e47aSAdrian Chadd 		return;
459*d546e47aSAdrian Chadd 	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
460*d546e47aSAdrian Chadd 		TAILQ_REMOVE(&lo->calib_list, cal, list);
461*d546e47aSAdrian Chadd 		free(cal, M_DEVBUF);
462*d546e47aSAdrian Chadd 	}
463*d546e47aSAdrian Chadd }
464*d546e47aSAdrian Chadd 
465*d546e47aSAdrian Chadd uint16_t
466*d546e47aSAdrian Chadd bwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
467*d546e47aSAdrian Chadd {
468*d546e47aSAdrian Chadd 
469*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
470*d546e47aSAdrian Chadd 	return (BWN_READ_2(mac, BWN_PHYDATA));
471*d546e47aSAdrian Chadd }
472*d546e47aSAdrian Chadd 
473*d546e47aSAdrian Chadd void
474*d546e47aSAdrian Chadd bwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
475*d546e47aSAdrian Chadd {
476*d546e47aSAdrian Chadd 
477*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
478*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_PHYDATA, value);
479*d546e47aSAdrian Chadd }
480*d546e47aSAdrian Chadd 
481*d546e47aSAdrian Chadd uint16_t
482*d546e47aSAdrian Chadd bwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
483*d546e47aSAdrian Chadd {
484*d546e47aSAdrian Chadd 
485*d546e47aSAdrian Chadd 	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
486*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
487*d546e47aSAdrian Chadd 	return (BWN_READ_2(mac, BWN_RFDATALO));
488*d546e47aSAdrian Chadd }
489*d546e47aSAdrian Chadd 
490*d546e47aSAdrian Chadd void
491*d546e47aSAdrian Chadd bwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
492*d546e47aSAdrian Chadd {
493*d546e47aSAdrian Chadd 
494*d546e47aSAdrian Chadd 	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
495*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_RFCTL, reg);
496*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_RFDATALO, value);
497*d546e47aSAdrian Chadd }
498*d546e47aSAdrian Chadd 
499*d546e47aSAdrian Chadd int
500*d546e47aSAdrian Chadd bwn_phy_g_hwpctl(struct bwn_mac *mac)
501*d546e47aSAdrian Chadd {
502*d546e47aSAdrian Chadd 
503*d546e47aSAdrian Chadd 	return (mac->mac_phy.rev >= 6);
504*d546e47aSAdrian Chadd }
505*d546e47aSAdrian Chadd 
506*d546e47aSAdrian Chadd void
507*d546e47aSAdrian Chadd bwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
508*d546e47aSAdrian Chadd {
509*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
510*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
511*d546e47aSAdrian Chadd 	unsigned int channel;
512*d546e47aSAdrian Chadd 	uint16_t rfover, rfoverval;
513*d546e47aSAdrian Chadd 
514*d546e47aSAdrian Chadd 	if (on) {
515*d546e47aSAdrian Chadd 		if (phy->rf_on)
516*d546e47aSAdrian Chadd 			return;
517*d546e47aSAdrian Chadd 
518*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x15, 0x8000);
519*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x15, 0xcc00);
520*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
521*d546e47aSAdrian Chadd 		if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
522*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
523*d546e47aSAdrian Chadd 			    pg->pg_radioctx_over);
524*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
525*d546e47aSAdrian Chadd 			    pg->pg_radioctx_overval);
526*d546e47aSAdrian Chadd 			pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
527*d546e47aSAdrian Chadd 		}
528*d546e47aSAdrian Chadd 		channel = phy->chan;
529*d546e47aSAdrian Chadd 		bwn_phy_g_switch_chan(mac, 6, 1);
530*d546e47aSAdrian Chadd 		bwn_phy_g_switch_chan(mac, channel, 0);
531*d546e47aSAdrian Chadd 		return;
532*d546e47aSAdrian Chadd 	}
533*d546e47aSAdrian Chadd 
534*d546e47aSAdrian Chadd 	rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
535*d546e47aSAdrian Chadd 	rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
536*d546e47aSAdrian Chadd 	pg->pg_radioctx_over = rfover;
537*d546e47aSAdrian Chadd 	pg->pg_radioctx_overval = rfoverval;
538*d546e47aSAdrian Chadd 	pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
539*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
540*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
541*d546e47aSAdrian Chadd }
542*d546e47aSAdrian Chadd 
543*d546e47aSAdrian Chadd int
544*d546e47aSAdrian Chadd bwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
545*d546e47aSAdrian Chadd {
546*d546e47aSAdrian Chadd 
547*d546e47aSAdrian Chadd 	if ((newchan < 1) || (newchan > 14))
548*d546e47aSAdrian Chadd 		return (EINVAL);
549*d546e47aSAdrian Chadd 	bwn_phy_g_switch_chan(mac, newchan, 0);
550*d546e47aSAdrian Chadd 
551*d546e47aSAdrian Chadd 	return (0);
552*d546e47aSAdrian Chadd }
553*d546e47aSAdrian Chadd 
554*d546e47aSAdrian Chadd uint32_t
555*d546e47aSAdrian Chadd bwn_phy_g_get_default_chan(struct bwn_mac *mac)
556*d546e47aSAdrian Chadd {
557*d546e47aSAdrian Chadd 
558*d546e47aSAdrian Chadd 	return (1);
559*d546e47aSAdrian Chadd }
560*d546e47aSAdrian Chadd 
561*d546e47aSAdrian Chadd void
562*d546e47aSAdrian Chadd bwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
563*d546e47aSAdrian Chadd {
564*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
565*d546e47aSAdrian Chadd 	uint64_t hf;
566*d546e47aSAdrian Chadd 	int autodiv = 0;
567*d546e47aSAdrian Chadd 	uint16_t tmp;
568*d546e47aSAdrian Chadd 
569*d546e47aSAdrian Chadd 	if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
570*d546e47aSAdrian Chadd 		autodiv = 1;
571*d546e47aSAdrian Chadd 
572*d546e47aSAdrian Chadd 	hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
573*d546e47aSAdrian Chadd 	bwn_hf_write(mac, hf);
574*d546e47aSAdrian Chadd 
575*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
576*d546e47aSAdrian Chadd 	    (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
577*d546e47aSAdrian Chadd 	    ((autodiv ? BWN_ANTAUTO1 : antenna)
578*d546e47aSAdrian Chadd 		<< BWN_PHY_BBANDCFG_RXANT_SHIFT));
579*d546e47aSAdrian Chadd 
580*d546e47aSAdrian Chadd 	if (autodiv) {
581*d546e47aSAdrian Chadd 		tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
582*d546e47aSAdrian Chadd 		if (antenna == BWN_ANTAUTO1)
583*d546e47aSAdrian Chadd 			tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
584*d546e47aSAdrian Chadd 		else
585*d546e47aSAdrian Chadd 			tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
586*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
587*d546e47aSAdrian Chadd 	}
588*d546e47aSAdrian Chadd 	tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
589*d546e47aSAdrian Chadd 	if (autodiv)
590*d546e47aSAdrian Chadd 		tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
591*d546e47aSAdrian Chadd 	else
592*d546e47aSAdrian Chadd 		tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
593*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
594*d546e47aSAdrian Chadd 	if (phy->rev >= 2) {
595*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
596*d546e47aSAdrian Chadd 		    BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
597*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
598*d546e47aSAdrian Chadd 		    (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
599*d546e47aSAdrian Chadd 		    0x15);
600*d546e47aSAdrian Chadd 		if (phy->rev == 2)
601*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
602*d546e47aSAdrian Chadd 		else
603*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
604*d546e47aSAdrian Chadd 			    (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
605*d546e47aSAdrian Chadd 			    8);
606*d546e47aSAdrian Chadd 	}
607*d546e47aSAdrian Chadd 	if (phy->rev >= 6)
608*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
609*d546e47aSAdrian Chadd 
610*d546e47aSAdrian Chadd 	hf |= BWN_HF_UCODE_ANTDIV_HELPER;
611*d546e47aSAdrian Chadd 	bwn_hf_write(mac, hf);
612*d546e47aSAdrian Chadd }
613*d546e47aSAdrian Chadd 
614*d546e47aSAdrian Chadd int
615*d546e47aSAdrian Chadd bwn_phy_g_im(struct bwn_mac *mac, int mode)
616*d546e47aSAdrian Chadd {
617*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
618*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
619*d546e47aSAdrian Chadd 
620*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
621*d546e47aSAdrian Chadd 	KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
622*d546e47aSAdrian Chadd 
623*d546e47aSAdrian Chadd 	if (phy->rev == 0 || !phy->gmode)
624*d546e47aSAdrian Chadd 		return (ENODEV);
625*d546e47aSAdrian Chadd 
626*d546e47aSAdrian Chadd 	pg->pg_aci_wlan_automatic = 0;
627*d546e47aSAdrian Chadd 	return (0);
628*d546e47aSAdrian Chadd }
629*d546e47aSAdrian Chadd 
630*d546e47aSAdrian Chadd int
631*d546e47aSAdrian Chadd bwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
632*d546e47aSAdrian Chadd {
633*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
634*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
635*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
636*d546e47aSAdrian Chadd 	unsigned int tssi;
637*d546e47aSAdrian Chadd 	int cck, ofdm;
638*d546e47aSAdrian Chadd 	int power;
639*d546e47aSAdrian Chadd 	int rfatt, bbatt;
640*d546e47aSAdrian Chadd 	unsigned int max;
641*d546e47aSAdrian Chadd 
642*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
643*d546e47aSAdrian Chadd 
644*d546e47aSAdrian Chadd 	cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
645*d546e47aSAdrian Chadd 	ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
646*d546e47aSAdrian Chadd 	if (cck < 0 && ofdm < 0) {
647*d546e47aSAdrian Chadd 		if (ignore_tssi == 0)
648*d546e47aSAdrian Chadd 			return (BWN_TXPWR_RES_DONE);
649*d546e47aSAdrian Chadd 		cck = 0;
650*d546e47aSAdrian Chadd 		ofdm = 0;
651*d546e47aSAdrian Chadd 	}
652*d546e47aSAdrian Chadd 	tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
653*d546e47aSAdrian Chadd 	if (pg->pg_avgtssi != 0xff)
654*d546e47aSAdrian Chadd 		tssi = (tssi + pg->pg_avgtssi) / 2;
655*d546e47aSAdrian Chadd 	pg->pg_avgtssi = tssi;
656*d546e47aSAdrian Chadd 	KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
657*d546e47aSAdrian Chadd 
658*d546e47aSAdrian Chadd 	max = siba_sprom_get_maxpwr_bg(sc->sc_dev);
659*d546e47aSAdrian Chadd 	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
660*d546e47aSAdrian Chadd 		max -= 3;
661*d546e47aSAdrian Chadd 	if (max >= 120) {
662*d546e47aSAdrian Chadd 		device_printf(sc->sc_dev, "invalid max TX-power value\n");
663*d546e47aSAdrian Chadd 		max = 80;
664*d546e47aSAdrian Chadd 		siba_sprom_set_maxpwr_bg(sc->sc_dev, max);
665*d546e47aSAdrian Chadd 	}
666*d546e47aSAdrian Chadd 
667*d546e47aSAdrian Chadd 	power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
668*d546e47aSAdrian Chadd 	    (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
669*d546e47aSAdrian Chadd 	     tssi, 0x00), 0x3f)]);
670*d546e47aSAdrian Chadd 	if (power == 0)
671*d546e47aSAdrian Chadd 		return (BWN_TXPWR_RES_DONE);
672*d546e47aSAdrian Chadd 
673*d546e47aSAdrian Chadd 	rfatt = -((power + 7) / 8);
674*d546e47aSAdrian Chadd 	bbatt = (-(power / 2)) - (4 * rfatt);
675*d546e47aSAdrian Chadd 	if ((rfatt == 0) && (bbatt == 0))
676*d546e47aSAdrian Chadd 		return (BWN_TXPWR_RES_DONE);
677*d546e47aSAdrian Chadd 	pg->pg_bbatt_delta = bbatt;
678*d546e47aSAdrian Chadd 	pg->pg_rfatt_delta = rfatt;
679*d546e47aSAdrian Chadd 	return (BWN_TXPWR_RES_NEED_ADJUST);
680*d546e47aSAdrian Chadd }
681*d546e47aSAdrian Chadd 
682*d546e47aSAdrian Chadd void
683*d546e47aSAdrian Chadd bwn_phy_g_set_txpwr(struct bwn_mac *mac)
684*d546e47aSAdrian Chadd {
685*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
686*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
687*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
688*d546e47aSAdrian Chadd 	int rfatt, bbatt;
689*d546e47aSAdrian Chadd 	uint8_t txctl;
690*d546e47aSAdrian Chadd 
691*d546e47aSAdrian Chadd 	bwn_mac_suspend(mac);
692*d546e47aSAdrian Chadd 
693*d546e47aSAdrian Chadd 	BWN_ASSERT_LOCKED(sc);
694*d546e47aSAdrian Chadd 
695*d546e47aSAdrian Chadd 	bbatt = pg->pg_bbatt.att;
696*d546e47aSAdrian Chadd 	bbatt += pg->pg_bbatt_delta;
697*d546e47aSAdrian Chadd 	rfatt = pg->pg_rfatt.att;
698*d546e47aSAdrian Chadd 	rfatt += pg->pg_rfatt_delta;
699*d546e47aSAdrian Chadd 
700*d546e47aSAdrian Chadd 	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
701*d546e47aSAdrian Chadd 	txctl = pg->pg_txctl;
702*d546e47aSAdrian Chadd 	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
703*d546e47aSAdrian Chadd 		if (rfatt <= 1) {
704*d546e47aSAdrian Chadd 			if (txctl == 0) {
705*d546e47aSAdrian Chadd 				txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
706*d546e47aSAdrian Chadd 				rfatt += 2;
707*d546e47aSAdrian Chadd 				bbatt += 2;
708*d546e47aSAdrian Chadd 			} else if (siba_sprom_get_bf_lo(sc->sc_dev) &
709*d546e47aSAdrian Chadd 			    BWN_BFL_PACTRL) {
710*d546e47aSAdrian Chadd 				bbatt += 4 * (rfatt - 2);
711*d546e47aSAdrian Chadd 				rfatt = 2;
712*d546e47aSAdrian Chadd 			}
713*d546e47aSAdrian Chadd 		} else if (rfatt > 4 && txctl) {
714*d546e47aSAdrian Chadd 			txctl = 0;
715*d546e47aSAdrian Chadd 			if (bbatt < 3) {
716*d546e47aSAdrian Chadd 				rfatt -= 3;
717*d546e47aSAdrian Chadd 				bbatt += 2;
718*d546e47aSAdrian Chadd 			} else {
719*d546e47aSAdrian Chadd 				rfatt -= 2;
720*d546e47aSAdrian Chadd 				bbatt -= 2;
721*d546e47aSAdrian Chadd 			}
722*d546e47aSAdrian Chadd 		}
723*d546e47aSAdrian Chadd 	}
724*d546e47aSAdrian Chadd 	pg->pg_txctl = txctl;
725*d546e47aSAdrian Chadd 	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
726*d546e47aSAdrian Chadd 	pg->pg_rfatt.att = rfatt;
727*d546e47aSAdrian Chadd 	pg->pg_bbatt.att = bbatt;
728*d546e47aSAdrian Chadd 
729*d546e47aSAdrian Chadd 	DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
730*d546e47aSAdrian Chadd 
731*d546e47aSAdrian Chadd 	bwn_phy_lock(mac);
732*d546e47aSAdrian Chadd 	bwn_rf_lock(mac);
733*d546e47aSAdrian Chadd 	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
734*d546e47aSAdrian Chadd 	    pg->pg_txctl);
735*d546e47aSAdrian Chadd 	bwn_rf_unlock(mac);
736*d546e47aSAdrian Chadd 	bwn_phy_unlock(mac);
737*d546e47aSAdrian Chadd 
738*d546e47aSAdrian Chadd 	bwn_mac_enable(mac);
739*d546e47aSAdrian Chadd }
740*d546e47aSAdrian Chadd 
741*d546e47aSAdrian Chadd void
742*d546e47aSAdrian Chadd bwn_phy_g_task_15s(struct bwn_mac *mac)
743*d546e47aSAdrian Chadd {
744*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
745*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
746*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
747*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
748*d546e47aSAdrian Chadd 	unsigned long expire, now;
749*d546e47aSAdrian Chadd 	struct bwn_lo_calib *cal, *tmp;
750*d546e47aSAdrian Chadd 	uint8_t expired = 0;
751*d546e47aSAdrian Chadd 
752*d546e47aSAdrian Chadd 	bwn_mac_suspend(mac);
753*d546e47aSAdrian Chadd 
754*d546e47aSAdrian Chadd 	if (lo == NULL)
755*d546e47aSAdrian Chadd 		goto fail;
756*d546e47aSAdrian Chadd 
757*d546e47aSAdrian Chadd 	BWN_GETTIME(now);
758*d546e47aSAdrian Chadd 	if (bwn_has_hwpctl(mac)) {
759*d546e47aSAdrian Chadd 		expire = now - BWN_LO_PWRVEC_EXPIRE;
760*d546e47aSAdrian Chadd 		if (ieee80211_time_before(lo->pwr_vec_read_time, expire)) {
761*d546e47aSAdrian Chadd 			bwn_lo_get_powervector(mac);
762*d546e47aSAdrian Chadd 			bwn_phy_g_dc_lookup_init(mac, 0);
763*d546e47aSAdrian Chadd 		}
764*d546e47aSAdrian Chadd 		goto fail;
765*d546e47aSAdrian Chadd 	}
766*d546e47aSAdrian Chadd 
767*d546e47aSAdrian Chadd 	expire = now - BWN_LO_CALIB_EXPIRE;
768*d546e47aSAdrian Chadd 	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
769*d546e47aSAdrian Chadd 		if (!ieee80211_time_before(cal->calib_time, expire))
770*d546e47aSAdrian Chadd 			continue;
771*d546e47aSAdrian Chadd 		if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
772*d546e47aSAdrian Chadd 		    BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
773*d546e47aSAdrian Chadd 			KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
774*d546e47aSAdrian Chadd 			expired = 1;
775*d546e47aSAdrian Chadd 		}
776*d546e47aSAdrian Chadd 
777*d546e47aSAdrian Chadd 		DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
778*d546e47aSAdrian Chadd 		    cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
779*d546e47aSAdrian Chadd 		    cal->ctl.i, cal->ctl.q);
780*d546e47aSAdrian Chadd 
781*d546e47aSAdrian Chadd 		TAILQ_REMOVE(&lo->calib_list, cal, list);
782*d546e47aSAdrian Chadd 		free(cal, M_DEVBUF);
783*d546e47aSAdrian Chadd 	}
784*d546e47aSAdrian Chadd 	if (expired || TAILQ_EMPTY(&lo->calib_list)) {
785*d546e47aSAdrian Chadd 		cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
786*d546e47aSAdrian Chadd 		    &pg->pg_rfatt);
787*d546e47aSAdrian Chadd 		if (cal == NULL) {
788*d546e47aSAdrian Chadd 			device_printf(sc->sc_dev,
789*d546e47aSAdrian Chadd 			    "failed to recalibrate LO\n");
790*d546e47aSAdrian Chadd 			goto fail;
791*d546e47aSAdrian Chadd 		}
792*d546e47aSAdrian Chadd 		TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
793*d546e47aSAdrian Chadd 		bwn_lo_write(mac, &cal->ctl);
794*d546e47aSAdrian Chadd 	}
795*d546e47aSAdrian Chadd 
796*d546e47aSAdrian Chadd fail:
797*d546e47aSAdrian Chadd 	bwn_mac_enable(mac);
798*d546e47aSAdrian Chadd }
799*d546e47aSAdrian Chadd 
800*d546e47aSAdrian Chadd void
801*d546e47aSAdrian Chadd bwn_phy_g_task_60s(struct bwn_mac *mac)
802*d546e47aSAdrian Chadd {
803*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
804*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
805*d546e47aSAdrian Chadd 	uint8_t old = phy->chan;
806*d546e47aSAdrian Chadd 
807*d546e47aSAdrian Chadd 	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI))
808*d546e47aSAdrian Chadd 		return;
809*d546e47aSAdrian Chadd 
810*d546e47aSAdrian Chadd 	bwn_mac_suspend(mac);
811*d546e47aSAdrian Chadd 	bwn_nrssi_slope_11g(mac);
812*d546e47aSAdrian Chadd 	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
813*d546e47aSAdrian Chadd 		bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
814*d546e47aSAdrian Chadd 		bwn_switch_channel(mac, old);
815*d546e47aSAdrian Chadd 	}
816*d546e47aSAdrian Chadd 	bwn_mac_enable(mac);
817*d546e47aSAdrian Chadd }
818*d546e47aSAdrian Chadd 
819*d546e47aSAdrian Chadd void
820*d546e47aSAdrian Chadd bwn_phy_switch_analog(struct bwn_mac *mac, int on)
821*d546e47aSAdrian Chadd {
822*d546e47aSAdrian Chadd 
823*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
824*d546e47aSAdrian Chadd }
825*d546e47aSAdrian Chadd 
826*d546e47aSAdrian Chadd static void
827*d546e47aSAdrian Chadd bwn_phy_g_init_sub(struct bwn_mac *mac)
828*d546e47aSAdrian Chadd {
829*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
830*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
831*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
832*d546e47aSAdrian Chadd 	uint16_t i, tmp;
833*d546e47aSAdrian Chadd 
834*d546e47aSAdrian Chadd 	if (phy->rev == 1)
835*d546e47aSAdrian Chadd 		bwn_phy_init_b5(mac);
836*d546e47aSAdrian Chadd 	else
837*d546e47aSAdrian Chadd 		bwn_phy_init_b6(mac);
838*d546e47aSAdrian Chadd 
839*d546e47aSAdrian Chadd 	if (phy->rev >= 2 || phy->gmode)
840*d546e47aSAdrian Chadd 		bwn_phy_init_a(mac);
841*d546e47aSAdrian Chadd 
842*d546e47aSAdrian Chadd 	if (phy->rev >= 2) {
843*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
844*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
845*d546e47aSAdrian Chadd 	}
846*d546e47aSAdrian Chadd 	if (phy->rev == 2) {
847*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
848*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
849*d546e47aSAdrian Chadd 	}
850*d546e47aSAdrian Chadd 	if (phy->rev > 5) {
851*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
852*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
853*d546e47aSAdrian Chadd 	}
854*d546e47aSAdrian Chadd 	if (phy->gmode || phy->rev >= 2) {
855*d546e47aSAdrian Chadd 		tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
856*d546e47aSAdrian Chadd 		tmp &= BWN_PHYVER_VERSION;
857*d546e47aSAdrian Chadd 		if (tmp == 3 || tmp == 5) {
858*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
859*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
860*d546e47aSAdrian Chadd 		}
861*d546e47aSAdrian Chadd 		if (tmp == 5) {
862*d546e47aSAdrian Chadd 			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
863*d546e47aSAdrian Chadd 			    0x1f00);
864*d546e47aSAdrian Chadd 		}
865*d546e47aSAdrian Chadd 	}
866*d546e47aSAdrian Chadd 	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
867*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
868*d546e47aSAdrian Chadd 	if (phy->rf_rev == 8) {
869*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
870*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
871*d546e47aSAdrian Chadd 	}
872*d546e47aSAdrian Chadd 	if (BWN_HAS_LOOPBACK(phy))
873*d546e47aSAdrian Chadd 		bwn_loopback_calcgain(mac);
874*d546e47aSAdrian Chadd 
875*d546e47aSAdrian Chadd 	if (phy->rf_rev != 8) {
876*d546e47aSAdrian Chadd 		if (pg->pg_initval == 0xffff)
877*d546e47aSAdrian Chadd 			pg->pg_initval = bwn_rf_init_bcm2050(mac);
878*d546e47aSAdrian Chadd 		else
879*d546e47aSAdrian Chadd 			BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
880*d546e47aSAdrian Chadd 	}
881*d546e47aSAdrian Chadd 	bwn_lo_g_init(mac);
882*d546e47aSAdrian Chadd 	if (BWN_HAS_TXMAG(phy)) {
883*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x52,
884*d546e47aSAdrian Chadd 		    (BWN_RF_READ(mac, 0x52) & 0xff00)
885*d546e47aSAdrian Chadd 		    | pg->pg_loctl.tx_bias |
886*d546e47aSAdrian Chadd 		    pg->pg_loctl.tx_magn);
887*d546e47aSAdrian Chadd 	} else {
888*d546e47aSAdrian Chadd 		BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
889*d546e47aSAdrian Chadd 	}
890*d546e47aSAdrian Chadd 	if (phy->rev >= 6) {
891*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
892*d546e47aSAdrian Chadd 		    (pg->pg_loctl.tx_bias << 12));
893*d546e47aSAdrian Chadd 	}
894*d546e47aSAdrian Chadd 	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
895*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
896*d546e47aSAdrian Chadd 	else
897*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
898*d546e47aSAdrian Chadd 	if (phy->rev < 2)
899*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
900*d546e47aSAdrian Chadd 	else
901*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
902*d546e47aSAdrian Chadd 	if (phy->gmode || phy->rev >= 2) {
903*d546e47aSAdrian Chadd 		bwn_lo_g_adjust(mac);
904*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
905*d546e47aSAdrian Chadd 	}
906*d546e47aSAdrian Chadd 
907*d546e47aSAdrian Chadd 	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
908*d546e47aSAdrian Chadd 		for (i = 0; i < 64; i++) {
909*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
910*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
911*d546e47aSAdrian Chadd 			    (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
912*d546e47aSAdrian Chadd 			    -32), 31));
913*d546e47aSAdrian Chadd 		}
914*d546e47aSAdrian Chadd 		bwn_nrssi_threshold(mac);
915*d546e47aSAdrian Chadd 	} else if (phy->gmode || phy->rev >= 2) {
916*d546e47aSAdrian Chadd 		if (pg->pg_nrssi[0] == -1000) {
917*d546e47aSAdrian Chadd 			KASSERT(pg->pg_nrssi[1] == -1000,
918*d546e47aSAdrian Chadd 			    ("%s:%d: fail", __func__, __LINE__));
919*d546e47aSAdrian Chadd 			bwn_nrssi_slope_11g(mac);
920*d546e47aSAdrian Chadd 		} else
921*d546e47aSAdrian Chadd 			bwn_nrssi_threshold(mac);
922*d546e47aSAdrian Chadd 	}
923*d546e47aSAdrian Chadd 	if (phy->rf_rev == 8)
924*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
925*d546e47aSAdrian Chadd 	bwn_phy_hwpctl_init(mac);
926*d546e47aSAdrian Chadd 	if ((siba_get_chipid(sc->sc_dev) == 0x4306
927*d546e47aSAdrian Chadd 	     && siba_get_chippkg(sc->sc_dev) == 2) || 0) {
928*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
929*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
930*d546e47aSAdrian Chadd 	}
931*d546e47aSAdrian Chadd }
932*d546e47aSAdrian Chadd 
933*d546e47aSAdrian Chadd static void
934*d546e47aSAdrian Chadd bwn_phy_init_b5(struct bwn_mac *mac)
935*d546e47aSAdrian Chadd {
936*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
937*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
938*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
939*d546e47aSAdrian Chadd 	uint16_t offset, value;
940*d546e47aSAdrian Chadd 	uint8_t old_channel;
941*d546e47aSAdrian Chadd 
942*d546e47aSAdrian Chadd 	if (phy->analog == 1)
943*d546e47aSAdrian Chadd 		BWN_RF_SET(mac, 0x007a, 0x0050);
944*d546e47aSAdrian Chadd 	if ((siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM) &&
945*d546e47aSAdrian Chadd 	    (siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306)) {
946*d546e47aSAdrian Chadd 		value = 0x2120;
947*d546e47aSAdrian Chadd 		for (offset = 0x00a8; offset < 0x00c7; offset++) {
948*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, offset, value);
949*d546e47aSAdrian Chadd 			value += 0x202;
950*d546e47aSAdrian Chadd 		}
951*d546e47aSAdrian Chadd 	}
952*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
953*d546e47aSAdrian Chadd 	if (phy->rf_ver == 0x2050)
954*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0038, 0x0667);
955*d546e47aSAdrian Chadd 
956*d546e47aSAdrian Chadd 	if (phy->gmode || phy->rev >= 2) {
957*d546e47aSAdrian Chadd 		if (phy->rf_ver == 0x2050) {
958*d546e47aSAdrian Chadd 			BWN_RF_SET(mac, 0x007a, 0x0020);
959*d546e47aSAdrian Chadd 			BWN_RF_SET(mac, 0x0051, 0x0004);
960*d546e47aSAdrian Chadd 		}
961*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
962*d546e47aSAdrian Chadd 
963*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0802, 0x0100);
964*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x042b, 0x2000);
965*d546e47aSAdrian Chadd 
966*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x001c, 0x186a);
967*d546e47aSAdrian Chadd 
968*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
969*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
970*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
971*d546e47aSAdrian Chadd 	}
972*d546e47aSAdrian Chadd 
973*d546e47aSAdrian Chadd 	if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
974*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
975*d546e47aSAdrian Chadd 
976*d546e47aSAdrian Chadd 	if (phy->analog == 1) {
977*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0026, 0xce00);
978*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0021, 0x3763);
979*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
980*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
981*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0024, 0x037e);
982*d546e47aSAdrian Chadd 	} else
983*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
984*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
985*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x03ec, 0x3f22);
986*d546e47aSAdrian Chadd 
987*d546e47aSAdrian Chadd 	if (phy->analog == 1)
988*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
989*d546e47aSAdrian Chadd 	else
990*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0020, 0x301c);
991*d546e47aSAdrian Chadd 
992*d546e47aSAdrian Chadd 	if (phy->analog == 0)
993*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x03e4, 0x3000);
994*d546e47aSAdrian Chadd 
995*d546e47aSAdrian Chadd 	old_channel = phy->chan;
996*d546e47aSAdrian Chadd 	bwn_phy_g_switch_chan(mac, 7, 0);
997*d546e47aSAdrian Chadd 
998*d546e47aSAdrian Chadd 	if (phy->rf_ver != 0x2050) {
999*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x0075, 0x0080);
1000*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x0079, 0x0081);
1001*d546e47aSAdrian Chadd 	}
1002*d546e47aSAdrian Chadd 
1003*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x0050, 0x0020);
1004*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x0050, 0x0023);
1005*d546e47aSAdrian Chadd 
1006*d546e47aSAdrian Chadd 	if (phy->rf_ver == 0x2050) {
1007*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x0050, 0x0020);
1008*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x005a, 0x0070);
1009*d546e47aSAdrian Chadd 	}
1010*d546e47aSAdrian Chadd 
1011*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x005b, 0x007b);
1012*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x005c, 0x00b0);
1013*d546e47aSAdrian Chadd 	BWN_RF_SET(mac, 0x007a, 0x0007);
1014*d546e47aSAdrian Chadd 
1015*d546e47aSAdrian Chadd 	bwn_phy_g_switch_chan(mac, old_channel, 0);
1016*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0014, 0x0080);
1017*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
1018*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
1019*d546e47aSAdrian Chadd 
1020*d546e47aSAdrian Chadd 	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
1021*d546e47aSAdrian Chadd 	    pg->pg_txctl);
1022*d546e47aSAdrian Chadd 
1023*d546e47aSAdrian Chadd 	if (phy->rf_ver == 0x2050)
1024*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x005d, 0x000d);
1025*d546e47aSAdrian Chadd 
1026*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
1027*d546e47aSAdrian Chadd }
1028*d546e47aSAdrian Chadd 
1029*d546e47aSAdrian Chadd static void
1030*d546e47aSAdrian Chadd bwn_loopback_calcgain(struct bwn_mac *mac)
1031*d546e47aSAdrian Chadd {
1032*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1033*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
1034*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
1035*d546e47aSAdrian Chadd 	uint16_t backup_phy[16] = { 0 };
1036*d546e47aSAdrian Chadd 	uint16_t backup_radio[3];
1037*d546e47aSAdrian Chadd 	uint16_t backup_bband;
1038*d546e47aSAdrian Chadd 	uint16_t i, j, loop_i_max;
1039*d546e47aSAdrian Chadd 	uint16_t trsw_rx;
1040*d546e47aSAdrian Chadd 	uint16_t loop1_outer_done, loop1_inner_done;
1041*d546e47aSAdrian Chadd 
1042*d546e47aSAdrian Chadd 	backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
1043*d546e47aSAdrian Chadd 	backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
1044*d546e47aSAdrian Chadd 	backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
1045*d546e47aSAdrian Chadd 	backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
1046*d546e47aSAdrian Chadd 	if (phy->rev != 1) {
1047*d546e47aSAdrian Chadd 		backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
1048*d546e47aSAdrian Chadd 		backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
1049*d546e47aSAdrian Chadd 	}
1050*d546e47aSAdrian Chadd 	backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
1051*d546e47aSAdrian Chadd 	backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
1052*d546e47aSAdrian Chadd 	backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
1053*d546e47aSAdrian Chadd 	backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
1054*d546e47aSAdrian Chadd 	backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
1055*d546e47aSAdrian Chadd 	backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
1056*d546e47aSAdrian Chadd 	backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
1057*d546e47aSAdrian Chadd 	backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
1058*d546e47aSAdrian Chadd 	backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
1059*d546e47aSAdrian Chadd 	backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
1060*d546e47aSAdrian Chadd 	backup_bband = pg->pg_bbatt.att;
1061*d546e47aSAdrian Chadd 	backup_radio[0] = BWN_RF_READ(mac, 0x52);
1062*d546e47aSAdrian Chadd 	backup_radio[1] = BWN_RF_READ(mac, 0x43);
1063*d546e47aSAdrian Chadd 	backup_radio[2] = BWN_RF_READ(mac, 0x7a);
1064*d546e47aSAdrian Chadd 
1065*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
1066*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
1067*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
1068*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
1069*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
1070*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
1071*d546e47aSAdrian Chadd 	if (phy->rev != 1) {
1072*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
1073*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
1074*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
1075*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
1076*d546e47aSAdrian Chadd 	}
1077*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
1078*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
1079*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
1080*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
1081*d546e47aSAdrian Chadd 
1082*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
1083*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
1084*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
1085*d546e47aSAdrian Chadd 
1086*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
1087*d546e47aSAdrian Chadd 	if (phy->rev != 1) {
1088*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
1089*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
1090*d546e47aSAdrian Chadd 	}
1091*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
1092*d546e47aSAdrian Chadd 
1093*d546e47aSAdrian Chadd 	if (phy->rf_rev == 8)
1094*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x43, 0x000f);
1095*d546e47aSAdrian Chadd 	else {
1096*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x52, 0);
1097*d546e47aSAdrian Chadd 		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
1098*d546e47aSAdrian Chadd 	}
1099*d546e47aSAdrian Chadd 	bwn_phy_g_set_bbatt(mac, 11);
1100*d546e47aSAdrian Chadd 
1101*d546e47aSAdrian Chadd 	if (phy->rev >= 3)
1102*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
1103*d546e47aSAdrian Chadd 	else
1104*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
1105*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
1106*d546e47aSAdrian Chadd 
1107*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
1108*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
1109*d546e47aSAdrian Chadd 
1110*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
1111*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
1112*d546e47aSAdrian Chadd 
1113*d546e47aSAdrian Chadd 	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) {
1114*d546e47aSAdrian Chadd 		if (phy->rev >= 7) {
1115*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
1116*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
1117*d546e47aSAdrian Chadd 		}
1118*d546e47aSAdrian Chadd 	}
1119*d546e47aSAdrian Chadd 	BWN_RF_MASK(mac, 0x7a, 0x00f7);
1120*d546e47aSAdrian Chadd 
1121*d546e47aSAdrian Chadd 	j = 0;
1122*d546e47aSAdrian Chadd 	loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
1123*d546e47aSAdrian Chadd 	for (i = 0; i < loop_i_max; i++) {
1124*d546e47aSAdrian Chadd 		for (j = 0; j < 16; j++) {
1125*d546e47aSAdrian Chadd 			BWN_RF_WRITE(mac, 0x43, i);
1126*d546e47aSAdrian Chadd 			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
1127*d546e47aSAdrian Chadd 			    (j << 8));
1128*d546e47aSAdrian Chadd 			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
1129*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
1130*d546e47aSAdrian Chadd 			DELAY(20);
1131*d546e47aSAdrian Chadd 			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
1132*d546e47aSAdrian Chadd 				goto done0;
1133*d546e47aSAdrian Chadd 		}
1134*d546e47aSAdrian Chadd 	}
1135*d546e47aSAdrian Chadd done0:
1136*d546e47aSAdrian Chadd 	loop1_outer_done = i;
1137*d546e47aSAdrian Chadd 	loop1_inner_done = j;
1138*d546e47aSAdrian Chadd 	if (j >= 8) {
1139*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
1140*d546e47aSAdrian Chadd 		trsw_rx = 0x1b;
1141*d546e47aSAdrian Chadd 		for (j = j - 8; j < 16; j++) {
1142*d546e47aSAdrian Chadd 			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
1143*d546e47aSAdrian Chadd 			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
1144*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
1145*d546e47aSAdrian Chadd 			DELAY(20);
1146*d546e47aSAdrian Chadd 			trsw_rx -= 3;
1147*d546e47aSAdrian Chadd 			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
1148*d546e47aSAdrian Chadd 				goto done1;
1149*d546e47aSAdrian Chadd 		}
1150*d546e47aSAdrian Chadd 	} else
1151*d546e47aSAdrian Chadd 		trsw_rx = 0x18;
1152*d546e47aSAdrian Chadd done1:
1153*d546e47aSAdrian Chadd 
1154*d546e47aSAdrian Chadd 	if (phy->rev != 1) {
1155*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
1156*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
1157*d546e47aSAdrian Chadd 	}
1158*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
1159*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
1160*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
1161*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
1162*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
1163*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
1164*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
1165*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
1166*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
1167*d546e47aSAdrian Chadd 
1168*d546e47aSAdrian Chadd 	bwn_phy_g_set_bbatt(mac, backup_bband);
1169*d546e47aSAdrian Chadd 
1170*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
1171*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
1172*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
1173*d546e47aSAdrian Chadd 
1174*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
1175*d546e47aSAdrian Chadd 	DELAY(10);
1176*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
1177*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
1178*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
1179*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
1180*d546e47aSAdrian Chadd 
1181*d546e47aSAdrian Chadd 	pg->pg_max_lb_gain =
1182*d546e47aSAdrian Chadd 	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
1183*d546e47aSAdrian Chadd 	pg->pg_trsw_rx_gain = trsw_rx * 2;
1184*d546e47aSAdrian Chadd }
1185*d546e47aSAdrian Chadd 
1186*d546e47aSAdrian Chadd static uint16_t
1187*d546e47aSAdrian Chadd bwn_rf_init_bcm2050(struct bwn_mac *mac)
1188*d546e47aSAdrian Chadd {
1189*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1190*d546e47aSAdrian Chadd 	uint32_t tmp1 = 0, tmp2 = 0;
1191*d546e47aSAdrian Chadd 	uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
1192*d546e47aSAdrian Chadd 	    analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
1193*d546e47aSAdrian Chadd 	    radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
1194*d546e47aSAdrian Chadd 	static const uint8_t rcc_table[] = {
1195*d546e47aSAdrian Chadd 		0x02, 0x03, 0x01, 0x0f,
1196*d546e47aSAdrian Chadd 		0x06, 0x07, 0x05, 0x0f,
1197*d546e47aSAdrian Chadd 		0x0a, 0x0b, 0x09, 0x0f,
1198*d546e47aSAdrian Chadd 		0x0e, 0x0f, 0x0d, 0x0f,
1199*d546e47aSAdrian Chadd 	};
1200*d546e47aSAdrian Chadd 
1201*d546e47aSAdrian Chadd 	loctl = lomask = reg0 = classctl = crs0 = analogoverval = analogover =
1202*d546e47aSAdrian Chadd 	    rfoverval = rfover = cck3 = 0;
1203*d546e47aSAdrian Chadd 	radio0 = BWN_RF_READ(mac, 0x43);
1204*d546e47aSAdrian Chadd 	radio1 = BWN_RF_READ(mac, 0x51);
1205*d546e47aSAdrian Chadd 	radio2 = BWN_RF_READ(mac, 0x52);
1206*d546e47aSAdrian Chadd 	pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
1207*d546e47aSAdrian Chadd 	cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
1208*d546e47aSAdrian Chadd 	cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
1209*d546e47aSAdrian Chadd 	cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
1210*d546e47aSAdrian Chadd 
1211*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_B) {
1212*d546e47aSAdrian Chadd 		cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
1213*d546e47aSAdrian Chadd 		reg0 = BWN_READ_2(mac, 0x3ec);
1214*d546e47aSAdrian Chadd 
1215*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
1216*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
1217*d546e47aSAdrian Chadd 	} else if (phy->gmode || phy->rev >= 2) {
1218*d546e47aSAdrian Chadd 		rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
1219*d546e47aSAdrian Chadd 		rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
1220*d546e47aSAdrian Chadd 		analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
1221*d546e47aSAdrian Chadd 		analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
1222*d546e47aSAdrian Chadd 		crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
1223*d546e47aSAdrian Chadd 		classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
1224*d546e47aSAdrian Chadd 
1225*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
1226*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
1227*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
1228*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
1229*d546e47aSAdrian Chadd 		if (BWN_HAS_LOOPBACK(phy)) {
1230*d546e47aSAdrian Chadd 			lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
1231*d546e47aSAdrian Chadd 			loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
1232*d546e47aSAdrian Chadd 			if (phy->rev >= 3)
1233*d546e47aSAdrian Chadd 				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
1234*d546e47aSAdrian Chadd 			else
1235*d546e47aSAdrian Chadd 				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
1236*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
1237*d546e47aSAdrian Chadd 		}
1238*d546e47aSAdrian Chadd 
1239*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1240*d546e47aSAdrian Chadd 		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
1241*d546e47aSAdrian Chadd 			BWN_LPD(0, 1, 1)));
1242*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
1243*d546e47aSAdrian Chadd 		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
1244*d546e47aSAdrian Chadd 	}
1245*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
1246*d546e47aSAdrian Chadd 
1247*d546e47aSAdrian Chadd 	syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
1248*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
1249*d546e47aSAdrian Chadd 	reg1 = BWN_READ_2(mac, 0x3e6);
1250*d546e47aSAdrian Chadd 	reg2 = BWN_READ_2(mac, 0x3f4);
1251*d546e47aSAdrian Chadd 
1252*d546e47aSAdrian Chadd 	if (phy->analog == 0)
1253*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x03e6, 0x0122);
1254*d546e47aSAdrian Chadd 	else {
1255*d546e47aSAdrian Chadd 		if (phy->analog >= 2)
1256*d546e47aSAdrian Chadd 			BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
1257*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
1258*d546e47aSAdrian Chadd 		    (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
1259*d546e47aSAdrian Chadd 	}
1260*d546e47aSAdrian Chadd 
1261*d546e47aSAdrian Chadd 	reg = BWN_RF_READ(mac, 0x60);
1262*d546e47aSAdrian Chadd 	index = (reg & 0x001e) >> 1;
1263*d546e47aSAdrian Chadd 	rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
1264*d546e47aSAdrian Chadd 
1265*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_B)
1266*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x78, 0x26);
1267*d546e47aSAdrian Chadd 	if (phy->gmode || phy->rev >= 2) {
1268*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1269*d546e47aSAdrian Chadd 		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
1270*d546e47aSAdrian Chadd 			BWN_LPD(0, 1, 1)));
1271*d546e47aSAdrian Chadd 	}
1272*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
1273*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
1274*d546e47aSAdrian Chadd 	if (phy->gmode || phy->rev >= 2) {
1275*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1276*d546e47aSAdrian Chadd 		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
1277*d546e47aSAdrian Chadd 			BWN_LPD(0, 0, 1)));
1278*d546e47aSAdrian Chadd 	}
1279*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
1280*d546e47aSAdrian Chadd 	BWN_RF_SET(mac, 0x51, 0x0004);
1281*d546e47aSAdrian Chadd 	if (phy->rf_rev == 8)
1282*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x43, 0x1f);
1283*d546e47aSAdrian Chadd 	else {
1284*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x52, 0);
1285*d546e47aSAdrian Chadd 		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
1286*d546e47aSAdrian Chadd 	}
1287*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
1288*d546e47aSAdrian Chadd 
1289*d546e47aSAdrian Chadd 	for (i = 0; i < 16; i++) {
1290*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
1291*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
1292*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
1293*d546e47aSAdrian Chadd 		if (phy->gmode || phy->rev >= 2) {
1294*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1295*d546e47aSAdrian Chadd 			    bwn_rf_2050_rfoverval(mac,
1296*d546e47aSAdrian Chadd 				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1297*d546e47aSAdrian Chadd 		}
1298*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
1299*d546e47aSAdrian Chadd 		DELAY(10);
1300*d546e47aSAdrian Chadd 		if (phy->gmode || phy->rev >= 2) {
1301*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1302*d546e47aSAdrian Chadd 			    bwn_rf_2050_rfoverval(mac,
1303*d546e47aSAdrian Chadd 				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1304*d546e47aSAdrian Chadd 		}
1305*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
1306*d546e47aSAdrian Chadd 		DELAY(10);
1307*d546e47aSAdrian Chadd 		if (phy->gmode || phy->rev >= 2) {
1308*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1309*d546e47aSAdrian Chadd 			    bwn_rf_2050_rfoverval(mac,
1310*d546e47aSAdrian Chadd 				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
1311*d546e47aSAdrian Chadd 		}
1312*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
1313*d546e47aSAdrian Chadd 		DELAY(20);
1314*d546e47aSAdrian Chadd 		tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
1315*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
1316*d546e47aSAdrian Chadd 		if (phy->gmode || phy->rev >= 2) {
1317*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1318*d546e47aSAdrian Chadd 			    bwn_rf_2050_rfoverval(mac,
1319*d546e47aSAdrian Chadd 				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1320*d546e47aSAdrian Chadd 		}
1321*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
1322*d546e47aSAdrian Chadd 	}
1323*d546e47aSAdrian Chadd 	DELAY(10);
1324*d546e47aSAdrian Chadd 
1325*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
1326*d546e47aSAdrian Chadd 	tmp1++;
1327*d546e47aSAdrian Chadd 	tmp1 >>= 9;
1328*d546e47aSAdrian Chadd 
1329*d546e47aSAdrian Chadd 	for (i = 0; i < 16; i++) {
1330*d546e47aSAdrian Chadd 		radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
1331*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x78, radio78);
1332*d546e47aSAdrian Chadd 		DELAY(10);
1333*d546e47aSAdrian Chadd 		for (j = 0; j < 16; j++) {
1334*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
1335*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
1336*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
1337*d546e47aSAdrian Chadd 			if (phy->gmode || phy->rev >= 2) {
1338*d546e47aSAdrian Chadd 				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1339*d546e47aSAdrian Chadd 				    bwn_rf_2050_rfoverval(mac,
1340*d546e47aSAdrian Chadd 					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1341*d546e47aSAdrian Chadd 			}
1342*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
1343*d546e47aSAdrian Chadd 			DELAY(10);
1344*d546e47aSAdrian Chadd 			if (phy->gmode || phy->rev >= 2) {
1345*d546e47aSAdrian Chadd 				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1346*d546e47aSAdrian Chadd 				    bwn_rf_2050_rfoverval(mac,
1347*d546e47aSAdrian Chadd 					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1348*d546e47aSAdrian Chadd 			}
1349*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
1350*d546e47aSAdrian Chadd 			DELAY(10);
1351*d546e47aSAdrian Chadd 			if (phy->gmode || phy->rev >= 2) {
1352*d546e47aSAdrian Chadd 				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1353*d546e47aSAdrian Chadd 				    bwn_rf_2050_rfoverval(mac,
1354*d546e47aSAdrian Chadd 					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
1355*d546e47aSAdrian Chadd 			}
1356*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
1357*d546e47aSAdrian Chadd 			DELAY(10);
1358*d546e47aSAdrian Chadd 			tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
1359*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
1360*d546e47aSAdrian Chadd 			if (phy->gmode || phy->rev >= 2) {
1361*d546e47aSAdrian Chadd 				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1362*d546e47aSAdrian Chadd 				    bwn_rf_2050_rfoverval(mac,
1363*d546e47aSAdrian Chadd 					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1364*d546e47aSAdrian Chadd 			}
1365*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
1366*d546e47aSAdrian Chadd 		}
1367*d546e47aSAdrian Chadd 		tmp2++;
1368*d546e47aSAdrian Chadd 		tmp2 >>= 8;
1369*d546e47aSAdrian Chadd 		if (tmp1 < tmp2)
1370*d546e47aSAdrian Chadd 			break;
1371*d546e47aSAdrian Chadd 	}
1372*d546e47aSAdrian Chadd 
1373*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
1374*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x51, radio1);
1375*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x52, radio2);
1376*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x43, radio0);
1377*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
1378*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
1379*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
1380*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x3e6, reg1);
1381*d546e47aSAdrian Chadd 	if (phy->analog != 0)
1382*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x3f4, reg2);
1383*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
1384*d546e47aSAdrian Chadd 	bwn_spu_workaround(mac, phy->chan);
1385*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_B) {
1386*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
1387*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x3ec, reg0);
1388*d546e47aSAdrian Chadd 	} else if (phy->gmode) {
1389*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, BWN_PHY_RADIO,
1390*d546e47aSAdrian Chadd 			    BWN_READ_2(mac, BWN_PHY_RADIO)
1391*d546e47aSAdrian Chadd 			    & 0x7fff);
1392*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
1393*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
1394*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
1395*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
1396*d546e47aSAdrian Chadd 			      analogoverval);
1397*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
1398*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
1399*d546e47aSAdrian Chadd 		if (BWN_HAS_LOOPBACK(phy)) {
1400*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
1401*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
1402*d546e47aSAdrian Chadd 		}
1403*d546e47aSAdrian Chadd 	}
1404*d546e47aSAdrian Chadd 
1405*d546e47aSAdrian Chadd 	return ((i > 15) ? radio78 : rcc);
1406*d546e47aSAdrian Chadd }
1407*d546e47aSAdrian Chadd 
1408*d546e47aSAdrian Chadd static void
1409*d546e47aSAdrian Chadd bwn_phy_init_b6(struct bwn_mac *mac)
1410*d546e47aSAdrian Chadd {
1411*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1412*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
1413*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
1414*d546e47aSAdrian Chadd 	uint16_t offset, val;
1415*d546e47aSAdrian Chadd 	uint8_t old_channel;
1416*d546e47aSAdrian Chadd 
1417*d546e47aSAdrian Chadd 	KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
1418*d546e47aSAdrian Chadd 	    ("%s:%d: fail", __func__, __LINE__));
1419*d546e47aSAdrian Chadd 
1420*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x003e, 0x817a);
1421*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
1422*d546e47aSAdrian Chadd 	if (phy->rf_rev == 4 || phy->rf_rev == 5) {
1423*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x51, 0x37);
1424*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x52, 0x70);
1425*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x53, 0xb3);
1426*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x54, 0x9b);
1427*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5a, 0x88);
1428*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5b, 0x88);
1429*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5d, 0x88);
1430*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5e, 0x88);
1431*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x7d, 0x88);
1432*d546e47aSAdrian Chadd 		bwn_hf_write(mac,
1433*d546e47aSAdrian Chadd 		    bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
1434*d546e47aSAdrian Chadd 	}
1435*d546e47aSAdrian Chadd 	if (phy->rf_rev == 8) {
1436*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x51, 0);
1437*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x52, 0x40);
1438*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x53, 0xb7);
1439*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x54, 0x98);
1440*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5a, 0x88);
1441*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5b, 0x6b);
1442*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5c, 0x0f);
1443*d546e47aSAdrian Chadd 		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_ALTIQ) {
1444*d546e47aSAdrian Chadd 			BWN_RF_WRITE(mac, 0x5d, 0xfa);
1445*d546e47aSAdrian Chadd 			BWN_RF_WRITE(mac, 0x5e, 0xd8);
1446*d546e47aSAdrian Chadd 		} else {
1447*d546e47aSAdrian Chadd 			BWN_RF_WRITE(mac, 0x5d, 0xf5);
1448*d546e47aSAdrian Chadd 			BWN_RF_WRITE(mac, 0x5e, 0xb8);
1449*d546e47aSAdrian Chadd 		}
1450*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x0073, 0x0003);
1451*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x007d, 0x00a8);
1452*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x007c, 0x0001);
1453*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x007e, 0x0008);
1454*d546e47aSAdrian Chadd 	}
1455*d546e47aSAdrian Chadd 	for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
1456*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, offset, val);
1457*d546e47aSAdrian Chadd 		val -= 0x0202;
1458*d546e47aSAdrian Chadd 	}
1459*d546e47aSAdrian Chadd 	for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
1460*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, offset, val);
1461*d546e47aSAdrian Chadd 		val -= 0x0202;
1462*d546e47aSAdrian Chadd 	}
1463*d546e47aSAdrian Chadd 	for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
1464*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
1465*d546e47aSAdrian Chadd 		val += 0x0202;
1466*d546e47aSAdrian Chadd 	}
1467*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_G) {
1468*d546e47aSAdrian Chadd 		BWN_RF_SET(mac, 0x007a, 0x0020);
1469*d546e47aSAdrian Chadd 		BWN_RF_SET(mac, 0x0051, 0x0004);
1470*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0802, 0x0100);
1471*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x042b, 0x2000);
1472*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x5b, 0);
1473*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x5c, 0);
1474*d546e47aSAdrian Chadd 	}
1475*d546e47aSAdrian Chadd 
1476*d546e47aSAdrian Chadd 	old_channel = phy->chan;
1477*d546e47aSAdrian Chadd 	bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
1478*d546e47aSAdrian Chadd 
1479*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x0050, 0x0020);
1480*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x0050, 0x0023);
1481*d546e47aSAdrian Chadd 	DELAY(40);
1482*d546e47aSAdrian Chadd 	if (phy->rf_rev < 6 || phy->rf_rev == 8) {
1483*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
1484*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x50, 0x20);
1485*d546e47aSAdrian Chadd 	}
1486*d546e47aSAdrian Chadd 	if (phy->rf_rev <= 2) {
1487*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x7c, 0x20);
1488*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5a, 0x70);
1489*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5b, 0x7b);
1490*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x5c, 0xb0);
1491*d546e47aSAdrian Chadd 	}
1492*d546e47aSAdrian Chadd 	BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
1493*d546e47aSAdrian Chadd 
1494*d546e47aSAdrian Chadd 	bwn_phy_g_switch_chan(mac, old_channel, 0);
1495*d546e47aSAdrian Chadd 
1496*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0014, 0x0200);
1497*d546e47aSAdrian Chadd 	if (phy->rf_rev >= 6)
1498*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
1499*d546e47aSAdrian Chadd 	else
1500*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
1501*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0038, 0x0668);
1502*d546e47aSAdrian Chadd 	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
1503*d546e47aSAdrian Chadd 	    pg->pg_txctl);
1504*d546e47aSAdrian Chadd 	if (phy->rf_rev <= 5)
1505*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
1506*d546e47aSAdrian Chadd 	if (phy->rf_rev <= 2)
1507*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x005d, 0x000d);
1508*d546e47aSAdrian Chadd 
1509*d546e47aSAdrian Chadd 	if (phy->analog == 4) {
1510*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x3e4, 9);
1511*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, 0x61, 0x0fff);
1512*d546e47aSAdrian Chadd 	} else
1513*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
1514*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_B)
1515*d546e47aSAdrian Chadd 		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1516*d546e47aSAdrian Chadd 	else if (phy->type == BWN_PHYTYPE_G)
1517*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x03e6, 0x0);
1518*d546e47aSAdrian Chadd }
1519*d546e47aSAdrian Chadd 
1520*d546e47aSAdrian Chadd static void
1521*d546e47aSAdrian Chadd bwn_phy_init_a(struct bwn_mac *mac)
1522*d546e47aSAdrian Chadd {
1523*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1524*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
1525*d546e47aSAdrian Chadd 
1526*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
1527*d546e47aSAdrian Chadd 	    ("%s:%d: fail", __func__, __LINE__));
1528*d546e47aSAdrian Chadd 
1529*d546e47aSAdrian Chadd 	if (phy->rev >= 6) {
1530*d546e47aSAdrian Chadd 		if (phy->type == BWN_PHYTYPE_A)
1531*d546e47aSAdrian Chadd 			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
1532*d546e47aSAdrian Chadd 		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
1533*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
1534*d546e47aSAdrian Chadd 		else
1535*d546e47aSAdrian Chadd 			BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
1536*d546e47aSAdrian Chadd 	}
1537*d546e47aSAdrian Chadd 
1538*d546e47aSAdrian Chadd 	bwn_wa_init(mac);
1539*d546e47aSAdrian Chadd 
1540*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_G &&
1541*d546e47aSAdrian Chadd 	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL))
1542*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
1543*d546e47aSAdrian Chadd }
1544*d546e47aSAdrian Chadd 
1545*d546e47aSAdrian Chadd static void
1546*d546e47aSAdrian Chadd bwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
1547*d546e47aSAdrian Chadd {
1548*d546e47aSAdrian Chadd 	int i;
1549*d546e47aSAdrian Chadd 
1550*d546e47aSAdrian Chadd 	for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
1551*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
1552*d546e47aSAdrian Chadd }
1553*d546e47aSAdrian Chadd 
1554*d546e47aSAdrian Chadd static void
1555*d546e47aSAdrian Chadd bwn_wa_agc(struct bwn_mac *mac)
1556*d546e47aSAdrian Chadd {
1557*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1558*d546e47aSAdrian Chadd 
1559*d546e47aSAdrian Chadd 	if (phy->rev == 1) {
1560*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
1561*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
1562*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
1563*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
1564*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
1565*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
1566*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
1567*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
1568*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
1569*d546e47aSAdrian Chadd 	} else {
1570*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
1571*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
1572*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
1573*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
1574*d546e47aSAdrian Chadd 	}
1575*d546e47aSAdrian Chadd 
1576*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
1577*d546e47aSAdrian Chadd 	    0x5700);
1578*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
1579*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
1580*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
1581*d546e47aSAdrian Chadd 	BWN_RF_SET(mac, 0x7a, 0x0008);
1582*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
1583*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
1584*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
1585*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
1586*d546e47aSAdrian Chadd 	if (phy->rev == 1)
1587*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
1588*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
1589*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
1590*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
1591*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
1592*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
1593*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
1594*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
1595*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
1596*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
1597*d546e47aSAdrian Chadd 	if (phy->rev == 1) {
1598*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
1599*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
1600*d546e47aSAdrian Chadd 	} else {
1601*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
1602*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
1603*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
1604*d546e47aSAdrian Chadd 		if (phy->rev >= 6) {
1605*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
1606*d546e47aSAdrian Chadd 			BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
1607*d546e47aSAdrian Chadd 			    (uint16_t)~0xf000, 0x3000);
1608*d546e47aSAdrian Chadd 		}
1609*d546e47aSAdrian Chadd 	}
1610*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
1611*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
1612*d546e47aSAdrian Chadd 	if (phy->rev == 1) {
1613*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
1614*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
1615*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
1616*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
1617*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
1618*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
1619*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
1620*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
1621*d546e47aSAdrian Chadd 	} else {
1622*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
1623*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
1624*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
1625*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
1626*d546e47aSAdrian Chadd 	}
1627*d546e47aSAdrian Chadd 	if (phy->rev >= 6) {
1628*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
1629*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
1630*d546e47aSAdrian Chadd 	}
1631*d546e47aSAdrian Chadd 	BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
1632*d546e47aSAdrian Chadd }
1633*d546e47aSAdrian Chadd 
1634*d546e47aSAdrian Chadd static void
1635*d546e47aSAdrian Chadd bwn_wa_grev1(struct bwn_mac *mac)
1636*d546e47aSAdrian Chadd {
1637*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1638*d546e47aSAdrian Chadd 	int i;
1639*d546e47aSAdrian Chadd 	static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
1640*d546e47aSAdrian Chadd 	static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
1641*d546e47aSAdrian Chadd 	static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
1642*d546e47aSAdrian Chadd 
1643*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
1644*d546e47aSAdrian Chadd 
1645*d546e47aSAdrian Chadd 	/* init CRSTHRES and ANTDWELL */
1646*d546e47aSAdrian Chadd 	if (phy->rev == 1) {
1647*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
1648*d546e47aSAdrian Chadd 	} else if (phy->rev == 2) {
1649*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
1650*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
1651*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
1652*d546e47aSAdrian Chadd 	} else {
1653*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
1654*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
1655*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
1656*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
1657*d546e47aSAdrian Chadd 	}
1658*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
1659*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
1660*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
1661*d546e47aSAdrian Chadd 
1662*d546e47aSAdrian Chadd 	/* XXX support PHY-A??? */
1663*d546e47aSAdrian Chadd 	for (i = 0; i < N(bwn_tab_finefreqg); i++)
1664*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
1665*d546e47aSAdrian Chadd 		    bwn_tab_finefreqg[i]);
1666*d546e47aSAdrian Chadd 
1667*d546e47aSAdrian Chadd 	/* XXX support PHY-A??? */
1668*d546e47aSAdrian Chadd 	if (phy->rev == 1)
1669*d546e47aSAdrian Chadd 		for (i = 0; i < N(bwn_tab_noise_g1); i++)
1670*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
1671*d546e47aSAdrian Chadd 			    bwn_tab_noise_g1[i]);
1672*d546e47aSAdrian Chadd 	else
1673*d546e47aSAdrian Chadd 		for (i = 0; i < N(bwn_tab_noise_g2); i++)
1674*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
1675*d546e47aSAdrian Chadd 			    bwn_tab_noise_g2[i]);
1676*d546e47aSAdrian Chadd 
1677*d546e47aSAdrian Chadd 
1678*d546e47aSAdrian Chadd 	for (i = 0; i < N(bwn_tab_rotor); i++)
1679*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
1680*d546e47aSAdrian Chadd 		    bwn_tab_rotor[i]);
1681*d546e47aSAdrian Chadd 
1682*d546e47aSAdrian Chadd 	/* XXX support PHY-A??? */
1683*d546e47aSAdrian Chadd 	if (phy->rev >= 6) {
1684*d546e47aSAdrian Chadd 		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
1685*d546e47aSAdrian Chadd 		    BWN_PHY_ENCORE_EN)
1686*d546e47aSAdrian Chadd 			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
1687*d546e47aSAdrian Chadd 		else
1688*d546e47aSAdrian Chadd 			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
1689*d546e47aSAdrian Chadd 	} else
1690*d546e47aSAdrian Chadd 		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
1691*d546e47aSAdrian Chadd 
1692*d546e47aSAdrian Chadd 	for (i = 0; i < N(bwn_tab_retard); i++)
1693*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
1694*d546e47aSAdrian Chadd 		    bwn_tab_retard[i]);
1695*d546e47aSAdrian Chadd 
1696*d546e47aSAdrian Chadd 	if (phy->rev == 1) {
1697*d546e47aSAdrian Chadd 		for (i = 0; i < 16; i++)
1698*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
1699*d546e47aSAdrian Chadd 			    i, 0x0020);
1700*d546e47aSAdrian Chadd 	} else {
1701*d546e47aSAdrian Chadd 		for (i = 0; i < 32; i++)
1702*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
1703*d546e47aSAdrian Chadd 	}
1704*d546e47aSAdrian Chadd 
1705*d546e47aSAdrian Chadd 	bwn_wa_agc(mac);
1706*d546e47aSAdrian Chadd }
1707*d546e47aSAdrian Chadd 
1708*d546e47aSAdrian Chadd static void
1709*d546e47aSAdrian Chadd bwn_wa_grev26789(struct bwn_mac *mac)
1710*d546e47aSAdrian Chadd {
1711*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1712*d546e47aSAdrian Chadd 	int i;
1713*d546e47aSAdrian Chadd 	static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
1714*d546e47aSAdrian Chadd 	uint16_t ofdmrev;
1715*d546e47aSAdrian Chadd 
1716*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
1717*d546e47aSAdrian Chadd 
1718*d546e47aSAdrian Chadd 	bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
1719*d546e47aSAdrian Chadd 
1720*d546e47aSAdrian Chadd 	/* init CRSTHRES and ANTDWELL */
1721*d546e47aSAdrian Chadd 	if (phy->rev == 1)
1722*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
1723*d546e47aSAdrian Chadd 	else if (phy->rev == 2) {
1724*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
1725*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
1726*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
1727*d546e47aSAdrian Chadd 	} else {
1728*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
1729*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
1730*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
1731*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
1732*d546e47aSAdrian Chadd 	}
1733*d546e47aSAdrian Chadd 
1734*d546e47aSAdrian Chadd 	for (i = 0; i < 64; i++)
1735*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
1736*d546e47aSAdrian Chadd 
1737*d546e47aSAdrian Chadd 	/* XXX support PHY-A??? */
1738*d546e47aSAdrian Chadd 	if (phy->rev == 1)
1739*d546e47aSAdrian Chadd 		for (i = 0; i < N(bwn_tab_noise_g1); i++)
1740*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
1741*d546e47aSAdrian Chadd 			    bwn_tab_noise_g1[i]);
1742*d546e47aSAdrian Chadd 	else
1743*d546e47aSAdrian Chadd 		for (i = 0; i < N(bwn_tab_noise_g2); i++)
1744*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
1745*d546e47aSAdrian Chadd 			    bwn_tab_noise_g2[i]);
1746*d546e47aSAdrian Chadd 
1747*d546e47aSAdrian Chadd 	/* XXX support PHY-A??? */
1748*d546e47aSAdrian Chadd 	if (phy->rev >= 6) {
1749*d546e47aSAdrian Chadd 		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
1750*d546e47aSAdrian Chadd 		    BWN_PHY_ENCORE_EN)
1751*d546e47aSAdrian Chadd 			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
1752*d546e47aSAdrian Chadd 		else
1753*d546e47aSAdrian Chadd 			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
1754*d546e47aSAdrian Chadd 	} else
1755*d546e47aSAdrian Chadd 		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
1756*d546e47aSAdrian Chadd 
1757*d546e47aSAdrian Chadd 	for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
1758*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
1759*d546e47aSAdrian Chadd 		    bwn_tab_sigmasqr2[i]);
1760*d546e47aSAdrian Chadd 
1761*d546e47aSAdrian Chadd 	if (phy->rev == 1) {
1762*d546e47aSAdrian Chadd 		for (i = 0; i < 16; i++)
1763*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
1764*d546e47aSAdrian Chadd 			    0x0020);
1765*d546e47aSAdrian Chadd 	} else {
1766*d546e47aSAdrian Chadd 		for (i = 0; i < 32; i++)
1767*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
1768*d546e47aSAdrian Chadd 	}
1769*d546e47aSAdrian Chadd 
1770*d546e47aSAdrian Chadd 	bwn_wa_agc(mac);
1771*d546e47aSAdrian Chadd 
1772*d546e47aSAdrian Chadd 	ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
1773*d546e47aSAdrian Chadd 	if (ofdmrev > 2) {
1774*d546e47aSAdrian Chadd 		if (phy->type == BWN_PHYTYPE_A)
1775*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
1776*d546e47aSAdrian Chadd 		else
1777*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
1778*d546e47aSAdrian Chadd 	} else {
1779*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
1780*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
1781*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
1782*d546e47aSAdrian Chadd 	}
1783*d546e47aSAdrian Chadd 
1784*d546e47aSAdrian Chadd 	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
1785*d546e47aSAdrian Chadd 	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
1786*d546e47aSAdrian Chadd }
1787*d546e47aSAdrian Chadd 
1788*d546e47aSAdrian Chadd static void
1789*d546e47aSAdrian Chadd bwn_wa_init(struct bwn_mac *mac)
1790*d546e47aSAdrian Chadd {
1791*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1792*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
1793*d546e47aSAdrian Chadd 
1794*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
1795*d546e47aSAdrian Chadd 
1796*d546e47aSAdrian Chadd 	switch (phy->rev) {
1797*d546e47aSAdrian Chadd 	case 1:
1798*d546e47aSAdrian Chadd 		bwn_wa_grev1(mac);
1799*d546e47aSAdrian Chadd 		break;
1800*d546e47aSAdrian Chadd 	case 2:
1801*d546e47aSAdrian Chadd 	case 6:
1802*d546e47aSAdrian Chadd 	case 7:
1803*d546e47aSAdrian Chadd 	case 8:
1804*d546e47aSAdrian Chadd 	case 9:
1805*d546e47aSAdrian Chadd 		bwn_wa_grev26789(mac);
1806*d546e47aSAdrian Chadd 		break;
1807*d546e47aSAdrian Chadd 	default:
1808*d546e47aSAdrian Chadd 		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1809*d546e47aSAdrian Chadd 	}
1810*d546e47aSAdrian Chadd 
1811*d546e47aSAdrian Chadd 	if (siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM ||
1812*d546e47aSAdrian Chadd 	    siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306 ||
1813*d546e47aSAdrian Chadd 	    siba_get_pci_revid(sc->sc_dev) != 0x17) {
1814*d546e47aSAdrian Chadd 		if (phy->rev < 2) {
1815*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
1816*d546e47aSAdrian Chadd 			    0x0002);
1817*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
1818*d546e47aSAdrian Chadd 			    0x0001);
1819*d546e47aSAdrian Chadd 		} else {
1820*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
1821*d546e47aSAdrian Chadd 			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
1822*d546e47aSAdrian Chadd 			if ((siba_sprom_get_bf_lo(sc->sc_dev) &
1823*d546e47aSAdrian Chadd 			     BWN_BFL_EXTLNA) &&
1824*d546e47aSAdrian Chadd 			    (phy->rev >= 7)) {
1825*d546e47aSAdrian Chadd 				BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
1826*d546e47aSAdrian Chadd 				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1827*d546e47aSAdrian Chadd 				    0x0020, 0x0001);
1828*d546e47aSAdrian Chadd 				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1829*d546e47aSAdrian Chadd 				    0x0021, 0x0001);
1830*d546e47aSAdrian Chadd 				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1831*d546e47aSAdrian Chadd 				    0x0022, 0x0001);
1832*d546e47aSAdrian Chadd 				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1833*d546e47aSAdrian Chadd 				    0x0023, 0x0000);
1834*d546e47aSAdrian Chadd 				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1835*d546e47aSAdrian Chadd 				    0x0000, 0x0000);
1836*d546e47aSAdrian Chadd 				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1837*d546e47aSAdrian Chadd 				    0x0003, 0x0002);
1838*d546e47aSAdrian Chadd 			}
1839*d546e47aSAdrian Chadd 		}
1840*d546e47aSAdrian Chadd 	}
1841*d546e47aSAdrian Chadd 	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) {
1842*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
1843*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
1844*d546e47aSAdrian Chadd 	}
1845*d546e47aSAdrian Chadd 
1846*d546e47aSAdrian Chadd 	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
1847*d546e47aSAdrian Chadd 	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
1848*d546e47aSAdrian Chadd }
1849*d546e47aSAdrian Chadd 
1850*d546e47aSAdrian Chadd static void
1851*d546e47aSAdrian Chadd bwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
1852*d546e47aSAdrian Chadd     uint16_t value)
1853*d546e47aSAdrian Chadd {
1854*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
1855*d546e47aSAdrian Chadd 	uint16_t addr;
1856*d546e47aSAdrian Chadd 
1857*d546e47aSAdrian Chadd 	addr = table + offset;
1858*d546e47aSAdrian Chadd 	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
1859*d546e47aSAdrian Chadd 	    (addr - 1 != pg->pg_ofdmtab_addr)) {
1860*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
1861*d546e47aSAdrian Chadd 		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
1862*d546e47aSAdrian Chadd 	}
1863*d546e47aSAdrian Chadd 	pg->pg_ofdmtab_addr = addr;
1864*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
1865*d546e47aSAdrian Chadd }
1866*d546e47aSAdrian Chadd 
1867*d546e47aSAdrian Chadd static void
1868*d546e47aSAdrian Chadd bwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
1869*d546e47aSAdrian Chadd     uint32_t value)
1870*d546e47aSAdrian Chadd {
1871*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
1872*d546e47aSAdrian Chadd 	uint16_t addr;
1873*d546e47aSAdrian Chadd 
1874*d546e47aSAdrian Chadd 	addr = table + offset;
1875*d546e47aSAdrian Chadd 	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
1876*d546e47aSAdrian Chadd 	    (addr - 1 != pg->pg_ofdmtab_addr)) {
1877*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
1878*d546e47aSAdrian Chadd 		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
1879*d546e47aSAdrian Chadd 	}
1880*d546e47aSAdrian Chadd 	pg->pg_ofdmtab_addr = addr;
1881*d546e47aSAdrian Chadd 
1882*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
1883*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
1884*d546e47aSAdrian Chadd }
1885*d546e47aSAdrian Chadd 
1886*d546e47aSAdrian Chadd static void
1887*d546e47aSAdrian Chadd bwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
1888*d546e47aSAdrian Chadd     uint16_t value)
1889*d546e47aSAdrian Chadd {
1890*d546e47aSAdrian Chadd 
1891*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
1892*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
1893*d546e47aSAdrian Chadd }
1894*d546e47aSAdrian Chadd 
1895*d546e47aSAdrian Chadd static void
1896*d546e47aSAdrian Chadd bwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
1897*d546e47aSAdrian Chadd {
1898*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1899*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
1900*d546e47aSAdrian Chadd 	unsigned int i, max_loop;
1901*d546e47aSAdrian Chadd 	uint16_t value;
1902*d546e47aSAdrian Chadd 	uint32_t buffer[5] = {
1903*d546e47aSAdrian Chadd 		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
1904*d546e47aSAdrian Chadd 	};
1905*d546e47aSAdrian Chadd 
1906*d546e47aSAdrian Chadd 	if (ofdm) {
1907*d546e47aSAdrian Chadd 		max_loop = 0x1e;
1908*d546e47aSAdrian Chadd 		buffer[0] = 0x000201cc;
1909*d546e47aSAdrian Chadd 	} else {
1910*d546e47aSAdrian Chadd 		max_loop = 0xfa;
1911*d546e47aSAdrian Chadd 		buffer[0] = 0x000b846e;
1912*d546e47aSAdrian Chadd 	}
1913*d546e47aSAdrian Chadd 
1914*d546e47aSAdrian Chadd 	BWN_ASSERT_LOCKED(mac->mac_sc);
1915*d546e47aSAdrian Chadd 
1916*d546e47aSAdrian Chadd 	for (i = 0; i < 5; i++)
1917*d546e47aSAdrian Chadd 		bwn_ram_write(mac, i * 4, buffer[i]);
1918*d546e47aSAdrian Chadd 
1919*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x0568, 0x0000);
1920*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x07c0,
1921*d546e47aSAdrian Chadd 	    (siba_get_revid(sc->sc_dev) < 11) ? 0x0000 : 0x0100);
1922*d546e47aSAdrian Chadd 	value = ((phy->type == BWN_PHYTYPE_A) ? 0x41 : 0x40);
1923*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x050c, value);
1924*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_LP)
1925*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x0514, 0x1a02);
1926*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x0508, 0x0000);
1927*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x050a, 0x0000);
1928*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x054c, 0x0000);
1929*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x056a, 0x0014);
1930*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x0568, 0x0826);
1931*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x0500, 0x0000);
1932*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_LP)
1933*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x0502, 0x0050);
1934*d546e47aSAdrian Chadd 	else
1935*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x0502, 0x0030);
1936*d546e47aSAdrian Chadd 
1937*d546e47aSAdrian Chadd 	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
1938*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x0051, 0x0017);
1939*d546e47aSAdrian Chadd 	for (i = 0x00; i < max_loop; i++) {
1940*d546e47aSAdrian Chadd 		value = BWN_READ_2(mac, 0x050e);
1941*d546e47aSAdrian Chadd 		if (value & 0x0080)
1942*d546e47aSAdrian Chadd 			break;
1943*d546e47aSAdrian Chadd 		DELAY(10);
1944*d546e47aSAdrian Chadd 	}
1945*d546e47aSAdrian Chadd 	for (i = 0x00; i < 0x0a; i++) {
1946*d546e47aSAdrian Chadd 		value = BWN_READ_2(mac, 0x050e);
1947*d546e47aSAdrian Chadd 		if (value & 0x0400)
1948*d546e47aSAdrian Chadd 			break;
1949*d546e47aSAdrian Chadd 		DELAY(10);
1950*d546e47aSAdrian Chadd 	}
1951*d546e47aSAdrian Chadd 	for (i = 0x00; i < 0x19; i++) {
1952*d546e47aSAdrian Chadd 		value = BWN_READ_2(mac, 0x0690);
1953*d546e47aSAdrian Chadd 		if (!(value & 0x0100))
1954*d546e47aSAdrian Chadd 			break;
1955*d546e47aSAdrian Chadd 		DELAY(10);
1956*d546e47aSAdrian Chadd 	}
1957*d546e47aSAdrian Chadd 	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
1958*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x0051, 0x0037);
1959*d546e47aSAdrian Chadd }
1960*d546e47aSAdrian Chadd 
1961*d546e47aSAdrian Chadd static void
1962*d546e47aSAdrian Chadd bwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
1963*d546e47aSAdrian Chadd {
1964*d546e47aSAdrian Chadd 	uint16_t value;
1965*d546e47aSAdrian Chadd 
1966*d546e47aSAdrian Chadd 	KASSERT(mac->mac_phy.type == BWN_PHYTYPE_G,
1967*d546e47aSAdrian Chadd 	    ("%s:%d: fail", __func__, __LINE__));
1968*d546e47aSAdrian Chadd 
1969*d546e47aSAdrian Chadd 	value = (uint8_t) (ctl->q);
1970*d546e47aSAdrian Chadd 	value |= ((uint8_t) (ctl->i)) << 8;
1971*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
1972*d546e47aSAdrian Chadd }
1973*d546e47aSAdrian Chadd 
1974*d546e47aSAdrian Chadd static uint16_t
1975*d546e47aSAdrian Chadd bwn_lo_calcfeed(struct bwn_mac *mac,
1976*d546e47aSAdrian Chadd     uint16_t lna, uint16_t pga, uint16_t trsw_rx)
1977*d546e47aSAdrian Chadd {
1978*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
1979*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
1980*d546e47aSAdrian Chadd 	uint16_t rfover;
1981*d546e47aSAdrian Chadd 	uint16_t feedthrough;
1982*d546e47aSAdrian Chadd 
1983*d546e47aSAdrian Chadd 	if (phy->gmode) {
1984*d546e47aSAdrian Chadd 		lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
1985*d546e47aSAdrian Chadd 		pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
1986*d546e47aSAdrian Chadd 
1987*d546e47aSAdrian Chadd 		KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
1988*d546e47aSAdrian Chadd 		    ("%s:%d: fail", __func__, __LINE__));
1989*d546e47aSAdrian Chadd 		KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
1990*d546e47aSAdrian Chadd 		    ("%s:%d: fail", __func__, __LINE__));
1991*d546e47aSAdrian Chadd 
1992*d546e47aSAdrian Chadd 		trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
1993*d546e47aSAdrian Chadd 
1994*d546e47aSAdrian Chadd 		rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
1995*d546e47aSAdrian Chadd 		if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) &&
1996*d546e47aSAdrian Chadd 		    phy->rev > 6)
1997*d546e47aSAdrian Chadd 			rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
1998*d546e47aSAdrian Chadd 
1999*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
2000*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
2001*d546e47aSAdrian Chadd 		DELAY(10);
2002*d546e47aSAdrian Chadd 		rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
2003*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
2004*d546e47aSAdrian Chadd 		DELAY(10);
2005*d546e47aSAdrian Chadd 		rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
2006*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
2007*d546e47aSAdrian Chadd 		DELAY(10);
2008*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
2009*d546e47aSAdrian Chadd 	} else {
2010*d546e47aSAdrian Chadd 		pga |= BWN_PHY_PGACTL_UNKNOWN;
2011*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
2012*d546e47aSAdrian Chadd 		DELAY(10);
2013*d546e47aSAdrian Chadd 		pga |= BWN_PHY_PGACTL_LOWBANDW;
2014*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
2015*d546e47aSAdrian Chadd 		DELAY(10);
2016*d546e47aSAdrian Chadd 		pga |= BWN_PHY_PGACTL_LPF;
2017*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
2018*d546e47aSAdrian Chadd 	}
2019*d546e47aSAdrian Chadd 	DELAY(21);
2020*d546e47aSAdrian Chadd 	feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
2021*d546e47aSAdrian Chadd 
2022*d546e47aSAdrian Chadd 	return (feedthrough);
2023*d546e47aSAdrian Chadd }
2024*d546e47aSAdrian Chadd 
2025*d546e47aSAdrian Chadd static uint16_t
2026*d546e47aSAdrian Chadd bwn_lo_txctl_regtable(struct bwn_mac *mac,
2027*d546e47aSAdrian Chadd     uint16_t *value, uint16_t *pad_mix_gain)
2028*d546e47aSAdrian Chadd {
2029*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2030*d546e47aSAdrian Chadd 	uint16_t reg, v, padmix;
2031*d546e47aSAdrian Chadd 
2032*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_B) {
2033*d546e47aSAdrian Chadd 		v = 0x30;
2034*d546e47aSAdrian Chadd 		if (phy->rf_rev <= 5) {
2035*d546e47aSAdrian Chadd 			reg = 0x43;
2036*d546e47aSAdrian Chadd 			padmix = 0;
2037*d546e47aSAdrian Chadd 		} else {
2038*d546e47aSAdrian Chadd 			reg = 0x52;
2039*d546e47aSAdrian Chadd 			padmix = 5;
2040*d546e47aSAdrian Chadd 		}
2041*d546e47aSAdrian Chadd 	} else {
2042*d546e47aSAdrian Chadd 		if (phy->rev >= 2 && phy->rf_rev == 8) {
2043*d546e47aSAdrian Chadd 			reg = 0x43;
2044*d546e47aSAdrian Chadd 			v = 0x10;
2045*d546e47aSAdrian Chadd 			padmix = 2;
2046*d546e47aSAdrian Chadd 		} else {
2047*d546e47aSAdrian Chadd 			reg = 0x52;
2048*d546e47aSAdrian Chadd 			v = 0x30;
2049*d546e47aSAdrian Chadd 			padmix = 5;
2050*d546e47aSAdrian Chadd 		}
2051*d546e47aSAdrian Chadd 	}
2052*d546e47aSAdrian Chadd 	if (value)
2053*d546e47aSAdrian Chadd 		*value = v;
2054*d546e47aSAdrian Chadd 	if (pad_mix_gain)
2055*d546e47aSAdrian Chadd 		*pad_mix_gain = padmix;
2056*d546e47aSAdrian Chadd 
2057*d546e47aSAdrian Chadd 	return (reg);
2058*d546e47aSAdrian Chadd }
2059*d546e47aSAdrian Chadd 
2060*d546e47aSAdrian Chadd static void
2061*d546e47aSAdrian Chadd bwn_lo_measure_txctl_values(struct bwn_mac *mac)
2062*d546e47aSAdrian Chadd {
2063*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2064*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2065*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2066*d546e47aSAdrian Chadd 	uint16_t reg, mask;
2067*d546e47aSAdrian Chadd 	uint16_t trsw_rx, pga;
2068*d546e47aSAdrian Chadd 	uint16_t rf_pctl_reg;
2069*d546e47aSAdrian Chadd 
2070*d546e47aSAdrian Chadd 	static const uint8_t tx_bias_values[] = {
2071*d546e47aSAdrian Chadd 		0x09, 0x08, 0x0a, 0x01, 0x00,
2072*d546e47aSAdrian Chadd 		0x02, 0x05, 0x04, 0x06,
2073*d546e47aSAdrian Chadd 	};
2074*d546e47aSAdrian Chadd 	static const uint8_t tx_magn_values[] = {
2075*d546e47aSAdrian Chadd 		0x70, 0x40,
2076*d546e47aSAdrian Chadd 	};
2077*d546e47aSAdrian Chadd 
2078*d546e47aSAdrian Chadd 	if (!BWN_HAS_LOOPBACK(phy)) {
2079*d546e47aSAdrian Chadd 		rf_pctl_reg = 6;
2080*d546e47aSAdrian Chadd 		trsw_rx = 2;
2081*d546e47aSAdrian Chadd 		pga = 0;
2082*d546e47aSAdrian Chadd 	} else {
2083*d546e47aSAdrian Chadd 		int lb_gain;
2084*d546e47aSAdrian Chadd 
2085*d546e47aSAdrian Chadd 		trsw_rx = 0;
2086*d546e47aSAdrian Chadd 		lb_gain = pg->pg_max_lb_gain / 2;
2087*d546e47aSAdrian Chadd 		if (lb_gain > 10) {
2088*d546e47aSAdrian Chadd 			rf_pctl_reg = 0;
2089*d546e47aSAdrian Chadd 			pga = abs(10 - lb_gain) / 6;
2090*d546e47aSAdrian Chadd 			pga = MIN(MAX(pga, 0), 15);
2091*d546e47aSAdrian Chadd 		} else {
2092*d546e47aSAdrian Chadd 			int cmp_val;
2093*d546e47aSAdrian Chadd 			int tmp;
2094*d546e47aSAdrian Chadd 
2095*d546e47aSAdrian Chadd 			pga = 0;
2096*d546e47aSAdrian Chadd 			cmp_val = 0x24;
2097*d546e47aSAdrian Chadd 			if ((phy->rev >= 2) &&
2098*d546e47aSAdrian Chadd 			    (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
2099*d546e47aSAdrian Chadd 				cmp_val = 0x3c;
2100*d546e47aSAdrian Chadd 			tmp = lb_gain;
2101*d546e47aSAdrian Chadd 			if ((10 - lb_gain) < cmp_val)
2102*d546e47aSAdrian Chadd 				tmp = (10 - lb_gain);
2103*d546e47aSAdrian Chadd 			if (tmp < 0)
2104*d546e47aSAdrian Chadd 				tmp += 6;
2105*d546e47aSAdrian Chadd 			else
2106*d546e47aSAdrian Chadd 				tmp += 3;
2107*d546e47aSAdrian Chadd 			cmp_val /= 4;
2108*d546e47aSAdrian Chadd 			tmp /= 4;
2109*d546e47aSAdrian Chadd 			if (tmp >= cmp_val)
2110*d546e47aSAdrian Chadd 				rf_pctl_reg = cmp_val;
2111*d546e47aSAdrian Chadd 			else
2112*d546e47aSAdrian Chadd 				rf_pctl_reg = tmp;
2113*d546e47aSAdrian Chadd 		}
2114*d546e47aSAdrian Chadd 	}
2115*d546e47aSAdrian Chadd 	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
2116*d546e47aSAdrian Chadd 	bwn_phy_g_set_bbatt(mac, 2);
2117*d546e47aSAdrian Chadd 
2118*d546e47aSAdrian Chadd 	reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
2119*d546e47aSAdrian Chadd 	mask = ~mask;
2120*d546e47aSAdrian Chadd 	BWN_RF_MASK(mac, reg, mask);
2121*d546e47aSAdrian Chadd 
2122*d546e47aSAdrian Chadd 	if (BWN_HAS_TXMAG(phy)) {
2123*d546e47aSAdrian Chadd 		int i, j;
2124*d546e47aSAdrian Chadd 		int feedthrough;
2125*d546e47aSAdrian Chadd 		int min_feedth = 0xffff;
2126*d546e47aSAdrian Chadd 		uint8_t tx_magn, tx_bias;
2127*d546e47aSAdrian Chadd 
2128*d546e47aSAdrian Chadd 		for (i = 0; i < N(tx_magn_values); i++) {
2129*d546e47aSAdrian Chadd 			tx_magn = tx_magn_values[i];
2130*d546e47aSAdrian Chadd 			BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
2131*d546e47aSAdrian Chadd 			for (j = 0; j < N(tx_bias_values); j++) {
2132*d546e47aSAdrian Chadd 				tx_bias = tx_bias_values[j];
2133*d546e47aSAdrian Chadd 				BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
2134*d546e47aSAdrian Chadd 				feedthrough = bwn_lo_calcfeed(mac, 0, pga,
2135*d546e47aSAdrian Chadd 				    trsw_rx);
2136*d546e47aSAdrian Chadd 				if (feedthrough < min_feedth) {
2137*d546e47aSAdrian Chadd 					lo->tx_bias = tx_bias;
2138*d546e47aSAdrian Chadd 					lo->tx_magn = tx_magn;
2139*d546e47aSAdrian Chadd 					min_feedth = feedthrough;
2140*d546e47aSAdrian Chadd 				}
2141*d546e47aSAdrian Chadd 				if (lo->tx_bias == 0)
2142*d546e47aSAdrian Chadd 					break;
2143*d546e47aSAdrian Chadd 			}
2144*d546e47aSAdrian Chadd 			BWN_RF_WRITE(mac, 0x52,
2145*d546e47aSAdrian Chadd 					  (BWN_RF_READ(mac, 0x52)
2146*d546e47aSAdrian Chadd 					   & 0xff00) | lo->tx_bias | lo->
2147*d546e47aSAdrian Chadd 					  tx_magn);
2148*d546e47aSAdrian Chadd 		}
2149*d546e47aSAdrian Chadd 	} else {
2150*d546e47aSAdrian Chadd 		lo->tx_magn = 0;
2151*d546e47aSAdrian Chadd 		lo->tx_bias = 0;
2152*d546e47aSAdrian Chadd 		BWN_RF_MASK(mac, 0x52, 0xfff0);
2153*d546e47aSAdrian Chadd 	}
2154*d546e47aSAdrian Chadd 
2155*d546e47aSAdrian Chadd 	BWN_GETTIME(lo->txctl_measured_time);
2156*d546e47aSAdrian Chadd }
2157*d546e47aSAdrian Chadd 
2158*d546e47aSAdrian Chadd static void
2159*d546e47aSAdrian Chadd bwn_lo_get_powervector(struct bwn_mac *mac)
2160*d546e47aSAdrian Chadd {
2161*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2162*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2163*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2164*d546e47aSAdrian Chadd 	int i;
2165*d546e47aSAdrian Chadd 	uint64_t tmp;
2166*d546e47aSAdrian Chadd 	uint64_t power_vector = 0;
2167*d546e47aSAdrian Chadd 
2168*d546e47aSAdrian Chadd 	for (i = 0; i < 8; i += 2) {
2169*d546e47aSAdrian Chadd 		tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
2170*d546e47aSAdrian Chadd 		power_vector |= (tmp << (i * 8));
2171*d546e47aSAdrian Chadd 		bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
2172*d546e47aSAdrian Chadd 	}
2173*d546e47aSAdrian Chadd 	if (power_vector)
2174*d546e47aSAdrian Chadd 		lo->power_vector = power_vector;
2175*d546e47aSAdrian Chadd 
2176*d546e47aSAdrian Chadd 	BWN_GETTIME(lo->pwr_vec_read_time);
2177*d546e47aSAdrian Chadd }
2178*d546e47aSAdrian Chadd 
2179*d546e47aSAdrian Chadd static void
2180*d546e47aSAdrian Chadd bwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
2181*d546e47aSAdrian Chadd     int use_trsw_rx)
2182*d546e47aSAdrian Chadd {
2183*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2184*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2185*d546e47aSAdrian Chadd 	uint16_t tmp;
2186*d546e47aSAdrian Chadd 
2187*d546e47aSAdrian Chadd 	if (max_rx_gain < 0)
2188*d546e47aSAdrian Chadd 		max_rx_gain = 0;
2189*d546e47aSAdrian Chadd 
2190*d546e47aSAdrian Chadd 	if (BWN_HAS_LOOPBACK(phy)) {
2191*d546e47aSAdrian Chadd 		int trsw_rx = 0;
2192*d546e47aSAdrian Chadd 		int trsw_rx_gain;
2193*d546e47aSAdrian Chadd 
2194*d546e47aSAdrian Chadd 		if (use_trsw_rx) {
2195*d546e47aSAdrian Chadd 			trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
2196*d546e47aSAdrian Chadd 			if (max_rx_gain >= trsw_rx_gain) {
2197*d546e47aSAdrian Chadd 				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
2198*d546e47aSAdrian Chadd 				trsw_rx = 0x20;
2199*d546e47aSAdrian Chadd 			}
2200*d546e47aSAdrian Chadd 		} else
2201*d546e47aSAdrian Chadd 			trsw_rx_gain = max_rx_gain;
2202*d546e47aSAdrian Chadd 		if (trsw_rx_gain < 9) {
2203*d546e47aSAdrian Chadd 			pg->pg_lna_lod_gain = 0;
2204*d546e47aSAdrian Chadd 		} else {
2205*d546e47aSAdrian Chadd 			pg->pg_lna_lod_gain = 1;
2206*d546e47aSAdrian Chadd 			trsw_rx_gain -= 8;
2207*d546e47aSAdrian Chadd 		}
2208*d546e47aSAdrian Chadd 		trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
2209*d546e47aSAdrian Chadd 		pg->pg_pga_gain = trsw_rx_gain / 3;
2210*d546e47aSAdrian Chadd 		if (pg->pg_pga_gain >= 5) {
2211*d546e47aSAdrian Chadd 			pg->pg_pga_gain -= 5;
2212*d546e47aSAdrian Chadd 			pg->pg_lna_gain = 2;
2213*d546e47aSAdrian Chadd 		} else
2214*d546e47aSAdrian Chadd 			pg->pg_lna_gain = 0;
2215*d546e47aSAdrian Chadd 	} else {
2216*d546e47aSAdrian Chadd 		pg->pg_lna_gain = 0;
2217*d546e47aSAdrian Chadd 		pg->pg_trsw_rx_gain = 0x20;
2218*d546e47aSAdrian Chadd 		if (max_rx_gain >= 0x14) {
2219*d546e47aSAdrian Chadd 			pg->pg_lna_lod_gain = 1;
2220*d546e47aSAdrian Chadd 			pg->pg_pga_gain = 2;
2221*d546e47aSAdrian Chadd 		} else if (max_rx_gain >= 0x12) {
2222*d546e47aSAdrian Chadd 			pg->pg_lna_lod_gain = 1;
2223*d546e47aSAdrian Chadd 			pg->pg_pga_gain = 1;
2224*d546e47aSAdrian Chadd 		} else if (max_rx_gain >= 0xf) {
2225*d546e47aSAdrian Chadd 			pg->pg_lna_lod_gain = 1;
2226*d546e47aSAdrian Chadd 			pg->pg_pga_gain = 0;
2227*d546e47aSAdrian Chadd 		} else {
2228*d546e47aSAdrian Chadd 			pg->pg_lna_lod_gain = 0;
2229*d546e47aSAdrian Chadd 			pg->pg_pga_gain = 0;
2230*d546e47aSAdrian Chadd 		}
2231*d546e47aSAdrian Chadd 	}
2232*d546e47aSAdrian Chadd 
2233*d546e47aSAdrian Chadd 	tmp = BWN_RF_READ(mac, 0x7a);
2234*d546e47aSAdrian Chadd 	if (pg->pg_lna_lod_gain == 0)
2235*d546e47aSAdrian Chadd 		tmp &= ~0x0008;
2236*d546e47aSAdrian Chadd 	else
2237*d546e47aSAdrian Chadd 		tmp |= 0x0008;
2238*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x7a, tmp);
2239*d546e47aSAdrian Chadd }
2240*d546e47aSAdrian Chadd 
2241*d546e47aSAdrian Chadd static void
2242*d546e47aSAdrian Chadd bwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
2243*d546e47aSAdrian Chadd {
2244*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2245*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2246*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
2247*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2248*d546e47aSAdrian Chadd 	struct timespec ts;
2249*d546e47aSAdrian Chadd 	uint16_t tmp;
2250*d546e47aSAdrian Chadd 
2251*d546e47aSAdrian Chadd 	if (bwn_has_hwpctl(mac)) {
2252*d546e47aSAdrian Chadd 		sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
2253*d546e47aSAdrian Chadd 		sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
2254*d546e47aSAdrian Chadd 		sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
2255*d546e47aSAdrian Chadd 		sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
2256*d546e47aSAdrian Chadd 		sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
2257*d546e47aSAdrian Chadd 
2258*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
2259*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
2260*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
2261*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
2262*d546e47aSAdrian Chadd 	}
2263*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_B &&
2264*d546e47aSAdrian Chadd 	    phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
2265*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
2266*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
2267*d546e47aSAdrian Chadd 	}
2268*d546e47aSAdrian Chadd 	if (phy->rev >= 2) {
2269*d546e47aSAdrian Chadd 		sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
2270*d546e47aSAdrian Chadd 		sav->phy_analogoverval =
2271*d546e47aSAdrian Chadd 		    BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
2272*d546e47aSAdrian Chadd 		sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
2273*d546e47aSAdrian Chadd 		sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
2274*d546e47aSAdrian Chadd 		sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
2275*d546e47aSAdrian Chadd 		sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
2276*d546e47aSAdrian Chadd 		sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
2277*d546e47aSAdrian Chadd 
2278*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
2279*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
2280*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
2281*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
2282*d546e47aSAdrian Chadd 		if (phy->type == BWN_PHYTYPE_G) {
2283*d546e47aSAdrian Chadd 			if ((phy->rev >= 7) &&
2284*d546e47aSAdrian Chadd 			    (siba_sprom_get_bf_lo(sc->sc_dev) &
2285*d546e47aSAdrian Chadd 			     BWN_BFL_EXTLNA)) {
2286*d546e47aSAdrian Chadd 				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
2287*d546e47aSAdrian Chadd 			} else {
2288*d546e47aSAdrian Chadd 				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
2289*d546e47aSAdrian Chadd 			}
2290*d546e47aSAdrian Chadd 		} else {
2291*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
2292*d546e47aSAdrian Chadd 		}
2293*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
2294*d546e47aSAdrian Chadd 	}
2295*d546e47aSAdrian Chadd 	sav->reg0 = BWN_READ_2(mac, 0x3f4);
2296*d546e47aSAdrian Chadd 	sav->reg1 = BWN_READ_2(mac, 0x3e2);
2297*d546e47aSAdrian Chadd 	sav->rf0 = BWN_RF_READ(mac, 0x43);
2298*d546e47aSAdrian Chadd 	sav->rf1 = BWN_RF_READ(mac, 0x7a);
2299*d546e47aSAdrian Chadd 	sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
2300*d546e47aSAdrian Chadd 	sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
2301*d546e47aSAdrian Chadd 	sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
2302*d546e47aSAdrian Chadd 	sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
2303*d546e47aSAdrian Chadd 
2304*d546e47aSAdrian Chadd 	if (!BWN_HAS_TXMAG(phy)) {
2305*d546e47aSAdrian Chadd 		sav->rf2 = BWN_RF_READ(mac, 0x52);
2306*d546e47aSAdrian Chadd 		sav->rf2 &= 0x00f0;
2307*d546e47aSAdrian Chadd 	}
2308*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_B) {
2309*d546e47aSAdrian Chadd 		sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
2310*d546e47aSAdrian Chadd 		sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
2311*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
2312*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
2313*d546e47aSAdrian Chadd 	} else {
2314*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
2315*d546e47aSAdrian Chadd 			    | 0x8000);
2316*d546e47aSAdrian Chadd 	}
2317*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
2318*d546e47aSAdrian Chadd 		    & 0xf000);
2319*d546e47aSAdrian Chadd 
2320*d546e47aSAdrian Chadd 	tmp =
2321*d546e47aSAdrian Chadd 	    (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
2322*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, tmp, 0x007f);
2323*d546e47aSAdrian Chadd 
2324*d546e47aSAdrian Chadd 	tmp = sav->phy_syncctl;
2325*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
2326*d546e47aSAdrian Chadd 	tmp = sav->rf1;
2327*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
2328*d546e47aSAdrian Chadd 
2329*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
2330*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_G ||
2331*d546e47aSAdrian Chadd 	    (phy->type == BWN_PHYTYPE_B &&
2332*d546e47aSAdrian Chadd 	     phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
2333*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
2334*d546e47aSAdrian Chadd 	} else
2335*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
2336*d546e47aSAdrian Chadd 	if (phy->rev >= 2)
2337*d546e47aSAdrian Chadd 		bwn_dummy_transmission(mac, 0, 1);
2338*d546e47aSAdrian Chadd 	bwn_phy_g_switch_chan(mac, 6, 0);
2339*d546e47aSAdrian Chadd 	BWN_RF_READ(mac, 0x51);
2340*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_G)
2341*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
2342*d546e47aSAdrian Chadd 
2343*d546e47aSAdrian Chadd 	nanouptime(&ts);
2344*d546e47aSAdrian Chadd 	if (ieee80211_time_before(lo->txctl_measured_time,
2345*d546e47aSAdrian Chadd 	    (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
2346*d546e47aSAdrian Chadd 		bwn_lo_measure_txctl_values(mac);
2347*d546e47aSAdrian Chadd 
2348*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
2349*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
2350*d546e47aSAdrian Chadd 	else {
2351*d546e47aSAdrian Chadd 		if (phy->type == BWN_PHYTYPE_B)
2352*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
2353*d546e47aSAdrian Chadd 		else
2354*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
2355*d546e47aSAdrian Chadd 	}
2356*d546e47aSAdrian Chadd }
2357*d546e47aSAdrian Chadd 
2358*d546e47aSAdrian Chadd static void
2359*d546e47aSAdrian Chadd bwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
2360*d546e47aSAdrian Chadd {
2361*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2362*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2363*d546e47aSAdrian Chadd 	uint16_t tmp;
2364*d546e47aSAdrian Chadd 
2365*d546e47aSAdrian Chadd 	if (phy->rev >= 2) {
2366*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
2367*d546e47aSAdrian Chadd 		tmp = (pg->pg_pga_gain << 8);
2368*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
2369*d546e47aSAdrian Chadd 		DELAY(5);
2370*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
2371*d546e47aSAdrian Chadd 		DELAY(2);
2372*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
2373*d546e47aSAdrian Chadd 	} else {
2374*d546e47aSAdrian Chadd 		tmp = (pg->pg_pga_gain | 0xefa0);
2375*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
2376*d546e47aSAdrian Chadd 	}
2377*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_G) {
2378*d546e47aSAdrian Chadd 		if (phy->rev >= 3)
2379*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
2380*d546e47aSAdrian Chadd 		else
2381*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
2382*d546e47aSAdrian Chadd 		if (phy->rev >= 2)
2383*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
2384*d546e47aSAdrian Chadd 		else
2385*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
2386*d546e47aSAdrian Chadd 	}
2387*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x3f4, sav->reg0);
2388*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
2389*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
2390*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
2391*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
2392*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x43, sav->rf0);
2393*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x7a, sav->rf1);
2394*d546e47aSAdrian Chadd 	if (!BWN_HAS_TXMAG(phy)) {
2395*d546e47aSAdrian Chadd 		tmp = sav->rf2;
2396*d546e47aSAdrian Chadd 		BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
2397*d546e47aSAdrian Chadd 	}
2398*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x3e2, sav->reg1);
2399*d546e47aSAdrian Chadd 	if (phy->type == BWN_PHYTYPE_B &&
2400*d546e47aSAdrian Chadd 	    phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
2401*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
2402*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
2403*d546e47aSAdrian Chadd 	}
2404*d546e47aSAdrian Chadd 	if (phy->rev >= 2) {
2405*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
2406*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
2407*d546e47aSAdrian Chadd 			      sav->phy_analogoverval);
2408*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
2409*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
2410*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
2411*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
2412*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
2413*d546e47aSAdrian Chadd 	}
2414*d546e47aSAdrian Chadd 	if (bwn_has_hwpctl(mac)) {
2415*d546e47aSAdrian Chadd 		tmp = (sav->phy_lomask & 0xbfff);
2416*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
2417*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
2418*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
2419*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
2420*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
2421*d546e47aSAdrian Chadd 	}
2422*d546e47aSAdrian Chadd 	bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
2423*d546e47aSAdrian Chadd }
2424*d546e47aSAdrian Chadd 
2425*d546e47aSAdrian Chadd static int
2426*d546e47aSAdrian Chadd bwn_lo_probe_loctl(struct bwn_mac *mac,
2427*d546e47aSAdrian Chadd     struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
2428*d546e47aSAdrian Chadd {
2429*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2430*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2431*d546e47aSAdrian Chadd 	struct bwn_loctl orig, test;
2432*d546e47aSAdrian Chadd 	struct bwn_loctl prev = { -100, -100 };
2433*d546e47aSAdrian Chadd 	static const struct bwn_loctl modifiers[] = {
2434*d546e47aSAdrian Chadd 		{  1,  1,}, {  1,  0,}, {  1, -1,}, {  0, -1,},
2435*d546e47aSAdrian Chadd 		{ -1, -1,}, { -1,  0,}, { -1,  1,}, {  0,  1,}
2436*d546e47aSAdrian Chadd 	};
2437*d546e47aSAdrian Chadd 	int begin, end, lower = 0, i;
2438*d546e47aSAdrian Chadd 	uint16_t feedth;
2439*d546e47aSAdrian Chadd 
2440*d546e47aSAdrian Chadd 	if (d->curstate == 0) {
2441*d546e47aSAdrian Chadd 		begin = 1;
2442*d546e47aSAdrian Chadd 		end = 8;
2443*d546e47aSAdrian Chadd 	} else if (d->curstate % 2 == 0) {
2444*d546e47aSAdrian Chadd 		begin = d->curstate - 1;
2445*d546e47aSAdrian Chadd 		end = d->curstate + 1;
2446*d546e47aSAdrian Chadd 	} else {
2447*d546e47aSAdrian Chadd 		begin = d->curstate - 2;
2448*d546e47aSAdrian Chadd 		end = d->curstate + 2;
2449*d546e47aSAdrian Chadd 	}
2450*d546e47aSAdrian Chadd 	if (begin < 1)
2451*d546e47aSAdrian Chadd 		begin += 8;
2452*d546e47aSAdrian Chadd 	if (end > 8)
2453*d546e47aSAdrian Chadd 		end -= 8;
2454*d546e47aSAdrian Chadd 
2455*d546e47aSAdrian Chadd 	memcpy(&orig, probe, sizeof(struct bwn_loctl));
2456*d546e47aSAdrian Chadd 	i = begin;
2457*d546e47aSAdrian Chadd 	d->curstate = i;
2458*d546e47aSAdrian Chadd 	while (1) {
2459*d546e47aSAdrian Chadd 		KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
2460*d546e47aSAdrian Chadd 		memcpy(&test, &orig, sizeof(struct bwn_loctl));
2461*d546e47aSAdrian Chadd 		test.i += modifiers[i - 1].i * d->multipler;
2462*d546e47aSAdrian Chadd 		test.q += modifiers[i - 1].q * d->multipler;
2463*d546e47aSAdrian Chadd 		if ((test.i != prev.i || test.q != prev.q) &&
2464*d546e47aSAdrian Chadd 		    (abs(test.i) <= 16 && abs(test.q) <= 16)) {
2465*d546e47aSAdrian Chadd 			bwn_lo_write(mac, &test);
2466*d546e47aSAdrian Chadd 			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
2467*d546e47aSAdrian Chadd 			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
2468*d546e47aSAdrian Chadd 			if (feedth < d->feedth) {
2469*d546e47aSAdrian Chadd 				memcpy(probe, &test,
2470*d546e47aSAdrian Chadd 				    sizeof(struct bwn_loctl));
2471*d546e47aSAdrian Chadd 				lower = 1;
2472*d546e47aSAdrian Chadd 				d->feedth = feedth;
2473*d546e47aSAdrian Chadd 				if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
2474*d546e47aSAdrian Chadd 					break;
2475*d546e47aSAdrian Chadd 			}
2476*d546e47aSAdrian Chadd 		}
2477*d546e47aSAdrian Chadd 		memcpy(&prev, &test, sizeof(prev));
2478*d546e47aSAdrian Chadd 		if (i == end)
2479*d546e47aSAdrian Chadd 			break;
2480*d546e47aSAdrian Chadd 		if (i == 8)
2481*d546e47aSAdrian Chadd 			i = 1;
2482*d546e47aSAdrian Chadd 		else
2483*d546e47aSAdrian Chadd 			i++;
2484*d546e47aSAdrian Chadd 		d->curstate = i;
2485*d546e47aSAdrian Chadd 	}
2486*d546e47aSAdrian Chadd 
2487*d546e47aSAdrian Chadd 	return (lower);
2488*d546e47aSAdrian Chadd }
2489*d546e47aSAdrian Chadd 
2490*d546e47aSAdrian Chadd static void
2491*d546e47aSAdrian Chadd bwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
2492*d546e47aSAdrian Chadd {
2493*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2494*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2495*d546e47aSAdrian Chadd 	struct bwn_lo_g_sm d;
2496*d546e47aSAdrian Chadd 	struct bwn_loctl probe;
2497*d546e47aSAdrian Chadd 	int lower, repeat, cnt = 0;
2498*d546e47aSAdrian Chadd 	uint16_t feedth;
2499*d546e47aSAdrian Chadd 
2500*d546e47aSAdrian Chadd 	d.nmeasure = 0;
2501*d546e47aSAdrian Chadd 	d.multipler = 1;
2502*d546e47aSAdrian Chadd 	if (BWN_HAS_LOOPBACK(phy))
2503*d546e47aSAdrian Chadd 		d.multipler = 3;
2504*d546e47aSAdrian Chadd 
2505*d546e47aSAdrian Chadd 	memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
2506*d546e47aSAdrian Chadd 	repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
2507*d546e47aSAdrian Chadd 
2508*d546e47aSAdrian Chadd 	do {
2509*d546e47aSAdrian Chadd 		bwn_lo_write(mac, &d.loctl);
2510*d546e47aSAdrian Chadd 		feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
2511*d546e47aSAdrian Chadd 		    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
2512*d546e47aSAdrian Chadd 		if (feedth < 0x258) {
2513*d546e47aSAdrian Chadd 			if (feedth >= 0x12c)
2514*d546e47aSAdrian Chadd 				*rxgain += 6;
2515*d546e47aSAdrian Chadd 			else
2516*d546e47aSAdrian Chadd 				*rxgain += 3;
2517*d546e47aSAdrian Chadd 			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
2518*d546e47aSAdrian Chadd 			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
2519*d546e47aSAdrian Chadd 		}
2520*d546e47aSAdrian Chadd 		d.feedth = feedth;
2521*d546e47aSAdrian Chadd 		d.curstate = 0;
2522*d546e47aSAdrian Chadd 		do {
2523*d546e47aSAdrian Chadd 			KASSERT(d.curstate >= 0 && d.curstate <= 8,
2524*d546e47aSAdrian Chadd 			    ("%s:%d: fail", __func__, __LINE__));
2525*d546e47aSAdrian Chadd 			memcpy(&probe, &d.loctl,
2526*d546e47aSAdrian Chadd 			       sizeof(struct bwn_loctl));
2527*d546e47aSAdrian Chadd 			lower = bwn_lo_probe_loctl(mac, &probe, &d);
2528*d546e47aSAdrian Chadd 			if (!lower)
2529*d546e47aSAdrian Chadd 				break;
2530*d546e47aSAdrian Chadd 			if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
2531*d546e47aSAdrian Chadd 				break;
2532*d546e47aSAdrian Chadd 			memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
2533*d546e47aSAdrian Chadd 			d.nmeasure++;
2534*d546e47aSAdrian Chadd 		} while (d.nmeasure < 24);
2535*d546e47aSAdrian Chadd 		memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
2536*d546e47aSAdrian Chadd 
2537*d546e47aSAdrian Chadd 		if (BWN_HAS_LOOPBACK(phy)) {
2538*d546e47aSAdrian Chadd 			if (d.feedth > 0x1194)
2539*d546e47aSAdrian Chadd 				*rxgain -= 6;
2540*d546e47aSAdrian Chadd 			else if (d.feedth < 0x5dc)
2541*d546e47aSAdrian Chadd 				*rxgain += 3;
2542*d546e47aSAdrian Chadd 			if (cnt == 0) {
2543*d546e47aSAdrian Chadd 				if (d.feedth <= 0x5dc) {
2544*d546e47aSAdrian Chadd 					d.multipler = 1;
2545*d546e47aSAdrian Chadd 					cnt++;
2546*d546e47aSAdrian Chadd 				} else
2547*d546e47aSAdrian Chadd 					d.multipler = 2;
2548*d546e47aSAdrian Chadd 			} else if (cnt == 2)
2549*d546e47aSAdrian Chadd 				d.multipler = 1;
2550*d546e47aSAdrian Chadd 		}
2551*d546e47aSAdrian Chadd 		bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
2552*d546e47aSAdrian Chadd 	} while (++cnt < repeat);
2553*d546e47aSAdrian Chadd }
2554*d546e47aSAdrian Chadd 
2555*d546e47aSAdrian Chadd static struct bwn_lo_calib *
2556*d546e47aSAdrian Chadd bwn_lo_calibset(struct bwn_mac *mac,
2557*d546e47aSAdrian Chadd     const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
2558*d546e47aSAdrian Chadd {
2559*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2560*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2561*d546e47aSAdrian Chadd 	struct bwn_loctl loctl = { 0, 0 };
2562*d546e47aSAdrian Chadd 	struct bwn_lo_calib *cal;
2563*d546e47aSAdrian Chadd 	struct bwn_lo_g_value sval = { 0 };
2564*d546e47aSAdrian Chadd 	int rxgain;
2565*d546e47aSAdrian Chadd 	uint16_t pad, reg, value;
2566*d546e47aSAdrian Chadd 
2567*d546e47aSAdrian Chadd 	sval.old_channel = phy->chan;
2568*d546e47aSAdrian Chadd 	bwn_mac_suspend(mac);
2569*d546e47aSAdrian Chadd 	bwn_lo_save(mac, &sval);
2570*d546e47aSAdrian Chadd 
2571*d546e47aSAdrian Chadd 	reg = bwn_lo_txctl_regtable(mac, &value, &pad);
2572*d546e47aSAdrian Chadd 	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
2573*d546e47aSAdrian Chadd 	BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
2574*d546e47aSAdrian Chadd 
2575*d546e47aSAdrian Chadd 	rxgain = (rfatt->att * 2) + (bbatt->att / 2);
2576*d546e47aSAdrian Chadd 	if (rfatt->padmix)
2577*d546e47aSAdrian Chadd 		rxgain -= pad;
2578*d546e47aSAdrian Chadd 	if (BWN_HAS_LOOPBACK(phy))
2579*d546e47aSAdrian Chadd 		rxgain += pg->pg_max_lb_gain;
2580*d546e47aSAdrian Chadd 	bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
2581*d546e47aSAdrian Chadd 	bwn_phy_g_set_bbatt(mac, bbatt->att);
2582*d546e47aSAdrian Chadd 	bwn_lo_probe_sm(mac, &loctl, &rxgain);
2583*d546e47aSAdrian Chadd 
2584*d546e47aSAdrian Chadd 	bwn_lo_restore(mac, &sval);
2585*d546e47aSAdrian Chadd 	bwn_mac_enable(mac);
2586*d546e47aSAdrian Chadd 
2587*d546e47aSAdrian Chadd 	cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
2588*d546e47aSAdrian Chadd 	if (!cal) {
2589*d546e47aSAdrian Chadd 		device_printf(mac->mac_sc->sc_dev, "out of memory\n");
2590*d546e47aSAdrian Chadd 		return (NULL);
2591*d546e47aSAdrian Chadd 	}
2592*d546e47aSAdrian Chadd 	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
2593*d546e47aSAdrian Chadd 	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
2594*d546e47aSAdrian Chadd 	memcpy(&cal->ctl, &loctl, sizeof(loctl));
2595*d546e47aSAdrian Chadd 
2596*d546e47aSAdrian Chadd 	BWN_GETTIME(cal->calib_time);
2597*d546e47aSAdrian Chadd 
2598*d546e47aSAdrian Chadd 	return (cal);
2599*d546e47aSAdrian Chadd }
2600*d546e47aSAdrian Chadd 
2601*d546e47aSAdrian Chadd static struct bwn_lo_calib *
2602*d546e47aSAdrian Chadd bwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
2603*d546e47aSAdrian Chadd     const struct bwn_rfatt *rfatt)
2604*d546e47aSAdrian Chadd {
2605*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
2606*d546e47aSAdrian Chadd 	struct bwn_lo_calib *c;
2607*d546e47aSAdrian Chadd 
2608*d546e47aSAdrian Chadd 	TAILQ_FOREACH(c, &lo->calib_list, list) {
2609*d546e47aSAdrian Chadd 		if (!BWN_BBATTCMP(&c->bbatt, bbatt))
2610*d546e47aSAdrian Chadd 			continue;
2611*d546e47aSAdrian Chadd 		if (!BWN_RFATTCMP(&c->rfatt, rfatt))
2612*d546e47aSAdrian Chadd 			continue;
2613*d546e47aSAdrian Chadd 		return (c);
2614*d546e47aSAdrian Chadd 	}
2615*d546e47aSAdrian Chadd 
2616*d546e47aSAdrian Chadd 	c = bwn_lo_calibset(mac, bbatt, rfatt);
2617*d546e47aSAdrian Chadd 	if (!c)
2618*d546e47aSAdrian Chadd 		return (NULL);
2619*d546e47aSAdrian Chadd 	TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
2620*d546e47aSAdrian Chadd 
2621*d546e47aSAdrian Chadd 	return (c);
2622*d546e47aSAdrian Chadd }
2623*d546e47aSAdrian Chadd 
2624*d546e47aSAdrian Chadd static void
2625*d546e47aSAdrian Chadd bwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
2626*d546e47aSAdrian Chadd {
2627*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2628*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2629*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
2630*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2631*d546e47aSAdrian Chadd 	const struct bwn_rfatt *rfatt;
2632*d546e47aSAdrian Chadd 	const struct bwn_bbatt *bbatt;
2633*d546e47aSAdrian Chadd 	uint64_t pvector;
2634*d546e47aSAdrian Chadd 	int i;
2635*d546e47aSAdrian Chadd 	int rf_offset, bb_offset;
2636*d546e47aSAdrian Chadd 	uint8_t changed = 0;
2637*d546e47aSAdrian Chadd 
2638*d546e47aSAdrian Chadd 	KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
2639*d546e47aSAdrian Chadd 	KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
2640*d546e47aSAdrian Chadd 	    ("%s:%d: fail", __func__, __LINE__));
2641*d546e47aSAdrian Chadd 
2642*d546e47aSAdrian Chadd 	pvector = lo->power_vector;
2643*d546e47aSAdrian Chadd 	if (!update && !pvector)
2644*d546e47aSAdrian Chadd 		return;
2645*d546e47aSAdrian Chadd 
2646*d546e47aSAdrian Chadd 	bwn_mac_suspend(mac);
2647*d546e47aSAdrian Chadd 
2648*d546e47aSAdrian Chadd 	for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
2649*d546e47aSAdrian Chadd 		struct bwn_lo_calib *cal;
2650*d546e47aSAdrian Chadd 		int idx;
2651*d546e47aSAdrian Chadd 		uint16_t val;
2652*d546e47aSAdrian Chadd 
2653*d546e47aSAdrian Chadd 		if (!update && !(pvector & (((uint64_t)1ULL) << i)))
2654*d546e47aSAdrian Chadd 			continue;
2655*d546e47aSAdrian Chadd 		bb_offset = i / lo->rfatt.len;
2656*d546e47aSAdrian Chadd 		rf_offset = i % lo->rfatt.len;
2657*d546e47aSAdrian Chadd 		bbatt = &(lo->bbatt.array[bb_offset]);
2658*d546e47aSAdrian Chadd 		rfatt = &(lo->rfatt.array[rf_offset]);
2659*d546e47aSAdrian Chadd 
2660*d546e47aSAdrian Chadd 		cal = bwn_lo_calibset(mac, bbatt, rfatt);
2661*d546e47aSAdrian Chadd 		if (!cal) {
2662*d546e47aSAdrian Chadd 			device_printf(sc->sc_dev, "LO: Could not "
2663*d546e47aSAdrian Chadd 			    "calibrate DC table entry\n");
2664*d546e47aSAdrian Chadd 			continue;
2665*d546e47aSAdrian Chadd 		}
2666*d546e47aSAdrian Chadd 		val = (uint8_t)(cal->ctl.q);
2667*d546e47aSAdrian Chadd 		val |= ((uint8_t)(cal->ctl.i)) << 4;
2668*d546e47aSAdrian Chadd 		free(cal, M_DEVBUF);
2669*d546e47aSAdrian Chadd 
2670*d546e47aSAdrian Chadd 		idx = i / 2;
2671*d546e47aSAdrian Chadd 		if (i % 2)
2672*d546e47aSAdrian Chadd 			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
2673*d546e47aSAdrian Chadd 			    | ((val & 0x00ff) << 8);
2674*d546e47aSAdrian Chadd 		else
2675*d546e47aSAdrian Chadd 			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
2676*d546e47aSAdrian Chadd 			    | (val & 0x00ff);
2677*d546e47aSAdrian Chadd 		changed = 1;
2678*d546e47aSAdrian Chadd 	}
2679*d546e47aSAdrian Chadd 	if (changed) {
2680*d546e47aSAdrian Chadd 		for (i = 0; i < BWN_DC_LT_SIZE; i++)
2681*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
2682*d546e47aSAdrian Chadd 	}
2683*d546e47aSAdrian Chadd 	bwn_mac_enable(mac);
2684*d546e47aSAdrian Chadd }
2685*d546e47aSAdrian Chadd 
2686*d546e47aSAdrian Chadd static void
2687*d546e47aSAdrian Chadd bwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
2688*d546e47aSAdrian Chadd {
2689*d546e47aSAdrian Chadd 
2690*d546e47aSAdrian Chadd 	if (!rf->padmix)
2691*d546e47aSAdrian Chadd 		return;
2692*d546e47aSAdrian Chadd 	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
2693*d546e47aSAdrian Chadd 		rf->att = 4;
2694*d546e47aSAdrian Chadd }
2695*d546e47aSAdrian Chadd 
2696*d546e47aSAdrian Chadd static void
2697*d546e47aSAdrian Chadd bwn_lo_g_adjust(struct bwn_mac *mac)
2698*d546e47aSAdrian Chadd {
2699*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
2700*d546e47aSAdrian Chadd 	struct bwn_lo_calib *cal;
2701*d546e47aSAdrian Chadd 	struct bwn_rfatt rf;
2702*d546e47aSAdrian Chadd 
2703*d546e47aSAdrian Chadd 	memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
2704*d546e47aSAdrian Chadd 	bwn_lo_fixup_rfatt(&rf);
2705*d546e47aSAdrian Chadd 
2706*d546e47aSAdrian Chadd 	cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
2707*d546e47aSAdrian Chadd 	if (!cal)
2708*d546e47aSAdrian Chadd 		return;
2709*d546e47aSAdrian Chadd 	bwn_lo_write(mac, &cal->ctl);
2710*d546e47aSAdrian Chadd }
2711*d546e47aSAdrian Chadd 
2712*d546e47aSAdrian Chadd static void
2713*d546e47aSAdrian Chadd bwn_lo_g_init(struct bwn_mac *mac)
2714*d546e47aSAdrian Chadd {
2715*d546e47aSAdrian Chadd 
2716*d546e47aSAdrian Chadd 	if (!bwn_has_hwpctl(mac))
2717*d546e47aSAdrian Chadd 		return;
2718*d546e47aSAdrian Chadd 
2719*d546e47aSAdrian Chadd 	bwn_lo_get_powervector(mac);
2720*d546e47aSAdrian Chadd 	bwn_phy_g_dc_lookup_init(mac, 1);
2721*d546e47aSAdrian Chadd }
2722*d546e47aSAdrian Chadd 
2723*d546e47aSAdrian Chadd static int16_t
2724*d546e47aSAdrian Chadd bwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
2725*d546e47aSAdrian Chadd {
2726*d546e47aSAdrian Chadd 
2727*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
2728*d546e47aSAdrian Chadd 	return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
2729*d546e47aSAdrian Chadd }
2730*d546e47aSAdrian Chadd 
2731*d546e47aSAdrian Chadd static void
2732*d546e47aSAdrian Chadd bwn_nrssi_threshold(struct bwn_mac *mac)
2733*d546e47aSAdrian Chadd {
2734*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2735*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2736*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
2737*d546e47aSAdrian Chadd 	int32_t a, b;
2738*d546e47aSAdrian Chadd 	int16_t tmp16;
2739*d546e47aSAdrian Chadd 	uint16_t tmpu16;
2740*d546e47aSAdrian Chadd 
2741*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2742*d546e47aSAdrian Chadd 
2743*d546e47aSAdrian Chadd 	if (phy->gmode && (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
2744*d546e47aSAdrian Chadd 		if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
2745*d546e47aSAdrian Chadd 			a = 0x13;
2746*d546e47aSAdrian Chadd 			b = 0x12;
2747*d546e47aSAdrian Chadd 		} else {
2748*d546e47aSAdrian Chadd 			a = 0xe;
2749*d546e47aSAdrian Chadd 			b = 0x11;
2750*d546e47aSAdrian Chadd 		}
2751*d546e47aSAdrian Chadd 
2752*d546e47aSAdrian Chadd 		a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
2753*d546e47aSAdrian Chadd 		a += (pg->pg_nrssi[0] << 6);
2754*d546e47aSAdrian Chadd 		a += (a < 32) ? 31 : 32;
2755*d546e47aSAdrian Chadd 		a = a >> 6;
2756*d546e47aSAdrian Chadd 		a = MIN(MAX(a, -31), 31);
2757*d546e47aSAdrian Chadd 
2758*d546e47aSAdrian Chadd 		b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
2759*d546e47aSAdrian Chadd 		b += (pg->pg_nrssi[0] << 6);
2760*d546e47aSAdrian Chadd 		if (b < 32)
2761*d546e47aSAdrian Chadd 			b += 31;
2762*d546e47aSAdrian Chadd 		else
2763*d546e47aSAdrian Chadd 			b += 32;
2764*d546e47aSAdrian Chadd 		b = b >> 6;
2765*d546e47aSAdrian Chadd 		b = MIN(MAX(b, -31), 31);
2766*d546e47aSAdrian Chadd 
2767*d546e47aSAdrian Chadd 		tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
2768*d546e47aSAdrian Chadd 		tmpu16 |= ((uint32_t)b & 0x0000003f);
2769*d546e47aSAdrian Chadd 		tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
2770*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x048a, tmpu16);
2771*d546e47aSAdrian Chadd 		return;
2772*d546e47aSAdrian Chadd 	}
2773*d546e47aSAdrian Chadd 
2774*d546e47aSAdrian Chadd 	tmp16 = bwn_nrssi_read(mac, 0x20);
2775*d546e47aSAdrian Chadd 	if (tmp16 >= 0x20)
2776*d546e47aSAdrian Chadd 		tmp16 -= 0x40;
2777*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
2778*d546e47aSAdrian Chadd }
2779*d546e47aSAdrian Chadd 
2780*d546e47aSAdrian Chadd static void
2781*d546e47aSAdrian Chadd bwn_nrssi_slope_11g(struct bwn_mac *mac)
2782*d546e47aSAdrian Chadd {
2783*d546e47aSAdrian Chadd #define	SAVE_RF_MAX		3
2784*d546e47aSAdrian Chadd #define	SAVE_PHY_COMM_MAX	4
2785*d546e47aSAdrian Chadd #define	SAVE_PHY3_MAX		8
2786*d546e47aSAdrian Chadd 	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
2787*d546e47aSAdrian Chadd 		{ 0x7a, 0x52, 0x43 };
2788*d546e47aSAdrian Chadd 	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
2789*d546e47aSAdrian Chadd 		{ 0x15, 0x5a, 0x59, 0x58 };
2790*d546e47aSAdrian Chadd 	static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
2791*d546e47aSAdrian Chadd 		0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
2792*d546e47aSAdrian Chadd 		0x0801, 0x0060, 0x0014, 0x0478
2793*d546e47aSAdrian Chadd 	};
2794*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2795*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
2796*d546e47aSAdrian Chadd 	int32_t i, tmp32, phy3_idx = 0;
2797*d546e47aSAdrian Chadd 	uint16_t delta, tmp;
2798*d546e47aSAdrian Chadd 	uint16_t save_rf[SAVE_RF_MAX];
2799*d546e47aSAdrian Chadd 	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
2800*d546e47aSAdrian Chadd 	uint16_t save_phy3[SAVE_PHY3_MAX];
2801*d546e47aSAdrian Chadd 	uint16_t ant_div, phy0, chan_ex;
2802*d546e47aSAdrian Chadd 	int16_t nrssi0, nrssi1;
2803*d546e47aSAdrian Chadd 
2804*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_G,
2805*d546e47aSAdrian Chadd 	    ("%s:%d: fail", __func__, __LINE__));
2806*d546e47aSAdrian Chadd 
2807*d546e47aSAdrian Chadd 	if (phy->rf_rev >= 9)
2808*d546e47aSAdrian Chadd 		return;
2809*d546e47aSAdrian Chadd 	if (phy->rf_rev == 8)
2810*d546e47aSAdrian Chadd 		bwn_nrssi_offset(mac);
2811*d546e47aSAdrian Chadd 
2812*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
2813*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, 0x0802, 0xfffc);
2814*d546e47aSAdrian Chadd 
2815*d546e47aSAdrian Chadd 	/*
2816*d546e47aSAdrian Chadd 	 * Save RF/PHY registers for later restoration
2817*d546e47aSAdrian Chadd 	 */
2818*d546e47aSAdrian Chadd 	ant_div = BWN_READ_2(mac, 0x03e2);
2819*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
2820*d546e47aSAdrian Chadd 	for (i = 0; i < SAVE_RF_MAX; ++i)
2821*d546e47aSAdrian Chadd 		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
2822*d546e47aSAdrian Chadd 	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
2823*d546e47aSAdrian Chadd 		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
2824*d546e47aSAdrian Chadd 
2825*d546e47aSAdrian Chadd 	phy0 = BWN_READ_2(mac, BWN_PHY0);
2826*d546e47aSAdrian Chadd 	chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
2827*d546e47aSAdrian Chadd 	if (phy->rev >= 3) {
2828*d546e47aSAdrian Chadd 		for (i = 0; i < SAVE_PHY3_MAX; ++i)
2829*d546e47aSAdrian Chadd 			save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
2830*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x002e, 0);
2831*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
2832*d546e47aSAdrian Chadd 		switch (phy->rev) {
2833*d546e47aSAdrian Chadd 		case 4:
2834*d546e47aSAdrian Chadd 		case 6:
2835*d546e47aSAdrian Chadd 		case 7:
2836*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, 0x0478, 0x0100);
2837*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, 0x0801, 0x0040);
2838*d546e47aSAdrian Chadd 			break;
2839*d546e47aSAdrian Chadd 		case 3:
2840*d546e47aSAdrian Chadd 		case 5:
2841*d546e47aSAdrian Chadd 			BWN_PHY_MASK(mac, 0x0801, 0xffbf);
2842*d546e47aSAdrian Chadd 			break;
2843*d546e47aSAdrian Chadd 		}
2844*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0060, 0x0040);
2845*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0014, 0x0200);
2846*d546e47aSAdrian Chadd 	}
2847*d546e47aSAdrian Chadd 	/*
2848*d546e47aSAdrian Chadd 	 * Calculate nrssi0
2849*d546e47aSAdrian Chadd 	 */
2850*d546e47aSAdrian Chadd 	BWN_RF_SET(mac, 0x007a, 0x0070);
2851*d546e47aSAdrian Chadd 	bwn_set_all_gains(mac, 0, 8, 0);
2852*d546e47aSAdrian Chadd 	BWN_RF_MASK(mac, 0x007a, 0x00f7);
2853*d546e47aSAdrian Chadd 	if (phy->rev >= 2) {
2854*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
2855*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
2856*d546e47aSAdrian Chadd 	}
2857*d546e47aSAdrian Chadd 	BWN_RF_SET(mac, 0x007a, 0x0080);
2858*d546e47aSAdrian Chadd 	DELAY(20);
2859*d546e47aSAdrian Chadd 
2860*d546e47aSAdrian Chadd 	nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
2861*d546e47aSAdrian Chadd 	if (nrssi0 >= 0x0020)
2862*d546e47aSAdrian Chadd 		nrssi0 -= 0x0040;
2863*d546e47aSAdrian Chadd 
2864*d546e47aSAdrian Chadd 	/*
2865*d546e47aSAdrian Chadd 	 * Calculate nrssi1
2866*d546e47aSAdrian Chadd 	 */
2867*d546e47aSAdrian Chadd 	BWN_RF_MASK(mac, 0x007a, 0x007f);
2868*d546e47aSAdrian Chadd 	if (phy->rev >= 2)
2869*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
2870*d546e47aSAdrian Chadd 
2871*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
2872*d546e47aSAdrian Chadd 	    BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
2873*d546e47aSAdrian Chadd 	BWN_RF_SET(mac, 0x007a, 0x000f);
2874*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0015, 0xf330);
2875*d546e47aSAdrian Chadd 	if (phy->rev >= 2) {
2876*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
2877*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
2878*d546e47aSAdrian Chadd 	}
2879*d546e47aSAdrian Chadd 
2880*d546e47aSAdrian Chadd 	bwn_set_all_gains(mac, 3, 0, 1);
2881*d546e47aSAdrian Chadd 	if (phy->rf_rev == 8) {
2882*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x0043, 0x001f);
2883*d546e47aSAdrian Chadd 	} else {
2884*d546e47aSAdrian Chadd 		tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
2885*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
2886*d546e47aSAdrian Chadd 		tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
2887*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
2888*d546e47aSAdrian Chadd 	}
2889*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x005a, 0x0480);
2890*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0059, 0x0810);
2891*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0058, 0x000d);
2892*d546e47aSAdrian Chadd 	DELAY(20);
2893*d546e47aSAdrian Chadd 	nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
2894*d546e47aSAdrian Chadd 
2895*d546e47aSAdrian Chadd 	/*
2896*d546e47aSAdrian Chadd 	 * Install calculated narrow RSSI values
2897*d546e47aSAdrian Chadd 	 */
2898*d546e47aSAdrian Chadd 	if (nrssi1 >= 0x0020)
2899*d546e47aSAdrian Chadd 		nrssi1 -= 0x0040;
2900*d546e47aSAdrian Chadd 	if (nrssi0 == nrssi1)
2901*d546e47aSAdrian Chadd 		pg->pg_nrssi_slope = 0x00010000;
2902*d546e47aSAdrian Chadd 	else
2903*d546e47aSAdrian Chadd 		pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
2904*d546e47aSAdrian Chadd 	if (nrssi0 >= -4) {
2905*d546e47aSAdrian Chadd 		pg->pg_nrssi[0] = nrssi1;
2906*d546e47aSAdrian Chadd 		pg->pg_nrssi[1] = nrssi0;
2907*d546e47aSAdrian Chadd 	}
2908*d546e47aSAdrian Chadd 
2909*d546e47aSAdrian Chadd 	/*
2910*d546e47aSAdrian Chadd 	 * Restore saved RF/PHY registers
2911*d546e47aSAdrian Chadd 	 */
2912*d546e47aSAdrian Chadd 	if (phy->rev >= 3) {
2913*d546e47aSAdrian Chadd 		for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
2914*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
2915*d546e47aSAdrian Chadd 			    save_phy3[phy3_idx]);
2916*d546e47aSAdrian Chadd 		}
2917*d546e47aSAdrian Chadd 	}
2918*d546e47aSAdrian Chadd 	if (phy->rev >= 2) {
2919*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, 0x0812, 0xffcf);
2920*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, 0x0811, 0xffcf);
2921*d546e47aSAdrian Chadd 	}
2922*d546e47aSAdrian Chadd 
2923*d546e47aSAdrian Chadd 	for (i = 0; i < SAVE_RF_MAX; ++i)
2924*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
2925*d546e47aSAdrian Chadd 
2926*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x03e2, ant_div);
2927*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, 0x03e6, phy0);
2928*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
2929*d546e47aSAdrian Chadd 
2930*d546e47aSAdrian Chadd 	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
2931*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
2932*d546e47aSAdrian Chadd 
2933*d546e47aSAdrian Chadd 	bwn_spu_workaround(mac, phy->chan);
2934*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
2935*d546e47aSAdrian Chadd 	bwn_set_original_gains(mac);
2936*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
2937*d546e47aSAdrian Chadd 	if (phy->rev >= 3) {
2938*d546e47aSAdrian Chadd 		for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
2939*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
2940*d546e47aSAdrian Chadd 			    save_phy3[phy3_idx]);
2941*d546e47aSAdrian Chadd 		}
2942*d546e47aSAdrian Chadd 	}
2943*d546e47aSAdrian Chadd 
2944*d546e47aSAdrian Chadd 	delta = 0x1f - pg->pg_nrssi[0];
2945*d546e47aSAdrian Chadd 	for (i = 0; i < 64; i++) {
2946*d546e47aSAdrian Chadd 		tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
2947*d546e47aSAdrian Chadd 		tmp32 = MIN(MAX(tmp32, 0), 0x3f);
2948*d546e47aSAdrian Chadd 		pg->pg_nrssi_lt[i] = tmp32;
2949*d546e47aSAdrian Chadd 	}
2950*d546e47aSAdrian Chadd 
2951*d546e47aSAdrian Chadd 	bwn_nrssi_threshold(mac);
2952*d546e47aSAdrian Chadd #undef SAVE_RF_MAX
2953*d546e47aSAdrian Chadd #undef SAVE_PHY_COMM_MAX
2954*d546e47aSAdrian Chadd #undef SAVE_PHY3_MAX
2955*d546e47aSAdrian Chadd }
2956*d546e47aSAdrian Chadd 
2957*d546e47aSAdrian Chadd static void
2958*d546e47aSAdrian Chadd bwn_nrssi_offset(struct bwn_mac *mac)
2959*d546e47aSAdrian Chadd {
2960*d546e47aSAdrian Chadd #define	SAVE_RF_MAX		2
2961*d546e47aSAdrian Chadd #define	SAVE_PHY_COMM_MAX	10
2962*d546e47aSAdrian Chadd #define	SAVE_PHY6_MAX		8
2963*d546e47aSAdrian Chadd 	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
2964*d546e47aSAdrian Chadd 		{ 0x7a, 0x43 };
2965*d546e47aSAdrian Chadd 	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
2966*d546e47aSAdrian Chadd 		0x0001, 0x0811, 0x0812, 0x0814,
2967*d546e47aSAdrian Chadd 		0x0815, 0x005a, 0x0059, 0x0058,
2968*d546e47aSAdrian Chadd 		0x000a, 0x0003
2969*d546e47aSAdrian Chadd 	};
2970*d546e47aSAdrian Chadd 	static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
2971*d546e47aSAdrian Chadd 		0x002e, 0x002f, 0x080f, 0x0810,
2972*d546e47aSAdrian Chadd 		0x0801, 0x0060, 0x0014, 0x0478
2973*d546e47aSAdrian Chadd 	};
2974*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
2975*d546e47aSAdrian Chadd 	int i, phy6_idx = 0;
2976*d546e47aSAdrian Chadd 	uint16_t save_rf[SAVE_RF_MAX];
2977*d546e47aSAdrian Chadd 	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
2978*d546e47aSAdrian Chadd 	uint16_t save_phy6[SAVE_PHY6_MAX];
2979*d546e47aSAdrian Chadd 	int16_t nrssi;
2980*d546e47aSAdrian Chadd 	uint16_t saved = 0xffff;
2981*d546e47aSAdrian Chadd 
2982*d546e47aSAdrian Chadd 	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
2983*d546e47aSAdrian Chadd 		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
2984*d546e47aSAdrian Chadd 	for (i = 0; i < SAVE_RF_MAX; ++i)
2985*d546e47aSAdrian Chadd 		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
2986*d546e47aSAdrian Chadd 
2987*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, 0x0429, 0x7fff);
2988*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
2989*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, 0x0811, 0x000c);
2990*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
2991*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
2992*d546e47aSAdrian Chadd 	if (phy->rev >= 6) {
2993*d546e47aSAdrian Chadd 		for (i = 0; i < SAVE_PHY6_MAX; ++i)
2994*d546e47aSAdrian Chadd 			save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
2995*d546e47aSAdrian Chadd 
2996*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x002e, 0);
2997*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x002f, 0);
2998*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x080f, 0);
2999*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0810, 0);
3000*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0478, 0x0100);
3001*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0801, 0x0040);
3002*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0060, 0x0040);
3003*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0014, 0x0200);
3004*d546e47aSAdrian Chadd 	}
3005*d546e47aSAdrian Chadd 	BWN_RF_SET(mac, 0x007a, 0x0070);
3006*d546e47aSAdrian Chadd 	BWN_RF_SET(mac, 0x007a, 0x0080);
3007*d546e47aSAdrian Chadd 	DELAY(30);
3008*d546e47aSAdrian Chadd 
3009*d546e47aSAdrian Chadd 	nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
3010*d546e47aSAdrian Chadd 	if (nrssi >= 0x20)
3011*d546e47aSAdrian Chadd 		nrssi -= 0x40;
3012*d546e47aSAdrian Chadd 	if (nrssi == 31) {
3013*d546e47aSAdrian Chadd 		for (i = 7; i >= 4; i--) {
3014*d546e47aSAdrian Chadd 			BWN_RF_WRITE(mac, 0x007b, i);
3015*d546e47aSAdrian Chadd 			DELAY(20);
3016*d546e47aSAdrian Chadd 			nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
3017*d546e47aSAdrian Chadd 			    0x003f);
3018*d546e47aSAdrian Chadd 			if (nrssi >= 0x20)
3019*d546e47aSAdrian Chadd 				nrssi -= 0x40;
3020*d546e47aSAdrian Chadd 			if (nrssi < 31 && saved == 0xffff)
3021*d546e47aSAdrian Chadd 				saved = i;
3022*d546e47aSAdrian Chadd 		}
3023*d546e47aSAdrian Chadd 		if (saved == 0xffff)
3024*d546e47aSAdrian Chadd 			saved = 4;
3025*d546e47aSAdrian Chadd 	} else {
3026*d546e47aSAdrian Chadd 		BWN_RF_MASK(mac, 0x007a, 0x007f);
3027*d546e47aSAdrian Chadd 		if (phy->rev != 1) {
3028*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, 0x0814, 0x0001);
3029*d546e47aSAdrian Chadd 			BWN_PHY_MASK(mac, 0x0815, 0xfffe);
3030*d546e47aSAdrian Chadd 		}
3031*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0811, 0x000c);
3032*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0812, 0x000c);
3033*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0811, 0x0030);
3034*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0812, 0x0030);
3035*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x005a, 0x0480);
3036*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0059, 0x0810);
3037*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x0058, 0x000d);
3038*d546e47aSAdrian Chadd 		if (phy->rev == 0)
3039*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, 0x0003, 0x0122);
3040*d546e47aSAdrian Chadd 		else
3041*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, 0x000a, 0x2000);
3042*d546e47aSAdrian Chadd 		if (phy->rev != 1) {
3043*d546e47aSAdrian Chadd 			BWN_PHY_SET(mac, 0x0814, 0x0004);
3044*d546e47aSAdrian Chadd 			BWN_PHY_MASK(mac, 0x0815, 0xfffb);
3045*d546e47aSAdrian Chadd 		}
3046*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
3047*d546e47aSAdrian Chadd 		BWN_RF_SET(mac, 0x007a, 0x000f);
3048*d546e47aSAdrian Chadd 		bwn_set_all_gains(mac, 3, 0, 1);
3049*d546e47aSAdrian Chadd 		BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
3050*d546e47aSAdrian Chadd 		DELAY(30);
3051*d546e47aSAdrian Chadd 		nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
3052*d546e47aSAdrian Chadd 		if (nrssi >= 0x20)
3053*d546e47aSAdrian Chadd 			nrssi -= 0x40;
3054*d546e47aSAdrian Chadd 		if (nrssi == -32) {
3055*d546e47aSAdrian Chadd 			for (i = 0; i < 4; i++) {
3056*d546e47aSAdrian Chadd 				BWN_RF_WRITE(mac, 0x007b, i);
3057*d546e47aSAdrian Chadd 				DELAY(20);
3058*d546e47aSAdrian Chadd 				nrssi = (int16_t)((BWN_PHY_READ(mac,
3059*d546e47aSAdrian Chadd 				    0x047f) >> 8) & 0x003f);
3060*d546e47aSAdrian Chadd 				if (nrssi >= 0x20)
3061*d546e47aSAdrian Chadd 					nrssi -= 0x40;
3062*d546e47aSAdrian Chadd 				if (nrssi > -31 && saved == 0xffff)
3063*d546e47aSAdrian Chadd 					saved = i;
3064*d546e47aSAdrian Chadd 			}
3065*d546e47aSAdrian Chadd 			if (saved == 0xffff)
3066*d546e47aSAdrian Chadd 				saved = 3;
3067*d546e47aSAdrian Chadd 		} else
3068*d546e47aSAdrian Chadd 			saved = 0;
3069*d546e47aSAdrian Chadd 	}
3070*d546e47aSAdrian Chadd 	BWN_RF_WRITE(mac, 0x007b, saved);
3071*d546e47aSAdrian Chadd 
3072*d546e47aSAdrian Chadd 	/*
3073*d546e47aSAdrian Chadd 	 * Restore saved RF/PHY registers
3074*d546e47aSAdrian Chadd 	 */
3075*d546e47aSAdrian Chadd 	if (phy->rev >= 6) {
3076*d546e47aSAdrian Chadd 		for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
3077*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
3078*d546e47aSAdrian Chadd 			    save_phy6[phy6_idx]);
3079*d546e47aSAdrian Chadd 		}
3080*d546e47aSAdrian Chadd 	}
3081*d546e47aSAdrian Chadd 	if (phy->rev != 1) {
3082*d546e47aSAdrian Chadd 		for (i = 3; i < 5; i++)
3083*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
3084*d546e47aSAdrian Chadd 			    save_phy_comm[i]);
3085*d546e47aSAdrian Chadd 	}
3086*d546e47aSAdrian Chadd 	for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
3087*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
3088*d546e47aSAdrian Chadd 
3089*d546e47aSAdrian Chadd 	for (i = SAVE_RF_MAX - 1; i >= 0; --i)
3090*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
3091*d546e47aSAdrian Chadd 
3092*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
3093*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, 0x0429, 0x8000);
3094*d546e47aSAdrian Chadd 	bwn_set_original_gains(mac);
3095*d546e47aSAdrian Chadd 	if (phy->rev >= 6) {
3096*d546e47aSAdrian Chadd 		for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
3097*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
3098*d546e47aSAdrian Chadd 			    save_phy6[phy6_idx]);
3099*d546e47aSAdrian Chadd 		}
3100*d546e47aSAdrian Chadd 	}
3101*d546e47aSAdrian Chadd 
3102*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
3103*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
3104*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
3105*d546e47aSAdrian Chadd }
3106*d546e47aSAdrian Chadd 
3107*d546e47aSAdrian Chadd static void
3108*d546e47aSAdrian Chadd bwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
3109*d546e47aSAdrian Chadd     int16_t third)
3110*d546e47aSAdrian Chadd {
3111*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
3112*d546e47aSAdrian Chadd 	uint16_t i;
3113*d546e47aSAdrian Chadd 	uint16_t start = 0x08, end = 0x18;
3114*d546e47aSAdrian Chadd 	uint16_t tmp;
3115*d546e47aSAdrian Chadd 	uint16_t table;
3116*d546e47aSAdrian Chadd 
3117*d546e47aSAdrian Chadd 	if (phy->rev <= 1) {
3118*d546e47aSAdrian Chadd 		start = 0x10;
3119*d546e47aSAdrian Chadd 		end = 0x20;
3120*d546e47aSAdrian Chadd 	}
3121*d546e47aSAdrian Chadd 
3122*d546e47aSAdrian Chadd 	table = BWN_OFDMTAB_GAINX;
3123*d546e47aSAdrian Chadd 	if (phy->rev <= 1)
3124*d546e47aSAdrian Chadd 		table = BWN_OFDMTAB_GAINX_R1;
3125*d546e47aSAdrian Chadd 	for (i = 0; i < 4; i++)
3126*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, table, i, first);
3127*d546e47aSAdrian Chadd 
3128*d546e47aSAdrian Chadd 	for (i = start; i < end; i++)
3129*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, table, i, second);
3130*d546e47aSAdrian Chadd 
3131*d546e47aSAdrian Chadd 	if (third != -1) {
3132*d546e47aSAdrian Chadd 		tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
3133*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
3134*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
3135*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
3136*d546e47aSAdrian Chadd 	}
3137*d546e47aSAdrian Chadd 	bwn_dummy_transmission(mac, 0, 1);
3138*d546e47aSAdrian Chadd }
3139*d546e47aSAdrian Chadd 
3140*d546e47aSAdrian Chadd static void
3141*d546e47aSAdrian Chadd bwn_set_original_gains(struct bwn_mac *mac)
3142*d546e47aSAdrian Chadd {
3143*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
3144*d546e47aSAdrian Chadd 	uint16_t i, tmp;
3145*d546e47aSAdrian Chadd 	uint16_t table;
3146*d546e47aSAdrian Chadd 	uint16_t start = 0x0008, end = 0x0018;
3147*d546e47aSAdrian Chadd 
3148*d546e47aSAdrian Chadd 	if (phy->rev <= 1) {
3149*d546e47aSAdrian Chadd 		start = 0x0010;
3150*d546e47aSAdrian Chadd 		end = 0x0020;
3151*d546e47aSAdrian Chadd 	}
3152*d546e47aSAdrian Chadd 
3153*d546e47aSAdrian Chadd 	table = BWN_OFDMTAB_GAINX;
3154*d546e47aSAdrian Chadd 	if (phy->rev <= 1)
3155*d546e47aSAdrian Chadd 		table = BWN_OFDMTAB_GAINX_R1;
3156*d546e47aSAdrian Chadd 	for (i = 0; i < 4; i++) {
3157*d546e47aSAdrian Chadd 		tmp = (i & 0xfffc);
3158*d546e47aSAdrian Chadd 		tmp |= (i & 0x0001) << 1;
3159*d546e47aSAdrian Chadd 		tmp |= (i & 0x0002) >> 1;
3160*d546e47aSAdrian Chadd 
3161*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, table, i, tmp);
3162*d546e47aSAdrian Chadd 	}
3163*d546e47aSAdrian Chadd 
3164*d546e47aSAdrian Chadd 	for (i = start; i < end; i++)
3165*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, table, i, i - start);
3166*d546e47aSAdrian Chadd 
3167*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
3168*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
3169*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
3170*d546e47aSAdrian Chadd 	bwn_dummy_transmission(mac, 0, 1);
3171*d546e47aSAdrian Chadd }
3172*d546e47aSAdrian Chadd 
3173*d546e47aSAdrian Chadd static void
3174*d546e47aSAdrian Chadd bwn_phy_hwpctl_init(struct bwn_mac *mac)
3175*d546e47aSAdrian Chadd {
3176*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
3177*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
3178*d546e47aSAdrian Chadd 	struct bwn_rfatt old_rfatt, rfatt;
3179*d546e47aSAdrian Chadd 	struct bwn_bbatt old_bbatt, bbatt;
3180*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
3181*d546e47aSAdrian Chadd 	uint8_t old_txctl = 0;
3182*d546e47aSAdrian Chadd 
3183*d546e47aSAdrian Chadd 	KASSERT(phy->type == BWN_PHYTYPE_G,
3184*d546e47aSAdrian Chadd 	    ("%s:%d: fail", __func__, __LINE__));
3185*d546e47aSAdrian Chadd 
3186*d546e47aSAdrian Chadd 	if ((siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM) &&
3187*d546e47aSAdrian Chadd 	    (siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306))
3188*d546e47aSAdrian Chadd 		return;
3189*d546e47aSAdrian Chadd 
3190*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0028, 0x8018);
3191*d546e47aSAdrian Chadd 
3192*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
3193*d546e47aSAdrian Chadd 
3194*d546e47aSAdrian Chadd 	if (!phy->gmode)
3195*d546e47aSAdrian Chadd 		return;
3196*d546e47aSAdrian Chadd 	bwn_hwpctl_early_init(mac);
3197*d546e47aSAdrian Chadd 	if (pg->pg_curtssi == 0) {
3198*d546e47aSAdrian Chadd 		if (phy->rf_ver == 0x2050 && phy->analog == 0) {
3199*d546e47aSAdrian Chadd 			BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
3200*d546e47aSAdrian Chadd 		} else {
3201*d546e47aSAdrian Chadd 			memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
3202*d546e47aSAdrian Chadd 			memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
3203*d546e47aSAdrian Chadd 			old_txctl = pg->pg_txctl;
3204*d546e47aSAdrian Chadd 
3205*d546e47aSAdrian Chadd 			bbatt.att = 11;
3206*d546e47aSAdrian Chadd 			if (phy->rf_rev == 8) {
3207*d546e47aSAdrian Chadd 				rfatt.att = 15;
3208*d546e47aSAdrian Chadd 				rfatt.padmix = 1;
3209*d546e47aSAdrian Chadd 			} else {
3210*d546e47aSAdrian Chadd 				rfatt.att = 9;
3211*d546e47aSAdrian Chadd 				rfatt.padmix = 0;
3212*d546e47aSAdrian Chadd 			}
3213*d546e47aSAdrian Chadd 			bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
3214*d546e47aSAdrian Chadd 		}
3215*d546e47aSAdrian Chadd 		bwn_dummy_transmission(mac, 0, 1);
3216*d546e47aSAdrian Chadd 		pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
3217*d546e47aSAdrian Chadd 		if (phy->rf_ver == 0x2050 && phy->analog == 0)
3218*d546e47aSAdrian Chadd 			BWN_RF_MASK(mac, 0x0076, 0xff7b);
3219*d546e47aSAdrian Chadd 		else
3220*d546e47aSAdrian Chadd 			bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
3221*d546e47aSAdrian Chadd 			    &old_rfatt, old_txctl);
3222*d546e47aSAdrian Chadd 	}
3223*d546e47aSAdrian Chadd 	bwn_hwpctl_init_gphy(mac);
3224*d546e47aSAdrian Chadd 
3225*d546e47aSAdrian Chadd 	/* clear TSSI */
3226*d546e47aSAdrian Chadd 	bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
3227*d546e47aSAdrian Chadd 	bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
3228*d546e47aSAdrian Chadd 	bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
3229*d546e47aSAdrian Chadd 	bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
3230*d546e47aSAdrian Chadd }
3231*d546e47aSAdrian Chadd 
3232*d546e47aSAdrian Chadd static void
3233*d546e47aSAdrian Chadd bwn_hwpctl_early_init(struct bwn_mac *mac)
3234*d546e47aSAdrian Chadd {
3235*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
3236*d546e47aSAdrian Chadd 
3237*d546e47aSAdrian Chadd 	if (!bwn_has_hwpctl(mac)) {
3238*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x047a, 0xc111);
3239*d546e47aSAdrian Chadd 		return;
3240*d546e47aSAdrian Chadd 	}
3241*d546e47aSAdrian Chadd 
3242*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, 0x0036, 0xfeff);
3243*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x002f, 0x0202);
3244*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, 0x047c, 0x0002);
3245*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, 0x047a, 0xf000);
3246*d546e47aSAdrian Chadd 	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
3247*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
3248*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x005d, 0x8000);
3249*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
3250*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
3251*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0036, 0x0400);
3252*d546e47aSAdrian Chadd 	} else {
3253*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0036, 0x0200);
3254*d546e47aSAdrian Chadd 		BWN_PHY_SET(mac, 0x0036, 0x0400);
3255*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, 0x005d, 0x7fff);
3256*d546e47aSAdrian Chadd 		BWN_PHY_MASK(mac, 0x004f, 0xfffe);
3257*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
3258*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
3259*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
3260*d546e47aSAdrian Chadd 	}
3261*d546e47aSAdrian Chadd }
3262*d546e47aSAdrian Chadd 
3263*d546e47aSAdrian Chadd static void
3264*d546e47aSAdrian Chadd bwn_hwpctl_init_gphy(struct bwn_mac *mac)
3265*d546e47aSAdrian Chadd {
3266*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
3267*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
3268*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
3269*d546e47aSAdrian Chadd 	int i;
3270*d546e47aSAdrian Chadd 	uint16_t nr_written = 0, tmp, value;
3271*d546e47aSAdrian Chadd 	uint8_t rf, bb;
3272*d546e47aSAdrian Chadd 
3273*d546e47aSAdrian Chadd 	if (!bwn_has_hwpctl(mac)) {
3274*d546e47aSAdrian Chadd 		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
3275*d546e47aSAdrian Chadd 		return;
3276*d546e47aSAdrian Chadd 	}
3277*d546e47aSAdrian Chadd 
3278*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
3279*d546e47aSAdrian Chadd 	    (pg->pg_idletssi - pg->pg_curtssi));
3280*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
3281*d546e47aSAdrian Chadd 	    (pg->pg_idletssi - pg->pg_curtssi));
3282*d546e47aSAdrian Chadd 
3283*d546e47aSAdrian Chadd 	for (i = 0; i < 32; i++)
3284*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
3285*d546e47aSAdrian Chadd 	for (i = 32; i < 64; i++)
3286*d546e47aSAdrian Chadd 		bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
3287*d546e47aSAdrian Chadd 	for (i = 0; i < 64; i += 2) {
3288*d546e47aSAdrian Chadd 		value = (uint16_t) pg->pg_tssi2dbm[i];
3289*d546e47aSAdrian Chadd 		value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
3290*d546e47aSAdrian Chadd 		BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
3291*d546e47aSAdrian Chadd 	}
3292*d546e47aSAdrian Chadd 
3293*d546e47aSAdrian Chadd 	for (rf = 0; rf < lo->rfatt.len; rf++) {
3294*d546e47aSAdrian Chadd 		for (bb = 0; bb < lo->bbatt.len; bb++) {
3295*d546e47aSAdrian Chadd 			if (nr_written >= 0x40)
3296*d546e47aSAdrian Chadd 				return;
3297*d546e47aSAdrian Chadd 			tmp = lo->bbatt.array[bb].att;
3298*d546e47aSAdrian Chadd 			tmp <<= 8;
3299*d546e47aSAdrian Chadd 			if (phy->rf_rev == 8)
3300*d546e47aSAdrian Chadd 				tmp |= 0x50;
3301*d546e47aSAdrian Chadd 			else
3302*d546e47aSAdrian Chadd 				tmp |= 0x40;
3303*d546e47aSAdrian Chadd 			tmp |= lo->rfatt.array[rf].att;
3304*d546e47aSAdrian Chadd 			BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
3305*d546e47aSAdrian Chadd 			nr_written++;
3306*d546e47aSAdrian Chadd 		}
3307*d546e47aSAdrian Chadd 	}
3308*d546e47aSAdrian Chadd 
3309*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, 0x0060, 0xffbf);
3310*d546e47aSAdrian Chadd 	BWN_PHY_WRITE(mac, 0x0014, 0x0000);
3311*d546e47aSAdrian Chadd 
3312*d546e47aSAdrian Chadd 	KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
3313*d546e47aSAdrian Chadd 	BWN_PHY_SET(mac, 0x0478, 0x0800);
3314*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, 0x0478, 0xfeff);
3315*d546e47aSAdrian Chadd 	BWN_PHY_MASK(mac, 0x0801, 0xffbf);
3316*d546e47aSAdrian Chadd 
3317*d546e47aSAdrian Chadd 	bwn_phy_g_dc_lookup_init(mac, 1);
3318*d546e47aSAdrian Chadd 	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
3319*d546e47aSAdrian Chadd }
3320*d546e47aSAdrian Chadd 
3321*d546e47aSAdrian Chadd static void
3322*d546e47aSAdrian Chadd bwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
3323*d546e47aSAdrian Chadd {
3324*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
3325*d546e47aSAdrian Chadd 
3326*d546e47aSAdrian Chadd 	if (spu != 0)
3327*d546e47aSAdrian Chadd 		bwn_spu_workaround(mac, channel);
3328*d546e47aSAdrian Chadd 
3329*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
3330*d546e47aSAdrian Chadd 
3331*d546e47aSAdrian Chadd 	if (channel == 14) {
3332*d546e47aSAdrian Chadd 		if (siba_sprom_get_ccode(sc->sc_dev) == SIBA_CCODE_JAPAN)
3333*d546e47aSAdrian Chadd 			bwn_hf_write(mac,
3334*d546e47aSAdrian Chadd 			    bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
3335*d546e47aSAdrian Chadd 		else
3336*d546e47aSAdrian Chadd 			bwn_hf_write(mac,
3337*d546e47aSAdrian Chadd 			    bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
3338*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
3339*d546e47aSAdrian Chadd 		    BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
3340*d546e47aSAdrian Chadd 		return;
3341*d546e47aSAdrian Chadd 	}
3342*d546e47aSAdrian Chadd 
3343*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
3344*d546e47aSAdrian Chadd 	    BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
3345*d546e47aSAdrian Chadd }
3346*d546e47aSAdrian Chadd 
3347*d546e47aSAdrian Chadd static uint16_t
3348*d546e47aSAdrian Chadd bwn_phy_g_chan2freq(uint8_t channel)
3349*d546e47aSAdrian Chadd {
3350*d546e47aSAdrian Chadd 	static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
3351*d546e47aSAdrian Chadd 
3352*d546e47aSAdrian Chadd 	KASSERT(channel >= 1 && channel <= 14,
3353*d546e47aSAdrian Chadd 	    ("%s:%d: fail", __func__, __LINE__));
3354*d546e47aSAdrian Chadd 
3355*d546e47aSAdrian Chadd 	return (bwn_phy_g_rf_channels[channel - 1]);
3356*d546e47aSAdrian Chadd }
3357*d546e47aSAdrian Chadd 
3358*d546e47aSAdrian Chadd static void
3359*d546e47aSAdrian Chadd bwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
3360*d546e47aSAdrian Chadd     const struct bwn_rfatt *rfatt, uint8_t txctl)
3361*d546e47aSAdrian Chadd {
3362*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
3363*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
3364*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
3365*d546e47aSAdrian Chadd 	uint16_t bb, rf;
3366*d546e47aSAdrian Chadd 	uint16_t tx_bias, tx_magn;
3367*d546e47aSAdrian Chadd 
3368*d546e47aSAdrian Chadd 	bb = bbatt->att;
3369*d546e47aSAdrian Chadd 	rf = rfatt->att;
3370*d546e47aSAdrian Chadd 	tx_bias = lo->tx_bias;
3371*d546e47aSAdrian Chadd 	tx_magn = lo->tx_magn;
3372*d546e47aSAdrian Chadd 	if (tx_bias == 0xff)
3373*d546e47aSAdrian Chadd 		tx_bias = 0;
3374*d546e47aSAdrian Chadd 
3375*d546e47aSAdrian Chadd 	pg->pg_txctl = txctl;
3376*d546e47aSAdrian Chadd 	memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
3377*d546e47aSAdrian Chadd 	pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
3378*d546e47aSAdrian Chadd 	memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
3379*d546e47aSAdrian Chadd 	bwn_phy_g_set_bbatt(mac, bb);
3380*d546e47aSAdrian Chadd 	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
3381*d546e47aSAdrian Chadd 	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
3382*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
3383*d546e47aSAdrian Chadd 	else {
3384*d546e47aSAdrian Chadd 		BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
3385*d546e47aSAdrian Chadd 		BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
3386*d546e47aSAdrian Chadd 	}
3387*d546e47aSAdrian Chadd 	if (BWN_HAS_TXMAG(phy))
3388*d546e47aSAdrian Chadd 		BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
3389*d546e47aSAdrian Chadd 	else
3390*d546e47aSAdrian Chadd 		BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
3391*d546e47aSAdrian Chadd 	bwn_lo_g_adjust(mac);
3392*d546e47aSAdrian Chadd }
3393*d546e47aSAdrian Chadd 
3394*d546e47aSAdrian Chadd static void
3395*d546e47aSAdrian Chadd bwn_phy_g_set_bbatt(struct bwn_mac *mac,
3396*d546e47aSAdrian Chadd     uint16_t bbatt)
3397*d546e47aSAdrian Chadd {
3398*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
3399*d546e47aSAdrian Chadd 
3400*d546e47aSAdrian Chadd 	if (phy->analog == 0) {
3401*d546e47aSAdrian Chadd 		BWN_WRITE_2(mac, BWN_PHY0,
3402*d546e47aSAdrian Chadd 		    (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
3403*d546e47aSAdrian Chadd 		return;
3404*d546e47aSAdrian Chadd 	}
3405*d546e47aSAdrian Chadd 	if (phy->analog > 1) {
3406*d546e47aSAdrian Chadd 		BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
3407*d546e47aSAdrian Chadd 		return;
3408*d546e47aSAdrian Chadd 	}
3409*d546e47aSAdrian Chadd 	BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
3410*d546e47aSAdrian Chadd }
3411*d546e47aSAdrian Chadd 
3412*d546e47aSAdrian Chadd static uint16_t
3413*d546e47aSAdrian Chadd bwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
3414*d546e47aSAdrian Chadd {
3415*d546e47aSAdrian Chadd 	struct bwn_phy *phy = &mac->mac_phy;
3416*d546e47aSAdrian Chadd 	struct bwn_phy_g *pg = &phy->phy_g;
3417*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
3418*d546e47aSAdrian Chadd 	int max_lb_gain;
3419*d546e47aSAdrian Chadd 	uint16_t extlna;
3420*d546e47aSAdrian Chadd 	uint16_t i;
3421*d546e47aSAdrian Chadd 
3422*d546e47aSAdrian Chadd 	if (phy->gmode == 0)
3423*d546e47aSAdrian Chadd 		return (0);
3424*d546e47aSAdrian Chadd 
3425*d546e47aSAdrian Chadd 	if (BWN_HAS_LOOPBACK(phy)) {
3426*d546e47aSAdrian Chadd 		max_lb_gain = pg->pg_max_lb_gain;
3427*d546e47aSAdrian Chadd 		max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
3428*d546e47aSAdrian Chadd 		if (max_lb_gain >= 0x46) {
3429*d546e47aSAdrian Chadd 			extlna = 0x3000;
3430*d546e47aSAdrian Chadd 			max_lb_gain -= 0x46;
3431*d546e47aSAdrian Chadd 		} else if (max_lb_gain >= 0x3a) {
3432*d546e47aSAdrian Chadd 			extlna = 0x1000;
3433*d546e47aSAdrian Chadd 			max_lb_gain -= 0x3a;
3434*d546e47aSAdrian Chadd 		} else if (max_lb_gain >= 0x2e) {
3435*d546e47aSAdrian Chadd 			extlna = 0x2000;
3436*d546e47aSAdrian Chadd 			max_lb_gain -= 0x2e;
3437*d546e47aSAdrian Chadd 		} else {
3438*d546e47aSAdrian Chadd 			extlna = 0;
3439*d546e47aSAdrian Chadd 			max_lb_gain -= 0x10;
3440*d546e47aSAdrian Chadd 		}
3441*d546e47aSAdrian Chadd 
3442*d546e47aSAdrian Chadd 		for (i = 0; i < 16; i++) {
3443*d546e47aSAdrian Chadd 			max_lb_gain -= (i * 6);
3444*d546e47aSAdrian Chadd 			if (max_lb_gain < 6)
3445*d546e47aSAdrian Chadd 				break;
3446*d546e47aSAdrian Chadd 		}
3447*d546e47aSAdrian Chadd 
3448*d546e47aSAdrian Chadd 		if ((phy->rev < 7) ||
3449*d546e47aSAdrian Chadd 		    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
3450*d546e47aSAdrian Chadd 			if (reg == BWN_PHY_RFOVER) {
3451*d546e47aSAdrian Chadd 				return (0x1b3);
3452*d546e47aSAdrian Chadd 			} else if (reg == BWN_PHY_RFOVERVAL) {
3453*d546e47aSAdrian Chadd 				extlna |= (i << 8);
3454*d546e47aSAdrian Chadd 				switch (lpd) {
3455*d546e47aSAdrian Chadd 				case BWN_LPD(0, 1, 1):
3456*d546e47aSAdrian Chadd 					return (0x0f92);
3457*d546e47aSAdrian Chadd 				case BWN_LPD(0, 0, 1):
3458*d546e47aSAdrian Chadd 				case BWN_LPD(1, 0, 1):
3459*d546e47aSAdrian Chadd 					return (0x0092 | extlna);
3460*d546e47aSAdrian Chadd 				case BWN_LPD(1, 0, 0):
3461*d546e47aSAdrian Chadd 					return (0x0093 | extlna);
3462*d546e47aSAdrian Chadd 				}
3463*d546e47aSAdrian Chadd 				KASSERT(0 == 1,
3464*d546e47aSAdrian Chadd 				    ("%s:%d: fail", __func__, __LINE__));
3465*d546e47aSAdrian Chadd 			}
3466*d546e47aSAdrian Chadd 			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3467*d546e47aSAdrian Chadd 		} else {
3468*d546e47aSAdrian Chadd 			if (reg == BWN_PHY_RFOVER)
3469*d546e47aSAdrian Chadd 				return (0x9b3);
3470*d546e47aSAdrian Chadd 			if (reg == BWN_PHY_RFOVERVAL) {
3471*d546e47aSAdrian Chadd 				if (extlna)
3472*d546e47aSAdrian Chadd 					extlna |= 0x8000;
3473*d546e47aSAdrian Chadd 				extlna |= (i << 8);
3474*d546e47aSAdrian Chadd 				switch (lpd) {
3475*d546e47aSAdrian Chadd 				case BWN_LPD(0, 1, 1):
3476*d546e47aSAdrian Chadd 					return (0x8f92);
3477*d546e47aSAdrian Chadd 				case BWN_LPD(0, 0, 1):
3478*d546e47aSAdrian Chadd 					return (0x8092 | extlna);
3479*d546e47aSAdrian Chadd 				case BWN_LPD(1, 0, 1):
3480*d546e47aSAdrian Chadd 					return (0x2092 | extlna);
3481*d546e47aSAdrian Chadd 				case BWN_LPD(1, 0, 0):
3482*d546e47aSAdrian Chadd 					return (0x2093 | extlna);
3483*d546e47aSAdrian Chadd 				}
3484*d546e47aSAdrian Chadd 				KASSERT(0 == 1,
3485*d546e47aSAdrian Chadd 				    ("%s:%d: fail", __func__, __LINE__));
3486*d546e47aSAdrian Chadd 			}
3487*d546e47aSAdrian Chadd 			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3488*d546e47aSAdrian Chadd 		}
3489*d546e47aSAdrian Chadd 		return (0);
3490*d546e47aSAdrian Chadd 	}
3491*d546e47aSAdrian Chadd 
3492*d546e47aSAdrian Chadd 	if ((phy->rev < 7) ||
3493*d546e47aSAdrian Chadd 	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
3494*d546e47aSAdrian Chadd 		if (reg == BWN_PHY_RFOVER) {
3495*d546e47aSAdrian Chadd 			return (0x1b3);
3496*d546e47aSAdrian Chadd 		} else if (reg == BWN_PHY_RFOVERVAL) {
3497*d546e47aSAdrian Chadd 			switch (lpd) {
3498*d546e47aSAdrian Chadd 			case BWN_LPD(0, 1, 1):
3499*d546e47aSAdrian Chadd 				return (0x0fb2);
3500*d546e47aSAdrian Chadd 			case BWN_LPD(0, 0, 1):
3501*d546e47aSAdrian Chadd 				return (0x00b2);
3502*d546e47aSAdrian Chadd 			case BWN_LPD(1, 0, 1):
3503*d546e47aSAdrian Chadd 				return (0x30b2);
3504*d546e47aSAdrian Chadd 			case BWN_LPD(1, 0, 0):
3505*d546e47aSAdrian Chadd 				return (0x30b3);
3506*d546e47aSAdrian Chadd 			}
3507*d546e47aSAdrian Chadd 			KASSERT(0 == 1,
3508*d546e47aSAdrian Chadd 			    ("%s:%d: fail", __func__, __LINE__));
3509*d546e47aSAdrian Chadd 		}
3510*d546e47aSAdrian Chadd 		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3511*d546e47aSAdrian Chadd 	} else {
3512*d546e47aSAdrian Chadd 		if (reg == BWN_PHY_RFOVER) {
3513*d546e47aSAdrian Chadd 			return (0x9b3);
3514*d546e47aSAdrian Chadd 		} else if (reg == BWN_PHY_RFOVERVAL) {
3515*d546e47aSAdrian Chadd 			switch (lpd) {
3516*d546e47aSAdrian Chadd 			case BWN_LPD(0, 1, 1):
3517*d546e47aSAdrian Chadd 				return (0x8fb2);
3518*d546e47aSAdrian Chadd 			case BWN_LPD(0, 0, 1):
3519*d546e47aSAdrian Chadd 				return (0x80b2);
3520*d546e47aSAdrian Chadd 			case BWN_LPD(1, 0, 1):
3521*d546e47aSAdrian Chadd 				return (0x20b2);
3522*d546e47aSAdrian Chadd 			case BWN_LPD(1, 0, 0):
3523*d546e47aSAdrian Chadd 				return (0x20b3);
3524*d546e47aSAdrian Chadd 			}
3525*d546e47aSAdrian Chadd 			KASSERT(0 == 1,
3526*d546e47aSAdrian Chadd 			    ("%s:%d: fail", __func__, __LINE__));
3527*d546e47aSAdrian Chadd 		}
3528*d546e47aSAdrian Chadd 		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3529*d546e47aSAdrian Chadd 	}
3530*d546e47aSAdrian Chadd 	return (0);
3531*d546e47aSAdrian Chadd }
3532*d546e47aSAdrian Chadd 
3533*d546e47aSAdrian Chadd static void
3534*d546e47aSAdrian Chadd bwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
3535*d546e47aSAdrian Chadd {
3536*d546e47aSAdrian Chadd 
3537*d546e47aSAdrian Chadd 	if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
3538*d546e47aSAdrian Chadd 		return;
3539*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
3540*d546e47aSAdrian Chadd 	    bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
3541*d546e47aSAdrian Chadd 	DELAY(1000);
3542*d546e47aSAdrian Chadd 	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
3543*d546e47aSAdrian Chadd }
3544*d546e47aSAdrian Chadd 
3545*d546e47aSAdrian Chadd static int
3546*d546e47aSAdrian Chadd bwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
3547*d546e47aSAdrian Chadd {
3548*d546e47aSAdrian Chadd 	const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
3549*d546e47aSAdrian Chadd 	unsigned int a, b, c, d;
3550*d546e47aSAdrian Chadd 	unsigned int avg;
3551*d546e47aSAdrian Chadd 	uint32_t tmp;
3552*d546e47aSAdrian Chadd 
3553*d546e47aSAdrian Chadd 	tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
3554*d546e47aSAdrian Chadd 	a = tmp & 0xff;
3555*d546e47aSAdrian Chadd 	b = (tmp >> 8) & 0xff;
3556*d546e47aSAdrian Chadd 	c = (tmp >> 16) & 0xff;
3557*d546e47aSAdrian Chadd 	d = (tmp >> 24) & 0xff;
3558*d546e47aSAdrian Chadd 	if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
3559*d546e47aSAdrian Chadd 	    c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
3560*d546e47aSAdrian Chadd 		return (ENOENT);
3561*d546e47aSAdrian Chadd 	bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
3562*d546e47aSAdrian Chadd 	    BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
3563*d546e47aSAdrian Chadd 	    (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
3564*d546e47aSAdrian Chadd 
3565*d546e47aSAdrian Chadd 	if (ofdm) {
3566*d546e47aSAdrian Chadd 		a = (a + 32) & 0x3f;
3567*d546e47aSAdrian Chadd 		b = (b + 32) & 0x3f;
3568*d546e47aSAdrian Chadd 		c = (c + 32) & 0x3f;
3569*d546e47aSAdrian Chadd 		d = (d + 32) & 0x3f;
3570*d546e47aSAdrian Chadd 	}
3571*d546e47aSAdrian Chadd 
3572*d546e47aSAdrian Chadd 	avg = (a + b + c + d + 2) / 4;
3573*d546e47aSAdrian Chadd 	if (ofdm) {
3574*d546e47aSAdrian Chadd 		if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
3575*d546e47aSAdrian Chadd 		    & BWN_HF_4DB_CCK_POWERBOOST)
3576*d546e47aSAdrian Chadd 			avg = (avg >= 13) ? (avg - 13) : 0;
3577*d546e47aSAdrian Chadd 	}
3578*d546e47aSAdrian Chadd 	return (avg);
3579*d546e47aSAdrian Chadd }
3580*d546e47aSAdrian Chadd 
3581*d546e47aSAdrian Chadd static void
3582*d546e47aSAdrian Chadd bwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
3583*d546e47aSAdrian Chadd {
3584*d546e47aSAdrian Chadd 	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
3585*d546e47aSAdrian Chadd 	int rfatt = *rfattp;
3586*d546e47aSAdrian Chadd 	int bbatt = *bbattp;
3587*d546e47aSAdrian Chadd 
3588*d546e47aSAdrian Chadd 	while (1) {
3589*d546e47aSAdrian Chadd 		if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
3590*d546e47aSAdrian Chadd 			break;
3591*d546e47aSAdrian Chadd 		if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
3592*d546e47aSAdrian Chadd 			break;
3593*d546e47aSAdrian Chadd 		if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
3594*d546e47aSAdrian Chadd 			break;
3595*d546e47aSAdrian Chadd 		if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
3596*d546e47aSAdrian Chadd 			break;
3597*d546e47aSAdrian Chadd 		if (bbatt > lo->bbatt.max) {
3598*d546e47aSAdrian Chadd 			bbatt -= 4;
3599*d546e47aSAdrian Chadd 			rfatt += 1;
3600*d546e47aSAdrian Chadd 			continue;
3601*d546e47aSAdrian Chadd 		}
3602*d546e47aSAdrian Chadd 		if (bbatt < lo->bbatt.min) {
3603*d546e47aSAdrian Chadd 			bbatt += 4;
3604*d546e47aSAdrian Chadd 			rfatt -= 1;
3605*d546e47aSAdrian Chadd 			continue;
3606*d546e47aSAdrian Chadd 		}
3607*d546e47aSAdrian Chadd 		if (rfatt > lo->rfatt.max) {
3608*d546e47aSAdrian Chadd 			rfatt -= 1;
3609*d546e47aSAdrian Chadd 			bbatt += 4;
3610*d546e47aSAdrian Chadd 			continue;
3611*d546e47aSAdrian Chadd 		}
3612*d546e47aSAdrian Chadd 		if (rfatt < lo->rfatt.min) {
3613*d546e47aSAdrian Chadd 			rfatt += 1;
3614*d546e47aSAdrian Chadd 			bbatt -= 4;
3615*d546e47aSAdrian Chadd 			continue;
3616*d546e47aSAdrian Chadd 		}
3617*d546e47aSAdrian Chadd 		break;
3618*d546e47aSAdrian Chadd 	}
3619*d546e47aSAdrian Chadd 
3620*d546e47aSAdrian Chadd 	*rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
3621*d546e47aSAdrian Chadd 	*bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
3622*d546e47aSAdrian Chadd }
3623*d546e47aSAdrian Chadd 
3624*d546e47aSAdrian Chadd static void
3625*d546e47aSAdrian Chadd bwn_phy_lock(struct bwn_mac *mac)
3626*d546e47aSAdrian Chadd {
3627*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
3628*d546e47aSAdrian Chadd 	struct ieee80211com *ic = &sc->sc_ic;
3629*d546e47aSAdrian Chadd 
3630*d546e47aSAdrian Chadd 	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
3631*d546e47aSAdrian Chadd 	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
3632*d546e47aSAdrian Chadd 
3633*d546e47aSAdrian Chadd 	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
3634*d546e47aSAdrian Chadd 		bwn_psctl(mac, BWN_PS_AWAKE);
3635*d546e47aSAdrian Chadd }
3636*d546e47aSAdrian Chadd 
3637*d546e47aSAdrian Chadd static void
3638*d546e47aSAdrian Chadd bwn_phy_unlock(struct bwn_mac *mac)
3639*d546e47aSAdrian Chadd {
3640*d546e47aSAdrian Chadd 	struct bwn_softc *sc = mac->mac_sc;
3641*d546e47aSAdrian Chadd 	struct ieee80211com *ic = &sc->sc_ic;
3642*d546e47aSAdrian Chadd 
3643*d546e47aSAdrian Chadd 	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
3644*d546e47aSAdrian Chadd 	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
3645*d546e47aSAdrian Chadd 
3646*d546e47aSAdrian Chadd 	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
3647*d546e47aSAdrian Chadd 		bwn_psctl(mac, 0);
3648*d546e47aSAdrian Chadd }
3649*d546e47aSAdrian Chadd 
3650*d546e47aSAdrian Chadd static void
3651*d546e47aSAdrian Chadd bwn_rf_lock(struct bwn_mac *mac)
3652*d546e47aSAdrian Chadd {
3653*d546e47aSAdrian Chadd 
3654*d546e47aSAdrian Chadd 	BWN_WRITE_4(mac, BWN_MACCTL,
3655*d546e47aSAdrian Chadd 	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
3656*d546e47aSAdrian Chadd 	BWN_READ_4(mac, BWN_MACCTL);
3657*d546e47aSAdrian Chadd 	DELAY(10);
3658*d546e47aSAdrian Chadd }
3659*d546e47aSAdrian Chadd 
3660*d546e47aSAdrian Chadd static void
3661*d546e47aSAdrian Chadd bwn_rf_unlock(struct bwn_mac *mac)
3662*d546e47aSAdrian Chadd {
3663*d546e47aSAdrian Chadd 
3664*d546e47aSAdrian Chadd 	BWN_READ_2(mac, BWN_PHYVER);
3665*d546e47aSAdrian Chadd 	BWN_WRITE_4(mac, BWN_MACCTL,
3666*d546e47aSAdrian Chadd 	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
3667*d546e47aSAdrian Chadd }
3668