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