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