root/sys/dev/bwn/if_bwn_phy_lp.c
/*-
 * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
 *    redistribution must be conditioned upon including a substantially
 *    similar Disclaimer requirement for further binary redistribution.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGES.
 */

#include <sys/cdefs.h>
#include "opt_bwn.h"
#include "opt_wlan.h"

/*
 * The Broadcom Wireless LAN controller driver.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <sys/firmware.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/socket.h>
#include <sys/sockio.h>

#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_llc.h>
#include <net/if_media.h>
#include <net/if_types.h>

#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>

#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_regdomain.h>
#include <net80211/ieee80211_phy.h>
#include <net80211/ieee80211_ratectl.h>

#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/bhnd_ids.h>

#include <dev/bhnd/cores/pmu/bhnd_pmu.h>

#include <dev/bwn/if_bwnreg.h>
#include <dev/bwn/if_bwnvar.h>

#include <dev/bwn/if_bwn_debug.h>
#include <dev/bwn/if_bwn_misc.h>
#include <dev/bwn/if_bwn_util.h>
#include <dev/bwn/if_bwn_phy_common.h>
#include <dev/bwn/if_bwn_phy_lp.h>

#include "bhnd_nvram_map.h"

static int      bwn_phy_lp_readsprom(struct bwn_mac *);
static void     bwn_phy_lp_bbinit(struct bwn_mac *);
static void     bwn_phy_lp_txpctl_init(struct bwn_mac *);
static void     bwn_phy_lp_calib(struct bwn_mac *);
static int      bwn_phy_lp_b2062_switch_channel(struct bwn_mac *, uint8_t);
static int      bwn_phy_lp_b2063_switch_channel(struct bwn_mac *, uint8_t);
static void     bwn_phy_lp_set_anafilter(struct bwn_mac *, uint8_t);
static void     bwn_phy_lp_set_gaintbl(struct bwn_mac *, uint32_t);
static void     bwn_phy_lp_digflt_save(struct bwn_mac *);
static void     bwn_phy_lp_get_txpctlmode(struct bwn_mac *);
static void     bwn_phy_lp_set_txpctlmode(struct bwn_mac *, uint8_t);
static void     bwn_phy_lp_bugfix(struct bwn_mac *);
static void     bwn_phy_lp_digflt_restore(struct bwn_mac *);
static void     bwn_phy_lp_tblinit(struct bwn_mac *);
static void     bwn_phy_lp_bbinit_r2(struct bwn_mac *);
static void     bwn_phy_lp_bbinit_r01(struct bwn_mac *);
static int      bwn_phy_lp_b2062_init(struct bwn_mac *);
static int      bwn_phy_lp_b2063_init(struct bwn_mac *);
static int      bwn_phy_lp_rxcal_r2(struct bwn_mac *);
static int      bwn_phy_lp_rccal_r12(struct bwn_mac *);
static void     bwn_phy_lp_set_rccap(struct bwn_mac *);
static uint32_t bwn_phy_lp_roundup(uint32_t, uint32_t, uint8_t);
static void     bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *);
static void     bwn_phy_lp_b2062_vco_calib(struct bwn_mac *);
static void     bwn_tab_write_multi(struct bwn_mac *, uint32_t, int,
                    const void *);
static void     bwn_tab_read_multi(struct bwn_mac *, uint32_t, int, void *);
static struct bwn_txgain
                bwn_phy_lp_get_txgain(struct bwn_mac *);
static uint8_t  bwn_phy_lp_get_bbmult(struct bwn_mac *);
static void     bwn_phy_lp_set_txgain(struct bwn_mac *, struct bwn_txgain *);
static void     bwn_phy_lp_set_bbmult(struct bwn_mac *, uint8_t);
static void     bwn_phy_lp_set_trsw_over(struct bwn_mac *, uint8_t, uint8_t);
static void     bwn_phy_lp_set_rxgain(struct bwn_mac *, uint32_t);
static void     bwn_phy_lp_set_deaf(struct bwn_mac *, uint8_t);
static int      bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *, uint16_t);
static void     bwn_phy_lp_clear_deaf(struct bwn_mac *, uint8_t);
static void     bwn_phy_lp_tblinit_r01(struct bwn_mac *);
static void     bwn_phy_lp_tblinit_r2(struct bwn_mac *);
static void     bwn_phy_lp_tblinit_txgain(struct bwn_mac *);
static void     bwn_tab_write(struct bwn_mac *, uint32_t, uint32_t);
static void     bwn_phy_lp_b2062_tblinit(struct bwn_mac *);
static void     bwn_phy_lp_b2063_tblinit(struct bwn_mac *);
static int      bwn_phy_lp_loopback(struct bwn_mac *);
static void     bwn_phy_lp_set_rxgain_idx(struct bwn_mac *, uint16_t);
static void     bwn_phy_lp_ddfs_turnon(struct bwn_mac *, int, int, int, int,
                    int);
static uint8_t  bwn_phy_lp_rx_iq_est(struct bwn_mac *, uint16_t, uint8_t,
                    struct bwn_phy_lp_iq_est *);
static void     bwn_phy_lp_ddfs_turnoff(struct bwn_mac *);
static uint32_t bwn_tab_read(struct bwn_mac *, uint32_t);
static void     bwn_phy_lp_set_txgain_dac(struct bwn_mac *, uint16_t);
static void     bwn_phy_lp_set_txgain_pa(struct bwn_mac *, uint16_t);
static void     bwn_phy_lp_set_txgain_override(struct bwn_mac *);
static uint16_t bwn_phy_lp_get_pa_gain(struct bwn_mac *);
static uint8_t  bwn_nbits(int32_t);
static void     bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *, int, int,
                    struct bwn_txgain_entry *);
static void     bwn_phy_lp_gaintbl_write(struct bwn_mac *, int,
                    struct bwn_txgain_entry);
static void     bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
                    struct bwn_txgain_entry);
static void     bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
                    struct bwn_txgain_entry);

static const uint8_t bwn_b2063_chantable_data[33][12] = {
        { 0x6f, 0x3c, 0x3c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
        { 0x6f, 0x2c, 0x2c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
        { 0x6f, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
        { 0x6e, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
        { 0x6e, 0xc, 0xc, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
        { 0x6a, 0xc, 0xc, 0, 0x2, 0x5, 0xd, 0xd, 0x77, 0x80, 0x20, 0 },
        { 0x6a, 0xc, 0xc, 0, 0x1, 0x5, 0xd, 0xc, 0x77, 0x80, 0x20, 0 },
        { 0x6a, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x80, 0x20, 0 },
        { 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x70, 0x20, 0 },
        { 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xb, 0xc, 0x77, 0x70, 0x20, 0 },
        { 0x69, 0xc, 0xc, 0, 0, 0x4, 0xb, 0xb, 0x77, 0x60, 0x20, 0 },
        { 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xb, 0x77, 0x60, 0x20, 0 },
        { 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xa, 0x77, 0x60, 0x20, 0 },
        { 0x68, 0xc, 0xc, 0, 0, 0x2, 0x9, 0x9, 0x77, 0x60, 0x20, 0 },
        { 0x68, 0xc, 0xc, 0, 0, 0x1, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
        { 0x67, 0xc, 0xc, 0, 0, 0, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
        { 0x64, 0xc, 0xc, 0, 0, 0, 0x2, 0x1, 0x77, 0x20, 0, 0 },
        { 0x64, 0xc, 0xc, 0, 0, 0, 0x1, 0x1, 0x77, 0x20, 0, 0 },
        { 0x63, 0xc, 0xc, 0, 0, 0, 0x1, 0, 0x77, 0x10, 0, 0 },
        { 0x63, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
        { 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
        { 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
        { 0x61, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
        { 0x60, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
        { 0x6e, 0xc, 0xc, 0, 0x9, 0xe, 0xf, 0xf, 0x77, 0xc0, 0x50, 0 },
        { 0x6e, 0xc, 0xc, 0, 0x9, 0xd, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
        { 0x6e, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
        { 0x6d, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
        { 0x6d, 0xc, 0xc, 0, 0x8, 0xb, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
        { 0x6d, 0xc, 0xc, 0, 0x8, 0xa, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
        { 0x6c, 0xc, 0xc, 0, 0x7, 0x9, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
        { 0x6c, 0xc, 0xc, 0, 0x6, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
        { 0x6c, 0xc, 0xc, 0, 0x5, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 }
};

static const struct bwn_b206x_chan bwn_b2063_chantable[] = {
        { 1, 2412, bwn_b2063_chantable_data[0] },
        { 2, 2417, bwn_b2063_chantable_data[0] },
        { 3, 2422, bwn_b2063_chantable_data[0] },
        { 4, 2427, bwn_b2063_chantable_data[1] },
        { 5, 2432, bwn_b2063_chantable_data[1] },
        { 6, 2437, bwn_b2063_chantable_data[1] },
        { 7, 2442, bwn_b2063_chantable_data[1] },
        { 8, 2447, bwn_b2063_chantable_data[1] },
        { 9, 2452, bwn_b2063_chantable_data[2] },
        { 10, 2457, bwn_b2063_chantable_data[2] },
        { 11, 2462, bwn_b2063_chantable_data[3] },
        { 12, 2467, bwn_b2063_chantable_data[3] },
        { 13, 2472, bwn_b2063_chantable_data[3] },
        { 14, 2484, bwn_b2063_chantable_data[4] },
        { 34, 5170, bwn_b2063_chantable_data[5] },
        { 36, 5180, bwn_b2063_chantable_data[6] },
        { 38, 5190, bwn_b2063_chantable_data[7] },
        { 40, 5200, bwn_b2063_chantable_data[8] },
        { 42, 5210, bwn_b2063_chantable_data[9] },
        { 44, 5220, bwn_b2063_chantable_data[10] },
        { 46, 5230, bwn_b2063_chantable_data[11] },
        { 48, 5240, bwn_b2063_chantable_data[12] },
        { 52, 5260, bwn_b2063_chantable_data[13] },
        { 56, 5280, bwn_b2063_chantable_data[14] },
        { 60, 5300, bwn_b2063_chantable_data[14] },
        { 64, 5320, bwn_b2063_chantable_data[15] },
        { 100, 5500, bwn_b2063_chantable_data[16] },
        { 104, 5520, bwn_b2063_chantable_data[17] },
        { 108, 5540, bwn_b2063_chantable_data[18] },
        { 112, 5560, bwn_b2063_chantable_data[19] },
        { 116, 5580, bwn_b2063_chantable_data[20] },
        { 120, 5600, bwn_b2063_chantable_data[21] },
        { 124, 5620, bwn_b2063_chantable_data[21] },
        { 128, 5640, bwn_b2063_chantable_data[22] },
        { 132, 5660, bwn_b2063_chantable_data[22] },
        { 136, 5680, bwn_b2063_chantable_data[22] },
        { 140, 5700, bwn_b2063_chantable_data[23] },
        { 149, 5745, bwn_b2063_chantable_data[23] },
        { 153, 5765, bwn_b2063_chantable_data[23] },
        { 157, 5785, bwn_b2063_chantable_data[23] },
        { 161, 5805, bwn_b2063_chantable_data[23] },
        { 165, 5825, bwn_b2063_chantable_data[23] },
        { 184, 4920, bwn_b2063_chantable_data[24] },
        { 188, 4940, bwn_b2063_chantable_data[25] },
        { 192, 4960, bwn_b2063_chantable_data[26] },
        { 196, 4980, bwn_b2063_chantable_data[27] },
        { 200, 5000, bwn_b2063_chantable_data[28] },
        { 204, 5020, bwn_b2063_chantable_data[29] },
        { 208, 5040, bwn_b2063_chantable_data[30] },
        { 212, 5060, bwn_b2063_chantable_data[31] },
        { 216, 5080, bwn_b2063_chantable_data[32] }
};

static const uint8_t bwn_b2062_chantable_data[22][12] = {
        { 0xff, 0xff, 0xb5, 0x1b, 0x24, 0x32, 0x32, 0x88, 0x88, 0, 0, 0 },
        { 0, 0x22, 0x20, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
        { 0, 0x11, 0x10, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
        { 0, 0, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
        { 0, 0x11, 0x20, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
        { 0, 0x11, 0x10, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
        { 0, 0x11, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
        { 0, 0, 0, 0x63, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
        { 0, 0, 0, 0x62, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
        { 0, 0, 0, 0x30, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
        { 0, 0, 0, 0x20, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
        { 0, 0, 0, 0x10, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
        { 0, 0, 0, 0, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
        { 0x55, 0x77, 0x90, 0xf7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
        { 0x44, 0x77, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
        { 0x44, 0x66, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
        { 0x33, 0x66, 0x70, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
        { 0x22, 0x55, 0x60, 0xd7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
        { 0x22, 0x55, 0x60, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
        { 0x22, 0x44, 0x50, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
        { 0x11, 0x44, 0x50, 0xa5, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
        { 0, 0x44, 0x40, 0xb6, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 }
};

static const struct bwn_b206x_chan bwn_b2062_chantable[] = {
        { 1, 2412, bwn_b2062_chantable_data[0] },
        { 2, 2417, bwn_b2062_chantable_data[0] },
        { 3, 2422, bwn_b2062_chantable_data[0] },
        { 4, 2427, bwn_b2062_chantable_data[0] },
        { 5, 2432, bwn_b2062_chantable_data[0] },
        { 6, 2437, bwn_b2062_chantable_data[0] },
        { 7, 2442, bwn_b2062_chantable_data[0] },
        { 8, 2447, bwn_b2062_chantable_data[0] },
        { 9, 2452, bwn_b2062_chantable_data[0] },
        { 10, 2457, bwn_b2062_chantable_data[0] },
        { 11, 2462, bwn_b2062_chantable_data[0] },
        { 12, 2467, bwn_b2062_chantable_data[0] },
        { 13, 2472, bwn_b2062_chantable_data[0] },
        { 14, 2484, bwn_b2062_chantable_data[0] },
        { 34, 5170, bwn_b2062_chantable_data[1] },
        { 38, 5190, bwn_b2062_chantable_data[2] },
        { 42, 5210, bwn_b2062_chantable_data[2] },
        { 46, 5230, bwn_b2062_chantable_data[3] },
        { 36, 5180, bwn_b2062_chantable_data[4] },
        { 40, 5200, bwn_b2062_chantable_data[5] },
        { 44, 5220, bwn_b2062_chantable_data[6] },
        { 48, 5240, bwn_b2062_chantable_data[3] },
        { 52, 5260, bwn_b2062_chantable_data[3] },
        { 56, 5280, bwn_b2062_chantable_data[3] },
        { 60, 5300, bwn_b2062_chantable_data[7] },
        { 64, 5320, bwn_b2062_chantable_data[8] },
        { 100, 5500, bwn_b2062_chantable_data[9] },
        { 104, 5520, bwn_b2062_chantable_data[10] },
        { 108, 5540, bwn_b2062_chantable_data[10] },
        { 112, 5560, bwn_b2062_chantable_data[10] },
        { 116, 5580, bwn_b2062_chantable_data[11] },
        { 120, 5600, bwn_b2062_chantable_data[12] },
        { 124, 5620, bwn_b2062_chantable_data[12] },
        { 128, 5640, bwn_b2062_chantable_data[12] },
        { 132, 5660, bwn_b2062_chantable_data[12] },
        { 136, 5680, bwn_b2062_chantable_data[12] },
        { 140, 5700, bwn_b2062_chantable_data[12] },
        { 149, 5745, bwn_b2062_chantable_data[12] },
        { 153, 5765, bwn_b2062_chantable_data[12] },
        { 157, 5785, bwn_b2062_chantable_data[12] },
        { 161, 5805, bwn_b2062_chantable_data[12] },
        { 165, 5825, bwn_b2062_chantable_data[12] },
        { 184, 4920, bwn_b2062_chantable_data[13] },
        { 188, 4940, bwn_b2062_chantable_data[14] },
        { 192, 4960, bwn_b2062_chantable_data[15] },
        { 196, 4980, bwn_b2062_chantable_data[16] },
        { 200, 5000, bwn_b2062_chantable_data[17] },
        { 204, 5020, bwn_b2062_chantable_data[18] },
        { 208, 5040, bwn_b2062_chantable_data[19] },
        { 212, 5060, bwn_b2062_chantable_data[20] },
        { 216, 5080, bwn_b2062_chantable_data[21] }
};

/* for LP PHY */
static const struct bwn_rxcompco bwn_rxcompco_5354[] = {
        {  1, -66, 15 }, {  2, -66, 15 }, {  3, -66, 15 }, {  4, -66, 15 },
        {  5, -66, 15 }, {  6, -66, 15 }, {  7, -66, 14 }, {  8, -66, 14 },
        {  9, -66, 14 }, { 10, -66, 14 }, { 11, -66, 14 }, { 12, -66, 13 },
        { 13, -66, 13 }, { 14, -66, 13 },
};

/* for LP PHY */
static const struct bwn_rxcompco bwn_rxcompco_r12[] = {
        {   1, -64, 13 }, {   2, -64, 13 }, {   3, -64, 13 }, {   4, -64, 13 },
        {   5, -64, 12 }, {   6, -64, 12 }, {   7, -64, 12 }, {   8, -64, 12 },
        {   9, -64, 12 }, {  10, -64, 11 }, {  11, -64, 11 }, {  12, -64, 11 },
        {  13, -64, 11 }, {  14, -64, 10 }, {  34, -62, 24 }, {  38, -62, 24 },
        {  42, -62, 24 }, {  46, -62, 23 }, {  36, -62, 24 }, {  40, -62, 24 },
        {  44, -62, 23 }, {  48, -62, 23 }, {  52, -62, 23 }, {  56, -62, 22 },
        {  60, -62, 22 }, {  64, -62, 22 }, { 100, -62, 16 }, { 104, -62, 16 },
        { 108, -62, 15 }, { 112, -62, 14 }, { 116, -62, 14 }, { 120, -62, 13 },
        { 124, -62, 12 }, { 128, -62, 12 }, { 132, -62, 12 }, { 136, -62, 11 },
        { 140, -62, 10 }, { 149, -61,  9 }, { 153, -61,  9 }, { 157, -61,  9 },
        { 161, -61,  8 }, { 165, -61,  8 }, { 184, -62, 25 }, { 188, -62, 25 },
        { 192, -62, 25 }, { 196, -62, 25 }, { 200, -62, 25 }, { 204, -62, 25 },
        { 208, -62, 25 }, { 212, -62, 25 }, { 216, -62, 26 },
};

static const struct bwn_rxcompco bwn_rxcompco_r2 = { 0, -64, 0 };

static const uint8_t bwn_tab_sigsq_tbl[] = {
        0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
        0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
        0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
        0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
        0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
        0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
};

static const uint8_t bwn_tab_pllfrac_tbl[] = {
        0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
        0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
};

static const uint16_t bwn_tabl_iqlocal_tbl[] = {
        0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
        0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
        0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
        0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};

void
bwn_phy_lp_init_pre(struct bwn_mac *mac)
{
        struct bwn_phy *phy = &mac->mac_phy;
        struct bwn_phy_lp *plp = &phy->phy_lp;

        plp->plp_antenna = BWN_ANT_DEFAULT;
}

int
bwn_phy_lp_init(struct bwn_mac *mac)
{
        static const struct bwn_stxtable tables[] = {
                { 2,  6, 0x3d, 3, 0x01 }, { 1, 12, 0x4c, 1, 0x01 },
                { 1,  8, 0x50, 0, 0x7f }, { 0,  8, 0x44, 0, 0xff },
                { 1,  0, 0x4a, 0, 0xff }, { 0,  4, 0x4d, 0, 0xff },
                { 1,  4, 0x4e, 0, 0xff }, { 0, 12, 0x4f, 0, 0x0f },
                { 1,  0, 0x4f, 4, 0x0f }, { 3,  0, 0x49, 0, 0x0f },
                { 4,  3, 0x46, 4, 0x07 }, { 3, 15, 0x46, 0, 0x01 },
                { 4,  0, 0x46, 1, 0x07 }, { 3,  8, 0x48, 4, 0x07 },
                { 3, 11, 0x48, 0, 0x0f }, { 3,  4, 0x49, 4, 0x0f },
                { 2, 15, 0x45, 0, 0x01 }, { 5, 13, 0x52, 4, 0x07 },
                { 6,  0, 0x52, 7, 0x01 }, { 5,  3, 0x41, 5, 0x07 },
                { 5,  6, 0x41, 0, 0x0f }, { 5, 10, 0x42, 5, 0x07 },
                { 4, 15, 0x42, 0, 0x01 }, { 5,  0, 0x42, 1, 0x07 },
                { 4, 11, 0x43, 4, 0x0f }, { 4,  7, 0x43, 0, 0x0f },
                { 4,  6, 0x45, 1, 0x01 }, { 2,  7, 0x40, 4, 0x0f },
                { 2, 11, 0x40, 0, 0x0f }
        };
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        const struct bwn_stxtable *st;
        struct ieee80211com *ic = &sc->sc_ic;
        int i, error;
        uint16_t tmp;

        /* All LP-PHY devices have a PMU */
        if (sc->sc_pmu == NULL) {
                device_printf(sc->sc_dev, "no PMU; cannot configure PAREF "
                    "LDO\n");
                return (ENXIO);
        }

        if ((error = bwn_phy_lp_readsprom(mac)))
                return (error);

        bwn_phy_lp_bbinit(mac);

        /* initialize RF */
        BWN_PHY_SET(mac, BWN_PHY_4WIRECTL, 0x2);
        DELAY(1);
        BWN_PHY_MASK(mac, BWN_PHY_4WIRECTL, 0xfffd);
        DELAY(1);

        if (mac->mac_phy.rf_ver == 0x2062) {
                if ((error = bwn_phy_lp_b2062_init(mac)))
                        return (error);
        } else {
                if ((error = bwn_phy_lp_b2063_init(mac)))
                        return (error);

                /* synchronize stx table. */
                for (i = 0; i < N(tables); i++) {
                        st = &tables[i];
                        tmp = BWN_RF_READ(mac, st->st_rfaddr);
                        tmp >>= st->st_rfshift;
                        tmp <<= st->st_physhift;
                        BWN_PHY_SETMASK(mac,
                            BWN_PHY_OFDM(0xf2 + st->st_phyoffset),
                            ~(st->st_mask << st->st_physhift), tmp);
                }

                BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf0), 0x5f80);
                BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf1), 0);
        }

        /* calibrate RC */
        if (mac->mac_phy.rev >= 2) {
                if ((error = bwn_phy_lp_rxcal_r2(mac)))
                        return (error);
        } else if (!plp->plp_rccap) {
                if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                        if ((error = bwn_phy_lp_rccal_r12(mac)))
                                return (error);
                }
        } else
                bwn_phy_lp_set_rccap(mac);

        error = bwn_phy_lp_switch_channel(mac, 7);
        if (error)
                device_printf(sc->sc_dev,
                    "failed to change channel 7 (%d)\n", error);
        bwn_phy_lp_txpctl_init(mac);
        bwn_phy_lp_calib(mac);
        return (0);
}

uint16_t
bwn_phy_lp_read(struct bwn_mac *mac, uint16_t reg)
{

        BWN_WRITE_2(mac, BWN_PHYCTL, reg);
        return (BWN_READ_2(mac, BWN_PHYDATA));
}

void
bwn_phy_lp_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
{

        BWN_WRITE_2(mac, BWN_PHYCTL, reg);
        BWN_WRITE_2(mac, BWN_PHYDATA, value);
}

void
bwn_phy_lp_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
    uint16_t set)
{

        BWN_WRITE_2(mac, BWN_PHYCTL, reg);
        BWN_WRITE_2(mac, BWN_PHYDATA,
            (BWN_READ_2(mac, BWN_PHYDATA) & mask) | set);
}

uint16_t
bwn_phy_lp_rf_read(struct bwn_mac *mac, uint16_t reg)
{

        KASSERT(reg != 1, ("unaccessible register %d", reg));
        if (mac->mac_phy.rev < 2 && reg != 0x4001)
                reg |= 0x100;
        if (mac->mac_phy.rev >= 2)
                reg |= 0x200;
        BWN_WRITE_2(mac, BWN_RFCTL, reg);
        return BWN_READ_2(mac, BWN_RFDATALO);
}

void
bwn_phy_lp_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
{

        KASSERT(reg != 1, ("unaccessible register %d", reg));
        BWN_WRITE_2(mac, BWN_RFCTL, reg);
        BWN_WRITE_2(mac, BWN_RFDATALO, value);
}

void
bwn_phy_lp_rf_onoff(struct bwn_mac *mac, int on)
{

        if (on) {
                BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xe0ff);
                BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2,
                    (mac->mac_phy.rev >= 2) ? 0xf7f7 : 0xffe7);
                return;
        }

        if (mac->mac_phy.rev >= 2) {
                BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x83ff);
                BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
                BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0x80ff);
                BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xdfff);
                BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0808);
                return;
        }

        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xe0ff);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfcff);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0018);
}

int
bwn_phy_lp_switch_channel(struct bwn_mac *mac, uint32_t chan)
{
        struct bwn_phy *phy = &mac->mac_phy;
        struct bwn_phy_lp *plp = &phy->phy_lp;
        int error;

        if (phy->rf_ver == 0x2063) {
                error = bwn_phy_lp_b2063_switch_channel(mac, chan);
                if (error)
                        return (error);
        } else {
                error = bwn_phy_lp_b2062_switch_channel(mac, chan);
                if (error)
                        return (error);
                bwn_phy_lp_set_anafilter(mac, chan);
                bwn_phy_lp_set_gaintbl(mac, ieee80211_ieee2mhz(chan, 0));
        }

        plp->plp_chan = chan;
        BWN_WRITE_2(mac, BWN_CHANNEL, chan);
        return (0);
}

uint32_t
bwn_phy_lp_get_default_chan(struct bwn_mac *mac)
{
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;

        return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36);
}

void
bwn_phy_lp_set_antenna(struct bwn_mac *mac, int antenna)
{
        struct bwn_phy *phy = &mac->mac_phy;
        struct bwn_phy_lp *plp = &phy->phy_lp;

        if (phy->rev >= 2 || antenna > BWN_ANTAUTO1)
                return;

        bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER);
        BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffd, antenna & 0x2);
        BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffe, antenna & 0x1);
        bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_UCODE_ANTDIV_HELPER);
        plp->plp_antenna = antenna;
}

void
bwn_phy_lp_task_60s(struct bwn_mac *mac)
{

        bwn_phy_lp_calib(mac);
}

static int
bwn_phy_lp_readsprom(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;

#define BWN_PHY_LP_READVAR(_dev, _type, _name, _result)         \
do {                                                                    \
        int error;                                                      \
                                                                        \
        error = bhnd_nvram_getvar_ ##_type((_dev), (_name), (_result)); \
        if (error) {                                                    \
                device_printf((_dev), "NVRAM variable %s unreadable: "  \
                    "%d\n", (_name), error);                            \
                return (error);                                         \
        }                                                               \
} while(0)

        if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_TRI2G,
                    &plp->plp_txisoband_m);
                BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_BXA2G,
                    &plp->plp_bxarch);
                BWN_PHY_LP_READVAR(sc->sc_dev, int8, BHND_NVAR_RXPO2G,
                    &plp->plp_rxpwroffset);
                BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_RSSISMF2G,
                    &plp->plp_rssivf);
                BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_RSSISMC2G,
                    &plp->plp_rssivc);
                BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_RSSISAV2G,
                    &plp->plp_rssigs);

                return (0);
        }

        BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_TRI5GL,
            &plp->plp_txisoband_l);
        BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_TRI5G,
            &plp->plp_txisoband_m);
        BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_TRI5GH,
            &plp->plp_txisoband_h);
        BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_BXA5G,
            &plp->plp_bxarch);
        BWN_PHY_LP_READVAR(sc->sc_dev, int8, BHND_NVAR_RXPO5G,
            &plp->plp_rxpwroffset);
        BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_RSSISMF5G,
            &plp->plp_rssivf);
        BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_RSSISMC5G,
            &plp->plp_rssivc);
        BWN_PHY_LP_READVAR(sc->sc_dev, uint8, BHND_NVAR_RSSISAV5G,
            &plp->plp_rssigs);

#undef  BWN_PHY_LP_READVAR

        return (0);
}

static void
bwn_phy_lp_bbinit(struct bwn_mac *mac)
{

        bwn_phy_lp_tblinit(mac);
        if (mac->mac_phy.rev >= 2)
                bwn_phy_lp_bbinit_r2(mac);
        else
                bwn_phy_lp_bbinit_r01(mac);
}

static void
bwn_phy_lp_txpctl_init(struct bwn_mac *mac)
{
        struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 };
        struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 };
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;

        bwn_phy_lp_set_txgain(mac,
            IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz);
        bwn_phy_lp_set_bbmult(mac, 150);
}

static void
bwn_phy_lp_calib(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        const struct bwn_rxcompco *rc = NULL;
        struct bwn_txgain ogain;
        int i, omode, oafeovr, orf, obbmult;
        uint8_t mode, fc = 0;

        if (plp->plp_chanfullcal != plp->plp_chan) {
                plp->plp_chanfullcal = plp->plp_chan;
                fc = 1;
        }

        bwn_mac_suspend(mac);

        /* BlueTooth Coexistance Override */
        BWN_WRITE_2(mac, BWN_BTCOEX_CTL, 0x3);
        BWN_WRITE_2(mac, BWN_BTCOEX_TXCTL, 0xff);

        if (mac->mac_phy.rev >= 2)
                bwn_phy_lp_digflt_save(mac);
        bwn_phy_lp_get_txpctlmode(mac);
        mode = plp->plp_txpctlmode;
        bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
        if (mac->mac_phy.rev == 0 && mode != BWN_PHYLP_TXPCTL_OFF)
                bwn_phy_lp_bugfix(mac);
        if (mac->mac_phy.rev >= 2 && fc == 1) {
                bwn_phy_lp_get_txpctlmode(mac);
                omode = plp->plp_txpctlmode;
                oafeovr = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40;
                if (oafeovr)
                        ogain = bwn_phy_lp_get_txgain(mac);
                orf = BWN_PHY_READ(mac, BWN_PHY_RF_PWR_OVERRIDE) & 0xff;
                obbmult = bwn_phy_lp_get_bbmult(mac);
                bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
                if (oafeovr)
                        bwn_phy_lp_set_txgain(mac, &ogain);
                bwn_phy_lp_set_bbmult(mac, obbmult);
                bwn_phy_lp_set_txpctlmode(mac, omode);
                BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00, orf);
        }
        bwn_phy_lp_set_txpctlmode(mac, mode);
        if (mac->mac_phy.rev >= 2)
                bwn_phy_lp_digflt_restore(mac);

        /* do RX IQ Calculation; assumes that noise is true. */
        if (sc->sc_cid.chip_id == BHND_CHIPID_BCM5354) {
                for (i = 0; i < N(bwn_rxcompco_5354); i++) {
                        if (bwn_rxcompco_5354[i].rc_chan == plp->plp_chan)
                                rc = &bwn_rxcompco_5354[i];
                }
        } else if (mac->mac_phy.rev >= 2)
                rc = &bwn_rxcompco_r2;
        else {
                for (i = 0; i < N(bwn_rxcompco_r12); i++) {
                        if (bwn_rxcompco_r12[i].rc_chan == plp->plp_chan)
                                rc = &bwn_rxcompco_r12[i];
                }
        }
        if (rc == NULL)
                goto fail;

        BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, rc->rc_c1);
        BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, rc->rc_c0 << 8);

        bwn_phy_lp_set_trsw_over(mac, 1 /* TX */, 0 /* RX */);

        if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
                BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7, 0);
        } else {
                BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
                BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf, 0);
        }

        bwn_phy_lp_set_rxgain(mac, 0x2d5d);
        BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
        BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
        bwn_phy_lp_set_deaf(mac, 0);
        /* XXX no checking return value? */
        (void)bwn_phy_lp_calc_rx_iq_comp(mac, 0xfff0);
        bwn_phy_lp_clear_deaf(mac, 0);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffc);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfff7);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffdf);

        /* disable RX GAIN override. */
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffe);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffef);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffbf);
        if (mac->mac_phy.rev >= 2) {
                BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
                if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfbff);
                        BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xe5), 0xfff7);
                }
        } else {
                BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfdff);
        }

        BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
        BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xf7ff);
fail:
        bwn_mac_enable(mac);
}

void
bwn_phy_lp_switch_analog(struct bwn_mac *mac, int on)
{

        if (on) {
                BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfff8);
                return;
        }

        BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVRVAL, 0x0007);
        BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x0007);
}

static int
bwn_phy_lp_b2063_switch_channel(struct bwn_mac *mac, uint8_t chan)
{
        static const struct bwn_b206x_chan *bc = NULL;
        struct bwn_softc *sc = mac->mac_sc;
        uint32_t count, freqref, freqvco, val[3], timeout, timeoutref,
            tmp[6];
        uint16_t old, scale, tmp16;
        u_int freqxtal;
        int error, i, div;

        for (i = 0; i < N(bwn_b2063_chantable); i++) {
                if (bwn_b2063_chantable[i].bc_chan == chan) {
                        bc = &bwn_b2063_chantable[i];
                        break;
                }
        }
        if (bc == NULL)
                return (EINVAL);

        error = bhnd_get_clock_freq(sc->sc_dev, BHND_CLOCK_ALP, &freqxtal);
        if (error) {
                device_printf(sc->sc_dev, "failed to fetch clock frequency: %d",
                    error);
                return (error);
        }

        BWN_RF_WRITE(mac, BWN_B2063_LOGEN_VCOBUF1, bc->bc_data[0]);
        BWN_RF_WRITE(mac, BWN_B2063_LOGEN_MIXER2, bc->bc_data[1]);
        BWN_RF_WRITE(mac, BWN_B2063_LOGEN_BUF2, bc->bc_data[2]);
        BWN_RF_WRITE(mac, BWN_B2063_LOGEN_RCCR1, bc->bc_data[3]);
        BWN_RF_WRITE(mac, BWN_B2063_A_RX_1ST3, bc->bc_data[4]);
        BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND1, bc->bc_data[5]);
        BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND4, bc->bc_data[6]);
        BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND7, bc->bc_data[7]);
        BWN_RF_WRITE(mac, BWN_B2063_A_RX_PS6, bc->bc_data[8]);
        BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL2, bc->bc_data[9]);
        BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL5, bc->bc_data[10]);
        BWN_RF_WRITE(mac, BWN_B2063_PA_CTL11, bc->bc_data[11]);

        old = BWN_RF_READ(mac, BWN_B2063_COM15);
        BWN_RF_SET(mac, BWN_B2063_COM15, 0x1e);

        freqvco = bc->bc_freq << ((bc->bc_freq > 4000) ? 1 : 2);
        freqref = freqxtal * 3;
        div = (freqxtal <= 26000000 ? 1 : 2);
        timeout = ((((8 * freqxtal) / (div * 5000000)) + 1) >> 1) - 1;
        timeoutref = ((((8 * freqxtal) / (div * (timeout + 1))) +
                999999) / 1000000) + 1;

        BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB3, 0x2);
        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB6,
            0xfff8, timeout >> 2);
        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
            0xff9f,timeout << 5);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB5, timeoutref);

        val[0] = bwn_phy_lp_roundup(freqxtal, 1000000, 16);
        val[1] = bwn_phy_lp_roundup(freqxtal, 1000000 * div, 16);
        val[2] = bwn_phy_lp_roundup(freqvco, 3, 16);

        count = (bwn_phy_lp_roundup(val[2], val[1] + 16, 16) * (timeout + 1) *
            (timeoutref + 1)) - 1;
        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
            0xf0, count >> 8);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB8, count & 0xff);

        tmp[0] = ((val[2] * 62500) / freqref) << 4;
        tmp[1] = ((val[2] * 62500) % freqref) << 4;
        while (tmp[1] >= freqref) {
                tmp[0]++;
                tmp[1] -= freqref;
        }
        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG1, 0xffe0, tmp[0] >> 4);
        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfe0f, tmp[0] << 4);
        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfff0, tmp[0] >> 16);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG3, (tmp[1] >> 8) & 0xff);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG4, tmp[1] & 0xff);

        BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF1, 0xb9);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF2, 0x88);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF3, 0x28);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF4, 0x63);

        tmp[2] = ((41 * (val[2] - 3000)) /1200) + 27;
        tmp[3] = bwn_phy_lp_roundup(132000 * tmp[0], 8451, 16);

        if (howmany(tmp[3], tmp[2]) > 60) {
                scale = 1;
                tmp[4] = ((tmp[3] + tmp[2]) / (tmp[2] << 1)) - 8;
        } else {
                scale = 0;
                tmp[4] = ((tmp[3] + (tmp[2] >> 1)) / tmp[2]) - 8;
        }
        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffc0, tmp[4]);
        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffbf, scale << 6);

        tmp[5] = bwn_phy_lp_roundup(100 * val[0], val[2], 16) * (tmp[4] * 8) *
            (scale + 1);
        if (tmp[5] > 150)
                tmp[5] = 0;

        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffe0, tmp[5]);
        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffdf, scale << 5);

        BWN_RF_SETMASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfffb, 0x4);
        if (freqxtal > 26000000)
                BWN_RF_SET(mac, BWN_B2063_JTAG_XTAL_12, 0x2);
        else
                BWN_RF_MASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfd);

        if (val[0] == 45)
                BWN_RF_SET(mac, BWN_B2063_JTAG_VCO1, 0x2);
        else
                BWN_RF_MASK(mac, BWN_B2063_JTAG_VCO1, 0xfd);

        BWN_RF_SET(mac, BWN_B2063_PLL_SP2, 0x3);
        DELAY(1);
        BWN_RF_MASK(mac, BWN_B2063_PLL_SP2, 0xfffc);

        /* VCO Calibration */
        BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, ~0x40);
        tmp16 = BWN_RF_READ(mac, BWN_B2063_JTAG_CALNRST) & 0xf8;
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16);
        DELAY(1);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x4);
        DELAY(1);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x6);
        DELAY(1);
        BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x7);
        DELAY(300);
        BWN_RF_SET(mac, BWN_B2063_PLL_SP1, 0x40);

        BWN_RF_WRITE(mac, BWN_B2063_COM15, old);
        return (0);
}

static int
bwn_phy_lp_b2062_switch_channel(struct bwn_mac *mac, uint8_t chan)
{
        struct bwn_softc *sc = mac->mac_sc;
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        const struct bwn_b206x_chan *bc = NULL;
        uint32_t tmp[9];
        u_int freqxtal;
        int error, i;

        for (i = 0; i < N(bwn_b2062_chantable); i++) {
                if (bwn_b2062_chantable[i].bc_chan == chan) {
                        bc = &bwn_b2062_chantable[i];
                        break;
                }
        }

        if (bc == NULL)
                return (EINVAL);

        error = bhnd_get_clock_freq(sc->sc_dev, BHND_CLOCK_ALP, &freqxtal);
        if (error) {
                device_printf(sc->sc_dev, "failed to fetch clock frequency: %d",
                    error);
                return (error);
        }

        BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL14, 0x04);
        BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE0, bc->bc_data[0]);
        BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE2, bc->bc_data[1]);
        BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE3, bc->bc_data[2]);
        BWN_RF_WRITE(mac, BWN_B2062_N_TX_TUNE, bc->bc_data[3]);
        BWN_RF_WRITE(mac, BWN_B2062_S_LGENG_CTL1, bc->bc_data[4]);
        BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL5, bc->bc_data[5]);
        BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL6, bc->bc_data[6]);
        BWN_RF_WRITE(mac, BWN_B2062_N_TX_PGA, bc->bc_data[7]);
        BWN_RF_WRITE(mac, BWN_B2062_N_TX_PAD, bc->bc_data[8]);

        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xcc);
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0x07);
        bwn_phy_lp_b2062_reset_pllbias(mac);
        tmp[0] = freqxtal / 1000;
        tmp[1] = plp->plp_div * 1000;
        tmp[2] = tmp[1] * ieee80211_ieee2mhz(chan, 0);
        if (ieee80211_ieee2mhz(chan, 0) < 4000)
                tmp[2] *= 2;
        tmp[3] = 48 * tmp[0];
        tmp[5] = tmp[2] / tmp[3];
        tmp[6] = tmp[2] % tmp[3];
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL26, tmp[5]);
        tmp[4] = tmp[6] * 0x100;
        tmp[5] = tmp[4] / tmp[3];
        tmp[6] = tmp[4] % tmp[3];
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL27, tmp[5]);
        tmp[4] = tmp[6] * 0x100;
        tmp[5] = tmp[4] / tmp[3];
        tmp[6] = tmp[4] % tmp[3];
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL28, tmp[5]);
        tmp[4] = tmp[6] * 0x100;
        tmp[5] = tmp[4] / tmp[3];
        tmp[6] = tmp[4] % tmp[3];
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL29,
            tmp[5] + ((2 * tmp[6]) / tmp[3]));
        tmp[7] = BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL19);
        tmp[8] = ((2 * tmp[2] * (tmp[7] + 1)) + (3 * tmp[0])) / (6 * tmp[0]);
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL23, (tmp[8] >> 8) + 16);
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL24, tmp[8] & 0xff);

        bwn_phy_lp_b2062_vco_calib(mac);
        if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
                BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xfc);
                BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0);
                bwn_phy_lp_b2062_reset_pllbias(mac);
                bwn_phy_lp_b2062_vco_calib(mac);
                if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
                        BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
                        return (EIO);
                }
        }
        BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
        return (0);
}

static void
bwn_phy_lp_set_anafilter(struct bwn_mac *mac, uint8_t channel)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        uint16_t tmp = (channel == 14);

        if (mac->mac_phy.rev < 2) {
                BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xfcff, tmp << 9);
                if ((mac->mac_phy.rev == 1) && (plp->plp_rccap))
                        bwn_phy_lp_set_rccap(mac);
                return;
        }

        BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, 0x3f);
}

static void
bwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        uint16_t iso, tmp[3];

        KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));

        if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
                iso = plp->plp_txisoband_m;
        else if (freq <= 5320)
                iso = plp->plp_txisoband_l;
        else if (freq <= 5700)
                iso = plp->plp_txisoband_m;
        else
                iso = plp->plp_txisoband_h;

        tmp[0] = ((iso - 26) / 12) << 12;
        tmp[1] = tmp[0] + 0x1000;
        tmp[2] = tmp[0] + 0x2000;

        bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), 3, tmp);
        bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), 3, tmp);
}

static void
bwn_phy_lp_digflt_save(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        int i;
        static const uint16_t addr[] = {
                BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
                BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
                BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
                BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
                BWN_PHY_OFDM(0xcf),
        };
        static const uint16_t val[] = {
                0xde5e, 0xe832, 0xe331, 0x4d26,
                0x0026, 0x1420, 0x0020, 0xfe08,
                0x0008,
        };

        for (i = 0; i < N(addr); i++) {
                plp->plp_digfilt[i] = BWN_PHY_READ(mac, addr[i]);
                BWN_PHY_WRITE(mac, addr[i], val[i]);
        }
}

static void
bwn_phy_lp_get_txpctlmode(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        uint16_t ctl;

        ctl = BWN_PHY_READ(mac, BWN_PHY_TX_PWR_CTL_CMD);
        switch (ctl & BWN_PHY_TX_PWR_CTL_CMD_MODE) {
        case BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF:
                plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_OFF;
                break;
        case BWN_PHY_TX_PWR_CTL_CMD_MODE_SW:
                plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_SW;
                break;
        case BWN_PHY_TX_PWR_CTL_CMD_MODE_HW:
                plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_HW;
                break;
        default:
                plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_UNKNOWN;
                device_printf(sc->sc_dev, "unknown command mode\n");
                break;
        }
}

static void
bwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        uint16_t ctl;
        uint8_t old;

        bwn_phy_lp_get_txpctlmode(mac);
        old = plp->plp_txpctlmode;
        if (old == mode)
                return;
        plp->plp_txpctlmode = mode;

        if (old != BWN_PHYLP_TXPCTL_ON_HW && mode == BWN_PHYLP_TXPCTL_ON_HW) {
                BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD, 0xff80,
                    plp->plp_tssiidx);
                BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_NNUM,
                    0x8fff, ((uint16_t)plp->plp_tssinpt << 16));

                /* disable TX GAIN override */
                if (mac->mac_phy.rev < 2)
                        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
                else {
                        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xff7f);
                        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xbfff);
                }
                BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xffbf);

                plp->plp_txpwridx = -1;
        }
        if (mac->mac_phy.rev >= 2) {
                if (mode == BWN_PHYLP_TXPCTL_ON_HW)
                        BWN_PHY_SET(mac, BWN_PHY_OFDM(0xd0), 0x2);
                else
                        BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xd0), 0xfffd);
        }

        /* writes TX Power Control mode */
        switch (plp->plp_txpctlmode) {
        case BWN_PHYLP_TXPCTL_OFF:
                ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF;
                break;
        case BWN_PHYLP_TXPCTL_ON_HW:
                ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_HW;
                break;
        case BWN_PHYLP_TXPCTL_ON_SW:
                ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
                break;
        default:
                ctl = 0;
                KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
        }
        BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
            (uint16_t)~BWN_PHY_TX_PWR_CTL_CMD_MODE, ctl);
}

static void
bwn_phy_lp_bugfix(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        const unsigned int size = 256;
        struct bwn_txgain tg;
        uint32_t rxcomp, txgain, coeff, rfpwr, *tabs;
        uint16_t tssinpt, tssiidx, value[2];
        uint8_t mode;
        int8_t txpwridx;

        tabs = (uint32_t *)malloc(sizeof(uint32_t) * size, M_DEVBUF,
            M_NOWAIT | M_ZERO);
        if (tabs == NULL) {
                device_printf(sc->sc_dev, "failed to allocate buffer.\n");
                return;
        }

        bwn_phy_lp_get_txpctlmode(mac);
        mode = plp->plp_txpctlmode;
        txpwridx = plp->plp_txpwridx;
        tssinpt = plp->plp_tssinpt;
        tssiidx = plp->plp_tssiidx;

        bwn_tab_read_multi(mac,
            (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
            BWN_TAB_4(7, 0x140), size, tabs);

        bwn_phy_lp_tblinit(mac);
        bwn_phy_lp_bbinit(mac);
        bwn_phy_lp_txpctl_init(mac);
        bwn_phy_lp_rf_onoff(mac, 1);
        bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);

        bwn_tab_write_multi(mac,
            (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
            BWN_TAB_4(7, 0x140), size, tabs);

        BWN_WRITE_2(mac, BWN_CHANNEL, plp->plp_chan);
        plp->plp_tssinpt = tssinpt;
        plp->plp_tssiidx = tssiidx;
        bwn_phy_lp_set_anafilter(mac, plp->plp_chan);
        if (txpwridx != -1) {
                /* set TX power by index */
                plp->plp_txpwridx = txpwridx;
                bwn_phy_lp_get_txpctlmode(mac);
                if (plp->plp_txpctlmode != BWN_PHYLP_TXPCTL_OFF)
                        bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_ON_SW);
                if (mac->mac_phy.rev >= 2) {
                        rxcomp = bwn_tab_read(mac,
                            BWN_TAB_4(7, txpwridx + 320));
                        txgain = bwn_tab_read(mac,
                            BWN_TAB_4(7, txpwridx + 192));
                        tg.tg_pad = (txgain >> 16) & 0xff;
                        tg.tg_gm = txgain & 0xff;
                        tg.tg_pga = (txgain >> 8) & 0xff;
                        tg.tg_dac = (rxcomp >> 28) & 0xff;
                        bwn_phy_lp_set_txgain(mac, &tg);
                } else {
                        rxcomp = bwn_tab_read(mac,
                            BWN_TAB_4(10, txpwridx + 320));
                        txgain = bwn_tab_read(mac,
                            BWN_TAB_4(10, txpwridx + 192));
                        BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
                            0xf800, (txgain >> 4) & 0x7fff);
                        bwn_phy_lp_set_txgain_dac(mac, txgain & 0x7);
                        bwn_phy_lp_set_txgain_pa(mac, (txgain >> 24) & 0x7f);
                }
                bwn_phy_lp_set_bbmult(mac, (rxcomp >> 20) & 0xff);

                /* set TX IQCC */
                value[0] = (rxcomp >> 10) & 0x3ff;
                value[1] = rxcomp & 0x3ff;
                bwn_tab_write_multi(mac, BWN_TAB_2(0, 80), 2, value);

                coeff = bwn_tab_read(mac,
                    (mac->mac_phy.rev >= 2) ? BWN_TAB_4(7, txpwridx + 448) :
                    BWN_TAB_4(10, txpwridx + 448));
                bwn_tab_write(mac, BWN_TAB_2(0, 85), coeff & 0xffff);
                if (mac->mac_phy.rev >= 2) {
                        rfpwr = bwn_tab_read(mac,
                            BWN_TAB_4(7, txpwridx + 576));
                        BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00,
                            rfpwr & 0xffff);
                }
                bwn_phy_lp_set_txgain_override(mac);
        }
        if (plp->plp_rccap)
                bwn_phy_lp_set_rccap(mac);
        bwn_phy_lp_set_antenna(mac, plp->plp_antenna);
        bwn_phy_lp_set_txpctlmode(mac, mode);
        free(tabs, M_DEVBUF);
}

static void
bwn_phy_lp_digflt_restore(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        int i;
        static const uint16_t addr[] = {
                BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
                BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
                BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
                BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
                BWN_PHY_OFDM(0xcf),
        };

        for (i = 0; i < N(addr); i++)
                BWN_PHY_WRITE(mac, addr[i], plp->plp_digfilt[i]);
}

static void
bwn_phy_lp_tblinit(struct bwn_mac *mac)
{
        uint32_t freq = ieee80211_ieee2mhz(bwn_phy_lp_get_default_chan(mac), 0);

        if (mac->mac_phy.rev < 2) {
                bwn_phy_lp_tblinit_r01(mac);
                bwn_phy_lp_tblinit_txgain(mac);
                bwn_phy_lp_set_gaintbl(mac, freq);
                return;
        }

        bwn_phy_lp_tblinit_r2(mac);
        bwn_phy_lp_tblinit_txgain(mac);
}

struct bwn_wpair {
        uint16_t                reg;
        uint16_t                value;
};

struct bwn_smpair {
        uint16_t                offset;
        uint16_t                mask;
        uint16_t                set;
};

static void
bwn_phy_lp_bbinit_r2(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        static const struct bwn_wpair v1[] = {
                { BWN_PHY_AFE_DAC_CTL, 0x50 },
                { BWN_PHY_AFE_CTL, 0x8800 },
                { BWN_PHY_AFE_CTL_OVR, 0 },
                { BWN_PHY_AFE_CTL_OVRVAL, 0 },
                { BWN_PHY_RF_OVERRIDE_0, 0 },
                { BWN_PHY_RF_OVERRIDE_2, 0 },
                { BWN_PHY_OFDM(0xf9), 0 },
                { BWN_PHY_TR_LOOKUP_1, 0 }
        };
        static const struct bwn_smpair v2[] = {
                { BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0xb4 },
                { BWN_PHY_DCOFFSETTRANSIENT, 0xf8ff, 0x200 },
                { BWN_PHY_DCOFFSETTRANSIENT, 0xff00, 0x7f },
                { BWN_PHY_GAINDIRECTMISMATCH, 0xff0f, 0x40 },
                { BWN_PHY_PREAMBLECONFIRMTO, 0xff00, 0x2 }
        };
        static const struct bwn_smpair v3[] = {
                { BWN_PHY_OFDM(0xfe), 0xffe0, 0x1f },
                { BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
                { BWN_PHY_OFDM(0x100), 0xff00, 0x19 },
                { BWN_PHY_OFDM(0xff), 0x03ff, 0x3c00 },
                { BWN_PHY_OFDM(0xfe), 0xfc1f, 0x3e0 },
                { BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
                { BWN_PHY_OFDM(0x100), 0x00ff, 0x1900 },
                { BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800 },
                { BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x12 },
                { BWN_PHY_GAINMISMATCH, 0x0fff, 0x9000 },

        };
        int i;

        for (i = 0; i < N(v1); i++)
                BWN_PHY_WRITE(mac, v1[i].reg, v1[i].value);
        BWN_PHY_SET(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x10);
        for (i = 0; i < N(v2); i++)
                BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask, v2[i].set);

        BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x4000);
        BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x2000);
        BWN_PHY_SET(mac, BWN_PHY_OFDM(0x10a), 0x1);
        if (sc->sc_board_info.board_rev >= 0x18) {
                bwn_tab_write(mac, BWN_TAB_4(17, 65), 0xec);
                BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x14);
        } else {
                BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x10);
        }
        BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0xff00, 0xf4);
        BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0x00ff, 0xf100);
        BWN_PHY_WRITE(mac, BWN_PHY_CLIPTHRESH, 0x48);
        BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0xff00, 0x46);
        BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe4), 0xff00, 0x10);
        BWN_PHY_SETMASK(mac, BWN_PHY_PWR_THRESH1, 0xfff0, 0x9);
        BWN_PHY_MASK(mac, BWN_PHY_GAINDIRECTMISMATCH, ~0xf);
        BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5500);
        BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0xa0);
        BWN_PHY_SETMASK(mac, BWN_PHY_GAINDIRECTMISMATCH, 0xe0ff, 0x300);
        BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2a00);
        if (sc->sc_cid.chip_id == BHND_CHIPID_BCM4325 &&
            sc->sc_cid.chip_pkg == 0) {
                BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
                BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xa);
        } else {
                BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x1e00);
                BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xd);
        }
        for (i = 0; i < N(v3); i++)
                BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask, v3[i].set);
        if (sc->sc_cid.chip_id == BHND_CHIPID_BCM4325 &&
            sc->sc_cid.chip_pkg == 0) {
                bwn_tab_write(mac, BWN_TAB_2(0x08, 0x14), 0);
                bwn_tab_write(mac, BWN_TAB_2(0x08, 0x12), 0x40);
        }

        if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x40);
                BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0xb00);
                BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x6);
                BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0x9d00);
                BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0xff00, 0xa1);
                BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
        } else
                BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x40);

        BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0xff00, 0xb3);
        BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00);
        BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB, 0xff00, plp->plp_rxpwroffset);
        BWN_PHY_SET(mac, BWN_PHY_RESET_CTL, 0x44);
        BWN_PHY_WRITE(mac, BWN_PHY_RESET_CTL, 0x80);
        BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, 0xa954);
        BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_1,
            0x2000 | ((uint16_t)plp->plp_rssigs << 10) |
            ((uint16_t)plp->plp_rssivc << 4) | plp->plp_rssivf);

        if (sc->sc_cid.chip_id == BHND_CHIPID_BCM4325 &&
            sc->sc_cid.chip_pkg == 0) {
                BWN_PHY_SET(mac, BWN_PHY_AFE_ADC_CTL_0, 0x1c);
                BWN_PHY_SETMASK(mac, BWN_PHY_AFE_CTL, 0x00ff, 0x8800);
                BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_1, 0xfc3c, 0x0400);
        }

        bwn_phy_lp_digflt_save(mac);
}

static void
bwn_phy_lp_bbinit_r01(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        static const struct bwn_smpair v1[] = {
                { BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 },
                { BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 },
                { BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x3c00 },
                { BWN_PHY_GAINDIRECTMISMATCH, 0xfff0, 0x0005 },
                { BWN_PHY_GAIN_MISMATCH_LIMIT, 0xffc0, 0x001a },
                { BWN_PHY_CRS_ED_THRESH, 0xff00, 0x00b3 },
                { BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00 }
        };
        static const struct bwn_smpair v2[] = {
                { BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_1, 0x3f00, 0x0900 },
                { BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
                { BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0400 },
                { BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0b00 },
                { BWN_PHY_TR_LOOKUP_5, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_5, 0xc0ff, 0x0900 },
                { BWN_PHY_TR_LOOKUP_6, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_6, 0xc0ff, 0x0b00 },
                { BWN_PHY_TR_LOOKUP_7, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_7, 0xc0ff, 0x0900 },
                { BWN_PHY_TR_LOOKUP_8, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_8, 0xc0ff, 0x0b00 }
        };
        static const struct bwn_smpair v3[] = {
                { BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0001 },
                { BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0400 },
                { BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0001 },
                { BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0500 },
                { BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
                { BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0800 },
                { BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
                { BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0a00 }
        };
        static const struct bwn_smpair v4[] = {
                { BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0004 },
                { BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0800 },
                { BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0004 },
                { BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0c00 },
                { BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
                { BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0100 },
                { BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
                { BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0300 }
        };
        static const struct bwn_smpair v5[] = {
                { BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0900 },
                { BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
                { BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
                { BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0006 },
                { BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0500 },
                { BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0006 },
                { BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0700 }
        };
        int error, i;
        uint16_t tmp, tmp2;

        BWN_PHY_MASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf7ff);
        BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL, 0);
        BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, 0);
        BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, 0);
        BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0);
        BWN_PHY_SET(mac, BWN_PHY_AFE_DAC_CTL, 0x0004);
        BWN_PHY_SETMASK(mac, BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0x0078);
        BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800);
        BWN_PHY_WRITE(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x0016);
        BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_0, 0xfff8, 0x0004);
        BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5400);
        BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2400);
        BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
        BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0x0006);
        BWN_PHY_MASK(mac, BWN_PHY_RX_RADIO_CTL, 0xfffe);
        for (i = 0; i < N(v1); i++)
                BWN_PHY_SETMASK(mac, v1[i].offset, v1[i].mask, v1[i].set);
        BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB,
            0xff00, plp->plp_rxpwroffset);
        if ((sc->sc_board_info.board_flags & BHND_BFL_FEM) &&
            ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
           (sc->sc_board_info.board_flags & BHND_BFL_PAREF))) {
                error = bhnd_pmu_set_voltage_raw(sc->sc_pmu,
                    BHND_REGULATOR_PAREF_LDO, 0x28);
                if (error)
                        device_printf(sc->sc_dev, "failed to set PAREF LDO "
                            "voltage: %d\n", error);

                error = bhnd_pmu_enable_regulator(sc->sc_pmu,
                    BHND_REGULATOR_PAREF_LDO);
                if (error)
                        device_printf(sc->sc_dev, "failed to enable PAREF LDO "
                            "regulator: %d\n", error);

                if (mac->mac_phy.rev == 0)
                        BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT,
                            0xffcf, 0x0010);
                bwn_tab_write(mac, BWN_TAB_2(11, 7), 60);
        } else {
                error = bhnd_pmu_disable_regulator(sc->sc_pmu,
                    BHND_REGULATOR_PAREF_LDO);
                if (error)
                        device_printf(sc->sc_dev, "failed to disable PAREF LDO "
                            "regulator: %d\n", error);

                BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT, 0xffcf, 0x0020);
                bwn_tab_write(mac, BWN_TAB_2(11, 7), 100);
        }
        tmp = plp->plp_rssivf | plp->plp_rssivc << 4 | 0xa000;
        BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, tmp);
        if (sc->sc_board_info.board_flags & BHND_BFL_RSSIINV)
                BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x0aaa);
        else
                BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x02aa);
        bwn_tab_write(mac, BWN_TAB_2(11, 1), 24);
        BWN_PHY_SETMASK(mac, BWN_PHY_RX_RADIO_CTL,
            0xfff9, (plp->plp_bxarch << 1));
        if (mac->mac_phy.rev == 1 &&
            (sc->sc_board_info.board_flags & BHND_BFL_FEM_BT)) {
                for (i = 0; i < N(v2); i++)
                        BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask,
                            v2[i].set);
        } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ||
            (sc->sc_board_info.board_type == 0x048a) ||
            ((mac->mac_phy.rev == 0) &&
             (sc->sc_board_info.board_flags & BHND_BFL_FEM))) {
                for (i = 0; i < N(v3); i++)
                        BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask,
                            v3[i].set);
        } else if (mac->mac_phy.rev == 1 ||
                  (sc->sc_board_info.board_flags & BHND_BFL_FEM)) {
                for (i = 0; i < N(v4); i++)
                        BWN_PHY_SETMASK(mac, v4[i].offset, v4[i].mask,
                            v4[i].set);
        } else {
                for (i = 0; i < N(v5); i++)
                        BWN_PHY_SETMASK(mac, v5[i].offset, v5[i].mask,
                            v5[i].set);
        }
        if (mac->mac_phy.rev == 1 &&
            (sc->sc_board_info.board_flags & BHND_BFL_PAREF)) {
                BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_5, BWN_PHY_TR_LOOKUP_1);
                BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_6, BWN_PHY_TR_LOOKUP_2);
                BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_7, BWN_PHY_TR_LOOKUP_3);
                BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_8, BWN_PHY_TR_LOOKUP_4);
        }
        if ((sc->sc_board_info.board_flags & BHND_BFL_FEM_BT) &&
            (sc->sc_cid.chip_id == BHND_CHIPID_BCM5354) &&
            (sc->sc_cid.chip_pkg == BHND_PKGID_BCM4712SMALL)) {
                BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0006);
                BWN_PHY_WRITE(mac, BWN_PHY_GPIO_SELECT, 0x0005);
                BWN_PHY_WRITE(mac, BWN_PHY_GPIO_OUTEN, 0xffff);
                bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_PR45960W);
        }
        if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x8000);
                BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0040);
                BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0xa400);
                BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0x0b00);
                BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x0007);
                BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xfff8, 0x0003);
                BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xffc7, 0x0020);
                BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
        } else {
                BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0x7fff);
                BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xffbf);
        }
        if (mac->mac_phy.rev == 1) {
                tmp = BWN_PHY_READ(mac, BWN_PHY_CLIPCTRTHRESH);
                tmp2 = (tmp & 0x03e0) >> 5;
                tmp2 |= tmp2 << 5;
                BWN_PHY_WRITE(mac, BWN_PHY_4C3, tmp2);
                tmp = BWN_PHY_READ(mac, BWN_PHY_GAINDIRECTMISMATCH);
                tmp2 = (tmp & 0x1f00) >> 8;
                tmp2 |= tmp2 << 5;
                BWN_PHY_WRITE(mac, BWN_PHY_4C4, tmp2);
                tmp = BWN_PHY_READ(mac, BWN_PHY_VERYLOWGAINDB);
                tmp2 = tmp & 0x00ff;
                tmp2 |= tmp << 8;
                BWN_PHY_WRITE(mac, BWN_PHY_4C5, tmp2);
        }
}

struct bwn_b2062_freq {
        uint16_t                freq;
        uint8_t                 value[6];
};

static int
bwn_phy_lp_b2062_init(struct bwn_mac *mac)
{
#define CALC_CTL7(freq, div)                                            \
        (((800000000 * (div) + (freq)) / (2 * (freq)) - 8) & 0xff)
#define CALC_CTL18(freq, div)                                           \
        ((((100 * (freq) + 16000000 * (div)) / (32000000 * (div))) - 1) & 0xff)
#define CALC_CTL19(freq, div)                                           \
        ((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff)
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        static const struct bwn_b2062_freq freqdata_tab[] = {
                { 12000, { 6, 6, 6, 6, 10, 6 } },
                { 13000, { 4, 4, 4, 4, 11, 7 } },
                { 14400, { 3, 3, 3, 3, 12, 7 } },
                { 16200, { 3, 3, 3, 3, 13, 8 } },
                { 18000, { 2, 2, 2, 2, 14, 8 } },
                { 19200, { 1, 1, 1, 1, 14, 9 } }
        };
        static const struct bwn_wpair v1[] = {
                { BWN_B2062_N_TXCTL3, 0 },
                { BWN_B2062_N_TXCTL4, 0 },
                { BWN_B2062_N_TXCTL5, 0 },
                { BWN_B2062_N_TXCTL6, 0 },
                { BWN_B2062_N_PDNCTL0, 0x40 },
                { BWN_B2062_N_PDNCTL0, 0 },
                { BWN_B2062_N_CALIB_TS, 0x10 },
                { BWN_B2062_N_CALIB_TS, 0 }
        };
        const struct bwn_b2062_freq *f = NULL;
        uint32_t ref;
        u_int xtalfreq;
        unsigned int i;
        int error;

        error = bhnd_get_clock_freq(sc->sc_dev, BHND_CLOCK_ALP, &xtalfreq);
        if (error) {
                device_printf(sc->sc_dev, "failed to fetch clock frequency: %d",
                    error);
                return (error);
        }

        bwn_phy_lp_b2062_tblinit(mac);

        for (i = 0; i < N(v1); i++)
                BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
        if (mac->mac_phy.rev > 0)
                BWN_RF_WRITE(mac, BWN_B2062_S_BG_CTL1,
                    (BWN_RF_READ(mac, BWN_B2062_N_COM2) >> 1) | 0x80);
        if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
                BWN_RF_SET(mac, BWN_B2062_N_TSSI_CTL0, 0x1);
        else
                BWN_RF_MASK(mac, BWN_B2062_N_TSSI_CTL0, ~0x1);

        if (xtalfreq <= 30000000) {
                plp->plp_div = 1;
                BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL1, 0xfffb);
        } else {
                plp->plp_div = 2;
                BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL1, 0x4);
        }

        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL7,
            CALC_CTL7(xtalfreq, plp->plp_div));
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL18,
            CALC_CTL18(xtalfreq, plp->plp_div));
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL19,
            CALC_CTL19(xtalfreq, plp->plp_div));

        ref = (1000 * plp->plp_div + 2 * xtalfreq) / (2000 * plp->plp_div);
        ref &= 0xffff;
        for (i = 0; i < N(freqdata_tab); i++) {
                if (ref < freqdata_tab[i].freq) {
                        f = &freqdata_tab[i];
                        break;
                }
        }
        if (f == NULL)
                f = &freqdata_tab[N(freqdata_tab) - 1];
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL8,
            ((uint16_t)(f->value[1]) << 4) | f->value[0]);
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL9,
            ((uint16_t)(f->value[3]) << 4) | f->value[2]);
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL10, f->value[4]);
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL11, f->value[5]);

        return (0);
#undef CALC_CTL7
#undef CALC_CTL18
#undef CALC_CTL19
}

static int
bwn_phy_lp_b2063_init(struct bwn_mac *mac)
{

        bwn_phy_lp_b2063_tblinit(mac);
        BWN_RF_WRITE(mac, BWN_B2063_LOGEN_SP5, 0);
        BWN_RF_SET(mac, BWN_B2063_COM8, 0x38);
        BWN_RF_WRITE(mac, BWN_B2063_REG_SP1, 0x56);
        BWN_RF_MASK(mac, BWN_B2063_RX_BB_CTL2, ~0x2);
        BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0);
        BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP6, 0x20);
        BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP9, 0x40);
        if (mac->mac_phy.rev == 2) {
                BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0xa0);
                BWN_RF_WRITE(mac, BWN_B2063_PA_SP4, 0xa0);
                BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x18);
        } else {
                BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0x20);
                BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x20);
        }

        return (0);
}

static int
bwn_phy_lp_rxcal_r2(struct bwn_mac *mac)
{
        struct bwn_softc *sc = mac->mac_sc;
        static const struct bwn_wpair v1[] = {
                { BWN_B2063_RX_BB_SP8, 0x0 },
                { BWN_B2063_RC_CALIB_CTL1, 0x7e },
                { BWN_B2063_RC_CALIB_CTL1, 0x7c },
                { BWN_B2063_RC_CALIB_CTL2, 0x15 },
                { BWN_B2063_RC_CALIB_CTL3, 0x70 },
                { BWN_B2063_RC_CALIB_CTL4, 0x52 },
                { BWN_B2063_RC_CALIB_CTL5, 0x1 },
                { BWN_B2063_RC_CALIB_CTL1, 0x7d }
        };
        static const struct bwn_wpair v2[] = {
                { BWN_B2063_TX_BB_SP3, 0x0 },
                { BWN_B2063_RC_CALIB_CTL1, 0x7e },
                { BWN_B2063_RC_CALIB_CTL1, 0x7c },
                { BWN_B2063_RC_CALIB_CTL2, 0x55 },
                { BWN_B2063_RC_CALIB_CTL3, 0x76 }
        };
        u_int freqxtal;
        int error, i;
        uint8_t tmp;

        error = bhnd_get_clock_freq(sc->sc_dev, BHND_CLOCK_ALP, &freqxtal);
        if (error) {
                device_printf(sc->sc_dev, "failed to fetch clock frequency: %d",
                    error);
                return (error);
        }

        tmp = BWN_RF_READ(mac, BWN_B2063_RX_BB_SP8) & 0xff;

        for (i = 0; i < 2; i++)
                BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
        BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, 0xf7);
        for (i = 2; i < N(v1); i++)
                BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
        for (i = 0; i < 10000; i++) {
                if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
                        break;
                DELAY(1000);
        }

        if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
                BWN_RF_WRITE(mac, BWN_B2063_RX_BB_SP8, tmp);

        tmp = BWN_RF_READ(mac, BWN_B2063_TX_BB_SP3) & 0xff;

        for (i = 0; i < N(v2); i++)
                BWN_RF_WRITE(mac, v2[i].reg, v2[i].value);
        if (freqxtal == 24000000) {
                BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0xfc);
                BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x0);
        } else {
                BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0x13);
                BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x1);
        }
        BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0x7d);
        for (i = 0; i < 10000; i++) {
                if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
                        break;
                DELAY(1000);
        }
        if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
                BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, tmp);
        BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL1, 0x7e);

        return (0);
}

static int
bwn_phy_lp_rccal_r12(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        struct bwn_phy_lp_iq_est ie;
        struct bwn_txgain tx_gains;
        static const uint32_t pwrtbl[21] = {
                0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
                0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
                0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
                0x0004c, 0x0002c, 0x0001a,
        };
        uint32_t npwr, ipwr, sqpwr, tmp;
        int loopback, i, j, sum, error;
        uint16_t save[7];
        uint8_t txo, bbmult, txpctlmode;

        error = bwn_phy_lp_switch_channel(mac, 7);
        if (error)
                device_printf(sc->sc_dev,
                    "failed to change channel to 7 (%d)\n", error);
        txo = (BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40) ? 1 : 0;
        bbmult = bwn_phy_lp_get_bbmult(mac);
        if (txo)
                tx_gains = bwn_phy_lp_get_txgain(mac);

        save[0] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_0);
        save[1] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_VAL_0);
        save[2] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR);
        save[3] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVRVAL);
        save[4] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2);
        save[5] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2_VAL);
        save[6] = BWN_PHY_READ(mac, BWN_PHY_LP_PHY_CTL);

        bwn_phy_lp_get_txpctlmode(mac);
        txpctlmode = plp->plp_txpctlmode;
        bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);

        /* disable CRS */
        bwn_phy_lp_set_deaf(mac, 1);
        bwn_phy_lp_set_trsw_over(mac, 0, 1);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffb);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x4);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x10);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffbf);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x7);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x38);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x100);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfdff);
        BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL0, 0);
        BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL1, 1);
        BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL2, 0x20);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfbff);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xf7ff);
        BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
        BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45af);
        BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0x3ff);

        loopback = bwn_phy_lp_loopback(mac);
        if (loopback == -1)
                goto done;
        bwn_phy_lp_set_rxgain_idx(mac, loopback);
        BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xffbf, 0x40);
        BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfff8, 0x1);
        BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xffc7, 0x8);
        BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f, 0xc0);

        tmp = 0;
        memset(&ie, 0, sizeof(ie));
        for (i = 128; i <= 159; i++) {
                BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2, i);
                sum = 0;
                for (j = 5; j <= 25; j++) {
                        bwn_phy_lp_ddfs_turnon(mac, 1, 1, j, j, 0);
                        if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
                                goto done;
                        sqpwr = ie.ie_ipwr + ie.ie_qpwr;
                        ipwr = ((pwrtbl[j - 5] >> 3) + 1) >> 1;
                        npwr = bwn_phy_lp_roundup(sqpwr, (j == 5) ? sqpwr : 0,
                            12);
                        sum += ((ipwr - npwr) * (ipwr - npwr));
                        if ((i == 128) || (sum < tmp)) {
                                plp->plp_rccap = i;
                                tmp = sum;
                        }
                }
        }
        bwn_phy_lp_ddfs_turnoff(mac);
done:
        /* restore CRS */
        bwn_phy_lp_clear_deaf(mac, 1);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xff80);
        BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfc00);

        BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_VAL_0, save[1]);
        BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, save[0]);
        BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVRVAL, save[3]);
        BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, save[2]);
        BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2_VAL, save[5]);
        BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, save[4]);
        BWN_PHY_WRITE(mac, BWN_PHY_LP_PHY_CTL, save[6]);

        bwn_phy_lp_set_bbmult(mac, bbmult);
        if (txo)
                bwn_phy_lp_set_txgain(mac, &tx_gains);
        bwn_phy_lp_set_txpctlmode(mac, txpctlmode);
        if (plp->plp_rccap)
                bwn_phy_lp_set_rccap(mac);

        return (0);
}

static void
bwn_phy_lp_set_rccap(struct bwn_mac *mac)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        uint8_t rc_cap = (plp->plp_rccap & 0x1f) >> 1;

        if (mac->mac_phy.rev == 1)
                rc_cap = MIN(rc_cap + 5, 15);

        BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2,
            MAX(plp->plp_rccap - 4, 0x80));
        BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, rc_cap | 0x80);
        BWN_RF_WRITE(mac, BWN_B2062_S_RXG_CNT16,
            ((plp->plp_rccap & 0x1f) >> 2) | 0x80);
}

static uint32_t
bwn_phy_lp_roundup(uint32_t value, uint32_t div, uint8_t pre)
{
        uint32_t i, q, r;

        if (div == 0)
                return (0);

        for (i = 0, q = value / div, r = value % div; i < pre; i++) {
                q <<= 1;
                if (r << 1 >= div) {
                        q++;
                        r = (r << 1) - div;
                }
        }
        if (r << 1 >= div)
                q++;
        return (q);
}

static void
bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *mac)
{
        struct bwn_softc *sc = mac->mac_sc;

        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0xff);
        DELAY(20);
        if (sc->sc_cid.chip_id == BHND_CHIPID_BCM5354) {
                BWN_RF_WRITE(mac, BWN_B2062_N_COM1, 4);
                BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 4);
        } else {
                BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0);
        }
        DELAY(5);
}

static void
bwn_phy_lp_b2062_vco_calib(struct bwn_mac *mac)
{

        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x42);
        BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x62);
        DELAY(200);
}

static void
bwn_phy_lp_b2062_tblinit(struct bwn_mac *mac)
{
#define FLAG_A  0x01
#define FLAG_G  0x02
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = {
                { BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
                { BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, },
                { BWN_B2062_N_PDNCTL3, 0x0, 0x0, FLAG_A | FLAG_G, },
                { BWN_B2062_N_PDNCTL4, 0x15, 0x2a, FLAG_A | FLAG_G, },
                { BWN_B2062_N_LGENC, 0xDB, 0xff, FLAG_A, },
                { BWN_B2062_N_LGENATUNE0, 0xdd, 0x0, FLAG_A | FLAG_G, },
                { BWN_B2062_N_LGENATUNE2, 0xdd, 0x0, FLAG_A | FLAG_G, },
                { BWN_B2062_N_LGENATUNE3, 0x77, 0xB5, FLAG_A | FLAG_G, },
                { BWN_B2062_N_LGENACTL3, 0x0, 0xff, FLAG_A | FLAG_G, },
                { BWN_B2062_N_LGENACTL7, 0x33, 0x33, FLAG_A | FLAG_G, },
                { BWN_B2062_N_RXA_CTL1, 0x0, 0x0, FLAG_G, },
                { BWN_B2062_N_RXBB_CTL0, 0x82, 0x80, FLAG_A | FLAG_G, },
                { BWN_B2062_N_RXBB_GAIN1, 0x4, 0x4, FLAG_A | FLAG_G, },
                { BWN_B2062_N_RXBB_GAIN2, 0x0, 0x0, FLAG_A | FLAG_G, },
                { BWN_B2062_N_TXCTL4, 0x3, 0x3, FLAG_A | FLAG_G, },
                { BWN_B2062_N_TXCTL5, 0x2, 0x2, FLAG_A | FLAG_G, },
                { BWN_B2062_N_TX_TUNE, 0x88, 0x1b, FLAG_A | FLAG_G, },
                { BWN_B2062_S_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
                { BWN_B2062_S_PDS_CTL0, 0xff, 0xff, FLAG_A | FLAG_G, },
                { BWN_B2062_S_LGENG_CTL0, 0xf8, 0xd8, FLAG_A | FLAG_G, },
                { BWN_B2062_S_LGENG_CTL1, 0x3c, 0x24, FLAG_A | FLAG_G, },
                { BWN_B2062_S_LGENG_CTL8, 0x88, 0x80, FLAG_A | FLAG_G, },
                { BWN_B2062_S_LGENG_CTL10, 0x88, 0x80, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL0, 0x98, 0x98, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL1, 0x10, 0x10, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL5, 0x43, 0x43, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL6, 0x47, 0x47, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL7, 0xc, 0xc, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL8, 0x11, 0x11, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL9, 0x11, 0x11, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL10, 0xe, 0xe, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL11, 0x8, 0x8, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL12, 0x33, 0x33, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL13, 0xa, 0xa, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL14, 0x6, 0x6, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL18, 0x3e, 0x3e, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL19, 0x13, 0x13, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL21, 0x62, 0x62, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL22, 0x7, 0x7, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL23, 0x16, 0x16, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL24, 0x5c, 0x5c, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL25, 0x95, 0x95, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL30, 0xa0, 0xa0, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL31, 0x4, 0x4, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL33, 0xcc, 0xcc, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RFPLLCTL34, 0x7, 0x7, FLAG_A | FLAG_G, },
                { BWN_B2062_S_RXG_CNT8, 0xf, 0xf, FLAG_A, },
        };
        const struct bwn_b206x_rfinit_entry *br;
        unsigned int i;

        for (i = 0; i < N(bwn_b2062_init_tab); i++) {
                br = &bwn_b2062_init_tab[i];
                if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                        if (br->br_flags & FLAG_G)
                                BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
                } else {
                        if (br->br_flags & FLAG_A)
                                BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
                }
        }
#undef FLAG_A
#undef FLAG_B
}

static void
bwn_phy_lp_b2063_tblinit(struct bwn_mac *mac)
{
#define FLAG_A  0x01
#define FLAG_G  0x02
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = {
                { BWN_B2063_COM1, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_COM10, 0x1, 0x0, FLAG_A, },
                { BWN_B2063_COM16, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_COM17, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_COM18, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_COM19, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_COM20, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_COM21, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_COM22, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_COM23, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_COM24, 0x0, 0x0, FLAG_G, },
                { BWN_B2063_LOGEN_SP1, 0xe8, 0xd4, FLAG_A | FLAG_G, },
                { BWN_B2063_LOGEN_SP2, 0xa7, 0x53, FLAG_A | FLAG_G, },
                { BWN_B2063_LOGEN_SP4, 0xf0, 0xf, FLAG_A | FLAG_G, },
                { BWN_B2063_G_RX_SP1, 0x1f, 0x5e, FLAG_G, },
                { BWN_B2063_G_RX_SP2, 0x7f, 0x7e, FLAG_G, },
                { BWN_B2063_G_RX_SP3, 0x30, 0xf0, FLAG_G, },
                { BWN_B2063_G_RX_SP7, 0x7f, 0x7f, FLAG_A | FLAG_G, },
                { BWN_B2063_G_RX_SP10, 0xc, 0xc, FLAG_A | FLAG_G, },
                { BWN_B2063_A_RX_SP1, 0x3c, 0x3f, FLAG_A, },
                { BWN_B2063_A_RX_SP2, 0xfc, 0xfe, FLAG_A, },
                { BWN_B2063_A_RX_SP7, 0x8, 0x8, FLAG_A | FLAG_G, },
                { BWN_B2063_RX_BB_SP4, 0x60, 0x60, FLAG_A | FLAG_G, },
                { BWN_B2063_RX_BB_SP8, 0x30, 0x30, FLAG_A | FLAG_G, },
                { BWN_B2063_TX_RF_SP3, 0xc, 0xb, FLAG_A | FLAG_G, },
                { BWN_B2063_TX_RF_SP4, 0x10, 0xf, FLAG_A | FLAG_G, },
                { BWN_B2063_PA_SP1, 0x3d, 0xfd, FLAG_A | FLAG_G, },
                { BWN_B2063_TX_BB_SP1, 0x2, 0x2, FLAG_A | FLAG_G, },
                { BWN_B2063_BANDGAP_CTL1, 0x56, 0x56, FLAG_A | FLAG_G, },
                { BWN_B2063_JTAG_VCO2, 0xF7, 0xF7, FLAG_A | FLAG_G, },
                { BWN_B2063_G_RX_MIX3, 0x71, 0x71, FLAG_A | FLAG_G, },
                { BWN_B2063_G_RX_MIX4, 0x71, 0x71, FLAG_A | FLAG_G, },
                { BWN_B2063_A_RX_1ST2, 0xf0, 0x30, FLAG_A, },
                { BWN_B2063_A_RX_PS6, 0x77, 0x77, FLAG_A | FLAG_G, },
                { BWN_B2063_A_RX_MIX4, 0x3, 0x3, FLAG_A | FLAG_G, },
                { BWN_B2063_A_RX_MIX5, 0xf, 0xf, FLAG_A | FLAG_G, },
                { BWN_B2063_A_RX_MIX6, 0xf, 0xf, FLAG_A | FLAG_G, },
                { BWN_B2063_RX_TIA_CTL1, 0x77, 0x77, FLAG_A | FLAG_G, },
                { BWN_B2063_RX_TIA_CTL3, 0x77, 0x77, FLAG_A | FLAG_G, },
                { BWN_B2063_RX_BB_CTL2, 0x4, 0x4, FLAG_A | FLAG_G, },
                { BWN_B2063_PA_CTL1, 0x0, 0x4, FLAG_A, },
                { BWN_B2063_VREG_CTL1, 0x3, 0x3, FLAG_A | FLAG_G, },
        };
        const struct bwn_b206x_rfinit_entry *br;
        unsigned int i;

        for (i = 0; i < N(bwn_b2063_init_tab); i++) {
                br = &bwn_b2063_init_tab[i];
                if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                        if (br->br_flags & FLAG_G)
                                BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
                } else {
                        if (br->br_flags & FLAG_A)
                                BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
                }
        }
#undef FLAG_A
#undef FLAG_B
}

static void
bwn_tab_read_multi(struct bwn_mac *mac, uint32_t typenoffset,
    int count, void *_data)
{
        unsigned int i;
        uint32_t offset, type;
        uint8_t *data = _data;

        type = BWN_TAB_GETTYPE(typenoffset);
        offset = BWN_TAB_GETOFFSET(typenoffset);
        KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));

        BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);

        for (i = 0; i < count; i++) {
                switch (type) {
                case BWN_TAB_8BIT:
                        *data = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
                        data++;
                        break;
                case BWN_TAB_16BIT:
                        *((uint16_t *)data) = BWN_PHY_READ(mac,
                            BWN_PHY_TABLEDATALO);
                        data += 2;
                        break;
                case BWN_TAB_32BIT:
                        *((uint32_t *)data) = BWN_PHY_READ(mac,
                            BWN_PHY_TABLEDATAHI);
                        *((uint32_t *)data) <<= 16;
                        *((uint32_t *)data) |= BWN_PHY_READ(mac,
                            BWN_PHY_TABLEDATALO);
                        data += 4;
                        break;
                default:
                        KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
                }
        }
}

static void
bwn_tab_write_multi(struct bwn_mac *mac, uint32_t typenoffset,
    int count, const void *_data)
{
        uint32_t offset, type, value;
        const uint8_t *data = _data;
        unsigned int i;

        type = BWN_TAB_GETTYPE(typenoffset);
        offset = BWN_TAB_GETOFFSET(typenoffset);
        KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));

        BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);

        for (i = 0; i < count; i++) {
                switch (type) {
                case BWN_TAB_8BIT:
                        value = *data;
                        data++;
                        KASSERT(!(value & ~0xff),
                            ("%s:%d: fail", __func__, __LINE__));
                        BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
                        break;
                case BWN_TAB_16BIT:
                        value = *((const uint16_t *)data);
                        data += 2;
                        KASSERT(!(value & ~0xffff),
                            ("%s:%d: fail", __func__, __LINE__));
                        BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
                        break;
                case BWN_TAB_32BIT:
                        value = *((const uint32_t *)data);
                        data += 4;
                        BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
                        BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
                        break;
                default:
                        KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
                }
        }
}

static struct bwn_txgain
bwn_phy_lp_get_txgain(struct bwn_mac *mac)
{
        struct bwn_txgain tg;
        uint16_t tmp;

        tg.tg_dac = (BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0x380) >> 7;
        if (mac->mac_phy.rev < 2) {
                tmp = BWN_PHY_READ(mac,
                    BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7ff;
                tg.tg_gm = tmp & 0x0007;
                tg.tg_pga = (tmp & 0x0078) >> 3;
                tg.tg_pad = (tmp & 0x780) >> 7;
                return (tg);
        }

        tmp = BWN_PHY_READ(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL);
        tg.tg_pad = BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0xff;
        tg.tg_gm = tmp & 0xff;
        tg.tg_pga = (tmp >> 8) & 0xff;
        return (tg);
}

static uint8_t
bwn_phy_lp_get_bbmult(struct bwn_mac *mac)
{

        return (bwn_tab_read(mac, BWN_TAB_2(0, 87)) & 0xff00) >> 8;
}

static void
bwn_phy_lp_set_txgain(struct bwn_mac *mac, struct bwn_txgain *tg)
{
        uint16_t pa;

        if (mac->mac_phy.rev < 2) {
                BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xf800,
                    (tg->tg_pad << 7) | (tg->tg_pga << 3) | tg->tg_gm);
                bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
                bwn_phy_lp_set_txgain_override(mac);
                return;
        }

        pa = bwn_phy_lp_get_pa_gain(mac);
        BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
            (tg->tg_pga << 8) | tg->tg_gm);
        BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0x8000,
            tg->tg_pad | (pa << 6));
        BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xfc), (tg->tg_pga << 8) | tg->tg_gm);
        BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x8000,
            tg->tg_pad | (pa << 8));
        bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
        bwn_phy_lp_set_txgain_override(mac);
}

static void
bwn_phy_lp_set_bbmult(struct bwn_mac *mac, uint8_t bbmult)
{

        bwn_tab_write(mac, BWN_TAB_2(0, 87), (uint16_t)bbmult << 8);
}

static void
bwn_phy_lp_set_trsw_over(struct bwn_mac *mac, uint8_t tx, uint8_t rx)
{
        uint16_t trsw = (tx << 1) | rx;

        BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffc, trsw);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x3);
}

static void
bwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain)
{
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp;

        if (mac->mac_phy.rev < 2) {
                trsw = gain & 0x1;
                lna = (gain & 0xfffc) | ((gain & 0xc) >> 2);
                ext_lna = (gain & 2) >> 1;

                BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
                BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
                    0xfbff, ext_lna << 10);
                BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
                    0xf7ff, ext_lna << 11);
                BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
        } else {
                low_gain = gain & 0xffff;
                high_gain = (gain >> 16) & 0xf;
                ext_lna = (gain >> 21) & 0x1;
                trsw = ~(gain >> 20) & 0x1;

                BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
                BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
                    0xfdff, ext_lna << 9);
                BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
                    0xfbff, ext_lna << 10);
                BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
                BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff0, high_gain);
                if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                        tmp = (gain >> 2) & 0x3;
                        BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
                            0xe7ff, tmp<<11);
                        BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe6), 0xffe7,
                            tmp << 3);
                }
        }

        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
        if (mac->mac_phy.rev >= 2) {
                BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
                if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
                        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x400);
                        BWN_PHY_SET(mac, BWN_PHY_OFDM(0xe5), 0x8);
                }
                return;
        }
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x200);
}

static void
bwn_phy_lp_set_deaf(struct bwn_mac *mac, uint8_t user)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;

        if (user)
                plp->plp_crsusr_off = 1;
        else
                plp->plp_crssys_off = 1;

        BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x80);
}

static void
bwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
{
        struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;

        if (user)
                plp->plp_crsusr_off = 0;
        else
                plp->plp_crssys_off = 0;

        if (plp->plp_crsusr_off || plp->plp_crssys_off)
                return;

        if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
                BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x60);
        else
                BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x20);
}

static int
bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *mac, uint16_t sample)
{
#define CALC_COEFF(_v, _x, _y, _z)      do {                            \
        int _t;                                                         \
        _t = _x - 20;                                                   \
        if (_t >= 0) {                                                  \
                _v = ((_y << (30 - _x)) + (_z >> (1 + _t))) / (_z >> _t); \
        } else {                                                        \
                _v = ((_y << (30 - _x)) + (_z << (-1 - _t))) / (_z << -_t); \
        }                                                               \
} while (0)
#define CALC_COEFF2(_v, _x, _y, _z)     do {                            \
        int _t;                                                         \
        _t = _x - 11;                                                   \
        if (_t >= 0)                                                    \
                _v = (_y << (31 - _x)) / (_z >> _t);                    \
        else                                                            \
                _v = (_y << (31 - _x)) / (_z << -_t);                   \
} while (0)
        struct bwn_phy_lp_iq_est ie;
        uint16_t v0, v1;
        int tmp[2], ret;

        v1 = BWN_PHY_READ(mac, BWN_PHY_RX_COMP_COEFF_S);
        v0 = v1 >> 8;
        v1 |= 0xff;

        BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, 0x00c0);
        BWN_PHY_MASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff);

        ret = bwn_phy_lp_rx_iq_est(mac, sample, 32, &ie);
        if (ret == 0)
                goto done;

        if (ie.ie_ipwr + ie.ie_qpwr < 2) {
                ret = 0;
                goto done;
        }

        CALC_COEFF(tmp[0], bwn_nbits(ie.ie_iqprod), ie.ie_iqprod, ie.ie_ipwr);
        CALC_COEFF2(tmp[1], bwn_nbits(ie.ie_qpwr), ie.ie_qpwr, ie.ie_ipwr);

        tmp[1] = -bwn_sqrt(mac, tmp[1] - (tmp[0] * tmp[0]));
        v0 = tmp[0] >> 3;
        v1 = tmp[1] >> 4;
done:
        BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, v1);
        BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, v0 << 8);
        return ret;
#undef CALC_COEFF
#undef CALC_COEFF2
}

static void
bwn_phy_lp_tblinit_r01(struct bwn_mac *mac)
{
        static const uint16_t noisescale[] = {
                0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
                0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4,
                0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
                0xa4a4, 0xa4a4, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x4c00, 0x2d36, 0x0000, 0x0000, 0x4c00, 0x2d36,
        };
        static const uint16_t crsgainnft[] = {
                0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f,
                0x036f, 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381,
                0x0374, 0x0381, 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f,
                0x0040, 0x005e, 0x007f, 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d,
                0x013d,
        };
        static const uint16_t filterctl[] = {
                0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077,
                0xff53, 0x0127,
        };
        static const uint32_t psctl[] = {
                0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101,
                0x00000080, 0x08080101, 0x00000040, 0x08080101, 0x000000c0,
                0x08a81501, 0x000000c0, 0x0fe8fd01, 0x000000c0, 0x08300105,
                0x000000c0, 0x08080201, 0x000000c0, 0x08280205, 0x000000c0,
                0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, 0x08080202,
                0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
                0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106,
                0x000000c0, 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
        };
        static const uint16_t ofdmcckgain_r0[] = {
                0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
                0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
                0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
                0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
                0x755d,
        };
        static const uint16_t ofdmcckgain_r1[] = {
                0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
                0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
                0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
                0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
                0x755d,
        };
        static const uint16_t gaindelta[] = {
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000,
        };
        static const uint32_t txpwrctl[] = {
                0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c,
                0x0000004b, 0x0000004a, 0x00000049, 0x00000048, 0x00000047,
                0x00000046, 0x00000045, 0x00000044, 0x00000043, 0x00000042,
                0x00000041, 0x00000040, 0x0000003f, 0x0000003e, 0x0000003d,
                0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, 0x00000038,
                0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
                0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e,
                0x0000002d, 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029,
                0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
                0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001f,
                0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001a,
                0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
                0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x000075a0, 0x000075a0, 0x000075a1,
                0x000075a1, 0x000075a2, 0x000075a2, 0x000075a3, 0x000075a3,
                0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, 0x000074b2,
                0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
                0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23,
                0x00006d23, 0x00004660, 0x00004660, 0x00004661, 0x00004661,
                0x00004662, 0x00004662, 0x00004663, 0x00004663, 0x00003e60,
                0x00003e60, 0x00003e61, 0x00003e61, 0x00003e62, 0x00003e62,
                0x00003e63, 0x00003e63, 0x00003660, 0x00003660, 0x00003661,
                0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
                0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62,
                0x00002e62, 0x00002e63, 0x00002e63, 0x00002660, 0x00002660,
                0x00002661, 0x00002661, 0x00002662, 0x00002662, 0x00002663,
                0x00002663, 0x000025e0, 0x000025e0, 0x000025e1, 0x000025e1,
                0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, 0x00001de0,
                0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
                0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61,
                0x00001d61, 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63,
                0x00001560, 0x00001560, 0x00001561, 0x00001561, 0x00001562,
                0x00001562, 0x00001563, 0x00001563, 0x00000d60, 0x00000d60,
                0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, 0x00000d63,
                0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
                0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10,
                0x00000e10, 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12,
                0x00000e13, 0x00000e13, 0x00000bf0, 0x00000bf0, 0x00000bf1,
                0x00000bf1, 0x00000bf2, 0x00000bf2, 0x00000bf3, 0x00000bf3,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
                0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
                0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc,
                0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04,
                0x0000fcff, 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006,
                0x0000ff03, 0x000007fc, 0x0000fc08, 0x00000203, 0x0000fffb,
                0x00000600, 0x0000fa01, 0x0000fc03, 0x0000fe06, 0x0000fe00,
                0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, 0x000004fd,
                0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
                0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa,
                0x00000700, 0x00000305, 0x000004ff, 0x00000801, 0x00000503,
                0x000005f9, 0x00000404, 0x0000fb08, 0x000005fd, 0x00000501,
                0x00000405, 0x0000fb03, 0x000007fc, 0x00000403, 0x00000303,
                0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, 0x0000fe01,
                0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
                0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa,
                0x000003fe, 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06,
                0x000008fc, 0x00000701, 0x00000504, 0x0000fdfe, 0x0000fdfc,
                0x000003fe, 0x00000704, 0x000002fc, 0x000004f9, 0x0000fdfd,
                0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, 0x000004f9,
                0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
                0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa,
                0x00000305, 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc,
                0x0000fe03, 0x00000701, 0x000001fb, 0x000001f9, 0x00000206,
                0x000006fd, 0x00000508, 0x00000700, 0x00000304, 0x000005fe,
                0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, 0x000007f9,
                0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
                0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb,
                0x00000702,
        };

        KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));

        bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
            bwn_tab_sigsq_tbl);
        bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
        bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(crsgainnft), crsgainnft);
        bwn_tab_write_multi(mac, BWN_TAB_2(8, 0), N(filterctl), filterctl);
        bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(psctl), psctl);
        bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
            bwn_tab_pllfrac_tbl);
        bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
            bwn_tabl_iqlocal_tbl);
        if (mac->mac_phy.rev == 0) {
                bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r0),
                    ofdmcckgain_r0);
                bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r0),
                    ofdmcckgain_r0);
        } else {
                bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r1),
                    ofdmcckgain_r1);
                bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r1),
                    ofdmcckgain_r1);
        }
        bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(gaindelta), gaindelta);
        bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(txpwrctl), txpwrctl);
}

static void
bwn_phy_lp_tblinit_r2(struct bwn_mac *mac)
{
        struct bwn_softc *sc = mac->mac_sc;
        int i;
        static const uint16_t noisescale[] = {
                0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
                0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
                0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
                0x00a4, 0x00a4, 0x0000, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
                0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
                0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
                0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4
        };
        static const uint32_t filterctl[] = {
                0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27,
                0x0000217f, 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f
        };
        static const uint32_t psctl[] = {
                0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000,
                0x00002080, 0x00006180, 0x00003002, 0x00000040, 0x00002042,
                0x00180047, 0x00080043, 0x00000041, 0x000020c1, 0x00046006,
                0x00042002, 0x00040000, 0x00002003, 0x00180006, 0x00080002
        };
        static const uint32_t gainidx[] = {
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x10000001, 0x00000000,
                0x20000082, 0x00000000, 0x40000104, 0x00000000, 0x60004207,
                0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
                0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288,
                0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
                0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794,
                0x00000010, 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011,
                0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21,
                0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
                0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329,
                0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
                0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082,
                0x00000000, 0x40000104, 0x00000000, 0x60004207, 0x00000001,
                0x7000838a, 0x00000001, 0xd021050d, 0x00000001, 0xe041c683,
                0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
                0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711,
                0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
                0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c,
                0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019,
                0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, 0xb36811a6,
                0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
                0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c,
                0x0000001a, 0x64ca55ad, 0x0000001a
        };
        static const uint16_t auxgainidx[] = {
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002,
                0x0004, 0x0016
        };
        static const uint16_t swctl[] = {
                0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
                0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
                0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
                0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
                0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
                0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
                0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
                0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018
        };
        static const uint8_t hf[] = {
                0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
                0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17
        };
        static const uint32_t gainval[] = {
                0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
                0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
                0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
                0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
                0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
                0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
                0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
                0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009,
                0x000000f1, 0x00000000, 0x00000000
        };
        static const uint16_t gain[] = {
                0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808,
                0x080a, 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813,
                0x0814, 0x0816, 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824,
                0x0830, 0x0834, 0x0837, 0x083b, 0x083f, 0x0840, 0x0844, 0x0857,
                0x085b, 0x085f, 0x08d7, 0x08db, 0x08df, 0x0957, 0x095b, 0x095f,
                0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, 0x175f, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
        };
        static const uint32_t papdeps[] = {
                0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9,
                0x00021fdf, 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7,
                0x0004efc2, 0x00055fb5, 0x0005cfb0, 0x00063fa8, 0x00068fa3,
                0x00071f98, 0x0007ef92, 0x00084f8b, 0x0008df82, 0x00097f77,
                0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, 0x000bff41,
                0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
                0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15,
                0x00143f1c, 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f,
                0x001e6f7e, 0x0021cfa4, 0x0025bfd2, 0x002a2008, 0x002fb047,
                0x00360090, 0x003d40e0, 0x0045c135, 0x004fb189, 0x005ae1d7,
                0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, 0x007ff2e3,
                0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
                0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506
        };
        static const uint32_t papdmult[] = {
                0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
                0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
                0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
                0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
                0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
                0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
                0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
                0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
                0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
                0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
                0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
                0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
                0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
        };
        static const uint32_t gainidx_a0[] = {
                0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
                0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
                0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
                0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
                0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
                0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
                0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
                0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
                0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
                0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
                0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
                0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
                0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
        };
        static const uint16_t auxgainidx_a0[] = {
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0002, 0x0014
        };
        static const uint32_t gainval_a0[] = {
                0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
                0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
                0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
                0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
                0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
                0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
                0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
                0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
                0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f,
                0x000000f7, 0x00000000, 0x00000000
        };
        static const uint16_t gain_a0[] = {
                0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b,
                0x000c, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016,
                0x0017, 0x001a, 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034,
                0x0037, 0x003b, 0x003f, 0x0040, 0x0044, 0x0057, 0x005b, 0x005f,
                0x00d7, 0x00db, 0x00df, 0x0157, 0x015b, 0x015f, 0x0357, 0x035b,
                0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
                0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
        };

        KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));

        for (i = 0; i < 704; i++)
                bwn_tab_write(mac, BWN_TAB_4(7, i), 0);

        bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
            bwn_tab_sigsq_tbl);
        bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
        bwn_tab_write_multi(mac, BWN_TAB_4(11, 0), N(filterctl), filterctl);
        bwn_tab_write_multi(mac, BWN_TAB_4(12, 0), N(psctl), psctl);
        bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx), gainidx);
        bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx), auxgainidx);
        bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(swctl), swctl);
        bwn_tab_write_multi(mac, BWN_TAB_1(16, 0), N(hf), hf);
        bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval), gainval);
        bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain), gain);
        bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
            bwn_tab_pllfrac_tbl);
        bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
            bwn_tabl_iqlocal_tbl);
        bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(papdeps), papdeps);
        bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(papdmult), papdmult);

        if (sc->sc_cid.chip_id == BHND_CHIPID_BCM4325 &&
            sc->sc_cid.chip_pkg == 0) {
                bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx_a0),
                    gainidx_a0);
                bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx_a0),
                    auxgainidx_a0);
                bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval_a0),
                    gainval_a0);
                bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain_a0), gain_a0);
        }
}

static void
bwn_phy_lp_tblinit_txgain(struct bwn_mac *mac)
{
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        static struct bwn_txgain_entry txgain_r2[] = {
                { 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 },
                { 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 },
                { 255, 255, 203, 0, 135 }, { 255, 255, 203, 0, 131 },
                { 255, 255, 203, 0, 128 }, { 255, 255, 203, 0, 124 },
                { 255, 255, 203, 0, 121 }, { 255, 255, 203, 0, 117 },
                { 255, 255, 203, 0, 114 }, { 255, 255, 203, 0, 111 },
                { 255, 255, 203, 0, 107 }, { 255, 255, 203, 0, 104 },
                { 255, 255, 203, 0, 101 }, { 255, 255, 203, 0, 99 },
                { 255, 255, 203, 0, 96 }, { 255, 255, 203, 0, 93 },
                { 255, 255, 203, 0, 90 }, { 255, 255, 203, 0, 88 },
                { 255, 255, 203, 0, 85 }, { 255, 255, 203, 0, 83 },
                { 255, 255, 203, 0, 81 }, { 255, 255, 203, 0, 78 },
                { 255, 255, 203, 0, 76 }, { 255, 255, 203, 0, 74 },
                { 255, 255, 203, 0, 72 }, { 255, 255, 203, 0, 70 },
                { 255, 255, 203, 0, 68 }, { 255, 255, 203, 0, 66 },
                { 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
                { 255, 255, 192, 0, 64 }, { 255, 255, 186, 0, 64 },
                { 255, 255, 181, 0, 64 }, { 255, 255, 176, 0, 64 },
                { 255, 255, 171, 0, 64 }, { 255, 255, 166, 0, 64 },
                { 255, 255, 161, 0, 64 }, { 255, 255, 157, 0, 64 },
                { 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
                { 255, 255, 144, 0, 64 }, { 255, 255, 140, 0, 64 },
                { 255, 255, 136, 0, 64 }, { 255, 255, 132, 0, 64 },
                { 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
                { 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
                { 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
                { 255, 255, 108, 0, 64 }, { 255, 255, 105, 0, 64 },
                { 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
                { 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
                { 255, 255, 91, 0, 64 }, { 255, 255, 88, 0, 64 },
                { 255, 255, 86, 0, 64 }, { 255, 255, 83, 0, 64 },
                { 255, 255, 81, 0, 64 }, { 255, 255, 79, 0, 64 },
                { 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
                { 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
                { 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
                { 255, 255, 64, 0, 64 }, { 255, 248, 64, 0, 64 },
                { 255, 248, 62, 0, 64 }, { 255, 241, 62, 0, 64 },
                { 255, 241, 60, 0, 64 }, { 255, 234, 60, 0, 64 },
                { 255, 234, 59, 0, 64 }, { 255, 227, 59, 0, 64 },
                { 255, 227, 57, 0, 64 }, { 255, 221, 57, 0, 64 },
                { 255, 221, 55, 0, 64 }, { 255, 215, 55, 0, 64 },
                { 255, 215, 54, 0, 64 }, { 255, 208, 54, 0, 64 },
                { 255, 208, 52, 0, 64 }, { 255, 203, 52, 0, 64 },
                { 255, 203, 51, 0, 64 }, { 255, 197, 51, 0, 64 },
                { 255, 197, 49, 0, 64 }, { 255, 191, 49, 0, 64 },
                { 255, 191, 48, 0, 64 }, { 255, 186, 48, 0, 64 },
                { 255, 186, 47, 0, 64 }, { 255, 181, 47, 0, 64 },
                { 255, 181, 45, 0, 64 }, { 255, 175, 45, 0, 64 },
                { 255, 175, 44, 0, 64 }, { 255, 170, 44, 0, 64 },
                { 255, 170, 43, 0, 64 }, { 255, 166, 43, 0, 64 },
                { 255, 166, 42, 0, 64 }, { 255, 161, 42, 0, 64 },
                { 255, 161, 40, 0, 64 }, { 255, 156, 40, 0, 64 },
                { 255, 156, 39, 0, 64 }, { 255, 152, 39, 0, 64 },
                { 255, 152, 38, 0, 64 }, { 255, 148, 38, 0, 64 },
                { 255, 148, 37, 0, 64 }, { 255, 143, 37, 0, 64 },
                { 255, 143, 36, 0, 64 }, { 255, 139, 36, 0, 64 },
                { 255, 139, 35, 0, 64 }, { 255, 135, 35, 0, 64 },
                { 255, 135, 34, 0, 64 }, { 255, 132, 34, 0, 64 },
                { 255, 132, 33, 0, 64 }, { 255, 128, 33, 0, 64 },
                { 255, 128, 32, 0, 64 }, { 255, 124, 32, 0, 64 },
                { 255, 124, 31, 0, 64 }, { 255, 121, 31, 0, 64 },
                { 255, 121, 30, 0, 64 }, { 255, 117, 30, 0, 64 },
                { 255, 117, 29, 0, 64 }, { 255, 114, 29, 0, 64 },
                { 255, 114, 29, 0, 64 }, { 255, 111, 29, 0, 64 },
        };
        static struct bwn_txgain_entry txgain_2ghz_r2[] = {
                { 7, 99, 255, 0, 64 }, { 7, 96, 255, 0, 64 },
                { 7, 93, 255, 0, 64 }, { 7, 90, 255, 0, 64 },
                { 7, 88, 255, 0, 64 }, { 7, 85, 255, 0, 64 },
                { 7, 83, 255, 0, 64 }, { 7, 81, 255, 0, 64 },
                { 7, 78, 255, 0, 64 }, { 7, 76, 255, 0, 64 },
                { 7, 74, 255, 0, 64 }, { 7, 72, 255, 0, 64 },
                { 7, 70, 255, 0, 64 }, { 7, 68, 255, 0, 64 },
                { 7, 66, 255, 0, 64 }, { 7, 64, 255, 0, 64 },
                { 7, 64, 255, 0, 64 }, { 7, 62, 255, 0, 64 },
                { 7, 62, 248, 0, 64 }, { 7, 60, 248, 0, 64 },
                { 7, 60, 241, 0, 64 }, { 7, 59, 241, 0, 64 },
                { 7, 59, 234, 0, 64 }, { 7, 57, 234, 0, 64 },
                { 7, 57, 227, 0, 64 }, { 7, 55, 227, 0, 64 },
                { 7, 55, 221, 0, 64 }, { 7, 54, 221, 0, 64 },
                { 7, 54, 215, 0, 64 }, { 7, 52, 215, 0, 64 },
                { 7, 52, 208, 0, 64 }, { 7, 51, 208, 0, 64 },
                { 7, 51, 203, 0, 64 }, { 7, 49, 203, 0, 64 },
                { 7, 49, 197, 0, 64 }, { 7, 48, 197, 0, 64 },
                { 7, 48, 191, 0, 64 }, { 7, 47, 191, 0, 64 },
                { 7, 47, 186, 0, 64 }, { 7, 45, 186, 0, 64 },
                { 7, 45, 181, 0, 64 }, { 7, 44, 181, 0, 64 },
                { 7, 44, 175, 0, 64 }, { 7, 43, 175, 0, 64 },
                { 7, 43, 170, 0, 64 }, { 7, 42, 170, 0, 64 },
                { 7, 42, 166, 0, 64 }, { 7, 40, 166, 0, 64 },
                { 7, 40, 161, 0, 64 }, { 7, 39, 161, 0, 64 },
                { 7, 39, 156, 0, 64 }, { 7, 38, 156, 0, 64 },
                { 7, 38, 152, 0, 64 }, { 7, 37, 152, 0, 64 },
                { 7, 37, 148, 0, 64 }, { 7, 36, 148, 0, 64 },
                { 7, 36, 143, 0, 64 }, { 7, 35, 143, 0, 64 },
                { 7, 35, 139, 0, 64 }, { 7, 34, 139, 0, 64 },
                { 7, 34, 135, 0, 64 }, { 7, 33, 135, 0, 64 },
                { 7, 33, 132, 0, 64 }, { 7, 32, 132, 0, 64 },
                { 7, 32, 128, 0, 64 }, { 7, 31, 128, 0, 64 },
                { 7, 31, 124, 0, 64 }, { 7, 30, 124, 0, 64 },
                { 7, 30, 121, 0, 64 }, { 7, 29, 121, 0, 64 },
                { 7, 29, 117, 0, 64 }, { 7, 29, 117, 0, 64 },
                { 7, 29, 114, 0, 64 }, { 7, 28, 114, 0, 64 },
                { 7, 28, 111, 0, 64 }, { 7, 27, 111, 0, 64 },
                { 7, 27, 108, 0, 64 }, { 7, 26, 108, 0, 64 },
                { 7, 26, 104, 0, 64 }, { 7, 25, 104, 0, 64 },
                { 7, 25, 102, 0, 64 }, { 7, 25, 102, 0, 64 },
                { 7, 25, 99, 0, 64 }, { 7, 24, 99, 0, 64 },
                { 7, 24, 96, 0, 64 }, { 7, 23, 96, 0, 64 },
                { 7, 23, 93, 0, 64 }, { 7, 23, 93, 0, 64 },
                { 7, 23, 90, 0, 64 }, { 7, 22, 90, 0, 64 },
                { 7, 22, 88, 0, 64 }, { 7, 21, 88, 0, 64 },
                { 7, 21, 85, 0, 64 }, { 7, 21, 85, 0, 64 },
                { 7, 21, 83, 0, 64 }, { 7, 20, 83, 0, 64 },
                { 7, 20, 81, 0, 64 }, { 7, 20, 81, 0, 64 },
                { 7, 20, 78, 0, 64 }, { 7, 19, 78, 0, 64 },
                { 7, 19, 76, 0, 64 }, { 7, 19, 76, 0, 64 },
                { 7, 19, 74, 0, 64 }, { 7, 18, 74, 0, 64 },
                { 7, 18, 72, 0, 64 }, { 7, 18, 72, 0, 64 },
                { 7, 18, 70, 0, 64 }, { 7, 17, 70, 0, 64 },
                { 7, 17, 68, 0, 64 }, { 7, 17, 68, 0, 64 },
                { 7, 17, 66, 0, 64 }, { 7, 16, 66, 0, 64 },
                { 7, 16, 64, 0, 64 }, { 7, 16, 64, 0, 64 },
                { 7, 16, 62, 0, 64 }, { 7, 15, 62, 0, 64 },
                { 7, 15, 60, 0, 64 }, { 7, 15, 60, 0, 64 },
                { 7, 15, 59, 0, 64 }, { 7, 14, 59, 0, 64 },
                { 7, 14, 57, 0, 64 }, { 7, 14, 57, 0, 64 },
                { 7, 14, 55, 0, 64 }, { 7, 14, 55, 0, 64 },
                { 7, 14, 54, 0, 64 }, { 7, 13, 54, 0, 64 },
                { 7, 13, 52, 0, 64 }, { 7, 13, 52, 0, 64 },
        };
        static struct bwn_txgain_entry txgain_5ghz_r2[] = {
                { 255, 255, 255, 0, 152 }, { 255, 255, 255, 0, 147 },
                { 255, 255, 255, 0, 143 }, { 255, 255, 255, 0, 139 },
                { 255, 255, 255, 0, 135 }, { 255, 255, 255, 0, 131 },
                { 255, 255, 255, 0, 128 }, { 255, 255, 255, 0, 124 },
                { 255, 255, 255, 0, 121 }, { 255, 255, 255, 0, 117 },
                { 255, 255, 255, 0, 114 }, { 255, 255, 255, 0, 111 },
                { 255, 255, 255, 0, 107 }, { 255, 255, 255, 0, 104 },
                { 255, 255, 255, 0, 101 }, { 255, 255, 255, 0, 99 },
                { 255, 255, 255, 0, 96 }, { 255, 255, 255, 0, 93 },
                { 255, 255, 255, 0, 90 }, { 255, 255, 255, 0, 88 },
                { 255, 255, 255, 0, 85 }, { 255, 255, 255, 0, 83 },
                { 255, 255, 255, 0, 81 }, { 255, 255, 255, 0, 78 },
                { 255, 255, 255, 0, 76 }, { 255, 255, 255, 0, 74 },
                { 255, 255, 255, 0, 72 }, { 255, 255, 255, 0, 70 },
                { 255, 255, 255, 0, 68 }, { 255, 255, 255, 0, 66 },
                { 255, 255, 255, 0, 64 }, { 255, 255, 248, 0, 64 },
                { 255, 255, 241, 0, 64 }, { 255, 255, 234, 0, 64 },
                { 255, 255, 227, 0, 64 }, { 255, 255, 221, 0, 64 },
                { 255, 255, 215, 0, 64 }, { 255, 255, 208, 0, 64 },
                { 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
                { 255, 255, 191, 0, 64 }, { 255, 255, 186, 0, 64 },
                { 255, 255, 181, 0, 64 }, { 255, 255, 175, 0, 64 },
                { 255, 255, 170, 0, 64 }, { 255, 255, 166, 0, 64 },
                { 255, 255, 161, 0, 64 }, { 255, 255, 156, 0, 64 },
                { 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
                { 255, 255, 143, 0, 64 }, { 255, 255, 139, 0, 64 },
                { 255, 255, 135, 0, 64 }, { 255, 255, 132, 0, 64 },
                { 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
                { 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
                { 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
                { 255, 255, 108, 0, 64 }, { 255, 255, 104, 0, 64 },
                { 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
                { 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
                { 255, 255, 90, 0, 64 }, { 255, 255, 88, 0, 64 },
                { 255, 255, 85, 0, 64 }, { 255, 255, 83, 0, 64 },
                { 255, 255, 81, 0, 64 }, { 255, 255, 78, 0, 64 },
                { 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
                { 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
                { 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
                { 255, 255, 64, 0, 64 }, { 255, 255, 64, 0, 64 },
                { 255, 255, 62, 0, 64 }, { 255, 248, 62, 0, 64 },
                { 255, 248, 60, 0, 64 }, { 255, 241, 60, 0, 64 },
                { 255, 241, 59, 0, 64 }, { 255, 234, 59, 0, 64 },
                { 255, 234, 57, 0, 64 }, { 255, 227, 57, 0, 64 },
                { 255, 227, 55, 0, 64 }, { 255, 221, 55, 0, 64 },
                { 255, 221, 54, 0, 64 }, { 255, 215, 54, 0, 64 },
                { 255, 215, 52, 0, 64 }, { 255, 208, 52, 0, 64 },
                { 255, 208, 51, 0, 64 }, { 255, 203, 51, 0, 64 },
                { 255, 203, 49, 0, 64 }, { 255, 197, 49, 0, 64 },
                { 255, 197, 48, 0, 64 }, { 255, 191, 48, 0, 64 },
                { 255, 191, 47, 0, 64 }, { 255, 186, 47, 0, 64 },
                { 255, 186, 45, 0, 64 }, { 255, 181, 45, 0, 64 },
                { 255, 181, 44, 0, 64 }, { 255, 175, 44, 0, 64 },
                { 255, 175, 43, 0, 64 }, { 255, 170, 43, 0, 64 },
                { 255, 170, 42, 0, 64 }, { 255, 166, 42, 0, 64 },
                { 255, 166, 40, 0, 64 }, { 255, 161, 40, 0, 64 },
                { 255, 161, 39, 0, 64 }, { 255, 156, 39, 0, 64 },
                { 255, 156, 38, 0, 64 }, { 255, 152, 38, 0, 64 },
                { 255, 152, 37, 0, 64 }, { 255, 148, 37, 0, 64 },
                { 255, 148, 36, 0, 64 }, { 255, 143, 36, 0, 64 },
                { 255, 143, 35, 0, 64 }, { 255, 139, 35, 0, 64 },
                { 255, 139, 34, 0, 64 }, { 255, 135, 34, 0, 64 },
                { 255, 135, 33, 0, 64 }, { 255, 132, 33, 0, 64 },
                { 255, 132, 32, 0, 64 }, { 255, 128, 32, 0, 64 }
        };
        static struct bwn_txgain_entry txgain_r0[] = {
                { 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
                { 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
                { 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
                { 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
                { 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
                { 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
                { 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
                { 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
                { 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
                { 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
                { 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
                { 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
                { 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
                { 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
                { 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
                { 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
                { 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
                { 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
                { 7, 15, 13, 0, 70 }, { 7, 15, 13, 0, 68 },
                { 7, 15, 13, 0, 66 }, { 7, 15, 13, 0, 64 },
                { 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
                { 7, 15, 13, 0, 59 }, { 7, 15, 13, 0, 57 },
                { 7, 15, 12, 0, 71 }, { 7, 15, 12, 0, 69 },
                { 7, 15, 12, 0, 67 }, { 7, 15, 12, 0, 65 },
                { 7, 15, 12, 0, 63 }, { 7, 15, 12, 0, 62 },
                { 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 58 },
                { 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 70 },
                { 7, 15, 11, 0, 68 }, { 7, 15, 11, 0, 66 },
                { 7, 15, 11, 0, 65 }, { 7, 15, 11, 0, 63 },
                { 7, 15, 11, 0, 61 }, { 7, 15, 11, 0, 59 },
                { 7, 15, 11, 0, 58 }, { 7, 15, 10, 0, 71 },
                { 7, 15, 10, 0, 69 }, { 7, 15, 10, 0, 67 },
                { 7, 15, 10, 0, 65 }, { 7, 15, 10, 0, 63 },
                { 7, 15, 10, 0, 61 }, { 7, 15, 10, 0, 60 },
                { 7, 15, 10, 0, 58 }, { 7, 15, 10, 0, 56 },
                { 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
                { 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
                { 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 60 },
                { 7, 15, 9, 0, 59 }, { 7, 14, 9, 0, 72 },
                { 7, 14, 9, 0, 70 }, { 7, 14, 9, 0, 68 },
                { 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 64 },
                { 7, 14, 9, 0, 62 }, { 7, 14, 9, 0, 60 },
                { 7, 14, 9, 0, 59 }, { 7, 13, 9, 0, 72 },
                { 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
                { 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
                { 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
                { 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
                { 7, 13, 8, 0, 72 }, { 7, 13, 8, 0, 70 },
                { 7, 13, 8, 0, 68 }, { 7, 13, 8, 0, 66 },
                { 7, 13, 8, 0, 64 }, { 7, 13, 8, 0, 62 },
                { 7, 13, 8, 0, 60 }, { 7, 13, 8, 0, 59 },
                { 7, 12, 8, 0, 72 }, { 7, 12, 8, 0, 70 },
                { 7, 12, 8, 0, 68 }, { 7, 12, 8, 0, 66 },
                { 7, 12, 8, 0, 64 }, { 7, 12, 8, 0, 62 },
                { 7, 12, 8, 0, 61 }, { 7, 12, 8, 0, 59 },
                { 7, 12, 7, 0, 73 }, { 7, 12, 7, 0, 71 },
                { 7, 12, 7, 0, 69 }, { 7, 12, 7, 0, 67 },
                { 7, 12, 7, 0, 65 }, { 7, 12, 7, 0, 63 },
                { 7, 12, 7, 0, 61 }, { 7, 12, 7, 0, 59 },
                { 7, 11, 7, 0, 72 }, { 7, 11, 7, 0, 70 },
                { 7, 11, 7, 0, 68 }, { 7, 11, 7, 0, 66 },
                { 7, 11, 7, 0, 65 }, { 7, 11, 7, 0, 63 },
                { 7, 11, 7, 0, 61 }, { 7, 11, 7, 0, 59 },
                { 7, 11, 6, 0, 73 }, { 7, 11, 6, 0, 71 }
        };
        static struct bwn_txgain_entry txgain_2ghz_r0[] = {
                { 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
                { 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
                { 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
                { 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
                { 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
                { 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
                { 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
                { 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
                { 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
                { 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
                { 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
                { 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
                { 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
                { 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
                { 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
                { 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
                { 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
                { 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
                { 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
                { 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
                { 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
                { 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
                { 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
                { 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
                { 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
                { 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
                { 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
                { 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
                { 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
                { 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
                { 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
                { 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
                { 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
                { 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 },
                { 4, 10, 6, 0, 59 }, { 4, 10, 5, 0, 72 },
                { 4, 10, 5, 0, 70 }, { 4, 10, 5, 0, 68 },
                { 4, 10, 5, 0, 66 }, { 4, 10, 5, 0, 64 },
                { 4, 10, 5, 0, 62 }, { 4, 10, 5, 0, 60 },
                { 4, 10, 5, 0, 59 }, { 4, 9, 5, 0, 70 },
                { 4, 9, 5, 0, 68 }, { 4, 9, 5, 0, 66 },
                { 4, 9, 5, 0, 64 }, { 4, 9, 5, 0, 63 },
                { 4, 9, 5, 0, 61 }, { 4, 9, 5, 0, 59 },
                { 4, 9, 4, 0, 71 }, { 4, 9, 4, 0, 69 },
                { 4, 9, 4, 0, 67 }, { 4, 9, 4, 0, 65 },
                { 4, 9, 4, 0, 63 }, { 4, 9, 4, 0, 62 },
                { 4, 9, 4, 0, 60 }, { 4, 9, 4, 0, 58 },
                { 4, 8, 4, 0, 70 }, { 4, 8, 4, 0, 68 },
                { 4, 8, 4, 0, 66 }, { 4, 8, 4, 0, 65 },
                { 4, 8, 4, 0, 63 }, { 4, 8, 4, 0, 61 },
                { 4, 8, 4, 0, 59 }, { 4, 7, 4, 0, 68 },
                { 4, 7, 4, 0, 66 }, { 4, 7, 4, 0, 64 },
                { 4, 7, 4, 0, 62 }, { 4, 7, 4, 0, 61 },
                { 4, 7, 4, 0, 59 }, { 4, 7, 3, 0, 67 },
                { 4, 7, 3, 0, 65 }, { 4, 7, 3, 0, 63 },
                { 4, 7, 3, 0, 62 }, { 4, 7, 3, 0, 60 },
                { 4, 6, 3, 0, 65 }, { 4, 6, 3, 0, 63 },
                { 4, 6, 3, 0, 61 }, { 4, 6, 3, 0, 60 },
                { 4, 6, 3, 0, 58 }, { 4, 5, 3, 0, 68 },
                { 4, 5, 3, 0, 66 }, { 4, 5, 3, 0, 64 },
                { 4, 5, 3, 0, 62 }, { 4, 5, 3, 0, 60 },
                { 4, 5, 3, 0, 59 }, { 4, 5, 3, 0, 57 },
                { 4, 4, 2, 0, 83 }, { 4, 4, 2, 0, 81 },
                { 4, 4, 2, 0, 78 }, { 4, 4, 2, 0, 76 },
                { 4, 4, 2, 0, 74 }, { 4, 4, 2, 0, 72 }
        };
        static struct bwn_txgain_entry txgain_5ghz_r0[] = {
                { 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
                { 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
                { 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
                { 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
                { 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
                { 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
                { 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
                { 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
                { 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
                { 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
                { 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
                { 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
                { 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
                { 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
                { 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
                { 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
                { 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
                { 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
                { 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
                { 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
                { 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
                { 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
                { 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
                { 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
                { 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
                { 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
                { 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
                { 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
                { 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
                { 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
                { 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
                { 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
                { 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
                { 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
                { 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
                { 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
                { 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
                { 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
                { 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
                { 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
                { 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
                { 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
                { 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
                { 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
                { 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
                { 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
                { 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
                { 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
                { 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
                { 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
                { 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
                { 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
                { 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
                { 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
                { 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
                { 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
                { 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
                { 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
                { 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
                { 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
                { 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
                { 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
                { 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
                { 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
        };
        static struct bwn_txgain_entry txgain_r1[] = {
                { 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
                { 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
                { 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
                { 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
                { 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
                { 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
                { 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
                { 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
                { 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
                { 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
                { 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
                { 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
                { 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
                { 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
                { 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
                { 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
                { 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
                { 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
                { 7, 15, 13, 0, 70 }, { 7, 15, 14, 0, 68 },
                { 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
                { 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
                { 7, 15, 14, 0, 59 }, { 7, 15, 14, 0, 57 },
                { 7, 15, 13, 0, 72 }, { 7, 15, 13, 0, 70 },
                { 7, 15, 13, 0, 68 }, { 7, 15, 13, 0, 66 },
                { 7, 15, 13, 0, 64 }, { 7, 15, 13, 0, 62 },
                { 7, 15, 13, 0, 60 }, { 7, 15, 13, 0, 59 },
                { 7, 15, 13, 0, 57 }, { 7, 15, 12, 0, 71 },
                { 7, 15, 12, 0, 69 }, { 7, 15, 12, 0, 67 },
                { 7, 15, 12, 0, 65 }, { 7, 15, 12, 0, 63 },
                { 7, 15, 12, 0, 62 }, { 7, 15, 12, 0, 60 },
                { 7, 15, 12, 0, 58 }, { 7, 15, 12, 0, 57 },
                { 7, 15, 11, 0, 70 }, { 7, 15, 11, 0, 68 },
                { 7, 15, 11, 0, 66 }, { 7, 15, 11, 0, 65 },
                { 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
                { 7, 15, 11, 0, 59 }, { 7, 15, 11, 0, 58 },
                { 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
                { 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
                { 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
                { 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
                { 7, 15, 10, 0, 56 }, { 7, 15, 9, 0, 70 },
                { 7, 15, 9, 0, 68 }, { 7, 15, 9, 0, 66 },
                { 7, 15, 9, 0, 64 }, { 7, 15, 9, 0, 62 },
                { 7, 15, 9, 0, 60 }, { 7, 15, 9, 0, 59 },
                { 7, 14, 9, 0, 72 }, { 7, 14, 9, 0, 70 },
                { 7, 14, 9, 0, 68 }, { 7, 14, 9, 0, 66 },
                { 7, 14, 9, 0, 64 }, { 7, 14, 9, 0, 62 },
                { 7, 14, 9, 0, 60 }, { 7, 14, 9, 0, 59 },
                { 7, 13, 9, 0, 72 }, { 7, 13, 9, 0, 70 },
                { 7, 13, 9, 0, 68 }, { 7, 13, 9, 0, 66 },
                { 7, 13, 9, 0, 64 }, { 7, 13, 9, 0, 63 },
                { 7, 13, 9, 0, 61 }, { 7, 13, 9, 0, 59 },
                { 7, 13, 9, 0, 57 }, { 7, 13, 8, 0, 72 },
                { 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
                { 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
                { 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
                { 7, 13, 8, 0, 59 }, { 7, 12, 8, 0, 72 },
                { 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
                { 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
                { 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
                { 7, 12, 8, 0, 59 }, { 7, 12, 7, 0, 73 },
                { 7, 12, 7, 0, 71 }, { 7, 12, 7, 0, 69 },
                { 7, 12, 7, 0, 67 }, { 7, 12, 7, 0, 65 },
                { 7, 12, 7, 0, 63 }, { 7, 12, 7, 0, 61 },
                { 7, 12, 7, 0, 59 }, { 7, 11, 7, 0, 72 },
                { 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
                { 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 65 },
                { 7, 11, 7, 0, 63 }, { 7, 11, 7, 0, 61 },
                { 7, 11, 7, 0, 59 }, { 7, 11, 6, 0, 73 },
                { 7, 11, 6, 0, 71 }
        };
        static struct bwn_txgain_entry txgain_2ghz_r1[] = {
                { 4, 15, 15, 0, 90 }, { 4, 15, 15, 0, 88 },
                { 4, 15, 15, 0, 85 }, { 4, 15, 15, 0, 83 },
                { 4, 15, 15, 0, 81 }, { 4, 15, 15, 0, 78 },
                { 4, 15, 15, 0, 76 }, { 4, 15, 15, 0, 74 },
                { 4, 15, 15, 0, 72 }, { 4, 15, 15, 0, 70 },
                { 4, 15, 15, 0, 68 }, { 4, 15, 15, 0, 66 },
                { 4, 15, 15, 0, 64 }, { 4, 15, 15, 0, 62 },
                { 4, 15, 15, 0, 60 }, { 4, 15, 15, 0, 59 },
                { 4, 15, 14, 0, 72 }, { 4, 15, 14, 0, 70 },
                { 4, 15, 14, 0, 68 }, { 4, 15, 14, 0, 66 },
                { 4, 15, 14, 0, 64 }, { 4, 15, 14, 0, 62 },
                { 4, 15, 14, 0, 60 }, { 4, 15, 14, 0, 59 },
                { 4, 15, 13, 0, 72 }, { 4, 15, 13, 0, 70 },
                { 4, 15, 13, 0, 68 }, { 4, 15, 13, 0, 66 },
                { 4, 15, 13, 0, 64 }, { 4, 15, 13, 0, 62 },
                { 4, 15, 13, 0, 60 }, { 4, 15, 13, 0, 59 },
                { 4, 15, 12, 0, 72 }, { 4, 15, 12, 0, 70 },
                { 4, 15, 12, 0, 68 }, { 4, 15, 12, 0, 66 },
                { 4, 15, 12, 0, 64 }, { 4, 15, 12, 0, 62 },
                { 4, 15, 12, 0, 60 }, { 4, 15, 12, 0, 59 },
                { 4, 15, 11, 0, 72 }, { 4, 15, 11, 0, 70 },
                { 4, 15, 11, 0, 68 }, { 4, 15, 11, 0, 66 },
                { 4, 15, 11, 0, 64 }, { 4, 15, 11, 0, 62 },
                { 4, 15, 11, 0, 60 }, { 4, 15, 11, 0, 59 },
                { 4, 15, 10, 0, 72 }, { 4, 15, 10, 0, 70 },
                { 4, 15, 10, 0, 68 }, { 4, 15, 10, 0, 66 },
                { 4, 15, 10, 0, 64 }, { 4, 15, 10, 0, 62 },
                { 4, 15, 10, 0, 60 }, { 4, 15, 10, 0, 59 },
                { 4, 15, 9, 0, 72 }, { 4, 15, 9, 0, 70 },
                { 4, 15, 9, 0, 68 }, { 4, 15, 9, 0, 66 },
                { 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
                { 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
                { 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
                { 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
                { 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
                { 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
                { 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
                { 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
                { 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
                { 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
                { 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
                { 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
                { 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
                { 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
                { 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
                { 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
                { 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
                { 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
                { 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
                { 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
                { 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
                { 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
                { 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
                { 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
                { 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
                { 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
                { 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
                { 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
                { 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
                { 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
                { 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
                { 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
                { 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
                { 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 }
        };
        static struct bwn_txgain_entry txgain_5ghz_r1[] = {
                { 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
                { 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
                { 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
                { 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
                { 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
                { 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
                { 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
                { 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
                { 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
                { 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
                { 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
                { 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
                { 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
                { 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
                { 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
                { 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
                { 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
                { 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
                { 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
                { 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
                { 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
                { 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
                { 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
                { 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
                { 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
                { 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
                { 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
                { 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
                { 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
                { 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
                { 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
                { 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
                { 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
                { 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
                { 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
                { 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
                { 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
                { 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
                { 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
                { 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
                { 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
                { 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
                { 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
                { 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
                { 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
                { 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
                { 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
                { 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
                { 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
                { 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
                { 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
                { 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
                { 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
                { 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
                { 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
                { 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
                { 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
                { 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
                { 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
                { 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
                { 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
                { 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
                { 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
                { 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
        };

        if (mac->mac_phy.rev != 0 && mac->mac_phy.rev != 1) {
                if (sc->sc_board_info.board_flags & BHND_BFL_NOPA)
                        bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r2);
                else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
                        bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
                            txgain_2ghz_r2);
                else
                        bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
                            txgain_5ghz_r2);
                return;
        }

        if (mac->mac_phy.rev == 0) {
                if ((sc->sc_board_info.board_flags & BHND_BFL_NOPA) ||
                    (sc->sc_board_info.board_flags & BHND_BFL_HGPA))
                        bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r0);
                else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
                        bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
                            txgain_2ghz_r0);
                else
                        bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
                            txgain_5ghz_r0);
                return;
        }

        if ((sc->sc_board_info.board_flags & BHND_BFL_NOPA) ||
            (sc->sc_board_info.board_flags & BHND_BFL_HGPA))
                bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r1);
        else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
                bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_2ghz_r1);
        else
                bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_5ghz_r1);
}

static void
bwn_tab_write(struct bwn_mac *mac, uint32_t typeoffset, uint32_t value)
{
        uint32_t offset, type;

        type = BWN_TAB_GETTYPE(typeoffset);
        offset = BWN_TAB_GETOFFSET(typeoffset);
        KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));

        switch (type) {
        case BWN_TAB_8BIT:
                KASSERT(!(value & ~0xff), ("%s:%d: fail", __func__, __LINE__));
                BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
                BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
                break;
        case BWN_TAB_16BIT:
                KASSERT(!(value & ~0xffff),
                    ("%s:%d: fail", __func__, __LINE__));
                BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
                BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
                break;
        case BWN_TAB_32BIT:
                BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
                BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
                BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
                break;
        default:
                KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
        }
}

static int
bwn_phy_lp_loopback(struct bwn_mac *mac)
{
        struct bwn_phy_lp_iq_est ie;
        int i, index = -1;
        uint32_t tmp;

        memset(&ie, 0, sizeof(ie));

        bwn_phy_lp_set_trsw_over(mac, 1, 1);
        BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 1);
        BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x8);
        BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, 0x80);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x80);
        BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x80);
        for (i = 0; i < 32; i++) {
                bwn_phy_lp_set_rxgain_idx(mac, i);
                bwn_phy_lp_ddfs_turnon(mac, 1, 1, 5, 5, 0);
                if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
                        continue;
                tmp = (ie.ie_ipwr + ie.ie_qpwr) / 1000;
                if ((tmp > 4000) && (tmp < 10000)) {
                        index = i;
                        break;
                }
        }
        bwn_phy_lp_ddfs_turnoff(mac);
        return (index);
}

static void
bwn_phy_lp_set_rxgain_idx(struct bwn_mac *mac, uint16_t idx)
{

        bwn_phy_lp_set_rxgain(mac, bwn_tab_read(mac, BWN_TAB_2(12, idx)));
}

static void
bwn_phy_lp_ddfs_turnon(struct bwn_mac *mac, int i_on, int q_on,
    int incr1, int incr2, int scale_idx)
{

        bwn_phy_lp_ddfs_turnoff(mac);
        BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0xff80);
        BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0x80ff);
        BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0xff80, incr1);
        BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0x80ff, incr2 << 8);
        BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff7, i_on << 3);
        BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xffef, q_on << 4);
        BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xff9f, scale_idx << 5);
        BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffb);
        BWN_PHY_SET(mac, BWN_PHY_AFE_DDFS, 0x2);
        BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x20);
}

static uint8_t
bwn_phy_lp_rx_iq_est(struct bwn_mac *mac, uint16_t sample, uint8_t time,
    struct bwn_phy_lp_iq_est *ie)
{
        int i;

        BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfff7);
        BWN_PHY_WRITE(mac, BWN_PHY_IQ_NUM_SMPLS_ADDR, sample);
        BWN_PHY_SETMASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xff00, time);
        BWN_PHY_MASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xfeff);
        BWN_PHY_SET(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);

        for (i = 0; i < 500; i++) {
                if (!(BWN_PHY_READ(mac,
                    BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
                        break;
                DELAY(1000);
        }
        if ((BWN_PHY_READ(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
                BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
                return 0;
        }

        ie->ie_iqprod = BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_HI_ADDR);
        ie->ie_iqprod <<= 16;
        ie->ie_iqprod |= BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_LO_ADDR);
        ie->ie_ipwr = BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_HI_ADDR);
        ie->ie_ipwr <<= 16;
        ie->ie_ipwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_LO_ADDR);
        ie->ie_qpwr = BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR);
        ie->ie_qpwr <<= 16;
        ie->ie_qpwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR);

        BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
        return 1;
}

static uint32_t
bwn_tab_read(struct bwn_mac *mac, uint32_t typeoffset)
{
        uint32_t offset, type, value;

        type = BWN_TAB_GETTYPE(typeoffset);
        offset = BWN_TAB_GETOFFSET(typeoffset);
        KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));

        switch (type) {
        case BWN_TAB_8BIT:
                BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
                value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
                break;
        case BWN_TAB_16BIT:
                BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
                value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
                break;
        case BWN_TAB_32BIT:
                BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
                value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATAHI);
                value <<= 16;
                value |= BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
                break;
        default:
                KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
                value = 0;
        }

        return (value);
}

static void
bwn_phy_lp_ddfs_turnoff(struct bwn_mac *mac)
{

        BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffd);
        BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0xffdf);
}

static void
bwn_phy_lp_set_txgain_dac(struct bwn_mac *mac, uint16_t dac)
{
        uint16_t ctl;

        ctl = BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0xc7f;
        ctl |= dac << 7;
        BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf000, ctl);
}

static void
bwn_phy_lp_set_txgain_pa(struct bwn_mac *mac, uint16_t gain)
{

        BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0xe03f, gain << 6);
        BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x80ff, gain << 8);
}

static void
bwn_phy_lp_set_txgain_override(struct bwn_mac *mac)
{

        if (mac->mac_phy.rev < 2)
                BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
        else {
                BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x80);
                BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x4000);
        }
        BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x40);
}

static uint16_t
bwn_phy_lp_get_pa_gain(struct bwn_mac *mac)
{

        return BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0x7f;
}

static uint8_t
bwn_nbits(int32_t val)
{
        uint32_t tmp;
        uint8_t nbits = 0;

        for (tmp = abs(val); tmp != 0; tmp >>= 1)
                nbits++;
        return (nbits);
}

static void
bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *mac, int offset, int count,
    struct bwn_txgain_entry *table)
{
        int i;

        for (i = offset; i < count; i++)
                bwn_phy_lp_gaintbl_write(mac, i, table[i]);
}

static void
bwn_phy_lp_gaintbl_write(struct bwn_mac *mac, int offset,
    struct bwn_txgain_entry data)
{

        if (mac->mac_phy.rev >= 2)
                bwn_phy_lp_gaintbl_write_r2(mac, offset, data);
        else
                bwn_phy_lp_gaintbl_write_r01(mac, offset, data);
}

static void
bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset,
    struct bwn_txgain_entry te)
{
        struct bwn_softc *sc = mac->mac_sc;
        struct ieee80211com *ic = &sc->sc_ic;
        uint32_t tmp;

        KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__));

        tmp = (te.te_pad << 16) | (te.te_pga << 8) | te.te_gm;
        if (mac->mac_phy.rev >= 3) {
                tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
                    (0x10 << 24) : (0x70 << 24));
        } else {
                tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
                    (0x14 << 24) : (0x7f << 24));
        }
        bwn_tab_write(mac, BWN_TAB_4(7, 0xc0 + offset), tmp);
        bwn_tab_write(mac, BWN_TAB_4(7, 0x140 + offset),
            te.te_bbmult << 20 | te.te_dac << 28);
}

static void
bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
    struct bwn_txgain_entry te)
{

        KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));

        bwn_tab_write(mac, BWN_TAB_4(10, 0xc0 + offset),
            (te.te_pad << 11) | (te.te_pga << 7) | (te.te_gm  << 4) |
            te.te_dac);
        bwn_tab_write(mac, BWN_TAB_4(10, 0x140 + offset), te.te_bbmult << 20);
}