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