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