Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 17 May 2016 07:09:25 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r300016 - in head/sys/gnu/dev: . bwn bwn/phy_n
Message-ID:  <201605170709.u4H79POZ028242@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Tue May 17 07:09:24 2016
New Revision: 300016
URL: https://svnweb.freebsd.org/changeset/base/300016

Log:
  [bwn] add initial bwn(4) N-PHY code, ported from Linux b43.
  
  This is a GPLv2 PHY-N implementation based on the Linux b43 driver,
  ported over to work in bwn(4).
  
  I've tested this on the BCM4321 11abgn device, in 11bg and 11a modes.
  The b43 PHY code only supports 11abg, no 11n, and 20MHz only wide
  channels.
  
  Yes, this is a GPLv2 driver, so it won't be included in the
  default builds.
  
  Tested:
  
  * BCM4321 11abgn device (Apple!), 11bg and 11a STA mode.
  
  Obtained from:	Linux b43

Added:
  head/sys/gnu/dev/
  head/sys/gnu/dev/bwn/
  head/sys/gnu/dev/bwn/phy_n/
  head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_core.c   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_core.h   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_ppr.c   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_ppr.h   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_regs.h   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_tables.c   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_tables.h   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_radio_2055.c   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_radio_2055.h   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_radio_2056.c   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_radio_2056.h   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_radio_2057.c   (contents, props changed)
  head/sys/gnu/dev/bwn/phy_n/if_bwn_radio_2057.h   (contents, props changed)

Added: head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_core.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_core.c	Tue May 17 07:09:24 2016	(r300016)
@@ -0,0 +1,6832 @@
+
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n PHY data tables
+
+  Copyright (c) 2008 Michael Buesch <m@bues.ch>
+  Copyright (c) 2010 Rafał Miłecki <zajec5@gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * 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_misc.h>
+#include <dev/bwn/if_bwn_util.h>
+#include <dev/bwn/if_bwn_debug.h>
+#include <dev/bwn/if_bwn_phy_common.h>
+#include <dev/bwn/if_bwn_chipid.h>
+#include <dev/bwn/if_bwn_cordic.h>
+
+#include <gnu/dev/bwn/phy_n/if_bwn_phy_n_regs.h>
+#include <gnu/dev/bwn/phy_n/if_bwn_phy_n_ppr.h>
+#include <gnu/dev/bwn/phy_n/if_bwn_phy_n_tables.h>
+#include <gnu/dev/bwn/phy_n/if_bwn_radio_2055.h>
+#include <gnu/dev/bwn/phy_n/if_bwn_radio_2056.h>
+#include <gnu/dev/bwn/phy_n/if_bwn_radio_2057.h>
+#include <gnu/dev/bwn/phy_n/if_bwn_phy_n_core.h>
+
+struct bwn_nphy_txgains {
+	uint16_t tx_lpf[2];
+	uint16_t txgm[2];
+	uint16_t pga[2];
+	uint16_t pad[2];
+	uint16_t ipa[2];
+};
+
+struct bwn_nphy_iqcal_params {
+	uint16_t tx_lpf;
+	uint16_t txgm;
+	uint16_t pga;
+	uint16_t pad;
+	uint16_t ipa;
+	uint16_t cal_gain;
+	uint16_t ncorr[5];
+};
+
+struct bwn_nphy_iq_est {
+	int32_t iq0_prod;
+	uint32_t i0_pwr;
+	uint32_t q0_pwr;
+	int32_t iq1_prod;
+	uint32_t i1_pwr;
+	uint32_t q1_pwr;
+};
+
+enum bwn_nphy_rf_sequence {
+	BWN_RFSEQ_RX2TX,
+	BWN_RFSEQ_TX2RX,
+	BWN_RFSEQ_RESET2RX,
+	BWN_RFSEQ_UPDATE_GAINH,
+	BWN_RFSEQ_UPDATE_GAINL,
+	BWN_RFSEQ_UPDATE_GAINU,
+};
+
+enum n_rf_ctl_over_cmd {
+	N_RF_CTL_OVER_CMD_RXRF_PU = 0,
+	N_RF_CTL_OVER_CMD_RX_PU = 1,
+	N_RF_CTL_OVER_CMD_TX_PU = 2,
+	N_RF_CTL_OVER_CMD_RX_GAIN = 3,
+	N_RF_CTL_OVER_CMD_TX_GAIN = 4,
+};
+
+enum n_intc_override {
+	N_INTC_OVERRIDE_OFF = 0,
+	N_INTC_OVERRIDE_TRSW = 1,
+	N_INTC_OVERRIDE_PA = 2,
+	N_INTC_OVERRIDE_EXT_LNA_PU = 3,
+	N_INTC_OVERRIDE_EXT_LNA_GAIN = 4,
+};
+
+enum n_rssi_type {
+	N_RSSI_W1 = 0,
+	N_RSSI_W2,
+	N_RSSI_NB,
+	N_RSSI_IQ,
+	N_RSSI_TSSI_2G,
+	N_RSSI_TSSI_5G,
+	N_RSSI_TBD,
+};
+
+enum n_rail_type {
+	N_RAIL_I = 0,
+	N_RAIL_Q = 1,
+};
+
+static inline bool bwn_nphy_ipa(struct bwn_mac *mac)
+{
+	bwn_band_t band = bwn_current_band(mac);
+	return ((mac->mac_phy.phy_n->ipa2g_on && band == BWN_BAND_2G) ||
+		(mac->mac_phy.phy_n->ipa5g_on && band == BWN_BAND_5G));
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreGetState */
+static uint8_t bwn_nphy_get_rx_core_state(struct bwn_mac *mac)
+{
+	return (BWN_PHY_READ(mac, BWN_NPHY_RFSEQCA) & BWN_NPHY_RFSEQCA_RXEN) >>
+		BWN_NPHY_RFSEQCA_RXEN_SHIFT;
+}
+
+/**************************************************
+ * RF (just without bwn_nphy_rf_ctl_intc_override)
+ **************************************************/
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */
+static void bwn_nphy_force_rf_sequence(struct bwn_mac *mac,
+				       enum bwn_nphy_rf_sequence seq)
+{
+	static const uint16_t trigger[] = {
+		[BWN_RFSEQ_RX2TX]		= BWN_NPHY_RFSEQTR_RX2TX,
+		[BWN_RFSEQ_TX2RX]		= BWN_NPHY_RFSEQTR_TX2RX,
+		[BWN_RFSEQ_RESET2RX]		= BWN_NPHY_RFSEQTR_RST2RX,
+		[BWN_RFSEQ_UPDATE_GAINH]	= BWN_NPHY_RFSEQTR_UPGH,
+		[BWN_RFSEQ_UPDATE_GAINL]	= BWN_NPHY_RFSEQTR_UPGL,
+		[BWN_RFSEQ_UPDATE_GAINU]	= BWN_NPHY_RFSEQTR_UPGU,
+	};
+	int i;
+	uint16_t seq_mode = BWN_PHY_READ(mac, BWN_NPHY_RFSEQMODE);
+
+	if (seq >= nitems(trigger)) {
+		BWN_WARNPRINTF(mac->mac_sc, "%s: seq %d > max", __func__, seq);
+	}
+
+	BWN_PHY_SET(mac, BWN_NPHY_RFSEQMODE,
+		    BWN_NPHY_RFSEQMODE_CAOVER | BWN_NPHY_RFSEQMODE_TROVER);
+	BWN_PHY_SET(mac, BWN_NPHY_RFSEQTR, trigger[seq]);
+	for (i = 0; i < 200; i++) {
+		if (!(BWN_PHY_READ(mac, BWN_NPHY_RFSEQST) & trigger[seq]))
+			goto ok;
+		DELAY(1000);
+	}
+	BWN_ERRPRINTF(mac->mac_sc, "RF sequence status timeout\n");
+ok:
+	BWN_PHY_WRITE(mac, BWN_NPHY_RFSEQMODE, seq_mode);
+}
+
+static void bwn_nphy_rf_ctl_override_rev19(struct bwn_mac *mac, uint16_t field,
+					   uint16_t value, uint8_t core, bool off,
+					   uint8_t override_id)
+{
+	/* TODO */
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */
+static void bwn_nphy_rf_ctl_override_rev7(struct bwn_mac *mac, uint16_t field,
+					  uint16_t value, uint8_t core, bool off,
+					  uint8_t override)
+{
+	struct bwn_phy *phy = &mac->mac_phy;
+	const struct bwn_nphy_rf_control_override_rev7 *e;
+	uint16_t en_addrs[3][2] = {
+		{ 0x0E7, 0x0EC }, { 0x342, 0x343 }, { 0x346, 0x347 }
+	};
+	uint16_t en_addr;
+	uint16_t en_mask = field;
+	uint16_t val_addr;
+	uint8_t i;
+
+	if (phy->rev >= 19 || phy->rev < 3) {
+		BWN_WARNPRINTF(mac->mac_sc, "%s: phy rev %d out of range\n",
+		    __func__,
+		    phy->rev);
+		return;
+	}
+
+	/* Remember: we can get NULL! */
+	e = bwn_nphy_get_rf_ctl_over_rev7(mac, field, override);
+
+	for (i = 0; i < 2; i++) {
+		if (override >= nitems(en_addrs)) {
+			BWN_ERRPRINTF(mac->mac_sc, "Invalid override value %d\n", override);
+			return;
+		}
+		en_addr = en_addrs[override][i];
+
+		if (e)
+			val_addr = (i == 0) ? e->val_addr_core0 : e->val_addr_core1;
+
+		if (off) {
+			BWN_PHY_MASK(mac, en_addr, ~en_mask);
+			if (e) /* Do it safer, better than wl */
+				BWN_PHY_MASK(mac, val_addr, ~e->val_mask);
+		} else {
+			if (!core || (core & (1 << i))) {
+				BWN_PHY_SET(mac, en_addr, en_mask);
+				if (e)
+					BWN_PHY_SETMASK(mac, val_addr, ~e->val_mask, (value << e->val_shift));
+			}
+		}
+	}
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverideOneToMany */
+static void bwn_nphy_rf_ctl_override_one_to_many(struct bwn_mac *mac,
+						 enum n_rf_ctl_over_cmd cmd,
+						 uint16_t value, uint8_t core, bool off)
+{
+	struct bwn_phy *phy = &mac->mac_phy;
+	uint16_t tmp;
+
+	if (phy->rev < 7) {
+		BWN_ERRPRINTF(mac->mac_sc, "%s: phy rev %d out of range\n",
+		    __func__,
+		    phy->rev);
+	}
+
+	switch (cmd) {
+	case N_RF_CTL_OVER_CMD_RXRF_PU:
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x20, value, core, off, 1);
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x10, value, core, off, 1);
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x08, value, core, off, 1);
+		break;
+	case N_RF_CTL_OVER_CMD_RX_PU:
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x4, value, core, off, 1);
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x2, value, core, off, 1);
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x1, value, core, off, 1);
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x2, value, core, off, 2);
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x0800, 0, core, off, 1);
+		break;
+	case N_RF_CTL_OVER_CMD_TX_PU:
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x4, value, core, off, 0);
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x2, value, core, off, 1);
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x1, value, core, off, 2);
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x0800, 1, core, off, 1);
+		break;
+	case N_RF_CTL_OVER_CMD_RX_GAIN:
+		tmp = value & 0xFF;
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x0800, tmp, core, off, 0);
+		tmp = value >> 8;
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x6000, tmp, core, off, 0);
+		break;
+	case N_RF_CTL_OVER_CMD_TX_GAIN:
+		tmp = value & 0x7FFF;
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x1000, tmp, core, off, 0);
+		tmp = value >> 14;
+		bwn_nphy_rf_ctl_override_rev7(mac, 0x4000, tmp, core, off, 0);
+		break;
+	}
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
+static void bwn_nphy_rf_ctl_override(struct bwn_mac *mac, uint16_t field,
+				     uint16_t value, uint8_t core, bool off)
+{
+	int i;
+	uint8_t index = fls(field);
+	uint8_t addr, en_addr, val_addr;
+
+	/* we expect only one bit set */
+	if (field & (~(1 << (index - 1)))) {
+		BWN_ERRPRINTF(mac->mac_sc, "%s: field 0x%04x has >1 bit set\n",
+		    __func__,
+		    field);
+	}
+
+	if (mac->mac_phy.rev >= 3) {
+		const struct bwn_nphy_rf_control_override_rev3 *rf_ctrl;
+		for (i = 0; i < 2; i++) {
+			if (index == 0 || index == 16) {
+				BWN_ERRPRINTF(mac->mac_sc,
+					"Unsupported RF Ctrl Override call\n");
+				return;
+			}
+
+			rf_ctrl = &tbl_rf_control_override_rev3[index - 1];
+			en_addr = BWN_PHY_N((i == 0) ?
+				rf_ctrl->en_addr0 : rf_ctrl->en_addr1);
+			val_addr = BWN_PHY_N((i == 0) ?
+				rf_ctrl->val_addr0 : rf_ctrl->val_addr1);
+
+			if (off) {
+				BWN_PHY_MASK(mac, en_addr, ~(field));
+				BWN_PHY_MASK(mac, val_addr,
+						~(rf_ctrl->val_mask));
+			} else {
+				if (core == 0 || ((1 << i) & core)) {
+					BWN_PHY_SET(mac, en_addr, field);
+					BWN_PHY_SETMASK(mac, val_addr,
+						~(rf_ctrl->val_mask),
+						(value << rf_ctrl->val_shift));
+				}
+			}
+		}
+	} else {
+		const struct bwn_nphy_rf_control_override_rev2 *rf_ctrl;
+		if (off) {
+			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER, ~(field));
+			value = 0;
+		} else {
+			BWN_PHY_SET(mac, BWN_NPHY_RFCTL_OVER, field);
+		}
+
+		for (i = 0; i < 2; i++) {
+			if (index <= 1 || index == 16) {
+				BWN_ERRPRINTF(mac->mac_sc,
+					"Unsupported RF Ctrl Override call\n");
+				return;
+			}
+
+			if (index == 2 || index == 10 ||
+			    (index >= 13 && index <= 15)) {
+				core = 1;
+			}
+
+			rf_ctrl = &tbl_rf_control_override_rev2[index - 2];
+			addr = BWN_PHY_N((i == 0) ?
+				rf_ctrl->addr0 : rf_ctrl->addr1);
+
+			if ((1 << i) & core)
+				BWN_PHY_SETMASK(mac, addr, ~(rf_ctrl->bmask),
+						(value << rf_ctrl->shift));
+
+			BWN_PHY_SET(mac, BWN_NPHY_RFCTL_OVER, 0x1);
+			BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
+					BWN_NPHY_RFCTL_CMD_START);
+			DELAY(1);
+			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER, 0xFFFE);
+		}
+	}
+}
+
+static void bwn_nphy_rf_ctl_intc_override_rev7(struct bwn_mac *mac,
+					       enum n_intc_override intc_override,
+					       uint16_t value, uint8_t core_sel)
+{
+	uint16_t reg, tmp, tmp2, val;
+	int core;
+
+	/* TODO: What about rev19+? Revs 3+ and 7+ are a bit similar */
+
+	for (core = 0; core < 2; core++) {
+		if ((core_sel == 1 && core != 0) ||
+		    (core_sel == 2 && core != 1))
+			continue;
+
+		reg = (core == 0) ? BWN_NPHY_RFCTL_INTC1 : BWN_NPHY_RFCTL_INTC2;
+
+		switch (intc_override) {
+		case N_INTC_OVERRIDE_OFF:
+			BWN_PHY_WRITE(mac, reg, 0);
+			BWN_PHY_MASK(mac, 0x2ff, ~0x2000);
+			bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
+			break;
+		case N_INTC_OVERRIDE_TRSW:
+			BWN_PHY_SETMASK(mac, reg, ~0xC0, value << 6);
+			BWN_PHY_SET(mac, reg, 0x400);
+
+			BWN_PHY_MASK(mac, 0x2ff, ~0xC000 & 0xFFFF);
+			BWN_PHY_SET(mac, 0x2ff, 0x2000);
+			BWN_PHY_SET(mac, 0x2ff, 0x0001);
+			break;
+		case N_INTC_OVERRIDE_PA:
+			tmp = 0x0030;
+			if (bwn_current_band(mac) == BWN_BAND_5G)
+				val = value << 5;
+			else
+				val = value << 4;
+			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
+			BWN_PHY_SET(mac, reg, 0x1000);
+			break;
+		case N_INTC_OVERRIDE_EXT_LNA_PU:
+			if (bwn_current_band(mac) == BWN_BAND_5G) {
+				tmp = 0x0001;
+				tmp2 = 0x0004;
+				val = value;
+			} else {
+				tmp = 0x0004;
+				tmp2 = 0x0001;
+				val = value << 2;
+			}
+			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
+			BWN_PHY_MASK(mac, reg, ~tmp2);
+			break;
+		case N_INTC_OVERRIDE_EXT_LNA_GAIN:
+			if (bwn_current_band(mac) == BWN_BAND_5G) {
+				tmp = 0x0002;
+				tmp2 = 0x0008;
+				val = value << 1;
+			} else {
+				tmp = 0x0008;
+				tmp2 = 0x0002;
+				val = value << 3;
+			}
+			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
+			BWN_PHY_MASK(mac, reg, ~tmp2);
+			break;
+		}
+	}
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */
+static void bwn_nphy_rf_ctl_intc_override(struct bwn_mac *mac,
+					  enum n_intc_override intc_override,
+					  uint16_t value, uint8_t core)
+{
+	uint8_t i, j;
+	uint16_t reg, tmp, val;
+
+	if (mac->mac_phy.rev >= 7) {
+		bwn_nphy_rf_ctl_intc_override_rev7(mac, intc_override, value,
+						   core);
+		return;
+	}
+
+	if (mac->mac_phy.rev < 3) {
+		BWN_ERRPRINTF(mac->mac_sc, "%s: phy rev %d out of range\n",
+		    __func__,
+		    mac->mac_phy.rev);
+	}
+
+	for (i = 0; i < 2; i++) {
+		if ((core == 1 && i == 1) || (core == 2 && !i))
+			continue;
+
+		reg = (i == 0) ?
+			BWN_NPHY_RFCTL_INTC1 : BWN_NPHY_RFCTL_INTC2;
+		BWN_PHY_SET(mac, reg, 0x400);
+
+		switch (intc_override) {
+		case N_INTC_OVERRIDE_OFF:
+			BWN_PHY_WRITE(mac, reg, 0);
+			bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
+			break;
+		case N_INTC_OVERRIDE_TRSW:
+			if (!i) {
+				BWN_PHY_SETMASK(mac, BWN_NPHY_RFCTL_INTC1,
+						0xFC3F, (value << 6));
+				BWN_PHY_SETMASK(mac, BWN_NPHY_TXF_40CO_B1S1,
+						0xFFFE, 1);
+				BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
+						BWN_NPHY_RFCTL_CMD_START);
+				for (j = 0; j < 100; j++) {
+					if (!(BWN_PHY_READ(mac, BWN_NPHY_RFCTL_CMD) & BWN_NPHY_RFCTL_CMD_START)) {
+						j = 0;
+						break;
+					}
+					DELAY(10);
+				}
+				if (j)
+					BWN_ERRPRINTF(mac->mac_sc,
+						"intc override timeout\n");
+				BWN_PHY_MASK(mac, BWN_NPHY_TXF_40CO_B1S1,
+						0xFFFE);
+			} else {
+				BWN_PHY_SETMASK(mac, BWN_NPHY_RFCTL_INTC2,
+						0xFC3F, (value << 6));
+				BWN_PHY_SETMASK(mac, BWN_NPHY_RFCTL_OVER,
+						0xFFFE, 1);
+				BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
+						BWN_NPHY_RFCTL_CMD_RXTX);
+				for (j = 0; j < 100; j++) {
+					if (!(BWN_PHY_READ(mac, BWN_NPHY_RFCTL_CMD) & BWN_NPHY_RFCTL_CMD_RXTX)) {
+						j = 0;
+						break;
+					}
+					DELAY(10);
+				}
+				if (j)
+					BWN_ERRPRINTF(mac->mac_sc,
+						"intc override timeout\n");
+				BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER,
+						0xFFFE);
+			}
+			break;
+		case N_INTC_OVERRIDE_PA:
+			if (bwn_current_band(mac) == BWN_BAND_5G) {
+				tmp = 0x0020;
+				val = value << 5;
+			} else {
+				tmp = 0x0010;
+				val = value << 4;
+			}
+			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
+			break;
+		case N_INTC_OVERRIDE_EXT_LNA_PU:
+			if (bwn_current_band(mac) == BWN_BAND_5G) {
+				tmp = 0x0001;
+				val = value;
+			} else {
+				tmp = 0x0004;
+				val = value << 2;
+			}
+			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
+			break;
+		case N_INTC_OVERRIDE_EXT_LNA_GAIN:
+			if (bwn_current_band(mac) == BWN_BAND_5G) {
+				tmp = 0x0002;
+				val = value << 1;
+			} else {
+				tmp = 0x0008;
+				val = value << 3;
+			}
+			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
+			break;
+		}
+	}
+}
+
+/**************************************************
+ * Various PHY ops
+ **************************************************/
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
+static void bwn_nphy_write_clip_detection(struct bwn_mac *mac,
+					  const uint16_t *clip_st)
+{
+	BWN_PHY_WRITE(mac, BWN_NPHY_C1_CLIP1THRES, clip_st[0]);
+	BWN_PHY_WRITE(mac, BWN_NPHY_C2_CLIP1THRES, clip_st[1]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
+static void bwn_nphy_read_clip_detection(struct bwn_mac *mac, uint16_t *clip_st)
+{
+	clip_st[0] = BWN_PHY_READ(mac, BWN_NPHY_C1_CLIP1THRES);
+	clip_st[1] = BWN_PHY_READ(mac, BWN_NPHY_C2_CLIP1THRES);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */
+static uint16_t bwn_nphy_classifier(struct bwn_mac *mac, uint16_t mask, uint16_t val)
+{
+	struct bwn_softc *sc = mac->mac_sc;
+	uint16_t tmp;
+
+	if (siba_get_revid(sc->sc_dev) == 16)
+		bwn_mac_suspend(mac);
+
+	tmp = BWN_PHY_READ(mac, BWN_NPHY_CLASSCTL);
+	tmp &= (BWN_NPHY_CLASSCTL_CCKEN | BWN_NPHY_CLASSCTL_OFDMEN |
+		BWN_NPHY_CLASSCTL_WAITEDEN);
+	tmp &= ~mask;
+	tmp |= (val & mask);
+	BWN_PHY_SETMASK(mac, BWN_NPHY_CLASSCTL, 0xFFF8, tmp);
+
+	if (siba_get_revid(sc->sc_dev) == 16)
+		bwn_mac_enable(mac);
+
+	return tmp;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
+static void bwn_nphy_reset_cca(struct bwn_mac *mac)
+{
+	uint16_t bbcfg;
+
+	bwn_phy_force_clock(mac, 1);
+	bbcfg = BWN_PHY_READ(mac, BWN_NPHY_BBCFG);
+	BWN_PHY_WRITE(mac, BWN_NPHY_BBCFG, bbcfg | BWN_NPHY_BBCFG_RSTCCA);
+	DELAY(1);
+	BWN_PHY_WRITE(mac, BWN_NPHY_BBCFG, bbcfg & ~BWN_NPHY_BBCFG_RSTCCA);
+	bwn_phy_force_clock(mac, 0);
+	bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */
+static void bwn_nphy_stay_in_carrier_search(struct bwn_mac *mac, bool enable)
+{
+	struct bwn_phy *phy = &mac->mac_phy;
+	struct bwn_phy_n *nphy = phy->phy_n;
+
+	if (enable) {
+		static const uint16_t clip[] = { 0xFFFF, 0xFFFF };
+		if (nphy->deaf_count++ == 0) {
+			nphy->classifier_state = bwn_nphy_classifier(mac, 0, 0);
+			bwn_nphy_classifier(mac, 0x7,
+					    BWN_NPHY_CLASSCTL_WAITEDEN);
+			bwn_nphy_read_clip_detection(mac, nphy->clip_state);
+			bwn_nphy_write_clip_detection(mac, clip);
+		}
+		bwn_nphy_reset_cca(mac);
+	} else {
+		if (--nphy->deaf_count == 0) {
+			bwn_nphy_classifier(mac, 0x7, nphy->classifier_state);
+			bwn_nphy_write_clip_detection(mac, nphy->clip_state);
+		}
+	}
+}
+
+/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */
+static uint16_t bwn_nphy_read_lpf_ctl(struct bwn_mac *mac, uint16_t offset)
+{
+	if (!offset)
+		offset = bwn_is_40mhz(mac) ? 0x159 : 0x154;
+	return bwn_ntab_read(mac, BWN_NTAB16(7, offset)) & 0x7;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */
+static void bwn_nphy_adjust_lna_gain_table(struct bwn_mac *mac)
+{
+	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
+
+	uint8_t i;
+	int16_t tmp;
+	uint16_t data[4];
+	int16_t gain[2];
+	uint16_t minmax[2];
+	static const uint16_t lna_gain[4] = { -2, 10, 19, 25 };
+
+	if (nphy->hang_avoid)
+		bwn_nphy_stay_in_carrier_search(mac, 1);
+
+	if (nphy->gain_boost) {
+		if (bwn_current_band(mac) == BWN_BAND_2G) {
+			gain[0] = 6;
+			gain[1] = 6;
+		} else {
+			tmp = 40370 - 315 * bwn_get_chan(mac);
+			gain[0] = ((tmp >> 13) + ((tmp >> 12) & 1));
+			tmp = 23242 - 224 * bwn_get_chan(mac);
+			gain[1] = ((tmp >> 13) + ((tmp >> 12) & 1));
+		}
+	} else {
+		gain[0] = 0;
+		gain[1] = 0;
+	}
+
+	for (i = 0; i < 2; i++) {
+		if (nphy->elna_gain_config) {
+			data[0] = 19 + gain[i];
+			data[1] = 25 + gain[i];
+			data[2] = 25 + gain[i];
+			data[3] = 25 + gain[i];
+		} else {
+			data[0] = lna_gain[0] + gain[i];
+			data[1] = lna_gain[1] + gain[i];
+			data[2] = lna_gain[2] + gain[i];
+			data[3] = lna_gain[3] + gain[i];
+		}
+		bwn_ntab_write_bulk(mac, BWN_NTAB16(i, 8), 4, data);
+
+		minmax[i] = 23 + gain[i];
+	}
+
+	BWN_PHY_SETMASK(mac, BWN_NPHY_C1_MINMAX_GAIN, ~BWN_NPHY_C1_MINGAIN,
+				minmax[0] << BWN_NPHY_C1_MINGAIN_SHIFT);
+	BWN_PHY_SETMASK(mac, BWN_NPHY_C2_MINMAX_GAIN, ~BWN_NPHY_C2_MINGAIN,
+				minmax[1] << BWN_NPHY_C2_MINGAIN_SHIFT);
+
+	if (nphy->hang_avoid)
+		bwn_nphy_stay_in_carrier_search(mac, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */
+static void bwn_nphy_set_rf_sequence(struct bwn_mac *mac, uint8_t cmd,
+					uint8_t *events, uint8_t *delays, uint8_t length)
+{
+	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
+	uint8_t i;
+	uint8_t end = (mac->mac_phy.rev >= 3) ? 0x1F : 0x0F;
+	uint16_t offset1 = cmd << 4;
+	uint16_t offset2 = offset1 + 0x80;
+
+	if (nphy->hang_avoid)
+		bwn_nphy_stay_in_carrier_search(mac, true);
+
+	bwn_ntab_write_bulk(mac, BWN_NTAB8(7, offset1), length, events);
+	bwn_ntab_write_bulk(mac, BWN_NTAB8(7, offset2), length, delays);
+
+	for (i = length; i < 16; i++) {
+		bwn_ntab_write(mac, BWN_NTAB8(7, offset1 + i), end);
+		bwn_ntab_write(mac, BWN_NTAB8(7, offset2 + i), 1);
+	}
+
+	if (nphy->hang_avoid)
+		bwn_nphy_stay_in_carrier_search(mac, false);
+}
+
+/**************************************************
+ * Radio 0x2057
+ **************************************************/
+
+static void bwn_radio_2057_chantab_upload(struct bwn_mac *mac,
+					  const struct bwn_nphy_chantabent_rev7 *e_r7,
+					  const struct bwn_nphy_chantabent_rev7_2g *e_r7_2g)
+{
+	if (e_r7_2g) {
+		BWN_RF_WRITE(mac, R2057_VCOCAL_COUNTVAL0, e_r7_2g->radio_vcocal_countval0);
+		BWN_RF_WRITE(mac, R2057_VCOCAL_COUNTVAL1, e_r7_2g->radio_vcocal_countval1);
+		BWN_RF_WRITE(mac, R2057_RFPLL_REFMASTER_SPAREXTALSIZE, e_r7_2g->radio_rfpll_refmaster_sparextalsize);
+		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, e_r7_2g->radio_rfpll_loopfilter_r1);
+		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, e_r7_2g->radio_rfpll_loopfilter_c2);
+		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, e_r7_2g->radio_rfpll_loopfilter_c1);
+		BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, e_r7_2g->radio_cp_kpd_idac);
+		BWN_RF_WRITE(mac, R2057_RFPLL_MMD0, e_r7_2g->radio_rfpll_mmd0);
+		BWN_RF_WRITE(mac, R2057_RFPLL_MMD1, e_r7_2g->radio_rfpll_mmd1);
+		BWN_RF_WRITE(mac, R2057_VCOBUF_TUNE, e_r7_2g->radio_vcobuf_tune);
+		BWN_RF_WRITE(mac, R2057_LOGEN_MX2G_TUNE, e_r7_2g->radio_logen_mx2g_tune);
+		BWN_RF_WRITE(mac, R2057_LOGEN_INDBUF2G_TUNE, e_r7_2g->radio_logen_indbuf2g_tune);
+		BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, e_r7_2g->radio_txmix2g_tune_boost_pu_core0);
+		BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE0, e_r7_2g->radio_pad2g_tune_pus_core0);
+		BWN_RF_WRITE(mac, R2057_LNA2G_TUNE_CORE0, e_r7_2g->radio_lna2g_tune_core0);
+		BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1, e_r7_2g->radio_txmix2g_tune_boost_pu_core1);
+		BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE1, e_r7_2g->radio_pad2g_tune_pus_core1);
+		BWN_RF_WRITE(mac, R2057_LNA2G_TUNE_CORE1, e_r7_2g->radio_lna2g_tune_core1);
+
+	} else {
+		BWN_RF_WRITE(mac, R2057_VCOCAL_COUNTVAL0, e_r7->radio_vcocal_countval0);
+		BWN_RF_WRITE(mac, R2057_VCOCAL_COUNTVAL1, e_r7->radio_vcocal_countval1);
+		BWN_RF_WRITE(mac, R2057_RFPLL_REFMASTER_SPAREXTALSIZE, e_r7->radio_rfpll_refmaster_sparextalsize);
+		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, e_r7->radio_rfpll_loopfilter_r1);
+		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, e_r7->radio_rfpll_loopfilter_c2);
+		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, e_r7->radio_rfpll_loopfilter_c1);
+		BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, e_r7->radio_cp_kpd_idac);
+		BWN_RF_WRITE(mac, R2057_RFPLL_MMD0, e_r7->radio_rfpll_mmd0);
+		BWN_RF_WRITE(mac, R2057_RFPLL_MMD1, e_r7->radio_rfpll_mmd1);
+		BWN_RF_WRITE(mac, R2057_VCOBUF_TUNE, e_r7->radio_vcobuf_tune);
+		BWN_RF_WRITE(mac, R2057_LOGEN_MX2G_TUNE, e_r7->radio_logen_mx2g_tune);
+		BWN_RF_WRITE(mac, R2057_LOGEN_MX5G_TUNE, e_r7->radio_logen_mx5g_tune);
+		BWN_RF_WRITE(mac, R2057_LOGEN_INDBUF2G_TUNE, e_r7->radio_logen_indbuf2g_tune);
+		BWN_RF_WRITE(mac, R2057_LOGEN_INDBUF5G_TUNE, e_r7->radio_logen_indbuf5g_tune);
+		BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, e_r7->radio_txmix2g_tune_boost_pu_core0);
+		BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE0, e_r7->radio_pad2g_tune_pus_core0);
+		BWN_RF_WRITE(mac, R2057_PGA_BOOST_TUNE_CORE0, e_r7->radio_pga_boost_tune_core0);
+		BWN_RF_WRITE(mac, R2057_TXMIX5G_BOOST_TUNE_CORE0, e_r7->radio_txmix5g_boost_tune_core0);
+		BWN_RF_WRITE(mac, R2057_PAD5G_TUNE_MISC_PUS_CORE0, e_r7->radio_pad5g_tune_misc_pus_core0);
+		BWN_RF_WRITE(mac, R2057_LNA2G_TUNE_CORE0, e_r7->radio_lna2g_tune_core0);
+		BWN_RF_WRITE(mac, R2057_LNA5G_TUNE_CORE0, e_r7->radio_lna5g_tune_core0);
+		BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1, e_r7->radio_txmix2g_tune_boost_pu_core1);
+		BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE1, e_r7->radio_pad2g_tune_pus_core1);
+		BWN_RF_WRITE(mac, R2057_PGA_BOOST_TUNE_CORE1, e_r7->radio_pga_boost_tune_core1);
+		BWN_RF_WRITE(mac, R2057_TXMIX5G_BOOST_TUNE_CORE1, e_r7->radio_txmix5g_boost_tune_core1);
+		BWN_RF_WRITE(mac, R2057_PAD5G_TUNE_MISC_PUS_CORE1, e_r7->radio_pad5g_tune_misc_pus_core1);
+		BWN_RF_WRITE(mac, R2057_LNA2G_TUNE_CORE1, e_r7->radio_lna2g_tune_core1);
+		BWN_RF_WRITE(mac, R2057_LNA5G_TUNE_CORE1, e_r7->radio_lna5g_tune_core1);
+	}
+}
+
+static void bwn_radio_2057_setup(struct bwn_mac *mac,
+				 const struct bwn_nphy_chantabent_rev7 *tabent_r7,
+				 const struct bwn_nphy_chantabent_rev7_2g *tabent_r7_2g)
+{
+	struct bwn_phy *phy = &mac->mac_phy;
+
+	bwn_radio_2057_chantab_upload(mac, tabent_r7, tabent_r7_2g);
+
+	switch (phy->rf_rev) {
+	case 0 ... 4:
+	case 6:
+		if (bwn_current_band(mac) == BWN_BAND_2G) {
+			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, 0x3f);
+			BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, 0x3f);
+			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, 0x8);
+			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, 0x8);
+		} else {
+			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, 0x1f);
+			BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, 0x3f);
+			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, 0x8);
+			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, 0x8);
+		}
+		break;
+	case 9: /* e.g. PHY rev 16 */
+		BWN_RF_WRITE(mac, R2057_LOGEN_PTAT_RESETS, 0x20);
+		BWN_RF_WRITE(mac, R2057_VCOBUF_IDACS, 0x18);
+		if (bwn_current_band(mac) == BWN_BAND_5G) {
+			BWN_RF_WRITE(mac, R2057_LOGEN_PTAT_RESETS, 0x38);
+			BWN_RF_WRITE(mac, R2057_VCOBUF_IDACS, 0x0f);
+
+			if (bwn_is_40mhz(mac)) {
+				/* TODO */
+			} else {
+				BWN_RF_WRITE(mac,
+						R2057_PAD_BIAS_FILTER_BWS_CORE0,
+						0x3c);
+				BWN_RF_WRITE(mac,
+						R2057_PAD_BIAS_FILTER_BWS_CORE1,
+						0x3c);
+			}
+		}
+		break;
+	case 14: /* 2 GHz only */
+		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, 0x1b);
+		BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, 0x3f);
+		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, 0x1f);
+		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, 0x1f);
+		break;
+	}
+
+	if (bwn_current_band(mac) == BWN_BAND_2G) {
+		uint16_t txmix2g_tune_boost_pu = 0;
+		uint16_t pad2g_tune_pus = 0;
+
+		if (bwn_nphy_ipa(mac)) {
+			switch (phy->rf_rev) {
+			case 9:
+				txmix2g_tune_boost_pu = 0x0041;
+				/* TODO */
+				break;
+			case 14:
+				txmix2g_tune_boost_pu = 0x21;
+				pad2g_tune_pus = 0x23;
+				break;
+			}
+		}
+
+		if (txmix2g_tune_boost_pu)
+			BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0,
+					txmix2g_tune_boost_pu);
+		if (pad2g_tune_pus)
+			BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE0,
+					pad2g_tune_pus);
+		if (txmix2g_tune_boost_pu)
+			BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1,
+					txmix2g_tune_boost_pu);
+		if (pad2g_tune_pus)
+			BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE1,
+					pad2g_tune_pus);
+	}
+
+	/* 50..100 */
+	DELAY(100);
+
+	/* VCO calibration */
+	BWN_RF_MASK(mac, R2057_RFPLL_MISC_EN, ~0x01);
+	BWN_RF_MASK(mac, R2057_RFPLL_MISC_CAL_RESETN, ~0x04);
+	BWN_RF_SET(mac, R2057_RFPLL_MISC_CAL_RESETN, 0x4);
+	BWN_RF_SET(mac, R2057_RFPLL_MISC_EN, 0x01);
+	/* 300..600 */
+	DELAY(600);
+}
+
+/* Calibrate resistors in LPF of PLL?
+ * http://bcm-v4.sipsolutions.net/PHY/radio205x_rcal
+ */
+static uint8_t bwn_radio_2057_rcal(struct bwn_mac *mac)
+{
+	struct bwn_phy *phy = &mac->mac_phy;
+	uint16_t saved_regs_phy[12];
+	uint16_t saved_regs_phy_rf[6];
+	uint16_t saved_regs_radio[2] = { };
+	static const uint16_t phy_to_store[] = {
+		BWN_NPHY_RFCTL_RSSIO1, BWN_NPHY_RFCTL_RSSIO2,
+		BWN_NPHY_RFCTL_LUT_TRSW_LO1, BWN_NPHY_RFCTL_LUT_TRSW_LO2,
+		BWN_NPHY_RFCTL_RXG1, BWN_NPHY_RFCTL_RXG2,
+		BWN_NPHY_RFCTL_TXG1, BWN_NPHY_RFCTL_TXG2,
+		BWN_NPHY_REV7_RF_CTL_MISC_REG3, BWN_NPHY_REV7_RF_CTL_MISC_REG4,
+		BWN_NPHY_REV7_RF_CTL_MISC_REG5, BWN_NPHY_REV7_RF_CTL_MISC_REG6,
+	};
+	static const uint16_t phy_to_store_rf[] = {
+		BWN_NPHY_REV3_RFCTL_OVER0, BWN_NPHY_REV3_RFCTL_OVER1,
+		BWN_NPHY_REV7_RF_CTL_OVER3, BWN_NPHY_REV7_RF_CTL_OVER4,
+		BWN_NPHY_REV7_RF_CTL_OVER5, BWN_NPHY_REV7_RF_CTL_OVER6,
+	};
+	uint16_t tmp;
+	int i;
+
+	/* Save */
+	for (i = 0; i < nitems(phy_to_store); i++)
+		saved_regs_phy[i] = BWN_PHY_READ(mac, phy_to_store[i]);
+	for (i = 0; i < nitems(phy_to_store_rf); i++)
+		saved_regs_phy_rf[i] = BWN_PHY_READ(mac, phy_to_store_rf[i]);
+
+	/* Set */
+	for (i = 0; i < nitems(phy_to_store); i++)
+		BWN_PHY_WRITE(mac, phy_to_store[i], 0);
+	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_RFCTL_OVER0, 0x07ff);
+	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_RFCTL_OVER1, 0x07ff);
+	BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER3, 0x07ff);
+	BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER4, 0x07ff);
+	BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER5, 0x007f);
+	BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER6, 0x007f);
+
+	switch (phy->rf_rev) {
+	case 5:
+		BWN_PHY_MASK(mac, BWN_NPHY_REV7_RF_CTL_OVER3, ~0x2);
+		DELAY(10);
+		BWN_RF_SET(mac, R2057_IQTEST_SEL_PU, 0x1);
+		BWN_RF_SETMASK(mac, R2057v7_IQTEST_SEL_PU2, ~0x2, 0x1);
+		break;
+	case 9:
+		BWN_PHY_SET(mac, BWN_NPHY_REV7_RF_CTL_OVER3, 0x2);
+		BWN_PHY_SET(mac, BWN_NPHY_REV7_RF_CTL_MISC_REG3, 0x2);
+		saved_regs_radio[0] = BWN_RF_READ(mac, R2057_IQTEST_SEL_PU);
+		BWN_RF_WRITE(mac, R2057_IQTEST_SEL_PU, 0x11);
+		break;
+	case 14:
+		saved_regs_radio[0] = BWN_RF_READ(mac, R2057_IQTEST_SEL_PU);
+		saved_regs_radio[1] = BWN_RF_READ(mac, R2057v7_IQTEST_SEL_PU2);
+		BWN_PHY_SET(mac, BWN_NPHY_REV7_RF_CTL_MISC_REG3, 0x2);
+		BWN_PHY_SET(mac, BWN_NPHY_REV7_RF_CTL_OVER3, 0x2);
+		BWN_RF_WRITE(mac, R2057v7_IQTEST_SEL_PU2, 0x2);
+		BWN_RF_WRITE(mac, R2057_IQTEST_SEL_PU, 0x1);
+		break;
+	}
+
+	/* Enable */
+	BWN_RF_SET(mac, R2057_RCAL_CONFIG, 0x1);
+	DELAY(10);
+
+	/* Start */
+	BWN_RF_SET(mac, R2057_RCAL_CONFIG, 0x2);
+	/* 100..200 */
+	DELAY(200);
+
+	/* Stop */
+	BWN_RF_MASK(mac, R2057_RCAL_CONFIG, ~0x2);
+
+	/* Wait and check for result */
+	if (!bwn_radio_wait_value(mac, R2057_RCAL_STATUS, 1, 1, 100, 1000000)) {
+		BWN_ERRPRINTF(mac->mac_sc, "Radio 0x2057 rcal timeout\n");
+		return 0;
+	}
+	tmp = BWN_RF_READ(mac, R2057_RCAL_STATUS) & 0x3E;
+
+	/* Disable */
+	BWN_RF_MASK(mac, R2057_RCAL_CONFIG, ~0x1);
+
+	/* Restore */
+	for (i = 0; i < nitems(phy_to_store_rf); i++)
+		BWN_PHY_WRITE(mac, phy_to_store_rf[i], saved_regs_phy_rf[i]);
+	for (i = 0; i < nitems(phy_to_store); i++)
+		BWN_PHY_WRITE(mac, phy_to_store[i], saved_regs_phy[i]);
+
+	switch (phy->rf_rev) {
+	case 0 ... 4:
+	case 6:
+		BWN_RF_SETMASK(mac, R2057_TEMPSENSE_CONFIG, ~0x3C, tmp);
+		BWN_RF_SETMASK(mac, R2057_BANDGAP_RCAL_TRIM, ~0xF0,
+				  tmp << 2);
+		break;
+	case 5:
+		BWN_RF_MASK(mac, R2057_IPA2G_CASCONV_CORE0, ~0x1);
+		BWN_RF_MASK(mac, R2057v7_IQTEST_SEL_PU2, ~0x2);
+		break;
+	case 9:
+		BWN_RF_WRITE(mac, R2057_IQTEST_SEL_PU, saved_regs_radio[0]);
+		break;
+	case 14:
+		BWN_RF_WRITE(mac, R2057_IQTEST_SEL_PU, saved_regs_radio[0]);
+		BWN_RF_WRITE(mac, R2057v7_IQTEST_SEL_PU2, saved_regs_radio[1]);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201605170709.u4H79POZ028242>