1298948Sadrian/*-
2298948Sadrian * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
3298948Sadrian * All rights reserved.
4298948Sadrian *
5298948Sadrian * Redistribution and use in source and binary forms, with or without
6298948Sadrian * modification, are permitted provided that the following conditions
7298948Sadrian * are met:
8298948Sadrian * 1. Redistributions of source code must retain the above copyright
9298948Sadrian *    notice, this list of conditions and the following disclaimer,
10298948Sadrian *    without modification.
11298948Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12298948Sadrian *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13298948Sadrian *    redistribution must be conditioned upon including a substantially
14298948Sadrian *    similar Disclaimer requirement for further binary redistribution.
15298948Sadrian *
16298948Sadrian * NO WARRANTY
17298948Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18298948Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19298948Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20298948Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21298948Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22298948Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23298948Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24298948Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25298948Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26298948Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27298948Sadrian * THE POSSIBILITY OF SUCH DAMAGES.
28298948Sadrian */
29298948Sadrian
30298948Sadrian#include <sys/cdefs.h>
31298948Sadrian__FBSDID("$FreeBSD$");
32298948Sadrian
33299984Sadrian#include "opt_bwn.h"
34299984Sadrian#include "opt_wlan.h"
35299984Sadrian
36298948Sadrian/*
37298948Sadrian * The Broadcom Wireless LAN controller driver.
38298948Sadrian */
39298948Sadrian
40298948Sadrian#include <sys/param.h>
41298948Sadrian#include <sys/systm.h>
42298948Sadrian#include <sys/kernel.h>
43298948Sadrian#include <sys/malloc.h>
44298948Sadrian#include <sys/module.h>
45298948Sadrian#include <sys/endian.h>
46298948Sadrian#include <sys/errno.h>
47298948Sadrian#include <sys/firmware.h>
48298948Sadrian#include <sys/lock.h>
49298948Sadrian#include <sys/mutex.h>
50298948Sadrian#include <machine/bus.h>
51298948Sadrian#include <machine/resource.h>
52298948Sadrian#include <sys/bus.h>
53298948Sadrian#include <sys/rman.h>
54298948Sadrian#include <sys/socket.h>
55298948Sadrian#include <sys/sockio.h>
56298948Sadrian
57298948Sadrian#include <net/ethernet.h>
58298948Sadrian#include <net/if.h>
59298948Sadrian#include <net/if_var.h>
60298948Sadrian#include <net/if_arp.h>
61298948Sadrian#include <net/if_dl.h>
62298948Sadrian#include <net/if_llc.h>
63298948Sadrian#include <net/if_media.h>
64298948Sadrian#include <net/if_types.h>
65298948Sadrian
66298948Sadrian#include <dev/pci/pcivar.h>
67298948Sadrian#include <dev/pci/pcireg.h>
68298948Sadrian#include <dev/siba/siba_ids.h>
69298948Sadrian#include <dev/siba/sibareg.h>
70298948Sadrian#include <dev/siba/sibavar.h>
71298948Sadrian
72298948Sadrian#include <net80211/ieee80211_var.h>
73298948Sadrian#include <net80211/ieee80211_radiotap.h>
74298948Sadrian#include <net80211/ieee80211_regdomain.h>
75298948Sadrian#include <net80211/ieee80211_phy.h>
76298948Sadrian#include <net80211/ieee80211_ratectl.h>
77298948Sadrian
78298948Sadrian#include <dev/bwn/if_bwnreg.h>
79298948Sadrian#include <dev/bwn/if_bwnvar.h>
80298948Sadrian
81298948Sadrian#include <dev/bwn/if_bwn_debug.h>
82298948Sadrian#include <dev/bwn/if_bwn_misc.h>
83298948Sadrian#include <dev/bwn/if_bwn_phy_g.h>
84298948Sadrian
85298948Sadrianstatic void	bwn_phy_g_init_sub(struct bwn_mac *);
86298948Sadrianstatic uint8_t	bwn_has_hwpctl(struct bwn_mac *);
87298948Sadrianstatic void	bwn_phy_init_b5(struct bwn_mac *);
88298948Sadrianstatic void	bwn_phy_init_b6(struct bwn_mac *);
89298948Sadrianstatic void	bwn_phy_init_a(struct bwn_mac *);
90298948Sadrianstatic void	bwn_loopback_calcgain(struct bwn_mac *);
91298948Sadrianstatic uint16_t	bwn_rf_init_bcm2050(struct bwn_mac *);
92298948Sadrianstatic void	bwn_lo_g_init(struct bwn_mac *);
93298948Sadrianstatic void	bwn_lo_g_adjust(struct bwn_mac *);
94298948Sadrianstatic void	bwn_lo_get_powervector(struct bwn_mac *);
95298948Sadrianstatic struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
96298948Sadrian		    const struct bwn_bbatt *, const struct bwn_rfatt *);
97298948Sadrianstatic void	bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
98298948Sadrianstatic void	bwn_phy_hwpctl_init(struct bwn_mac *);
99298948Sadrianstatic void	bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
100298948Sadrianstatic void	bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
101298948Sadrian		    const struct bwn_bbatt *, const struct bwn_rfatt *,
102298948Sadrian		    uint8_t);
103298948Sadrianstatic void	bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
104298948Sadrianstatic uint16_t	bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
105298948Sadrianstatic void	bwn_spu_workaround(struct bwn_mac *, uint8_t);
106298948Sadrianstatic void	bwn_wa_init(struct bwn_mac *);
107298948Sadrianstatic void	bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
108298948Sadrian		    uint16_t);
109298948Sadrianstatic void	bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
110298948Sadrian		    uint32_t);
111298948Sadrianstatic void	bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
112298948Sadrian		    uint16_t);
113298948Sadrianstatic int16_t	bwn_nrssi_read(struct bwn_mac *, uint16_t);
114298948Sadrianstatic void	bwn_nrssi_offset(struct bwn_mac *);
115298948Sadrianstatic void	bwn_nrssi_threshold(struct bwn_mac *);
116298948Sadrianstatic void	bwn_nrssi_slope_11g(struct bwn_mac *);
117298948Sadrianstatic void	bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
118298948Sadrian		    int16_t);
119298948Sadrianstatic void	bwn_set_original_gains(struct bwn_mac *);
120298948Sadrianstatic void	bwn_hwpctl_early_init(struct bwn_mac *);
121298948Sadrianstatic void	bwn_hwpctl_init_gphy(struct bwn_mac *);
122298948Sadrianstatic uint16_t	bwn_phy_g_chan2freq(uint8_t);
123298948Sadrianstatic void	bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
124298948Sadrian
125298948Sadrian/* Stuff we need */
126298948Sadrian
127298948Sadrianstatic uint16_t	bwn_phy_g_txctl(struct bwn_mac *mac);
128298948Sadrianstatic int	bwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset);
129298948Sadrianstatic void	bwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp);
130298948Sadrianstatic void	bwn_phy_lock(struct bwn_mac *mac);
131298948Sadrianstatic void	bwn_phy_unlock(struct bwn_mac *mac);
132298948Sadrianstatic void	bwn_rf_lock(struct bwn_mac *mac);
133298948Sadrianstatic void	bwn_rf_unlock(struct bwn_mac *mac);
134298948Sadrian
135298948Sadrianstatic const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
136298948Sadrianstatic const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
137298948Sadrianstatic const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
138298948Sadrianstatic const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
139298948Sadrianstatic const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
140298948Sadrianconst uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
141298948Sadrian
142298948Sadrianstatic uint8_t
143298948Sadrianbwn_has_hwpctl(struct bwn_mac *mac)
144298948Sadrian{
145298948Sadrian
146298948Sadrian	if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
147298948Sadrian		return (0);
148298948Sadrian	return (mac->mac_phy.use_hwpctl(mac));
149298948Sadrian}
150298948Sadrian
151298948Sadrianint
152298948Sadrianbwn_phy_g_attach(struct bwn_mac *mac)
153298948Sadrian{
154298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
155298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
156298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
157298948Sadrian	unsigned int i;
158298948Sadrian	int16_t pab0, pab1, pab2;
159298948Sadrian	static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
160298948Sadrian	int8_t bg;
161298948Sadrian
162298948Sadrian	bg = (int8_t)siba_sprom_get_tssi_bg(sc->sc_dev);
163298948Sadrian	pab0 = (int16_t)siba_sprom_get_pa0b0(sc->sc_dev);
164298948Sadrian	pab1 = (int16_t)siba_sprom_get_pa0b1(sc->sc_dev);
165298948Sadrian	pab2 = (int16_t)siba_sprom_get_pa0b2(sc->sc_dev);
166298948Sadrian
167298948Sadrian	if ((siba_get_chipid(sc->sc_dev) == 0x4301) && (phy->rf_ver != 0x2050))
168298948Sadrian		device_printf(sc->sc_dev, "not supported anymore\n");
169298948Sadrian
170298948Sadrian	pg->pg_flags = 0;
171298948Sadrian	if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
172298948Sadrian	    pab2 == -1) {
173298948Sadrian		pg->pg_idletssi = 52;
174298948Sadrian		pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
175298948Sadrian		return (0);
176298948Sadrian	}
177298948Sadrian
178298948Sadrian	pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
179298948Sadrian	pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
180298948Sadrian	if (pg->pg_tssi2dbm == NULL) {
181298948Sadrian		device_printf(sc->sc_dev, "failed to allocate buffer\n");
182298948Sadrian		return (ENOMEM);
183298948Sadrian	}
184298948Sadrian	for (i = 0; i < 64; i++) {
185298948Sadrian		int32_t m1, m2, f, q, delta;
186298948Sadrian		int8_t j = 0;
187298948Sadrian
188298948Sadrian		m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
189298948Sadrian		m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
190298948Sadrian		f = 256;
191298948Sadrian
192298948Sadrian		do {
193298948Sadrian			if (j > 15) {
194298948Sadrian				device_printf(sc->sc_dev,
195298948Sadrian				    "failed to generate tssi2dBm\n");
196298948Sadrian				free(pg->pg_tssi2dbm, M_DEVBUF);
197298948Sadrian				return (ENOMEM);
198298948Sadrian			}
199298948Sadrian			q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
200298948Sadrian			    f, 2048);
201298948Sadrian			delta = abs(q - f);
202298948Sadrian			f = q;
203298948Sadrian			j++;
204298948Sadrian		} while (delta >= 2);
205298948Sadrian
206298948Sadrian		pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
207298948Sadrian		    128);
208298948Sadrian	}
209298948Sadrian
210298948Sadrian	pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
211298948Sadrian	return (0);
212298948Sadrian}
213298948Sadrian
214298948Sadrianvoid
215298948Sadrianbwn_phy_g_detach(struct bwn_mac *mac)
216298948Sadrian{
217298948Sadrian	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
218298948Sadrian
219298948Sadrian	if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
220298948Sadrian		free(pg->pg_tssi2dbm, M_DEVBUF);
221298948Sadrian		pg->pg_tssi2dbm = NULL;
222298948Sadrian	}
223298948Sadrian	pg->pg_flags = 0;
224298948Sadrian}
225298948Sadrian
226298948Sadrianvoid
227298948Sadrianbwn_phy_g_init_pre(struct bwn_mac *mac)
228298948Sadrian{
229298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
230298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
231298948Sadrian	void *tssi2dbm;
232298948Sadrian	int idletssi;
233298948Sadrian	unsigned int i;
234298948Sadrian
235298948Sadrian	tssi2dbm = pg->pg_tssi2dbm;
236298948Sadrian	idletssi = pg->pg_idletssi;
237298948Sadrian
238298948Sadrian	memset(pg, 0, sizeof(*pg));
239298948Sadrian
240298948Sadrian	pg->pg_tssi2dbm = tssi2dbm;
241298948Sadrian	pg->pg_idletssi = idletssi;
242298948Sadrian
243298948Sadrian	memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
244298948Sadrian
245298948Sadrian	for (i = 0; i < N(pg->pg_nrssi); i++)
246298948Sadrian		pg->pg_nrssi[i] = -1000;
247298948Sadrian	for (i = 0; i < N(pg->pg_nrssi_lt); i++)
248298948Sadrian		pg->pg_nrssi_lt[i] = i;
249298948Sadrian	pg->pg_lofcal = 0xffff;
250298948Sadrian	pg->pg_initval = 0xffff;
251298948Sadrian	pg->pg_immode = BWN_IMMODE_NONE;
252298948Sadrian	pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
253298948Sadrian	pg->pg_avgtssi = 0xff;
254298948Sadrian
255298948Sadrian	pg->pg_loctl.tx_bias = 0xff;
256298948Sadrian	TAILQ_INIT(&pg->pg_loctl.calib_list);
257298948Sadrian}
258298948Sadrian
259298948Sadrianint
260298948Sadrianbwn_phy_g_prepare_hw(struct bwn_mac *mac)
261298948Sadrian{
262298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
263298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
264298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
265298948Sadrian	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
266298948Sadrian	static const struct bwn_rfatt rfatt0[] = {
267298948Sadrian		{ 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 },	{ 9, 0 }, { 2, 0 },
268298948Sadrian		{ 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
269298948Sadrian		{ 3, 1 }, { 4, 1 }
270298948Sadrian	};
271298948Sadrian	static const struct bwn_rfatt rfatt1[] = {
272298948Sadrian		{ 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
273298948Sadrian		{ 14, 1 }
274298948Sadrian	};
275298948Sadrian	static const struct bwn_rfatt rfatt2[] = {
276298948Sadrian		{ 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
277298948Sadrian		{ 9, 1 }
278298948Sadrian	};
279298948Sadrian	static const struct bwn_bbatt bbatt_0[] = {
280298948Sadrian		{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
281298948Sadrian	};
282298948Sadrian
283298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
284298948Sadrian
285298948Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
286298948Sadrian		pg->pg_bbatt.att = 0;
287298948Sadrian	else
288298948Sadrian		pg->pg_bbatt.att = 2;
289298948Sadrian
290298948Sadrian	/* prepare Radio Attenuation */
291298948Sadrian	pg->pg_rfatt.padmix = 0;
292298948Sadrian
293298948Sadrian	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
294298948Sadrian	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BCM4309G) {
295298948Sadrian		if (siba_get_pci_revid(sc->sc_dev) < 0x43) {
296298948Sadrian			pg->pg_rfatt.att = 2;
297298948Sadrian			goto done;
298298948Sadrian		} else if (siba_get_pci_revid(sc->sc_dev) < 0x51) {
299298948Sadrian			pg->pg_rfatt.att = 3;
300298948Sadrian			goto done;
301298948Sadrian		}
302298948Sadrian	}
303298948Sadrian
304298948Sadrian	if (phy->type == BWN_PHYTYPE_A) {
305298948Sadrian		pg->pg_rfatt.att = 0x60;
306298948Sadrian		goto done;
307298948Sadrian	}
308298948Sadrian
309298948Sadrian	switch (phy->rf_ver) {
310298948Sadrian	case 0x2050:
311298948Sadrian		switch (phy->rf_rev) {
312298948Sadrian		case 0:
313298948Sadrian			pg->pg_rfatt.att = 5;
314298948Sadrian			goto done;
315298948Sadrian		case 1:
316298948Sadrian			if (phy->type == BWN_PHYTYPE_G) {
317298948Sadrian				if (siba_get_pci_subvendor(sc->sc_dev) ==
318298948Sadrian				    SIBA_BOARDVENDOR_BCM &&
319298948Sadrian				    siba_get_pci_subdevice(sc->sc_dev) ==
320298948Sadrian				    SIBA_BOARD_BCM4309G &&
321298948Sadrian				    siba_get_pci_revid(sc->sc_dev) >= 30)
322298948Sadrian					pg->pg_rfatt.att = 3;
323298948Sadrian				else if (siba_get_pci_subvendor(sc->sc_dev) ==
324298948Sadrian				    SIBA_BOARDVENDOR_BCM &&
325298948Sadrian				    siba_get_pci_subdevice(sc->sc_dev) ==
326298948Sadrian				    SIBA_BOARD_BU4306)
327298948Sadrian					pg->pg_rfatt.att = 3;
328298948Sadrian				else
329298948Sadrian					pg->pg_rfatt.att = 1;
330298948Sadrian			} else {
331298948Sadrian				if (siba_get_pci_subvendor(sc->sc_dev) ==
332298948Sadrian				    SIBA_BOARDVENDOR_BCM &&
333298948Sadrian				    siba_get_pci_subdevice(sc->sc_dev) ==
334298948Sadrian				    SIBA_BOARD_BCM4309G &&
335298948Sadrian				    siba_get_pci_revid(sc->sc_dev) >= 30)
336298948Sadrian					pg->pg_rfatt.att = 7;
337298948Sadrian				else
338298948Sadrian					pg->pg_rfatt.att = 6;
339298948Sadrian			}
340298948Sadrian			goto done;
341298948Sadrian		case 2:
342298948Sadrian			if (phy->type == BWN_PHYTYPE_G) {
343298948Sadrian				if (siba_get_pci_subvendor(sc->sc_dev) ==
344298948Sadrian				    SIBA_BOARDVENDOR_BCM &&
345298948Sadrian				    siba_get_pci_subdevice(sc->sc_dev) ==
346298948Sadrian				    SIBA_BOARD_BCM4309G &&
347298948Sadrian				    siba_get_pci_revid(sc->sc_dev) >= 30)
348298948Sadrian					pg->pg_rfatt.att = 3;
349298948Sadrian				else if (siba_get_pci_subvendor(sc->sc_dev) ==
350298948Sadrian				    SIBA_BOARDVENDOR_BCM &&
351298948Sadrian				    siba_get_pci_subdevice(sc->sc_dev) ==
352298948Sadrian				    SIBA_BOARD_BU4306)
353298948Sadrian					pg->pg_rfatt.att = 5;
354298948Sadrian				else if (siba_get_chipid(sc->sc_dev) == 0x4320)
355298948Sadrian					pg->pg_rfatt.att = 4;
356298948Sadrian				else
357298948Sadrian					pg->pg_rfatt.att = 3;
358298948Sadrian			} else
359298948Sadrian				pg->pg_rfatt.att = 6;
360298948Sadrian			goto done;
361298948Sadrian		case 3:
362298948Sadrian			pg->pg_rfatt.att = 5;
363298948Sadrian			goto done;
364298948Sadrian		case 4:
365298948Sadrian		case 5:
366298948Sadrian			pg->pg_rfatt.att = 1;
367298948Sadrian			goto done;
368298948Sadrian		case 6:
369298948Sadrian		case 7:
370298948Sadrian			pg->pg_rfatt.att = 5;
371298948Sadrian			goto done;
372298948Sadrian		case 8:
373298948Sadrian			pg->pg_rfatt.att = 0xa;
374298948Sadrian			pg->pg_rfatt.padmix = 1;
375298948Sadrian			goto done;
376298948Sadrian		case 9:
377298948Sadrian		default:
378298948Sadrian			pg->pg_rfatt.att = 5;
379298948Sadrian			goto done;
380298948Sadrian		}
381298948Sadrian		break;
382298948Sadrian	case 0x2053:
383298948Sadrian		switch (phy->rf_rev) {
384298948Sadrian		case 1:
385298948Sadrian			pg->pg_rfatt.att = 6;
386298948Sadrian			goto done;
387298948Sadrian		}
388298948Sadrian		break;
389298948Sadrian	}
390298948Sadrian	pg->pg_rfatt.att = 5;
391298948Sadriandone:
392298948Sadrian	pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
393298948Sadrian
394298948Sadrian	if (!bwn_has_hwpctl(mac)) {
395298948Sadrian		lo->rfatt.array = rfatt0;
396298948Sadrian		lo->rfatt.len = N(rfatt0);
397298948Sadrian		lo->rfatt.min = 0;
398298948Sadrian		lo->rfatt.max = 9;
399298948Sadrian		goto genbbatt;
400298948Sadrian	}
401298948Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
402298948Sadrian		lo->rfatt.array = rfatt1;
403298948Sadrian		lo->rfatt.len = N(rfatt1);
404298948Sadrian		lo->rfatt.min = 0;
405298948Sadrian		lo->rfatt.max = 14;
406298948Sadrian		goto genbbatt;
407298948Sadrian	}
408298948Sadrian	lo->rfatt.array = rfatt2;
409298948Sadrian	lo->rfatt.len = N(rfatt2);
410298948Sadrian	lo->rfatt.min = 0;
411298948Sadrian	lo->rfatt.max = 9;
412298948Sadriangenbbatt:
413298948Sadrian	lo->bbatt.array = bbatt_0;
414298948Sadrian	lo->bbatt.len = N(bbatt_0);
415298948Sadrian	lo->bbatt.min = 0;
416298948Sadrian	lo->bbatt.max = 8;
417298948Sadrian
418298948Sadrian	BWN_READ_4(mac, BWN_MACCTL);
419298948Sadrian	if (phy->rev == 1) {
420298948Sadrian		phy->gmode = 0;
421298948Sadrian		bwn_reset_core(mac, 0);
422298948Sadrian		bwn_phy_g_init_sub(mac);
423298948Sadrian		phy->gmode = 1;
424299776Sadrian		bwn_reset_core(mac, 1);
425298948Sadrian	}
426298948Sadrian	return (0);
427298948Sadrian}
428298948Sadrian
429298948Sadrianstatic uint16_t
430298948Sadrianbwn_phy_g_txctl(struct bwn_mac *mac)
431298948Sadrian{
432298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
433298948Sadrian
434298948Sadrian	if (phy->rf_ver != 0x2050)
435298948Sadrian		return (0);
436298948Sadrian	if (phy->rf_rev == 1)
437298948Sadrian		return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
438298948Sadrian	if (phy->rf_rev < 6)
439298948Sadrian		return (BWN_TXCTL_PA2DB);
440298948Sadrian	if (phy->rf_rev == 8)
441298948Sadrian		return (BWN_TXCTL_TXMIX);
442298948Sadrian	return (0);
443298948Sadrian}
444298948Sadrian
445298948Sadrianint
446298948Sadrianbwn_phy_g_init(struct bwn_mac *mac)
447298948Sadrian{
448298948Sadrian
449298948Sadrian	bwn_phy_g_init_sub(mac);
450298948Sadrian	return (0);
451298948Sadrian}
452298948Sadrian
453298948Sadrianvoid
454298948Sadrianbwn_phy_g_exit(struct bwn_mac *mac)
455298948Sadrian{
456298948Sadrian	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
457298948Sadrian	struct bwn_lo_calib *cal, *tmp;
458298948Sadrian
459298948Sadrian	if (lo == NULL)
460298948Sadrian		return;
461298948Sadrian	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
462298948Sadrian		TAILQ_REMOVE(&lo->calib_list, cal, list);
463298948Sadrian		free(cal, M_DEVBUF);
464298948Sadrian	}
465298948Sadrian}
466298948Sadrian
467298948Sadrianuint16_t
468298948Sadrianbwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
469298948Sadrian{
470298948Sadrian
471298948Sadrian	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
472298948Sadrian	return (BWN_READ_2(mac, BWN_PHYDATA));
473298948Sadrian}
474298948Sadrian
475298948Sadrianvoid
476298948Sadrianbwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
477298948Sadrian{
478298948Sadrian
479298948Sadrian	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
480298948Sadrian	BWN_WRITE_2(mac, BWN_PHYDATA, value);
481298948Sadrian}
482298948Sadrian
483298948Sadrianuint16_t
484298948Sadrianbwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
485298948Sadrian{
486298948Sadrian
487298948Sadrian	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
488298948Sadrian	BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
489298948Sadrian	return (BWN_READ_2(mac, BWN_RFDATALO));
490298948Sadrian}
491298948Sadrian
492298948Sadrianvoid
493298948Sadrianbwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
494298948Sadrian{
495298948Sadrian
496298948Sadrian	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
497298948Sadrian	BWN_WRITE_2(mac, BWN_RFCTL, reg);
498298948Sadrian	BWN_WRITE_2(mac, BWN_RFDATALO, value);
499298948Sadrian}
500298948Sadrian
501298948Sadrianint
502298948Sadrianbwn_phy_g_hwpctl(struct bwn_mac *mac)
503298948Sadrian{
504298948Sadrian
505298948Sadrian	return (mac->mac_phy.rev >= 6);
506298948Sadrian}
507298948Sadrian
508298948Sadrianvoid
509298948Sadrianbwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
510298948Sadrian{
511298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
512298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
513298948Sadrian	unsigned int channel;
514298948Sadrian	uint16_t rfover, rfoverval;
515298948Sadrian
516298948Sadrian	if (on) {
517298948Sadrian		if (phy->rf_on)
518298948Sadrian			return;
519298948Sadrian
520298948Sadrian		BWN_PHY_WRITE(mac, 0x15, 0x8000);
521298948Sadrian		BWN_PHY_WRITE(mac, 0x15, 0xcc00);
522298948Sadrian		BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
523298948Sadrian		if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
524298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
525298948Sadrian			    pg->pg_radioctx_over);
526298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
527298948Sadrian			    pg->pg_radioctx_overval);
528298948Sadrian			pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
529298948Sadrian		}
530298948Sadrian		channel = phy->chan;
531298948Sadrian		bwn_phy_g_switch_chan(mac, 6, 1);
532298948Sadrian		bwn_phy_g_switch_chan(mac, channel, 0);
533298948Sadrian		return;
534298948Sadrian	}
535298948Sadrian
536298948Sadrian	rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
537298948Sadrian	rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
538298948Sadrian	pg->pg_radioctx_over = rfover;
539298948Sadrian	pg->pg_radioctx_overval = rfoverval;
540298948Sadrian	pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
541298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
542298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
543298948Sadrian}
544298948Sadrian
545298948Sadrianint
546298948Sadrianbwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
547298948Sadrian{
548298948Sadrian
549298948Sadrian	if ((newchan < 1) || (newchan > 14))
550298948Sadrian		return (EINVAL);
551298948Sadrian	bwn_phy_g_switch_chan(mac, newchan, 0);
552298948Sadrian
553298948Sadrian	return (0);
554298948Sadrian}
555298948Sadrian
556298948Sadrianuint32_t
557298948Sadrianbwn_phy_g_get_default_chan(struct bwn_mac *mac)
558298948Sadrian{
559298948Sadrian
560298948Sadrian	return (1);
561298948Sadrian}
562298948Sadrian
563298948Sadrianvoid
564298948Sadrianbwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
565298948Sadrian{
566298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
567298948Sadrian	uint64_t hf;
568298948Sadrian	int autodiv = 0;
569298948Sadrian	uint16_t tmp;
570298948Sadrian
571298948Sadrian	if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
572298948Sadrian		autodiv = 1;
573298948Sadrian
574298948Sadrian	hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
575298948Sadrian	bwn_hf_write(mac, hf);
576298948Sadrian
577298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
578298948Sadrian	    (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
579298948Sadrian	    ((autodiv ? BWN_ANTAUTO1 : antenna)
580298948Sadrian		<< BWN_PHY_BBANDCFG_RXANT_SHIFT));
581298948Sadrian
582298948Sadrian	if (autodiv) {
583298948Sadrian		tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
584298948Sadrian		if (antenna == BWN_ANTAUTO1)
585298948Sadrian			tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
586298948Sadrian		else
587298948Sadrian			tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
588298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
589298948Sadrian	}
590298948Sadrian	tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
591298948Sadrian	if (autodiv)
592298948Sadrian		tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
593298948Sadrian	else
594298948Sadrian		tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
595298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
596298948Sadrian	if (phy->rev >= 2) {
597298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
598298948Sadrian		    BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
599298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
600298948Sadrian		    (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
601298948Sadrian		    0x15);
602298948Sadrian		if (phy->rev == 2)
603298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
604298948Sadrian		else
605298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
606298948Sadrian			    (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
607298948Sadrian			    8);
608298948Sadrian	}
609298948Sadrian	if (phy->rev >= 6)
610298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
611298948Sadrian
612298948Sadrian	hf |= BWN_HF_UCODE_ANTDIV_HELPER;
613298948Sadrian	bwn_hf_write(mac, hf);
614298948Sadrian}
615298948Sadrian
616298948Sadrianint
617298948Sadrianbwn_phy_g_im(struct bwn_mac *mac, int mode)
618298948Sadrian{
619298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
620298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
621298948Sadrian
622298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
623298948Sadrian	KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
624298948Sadrian
625298948Sadrian	if (phy->rev == 0 || !phy->gmode)
626298948Sadrian		return (ENODEV);
627298948Sadrian
628298948Sadrian	pg->pg_aci_wlan_automatic = 0;
629298948Sadrian	return (0);
630298948Sadrian}
631298948Sadrian
632299791Sadrianbwn_txpwr_result_t
633298948Sadrianbwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
634298948Sadrian{
635298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
636298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
637298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
638298948Sadrian	unsigned int tssi;
639298948Sadrian	int cck, ofdm;
640298948Sadrian	int power;
641298948Sadrian	int rfatt, bbatt;
642298948Sadrian	unsigned int max;
643298948Sadrian
644298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
645298948Sadrian
646298948Sadrian	cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
647298948Sadrian	ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
648298948Sadrian	if (cck < 0 && ofdm < 0) {
649298948Sadrian		if (ignore_tssi == 0)
650298948Sadrian			return (BWN_TXPWR_RES_DONE);
651298948Sadrian		cck = 0;
652298948Sadrian		ofdm = 0;
653298948Sadrian	}
654298948Sadrian	tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
655298948Sadrian	if (pg->pg_avgtssi != 0xff)
656298948Sadrian		tssi = (tssi + pg->pg_avgtssi) / 2;
657298948Sadrian	pg->pg_avgtssi = tssi;
658298948Sadrian	KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
659298948Sadrian
660298948Sadrian	max = siba_sprom_get_maxpwr_bg(sc->sc_dev);
661298948Sadrian	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
662298948Sadrian		max -= 3;
663298948Sadrian	if (max >= 120) {
664298948Sadrian		device_printf(sc->sc_dev, "invalid max TX-power value\n");
665298948Sadrian		max = 80;
666298948Sadrian		siba_sprom_set_maxpwr_bg(sc->sc_dev, max);
667298948Sadrian	}
668298948Sadrian
669298948Sadrian	power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
670298948Sadrian	    (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
671298948Sadrian	     tssi, 0x00), 0x3f)]);
672298948Sadrian	if (power == 0)
673298948Sadrian		return (BWN_TXPWR_RES_DONE);
674298948Sadrian
675298948Sadrian	rfatt = -((power + 7) / 8);
676298948Sadrian	bbatt = (-(power / 2)) - (4 * rfatt);
677298948Sadrian	if ((rfatt == 0) && (bbatt == 0))
678298948Sadrian		return (BWN_TXPWR_RES_DONE);
679298948Sadrian	pg->pg_bbatt_delta = bbatt;
680298948Sadrian	pg->pg_rfatt_delta = rfatt;
681298948Sadrian	return (BWN_TXPWR_RES_NEED_ADJUST);
682298948Sadrian}
683298948Sadrian
684298948Sadrianvoid
685298948Sadrianbwn_phy_g_set_txpwr(struct bwn_mac *mac)
686298948Sadrian{
687298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
688298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
689298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
690298948Sadrian	int rfatt, bbatt;
691298948Sadrian	uint8_t txctl;
692298948Sadrian
693298948Sadrian	bwn_mac_suspend(mac);
694298948Sadrian
695298948Sadrian	BWN_ASSERT_LOCKED(sc);
696298948Sadrian
697298948Sadrian	bbatt = pg->pg_bbatt.att;
698298948Sadrian	bbatt += pg->pg_bbatt_delta;
699298948Sadrian	rfatt = pg->pg_rfatt.att;
700298948Sadrian	rfatt += pg->pg_rfatt_delta;
701298948Sadrian
702298948Sadrian	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
703298948Sadrian	txctl = pg->pg_txctl;
704298948Sadrian	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
705298948Sadrian		if (rfatt <= 1) {
706298948Sadrian			if (txctl == 0) {
707298948Sadrian				txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
708298948Sadrian				rfatt += 2;
709298948Sadrian				bbatt += 2;
710298948Sadrian			} else if (siba_sprom_get_bf_lo(sc->sc_dev) &
711298948Sadrian			    BWN_BFL_PACTRL) {
712298948Sadrian				bbatt += 4 * (rfatt - 2);
713298948Sadrian				rfatt = 2;
714298948Sadrian			}
715298948Sadrian		} else if (rfatt > 4 && txctl) {
716298948Sadrian			txctl = 0;
717298948Sadrian			if (bbatt < 3) {
718298948Sadrian				rfatt -= 3;
719298948Sadrian				bbatt += 2;
720298948Sadrian			} else {
721298948Sadrian				rfatt -= 2;
722298948Sadrian				bbatt -= 2;
723298948Sadrian			}
724298948Sadrian		}
725298948Sadrian	}
726298948Sadrian	pg->pg_txctl = txctl;
727298948Sadrian	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
728298948Sadrian	pg->pg_rfatt.att = rfatt;
729298948Sadrian	pg->pg_bbatt.att = bbatt;
730298948Sadrian
731298948Sadrian	DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
732298948Sadrian
733298948Sadrian	bwn_phy_lock(mac);
734298948Sadrian	bwn_rf_lock(mac);
735298948Sadrian	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
736298948Sadrian	    pg->pg_txctl);
737298948Sadrian	bwn_rf_unlock(mac);
738298948Sadrian	bwn_phy_unlock(mac);
739298948Sadrian
740298948Sadrian	bwn_mac_enable(mac);
741298948Sadrian}
742298948Sadrian
743298948Sadrianvoid
744298948Sadrianbwn_phy_g_task_15s(struct bwn_mac *mac)
745298948Sadrian{
746298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
747298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
748298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
749298948Sadrian	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
750298948Sadrian	unsigned long expire, now;
751298948Sadrian	struct bwn_lo_calib *cal, *tmp;
752298948Sadrian	uint8_t expired = 0;
753298948Sadrian
754298948Sadrian	bwn_mac_suspend(mac);
755298948Sadrian
756298948Sadrian	if (lo == NULL)
757298948Sadrian		goto fail;
758298948Sadrian
759298948Sadrian	BWN_GETTIME(now);
760298948Sadrian	if (bwn_has_hwpctl(mac)) {
761298948Sadrian		expire = now - BWN_LO_PWRVEC_EXPIRE;
762298948Sadrian		if (ieee80211_time_before(lo->pwr_vec_read_time, expire)) {
763298948Sadrian			bwn_lo_get_powervector(mac);
764298948Sadrian			bwn_phy_g_dc_lookup_init(mac, 0);
765298948Sadrian		}
766298948Sadrian		goto fail;
767298948Sadrian	}
768298948Sadrian
769298948Sadrian	expire = now - BWN_LO_CALIB_EXPIRE;
770298948Sadrian	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
771298948Sadrian		if (!ieee80211_time_before(cal->calib_time, expire))
772298948Sadrian			continue;
773298948Sadrian		if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
774298948Sadrian		    BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
775298948Sadrian			KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
776298948Sadrian			expired = 1;
777298948Sadrian		}
778298948Sadrian
779298948Sadrian		DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
780298948Sadrian		    cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
781298948Sadrian		    cal->ctl.i, cal->ctl.q);
782298948Sadrian
783298948Sadrian		TAILQ_REMOVE(&lo->calib_list, cal, list);
784298948Sadrian		free(cal, M_DEVBUF);
785298948Sadrian	}
786298948Sadrian	if (expired || TAILQ_EMPTY(&lo->calib_list)) {
787298948Sadrian		cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
788298948Sadrian		    &pg->pg_rfatt);
789298948Sadrian		if (cal == NULL) {
790298948Sadrian			device_printf(sc->sc_dev,
791298948Sadrian			    "failed to recalibrate LO\n");
792298948Sadrian			goto fail;
793298948Sadrian		}
794298948Sadrian		TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
795298948Sadrian		bwn_lo_write(mac, &cal->ctl);
796298948Sadrian	}
797298948Sadrian
798298948Sadrianfail:
799298948Sadrian	bwn_mac_enable(mac);
800298948Sadrian}
801298948Sadrian
802298948Sadrianvoid
803298948Sadrianbwn_phy_g_task_60s(struct bwn_mac *mac)
804298948Sadrian{
805298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
806298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
807298948Sadrian	uint8_t old = phy->chan;
808298948Sadrian
809298948Sadrian	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI))
810298948Sadrian		return;
811298948Sadrian
812298948Sadrian	bwn_mac_suspend(mac);
813298948Sadrian	bwn_nrssi_slope_11g(mac);
814298948Sadrian	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
815298948Sadrian		bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
816298948Sadrian		bwn_switch_channel(mac, old);
817298948Sadrian	}
818298948Sadrian	bwn_mac_enable(mac);
819298948Sadrian}
820298948Sadrian
821298948Sadrianvoid
822298948Sadrianbwn_phy_switch_analog(struct bwn_mac *mac, int on)
823298948Sadrian{
824298948Sadrian
825298948Sadrian	BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
826298948Sadrian}
827298948Sadrian
828298948Sadrianstatic void
829298948Sadrianbwn_phy_g_init_sub(struct bwn_mac *mac)
830298948Sadrian{
831298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
832298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
833298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
834298948Sadrian	uint16_t i, tmp;
835298948Sadrian
836298948Sadrian	if (phy->rev == 1)
837298948Sadrian		bwn_phy_init_b5(mac);
838298948Sadrian	else
839298948Sadrian		bwn_phy_init_b6(mac);
840298948Sadrian
841298948Sadrian	if (phy->rev >= 2 || phy->gmode)
842298948Sadrian		bwn_phy_init_a(mac);
843298948Sadrian
844298948Sadrian	if (phy->rev >= 2) {
845298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
846298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
847298948Sadrian	}
848298948Sadrian	if (phy->rev == 2) {
849298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
850298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
851298948Sadrian	}
852298948Sadrian	if (phy->rev > 5) {
853298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
854298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
855298948Sadrian	}
856298948Sadrian	if (phy->gmode || phy->rev >= 2) {
857298948Sadrian		tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
858298948Sadrian		tmp &= BWN_PHYVER_VERSION;
859298948Sadrian		if (tmp == 3 || tmp == 5) {
860298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
861298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
862298948Sadrian		}
863298948Sadrian		if (tmp == 5) {
864298948Sadrian			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
865298948Sadrian			    0x1f00);
866298948Sadrian		}
867298948Sadrian	}
868298948Sadrian	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
869298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
870298948Sadrian	if (phy->rf_rev == 8) {
871298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
872298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
873298948Sadrian	}
874298948Sadrian	if (BWN_HAS_LOOPBACK(phy))
875298948Sadrian		bwn_loopback_calcgain(mac);
876298948Sadrian
877298948Sadrian	if (phy->rf_rev != 8) {
878298948Sadrian		if (pg->pg_initval == 0xffff)
879298948Sadrian			pg->pg_initval = bwn_rf_init_bcm2050(mac);
880298948Sadrian		else
881298948Sadrian			BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
882298948Sadrian	}
883298948Sadrian	bwn_lo_g_init(mac);
884298948Sadrian	if (BWN_HAS_TXMAG(phy)) {
885298948Sadrian		BWN_RF_WRITE(mac, 0x52,
886298948Sadrian		    (BWN_RF_READ(mac, 0x52) & 0xff00)
887298948Sadrian		    | pg->pg_loctl.tx_bias |
888298948Sadrian		    pg->pg_loctl.tx_magn);
889298948Sadrian	} else {
890298948Sadrian		BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
891298948Sadrian	}
892298948Sadrian	if (phy->rev >= 6) {
893298948Sadrian		BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
894298948Sadrian		    (pg->pg_loctl.tx_bias << 12));
895298948Sadrian	}
896298948Sadrian	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
897298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
898298948Sadrian	else
899298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
900298948Sadrian	if (phy->rev < 2)
901298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
902298948Sadrian	else
903298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
904298948Sadrian	if (phy->gmode || phy->rev >= 2) {
905298948Sadrian		bwn_lo_g_adjust(mac);
906298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
907298948Sadrian	}
908298948Sadrian
909298948Sadrian	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
910298948Sadrian		for (i = 0; i < 64; i++) {
911298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
912298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
913298948Sadrian			    (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
914298948Sadrian			    -32), 31));
915298948Sadrian		}
916298948Sadrian		bwn_nrssi_threshold(mac);
917298948Sadrian	} else if (phy->gmode || phy->rev >= 2) {
918298948Sadrian		if (pg->pg_nrssi[0] == -1000) {
919298948Sadrian			KASSERT(pg->pg_nrssi[1] == -1000,
920298948Sadrian			    ("%s:%d: fail", __func__, __LINE__));
921298948Sadrian			bwn_nrssi_slope_11g(mac);
922298948Sadrian		} else
923298948Sadrian			bwn_nrssi_threshold(mac);
924298948Sadrian	}
925298948Sadrian	if (phy->rf_rev == 8)
926298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
927298948Sadrian	bwn_phy_hwpctl_init(mac);
928298948Sadrian	if ((siba_get_chipid(sc->sc_dev) == 0x4306
929298948Sadrian	     && siba_get_chippkg(sc->sc_dev) == 2) || 0) {
930298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
931298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
932298948Sadrian	}
933298948Sadrian}
934298948Sadrian
935298948Sadrianstatic void
936298948Sadrianbwn_phy_init_b5(struct bwn_mac *mac)
937298948Sadrian{
938298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
939298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
940298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
941298948Sadrian	uint16_t offset, value;
942298948Sadrian	uint8_t old_channel;
943298948Sadrian
944298948Sadrian	if (phy->analog == 1)
945298948Sadrian		BWN_RF_SET(mac, 0x007a, 0x0050);
946298948Sadrian	if ((siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM) &&
947298948Sadrian	    (siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306)) {
948298948Sadrian		value = 0x2120;
949298948Sadrian		for (offset = 0x00a8; offset < 0x00c7; offset++) {
950298948Sadrian			BWN_PHY_WRITE(mac, offset, value);
951298948Sadrian			value += 0x202;
952298948Sadrian		}
953298948Sadrian	}
954298948Sadrian	BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
955298948Sadrian	if (phy->rf_ver == 0x2050)
956298948Sadrian		BWN_PHY_WRITE(mac, 0x0038, 0x0667);
957298948Sadrian
958298948Sadrian	if (phy->gmode || phy->rev >= 2) {
959298948Sadrian		if (phy->rf_ver == 0x2050) {
960298948Sadrian			BWN_RF_SET(mac, 0x007a, 0x0020);
961298948Sadrian			BWN_RF_SET(mac, 0x0051, 0x0004);
962298948Sadrian		}
963298948Sadrian		BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
964298948Sadrian
965298948Sadrian		BWN_PHY_SET(mac, 0x0802, 0x0100);
966298948Sadrian		BWN_PHY_SET(mac, 0x042b, 0x2000);
967298948Sadrian
968298948Sadrian		BWN_PHY_WRITE(mac, 0x001c, 0x186a);
969298948Sadrian
970298948Sadrian		BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
971298948Sadrian		BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
972298948Sadrian		BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
973298948Sadrian	}
974298948Sadrian
975298948Sadrian	if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
976298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
977298948Sadrian
978298948Sadrian	if (phy->analog == 1) {
979298948Sadrian		BWN_PHY_WRITE(mac, 0x0026, 0xce00);
980298948Sadrian		BWN_PHY_WRITE(mac, 0x0021, 0x3763);
981298948Sadrian		BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
982298948Sadrian		BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
983298948Sadrian		BWN_PHY_WRITE(mac, 0x0024, 0x037e);
984298948Sadrian	} else
985298948Sadrian		BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
986298948Sadrian	BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
987298948Sadrian	BWN_WRITE_2(mac, 0x03ec, 0x3f22);
988298948Sadrian
989298948Sadrian	if (phy->analog == 1)
990298948Sadrian		BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
991298948Sadrian	else
992298948Sadrian		BWN_PHY_WRITE(mac, 0x0020, 0x301c);
993298948Sadrian
994298948Sadrian	if (phy->analog == 0)
995298948Sadrian		BWN_WRITE_2(mac, 0x03e4, 0x3000);
996298948Sadrian
997298948Sadrian	old_channel = phy->chan;
998298948Sadrian	bwn_phy_g_switch_chan(mac, 7, 0);
999298948Sadrian
1000298948Sadrian	if (phy->rf_ver != 0x2050) {
1001298948Sadrian		BWN_RF_WRITE(mac, 0x0075, 0x0080);
1002298948Sadrian		BWN_RF_WRITE(mac, 0x0079, 0x0081);
1003298948Sadrian	}
1004298948Sadrian
1005298948Sadrian	BWN_RF_WRITE(mac, 0x0050, 0x0020);
1006298948Sadrian	BWN_RF_WRITE(mac, 0x0050, 0x0023);
1007298948Sadrian
1008298948Sadrian	if (phy->rf_ver == 0x2050) {
1009298948Sadrian		BWN_RF_WRITE(mac, 0x0050, 0x0020);
1010298948Sadrian		BWN_RF_WRITE(mac, 0x005a, 0x0070);
1011298948Sadrian	}
1012298948Sadrian
1013298948Sadrian	BWN_RF_WRITE(mac, 0x005b, 0x007b);
1014298948Sadrian	BWN_RF_WRITE(mac, 0x005c, 0x00b0);
1015298948Sadrian	BWN_RF_SET(mac, 0x007a, 0x0007);
1016298948Sadrian
1017298948Sadrian	bwn_phy_g_switch_chan(mac, old_channel, 0);
1018298948Sadrian	BWN_PHY_WRITE(mac, 0x0014, 0x0080);
1019298948Sadrian	BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
1020298948Sadrian	BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
1021298948Sadrian
1022298948Sadrian	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
1023298948Sadrian	    pg->pg_txctl);
1024298948Sadrian
1025298948Sadrian	if (phy->rf_ver == 0x2050)
1026298948Sadrian		BWN_RF_WRITE(mac, 0x005d, 0x000d);
1027298948Sadrian
1028298948Sadrian	BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
1029298948Sadrian}
1030298948Sadrian
1031298948Sadrianstatic void
1032298948Sadrianbwn_loopback_calcgain(struct bwn_mac *mac)
1033298948Sadrian{
1034298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1035298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
1036298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
1037298948Sadrian	uint16_t backup_phy[16] = { 0 };
1038298948Sadrian	uint16_t backup_radio[3];
1039298948Sadrian	uint16_t backup_bband;
1040298948Sadrian	uint16_t i, j, loop_i_max;
1041298948Sadrian	uint16_t trsw_rx;
1042298948Sadrian	uint16_t loop1_outer_done, loop1_inner_done;
1043298948Sadrian
1044298948Sadrian	backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
1045298948Sadrian	backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
1046298948Sadrian	backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
1047298948Sadrian	backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
1048298948Sadrian	if (phy->rev != 1) {
1049298948Sadrian		backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
1050298948Sadrian		backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
1051298948Sadrian	}
1052298948Sadrian	backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
1053298948Sadrian	backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
1054298948Sadrian	backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
1055298948Sadrian	backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
1056298948Sadrian	backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
1057298948Sadrian	backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
1058298948Sadrian	backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
1059298948Sadrian	backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
1060298948Sadrian	backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
1061298948Sadrian	backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
1062298948Sadrian	backup_bband = pg->pg_bbatt.att;
1063298948Sadrian	backup_radio[0] = BWN_RF_READ(mac, 0x52);
1064298948Sadrian	backup_radio[1] = BWN_RF_READ(mac, 0x43);
1065298948Sadrian	backup_radio[2] = BWN_RF_READ(mac, 0x7a);
1066298948Sadrian
1067298948Sadrian	BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
1068298948Sadrian	BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
1069298948Sadrian	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
1070298948Sadrian	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
1071298948Sadrian	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
1072298948Sadrian	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
1073298948Sadrian	if (phy->rev != 1) {
1074298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
1075298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
1076298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
1077298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
1078298948Sadrian	}
1079298948Sadrian	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
1080298948Sadrian	BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
1081298948Sadrian	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
1082298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
1083298948Sadrian
1084298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
1085298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
1086298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
1087298948Sadrian
1088298948Sadrian	BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
1089298948Sadrian	if (phy->rev != 1) {
1090298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
1091298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
1092298948Sadrian	}
1093298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
1094298948Sadrian
1095298948Sadrian	if (phy->rf_rev == 8)
1096298948Sadrian		BWN_RF_WRITE(mac, 0x43, 0x000f);
1097298948Sadrian	else {
1098298948Sadrian		BWN_RF_WRITE(mac, 0x52, 0);
1099298948Sadrian		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
1100298948Sadrian	}
1101298948Sadrian	bwn_phy_g_set_bbatt(mac, 11);
1102298948Sadrian
1103298948Sadrian	if (phy->rev >= 3)
1104298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
1105298948Sadrian	else
1106298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
1107298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
1108298948Sadrian
1109298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
1110298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
1111298948Sadrian
1112298948Sadrian	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
1113298948Sadrian	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
1114298948Sadrian
1115298948Sadrian	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) {
1116298948Sadrian		if (phy->rev >= 7) {
1117298948Sadrian			BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
1118298948Sadrian			BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
1119298948Sadrian		}
1120298948Sadrian	}
1121298948Sadrian	BWN_RF_MASK(mac, 0x7a, 0x00f7);
1122298948Sadrian
1123298948Sadrian	j = 0;
1124298948Sadrian	loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
1125298948Sadrian	for (i = 0; i < loop_i_max; i++) {
1126298948Sadrian		for (j = 0; j < 16; j++) {
1127298948Sadrian			BWN_RF_WRITE(mac, 0x43, i);
1128298948Sadrian			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
1129298948Sadrian			    (j << 8));
1130298948Sadrian			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
1131298948Sadrian			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
1132298948Sadrian			DELAY(20);
1133298948Sadrian			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
1134298948Sadrian				goto done0;
1135298948Sadrian		}
1136298948Sadrian	}
1137298948Sadriandone0:
1138298948Sadrian	loop1_outer_done = i;
1139298948Sadrian	loop1_inner_done = j;
1140298948Sadrian	if (j >= 8) {
1141298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
1142298948Sadrian		trsw_rx = 0x1b;
1143298948Sadrian		for (j = j - 8; j < 16; j++) {
1144298948Sadrian			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
1145298948Sadrian			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
1146298948Sadrian			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
1147298948Sadrian			DELAY(20);
1148298948Sadrian			trsw_rx -= 3;
1149298948Sadrian			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
1150298948Sadrian				goto done1;
1151298948Sadrian		}
1152298948Sadrian	} else
1153298948Sadrian		trsw_rx = 0x18;
1154298948Sadriandone1:
1155298948Sadrian
1156298948Sadrian	if (phy->rev != 1) {
1157298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
1158298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
1159298948Sadrian	}
1160298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
1161298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
1162298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
1163298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
1164298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
1165298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
1166298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
1167298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
1168298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
1169298948Sadrian
1170298948Sadrian	bwn_phy_g_set_bbatt(mac, backup_bband);
1171298948Sadrian
1172298948Sadrian	BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
1173298948Sadrian	BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
1174298948Sadrian	BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
1175298948Sadrian
1176298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
1177298948Sadrian	DELAY(10);
1178298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
1179298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
1180298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
1181298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
1182298948Sadrian
1183298948Sadrian	pg->pg_max_lb_gain =
1184298948Sadrian	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
1185298948Sadrian	pg->pg_trsw_rx_gain = trsw_rx * 2;
1186298948Sadrian}
1187298948Sadrian
1188298948Sadrianstatic uint16_t
1189298948Sadrianbwn_rf_init_bcm2050(struct bwn_mac *mac)
1190298948Sadrian{
1191298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1192298948Sadrian	uint32_t tmp1 = 0, tmp2 = 0;
1193298948Sadrian	uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
1194298948Sadrian	    analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
1195298948Sadrian	    radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
1196298948Sadrian	static const uint8_t rcc_table[] = {
1197298948Sadrian		0x02, 0x03, 0x01, 0x0f,
1198298948Sadrian		0x06, 0x07, 0x05, 0x0f,
1199298948Sadrian		0x0a, 0x0b, 0x09, 0x0f,
1200298948Sadrian		0x0e, 0x0f, 0x0d, 0x0f,
1201298948Sadrian	};
1202298948Sadrian
1203298948Sadrian	loctl = lomask = reg0 = classctl = crs0 = analogoverval = analogover =
1204298948Sadrian	    rfoverval = rfover = cck3 = 0;
1205298948Sadrian	radio0 = BWN_RF_READ(mac, 0x43);
1206298948Sadrian	radio1 = BWN_RF_READ(mac, 0x51);
1207298948Sadrian	radio2 = BWN_RF_READ(mac, 0x52);
1208298948Sadrian	pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
1209298948Sadrian	cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
1210298948Sadrian	cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
1211298948Sadrian	cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
1212298948Sadrian
1213298948Sadrian	if (phy->type == BWN_PHYTYPE_B) {
1214298948Sadrian		cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
1215298948Sadrian		reg0 = BWN_READ_2(mac, 0x3ec);
1216298948Sadrian
1217298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
1218298948Sadrian		BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
1219298948Sadrian	} else if (phy->gmode || phy->rev >= 2) {
1220298948Sadrian		rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
1221298948Sadrian		rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
1222298948Sadrian		analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
1223298948Sadrian		analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
1224298948Sadrian		crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
1225298948Sadrian		classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
1226298948Sadrian
1227298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
1228298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
1229298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
1230298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
1231298948Sadrian		if (BWN_HAS_LOOPBACK(phy)) {
1232298948Sadrian			lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
1233298948Sadrian			loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
1234298948Sadrian			if (phy->rev >= 3)
1235298948Sadrian				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
1236298948Sadrian			else
1237298948Sadrian				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
1238298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
1239298948Sadrian		}
1240298948Sadrian
1241298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1242298948Sadrian		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
1243298948Sadrian			BWN_LPD(0, 1, 1)));
1244298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
1245298948Sadrian		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
1246298948Sadrian	}
1247298948Sadrian	BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
1248298948Sadrian
1249298948Sadrian	syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
1250298948Sadrian	BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
1251298948Sadrian	reg1 = BWN_READ_2(mac, 0x3e6);
1252298948Sadrian	reg2 = BWN_READ_2(mac, 0x3f4);
1253298948Sadrian
1254298948Sadrian	if (phy->analog == 0)
1255298948Sadrian		BWN_WRITE_2(mac, 0x03e6, 0x0122);
1256298948Sadrian	else {
1257298948Sadrian		if (phy->analog >= 2)
1258298948Sadrian			BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
1259298948Sadrian		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
1260298948Sadrian		    (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
1261298948Sadrian	}
1262298948Sadrian
1263298948Sadrian	reg = BWN_RF_READ(mac, 0x60);
1264298948Sadrian	index = (reg & 0x001e) >> 1;
1265298948Sadrian	rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
1266298948Sadrian
1267298948Sadrian	if (phy->type == BWN_PHYTYPE_B)
1268298948Sadrian		BWN_RF_WRITE(mac, 0x78, 0x26);
1269298948Sadrian	if (phy->gmode || phy->rev >= 2) {
1270298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1271298948Sadrian		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
1272298948Sadrian			BWN_LPD(0, 1, 1)));
1273298948Sadrian	}
1274298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
1275298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
1276298948Sadrian	if (phy->gmode || phy->rev >= 2) {
1277298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1278298948Sadrian		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
1279298948Sadrian			BWN_LPD(0, 0, 1)));
1280298948Sadrian	}
1281298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
1282298948Sadrian	BWN_RF_SET(mac, 0x51, 0x0004);
1283298948Sadrian	if (phy->rf_rev == 8)
1284298948Sadrian		BWN_RF_WRITE(mac, 0x43, 0x1f);
1285298948Sadrian	else {
1286298948Sadrian		BWN_RF_WRITE(mac, 0x52, 0);
1287298948Sadrian		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
1288298948Sadrian	}
1289298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
1290298948Sadrian
1291298948Sadrian	for (i = 0; i < 16; i++) {
1292298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
1293298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
1294298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
1295298948Sadrian		if (phy->gmode || phy->rev >= 2) {
1296298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1297298948Sadrian			    bwn_rf_2050_rfoverval(mac,
1298298948Sadrian				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1299298948Sadrian		}
1300298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
1301298948Sadrian		DELAY(10);
1302298948Sadrian		if (phy->gmode || phy->rev >= 2) {
1303298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1304298948Sadrian			    bwn_rf_2050_rfoverval(mac,
1305298948Sadrian				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1306298948Sadrian		}
1307298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
1308298948Sadrian		DELAY(10);
1309298948Sadrian		if (phy->gmode || phy->rev >= 2) {
1310298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1311298948Sadrian			    bwn_rf_2050_rfoverval(mac,
1312298948Sadrian				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
1313298948Sadrian		}
1314298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
1315298948Sadrian		DELAY(20);
1316298948Sadrian		tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
1317298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
1318298948Sadrian		if (phy->gmode || phy->rev >= 2) {
1319298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1320298948Sadrian			    bwn_rf_2050_rfoverval(mac,
1321298948Sadrian				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1322298948Sadrian		}
1323298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
1324298948Sadrian	}
1325298948Sadrian	DELAY(10);
1326298948Sadrian
1327298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
1328298948Sadrian	tmp1++;
1329298948Sadrian	tmp1 >>= 9;
1330298948Sadrian
1331298948Sadrian	for (i = 0; i < 16; i++) {
1332298948Sadrian		radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
1333298948Sadrian		BWN_RF_WRITE(mac, 0x78, radio78);
1334298948Sadrian		DELAY(10);
1335298948Sadrian		for (j = 0; j < 16; j++) {
1336298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
1337298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
1338298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
1339298948Sadrian			if (phy->gmode || phy->rev >= 2) {
1340298948Sadrian				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1341298948Sadrian				    bwn_rf_2050_rfoverval(mac,
1342298948Sadrian					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1343298948Sadrian			}
1344298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
1345298948Sadrian			DELAY(10);
1346298948Sadrian			if (phy->gmode || phy->rev >= 2) {
1347298948Sadrian				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1348298948Sadrian				    bwn_rf_2050_rfoverval(mac,
1349298948Sadrian					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1350298948Sadrian			}
1351298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
1352298948Sadrian			DELAY(10);
1353298948Sadrian			if (phy->gmode || phy->rev >= 2) {
1354298948Sadrian				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1355298948Sadrian				    bwn_rf_2050_rfoverval(mac,
1356298948Sadrian					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
1357298948Sadrian			}
1358298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
1359298948Sadrian			DELAY(10);
1360298948Sadrian			tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
1361298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
1362298948Sadrian			if (phy->gmode || phy->rev >= 2) {
1363298948Sadrian				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
1364298948Sadrian				    bwn_rf_2050_rfoverval(mac,
1365298948Sadrian					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
1366298948Sadrian			}
1367298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
1368298948Sadrian		}
1369298948Sadrian		tmp2++;
1370298948Sadrian		tmp2 >>= 8;
1371298948Sadrian		if (tmp1 < tmp2)
1372298948Sadrian			break;
1373298948Sadrian	}
1374298948Sadrian
1375298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
1376298948Sadrian	BWN_RF_WRITE(mac, 0x51, radio1);
1377298948Sadrian	BWN_RF_WRITE(mac, 0x52, radio2);
1378298948Sadrian	BWN_RF_WRITE(mac, 0x43, radio0);
1379298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
1380298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
1381298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
1382298948Sadrian	BWN_WRITE_2(mac, 0x3e6, reg1);
1383298948Sadrian	if (phy->analog != 0)
1384298948Sadrian		BWN_WRITE_2(mac, 0x3f4, reg2);
1385298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
1386298948Sadrian	bwn_spu_workaround(mac, phy->chan);
1387298948Sadrian	if (phy->type == BWN_PHYTYPE_B) {
1388298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
1389298948Sadrian		BWN_WRITE_2(mac, 0x3ec, reg0);
1390298948Sadrian	} else if (phy->gmode) {
1391298948Sadrian		BWN_WRITE_2(mac, BWN_PHY_RADIO,
1392298948Sadrian			    BWN_READ_2(mac, BWN_PHY_RADIO)
1393298948Sadrian			    & 0x7fff);
1394298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
1395298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
1396298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
1397298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
1398298948Sadrian			      analogoverval);
1399298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
1400298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
1401298948Sadrian		if (BWN_HAS_LOOPBACK(phy)) {
1402298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
1403298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
1404298948Sadrian		}
1405298948Sadrian	}
1406298948Sadrian
1407298948Sadrian	return ((i > 15) ? radio78 : rcc);
1408298948Sadrian}
1409298948Sadrian
1410298948Sadrianstatic void
1411298948Sadrianbwn_phy_init_b6(struct bwn_mac *mac)
1412298948Sadrian{
1413298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1414298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
1415298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
1416298948Sadrian	uint16_t offset, val;
1417298948Sadrian	uint8_t old_channel;
1418298948Sadrian
1419298948Sadrian	KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
1420298948Sadrian	    ("%s:%d: fail", __func__, __LINE__));
1421298948Sadrian
1422298948Sadrian	BWN_PHY_WRITE(mac, 0x003e, 0x817a);
1423298948Sadrian	BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
1424298948Sadrian	if (phy->rf_rev == 4 || phy->rf_rev == 5) {
1425298948Sadrian		BWN_RF_WRITE(mac, 0x51, 0x37);
1426298948Sadrian		BWN_RF_WRITE(mac, 0x52, 0x70);
1427298948Sadrian		BWN_RF_WRITE(mac, 0x53, 0xb3);
1428298948Sadrian		BWN_RF_WRITE(mac, 0x54, 0x9b);
1429298948Sadrian		BWN_RF_WRITE(mac, 0x5a, 0x88);
1430298948Sadrian		BWN_RF_WRITE(mac, 0x5b, 0x88);
1431298948Sadrian		BWN_RF_WRITE(mac, 0x5d, 0x88);
1432298948Sadrian		BWN_RF_WRITE(mac, 0x5e, 0x88);
1433298948Sadrian		BWN_RF_WRITE(mac, 0x7d, 0x88);
1434298948Sadrian		bwn_hf_write(mac,
1435298948Sadrian		    bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
1436298948Sadrian	}
1437298948Sadrian	if (phy->rf_rev == 8) {
1438298948Sadrian		BWN_RF_WRITE(mac, 0x51, 0);
1439298948Sadrian		BWN_RF_WRITE(mac, 0x52, 0x40);
1440298948Sadrian		BWN_RF_WRITE(mac, 0x53, 0xb7);
1441298948Sadrian		BWN_RF_WRITE(mac, 0x54, 0x98);
1442298948Sadrian		BWN_RF_WRITE(mac, 0x5a, 0x88);
1443298948Sadrian		BWN_RF_WRITE(mac, 0x5b, 0x6b);
1444298948Sadrian		BWN_RF_WRITE(mac, 0x5c, 0x0f);
1445298948Sadrian		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_ALTIQ) {
1446298948Sadrian			BWN_RF_WRITE(mac, 0x5d, 0xfa);
1447298948Sadrian			BWN_RF_WRITE(mac, 0x5e, 0xd8);
1448298948Sadrian		} else {
1449298948Sadrian			BWN_RF_WRITE(mac, 0x5d, 0xf5);
1450298948Sadrian			BWN_RF_WRITE(mac, 0x5e, 0xb8);
1451298948Sadrian		}
1452298948Sadrian		BWN_RF_WRITE(mac, 0x0073, 0x0003);
1453298948Sadrian		BWN_RF_WRITE(mac, 0x007d, 0x00a8);
1454298948Sadrian		BWN_RF_WRITE(mac, 0x007c, 0x0001);
1455298948Sadrian		BWN_RF_WRITE(mac, 0x007e, 0x0008);
1456298948Sadrian	}
1457298948Sadrian	for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
1458298948Sadrian		BWN_PHY_WRITE(mac, offset, val);
1459298948Sadrian		val -= 0x0202;
1460298948Sadrian	}
1461298948Sadrian	for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
1462298948Sadrian		BWN_PHY_WRITE(mac, offset, val);
1463298948Sadrian		val -= 0x0202;
1464298948Sadrian	}
1465298948Sadrian	for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
1466298948Sadrian		BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
1467298948Sadrian		val += 0x0202;
1468298948Sadrian	}
1469298948Sadrian	if (phy->type == BWN_PHYTYPE_G) {
1470298948Sadrian		BWN_RF_SET(mac, 0x007a, 0x0020);
1471298948Sadrian		BWN_RF_SET(mac, 0x0051, 0x0004);
1472298948Sadrian		BWN_PHY_SET(mac, 0x0802, 0x0100);
1473298948Sadrian		BWN_PHY_SET(mac, 0x042b, 0x2000);
1474298948Sadrian		BWN_PHY_WRITE(mac, 0x5b, 0);
1475298948Sadrian		BWN_PHY_WRITE(mac, 0x5c, 0);
1476298948Sadrian	}
1477298948Sadrian
1478298948Sadrian	old_channel = phy->chan;
1479298948Sadrian	bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
1480298948Sadrian
1481298948Sadrian	BWN_RF_WRITE(mac, 0x0050, 0x0020);
1482298948Sadrian	BWN_RF_WRITE(mac, 0x0050, 0x0023);
1483298948Sadrian	DELAY(40);
1484298948Sadrian	if (phy->rf_rev < 6 || phy->rf_rev == 8) {
1485298948Sadrian		BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
1486298948Sadrian		BWN_RF_WRITE(mac, 0x50, 0x20);
1487298948Sadrian	}
1488298948Sadrian	if (phy->rf_rev <= 2) {
1489298948Sadrian		BWN_RF_WRITE(mac, 0x7c, 0x20);
1490298948Sadrian		BWN_RF_WRITE(mac, 0x5a, 0x70);
1491298948Sadrian		BWN_RF_WRITE(mac, 0x5b, 0x7b);
1492298948Sadrian		BWN_RF_WRITE(mac, 0x5c, 0xb0);
1493298948Sadrian	}
1494298948Sadrian	BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
1495298948Sadrian
1496298948Sadrian	bwn_phy_g_switch_chan(mac, old_channel, 0);
1497298948Sadrian
1498298948Sadrian	BWN_PHY_WRITE(mac, 0x0014, 0x0200);
1499298948Sadrian	if (phy->rf_rev >= 6)
1500298948Sadrian		BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
1501298948Sadrian	else
1502298948Sadrian		BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
1503298948Sadrian	BWN_PHY_WRITE(mac, 0x0038, 0x0668);
1504298948Sadrian	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
1505298948Sadrian	    pg->pg_txctl);
1506298948Sadrian	if (phy->rf_rev <= 5)
1507298948Sadrian		BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
1508298948Sadrian	if (phy->rf_rev <= 2)
1509298948Sadrian		BWN_RF_WRITE(mac, 0x005d, 0x000d);
1510298948Sadrian
1511298948Sadrian	if (phy->analog == 4) {
1512298948Sadrian		BWN_WRITE_2(mac, 0x3e4, 9);
1513298948Sadrian		BWN_PHY_MASK(mac, 0x61, 0x0fff);
1514298948Sadrian	} else
1515298948Sadrian		BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
1516298948Sadrian	if (phy->type == BWN_PHYTYPE_B)
1517298948Sadrian		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1518298948Sadrian	else if (phy->type == BWN_PHYTYPE_G)
1519298948Sadrian		BWN_WRITE_2(mac, 0x03e6, 0x0);
1520298948Sadrian}
1521298948Sadrian
1522298948Sadrianstatic void
1523298948Sadrianbwn_phy_init_a(struct bwn_mac *mac)
1524298948Sadrian{
1525298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1526298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
1527298948Sadrian
1528298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
1529298948Sadrian	    ("%s:%d: fail", __func__, __LINE__));
1530298948Sadrian
1531298948Sadrian	if (phy->rev >= 6) {
1532298948Sadrian		if (phy->type == BWN_PHYTYPE_A)
1533298948Sadrian			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
1534298948Sadrian		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
1535298948Sadrian			BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
1536298948Sadrian		else
1537298948Sadrian			BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
1538298948Sadrian	}
1539298948Sadrian
1540298948Sadrian	bwn_wa_init(mac);
1541298948Sadrian
1542298948Sadrian	if (phy->type == BWN_PHYTYPE_G &&
1543298948Sadrian	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL))
1544298948Sadrian		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
1545298948Sadrian}
1546298948Sadrian
1547298948Sadrianstatic void
1548298948Sadrianbwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
1549298948Sadrian{
1550298948Sadrian	int i;
1551298948Sadrian
1552298948Sadrian	for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
1553298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
1554298948Sadrian}
1555298948Sadrian
1556298948Sadrianstatic void
1557298948Sadrianbwn_wa_agc(struct bwn_mac *mac)
1558298948Sadrian{
1559298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1560298948Sadrian
1561298948Sadrian	if (phy->rev == 1) {
1562298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
1563298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
1564298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
1565298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
1566298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
1567298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
1568298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
1569298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
1570298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
1571298948Sadrian	} else {
1572298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
1573298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
1574298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
1575298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
1576298948Sadrian	}
1577298948Sadrian
1578298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
1579298948Sadrian	    0x5700);
1580298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
1581298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
1582298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
1583298948Sadrian	BWN_RF_SET(mac, 0x7a, 0x0008);
1584298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
1585298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
1586298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
1587298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
1588298948Sadrian	if (phy->rev == 1)
1589298948Sadrian		BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
1590298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
1591298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
1592298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
1593298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
1594298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
1595298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
1596298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
1597298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
1598298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
1599298948Sadrian	if (phy->rev == 1) {
1600298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
1601298948Sadrian		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
1602298948Sadrian	} else {
1603298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
1604298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
1605298948Sadrian		BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
1606298948Sadrian		if (phy->rev >= 6) {
1607298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
1608298948Sadrian			BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
1609298948Sadrian			    (uint16_t)~0xf000, 0x3000);
1610298948Sadrian		}
1611298948Sadrian	}
1612298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
1613298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
1614298948Sadrian	if (phy->rev == 1) {
1615298948Sadrian		BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
1616298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
1617298948Sadrian		BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
1618298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
1619298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
1620298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
1621298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
1622298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
1623298948Sadrian	} else {
1624298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
1625298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
1626298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
1627298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
1628298948Sadrian	}
1629298948Sadrian	if (phy->rev >= 6) {
1630298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
1631298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
1632298948Sadrian	}
1633298948Sadrian	BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
1634298948Sadrian}
1635298948Sadrian
1636298948Sadrianstatic void
1637298948Sadrianbwn_wa_grev1(struct bwn_mac *mac)
1638298948Sadrian{
1639298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1640298948Sadrian	int i;
1641298948Sadrian	static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
1642298948Sadrian	static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
1643298948Sadrian	static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
1644298948Sadrian
1645298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
1646298948Sadrian
1647298948Sadrian	/* init CRSTHRES and ANTDWELL */
1648298948Sadrian	if (phy->rev == 1) {
1649298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
1650298948Sadrian	} else if (phy->rev == 2) {
1651298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
1652298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
1653298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
1654298948Sadrian	} else {
1655298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
1656298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
1657298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
1658298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
1659298948Sadrian	}
1660298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
1661298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
1662298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
1663298948Sadrian
1664298948Sadrian	/* XXX support PHY-A??? */
1665298948Sadrian	for (i = 0; i < N(bwn_tab_finefreqg); i++)
1666298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
1667298948Sadrian		    bwn_tab_finefreqg[i]);
1668298948Sadrian
1669298948Sadrian	/* XXX support PHY-A??? */
1670298948Sadrian	if (phy->rev == 1)
1671298948Sadrian		for (i = 0; i < N(bwn_tab_noise_g1); i++)
1672298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
1673298948Sadrian			    bwn_tab_noise_g1[i]);
1674298948Sadrian	else
1675298948Sadrian		for (i = 0; i < N(bwn_tab_noise_g2); i++)
1676298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
1677298948Sadrian			    bwn_tab_noise_g2[i]);
1678298948Sadrian
1679298948Sadrian
1680298948Sadrian	for (i = 0; i < N(bwn_tab_rotor); i++)
1681298948Sadrian		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
1682298948Sadrian		    bwn_tab_rotor[i]);
1683298948Sadrian
1684298948Sadrian	/* XXX support PHY-A??? */
1685298948Sadrian	if (phy->rev >= 6) {
1686298948Sadrian		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
1687298948Sadrian		    BWN_PHY_ENCORE_EN)
1688298948Sadrian			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
1689298948Sadrian		else
1690298948Sadrian			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
1691298948Sadrian	} else
1692298948Sadrian		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
1693298948Sadrian
1694298948Sadrian	for (i = 0; i < N(bwn_tab_retard); i++)
1695298948Sadrian		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
1696298948Sadrian		    bwn_tab_retard[i]);
1697298948Sadrian
1698298948Sadrian	if (phy->rev == 1) {
1699298948Sadrian		for (i = 0; i < 16; i++)
1700298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
1701298948Sadrian			    i, 0x0020);
1702298948Sadrian	} else {
1703298948Sadrian		for (i = 0; i < 32; i++)
1704298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
1705298948Sadrian	}
1706298948Sadrian
1707298948Sadrian	bwn_wa_agc(mac);
1708298948Sadrian}
1709298948Sadrian
1710298948Sadrianstatic void
1711298948Sadrianbwn_wa_grev26789(struct bwn_mac *mac)
1712298948Sadrian{
1713298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1714298948Sadrian	int i;
1715298948Sadrian	static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
1716298948Sadrian	uint16_t ofdmrev;
1717298948Sadrian
1718298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
1719298948Sadrian
1720298948Sadrian	bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
1721298948Sadrian
1722298948Sadrian	/* init CRSTHRES and ANTDWELL */
1723298948Sadrian	if (phy->rev == 1)
1724298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
1725298948Sadrian	else if (phy->rev == 2) {
1726298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
1727298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
1728298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
1729298948Sadrian	} else {
1730298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
1731298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
1732298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
1733298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
1734298948Sadrian	}
1735298948Sadrian
1736298948Sadrian	for (i = 0; i < 64; i++)
1737298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
1738298948Sadrian
1739298948Sadrian	/* XXX support PHY-A??? */
1740298948Sadrian	if (phy->rev == 1)
1741298948Sadrian		for (i = 0; i < N(bwn_tab_noise_g1); i++)
1742298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
1743298948Sadrian			    bwn_tab_noise_g1[i]);
1744298948Sadrian	else
1745298948Sadrian		for (i = 0; i < N(bwn_tab_noise_g2); i++)
1746298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
1747298948Sadrian			    bwn_tab_noise_g2[i]);
1748298948Sadrian
1749298948Sadrian	/* XXX support PHY-A??? */
1750298948Sadrian	if (phy->rev >= 6) {
1751298948Sadrian		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
1752298948Sadrian		    BWN_PHY_ENCORE_EN)
1753298948Sadrian			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
1754298948Sadrian		else
1755298948Sadrian			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
1756298948Sadrian	} else
1757298948Sadrian		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
1758298948Sadrian
1759298948Sadrian	for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
1760298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
1761298948Sadrian		    bwn_tab_sigmasqr2[i]);
1762298948Sadrian
1763298948Sadrian	if (phy->rev == 1) {
1764298948Sadrian		for (i = 0; i < 16; i++)
1765298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
1766298948Sadrian			    0x0020);
1767298948Sadrian	} else {
1768298948Sadrian		for (i = 0; i < 32; i++)
1769298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
1770298948Sadrian	}
1771298948Sadrian
1772298948Sadrian	bwn_wa_agc(mac);
1773298948Sadrian
1774298948Sadrian	ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
1775298948Sadrian	if (ofdmrev > 2) {
1776298948Sadrian		if (phy->type == BWN_PHYTYPE_A)
1777298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
1778298948Sadrian		else
1779298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
1780298948Sadrian	} else {
1781298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
1782298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
1783298948Sadrian		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
1784298948Sadrian	}
1785298948Sadrian
1786298948Sadrian	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
1787298948Sadrian	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
1788298948Sadrian}
1789298948Sadrian
1790298948Sadrianstatic void
1791298948Sadrianbwn_wa_init(struct bwn_mac *mac)
1792298948Sadrian{
1793298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1794298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
1795298948Sadrian
1796298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
1797298948Sadrian
1798298948Sadrian	switch (phy->rev) {
1799298948Sadrian	case 1:
1800298948Sadrian		bwn_wa_grev1(mac);
1801298948Sadrian		break;
1802298948Sadrian	case 2:
1803298948Sadrian	case 6:
1804298948Sadrian	case 7:
1805298948Sadrian	case 8:
1806298948Sadrian	case 9:
1807298948Sadrian		bwn_wa_grev26789(mac);
1808298948Sadrian		break;
1809298948Sadrian	default:
1810298948Sadrian		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1811298948Sadrian	}
1812298948Sadrian
1813298948Sadrian	if (siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM ||
1814298948Sadrian	    siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306 ||
1815298948Sadrian	    siba_get_pci_revid(sc->sc_dev) != 0x17) {
1816298948Sadrian		if (phy->rev < 2) {
1817298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
1818298948Sadrian			    0x0002);
1819298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
1820298948Sadrian			    0x0001);
1821298948Sadrian		} else {
1822298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
1823298948Sadrian			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
1824298948Sadrian			if ((siba_sprom_get_bf_lo(sc->sc_dev) &
1825298948Sadrian			     BWN_BFL_EXTLNA) &&
1826298948Sadrian			    (phy->rev >= 7)) {
1827298948Sadrian				BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
1828298948Sadrian				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1829298948Sadrian				    0x0020, 0x0001);
1830298948Sadrian				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1831298948Sadrian				    0x0021, 0x0001);
1832298948Sadrian				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1833298948Sadrian				    0x0022, 0x0001);
1834298948Sadrian				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1835298948Sadrian				    0x0023, 0x0000);
1836298948Sadrian				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1837298948Sadrian				    0x0000, 0x0000);
1838298948Sadrian				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
1839298948Sadrian				    0x0003, 0x0002);
1840298948Sadrian			}
1841298948Sadrian		}
1842298948Sadrian	}
1843298948Sadrian	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) {
1844298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
1845298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
1846298948Sadrian	}
1847298948Sadrian
1848298948Sadrian	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
1849298948Sadrian	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
1850298948Sadrian}
1851298948Sadrian
1852298948Sadrianstatic void
1853298948Sadrianbwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
1854298948Sadrian    uint16_t value)
1855298948Sadrian{
1856298948Sadrian	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
1857298948Sadrian	uint16_t addr;
1858298948Sadrian
1859298948Sadrian	addr = table + offset;
1860298948Sadrian	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
1861298948Sadrian	    (addr - 1 != pg->pg_ofdmtab_addr)) {
1862298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
1863298948Sadrian		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
1864298948Sadrian	}
1865298948Sadrian	pg->pg_ofdmtab_addr = addr;
1866298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
1867298948Sadrian}
1868298948Sadrian
1869298948Sadrianstatic void
1870298948Sadrianbwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
1871298948Sadrian    uint32_t value)
1872298948Sadrian{
1873298948Sadrian	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
1874298948Sadrian	uint16_t addr;
1875298948Sadrian
1876298948Sadrian	addr = table + offset;
1877298948Sadrian	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
1878298948Sadrian	    (addr - 1 != pg->pg_ofdmtab_addr)) {
1879298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
1880298948Sadrian		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
1881298948Sadrian	}
1882298948Sadrian	pg->pg_ofdmtab_addr = addr;
1883298948Sadrian
1884298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
1885298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
1886298948Sadrian}
1887298948Sadrian
1888298948Sadrianstatic void
1889298948Sadrianbwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
1890298948Sadrian    uint16_t value)
1891298948Sadrian{
1892298948Sadrian
1893298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
1894298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
1895298948Sadrian}
1896298948Sadrian
1897298948Sadrianstatic void
1898298948Sadrianbwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
1899298948Sadrian{
1900298948Sadrian	uint16_t value;
1901298948Sadrian
1902298948Sadrian	KASSERT(mac->mac_phy.type == BWN_PHYTYPE_G,
1903298948Sadrian	    ("%s:%d: fail", __func__, __LINE__));
1904298948Sadrian
1905298948Sadrian	value = (uint8_t) (ctl->q);
1906298948Sadrian	value |= ((uint8_t) (ctl->i)) << 8;
1907298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
1908298948Sadrian}
1909298948Sadrian
1910298948Sadrianstatic uint16_t
1911298948Sadrianbwn_lo_calcfeed(struct bwn_mac *mac,
1912298948Sadrian    uint16_t lna, uint16_t pga, uint16_t trsw_rx)
1913298948Sadrian{
1914298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1915298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
1916298948Sadrian	uint16_t rfover;
1917298948Sadrian	uint16_t feedthrough;
1918298948Sadrian
1919298948Sadrian	if (phy->gmode) {
1920298948Sadrian		lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
1921298948Sadrian		pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
1922298948Sadrian
1923298948Sadrian		KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
1924298948Sadrian		    ("%s:%d: fail", __func__, __LINE__));
1925298948Sadrian		KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
1926298948Sadrian		    ("%s:%d: fail", __func__, __LINE__));
1927298948Sadrian
1928298948Sadrian		trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
1929298948Sadrian
1930298948Sadrian		rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
1931298948Sadrian		if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) &&
1932298948Sadrian		    phy->rev > 6)
1933298948Sadrian			rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
1934298948Sadrian
1935298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
1936298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
1937298948Sadrian		DELAY(10);
1938298948Sadrian		rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
1939298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
1940298948Sadrian		DELAY(10);
1941298948Sadrian		rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
1942298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
1943298948Sadrian		DELAY(10);
1944298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
1945298948Sadrian	} else {
1946298948Sadrian		pga |= BWN_PHY_PGACTL_UNKNOWN;
1947298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
1948298948Sadrian		DELAY(10);
1949298948Sadrian		pga |= BWN_PHY_PGACTL_LOWBANDW;
1950298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
1951298948Sadrian		DELAY(10);
1952298948Sadrian		pga |= BWN_PHY_PGACTL_LPF;
1953298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
1954298948Sadrian	}
1955298948Sadrian	DELAY(21);
1956298948Sadrian	feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
1957298948Sadrian
1958298948Sadrian	return (feedthrough);
1959298948Sadrian}
1960298948Sadrian
1961298948Sadrianstatic uint16_t
1962298948Sadrianbwn_lo_txctl_regtable(struct bwn_mac *mac,
1963298948Sadrian    uint16_t *value, uint16_t *pad_mix_gain)
1964298948Sadrian{
1965298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1966298948Sadrian	uint16_t reg, v, padmix;
1967298948Sadrian
1968298948Sadrian	if (phy->type == BWN_PHYTYPE_B) {
1969298948Sadrian		v = 0x30;
1970298948Sadrian		if (phy->rf_rev <= 5) {
1971298948Sadrian			reg = 0x43;
1972298948Sadrian			padmix = 0;
1973298948Sadrian		} else {
1974298948Sadrian			reg = 0x52;
1975298948Sadrian			padmix = 5;
1976298948Sadrian		}
1977298948Sadrian	} else {
1978298948Sadrian		if (phy->rev >= 2 && phy->rf_rev == 8) {
1979298948Sadrian			reg = 0x43;
1980298948Sadrian			v = 0x10;
1981298948Sadrian			padmix = 2;
1982298948Sadrian		} else {
1983298948Sadrian			reg = 0x52;
1984298948Sadrian			v = 0x30;
1985298948Sadrian			padmix = 5;
1986298948Sadrian		}
1987298948Sadrian	}
1988298948Sadrian	if (value)
1989298948Sadrian		*value = v;
1990298948Sadrian	if (pad_mix_gain)
1991298948Sadrian		*pad_mix_gain = padmix;
1992298948Sadrian
1993298948Sadrian	return (reg);
1994298948Sadrian}
1995298948Sadrian
1996298948Sadrianstatic void
1997298948Sadrianbwn_lo_measure_txctl_values(struct bwn_mac *mac)
1998298948Sadrian{
1999298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2000298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2001298948Sadrian	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2002298948Sadrian	uint16_t reg, mask;
2003298948Sadrian	uint16_t trsw_rx, pga;
2004298948Sadrian	uint16_t rf_pctl_reg;
2005298948Sadrian
2006298948Sadrian	static const uint8_t tx_bias_values[] = {
2007298948Sadrian		0x09, 0x08, 0x0a, 0x01, 0x00,
2008298948Sadrian		0x02, 0x05, 0x04, 0x06,
2009298948Sadrian	};
2010298948Sadrian	static const uint8_t tx_magn_values[] = {
2011298948Sadrian		0x70, 0x40,
2012298948Sadrian	};
2013298948Sadrian
2014298948Sadrian	if (!BWN_HAS_LOOPBACK(phy)) {
2015298948Sadrian		rf_pctl_reg = 6;
2016298948Sadrian		trsw_rx = 2;
2017298948Sadrian		pga = 0;
2018298948Sadrian	} else {
2019298948Sadrian		int lb_gain;
2020298948Sadrian
2021298948Sadrian		trsw_rx = 0;
2022298948Sadrian		lb_gain = pg->pg_max_lb_gain / 2;
2023298948Sadrian		if (lb_gain > 10) {
2024298948Sadrian			rf_pctl_reg = 0;
2025298948Sadrian			pga = abs(10 - lb_gain) / 6;
2026298948Sadrian			pga = MIN(MAX(pga, 0), 15);
2027298948Sadrian		} else {
2028298948Sadrian			int cmp_val;
2029298948Sadrian			int tmp;
2030298948Sadrian
2031298948Sadrian			pga = 0;
2032298948Sadrian			cmp_val = 0x24;
2033298948Sadrian			if ((phy->rev >= 2) &&
2034298948Sadrian			    (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
2035298948Sadrian				cmp_val = 0x3c;
2036298948Sadrian			tmp = lb_gain;
2037298948Sadrian			if ((10 - lb_gain) < cmp_val)
2038298948Sadrian				tmp = (10 - lb_gain);
2039298948Sadrian			if (tmp < 0)
2040298948Sadrian				tmp += 6;
2041298948Sadrian			else
2042298948Sadrian				tmp += 3;
2043298948Sadrian			cmp_val /= 4;
2044298948Sadrian			tmp /= 4;
2045298948Sadrian			if (tmp >= cmp_val)
2046298948Sadrian				rf_pctl_reg = cmp_val;
2047298948Sadrian			else
2048298948Sadrian				rf_pctl_reg = tmp;
2049298948Sadrian		}
2050298948Sadrian	}
2051298948Sadrian	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
2052298948Sadrian	bwn_phy_g_set_bbatt(mac, 2);
2053298948Sadrian
2054298948Sadrian	reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
2055298948Sadrian	mask = ~mask;
2056298948Sadrian	BWN_RF_MASK(mac, reg, mask);
2057298948Sadrian
2058298948Sadrian	if (BWN_HAS_TXMAG(phy)) {
2059298948Sadrian		int i, j;
2060298948Sadrian		int feedthrough;
2061298948Sadrian		int min_feedth = 0xffff;
2062298948Sadrian		uint8_t tx_magn, tx_bias;
2063298948Sadrian
2064298948Sadrian		for (i = 0; i < N(tx_magn_values); i++) {
2065298948Sadrian			tx_magn = tx_magn_values[i];
2066298948Sadrian			BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
2067298948Sadrian			for (j = 0; j < N(tx_bias_values); j++) {
2068298948Sadrian				tx_bias = tx_bias_values[j];
2069298948Sadrian				BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
2070298948Sadrian				feedthrough = bwn_lo_calcfeed(mac, 0, pga,
2071298948Sadrian				    trsw_rx);
2072298948Sadrian				if (feedthrough < min_feedth) {
2073298948Sadrian					lo->tx_bias = tx_bias;
2074298948Sadrian					lo->tx_magn = tx_magn;
2075298948Sadrian					min_feedth = feedthrough;
2076298948Sadrian				}
2077298948Sadrian				if (lo->tx_bias == 0)
2078298948Sadrian					break;
2079298948Sadrian			}
2080298948Sadrian			BWN_RF_WRITE(mac, 0x52,
2081298948Sadrian					  (BWN_RF_READ(mac, 0x52)
2082298948Sadrian					   & 0xff00) | lo->tx_bias | lo->
2083298948Sadrian					  tx_magn);
2084298948Sadrian		}
2085298948Sadrian	} else {
2086298948Sadrian		lo->tx_magn = 0;
2087298948Sadrian		lo->tx_bias = 0;
2088298948Sadrian		BWN_RF_MASK(mac, 0x52, 0xfff0);
2089298948Sadrian	}
2090298948Sadrian
2091298948Sadrian	BWN_GETTIME(lo->txctl_measured_time);
2092298948Sadrian}
2093298948Sadrian
2094298948Sadrianstatic void
2095298948Sadrianbwn_lo_get_powervector(struct bwn_mac *mac)
2096298948Sadrian{
2097298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2098298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2099298948Sadrian	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2100298948Sadrian	int i;
2101298948Sadrian	uint64_t tmp;
2102298948Sadrian	uint64_t power_vector = 0;
2103298948Sadrian
2104298948Sadrian	for (i = 0; i < 8; i += 2) {
2105298948Sadrian		tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
2106298948Sadrian		power_vector |= (tmp << (i * 8));
2107298948Sadrian		bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
2108298948Sadrian	}
2109298948Sadrian	if (power_vector)
2110298948Sadrian		lo->power_vector = power_vector;
2111298948Sadrian
2112298948Sadrian	BWN_GETTIME(lo->pwr_vec_read_time);
2113298948Sadrian}
2114298948Sadrian
2115298948Sadrianstatic void
2116298948Sadrianbwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
2117298948Sadrian    int use_trsw_rx)
2118298948Sadrian{
2119298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2120298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2121298948Sadrian	uint16_t tmp;
2122298948Sadrian
2123298948Sadrian	if (max_rx_gain < 0)
2124298948Sadrian		max_rx_gain = 0;
2125298948Sadrian
2126298948Sadrian	if (BWN_HAS_LOOPBACK(phy)) {
2127298948Sadrian		int trsw_rx = 0;
2128298948Sadrian		int trsw_rx_gain;
2129298948Sadrian
2130298948Sadrian		if (use_trsw_rx) {
2131298948Sadrian			trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
2132298948Sadrian			if (max_rx_gain >= trsw_rx_gain) {
2133298948Sadrian				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
2134298948Sadrian				trsw_rx = 0x20;
2135298948Sadrian			}
2136298948Sadrian		} else
2137298948Sadrian			trsw_rx_gain = max_rx_gain;
2138298948Sadrian		if (trsw_rx_gain < 9) {
2139298948Sadrian			pg->pg_lna_lod_gain = 0;
2140298948Sadrian		} else {
2141298948Sadrian			pg->pg_lna_lod_gain = 1;
2142298948Sadrian			trsw_rx_gain -= 8;
2143298948Sadrian		}
2144298948Sadrian		trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
2145298948Sadrian		pg->pg_pga_gain = trsw_rx_gain / 3;
2146298948Sadrian		if (pg->pg_pga_gain >= 5) {
2147298948Sadrian			pg->pg_pga_gain -= 5;
2148298948Sadrian			pg->pg_lna_gain = 2;
2149298948Sadrian		} else
2150298948Sadrian			pg->pg_lna_gain = 0;
2151298948Sadrian	} else {
2152298948Sadrian		pg->pg_lna_gain = 0;
2153298948Sadrian		pg->pg_trsw_rx_gain = 0x20;
2154298948Sadrian		if (max_rx_gain >= 0x14) {
2155298948Sadrian			pg->pg_lna_lod_gain = 1;
2156298948Sadrian			pg->pg_pga_gain = 2;
2157298948Sadrian		} else if (max_rx_gain >= 0x12) {
2158298948Sadrian			pg->pg_lna_lod_gain = 1;
2159298948Sadrian			pg->pg_pga_gain = 1;
2160298948Sadrian		} else if (max_rx_gain >= 0xf) {
2161298948Sadrian			pg->pg_lna_lod_gain = 1;
2162298948Sadrian			pg->pg_pga_gain = 0;
2163298948Sadrian		} else {
2164298948Sadrian			pg->pg_lna_lod_gain = 0;
2165298948Sadrian			pg->pg_pga_gain = 0;
2166298948Sadrian		}
2167298948Sadrian	}
2168298948Sadrian
2169298948Sadrian	tmp = BWN_RF_READ(mac, 0x7a);
2170298948Sadrian	if (pg->pg_lna_lod_gain == 0)
2171298948Sadrian		tmp &= ~0x0008;
2172298948Sadrian	else
2173298948Sadrian		tmp |= 0x0008;
2174298948Sadrian	BWN_RF_WRITE(mac, 0x7a, tmp);
2175298948Sadrian}
2176298948Sadrian
2177298948Sadrianstatic void
2178298948Sadrianbwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
2179298948Sadrian{
2180298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2181298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2182298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
2183298948Sadrian	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2184298948Sadrian	struct timespec ts;
2185298948Sadrian	uint16_t tmp;
2186298948Sadrian
2187298948Sadrian	if (bwn_has_hwpctl(mac)) {
2188298948Sadrian		sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
2189298948Sadrian		sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
2190298948Sadrian		sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
2191298948Sadrian		sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
2192298948Sadrian		sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
2193298948Sadrian
2194298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
2195298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
2196298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
2197298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
2198298948Sadrian	}
2199298948Sadrian	if (phy->type == BWN_PHYTYPE_B &&
2200298948Sadrian	    phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
2201298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
2202298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
2203298948Sadrian	}
2204298948Sadrian	if (phy->rev >= 2) {
2205298948Sadrian		sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
2206298948Sadrian		sav->phy_analogoverval =
2207298948Sadrian		    BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
2208298948Sadrian		sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
2209298948Sadrian		sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
2210298948Sadrian		sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
2211298948Sadrian		sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
2212298948Sadrian		sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
2213298948Sadrian
2214298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
2215298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
2216298948Sadrian		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
2217298948Sadrian		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
2218298948Sadrian		if (phy->type == BWN_PHYTYPE_G) {
2219298948Sadrian			if ((phy->rev >= 7) &&
2220298948Sadrian			    (siba_sprom_get_bf_lo(sc->sc_dev) &
2221298948Sadrian			     BWN_BFL_EXTLNA)) {
2222298948Sadrian				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
2223298948Sadrian			} else {
2224298948Sadrian				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
2225298948Sadrian			}
2226298948Sadrian		} else {
2227298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
2228298948Sadrian		}
2229298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
2230298948Sadrian	}
2231298948Sadrian	sav->reg0 = BWN_READ_2(mac, 0x3f4);
2232298948Sadrian	sav->reg1 = BWN_READ_2(mac, 0x3e2);
2233298948Sadrian	sav->rf0 = BWN_RF_READ(mac, 0x43);
2234298948Sadrian	sav->rf1 = BWN_RF_READ(mac, 0x7a);
2235298948Sadrian	sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
2236298948Sadrian	sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
2237298948Sadrian	sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
2238298948Sadrian	sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
2239298948Sadrian
2240298948Sadrian	if (!BWN_HAS_TXMAG(phy)) {
2241298948Sadrian		sav->rf2 = BWN_RF_READ(mac, 0x52);
2242298948Sadrian		sav->rf2 &= 0x00f0;
2243298948Sadrian	}
2244298948Sadrian	if (phy->type == BWN_PHYTYPE_B) {
2245298948Sadrian		sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
2246298948Sadrian		sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
2247298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
2248298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
2249298948Sadrian	} else {
2250298948Sadrian		BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
2251298948Sadrian			    | 0x8000);
2252298948Sadrian	}
2253298948Sadrian	BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
2254298948Sadrian		    & 0xf000);
2255298948Sadrian
2256298948Sadrian	tmp =
2257298948Sadrian	    (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
2258298948Sadrian	BWN_PHY_WRITE(mac, tmp, 0x007f);
2259298948Sadrian
2260298948Sadrian	tmp = sav->phy_syncctl;
2261298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
2262298948Sadrian	tmp = sav->rf1;
2263298948Sadrian	BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
2264298948Sadrian
2265298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
2266298948Sadrian	if (phy->type == BWN_PHYTYPE_G ||
2267298948Sadrian	    (phy->type == BWN_PHYTYPE_B &&
2268298948Sadrian	     phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
2269298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
2270298948Sadrian	} else
2271298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
2272298948Sadrian	if (phy->rev >= 2)
2273298948Sadrian		bwn_dummy_transmission(mac, 0, 1);
2274298948Sadrian	bwn_phy_g_switch_chan(mac, 6, 0);
2275298948Sadrian	BWN_RF_READ(mac, 0x51);
2276298948Sadrian	if (phy->type == BWN_PHYTYPE_G)
2277298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
2278298948Sadrian
2279298948Sadrian	nanouptime(&ts);
2280298948Sadrian	if (ieee80211_time_before(lo->txctl_measured_time,
2281298948Sadrian	    (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
2282298948Sadrian		bwn_lo_measure_txctl_values(mac);
2283298948Sadrian
2284298948Sadrian	if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
2285298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
2286298948Sadrian	else {
2287298948Sadrian		if (phy->type == BWN_PHYTYPE_B)
2288298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
2289298948Sadrian		else
2290298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
2291298948Sadrian	}
2292298948Sadrian}
2293298948Sadrian
2294298948Sadrianstatic void
2295298948Sadrianbwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
2296298948Sadrian{
2297298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2298298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2299298948Sadrian	uint16_t tmp;
2300298948Sadrian
2301298948Sadrian	if (phy->rev >= 2) {
2302298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
2303298948Sadrian		tmp = (pg->pg_pga_gain << 8);
2304298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
2305298948Sadrian		DELAY(5);
2306298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
2307298948Sadrian		DELAY(2);
2308298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
2309298948Sadrian	} else {
2310298948Sadrian		tmp = (pg->pg_pga_gain | 0xefa0);
2311298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
2312298948Sadrian	}
2313298948Sadrian	if (phy->type == BWN_PHYTYPE_G) {
2314298948Sadrian		if (phy->rev >= 3)
2315298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
2316298948Sadrian		else
2317298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
2318298948Sadrian		if (phy->rev >= 2)
2319298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
2320298948Sadrian		else
2321298948Sadrian			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
2322298948Sadrian	}
2323298948Sadrian	BWN_WRITE_2(mac, 0x3f4, sav->reg0);
2324298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
2325298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
2326298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
2327298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
2328298948Sadrian	BWN_RF_WRITE(mac, 0x43, sav->rf0);
2329298948Sadrian	BWN_RF_WRITE(mac, 0x7a, sav->rf1);
2330298948Sadrian	if (!BWN_HAS_TXMAG(phy)) {
2331298948Sadrian		tmp = sav->rf2;
2332298948Sadrian		BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
2333298948Sadrian	}
2334298948Sadrian	BWN_WRITE_2(mac, 0x3e2, sav->reg1);
2335298948Sadrian	if (phy->type == BWN_PHYTYPE_B &&
2336298948Sadrian	    phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
2337298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
2338298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
2339298948Sadrian	}
2340298948Sadrian	if (phy->rev >= 2) {
2341298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
2342298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
2343298948Sadrian			      sav->phy_analogoverval);
2344298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
2345298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
2346298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
2347298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
2348298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
2349298948Sadrian	}
2350298948Sadrian	if (bwn_has_hwpctl(mac)) {
2351298948Sadrian		tmp = (sav->phy_lomask & 0xbfff);
2352298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
2353298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
2354298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
2355298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
2356298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
2357298948Sadrian	}
2358298948Sadrian	bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
2359298948Sadrian}
2360298948Sadrian
2361298948Sadrianstatic int
2362298948Sadrianbwn_lo_probe_loctl(struct bwn_mac *mac,
2363298948Sadrian    struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
2364298948Sadrian{
2365298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2366298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2367298948Sadrian	struct bwn_loctl orig, test;
2368298948Sadrian	struct bwn_loctl prev = { -100, -100 };
2369298948Sadrian	static const struct bwn_loctl modifiers[] = {
2370298948Sadrian		{  1,  1,}, {  1,  0,}, {  1, -1,}, {  0, -1,},
2371298948Sadrian		{ -1, -1,}, { -1,  0,}, { -1,  1,}, {  0,  1,}
2372298948Sadrian	};
2373298948Sadrian	int begin, end, lower = 0, i;
2374298948Sadrian	uint16_t feedth;
2375298948Sadrian
2376298948Sadrian	if (d->curstate == 0) {
2377298948Sadrian		begin = 1;
2378298948Sadrian		end = 8;
2379298948Sadrian	} else if (d->curstate % 2 == 0) {
2380298948Sadrian		begin = d->curstate - 1;
2381298948Sadrian		end = d->curstate + 1;
2382298948Sadrian	} else {
2383298948Sadrian		begin = d->curstate - 2;
2384298948Sadrian		end = d->curstate + 2;
2385298948Sadrian	}
2386298948Sadrian	if (begin < 1)
2387298948Sadrian		begin += 8;
2388298948Sadrian	if (end > 8)
2389298948Sadrian		end -= 8;
2390298948Sadrian
2391298948Sadrian	memcpy(&orig, probe, sizeof(struct bwn_loctl));
2392298948Sadrian	i = begin;
2393298948Sadrian	d->curstate = i;
2394298948Sadrian	while (1) {
2395298948Sadrian		KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
2396298948Sadrian		memcpy(&test, &orig, sizeof(struct bwn_loctl));
2397298948Sadrian		test.i += modifiers[i - 1].i * d->multipler;
2398298948Sadrian		test.q += modifiers[i - 1].q * d->multipler;
2399298948Sadrian		if ((test.i != prev.i || test.q != prev.q) &&
2400298948Sadrian		    (abs(test.i) <= 16 && abs(test.q) <= 16)) {
2401298948Sadrian			bwn_lo_write(mac, &test);
2402298948Sadrian			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
2403298948Sadrian			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
2404298948Sadrian			if (feedth < d->feedth) {
2405298948Sadrian				memcpy(probe, &test,
2406298948Sadrian				    sizeof(struct bwn_loctl));
2407298948Sadrian				lower = 1;
2408298948Sadrian				d->feedth = feedth;
2409298948Sadrian				if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
2410298948Sadrian					break;
2411298948Sadrian			}
2412298948Sadrian		}
2413298948Sadrian		memcpy(&prev, &test, sizeof(prev));
2414298948Sadrian		if (i == end)
2415298948Sadrian			break;
2416298948Sadrian		if (i == 8)
2417298948Sadrian			i = 1;
2418298948Sadrian		else
2419298948Sadrian			i++;
2420298948Sadrian		d->curstate = i;
2421298948Sadrian	}
2422298948Sadrian
2423298948Sadrian	return (lower);
2424298948Sadrian}
2425298948Sadrian
2426298948Sadrianstatic void
2427298948Sadrianbwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
2428298948Sadrian{
2429298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2430298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2431298948Sadrian	struct bwn_lo_g_sm d;
2432298948Sadrian	struct bwn_loctl probe;
2433298948Sadrian	int lower, repeat, cnt = 0;
2434298948Sadrian	uint16_t feedth;
2435298948Sadrian
2436298948Sadrian	d.nmeasure = 0;
2437298948Sadrian	d.multipler = 1;
2438298948Sadrian	if (BWN_HAS_LOOPBACK(phy))
2439298948Sadrian		d.multipler = 3;
2440298948Sadrian
2441298948Sadrian	memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
2442298948Sadrian	repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
2443298948Sadrian
2444298948Sadrian	do {
2445298948Sadrian		bwn_lo_write(mac, &d.loctl);
2446298948Sadrian		feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
2447298948Sadrian		    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
2448298948Sadrian		if (feedth < 0x258) {
2449298948Sadrian			if (feedth >= 0x12c)
2450298948Sadrian				*rxgain += 6;
2451298948Sadrian			else
2452298948Sadrian				*rxgain += 3;
2453298948Sadrian			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
2454298948Sadrian			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
2455298948Sadrian		}
2456298948Sadrian		d.feedth = feedth;
2457298948Sadrian		d.curstate = 0;
2458298948Sadrian		do {
2459298948Sadrian			KASSERT(d.curstate >= 0 && d.curstate <= 8,
2460298948Sadrian			    ("%s:%d: fail", __func__, __LINE__));
2461298948Sadrian			memcpy(&probe, &d.loctl,
2462298948Sadrian			       sizeof(struct bwn_loctl));
2463298948Sadrian			lower = bwn_lo_probe_loctl(mac, &probe, &d);
2464298948Sadrian			if (!lower)
2465298948Sadrian				break;
2466298948Sadrian			if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
2467298948Sadrian				break;
2468298948Sadrian			memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
2469298948Sadrian			d.nmeasure++;
2470298948Sadrian		} while (d.nmeasure < 24);
2471298948Sadrian		memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
2472298948Sadrian
2473298948Sadrian		if (BWN_HAS_LOOPBACK(phy)) {
2474298948Sadrian			if (d.feedth > 0x1194)
2475298948Sadrian				*rxgain -= 6;
2476298948Sadrian			else if (d.feedth < 0x5dc)
2477298948Sadrian				*rxgain += 3;
2478298948Sadrian			if (cnt == 0) {
2479298948Sadrian				if (d.feedth <= 0x5dc) {
2480298948Sadrian					d.multipler = 1;
2481298948Sadrian					cnt++;
2482298948Sadrian				} else
2483298948Sadrian					d.multipler = 2;
2484298948Sadrian			} else if (cnt == 2)
2485298948Sadrian				d.multipler = 1;
2486298948Sadrian		}
2487298948Sadrian		bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
2488298948Sadrian	} while (++cnt < repeat);
2489298948Sadrian}
2490298948Sadrian
2491298948Sadrianstatic struct bwn_lo_calib *
2492298948Sadrianbwn_lo_calibset(struct bwn_mac *mac,
2493298948Sadrian    const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
2494298948Sadrian{
2495298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2496298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2497298948Sadrian	struct bwn_loctl loctl = { 0, 0 };
2498298948Sadrian	struct bwn_lo_calib *cal;
2499298948Sadrian	struct bwn_lo_g_value sval = { 0 };
2500298948Sadrian	int rxgain;
2501298948Sadrian	uint16_t pad, reg, value;
2502298948Sadrian
2503298948Sadrian	sval.old_channel = phy->chan;
2504298948Sadrian	bwn_mac_suspend(mac);
2505298948Sadrian	bwn_lo_save(mac, &sval);
2506298948Sadrian
2507298948Sadrian	reg = bwn_lo_txctl_regtable(mac, &value, &pad);
2508298948Sadrian	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
2509298948Sadrian	BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
2510298948Sadrian
2511298948Sadrian	rxgain = (rfatt->att * 2) + (bbatt->att / 2);
2512298948Sadrian	if (rfatt->padmix)
2513298948Sadrian		rxgain -= pad;
2514298948Sadrian	if (BWN_HAS_LOOPBACK(phy))
2515298948Sadrian		rxgain += pg->pg_max_lb_gain;
2516298948Sadrian	bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
2517298948Sadrian	bwn_phy_g_set_bbatt(mac, bbatt->att);
2518298948Sadrian	bwn_lo_probe_sm(mac, &loctl, &rxgain);
2519298948Sadrian
2520298948Sadrian	bwn_lo_restore(mac, &sval);
2521298948Sadrian	bwn_mac_enable(mac);
2522298948Sadrian
2523298948Sadrian	cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
2524298948Sadrian	if (!cal) {
2525298948Sadrian		device_printf(mac->mac_sc->sc_dev, "out of memory\n");
2526298948Sadrian		return (NULL);
2527298948Sadrian	}
2528298948Sadrian	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
2529298948Sadrian	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
2530298948Sadrian	memcpy(&cal->ctl, &loctl, sizeof(loctl));
2531298948Sadrian
2532298948Sadrian	BWN_GETTIME(cal->calib_time);
2533298948Sadrian
2534298948Sadrian	return (cal);
2535298948Sadrian}
2536298948Sadrian
2537298948Sadrianstatic struct bwn_lo_calib *
2538298948Sadrianbwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
2539298948Sadrian    const struct bwn_rfatt *rfatt)
2540298948Sadrian{
2541298948Sadrian	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
2542298948Sadrian	struct bwn_lo_calib *c;
2543298948Sadrian
2544298948Sadrian	TAILQ_FOREACH(c, &lo->calib_list, list) {
2545298948Sadrian		if (!BWN_BBATTCMP(&c->bbatt, bbatt))
2546298948Sadrian			continue;
2547298948Sadrian		if (!BWN_RFATTCMP(&c->rfatt, rfatt))
2548298948Sadrian			continue;
2549298948Sadrian		return (c);
2550298948Sadrian	}
2551298948Sadrian
2552298948Sadrian	c = bwn_lo_calibset(mac, bbatt, rfatt);
2553298948Sadrian	if (!c)
2554298948Sadrian		return (NULL);
2555298948Sadrian	TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
2556298948Sadrian
2557298948Sadrian	return (c);
2558298948Sadrian}
2559298948Sadrian
2560298948Sadrianstatic void
2561298948Sadrianbwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
2562298948Sadrian{
2563298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2564298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2565298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
2566298948Sadrian	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2567298948Sadrian	const struct bwn_rfatt *rfatt;
2568298948Sadrian	const struct bwn_bbatt *bbatt;
2569298948Sadrian	uint64_t pvector;
2570298948Sadrian	int i;
2571298948Sadrian	int rf_offset, bb_offset;
2572298948Sadrian	uint8_t changed = 0;
2573298948Sadrian
2574298948Sadrian	KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
2575298948Sadrian	KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
2576298948Sadrian	    ("%s:%d: fail", __func__, __LINE__));
2577298948Sadrian
2578298948Sadrian	pvector = lo->power_vector;
2579298948Sadrian	if (!update && !pvector)
2580298948Sadrian		return;
2581298948Sadrian
2582298948Sadrian	bwn_mac_suspend(mac);
2583298948Sadrian
2584298948Sadrian	for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
2585298948Sadrian		struct bwn_lo_calib *cal;
2586298948Sadrian		int idx;
2587298948Sadrian		uint16_t val;
2588298948Sadrian
2589298948Sadrian		if (!update && !(pvector & (((uint64_t)1ULL) << i)))
2590298948Sadrian			continue;
2591298948Sadrian		bb_offset = i / lo->rfatt.len;
2592298948Sadrian		rf_offset = i % lo->rfatt.len;
2593298948Sadrian		bbatt = &(lo->bbatt.array[bb_offset]);
2594298948Sadrian		rfatt = &(lo->rfatt.array[rf_offset]);
2595298948Sadrian
2596298948Sadrian		cal = bwn_lo_calibset(mac, bbatt, rfatt);
2597298948Sadrian		if (!cal) {
2598298948Sadrian			device_printf(sc->sc_dev, "LO: Could not "
2599298948Sadrian			    "calibrate DC table entry\n");
2600298948Sadrian			continue;
2601298948Sadrian		}
2602298948Sadrian		val = (uint8_t)(cal->ctl.q);
2603298948Sadrian		val |= ((uint8_t)(cal->ctl.i)) << 4;
2604298948Sadrian		free(cal, M_DEVBUF);
2605298948Sadrian
2606298948Sadrian		idx = i / 2;
2607298948Sadrian		if (i % 2)
2608298948Sadrian			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
2609298948Sadrian			    | ((val & 0x00ff) << 8);
2610298948Sadrian		else
2611298948Sadrian			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
2612298948Sadrian			    | (val & 0x00ff);
2613298948Sadrian		changed = 1;
2614298948Sadrian	}
2615298948Sadrian	if (changed) {
2616298948Sadrian		for (i = 0; i < BWN_DC_LT_SIZE; i++)
2617298948Sadrian			BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
2618298948Sadrian	}
2619298948Sadrian	bwn_mac_enable(mac);
2620298948Sadrian}
2621298948Sadrian
2622298948Sadrianstatic void
2623298948Sadrianbwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
2624298948Sadrian{
2625298948Sadrian
2626298948Sadrian	if (!rf->padmix)
2627298948Sadrian		return;
2628298948Sadrian	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
2629298948Sadrian		rf->att = 4;
2630298948Sadrian}
2631298948Sadrian
2632298948Sadrianstatic void
2633298948Sadrianbwn_lo_g_adjust(struct bwn_mac *mac)
2634298948Sadrian{
2635298948Sadrian	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
2636298948Sadrian	struct bwn_lo_calib *cal;
2637298948Sadrian	struct bwn_rfatt rf;
2638298948Sadrian
2639298948Sadrian	memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
2640298948Sadrian	bwn_lo_fixup_rfatt(&rf);
2641298948Sadrian
2642298948Sadrian	cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
2643298948Sadrian	if (!cal)
2644298948Sadrian		return;
2645298948Sadrian	bwn_lo_write(mac, &cal->ctl);
2646298948Sadrian}
2647298948Sadrian
2648298948Sadrianstatic void
2649298948Sadrianbwn_lo_g_init(struct bwn_mac *mac)
2650298948Sadrian{
2651298948Sadrian
2652298948Sadrian	if (!bwn_has_hwpctl(mac))
2653298948Sadrian		return;
2654298948Sadrian
2655298948Sadrian	bwn_lo_get_powervector(mac);
2656298948Sadrian	bwn_phy_g_dc_lookup_init(mac, 1);
2657298948Sadrian}
2658298948Sadrian
2659298948Sadrianstatic int16_t
2660298948Sadrianbwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
2661298948Sadrian{
2662298948Sadrian
2663298948Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
2664298948Sadrian	return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
2665298948Sadrian}
2666298948Sadrian
2667298948Sadrianstatic void
2668298948Sadrianbwn_nrssi_threshold(struct bwn_mac *mac)
2669298948Sadrian{
2670298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2671298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2672298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
2673298948Sadrian	int32_t a, b;
2674298948Sadrian	int16_t tmp16;
2675298948Sadrian	uint16_t tmpu16;
2676298948Sadrian
2677298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2678298948Sadrian
2679298948Sadrian	if (phy->gmode && (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
2680298948Sadrian		if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
2681298948Sadrian			a = 0x13;
2682298948Sadrian			b = 0x12;
2683298948Sadrian		} else {
2684298948Sadrian			a = 0xe;
2685298948Sadrian			b = 0x11;
2686298948Sadrian		}
2687298948Sadrian
2688298948Sadrian		a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
2689298948Sadrian		a += (pg->pg_nrssi[0] << 6);
2690298948Sadrian		a += (a < 32) ? 31 : 32;
2691298948Sadrian		a = a >> 6;
2692298948Sadrian		a = MIN(MAX(a, -31), 31);
2693298948Sadrian
2694298948Sadrian		b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
2695298948Sadrian		b += (pg->pg_nrssi[0] << 6);
2696298948Sadrian		if (b < 32)
2697298948Sadrian			b += 31;
2698298948Sadrian		else
2699298948Sadrian			b += 32;
2700298948Sadrian		b = b >> 6;
2701298948Sadrian		b = MIN(MAX(b, -31), 31);
2702298948Sadrian
2703298948Sadrian		tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
2704298948Sadrian		tmpu16 |= ((uint32_t)b & 0x0000003f);
2705298948Sadrian		tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
2706298948Sadrian		BWN_PHY_WRITE(mac, 0x048a, tmpu16);
2707298948Sadrian		return;
2708298948Sadrian	}
2709298948Sadrian
2710298948Sadrian	tmp16 = bwn_nrssi_read(mac, 0x20);
2711298948Sadrian	if (tmp16 >= 0x20)
2712298948Sadrian		tmp16 -= 0x40;
2713298948Sadrian	BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
2714298948Sadrian}
2715298948Sadrian
2716298948Sadrianstatic void
2717298948Sadrianbwn_nrssi_slope_11g(struct bwn_mac *mac)
2718298948Sadrian{
2719298948Sadrian#define	SAVE_RF_MAX		3
2720298948Sadrian#define	SAVE_PHY_COMM_MAX	4
2721298948Sadrian#define	SAVE_PHY3_MAX		8
2722298948Sadrian	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
2723298948Sadrian		{ 0x7a, 0x52, 0x43 };
2724298948Sadrian	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
2725298948Sadrian		{ 0x15, 0x5a, 0x59, 0x58 };
2726298948Sadrian	static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
2727298948Sadrian		0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
2728298948Sadrian		0x0801, 0x0060, 0x0014, 0x0478
2729298948Sadrian	};
2730298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2731298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
2732298948Sadrian	int32_t i, tmp32, phy3_idx = 0;
2733298948Sadrian	uint16_t delta, tmp;
2734298948Sadrian	uint16_t save_rf[SAVE_RF_MAX];
2735298948Sadrian	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
2736298948Sadrian	uint16_t save_phy3[SAVE_PHY3_MAX];
2737298948Sadrian	uint16_t ant_div, phy0, chan_ex;
2738298948Sadrian	int16_t nrssi0, nrssi1;
2739298948Sadrian
2740298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_G,
2741298948Sadrian	    ("%s:%d: fail", __func__, __LINE__));
2742298948Sadrian
2743298948Sadrian	if (phy->rf_rev >= 9)
2744298948Sadrian		return;
2745298948Sadrian	if (phy->rf_rev == 8)
2746298948Sadrian		bwn_nrssi_offset(mac);
2747298948Sadrian
2748298948Sadrian	BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
2749298948Sadrian	BWN_PHY_MASK(mac, 0x0802, 0xfffc);
2750298948Sadrian
2751298948Sadrian	/*
2752298948Sadrian	 * Save RF/PHY registers for later restoration
2753298948Sadrian	 */
2754298948Sadrian	ant_div = BWN_READ_2(mac, 0x03e2);
2755298948Sadrian	BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
2756298948Sadrian	for (i = 0; i < SAVE_RF_MAX; ++i)
2757298948Sadrian		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
2758298948Sadrian	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
2759298948Sadrian		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
2760298948Sadrian
2761298948Sadrian	phy0 = BWN_READ_2(mac, BWN_PHY0);
2762298948Sadrian	chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
2763298948Sadrian	if (phy->rev >= 3) {
2764298948Sadrian		for (i = 0; i < SAVE_PHY3_MAX; ++i)
2765298948Sadrian			save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
2766298948Sadrian		BWN_PHY_WRITE(mac, 0x002e, 0);
2767298948Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
2768298948Sadrian		switch (phy->rev) {
2769298948Sadrian		case 4:
2770298948Sadrian		case 6:
2771298948Sadrian		case 7:
2772298948Sadrian			BWN_PHY_SET(mac, 0x0478, 0x0100);
2773298948Sadrian			BWN_PHY_SET(mac, 0x0801, 0x0040);
2774298948Sadrian			break;
2775298948Sadrian		case 3:
2776298948Sadrian		case 5:
2777298948Sadrian			BWN_PHY_MASK(mac, 0x0801, 0xffbf);
2778298948Sadrian			break;
2779298948Sadrian		}
2780298948Sadrian		BWN_PHY_SET(mac, 0x0060, 0x0040);
2781298948Sadrian		BWN_PHY_SET(mac, 0x0014, 0x0200);
2782298948Sadrian	}
2783298948Sadrian	/*
2784298948Sadrian	 * Calculate nrssi0
2785298948Sadrian	 */
2786298948Sadrian	BWN_RF_SET(mac, 0x007a, 0x0070);
2787298948Sadrian	bwn_set_all_gains(mac, 0, 8, 0);
2788298948Sadrian	BWN_RF_MASK(mac, 0x007a, 0x00f7);
2789298948Sadrian	if (phy->rev >= 2) {
2790298948Sadrian		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
2791298948Sadrian		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
2792298948Sadrian	}
2793298948Sadrian	BWN_RF_SET(mac, 0x007a, 0x0080);
2794298948Sadrian	DELAY(20);
2795298948Sadrian
2796298948Sadrian	nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
2797298948Sadrian	if (nrssi0 >= 0x0020)
2798298948Sadrian		nrssi0 -= 0x0040;
2799298948Sadrian
2800298948Sadrian	/*
2801298948Sadrian	 * Calculate nrssi1
2802298948Sadrian	 */
2803298948Sadrian	BWN_RF_MASK(mac, 0x007a, 0x007f);
2804298948Sadrian	if (phy->rev >= 2)
2805298948Sadrian		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
2806298948Sadrian
2807298948Sadrian	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
2808298948Sadrian	    BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
2809298948Sadrian	BWN_RF_SET(mac, 0x007a, 0x000f);
2810298948Sadrian	BWN_PHY_WRITE(mac, 0x0015, 0xf330);
2811298948Sadrian	if (phy->rev >= 2) {
2812298948Sadrian		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
2813298948Sadrian		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
2814298948Sadrian	}
2815298948Sadrian
2816298948Sadrian	bwn_set_all_gains(mac, 3, 0, 1);
2817298948Sadrian	if (phy->rf_rev == 8) {
2818298948Sadrian		BWN_RF_WRITE(mac, 0x0043, 0x001f);
2819298948Sadrian	} else {
2820298948Sadrian		tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
2821298948Sadrian		BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
2822298948Sadrian		tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
2823298948Sadrian		BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
2824298948Sadrian	}
2825298948Sadrian	BWN_PHY_WRITE(mac, 0x005a, 0x0480);
2826298948Sadrian	BWN_PHY_WRITE(mac, 0x0059, 0x0810);
2827298948Sadrian	BWN_PHY_WRITE(mac, 0x0058, 0x000d);
2828298948Sadrian	DELAY(20);
2829298948Sadrian	nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
2830298948Sadrian
2831298948Sadrian	/*
2832298948Sadrian	 * Install calculated narrow RSSI values
2833298948Sadrian	 */
2834298948Sadrian	if (nrssi1 >= 0x0020)
2835298948Sadrian		nrssi1 -= 0x0040;
2836298948Sadrian	if (nrssi0 == nrssi1)
2837298948Sadrian		pg->pg_nrssi_slope = 0x00010000;
2838298948Sadrian	else
2839298948Sadrian		pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
2840298948Sadrian	if (nrssi0 >= -4) {
2841298948Sadrian		pg->pg_nrssi[0] = nrssi1;
2842298948Sadrian		pg->pg_nrssi[1] = nrssi0;
2843298948Sadrian	}
2844298948Sadrian
2845298948Sadrian	/*
2846298948Sadrian	 * Restore saved RF/PHY registers
2847298948Sadrian	 */
2848298948Sadrian	if (phy->rev >= 3) {
2849298948Sadrian		for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
2850298948Sadrian			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
2851298948Sadrian			    save_phy3[phy3_idx]);
2852298948Sadrian		}
2853298948Sadrian	}
2854298948Sadrian	if (phy->rev >= 2) {
2855298948Sadrian		BWN_PHY_MASK(mac, 0x0812, 0xffcf);
2856298948Sadrian		BWN_PHY_MASK(mac, 0x0811, 0xffcf);
2857298948Sadrian	}
2858298948Sadrian
2859298948Sadrian	for (i = 0; i < SAVE_RF_MAX; ++i)
2860298948Sadrian		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
2861298948Sadrian
2862298948Sadrian	BWN_WRITE_2(mac, 0x03e2, ant_div);
2863298948Sadrian	BWN_WRITE_2(mac, 0x03e6, phy0);
2864298948Sadrian	BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
2865298948Sadrian
2866298948Sadrian	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
2867298948Sadrian		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
2868298948Sadrian
2869298948Sadrian	bwn_spu_workaround(mac, phy->chan);
2870298948Sadrian	BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
2871298948Sadrian	bwn_set_original_gains(mac);
2872298948Sadrian	BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
2873298948Sadrian	if (phy->rev >= 3) {
2874298948Sadrian		for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
2875298948Sadrian			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
2876298948Sadrian			    save_phy3[phy3_idx]);
2877298948Sadrian		}
2878298948Sadrian	}
2879298948Sadrian
2880298948Sadrian	delta = 0x1f - pg->pg_nrssi[0];
2881298948Sadrian	for (i = 0; i < 64; i++) {
2882298948Sadrian		tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
2883298948Sadrian		tmp32 = MIN(MAX(tmp32, 0), 0x3f);
2884298948Sadrian		pg->pg_nrssi_lt[i] = tmp32;
2885298948Sadrian	}
2886298948Sadrian
2887298948Sadrian	bwn_nrssi_threshold(mac);
2888298948Sadrian#undef SAVE_RF_MAX
2889298948Sadrian#undef SAVE_PHY_COMM_MAX
2890298948Sadrian#undef SAVE_PHY3_MAX
2891298948Sadrian}
2892298948Sadrian
2893298948Sadrianstatic void
2894298948Sadrianbwn_nrssi_offset(struct bwn_mac *mac)
2895298948Sadrian{
2896298948Sadrian#define	SAVE_RF_MAX		2
2897298948Sadrian#define	SAVE_PHY_COMM_MAX	10
2898298948Sadrian#define	SAVE_PHY6_MAX		8
2899298948Sadrian	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
2900298948Sadrian		{ 0x7a, 0x43 };
2901298948Sadrian	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
2902298948Sadrian		0x0001, 0x0811, 0x0812, 0x0814,
2903298948Sadrian		0x0815, 0x005a, 0x0059, 0x0058,
2904298948Sadrian		0x000a, 0x0003
2905298948Sadrian	};
2906298948Sadrian	static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
2907298948Sadrian		0x002e, 0x002f, 0x080f, 0x0810,
2908298948Sadrian		0x0801, 0x0060, 0x0014, 0x0478
2909298948Sadrian	};
2910298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2911298948Sadrian	int i, phy6_idx = 0;
2912298948Sadrian	uint16_t save_rf[SAVE_RF_MAX];
2913298948Sadrian	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
2914298948Sadrian	uint16_t save_phy6[SAVE_PHY6_MAX];
2915298948Sadrian	int16_t nrssi;
2916298948Sadrian	uint16_t saved = 0xffff;
2917298948Sadrian
2918298948Sadrian	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
2919298948Sadrian		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
2920298948Sadrian	for (i = 0; i < SAVE_RF_MAX; ++i)
2921298948Sadrian		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
2922298948Sadrian
2923298948Sadrian	BWN_PHY_MASK(mac, 0x0429, 0x7fff);
2924298948Sadrian	BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
2925298948Sadrian	BWN_PHY_SET(mac, 0x0811, 0x000c);
2926298948Sadrian	BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
2927298948Sadrian	BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
2928298948Sadrian	if (phy->rev >= 6) {
2929298948Sadrian		for (i = 0; i < SAVE_PHY6_MAX; ++i)
2930298948Sadrian			save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
2931298948Sadrian
2932298948Sadrian		BWN_PHY_WRITE(mac, 0x002e, 0);
2933298948Sadrian		BWN_PHY_WRITE(mac, 0x002f, 0);
2934298948Sadrian		BWN_PHY_WRITE(mac, 0x080f, 0);
2935298948Sadrian		BWN_PHY_WRITE(mac, 0x0810, 0);
2936298948Sadrian		BWN_PHY_SET(mac, 0x0478, 0x0100);
2937298948Sadrian		BWN_PHY_SET(mac, 0x0801, 0x0040);
2938298948Sadrian		BWN_PHY_SET(mac, 0x0060, 0x0040);
2939298948Sadrian		BWN_PHY_SET(mac, 0x0014, 0x0200);
2940298948Sadrian	}
2941298948Sadrian	BWN_RF_SET(mac, 0x007a, 0x0070);
2942298948Sadrian	BWN_RF_SET(mac, 0x007a, 0x0080);
2943298948Sadrian	DELAY(30);
2944298948Sadrian
2945298948Sadrian	nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
2946298948Sadrian	if (nrssi >= 0x20)
2947298948Sadrian		nrssi -= 0x40;
2948298948Sadrian	if (nrssi == 31) {
2949298948Sadrian		for (i = 7; i >= 4; i--) {
2950298948Sadrian			BWN_RF_WRITE(mac, 0x007b, i);
2951298948Sadrian			DELAY(20);
2952298948Sadrian			nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
2953298948Sadrian			    0x003f);
2954298948Sadrian			if (nrssi >= 0x20)
2955298948Sadrian				nrssi -= 0x40;
2956298948Sadrian			if (nrssi < 31 && saved == 0xffff)
2957298948Sadrian				saved = i;
2958298948Sadrian		}
2959298948Sadrian		if (saved == 0xffff)
2960298948Sadrian			saved = 4;
2961298948Sadrian	} else {
2962298948Sadrian		BWN_RF_MASK(mac, 0x007a, 0x007f);
2963298948Sadrian		if (phy->rev != 1) {
2964298948Sadrian			BWN_PHY_SET(mac, 0x0814, 0x0001);
2965298948Sadrian			BWN_PHY_MASK(mac, 0x0815, 0xfffe);
2966298948Sadrian		}
2967298948Sadrian		BWN_PHY_SET(mac, 0x0811, 0x000c);
2968298948Sadrian		BWN_PHY_SET(mac, 0x0812, 0x000c);
2969298948Sadrian		BWN_PHY_SET(mac, 0x0811, 0x0030);
2970298948Sadrian		BWN_PHY_SET(mac, 0x0812, 0x0030);
2971298948Sadrian		BWN_PHY_WRITE(mac, 0x005a, 0x0480);
2972298948Sadrian		BWN_PHY_WRITE(mac, 0x0059, 0x0810);
2973298948Sadrian		BWN_PHY_WRITE(mac, 0x0058, 0x000d);
2974298948Sadrian		if (phy->rev == 0)
2975298948Sadrian			BWN_PHY_WRITE(mac, 0x0003, 0x0122);
2976298948Sadrian		else
2977298948Sadrian			BWN_PHY_SET(mac, 0x000a, 0x2000);
2978298948Sadrian		if (phy->rev != 1) {
2979298948Sadrian			BWN_PHY_SET(mac, 0x0814, 0x0004);
2980298948Sadrian			BWN_PHY_MASK(mac, 0x0815, 0xfffb);
2981298948Sadrian		}
2982298948Sadrian		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
2983298948Sadrian		BWN_RF_SET(mac, 0x007a, 0x000f);
2984298948Sadrian		bwn_set_all_gains(mac, 3, 0, 1);
2985298948Sadrian		BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
2986298948Sadrian		DELAY(30);
2987298948Sadrian		nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
2988298948Sadrian		if (nrssi >= 0x20)
2989298948Sadrian			nrssi -= 0x40;
2990298948Sadrian		if (nrssi == -32) {
2991298948Sadrian			for (i = 0; i < 4; i++) {
2992298948Sadrian				BWN_RF_WRITE(mac, 0x007b, i);
2993298948Sadrian				DELAY(20);
2994298948Sadrian				nrssi = (int16_t)((BWN_PHY_READ(mac,
2995298948Sadrian				    0x047f) >> 8) & 0x003f);
2996298948Sadrian				if (nrssi >= 0x20)
2997298948Sadrian					nrssi -= 0x40;
2998298948Sadrian				if (nrssi > -31 && saved == 0xffff)
2999298948Sadrian					saved = i;
3000298948Sadrian			}
3001298948Sadrian			if (saved == 0xffff)
3002298948Sadrian				saved = 3;
3003298948Sadrian		} else
3004298948Sadrian			saved = 0;
3005298948Sadrian	}
3006298948Sadrian	BWN_RF_WRITE(mac, 0x007b, saved);
3007298948Sadrian
3008298948Sadrian	/*
3009298948Sadrian	 * Restore saved RF/PHY registers
3010298948Sadrian	 */
3011298948Sadrian	if (phy->rev >= 6) {
3012298948Sadrian		for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
3013298948Sadrian			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
3014298948Sadrian			    save_phy6[phy6_idx]);
3015298948Sadrian		}
3016298948Sadrian	}
3017298948Sadrian	if (phy->rev != 1) {
3018298948Sadrian		for (i = 3; i < 5; i++)
3019298948Sadrian			BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
3020298948Sadrian			    save_phy_comm[i]);
3021298948Sadrian	}
3022298948Sadrian	for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
3023298948Sadrian		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
3024298948Sadrian
3025298948Sadrian	for (i = SAVE_RF_MAX - 1; i >= 0; --i)
3026298948Sadrian		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
3027298948Sadrian
3028298948Sadrian	BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
3029298948Sadrian	BWN_PHY_SET(mac, 0x0429, 0x8000);
3030298948Sadrian	bwn_set_original_gains(mac);
3031298948Sadrian	if (phy->rev >= 6) {
3032298948Sadrian		for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
3033298948Sadrian			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
3034298948Sadrian			    save_phy6[phy6_idx]);
3035298948Sadrian		}
3036298948Sadrian	}
3037298948Sadrian
3038298948Sadrian	BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
3039298948Sadrian	BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
3040298948Sadrian	BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
3041298948Sadrian}
3042298948Sadrian
3043298948Sadrianstatic void
3044298948Sadrianbwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
3045298948Sadrian    int16_t third)
3046298948Sadrian{
3047298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3048298948Sadrian	uint16_t i;
3049298948Sadrian	uint16_t start = 0x08, end = 0x18;
3050298948Sadrian	uint16_t tmp;
3051298948Sadrian	uint16_t table;
3052298948Sadrian
3053298948Sadrian	if (phy->rev <= 1) {
3054298948Sadrian		start = 0x10;
3055298948Sadrian		end = 0x20;
3056298948Sadrian	}
3057298948Sadrian
3058298948Sadrian	table = BWN_OFDMTAB_GAINX;
3059298948Sadrian	if (phy->rev <= 1)
3060298948Sadrian		table = BWN_OFDMTAB_GAINX_R1;
3061298948Sadrian	for (i = 0; i < 4; i++)
3062298948Sadrian		bwn_ofdmtab_write_2(mac, table, i, first);
3063298948Sadrian
3064298948Sadrian	for (i = start; i < end; i++)
3065298948Sadrian		bwn_ofdmtab_write_2(mac, table, i, second);
3066298948Sadrian
3067298948Sadrian	if (third != -1) {
3068298948Sadrian		tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
3069298948Sadrian		BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
3070298948Sadrian		BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
3071298948Sadrian		BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
3072298948Sadrian	}
3073298948Sadrian	bwn_dummy_transmission(mac, 0, 1);
3074298948Sadrian}
3075298948Sadrian
3076298948Sadrianstatic void
3077298948Sadrianbwn_set_original_gains(struct bwn_mac *mac)
3078298948Sadrian{
3079298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3080298948Sadrian	uint16_t i, tmp;
3081298948Sadrian	uint16_t table;
3082298948Sadrian	uint16_t start = 0x0008, end = 0x0018;
3083298948Sadrian
3084298948Sadrian	if (phy->rev <= 1) {
3085298948Sadrian		start = 0x0010;
3086298948Sadrian		end = 0x0020;
3087298948Sadrian	}
3088298948Sadrian
3089298948Sadrian	table = BWN_OFDMTAB_GAINX;
3090298948Sadrian	if (phy->rev <= 1)
3091298948Sadrian		table = BWN_OFDMTAB_GAINX_R1;
3092298948Sadrian	for (i = 0; i < 4; i++) {
3093298948Sadrian		tmp = (i & 0xfffc);
3094298948Sadrian		tmp |= (i & 0x0001) << 1;
3095298948Sadrian		tmp |= (i & 0x0002) >> 1;
3096298948Sadrian
3097298948Sadrian		bwn_ofdmtab_write_2(mac, table, i, tmp);
3098298948Sadrian	}
3099298948Sadrian
3100298948Sadrian	for (i = start; i < end; i++)
3101298948Sadrian		bwn_ofdmtab_write_2(mac, table, i, i - start);
3102298948Sadrian
3103298948Sadrian	BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
3104298948Sadrian	BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
3105298948Sadrian	BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
3106298948Sadrian	bwn_dummy_transmission(mac, 0, 1);
3107298948Sadrian}
3108298948Sadrian
3109298948Sadrianstatic void
3110298948Sadrianbwn_phy_hwpctl_init(struct bwn_mac *mac)
3111298948Sadrian{
3112298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3113298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
3114298948Sadrian	struct bwn_rfatt old_rfatt, rfatt;
3115298948Sadrian	struct bwn_bbatt old_bbatt, bbatt;
3116298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
3117298948Sadrian	uint8_t old_txctl = 0;
3118298948Sadrian
3119298948Sadrian	KASSERT(phy->type == BWN_PHYTYPE_G,
3120298948Sadrian	    ("%s:%d: fail", __func__, __LINE__));
3121298948Sadrian
3122298948Sadrian	if ((siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM) &&
3123298948Sadrian	    (siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306))
3124298948Sadrian		return;
3125298948Sadrian
3126298948Sadrian	BWN_PHY_WRITE(mac, 0x0028, 0x8018);
3127298948Sadrian
3128298948Sadrian	BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
3129298948Sadrian
3130298948Sadrian	if (!phy->gmode)
3131298948Sadrian		return;
3132298948Sadrian	bwn_hwpctl_early_init(mac);
3133298948Sadrian	if (pg->pg_curtssi == 0) {
3134298948Sadrian		if (phy->rf_ver == 0x2050 && phy->analog == 0) {
3135298948Sadrian			BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
3136298948Sadrian		} else {
3137298948Sadrian			memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
3138298948Sadrian			memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
3139298948Sadrian			old_txctl = pg->pg_txctl;
3140298948Sadrian
3141298948Sadrian			bbatt.att = 11;
3142298948Sadrian			if (phy->rf_rev == 8) {
3143298948Sadrian				rfatt.att = 15;
3144298948Sadrian				rfatt.padmix = 1;
3145298948Sadrian			} else {
3146298948Sadrian				rfatt.att = 9;
3147298948Sadrian				rfatt.padmix = 0;
3148298948Sadrian			}
3149298948Sadrian			bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
3150298948Sadrian		}
3151298948Sadrian		bwn_dummy_transmission(mac, 0, 1);
3152298948Sadrian		pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
3153298948Sadrian		if (phy->rf_ver == 0x2050 && phy->analog == 0)
3154298948Sadrian			BWN_RF_MASK(mac, 0x0076, 0xff7b);
3155298948Sadrian		else
3156298948Sadrian			bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
3157298948Sadrian			    &old_rfatt, old_txctl);
3158298948Sadrian	}
3159298948Sadrian	bwn_hwpctl_init_gphy(mac);
3160298948Sadrian
3161298948Sadrian	/* clear TSSI */
3162298948Sadrian	bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
3163298948Sadrian	bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
3164298948Sadrian	bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
3165298948Sadrian	bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
3166298948Sadrian}
3167298948Sadrian
3168298948Sadrianstatic void
3169298948Sadrianbwn_hwpctl_early_init(struct bwn_mac *mac)
3170298948Sadrian{
3171298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3172298948Sadrian
3173298948Sadrian	if (!bwn_has_hwpctl(mac)) {
3174298948Sadrian		BWN_PHY_WRITE(mac, 0x047a, 0xc111);
3175298948Sadrian		return;
3176298948Sadrian	}
3177298948Sadrian
3178298948Sadrian	BWN_PHY_MASK(mac, 0x0036, 0xfeff);
3179298948Sadrian	BWN_PHY_WRITE(mac, 0x002f, 0x0202);
3180298948Sadrian	BWN_PHY_SET(mac, 0x047c, 0x0002);
3181298948Sadrian	BWN_PHY_SET(mac, 0x047a, 0xf000);
3182298948Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
3183298948Sadrian		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
3184298948Sadrian		BWN_PHY_SET(mac, 0x005d, 0x8000);
3185298948Sadrian		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
3186298948Sadrian		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
3187298948Sadrian		BWN_PHY_SET(mac, 0x0036, 0x0400);
3188298948Sadrian	} else {
3189298948Sadrian		BWN_PHY_SET(mac, 0x0036, 0x0200);
3190298948Sadrian		BWN_PHY_SET(mac, 0x0036, 0x0400);
3191298948Sadrian		BWN_PHY_MASK(mac, 0x005d, 0x7fff);
3192298948Sadrian		BWN_PHY_MASK(mac, 0x004f, 0xfffe);
3193298948Sadrian		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
3194298948Sadrian		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
3195298948Sadrian		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
3196298948Sadrian	}
3197298948Sadrian}
3198298948Sadrian
3199298948Sadrianstatic void
3200298948Sadrianbwn_hwpctl_init_gphy(struct bwn_mac *mac)
3201298948Sadrian{
3202298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3203298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
3204298948Sadrian	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
3205298948Sadrian	int i;
3206298948Sadrian	uint16_t nr_written = 0, tmp, value;
3207298948Sadrian	uint8_t rf, bb;
3208298948Sadrian
3209298948Sadrian	if (!bwn_has_hwpctl(mac)) {
3210298948Sadrian		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
3211298948Sadrian		return;
3212298948Sadrian	}
3213298948Sadrian
3214298948Sadrian	BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
3215298948Sadrian	    (pg->pg_idletssi - pg->pg_curtssi));
3216298948Sadrian	BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
3217298948Sadrian	    (pg->pg_idletssi - pg->pg_curtssi));
3218298948Sadrian
3219298948Sadrian	for (i = 0; i < 32; i++)
3220298948Sadrian		bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
3221298948Sadrian	for (i = 32; i < 64; i++)
3222298948Sadrian		bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
3223298948Sadrian	for (i = 0; i < 64; i += 2) {
3224298948Sadrian		value = (uint16_t) pg->pg_tssi2dbm[i];
3225298948Sadrian		value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
3226298948Sadrian		BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
3227298948Sadrian	}
3228298948Sadrian
3229298948Sadrian	for (rf = 0; rf < lo->rfatt.len; rf++) {
3230298948Sadrian		for (bb = 0; bb < lo->bbatt.len; bb++) {
3231298948Sadrian			if (nr_written >= 0x40)
3232298948Sadrian				return;
3233298948Sadrian			tmp = lo->bbatt.array[bb].att;
3234298948Sadrian			tmp <<= 8;
3235298948Sadrian			if (phy->rf_rev == 8)
3236298948Sadrian				tmp |= 0x50;
3237298948Sadrian			else
3238298948Sadrian				tmp |= 0x40;
3239298948Sadrian			tmp |= lo->rfatt.array[rf].att;
3240298948Sadrian			BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
3241298948Sadrian			nr_written++;
3242298948Sadrian		}
3243298948Sadrian	}
3244298948Sadrian
3245298948Sadrian	BWN_PHY_MASK(mac, 0x0060, 0xffbf);
3246298948Sadrian	BWN_PHY_WRITE(mac, 0x0014, 0x0000);
3247298948Sadrian
3248298948Sadrian	KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
3249298948Sadrian	BWN_PHY_SET(mac, 0x0478, 0x0800);
3250298948Sadrian	BWN_PHY_MASK(mac, 0x0478, 0xfeff);
3251298948Sadrian	BWN_PHY_MASK(mac, 0x0801, 0xffbf);
3252298948Sadrian
3253298948Sadrian	bwn_phy_g_dc_lookup_init(mac, 1);
3254298948Sadrian	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
3255298948Sadrian}
3256298948Sadrian
3257298948Sadrianstatic void
3258298948Sadrianbwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
3259298948Sadrian{
3260298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
3261298948Sadrian
3262298948Sadrian	if (spu != 0)
3263298948Sadrian		bwn_spu_workaround(mac, channel);
3264298948Sadrian
3265298948Sadrian	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
3266298948Sadrian
3267298948Sadrian	if (channel == 14) {
3268298948Sadrian		if (siba_sprom_get_ccode(sc->sc_dev) == SIBA_CCODE_JAPAN)
3269298948Sadrian			bwn_hf_write(mac,
3270298948Sadrian			    bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
3271298948Sadrian		else
3272298948Sadrian			bwn_hf_write(mac,
3273298948Sadrian			    bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
3274298948Sadrian		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
3275298948Sadrian		    BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
3276298948Sadrian		return;
3277298948Sadrian	}
3278298948Sadrian
3279298948Sadrian	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
3280298948Sadrian	    BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
3281298948Sadrian}
3282298948Sadrian
3283298948Sadrianstatic uint16_t
3284298948Sadrianbwn_phy_g_chan2freq(uint8_t channel)
3285298948Sadrian{
3286298948Sadrian	static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
3287298948Sadrian
3288298948Sadrian	KASSERT(channel >= 1 && channel <= 14,
3289298948Sadrian	    ("%s:%d: fail", __func__, __LINE__));
3290298948Sadrian
3291298948Sadrian	return (bwn_phy_g_rf_channels[channel - 1]);
3292298948Sadrian}
3293298948Sadrian
3294298948Sadrianstatic void
3295298948Sadrianbwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
3296298948Sadrian    const struct bwn_rfatt *rfatt, uint8_t txctl)
3297298948Sadrian{
3298298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3299298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
3300298948Sadrian	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
3301298948Sadrian	uint16_t bb, rf;
3302298948Sadrian	uint16_t tx_bias, tx_magn;
3303298948Sadrian
3304298948Sadrian	bb = bbatt->att;
3305298948Sadrian	rf = rfatt->att;
3306298948Sadrian	tx_bias = lo->tx_bias;
3307298948Sadrian	tx_magn = lo->tx_magn;
3308298948Sadrian	if (tx_bias == 0xff)
3309298948Sadrian		tx_bias = 0;
3310298948Sadrian
3311298948Sadrian	pg->pg_txctl = txctl;
3312298948Sadrian	memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
3313298948Sadrian	pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
3314298948Sadrian	memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
3315298948Sadrian	bwn_phy_g_set_bbatt(mac, bb);
3316298948Sadrian	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
3317298948Sadrian	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
3318298948Sadrian		BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
3319298948Sadrian	else {
3320298948Sadrian		BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
3321298948Sadrian		BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
3322298948Sadrian	}
3323298948Sadrian	if (BWN_HAS_TXMAG(phy))
3324298948Sadrian		BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
3325298948Sadrian	else
3326298948Sadrian		BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
3327298948Sadrian	bwn_lo_g_adjust(mac);
3328298948Sadrian}
3329298948Sadrian
3330298948Sadrianstatic void
3331298948Sadrianbwn_phy_g_set_bbatt(struct bwn_mac *mac,
3332298948Sadrian    uint16_t bbatt)
3333298948Sadrian{
3334298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3335298948Sadrian
3336298948Sadrian	if (phy->analog == 0) {
3337298948Sadrian		BWN_WRITE_2(mac, BWN_PHY0,
3338298948Sadrian		    (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
3339298948Sadrian		return;
3340298948Sadrian	}
3341298948Sadrian	if (phy->analog > 1) {
3342298948Sadrian		BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
3343298948Sadrian		return;
3344298948Sadrian	}
3345298948Sadrian	BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
3346298948Sadrian}
3347298948Sadrian
3348298948Sadrianstatic uint16_t
3349298948Sadrianbwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
3350298948Sadrian{
3351298948Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3352298948Sadrian	struct bwn_phy_g *pg = &phy->phy_g;
3353298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
3354298948Sadrian	int max_lb_gain;
3355298948Sadrian	uint16_t extlna;
3356298948Sadrian	uint16_t i;
3357298948Sadrian
3358298948Sadrian	if (phy->gmode == 0)
3359298948Sadrian		return (0);
3360298948Sadrian
3361298948Sadrian	if (BWN_HAS_LOOPBACK(phy)) {
3362298948Sadrian		max_lb_gain = pg->pg_max_lb_gain;
3363298948Sadrian		max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
3364298948Sadrian		if (max_lb_gain >= 0x46) {
3365298948Sadrian			extlna = 0x3000;
3366298948Sadrian			max_lb_gain -= 0x46;
3367298948Sadrian		} else if (max_lb_gain >= 0x3a) {
3368298948Sadrian			extlna = 0x1000;
3369298948Sadrian			max_lb_gain -= 0x3a;
3370298948Sadrian		} else if (max_lb_gain >= 0x2e) {
3371298948Sadrian			extlna = 0x2000;
3372298948Sadrian			max_lb_gain -= 0x2e;
3373298948Sadrian		} else {
3374298948Sadrian			extlna = 0;
3375298948Sadrian			max_lb_gain -= 0x10;
3376298948Sadrian		}
3377298948Sadrian
3378298948Sadrian		for (i = 0; i < 16; i++) {
3379298948Sadrian			max_lb_gain -= (i * 6);
3380298948Sadrian			if (max_lb_gain < 6)
3381298948Sadrian				break;
3382298948Sadrian		}
3383298948Sadrian
3384298948Sadrian		if ((phy->rev < 7) ||
3385298948Sadrian		    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
3386298948Sadrian			if (reg == BWN_PHY_RFOVER) {
3387298948Sadrian				return (0x1b3);
3388298948Sadrian			} else if (reg == BWN_PHY_RFOVERVAL) {
3389298948Sadrian				extlna |= (i << 8);
3390298948Sadrian				switch (lpd) {
3391298948Sadrian				case BWN_LPD(0, 1, 1):
3392298948Sadrian					return (0x0f92);
3393298948Sadrian				case BWN_LPD(0, 0, 1):
3394298948Sadrian				case BWN_LPD(1, 0, 1):
3395298948Sadrian					return (0x0092 | extlna);
3396298948Sadrian				case BWN_LPD(1, 0, 0):
3397298948Sadrian					return (0x0093 | extlna);
3398298948Sadrian				}
3399298948Sadrian				KASSERT(0 == 1,
3400298948Sadrian				    ("%s:%d: fail", __func__, __LINE__));
3401298948Sadrian			}
3402298948Sadrian			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3403298948Sadrian		} else {
3404298948Sadrian			if (reg == BWN_PHY_RFOVER)
3405298948Sadrian				return (0x9b3);
3406298948Sadrian			if (reg == BWN_PHY_RFOVERVAL) {
3407298948Sadrian				if (extlna)
3408298948Sadrian					extlna |= 0x8000;
3409298948Sadrian				extlna |= (i << 8);
3410298948Sadrian				switch (lpd) {
3411298948Sadrian				case BWN_LPD(0, 1, 1):
3412298948Sadrian					return (0x8f92);
3413298948Sadrian				case BWN_LPD(0, 0, 1):
3414298948Sadrian					return (0x8092 | extlna);
3415298948Sadrian				case BWN_LPD(1, 0, 1):
3416298948Sadrian					return (0x2092 | extlna);
3417298948Sadrian				case BWN_LPD(1, 0, 0):
3418298948Sadrian					return (0x2093 | extlna);
3419298948Sadrian				}
3420298948Sadrian				KASSERT(0 == 1,
3421298948Sadrian				    ("%s:%d: fail", __func__, __LINE__));
3422298948Sadrian			}
3423298948Sadrian			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3424298948Sadrian		}
3425298948Sadrian		return (0);
3426298948Sadrian	}
3427298948Sadrian
3428298948Sadrian	if ((phy->rev < 7) ||
3429298948Sadrian	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
3430298948Sadrian		if (reg == BWN_PHY_RFOVER) {
3431298948Sadrian			return (0x1b3);
3432298948Sadrian		} else if (reg == BWN_PHY_RFOVERVAL) {
3433298948Sadrian			switch (lpd) {
3434298948Sadrian			case BWN_LPD(0, 1, 1):
3435298948Sadrian				return (0x0fb2);
3436298948Sadrian			case BWN_LPD(0, 0, 1):
3437298948Sadrian				return (0x00b2);
3438298948Sadrian			case BWN_LPD(1, 0, 1):
3439298948Sadrian				return (0x30b2);
3440298948Sadrian			case BWN_LPD(1, 0, 0):
3441298948Sadrian				return (0x30b3);
3442298948Sadrian			}
3443298948Sadrian			KASSERT(0 == 1,
3444298948Sadrian			    ("%s:%d: fail", __func__, __LINE__));
3445298948Sadrian		}
3446298948Sadrian		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3447298948Sadrian	} else {
3448298948Sadrian		if (reg == BWN_PHY_RFOVER) {
3449298948Sadrian			return (0x9b3);
3450298948Sadrian		} else if (reg == BWN_PHY_RFOVERVAL) {
3451298948Sadrian			switch (lpd) {
3452298948Sadrian			case BWN_LPD(0, 1, 1):
3453298948Sadrian				return (0x8fb2);
3454298948Sadrian			case BWN_LPD(0, 0, 1):
3455298948Sadrian				return (0x80b2);
3456298948Sadrian			case BWN_LPD(1, 0, 1):
3457298948Sadrian				return (0x20b2);
3458298948Sadrian			case BWN_LPD(1, 0, 0):
3459298948Sadrian				return (0x20b3);
3460298948Sadrian			}
3461298948Sadrian			KASSERT(0 == 1,
3462298948Sadrian			    ("%s:%d: fail", __func__, __LINE__));
3463298948Sadrian		}
3464298948Sadrian		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3465298948Sadrian	}
3466298948Sadrian	return (0);
3467298948Sadrian}
3468298948Sadrian
3469298948Sadrianstatic void
3470298948Sadrianbwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
3471298948Sadrian{
3472298948Sadrian
3473298948Sadrian	if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
3474298948Sadrian		return;
3475298948Sadrian	BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
3476298948Sadrian	    bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
3477298948Sadrian	DELAY(1000);
3478298948Sadrian	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
3479298948Sadrian}
3480298948Sadrian
3481298948Sadrianstatic int
3482298948Sadrianbwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
3483298948Sadrian{
3484298948Sadrian	const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
3485298948Sadrian	unsigned int a, b, c, d;
3486298948Sadrian	unsigned int avg;
3487298948Sadrian	uint32_t tmp;
3488298948Sadrian
3489298948Sadrian	tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
3490298948Sadrian	a = tmp & 0xff;
3491298948Sadrian	b = (tmp >> 8) & 0xff;
3492298948Sadrian	c = (tmp >> 16) & 0xff;
3493298948Sadrian	d = (tmp >> 24) & 0xff;
3494298948Sadrian	if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
3495298948Sadrian	    c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
3496298948Sadrian		return (ENOENT);
3497298948Sadrian	bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
3498298948Sadrian	    BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
3499298948Sadrian	    (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
3500298948Sadrian
3501298948Sadrian	if (ofdm) {
3502298948Sadrian		a = (a + 32) & 0x3f;
3503298948Sadrian		b = (b + 32) & 0x3f;
3504298948Sadrian		c = (c + 32) & 0x3f;
3505298948Sadrian		d = (d + 32) & 0x3f;
3506298948Sadrian	}
3507298948Sadrian
3508298948Sadrian	avg = (a + b + c + d + 2) / 4;
3509298948Sadrian	if (ofdm) {
3510298948Sadrian		if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
3511298948Sadrian		    & BWN_HF_4DB_CCK_POWERBOOST)
3512298948Sadrian			avg = (avg >= 13) ? (avg - 13) : 0;
3513298948Sadrian	}
3514298948Sadrian	return (avg);
3515298948Sadrian}
3516298948Sadrian
3517298948Sadrianstatic void
3518298948Sadrianbwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
3519298948Sadrian{
3520298948Sadrian	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
3521298948Sadrian	int rfatt = *rfattp;
3522298948Sadrian	int bbatt = *bbattp;
3523298948Sadrian
3524298948Sadrian	while (1) {
3525298948Sadrian		if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
3526298948Sadrian			break;
3527298948Sadrian		if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
3528298948Sadrian			break;
3529298948Sadrian		if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
3530298948Sadrian			break;
3531298948Sadrian		if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
3532298948Sadrian			break;
3533298948Sadrian		if (bbatt > lo->bbatt.max) {
3534298948Sadrian			bbatt -= 4;
3535298948Sadrian			rfatt += 1;
3536298948Sadrian			continue;
3537298948Sadrian		}
3538298948Sadrian		if (bbatt < lo->bbatt.min) {
3539298948Sadrian			bbatt += 4;
3540298948Sadrian			rfatt -= 1;
3541298948Sadrian			continue;
3542298948Sadrian		}
3543298948Sadrian		if (rfatt > lo->rfatt.max) {
3544298948Sadrian			rfatt -= 1;
3545298948Sadrian			bbatt += 4;
3546298948Sadrian			continue;
3547298948Sadrian		}
3548298948Sadrian		if (rfatt < lo->rfatt.min) {
3549298948Sadrian			rfatt += 1;
3550298948Sadrian			bbatt -= 4;
3551298948Sadrian			continue;
3552298948Sadrian		}
3553298948Sadrian		break;
3554298948Sadrian	}
3555298948Sadrian
3556298948Sadrian	*rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
3557298948Sadrian	*bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
3558298948Sadrian}
3559298948Sadrian
3560298948Sadrianstatic void
3561298948Sadrianbwn_phy_lock(struct bwn_mac *mac)
3562298948Sadrian{
3563298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
3564298948Sadrian	struct ieee80211com *ic = &sc->sc_ic;
3565298948Sadrian
3566298948Sadrian	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
3567298948Sadrian	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
3568298948Sadrian
3569298948Sadrian	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
3570298948Sadrian		bwn_psctl(mac, BWN_PS_AWAKE);
3571298948Sadrian}
3572298948Sadrian
3573298948Sadrianstatic void
3574298948Sadrianbwn_phy_unlock(struct bwn_mac *mac)
3575298948Sadrian{
3576298948Sadrian	struct bwn_softc *sc = mac->mac_sc;
3577298948Sadrian	struct ieee80211com *ic = &sc->sc_ic;
3578298948Sadrian
3579298948Sadrian	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
3580298948Sadrian	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
3581298948Sadrian
3582298948Sadrian	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
3583298948Sadrian		bwn_psctl(mac, 0);
3584298948Sadrian}
3585298948Sadrian
3586298948Sadrianstatic void
3587298948Sadrianbwn_rf_lock(struct bwn_mac *mac)
3588298948Sadrian{
3589298948Sadrian
3590298948Sadrian	BWN_WRITE_4(mac, BWN_MACCTL,
3591298948Sadrian	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
3592298948Sadrian	BWN_READ_4(mac, BWN_MACCTL);
3593298948Sadrian	DELAY(10);
3594298948Sadrian}
3595298948Sadrian
3596298948Sadrianstatic void
3597298948Sadrianbwn_rf_unlock(struct bwn_mac *mac)
3598298948Sadrian{
3599298948Sadrian
3600298948Sadrian	BWN_READ_2(mac, BWN_PHYVER);
3601298948Sadrian	BWN_WRITE_4(mac, BWN_MACCTL,
3602298948Sadrian	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
3603298948Sadrian}
3604