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