/*-
 * 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>
__FBSDID("$FreeBSD$");

#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 <dev/siba/siba_ids.h>
#include <dev/siba/sibareg.h>
#include <dev/siba/sibavar.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/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>

static void	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 void	bwn_phy_lp_b2062_init(struct bwn_mac *);
static void	bwn_phy_lp_b2063_init(struct bwn_mac *);
static void	bwn_phy_lp_rxcal_r2(struct bwn_mac *);
static void	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;

	bwn_phy_lp_readsprom(mac);	/* XXX bad place */
	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)
		bwn_phy_lp_b2062_init(mac);
	else {
		bwn_phy_lp_b2063_init(mac);

		/* 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)
		bwn_phy_lp_rxcal_r2(mac);
	else if (!plp->plp_rccap) {
		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
			bwn_phy_lp_rccal_r12(mac);
	} 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 void
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;

	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
		plp->plp_txisoband_m = siba_sprom_get_tri2g(sc->sc_dev);
		plp->plp_bxarch = siba_sprom_get_bxa2g(sc->sc_dev);
		plp->plp_rxpwroffset = siba_sprom_get_rxpo2g(sc->sc_dev);
		plp->plp_rssivf = siba_sprom_get_rssismf2g(sc->sc_dev);
		plp->plp_rssivc = siba_sprom_get_rssismc2g(sc->sc_dev);
		plp->plp_rssigs = siba_sprom_get_rssisav2g(sc->sc_dev);
		return;
	}

	plp->plp_txisoband_l = siba_sprom_get_tri5gl(sc->sc_dev);
	plp->plp_txisoband_m = siba_sprom_get_tri5g(sc->sc_dev);
	plp->plp_txisoband_h = siba_sprom_get_tri5gh(sc->sc_dev);
	plp->plp_bxarch = siba_sprom_get_bxa5g(sc->sc_dev);
	plp->plp_rxpwroffset = siba_sprom_get_rxpo5g(sc->sc_dev);
	plp->plp_rssivf = siba_sprom_get_rssismf5g(sc->sc_dev);
	plp->plp_rssivc = siba_sprom_get_rssismc5g(sc->sc_dev);
	plp->plp_rssigs = siba_sprom_get_rssisav5g(sc->sc_dev);
}

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 (siba_get_chipid(sc->sc_dev) == 0x5354) {
		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, freqxtal, val[3], timeout, timeoutref,
	    tmp[6];
	uint16_t old, scale, tmp16;
	int 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);

	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);

	freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
	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 freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
	uint32_t tmp[9];
	int 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);

	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 (siba_get_pci_revid(sc->sc_dev) >= 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 ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
	    (siba_get_chiprev(sc->sc_dev) == 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 ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
	    (siba_get_chiprev(sc->sc_dev) == 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 ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
	    (siba_get_chiprev(sc->sc_dev) == 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 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 ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) &&
	    ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
	   (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_PAREF))) {
		siba_cc_pmu_set_ldovolt(sc->sc_dev, SIBA_LDO_PAREF, 0x28);
		siba_cc_pmu_set_ldoparef(sc->sc_dev, 1);
		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 {
		siba_cc_pmu_set_ldoparef(sc->sc_dev, 0);
		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 (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_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 &&
	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_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) ||
	    (siba_get_pci_subdevice(sc->sc_dev) == 0x048a) ||
	    ((mac->mac_phy.rev == 0) &&
	     (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_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 ||
		  (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_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 &&
	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_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 ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_FEM_BT) &&
	    (siba_get_chipid(sc->sc_dev) == 0x5354) &&
	    (siba_get_chippkg(sc->sc_dev) == SIBA_CHIPPACK_BCM4712S)) {
		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 void
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 xtalfreq, ref;
	unsigned int i;

	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);

	KASSERT(siba_get_cc_caps(sc->sc_dev) & SIBA_CC_CAPS_PMU,
	    ("%s:%d: fail", __func__, __LINE__));
	xtalfreq = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
	KASSERT(xtalfreq != 0, ("%s:%d: fail", __func__, __LINE__));

	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]);
#undef CALC_CTL7
#undef CALC_CTL18
#undef CALC_CTL19
}

static void
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);
	}
}

static void
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 }
	};
	uint32_t freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
	int i;
	uint8_t tmp;

	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);
}

static void
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);
}

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 (siba_get_chipid(sc->sc_dev) == 0x5354) {
		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 ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
	    (siba_get_chiprev(sc->sc_dev) == 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 (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_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 ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
		    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_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 ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_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);
}