if_bwn_phy_n_core.c revision 300190
1300016Sadrian
2300016Sadrian/*
3300016Sadrian
4300016Sadrian  Broadcom B43 wireless driver
5300016Sadrian  IEEE 802.11n PHY data tables
6300016Sadrian
7300016Sadrian  Copyright (c) 2008 Michael Buesch <m@bues.ch>
8300016Sadrian  Copyright (c) 2010 Rafa�� Mi��ecki <zajec5@gmail.com>
9300016Sadrian
10300016Sadrian  This program is free software; you can redistribute it and/or modify
11300016Sadrian  it under the terms of the GNU General Public License as published by
12300016Sadrian  the Free Software Foundation; either version 2 of the License, or
13300016Sadrian  (at your option) any later version.
14300016Sadrian
15300016Sadrian  This program is distributed in the hope that it will be useful,
16300016Sadrian  but WITHOUT ANY WARRANTY; without even the implied warranty of
17300016Sadrian  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18300016Sadrian  GNU General Public License for more details.
19300016Sadrian
20300016Sadrian  You should have received a copy of the GNU General Public License
21300016Sadrian  along with this program; see the file COPYING.  If not, write to
22300016Sadrian  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
23300016Sadrian  Boston, MA 02110-1301, USA.
24300016Sadrian
25300016Sadrian*/
26300016Sadrian
27300016Sadrian#include <sys/cdefs.h>
28300016Sadrian__FBSDID("$FreeBSD: head/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_core.c 300190 2016-05-19 04:45:50Z adrian $");
29300016Sadrian
30300016Sadrian/*
31300016Sadrian * The Broadcom Wireless LAN controller driver.
32300016Sadrian */
33300016Sadrian
34300190Sadrian#include "opt_wlan.h"
35300190Sadrian#include "opt_bwn.h"
36300190Sadrian
37300016Sadrian#include <sys/param.h>
38300016Sadrian#include <sys/systm.h>
39300016Sadrian#include <sys/kernel.h>
40300016Sadrian#include <sys/malloc.h>
41300016Sadrian#include <sys/module.h>
42300016Sadrian#include <sys/endian.h>
43300016Sadrian#include <sys/errno.h>
44300016Sadrian#include <sys/firmware.h>
45300016Sadrian#include <sys/lock.h>
46300016Sadrian#include <sys/mutex.h>
47300016Sadrian#include <machine/bus.h>
48300016Sadrian#include <machine/resource.h>
49300016Sadrian#include <sys/bus.h>
50300016Sadrian#include <sys/rman.h>
51300016Sadrian#include <sys/socket.h>
52300016Sadrian#include <sys/sockio.h>
53300016Sadrian
54300016Sadrian#include <net/ethernet.h>
55300016Sadrian#include <net/if.h>
56300016Sadrian#include <net/if_var.h>
57300016Sadrian#include <net/if_arp.h>
58300016Sadrian#include <net/if_dl.h>
59300016Sadrian#include <net/if_llc.h>
60300016Sadrian#include <net/if_media.h>
61300016Sadrian#include <net/if_types.h>
62300016Sadrian
63300016Sadrian#include <dev/pci/pcivar.h>
64300016Sadrian#include <dev/pci/pcireg.h>
65300016Sadrian#include <dev/siba/siba_ids.h>
66300016Sadrian#include <dev/siba/sibareg.h>
67300016Sadrian#include <dev/siba/sibavar.h>
68300016Sadrian
69300016Sadrian#include <net80211/ieee80211_var.h>
70300016Sadrian#include <net80211/ieee80211_radiotap.h>
71300016Sadrian#include <net80211/ieee80211_regdomain.h>
72300016Sadrian#include <net80211/ieee80211_phy.h>
73300016Sadrian#include <net80211/ieee80211_ratectl.h>
74300016Sadrian
75300016Sadrian#include <dev/bwn/if_bwnreg.h>
76300016Sadrian#include <dev/bwn/if_bwnvar.h>
77300016Sadrian#include <dev/bwn/if_bwn_misc.h>
78300016Sadrian#include <dev/bwn/if_bwn_util.h>
79300016Sadrian#include <dev/bwn/if_bwn_debug.h>
80300016Sadrian#include <dev/bwn/if_bwn_phy_common.h>
81300016Sadrian#include <dev/bwn/if_bwn_chipid.h>
82300016Sadrian#include <dev/bwn/if_bwn_cordic.h>
83300016Sadrian
84300016Sadrian#include <gnu/dev/bwn/phy_n/if_bwn_phy_n_regs.h>
85300016Sadrian#include <gnu/dev/bwn/phy_n/if_bwn_phy_n_ppr.h>
86300016Sadrian#include <gnu/dev/bwn/phy_n/if_bwn_phy_n_tables.h>
87300016Sadrian#include <gnu/dev/bwn/phy_n/if_bwn_radio_2055.h>
88300016Sadrian#include <gnu/dev/bwn/phy_n/if_bwn_radio_2056.h>
89300016Sadrian#include <gnu/dev/bwn/phy_n/if_bwn_radio_2057.h>
90300016Sadrian#include <gnu/dev/bwn/phy_n/if_bwn_phy_n_core.h>
91300016Sadrian
92300016Sadrianstruct bwn_nphy_txgains {
93300016Sadrian	uint16_t tx_lpf[2];
94300016Sadrian	uint16_t txgm[2];
95300016Sadrian	uint16_t pga[2];
96300016Sadrian	uint16_t pad[2];
97300016Sadrian	uint16_t ipa[2];
98300016Sadrian};
99300016Sadrian
100300016Sadrianstruct bwn_nphy_iqcal_params {
101300016Sadrian	uint16_t tx_lpf;
102300016Sadrian	uint16_t txgm;
103300016Sadrian	uint16_t pga;
104300016Sadrian	uint16_t pad;
105300016Sadrian	uint16_t ipa;
106300016Sadrian	uint16_t cal_gain;
107300016Sadrian	uint16_t ncorr[5];
108300016Sadrian};
109300016Sadrian
110300016Sadrianstruct bwn_nphy_iq_est {
111300016Sadrian	int32_t iq0_prod;
112300016Sadrian	uint32_t i0_pwr;
113300016Sadrian	uint32_t q0_pwr;
114300016Sadrian	int32_t iq1_prod;
115300016Sadrian	uint32_t i1_pwr;
116300016Sadrian	uint32_t q1_pwr;
117300016Sadrian};
118300016Sadrian
119300016Sadrianenum bwn_nphy_rf_sequence {
120300016Sadrian	BWN_RFSEQ_RX2TX,
121300016Sadrian	BWN_RFSEQ_TX2RX,
122300016Sadrian	BWN_RFSEQ_RESET2RX,
123300016Sadrian	BWN_RFSEQ_UPDATE_GAINH,
124300016Sadrian	BWN_RFSEQ_UPDATE_GAINL,
125300016Sadrian	BWN_RFSEQ_UPDATE_GAINU,
126300016Sadrian};
127300016Sadrian
128300016Sadrianenum n_rf_ctl_over_cmd {
129300016Sadrian	N_RF_CTL_OVER_CMD_RXRF_PU = 0,
130300016Sadrian	N_RF_CTL_OVER_CMD_RX_PU = 1,
131300016Sadrian	N_RF_CTL_OVER_CMD_TX_PU = 2,
132300016Sadrian	N_RF_CTL_OVER_CMD_RX_GAIN = 3,
133300016Sadrian	N_RF_CTL_OVER_CMD_TX_GAIN = 4,
134300016Sadrian};
135300016Sadrian
136300016Sadrianenum n_intc_override {
137300016Sadrian	N_INTC_OVERRIDE_OFF = 0,
138300016Sadrian	N_INTC_OVERRIDE_TRSW = 1,
139300016Sadrian	N_INTC_OVERRIDE_PA = 2,
140300016Sadrian	N_INTC_OVERRIDE_EXT_LNA_PU = 3,
141300016Sadrian	N_INTC_OVERRIDE_EXT_LNA_GAIN = 4,
142300016Sadrian};
143300016Sadrian
144300016Sadrianenum n_rssi_type {
145300016Sadrian	N_RSSI_W1 = 0,
146300016Sadrian	N_RSSI_W2,
147300016Sadrian	N_RSSI_NB,
148300016Sadrian	N_RSSI_IQ,
149300016Sadrian	N_RSSI_TSSI_2G,
150300016Sadrian	N_RSSI_TSSI_5G,
151300016Sadrian	N_RSSI_TBD,
152300016Sadrian};
153300016Sadrian
154300016Sadrianenum n_rail_type {
155300016Sadrian	N_RAIL_I = 0,
156300016Sadrian	N_RAIL_Q = 1,
157300016Sadrian};
158300016Sadrian
159300016Sadrianstatic inline bool bwn_nphy_ipa(struct bwn_mac *mac)
160300016Sadrian{
161300016Sadrian	bwn_band_t band = bwn_current_band(mac);
162300016Sadrian	return ((mac->mac_phy.phy_n->ipa2g_on && band == BWN_BAND_2G) ||
163300016Sadrian		(mac->mac_phy.phy_n->ipa5g_on && band == BWN_BAND_5G));
164300016Sadrian}
165300016Sadrian
166300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreGetState */
167300016Sadrianstatic uint8_t bwn_nphy_get_rx_core_state(struct bwn_mac *mac)
168300016Sadrian{
169300016Sadrian	return (BWN_PHY_READ(mac, BWN_NPHY_RFSEQCA) & BWN_NPHY_RFSEQCA_RXEN) >>
170300016Sadrian		BWN_NPHY_RFSEQCA_RXEN_SHIFT;
171300016Sadrian}
172300016Sadrian
173300016Sadrian/**************************************************
174300016Sadrian * RF (just without bwn_nphy_rf_ctl_intc_override)
175300016Sadrian **************************************************/
176300016Sadrian
177300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */
178300016Sadrianstatic void bwn_nphy_force_rf_sequence(struct bwn_mac *mac,
179300016Sadrian				       enum bwn_nphy_rf_sequence seq)
180300016Sadrian{
181300016Sadrian	static const uint16_t trigger[] = {
182300016Sadrian		[BWN_RFSEQ_RX2TX]		= BWN_NPHY_RFSEQTR_RX2TX,
183300016Sadrian		[BWN_RFSEQ_TX2RX]		= BWN_NPHY_RFSEQTR_TX2RX,
184300016Sadrian		[BWN_RFSEQ_RESET2RX]		= BWN_NPHY_RFSEQTR_RST2RX,
185300016Sadrian		[BWN_RFSEQ_UPDATE_GAINH]	= BWN_NPHY_RFSEQTR_UPGH,
186300016Sadrian		[BWN_RFSEQ_UPDATE_GAINL]	= BWN_NPHY_RFSEQTR_UPGL,
187300016Sadrian		[BWN_RFSEQ_UPDATE_GAINU]	= BWN_NPHY_RFSEQTR_UPGU,
188300016Sadrian	};
189300016Sadrian	int i;
190300016Sadrian	uint16_t seq_mode = BWN_PHY_READ(mac, BWN_NPHY_RFSEQMODE);
191300016Sadrian
192300016Sadrian	if (seq >= nitems(trigger)) {
193300016Sadrian		BWN_WARNPRINTF(mac->mac_sc, "%s: seq %d > max", __func__, seq);
194300016Sadrian	}
195300016Sadrian
196300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFSEQMODE,
197300016Sadrian		    BWN_NPHY_RFSEQMODE_CAOVER | BWN_NPHY_RFSEQMODE_TROVER);
198300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFSEQTR, trigger[seq]);
199300016Sadrian	for (i = 0; i < 200; i++) {
200300016Sadrian		if (!(BWN_PHY_READ(mac, BWN_NPHY_RFSEQST) & trigger[seq]))
201300016Sadrian			goto ok;
202300016Sadrian		DELAY(1000);
203300016Sadrian	}
204300016Sadrian	BWN_ERRPRINTF(mac->mac_sc, "RF sequence status timeout\n");
205300016Sadrianok:
206300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFSEQMODE, seq_mode);
207300016Sadrian}
208300016Sadrian
209300016Sadrianstatic void bwn_nphy_rf_ctl_override_rev19(struct bwn_mac *mac, uint16_t field,
210300016Sadrian					   uint16_t value, uint8_t core, bool off,
211300016Sadrian					   uint8_t override_id)
212300016Sadrian{
213300016Sadrian	/* TODO */
214300016Sadrian}
215300016Sadrian
216300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */
217300016Sadrianstatic void bwn_nphy_rf_ctl_override_rev7(struct bwn_mac *mac, uint16_t field,
218300016Sadrian					  uint16_t value, uint8_t core, bool off,
219300016Sadrian					  uint8_t override)
220300016Sadrian{
221300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
222300016Sadrian	const struct bwn_nphy_rf_control_override_rev7 *e;
223300016Sadrian	uint16_t en_addrs[3][2] = {
224300016Sadrian		{ 0x0E7, 0x0EC }, { 0x342, 0x343 }, { 0x346, 0x347 }
225300016Sadrian	};
226300016Sadrian	uint16_t en_addr;
227300016Sadrian	uint16_t en_mask = field;
228300016Sadrian	uint16_t val_addr;
229300016Sadrian	uint8_t i;
230300016Sadrian
231300016Sadrian	if (phy->rev >= 19 || phy->rev < 3) {
232300016Sadrian		BWN_WARNPRINTF(mac->mac_sc, "%s: phy rev %d out of range\n",
233300016Sadrian		    __func__,
234300016Sadrian		    phy->rev);
235300016Sadrian		return;
236300016Sadrian	}
237300016Sadrian
238300016Sadrian	/* Remember: we can get NULL! */
239300016Sadrian	e = bwn_nphy_get_rf_ctl_over_rev7(mac, field, override);
240300016Sadrian
241300016Sadrian	for (i = 0; i < 2; i++) {
242300016Sadrian		if (override >= nitems(en_addrs)) {
243300016Sadrian			BWN_ERRPRINTF(mac->mac_sc, "Invalid override value %d\n", override);
244300016Sadrian			return;
245300016Sadrian		}
246300016Sadrian		en_addr = en_addrs[override][i];
247300016Sadrian
248300016Sadrian		if (e)
249300016Sadrian			val_addr = (i == 0) ? e->val_addr_core0 : e->val_addr_core1;
250300016Sadrian
251300016Sadrian		if (off) {
252300016Sadrian			BWN_PHY_MASK(mac, en_addr, ~en_mask);
253300016Sadrian			if (e) /* Do it safer, better than wl */
254300016Sadrian				BWN_PHY_MASK(mac, val_addr, ~e->val_mask);
255300016Sadrian		} else {
256300016Sadrian			if (!core || (core & (1 << i))) {
257300016Sadrian				BWN_PHY_SET(mac, en_addr, en_mask);
258300016Sadrian				if (e)
259300016Sadrian					BWN_PHY_SETMASK(mac, val_addr, ~e->val_mask, (value << e->val_shift));
260300016Sadrian			}
261300016Sadrian		}
262300016Sadrian	}
263300016Sadrian}
264300016Sadrian
265300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverideOneToMany */
266300016Sadrianstatic void bwn_nphy_rf_ctl_override_one_to_many(struct bwn_mac *mac,
267300016Sadrian						 enum n_rf_ctl_over_cmd cmd,
268300016Sadrian						 uint16_t value, uint8_t core, bool off)
269300016Sadrian{
270300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
271300016Sadrian	uint16_t tmp;
272300016Sadrian
273300016Sadrian	if (phy->rev < 7) {
274300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: phy rev %d out of range\n",
275300016Sadrian		    __func__,
276300016Sadrian		    phy->rev);
277300016Sadrian	}
278300016Sadrian
279300016Sadrian	switch (cmd) {
280300016Sadrian	case N_RF_CTL_OVER_CMD_RXRF_PU:
281300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x20, value, core, off, 1);
282300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x10, value, core, off, 1);
283300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x08, value, core, off, 1);
284300016Sadrian		break;
285300016Sadrian	case N_RF_CTL_OVER_CMD_RX_PU:
286300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x4, value, core, off, 1);
287300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x2, value, core, off, 1);
288300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x1, value, core, off, 1);
289300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x2, value, core, off, 2);
290300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x0800, 0, core, off, 1);
291300016Sadrian		break;
292300016Sadrian	case N_RF_CTL_OVER_CMD_TX_PU:
293300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x4, value, core, off, 0);
294300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x2, value, core, off, 1);
295300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x1, value, core, off, 2);
296300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x0800, 1, core, off, 1);
297300016Sadrian		break;
298300016Sadrian	case N_RF_CTL_OVER_CMD_RX_GAIN:
299300016Sadrian		tmp = value & 0xFF;
300300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x0800, tmp, core, off, 0);
301300016Sadrian		tmp = value >> 8;
302300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x6000, tmp, core, off, 0);
303300016Sadrian		break;
304300016Sadrian	case N_RF_CTL_OVER_CMD_TX_GAIN:
305300016Sadrian		tmp = value & 0x7FFF;
306300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x1000, tmp, core, off, 0);
307300016Sadrian		tmp = value >> 14;
308300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x4000, tmp, core, off, 0);
309300016Sadrian		break;
310300016Sadrian	}
311300016Sadrian}
312300016Sadrian
313300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
314300016Sadrianstatic void bwn_nphy_rf_ctl_override(struct bwn_mac *mac, uint16_t field,
315300016Sadrian				     uint16_t value, uint8_t core, bool off)
316300016Sadrian{
317300016Sadrian	int i;
318300016Sadrian	uint8_t index = fls(field);
319300016Sadrian	uint8_t addr, en_addr, val_addr;
320300016Sadrian
321300016Sadrian	/* we expect only one bit set */
322300016Sadrian	if (field & (~(1 << (index - 1)))) {
323300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: field 0x%04x has >1 bit set\n",
324300016Sadrian		    __func__,
325300016Sadrian		    field);
326300016Sadrian	}
327300016Sadrian
328300016Sadrian	if (mac->mac_phy.rev >= 3) {
329300016Sadrian		const struct bwn_nphy_rf_control_override_rev3 *rf_ctrl;
330300016Sadrian		for (i = 0; i < 2; i++) {
331300016Sadrian			if (index == 0 || index == 16) {
332300016Sadrian				BWN_ERRPRINTF(mac->mac_sc,
333300016Sadrian					"Unsupported RF Ctrl Override call\n");
334300016Sadrian				return;
335300016Sadrian			}
336300016Sadrian
337300016Sadrian			rf_ctrl = &tbl_rf_control_override_rev3[index - 1];
338300016Sadrian			en_addr = BWN_PHY_N((i == 0) ?
339300016Sadrian				rf_ctrl->en_addr0 : rf_ctrl->en_addr1);
340300016Sadrian			val_addr = BWN_PHY_N((i == 0) ?
341300016Sadrian				rf_ctrl->val_addr0 : rf_ctrl->val_addr1);
342300016Sadrian
343300016Sadrian			if (off) {
344300016Sadrian				BWN_PHY_MASK(mac, en_addr, ~(field));
345300016Sadrian				BWN_PHY_MASK(mac, val_addr,
346300016Sadrian						~(rf_ctrl->val_mask));
347300016Sadrian			} else {
348300016Sadrian				if (core == 0 || ((1 << i) & core)) {
349300016Sadrian					BWN_PHY_SET(mac, en_addr, field);
350300016Sadrian					BWN_PHY_SETMASK(mac, val_addr,
351300016Sadrian						~(rf_ctrl->val_mask),
352300016Sadrian						(value << rf_ctrl->val_shift));
353300016Sadrian				}
354300016Sadrian			}
355300016Sadrian		}
356300016Sadrian	} else {
357300016Sadrian		const struct bwn_nphy_rf_control_override_rev2 *rf_ctrl;
358300016Sadrian		if (off) {
359300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER, ~(field));
360300016Sadrian			value = 0;
361300016Sadrian		} else {
362300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_RFCTL_OVER, field);
363300016Sadrian		}
364300016Sadrian
365300016Sadrian		for (i = 0; i < 2; i++) {
366300016Sadrian			if (index <= 1 || index == 16) {
367300016Sadrian				BWN_ERRPRINTF(mac->mac_sc,
368300016Sadrian					"Unsupported RF Ctrl Override call\n");
369300016Sadrian				return;
370300016Sadrian			}
371300016Sadrian
372300016Sadrian			if (index == 2 || index == 10 ||
373300016Sadrian			    (index >= 13 && index <= 15)) {
374300016Sadrian				core = 1;
375300016Sadrian			}
376300016Sadrian
377300016Sadrian			rf_ctrl = &tbl_rf_control_override_rev2[index - 2];
378300016Sadrian			addr = BWN_PHY_N((i == 0) ?
379300016Sadrian				rf_ctrl->addr0 : rf_ctrl->addr1);
380300016Sadrian
381300016Sadrian			if ((1 << i) & core)
382300016Sadrian				BWN_PHY_SETMASK(mac, addr, ~(rf_ctrl->bmask),
383300016Sadrian						(value << rf_ctrl->shift));
384300016Sadrian
385300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_RFCTL_OVER, 0x1);
386300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
387300016Sadrian					BWN_NPHY_RFCTL_CMD_START);
388300016Sadrian			DELAY(1);
389300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER, 0xFFFE);
390300016Sadrian		}
391300016Sadrian	}
392300016Sadrian}
393300016Sadrian
394300016Sadrianstatic void bwn_nphy_rf_ctl_intc_override_rev7(struct bwn_mac *mac,
395300016Sadrian					       enum n_intc_override intc_override,
396300016Sadrian					       uint16_t value, uint8_t core_sel)
397300016Sadrian{
398300016Sadrian	uint16_t reg, tmp, tmp2, val;
399300016Sadrian	int core;
400300016Sadrian
401300016Sadrian	/* TODO: What about rev19+? Revs 3+ and 7+ are a bit similar */
402300016Sadrian
403300016Sadrian	for (core = 0; core < 2; core++) {
404300016Sadrian		if ((core_sel == 1 && core != 0) ||
405300016Sadrian		    (core_sel == 2 && core != 1))
406300016Sadrian			continue;
407300016Sadrian
408300016Sadrian		reg = (core == 0) ? BWN_NPHY_RFCTL_INTC1 : BWN_NPHY_RFCTL_INTC2;
409300016Sadrian
410300016Sadrian		switch (intc_override) {
411300016Sadrian		case N_INTC_OVERRIDE_OFF:
412300016Sadrian			BWN_PHY_WRITE(mac, reg, 0);
413300016Sadrian			BWN_PHY_MASK(mac, 0x2ff, ~0x2000);
414300016Sadrian			bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
415300016Sadrian			break;
416300016Sadrian		case N_INTC_OVERRIDE_TRSW:
417300016Sadrian			BWN_PHY_SETMASK(mac, reg, ~0xC0, value << 6);
418300016Sadrian			BWN_PHY_SET(mac, reg, 0x400);
419300016Sadrian
420300016Sadrian			BWN_PHY_MASK(mac, 0x2ff, ~0xC000 & 0xFFFF);
421300016Sadrian			BWN_PHY_SET(mac, 0x2ff, 0x2000);
422300016Sadrian			BWN_PHY_SET(mac, 0x2ff, 0x0001);
423300016Sadrian			break;
424300016Sadrian		case N_INTC_OVERRIDE_PA:
425300016Sadrian			tmp = 0x0030;
426300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_5G)
427300016Sadrian				val = value << 5;
428300016Sadrian			else
429300016Sadrian				val = value << 4;
430300016Sadrian			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
431300016Sadrian			BWN_PHY_SET(mac, reg, 0x1000);
432300016Sadrian			break;
433300016Sadrian		case N_INTC_OVERRIDE_EXT_LNA_PU:
434300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_5G) {
435300016Sadrian				tmp = 0x0001;
436300016Sadrian				tmp2 = 0x0004;
437300016Sadrian				val = value;
438300016Sadrian			} else {
439300016Sadrian				tmp = 0x0004;
440300016Sadrian				tmp2 = 0x0001;
441300016Sadrian				val = value << 2;
442300016Sadrian			}
443300016Sadrian			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
444300016Sadrian			BWN_PHY_MASK(mac, reg, ~tmp2);
445300016Sadrian			break;
446300016Sadrian		case N_INTC_OVERRIDE_EXT_LNA_GAIN:
447300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_5G) {
448300016Sadrian				tmp = 0x0002;
449300016Sadrian				tmp2 = 0x0008;
450300016Sadrian				val = value << 1;
451300016Sadrian			} else {
452300016Sadrian				tmp = 0x0008;
453300016Sadrian				tmp2 = 0x0002;
454300016Sadrian				val = value << 3;
455300016Sadrian			}
456300016Sadrian			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
457300016Sadrian			BWN_PHY_MASK(mac, reg, ~tmp2);
458300016Sadrian			break;
459300016Sadrian		}
460300016Sadrian	}
461300016Sadrian}
462300016Sadrian
463300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */
464300016Sadrianstatic void bwn_nphy_rf_ctl_intc_override(struct bwn_mac *mac,
465300016Sadrian					  enum n_intc_override intc_override,
466300016Sadrian					  uint16_t value, uint8_t core)
467300016Sadrian{
468300016Sadrian	uint8_t i, j;
469300016Sadrian	uint16_t reg, tmp, val;
470300016Sadrian
471300016Sadrian	if (mac->mac_phy.rev >= 7) {
472300016Sadrian		bwn_nphy_rf_ctl_intc_override_rev7(mac, intc_override, value,
473300016Sadrian						   core);
474300016Sadrian		return;
475300016Sadrian	}
476300016Sadrian
477300016Sadrian	if (mac->mac_phy.rev < 3) {
478300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: phy rev %d out of range\n",
479300016Sadrian		    __func__,
480300016Sadrian		    mac->mac_phy.rev);
481300016Sadrian	}
482300016Sadrian
483300016Sadrian	for (i = 0; i < 2; i++) {
484300016Sadrian		if ((core == 1 && i == 1) || (core == 2 && !i))
485300016Sadrian			continue;
486300016Sadrian
487300016Sadrian		reg = (i == 0) ?
488300016Sadrian			BWN_NPHY_RFCTL_INTC1 : BWN_NPHY_RFCTL_INTC2;
489300016Sadrian		BWN_PHY_SET(mac, reg, 0x400);
490300016Sadrian
491300016Sadrian		switch (intc_override) {
492300016Sadrian		case N_INTC_OVERRIDE_OFF:
493300016Sadrian			BWN_PHY_WRITE(mac, reg, 0);
494300016Sadrian			bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
495300016Sadrian			break;
496300016Sadrian		case N_INTC_OVERRIDE_TRSW:
497300016Sadrian			if (!i) {
498300016Sadrian				BWN_PHY_SETMASK(mac, BWN_NPHY_RFCTL_INTC1,
499300016Sadrian						0xFC3F, (value << 6));
500300016Sadrian				BWN_PHY_SETMASK(mac, BWN_NPHY_TXF_40CO_B1S1,
501300016Sadrian						0xFFFE, 1);
502300016Sadrian				BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
503300016Sadrian						BWN_NPHY_RFCTL_CMD_START);
504300016Sadrian				for (j = 0; j < 100; j++) {
505300016Sadrian					if (!(BWN_PHY_READ(mac, BWN_NPHY_RFCTL_CMD) & BWN_NPHY_RFCTL_CMD_START)) {
506300016Sadrian						j = 0;
507300016Sadrian						break;
508300016Sadrian					}
509300016Sadrian					DELAY(10);
510300016Sadrian				}
511300016Sadrian				if (j)
512300016Sadrian					BWN_ERRPRINTF(mac->mac_sc,
513300016Sadrian						"intc override timeout\n");
514300016Sadrian				BWN_PHY_MASK(mac, BWN_NPHY_TXF_40CO_B1S1,
515300016Sadrian						0xFFFE);
516300016Sadrian			} else {
517300016Sadrian				BWN_PHY_SETMASK(mac, BWN_NPHY_RFCTL_INTC2,
518300016Sadrian						0xFC3F, (value << 6));
519300016Sadrian				BWN_PHY_SETMASK(mac, BWN_NPHY_RFCTL_OVER,
520300016Sadrian						0xFFFE, 1);
521300016Sadrian				BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
522300016Sadrian						BWN_NPHY_RFCTL_CMD_RXTX);
523300016Sadrian				for (j = 0; j < 100; j++) {
524300016Sadrian					if (!(BWN_PHY_READ(mac, BWN_NPHY_RFCTL_CMD) & BWN_NPHY_RFCTL_CMD_RXTX)) {
525300016Sadrian						j = 0;
526300016Sadrian						break;
527300016Sadrian					}
528300016Sadrian					DELAY(10);
529300016Sadrian				}
530300016Sadrian				if (j)
531300016Sadrian					BWN_ERRPRINTF(mac->mac_sc,
532300016Sadrian						"intc override timeout\n");
533300016Sadrian				BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER,
534300016Sadrian						0xFFFE);
535300016Sadrian			}
536300016Sadrian			break;
537300016Sadrian		case N_INTC_OVERRIDE_PA:
538300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_5G) {
539300016Sadrian				tmp = 0x0020;
540300016Sadrian				val = value << 5;
541300016Sadrian			} else {
542300016Sadrian				tmp = 0x0010;
543300016Sadrian				val = value << 4;
544300016Sadrian			}
545300016Sadrian			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
546300016Sadrian			break;
547300016Sadrian		case N_INTC_OVERRIDE_EXT_LNA_PU:
548300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_5G) {
549300016Sadrian				tmp = 0x0001;
550300016Sadrian				val = value;
551300016Sadrian			} else {
552300016Sadrian				tmp = 0x0004;
553300016Sadrian				val = value << 2;
554300016Sadrian			}
555300016Sadrian			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
556300016Sadrian			break;
557300016Sadrian		case N_INTC_OVERRIDE_EXT_LNA_GAIN:
558300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_5G) {
559300016Sadrian				tmp = 0x0002;
560300016Sadrian				val = value << 1;
561300016Sadrian			} else {
562300016Sadrian				tmp = 0x0008;
563300016Sadrian				val = value << 3;
564300016Sadrian			}
565300016Sadrian			BWN_PHY_SETMASK(mac, reg, ~tmp, val);
566300016Sadrian			break;
567300016Sadrian		}
568300016Sadrian	}
569300016Sadrian}
570300016Sadrian
571300016Sadrian/**************************************************
572300016Sadrian * Various PHY ops
573300016Sadrian **************************************************/
574300016Sadrian
575300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
576300016Sadrianstatic void bwn_nphy_write_clip_detection(struct bwn_mac *mac,
577300016Sadrian					  const uint16_t *clip_st)
578300016Sadrian{
579300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_C1_CLIP1THRES, clip_st[0]);
580300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_C2_CLIP1THRES, clip_st[1]);
581300016Sadrian}
582300016Sadrian
583300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
584300016Sadrianstatic void bwn_nphy_read_clip_detection(struct bwn_mac *mac, uint16_t *clip_st)
585300016Sadrian{
586300016Sadrian	clip_st[0] = BWN_PHY_READ(mac, BWN_NPHY_C1_CLIP1THRES);
587300016Sadrian	clip_st[1] = BWN_PHY_READ(mac, BWN_NPHY_C2_CLIP1THRES);
588300016Sadrian}
589300016Sadrian
590300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */
591300016Sadrianstatic uint16_t bwn_nphy_classifier(struct bwn_mac *mac, uint16_t mask, uint16_t val)
592300016Sadrian{
593300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
594300016Sadrian	uint16_t tmp;
595300016Sadrian
596300016Sadrian	if (siba_get_revid(sc->sc_dev) == 16)
597300016Sadrian		bwn_mac_suspend(mac);
598300016Sadrian
599300016Sadrian	tmp = BWN_PHY_READ(mac, BWN_NPHY_CLASSCTL);
600300016Sadrian	tmp &= (BWN_NPHY_CLASSCTL_CCKEN | BWN_NPHY_CLASSCTL_OFDMEN |
601300016Sadrian		BWN_NPHY_CLASSCTL_WAITEDEN);
602300016Sadrian	tmp &= ~mask;
603300016Sadrian	tmp |= (val & mask);
604300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_CLASSCTL, 0xFFF8, tmp);
605300016Sadrian
606300016Sadrian	if (siba_get_revid(sc->sc_dev) == 16)
607300016Sadrian		bwn_mac_enable(mac);
608300016Sadrian
609300016Sadrian	return tmp;
610300016Sadrian}
611300016Sadrian
612300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
613300016Sadrianstatic void bwn_nphy_reset_cca(struct bwn_mac *mac)
614300016Sadrian{
615300016Sadrian	uint16_t bbcfg;
616300016Sadrian
617300016Sadrian	bwn_phy_force_clock(mac, 1);
618300016Sadrian	bbcfg = BWN_PHY_READ(mac, BWN_NPHY_BBCFG);
619300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BBCFG, bbcfg | BWN_NPHY_BBCFG_RSTCCA);
620300016Sadrian	DELAY(1);
621300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BBCFG, bbcfg & ~BWN_NPHY_BBCFG_RSTCCA);
622300016Sadrian	bwn_phy_force_clock(mac, 0);
623300016Sadrian	bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
624300016Sadrian}
625300016Sadrian
626300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */
627300016Sadrianstatic void bwn_nphy_stay_in_carrier_search(struct bwn_mac *mac, bool enable)
628300016Sadrian{
629300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
630300016Sadrian	struct bwn_phy_n *nphy = phy->phy_n;
631300016Sadrian
632300016Sadrian	if (enable) {
633300016Sadrian		static const uint16_t clip[] = { 0xFFFF, 0xFFFF };
634300016Sadrian		if (nphy->deaf_count++ == 0) {
635300016Sadrian			nphy->classifier_state = bwn_nphy_classifier(mac, 0, 0);
636300016Sadrian			bwn_nphy_classifier(mac, 0x7,
637300016Sadrian					    BWN_NPHY_CLASSCTL_WAITEDEN);
638300016Sadrian			bwn_nphy_read_clip_detection(mac, nphy->clip_state);
639300016Sadrian			bwn_nphy_write_clip_detection(mac, clip);
640300016Sadrian		}
641300016Sadrian		bwn_nphy_reset_cca(mac);
642300016Sadrian	} else {
643300016Sadrian		if (--nphy->deaf_count == 0) {
644300016Sadrian			bwn_nphy_classifier(mac, 0x7, nphy->classifier_state);
645300016Sadrian			bwn_nphy_write_clip_detection(mac, nphy->clip_state);
646300016Sadrian		}
647300016Sadrian	}
648300016Sadrian}
649300016Sadrian
650300016Sadrian/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */
651300016Sadrianstatic uint16_t bwn_nphy_read_lpf_ctl(struct bwn_mac *mac, uint16_t offset)
652300016Sadrian{
653300016Sadrian	if (!offset)
654300016Sadrian		offset = bwn_is_40mhz(mac) ? 0x159 : 0x154;
655300016Sadrian	return bwn_ntab_read(mac, BWN_NTAB16(7, offset)) & 0x7;
656300016Sadrian}
657300016Sadrian
658300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */
659300016Sadrianstatic void bwn_nphy_adjust_lna_gain_table(struct bwn_mac *mac)
660300016Sadrian{
661300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
662300016Sadrian
663300016Sadrian	uint8_t i;
664300016Sadrian	int16_t tmp;
665300016Sadrian	uint16_t data[4];
666300016Sadrian	int16_t gain[2];
667300016Sadrian	uint16_t minmax[2];
668300016Sadrian	static const uint16_t lna_gain[4] = { -2, 10, 19, 25 };
669300016Sadrian
670300016Sadrian	if (nphy->hang_avoid)
671300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 1);
672300016Sadrian
673300016Sadrian	if (nphy->gain_boost) {
674300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G) {
675300016Sadrian			gain[0] = 6;
676300016Sadrian			gain[1] = 6;
677300016Sadrian		} else {
678300016Sadrian			tmp = 40370 - 315 * bwn_get_chan(mac);
679300016Sadrian			gain[0] = ((tmp >> 13) + ((tmp >> 12) & 1));
680300016Sadrian			tmp = 23242 - 224 * bwn_get_chan(mac);
681300016Sadrian			gain[1] = ((tmp >> 13) + ((tmp >> 12) & 1));
682300016Sadrian		}
683300016Sadrian	} else {
684300016Sadrian		gain[0] = 0;
685300016Sadrian		gain[1] = 0;
686300016Sadrian	}
687300016Sadrian
688300016Sadrian	for (i = 0; i < 2; i++) {
689300016Sadrian		if (nphy->elna_gain_config) {
690300016Sadrian			data[0] = 19 + gain[i];
691300016Sadrian			data[1] = 25 + gain[i];
692300016Sadrian			data[2] = 25 + gain[i];
693300016Sadrian			data[3] = 25 + gain[i];
694300016Sadrian		} else {
695300016Sadrian			data[0] = lna_gain[0] + gain[i];
696300016Sadrian			data[1] = lna_gain[1] + gain[i];
697300016Sadrian			data[2] = lna_gain[2] + gain[i];
698300016Sadrian			data[3] = lna_gain[3] + gain[i];
699300016Sadrian		}
700300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(i, 8), 4, data);
701300016Sadrian
702300016Sadrian		minmax[i] = 23 + gain[i];
703300016Sadrian	}
704300016Sadrian
705300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_C1_MINMAX_GAIN, ~BWN_NPHY_C1_MINGAIN,
706300016Sadrian				minmax[0] << BWN_NPHY_C1_MINGAIN_SHIFT);
707300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_C2_MINMAX_GAIN, ~BWN_NPHY_C2_MINGAIN,
708300016Sadrian				minmax[1] << BWN_NPHY_C2_MINGAIN_SHIFT);
709300016Sadrian
710300016Sadrian	if (nphy->hang_avoid)
711300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 0);
712300016Sadrian}
713300016Sadrian
714300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */
715300016Sadrianstatic void bwn_nphy_set_rf_sequence(struct bwn_mac *mac, uint8_t cmd,
716300016Sadrian					uint8_t *events, uint8_t *delays, uint8_t length)
717300016Sadrian{
718300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
719300016Sadrian	uint8_t i;
720300016Sadrian	uint8_t end = (mac->mac_phy.rev >= 3) ? 0x1F : 0x0F;
721300016Sadrian	uint16_t offset1 = cmd << 4;
722300016Sadrian	uint16_t offset2 = offset1 + 0x80;
723300016Sadrian
724300016Sadrian	if (nphy->hang_avoid)
725300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, true);
726300016Sadrian
727300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(7, offset1), length, events);
728300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(7, offset2), length, delays);
729300016Sadrian
730300016Sadrian	for (i = length; i < 16; i++) {
731300016Sadrian		bwn_ntab_write(mac, BWN_NTAB8(7, offset1 + i), end);
732300016Sadrian		bwn_ntab_write(mac, BWN_NTAB8(7, offset2 + i), 1);
733300016Sadrian	}
734300016Sadrian
735300016Sadrian	if (nphy->hang_avoid)
736300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, false);
737300016Sadrian}
738300016Sadrian
739300016Sadrian/**************************************************
740300016Sadrian * Radio 0x2057
741300016Sadrian **************************************************/
742300016Sadrian
743300016Sadrianstatic void bwn_radio_2057_chantab_upload(struct bwn_mac *mac,
744300016Sadrian					  const struct bwn_nphy_chantabent_rev7 *e_r7,
745300016Sadrian					  const struct bwn_nphy_chantabent_rev7_2g *e_r7_2g)
746300016Sadrian{
747300016Sadrian	if (e_r7_2g) {
748300016Sadrian		BWN_RF_WRITE(mac, R2057_VCOCAL_COUNTVAL0, e_r7_2g->radio_vcocal_countval0);
749300016Sadrian		BWN_RF_WRITE(mac, R2057_VCOCAL_COUNTVAL1, e_r7_2g->radio_vcocal_countval1);
750300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_REFMASTER_SPAREXTALSIZE, e_r7_2g->radio_rfpll_refmaster_sparextalsize);
751300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, e_r7_2g->radio_rfpll_loopfilter_r1);
752300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, e_r7_2g->radio_rfpll_loopfilter_c2);
753300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, e_r7_2g->radio_rfpll_loopfilter_c1);
754300016Sadrian		BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, e_r7_2g->radio_cp_kpd_idac);
755300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_MMD0, e_r7_2g->radio_rfpll_mmd0);
756300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_MMD1, e_r7_2g->radio_rfpll_mmd1);
757300016Sadrian		BWN_RF_WRITE(mac, R2057_VCOBUF_TUNE, e_r7_2g->radio_vcobuf_tune);
758300016Sadrian		BWN_RF_WRITE(mac, R2057_LOGEN_MX2G_TUNE, e_r7_2g->radio_logen_mx2g_tune);
759300016Sadrian		BWN_RF_WRITE(mac, R2057_LOGEN_INDBUF2G_TUNE, e_r7_2g->radio_logen_indbuf2g_tune);
760300016Sadrian		BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, e_r7_2g->radio_txmix2g_tune_boost_pu_core0);
761300016Sadrian		BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE0, e_r7_2g->radio_pad2g_tune_pus_core0);
762300016Sadrian		BWN_RF_WRITE(mac, R2057_LNA2G_TUNE_CORE0, e_r7_2g->radio_lna2g_tune_core0);
763300016Sadrian		BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1, e_r7_2g->radio_txmix2g_tune_boost_pu_core1);
764300016Sadrian		BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE1, e_r7_2g->radio_pad2g_tune_pus_core1);
765300016Sadrian		BWN_RF_WRITE(mac, R2057_LNA2G_TUNE_CORE1, e_r7_2g->radio_lna2g_tune_core1);
766300016Sadrian
767300016Sadrian	} else {
768300016Sadrian		BWN_RF_WRITE(mac, R2057_VCOCAL_COUNTVAL0, e_r7->radio_vcocal_countval0);
769300016Sadrian		BWN_RF_WRITE(mac, R2057_VCOCAL_COUNTVAL1, e_r7->radio_vcocal_countval1);
770300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_REFMASTER_SPAREXTALSIZE, e_r7->radio_rfpll_refmaster_sparextalsize);
771300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, e_r7->radio_rfpll_loopfilter_r1);
772300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, e_r7->radio_rfpll_loopfilter_c2);
773300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, e_r7->radio_rfpll_loopfilter_c1);
774300016Sadrian		BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, e_r7->radio_cp_kpd_idac);
775300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_MMD0, e_r7->radio_rfpll_mmd0);
776300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_MMD1, e_r7->radio_rfpll_mmd1);
777300016Sadrian		BWN_RF_WRITE(mac, R2057_VCOBUF_TUNE, e_r7->radio_vcobuf_tune);
778300016Sadrian		BWN_RF_WRITE(mac, R2057_LOGEN_MX2G_TUNE, e_r7->radio_logen_mx2g_tune);
779300016Sadrian		BWN_RF_WRITE(mac, R2057_LOGEN_MX5G_TUNE, e_r7->radio_logen_mx5g_tune);
780300016Sadrian		BWN_RF_WRITE(mac, R2057_LOGEN_INDBUF2G_TUNE, e_r7->radio_logen_indbuf2g_tune);
781300016Sadrian		BWN_RF_WRITE(mac, R2057_LOGEN_INDBUF5G_TUNE, e_r7->radio_logen_indbuf5g_tune);
782300016Sadrian		BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, e_r7->radio_txmix2g_tune_boost_pu_core0);
783300016Sadrian		BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE0, e_r7->radio_pad2g_tune_pus_core0);
784300016Sadrian		BWN_RF_WRITE(mac, R2057_PGA_BOOST_TUNE_CORE0, e_r7->radio_pga_boost_tune_core0);
785300016Sadrian		BWN_RF_WRITE(mac, R2057_TXMIX5G_BOOST_TUNE_CORE0, e_r7->radio_txmix5g_boost_tune_core0);
786300016Sadrian		BWN_RF_WRITE(mac, R2057_PAD5G_TUNE_MISC_PUS_CORE0, e_r7->radio_pad5g_tune_misc_pus_core0);
787300016Sadrian		BWN_RF_WRITE(mac, R2057_LNA2G_TUNE_CORE0, e_r7->radio_lna2g_tune_core0);
788300016Sadrian		BWN_RF_WRITE(mac, R2057_LNA5G_TUNE_CORE0, e_r7->radio_lna5g_tune_core0);
789300016Sadrian		BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1, e_r7->radio_txmix2g_tune_boost_pu_core1);
790300016Sadrian		BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE1, e_r7->radio_pad2g_tune_pus_core1);
791300016Sadrian		BWN_RF_WRITE(mac, R2057_PGA_BOOST_TUNE_CORE1, e_r7->radio_pga_boost_tune_core1);
792300016Sadrian		BWN_RF_WRITE(mac, R2057_TXMIX5G_BOOST_TUNE_CORE1, e_r7->radio_txmix5g_boost_tune_core1);
793300016Sadrian		BWN_RF_WRITE(mac, R2057_PAD5G_TUNE_MISC_PUS_CORE1, e_r7->radio_pad5g_tune_misc_pus_core1);
794300016Sadrian		BWN_RF_WRITE(mac, R2057_LNA2G_TUNE_CORE1, e_r7->radio_lna2g_tune_core1);
795300016Sadrian		BWN_RF_WRITE(mac, R2057_LNA5G_TUNE_CORE1, e_r7->radio_lna5g_tune_core1);
796300016Sadrian	}
797300016Sadrian}
798300016Sadrian
799300016Sadrianstatic void bwn_radio_2057_setup(struct bwn_mac *mac,
800300016Sadrian				 const struct bwn_nphy_chantabent_rev7 *tabent_r7,
801300016Sadrian				 const struct bwn_nphy_chantabent_rev7_2g *tabent_r7_2g)
802300016Sadrian{
803300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
804300016Sadrian
805300016Sadrian	bwn_radio_2057_chantab_upload(mac, tabent_r7, tabent_r7_2g);
806300016Sadrian
807300016Sadrian	switch (phy->rf_rev) {
808300016Sadrian	case 0 ... 4:
809300016Sadrian	case 6:
810300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G) {
811300016Sadrian			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, 0x3f);
812300016Sadrian			BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, 0x3f);
813300016Sadrian			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, 0x8);
814300016Sadrian			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, 0x8);
815300016Sadrian		} else {
816300016Sadrian			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, 0x1f);
817300016Sadrian			BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, 0x3f);
818300016Sadrian			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, 0x8);
819300016Sadrian			BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, 0x8);
820300016Sadrian		}
821300016Sadrian		break;
822300016Sadrian	case 9: /* e.g. PHY rev 16 */
823300016Sadrian		BWN_RF_WRITE(mac, R2057_LOGEN_PTAT_RESETS, 0x20);
824300016Sadrian		BWN_RF_WRITE(mac, R2057_VCOBUF_IDACS, 0x18);
825300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_5G) {
826300016Sadrian			BWN_RF_WRITE(mac, R2057_LOGEN_PTAT_RESETS, 0x38);
827300016Sadrian			BWN_RF_WRITE(mac, R2057_VCOBUF_IDACS, 0x0f);
828300016Sadrian
829300016Sadrian			if (bwn_is_40mhz(mac)) {
830300016Sadrian				/* TODO */
831300016Sadrian			} else {
832300016Sadrian				BWN_RF_WRITE(mac,
833300016Sadrian						R2057_PAD_BIAS_FILTER_BWS_CORE0,
834300016Sadrian						0x3c);
835300016Sadrian				BWN_RF_WRITE(mac,
836300016Sadrian						R2057_PAD_BIAS_FILTER_BWS_CORE1,
837300016Sadrian						0x3c);
838300016Sadrian			}
839300016Sadrian		}
840300016Sadrian		break;
841300016Sadrian	case 14: /* 2 GHz only */
842300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_R1, 0x1b);
843300016Sadrian		BWN_RF_WRITE(mac, R2057_CP_KPD_IDAC, 0x3f);
844300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C1, 0x1f);
845300016Sadrian		BWN_RF_WRITE(mac, R2057_RFPLL_LOOPFILTER_C2, 0x1f);
846300016Sadrian		break;
847300016Sadrian	}
848300016Sadrian
849300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G) {
850300016Sadrian		uint16_t txmix2g_tune_boost_pu = 0;
851300016Sadrian		uint16_t pad2g_tune_pus = 0;
852300016Sadrian
853300016Sadrian		if (bwn_nphy_ipa(mac)) {
854300016Sadrian			switch (phy->rf_rev) {
855300016Sadrian			case 9:
856300016Sadrian				txmix2g_tune_boost_pu = 0x0041;
857300016Sadrian				/* TODO */
858300016Sadrian				break;
859300016Sadrian			case 14:
860300016Sadrian				txmix2g_tune_boost_pu = 0x21;
861300016Sadrian				pad2g_tune_pus = 0x23;
862300016Sadrian				break;
863300016Sadrian			}
864300016Sadrian		}
865300016Sadrian
866300016Sadrian		if (txmix2g_tune_boost_pu)
867300016Sadrian			BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0,
868300016Sadrian					txmix2g_tune_boost_pu);
869300016Sadrian		if (pad2g_tune_pus)
870300016Sadrian			BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE0,
871300016Sadrian					pad2g_tune_pus);
872300016Sadrian		if (txmix2g_tune_boost_pu)
873300016Sadrian			BWN_RF_WRITE(mac, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1,
874300016Sadrian					txmix2g_tune_boost_pu);
875300016Sadrian		if (pad2g_tune_pus)
876300016Sadrian			BWN_RF_WRITE(mac, R2057_PAD2G_TUNE_PUS_CORE1,
877300016Sadrian					pad2g_tune_pus);
878300016Sadrian	}
879300016Sadrian
880300016Sadrian	/* 50..100 */
881300016Sadrian	DELAY(100);
882300016Sadrian
883300016Sadrian	/* VCO calibration */
884300016Sadrian	BWN_RF_MASK(mac, R2057_RFPLL_MISC_EN, ~0x01);
885300016Sadrian	BWN_RF_MASK(mac, R2057_RFPLL_MISC_CAL_RESETN, ~0x04);
886300016Sadrian	BWN_RF_SET(mac, R2057_RFPLL_MISC_CAL_RESETN, 0x4);
887300016Sadrian	BWN_RF_SET(mac, R2057_RFPLL_MISC_EN, 0x01);
888300016Sadrian	/* 300..600 */
889300016Sadrian	DELAY(600);
890300016Sadrian}
891300016Sadrian
892300016Sadrian/* Calibrate resistors in LPF of PLL?
893300016Sadrian * http://bcm-v4.sipsolutions.net/PHY/radio205x_rcal
894300016Sadrian */
895300016Sadrianstatic uint8_t bwn_radio_2057_rcal(struct bwn_mac *mac)
896300016Sadrian{
897300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
898300016Sadrian	uint16_t saved_regs_phy[12];
899300016Sadrian	uint16_t saved_regs_phy_rf[6];
900300016Sadrian	uint16_t saved_regs_radio[2] = { };
901300016Sadrian	static const uint16_t phy_to_store[] = {
902300016Sadrian		BWN_NPHY_RFCTL_RSSIO1, BWN_NPHY_RFCTL_RSSIO2,
903300016Sadrian		BWN_NPHY_RFCTL_LUT_TRSW_LO1, BWN_NPHY_RFCTL_LUT_TRSW_LO2,
904300016Sadrian		BWN_NPHY_RFCTL_RXG1, BWN_NPHY_RFCTL_RXG2,
905300016Sadrian		BWN_NPHY_RFCTL_TXG1, BWN_NPHY_RFCTL_TXG2,
906300016Sadrian		BWN_NPHY_REV7_RF_CTL_MISC_REG3, BWN_NPHY_REV7_RF_CTL_MISC_REG4,
907300016Sadrian		BWN_NPHY_REV7_RF_CTL_MISC_REG5, BWN_NPHY_REV7_RF_CTL_MISC_REG6,
908300016Sadrian	};
909300016Sadrian	static const uint16_t phy_to_store_rf[] = {
910300016Sadrian		BWN_NPHY_REV3_RFCTL_OVER0, BWN_NPHY_REV3_RFCTL_OVER1,
911300016Sadrian		BWN_NPHY_REV7_RF_CTL_OVER3, BWN_NPHY_REV7_RF_CTL_OVER4,
912300016Sadrian		BWN_NPHY_REV7_RF_CTL_OVER5, BWN_NPHY_REV7_RF_CTL_OVER6,
913300016Sadrian	};
914300016Sadrian	uint16_t tmp;
915300016Sadrian	int i;
916300016Sadrian
917300016Sadrian	/* Save */
918300016Sadrian	for (i = 0; i < nitems(phy_to_store); i++)
919300016Sadrian		saved_regs_phy[i] = BWN_PHY_READ(mac, phy_to_store[i]);
920300016Sadrian	for (i = 0; i < nitems(phy_to_store_rf); i++)
921300016Sadrian		saved_regs_phy_rf[i] = BWN_PHY_READ(mac, phy_to_store_rf[i]);
922300016Sadrian
923300016Sadrian	/* Set */
924300016Sadrian	for (i = 0; i < nitems(phy_to_store); i++)
925300016Sadrian		BWN_PHY_WRITE(mac, phy_to_store[i], 0);
926300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_RFCTL_OVER0, 0x07ff);
927300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_RFCTL_OVER1, 0x07ff);
928300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER3, 0x07ff);
929300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER4, 0x07ff);
930300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER5, 0x007f);
931300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER6, 0x007f);
932300016Sadrian
933300016Sadrian	switch (phy->rf_rev) {
934300016Sadrian	case 5:
935300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_REV7_RF_CTL_OVER3, ~0x2);
936300016Sadrian		DELAY(10);
937300016Sadrian		BWN_RF_SET(mac, R2057_IQTEST_SEL_PU, 0x1);
938300016Sadrian		BWN_RF_SETMASK(mac, R2057v7_IQTEST_SEL_PU2, ~0x2, 0x1);
939300016Sadrian		break;
940300016Sadrian	case 9:
941300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_REV7_RF_CTL_OVER3, 0x2);
942300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_REV7_RF_CTL_MISC_REG3, 0x2);
943300016Sadrian		saved_regs_radio[0] = BWN_RF_READ(mac, R2057_IQTEST_SEL_PU);
944300016Sadrian		BWN_RF_WRITE(mac, R2057_IQTEST_SEL_PU, 0x11);
945300016Sadrian		break;
946300016Sadrian	case 14:
947300016Sadrian		saved_regs_radio[0] = BWN_RF_READ(mac, R2057_IQTEST_SEL_PU);
948300016Sadrian		saved_regs_radio[1] = BWN_RF_READ(mac, R2057v7_IQTEST_SEL_PU2);
949300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_REV7_RF_CTL_MISC_REG3, 0x2);
950300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_REV7_RF_CTL_OVER3, 0x2);
951300016Sadrian		BWN_RF_WRITE(mac, R2057v7_IQTEST_SEL_PU2, 0x2);
952300016Sadrian		BWN_RF_WRITE(mac, R2057_IQTEST_SEL_PU, 0x1);
953300016Sadrian		break;
954300016Sadrian	}
955300016Sadrian
956300016Sadrian	/* Enable */
957300016Sadrian	BWN_RF_SET(mac, R2057_RCAL_CONFIG, 0x1);
958300016Sadrian	DELAY(10);
959300016Sadrian
960300016Sadrian	/* Start */
961300016Sadrian	BWN_RF_SET(mac, R2057_RCAL_CONFIG, 0x2);
962300016Sadrian	/* 100..200 */
963300016Sadrian	DELAY(200);
964300016Sadrian
965300016Sadrian	/* Stop */
966300016Sadrian	BWN_RF_MASK(mac, R2057_RCAL_CONFIG, ~0x2);
967300016Sadrian
968300016Sadrian	/* Wait and check for result */
969300016Sadrian	if (!bwn_radio_wait_value(mac, R2057_RCAL_STATUS, 1, 1, 100, 1000000)) {
970300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "Radio 0x2057 rcal timeout\n");
971300016Sadrian		return 0;
972300016Sadrian	}
973300016Sadrian	tmp = BWN_RF_READ(mac, R2057_RCAL_STATUS) & 0x3E;
974300016Sadrian
975300016Sadrian	/* Disable */
976300016Sadrian	BWN_RF_MASK(mac, R2057_RCAL_CONFIG, ~0x1);
977300016Sadrian
978300016Sadrian	/* Restore */
979300016Sadrian	for (i = 0; i < nitems(phy_to_store_rf); i++)
980300016Sadrian		BWN_PHY_WRITE(mac, phy_to_store_rf[i], saved_regs_phy_rf[i]);
981300016Sadrian	for (i = 0; i < nitems(phy_to_store); i++)
982300016Sadrian		BWN_PHY_WRITE(mac, phy_to_store[i], saved_regs_phy[i]);
983300016Sadrian
984300016Sadrian	switch (phy->rf_rev) {
985300016Sadrian	case 0 ... 4:
986300016Sadrian	case 6:
987300016Sadrian		BWN_RF_SETMASK(mac, R2057_TEMPSENSE_CONFIG, ~0x3C, tmp);
988300016Sadrian		BWN_RF_SETMASK(mac, R2057_BANDGAP_RCAL_TRIM, ~0xF0,
989300016Sadrian				  tmp << 2);
990300016Sadrian		break;
991300016Sadrian	case 5:
992300016Sadrian		BWN_RF_MASK(mac, R2057_IPA2G_CASCONV_CORE0, ~0x1);
993300016Sadrian		BWN_RF_MASK(mac, R2057v7_IQTEST_SEL_PU2, ~0x2);
994300016Sadrian		break;
995300016Sadrian	case 9:
996300016Sadrian		BWN_RF_WRITE(mac, R2057_IQTEST_SEL_PU, saved_regs_radio[0]);
997300016Sadrian		break;
998300016Sadrian	case 14:
999300016Sadrian		BWN_RF_WRITE(mac, R2057_IQTEST_SEL_PU, saved_regs_radio[0]);
1000300016Sadrian		BWN_RF_WRITE(mac, R2057v7_IQTEST_SEL_PU2, saved_regs_radio[1]);
1001300016Sadrian		break;
1002300016Sadrian	}
1003300016Sadrian
1004300016Sadrian	return tmp & 0x3e;
1005300016Sadrian}
1006300016Sadrian
1007300016Sadrian/* Calibrate the internal RC oscillator?
1008300016Sadrian * http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal
1009300016Sadrian */
1010300016Sadrianstatic uint16_t bwn_radio_2057_rccal(struct bwn_mac *mac)
1011300016Sadrian{
1012300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1013300016Sadrian	bool special = (phy->rf_rev == 3 || phy->rf_rev == 4 ||
1014300016Sadrian			phy->rf_rev == 6);
1015300016Sadrian	uint16_t tmp;
1016300016Sadrian
1017300016Sadrian	/* Setup cal */
1018300016Sadrian	if (special) {
1019300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_MASTER, 0x61);
1020300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_TRC0, 0xC0);
1021300016Sadrian	} else {
1022300016Sadrian		BWN_RF_WRITE(mac, R2057v7_RCCAL_MASTER, 0x61);
1023300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_TRC0, 0xE9);
1024300016Sadrian	}
1025300016Sadrian	BWN_RF_WRITE(mac, R2057_RCCAL_X1, 0x6E);
1026300016Sadrian
1027300016Sadrian	/* Start, wait, stop */
1028300016Sadrian	BWN_RF_WRITE(mac, R2057_RCCAL_START_R1_Q1_P1, 0x55);
1029300016Sadrian	if (!bwn_radio_wait_value(mac, R2057_RCCAL_DONE_OSCCAP, 2, 2, 500,
1030300016Sadrian				  5000000))
1031300016Sadrian		BWN_DBGPRINTF(mac, "Radio 0x2057 rccal timeout\n");
1032300016Sadrian	/* 35..70 */
1033300016Sadrian	DELAY(70);
1034300016Sadrian	BWN_RF_WRITE(mac, R2057_RCCAL_START_R1_Q1_P1, 0x15);
1035300016Sadrian	/* 70..140 */
1036300016Sadrian	DELAY(140);
1037300016Sadrian
1038300016Sadrian	/* Setup cal */
1039300016Sadrian	if (special) {
1040300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_MASTER, 0x69);
1041300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_TRC0, 0xB0);
1042300016Sadrian	} else {
1043300016Sadrian		BWN_RF_WRITE(mac, R2057v7_RCCAL_MASTER, 0x69);
1044300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_TRC0, 0xD5);
1045300016Sadrian	}
1046300016Sadrian	BWN_RF_WRITE(mac, R2057_RCCAL_X1, 0x6E);
1047300016Sadrian
1048300016Sadrian	/* Start, wait, stop */
1049300016Sadrian	/* 35..70 */
1050300016Sadrian	DELAY(70);
1051300016Sadrian	BWN_RF_WRITE(mac, R2057_RCCAL_START_R1_Q1_P1, 0x55);
1052300016Sadrian	/* 70..140 */
1053300016Sadrian	DELAY(140);
1054300016Sadrian	if (!bwn_radio_wait_value(mac, R2057_RCCAL_DONE_OSCCAP, 2, 2, 500,
1055300016Sadrian				  5000000))
1056300016Sadrian		BWN_DBGPRINTF(mac, "Radio 0x2057 rccal timeout\n");
1057300016Sadrian	/* 35..70 */
1058300016Sadrian	DELAY(70);
1059300016Sadrian	BWN_RF_WRITE(mac, R2057_RCCAL_START_R1_Q1_P1, 0x15);
1060300016Sadrian	/* 70..140 */
1061300016Sadrian	DELAY(140);
1062300016Sadrian
1063300016Sadrian	/* Setup cal */
1064300016Sadrian	if (special) {
1065300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_MASTER, 0x73);
1066300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_X1, 0x28);
1067300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_TRC0, 0xB0);
1068300016Sadrian	} else {
1069300016Sadrian		BWN_RF_WRITE(mac, R2057v7_RCCAL_MASTER, 0x73);
1070300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_X1, 0x6E);
1071300016Sadrian		BWN_RF_WRITE(mac, R2057_RCCAL_TRC0, 0x99);
1072300016Sadrian	}
1073300016Sadrian
1074300016Sadrian	/* Start, wait, stop */
1075300016Sadrian	/* 35..70 */
1076300016Sadrian	DELAY(70);
1077300016Sadrian	BWN_RF_WRITE(mac, R2057_RCCAL_START_R1_Q1_P1, 0x55);
1078300016Sadrian	/* 70..140 */
1079300016Sadrian	DELAY(140);
1080300016Sadrian	if (!bwn_radio_wait_value(mac, R2057_RCCAL_DONE_OSCCAP, 2, 2, 500,
1081300016Sadrian				  5000000)) {
1082300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "Radio 0x2057 rcal timeout\n");
1083300016Sadrian		return 0;
1084300016Sadrian	}
1085300016Sadrian	tmp = BWN_RF_READ(mac, R2057_RCCAL_DONE_OSCCAP);
1086300016Sadrian	/* 35..70 */
1087300016Sadrian	DELAY(70);
1088300016Sadrian	BWN_RF_WRITE(mac, R2057_RCCAL_START_R1_Q1_P1, 0x15);
1089300016Sadrian	/* 70..140 */
1090300016Sadrian	DELAY(140);
1091300016Sadrian
1092300016Sadrian	if (special)
1093300016Sadrian		BWN_RF_MASK(mac, R2057_RCCAL_MASTER, ~0x1);
1094300016Sadrian	else
1095300016Sadrian		BWN_RF_MASK(mac, R2057v7_RCCAL_MASTER, ~0x1);
1096300016Sadrian
1097300016Sadrian	return tmp;
1098300016Sadrian}
1099300016Sadrian
1100300016Sadrianstatic void bwn_radio_2057_init_pre(struct bwn_mac *mac)
1101300016Sadrian{
1102300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_CMD, ~BWN_NPHY_RFCTL_CMD_CHIP0PU);
1103300016Sadrian	/* Maybe wl meant to reset and set (order?) RFCTL_CMD_OEPORFORCE? */
1104300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_CMD, BWN_NPHY_RFCTL_CMD_OEPORFORCE);
1105300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD, ~BWN_NPHY_RFCTL_CMD_OEPORFORCE);
1106300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD, BWN_NPHY_RFCTL_CMD_CHIP0PU);
1107300016Sadrian}
1108300016Sadrian
1109300016Sadrianstatic void bwn_radio_2057_init_post(struct bwn_mac *mac)
1110300016Sadrian{
1111300016Sadrian	BWN_RF_SET(mac, R2057_XTALPUOVR_PINCTRL, 0x1);
1112300016Sadrian
1113300016Sadrian	if (0) /* FIXME: Is this BCM43217 specific? */
1114300016Sadrian		BWN_RF_SET(mac, R2057_XTALPUOVR_PINCTRL, 0x2);
1115300016Sadrian
1116300016Sadrian	BWN_RF_SET(mac, R2057_RFPLL_MISC_CAL_RESETN, 0x78);
1117300016Sadrian	BWN_RF_SET(mac, R2057_XTAL_CONFIG2, 0x80);
1118300016Sadrian	DELAY(2000);
1119300016Sadrian	BWN_RF_MASK(mac, R2057_RFPLL_MISC_CAL_RESETN, ~0x78);
1120300016Sadrian	BWN_RF_MASK(mac, R2057_XTAL_CONFIG2, ~0x80);
1121300016Sadrian
1122300016Sadrian	if (mac->mac_phy.phy_do_full_init) {
1123300016Sadrian		bwn_radio_2057_rcal(mac);
1124300016Sadrian		bwn_radio_2057_rccal(mac);
1125300016Sadrian	}
1126300016Sadrian	BWN_RF_MASK(mac, R2057_RFPLL_MASTER, ~0x8);
1127300016Sadrian}
1128300016Sadrian
1129300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/Radio/2057/Init */
1130300016Sadrianstatic void bwn_radio_2057_init(struct bwn_mac *mac)
1131300016Sadrian{
1132300016Sadrian	bwn_radio_2057_init_pre(mac);
1133300016Sadrian	r2057_upload_inittabs(mac);
1134300016Sadrian	bwn_radio_2057_init_post(mac);
1135300016Sadrian}
1136300016Sadrian
1137300016Sadrian/**************************************************
1138300016Sadrian * Radio 0x2056
1139300016Sadrian **************************************************/
1140300016Sadrian
1141300016Sadrianstatic void bwn_chantab_radio_2056_upload(struct bwn_mac *mac,
1142300016Sadrian				const struct bwn_nphy_channeltab_entry_rev3 *e)
1143300016Sadrian{
1144300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_VCOCAL1, e->radio_syn_pll_vcocal1);
1145300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_VCOCAL2, e->radio_syn_pll_vcocal2);
1146300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_REFDIV, e->radio_syn_pll_refdiv);
1147300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_MMD2, e->radio_syn_pll_mmd2);
1148300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_MMD1, e->radio_syn_pll_mmd1);
1149300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER1,
1150300016Sadrian					e->radio_syn_pll_loopfilter1);
1151300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER2,
1152300016Sadrian					e->radio_syn_pll_loopfilter2);
1153300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER3,
1154300016Sadrian					e->radio_syn_pll_loopfilter3);
1155300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER4,
1156300016Sadrian					e->radio_syn_pll_loopfilter4);
1157300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER5,
1158300016Sadrian					e->radio_syn_pll_loopfilter5);
1159300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_RESERVED_ADDR27,
1160300016Sadrian					e->radio_syn_reserved_addr27);
1161300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_RESERVED_ADDR28,
1162300016Sadrian					e->radio_syn_reserved_addr28);
1163300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_RESERVED_ADDR29,
1164300016Sadrian					e->radio_syn_reserved_addr29);
1165300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_LOGEN_VCOBUF1,
1166300016Sadrian					e->radio_syn_logen_vcobuf1);
1167300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_LOGEN_MIXER2, e->radio_syn_logen_mixer2);
1168300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_LOGEN_BUF3, e->radio_syn_logen_buf3);
1169300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_LOGEN_BUF4, e->radio_syn_logen_buf4);
1170300016Sadrian
1171300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_LNAA_TUNE,
1172300016Sadrian					e->radio_rx0_lnaa_tune);
1173300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_LNAG_TUNE,
1174300016Sadrian					e->radio_rx0_lnag_tune);
1175300016Sadrian
1176300016Sadrian	BWN_RF_WRITE(mac, B2056_TX0 | B2056_TX_INTPAA_BOOST_TUNE,
1177300016Sadrian					e->radio_tx0_intpaa_boost_tune);
1178300016Sadrian	BWN_RF_WRITE(mac, B2056_TX0 | B2056_TX_INTPAG_BOOST_TUNE,
1179300016Sadrian					e->radio_tx0_intpag_boost_tune);
1180300016Sadrian	BWN_RF_WRITE(mac, B2056_TX0 | B2056_TX_PADA_BOOST_TUNE,
1181300016Sadrian					e->radio_tx0_pada_boost_tune);
1182300016Sadrian	BWN_RF_WRITE(mac, B2056_TX0 | B2056_TX_PADG_BOOST_TUNE,
1183300016Sadrian					e->radio_tx0_padg_boost_tune);
1184300016Sadrian	BWN_RF_WRITE(mac, B2056_TX0 | B2056_TX_PGAA_BOOST_TUNE,
1185300016Sadrian					e->radio_tx0_pgaa_boost_tune);
1186300016Sadrian	BWN_RF_WRITE(mac, B2056_TX0 | B2056_TX_PGAG_BOOST_TUNE,
1187300016Sadrian					e->radio_tx0_pgag_boost_tune);
1188300016Sadrian	BWN_RF_WRITE(mac, B2056_TX0 | B2056_TX_MIXA_BOOST_TUNE,
1189300016Sadrian					e->radio_tx0_mixa_boost_tune);
1190300016Sadrian	BWN_RF_WRITE(mac, B2056_TX0 | B2056_TX_MIXG_BOOST_TUNE,
1191300016Sadrian					e->radio_tx0_mixg_boost_tune);
1192300016Sadrian
1193300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_LNAA_TUNE,
1194300016Sadrian					e->radio_rx1_lnaa_tune);
1195300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_LNAG_TUNE,
1196300016Sadrian					e->radio_rx1_lnag_tune);
1197300016Sadrian
1198300016Sadrian	BWN_RF_WRITE(mac, B2056_TX1 | B2056_TX_INTPAA_BOOST_TUNE,
1199300016Sadrian					e->radio_tx1_intpaa_boost_tune);
1200300016Sadrian	BWN_RF_WRITE(mac, B2056_TX1 | B2056_TX_INTPAG_BOOST_TUNE,
1201300016Sadrian					e->radio_tx1_intpag_boost_tune);
1202300016Sadrian	BWN_RF_WRITE(mac, B2056_TX1 | B2056_TX_PADA_BOOST_TUNE,
1203300016Sadrian					e->radio_tx1_pada_boost_tune);
1204300016Sadrian	BWN_RF_WRITE(mac, B2056_TX1 | B2056_TX_PADG_BOOST_TUNE,
1205300016Sadrian					e->radio_tx1_padg_boost_tune);
1206300016Sadrian	BWN_RF_WRITE(mac, B2056_TX1 | B2056_TX_PGAA_BOOST_TUNE,
1207300016Sadrian					e->radio_tx1_pgaa_boost_tune);
1208300016Sadrian	BWN_RF_WRITE(mac, B2056_TX1 | B2056_TX_PGAG_BOOST_TUNE,
1209300016Sadrian					e->radio_tx1_pgag_boost_tune);
1210300016Sadrian	BWN_RF_WRITE(mac, B2056_TX1 | B2056_TX_MIXA_BOOST_TUNE,
1211300016Sadrian					e->radio_tx1_mixa_boost_tune);
1212300016Sadrian	BWN_RF_WRITE(mac, B2056_TX1 | B2056_TX_MIXG_BOOST_TUNE,
1213300016Sadrian					e->radio_tx1_mixg_boost_tune);
1214300016Sadrian}
1215300016Sadrian
1216300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2056Setup */
1217300016Sadrianstatic void bwn_radio_2056_setup(struct bwn_mac *mac,
1218300016Sadrian				const struct bwn_nphy_channeltab_entry_rev3 *e)
1219300016Sadrian{
1220300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
1221300016Sadrian	bwn_band_t band = bwn_current_band(mac);
1222300016Sadrian	uint16_t offset;
1223300016Sadrian	uint8_t i;
1224300016Sadrian	uint16_t bias, cbias;
1225300016Sadrian	uint16_t pag_boost, padg_boost, pgag_boost, mixg_boost;
1226300016Sadrian	uint16_t paa_boost, pada_boost, pgaa_boost, mixa_boost;
1227300016Sadrian	bool is_pkg_fab_smic;
1228300016Sadrian
1229300016Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RF, "%s: called\n", __func__);
1230300016Sadrian
1231300016Sadrian	if (mac->mac_phy.rev < 3) {
1232300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: phy rev %d out of range\n",
1233300016Sadrian		    __func__,
1234300016Sadrian		    mac->mac_phy.rev);
1235300016Sadrian	}
1236300016Sadrian
1237300016Sadrian	is_pkg_fab_smic =
1238300016Sadrian		((siba_get_chipid(sc->sc_dev) == BCMA_CHIP_ID_BCM43224 ||
1239300016Sadrian		  siba_get_chipid(sc->sc_dev) == BCMA_CHIP_ID_BCM43225 ||
1240300016Sadrian		  siba_get_chipid(sc->sc_dev) == BCMA_CHIP_ID_BCM43421) &&
1241300016Sadrian		 siba_get_chippkg(sc->sc_dev) == BCMA_PKG_ID_BCM43224_FAB_SMIC);
1242300016Sadrian
1243300016Sadrian	bwn_chantab_radio_2056_upload(mac, e);
1244300016Sadrian	b2056_upload_syn_pll_cp2(mac, band == BWN_BAND_5G);
1245300016Sadrian
1246300016Sadrian	if (siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_GPLL_WAR &&
1247300016Sadrian	    bwn_current_band(mac) == BWN_BAND_2G) {
1248300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER1, 0x1F);
1249300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER2, 0x1F);
1250300016Sadrian		if (siba_get_chipid(sc->sc_dev) == BCMA_CHIP_ID_BCM4716 ||
1251300016Sadrian		    siba_get_chipid(sc->sc_dev) == BCMA_CHIP_ID_BCM47162) {
1252300016Sadrian			BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER4, 0x14);
1253300016Sadrian			BWN_RF_WRITE(mac, B2056_SYN_PLL_CP2, 0);
1254300016Sadrian		} else {
1255300016Sadrian			BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER4, 0x0B);
1256300016Sadrian			BWN_RF_WRITE(mac, B2056_SYN_PLL_CP2, 0x14);
1257300016Sadrian		}
1258300016Sadrian	}
1259300016Sadrian	if (siba_sprom_get_bf2_hi(sc->sc_dev) & BWN_BFH2_GPLL_WAR2 &&
1260300016Sadrian	    bwn_current_band(mac) == BWN_BAND_2G) {
1261300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER1, 0x1f);
1262300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER2, 0x1f);
1263300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER4, 0x0b);
1264300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_CP2, 0x20);
1265300016Sadrian	}
1266300016Sadrian	if (siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_APLL_WAR &&
1267300016Sadrian	    bwn_current_band(mac) == BWN_BAND_5G) {
1268300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER1, 0x1F);
1269300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER2, 0x1F);
1270300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_LOOPFILTER4, 0x05);
1271300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_PLL_CP2, 0x0C);
1272300016Sadrian	}
1273300016Sadrian
1274300016Sadrian	if (mac->mac_phy.phy_n->ipa2g_on && band == BWN_BAND_2G) {
1275300016Sadrian		for (i = 0; i < 2; i++) {
1276300016Sadrian			offset = i ? B2056_TX1 : B2056_TX0;
1277300016Sadrian			if (mac->mac_phy.rev >= 5) {
1278300016Sadrian				BWN_RF_WRITE(mac,
1279300016Sadrian					offset | B2056_TX_PADG_IDAC, 0xcc);
1280300016Sadrian
1281300016Sadrian				if (siba_get_chipid(sc->sc_dev) == BCMA_CHIP_ID_BCM4716 ||
1282300016Sadrian				    siba_get_chipid(sc->sc_dev) == BCMA_CHIP_ID_BCM47162) {
1283300016Sadrian					bias = 0x40;
1284300016Sadrian					cbias = 0x45;
1285300016Sadrian					pag_boost = 0x5;
1286300016Sadrian					pgag_boost = 0x33;
1287300016Sadrian					mixg_boost = 0x55;
1288300016Sadrian				} else {
1289300016Sadrian					bias = 0x25;
1290300016Sadrian					cbias = 0x20;
1291300016Sadrian					if (is_pkg_fab_smic) {
1292300016Sadrian						bias = 0x2a;
1293300016Sadrian						cbias = 0x38;
1294300016Sadrian					}
1295300016Sadrian					pag_boost = 0x4;
1296300016Sadrian					pgag_boost = 0x03;
1297300016Sadrian					mixg_boost = 0x65;
1298300016Sadrian				}
1299300016Sadrian				padg_boost = 0x77;
1300300016Sadrian
1301300016Sadrian				BWN_RF_WRITE(mac,
1302300016Sadrian					offset | B2056_TX_INTPAG_IMAIN_STAT,
1303300016Sadrian					bias);
1304300016Sadrian				BWN_RF_WRITE(mac,
1305300016Sadrian					offset | B2056_TX_INTPAG_IAUX_STAT,
1306300016Sadrian					bias);
1307300016Sadrian				BWN_RF_WRITE(mac,
1308300016Sadrian					offset | B2056_TX_INTPAG_CASCBIAS,
1309300016Sadrian					cbias);
1310300016Sadrian				BWN_RF_WRITE(mac,
1311300016Sadrian					offset | B2056_TX_INTPAG_BOOST_TUNE,
1312300016Sadrian					pag_boost);
1313300016Sadrian				BWN_RF_WRITE(mac,
1314300016Sadrian					offset | B2056_TX_PGAG_BOOST_TUNE,
1315300016Sadrian					pgag_boost);
1316300016Sadrian				BWN_RF_WRITE(mac,
1317300016Sadrian					offset | B2056_TX_PADG_BOOST_TUNE,
1318300016Sadrian					padg_boost);
1319300016Sadrian				BWN_RF_WRITE(mac,
1320300016Sadrian					offset | B2056_TX_MIXG_BOOST_TUNE,
1321300016Sadrian					mixg_boost);
1322300016Sadrian			} else {
1323300016Sadrian				bias = bwn_is_40mhz(mac) ? 0x40 : 0x20;
1324300016Sadrian				BWN_RF_WRITE(mac,
1325300016Sadrian					offset | B2056_TX_INTPAG_IMAIN_STAT,
1326300016Sadrian					bias);
1327300016Sadrian				BWN_RF_WRITE(mac,
1328300016Sadrian					offset | B2056_TX_INTPAG_IAUX_STAT,
1329300016Sadrian					bias);
1330300016Sadrian				BWN_RF_WRITE(mac,
1331300016Sadrian					offset | B2056_TX_INTPAG_CASCBIAS,
1332300016Sadrian					0x30);
1333300016Sadrian			}
1334300016Sadrian			BWN_RF_WRITE(mac, offset | B2056_TX_PA_SPARE1, 0xee);
1335300016Sadrian		}
1336300016Sadrian	} else if (mac->mac_phy.phy_n->ipa5g_on && band == BWN_BAND_5G) {
1337300016Sadrian		uint16_t freq = bwn_get_centre_freq(mac);
1338300016Sadrian		/* XXX 5g low/med/high? */
1339300016Sadrian		if (freq < 5100) {
1340300016Sadrian			paa_boost = 0xA;
1341300016Sadrian			pada_boost = 0x77;
1342300016Sadrian			pgaa_boost = 0xF;
1343300016Sadrian			mixa_boost = 0xF;
1344300016Sadrian		} else if (freq < 5340) {
1345300016Sadrian			paa_boost = 0x8;
1346300016Sadrian			pada_boost = 0x77;
1347300016Sadrian			pgaa_boost = 0xFB;
1348300016Sadrian			mixa_boost = 0xF;
1349300016Sadrian		} else if (freq < 5650) {
1350300016Sadrian			paa_boost = 0x0;
1351300016Sadrian			pada_boost = 0x77;
1352300016Sadrian			pgaa_boost = 0xB;
1353300016Sadrian			mixa_boost = 0xF;
1354300016Sadrian		} else {
1355300016Sadrian			paa_boost = 0x0;
1356300016Sadrian			pada_boost = 0x77;
1357300016Sadrian			if (freq != 5825)
1358300016Sadrian				pgaa_boost = -(freq - 18) / 36 + 168;
1359300016Sadrian			else
1360300016Sadrian				pgaa_boost = 6;
1361300016Sadrian			mixa_boost = 0xF;
1362300016Sadrian		}
1363300016Sadrian
1364300016Sadrian		cbias = is_pkg_fab_smic ? 0x35 : 0x30;
1365300016Sadrian
1366300016Sadrian		for (i = 0; i < 2; i++) {
1367300016Sadrian			offset = i ? B2056_TX1 : B2056_TX0;
1368300016Sadrian
1369300016Sadrian			BWN_RF_WRITE(mac,
1370300016Sadrian				offset | B2056_TX_INTPAA_BOOST_TUNE, paa_boost);
1371300016Sadrian			BWN_RF_WRITE(mac,
1372300016Sadrian				offset | B2056_TX_PADA_BOOST_TUNE, pada_boost);
1373300016Sadrian			BWN_RF_WRITE(mac,
1374300016Sadrian				offset | B2056_TX_PGAA_BOOST_TUNE, pgaa_boost);
1375300016Sadrian			BWN_RF_WRITE(mac,
1376300016Sadrian				offset | B2056_TX_MIXA_BOOST_TUNE, mixa_boost);
1377300016Sadrian			BWN_RF_WRITE(mac,
1378300016Sadrian				offset | B2056_TX_TXSPARE1, 0x30);
1379300016Sadrian			BWN_RF_WRITE(mac,
1380300016Sadrian				offset | B2056_TX_PA_SPARE2, 0xee);
1381300016Sadrian			BWN_RF_WRITE(mac,
1382300016Sadrian				offset | B2056_TX_PADA_CASCBIAS, 0x03);
1383300016Sadrian			BWN_RF_WRITE(mac,
1384300016Sadrian				offset | B2056_TX_INTPAA_IAUX_STAT, 0x30);
1385300016Sadrian			BWN_RF_WRITE(mac,
1386300016Sadrian				offset | B2056_TX_INTPAA_IMAIN_STAT, 0x30);
1387300016Sadrian			BWN_RF_WRITE(mac,
1388300016Sadrian				offset | B2056_TX_INTPAA_CASCBIAS, cbias);
1389300016Sadrian		}
1390300016Sadrian	}
1391300016Sadrian
1392300016Sadrian	DELAY(50);
1393300016Sadrian	/* VCO calibration */
1394300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_VCOCAL12, 0x00);
1395300016Sadrian	BWN_RF_WRITE(mac, B2056_TX_INTPAA_PA_MISC, 0x38);
1396300016Sadrian	BWN_RF_WRITE(mac, B2056_TX_INTPAA_PA_MISC, 0x18);
1397300016Sadrian	BWN_RF_WRITE(mac, B2056_TX_INTPAA_PA_MISC, 0x38);
1398300016Sadrian	BWN_RF_WRITE(mac, B2056_TX_INTPAA_PA_MISC, 0x39);
1399300016Sadrian	DELAY(300);
1400300016Sadrian}
1401300016Sadrian
1402300016Sadrianstatic uint8_t bwn_radio_2056_rcal(struct bwn_mac *mac)
1403300016Sadrian{
1404300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1405300016Sadrian	uint16_t mast2, tmp;
1406300016Sadrian
1407300016Sadrian	if (phy->rev != 3)
1408300016Sadrian		return 0;
1409300016Sadrian
1410300016Sadrian	mast2 = BWN_RF_READ(mac, B2056_SYN_PLL_MAST2);
1411300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_MAST2, mast2 | 0x7);
1412300016Sadrian
1413300016Sadrian	DELAY(10);
1414300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_RCAL_MASTER, 0x01);
1415300016Sadrian	DELAY(10);
1416300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_RCAL_MASTER, 0x09);
1417300016Sadrian
1418300016Sadrian	if (!bwn_radio_wait_value(mac, B2056_SYN_RCAL_CODE_OUT, 0x80, 0x80, 100,
1419300016Sadrian				  1000000)) {
1420300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "Radio recalibration timeout\n");
1421300016Sadrian		return 0;
1422300016Sadrian	}
1423300016Sadrian
1424300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_RCAL_MASTER, 0x01);
1425300016Sadrian	tmp = BWN_RF_READ(mac, B2056_SYN_RCAL_CODE_OUT);
1426300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_RCAL_MASTER, 0x00);
1427300016Sadrian
1428300016Sadrian	BWN_RF_WRITE(mac, B2056_SYN_PLL_MAST2, mast2);
1429300016Sadrian
1430300016Sadrian	return tmp & 0x1f;
1431300016Sadrian}
1432300016Sadrian
1433300016Sadrianstatic void bwn_radio_init2056_pre(struct bwn_mac *mac)
1434300016Sadrian{
1435300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_CMD,
1436300016Sadrian		     ~BWN_NPHY_RFCTL_CMD_CHIP0PU);
1437300016Sadrian	/* Maybe wl meant to reset and set (order?) RFCTL_CMD_OEPORFORCE? */
1438300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_CMD,
1439300016Sadrian		     BWN_NPHY_RFCTL_CMD_OEPORFORCE);
1440300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
1441300016Sadrian		    ~BWN_NPHY_RFCTL_CMD_OEPORFORCE);
1442300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
1443300016Sadrian		    BWN_NPHY_RFCTL_CMD_CHIP0PU);
1444300016Sadrian}
1445300016Sadrian
1446300016Sadrianstatic void bwn_radio_init2056_post(struct bwn_mac *mac)
1447300016Sadrian{
1448300016Sadrian	BWN_RF_SET(mac, B2056_SYN_COM_CTRL, 0xB);
1449300016Sadrian	BWN_RF_SET(mac, B2056_SYN_COM_PU, 0x2);
1450300016Sadrian	BWN_RF_SET(mac, B2056_SYN_COM_RESET, 0x2);
1451300016Sadrian	DELAY(1000);
1452300016Sadrian	BWN_RF_MASK(mac, B2056_SYN_COM_RESET, ~0x2);
1453300016Sadrian	BWN_RF_MASK(mac, B2056_SYN_PLL_MAST2, ~0xFC);
1454300016Sadrian	BWN_RF_MASK(mac, B2056_SYN_RCCAL_CTRL0, ~0x1);
1455300016Sadrian	if (mac->mac_phy.phy_do_full_init)
1456300016Sadrian		bwn_radio_2056_rcal(mac);
1457300016Sadrian}
1458300016Sadrian
1459300016Sadrian/*
1460300016Sadrian * Initialize a Broadcom 2056 N-radio
1461300016Sadrian * http://bcm-v4.sipsolutions.net/802.11/Radio/2056/Init
1462300016Sadrian */
1463300016Sadrianstatic void bwn_radio_init2056(struct bwn_mac *mac)
1464300016Sadrian{
1465300016Sadrian	bwn_radio_init2056_pre(mac);
1466300016Sadrian	b2056_upload_inittabs(mac, 0, 0);
1467300016Sadrian	bwn_radio_init2056_post(mac);
1468300016Sadrian}
1469300016Sadrian
1470300016Sadrian/**************************************************
1471300016Sadrian * Radio 0x2055
1472300016Sadrian **************************************************/
1473300016Sadrian
1474300016Sadrianstatic void bwn_chantab_radio_upload(struct bwn_mac *mac,
1475300016Sadrian				const struct bwn_nphy_channeltab_entry_rev2 *e)
1476300016Sadrian{
1477300016Sadrian	BWN_RF_WRITE(mac, B2055_PLL_REF, e->radio_pll_ref);
1478300016Sadrian	BWN_RF_WRITE(mac, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
1479300016Sadrian	BWN_RF_WRITE(mac, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
1480300016Sadrian	BWN_RF_WRITE(mac, B2055_VCO_CAPTAIL, e->radio_vco_captail);
1481300016Sadrian	BWN_READ_4(mac, BWN_MACCTL); /* flush writes */
1482300016Sadrian
1483300016Sadrian	BWN_RF_WRITE(mac, B2055_VCO_CAL1, e->radio_vco_cal1);
1484300016Sadrian	BWN_RF_WRITE(mac, B2055_VCO_CAL2, e->radio_vco_cal2);
1485300016Sadrian	BWN_RF_WRITE(mac, B2055_PLL_LFC1, e->radio_pll_lfc1);
1486300016Sadrian	BWN_RF_WRITE(mac, B2055_PLL_LFR1, e->radio_pll_lfr1);
1487300016Sadrian	BWN_READ_4(mac, BWN_MACCTL); /* flush writes */
1488300016Sadrian
1489300016Sadrian	BWN_RF_WRITE(mac, B2055_PLL_LFC2, e->radio_pll_lfc2);
1490300016Sadrian	BWN_RF_WRITE(mac, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
1491300016Sadrian	BWN_RF_WRITE(mac, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
1492300016Sadrian	BWN_RF_WRITE(mac, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
1493300016Sadrian	BWN_READ_4(mac, BWN_MACCTL); /* flush writes */
1494300016Sadrian
1495300016Sadrian	BWN_RF_WRITE(mac, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
1496300016Sadrian	BWN_RF_WRITE(mac, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
1497300016Sadrian	BWN_RF_WRITE(mac, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
1498300016Sadrian	BWN_RF_WRITE(mac, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
1499300016Sadrian	BWN_READ_4(mac, BWN_MACCTL); /* flush writes */
1500300016Sadrian
1501300016Sadrian	BWN_RF_WRITE(mac, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
1502300016Sadrian	BWN_RF_WRITE(mac, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
1503300016Sadrian	BWN_RF_WRITE(mac, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
1504300016Sadrian	BWN_RF_WRITE(mac, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
1505300016Sadrian	BWN_READ_4(mac, BWN_MACCTL); /* flush writes */
1506300016Sadrian
1507300016Sadrian	BWN_RF_WRITE(mac, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
1508300016Sadrian	BWN_RF_WRITE(mac, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
1509300016Sadrian}
1510300016Sadrian
1511300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */
1512300016Sadrianstatic void bwn_radio_2055_setup(struct bwn_mac *mac,
1513300016Sadrian				const struct bwn_nphy_channeltab_entry_rev2 *e)
1514300016Sadrian{
1515300016Sadrian
1516300016Sadrian	if (mac->mac_phy.rev >= 3) {
1517300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: phy rev %d out of range\n",
1518300016Sadrian		    __func__,
1519300016Sadrian		    mac->mac_phy.rev);
1520300016Sadrian	}
1521300016Sadrian
1522300016Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_RF, "%s: called\n", __func__);
1523300016Sadrian
1524300016Sadrian	bwn_chantab_radio_upload(mac, e);
1525300016Sadrian	DELAY(50);
1526300016Sadrian	BWN_RF_WRITE(mac, B2055_VCO_CAL10, 0x05);
1527300016Sadrian	BWN_RF_WRITE(mac, B2055_VCO_CAL10, 0x45);
1528300016Sadrian	BWN_READ_4(mac, BWN_MACCTL); /* flush writes */
1529300016Sadrian	BWN_RF_WRITE(mac, B2055_VCO_CAL10, 0x65);
1530300016Sadrian	DELAY(300);
1531300016Sadrian}
1532300016Sadrian
1533300016Sadrianstatic void bwn_radio_init2055_pre(struct bwn_mac *mac)
1534300016Sadrian{
1535300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_CMD,
1536300016Sadrian		     ~BWN_NPHY_RFCTL_CMD_PORFORCE);
1537300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
1538300016Sadrian		    BWN_NPHY_RFCTL_CMD_CHIP0PU |
1539300016Sadrian		    BWN_NPHY_RFCTL_CMD_OEPORFORCE);
1540300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
1541300016Sadrian		    BWN_NPHY_RFCTL_CMD_PORFORCE);
1542300016Sadrian}
1543300016Sadrian
1544300016Sadrianstatic void bwn_radio_init2055_post(struct bwn_mac *mac)
1545300016Sadrian{
1546300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
1547300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
1548300016Sadrian	bool workaround = false;
1549300016Sadrian
1550300016Sadrian	if (siba_get_revid(sc->sc_dev) < 4)
1551300016Sadrian		workaround =
1552300016Sadrian		    (siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM)
1553300016Sadrian		    && (siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BCM4321)
1554300016Sadrian		      && (siba_sprom_get_brev(sc->sc_dev) >= 0x41);
1555300016Sadrian	else
1556300016Sadrian		workaround =
1557300016Sadrian			!(siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_RXBB_INT_REG_DIS);
1558300016Sadrian
1559300016Sadrian	BWN_RF_MASK(mac, B2055_MASTER1, 0xFFF3);
1560300016Sadrian	if (workaround) {
1561300016Sadrian		BWN_RF_MASK(mac, B2055_C1_RX_BB_REG, 0x7F);
1562300016Sadrian		BWN_RF_MASK(mac, B2055_C2_RX_BB_REG, 0x7F);
1563300016Sadrian	}
1564300016Sadrian	BWN_RF_SETMASK(mac, B2055_RRCCAL_NOPTSEL, 0xFFC0, 0x2C);
1565300016Sadrian	BWN_RF_WRITE(mac, B2055_CAL_MISC, 0x3C);
1566300016Sadrian	BWN_RF_MASK(mac, B2055_CAL_MISC, 0xFFBE);
1567300016Sadrian	BWN_RF_SET(mac, B2055_CAL_LPOCTL, 0x80);
1568300016Sadrian	BWN_RF_SET(mac, B2055_CAL_MISC, 0x1);
1569300016Sadrian	DELAY(1000);
1570300016Sadrian	BWN_RF_SET(mac, B2055_CAL_MISC, 0x40);
1571300016Sadrian	if (!bwn_radio_wait_value(mac, B2055_CAL_COUT2, 0x80, 0x80, 10, 2000))
1572300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "radio post init timeout\n");
1573300016Sadrian	BWN_RF_MASK(mac, B2055_CAL_LPOCTL, 0xFF7F);
1574300016Sadrian	bwn_switch_channel(mac, bwn_get_chan(mac));
1575300016Sadrian	BWN_RF_WRITE(mac, B2055_C1_RX_BB_LPF, 0x9);
1576300016Sadrian	BWN_RF_WRITE(mac, B2055_C2_RX_BB_LPF, 0x9);
1577300016Sadrian	BWN_RF_WRITE(mac, B2055_C1_RX_BB_MIDACHP, 0x83);
1578300016Sadrian	BWN_RF_WRITE(mac, B2055_C2_RX_BB_MIDACHP, 0x83);
1579300016Sadrian	BWN_RF_SETMASK(mac, B2055_C1_LNA_GAINBST, 0xFFF8, 0x6);
1580300016Sadrian	BWN_RF_SETMASK(mac, B2055_C2_LNA_GAINBST, 0xFFF8, 0x6);
1581300016Sadrian	if (!nphy->gain_boost) {
1582300016Sadrian		BWN_RF_SET(mac, B2055_C1_RX_RFSPC1, 0x2);
1583300016Sadrian		BWN_RF_SET(mac, B2055_C2_RX_RFSPC1, 0x2);
1584300016Sadrian	} else {
1585300016Sadrian		BWN_RF_MASK(mac, B2055_C1_RX_RFSPC1, 0xFFFD);
1586300016Sadrian		BWN_RF_MASK(mac, B2055_C2_RX_RFSPC1, 0xFFFD);
1587300016Sadrian	}
1588300016Sadrian	DELAY(2);
1589300016Sadrian}
1590300016Sadrian
1591300016Sadrian/*
1592300016Sadrian * Initialize a Broadcom 2055 N-radio
1593300016Sadrian * http://bcm-v4.sipsolutions.net/802.11/Radio/2055/Init
1594300016Sadrian */
1595300016Sadrianstatic void bwn_radio_init2055(struct bwn_mac *mac)
1596300016Sadrian{
1597300016Sadrian	bwn_radio_init2055_pre(mac);
1598300016Sadrian	if (mac->mac_status < BWN_MAC_STATUS_INITED) {
1599300016Sadrian		/* Follow wl, not specs. Do not force uploading all regs */
1600300016Sadrian		b2055_upload_inittab(mac, 0, 0);
1601300016Sadrian	} else {
1602300016Sadrian		bool ghz5 = bwn_current_band(mac) == BWN_BAND_5G;
1603300016Sadrian		b2055_upload_inittab(mac, ghz5, 0);
1604300016Sadrian	}
1605300016Sadrian	bwn_radio_init2055_post(mac);
1606300016Sadrian}
1607300016Sadrian
1608300016Sadrian/**************************************************
1609300016Sadrian * Samples
1610300016Sadrian **************************************************/
1611300016Sadrian
1612300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */
1613300016Sadrianstatic int bwn_nphy_load_samples(struct bwn_mac *mac,
1614300016Sadrian					struct bwn_c32 *samples, uint16_t len) {
1615300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
1616300016Sadrian	uint16_t i;
1617300016Sadrian	uint32_t *data;
1618300016Sadrian
1619300016Sadrian	data = malloc(len * sizeof(uint32_t), M_DEVBUF, M_NOWAIT | M_ZERO);
1620300016Sadrian	if (!data) {
1621300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "allocation for samples loading failed\n");
1622300016Sadrian		return -ENOMEM;
1623300016Sadrian	}
1624300016Sadrian	if (nphy->hang_avoid)
1625300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 1);
1626300016Sadrian
1627300016Sadrian	for (i = 0; i < len; i++) {
1628300016Sadrian		data[i] = (samples[i].i & 0x3FF << 10);
1629300016Sadrian		data[i] |= samples[i].q & 0x3FF;
1630300016Sadrian	}
1631300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB32(17, 0), len, data);
1632300016Sadrian
1633300016Sadrian	free(data, M_DEVBUF);
1634300016Sadrian	if (nphy->hang_avoid)
1635300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 0);
1636300016Sadrian	return 0;
1637300016Sadrian}
1638300016Sadrian
1639300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */
1640300016Sadrianstatic uint16_t bwn_nphy_gen_load_samples(struct bwn_mac *mac, uint32_t freq, uint16_t max,
1641300016Sadrian					bool test)
1642300016Sadrian{
1643300016Sadrian	int i;
1644300016Sadrian	uint16_t bw, len, rot, angle;
1645300016Sadrian	struct bwn_c32 *samples;
1646300016Sadrian
1647300016Sadrian	bw = bwn_is_40mhz(mac) ? 40 : 20;
1648300016Sadrian	len = bw << 3;
1649300016Sadrian
1650300016Sadrian	if (test) {
1651300016Sadrian		if (BWN_PHY_READ(mac, BWN_NPHY_BBCFG) & BWN_NPHY_BBCFG_RSTRX)
1652300016Sadrian			bw = 82;
1653300016Sadrian		else
1654300016Sadrian			bw = 80;
1655300016Sadrian
1656300016Sadrian		if (bwn_is_40mhz(mac))
1657300016Sadrian			bw <<= 1;
1658300016Sadrian
1659300016Sadrian		len = bw << 1;
1660300016Sadrian	}
1661300016Sadrian
1662300016Sadrian	samples = malloc(len * sizeof(struct bwn_c32), M_DEVBUF, M_NOWAIT | M_ZERO);
1663300016Sadrian	if (!samples) {
1664300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "allocation for samples generation failed\n");
1665300016Sadrian		return 0;
1666300016Sadrian	}
1667300016Sadrian	rot = (((freq * 36) / bw) << 16) / 100;
1668300016Sadrian	angle = 0;
1669300016Sadrian
1670300016Sadrian	for (i = 0; i < len; i++) {
1671300016Sadrian		samples[i] = bwn_cordic(angle);
1672300016Sadrian		angle += rot;
1673300016Sadrian		samples[i].q = CORDIC_CONVERT(samples[i].q * max);
1674300016Sadrian		samples[i].i = CORDIC_CONVERT(samples[i].i * max);
1675300016Sadrian	}
1676300016Sadrian
1677300016Sadrian	i = bwn_nphy_load_samples(mac, samples, len);
1678300016Sadrian	free(samples, M_DEVBUF);
1679300016Sadrian	return (i < 0) ? 0 : len;
1680300016Sadrian}
1681300016Sadrian
1682300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */
1683300016Sadrianstatic void bwn_nphy_run_samples(struct bwn_mac *mac, uint16_t samps, uint16_t loops,
1684300016Sadrian				 uint16_t wait, bool iqmode, bool dac_test,
1685300016Sadrian				 bool modify_bbmult)
1686300016Sadrian{
1687300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
1688300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
1689300016Sadrian	int i;
1690300016Sadrian	uint16_t seq_mode;
1691300016Sadrian	uint32_t tmp;
1692300016Sadrian
1693300016Sadrian	bwn_nphy_stay_in_carrier_search(mac, true);
1694300016Sadrian
1695300016Sadrian	if (phy->rev >= 7) {
1696300016Sadrian		bool lpf_bw3, lpf_bw4;
1697300016Sadrian
1698300016Sadrian		lpf_bw3 = BWN_PHY_READ(mac, BWN_NPHY_REV7_RF_CTL_OVER3) & 0x80;
1699300016Sadrian		lpf_bw4 = BWN_PHY_READ(mac, BWN_NPHY_REV7_RF_CTL_OVER4) & 0x80;
1700300016Sadrian
1701300016Sadrian		if (lpf_bw3 || lpf_bw4) {
1702300016Sadrian			/* TODO */
1703300016Sadrian		} else {
1704300016Sadrian			uint16_t value = bwn_nphy_read_lpf_ctl(mac, 0);
1705300016Sadrian			if (phy->rev >= 19)
1706300016Sadrian				bwn_nphy_rf_ctl_override_rev19(mac, 0x80, value,
1707300016Sadrian							       0, false, 1);
1708300016Sadrian			else
1709300016Sadrian				bwn_nphy_rf_ctl_override_rev7(mac, 0x80, value,
1710300016Sadrian							      0, false, 1);
1711300016Sadrian			nphy->lpf_bw_overrode_for_sample_play = true;
1712300016Sadrian		}
1713300016Sadrian	}
1714300016Sadrian
1715300016Sadrian	if ((nphy->bb_mult_save & 0x80000000) == 0) {
1716300016Sadrian		tmp = bwn_ntab_read(mac, BWN_NTAB16(15, 87));
1717300016Sadrian		nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
1718300016Sadrian	}
1719300016Sadrian
1720300016Sadrian	if (modify_bbmult) {
1721300016Sadrian		tmp = !bwn_is_40mhz(mac) ? 0x6464 : 0x4747;
1722300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(15, 87), tmp);
1723300016Sadrian	}
1724300016Sadrian
1725300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_SAMP_DEPCNT, (samps - 1));
1726300016Sadrian
1727300016Sadrian	if (loops != 0xFFFF)
1728300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_SAMP_LOOPCNT, (loops - 1));
1729300016Sadrian	else
1730300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_SAMP_LOOPCNT, loops);
1731300016Sadrian
1732300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_SAMP_WAITCNT, wait);
1733300016Sadrian
1734300016Sadrian	seq_mode = BWN_PHY_READ(mac, BWN_NPHY_RFSEQMODE);
1735300016Sadrian
1736300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFSEQMODE, BWN_NPHY_RFSEQMODE_CAOVER);
1737300016Sadrian	if (iqmode) {
1738300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
1739300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_IQLOCAL_CMDGCTL, 0x8000);
1740300016Sadrian	} else {
1741300016Sadrian		tmp = dac_test ? 5 : 1;
1742300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_SAMP_CMD, tmp);
1743300016Sadrian	}
1744300016Sadrian	for (i = 0; i < 100; i++) {
1745300016Sadrian		if (!(BWN_PHY_READ(mac, BWN_NPHY_RFSEQST) & 1)) {
1746300016Sadrian			i = 0;
1747300016Sadrian			break;
1748300016Sadrian		}
1749300016Sadrian		DELAY(10);
1750300016Sadrian	}
1751300016Sadrian	if (i)
1752300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "run samples timeout\n");
1753300016Sadrian
1754300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFSEQMODE, seq_mode);
1755300016Sadrian
1756300016Sadrian	bwn_nphy_stay_in_carrier_search(mac, false);
1757300016Sadrian}
1758300016Sadrian
1759300016Sadrian/**************************************************
1760300016Sadrian * RSSI
1761300016Sadrian **************************************************/
1762300016Sadrian
1763300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */
1764300016Sadrianstatic void bwn_nphy_scale_offset_rssi(struct bwn_mac *mac, uint16_t scale,
1765300016Sadrian					int8_t offset, uint8_t core,
1766300016Sadrian					enum n_rail_type rail,
1767300016Sadrian					enum n_rssi_type rssi_type)
1768300016Sadrian{
1769300016Sadrian	uint16_t tmp;
1770300016Sadrian	bool core1or5 = (core == 1) || (core == 5);
1771300016Sadrian	bool core2or5 = (core == 2) || (core == 5);
1772300016Sadrian
1773300016Sadrian	offset = bwn_clamp_val(offset, -32, 31);
1774300016Sadrian	tmp = ((scale & 0x3F) << 8) | (offset & 0x3F);
1775300016Sadrian
1776300016Sadrian	switch (rssi_type) {
1777300016Sadrian	case N_RSSI_NB:
1778300016Sadrian		if (core1or5 && rail == N_RAIL_I)
1779300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0I_RSSI_Z, tmp);
1780300016Sadrian		if (core1or5 && rail == N_RAIL_Q)
1781300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
1782300016Sadrian		if (core2or5 && rail == N_RAIL_I)
1783300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1I_RSSI_Z, tmp);
1784300016Sadrian		if (core2or5 && rail == N_RAIL_Q)
1785300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
1786300016Sadrian		break;
1787300016Sadrian	case N_RSSI_W1:
1788300016Sadrian		if (core1or5 && rail == N_RAIL_I)
1789300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0I_RSSI_X, tmp);
1790300016Sadrian		if (core1or5 && rail == N_RAIL_Q)
1791300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0Q_RSSI_X, tmp);
1792300016Sadrian		if (core2or5 && rail == N_RAIL_I)
1793300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1I_RSSI_X, tmp);
1794300016Sadrian		if (core2or5 && rail == N_RAIL_Q)
1795300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1Q_RSSI_X, tmp);
1796300016Sadrian		break;
1797300016Sadrian	case N_RSSI_W2:
1798300016Sadrian		if (core1or5 && rail == N_RAIL_I)
1799300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0I_RSSI_Y, tmp);
1800300016Sadrian		if (core1or5 && rail == N_RAIL_Q)
1801300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
1802300016Sadrian		if (core2or5 && rail == N_RAIL_I)
1803300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1I_RSSI_Y, tmp);
1804300016Sadrian		if (core2or5 && rail == N_RAIL_Q)
1805300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
1806300016Sadrian		break;
1807300016Sadrian	case N_RSSI_TBD:
1808300016Sadrian		if (core1or5 && rail == N_RAIL_I)
1809300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0I_TBD, tmp);
1810300016Sadrian		if (core1or5 && rail == N_RAIL_Q)
1811300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0Q_TBD, tmp);
1812300016Sadrian		if (core2or5 && rail == N_RAIL_I)
1813300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1I_TBD, tmp);
1814300016Sadrian		if (core2or5 && rail == N_RAIL_Q)
1815300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1Q_TBD, tmp);
1816300016Sadrian		break;
1817300016Sadrian	case N_RSSI_IQ:
1818300016Sadrian		if (core1or5 && rail == N_RAIL_I)
1819300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0I_PWRDET, tmp);
1820300016Sadrian		if (core1or5 && rail == N_RAIL_Q)
1821300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0Q_PWRDET, tmp);
1822300016Sadrian		if (core2or5 && rail == N_RAIL_I)
1823300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1I_PWRDET, tmp);
1824300016Sadrian		if (core2or5 && rail == N_RAIL_Q)
1825300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1Q_PWRDET, tmp);
1826300016Sadrian		break;
1827300016Sadrian	case N_RSSI_TSSI_2G:
1828300016Sadrian		if (core1or5)
1829300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0I_TSSI, tmp);
1830300016Sadrian		if (core2or5)
1831300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1I_TSSI, tmp);
1832300016Sadrian		break;
1833300016Sadrian	case N_RSSI_TSSI_5G:
1834300016Sadrian		if (core1or5)
1835300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0Q_TSSI, tmp);
1836300016Sadrian		if (core2or5)
1837300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1Q_TSSI, tmp);
1838300016Sadrian		break;
1839300016Sadrian	}
1840300016Sadrian}
1841300016Sadrian
1842300016Sadrianstatic void bwn_nphy_rssi_select_rev19(struct bwn_mac *mac, uint8_t code,
1843300016Sadrian				       enum n_rssi_type rssi_type)
1844300016Sadrian{
1845300016Sadrian	/* TODO */
1846300016Sadrian}
1847300016Sadrian
1848300016Sadrianstatic void bwn_nphy_rev3_rssi_select(struct bwn_mac *mac, uint8_t code,
1849300016Sadrian				      enum n_rssi_type rssi_type)
1850300016Sadrian{
1851300016Sadrian	uint8_t i;
1852300016Sadrian	uint16_t reg, val;
1853300016Sadrian
1854300016Sadrian	if (code == 0) {
1855300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_OVER1, 0xFDFF);
1856300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_OVER, 0xFDFF);
1857300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_C1, 0xFCFF);
1858300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_C2, 0xFCFF);
1859300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_TXF_40CO_B1S0, 0xFFDF);
1860300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_TXF_40CO_B32S1, 0xFFDF);
1861300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_LUT_TRSW_UP1, 0xFFC3);
1862300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_LUT_TRSW_UP2, 0xFFC3);
1863300016Sadrian	} else {
1864300016Sadrian		for (i = 0; i < 2; i++) {
1865300016Sadrian			if ((code == 1 && i == 1) || (code == 2 && !i))
1866300016Sadrian				continue;
1867300016Sadrian
1868300016Sadrian			reg = (i == 0) ?
1869300016Sadrian				BWN_NPHY_AFECTL_OVER1 : BWN_NPHY_AFECTL_OVER;
1870300016Sadrian			BWN_PHY_SETMASK(mac, reg, 0xFDFF, 0x0200);
1871300016Sadrian
1872300016Sadrian			if (rssi_type == N_RSSI_W1 ||
1873300016Sadrian			    rssi_type == N_RSSI_W2 ||
1874300016Sadrian			    rssi_type == N_RSSI_NB) {
1875300016Sadrian				reg = (i == 0) ?
1876300016Sadrian					BWN_NPHY_AFECTL_C1 :
1877300016Sadrian					BWN_NPHY_AFECTL_C2;
1878300016Sadrian				BWN_PHY_SETMASK(mac, reg, 0xFCFF, 0);
1879300016Sadrian
1880300016Sadrian				reg = (i == 0) ?
1881300016Sadrian					BWN_NPHY_RFCTL_LUT_TRSW_UP1 :
1882300016Sadrian					BWN_NPHY_RFCTL_LUT_TRSW_UP2;
1883300016Sadrian				BWN_PHY_SETMASK(mac, reg, 0xFFC3, 0);
1884300016Sadrian
1885300016Sadrian				if (rssi_type == N_RSSI_W1)
1886300016Sadrian					val = (bwn_current_band(mac) == BWN_BAND_5G) ? 4 : 8;
1887300016Sadrian				else if (rssi_type == N_RSSI_W2)
1888300016Sadrian					val = 16;
1889300016Sadrian				else
1890300016Sadrian					val = 32;
1891300016Sadrian				BWN_PHY_SET(mac, reg, val);
1892300016Sadrian
1893300016Sadrian				reg = (i == 0) ?
1894300016Sadrian					BWN_NPHY_TXF_40CO_B1S0 :
1895300016Sadrian					BWN_NPHY_TXF_40CO_B32S1;
1896300016Sadrian				BWN_PHY_SET(mac, reg, 0x0020);
1897300016Sadrian			} else {
1898300016Sadrian				if (rssi_type == N_RSSI_TBD)
1899300016Sadrian					val = 0x0100;
1900300016Sadrian				else if (rssi_type == N_RSSI_IQ)
1901300016Sadrian					val = 0x0200;
1902300016Sadrian				else
1903300016Sadrian					val = 0x0300;
1904300016Sadrian
1905300016Sadrian				reg = (i == 0) ?
1906300016Sadrian					BWN_NPHY_AFECTL_C1 :
1907300016Sadrian					BWN_NPHY_AFECTL_C2;
1908300016Sadrian
1909300016Sadrian				BWN_PHY_SETMASK(mac, reg, 0xFCFF, val);
1910300016Sadrian				BWN_PHY_SETMASK(mac, reg, 0xF3FF, val << 2);
1911300016Sadrian
1912300016Sadrian				if (rssi_type != N_RSSI_IQ &&
1913300016Sadrian				    rssi_type != N_RSSI_TBD) {
1914300016Sadrian					bwn_band_t band =
1915300016Sadrian						bwn_current_band(mac);
1916300016Sadrian
1917300016Sadrian					if (mac->mac_phy.rev < 7) {
1918300016Sadrian						if (bwn_nphy_ipa(mac))
1919300016Sadrian							val = (band == BWN_BAND_5G) ? 0xC : 0xE;
1920300016Sadrian						else
1921300016Sadrian							val = 0x11;
1922300016Sadrian						reg = (i == 0) ? B2056_TX0 : B2056_TX1;
1923300016Sadrian						reg |= B2056_TX_TX_SSI_MUX;
1924300016Sadrian						BWN_RF_WRITE(mac, reg, val);
1925300016Sadrian					}
1926300016Sadrian
1927300016Sadrian					reg = (i == 0) ?
1928300016Sadrian						BWN_NPHY_AFECTL_OVER1 :
1929300016Sadrian						BWN_NPHY_AFECTL_OVER;
1930300016Sadrian					BWN_PHY_SET(mac, reg, 0x0200);
1931300016Sadrian				}
1932300016Sadrian			}
1933300016Sadrian		}
1934300016Sadrian	}
1935300016Sadrian}
1936300016Sadrian
1937300016Sadrianstatic void bwn_nphy_rev2_rssi_select(struct bwn_mac *mac, uint8_t code,
1938300016Sadrian				      enum n_rssi_type rssi_type)
1939300016Sadrian{
1940300016Sadrian	uint16_t val;
1941300016Sadrian	bool rssi_w1_w2_nb = false;
1942300016Sadrian
1943300016Sadrian	switch (rssi_type) {
1944300016Sadrian	case N_RSSI_W1:
1945300016Sadrian	case N_RSSI_W2:
1946300016Sadrian	case N_RSSI_NB:
1947300016Sadrian		val = 0;
1948300016Sadrian		rssi_w1_w2_nb = true;
1949300016Sadrian		break;
1950300016Sadrian	case N_RSSI_TBD:
1951300016Sadrian		val = 1;
1952300016Sadrian		break;
1953300016Sadrian	case N_RSSI_IQ:
1954300016Sadrian		val = 2;
1955300016Sadrian		break;
1956300016Sadrian	default:
1957300016Sadrian		val = 3;
1958300016Sadrian	}
1959300016Sadrian
1960300016Sadrian	val = (val << 12) | (val << 14);
1961300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_AFECTL_C1, 0x0FFF, val);
1962300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_AFECTL_C2, 0x0FFF, val);
1963300016Sadrian
1964300016Sadrian	if (rssi_w1_w2_nb) {
1965300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_RFCTL_RSSIO1, 0xFFCF,
1966300016Sadrian				(rssi_type + 1) << 4);
1967300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_RFCTL_RSSIO2, 0xFFCF,
1968300016Sadrian				(rssi_type + 1) << 4);
1969300016Sadrian	}
1970300016Sadrian
1971300016Sadrian	if (code == 0) {
1972300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_OVER, ~0x3000);
1973300016Sadrian		if (rssi_w1_w2_nb) {
1974300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_CMD,
1975300016Sadrian				~(BWN_NPHY_RFCTL_CMD_RXEN |
1976300016Sadrian				  BWN_NPHY_RFCTL_CMD_CORESEL));
1977300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER,
1978300016Sadrian				~(0x1 << 12 |
1979300016Sadrian				  0x1 << 5 |
1980300016Sadrian				  0x1 << 1 |
1981300016Sadrian				  0x1));
1982300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_CMD,
1983300016Sadrian				~BWN_NPHY_RFCTL_CMD_START);
1984300016Sadrian			DELAY(20);
1985300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER, ~0x1);
1986300016Sadrian		}
1987300016Sadrian	} else {
1988300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER, 0x3000);
1989300016Sadrian		if (rssi_w1_w2_nb) {
1990300016Sadrian			BWN_PHY_SETMASK(mac, BWN_NPHY_RFCTL_CMD,
1991300016Sadrian				~(BWN_NPHY_RFCTL_CMD_RXEN |
1992300016Sadrian				  BWN_NPHY_RFCTL_CMD_CORESEL),
1993300016Sadrian				(BWN_NPHY_RFCTL_CMD_RXEN |
1994300016Sadrian				 code << BWN_NPHY_RFCTL_CMD_CORESEL_SHIFT));
1995300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_RFCTL_OVER,
1996300016Sadrian				(0x1 << 12 |
1997300016Sadrian				  0x1 << 5 |
1998300016Sadrian				  0x1 << 1 |
1999300016Sadrian				  0x1));
2000300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD,
2001300016Sadrian				BWN_NPHY_RFCTL_CMD_START);
2002300016Sadrian			DELAY(20);
2003300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER, ~0x1);
2004300016Sadrian		}
2005300016Sadrian	}
2006300016Sadrian}
2007300016Sadrian
2008300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
2009300016Sadrianstatic void bwn_nphy_rssi_select(struct bwn_mac *mac, uint8_t code,
2010300016Sadrian				 enum n_rssi_type type)
2011300016Sadrian{
2012300016Sadrian	if (mac->mac_phy.rev >= 19)
2013300016Sadrian		bwn_nphy_rssi_select_rev19(mac, code, type);
2014300016Sadrian	else if (mac->mac_phy.rev >= 3)
2015300016Sadrian		bwn_nphy_rev3_rssi_select(mac, code, type);
2016300016Sadrian	else
2017300016Sadrian		bwn_nphy_rev2_rssi_select(mac, code, type);
2018300016Sadrian}
2019300016Sadrian
2020300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */
2021300016Sadrianstatic void bwn_nphy_set_rssi_2055_vcm(struct bwn_mac *mac,
2022300016Sadrian				       enum n_rssi_type rssi_type, uint8_t *buf)
2023300016Sadrian{
2024300016Sadrian	int i;
2025300016Sadrian	for (i = 0; i < 2; i++) {
2026300016Sadrian		if (rssi_type == N_RSSI_NB) {
2027300016Sadrian			if (i == 0) {
2028300016Sadrian				BWN_RF_SETMASK(mac, B2055_C1_B0NB_RSSIVCM,
2029300016Sadrian						  0xFC, buf[0]);
2030300016Sadrian				BWN_RF_SETMASK(mac, B2055_C1_RX_BB_RSSICTL5,
2031300016Sadrian						  0xFC, buf[1]);
2032300016Sadrian			} else {
2033300016Sadrian				BWN_RF_SETMASK(mac, B2055_C2_B0NB_RSSIVCM,
2034300016Sadrian						  0xFC, buf[2 * i]);
2035300016Sadrian				BWN_RF_SETMASK(mac, B2055_C2_RX_BB_RSSICTL5,
2036300016Sadrian						  0xFC, buf[2 * i + 1]);
2037300016Sadrian			}
2038300016Sadrian		} else {
2039300016Sadrian			if (i == 0)
2040300016Sadrian				BWN_RF_SETMASK(mac, B2055_C1_RX_BB_RSSICTL5,
2041300016Sadrian						  0xF3, buf[0] << 2);
2042300016Sadrian			else
2043300016Sadrian				BWN_RF_SETMASK(mac, B2055_C2_RX_BB_RSSICTL5,
2044300016Sadrian						  0xF3, buf[2 * i + 1] << 2);
2045300016Sadrian		}
2046300016Sadrian	}
2047300016Sadrian}
2048300016Sadrian
2049300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */
2050300016Sadrianstatic int bwn_nphy_poll_rssi(struct bwn_mac *mac, enum n_rssi_type rssi_type,
2051300016Sadrian			      int32_t *buf, uint8_t nsamp)
2052300016Sadrian{
2053300016Sadrian	int i;
2054300016Sadrian	int out;
2055300016Sadrian	uint16_t save_regs_phy[9];
2056300016Sadrian	uint16_t s[2];
2057300016Sadrian
2058300016Sadrian	/* TODO: rev7+ is treated like rev3+, what about rev19+? */
2059300016Sadrian
2060300016Sadrian	if (mac->mac_phy.rev >= 3) {
2061300016Sadrian		save_regs_phy[0] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_C1);
2062300016Sadrian		save_regs_phy[1] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_C2);
2063300016Sadrian		save_regs_phy[2] = BWN_PHY_READ(mac,
2064300016Sadrian						BWN_NPHY_RFCTL_LUT_TRSW_UP1);
2065300016Sadrian		save_regs_phy[3] = BWN_PHY_READ(mac,
2066300016Sadrian						BWN_NPHY_RFCTL_LUT_TRSW_UP2);
2067300016Sadrian		save_regs_phy[4] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_OVER1);
2068300016Sadrian		save_regs_phy[5] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_OVER);
2069300016Sadrian		save_regs_phy[6] = BWN_PHY_READ(mac, BWN_NPHY_TXF_40CO_B1S0);
2070300016Sadrian		save_regs_phy[7] = BWN_PHY_READ(mac, BWN_NPHY_TXF_40CO_B32S1);
2071300016Sadrian		save_regs_phy[8] = 0;
2072300016Sadrian	} else {
2073300016Sadrian		save_regs_phy[0] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_C1);
2074300016Sadrian		save_regs_phy[1] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_C2);
2075300016Sadrian		save_regs_phy[2] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_OVER);
2076300016Sadrian		save_regs_phy[3] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_CMD);
2077300016Sadrian		save_regs_phy[4] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_OVER);
2078300016Sadrian		save_regs_phy[5] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_RSSIO1);
2079300016Sadrian		save_regs_phy[6] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_RSSIO2);
2080300016Sadrian		save_regs_phy[7] = 0;
2081300016Sadrian		save_regs_phy[8] = 0;
2082300016Sadrian	}
2083300016Sadrian
2084300016Sadrian	bwn_nphy_rssi_select(mac, 5, rssi_type);
2085300016Sadrian
2086300016Sadrian	if (mac->mac_phy.rev < 2) {
2087300016Sadrian		save_regs_phy[8] = BWN_PHY_READ(mac, BWN_NPHY_GPIO_SEL);
2088300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_GPIO_SEL, 5);
2089300016Sadrian	}
2090300016Sadrian
2091300016Sadrian	for (i = 0; i < 4; i++)
2092300016Sadrian		buf[i] = 0;
2093300016Sadrian
2094300016Sadrian	for (i = 0; i < nsamp; i++) {
2095300016Sadrian		if (mac->mac_phy.rev < 2) {
2096300016Sadrian			s[0] = BWN_PHY_READ(mac, BWN_NPHY_GPIO_LOOUT);
2097300016Sadrian			s[1] = BWN_PHY_READ(mac, BWN_NPHY_GPIO_HIOUT);
2098300016Sadrian		} else {
2099300016Sadrian			s[0] = BWN_PHY_READ(mac, BWN_NPHY_RSSI1);
2100300016Sadrian			s[1] = BWN_PHY_READ(mac, BWN_NPHY_RSSI2);
2101300016Sadrian		}
2102300016Sadrian
2103300016Sadrian		buf[0] += ((int8_t)((s[0] & 0x3F) << 2)) >> 2;
2104300016Sadrian		buf[1] += ((int8_t)(((s[0] >> 8) & 0x3F) << 2)) >> 2;
2105300016Sadrian		buf[2] += ((int8_t)((s[1] & 0x3F) << 2)) >> 2;
2106300016Sadrian		buf[3] += ((int8_t)(((s[1] >> 8) & 0x3F) << 2)) >> 2;
2107300016Sadrian	}
2108300016Sadrian	out = (buf[0] & 0xFF) << 24 | (buf[1] & 0xFF) << 16 |
2109300016Sadrian		(buf[2] & 0xFF) << 8 | (buf[3] & 0xFF);
2110300016Sadrian
2111300016Sadrian	if (mac->mac_phy.rev < 2)
2112300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_GPIO_SEL, save_regs_phy[8]);
2113300016Sadrian
2114300016Sadrian	if (mac->mac_phy.rev >= 3) {
2115300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C1, save_regs_phy[0]);
2116300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C2, save_regs_phy[1]);
2117300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_UP1,
2118300016Sadrian				save_regs_phy[2]);
2119300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_UP2,
2120300016Sadrian				save_regs_phy[3]);
2121300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER1, save_regs_phy[4]);
2122300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, save_regs_phy[5]);
2123300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXF_40CO_B1S0, save_regs_phy[6]);
2124300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXF_40CO_B32S1, save_regs_phy[7]);
2125300016Sadrian	} else {
2126300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C1, save_regs_phy[0]);
2127300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C2, save_regs_phy[1]);
2128300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, save_regs_phy[2]);
2129300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_CMD, save_regs_phy[3]);
2130300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_OVER, save_regs_phy[4]);
2131300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_RSSIO1, save_regs_phy[5]);
2132300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_RSSIO2, save_regs_phy[6]);
2133300016Sadrian	}
2134300016Sadrian
2135300016Sadrian	return out;
2136300016Sadrian}
2137300016Sadrian
2138300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
2139300016Sadrianstatic void bwn_nphy_rev3_rssi_cal(struct bwn_mac *mac)
2140300016Sadrian{
2141300016Sadrian	//struct bwn_phy *phy = &mac->mac_phy;
2142300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
2143300016Sadrian
2144300016Sadrian	uint16_t saved_regs_phy_rfctl[2];
2145300016Sadrian	uint16_t saved_regs_phy[22];
2146300016Sadrian	uint16_t regs_to_store_rev3[] = {
2147300016Sadrian		BWN_NPHY_AFECTL_OVER1, BWN_NPHY_AFECTL_OVER,
2148300016Sadrian		BWN_NPHY_AFECTL_C1, BWN_NPHY_AFECTL_C2,
2149300016Sadrian		BWN_NPHY_TXF_40CO_B1S1, BWN_NPHY_RFCTL_OVER,
2150300016Sadrian		BWN_NPHY_TXF_40CO_B1S0, BWN_NPHY_TXF_40CO_B32S1,
2151300016Sadrian		BWN_NPHY_RFCTL_CMD,
2152300016Sadrian		BWN_NPHY_RFCTL_LUT_TRSW_UP1, BWN_NPHY_RFCTL_LUT_TRSW_UP2,
2153300016Sadrian		BWN_NPHY_RFCTL_RSSIO1, BWN_NPHY_RFCTL_RSSIO2
2154300016Sadrian	};
2155300016Sadrian	uint16_t regs_to_store_rev7[] = {
2156300016Sadrian		BWN_NPHY_AFECTL_OVER1, BWN_NPHY_AFECTL_OVER,
2157300016Sadrian		BWN_NPHY_AFECTL_C1, BWN_NPHY_AFECTL_C2,
2158300016Sadrian		BWN_NPHY_TXF_40CO_B1S1, BWN_NPHY_RFCTL_OVER,
2159300016Sadrian		BWN_NPHY_REV7_RF_CTL_OVER3, BWN_NPHY_REV7_RF_CTL_OVER4,
2160300016Sadrian		BWN_NPHY_REV7_RF_CTL_OVER5, BWN_NPHY_REV7_RF_CTL_OVER6,
2161300016Sadrian		0x2ff,
2162300016Sadrian		BWN_NPHY_TXF_40CO_B1S0, BWN_NPHY_TXF_40CO_B32S1,
2163300016Sadrian		BWN_NPHY_RFCTL_CMD,
2164300016Sadrian		BWN_NPHY_RFCTL_LUT_TRSW_UP1, BWN_NPHY_RFCTL_LUT_TRSW_UP2,
2165300016Sadrian		BWN_NPHY_REV7_RF_CTL_MISC_REG3, BWN_NPHY_REV7_RF_CTL_MISC_REG4,
2166300016Sadrian		BWN_NPHY_REV7_RF_CTL_MISC_REG5, BWN_NPHY_REV7_RF_CTL_MISC_REG6,
2167300016Sadrian		BWN_NPHY_RFCTL_RSSIO1, BWN_NPHY_RFCTL_RSSIO2
2168300016Sadrian	};
2169300016Sadrian	uint16_t *regs_to_store;
2170300016Sadrian	int regs_amount;
2171300016Sadrian
2172300016Sadrian	uint16_t class;
2173300016Sadrian
2174300016Sadrian	uint16_t clip_state[2];
2175300016Sadrian	uint16_t clip_off[2] = { 0xFFFF, 0xFFFF };
2176300016Sadrian
2177300016Sadrian	uint8_t vcm_final = 0;
2178300016Sadrian	int32_t offset[4];
2179300016Sadrian	int32_t results[8][4] = { };
2180300016Sadrian	int32_t results_min[4] = { };
2181300016Sadrian	int32_t poll_results[4] = { };
2182300016Sadrian
2183300016Sadrian	uint16_t *rssical_radio_regs = NULL;
2184300016Sadrian	uint16_t *rssical_phy_regs = NULL;
2185300016Sadrian
2186300016Sadrian	uint16_t r; /* routing */
2187300016Sadrian	uint8_t rx_core_state;
2188300016Sadrian	int core, i, j, vcm;
2189300016Sadrian
2190300016Sadrian	if (mac->mac_phy.rev >= 7) {
2191300016Sadrian		regs_to_store = regs_to_store_rev7;
2192300016Sadrian		regs_amount = nitems(regs_to_store_rev7);
2193300016Sadrian	} else {
2194300016Sadrian		regs_to_store = regs_to_store_rev3;
2195300016Sadrian		regs_amount = nitems(regs_to_store_rev3);
2196300016Sadrian	}
2197300016Sadrian	KASSERT((regs_amount <= nitems(saved_regs_phy)),
2198300016Sadrian	    ("%s: reg_amount (%d) too large\n",
2199300016Sadrian	    __func__,
2200300016Sadrian	    regs_amount));
2201300016Sadrian
2202300016Sadrian	class = bwn_nphy_classifier(mac, 0, 0);
2203300016Sadrian	bwn_nphy_classifier(mac, 7, 4);
2204300016Sadrian	bwn_nphy_read_clip_detection(mac, clip_state);
2205300016Sadrian	bwn_nphy_write_clip_detection(mac, clip_off);
2206300016Sadrian
2207300016Sadrian	saved_regs_phy_rfctl[0] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC1);
2208300016Sadrian	saved_regs_phy_rfctl[1] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC2);
2209300016Sadrian	for (i = 0; i < regs_amount; i++)
2210300016Sadrian		saved_regs_phy[i] = BWN_PHY_READ(mac, regs_to_store[i]);
2211300016Sadrian
2212300016Sadrian	bwn_nphy_rf_ctl_intc_override(mac, N_INTC_OVERRIDE_OFF, 0, 7);
2213300016Sadrian	bwn_nphy_rf_ctl_intc_override(mac, N_INTC_OVERRIDE_TRSW, 1, 7);
2214300016Sadrian
2215300016Sadrian	if (mac->mac_phy.rev >= 7) {
2216300016Sadrian		bwn_nphy_rf_ctl_override_one_to_many(mac,
2217300016Sadrian						     N_RF_CTL_OVER_CMD_RXRF_PU,
2218300016Sadrian						     0, 0, false);
2219300016Sadrian		bwn_nphy_rf_ctl_override_one_to_many(mac,
2220300016Sadrian						     N_RF_CTL_OVER_CMD_RX_PU,
2221300016Sadrian						     1, 0, false);
2222300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x80, 1, 0, false, 0);
2223300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x40, 1, 0, false, 0);
2224300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_5G) {
2225300016Sadrian			bwn_nphy_rf_ctl_override_rev7(mac, 0x20, 0, 0, false,
2226300016Sadrian						      0);
2227300016Sadrian			bwn_nphy_rf_ctl_override_rev7(mac, 0x10, 1, 0, false,
2228300016Sadrian						      0);
2229300016Sadrian		} else {
2230300016Sadrian			bwn_nphy_rf_ctl_override_rev7(mac, 0x10, 0, 0, false,
2231300016Sadrian						      0);
2232300016Sadrian			bwn_nphy_rf_ctl_override_rev7(mac, 0x20, 1, 0, false,
2233300016Sadrian						      0);
2234300016Sadrian		}
2235300016Sadrian	} else {
2236300016Sadrian		bwn_nphy_rf_ctl_override(mac, 0x1, 0, 0, false);
2237300016Sadrian		bwn_nphy_rf_ctl_override(mac, 0x2, 1, 0, false);
2238300016Sadrian		bwn_nphy_rf_ctl_override(mac, 0x80, 1, 0, false);
2239300016Sadrian		bwn_nphy_rf_ctl_override(mac, 0x40, 1, 0, false);
2240300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_5G) {
2241300016Sadrian			bwn_nphy_rf_ctl_override(mac, 0x20, 0, 0, false);
2242300016Sadrian			bwn_nphy_rf_ctl_override(mac, 0x10, 1, 0, false);
2243300016Sadrian		} else {
2244300016Sadrian			bwn_nphy_rf_ctl_override(mac, 0x10, 0, 0, false);
2245300016Sadrian			bwn_nphy_rf_ctl_override(mac, 0x20, 1, 0, false);
2246300016Sadrian		}
2247300016Sadrian	}
2248300016Sadrian
2249300016Sadrian	rx_core_state = bwn_nphy_get_rx_core_state(mac);
2250300016Sadrian	for (core = 0; core < 2; core++) {
2251300016Sadrian		if (!(rx_core_state & (1 << core)))
2252300016Sadrian			continue;
2253300016Sadrian		r = core ? B2056_RX1 : B2056_RX0;
2254300016Sadrian		bwn_nphy_scale_offset_rssi(mac, 0, 0, core + 1, N_RAIL_I,
2255300016Sadrian					   N_RSSI_NB);
2256300016Sadrian		bwn_nphy_scale_offset_rssi(mac, 0, 0, core + 1, N_RAIL_Q,
2257300016Sadrian					   N_RSSI_NB);
2258300016Sadrian
2259300016Sadrian		/* Grab RSSI results for every possible VCM */
2260300016Sadrian		for (vcm = 0; vcm < 8; vcm++) {
2261300016Sadrian			if (mac->mac_phy.rev >= 7)
2262300016Sadrian				BWN_RF_SETMASK(mac,
2263300016Sadrian						  core ? R2057_NB_MASTER_CORE1 :
2264300016Sadrian							 R2057_NB_MASTER_CORE0,
2265300016Sadrian						  ~R2057_VCM_MASK, vcm);
2266300016Sadrian			else
2267300016Sadrian				BWN_RF_SETMASK(mac, r | B2056_RX_RSSI_MISC,
2268300016Sadrian						  0xE3, vcm << 2);
2269300016Sadrian			bwn_nphy_poll_rssi(mac, N_RSSI_NB, results[vcm], 8);
2270300016Sadrian		}
2271300016Sadrian
2272300016Sadrian		/* Find out which VCM got the best results */
2273300016Sadrian		for (i = 0; i < 4; i += 2) {
2274300016Sadrian			int32_t currd;
2275300016Sadrian			int32_t mind = 0x100000;
2276300016Sadrian			int32_t minpoll = 249;
2277300016Sadrian			uint8_t minvcm = 0;
2278300016Sadrian			if (2 * core != i)
2279300016Sadrian				continue;
2280300016Sadrian			for (vcm = 0; vcm < 8; vcm++) {
2281300016Sadrian				currd = results[vcm][i] * results[vcm][i] +
2282300016Sadrian					results[vcm][i + 1] * results[vcm][i];
2283300016Sadrian				if (currd < mind) {
2284300016Sadrian					mind = currd;
2285300016Sadrian					minvcm = vcm;
2286300016Sadrian				}
2287300016Sadrian				if (results[vcm][i] < minpoll)
2288300016Sadrian					minpoll = results[vcm][i];
2289300016Sadrian			}
2290300016Sadrian			vcm_final = minvcm;
2291300016Sadrian			results_min[i] = minpoll;
2292300016Sadrian		}
2293300016Sadrian
2294300016Sadrian		/* Select the best VCM */
2295300016Sadrian		if (mac->mac_phy.rev >= 7)
2296300016Sadrian			BWN_RF_SETMASK(mac,
2297300016Sadrian					  core ? R2057_NB_MASTER_CORE1 :
2298300016Sadrian						 R2057_NB_MASTER_CORE0,
2299300016Sadrian					  ~R2057_VCM_MASK, vcm);
2300300016Sadrian		else
2301300016Sadrian			BWN_RF_SETMASK(mac, r | B2056_RX_RSSI_MISC,
2302300016Sadrian					  0xE3, vcm_final << 2);
2303300016Sadrian
2304300016Sadrian		for (i = 0; i < 4; i++) {
2305300016Sadrian			if (core != i / 2)
2306300016Sadrian				continue;
2307300016Sadrian			offset[i] = -results[vcm_final][i];
2308300016Sadrian			if (offset[i] < 0)
2309300016Sadrian				offset[i] = -((abs(offset[i]) + 4) / 8);
2310300016Sadrian			else
2311300016Sadrian				offset[i] = (offset[i] + 4) / 8;
2312300016Sadrian			if (results_min[i] == 248)
2313300016Sadrian				offset[i] = -32;
2314300016Sadrian			bwn_nphy_scale_offset_rssi(mac, 0, offset[i],
2315300016Sadrian						   (i / 2 == 0) ? 1 : 2,
2316300016Sadrian						   (i % 2 == 0) ? N_RAIL_I : N_RAIL_Q,
2317300016Sadrian						   N_RSSI_NB);
2318300016Sadrian		}
2319300016Sadrian	}
2320300016Sadrian
2321300016Sadrian	for (core = 0; core < 2; core++) {
2322300016Sadrian		if (!(rx_core_state & (1 << core)))
2323300016Sadrian			continue;
2324300016Sadrian		for (i = 0; i < 2; i++) {
2325300016Sadrian			bwn_nphy_scale_offset_rssi(mac, 0, 0, core + 1,
2326300016Sadrian						   N_RAIL_I, i);
2327300016Sadrian			bwn_nphy_scale_offset_rssi(mac, 0, 0, core + 1,
2328300016Sadrian						   N_RAIL_Q, i);
2329300016Sadrian			bwn_nphy_poll_rssi(mac, i, poll_results, 8);
2330300016Sadrian			for (j = 0; j < 4; j++) {
2331300016Sadrian				if (j / 2 == core) {
2332300016Sadrian					offset[j] = 232 - poll_results[j];
2333300016Sadrian					if (offset[j] < 0)
2334300016Sadrian						offset[j] = -(abs(offset[j] + 4) / 8);
2335300016Sadrian					else
2336300016Sadrian						offset[j] = (offset[j] + 4) / 8;
2337300016Sadrian					bwn_nphy_scale_offset_rssi(mac, 0,
2338300016Sadrian						offset[2 * core], core + 1, j % 2, i);
2339300016Sadrian				}
2340300016Sadrian			}
2341300016Sadrian		}
2342300016Sadrian	}
2343300016Sadrian
2344300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1, saved_regs_phy_rfctl[0]);
2345300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2, saved_regs_phy_rfctl[1]);
2346300016Sadrian
2347300016Sadrian	bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
2348300016Sadrian
2349300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_TXF_40CO_B1S1, 0x1);
2350300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD, BWN_NPHY_RFCTL_CMD_START);
2351300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_TXF_40CO_B1S1, ~0x1);
2352300016Sadrian
2353300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFCTL_OVER, 0x1);
2354300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RFCTL_CMD, BWN_NPHY_RFCTL_CMD_RXTX);
2355300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_OVER, ~0x1);
2356300016Sadrian
2357300016Sadrian	for (i = 0; i < regs_amount; i++)
2358300016Sadrian		BWN_PHY_WRITE(mac, regs_to_store[i], saved_regs_phy[i]);
2359300016Sadrian
2360300016Sadrian	/* Store for future configuration */
2361300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G) {
2362300016Sadrian		rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_2G;
2363300016Sadrian		rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_2G;
2364300016Sadrian	} else {
2365300016Sadrian		rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G;
2366300016Sadrian		rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G;
2367300016Sadrian	}
2368300016Sadrian	if (mac->mac_phy.rev >= 7) {
2369300016Sadrian		rssical_radio_regs[0] = BWN_RF_READ(mac,
2370300016Sadrian						       R2057_NB_MASTER_CORE0);
2371300016Sadrian		rssical_radio_regs[1] = BWN_RF_READ(mac,
2372300016Sadrian						       R2057_NB_MASTER_CORE1);
2373300016Sadrian	} else {
2374300016Sadrian		rssical_radio_regs[0] = BWN_RF_READ(mac, B2056_RX0 |
2375300016Sadrian						       B2056_RX_RSSI_MISC);
2376300016Sadrian		rssical_radio_regs[1] = BWN_RF_READ(mac, B2056_RX1 |
2377300016Sadrian						       B2056_RX_RSSI_MISC);
2378300016Sadrian	}
2379300016Sadrian	rssical_phy_regs[0] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_0I_RSSI_Z);
2380300016Sadrian	rssical_phy_regs[1] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_0Q_RSSI_Z);
2381300016Sadrian	rssical_phy_regs[2] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_1I_RSSI_Z);
2382300016Sadrian	rssical_phy_regs[3] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_1Q_RSSI_Z);
2383300016Sadrian	rssical_phy_regs[4] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_0I_RSSI_X);
2384300016Sadrian	rssical_phy_regs[5] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_0Q_RSSI_X);
2385300016Sadrian	rssical_phy_regs[6] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_1I_RSSI_X);
2386300016Sadrian	rssical_phy_regs[7] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_1Q_RSSI_X);
2387300016Sadrian	rssical_phy_regs[8] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_0I_RSSI_Y);
2388300016Sadrian	rssical_phy_regs[9] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_0Q_RSSI_Y);
2389300016Sadrian	rssical_phy_regs[10] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_1I_RSSI_Y);
2390300016Sadrian	rssical_phy_regs[11] = BWN_PHY_READ(mac, BWN_NPHY_RSSIMC_1Q_RSSI_Y);
2391300016Sadrian
2392300016Sadrian	/* Remember for which channel we store configuration */
2393300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G)
2394300016Sadrian		nphy->rssical_chanspec_2G.center_freq = bwn_get_centre_freq(mac);
2395300016Sadrian	else
2396300016Sadrian		nphy->rssical_chanspec_5G.center_freq = bwn_get_centre_freq(mac);
2397300016Sadrian
2398300016Sadrian	/* End of calibration, restore configuration */
2399300016Sadrian	bwn_nphy_classifier(mac, 7, class);
2400300016Sadrian	bwn_nphy_write_clip_detection(mac, clip_state);
2401300016Sadrian}
2402300016Sadrian
2403300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */
2404300016Sadrianstatic void bwn_nphy_rev2_rssi_cal(struct bwn_mac *mac, enum n_rssi_type type)
2405300016Sadrian{
2406300016Sadrian	int i, j, vcm;
2407300016Sadrian	uint8_t state[4];
2408300016Sadrian	uint8_t code, val;
2409300016Sadrian	uint16_t class, override;
2410300016Sadrian	uint8_t regs_save_radio[2];
2411300016Sadrian	uint16_t regs_save_phy[2];
2412300016Sadrian
2413300016Sadrian	int32_t offset[4];
2414300016Sadrian	uint8_t core;
2415300016Sadrian	uint8_t rail;
2416300016Sadrian
2417300016Sadrian	uint16_t clip_state[2];
2418300016Sadrian	uint16_t clip_off[2] = { 0xFFFF, 0xFFFF };
2419300016Sadrian	int32_t results_min[4] = { };
2420300016Sadrian	uint8_t vcm_final[4] = { };
2421300016Sadrian	int32_t results[4][4] = { };
2422300016Sadrian	int32_t miniq[4][2] = { };
2423300016Sadrian
2424300016Sadrian	if (type == N_RSSI_NB) {
2425300016Sadrian		code = 0;
2426300016Sadrian		val = 6;
2427300016Sadrian	} else if (type == N_RSSI_W1 || type == N_RSSI_W2) {
2428300016Sadrian		code = 25;
2429300016Sadrian		val = 4;
2430300016Sadrian	} else {
2431300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: RSSI type %d invalid\n",
2432300016Sadrian		    __func__,
2433300016Sadrian		    type);
2434300016Sadrian		return;
2435300016Sadrian	}
2436300016Sadrian
2437300016Sadrian	class = bwn_nphy_classifier(mac, 0, 0);
2438300016Sadrian	bwn_nphy_classifier(mac, 7, 4);
2439300016Sadrian	bwn_nphy_read_clip_detection(mac, clip_state);
2440300016Sadrian	bwn_nphy_write_clip_detection(mac, clip_off);
2441300016Sadrian
2442300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_5G)
2443300016Sadrian		override = 0x140;
2444300016Sadrian	else
2445300016Sadrian		override = 0x110;
2446300016Sadrian
2447300016Sadrian	regs_save_phy[0] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC1);
2448300016Sadrian	regs_save_radio[0] = BWN_RF_READ(mac, B2055_C1_PD_RXTX);
2449300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1, override);
2450300016Sadrian	BWN_RF_WRITE(mac, B2055_C1_PD_RXTX, val);
2451300016Sadrian
2452300016Sadrian	regs_save_phy[1] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC2);
2453300016Sadrian	regs_save_radio[1] = BWN_RF_READ(mac, B2055_C2_PD_RXTX);
2454300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2, override);
2455300016Sadrian	BWN_RF_WRITE(mac, B2055_C2_PD_RXTX, val);
2456300016Sadrian
2457300016Sadrian	state[0] = BWN_RF_READ(mac, B2055_C1_PD_RSSIMISC) & 0x07;
2458300016Sadrian	state[1] = BWN_RF_READ(mac, B2055_C2_PD_RSSIMISC) & 0x07;
2459300016Sadrian	BWN_RF_MASK(mac, B2055_C1_PD_RSSIMISC, 0xF8);
2460300016Sadrian	BWN_RF_MASK(mac, B2055_C2_PD_RSSIMISC, 0xF8);
2461300016Sadrian	state[2] = BWN_RF_READ(mac, B2055_C1_SP_RSSI) & 0x07;
2462300016Sadrian	state[3] = BWN_RF_READ(mac, B2055_C2_SP_RSSI) & 0x07;
2463300016Sadrian
2464300016Sadrian	bwn_nphy_rssi_select(mac, 5, type);
2465300016Sadrian	bwn_nphy_scale_offset_rssi(mac, 0, 0, 5, N_RAIL_I, type);
2466300016Sadrian	bwn_nphy_scale_offset_rssi(mac, 0, 0, 5, N_RAIL_Q, type);
2467300016Sadrian
2468300016Sadrian	for (vcm = 0; vcm < 4; vcm++) {
2469300016Sadrian		uint8_t tmp[4];
2470300016Sadrian		for (j = 0; j < 4; j++)
2471300016Sadrian			tmp[j] = vcm;
2472300016Sadrian		if (type != N_RSSI_W2)
2473300016Sadrian			bwn_nphy_set_rssi_2055_vcm(mac, type, tmp);
2474300016Sadrian		bwn_nphy_poll_rssi(mac, type, results[vcm], 8);
2475300016Sadrian		if (type == N_RSSI_W1 || type == N_RSSI_W2)
2476300016Sadrian			for (j = 0; j < 2; j++)
2477300016Sadrian				miniq[vcm][j] = min(results[vcm][2 * j],
2478300016Sadrian						    results[vcm][2 * j + 1]);
2479300016Sadrian	}
2480300016Sadrian
2481300016Sadrian	for (i = 0; i < 4; i++) {
2482300016Sadrian		int32_t mind = 0x100000;
2483300016Sadrian		uint8_t minvcm = 0;
2484300016Sadrian		int32_t minpoll = 249;
2485300016Sadrian		int32_t currd;
2486300016Sadrian		for (vcm = 0; vcm < 4; vcm++) {
2487300016Sadrian			if (type == N_RSSI_NB)
2488300016Sadrian				currd = abs(results[vcm][i] - code * 8);
2489300016Sadrian			else
2490300016Sadrian				currd = abs(miniq[vcm][i / 2] - code * 8);
2491300016Sadrian
2492300016Sadrian			if (currd < mind) {
2493300016Sadrian				mind = currd;
2494300016Sadrian				minvcm = vcm;
2495300016Sadrian			}
2496300016Sadrian
2497300016Sadrian			if (results[vcm][i] < minpoll)
2498300016Sadrian				minpoll = results[vcm][i];
2499300016Sadrian		}
2500300016Sadrian		results_min[i] = minpoll;
2501300016Sadrian		vcm_final[i] = minvcm;
2502300016Sadrian	}
2503300016Sadrian
2504300016Sadrian	if (type != N_RSSI_W2)
2505300016Sadrian		bwn_nphy_set_rssi_2055_vcm(mac, type, vcm_final);
2506300016Sadrian
2507300016Sadrian	for (i = 0; i < 4; i++) {
2508300016Sadrian		offset[i] = (code * 8) - results[vcm_final[i]][i];
2509300016Sadrian
2510300016Sadrian		if (offset[i] < 0)
2511300016Sadrian			offset[i] = -((abs(offset[i]) + 4) / 8);
2512300016Sadrian		else
2513300016Sadrian			offset[i] = (offset[i] + 4) / 8;
2514300016Sadrian
2515300016Sadrian		if (results_min[i] == 248)
2516300016Sadrian			offset[i] = code - 32;
2517300016Sadrian
2518300016Sadrian		core = (i / 2) ? 2 : 1;
2519300016Sadrian		rail = (i % 2) ? N_RAIL_Q : N_RAIL_I;
2520300016Sadrian
2521300016Sadrian		bwn_nphy_scale_offset_rssi(mac, 0, offset[i], core, rail,
2522300016Sadrian						type);
2523300016Sadrian	}
2524300016Sadrian
2525300016Sadrian	BWN_RF_SETMASK(mac, B2055_C1_PD_RSSIMISC, 0xF8, state[0]);
2526300016Sadrian	BWN_RF_SETMASK(mac, B2055_C2_PD_RSSIMISC, 0xF8, state[1]);
2527300016Sadrian
2528300016Sadrian	switch (state[2]) {
2529300016Sadrian	case 1:
2530300016Sadrian		bwn_nphy_rssi_select(mac, 1, N_RSSI_NB);
2531300016Sadrian		break;
2532300016Sadrian	case 4:
2533300016Sadrian		bwn_nphy_rssi_select(mac, 1, N_RSSI_W1);
2534300016Sadrian		break;
2535300016Sadrian	case 2:
2536300016Sadrian		bwn_nphy_rssi_select(mac, 1, N_RSSI_W2);
2537300016Sadrian		break;
2538300016Sadrian	default:
2539300016Sadrian		bwn_nphy_rssi_select(mac, 1, N_RSSI_W2);
2540300016Sadrian		break;
2541300016Sadrian	}
2542300016Sadrian
2543300016Sadrian	switch (state[3]) {
2544300016Sadrian	case 1:
2545300016Sadrian		bwn_nphy_rssi_select(mac, 2, N_RSSI_NB);
2546300016Sadrian		break;
2547300016Sadrian	case 4:
2548300016Sadrian		bwn_nphy_rssi_select(mac, 2, N_RSSI_W1);
2549300016Sadrian		break;
2550300016Sadrian	default:
2551300016Sadrian		bwn_nphy_rssi_select(mac, 2, N_RSSI_W2);
2552300016Sadrian		break;
2553300016Sadrian	}
2554300016Sadrian
2555300016Sadrian	bwn_nphy_rssi_select(mac, 0, type);
2556300016Sadrian
2557300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1, regs_save_phy[0]);
2558300016Sadrian	BWN_RF_WRITE(mac, B2055_C1_PD_RXTX, regs_save_radio[0]);
2559300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2, regs_save_phy[1]);
2560300016Sadrian	BWN_RF_WRITE(mac, B2055_C2_PD_RXTX, regs_save_radio[1]);
2561300016Sadrian
2562300016Sadrian	bwn_nphy_classifier(mac, 7, class);
2563300016Sadrian	bwn_nphy_write_clip_detection(mac, clip_state);
2564300016Sadrian	/* Specs don't say about reset here, but it makes wl and b43 dumps
2565300016Sadrian	   identical, it really seems wl performs this */
2566300016Sadrian	bwn_nphy_reset_cca(mac);
2567300016Sadrian}
2568300016Sadrian
2569300016Sadrian/*
2570300016Sadrian * RSSI Calibration
2571300016Sadrian * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal
2572300016Sadrian */
2573300016Sadrianstatic void bwn_nphy_rssi_cal(struct bwn_mac *mac)
2574300016Sadrian{
2575300016Sadrian	if (mac->mac_phy.rev >= 19) {
2576300016Sadrian		/* TODO */
2577300016Sadrian	} else if (mac->mac_phy.rev >= 3) {
2578300016Sadrian		bwn_nphy_rev3_rssi_cal(mac);
2579300016Sadrian	} else {
2580300016Sadrian		bwn_nphy_rev2_rssi_cal(mac, N_RSSI_NB);
2581300016Sadrian		bwn_nphy_rev2_rssi_cal(mac, N_RSSI_W1);
2582300016Sadrian		bwn_nphy_rev2_rssi_cal(mac, N_RSSI_W2);
2583300016Sadrian	}
2584300016Sadrian}
2585300016Sadrian
2586300016Sadrian/**************************************************
2587300016Sadrian * Workarounds
2588300016Sadrian **************************************************/
2589300016Sadrian
2590300016Sadrianstatic void bwn_nphy_gain_ctl_workarounds_rev19(struct bwn_mac *mac)
2591300016Sadrian{
2592300016Sadrian	/* TODO */
2593300016Sadrian}
2594300016Sadrian
2595300016Sadrianstatic void bwn_nphy_gain_ctl_workarounds_rev7(struct bwn_mac *mac)
2596300016Sadrian{
2597300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2598300016Sadrian
2599300016Sadrian	switch (phy->rev) {
2600300016Sadrian	/* TODO */
2601300016Sadrian	}
2602300016Sadrian}
2603300016Sadrian
2604300016Sadrianstatic void bwn_nphy_gain_ctl_workarounds_rev3(struct bwn_mac *mac)
2605300016Sadrian{
2606300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
2607300016Sadrian	bool ghz5;
2608300016Sadrian	bool ext_lna;
2609300016Sadrian	uint16_t rssi_gain;
2610300016Sadrian	struct bwn_nphy_gain_ctl_workaround_entry *e;
2611300016Sadrian	uint8_t lpf_gain[6] = { 0x00, 0x06, 0x0C, 0x12, 0x12, 0x12 };
2612300016Sadrian	uint8_t lpf_bits[6] = { 0, 1, 2, 3, 3, 3 };
2613300016Sadrian
2614300016Sadrian	/* Prepare values */
2615300016Sadrian	ghz5 = BWN_PHY_READ(mac, BWN_NPHY_BANDCTL)
2616300016Sadrian		& BWN_NPHY_BANDCTL_5GHZ;
2617300016Sadrian	ext_lna = ghz5 ? siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_EXTLNA_5GHZ :
2618300016Sadrian		siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA;
2619300016Sadrian	e = bwn_nphy_get_gain_ctl_workaround_ent(mac, ghz5, ext_lna);
2620300016Sadrian	if (ghz5 && mac->mac_phy.rev >= 5)
2621300016Sadrian		rssi_gain = 0x90;
2622300016Sadrian	else
2623300016Sadrian		rssi_gain = 0x50;
2624300016Sadrian
2625300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_RXCTL, 0x0040);
2626300016Sadrian
2627300016Sadrian	/* Set Clip 2 detect */
2628300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_C1_CGAINI, BWN_NPHY_C1_CGAINI_CL2DETECT);
2629300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_C2_CGAINI, BWN_NPHY_C2_CGAINI_CL2DETECT);
2630300016Sadrian
2631300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_BIASPOLE_LNAG1_IDAC,
2632300016Sadrian			0x17);
2633300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_BIASPOLE_LNAG1_IDAC,
2634300016Sadrian			0x17);
2635300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_LNAG2_IDAC, 0xF0);
2636300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_LNAG2_IDAC, 0xF0);
2637300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_RSSI_POLE, 0x00);
2638300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_RSSI_POLE, 0x00);
2639300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_RSSI_GAIN,
2640300016Sadrian			rssi_gain);
2641300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_RSSI_GAIN,
2642300016Sadrian			rssi_gain);
2643300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_BIASPOLE_LNAA1_IDAC,
2644300016Sadrian			0x17);
2645300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_BIASPOLE_LNAA1_IDAC,
2646300016Sadrian			0x17);
2647300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_LNAA2_IDAC, 0xFF);
2648300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_LNAA2_IDAC, 0xFF);
2649300016Sadrian
2650300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(0, 8), 4, e->lna1_gain);
2651300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(1, 8), 4, e->lna1_gain);
2652300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(0, 16), 4, e->lna2_gain);
2653300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(1, 16), 4, e->lna2_gain);
2654300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(0, 32), 10, e->gain_db);
2655300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(1, 32), 10, e->gain_db);
2656300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(2, 32), 10, e->gain_bits);
2657300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(3, 32), 10, e->gain_bits);
2658300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(0, 0x40), 6, lpf_gain);
2659300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(1, 0x40), 6, lpf_gain);
2660300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(2, 0x40), 6, lpf_bits);
2661300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(3, 0x40), 6, lpf_bits);
2662300016Sadrian
2663300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C1_INITGAIN_A, e->init_gain);
2664300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C2_INITGAIN_A, e->init_gain);
2665300016Sadrian
2666300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(7, 0x106), 2,
2667300016Sadrian				e->rfseq_init);
2668300016Sadrian
2669300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C1_CLIP_HIGAIN_A, e->cliphi_gain);
2670300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C2_CLIP_HIGAIN_A, e->cliphi_gain);
2671300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C1_CLIP_MEDGAIN_A, e->clipmd_gain);
2672300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C2_CLIP_MEDGAIN_A, e->clipmd_gain);
2673300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C1_CLIP_LOGAIN_A, e->cliplo_gain);
2674300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C2_CLIP_LOGAIN_A, e->cliplo_gain);
2675300016Sadrian
2676300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_CRSMINPOWER0, 0xFF00, e->crsmin);
2677300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_CRSMINPOWERL0, 0xFF00, e->crsminl);
2678300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_CRSMINPOWERU0, 0xFF00, e->crsminu);
2679300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_C1_NBCLIPTHRES, e->nbclip);
2680300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_C2_NBCLIPTHRES, e->nbclip);
2681300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_C1_CLIPWBTHRES,
2682300016Sadrian			~BWN_NPHY_C1_CLIPWBTHRES_CLIP2, e->wlclip);
2683300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_C2_CLIPWBTHRES,
2684300016Sadrian			~BWN_NPHY_C2_CLIPWBTHRES_CLIP2, e->wlclip);
2685300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_CCK_SHIFTB_REF, 0x809C);
2686300016Sadrian}
2687300016Sadrian
2688300016Sadrianstatic void bwn_nphy_gain_ctl_workarounds_rev1_2(struct bwn_mac *mac)
2689300016Sadrian{
2690300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
2691300016Sadrian
2692300016Sadrian	uint8_t i, j;
2693300016Sadrian	uint8_t code;
2694300016Sadrian	uint16_t tmp;
2695300016Sadrian	uint8_t rfseq_events[3] = { 6, 8, 7 };
2696300016Sadrian	uint8_t rfseq_delays[3] = { 10, 30, 1 };
2697300016Sadrian
2698300016Sadrian	/* Set Clip 2 detect */
2699300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_C1_CGAINI, BWN_NPHY_C1_CGAINI_CL2DETECT);
2700300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_C2_CGAINI, BWN_NPHY_C2_CGAINI_CL2DETECT);
2701300016Sadrian
2702300016Sadrian	/* Set narrowband clip threshold */
2703300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_C1_NBCLIPTHRES, 0x84);
2704300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_C2_NBCLIPTHRES, 0x84);
2705300016Sadrian
2706300016Sadrian	if (!bwn_is_40mhz(mac)) {
2707300016Sadrian		/* Set dwell lengths */
2708300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
2709300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
2710300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_W1CLIP1_DWELL_LEN, 0x0009);
2711300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_W1CLIP2_DWELL_LEN, 0x0009);
2712300016Sadrian	}
2713300016Sadrian
2714300016Sadrian	/* Set wideband clip 2 threshold */
2715300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_C1_CLIPWBTHRES,
2716300016Sadrian			~BWN_NPHY_C1_CLIPWBTHRES_CLIP2, 21);
2717300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_C2_CLIPWBTHRES,
2718300016Sadrian			~BWN_NPHY_C2_CLIPWBTHRES_CLIP2, 21);
2719300016Sadrian
2720300016Sadrian	if (!bwn_is_40mhz(mac)) {
2721300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_C1_CGAINI,
2722300016Sadrian			~BWN_NPHY_C1_CGAINI_GAINBKOFF, 0x1);
2723300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_C2_CGAINI,
2724300016Sadrian			~BWN_NPHY_C2_CGAINI_GAINBKOFF, 0x1);
2725300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_C1_CCK_CGAINI,
2726300016Sadrian			~BWN_NPHY_C1_CCK_CGAINI_GAINBKOFF, 0x1);
2727300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_C2_CCK_CGAINI,
2728300016Sadrian			~BWN_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1);
2729300016Sadrian	}
2730300016Sadrian
2731300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_CCK_SHIFTB_REF, 0x809C);
2732300016Sadrian
2733300016Sadrian	if (nphy->gain_boost) {
2734300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G &&
2735300016Sadrian		    bwn_is_40mhz(mac))
2736300016Sadrian			code = 4;
2737300016Sadrian		else
2738300016Sadrian			code = 5;
2739300016Sadrian	} else {
2740300016Sadrian		code = bwn_is_40mhz(mac) ? 6 : 7;
2741300016Sadrian	}
2742300016Sadrian
2743300016Sadrian	/* Set HPVGA2 index */
2744300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_C1_INITGAIN, ~BWN_NPHY_C1_INITGAIN_HPVGA2,
2745300016Sadrian			code << BWN_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
2746300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_C2_INITGAIN, ~BWN_NPHY_C2_INITGAIN_HPVGA2,
2747300016Sadrian			code << BWN_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
2748300016Sadrian
2749300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_ADDR, 0x1D06);
2750300016Sadrian	/* specs say about 2 loops, but wl does 4 */
2751300016Sadrian	for (i = 0; i < 4; i++)
2752300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, (code << 8 | 0x7C));
2753300016Sadrian
2754300016Sadrian	bwn_nphy_adjust_lna_gain_table(mac);
2755300016Sadrian
2756300016Sadrian	if (nphy->elna_gain_config) {
2757300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_ADDR, 0x0808);
2758300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0x0);
2759300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0x1);
2760300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0x1);
2761300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0x1);
2762300016Sadrian
2763300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_ADDR, 0x0C08);
2764300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0x0);
2765300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0x1);
2766300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0x1);
2767300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0x1);
2768300016Sadrian
2769300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_ADDR, 0x1D06);
2770300016Sadrian		/* specs say about 2 loops, but wl does 4 */
2771300016Sadrian		for (i = 0; i < 4; i++)
2772300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO,
2773300016Sadrian						(code << 8 | 0x74));
2774300016Sadrian	}
2775300016Sadrian
2776300016Sadrian	if (mac->mac_phy.rev == 2) {
2777300016Sadrian		for (i = 0; i < 4; i++) {
2778300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_ADDR,
2779300016Sadrian					(0x0400 * i) + 0x0020);
2780300016Sadrian			for (j = 0; j < 21; j++) {
2781300016Sadrian				tmp = j * (i < 2 ? 3 : 1);
2782300016Sadrian				BWN_PHY_WRITE(mac,
2783300016Sadrian					BWN_NPHY_TABLE_DATALO, tmp);
2784300016Sadrian			}
2785300016Sadrian		}
2786300016Sadrian	}
2787300016Sadrian
2788300016Sadrian	bwn_nphy_set_rf_sequence(mac, 5, rfseq_events, rfseq_delays, 3);
2789300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_OVER_DGAIN1,
2790300016Sadrian		~BWN_NPHY_OVER_DGAIN_CCKDGECV & 0xFFFF,
2791300016Sadrian		0x5A << BWN_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
2792300016Sadrian
2793300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G)
2794300016Sadrian		BWN_PHY_SETMASK(mac, BWN_PHY_N(0xC5D), 0xFF80, 4);
2795300016Sadrian}
2796300016Sadrian
2797300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
2798300016Sadrianstatic void bwn_nphy_gain_ctl_workarounds(struct bwn_mac *mac)
2799300016Sadrian{
2800300016Sadrian	if (mac->mac_phy.rev >= 19)
2801300016Sadrian		bwn_nphy_gain_ctl_workarounds_rev19(mac);
2802300016Sadrian	else if (mac->mac_phy.rev >= 7)
2803300016Sadrian		bwn_nphy_gain_ctl_workarounds_rev7(mac);
2804300016Sadrian	else if (mac->mac_phy.rev >= 3)
2805300016Sadrian		bwn_nphy_gain_ctl_workarounds_rev3(mac);
2806300016Sadrian	else
2807300016Sadrian		bwn_nphy_gain_ctl_workarounds_rev1_2(mac);
2808300016Sadrian}
2809300016Sadrian
2810300016Sadrianstatic void bwn_nphy_workarounds_rev7plus(struct bwn_mac *mac)
2811300016Sadrian{
2812300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
2813300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
2814300016Sadrian
2815300016Sadrian	/* TX to RX */
2816300016Sadrian	uint8_t tx2rx_events[7] = { 4, 3, 5, 2, 1, 8, 31, };
2817300016Sadrian	uint8_t tx2rx_delays[7] = { 8, 4, 4, 4, 4, 6, 1, };
2818300016Sadrian	/* RX to TX */
2819300016Sadrian	uint8_t rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3,
2820300016Sadrian					0x1F };
2821300016Sadrian	uint8_t rx2tx_delays_ipa[9] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
2822300016Sadrian
2823300016Sadrian	static const uint16_t ntab7_15e_16e[] = { 0, 0x10f, 0x10f };
2824300016Sadrian	uint8_t ntab7_138_146[] = { 0x11, 0x11 };
2825300016Sadrian	uint8_t ntab7_133[] = { 0x77, 0x11, 0x11 };
2826300016Sadrian
2827300016Sadrian	uint16_t lpf_ofdm_20mhz[2], lpf_ofdm_40mhz[2], lpf_11b[2];
2828300016Sadrian	uint16_t bcap_val;
2829300016Sadrian	int16_t bcap_val_11b[2], bcap_val_11n_20[2], bcap_val_11n_40[2];
2830300016Sadrian	uint16_t scap_val;
2831300016Sadrian	int16_t scap_val_11b[2], scap_val_11n_20[2], scap_val_11n_40[2];
2832300016Sadrian	bool rccal_ovrd = false;
2833300016Sadrian
2834300016Sadrian	uint16_t bias, conv, filt;
2835300016Sadrian
2836300016Sadrian	uint32_t noise_tbl[2];
2837300016Sadrian
2838300016Sadrian	uint32_t tmp32;
2839300016Sadrian	uint8_t core;
2840300016Sadrian
2841300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_A0, 0x0125);
2842300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_A1, 0x01b3);
2843300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_A2, 0x0105);
2844300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_B0, 0x016e);
2845300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_B1, 0x00cd);
2846300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_B2, 0x0020);
2847300016Sadrian
2848300016Sadrian	if (phy->rev == 7) {
2849300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_FINERX2_CGC, 0x10);
2850300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN0, 0xFF80, 0x0020);
2851300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN0, 0x80FF, 0x2700);
2852300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN1, 0xFF80, 0x002E);
2853300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN1, 0x80FF, 0x3300);
2854300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN2, 0xFF80, 0x0037);
2855300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN2, 0x80FF, 0x3A00);
2856300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN3, 0xFF80, 0x003C);
2857300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN3, 0x80FF, 0x3E00);
2858300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN4, 0xFF80, 0x003E);
2859300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN4, 0x80FF, 0x3F00);
2860300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN5, 0xFF80, 0x0040);
2861300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN5, 0x80FF, 0x4000);
2862300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN6, 0xFF80, 0x0040);
2863300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN6, 0x80FF, 0x4000);
2864300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN7, 0xFF80, 0x0040);
2865300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_FREQGAIN7, 0x80FF, 0x4000);
2866300016Sadrian	}
2867300016Sadrian
2868300016Sadrian	if (phy->rev >= 16) {
2869300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_FORCEFRONT0, 0x7ff);
2870300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_FORCEFRONT1, 0x7ff);
2871300016Sadrian	} else if (phy->rev <= 8) {
2872300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_FORCEFRONT0, 0x1B0);
2873300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_FORCEFRONT1, 0x1B0);
2874300016Sadrian	}
2875300016Sadrian
2876300016Sadrian	if (phy->rev >= 16)
2877300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_TXTAILCNT, ~0xFF, 0xa0);
2878300016Sadrian	else if (phy->rev >= 8)
2879300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_TXTAILCNT, ~0xFF, 0x72);
2880300016Sadrian
2881300016Sadrian	bwn_ntab_write(mac, BWN_NTAB16(8, 0x00), 2);
2882300016Sadrian	bwn_ntab_write(mac, BWN_NTAB16(8, 0x10), 2);
2883300016Sadrian	tmp32 = bwn_ntab_read(mac, BWN_NTAB32(30, 0));
2884300016Sadrian	tmp32 &= 0xffffff;
2885300016Sadrian	bwn_ntab_write(mac, BWN_NTAB32(30, 0), tmp32);
2886300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(7, 0x15d), 3, ntab7_15e_16e);
2887300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(7, 0x16d), 3, ntab7_15e_16e);
2888300016Sadrian
2889300016Sadrian	bwn_nphy_set_rf_sequence(mac, 1, tx2rx_events, tx2rx_delays,
2890300016Sadrian				 nitems(tx2rx_events));
2891300016Sadrian	if (bwn_nphy_ipa(mac))
2892300016Sadrian		bwn_nphy_set_rf_sequence(mac, 0, rx2tx_events_ipa,
2893300016Sadrian				rx2tx_delays_ipa, nitems(rx2tx_events_ipa));
2894300016Sadrian
2895300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_EPS_OVERRIDEI_0, 0x3FFF, 0x4000);
2896300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_EPS_OVERRIDEI_1, 0x3FFF, 0x4000);
2897300016Sadrian
2898300016Sadrian	for (core = 0; core < 2; core++) {
2899300016Sadrian		lpf_ofdm_20mhz[core] = bwn_nphy_read_lpf_ctl(mac, 0x154 + core * 0x10);
2900300016Sadrian		lpf_ofdm_40mhz[core] = bwn_nphy_read_lpf_ctl(mac, 0x159 + core * 0x10);
2901300016Sadrian		lpf_11b[core] = bwn_nphy_read_lpf_ctl(mac, 0x152 + core * 0x10);
2902300016Sadrian	}
2903300016Sadrian
2904300016Sadrian	bcap_val = BWN_RF_READ(mac, R2057_RCCAL_BCAP_VAL);
2905300016Sadrian	scap_val = BWN_RF_READ(mac, R2057_RCCAL_SCAP_VAL);
2906300016Sadrian
2907300016Sadrian	if (bwn_nphy_ipa(mac)) {
2908300016Sadrian		bool ghz2 = bwn_current_band(mac) == BWN_BAND_2G;
2909300016Sadrian
2910300016Sadrian		switch (phy->rf_rev) {
2911300016Sadrian		case 5:
2912300016Sadrian			/* Check radio version (to be 0) by PHY rev for now */
2913300016Sadrian			if (phy->rev == 8 && bwn_is_40mhz(mac)) {
2914300016Sadrian				for (core = 0; core < 2; core++) {
2915300016Sadrian					scap_val_11b[core] = scap_val;
2916300016Sadrian					bcap_val_11b[core] = bcap_val;
2917300016Sadrian					scap_val_11n_20[core] = scap_val;
2918300016Sadrian					bcap_val_11n_20[core] = bcap_val;
2919300016Sadrian					scap_val_11n_40[core] = 0xc;
2920300016Sadrian					bcap_val_11n_40[core] = 0xc;
2921300016Sadrian				}
2922300016Sadrian
2923300016Sadrian				rccal_ovrd = true;
2924300016Sadrian			}
2925300016Sadrian			if (phy->rev == 9) {
2926300016Sadrian				/* TODO: Radio version 1 (e.g. BCM5357B0) */
2927300016Sadrian			}
2928300016Sadrian			break;
2929300016Sadrian		case 7:
2930300016Sadrian		case 8:
2931300016Sadrian			for (core = 0; core < 2; core++) {
2932300016Sadrian				scap_val_11b[core] = scap_val;
2933300016Sadrian				bcap_val_11b[core] = bcap_val;
2934300016Sadrian				lpf_ofdm_20mhz[core] = 4;
2935300016Sadrian				lpf_11b[core] = 1;
2936300016Sadrian				if (bwn_current_band(mac) == BWN_BAND_2G) {
2937300016Sadrian					scap_val_11n_20[core] = 0xc;
2938300016Sadrian					bcap_val_11n_20[core] = 0xc;
2939300016Sadrian					scap_val_11n_40[core] = 0xa;
2940300016Sadrian					bcap_val_11n_40[core] = 0xa;
2941300016Sadrian				} else {
2942300016Sadrian					scap_val_11n_20[core] = 0x14;
2943300016Sadrian					bcap_val_11n_20[core] = 0x14;
2944300016Sadrian					scap_val_11n_40[core] = 0xf;
2945300016Sadrian					bcap_val_11n_40[core] = 0xf;
2946300016Sadrian				}
2947300016Sadrian			}
2948300016Sadrian
2949300016Sadrian			rccal_ovrd = true;
2950300016Sadrian			break;
2951300016Sadrian		case 9:
2952300016Sadrian			for (core = 0; core < 2; core++) {
2953300016Sadrian				bcap_val_11b[core] = bcap_val;
2954300016Sadrian				scap_val_11b[core] = scap_val;
2955300016Sadrian				lpf_11b[core] = 1;
2956300016Sadrian
2957300016Sadrian				if (ghz2) {
2958300016Sadrian					bcap_val_11n_20[core] = bcap_val + 13;
2959300016Sadrian					scap_val_11n_20[core] = scap_val + 15;
2960300016Sadrian				} else {
2961300016Sadrian					bcap_val_11n_20[core] = bcap_val + 14;
2962300016Sadrian					scap_val_11n_20[core] = scap_val + 15;
2963300016Sadrian				}
2964300016Sadrian				lpf_ofdm_20mhz[core] = 4;
2965300016Sadrian
2966300016Sadrian				if (ghz2) {
2967300016Sadrian					bcap_val_11n_40[core] = bcap_val - 7;
2968300016Sadrian					scap_val_11n_40[core] = scap_val - 5;
2969300016Sadrian				} else {
2970300016Sadrian					bcap_val_11n_40[core] = bcap_val + 2;
2971300016Sadrian					scap_val_11n_40[core] = scap_val + 4;
2972300016Sadrian				}
2973300016Sadrian				lpf_ofdm_40mhz[core] = 4;
2974300016Sadrian			}
2975300016Sadrian
2976300016Sadrian			rccal_ovrd = true;
2977300016Sadrian			break;
2978300016Sadrian		case 14:
2979300016Sadrian			for (core = 0; core < 2; core++) {
2980300016Sadrian				bcap_val_11b[core] = bcap_val;
2981300016Sadrian				scap_val_11b[core] = scap_val;
2982300016Sadrian				lpf_11b[core] = 1;
2983300016Sadrian			}
2984300016Sadrian
2985300016Sadrian			bcap_val_11n_20[0] = bcap_val + 20;
2986300016Sadrian			scap_val_11n_20[0] = scap_val + 20;
2987300016Sadrian			lpf_ofdm_20mhz[0] = 3;
2988300016Sadrian
2989300016Sadrian			bcap_val_11n_20[1] = bcap_val + 16;
2990300016Sadrian			scap_val_11n_20[1] = scap_val + 16;
2991300016Sadrian			lpf_ofdm_20mhz[1] = 3;
2992300016Sadrian
2993300016Sadrian			bcap_val_11n_40[0] = bcap_val + 20;
2994300016Sadrian			scap_val_11n_40[0] = scap_val + 20;
2995300016Sadrian			lpf_ofdm_40mhz[0] = 4;
2996300016Sadrian
2997300016Sadrian			bcap_val_11n_40[1] = bcap_val + 10;
2998300016Sadrian			scap_val_11n_40[1] = scap_val + 10;
2999300016Sadrian			lpf_ofdm_40mhz[1] = 4;
3000300016Sadrian
3001300016Sadrian			rccal_ovrd = true;
3002300016Sadrian			break;
3003300016Sadrian		}
3004300016Sadrian	} else {
3005300016Sadrian		if (phy->rf_rev == 5) {
3006300016Sadrian			for (core = 0; core < 2; core++) {
3007300016Sadrian				lpf_ofdm_20mhz[core] = 1;
3008300016Sadrian				lpf_ofdm_40mhz[core] = 3;
3009300016Sadrian				scap_val_11b[core] = scap_val;
3010300016Sadrian				bcap_val_11b[core] = bcap_val;
3011300016Sadrian				scap_val_11n_20[core] = 0x11;
3012300016Sadrian				scap_val_11n_40[core] = 0x11;
3013300016Sadrian				bcap_val_11n_20[core] = 0x13;
3014300016Sadrian				bcap_val_11n_40[core] = 0x13;
3015300016Sadrian			}
3016300016Sadrian
3017300016Sadrian			rccal_ovrd = true;
3018300016Sadrian		}
3019300016Sadrian	}
3020300016Sadrian	if (rccal_ovrd) {
3021300016Sadrian		uint16_t rx2tx_lut_20_11b[2], rx2tx_lut_20_11n[2], rx2tx_lut_40_11n[2];
3022300016Sadrian		uint8_t rx2tx_lut_extra = 1;
3023300016Sadrian
3024300016Sadrian		for (core = 0; core < 2; core++) {
3025300016Sadrian			bcap_val_11b[core] = bwn_clamp_val(bcap_val_11b[core], 0, 0x1f);
3026300016Sadrian			scap_val_11b[core] = bwn_clamp_val(scap_val_11b[core], 0, 0x1f);
3027300016Sadrian			bcap_val_11n_20[core] = bwn_clamp_val(bcap_val_11n_20[core], 0, 0x1f);
3028300016Sadrian			scap_val_11n_20[core] = bwn_clamp_val(scap_val_11n_20[core], 0, 0x1f);
3029300016Sadrian			bcap_val_11n_40[core] = bwn_clamp_val(bcap_val_11n_40[core], 0, 0x1f);
3030300016Sadrian			scap_val_11n_40[core] = bwn_clamp_val(scap_val_11n_40[core], 0, 0x1f);
3031300016Sadrian
3032300016Sadrian			rx2tx_lut_20_11b[core] = (rx2tx_lut_extra << 13) |
3033300016Sadrian						 (bcap_val_11b[core] << 8) |
3034300016Sadrian						 (scap_val_11b[core] << 3) |
3035300016Sadrian						 lpf_11b[core];
3036300016Sadrian			rx2tx_lut_20_11n[core] = (rx2tx_lut_extra << 13) |
3037300016Sadrian						 (bcap_val_11n_20[core] << 8) |
3038300016Sadrian						 (scap_val_11n_20[core] << 3) |
3039300016Sadrian						 lpf_ofdm_20mhz[core];
3040300016Sadrian			rx2tx_lut_40_11n[core] = (rx2tx_lut_extra << 13) |
3041300016Sadrian						 (bcap_val_11n_40[core] << 8) |
3042300016Sadrian						 (scap_val_11n_40[core] << 3) |
3043300016Sadrian						 lpf_ofdm_40mhz[core];
3044300016Sadrian		}
3045300016Sadrian
3046300016Sadrian		for (core = 0; core < 2; core++) {
3047300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(7, 0x152 + core * 16),
3048300016Sadrian				       rx2tx_lut_20_11b[core]);
3049300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(7, 0x153 + core * 16),
3050300016Sadrian				       rx2tx_lut_20_11n[core]);
3051300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(7, 0x154 + core * 16),
3052300016Sadrian				       rx2tx_lut_20_11n[core]);
3053300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(7, 0x155 + core * 16),
3054300016Sadrian				       rx2tx_lut_40_11n[core]);
3055300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(7, 0x156 + core * 16),
3056300016Sadrian				       rx2tx_lut_40_11n[core]);
3057300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(7, 0x157 + core * 16),
3058300016Sadrian				       rx2tx_lut_40_11n[core]);
3059300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(7, 0x158 + core * 16),
3060300016Sadrian				       rx2tx_lut_40_11n[core]);
3061300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(7, 0x159 + core * 16),
3062300016Sadrian				       rx2tx_lut_40_11n[core]);
3063300016Sadrian		}
3064300016Sadrian	}
3065300016Sadrian
3066300016Sadrian	BWN_PHY_WRITE(mac, 0x32F, 0x3);
3067300016Sadrian
3068300016Sadrian	if (phy->rf_rev == 4 || phy->rf_rev == 6)
3069300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 4, 1, 3, false, 0);
3070300016Sadrian
3071300016Sadrian	if (phy->rf_rev == 3 || phy->rf_rev == 4 || phy->rf_rev == 6) {
3072300016Sadrian		if (siba_sprom_get_rev(sc->sc_dev) &&
3073300016Sadrian		    siba_sprom_get_bf2_hi(sc->sc_dev) & BWN_BFH2_IPALVLSHIFT_3P3) {
3074300016Sadrian			BWN_RF_WRITE(mac, 0x5, 0x05);
3075300016Sadrian			BWN_RF_WRITE(mac, 0x6, 0x30);
3076300016Sadrian			BWN_RF_WRITE(mac, 0x7, 0x00);
3077300016Sadrian			BWN_RF_SET(mac, 0x4f, 0x1);
3078300016Sadrian			BWN_RF_SET(mac, 0xd4, 0x1);
3079300016Sadrian			bias = 0x1f;
3080300016Sadrian			conv = 0x6f;
3081300016Sadrian			filt = 0xaa;
3082300016Sadrian		} else {
3083300016Sadrian			bias = 0x2b;
3084300016Sadrian			conv = 0x7f;
3085300016Sadrian			filt = 0xee;
3086300016Sadrian		}
3087300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G) {
3088300016Sadrian			for (core = 0; core < 2; core++) {
3089300016Sadrian				if (core == 0) {
3090300016Sadrian					BWN_RF_WRITE(mac, 0x5F, bias);
3091300016Sadrian					BWN_RF_WRITE(mac, 0x64, conv);
3092300016Sadrian					BWN_RF_WRITE(mac, 0x66, filt);
3093300016Sadrian				} else {
3094300016Sadrian					BWN_RF_WRITE(mac, 0xE8, bias);
3095300016Sadrian					BWN_RF_WRITE(mac, 0xE9, conv);
3096300016Sadrian					BWN_RF_WRITE(mac, 0xEB, filt);
3097300016Sadrian				}
3098300016Sadrian			}
3099300016Sadrian		}
3100300016Sadrian	}
3101300016Sadrian
3102300016Sadrian	if (bwn_nphy_ipa(mac)) {
3103300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G) {
3104300016Sadrian			if (phy->rf_rev == 3 || phy->rf_rev == 4 ||
3105300016Sadrian			    phy->rf_rev == 6) {
3106300016Sadrian				for (core = 0; core < 2; core++) {
3107300016Sadrian					if (core == 0)
3108300016Sadrian						BWN_RF_WRITE(mac, 0x51,
3109300016Sadrian								0x7f);
3110300016Sadrian					else
3111300016Sadrian						BWN_RF_WRITE(mac, 0xd6,
3112300016Sadrian								0x7f);
3113300016Sadrian				}
3114300016Sadrian			}
3115300016Sadrian			switch (phy->rf_rev) {
3116300016Sadrian			case 3:
3117300016Sadrian				for (core = 0; core < 2; core++) {
3118300016Sadrian					if (core == 0) {
3119300016Sadrian						BWN_RF_WRITE(mac, 0x64,
3120300016Sadrian								0x13);
3121300016Sadrian						BWN_RF_WRITE(mac, 0x5F,
3122300016Sadrian								0x1F);
3123300016Sadrian						BWN_RF_WRITE(mac, 0x66,
3124300016Sadrian								0xEE);
3125300016Sadrian						BWN_RF_WRITE(mac, 0x59,
3126300016Sadrian								0x8A);
3127300016Sadrian						BWN_RF_WRITE(mac, 0x80,
3128300016Sadrian								0x3E);
3129300016Sadrian					} else {
3130300016Sadrian						BWN_RF_WRITE(mac, 0x69,
3131300016Sadrian								0x13);
3132300016Sadrian						BWN_RF_WRITE(mac, 0xE8,
3133300016Sadrian								0x1F);
3134300016Sadrian						BWN_RF_WRITE(mac, 0xEB,
3135300016Sadrian								0xEE);
3136300016Sadrian						BWN_RF_WRITE(mac, 0xDE,
3137300016Sadrian								0x8A);
3138300016Sadrian						BWN_RF_WRITE(mac, 0x105,
3139300016Sadrian								0x3E);
3140300016Sadrian					}
3141300016Sadrian				}
3142300016Sadrian				break;
3143300016Sadrian			case 7:
3144300016Sadrian			case 8:
3145300016Sadrian				if (!bwn_is_40mhz(mac)) {
3146300016Sadrian					BWN_RF_WRITE(mac, 0x5F, 0x14);
3147300016Sadrian					BWN_RF_WRITE(mac, 0xE8, 0x12);
3148300016Sadrian				} else {
3149300016Sadrian					BWN_RF_WRITE(mac, 0x5F, 0x16);
3150300016Sadrian					BWN_RF_WRITE(mac, 0xE8, 0x16);
3151300016Sadrian				}
3152300016Sadrian				break;
3153300016Sadrian			case 14:
3154300016Sadrian				for (core = 0; core < 2; core++) {
3155300016Sadrian					int o = core ? 0x85 : 0;
3156300016Sadrian
3157300016Sadrian					BWN_RF_WRITE(mac, o + R2057_IPA2G_CASCONV_CORE0, 0x13);
3158300016Sadrian					BWN_RF_WRITE(mac, o + R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, 0x21);
3159300016Sadrian					BWN_RF_WRITE(mac, o + R2057_IPA2G_BIAS_FILTER_CORE0, 0xff);
3160300016Sadrian					BWN_RF_WRITE(mac, o + R2057_PAD2G_IDACS_CORE0, 0x88);
3161300016Sadrian					BWN_RF_WRITE(mac, o + R2057_PAD2G_TUNE_PUS_CORE0, 0x23);
3162300016Sadrian					BWN_RF_WRITE(mac, o + R2057_IPA2G_IMAIN_CORE0, 0x16);
3163300016Sadrian					BWN_RF_WRITE(mac, o + R2057_PAD_BIAS_FILTER_BWS_CORE0, 0x3e);
3164300016Sadrian					BWN_RF_WRITE(mac, o + R2057_BACKUP1_CORE0, 0x10);
3165300016Sadrian				}
3166300016Sadrian				break;
3167300016Sadrian			}
3168300016Sadrian		} else {
3169300016Sadrian			uint16_t freq = bwn_get_centre_freq(mac);
3170300016Sadrian			if ((freq >= 5180 && freq <= 5230) ||
3171300016Sadrian			    (freq >= 5745 && freq <= 5805)) {
3172300016Sadrian				BWN_RF_WRITE(mac, 0x7D, 0xFF);
3173300016Sadrian				BWN_RF_WRITE(mac, 0xFE, 0xFF);
3174300016Sadrian			}
3175300016Sadrian		}
3176300016Sadrian	} else {
3177300016Sadrian		if (phy->rf_rev != 5) {
3178300016Sadrian			for (core = 0; core < 2; core++) {
3179300016Sadrian				if (core == 0) {
3180300016Sadrian					BWN_RF_WRITE(mac, 0x5c, 0x61);
3181300016Sadrian					BWN_RF_WRITE(mac, 0x51, 0x70);
3182300016Sadrian				} else {
3183300016Sadrian					BWN_RF_WRITE(mac, 0xe1, 0x61);
3184300016Sadrian					BWN_RF_WRITE(mac, 0xd6, 0x70);
3185300016Sadrian				}
3186300016Sadrian			}
3187300016Sadrian		}
3188300016Sadrian	}
3189300016Sadrian
3190300016Sadrian	if (phy->rf_rev == 4) {
3191300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x05), 0x20);
3192300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x15), 0x20);
3193300016Sadrian		for (core = 0; core < 2; core++) {
3194300016Sadrian			if (core == 0) {
3195300016Sadrian				BWN_RF_WRITE(mac, 0x1a1, 0x00);
3196300016Sadrian				BWN_RF_WRITE(mac, 0x1a2, 0x3f);
3197300016Sadrian				BWN_RF_WRITE(mac, 0x1a6, 0x3f);
3198300016Sadrian			} else {
3199300016Sadrian				BWN_RF_WRITE(mac, 0x1a7, 0x00);
3200300016Sadrian				BWN_RF_WRITE(mac, 0x1ab, 0x3f);
3201300016Sadrian				BWN_RF_WRITE(mac, 0x1ac, 0x3f);
3202300016Sadrian			}
3203300016Sadrian		}
3204300016Sadrian	} else {
3205300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_C1, 0x4);
3206300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER1, 0x4);
3207300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_C2, 0x4);
3208300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER, 0x4);
3209300016Sadrian
3210300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_C1, ~0x1);
3211300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER1, 0x1);
3212300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_C2, ~0x1);
3213300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER, 0x1);
3214300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x05), 0);
3215300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x15), 0);
3216300016Sadrian
3217300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_C1, ~0x4);
3218300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_OVER1, ~0x4);
3219300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_C2, ~0x4);
3220300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_OVER, ~0x4);
3221300016Sadrian	}
3222300016Sadrian
3223300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ENDROP_TLEN, 0x2);
3224300016Sadrian
3225300016Sadrian	bwn_ntab_write(mac, BWN_NTAB32(16, 0x100), 20);
3226300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(7, 0x138), 2, ntab7_138_146);
3227300016Sadrian	bwn_ntab_write(mac, BWN_NTAB16(7, 0x141), 0x77);
3228300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(7, 0x133), 3, ntab7_133);
3229300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB8(7, 0x146), 2, ntab7_138_146);
3230300016Sadrian	bwn_ntab_write(mac, BWN_NTAB16(7, 0x123), 0x77);
3231300016Sadrian	bwn_ntab_write(mac, BWN_NTAB16(7, 0x12A), 0x77);
3232300016Sadrian
3233300016Sadrian	bwn_ntab_read_bulk(mac, BWN_NTAB32(16, 0x02), 1, noise_tbl);
3234300016Sadrian	noise_tbl[1] = bwn_is_40mhz(mac) ? 0x14D : 0x18D;
3235300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB32(16, 0x02), 2, noise_tbl);
3236300016Sadrian
3237300016Sadrian	bwn_ntab_read_bulk(mac, BWN_NTAB32(16, 0x7E), 1, noise_tbl);
3238300016Sadrian	noise_tbl[1] = bwn_is_40mhz(mac) ? 0x14D : 0x18D;
3239300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB32(16, 0x7E), 2, noise_tbl);
3240300016Sadrian
3241300016Sadrian	bwn_nphy_gain_ctl_workarounds(mac);
3242300016Sadrian
3243300016Sadrian	/* TODO
3244300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x08), 4,
3245300016Sadrian			    aux_adc_vmid_rev7_core0);
3246300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x18), 4,
3247300016Sadrian			    aux_adc_vmid_rev7_core1);
3248300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x0C), 4,
3249300016Sadrian			    aux_adc_gain_rev7);
3250300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x1C), 4,
3251300016Sadrian			    aux_adc_gain_rev7);
3252300016Sadrian	*/
3253300016Sadrian}
3254300016Sadrian
3255300016Sadrianstatic void bwn_nphy_workarounds_rev3plus(struct bwn_mac *mac)
3256300016Sadrian{
3257300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
3258300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
3259300016Sadrian
3260300016Sadrian	/* TX to RX */
3261300016Sadrian	uint8_t tx2rx_events[7] = { 0x4, 0x3, 0x5, 0x2, 0x1, 0x8, 0x1F };
3262300016Sadrian	uint8_t tx2rx_delays[7] = { 8, 4, 4, 4, 4, 6, 1 };
3263300016Sadrian	/* RX to TX */
3264300016Sadrian	uint8_t rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3,
3265300016Sadrian					0x1F };
3266300016Sadrian	uint8_t rx2tx_delays_ipa[9] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
3267300016Sadrian	uint8_t rx2tx_events[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0x3, 0x4, 0x1F };
3268300016Sadrian	uint8_t rx2tx_delays[9] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 };
3269300016Sadrian
3270300016Sadrian	uint16_t vmids[5][4] = {
3271300016Sadrian		{ 0xa2, 0xb4, 0xb4, 0x89, }, /* 0 */
3272300016Sadrian		{ 0xb4, 0xb4, 0xb4, 0x24, }, /* 1 */
3273300016Sadrian		{ 0xa2, 0xb4, 0xb4, 0x74, }, /* 2 */
3274300016Sadrian		{ 0xa2, 0xb4, 0xb4, 0x270, }, /* 3 */
3275300016Sadrian		{ 0xa2, 0xb4, 0xb4, 0x00, }, /* 4 and 5 */
3276300016Sadrian	};
3277300016Sadrian	uint16_t gains[5][4] = {
3278300016Sadrian		{ 0x02, 0x02, 0x02, 0x00, }, /* 0 */
3279300016Sadrian		{ 0x02, 0x02, 0x02, 0x02, }, /* 1 */
3280300016Sadrian		{ 0x02, 0x02, 0x02, 0x04, }, /* 2 */
3281300016Sadrian		{ 0x02, 0x02, 0x02, 0x00, }, /* 3 */
3282300016Sadrian		{ 0x02, 0x02, 0x02, 0x00, }, /* 4 and 5 */
3283300016Sadrian	};
3284300016Sadrian	uint16_t *vmid, *gain;
3285300016Sadrian
3286300016Sadrian	uint8_t pdet_range;
3287300016Sadrian	uint16_t tmp16;
3288300016Sadrian	uint32_t tmp32;
3289300016Sadrian
3290300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_FORCEFRONT0, 0x1f8);
3291300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_FORCEFRONT1, 0x1f8);
3292300016Sadrian
3293300016Sadrian	tmp32 = bwn_ntab_read(mac, BWN_NTAB32(30, 0));
3294300016Sadrian	tmp32 &= 0xffffff;
3295300016Sadrian	bwn_ntab_write(mac, BWN_NTAB32(30, 0), tmp32);
3296300016Sadrian
3297300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_A0, 0x0125);
3298300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_A1, 0x01B3);
3299300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_A2, 0x0105);
3300300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_B0, 0x016E);
3301300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_B1, 0x00CD);
3302300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_B2, 0x0020);
3303300016Sadrian
3304300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C1_CLIP_LOGAIN_B, 0x000C);
3305300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_REV3_C2_CLIP_LOGAIN_B, 0x000C);
3306300016Sadrian
3307300016Sadrian	/* TX to RX */
3308300016Sadrian	bwn_nphy_set_rf_sequence(mac, 1, tx2rx_events, tx2rx_delays,
3309300016Sadrian				 nitems(tx2rx_events));
3310300016Sadrian
3311300016Sadrian	/* RX to TX */
3312300016Sadrian	if (bwn_nphy_ipa(mac))
3313300016Sadrian		bwn_nphy_set_rf_sequence(mac, 0, rx2tx_events_ipa,
3314300016Sadrian				rx2tx_delays_ipa, nitems(rx2tx_events_ipa));
3315300016Sadrian	if (nphy->hw_phyrxchain != 3 &&
3316300016Sadrian	    nphy->hw_phyrxchain != nphy->hw_phytxchain) {
3317300016Sadrian		if (bwn_nphy_ipa(mac)) {
3318300016Sadrian			rx2tx_delays[5] = 59;
3319300016Sadrian			rx2tx_delays[6] = 1;
3320300016Sadrian			rx2tx_events[7] = 0x1F;
3321300016Sadrian		}
3322300016Sadrian		bwn_nphy_set_rf_sequence(mac, 0, rx2tx_events, rx2tx_delays,
3323300016Sadrian					 nitems(rx2tx_events));
3324300016Sadrian	}
3325300016Sadrian
3326300016Sadrian	tmp16 = (bwn_current_band(mac) == BWN_BAND_2G) ?
3327300016Sadrian		0x2 : 0x9C40;
3328300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ENDROP_TLEN, tmp16);
3329300016Sadrian
3330300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_SGILTRNOFFSET, 0xF0FF, 0x0700);
3331300016Sadrian
3332300016Sadrian	if (!bwn_is_40mhz(mac)) {
3333300016Sadrian		bwn_ntab_write(mac, BWN_NTAB32(16, 3), 0x18D);
3334300016Sadrian		bwn_ntab_write(mac, BWN_NTAB32(16, 127), 0x18D);
3335300016Sadrian	} else {
3336300016Sadrian		bwn_ntab_write(mac, BWN_NTAB32(16, 3), 0x14D);
3337300016Sadrian		bwn_ntab_write(mac, BWN_NTAB32(16, 127), 0x14D);
3338300016Sadrian	}
3339300016Sadrian
3340300016Sadrian	bwn_nphy_gain_ctl_workarounds(mac);
3341300016Sadrian
3342300016Sadrian	bwn_ntab_write(mac, BWN_NTAB16(8, 0), 2);
3343300016Sadrian	bwn_ntab_write(mac, BWN_NTAB16(8, 16), 2);
3344300016Sadrian
3345300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G)
3346300016Sadrian		pdet_range = siba_sprom_get_fem_2ghz_pdet_range(sc->sc_dev);
3347300016Sadrian	else
3348300016Sadrian		pdet_range = siba_sprom_get_fem_5ghz_pdet_range(sc->sc_dev);
3349300016Sadrian	/* uint16_t min() */
3350300016Sadrian	vmid = vmids[min(pdet_range, 4)];
3351300016Sadrian	gain = gains[min(pdet_range, 4)];
3352300016Sadrian	switch (pdet_range) {
3353300016Sadrian	case 3:
3354300016Sadrian		if (!(mac->mac_phy.rev >= 4 &&
3355300016Sadrian		      bwn_current_band(mac) == BWN_BAND_2G))
3356300016Sadrian			break;
3357300016Sadrian		/* FALL THROUGH */
3358300016Sadrian	case 0:
3359300016Sadrian	case 1:
3360300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x08), 4, vmid);
3361300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x18), 4, vmid);
3362300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x0c), 4, gain);
3363300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x1c), 4, gain);
3364300016Sadrian		break;
3365300016Sadrian	case 2:
3366300016Sadrian		if (mac->mac_phy.rev >= 6) {
3367300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_2G)
3368300016Sadrian				vmid[3] = 0x94;
3369300016Sadrian			else
3370300016Sadrian				vmid[3] = 0x8e;
3371300016Sadrian			gain[3] = 3;
3372300016Sadrian		} else if (mac->mac_phy.rev == 5) {
3373300016Sadrian			vmid[3] = 0x84;
3374300016Sadrian			gain[3] = 2;
3375300016Sadrian		}
3376300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x08), 4, vmid);
3377300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x18), 4, vmid);
3378300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x0c), 4, gain);
3379300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x1c), 4, gain);
3380300016Sadrian		break;
3381300016Sadrian	case 4:
3382300016Sadrian	case 5:
3383300016Sadrian		if (bwn_current_band(mac) != BWN_BAND_2G) {
3384300016Sadrian			if (pdet_range == 4) {
3385300016Sadrian				vmid[3] = 0x8e;
3386300016Sadrian				tmp16 = 0x96;
3387300016Sadrian				gain[3] = 0x2;
3388300016Sadrian			} else {
3389300016Sadrian				vmid[3] = 0x89;
3390300016Sadrian				tmp16 = 0x89;
3391300016Sadrian				gain[3] = 0;
3392300016Sadrian			}
3393300016Sadrian		} else {
3394300016Sadrian			if (pdet_range == 4) {
3395300016Sadrian				vmid[3] = 0x89;
3396300016Sadrian				tmp16 = 0x8b;
3397300016Sadrian				gain[3] = 0x2;
3398300016Sadrian			} else {
3399300016Sadrian				vmid[3] = 0x74;
3400300016Sadrian				tmp16 = 0x70;
3401300016Sadrian				gain[3] = 0;
3402300016Sadrian			}
3403300016Sadrian		}
3404300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x08), 4, vmid);
3405300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x0c), 4, gain);
3406300016Sadrian		vmid[3] = tmp16;
3407300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x18), 4, vmid);
3408300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(8, 0x1c), 4, gain);
3409300016Sadrian		break;
3410300016Sadrian	}
3411300016Sadrian
3412300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_MIXA_MAST_BIAS, 0x00);
3413300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_MIXA_MAST_BIAS, 0x00);
3414300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_MIXA_BIAS_MAIN, 0x06);
3415300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_MIXA_BIAS_MAIN, 0x06);
3416300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_MIXA_BIAS_AUX, 0x07);
3417300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_MIXA_BIAS_AUX, 0x07);
3418300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_MIXA_LOB_BIAS, 0x88);
3419300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_MIXA_LOB_BIAS, 0x88);
3420300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_MIXA_CMFB_IDAC, 0x00);
3421300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_MIXA_CMFB_IDAC, 0x00);
3422300016Sadrian	BWN_RF_WRITE(mac, B2056_RX0 | B2056_RX_MIXG_CMFB_IDAC, 0x00);
3423300016Sadrian	BWN_RF_WRITE(mac, B2056_RX1 | B2056_RX_MIXG_CMFB_IDAC, 0x00);
3424300016Sadrian
3425300016Sadrian	/* N PHY WAR TX Chain Update with hw_phytxchain as argument */
3426300016Sadrian
3427300016Sadrian	if ((siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_APLL_WAR &&
3428300016Sadrian	     bwn_current_band(mac) == BWN_BAND_5G) ||
3429300016Sadrian	    (siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_GPLL_WAR &&
3430300016Sadrian	     bwn_current_band(mac) == BWN_BAND_2G))
3431300016Sadrian		tmp32 = 0x00088888;
3432300016Sadrian	else
3433300016Sadrian		tmp32 = 0x88888888;
3434300016Sadrian	bwn_ntab_write(mac, BWN_NTAB32(30, 1), tmp32);
3435300016Sadrian	bwn_ntab_write(mac, BWN_NTAB32(30, 2), tmp32);
3436300016Sadrian	bwn_ntab_write(mac, BWN_NTAB32(30, 3), tmp32);
3437300016Sadrian
3438300016Sadrian	if (mac->mac_phy.rev == 4 &&
3439300016Sadrian	    bwn_current_band(mac) == BWN_BAND_5G) {
3440300016Sadrian		BWN_RF_WRITE(mac, B2056_TX0 | B2056_TX_GMBB_IDAC,
3441300016Sadrian				0x70);
3442300016Sadrian		BWN_RF_WRITE(mac, B2056_TX1 | B2056_TX_GMBB_IDAC,
3443300016Sadrian				0x70);
3444300016Sadrian	}
3445300016Sadrian
3446300016Sadrian	/* Dropped probably-always-true condition */
3447300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS40ASSERTTHRESH0, 0x03eb);
3448300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS40ASSERTTHRESH1, 0x03eb);
3449300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS40DEASSERTTHRESH0, 0x0341);
3450300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS40DEASSERTTHRESH1, 0x0341);
3451300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS20LASSERTTHRESH0, 0x042b);
3452300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS20LASSERTTHRESH1, 0x042b);
3453300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS20LDEASSERTTHRESH0, 0x0381);
3454300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS20LDEASSERTTHRESH1, 0x0381);
3455300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS20UASSERTTHRESH0, 0x042b);
3456300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS20UASSERTTHRESH1, 0x042b);
3457300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS20UDEASSERTTHRESH0, 0x0381);
3458300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_ED_CRS20UDEASSERTTHRESH1, 0x0381);
3459300016Sadrian
3460300016Sadrian	if (mac->mac_phy.rev >= 6 && siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_SINGLEANT_CCK)
3461300016Sadrian		; /* TODO: 0x0080000000000000 HF */
3462300016Sadrian}
3463300016Sadrian
3464300016Sadrianstatic void bwn_nphy_workarounds_rev1_2(struct bwn_mac *mac)
3465300016Sadrian{
3466300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
3467300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3468300016Sadrian	struct bwn_phy_n *nphy = phy->phy_n;
3469300016Sadrian
3470300016Sadrian	uint8_t events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 };
3471300016Sadrian	uint8_t delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 };
3472300016Sadrian
3473300016Sadrian	uint8_t events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
3474300016Sadrian	uint8_t delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
3475300016Sadrian
3476300016Sadrian	if (siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_SKWRKFEM_BRD ||
3477300016Sadrian	    siba_get_pci_subdevice(sc->sc_dev)== BCMA_BOARD_TYPE_BCM943224M93) {
3478300016Sadrian		delays1[0] = 0x1;
3479300016Sadrian		delays1[5] = 0x14;
3480300016Sadrian	}
3481300016Sadrian
3482300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_5G &&
3483300016Sadrian	    nphy->band5g_pwrgain) {
3484300016Sadrian		BWN_RF_MASK(mac, B2055_C1_TX_RF_SPARE, ~0x8);
3485300016Sadrian		BWN_RF_MASK(mac, B2055_C2_TX_RF_SPARE, ~0x8);
3486300016Sadrian	} else {
3487300016Sadrian		BWN_RF_SET(mac, B2055_C1_TX_RF_SPARE, 0x8);
3488300016Sadrian		BWN_RF_SET(mac, B2055_C2_TX_RF_SPARE, 0x8);
3489300016Sadrian	}
3490300016Sadrian
3491300016Sadrian	bwn_ntab_write(mac, BWN_NTAB16(8, 0x00), 0x000A);
3492300016Sadrian	bwn_ntab_write(mac, BWN_NTAB16(8, 0x10), 0x000A);
3493300016Sadrian	if (mac->mac_phy.rev < 3) {
3494300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x02), 0xCDAA);
3495300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x12), 0xCDAA);
3496300016Sadrian	}
3497300016Sadrian
3498300016Sadrian	if (mac->mac_phy.rev < 2) {
3499300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x08), 0x0000);
3500300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x18), 0x0000);
3501300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x07), 0x7AAB);
3502300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x17), 0x7AAB);
3503300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x06), 0x0800);
3504300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 0x16), 0x0800);
3505300016Sadrian	}
3506300016Sadrian
3507300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
3508300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
3509300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
3510300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
3511300016Sadrian
3512300016Sadrian	bwn_nphy_set_rf_sequence(mac, 0, events1, delays1, 7);
3513300016Sadrian	bwn_nphy_set_rf_sequence(mac, 1, events2, delays2, 7);
3514300016Sadrian
3515300016Sadrian	bwn_nphy_gain_ctl_workarounds(mac);
3516300016Sadrian
3517300016Sadrian	if (mac->mac_phy.rev < 2) {
3518300016Sadrian		if (BWN_PHY_READ(mac, BWN_NPHY_RXCTL) & 0x2)
3519300016Sadrian			bwn_hf_write(mac, bwn_hf_read(mac) |
3520300016Sadrian					BWN_HF_MLADVW);
3521300016Sadrian	} else if (mac->mac_phy.rev == 2) {
3522300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_CRSCHECK2, 0);
3523300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_CRSCHECK3, 0);
3524300016Sadrian	}
3525300016Sadrian
3526300016Sadrian	if (mac->mac_phy.rev < 2)
3527300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_SCRAM_SIGCTL,
3528300016Sadrian				~BWN_NPHY_SCRAM_SIGCTL_SCM);
3529300016Sadrian
3530300016Sadrian	/* Set phase track alpha and beta */
3531300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_A0, 0x125);
3532300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_A1, 0x1B3);
3533300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_A2, 0x105);
3534300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_B0, 0x16E);
3535300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_B1, 0xCD);
3536300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PHASETR_B2, 0x20);
3537300016Sadrian
3538300016Sadrian	if (mac->mac_phy.rev < 3) {
3539300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_PIL_DW1,
3540300016Sadrian			     ~BWN_NPHY_PIL_DW_64QAM & 0xFFFF);
3541300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXF_20CO_S2B1, 0xB5);
3542300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXF_20CO_S2B2, 0xA4);
3543300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXF_20CO_S2B3, 0x00);
3544300016Sadrian	}
3545300016Sadrian
3546300016Sadrian	if (mac->mac_phy.rev == 2)
3547300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_FINERX2_CGC,
3548300016Sadrian				BWN_NPHY_FINERX2_CGC_DECGC);
3549300016Sadrian}
3550300016Sadrian
3551300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
3552300016Sadrianstatic void bwn_nphy_workarounds(struct bwn_mac *mac)
3553300016Sadrian{
3554300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3555300016Sadrian	struct bwn_phy_n *nphy = phy->phy_n;
3556300016Sadrian
3557300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_5G)
3558300016Sadrian		bwn_nphy_classifier(mac, 1, 0);
3559300016Sadrian	else
3560300016Sadrian		bwn_nphy_classifier(mac, 1, 1);
3561300016Sadrian
3562300016Sadrian	if (nphy->hang_avoid)
3563300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 1);
3564300016Sadrian
3565300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_IQFLIP,
3566300016Sadrian		    BWN_NPHY_IQFLIP_ADC1 | BWN_NPHY_IQFLIP_ADC2);
3567300016Sadrian
3568300016Sadrian	/* TODO: rev19+ */
3569300016Sadrian	if (mac->mac_phy.rev >= 7)
3570300016Sadrian		bwn_nphy_workarounds_rev7plus(mac);
3571300016Sadrian	else if (mac->mac_phy.rev >= 3)
3572300016Sadrian		bwn_nphy_workarounds_rev3plus(mac);
3573300016Sadrian	else
3574300016Sadrian		bwn_nphy_workarounds_rev1_2(mac);
3575300016Sadrian
3576300016Sadrian	if (nphy->hang_avoid)
3577300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 0);
3578300016Sadrian}
3579300016Sadrian
3580300016Sadrian/**************************************************
3581300016Sadrian * Tx/Rx common
3582300016Sadrian **************************************************/
3583300016Sadrian
3584300016Sadrian/*
3585300016Sadrian * Transmits a known value for LO calibration
3586300016Sadrian * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
3587300016Sadrian */
3588300016Sadrianstatic int bwn_nphy_tx_tone(struct bwn_mac *mac, uint32_t freq, uint16_t max_val,
3589300016Sadrian			    bool iqmode, bool dac_test, bool modify_bbmult)
3590300016Sadrian{
3591300016Sadrian	uint16_t samp = bwn_nphy_gen_load_samples(mac, freq, max_val, dac_test);
3592300016Sadrian	if (samp == 0)
3593300016Sadrian		return -1;
3594300016Sadrian	bwn_nphy_run_samples(mac, samp, 0xFFFF, 0, iqmode, dac_test,
3595300016Sadrian			     modify_bbmult);
3596300016Sadrian	return 0;
3597300016Sadrian}
3598300016Sadrian
3599300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */
3600300016Sadrianstatic void bwn_nphy_update_txrx_chain(struct bwn_mac *mac)
3601300016Sadrian{
3602300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
3603300016Sadrian
3604300016Sadrian	bool override = false;
3605300016Sadrian	uint16_t chain = 0x33;
3606300016Sadrian
3607300016Sadrian	if (nphy->txrx_chain == 0) {
3608300016Sadrian		chain = 0x11;
3609300016Sadrian		override = true;
3610300016Sadrian	} else if (nphy->txrx_chain == 1) {
3611300016Sadrian		chain = 0x22;
3612300016Sadrian		override = true;
3613300016Sadrian	}
3614300016Sadrian
3615300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_RFSEQCA,
3616300016Sadrian			~(BWN_NPHY_RFSEQCA_TXEN | BWN_NPHY_RFSEQCA_RXEN),
3617300016Sadrian			chain);
3618300016Sadrian
3619300016Sadrian	if (override)
3620300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_RFSEQMODE,
3621300016Sadrian				BWN_NPHY_RFSEQMODE_CAOVER);
3622300016Sadrian	else
3623300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_RFSEQMODE,
3624300016Sadrian				~BWN_NPHY_RFSEQMODE_CAOVER);
3625300016Sadrian}
3626300016Sadrian
3627300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
3628300016Sadrianstatic void bwn_nphy_stop_playback(struct bwn_mac *mac)
3629300016Sadrian{
3630300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3631300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
3632300016Sadrian	uint16_t tmp;
3633300016Sadrian
3634300016Sadrian	if (nphy->hang_avoid)
3635300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 1);
3636300016Sadrian
3637300016Sadrian	tmp = BWN_PHY_READ(mac, BWN_NPHY_SAMP_STAT);
3638300016Sadrian	if (tmp & 0x1)
3639300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_SAMP_CMD, BWN_NPHY_SAMP_CMD_STOP);
3640300016Sadrian	else if (tmp & 0x2)
3641300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
3642300016Sadrian
3643300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_SAMP_CMD, ~0x0004);
3644300016Sadrian
3645300016Sadrian	if (nphy->bb_mult_save & 0x80000000) {
3646300016Sadrian		tmp = nphy->bb_mult_save & 0xFFFF;
3647300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(15, 87), tmp);
3648300016Sadrian		nphy->bb_mult_save = 0;
3649300016Sadrian	}
3650300016Sadrian
3651300016Sadrian	if (phy->rev >= 7 && nphy->lpf_bw_overrode_for_sample_play) {
3652300016Sadrian		if (phy->rev >= 19)
3653300016Sadrian			bwn_nphy_rf_ctl_override_rev19(mac, 0x80, 0, 0, true,
3654300016Sadrian						       1);
3655300016Sadrian		else
3656300016Sadrian			bwn_nphy_rf_ctl_override_rev7(mac, 0x80, 0, 0, true, 1);
3657300016Sadrian		nphy->lpf_bw_overrode_for_sample_play = false;
3658300016Sadrian	}
3659300016Sadrian
3660300016Sadrian	if (nphy->hang_avoid)
3661300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 0);
3662300016Sadrian}
3663300016Sadrian
3664300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */
3665300016Sadrianstatic void bwn_nphy_iq_cal_gain_params(struct bwn_mac *mac, uint16_t core,
3666300016Sadrian					struct bwn_nphy_txgains target,
3667300016Sadrian					struct bwn_nphy_iqcal_params *params)
3668300016Sadrian{
3669300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3670300016Sadrian	int i, j, indx;
3671300016Sadrian	uint16_t gain;
3672300016Sadrian
3673300016Sadrian	if (mac->mac_phy.rev >= 3) {
3674300016Sadrian		params->tx_lpf = target.tx_lpf[core]; /* Rev 7+ */
3675300016Sadrian		params->txgm = target.txgm[core];
3676300016Sadrian		params->pga = target.pga[core];
3677300016Sadrian		params->pad = target.pad[core];
3678300016Sadrian		params->ipa = target.ipa[core];
3679300016Sadrian		if (phy->rev >= 19) {
3680300016Sadrian			/* TODO */
3681300016Sadrian		} else if (phy->rev >= 7) {
3682300016Sadrian			params->cal_gain = (params->txgm << 12) | (params->pga << 8) | (params->pad << 3) | (params->ipa) | (params->tx_lpf << 15);
3683300016Sadrian		} else {
3684300016Sadrian			params->cal_gain = (params->txgm << 12) | (params->pga << 8) | (params->pad << 4) | (params->ipa);
3685300016Sadrian		}
3686300016Sadrian		for (j = 0; j < 5; j++)
3687300016Sadrian			params->ncorr[j] = 0x79;
3688300016Sadrian	} else {
3689300016Sadrian		gain = (target.pad[core]) | (target.pga[core] << 4) |
3690300016Sadrian			(target.txgm[core] << 8);
3691300016Sadrian
3692300016Sadrian		indx = (bwn_current_band(mac) == BWN_BAND_5G) ?
3693300016Sadrian			1 : 0;
3694300016Sadrian		for (i = 0; i < 9; i++)
3695300016Sadrian			if (tbl_iqcal_gainparams[indx][i][0] == gain)
3696300016Sadrian				break;
3697300016Sadrian		i = min(i, 8);
3698300016Sadrian
3699300016Sadrian		params->txgm = tbl_iqcal_gainparams[indx][i][1];
3700300016Sadrian		params->pga = tbl_iqcal_gainparams[indx][i][2];
3701300016Sadrian		params->pad = tbl_iqcal_gainparams[indx][i][3];
3702300016Sadrian		params->cal_gain = (params->txgm << 7) | (params->pga << 4) |
3703300016Sadrian					(params->pad << 2);
3704300016Sadrian		for (j = 0; j < 4; j++)
3705300016Sadrian			params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j];
3706300016Sadrian	}
3707300016Sadrian}
3708300016Sadrian
3709300016Sadrian/**************************************************
3710300016Sadrian * Tx and Rx
3711300016Sadrian **************************************************/
3712300016Sadrian
3713300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
3714300016Sadrianstatic void bwn_nphy_tx_power_ctrl(struct bwn_mac *mac, bool enable)
3715300016Sadrian{
3716300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3717300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
3718300016Sadrian	uint8_t i;
3719300016Sadrian	uint16_t bmask, val, tmp;
3720300016Sadrian	bwn_band_t band = bwn_current_band(mac);
3721300016Sadrian
3722300016Sadrian	if (nphy->hang_avoid)
3723300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 1);
3724300016Sadrian
3725300016Sadrian	nphy->txpwrctrl = enable;
3726300016Sadrian	if (!enable) {
3727300016Sadrian		if (mac->mac_phy.rev >= 3 &&
3728300016Sadrian		    (BWN_PHY_READ(mac, BWN_NPHY_TXPCTL_CMD) &
3729300016Sadrian		     (BWN_NPHY_TXPCTL_CMD_COEFF |
3730300016Sadrian		      BWN_NPHY_TXPCTL_CMD_HWPCTLEN |
3731300016Sadrian		      BWN_NPHY_TXPCTL_CMD_PCTLEN))) {
3732300016Sadrian			/* We disable enabled TX pwr ctl, save it's state */
3733300016Sadrian			nphy->tx_pwr_idx[0] = BWN_PHY_READ(mac,
3734300016Sadrian						BWN_NPHY_C1_TXPCTL_STAT) & 0x7f;
3735300016Sadrian			nphy->tx_pwr_idx[1] = BWN_PHY_READ(mac,
3736300016Sadrian						BWN_NPHY_C2_TXPCTL_STAT) & 0x7f;
3737300016Sadrian		}
3738300016Sadrian
3739300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_ADDR, 0x6840);
3740300016Sadrian		for (i = 0; i < 84; i++)
3741300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0);
3742300016Sadrian
3743300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_ADDR, 0x6C40);
3744300016Sadrian		for (i = 0; i < 84; i++)
3745300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO, 0);
3746300016Sadrian
3747300016Sadrian		tmp = BWN_NPHY_TXPCTL_CMD_COEFF | BWN_NPHY_TXPCTL_CMD_HWPCTLEN;
3748300016Sadrian		if (mac->mac_phy.rev >= 3)
3749300016Sadrian			tmp |= BWN_NPHY_TXPCTL_CMD_PCTLEN;
3750300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_TXPCTL_CMD, ~tmp);
3751300016Sadrian
3752300016Sadrian		if (mac->mac_phy.rev >= 3) {
3753300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER1, 0x0100);
3754300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER, 0x0100);
3755300016Sadrian		} else {
3756300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER, 0x4000);
3757300016Sadrian		}
3758300016Sadrian
3759300016Sadrian		if (mac->mac_phy.rev == 2)
3760300016Sadrian			BWN_PHY_SETMASK(mac, BWN_NPHY_BPHY_CTL3,
3761300016Sadrian				~BWN_NPHY_BPHY_CTL3_SCALE, 0x53);
3762300016Sadrian		else if (mac->mac_phy.rev < 2)
3763300016Sadrian			BWN_PHY_SETMASK(mac, BWN_NPHY_BPHY_CTL3,
3764300016Sadrian				~BWN_NPHY_BPHY_CTL3_SCALE, 0x5A);
3765300016Sadrian
3766300016Sadrian		if (mac->mac_phy.rev < 2 && bwn_is_40mhz(mac))
3767300016Sadrian			bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
3768300016Sadrian	} else {
3769300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(26, 64), 84,
3770300016Sadrian				    nphy->adj_pwr_tbl);
3771300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(27, 64), 84,
3772300016Sadrian				    nphy->adj_pwr_tbl);
3773300016Sadrian
3774300016Sadrian		bmask = BWN_NPHY_TXPCTL_CMD_COEFF |
3775300016Sadrian			BWN_NPHY_TXPCTL_CMD_HWPCTLEN;
3776300016Sadrian		/* wl does useless check for "enable" param here */
3777300016Sadrian		val = BWN_NPHY_TXPCTL_CMD_COEFF | BWN_NPHY_TXPCTL_CMD_HWPCTLEN;
3778300016Sadrian		if (mac->mac_phy.rev >= 3) {
3779300016Sadrian			bmask |= BWN_NPHY_TXPCTL_CMD_PCTLEN;
3780300016Sadrian			if (val)
3781300016Sadrian				val |= BWN_NPHY_TXPCTL_CMD_PCTLEN;
3782300016Sadrian		}
3783300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_TXPCTL_CMD, ~(bmask), val);
3784300016Sadrian
3785300016Sadrian		if (band == BWN_BAND_5G) {
3786300016Sadrian			if (phy->rev >= 19) {
3787300016Sadrian				/* TODO */
3788300016Sadrian			} else if (phy->rev >= 7) {
3789300016Sadrian				BWN_PHY_SETMASK(mac, BWN_NPHY_TXPCTL_CMD,
3790300016Sadrian						~BWN_NPHY_TXPCTL_CMD_INIT,
3791300016Sadrian						0x32);
3792300016Sadrian				BWN_PHY_SETMASK(mac, BWN_NPHY_TXPCTL_INIT,
3793300016Sadrian						~BWN_NPHY_TXPCTL_INIT_PIDXI1,
3794300016Sadrian						0x32);
3795300016Sadrian			} else {
3796300016Sadrian				BWN_PHY_SETMASK(mac, BWN_NPHY_TXPCTL_CMD,
3797300016Sadrian						~BWN_NPHY_TXPCTL_CMD_INIT,
3798300016Sadrian						0x64);
3799300016Sadrian				if (phy->rev > 1)
3800300016Sadrian					BWN_PHY_SETMASK(mac,
3801300016Sadrian							BWN_NPHY_TXPCTL_INIT,
3802300016Sadrian							~BWN_NPHY_TXPCTL_INIT_PIDXI1,
3803300016Sadrian							0x64);
3804300016Sadrian			}
3805300016Sadrian		}
3806300016Sadrian
3807300016Sadrian		if (mac->mac_phy.rev >= 3) {
3808300016Sadrian			if (nphy->tx_pwr_idx[0] != 128 &&
3809300016Sadrian			    nphy->tx_pwr_idx[1] != 128) {
3810300016Sadrian				/* Recover TX pwr ctl state */
3811300016Sadrian				BWN_PHY_SETMASK(mac, BWN_NPHY_TXPCTL_CMD,
3812300016Sadrian						~BWN_NPHY_TXPCTL_CMD_INIT,
3813300016Sadrian						nphy->tx_pwr_idx[0]);
3814300016Sadrian				if (mac->mac_phy.rev > 1)
3815300016Sadrian					BWN_PHY_SETMASK(mac,
3816300016Sadrian						BWN_NPHY_TXPCTL_INIT,
3817300016Sadrian						~0xff, nphy->tx_pwr_idx[1]);
3818300016Sadrian			}
3819300016Sadrian		}
3820300016Sadrian
3821300016Sadrian		if (phy->rev >= 7) {
3822300016Sadrian			/* TODO */
3823300016Sadrian		}
3824300016Sadrian
3825300016Sadrian		if (mac->mac_phy.rev >= 3) {
3826300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_OVER1, ~0x100);
3827300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_OVER, ~0x100);
3828300016Sadrian		} else {
3829300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_OVER, ~0x4000);
3830300016Sadrian		}
3831300016Sadrian
3832300016Sadrian		if (mac->mac_phy.rev == 2)
3833300016Sadrian			BWN_PHY_SETMASK(mac, BWN_NPHY_BPHY_CTL3, ~0xFF, 0x3b);
3834300016Sadrian		else if (mac->mac_phy.rev < 2)
3835300016Sadrian			BWN_PHY_SETMASK(mac, BWN_NPHY_BPHY_CTL3, ~0xFF, 0x40);
3836300016Sadrian
3837300016Sadrian		if (mac->mac_phy.rev < 2 && bwn_is_40mhz(mac))
3838300016Sadrian			bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_TSSI_RESET_PSM_WORKAROUN);
3839300016Sadrian
3840300016Sadrian		if (bwn_nphy_ipa(mac)) {
3841300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_PAPD_EN0, ~0x4);
3842300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_PAPD_EN1, ~0x4);
3843300016Sadrian		}
3844300016Sadrian	}
3845300016Sadrian
3846300016Sadrian	if (nphy->hang_avoid)
3847300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 0);
3848300016Sadrian}
3849300016Sadrian
3850300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */
3851300016Sadrianstatic void bwn_nphy_tx_power_fix(struct bwn_mac *mac)
3852300016Sadrian{
3853300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
3854300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
3855300016Sadrian
3856300016Sadrian	uint8_t txpi[2], bbmult, i;
3857300016Sadrian	uint16_t tmp, radio_gain, dac_gain;
3858300016Sadrian	uint16_t freq = bwn_get_centre_freq(mac);
3859300016Sadrian	uint32_t txgain;
3860300016Sadrian	/* uint32_t gaintbl; rev3+ */
3861300016Sadrian
3862300016Sadrian	if (nphy->hang_avoid)
3863300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 1);
3864300016Sadrian
3865300016Sadrian	/* TODO: rev19+ */
3866300016Sadrian	if (mac->mac_phy.rev >= 7) {
3867300016Sadrian		txpi[0] = txpi[1] = 30;
3868300016Sadrian	} else if (mac->mac_phy.rev >= 3) {
3869300016Sadrian		txpi[0] = 40;
3870300016Sadrian		txpi[1] = 40;
3871300016Sadrian	} else if (siba_sprom_get_rev(sc->sc_dev) < 4) {
3872300016Sadrian		txpi[0] = 72;
3873300016Sadrian		txpi[1] = 72;
3874300016Sadrian	} else {
3875300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G) {
3876300016Sadrian			txpi[0] = siba_sprom_get_txpid_2g_0(sc->sc_dev);
3877300016Sadrian			txpi[1] = siba_sprom_get_txpid_2g_1(sc->sc_dev);
3878300016Sadrian		} else if (freq >= 4900 && freq < 5100) {
3879300016Sadrian			txpi[0] = siba_sprom_get_txpid_5gl_0(sc->sc_dev);
3880300016Sadrian			txpi[1] = siba_sprom_get_txpid_5gl_1(sc->sc_dev);
3881300016Sadrian		} else if (freq >= 5100 && freq < 5500) {
3882300016Sadrian			txpi[0] = siba_sprom_get_txpid_5g_0(sc->sc_dev);
3883300016Sadrian			txpi[1] = siba_sprom_get_txpid_5g_1(sc->sc_dev);
3884300016Sadrian		} else if (freq >= 5500) {
3885300016Sadrian			txpi[0] = siba_sprom_get_txpid_5gh_0(sc->sc_dev);
3886300016Sadrian			txpi[1] = siba_sprom_get_txpid_5gh_1(sc->sc_dev);
3887300016Sadrian		} else {
3888300016Sadrian			txpi[0] = 91;
3889300016Sadrian			txpi[1] = 91;
3890300016Sadrian		}
3891300016Sadrian	}
3892300016Sadrian	if (mac->mac_phy.rev < 7 &&
3893300016Sadrian	    (txpi[0] < 40 || txpi[0] > 100 || txpi[1] < 40 || txpi[1] > 100))
3894300016Sadrian		txpi[0] = txpi[1] = 91;
3895300016Sadrian
3896300016Sadrian	/*
3897300016Sadrian	for (i = 0; i < 2; i++) {
3898300016Sadrian		nphy->txpwrindex[i].index_internal = txpi[i];
3899300016Sadrian		nphy->txpwrindex[i].index_internal_save = txpi[i];
3900300016Sadrian	}
3901300016Sadrian	*/
3902300016Sadrian
3903300016Sadrian	for (i = 0; i < 2; i++) {
3904300016Sadrian		const uint32_t *table = bwn_nphy_get_tx_gain_table(mac);
3905300016Sadrian
3906300016Sadrian		if (!table)
3907300016Sadrian			break;
3908300016Sadrian		txgain = *(table + txpi[i]);
3909300016Sadrian
3910300016Sadrian		if (mac->mac_phy.rev >= 3)
3911300016Sadrian			radio_gain = (txgain >> 16) & 0x1FFFF;
3912300016Sadrian		else
3913300016Sadrian			radio_gain = (txgain >> 16) & 0x1FFF;
3914300016Sadrian
3915300016Sadrian		if (mac->mac_phy.rev >= 7)
3916300016Sadrian			dac_gain = (txgain >> 8) & 0x7;
3917300016Sadrian		else
3918300016Sadrian			dac_gain = (txgain >> 8) & 0x3F;
3919300016Sadrian		bbmult = txgain & 0xFF;
3920300016Sadrian
3921300016Sadrian		if (mac->mac_phy.rev >= 3) {
3922300016Sadrian			if (i == 0)
3923300016Sadrian				BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER1, 0x0100);
3924300016Sadrian			else
3925300016Sadrian				BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER, 0x0100);
3926300016Sadrian		} else {
3927300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER, 0x4000);
3928300016Sadrian		}
3929300016Sadrian
3930300016Sadrian		if (i == 0)
3931300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_DACGAIN1, dac_gain);
3932300016Sadrian		else
3933300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_DACGAIN2, dac_gain);
3934300016Sadrian
3935300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(0x7, 0x110 + i), radio_gain);
3936300016Sadrian
3937300016Sadrian		tmp = bwn_ntab_read(mac, BWN_NTAB16(0xF, 0x57));
3938300016Sadrian		if (i == 0)
3939300016Sadrian			tmp = (tmp & 0x00FF) | (bbmult << 8);
3940300016Sadrian		else
3941300016Sadrian			tmp = (tmp & 0xFF00) | bbmult;
3942300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(0xF, 0x57), tmp);
3943300016Sadrian
3944300016Sadrian		if (bwn_nphy_ipa(mac)) {
3945300016Sadrian			uint32_t tmp32;
3946300016Sadrian			uint16_t reg = (i == 0) ?
3947300016Sadrian				BWN_NPHY_PAPD_EN0 : BWN_NPHY_PAPD_EN1;
3948300016Sadrian			tmp32 = bwn_ntab_read(mac, BWN_NTAB32(26 + i,
3949300016Sadrian							      576 + txpi[i]));
3950300016Sadrian			BWN_PHY_SETMASK(mac, reg, 0xE00F, (uint32_t) tmp32 << 4);
3951300016Sadrian			BWN_PHY_SET(mac, reg, 0x4);
3952300016Sadrian		}
3953300016Sadrian	}
3954300016Sadrian
3955300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_BPHY_CTL2, ~BWN_NPHY_BPHY_CTL2_LUT);
3956300016Sadrian
3957300016Sadrian	if (nphy->hang_avoid)
3958300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 0);
3959300016Sadrian}
3960300016Sadrian
3961300016Sadrianstatic void bwn_nphy_ipa_internal_tssi_setup(struct bwn_mac *mac)
3962300016Sadrian{
3963300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
3964300016Sadrian
3965300016Sadrian	uint8_t core;
3966300016Sadrian	uint16_t r; /* routing */
3967300016Sadrian
3968300016Sadrian	if (phy->rev >= 19) {
3969300016Sadrian		/* TODO */
3970300016Sadrian	} else if (phy->rev >= 7) {
3971300016Sadrian		for (core = 0; core < 2; core++) {
3972300016Sadrian			r = core ? 0x190 : 0x170;
3973300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_2G) {
3974300016Sadrian				BWN_RF_WRITE(mac, r + 0x5, 0x5);
3975300016Sadrian				BWN_RF_WRITE(mac, r + 0x9, 0xE);
3976300016Sadrian				if (phy->rev != 5)
3977300016Sadrian					BWN_RF_WRITE(mac, r + 0xA, 0);
3978300016Sadrian				if (phy->rev != 7)
3979300016Sadrian					BWN_RF_WRITE(mac, r + 0xB, 1);
3980300016Sadrian				else
3981300016Sadrian					BWN_RF_WRITE(mac, r + 0xB, 0x31);
3982300016Sadrian			} else {
3983300016Sadrian				BWN_RF_WRITE(mac, r + 0x5, 0x9);
3984300016Sadrian				BWN_RF_WRITE(mac, r + 0x9, 0xC);
3985300016Sadrian				BWN_RF_WRITE(mac, r + 0xB, 0x0);
3986300016Sadrian				if (phy->rev != 5)
3987300016Sadrian					BWN_RF_WRITE(mac, r + 0xA, 1);
3988300016Sadrian				else
3989300016Sadrian					BWN_RF_WRITE(mac, r + 0xA, 0x31);
3990300016Sadrian			}
3991300016Sadrian			BWN_RF_WRITE(mac, r + 0x6, 0);
3992300016Sadrian			BWN_RF_WRITE(mac, r + 0x7, 0);
3993300016Sadrian			BWN_RF_WRITE(mac, r + 0x8, 3);
3994300016Sadrian			BWN_RF_WRITE(mac, r + 0xC, 0);
3995300016Sadrian		}
3996300016Sadrian	} else {
3997300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G)
3998300016Sadrian			BWN_RF_WRITE(mac, B2056_SYN_RESERVED_ADDR31, 0x128);
3999300016Sadrian		else
4000300016Sadrian			BWN_RF_WRITE(mac, B2056_SYN_RESERVED_ADDR31, 0x80);
4001300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_RESERVED_ADDR30, 0);
4002300016Sadrian		BWN_RF_WRITE(mac, B2056_SYN_GPIO_MASTER1, 0x29);
4003300016Sadrian
4004300016Sadrian		for (core = 0; core < 2; core++) {
4005300016Sadrian			r = core ? B2056_TX1 : B2056_TX0;
4006300016Sadrian
4007300016Sadrian			BWN_RF_WRITE(mac, r | B2056_TX_IQCAL_VCM_HG, 0);
4008300016Sadrian			BWN_RF_WRITE(mac, r | B2056_TX_IQCAL_IDAC, 0);
4009300016Sadrian			BWN_RF_WRITE(mac, r | B2056_TX_TSSI_VCM, 3);
4010300016Sadrian			BWN_RF_WRITE(mac, r | B2056_TX_TX_AMP_DET, 0);
4011300016Sadrian			BWN_RF_WRITE(mac, r | B2056_TX_TSSI_MISC1, 8);
4012300016Sadrian			BWN_RF_WRITE(mac, r | B2056_TX_TSSI_MISC2, 0);
4013300016Sadrian			BWN_RF_WRITE(mac, r | B2056_TX_TSSI_MISC3, 0);
4014300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_2G) {
4015300016Sadrian				BWN_RF_WRITE(mac, r | B2056_TX_TX_SSI_MASTER,
4016300016Sadrian						0x5);
4017300016Sadrian				if (phy->rev != 5)
4018300016Sadrian					BWN_RF_WRITE(mac, r | B2056_TX_TSSIA,
4019300016Sadrian							0x00);
4020300016Sadrian				if (phy->rev >= 5)
4021300016Sadrian					BWN_RF_WRITE(mac, r | B2056_TX_TSSIG,
4022300016Sadrian							0x31);
4023300016Sadrian				else
4024300016Sadrian					BWN_RF_WRITE(mac, r | B2056_TX_TSSIG,
4025300016Sadrian							0x11);
4026300016Sadrian				BWN_RF_WRITE(mac, r | B2056_TX_TX_SSI_MUX,
4027300016Sadrian						0xE);
4028300016Sadrian			} else {
4029300016Sadrian				BWN_RF_WRITE(mac, r | B2056_TX_TX_SSI_MASTER,
4030300016Sadrian						0x9);
4031300016Sadrian				BWN_RF_WRITE(mac, r | B2056_TX_TSSIA, 0x31);
4032300016Sadrian				BWN_RF_WRITE(mac, r | B2056_TX_TSSIG, 0x0);
4033300016Sadrian				BWN_RF_WRITE(mac, r | B2056_TX_TX_SSI_MUX,
4034300016Sadrian						0xC);
4035300016Sadrian			}
4036300016Sadrian		}
4037300016Sadrian	}
4038300016Sadrian}
4039300016Sadrian
4040300016Sadrian/*
4041300016Sadrian * Stop radio and transmit known signal. Then check received signal strength to
4042300016Sadrian * get TSSI (Transmit Signal Strength Indicator).
4043300016Sadrian * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlIdleTssi
4044300016Sadrian */
4045300016Sadrianstatic void bwn_nphy_tx_power_ctl_idle_tssi(struct bwn_mac *mac)
4046300016Sadrian{
4047300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
4048300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
4049300016Sadrian
4050300016Sadrian	uint32_t tmp;
4051300016Sadrian	int32_t rssi[4] = { };
4052300016Sadrian
4053300016Sadrian	if (bwn_is_chan_passive(mac))
4054300016Sadrian		return;
4055300016Sadrian
4056300016Sadrian	if (bwn_nphy_ipa(mac))
4057300016Sadrian		bwn_nphy_ipa_internal_tssi_setup(mac);
4058300016Sadrian
4059300016Sadrian	if (phy->rev >= 19)
4060300016Sadrian		bwn_nphy_rf_ctl_override_rev19(mac, 0x1000, 0, 3, false, 0);
4061300016Sadrian	else if (phy->rev >= 7)
4062300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x1000, 0, 3, false, 0);
4063300016Sadrian	else if (phy->rev >= 3)
4064300016Sadrian		bwn_nphy_rf_ctl_override(mac, 0x2000, 0, 3, false);
4065300016Sadrian
4066300016Sadrian	bwn_nphy_stop_playback(mac);
4067300016Sadrian	bwn_nphy_tx_tone(mac, 4000, 0, false, false, false);
4068300016Sadrian	DELAY(20);
4069300016Sadrian	tmp = bwn_nphy_poll_rssi(mac, N_RSSI_TSSI_2G, rssi, 1);
4070300016Sadrian	bwn_nphy_stop_playback(mac);
4071300016Sadrian
4072300016Sadrian	bwn_nphy_rssi_select(mac, 0, N_RSSI_W1);
4073300016Sadrian
4074300016Sadrian	if (phy->rev >= 19)
4075300016Sadrian		bwn_nphy_rf_ctl_override_rev19(mac, 0x1000, 0, 3, true, 0);
4076300016Sadrian	else if (phy->rev >= 7)
4077300016Sadrian		bwn_nphy_rf_ctl_override_rev7(mac, 0x1000, 0, 3, true, 0);
4078300016Sadrian	else if (phy->rev >= 3)
4079300016Sadrian		bwn_nphy_rf_ctl_override(mac, 0x2000, 0, 3, true);
4080300016Sadrian
4081300016Sadrian	if (phy->rev >= 19) {
4082300016Sadrian		/* TODO */
4083300016Sadrian		return;
4084300016Sadrian	} else if (phy->rev >= 3) {
4085300016Sadrian		nphy->pwr_ctl_info[0].idle_tssi_5g = (tmp >> 24) & 0xFF;
4086300016Sadrian		nphy->pwr_ctl_info[1].idle_tssi_5g = (tmp >> 8) & 0xFF;
4087300016Sadrian	} else {
4088300016Sadrian		nphy->pwr_ctl_info[0].idle_tssi_5g = (tmp >> 16) & 0xFF;
4089300016Sadrian		nphy->pwr_ctl_info[1].idle_tssi_5g = tmp & 0xFF;
4090300016Sadrian	}
4091300016Sadrian	nphy->pwr_ctl_info[0].idle_tssi_2g = (tmp >> 24) & 0xFF;
4092300016Sadrian	nphy->pwr_ctl_info[1].idle_tssi_2g = (tmp >> 8) & 0xFF;
4093300016Sadrian}
4094300016Sadrian
4095300016Sadrian/* http://bcm-v4.sipsolutions.net/PHY/N/TxPwrLimitToTbl */
4096300016Sadrianstatic void bwn_nphy_tx_prepare_adjusted_power_table(struct bwn_mac *mac)
4097300016Sadrian{
4098300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
4099300016Sadrian
4100300016Sadrian	uint8_t idx, delta;
4101300016Sadrian	uint8_t i, stf_mode;
4102300016Sadrian
4103300016Sadrian	/* Array adj_pwr_tbl corresponds to the hardware table. It consists of
4104300016Sadrian	 * 21 groups, each containing 4 entries.
4105300016Sadrian	 *
4106300016Sadrian	 * First group has entries for CCK modulation.
4107300016Sadrian	 * The rest of groups has 1 entry per modulation (SISO, CDD, STBC, SDM).
4108300016Sadrian	 *
4109300016Sadrian	 * Group 0 is for CCK
4110300016Sadrian	 * Groups 1..4 use BPSK (group per coding rate)
4111300016Sadrian	 * Groups 5..8 use QPSK (group per coding rate)
4112300016Sadrian	 * Groups 9..12 use 16-QAM (group per coding rate)
4113300016Sadrian	 * Groups 13..16 use 64-QAM (group per coding rate)
4114300016Sadrian	 * Groups 17..20 are unknown
4115300016Sadrian	 */
4116300016Sadrian
4117300016Sadrian	for (i = 0; i < 4; i++)
4118300016Sadrian		nphy->adj_pwr_tbl[i] = nphy->tx_power_offset[i];
4119300016Sadrian
4120300016Sadrian	for (stf_mode = 0; stf_mode < 4; stf_mode++) {
4121300016Sadrian		delta = 0;
4122300016Sadrian		switch (stf_mode) {
4123300016Sadrian		case 0:
4124300016Sadrian			if (bwn_is_40mhz(mac) && mac->mac_phy.rev >= 5) {
4125300016Sadrian				idx = 68;
4126300016Sadrian			} else {
4127300016Sadrian				delta = 1;
4128300016Sadrian				idx = bwn_is_40mhz(mac) ? 52 : 4;
4129300016Sadrian			}
4130300016Sadrian			break;
4131300016Sadrian		case 1:
4132300016Sadrian			idx = bwn_is_40mhz(mac) ? 76 : 28;
4133300016Sadrian			break;
4134300016Sadrian		case 2:
4135300016Sadrian			idx = bwn_is_40mhz(mac) ? 84 : 36;
4136300016Sadrian			break;
4137300016Sadrian		case 3:
4138300016Sadrian			idx = bwn_is_40mhz(mac) ? 92 : 44;
4139300016Sadrian			break;
4140300016Sadrian		}
4141300016Sadrian
4142300016Sadrian		for (i = 0; i < 20; i++) {
4143300016Sadrian			nphy->adj_pwr_tbl[4 + 4 * i + stf_mode] =
4144300016Sadrian				nphy->tx_power_offset[idx];
4145300016Sadrian			if (i == 0)
4146300016Sadrian				idx += delta;
4147300016Sadrian			if (i == 14)
4148300016Sadrian				idx += 1 - delta;
4149300016Sadrian			if (i == 3 || i == 4 || i == 7 || i == 8 || i == 11 ||
4150300016Sadrian			    i == 13)
4151300016Sadrian				idx += 1;
4152300016Sadrian		}
4153300016Sadrian	}
4154300016Sadrian}
4155300016Sadrian
4156300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlSetup */
4157300016Sadrianstatic void bwn_nphy_tx_power_ctl_setup(struct bwn_mac *mac)
4158300016Sadrian{
4159300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
4160300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
4161300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
4162300016Sadrian	struct siba_sprom_core_pwr_info core_pwr_info[4];
4163300016Sadrian	int n;
4164300016Sadrian
4165300016Sadrian	int16_t a1[2], b0[2], b1[2];
4166300016Sadrian	uint8_t idle[2];
4167300016Sadrian	uint8_t ppr_max;
4168300016Sadrian	int8_t target[2];
4169300016Sadrian	int32_t num, den, pwr;
4170300016Sadrian	uint32_t regval[64];
4171300016Sadrian
4172300016Sadrian	uint16_t freq = bwn_get_centre_freq(mac);
4173300016Sadrian	uint16_t tmp;
4174300016Sadrian	uint16_t r; /* routing */
4175300016Sadrian	uint8_t i, c;
4176300016Sadrian
4177300016Sadrian	for (n = 0; n < 4; n++) {
4178300016Sadrian		bzero(&core_pwr_info[n], sizeof(core_pwr_info[n]));
4179300016Sadrian		if (siba_sprom_get_core_power_info(sc->sc_dev, n,
4180300016Sadrian		    &core_pwr_info[n]) != 0) {
4181300016Sadrian			BWN_ERRPRINTF(mac->mac_sc,
4182300016Sadrian			    "%s: failed to get core_pwr_info for core %d\n",
4183300016Sadrian			    __func__,
4184300016Sadrian			    n);
4185300016Sadrian		}
4186300016Sadrian	}
4187300016Sadrian
4188300016Sadrian	if (siba_get_revid(sc->sc_dev) == 11 || siba_get_revid(sc->sc_dev) == 12) {
4189300016Sadrian		BWN_WRITE_SETMASK4(mac, BWN_MACCTL, ~0, 0x200000);
4190300016Sadrian		BWN_READ_4(mac, BWN_MACCTL);
4191300016Sadrian		DELAY(1);
4192300016Sadrian	}
4193300016Sadrian
4194300016Sadrian	if (nphy->hang_avoid)
4195300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, true);
4196300016Sadrian
4197300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_TSSIMODE, BWN_NPHY_TSSIMODE_EN);
4198300016Sadrian	if (mac->mac_phy.rev >= 3)
4199300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_TXPCTL_CMD,
4200300016Sadrian			     ~BWN_NPHY_TXPCTL_CMD_PCTLEN & 0xFFFF);
4201300016Sadrian	else
4202300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_TXPCTL_CMD,
4203300016Sadrian			    BWN_NPHY_TXPCTL_CMD_PCTLEN);
4204300016Sadrian
4205300016Sadrian	if (siba_get_revid(sc->sc_dev) == 11 || siba_get_revid(sc->sc_dev) == 12)
4206300016Sadrian		BWN_WRITE_SETMASK4(mac, BWN_MACCTL, ~0x200000, 0);
4207300016Sadrian
4208300016Sadrian	/*
4209300016Sadrian	 * XXX TODO: see if those bandsbelow map to 5g-lo, 5g-mid, 5g-hi in
4210300016Sadrian	 * any way.
4211300016Sadrian	 */
4212300016Sadrian	if (siba_sprom_get_rev(sc->sc_dev) < 4) {
4213300016Sadrian		idle[0] = nphy->pwr_ctl_info[0].idle_tssi_2g;
4214300016Sadrian		idle[1] = nphy->pwr_ctl_info[1].idle_tssi_2g;
4215300016Sadrian		target[0] = target[1] = 52;
4216300016Sadrian		a1[0] = a1[1] = -424;
4217300016Sadrian		b0[0] = b0[1] = 5612;
4218300016Sadrian		b1[0] = b1[1] = -1393;
4219300016Sadrian	} else {
4220300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G) {
4221300016Sadrian			for (c = 0; c < 2; c++) {
4222300016Sadrian				idle[c] = nphy->pwr_ctl_info[c].idle_tssi_2g;
4223300016Sadrian				target[c] = core_pwr_info[c].maxpwr_2g;
4224300016Sadrian				a1[c] = core_pwr_info[c].pa_2g[0];
4225300016Sadrian				b0[c] = core_pwr_info[c].pa_2g[1];
4226300016Sadrian				b1[c] = core_pwr_info[c].pa_2g[2];
4227300016Sadrian			}
4228300016Sadrian		} else if (freq >= 4900 && freq < 5100) {
4229300016Sadrian			for (c = 0; c < 2; c++) {
4230300016Sadrian				idle[c] = nphy->pwr_ctl_info[c].idle_tssi_5g;
4231300016Sadrian				target[c] = core_pwr_info[c].maxpwr_5gl;
4232300016Sadrian				a1[c] = core_pwr_info[c].pa_5gl[0];
4233300016Sadrian				b0[c] = core_pwr_info[c].pa_5gl[1];
4234300016Sadrian				b1[c] = core_pwr_info[c].pa_5gl[2];
4235300016Sadrian			}
4236300016Sadrian		} else if (freq >= 5100 && freq < 5500) {
4237300016Sadrian			for (c = 0; c < 2; c++) {
4238300016Sadrian				idle[c] = nphy->pwr_ctl_info[c].idle_tssi_5g;
4239300016Sadrian				target[c] = core_pwr_info[c].maxpwr_5g;
4240300016Sadrian				a1[c] = core_pwr_info[c].pa_5g[0];
4241300016Sadrian				b0[c] = core_pwr_info[c].pa_5g[1];
4242300016Sadrian				b1[c] = core_pwr_info[c].pa_5g[2];
4243300016Sadrian			}
4244300016Sadrian		} else if (freq >= 5500) {
4245300016Sadrian			for (c = 0; c < 2; c++) {
4246300016Sadrian				idle[c] = nphy->pwr_ctl_info[c].idle_tssi_5g;
4247300016Sadrian				target[c] = core_pwr_info[c].maxpwr_5gh;
4248300016Sadrian				a1[c] = core_pwr_info[c].pa_5gh[0];
4249300016Sadrian				b0[c] = core_pwr_info[c].pa_5gh[1];
4250300016Sadrian				b1[c] = core_pwr_info[c].pa_5gh[2];
4251300016Sadrian			}
4252300016Sadrian		} else {
4253300016Sadrian			idle[0] = nphy->pwr_ctl_info[0].idle_tssi_5g;
4254300016Sadrian			idle[1] = nphy->pwr_ctl_info[1].idle_tssi_5g;
4255300016Sadrian			target[0] = target[1] = 52;
4256300016Sadrian			a1[0] = a1[1] = -424;
4257300016Sadrian			b0[0] = b0[1] = 5612;
4258300016Sadrian			b1[0] = b1[1] = -1393;
4259300016Sadrian		}
4260300016Sadrian	}
4261300016Sadrian
4262300016Sadrian	ppr_max = bwn_ppr_get_max(mac, &nphy->tx_pwr_max_ppr);
4263300016Sadrian	if (ppr_max) {
4264300016Sadrian		target[0] = ppr_max;
4265300016Sadrian		target[1] = ppr_max;
4266300016Sadrian	}
4267300016Sadrian
4268300016Sadrian	if (mac->mac_phy.rev >= 3) {
4269300016Sadrian		if (siba_sprom_get_fem_2ghz_tssipos(sc->sc_dev))
4270300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_TXPCTL_ITSSI, 0x4000);
4271300016Sadrian		if (mac->mac_phy.rev >= 7) {
4272300016Sadrian			for (c = 0; c < 2; c++) {
4273300016Sadrian				r = c ? 0x190 : 0x170;
4274300016Sadrian				if (bwn_nphy_ipa(mac))
4275300016Sadrian					BWN_RF_WRITE(mac, r + 0x9, (bwn_current_band(mac) == BWN_BAND_2G) ? 0xE : 0xC);
4276300016Sadrian			}
4277300016Sadrian		} else {
4278300016Sadrian			if (bwn_nphy_ipa(mac)) {
4279300016Sadrian				tmp = (bwn_current_band(mac) == BWN_BAND_5G) ? 0xC : 0xE;
4280300016Sadrian				BWN_RF_WRITE(mac,
4281300016Sadrian					B2056_TX0 | B2056_TX_TX_SSI_MUX, tmp);
4282300016Sadrian				BWN_RF_WRITE(mac,
4283300016Sadrian					B2056_TX1 | B2056_TX_TX_SSI_MUX, tmp);
4284300016Sadrian			} else {
4285300016Sadrian				BWN_RF_WRITE(mac,
4286300016Sadrian					B2056_TX0 | B2056_TX_TX_SSI_MUX, 0x11);
4287300016Sadrian				BWN_RF_WRITE(mac,
4288300016Sadrian					B2056_TX1 | B2056_TX_TX_SSI_MUX, 0x11);
4289300016Sadrian			}
4290300016Sadrian		}
4291300016Sadrian	}
4292300016Sadrian
4293300016Sadrian	if (siba_get_revid(sc->sc_dev) == 11 || siba_get_revid(sc->sc_dev) == 12) {
4294300016Sadrian		BWN_WRITE_SETMASK4(mac, BWN_MACCTL, ~0, 0x200000);
4295300016Sadrian		BWN_READ_4(mac, BWN_MACCTL);
4296300016Sadrian		DELAY(1);
4297300016Sadrian	}
4298300016Sadrian
4299300016Sadrian	if (phy->rev >= 19) {
4300300016Sadrian		/* TODO */
4301300016Sadrian	} else if (phy->rev >= 7) {
4302300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_TXPCTL_CMD,
4303300016Sadrian				~BWN_NPHY_TXPCTL_CMD_INIT, 0x19);
4304300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_TXPCTL_INIT,
4305300016Sadrian				~BWN_NPHY_TXPCTL_INIT_PIDXI1, 0x19);
4306300016Sadrian	} else {
4307300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_TXPCTL_CMD,
4308300016Sadrian				~BWN_NPHY_TXPCTL_CMD_INIT, 0x40);
4309300016Sadrian		if (mac->mac_phy.rev > 1)
4310300016Sadrian			BWN_PHY_SETMASK(mac, BWN_NPHY_TXPCTL_INIT,
4311300016Sadrian				~BWN_NPHY_TXPCTL_INIT_PIDXI1, 0x40);
4312300016Sadrian	}
4313300016Sadrian
4314300016Sadrian	if (siba_get_revid(sc->sc_dev) == 11 || siba_get_revid(sc->sc_dev) == 12)
4315300016Sadrian		BWN_WRITE_SETMASK4(mac, BWN_MACCTL, ~0x200000, 0);
4316300016Sadrian
4317300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_TXPCTL_N,
4318300016Sadrian		      0xF0 << BWN_NPHY_TXPCTL_N_TSSID_SHIFT |
4319300016Sadrian		      3 << BWN_NPHY_TXPCTL_N_NPTIL2_SHIFT);
4320300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_TXPCTL_ITSSI,
4321300016Sadrian		      idle[0] << BWN_NPHY_TXPCTL_ITSSI_0_SHIFT |
4322300016Sadrian		      idle[1] << BWN_NPHY_TXPCTL_ITSSI_1_SHIFT |
4323300016Sadrian		      BWN_NPHY_TXPCTL_ITSSI_BINF);
4324300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_TXPCTL_TPWR,
4325300016Sadrian		      target[0] << BWN_NPHY_TXPCTL_TPWR_0_SHIFT |
4326300016Sadrian		      target[1] << BWN_NPHY_TXPCTL_TPWR_1_SHIFT);
4327300016Sadrian
4328300016Sadrian	for (c = 0; c < 2; c++) {
4329300016Sadrian		for (i = 0; i < 64; i++) {
4330300016Sadrian			num = 8 * (16 * b0[c] + b1[c] * i);
4331300016Sadrian			den = 32768 + a1[c] * i;
4332300016Sadrian			pwr = max((4 * num + den / 2) / den, -8);
4333300016Sadrian			if (mac->mac_phy.rev < 3 && (i <= (31 - idle[c] + 1)))
4334300016Sadrian				pwr = max(pwr, target[c] + 1);
4335300016Sadrian			regval[i] = pwr;
4336300016Sadrian		}
4337300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB32(26 + c, 0), 64, regval);
4338300016Sadrian	}
4339300016Sadrian
4340300016Sadrian	bwn_nphy_tx_prepare_adjusted_power_table(mac);
4341300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(26, 64), 84, nphy->adj_pwr_tbl);
4342300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(27, 64), 84, nphy->adj_pwr_tbl);
4343300016Sadrian
4344300016Sadrian	if (nphy->hang_avoid)
4345300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, false);
4346300016Sadrian}
4347300016Sadrian
4348300016Sadrianstatic void bwn_nphy_tx_gain_table_upload(struct bwn_mac *mac)
4349300016Sadrian{
4350300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
4351300016Sadrian
4352300016Sadrian	const uint32_t *table = NULL;
4353300016Sadrian	uint32_t rfpwr_offset;
4354300016Sadrian	uint8_t pga_gain, pad_gain;
4355300016Sadrian	int i;
4356300016Sadrian	const int16_t *rf_pwr_offset_table = NULL;
4357300016Sadrian
4358300016Sadrian	table = bwn_nphy_get_tx_gain_table(mac);
4359300016Sadrian	if (!table)
4360300016Sadrian		return;
4361300016Sadrian
4362300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB32(26, 192), 128, table);
4363300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB32(27, 192), 128, table);
4364300016Sadrian
4365300016Sadrian	if (phy->rev < 3)
4366300016Sadrian		return;
4367300016Sadrian
4368300016Sadrian#if 0
4369300016Sadrian	nphy->gmval = (table[0] >> 16) & 0x7000;
4370300016Sadrian#endif
4371300016Sadrian
4372300016Sadrian	if (phy->rev >= 19) {
4373300016Sadrian		return;
4374300016Sadrian	} else if (phy->rev >= 7) {
4375300016Sadrian		rf_pwr_offset_table = bwn_ntab_get_rf_pwr_offset_table(mac);
4376300016Sadrian		if (!rf_pwr_offset_table)
4377300016Sadrian			return;
4378300016Sadrian		/* TODO: Enable this once we have gains configured */
4379300016Sadrian		return;
4380300016Sadrian	}
4381300016Sadrian
4382300016Sadrian	for (i = 0; i < 128; i++) {
4383300016Sadrian		if (phy->rev >= 19) {
4384300016Sadrian			/* TODO */
4385300016Sadrian			return;
4386300016Sadrian		} else if (phy->rev >= 7) {
4387300016Sadrian			pga_gain = (table[i] >> 24) & 0xf;
4388300016Sadrian			pad_gain = (table[i] >> 19) & 0x1f;
4389300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_2G)
4390300016Sadrian				rfpwr_offset = rf_pwr_offset_table[pad_gain];
4391300016Sadrian			else
4392300016Sadrian				rfpwr_offset = rf_pwr_offset_table[pga_gain];
4393300016Sadrian		} else {
4394300016Sadrian			pga_gain = (table[i] >> 24) & 0xF;
4395300016Sadrian			if (bwn_current_band(mac) == BWN_BAND_2G)
4396300016Sadrian				rfpwr_offset = bwn_ntab_papd_pga_gain_delta_ipa_2g[pga_gain];
4397300016Sadrian			else
4398300016Sadrian				rfpwr_offset = 0; /* FIXME */
4399300016Sadrian		}
4400300016Sadrian
4401300016Sadrian		bwn_ntab_write(mac, BWN_NTAB32(26, 576 + i), rfpwr_offset);
4402300016Sadrian		bwn_ntab_write(mac, BWN_NTAB32(27, 576 + i), rfpwr_offset);
4403300016Sadrian	}
4404300016Sadrian}
4405300016Sadrian
4406300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */
4407300016Sadrianstatic void bwn_nphy_pa_override(struct bwn_mac *mac, bool enable)
4408300016Sadrian{
4409300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
4410300016Sadrian	bwn_band_t band;
4411300016Sadrian	uint16_t tmp;
4412300016Sadrian
4413300016Sadrian	if (!enable) {
4414300016Sadrian		nphy->rfctrl_intc1_save = BWN_PHY_READ(mac,
4415300016Sadrian						       BWN_NPHY_RFCTL_INTC1);
4416300016Sadrian		nphy->rfctrl_intc2_save = BWN_PHY_READ(mac,
4417300016Sadrian						       BWN_NPHY_RFCTL_INTC2);
4418300016Sadrian		band = bwn_current_band(mac);
4419300016Sadrian		if (mac->mac_phy.rev >= 7) {
4420300016Sadrian			tmp = 0x1480;
4421300016Sadrian		} else if (mac->mac_phy.rev >= 3) {
4422300016Sadrian			if (band == BWN_BAND_5G)
4423300016Sadrian				tmp = 0x600;
4424300016Sadrian			else
4425300016Sadrian				tmp = 0x480;
4426300016Sadrian		} else {
4427300016Sadrian			if (band == BWN_BAND_5G)
4428300016Sadrian				tmp = 0x180;
4429300016Sadrian			else
4430300016Sadrian				tmp = 0x120;
4431300016Sadrian		}
4432300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1, tmp);
4433300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2, tmp);
4434300016Sadrian	} else {
4435300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1,
4436300016Sadrian				nphy->rfctrl_intc1_save);
4437300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2,
4438300016Sadrian				nphy->rfctrl_intc2_save);
4439300016Sadrian	}
4440300016Sadrian}
4441300016Sadrian
4442300016Sadrian/*
4443300016Sadrian * TX low-pass filter bandwidth setup
4444300016Sadrian * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw
4445300016Sadrian */
4446300016Sadrianstatic void bwn_nphy_tx_lpf_bw(struct bwn_mac *mac)
4447300016Sadrian{
4448300016Sadrian	uint16_t tmp;
4449300016Sadrian
4450300016Sadrian	if (mac->mac_phy.rev < 3 || mac->mac_phy.rev >= 7)
4451300016Sadrian		return;
4452300016Sadrian
4453300016Sadrian	if (bwn_nphy_ipa(mac))
4454300016Sadrian		tmp = bwn_is_40mhz(mac) ? 5 : 4;
4455300016Sadrian	else
4456300016Sadrian		tmp = bwn_is_40mhz(mac) ? 3 : 1;
4457300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_TXF_40CO_B32S2,
4458300016Sadrian		      (tmp << 9) | (tmp << 6) | (tmp << 3) | tmp);
4459300016Sadrian
4460300016Sadrian	if (bwn_nphy_ipa(mac)) {
4461300016Sadrian		tmp = bwn_is_40mhz(mac) ? 4 : 1;
4462300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXF_40CO_B1S2,
4463300016Sadrian			      (tmp << 9) | (tmp << 6) | (tmp << 3) | tmp);
4464300016Sadrian	}
4465300016Sadrian}
4466300016Sadrian
4467300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */
4468300016Sadrianstatic void bwn_nphy_rx_iq_est(struct bwn_mac *mac, struct bwn_nphy_iq_est *est,
4469300016Sadrian				uint16_t samps, uint8_t time, bool wait)
4470300016Sadrian{
4471300016Sadrian	int i;
4472300016Sadrian	uint16_t tmp;
4473300016Sadrian
4474300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_IQEST_SAMCNT, samps);
4475300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_IQEST_WT, ~BWN_NPHY_IQEST_WT_VAL, time);
4476300016Sadrian	if (wait)
4477300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_IQEST_CMD, BWN_NPHY_IQEST_CMD_MODE);
4478300016Sadrian	else
4479300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_IQEST_CMD, ~BWN_NPHY_IQEST_CMD_MODE);
4480300016Sadrian
4481300016Sadrian	BWN_PHY_SET(mac, BWN_NPHY_IQEST_CMD, BWN_NPHY_IQEST_CMD_START);
4482300016Sadrian
4483300016Sadrian	for (i = 1000; i; i--) {
4484300016Sadrian		tmp = BWN_PHY_READ(mac, BWN_NPHY_IQEST_CMD);
4485300016Sadrian		if (!(tmp & BWN_NPHY_IQEST_CMD_START)) {
4486300016Sadrian			est->i0_pwr = (BWN_PHY_READ(mac, BWN_NPHY_IQEST_IPACC_HI0) << 16) |
4487300016Sadrian					BWN_PHY_READ(mac, BWN_NPHY_IQEST_IPACC_LO0);
4488300016Sadrian			est->q0_pwr = (BWN_PHY_READ(mac, BWN_NPHY_IQEST_QPACC_HI0) << 16) |
4489300016Sadrian					BWN_PHY_READ(mac, BWN_NPHY_IQEST_QPACC_LO0);
4490300016Sadrian			est->iq0_prod = (BWN_PHY_READ(mac, BWN_NPHY_IQEST_IQACC_HI0) << 16) |
4491300016Sadrian					BWN_PHY_READ(mac, BWN_NPHY_IQEST_IQACC_LO0);
4492300016Sadrian
4493300016Sadrian			est->i1_pwr = (BWN_PHY_READ(mac, BWN_NPHY_IQEST_IPACC_HI1) << 16) |
4494300016Sadrian					BWN_PHY_READ(mac, BWN_NPHY_IQEST_IPACC_LO1);
4495300016Sadrian			est->q1_pwr = (BWN_PHY_READ(mac, BWN_NPHY_IQEST_QPACC_HI1) << 16) |
4496300016Sadrian					BWN_PHY_READ(mac, BWN_NPHY_IQEST_QPACC_LO1);
4497300016Sadrian			est->iq1_prod = (BWN_PHY_READ(mac, BWN_NPHY_IQEST_IQACC_HI1) << 16) |
4498300016Sadrian					BWN_PHY_READ(mac, BWN_NPHY_IQEST_IQACC_LO1);
4499300016Sadrian			return;
4500300016Sadrian		}
4501300016Sadrian		DELAY(10);
4502300016Sadrian	}
4503300016Sadrian	memset(est, 0, sizeof(*est));
4504300016Sadrian}
4505300016Sadrian
4506300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */
4507300016Sadrianstatic void bwn_nphy_rx_iq_coeffs(struct bwn_mac *mac, bool write,
4508300016Sadrian					struct bwn_phy_n_iq_comp *pcomp)
4509300016Sadrian{
4510300016Sadrian	if (write) {
4511300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_C1_RXIQ_COMPA0, pcomp->a0);
4512300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_C1_RXIQ_COMPB0, pcomp->b0);
4513300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_C2_RXIQ_COMPA1, pcomp->a1);
4514300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_C2_RXIQ_COMPB1, pcomp->b1);
4515300016Sadrian	} else {
4516300016Sadrian		pcomp->a0 = BWN_PHY_READ(mac, BWN_NPHY_C1_RXIQ_COMPA0);
4517300016Sadrian		pcomp->b0 = BWN_PHY_READ(mac, BWN_NPHY_C1_RXIQ_COMPB0);
4518300016Sadrian		pcomp->a1 = BWN_PHY_READ(mac, BWN_NPHY_C2_RXIQ_COMPA1);
4519300016Sadrian		pcomp->b1 = BWN_PHY_READ(mac, BWN_NPHY_C2_RXIQ_COMPB1);
4520300016Sadrian	}
4521300016Sadrian}
4522300016Sadrian
4523300016Sadrian#if 0
4524300016Sadrian/* Ready but not used anywhere */
4525300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */
4526300016Sadrianstatic void bwn_nphy_rx_cal_phy_cleanup(struct bwn_mac *mac, uint8_t core)
4527300016Sadrian{
4528300016Sadrian	uint16_t *regs = mac->mac_phy.phy_n->tx_rx_cal_phy_saveregs;
4529300016Sadrian
4530300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFSEQCA, regs[0]);
4531300016Sadrian	if (core == 0) {
4532300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C1, regs[1]);
4533300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER1, regs[2]);
4534300016Sadrian	} else {
4535300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C2, regs[1]);
4536300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, regs[2]);
4537300016Sadrian	}
4538300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1, regs[3]);
4539300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2, regs[4]);
4540300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_RSSIO1, regs[5]);
4541300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_RSSIO2, regs[6]);
4542300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_TXF_40CO_B1S1, regs[7]);
4543300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_OVER, regs[8]);
4544300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PAPD_EN0, regs[9]);
4545300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PAPD_EN1, regs[10]);
4546300016Sadrian}
4547300016Sadrian
4548300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */
4549300016Sadrianstatic void bwn_nphy_rx_cal_phy_setup(struct bwn_mac *mac, uint8_t core)
4550300016Sadrian{
4551300016Sadrian	uint8_t rxval, txval;
4552300016Sadrian	uint16_t *regs = mac->mac_phy.phy_n->tx_rx_cal_phy_saveregs;
4553300016Sadrian
4554300016Sadrian	regs[0] = BWN_PHY_READ(mac, BWN_NPHY_RFSEQCA);
4555300016Sadrian	if (core == 0) {
4556300016Sadrian		regs[1] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_C1);
4557300016Sadrian		regs[2] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_OVER1);
4558300016Sadrian	} else {
4559300016Sadrian		regs[1] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_C2);
4560300016Sadrian		regs[2] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_OVER);
4561300016Sadrian	}
4562300016Sadrian	regs[3] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC1);
4563300016Sadrian	regs[4] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC2);
4564300016Sadrian	regs[5] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_RSSIO1);
4565300016Sadrian	regs[6] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_RSSIO2);
4566300016Sadrian	regs[7] = BWN_PHY_READ(mac, BWN_NPHY_TXF_40CO_B1S1);
4567300016Sadrian	regs[8] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_OVER);
4568300016Sadrian	regs[9] = BWN_PHY_READ(mac, BWN_NPHY_PAPD_EN0);
4569300016Sadrian	regs[10] = BWN_PHY_READ(mac, BWN_NPHY_PAPD_EN1);
4570300016Sadrian
4571300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_PAPD_EN0, ~0x0001);
4572300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_PAPD_EN1, ~0x0001);
4573300016Sadrian
4574300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_RFSEQCA,
4575300016Sadrian			~BWN_NPHY_RFSEQCA_RXDIS & 0xFFFF,
4576300016Sadrian			((1 - core) << BWN_NPHY_RFSEQCA_RXDIS_SHIFT));
4577300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_RFSEQCA, ~BWN_NPHY_RFSEQCA_TXEN,
4578300016Sadrian			((1 - core) << BWN_NPHY_RFSEQCA_TXEN_SHIFT));
4579300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_RFSEQCA, ~BWN_NPHY_RFSEQCA_RXEN,
4580300016Sadrian			(core << BWN_NPHY_RFSEQCA_RXEN_SHIFT));
4581300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_RFSEQCA, ~BWN_NPHY_RFSEQCA_TXDIS,
4582300016Sadrian			(core << BWN_NPHY_RFSEQCA_TXDIS_SHIFT));
4583300016Sadrian
4584300016Sadrian	if (core == 0) {
4585300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_C1, ~0x0007);
4586300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER1, 0x0007);
4587300016Sadrian	} else {
4588300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_AFECTL_C2, ~0x0007);
4589300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER, 0x0007);
4590300016Sadrian	}
4591300016Sadrian
4592300016Sadrian	bwn_nphy_rf_ctl_intc_override(mac, N_INTC_OVERRIDE_PA, 0, 3);
4593300016Sadrian	bwn_nphy_rf_ctl_override(mac, 8, 0, 3, false);
4594300016Sadrian	bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RX2TX);
4595300016Sadrian
4596300016Sadrian	if (core == 0) {
4597300016Sadrian		rxval = 1;
4598300016Sadrian		txval = 8;
4599300016Sadrian	} else {
4600300016Sadrian		rxval = 4;
4601300016Sadrian		txval = 2;
4602300016Sadrian	}
4603300016Sadrian	bwn_nphy_rf_ctl_intc_override(mac, N_INTC_OVERRIDE_TRSW, rxval,
4604300016Sadrian				      core + 1);
4605300016Sadrian	bwn_nphy_rf_ctl_intc_override(mac, N_INTC_OVERRIDE_TRSW, txval,
4606300016Sadrian				      2 - core);
4607300016Sadrian}
4608300016Sadrian#endif
4609300016Sadrian
4610300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */
4611300016Sadrianstatic void bwn_nphy_calc_rx_iq_comp(struct bwn_mac *mac, uint8_t mask)
4612300016Sadrian{
4613300016Sadrian	int i;
4614300016Sadrian	int32_t iq;
4615300016Sadrian	uint32_t ii;
4616300016Sadrian	uint32_t qq;
4617300016Sadrian	int iq_nbits, qq_nbits;
4618300016Sadrian	int arsh, brsh;
4619300016Sadrian	uint16_t tmp, a, b;
4620300016Sadrian
4621300016Sadrian	struct bwn_nphy_iq_est est;
4622300016Sadrian	struct bwn_phy_n_iq_comp old;
4623300016Sadrian	struct bwn_phy_n_iq_comp new = { };
4624300016Sadrian	bool error = false;
4625300016Sadrian
4626300016Sadrian	if (mask == 0)
4627300016Sadrian		return;
4628300016Sadrian
4629300016Sadrian	bwn_nphy_rx_iq_coeffs(mac, false, &old);
4630300016Sadrian	bwn_nphy_rx_iq_coeffs(mac, true, &new);
4631300016Sadrian	bwn_nphy_rx_iq_est(mac, &est, 0x4000, 32, false);
4632300016Sadrian	new = old;
4633300016Sadrian
4634300016Sadrian	for (i = 0; i < 2; i++) {
4635300016Sadrian		if (i == 0 && (mask & 1)) {
4636300016Sadrian			iq = est.iq0_prod;
4637300016Sadrian			ii = est.i0_pwr;
4638300016Sadrian			qq = est.q0_pwr;
4639300016Sadrian		} else if (i == 1 && (mask & 2)) {
4640300016Sadrian			iq = est.iq1_prod;
4641300016Sadrian			ii = est.i1_pwr;
4642300016Sadrian			qq = est.q1_pwr;
4643300016Sadrian		} else {
4644300016Sadrian			continue;
4645300016Sadrian		}
4646300016Sadrian
4647300016Sadrian		if (ii + qq < 2) {
4648300016Sadrian			error = true;
4649300016Sadrian			break;
4650300016Sadrian		}
4651300016Sadrian
4652300016Sadrian		iq_nbits = fls(abs(iq));
4653300016Sadrian		qq_nbits = fls(qq);
4654300016Sadrian
4655300016Sadrian		arsh = iq_nbits - 20;
4656300016Sadrian		if (arsh >= 0) {
4657300016Sadrian			a = -((iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
4658300016Sadrian			tmp = ii >> arsh;
4659300016Sadrian		} else {
4660300016Sadrian			a = -((iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
4661300016Sadrian			tmp = ii << -arsh;
4662300016Sadrian		}
4663300016Sadrian		if (tmp == 0) {
4664300016Sadrian			error = true;
4665300016Sadrian			break;
4666300016Sadrian		}
4667300016Sadrian		a /= tmp;
4668300016Sadrian
4669300016Sadrian		brsh = qq_nbits - 11;
4670300016Sadrian		if (brsh >= 0) {
4671300016Sadrian			b = (qq << (31 - qq_nbits));
4672300016Sadrian			tmp = ii >> brsh;
4673300016Sadrian		} else {
4674300016Sadrian			b = (qq << (31 - qq_nbits));
4675300016Sadrian			tmp = ii << -brsh;
4676300016Sadrian		}
4677300016Sadrian		if (tmp == 0) {
4678300016Sadrian			error = true;
4679300016Sadrian			break;
4680300016Sadrian		}
4681300016Sadrian		b = bwn_sqrt(mac, b / tmp - a * a) - (1 << 10);
4682300016Sadrian
4683300016Sadrian		if (i == 0 && (mask & 0x1)) {
4684300016Sadrian			if (mac->mac_phy.rev >= 3) {
4685300016Sadrian				new.a0 = a & 0x3FF;
4686300016Sadrian				new.b0 = b & 0x3FF;
4687300016Sadrian			} else {
4688300016Sadrian				new.a0 = b & 0x3FF;
4689300016Sadrian				new.b0 = a & 0x3FF;
4690300016Sadrian			}
4691300016Sadrian		} else if (i == 1 && (mask & 0x2)) {
4692300016Sadrian			if (mac->mac_phy.rev >= 3) {
4693300016Sadrian				new.a1 = a & 0x3FF;
4694300016Sadrian				new.b1 = b & 0x3FF;
4695300016Sadrian			} else {
4696300016Sadrian				new.a1 = b & 0x3FF;
4697300016Sadrian				new.b1 = a & 0x3FF;
4698300016Sadrian			}
4699300016Sadrian		}
4700300016Sadrian	}
4701300016Sadrian
4702300016Sadrian	if (error)
4703300016Sadrian		new = old;
4704300016Sadrian
4705300016Sadrian	bwn_nphy_rx_iq_coeffs(mac, true, &new);
4706300016Sadrian}
4707300016Sadrian
4708300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */
4709300016Sadrianstatic void bwn_nphy_tx_iq_workaround(struct bwn_mac *mac)
4710300016Sadrian{
4711300016Sadrian	uint16_t array[4];
4712300016Sadrian	bwn_ntab_read_bulk(mac, BWN_NTAB16(0xF, 0x50), 4, array);
4713300016Sadrian
4714300016Sadrian	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHM_SH_NPHY_TXIQW0, array[0]);
4715300016Sadrian	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHM_SH_NPHY_TXIQW1, array[1]);
4716300016Sadrian	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHM_SH_NPHY_TXIQW2, array[2]);
4717300016Sadrian	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHM_SH_NPHY_TXIQW3, array[3]);
4718300016Sadrian}
4719300016Sadrian
4720300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */
4721300016Sadrianstatic void bwn_nphy_spur_workaround(struct bwn_mac *mac)
4722300016Sadrian{
4723300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
4724300016Sadrian
4725300016Sadrian	uint8_t channel = bwn_get_chan(mac);
4726300016Sadrian	int tone[2] = { 57, 58 };
4727300016Sadrian	uint32_t noise[2] = { 0x3FF, 0x3FF };
4728300016Sadrian
4729300016Sadrian	if (mac->mac_phy.rev < 3) {
4730300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: phy rev %d out of range\n",
4731300016Sadrian		    __func__,
4732300016Sadrian		    mac->mac_phy.rev);
4733300016Sadrian	}
4734300016Sadrian
4735300016Sadrian	if (nphy->hang_avoid)
4736300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 1);
4737300016Sadrian
4738300016Sadrian	if (nphy->gband_spurwar_en) {
4739300016Sadrian		/* TODO: N PHY Adjust Analog Pfbw (7) */
4740300016Sadrian		if (channel == 11 && bwn_is_40mhz(mac))
4741300016Sadrian			; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/
4742300016Sadrian		else
4743300016Sadrian			; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
4744300016Sadrian		/* TODO: N PHY Adjust CRS Min Power (0x1E) */
4745300016Sadrian	}
4746300016Sadrian
4747300016Sadrian	if (nphy->aband_spurwar_en) {
4748300016Sadrian		if (channel == 54) {
4749300016Sadrian			tone[0] = 0x20;
4750300016Sadrian			noise[0] = 0x25F;
4751300016Sadrian		} else if (channel == 38 || channel == 102 || channel == 118) {
4752300016Sadrian			if (0 /* FIXME */) {
4753300016Sadrian				tone[0] = 0x20;
4754300016Sadrian				noise[0] = 0x21F;
4755300016Sadrian			} else {
4756300016Sadrian				tone[0] = 0;
4757300016Sadrian				noise[0] = 0;
4758300016Sadrian			}
4759300016Sadrian		} else if (channel == 134) {
4760300016Sadrian			tone[0] = 0x20;
4761300016Sadrian			noise[0] = 0x21F;
4762300016Sadrian		} else if (channel == 151) {
4763300016Sadrian			tone[0] = 0x10;
4764300016Sadrian			noise[0] = 0x23F;
4765300016Sadrian		} else if (channel == 153 || channel == 161) {
4766300016Sadrian			tone[0] = 0x30;
4767300016Sadrian			noise[0] = 0x23F;
4768300016Sadrian		} else {
4769300016Sadrian			tone[0] = 0;
4770300016Sadrian			noise[0] = 0;
4771300016Sadrian		}
4772300016Sadrian
4773300016Sadrian		if (!tone[0] && !noise[0])
4774300016Sadrian			; /* TODO: N PHY Adjust Min Noise Var(1, tone, noise)*/
4775300016Sadrian		else
4776300016Sadrian			; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
4777300016Sadrian	}
4778300016Sadrian
4779300016Sadrian	if (nphy->hang_avoid)
4780300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 0);
4781300016Sadrian}
4782300016Sadrian
4783300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
4784300016Sadrianstatic void bwn_nphy_tx_pwr_ctrl_coef_setup(struct bwn_mac *mac)
4785300016Sadrian{
4786300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
4787300016Sadrian	int i, j;
4788300016Sadrian	uint32_t tmp;
4789300016Sadrian	uint32_t cur_real, cur_imag, real_part, imag_part;
4790300016Sadrian
4791300016Sadrian	uint16_t buffer[7];
4792300016Sadrian
4793300016Sadrian	if (nphy->hang_avoid)
4794300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, true);
4795300016Sadrian
4796300016Sadrian	bwn_ntab_read_bulk(mac, BWN_NTAB16(15, 80), 7, buffer);
4797300016Sadrian
4798300016Sadrian	for (i = 0; i < 2; i++) {
4799300016Sadrian		tmp = ((buffer[i * 2] & 0x3FF) << 10) |
4800300016Sadrian			(buffer[i * 2 + 1] & 0x3FF);
4801300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_ADDR,
4802300016Sadrian				(((i + 26) << 10) | 320));
4803300016Sadrian		for (j = 0; j < 128; j++) {
4804300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATAHI,
4805300016Sadrian					((tmp >> 16) & 0xFFFF));
4806300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO,
4807300016Sadrian					(tmp & 0xFFFF));
4808300016Sadrian		}
4809300016Sadrian	}
4810300016Sadrian
4811300016Sadrian	for (i = 0; i < 2; i++) {
4812300016Sadrian		tmp = buffer[5 + i];
4813300016Sadrian		real_part = (tmp >> 8) & 0xFF;
4814300016Sadrian		imag_part = (tmp & 0xFF);
4815300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_ADDR,
4816300016Sadrian				(((i + 26) << 10) | 448));
4817300016Sadrian
4818300016Sadrian		if (mac->mac_phy.rev >= 3) {
4819300016Sadrian			cur_real = real_part;
4820300016Sadrian			cur_imag = imag_part;
4821300016Sadrian			tmp = ((cur_real & 0xFF) << 8) | (cur_imag & 0xFF);
4822300016Sadrian		}
4823300016Sadrian
4824300016Sadrian		for (j = 0; j < 128; j++) {
4825300016Sadrian			if (mac->mac_phy.rev < 3) {
4826300016Sadrian				cur_real = (real_part * loscale[j] + 128) >> 8;
4827300016Sadrian				cur_imag = (imag_part * loscale[j] + 128) >> 8;
4828300016Sadrian				tmp = ((cur_real & 0xFF) << 8) |
4829300016Sadrian					(cur_imag & 0xFF);
4830300016Sadrian			}
4831300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATAHI,
4832300016Sadrian					((tmp >> 16) & 0xFFFF));
4833300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_TABLE_DATALO,
4834300016Sadrian					(tmp & 0xFFFF));
4835300016Sadrian		}
4836300016Sadrian	}
4837300016Sadrian
4838300016Sadrian	if (mac->mac_phy.rev >= 3) {
4839300016Sadrian		bwn_shm_write_2(mac, BWN_SHARED,
4840300016Sadrian				BWN_SHM_SH_NPHY_TXPWR_INDX0, 0xFFFF);
4841300016Sadrian		bwn_shm_write_2(mac, BWN_SHARED,
4842300016Sadrian				BWN_SHM_SH_NPHY_TXPWR_INDX1, 0xFFFF);
4843300016Sadrian	}
4844300016Sadrian
4845300016Sadrian	if (nphy->hang_avoid)
4846300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, false);
4847300016Sadrian}
4848300016Sadrian
4849300016Sadrian/*
4850300016Sadrian * Restore RSSI Calibration
4851300016Sadrian * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal
4852300016Sadrian */
4853300016Sadrianstatic void bwn_nphy_restore_rssi_cal(struct bwn_mac *mac)
4854300016Sadrian{
4855300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
4856300016Sadrian
4857300016Sadrian	uint16_t *rssical_radio_regs = NULL;
4858300016Sadrian	uint16_t *rssical_phy_regs = NULL;
4859300016Sadrian
4860300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G) {
4861300016Sadrian		if (!nphy->rssical_chanspec_2G.center_freq)
4862300016Sadrian			return;
4863300016Sadrian		rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_2G;
4864300016Sadrian		rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_2G;
4865300016Sadrian	} else {
4866300016Sadrian		if (!nphy->rssical_chanspec_5G.center_freq)
4867300016Sadrian			return;
4868300016Sadrian		rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G;
4869300016Sadrian		rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G;
4870300016Sadrian	}
4871300016Sadrian
4872300016Sadrian	if (mac->mac_phy.rev >= 19) {
4873300016Sadrian		/* TODO */
4874300016Sadrian	} else if (mac->mac_phy.rev >= 7) {
4875300016Sadrian		BWN_RF_SETMASK(mac, R2057_NB_MASTER_CORE0, ~R2057_VCM_MASK,
4876300016Sadrian				  rssical_radio_regs[0]);
4877300016Sadrian		BWN_RF_SETMASK(mac, R2057_NB_MASTER_CORE1, ~R2057_VCM_MASK,
4878300016Sadrian				  rssical_radio_regs[1]);
4879300016Sadrian	} else {
4880300016Sadrian		BWN_RF_SETMASK(mac, B2056_RX0 | B2056_RX_RSSI_MISC, 0xE3,
4881300016Sadrian				  rssical_radio_regs[0]);
4882300016Sadrian		BWN_RF_SETMASK(mac, B2056_RX1 | B2056_RX_RSSI_MISC, 0xE3,
4883300016Sadrian				  rssical_radio_regs[1]);
4884300016Sadrian	}
4885300016Sadrian
4886300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0I_RSSI_Z, rssical_phy_regs[0]);
4887300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0Q_RSSI_Z, rssical_phy_regs[1]);
4888300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1I_RSSI_Z, rssical_phy_regs[2]);
4889300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1Q_RSSI_Z, rssical_phy_regs[3]);
4890300016Sadrian
4891300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0I_RSSI_X, rssical_phy_regs[4]);
4892300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0Q_RSSI_X, rssical_phy_regs[5]);
4893300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1I_RSSI_X, rssical_phy_regs[6]);
4894300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1Q_RSSI_X, rssical_phy_regs[7]);
4895300016Sadrian
4896300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0I_RSSI_Y, rssical_phy_regs[8]);
4897300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_0Q_RSSI_Y, rssical_phy_regs[9]);
4898300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1I_RSSI_Y, rssical_phy_regs[10]);
4899300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]);
4900300016Sadrian}
4901300016Sadrian
4902300016Sadrianstatic void bwn_nphy_tx_cal_radio_setup_rev19(struct bwn_mac *mac)
4903300016Sadrian{
4904300016Sadrian	/* TODO */
4905300016Sadrian}
4906300016Sadrian
4907300016Sadrianstatic void bwn_nphy_tx_cal_radio_setup_rev7(struct bwn_mac *mac)
4908300016Sadrian{
4909300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
4910300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
4911300016Sadrian	uint16_t *save = nphy->tx_rx_cal_radio_saveregs;
4912300016Sadrian	int core, off;
4913300016Sadrian	uint16_t r, tmp;
4914300016Sadrian
4915300016Sadrian	for (core = 0; core < 2; core++) {
4916300016Sadrian		r = core ? 0x20 : 0;
4917300016Sadrian		off = core * 11;
4918300016Sadrian
4919300016Sadrian		save[off + 0] = BWN_RF_READ(mac, r + R2057_TX0_TX_SSI_MASTER);
4920300016Sadrian		save[off + 1] = BWN_RF_READ(mac, r + R2057_TX0_IQCAL_VCM_HG);
4921300016Sadrian		save[off + 2] = BWN_RF_READ(mac, r + R2057_TX0_IQCAL_IDAC);
4922300016Sadrian		save[off + 3] = BWN_RF_READ(mac, r + R2057_TX0_TSSI_VCM);
4923300016Sadrian		save[off + 4] = 0;
4924300016Sadrian		save[off + 5] = BWN_RF_READ(mac, r + R2057_TX0_TX_SSI_MUX);
4925300016Sadrian		if (phy->rf_rev != 5)
4926300016Sadrian			save[off + 6] = BWN_RF_READ(mac, r + R2057_TX0_TSSIA);
4927300016Sadrian		save[off + 7] = BWN_RF_READ(mac, r + R2057_TX0_TSSIG);
4928300016Sadrian		save[off + 8] = BWN_RF_READ(mac, r + R2057_TX0_TSSI_MISC1);
4929300016Sadrian
4930300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_5G) {
4931300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_TX_SSI_MASTER, 0xA);
4932300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_IQCAL_VCM_HG, 0x43);
4933300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_IQCAL_IDAC, 0x55);
4934300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_TSSI_VCM, 0);
4935300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_TSSIG, 0);
4936300016Sadrian			if (nphy->use_int_tx_iq_lo_cal) {
4937300016Sadrian				BWN_RF_WRITE(mac, r + R2057_TX0_TX_SSI_MUX, 0x4);
4938300016Sadrian				tmp = true ? 0x31 : 0x21; /* TODO */
4939300016Sadrian				BWN_RF_WRITE(mac, r + R2057_TX0_TSSIA, tmp);
4940300016Sadrian			}
4941300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_TSSI_MISC1, 0x00);
4942300016Sadrian		} else {
4943300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_TX_SSI_MASTER, 0x6);
4944300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_IQCAL_VCM_HG, 0x43);
4945300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_IQCAL_IDAC, 0x55);
4946300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_TSSI_VCM, 0);
4947300016Sadrian
4948300016Sadrian			if (phy->rf_rev != 5)
4949300016Sadrian				BWN_RF_WRITE(mac, r + R2057_TX0_TSSIA, 0);
4950300016Sadrian			if (nphy->use_int_tx_iq_lo_cal) {
4951300016Sadrian				BWN_RF_WRITE(mac, r + R2057_TX0_TX_SSI_MUX, 0x6);
4952300016Sadrian				tmp = true ? 0x31 : 0x21; /* TODO */
4953300016Sadrian				BWN_RF_WRITE(mac, r + R2057_TX0_TSSIG, tmp);
4954300016Sadrian			}
4955300016Sadrian			BWN_RF_WRITE(mac, r + R2057_TX0_TSSI_MISC1, 0);
4956300016Sadrian		}
4957300016Sadrian	}
4958300016Sadrian}
4959300016Sadrian
4960300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */
4961300016Sadrianstatic void bwn_nphy_tx_cal_radio_setup(struct bwn_mac *mac)
4962300016Sadrian{
4963300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
4964300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
4965300016Sadrian	uint16_t *save = nphy->tx_rx_cal_radio_saveregs;
4966300016Sadrian	uint16_t tmp;
4967300016Sadrian	uint8_t offset, i;
4968300016Sadrian
4969300016Sadrian	if (phy->rev >= 19) {
4970300016Sadrian		bwn_nphy_tx_cal_radio_setup_rev19(mac);
4971300016Sadrian	} else if (phy->rev >= 7) {
4972300016Sadrian		bwn_nphy_tx_cal_radio_setup_rev7(mac);
4973300016Sadrian	} else if (phy->rev >= 3) {
4974300016Sadrian	    for (i = 0; i < 2; i++) {
4975300016Sadrian		tmp = (i == 0) ? 0x2000 : 0x3000;
4976300016Sadrian		offset = i * 11;
4977300016Sadrian
4978300016Sadrian		save[offset + 0] = BWN_RF_READ(mac, B2055_CAL_RVARCTL);
4979300016Sadrian		save[offset + 1] = BWN_RF_READ(mac, B2055_CAL_LPOCTL);
4980300016Sadrian		save[offset + 2] = BWN_RF_READ(mac, B2055_CAL_TS);
4981300016Sadrian		save[offset + 3] = BWN_RF_READ(mac, B2055_CAL_RCCALRTS);
4982300016Sadrian		save[offset + 4] = BWN_RF_READ(mac, B2055_CAL_RCALRTS);
4983300016Sadrian		save[offset + 5] = BWN_RF_READ(mac, B2055_PADDRV);
4984300016Sadrian		save[offset + 6] = BWN_RF_READ(mac, B2055_XOCTL1);
4985300016Sadrian		save[offset + 7] = BWN_RF_READ(mac, B2055_XOCTL2);
4986300016Sadrian		save[offset + 8] = BWN_RF_READ(mac, B2055_XOREGUL);
4987300016Sadrian		save[offset + 9] = BWN_RF_READ(mac, B2055_XOMISC);
4988300016Sadrian		save[offset + 10] = BWN_RF_READ(mac, B2055_PLL_LFC1);
4989300016Sadrian
4990300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_5G) {
4991300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_RVARCTL, 0x0A);
4992300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_LPOCTL, 0x40);
4993300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_TS, 0x55);
4994300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_RCCALRTS, 0);
4995300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_RCALRTS, 0);
4996300016Sadrian			if (nphy->ipa5g_on) {
4997300016Sadrian				BWN_RF_WRITE(mac, tmp | B2055_PADDRV, 4);
4998300016Sadrian				BWN_RF_WRITE(mac, tmp | B2055_XOCTL1, 1);
4999300016Sadrian			} else {
5000300016Sadrian				BWN_RF_WRITE(mac, tmp | B2055_PADDRV, 0);
5001300016Sadrian				BWN_RF_WRITE(mac, tmp | B2055_XOCTL1, 0x2F);
5002300016Sadrian			}
5003300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_XOCTL2, 0);
5004300016Sadrian		} else {
5005300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_RVARCTL, 0x06);
5006300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_LPOCTL, 0x40);
5007300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_TS, 0x55);
5008300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_RCCALRTS, 0);
5009300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_CAL_RCALRTS, 0);
5010300016Sadrian			BWN_RF_WRITE(mac, tmp | B2055_XOCTL1, 0);
5011300016Sadrian			if (nphy->ipa2g_on) {
5012300016Sadrian				BWN_RF_WRITE(mac, tmp | B2055_PADDRV, 6);
5013300016Sadrian				BWN_RF_WRITE(mac, tmp | B2055_XOCTL2,
5014300016Sadrian					(mac->mac_phy.rev < 5) ? 0x11 : 0x01);
5015300016Sadrian			} else {
5016300016Sadrian				BWN_RF_WRITE(mac, tmp | B2055_PADDRV, 0);
5017300016Sadrian				BWN_RF_WRITE(mac, tmp | B2055_XOCTL2, 0);
5018300016Sadrian			}
5019300016Sadrian		}
5020300016Sadrian		BWN_RF_WRITE(mac, tmp | B2055_XOREGUL, 0);
5021300016Sadrian		BWN_RF_WRITE(mac, tmp | B2055_XOMISC, 0);
5022300016Sadrian		BWN_RF_WRITE(mac, tmp | B2055_PLL_LFC1, 0);
5023300016Sadrian	    }
5024300016Sadrian	} else {
5025300016Sadrian		save[0] = BWN_RF_READ(mac, B2055_C1_TX_RF_IQCAL1);
5026300016Sadrian		BWN_RF_WRITE(mac, B2055_C1_TX_RF_IQCAL1, 0x29);
5027300016Sadrian
5028300016Sadrian		save[1] = BWN_RF_READ(mac, B2055_C1_TX_RF_IQCAL2);
5029300016Sadrian		BWN_RF_WRITE(mac, B2055_C1_TX_RF_IQCAL2, 0x54);
5030300016Sadrian
5031300016Sadrian		save[2] = BWN_RF_READ(mac, B2055_C2_TX_RF_IQCAL1);
5032300016Sadrian		BWN_RF_WRITE(mac, B2055_C2_TX_RF_IQCAL1, 0x29);
5033300016Sadrian
5034300016Sadrian		save[3] = BWN_RF_READ(mac, B2055_C2_TX_RF_IQCAL2);
5035300016Sadrian		BWN_RF_WRITE(mac, B2055_C2_TX_RF_IQCAL2, 0x54);
5036300016Sadrian
5037300016Sadrian		save[3] = BWN_RF_READ(mac, B2055_C1_PWRDET_RXTX);
5038300016Sadrian		save[4] = BWN_RF_READ(mac, B2055_C2_PWRDET_RXTX);
5039300016Sadrian
5040300016Sadrian		if (!(BWN_PHY_READ(mac, BWN_NPHY_BANDCTL) &
5041300016Sadrian		    BWN_NPHY_BANDCTL_5GHZ)) {
5042300016Sadrian			BWN_RF_WRITE(mac, B2055_C1_PWRDET_RXTX, 0x04);
5043300016Sadrian			BWN_RF_WRITE(mac, B2055_C2_PWRDET_RXTX, 0x04);
5044300016Sadrian		} else {
5045300016Sadrian			BWN_RF_WRITE(mac, B2055_C1_PWRDET_RXTX, 0x20);
5046300016Sadrian			BWN_RF_WRITE(mac, B2055_C2_PWRDET_RXTX, 0x20);
5047300016Sadrian		}
5048300016Sadrian
5049300016Sadrian		if (mac->mac_phy.rev < 2) {
5050300016Sadrian			BWN_RF_SET(mac, B2055_C1_TX_BB_MXGM, 0x20);
5051300016Sadrian			BWN_RF_SET(mac, B2055_C2_TX_BB_MXGM, 0x20);
5052300016Sadrian		} else {
5053300016Sadrian			BWN_RF_MASK(mac, B2055_C1_TX_BB_MXGM, ~0x20);
5054300016Sadrian			BWN_RF_MASK(mac, B2055_C2_TX_BB_MXGM, ~0x20);
5055300016Sadrian		}
5056300016Sadrian	}
5057300016Sadrian}
5058300016Sadrian
5059300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */
5060300016Sadrianstatic void bwn_nphy_update_tx_cal_ladder(struct bwn_mac *mac, uint16_t core)
5061300016Sadrian{
5062300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
5063300016Sadrian	int i;
5064300016Sadrian	uint16_t scale, entry;
5065300016Sadrian
5066300016Sadrian	uint16_t tmp = nphy->txcal_bbmult;
5067300016Sadrian	if (core == 0)
5068300016Sadrian		tmp >>= 8;
5069300016Sadrian	tmp &= 0xff;
5070300016Sadrian
5071300016Sadrian	for (i = 0; i < 18; i++) {
5072300016Sadrian		scale = (ladder_lo[i].percent * tmp) / 100;
5073300016Sadrian		entry = ((scale & 0xFF) << 8) | ladder_lo[i].g_env;
5074300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(15, i), entry);
5075300016Sadrian
5076300016Sadrian		scale = (ladder_iq[i].percent * tmp) / 100;
5077300016Sadrian		entry = ((scale & 0xFF) << 8) | ladder_iq[i].g_env;
5078300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(15, i + 32), entry);
5079300016Sadrian	}
5080300016Sadrian}
5081300016Sadrian
5082300016Sadrianstatic void bwn_nphy_pa_set_tx_dig_filter(struct bwn_mac *mac, uint16_t offset,
5083300016Sadrian					  const int16_t *filter)
5084300016Sadrian{
5085300016Sadrian	int i;
5086300016Sadrian
5087300016Sadrian	offset = BWN_PHY_N(offset);
5088300016Sadrian
5089300016Sadrian	for (i = 0; i < 15; i++, offset++)
5090300016Sadrian		BWN_PHY_WRITE(mac, offset, filter[i]);
5091300016Sadrian}
5092300016Sadrian
5093300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */
5094300016Sadrianstatic void bwn_nphy_ext_pa_set_tx_dig_filters(struct bwn_mac *mac)
5095300016Sadrian{
5096300016Sadrian	bwn_nphy_pa_set_tx_dig_filter(mac, 0x2C5,
5097300016Sadrian				      tbl_tx_filter_coef_rev4[2]);
5098300016Sadrian}
5099300016Sadrian
5100300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */
5101300016Sadrianstatic void bwn_nphy_int_pa_set_tx_dig_filters(struct bwn_mac *mac)
5102300016Sadrian{
5103300016Sadrian	/* BWN_NPHY_TXF_20CO_S0A1, BWN_NPHY_TXF_40CO_S0A1, unknown */
5104300016Sadrian	static const uint16_t offset[] = { 0x186, 0x195, 0x2C5 };
5105300016Sadrian	static const int16_t dig_filter_phy_rev16[] = {
5106300016Sadrian		-375, 136, -407, 208, -1527,
5107300016Sadrian		956, 93, 186, 93, 230,
5108300016Sadrian		-44, 230, 201, -191, 201,
5109300016Sadrian	};
5110300016Sadrian	int i;
5111300016Sadrian
5112300016Sadrian	for (i = 0; i < 3; i++)
5113300016Sadrian		bwn_nphy_pa_set_tx_dig_filter(mac, offset[i],
5114300016Sadrian					      tbl_tx_filter_coef_rev4[i]);
5115300016Sadrian
5116300016Sadrian	/* Verified with BCM43227 and BCM43228 */
5117300016Sadrian	if (mac->mac_phy.rev == 16)
5118300016Sadrian		bwn_nphy_pa_set_tx_dig_filter(mac, 0x186, dig_filter_phy_rev16);
5119300016Sadrian
5120300016Sadrian	/* Verified with BCM43131 and BCM43217 */
5121300016Sadrian	if (mac->mac_phy.rev == 17) {
5122300016Sadrian		bwn_nphy_pa_set_tx_dig_filter(mac, 0x186, dig_filter_phy_rev16);
5123300016Sadrian		bwn_nphy_pa_set_tx_dig_filter(mac, 0x195,
5124300016Sadrian					      tbl_tx_filter_coef_rev4[1]);
5125300016Sadrian	}
5126300016Sadrian
5127300016Sadrian	if (bwn_is_40mhz(mac)) {
5128300016Sadrian		bwn_nphy_pa_set_tx_dig_filter(mac, 0x186,
5129300016Sadrian					      tbl_tx_filter_coef_rev4[3]);
5130300016Sadrian	} else {
5131300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_5G)
5132300016Sadrian			bwn_nphy_pa_set_tx_dig_filter(mac, 0x186,
5133300016Sadrian						      tbl_tx_filter_coef_rev4[5]);
5134300016Sadrian		if (bwn_get_chan(mac) == 14)
5135300016Sadrian			bwn_nphy_pa_set_tx_dig_filter(mac, 0x186,
5136300016Sadrian						      tbl_tx_filter_coef_rev4[6]);
5137300016Sadrian	}
5138300016Sadrian}
5139300016Sadrian
5140300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */
5141300016Sadrianstatic struct bwn_nphy_txgains bwn_nphy_get_tx_gains(struct bwn_mac *mac)
5142300016Sadrian{
5143300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
5144300016Sadrian
5145300016Sadrian	uint16_t curr_gain[2];
5146300016Sadrian	struct bwn_nphy_txgains target;
5147300016Sadrian	const uint32_t *table = NULL;
5148300016Sadrian
5149300016Sadrian	if (!nphy->txpwrctrl) {
5150300016Sadrian		int i;
5151300016Sadrian
5152300016Sadrian		if (nphy->hang_avoid)
5153300016Sadrian			bwn_nphy_stay_in_carrier_search(mac, true);
5154300016Sadrian		bwn_ntab_read_bulk(mac, BWN_NTAB16(7, 0x110), 2, curr_gain);
5155300016Sadrian		if (nphy->hang_avoid)
5156300016Sadrian			bwn_nphy_stay_in_carrier_search(mac, false);
5157300016Sadrian
5158300016Sadrian		for (i = 0; i < 2; ++i) {
5159300016Sadrian			if (mac->mac_phy.rev >= 7) {
5160300016Sadrian				target.ipa[i] = curr_gain[i] & 0x0007;
5161300016Sadrian				target.pad[i] = (curr_gain[i] & 0x00F8) >> 3;
5162300016Sadrian				target.pga[i] = (curr_gain[i] & 0x0F00) >> 8;
5163300016Sadrian				target.txgm[i] = (curr_gain[i] & 0x7000) >> 12;
5164300016Sadrian				target.tx_lpf[i] = (curr_gain[i] & 0x8000) >> 15;
5165300016Sadrian			} else if (mac->mac_phy.rev >= 3) {
5166300016Sadrian				target.ipa[i] = curr_gain[i] & 0x000F;
5167300016Sadrian				target.pad[i] = (curr_gain[i] & 0x00F0) >> 4;
5168300016Sadrian				target.pga[i] = (curr_gain[i] & 0x0F00) >> 8;
5169300016Sadrian				target.txgm[i] = (curr_gain[i] & 0x7000) >> 12;
5170300016Sadrian			} else {
5171300016Sadrian				target.ipa[i] = curr_gain[i] & 0x0003;
5172300016Sadrian				target.pad[i] = (curr_gain[i] & 0x000C) >> 2;
5173300016Sadrian				target.pga[i] = (curr_gain[i] & 0x0070) >> 4;
5174300016Sadrian				target.txgm[i] = (curr_gain[i] & 0x0380) >> 7;
5175300016Sadrian			}
5176300016Sadrian		}
5177300016Sadrian	} else {
5178300016Sadrian		int i;
5179300016Sadrian		uint16_t index[2];
5180300016Sadrian		index[0] = (BWN_PHY_READ(mac, BWN_NPHY_C1_TXPCTL_STAT) &
5181300016Sadrian			BWN_NPHY_TXPCTL_STAT_BIDX) >>
5182300016Sadrian			BWN_NPHY_TXPCTL_STAT_BIDX_SHIFT;
5183300016Sadrian		index[1] = (BWN_PHY_READ(mac, BWN_NPHY_C2_TXPCTL_STAT) &
5184300016Sadrian			BWN_NPHY_TXPCTL_STAT_BIDX) >>
5185300016Sadrian			BWN_NPHY_TXPCTL_STAT_BIDX_SHIFT;
5186300016Sadrian
5187300016Sadrian		for (i = 0; i < 2; ++i) {
5188300016Sadrian			table = bwn_nphy_get_tx_gain_table(mac);
5189300016Sadrian			if (!table)
5190300016Sadrian				break;
5191300016Sadrian
5192300016Sadrian			if (mac->mac_phy.rev >= 7) {
5193300016Sadrian				target.ipa[i] = (table[index[i]] >> 16) & 0x7;
5194300016Sadrian				target.pad[i] = (table[index[i]] >> 19) & 0x1F;
5195300016Sadrian				target.pga[i] = (table[index[i]] >> 24) & 0xF;
5196300016Sadrian				target.txgm[i] = (table[index[i]] >> 28) & 0x7;
5197300016Sadrian				target.tx_lpf[i] = (table[index[i]] >> 31) & 0x1;
5198300016Sadrian			} else if (mac->mac_phy.rev >= 3) {
5199300016Sadrian				target.ipa[i] = (table[index[i]] >> 16) & 0xF;
5200300016Sadrian				target.pad[i] = (table[index[i]] >> 20) & 0xF;
5201300016Sadrian				target.pga[i] = (table[index[i]] >> 24) & 0xF;
5202300016Sadrian				target.txgm[i] = (table[index[i]] >> 28) & 0xF;
5203300016Sadrian			} else {
5204300016Sadrian				target.ipa[i] = (table[index[i]] >> 16) & 0x3;
5205300016Sadrian				target.pad[i] = (table[index[i]] >> 18) & 0x3;
5206300016Sadrian				target.pga[i] = (table[index[i]] >> 20) & 0x7;
5207300016Sadrian				target.txgm[i] = (table[index[i]] >> 23) & 0x7;
5208300016Sadrian			}
5209300016Sadrian		}
5210300016Sadrian	}
5211300016Sadrian
5212300016Sadrian	return target;
5213300016Sadrian}
5214300016Sadrian
5215300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhyCleanup */
5216300016Sadrianstatic void bwn_nphy_tx_cal_phy_cleanup(struct bwn_mac *mac)
5217300016Sadrian{
5218300016Sadrian	uint16_t *regs = mac->mac_phy.phy_n->tx_rx_cal_phy_saveregs;
5219300016Sadrian
5220300016Sadrian	if (mac->mac_phy.rev >= 3) {
5221300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C1, regs[0]);
5222300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C2, regs[1]);
5223300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER1, regs[2]);
5224300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, regs[3]);
5225300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_BBCFG, regs[4]);
5226300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 3), regs[5]);
5227300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 19), regs[6]);
5228300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1, regs[7]);
5229300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2, regs[8]);
5230300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_PAPD_EN0, regs[9]);
5231300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_PAPD_EN1, regs[10]);
5232300016Sadrian		bwn_nphy_reset_cca(mac);
5233300016Sadrian	} else {
5234300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_AFECTL_C1, 0x0FFF, regs[0]);
5235300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_AFECTL_C2, 0x0FFF, regs[1]);
5236300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, regs[2]);
5237300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 2), regs[3]);
5238300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 18), regs[4]);
5239300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1, regs[5]);
5240300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2, regs[6]);
5241300016Sadrian	}
5242300016Sadrian}
5243300016Sadrian
5244300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */
5245300016Sadrianstatic void bwn_nphy_tx_cal_phy_setup(struct bwn_mac *mac)
5246300016Sadrian{
5247300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
5248300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
5249300016Sadrian	uint16_t *regs = mac->mac_phy.phy_n->tx_rx_cal_phy_saveregs;
5250300016Sadrian	uint16_t tmp;
5251300016Sadrian
5252300016Sadrian	regs[0] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_C1);
5253300016Sadrian	regs[1] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_C2);
5254300016Sadrian	if (mac->mac_phy.rev >= 3) {
5255300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_AFECTL_C1, 0xF0FF, 0x0A00);
5256300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_AFECTL_C2, 0xF0FF, 0x0A00);
5257300016Sadrian
5258300016Sadrian		tmp = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_OVER1);
5259300016Sadrian		regs[2] = tmp;
5260300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER1, tmp | 0x0600);
5261300016Sadrian
5262300016Sadrian		tmp = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_OVER);
5263300016Sadrian		regs[3] = tmp;
5264300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, tmp | 0x0600);
5265300016Sadrian
5266300016Sadrian		regs[4] = BWN_PHY_READ(mac, BWN_NPHY_BBCFG);
5267300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_BBCFG,
5268300016Sadrian			     ~BWN_NPHY_BBCFG_RSTRX & 0xFFFF);
5269300016Sadrian
5270300016Sadrian		tmp = bwn_ntab_read(mac, BWN_NTAB16(8, 3));
5271300016Sadrian		regs[5] = tmp;
5272300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 3), 0);
5273300016Sadrian
5274300016Sadrian		tmp = bwn_ntab_read(mac, BWN_NTAB16(8, 19));
5275300016Sadrian		regs[6] = tmp;
5276300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 19), 0);
5277300016Sadrian		regs[7] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC1);
5278300016Sadrian		regs[8] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC2);
5279300016Sadrian
5280300016Sadrian		if (!nphy->use_int_tx_iq_lo_cal)
5281300016Sadrian			bwn_nphy_rf_ctl_intc_override(mac, N_INTC_OVERRIDE_PA,
5282300016Sadrian						      1, 3);
5283300016Sadrian		else
5284300016Sadrian			bwn_nphy_rf_ctl_intc_override(mac, N_INTC_OVERRIDE_PA,
5285300016Sadrian						      0, 3);
5286300016Sadrian		bwn_nphy_rf_ctl_intc_override(mac, N_INTC_OVERRIDE_TRSW, 2, 1);
5287300016Sadrian		bwn_nphy_rf_ctl_intc_override(mac, N_INTC_OVERRIDE_TRSW, 8, 2);
5288300016Sadrian
5289300016Sadrian		regs[9] = BWN_PHY_READ(mac, BWN_NPHY_PAPD_EN0);
5290300016Sadrian		regs[10] = BWN_PHY_READ(mac, BWN_NPHY_PAPD_EN1);
5291300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_PAPD_EN0, ~0x0001);
5292300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_PAPD_EN1, ~0x0001);
5293300016Sadrian
5294300016Sadrian		tmp = bwn_nphy_read_lpf_ctl(mac, 0);
5295300016Sadrian		if (phy->rev >= 19)
5296300016Sadrian			bwn_nphy_rf_ctl_override_rev19(mac, 0x80, tmp, 0, false,
5297300016Sadrian						       1);
5298300016Sadrian		else if (phy->rev >= 7)
5299300016Sadrian			bwn_nphy_rf_ctl_override_rev7(mac, 0x80, tmp, 0, false,
5300300016Sadrian						      1);
5301300016Sadrian
5302300016Sadrian		if (nphy->use_int_tx_iq_lo_cal && true /* FIXME */) {
5303300016Sadrian			if (phy->rev >= 19) {
5304300016Sadrian				bwn_nphy_rf_ctl_override_rev19(mac, 0x8, 0, 0x3,
5305300016Sadrian							       false, 0);
5306300016Sadrian			} else if (phy->rev >= 8) {
5307300016Sadrian				bwn_nphy_rf_ctl_override_rev7(mac, 0x8, 0, 0x3,
5308300016Sadrian							      false, 0);
5309300016Sadrian			} else if (phy->rev == 7) {
5310300016Sadrian				BWN_RF_SETMASK(mac, R2057_OVR_REG0, 1 << 4, 1 << 4);
5311300016Sadrian				if (bwn_current_band(mac) == BWN_BAND_2G) {
5312300016Sadrian					BWN_RF_SETMASK(mac, R2057_PAD2G_TUNE_PUS_CORE0, ~1, 0);
5313300016Sadrian					BWN_RF_SETMASK(mac, R2057_PAD2G_TUNE_PUS_CORE1, ~1, 0);
5314300016Sadrian				} else {
5315300016Sadrian					BWN_RF_SETMASK(mac, R2057_IPA5G_CASCOFFV_PU_CORE0, ~1, 0);
5316300016Sadrian					BWN_RF_SETMASK(mac, R2057_IPA5G_CASCOFFV_PU_CORE1, ~1, 0);
5317300016Sadrian				}
5318300016Sadrian			}
5319300016Sadrian		}
5320300016Sadrian	} else {
5321300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_AFECTL_C1, 0x0FFF, 0xA000);
5322300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_AFECTL_C2, 0x0FFF, 0xA000);
5323300016Sadrian		tmp = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_OVER);
5324300016Sadrian		regs[2] = tmp;
5325300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, tmp | 0x3000);
5326300016Sadrian		tmp = bwn_ntab_read(mac, BWN_NTAB16(8, 2));
5327300016Sadrian		regs[3] = tmp;
5328300016Sadrian		tmp |= 0x2000;
5329300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 2), tmp);
5330300016Sadrian		tmp = bwn_ntab_read(mac, BWN_NTAB16(8, 18));
5331300016Sadrian		regs[4] = tmp;
5332300016Sadrian		tmp |= 0x2000;
5333300016Sadrian		bwn_ntab_write(mac, BWN_NTAB16(8, 18), tmp);
5334300016Sadrian		regs[5] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC1);
5335300016Sadrian		regs[6] = BWN_PHY_READ(mac, BWN_NPHY_RFCTL_INTC2);
5336300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_5G)
5337300016Sadrian			tmp = 0x0180;
5338300016Sadrian		else
5339300016Sadrian			tmp = 0x0120;
5340300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1, tmp);
5341300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2, tmp);
5342300016Sadrian	}
5343300016Sadrian}
5344300016Sadrian
5345300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */
5346300016Sadrianstatic void bwn_nphy_save_cal(struct bwn_mac *mac)
5347300016Sadrian{
5348300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
5349300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
5350300016Sadrian
5351300016Sadrian	struct bwn_phy_n_iq_comp *rxcal_coeffs = NULL;
5352300016Sadrian	uint16_t *txcal_radio_regs = NULL;
5353300016Sadrian	struct bwn_chanspec *iqcal_chanspec;
5354300016Sadrian	uint16_t *table = NULL;
5355300016Sadrian
5356300016Sadrian	if (nphy->hang_avoid)
5357300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 1);
5358300016Sadrian
5359300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G) {
5360300016Sadrian		rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G;
5361300016Sadrian		txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G;
5362300016Sadrian		iqcal_chanspec = &nphy->iqcal_chanspec_2G;
5363300016Sadrian		table = nphy->cal_cache.txcal_coeffs_2G;
5364300016Sadrian	} else {
5365300016Sadrian		rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G;
5366300016Sadrian		txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G;
5367300016Sadrian		iqcal_chanspec = &nphy->iqcal_chanspec_5G;
5368300016Sadrian		table = nphy->cal_cache.txcal_coeffs_5G;
5369300016Sadrian	}
5370300016Sadrian
5371300016Sadrian	bwn_nphy_rx_iq_coeffs(mac, false, rxcal_coeffs);
5372300016Sadrian	/* TODO use some definitions */
5373300016Sadrian	if (phy->rev >= 19) {
5374300016Sadrian		/* TODO */
5375300016Sadrian	} else if (phy->rev >= 7) {
5376300016Sadrian		txcal_radio_regs[0] = BWN_RF_READ(mac,
5377300016Sadrian						     R2057_TX0_LOFT_FINE_I);
5378300016Sadrian		txcal_radio_regs[1] = BWN_RF_READ(mac,
5379300016Sadrian						     R2057_TX0_LOFT_FINE_Q);
5380300016Sadrian		txcal_radio_regs[4] = BWN_RF_READ(mac,
5381300016Sadrian						     R2057_TX0_LOFT_COARSE_I);
5382300016Sadrian		txcal_radio_regs[5] = BWN_RF_READ(mac,
5383300016Sadrian						     R2057_TX0_LOFT_COARSE_Q);
5384300016Sadrian		txcal_radio_regs[2] = BWN_RF_READ(mac,
5385300016Sadrian						     R2057_TX1_LOFT_FINE_I);
5386300016Sadrian		txcal_radio_regs[3] = BWN_RF_READ(mac,
5387300016Sadrian						     R2057_TX1_LOFT_FINE_Q);
5388300016Sadrian		txcal_radio_regs[6] = BWN_RF_READ(mac,
5389300016Sadrian						     R2057_TX1_LOFT_COARSE_I);
5390300016Sadrian		txcal_radio_regs[7] = BWN_RF_READ(mac,
5391300016Sadrian						     R2057_TX1_LOFT_COARSE_Q);
5392300016Sadrian	} else if (phy->rev >= 3) {
5393300016Sadrian		txcal_radio_regs[0] = BWN_RF_READ(mac, 0x2021);
5394300016Sadrian		txcal_radio_regs[1] = BWN_RF_READ(mac, 0x2022);
5395300016Sadrian		txcal_radio_regs[2] = BWN_RF_READ(mac, 0x3021);
5396300016Sadrian		txcal_radio_regs[3] = BWN_RF_READ(mac, 0x3022);
5397300016Sadrian		txcal_radio_regs[4] = BWN_RF_READ(mac, 0x2023);
5398300016Sadrian		txcal_radio_regs[5] = BWN_RF_READ(mac, 0x2024);
5399300016Sadrian		txcal_radio_regs[6] = BWN_RF_READ(mac, 0x3023);
5400300016Sadrian		txcal_radio_regs[7] = BWN_RF_READ(mac, 0x3024);
5401300016Sadrian	} else {
5402300016Sadrian		txcal_radio_regs[0] = BWN_RF_READ(mac, 0x8B);
5403300016Sadrian		txcal_radio_regs[1] = BWN_RF_READ(mac, 0xBA);
5404300016Sadrian		txcal_radio_regs[2] = BWN_RF_READ(mac, 0x8D);
5405300016Sadrian		txcal_radio_regs[3] = BWN_RF_READ(mac, 0xBC);
5406300016Sadrian	}
5407300016Sadrian	iqcal_chanspec->center_freq = bwn_get_centre_freq(mac);
5408300016Sadrian	iqcal_chanspec->channel_type = bwn_get_chan_type(mac, NULL);
5409300016Sadrian	bwn_ntab_read_bulk(mac, BWN_NTAB16(15, 80), 8, table);
5410300016Sadrian
5411300016Sadrian	if (nphy->hang_avoid)
5412300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, 0);
5413300016Sadrian}
5414300016Sadrian
5415300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */
5416300016Sadrianstatic void bwn_nphy_restore_cal(struct bwn_mac *mac)
5417300016Sadrian{
5418300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
5419300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
5420300016Sadrian
5421300016Sadrian	uint16_t coef[4];
5422300016Sadrian	uint16_t *loft = NULL;
5423300016Sadrian	uint16_t *table = NULL;
5424300016Sadrian
5425300016Sadrian	int i;
5426300016Sadrian	uint16_t *txcal_radio_regs = NULL;
5427300016Sadrian	struct bwn_phy_n_iq_comp *rxcal_coeffs = NULL;
5428300016Sadrian
5429300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G) {
5430300016Sadrian		if (!nphy->iqcal_chanspec_2G.center_freq)
5431300016Sadrian			return;
5432300016Sadrian		table = nphy->cal_cache.txcal_coeffs_2G;
5433300016Sadrian		loft = &nphy->cal_cache.txcal_coeffs_2G[5];
5434300016Sadrian	} else {
5435300016Sadrian		if (!nphy->iqcal_chanspec_5G.center_freq)
5436300016Sadrian			return;
5437300016Sadrian		table = nphy->cal_cache.txcal_coeffs_5G;
5438300016Sadrian		loft = &nphy->cal_cache.txcal_coeffs_5G[5];
5439300016Sadrian	}
5440300016Sadrian
5441300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 80), 4, table);
5442300016Sadrian
5443300016Sadrian	for (i = 0; i < 4; i++) {
5444300016Sadrian		if (mac->mac_phy.rev >= 3)
5445300016Sadrian			table[i] = coef[i];
5446300016Sadrian		else
5447300016Sadrian			coef[i] = 0;
5448300016Sadrian	}
5449300016Sadrian
5450300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 88), 4, coef);
5451300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 85), 2, loft);
5452300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 93), 2, loft);
5453300016Sadrian
5454300016Sadrian	if (mac->mac_phy.rev < 2)
5455300016Sadrian		bwn_nphy_tx_iq_workaround(mac);
5456300016Sadrian
5457300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G) {
5458300016Sadrian		txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G;
5459300016Sadrian		rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G;
5460300016Sadrian	} else {
5461300016Sadrian		txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G;
5462300016Sadrian		rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G;
5463300016Sadrian	}
5464300016Sadrian
5465300016Sadrian	/* TODO use some definitions */
5466300016Sadrian	if (phy->rev >= 19) {
5467300016Sadrian		/* TODO */
5468300016Sadrian	} else if (phy->rev >= 7) {
5469300016Sadrian		BWN_RF_WRITE(mac, R2057_TX0_LOFT_FINE_I,
5470300016Sadrian				txcal_radio_regs[0]);
5471300016Sadrian		BWN_RF_WRITE(mac, R2057_TX0_LOFT_FINE_Q,
5472300016Sadrian				txcal_radio_regs[1]);
5473300016Sadrian		BWN_RF_WRITE(mac, R2057_TX0_LOFT_COARSE_I,
5474300016Sadrian				txcal_radio_regs[4]);
5475300016Sadrian		BWN_RF_WRITE(mac, R2057_TX0_LOFT_COARSE_Q,
5476300016Sadrian				txcal_radio_regs[5]);
5477300016Sadrian		BWN_RF_WRITE(mac, R2057_TX1_LOFT_FINE_I,
5478300016Sadrian				txcal_radio_regs[2]);
5479300016Sadrian		BWN_RF_WRITE(mac, R2057_TX1_LOFT_FINE_Q,
5480300016Sadrian				txcal_radio_regs[3]);
5481300016Sadrian		BWN_RF_WRITE(mac, R2057_TX1_LOFT_COARSE_I,
5482300016Sadrian				txcal_radio_regs[6]);
5483300016Sadrian		BWN_RF_WRITE(mac, R2057_TX1_LOFT_COARSE_Q,
5484300016Sadrian				txcal_radio_regs[7]);
5485300016Sadrian	} else if (phy->rev >= 3) {
5486300016Sadrian		BWN_RF_WRITE(mac, 0x2021, txcal_radio_regs[0]);
5487300016Sadrian		BWN_RF_WRITE(mac, 0x2022, txcal_radio_regs[1]);
5488300016Sadrian		BWN_RF_WRITE(mac, 0x3021, txcal_radio_regs[2]);
5489300016Sadrian		BWN_RF_WRITE(mac, 0x3022, txcal_radio_regs[3]);
5490300016Sadrian		BWN_RF_WRITE(mac, 0x2023, txcal_radio_regs[4]);
5491300016Sadrian		BWN_RF_WRITE(mac, 0x2024, txcal_radio_regs[5]);
5492300016Sadrian		BWN_RF_WRITE(mac, 0x3023, txcal_radio_regs[6]);
5493300016Sadrian		BWN_RF_WRITE(mac, 0x3024, txcal_radio_regs[7]);
5494300016Sadrian	} else {
5495300016Sadrian		BWN_RF_WRITE(mac, 0x8B, txcal_radio_regs[0]);
5496300016Sadrian		BWN_RF_WRITE(mac, 0xBA, txcal_radio_regs[1]);
5497300016Sadrian		BWN_RF_WRITE(mac, 0x8D, txcal_radio_regs[2]);
5498300016Sadrian		BWN_RF_WRITE(mac, 0xBC, txcal_radio_regs[3]);
5499300016Sadrian	}
5500300016Sadrian	bwn_nphy_rx_iq_coeffs(mac, true, rxcal_coeffs);
5501300016Sadrian}
5502300016Sadrian
5503300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */
5504300016Sadrianstatic int bwn_nphy_cal_tx_iq_lo(struct bwn_mac *mac,
5505300016Sadrian				struct bwn_nphy_txgains target,
5506300016Sadrian				bool full, bool mphase)
5507300016Sadrian{
5508300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
5509300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
5510300016Sadrian	int i;
5511300016Sadrian	int error = 0;
5512300016Sadrian	int freq;
5513300016Sadrian	bool avoid = false;
5514300016Sadrian	uint8_t length;
5515300016Sadrian	uint16_t tmp, core, type, count, max, numb, last = 0, cmd;
5516300016Sadrian	const uint16_t *table;
5517300016Sadrian	bool phy6or5x;
5518300016Sadrian
5519300016Sadrian	uint16_t buffer[11];
5520300016Sadrian	uint16_t diq_start = 0;
5521300016Sadrian	uint16_t save[2];
5522300016Sadrian	uint16_t gain[2];
5523300016Sadrian	struct bwn_nphy_iqcal_params params[2];
5524300016Sadrian	bool updated[2] = { };
5525300016Sadrian
5526300016Sadrian	bwn_nphy_stay_in_carrier_search(mac, true);
5527300016Sadrian
5528300016Sadrian	if (mac->mac_phy.rev >= 4) {
5529300016Sadrian		avoid = nphy->hang_avoid;
5530300016Sadrian		nphy->hang_avoid = false;
5531300016Sadrian	}
5532300016Sadrian
5533300016Sadrian	bwn_ntab_read_bulk(mac, BWN_NTAB16(7, 0x110), 2, save);
5534300016Sadrian
5535300016Sadrian	for (i = 0; i < 2; i++) {
5536300016Sadrian		bwn_nphy_iq_cal_gain_params(mac, i, target, &params[i]);
5537300016Sadrian		gain[i] = params[i].cal_gain;
5538300016Sadrian	}
5539300016Sadrian
5540300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(7, 0x110), 2, gain);
5541300016Sadrian
5542300016Sadrian	bwn_nphy_tx_cal_radio_setup(mac);
5543300016Sadrian	bwn_nphy_tx_cal_phy_setup(mac);
5544300016Sadrian
5545300016Sadrian	phy6or5x = mac->mac_phy.rev >= 6 ||
5546300016Sadrian		(mac->mac_phy.rev == 5 && nphy->ipa2g_on &&
5547300016Sadrian		bwn_current_band(mac) == BWN_BAND_2G);
5548300016Sadrian	if (phy6or5x) {
5549300016Sadrian		if (bwn_is_40mhz(mac)) {
5550300016Sadrian			bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 0), 18,
5551300016Sadrian					tbl_tx_iqlo_cal_loft_ladder_40);
5552300016Sadrian			bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 32), 18,
5553300016Sadrian					tbl_tx_iqlo_cal_iqimb_ladder_40);
5554300016Sadrian		} else {
5555300016Sadrian			bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 0), 18,
5556300016Sadrian					tbl_tx_iqlo_cal_loft_ladder_20);
5557300016Sadrian			bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 32), 18,
5558300016Sadrian					tbl_tx_iqlo_cal_iqimb_ladder_20);
5559300016Sadrian		}
5560300016Sadrian	}
5561300016Sadrian
5562300016Sadrian	if (phy->rev >= 19) {
5563300016Sadrian		/* TODO */
5564300016Sadrian	} else if (phy->rev >= 7) {
5565300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_IQLOCAL_CMDGCTL, 0x8AD9);
5566300016Sadrian	} else {
5567300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_IQLOCAL_CMDGCTL, 0x8AA9);
5568300016Sadrian	}
5569300016Sadrian
5570300016Sadrian	if (!bwn_is_40mhz(mac))
5571300016Sadrian		freq = 2500;
5572300016Sadrian	else
5573300016Sadrian		freq = 5000;
5574300016Sadrian
5575300016Sadrian	if (nphy->mphase_cal_phase_id > 2)
5576300016Sadrian		bwn_nphy_run_samples(mac, (bwn_is_40mhz(mac) ? 40 : 20) * 8,
5577300016Sadrian				     0xFFFF, 0, true, false, false);
5578300016Sadrian	else
5579300016Sadrian		error = bwn_nphy_tx_tone(mac, freq, 250, true, false, false);
5580300016Sadrian
5581300016Sadrian	if (error == 0) {
5582300016Sadrian		if (nphy->mphase_cal_phase_id > 2) {
5583300016Sadrian			table = nphy->mphase_txcal_bestcoeffs;
5584300016Sadrian			length = 11;
5585300016Sadrian			if (mac->mac_phy.rev < 3)
5586300016Sadrian				length -= 2;
5587300016Sadrian		} else {
5588300016Sadrian			if (!full && nphy->txiqlocal_coeffsvalid) {
5589300016Sadrian				table = nphy->txiqlocal_bestc;
5590300016Sadrian				length = 11;
5591300016Sadrian				if (mac->mac_phy.rev < 3)
5592300016Sadrian					length -= 2;
5593300016Sadrian			} else {
5594300016Sadrian				full = true;
5595300016Sadrian				if (mac->mac_phy.rev >= 3) {
5596300016Sadrian					table = tbl_tx_iqlo_cal_startcoefs_nphyrev3;
5597300016Sadrian					length = BWN_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3;
5598300016Sadrian				} else {
5599300016Sadrian					table = tbl_tx_iqlo_cal_startcoefs;
5600300016Sadrian					length = BWN_NTAB_TX_IQLO_CAL_STARTCOEFS;
5601300016Sadrian				}
5602300016Sadrian			}
5603300016Sadrian		}
5604300016Sadrian
5605300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 64), length, table);
5606300016Sadrian
5607300016Sadrian		if (full) {
5608300016Sadrian			if (mac->mac_phy.rev >= 3)
5609300016Sadrian				max = BWN_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3;
5610300016Sadrian			else
5611300016Sadrian				max = BWN_NTAB_TX_IQLO_CAL_CMDS_FULLCAL;
5612300016Sadrian		} else {
5613300016Sadrian			if (mac->mac_phy.rev >= 3)
5614300016Sadrian				max = BWN_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3;
5615300016Sadrian			else
5616300016Sadrian				max = BWN_NTAB_TX_IQLO_CAL_CMDS_RECAL;
5617300016Sadrian		}
5618300016Sadrian
5619300016Sadrian		if (mphase) {
5620300016Sadrian			count = nphy->mphase_txcal_cmdidx;
5621300016Sadrian			numb = min(max,
5622300016Sadrian				(uint16_t)(count + nphy->mphase_txcal_numcmds));
5623300016Sadrian		} else {
5624300016Sadrian			count = 0;
5625300016Sadrian			numb = max;
5626300016Sadrian		}
5627300016Sadrian
5628300016Sadrian		for (; count < numb; count++) {
5629300016Sadrian			if (full) {
5630300016Sadrian				if (mac->mac_phy.rev >= 3)
5631300016Sadrian					cmd = tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[count];
5632300016Sadrian				else
5633300016Sadrian					cmd = tbl_tx_iqlo_cal_cmds_fullcal[count];
5634300016Sadrian			} else {
5635300016Sadrian				if (mac->mac_phy.rev >= 3)
5636300016Sadrian					cmd = tbl_tx_iqlo_cal_cmds_recal_nphyrev3[count];
5637300016Sadrian				else
5638300016Sadrian					cmd = tbl_tx_iqlo_cal_cmds_recal[count];
5639300016Sadrian			}
5640300016Sadrian
5641300016Sadrian			core = (cmd & 0x3000) >> 12;
5642300016Sadrian			type = (cmd & 0x0F00) >> 8;
5643300016Sadrian
5644300016Sadrian			if (phy6or5x && updated[core] == 0) {
5645300016Sadrian				bwn_nphy_update_tx_cal_ladder(mac, core);
5646300016Sadrian				updated[core] = true;
5647300016Sadrian			}
5648300016Sadrian
5649300016Sadrian			tmp = (params[core].ncorr[type] << 8) | 0x66;
5650300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_IQLOCAL_CMDNNUM, tmp);
5651300016Sadrian
5652300016Sadrian			if (type == 1 || type == 3 || type == 4) {
5653300016Sadrian				buffer[0] = bwn_ntab_read(mac,
5654300016Sadrian						BWN_NTAB16(15, 69 + core));
5655300016Sadrian				diq_start = buffer[0];
5656300016Sadrian				buffer[0] = 0;
5657300016Sadrian				bwn_ntab_write(mac, BWN_NTAB16(15, 69 + core),
5658300016Sadrian						0);
5659300016Sadrian			}
5660300016Sadrian
5661300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_IQLOCAL_CMD, cmd);
5662300016Sadrian			for (i = 0; i < 2000; i++) {
5663300016Sadrian				tmp = BWN_PHY_READ(mac, BWN_NPHY_IQLOCAL_CMD);
5664300016Sadrian				if (tmp & 0xC000)
5665300016Sadrian					break;
5666300016Sadrian				DELAY(10);
5667300016Sadrian			}
5668300016Sadrian
5669300016Sadrian			bwn_ntab_read_bulk(mac, BWN_NTAB16(15, 96), length,
5670300016Sadrian						buffer);
5671300016Sadrian			bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 64), length,
5672300016Sadrian						buffer);
5673300016Sadrian
5674300016Sadrian			if (type == 1 || type == 3 || type == 4)
5675300016Sadrian				buffer[0] = diq_start;
5676300016Sadrian		}
5677300016Sadrian
5678300016Sadrian		if (mphase)
5679300016Sadrian			nphy->mphase_txcal_cmdidx = (numb >= max) ? 0 : numb;
5680300016Sadrian
5681300016Sadrian		last = (mac->mac_phy.rev < 3) ? 6 : 7;
5682300016Sadrian
5683300016Sadrian		if (!mphase || nphy->mphase_cal_phase_id == last) {
5684300016Sadrian			bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 96), 4, buffer);
5685300016Sadrian			bwn_ntab_read_bulk(mac, BWN_NTAB16(15, 80), 4, buffer);
5686300016Sadrian			if (mac->mac_phy.rev < 3) {
5687300016Sadrian				buffer[0] = 0;
5688300016Sadrian				buffer[1] = 0;
5689300016Sadrian				buffer[2] = 0;
5690300016Sadrian				buffer[3] = 0;
5691300016Sadrian			}
5692300016Sadrian			bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 88), 4,
5693300016Sadrian						buffer);
5694300016Sadrian			bwn_ntab_read_bulk(mac, BWN_NTAB16(15, 101), 2,
5695300016Sadrian						buffer);
5696300016Sadrian			bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 85), 2,
5697300016Sadrian						buffer);
5698300016Sadrian			bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 93), 2,
5699300016Sadrian						buffer);
5700300016Sadrian			length = 11;
5701300016Sadrian			if (mac->mac_phy.rev < 3)
5702300016Sadrian				length -= 2;
5703300016Sadrian			bwn_ntab_read_bulk(mac, BWN_NTAB16(15, 96), length,
5704300016Sadrian						nphy->txiqlocal_bestc);
5705300016Sadrian			nphy->txiqlocal_coeffsvalid = true;
5706300016Sadrian			nphy->txiqlocal_chanspec.center_freq =
5707300016Sadrian						bwn_get_centre_freq(mac);
5708300016Sadrian			nphy->txiqlocal_chanspec.channel_type = bwn_get_chan_type(mac, NULL);
5709300016Sadrian		} else {
5710300016Sadrian			length = 11;
5711300016Sadrian			if (mac->mac_phy.rev < 3)
5712300016Sadrian				length -= 2;
5713300016Sadrian			bwn_ntab_read_bulk(mac, BWN_NTAB16(15, 96), length,
5714300016Sadrian						nphy->mphase_txcal_bestcoeffs);
5715300016Sadrian		}
5716300016Sadrian
5717300016Sadrian		bwn_nphy_stop_playback(mac);
5718300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_IQLOCAL_CMDGCTL, 0);
5719300016Sadrian	}
5720300016Sadrian
5721300016Sadrian	bwn_nphy_tx_cal_phy_cleanup(mac);
5722300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(7, 0x110), 2, save);
5723300016Sadrian
5724300016Sadrian	if (mac->mac_phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last))
5725300016Sadrian		bwn_nphy_tx_iq_workaround(mac);
5726300016Sadrian
5727300016Sadrian	if (mac->mac_phy.rev >= 4)
5728300016Sadrian		nphy->hang_avoid = avoid;
5729300016Sadrian
5730300016Sadrian	bwn_nphy_stay_in_carrier_search(mac, false);
5731300016Sadrian
5732300016Sadrian	return error;
5733300016Sadrian}
5734300016Sadrian
5735300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ReapplyTxCalCoeffs */
5736300016Sadrianstatic void bwn_nphy_reapply_tx_cal_coeffs(struct bwn_mac *mac)
5737300016Sadrian{
5738300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
5739300016Sadrian	uint8_t i;
5740300016Sadrian	uint16_t buffer[7];
5741300016Sadrian	bool equal = true;
5742300016Sadrian
5743300016Sadrian	if (!nphy->txiqlocal_coeffsvalid ||
5744300016Sadrian	    nphy->txiqlocal_chanspec.center_freq != bwn_get_centre_freq(mac) ||
5745300016Sadrian	    nphy->txiqlocal_chanspec.channel_type != bwn_get_chan_type(mac, NULL))
5746300016Sadrian		return;
5747300016Sadrian
5748300016Sadrian	bwn_ntab_read_bulk(mac, BWN_NTAB16(15, 80), 7, buffer);
5749300016Sadrian	for (i = 0; i < 4; i++) {
5750300016Sadrian		if (buffer[i] != nphy->txiqlocal_bestc[i]) {
5751300016Sadrian			equal = false;
5752300016Sadrian			break;
5753300016Sadrian		}
5754300016Sadrian	}
5755300016Sadrian
5756300016Sadrian	if (!equal) {
5757300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 80), 4,
5758300016Sadrian					nphy->txiqlocal_bestc);
5759300016Sadrian		for (i = 0; i < 4; i++)
5760300016Sadrian			buffer[i] = 0;
5761300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 88), 4,
5762300016Sadrian					buffer);
5763300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 85), 2,
5764300016Sadrian					&nphy->txiqlocal_bestc[5]);
5765300016Sadrian		bwn_ntab_write_bulk(mac, BWN_NTAB16(15, 93), 2,
5766300016Sadrian					&nphy->txiqlocal_bestc[5]);
5767300016Sadrian	}
5768300016Sadrian}
5769300016Sadrian
5770300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */
5771300016Sadrianstatic int bwn_nphy_rev2_cal_rx_iq(struct bwn_mac *mac,
5772300016Sadrian			struct bwn_nphy_txgains target, uint8_t type, bool debug)
5773300016Sadrian{
5774300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
5775300016Sadrian	int i, j, index;
5776300016Sadrian	uint8_t rfctl[2];
5777300016Sadrian	uint8_t afectl_core;
5778300016Sadrian	uint16_t tmp[6];
5779300016Sadrian	uint16_t cur_hpf1, cur_hpf2, cur_lna;
5780300016Sadrian	uint32_t real, imag;
5781300016Sadrian	bwn_band_t band;
5782300016Sadrian
5783300016Sadrian	uint8_t use;
5784300016Sadrian	uint16_t cur_hpf;
5785300016Sadrian	uint16_t lna[3] = { 3, 3, 1 };
5786300016Sadrian	uint16_t hpf1[3] = { 7, 2, 0 };
5787300016Sadrian	uint16_t hpf2[3] = { 2, 0, 0 };
5788300016Sadrian	uint32_t power[3] = { };
5789300016Sadrian	uint16_t gain_save[2];
5790300016Sadrian	uint16_t cal_gain[2];
5791300016Sadrian	struct bwn_nphy_iqcal_params cal_params[2];
5792300016Sadrian	struct bwn_nphy_iq_est est;
5793300016Sadrian	int ret = 0;
5794300016Sadrian	bool playtone = true;
5795300016Sadrian	int desired = 13;
5796300016Sadrian
5797300016Sadrian	bwn_nphy_stay_in_carrier_search(mac, 1);
5798300016Sadrian
5799300016Sadrian	if (mac->mac_phy.rev < 2)
5800300016Sadrian		bwn_nphy_reapply_tx_cal_coeffs(mac);
5801300016Sadrian	bwn_ntab_read_bulk(mac, BWN_NTAB16(7, 0x110), 2, gain_save);
5802300016Sadrian	for (i = 0; i < 2; i++) {
5803300016Sadrian		bwn_nphy_iq_cal_gain_params(mac, i, target, &cal_params[i]);
5804300016Sadrian		cal_gain[i] = cal_params[i].cal_gain;
5805300016Sadrian	}
5806300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(7, 0x110), 2, cal_gain);
5807300016Sadrian
5808300016Sadrian	for (i = 0; i < 2; i++) {
5809300016Sadrian		if (i == 0) {
5810300016Sadrian			rfctl[0] = BWN_NPHY_RFCTL_INTC1;
5811300016Sadrian			rfctl[1] = BWN_NPHY_RFCTL_INTC2;
5812300016Sadrian			afectl_core = BWN_NPHY_AFECTL_C1;
5813300016Sadrian		} else {
5814300016Sadrian			rfctl[0] = BWN_NPHY_RFCTL_INTC2;
5815300016Sadrian			rfctl[1] = BWN_NPHY_RFCTL_INTC1;
5816300016Sadrian			afectl_core = BWN_NPHY_AFECTL_C2;
5817300016Sadrian		}
5818300016Sadrian
5819300016Sadrian		tmp[1] = BWN_PHY_READ(mac, BWN_NPHY_RFSEQCA);
5820300016Sadrian		tmp[2] = BWN_PHY_READ(mac, afectl_core);
5821300016Sadrian		tmp[3] = BWN_PHY_READ(mac, BWN_NPHY_AFECTL_OVER);
5822300016Sadrian		tmp[4] = BWN_PHY_READ(mac, rfctl[0]);
5823300016Sadrian		tmp[5] = BWN_PHY_READ(mac, rfctl[1]);
5824300016Sadrian
5825300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_RFSEQCA,
5826300016Sadrian				~BWN_NPHY_RFSEQCA_RXDIS & 0xFFFF,
5827300016Sadrian				((1 - i) << BWN_NPHY_RFSEQCA_RXDIS_SHIFT));
5828300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_RFSEQCA, ~BWN_NPHY_RFSEQCA_TXEN,
5829300016Sadrian				(1 - i));
5830300016Sadrian		BWN_PHY_SET(mac, afectl_core, 0x0006);
5831300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_AFECTL_OVER, 0x0006);
5832300016Sadrian
5833300016Sadrian		band = bwn_current_band(mac);
5834300016Sadrian
5835300016Sadrian		if (nphy->rxcalparams & 0xFF000000) {
5836300016Sadrian			if (band == BWN_BAND_5G)
5837300016Sadrian				BWN_PHY_WRITE(mac, rfctl[0], 0x140);
5838300016Sadrian			else
5839300016Sadrian				BWN_PHY_WRITE(mac, rfctl[0], 0x110);
5840300016Sadrian		} else {
5841300016Sadrian			if (band == BWN_BAND_5G)
5842300016Sadrian				BWN_PHY_WRITE(mac, rfctl[0], 0x180);
5843300016Sadrian			else
5844300016Sadrian				BWN_PHY_WRITE(mac, rfctl[0], 0x120);
5845300016Sadrian		}
5846300016Sadrian
5847300016Sadrian		if (band == BWN_BAND_5G)
5848300016Sadrian			BWN_PHY_WRITE(mac, rfctl[1], 0x148);
5849300016Sadrian		else
5850300016Sadrian			BWN_PHY_WRITE(mac, rfctl[1], 0x114);
5851300016Sadrian
5852300016Sadrian		if (nphy->rxcalparams & 0x10000) {
5853300016Sadrian			BWN_RF_SETMASK(mac, B2055_C1_GENSPARE2, 0xFC,
5854300016Sadrian					(i + 1));
5855300016Sadrian			BWN_RF_SETMASK(mac, B2055_C2_GENSPARE2, 0xFC,
5856300016Sadrian					(2 - i));
5857300016Sadrian		}
5858300016Sadrian
5859300016Sadrian		for (j = 0; j < 4; j++) {
5860300016Sadrian			if (j < 3) {
5861300016Sadrian				cur_lna = lna[j];
5862300016Sadrian				cur_hpf1 = hpf1[j];
5863300016Sadrian				cur_hpf2 = hpf2[j];
5864300016Sadrian			} else {
5865300016Sadrian				if (power[1] > 10000) {
5866300016Sadrian					use = 1;
5867300016Sadrian					cur_hpf = cur_hpf1;
5868300016Sadrian					index = 2;
5869300016Sadrian				} else {
5870300016Sadrian					if (power[0] > 10000) {
5871300016Sadrian						use = 1;
5872300016Sadrian						cur_hpf = cur_hpf1;
5873300016Sadrian						index = 1;
5874300016Sadrian					} else {
5875300016Sadrian						index = 0;
5876300016Sadrian						use = 2;
5877300016Sadrian						cur_hpf = cur_hpf2;
5878300016Sadrian					}
5879300016Sadrian				}
5880300016Sadrian				cur_lna = lna[index];
5881300016Sadrian				cur_hpf1 = hpf1[index];
5882300016Sadrian				cur_hpf2 = hpf2[index];
5883300016Sadrian				cur_hpf += desired - bwn_hweight32(power[index]);
5884300016Sadrian				cur_hpf = bwn_clamp_val(cur_hpf, 0, 10);
5885300016Sadrian				if (use == 1)
5886300016Sadrian					cur_hpf1 = cur_hpf;
5887300016Sadrian				else
5888300016Sadrian					cur_hpf2 = cur_hpf;
5889300016Sadrian			}
5890300016Sadrian
5891300016Sadrian			tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) |
5892300016Sadrian					(cur_lna << 2));
5893300016Sadrian			bwn_nphy_rf_ctl_override(mac, 0x400, tmp[0], 3,
5894300016Sadrian									false);
5895300016Sadrian			bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
5896300016Sadrian			bwn_nphy_stop_playback(mac);
5897300016Sadrian
5898300016Sadrian			if (playtone) {
5899300016Sadrian				ret = bwn_nphy_tx_tone(mac, 4000,
5900300016Sadrian						(nphy->rxcalparams & 0xFFFF),
5901300016Sadrian						false, false, true);
5902300016Sadrian				playtone = false;
5903300016Sadrian			} else {
5904300016Sadrian				bwn_nphy_run_samples(mac, 160, 0xFFFF, 0, false,
5905300016Sadrian						     false, true);
5906300016Sadrian			}
5907300016Sadrian
5908300016Sadrian			if (ret == 0) {
5909300016Sadrian				if (j < 3) {
5910300016Sadrian					bwn_nphy_rx_iq_est(mac, &est, 1024, 32,
5911300016Sadrian									false);
5912300016Sadrian					if (i == 0) {
5913300016Sadrian						real = est.i0_pwr;
5914300016Sadrian						imag = est.q0_pwr;
5915300016Sadrian					} else {
5916300016Sadrian						real = est.i1_pwr;
5917300016Sadrian						imag = est.q1_pwr;
5918300016Sadrian					}
5919300016Sadrian					power[i] = ((real + imag) / 1024) + 1;
5920300016Sadrian				} else {
5921300016Sadrian					bwn_nphy_calc_rx_iq_comp(mac, 1 << i);
5922300016Sadrian				}
5923300016Sadrian				bwn_nphy_stop_playback(mac);
5924300016Sadrian			}
5925300016Sadrian
5926300016Sadrian			if (ret != 0)
5927300016Sadrian				break;
5928300016Sadrian		}
5929300016Sadrian
5930300016Sadrian		BWN_RF_MASK(mac, B2055_C1_GENSPARE2, 0xFC);
5931300016Sadrian		BWN_RF_MASK(mac, B2055_C2_GENSPARE2, 0xFC);
5932300016Sadrian		BWN_PHY_WRITE(mac, rfctl[1], tmp[5]);
5933300016Sadrian		BWN_PHY_WRITE(mac, rfctl[0], tmp[4]);
5934300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, tmp[3]);
5935300016Sadrian		BWN_PHY_WRITE(mac, afectl_core, tmp[2]);
5936300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFSEQCA, tmp[1]);
5937300016Sadrian
5938300016Sadrian		if (ret != 0)
5939300016Sadrian			break;
5940300016Sadrian	}
5941300016Sadrian
5942300016Sadrian	bwn_nphy_rf_ctl_override(mac, 0x400, 0, 3, true);
5943300016Sadrian	bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
5944300016Sadrian	bwn_ntab_write_bulk(mac, BWN_NTAB16(7, 0x110), 2, gain_save);
5945300016Sadrian
5946300016Sadrian	bwn_nphy_stay_in_carrier_search(mac, 0);
5947300016Sadrian
5948300016Sadrian	return ret;
5949300016Sadrian}
5950300016Sadrian
5951300016Sadrianstatic int bwn_nphy_rev3_cal_rx_iq(struct bwn_mac *mac,
5952300016Sadrian			struct bwn_nphy_txgains target, uint8_t type, bool debug)
5953300016Sadrian{
5954300016Sadrian	return -1;
5955300016Sadrian}
5956300016Sadrian
5957300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */
5958300016Sadrianstatic int bwn_nphy_cal_rx_iq(struct bwn_mac *mac,
5959300016Sadrian			struct bwn_nphy_txgains target, uint8_t type, bool debug)
5960300016Sadrian{
5961300016Sadrian	if (mac->mac_phy.rev >= 7)
5962300016Sadrian		type = 0;
5963300016Sadrian
5964300016Sadrian	if (mac->mac_phy.rev >= 3)
5965300016Sadrian		return bwn_nphy_rev3_cal_rx_iq(mac, target, type, debug);
5966300016Sadrian	else
5967300016Sadrian		return bwn_nphy_rev2_cal_rx_iq(mac, target, type, debug);
5968300016Sadrian}
5969300016Sadrian
5970300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */
5971300016Sadrianstatic void bwn_nphy_set_rx_core_state(struct bwn_mac *mac, uint8_t mask)
5972300016Sadrian{
5973300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
5974300016Sadrian	struct bwn_phy_n *nphy = phy->phy_n;
5975300016Sadrian	/* uint16_t buf[16]; it's rev3+ */
5976300016Sadrian
5977300016Sadrian	nphy->phyrxchain = mask;
5978300016Sadrian
5979300016Sadrian	if (0 /* FIXME clk */)
5980300016Sadrian		return;
5981300016Sadrian
5982300016Sadrian	bwn_mac_suspend(mac);
5983300016Sadrian
5984300016Sadrian	if (nphy->hang_avoid)
5985300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, true);
5986300016Sadrian
5987300016Sadrian	BWN_PHY_SETMASK(mac, BWN_NPHY_RFSEQCA, ~BWN_NPHY_RFSEQCA_RXEN,
5988300016Sadrian			(mask & 0x3) << BWN_NPHY_RFSEQCA_RXEN_SHIFT);
5989300016Sadrian
5990300016Sadrian	if ((mask & 0x3) != 0x3) {
5991300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_HPANT_SWTHRES, 1);
5992300016Sadrian		if (mac->mac_phy.rev >= 3) {
5993300016Sadrian			/* TODO */
5994300016Sadrian		}
5995300016Sadrian	} else {
5996300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_HPANT_SWTHRES, 0x1E);
5997300016Sadrian		if (mac->mac_phy.rev >= 3) {
5998300016Sadrian			/* TODO */
5999300016Sadrian		}
6000300016Sadrian	}
6001300016Sadrian
6002300016Sadrian	bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
6003300016Sadrian
6004300016Sadrian	if (nphy->hang_avoid)
6005300016Sadrian		bwn_nphy_stay_in_carrier_search(mac, false);
6006300016Sadrian
6007300016Sadrian	bwn_mac_enable(mac);
6008300016Sadrian}
6009300016Sadrian
6010300016Sadrianbwn_txpwr_result_t
6011300016Sadrianbwn_nphy_op_recalc_txpower(struct bwn_mac *mac, bool ignore_tssi)
6012300016Sadrian{
6013300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
6014300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
6015300016Sadrian	struct ieee80211_channel *channel = bwn_get_channel(mac);
6016300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
6017300016Sadrian	struct bwn_ppr *ppr = &nphy->tx_pwr_max_ppr;
6018300016Sadrian	uint8_t max; /* qdBm */
6019300016Sadrian	bool tx_pwr_state;
6020300016Sadrian
6021300016Sadrian	if (nphy->tx_pwr_last_recalc_freq == bwn_get_centre_freq(mac) &&
6022300016Sadrian	    nphy->tx_pwr_last_recalc_limit == phy->txpower)
6023300016Sadrian		return BWN_TXPWR_RES_DONE;
6024300016Sadrian
6025300016Sadrian	/* Make sure we have a clean PPR */
6026300016Sadrian	bwn_ppr_clear(mac, ppr);
6027300016Sadrian
6028300016Sadrian	/* HW limitations */
6029300016Sadrian	bwn_ppr_load_max_from_sprom(mac, ppr, BWN_PHY_BAND_2G);
6030300016Sadrian	/* XXX TODO: other bands? */
6031300016Sadrian
6032300016Sadrian	/* Regulatory & user settings */
6033300016Sadrian	max = INT_TO_Q52(bwn_get_chan_power(mac, channel));
6034300016Sadrian	/* uint8_t */
6035300016Sadrian	if (phy->txpower)
6036300016Sadrian		max = min(max, INT_TO_Q52(phy->txpower));
6037300016Sadrian	bwn_ppr_apply_max(mac, ppr, max);
6038300016Sadrian	DPRINTF(mac->mac_sc, BWN_DEBUG_XMIT_POWER,
6039300016Sadrian	    "Calculated TX power: " Q52_FMT "\n",
6040300016Sadrian	     Q52_ARG(bwn_ppr_get_max(mac, ppr)));
6041300016Sadrian
6042300016Sadrian	/* TODO: Enable this once we get gains working */
6043300016Sadrian#if 0
6044300016Sadrian	/* Some extra gains */
6045300016Sadrian	hw_gain = 6; /* N-PHY specific */
6046300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G)
6047300016Sadrian		hw_gain += sprom->antenna_gain.a0;
6048300016Sadrian	else
6049300016Sadrian		hw_gain += sprom->antenna_gain.a1;
6050300016Sadrian	bwn_ppr_add(mac, ppr, -hw_gain);
6051300016Sadrian#endif
6052300016Sadrian
6053300016Sadrian	/* Make sure we didn't go too low */
6054300016Sadrian	bwn_ppr_apply_min(mac, ppr, INT_TO_Q52(8));
6055300016Sadrian
6056300016Sadrian	/* Apply */
6057300016Sadrian	tx_pwr_state = nphy->txpwrctrl;
6058300016Sadrian	bwn_mac_suspend(mac);
6059300016Sadrian	bwn_nphy_tx_power_ctl_setup(mac);
6060300016Sadrian	if (siba_get_revid(sc->sc_dev) == 11 || siba_get_revid(sc->sc_dev) == 12) {
6061300016Sadrian		BWN_WRITE_SETMASK4(mac, BWN_MACCTL, ~0, BWN_MACCTL_PHY_LOCK);
6062300016Sadrian		BWN_READ_4(mac, BWN_MACCTL);
6063300016Sadrian		DELAY(1);
6064300016Sadrian	}
6065300016Sadrian	bwn_nphy_tx_power_ctrl(mac, nphy->txpwrctrl);
6066300016Sadrian	if (siba_get_revid(sc->sc_dev) == 11 || siba_get_revid(sc->sc_dev) == 12)
6067300016Sadrian		BWN_WRITE_SETMASK4(mac, BWN_MACCTL, ~BWN_MACCTL_PHY_LOCK, 0);
6068300016Sadrian	bwn_mac_enable(mac);
6069300016Sadrian
6070300016Sadrian	nphy->tx_pwr_last_recalc_freq = bwn_get_centre_freq(mac);
6071300016Sadrian	nphy->tx_pwr_last_recalc_limit = phy->txpower;
6072300016Sadrian
6073300016Sadrian	return BWN_TXPWR_RES_DONE;
6074300016Sadrian}
6075300016Sadrian
6076300016Sadrian/**************************************************
6077300016Sadrian * N-PHY init
6078300016Sadrian **************************************************/
6079300016Sadrian
6080300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */
6081300016Sadrianstatic void bwn_nphy_update_mimo_config(struct bwn_mac *mac, int32_t preamble)
6082300016Sadrian{
6083300016Sadrian	uint16_t mimocfg = BWN_PHY_READ(mac, BWN_NPHY_MIMOCFG);
6084300016Sadrian
6085300016Sadrian	mimocfg |= BWN_NPHY_MIMOCFG_AUTO;
6086300016Sadrian	if (preamble == 1)
6087300016Sadrian		mimocfg |= BWN_NPHY_MIMOCFG_GFMIX;
6088300016Sadrian	else
6089300016Sadrian		mimocfg &= ~BWN_NPHY_MIMOCFG_GFMIX;
6090300016Sadrian
6091300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_MIMOCFG, mimocfg);
6092300016Sadrian}
6093300016Sadrian
6094300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */
6095300016Sadrianstatic void bwn_nphy_bphy_init(struct bwn_mac *mac)
6096300016Sadrian{
6097300016Sadrian	unsigned int i;
6098300016Sadrian	uint16_t val;
6099300016Sadrian
6100300016Sadrian	val = 0x1E1F;
6101300016Sadrian	for (i = 0; i < 16; i++) {
6102300016Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_N_BMODE(0x88 + i), val);
6103300016Sadrian		val -= 0x202;
6104300016Sadrian	}
6105300016Sadrian	val = 0x3E3F;
6106300016Sadrian	for (i = 0; i < 16; i++) {
6107300016Sadrian		BWN_PHY_WRITE(mac, BWN_PHY_N_BMODE(0x98 + i), val);
6108300016Sadrian		val -= 0x202;
6109300016Sadrian	}
6110300016Sadrian	BWN_PHY_WRITE(mac, BWN_PHY_N_BMODE(0x38), 0x668);
6111300016Sadrian}
6112300016Sadrian
6113300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */
6114300016Sadrianstatic void bwn_nphy_superswitch_init(struct bwn_mac *mac, bool init)
6115300016Sadrian{
6116300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
6117300016Sadrian
6118300016Sadrian	if (mac->mac_phy.rev >= 7)
6119300016Sadrian		return;
6120300016Sadrian
6121300016Sadrian	if (mac->mac_phy.rev >= 3) {
6122300016Sadrian		if (!init)
6123300016Sadrian			return;
6124300016Sadrian		if (0 /* FIXME */) {
6125300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(9, 2), 0x211);
6126300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(9, 3), 0x222);
6127300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(9, 8), 0x144);
6128300016Sadrian			bwn_ntab_write(mac, BWN_NTAB16(9, 12), 0x188);
6129300016Sadrian		}
6130300016Sadrian	} else {
6131300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_GPIO_LOOEN, 0);
6132300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_GPIO_HIOEN, 0);
6133300016Sadrian
6134300016Sadrian		/* XXX handle bhnd bus */
6135300016Sadrian		if (bwn_is_bus_siba(mac)) {
6136300016Sadrian			siba_gpio_set(sc->sc_dev, 0xfc00);
6137300016Sadrian		}
6138300016Sadrian
6139300016Sadrian		BWN_WRITE_SETMASK4(mac, BWN_MACCTL, ~BWN_MACCTL_GPOUT_MASK, 0);
6140300016Sadrian		BWN_WRITE_SETMASK2(mac, BWN_GPIO_MASK, ~0, 0xFC00);
6141300016Sadrian		BWN_WRITE_SETMASK2(mac, BWN_GPIO_CONTROL, (~0xFC00 & 0xFFFF),
6142300016Sadrian			      0);
6143300016Sadrian
6144300016Sadrian		if (init) {
6145300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
6146300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
6147300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
6148300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
6149300016Sadrian		}
6150300016Sadrian	}
6151300016Sadrian}
6152300016Sadrian
6153300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N */
6154300016Sadrianstatic int bwn_phy_initn(struct bwn_mac *mac)
6155300016Sadrian{
6156300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
6157300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
6158300016Sadrian	struct bwn_phy_n *nphy = phy->phy_n;
6159300016Sadrian	uint8_t tx_pwr_state;
6160300016Sadrian	struct bwn_nphy_txgains target;
6161300016Sadrian	uint16_t tmp;
6162300016Sadrian	bwn_band_t tmp2;
6163300016Sadrian	bool do_rssi_cal;
6164300016Sadrian
6165300016Sadrian	uint16_t clip[2];
6166300016Sadrian	bool do_cal = false;
6167300016Sadrian
6168300016Sadrian	if ((mac->mac_phy.rev >= 3) &&
6169300016Sadrian	   (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) &&
6170300016Sadrian	   (bwn_current_band(mac) == BWN_BAND_2G)) {
6171300016Sadrian		/* XXX bhnd bus */
6172300016Sadrian		if (bwn_is_bus_siba(mac)) {
6173300016Sadrian			siba_cc_set32(sc->sc_dev, SIBA_CC_CHIPCTL, 0x40);
6174300016Sadrian		}
6175300016Sadrian	}
6176300016Sadrian	nphy->use_int_tx_iq_lo_cal = bwn_nphy_ipa(mac) ||
6177300016Sadrian		phy->rev >= 7 ||
6178300016Sadrian		(phy->rev >= 5 &&
6179300016Sadrian		 siba_sprom_get_bf2_hi(sc->sc_dev) & BWN_BFH2_INTERNDET_TXIQCAL);
6180300016Sadrian	nphy->deaf_count = 0;
6181300016Sadrian	bwn_nphy_tables_init(mac);
6182300016Sadrian	nphy->crsminpwr_adjusted = false;
6183300016Sadrian	nphy->noisevars_adjusted = false;
6184300016Sadrian
6185300016Sadrian	/* Clear all overrides */
6186300016Sadrian	if (mac->mac_phy.rev >= 3) {
6187300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXF_40CO_B1S1, 0);
6188300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_OVER, 0);
6189300016Sadrian		if (phy->rev >= 7) {
6190300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER3, 0);
6191300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER4, 0);
6192300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER5, 0);
6193300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_REV7_RF_CTL_OVER6, 0);
6194300016Sadrian		}
6195300016Sadrian		if (phy->rev >= 19) {
6196300016Sadrian			/* TODO */
6197300016Sadrian		}
6198300016Sadrian
6199300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXF_40CO_B1S0, 0);
6200300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXF_40CO_B32S1, 0);
6201300016Sadrian	} else {
6202300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_OVER, 0);
6203300016Sadrian	}
6204300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC1, 0);
6205300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC2, 0);
6206300016Sadrian	if (mac->mac_phy.rev < 6) {
6207300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC3, 0);
6208300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_RFCTL_INTC4, 0);
6209300016Sadrian	}
6210300016Sadrian	BWN_PHY_MASK(mac, BWN_NPHY_RFSEQMODE,
6211300016Sadrian		     ~(BWN_NPHY_RFSEQMODE_CAOVER |
6212300016Sadrian		       BWN_NPHY_RFSEQMODE_TROVER));
6213300016Sadrian	if (mac->mac_phy.rev >= 3)
6214300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER1, 0);
6215300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, 0);
6216300016Sadrian
6217300016Sadrian	if (mac->mac_phy.rev <= 2) {
6218300016Sadrian		tmp = (mac->mac_phy.rev == 2) ? 0x3B : 0x40;
6219300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_BPHY_CTL3,
6220300016Sadrian				~BWN_NPHY_BPHY_CTL3_SCALE,
6221300016Sadrian				tmp << BWN_NPHY_BPHY_CTL3_SCALE_SHIFT);
6222300016Sadrian	}
6223300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
6224300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
6225300016Sadrian
6226300016Sadrian	if (siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_SKWRKFEM_BRD ||
6227300016Sadrian	    (siba_get_pci_subvendor(sc->sc_dev) == PCI_VENDOR_APPLE &&
6228300016Sadrian	     siba_get_pci_subdevice(sc->sc_dev) == BCMA_BOARD_TYPE_BCM943224M93))
6229300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXREALFD, 0xA0);
6230300016Sadrian	else
6231300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_TXREALFD, 0xB8);
6232300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_MIMO_CRSTXEXT, 0xC8);
6233300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_PLOAD_CSENSE_EXTLEN, 0x50);
6234300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_TXRIFS_FRDEL, 0x30);
6235300016Sadrian
6236300016Sadrian	if (phy->rev < 8)
6237300016Sadrian		bwn_nphy_update_mimo_config(mac, nphy->preamble_override);
6238300016Sadrian
6239300016Sadrian	bwn_nphy_update_txrx_chain(mac);
6240300016Sadrian
6241300016Sadrian	if (phy->rev < 2) {
6242300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_DUP40_GFBL, 0xAA8);
6243300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_DUP40_BL, 0x9A4);
6244300016Sadrian	}
6245300016Sadrian
6246300016Sadrian	tmp2 = bwn_current_band(mac);
6247300016Sadrian	if (bwn_nphy_ipa(mac)) {
6248300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_PAPD_EN0, 0x1);
6249300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_EPS_TABLE_ADJ0, 0x007F,
6250300016Sadrian				nphy->papd_epsilon_offset[0] << 7);
6251300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_PAPD_EN1, 0x1);
6252300016Sadrian		BWN_PHY_SETMASK(mac, BWN_NPHY_EPS_TABLE_ADJ1, 0x007F,
6253300016Sadrian				nphy->papd_epsilon_offset[1] << 7);
6254300016Sadrian		bwn_nphy_int_pa_set_tx_dig_filters(mac);
6255300016Sadrian	} else if (phy->rev >= 5) {
6256300016Sadrian		bwn_nphy_ext_pa_set_tx_dig_filters(mac);
6257300016Sadrian	}
6258300016Sadrian
6259300016Sadrian	bwn_nphy_workarounds(mac);
6260300016Sadrian
6261300016Sadrian	/* Reset CCA, in init code it differs a little from standard way */
6262300016Sadrian	bwn_phy_force_clock(mac, 1);
6263300016Sadrian	tmp = BWN_PHY_READ(mac, BWN_NPHY_BBCFG);
6264300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BBCFG, tmp | BWN_NPHY_BBCFG_RSTCCA);
6265300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BBCFG, tmp & ~BWN_NPHY_BBCFG_RSTCCA);
6266300016Sadrian	bwn_phy_force_clock(mac, 0);
6267300016Sadrian
6268300016Sadrian	bwn_mac_phy_clock_set(mac, true);
6269300016Sadrian
6270300016Sadrian	if (phy->rev < 7) {
6271300016Sadrian		bwn_nphy_pa_override(mac, false);
6272300016Sadrian		bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RX2TX);
6273300016Sadrian		bwn_nphy_force_rf_sequence(mac, BWN_RFSEQ_RESET2RX);
6274300016Sadrian		bwn_nphy_pa_override(mac, true);
6275300016Sadrian	}
6276300016Sadrian
6277300016Sadrian	bwn_nphy_classifier(mac, 0, 0);
6278300016Sadrian	bwn_nphy_read_clip_detection(mac, clip);
6279300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G)
6280300016Sadrian		bwn_nphy_bphy_init(mac);
6281300016Sadrian
6282300016Sadrian	tx_pwr_state = nphy->txpwrctrl;
6283300016Sadrian	bwn_nphy_tx_power_ctrl(mac, false);
6284300016Sadrian	bwn_nphy_tx_power_fix(mac);
6285300016Sadrian	bwn_nphy_tx_power_ctl_idle_tssi(mac);
6286300016Sadrian	bwn_nphy_tx_power_ctl_setup(mac);
6287300016Sadrian	bwn_nphy_tx_gain_table_upload(mac);
6288300016Sadrian
6289300016Sadrian	if (nphy->phyrxchain != 3)
6290300016Sadrian		bwn_nphy_set_rx_core_state(mac, nphy->phyrxchain);
6291300016Sadrian	if (nphy->mphase_cal_phase_id > 0)
6292300016Sadrian		;/* TODO PHY Periodic Calibration Multi-Phase Restart */
6293300016Sadrian
6294300016Sadrian	do_rssi_cal = false;
6295300016Sadrian	if (phy->rev >= 3) {
6296300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G)
6297300016Sadrian			do_rssi_cal = !nphy->rssical_chanspec_2G.center_freq;
6298300016Sadrian		else
6299300016Sadrian			do_rssi_cal = !nphy->rssical_chanspec_5G.center_freq;
6300300016Sadrian
6301300016Sadrian		if (do_rssi_cal)
6302300016Sadrian			bwn_nphy_rssi_cal(mac);
6303300016Sadrian		else
6304300016Sadrian			bwn_nphy_restore_rssi_cal(mac);
6305300016Sadrian	} else {
6306300016Sadrian		bwn_nphy_rssi_cal(mac);
6307300016Sadrian	}
6308300016Sadrian
6309300016Sadrian	if (!((nphy->measure_hold & 0x6) != 0)) {
6310300016Sadrian		if (bwn_current_band(mac) == BWN_BAND_2G)
6311300016Sadrian			do_cal = !nphy->iqcal_chanspec_2G.center_freq;
6312300016Sadrian		else
6313300016Sadrian			do_cal = !nphy->iqcal_chanspec_5G.center_freq;
6314300016Sadrian
6315300016Sadrian		if (nphy->mute)
6316300016Sadrian			do_cal = false;
6317300016Sadrian
6318300016Sadrian		if (do_cal) {
6319300016Sadrian			target = bwn_nphy_get_tx_gains(mac);
6320300016Sadrian
6321300016Sadrian			if (nphy->antsel_type == 2)
6322300016Sadrian				bwn_nphy_superswitch_init(mac, true);
6323300016Sadrian			if (nphy->perical != 2) {
6324300016Sadrian				bwn_nphy_rssi_cal(mac);
6325300016Sadrian				if (phy->rev >= 3) {
6326300016Sadrian					nphy->cal_orig_pwr_idx[0] =
6327300016Sadrian					    nphy->txpwrindex[0].index_internal;
6328300016Sadrian					nphy->cal_orig_pwr_idx[1] =
6329300016Sadrian					    nphy->txpwrindex[1].index_internal;
6330300016Sadrian					/* TODO N PHY Pre Calibrate TX Gain */
6331300016Sadrian					target = bwn_nphy_get_tx_gains(mac);
6332300016Sadrian				}
6333300016Sadrian				if (!bwn_nphy_cal_tx_iq_lo(mac, target, true, false))
6334300016Sadrian					if (bwn_nphy_cal_rx_iq(mac, target, 2, 0) == 0)
6335300016Sadrian						bwn_nphy_save_cal(mac);
6336300016Sadrian			} else if (nphy->mphase_cal_phase_id == 0)
6337300016Sadrian				;/* N PHY Periodic Calibration with arg 3 */
6338300016Sadrian		} else {
6339300016Sadrian			bwn_nphy_restore_cal(mac);
6340300016Sadrian		}
6341300016Sadrian	}
6342300016Sadrian
6343300016Sadrian	bwn_nphy_tx_pwr_ctrl_coef_setup(mac);
6344300016Sadrian	bwn_nphy_tx_power_ctrl(mac, tx_pwr_state);
6345300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_TXMACIF_HOLDOFF, 0x0015);
6346300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_TXMACDELAY, 0x0320);
6347300016Sadrian	if (phy->rev >= 3 && phy->rev <= 6)
6348300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_PLOAD_CSENSE_EXTLEN, 0x0032);
6349300016Sadrian	bwn_nphy_tx_lpf_bw(mac);
6350300016Sadrian	if (phy->rev >= 3)
6351300016Sadrian		bwn_nphy_spur_workaround(mac);
6352300016Sadrian
6353300016Sadrian	return 0;
6354300016Sadrian}
6355300016Sadrian
6356300016Sadrian/**************************************************
6357300016Sadrian * Channel switching ops.
6358300016Sadrian **************************************************/
6359300016Sadrian
6360300016Sadrianstatic void bwn_chantab_phy_upload(struct bwn_mac *mac,
6361300016Sadrian				   const struct bwn_phy_n_sfo_cfg *e)
6362300016Sadrian{
6363300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BW1A, e->phy_bw1a);
6364300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BW2, e->phy_bw2);
6365300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BW3, e->phy_bw3);
6366300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BW4, e->phy_bw4);
6367300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BW5, e->phy_bw5);
6368300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_BW6, e->phy_bw6);
6369300016Sadrian}
6370300016Sadrian
6371300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PmuSpurAvoid */
6372300016Sadrianstatic void bwn_nphy_pmu_spur_avoid(struct bwn_mac *mac, bool avoid)
6373300016Sadrian{
6374300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
6375300016Sadrian
6376300016Sadrian	/* XXX bhnd */
6377300016Sadrian	if (bwn_is_bus_siba(mac)) {
6378300016Sadrian		siba_pmu_spuravoid_pllupdate(sc->sc_dev, avoid);
6379300016Sadrian	}
6380300016Sadrian}
6381300016Sadrian
6382300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */
6383300016Sadrianstatic void bwn_nphy_channel_setup(struct bwn_mac *mac,
6384300016Sadrian				const struct bwn_phy_n_sfo_cfg *e,
6385300016Sadrian				struct ieee80211_channel *new_channel)
6386300016Sadrian{
6387300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
6388300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
6389300016Sadrian	struct bwn_phy_n *nphy = mac->mac_phy.phy_n;
6390300016Sadrian	int ch = new_channel->ic_ieee;
6391300016Sadrian	uint16_t tmp16;
6392300016Sadrian
6393300016Sadrian	if (bwn_channel_band(mac, new_channel) == BWN_BAND_5G) {
6394300016Sadrian		DPRINTF(sc, BWN_DEBUG_RESET, "%s: BAND_2G\n", __func__);
6395300016Sadrian		/* Switch to 2 GHz for a moment to access BWN_PHY_B_BBCFG */
6396300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_BANDCTL, ~BWN_NPHY_BANDCTL_5GHZ);
6397300016Sadrian
6398300016Sadrian		tmp16 = BWN_READ_2(mac, BWN_PSM_PHY_HDR);
6399300016Sadrian		BWN_WRITE_2(mac, BWN_PSM_PHY_HDR, tmp16 | 4);
6400300016Sadrian		/* Put BPHY in the reset */
6401300016Sadrian		BWN_PHY_SET(mac, BWN_PHY_B_BBCFG,
6402300016Sadrian			    BWN_PHY_B_BBCFG_RSTCCA | BWN_PHY_B_BBCFG_RSTRX);
6403300016Sadrian		BWN_WRITE_2(mac, BWN_PSM_PHY_HDR, tmp16);
6404300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_BANDCTL, BWN_NPHY_BANDCTL_5GHZ);
6405300016Sadrian	} else if (bwn_channel_band(mac, new_channel) == BWN_BAND_2G) {
6406300016Sadrian		DPRINTF(sc, BWN_DEBUG_RESET, "%s: BAND_2G\n", __func__);
6407300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_BANDCTL, ~BWN_NPHY_BANDCTL_5GHZ);
6408300016Sadrian		tmp16 = BWN_READ_2(mac, BWN_PSM_PHY_HDR);
6409300016Sadrian		BWN_WRITE_2(mac, BWN_PSM_PHY_HDR, tmp16 | 4);
6410300016Sadrian		/* Take BPHY out of the reset */
6411300016Sadrian		BWN_PHY_MASK(mac, BWN_PHY_B_BBCFG,
6412300016Sadrian			     (uint16_t)~(BWN_PHY_B_BBCFG_RSTCCA | BWN_PHY_B_BBCFG_RSTRX));
6413300016Sadrian		BWN_WRITE_2(mac, BWN_PSM_PHY_HDR, tmp16);
6414300016Sadrian	} else {
6415300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: unknown band?\n", __func__);
6416300016Sadrian	}
6417300016Sadrian
6418300016Sadrian	bwn_chantab_phy_upload(mac, e);
6419300016Sadrian
6420300016Sadrian	if (new_channel->ic_ieee == 14) {
6421300016Sadrian		bwn_nphy_classifier(mac, 2, 0);
6422300016Sadrian		BWN_PHY_SET(mac, BWN_PHY_B_TEST, 0x0800);
6423300016Sadrian	} else {
6424300016Sadrian		bwn_nphy_classifier(mac, 2, 2);
6425300016Sadrian		if (bwn_channel_band(mac, new_channel) == BWN_BAND_2G)
6426300016Sadrian			BWN_PHY_MASK(mac, BWN_PHY_B_TEST, ~0x840);
6427300016Sadrian	}
6428300016Sadrian
6429300016Sadrian	if (!nphy->txpwrctrl)
6430300016Sadrian		bwn_nphy_tx_power_fix(mac);
6431300016Sadrian
6432300016Sadrian	if (mac->mac_phy.rev < 3)
6433300016Sadrian		bwn_nphy_adjust_lna_gain_table(mac);
6434300016Sadrian
6435300016Sadrian	bwn_nphy_tx_lpf_bw(mac);
6436300016Sadrian
6437300016Sadrian	if (mac->mac_phy.rev >= 3 &&
6438300016Sadrian	    mac->mac_phy.phy_n->spur_avoid != BWN_SPUR_AVOID_DISABLE) {
6439300016Sadrian		uint8_t spuravoid = 0;
6440300016Sadrian
6441300016Sadrian		if (mac->mac_phy.phy_n->spur_avoid == BWN_SPUR_AVOID_FORCE) {
6442300016Sadrian			spuravoid = 1;
6443300016Sadrian		} else if (phy->rev >= 19) {
6444300016Sadrian			/* TODO */
6445300016Sadrian		} else if (phy->rev >= 18) {
6446300016Sadrian			/* TODO */
6447300016Sadrian		} else if (phy->rev >= 17) {
6448300016Sadrian			/* TODO: Off for channels 1-11, but check 12-14! */
6449300016Sadrian		} else if (phy->rev >= 16) {
6450300016Sadrian			/* TODO: Off for 2 GHz, but check 5 GHz! */
6451300016Sadrian		} else if (phy->rev >= 7) {
6452300016Sadrian			if (!bwn_is_40mhz(mac)) { /* 20MHz */
6453300016Sadrian				if (ch == 13 || ch == 14 || ch == 153)
6454300016Sadrian					spuravoid = 1;
6455300016Sadrian			} else { /* 40 MHz */
6456300016Sadrian				if (ch == 54)
6457300016Sadrian					spuravoid = 1;
6458300016Sadrian			}
6459300016Sadrian		} else {
6460300016Sadrian			if (!bwn_is_40mhz(mac)) { /* 20MHz */
6461300016Sadrian				if ((ch >= 5 && ch <= 8) || ch == 13 || ch == 14)
6462300016Sadrian					spuravoid = 1;
6463300016Sadrian			} else { /* 40MHz */
6464300016Sadrian				if (nphy->aband_spurwar_en &&
6465300016Sadrian				    (ch == 38 || ch == 102 || ch == 118))
6466300016Sadrian					spuravoid = siba_get_chipid(sc->sc_dev) == 0x4716;
6467300016Sadrian			}
6468300016Sadrian		}
6469300016Sadrian
6470300016Sadrian		bwn_nphy_pmu_spur_avoid(mac, spuravoid);
6471300016Sadrian
6472300016Sadrian		bwn_mac_switch_freq(mac, spuravoid);
6473300016Sadrian
6474300016Sadrian		if (mac->mac_phy.rev == 3 || mac->mac_phy.rev == 4)
6475300016Sadrian			bwn_wireless_core_phy_pll_reset(mac);
6476300016Sadrian
6477300016Sadrian		if (spuravoid)
6478300016Sadrian			BWN_PHY_SET(mac, BWN_NPHY_BBCFG, BWN_NPHY_BBCFG_RSTRX);
6479300016Sadrian		else
6480300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_BBCFG,
6481300016Sadrian				     ~BWN_NPHY_BBCFG_RSTRX & 0xFFFF);
6482300016Sadrian
6483300016Sadrian		bwn_nphy_reset_cca(mac);
6484300016Sadrian
6485300016Sadrian		/* wl sets useless phy_isspuravoid here */
6486300016Sadrian	}
6487300016Sadrian
6488300016Sadrian	BWN_PHY_WRITE(mac, BWN_NPHY_NDATAT_DUP40, 0x3830);
6489300016Sadrian
6490300016Sadrian	if (phy->rev >= 3)
6491300016Sadrian		bwn_nphy_spur_workaround(mac);
6492300016Sadrian}
6493300016Sadrian
6494300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */
6495300016Sadrianstatic int bwn_nphy_set_channel(struct bwn_mac *mac,
6496300016Sadrian				struct ieee80211_channel *channel,
6497300016Sadrian				bwn_chan_type_t channel_type)
6498300016Sadrian{
6499300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
6500300016Sadrian
6501300016Sadrian	const struct bwn_nphy_channeltab_entry_rev2 *tabent_r2 = NULL;
6502300016Sadrian	const struct bwn_nphy_channeltab_entry_rev3 *tabent_r3 = NULL;
6503300016Sadrian	const struct bwn_nphy_chantabent_rev7 *tabent_r7 = NULL;
6504300016Sadrian	const struct bwn_nphy_chantabent_rev7_2g *tabent_r7_2g = NULL;
6505300016Sadrian
6506300016Sadrian	uint8_t tmp;
6507300016Sadrian
6508300016Sadrian	if (phy->rev >= 19) {
6509300016Sadrian		return -ESRCH;
6510300016Sadrian		/* TODO */
6511300016Sadrian	} else if (phy->rev >= 7) {
6512300016Sadrian		r2057_get_chantabent_rev7(mac, bwn_get_chan_centre_freq(mac, channel),
6513300016Sadrian					  &tabent_r7, &tabent_r7_2g);
6514300016Sadrian		if (!tabent_r7 && !tabent_r7_2g)
6515300016Sadrian			return -ESRCH;
6516300016Sadrian	} else if (phy->rev >= 3) {
6517300016Sadrian		tabent_r3 = bwn_nphy_get_chantabent_rev3(mac,
6518300016Sadrian		    bwn_get_chan_centre_freq(mac, channel));
6519300016Sadrian		if (!tabent_r3)
6520300016Sadrian			return -ESRCH;
6521300016Sadrian	} else {
6522300016Sadrian		tabent_r2 = bwn_nphy_get_chantabent_rev2(mac,
6523300016Sadrian		    channel->ic_ieee);
6524300016Sadrian		if (!tabent_r2)
6525300016Sadrian			return -ESRCH;
6526300016Sadrian	}
6527300016Sadrian
6528300016Sadrian	/* Channel is set later in common code, but we need to set it on our
6529300016Sadrian	   own to let this function's subcalls work properly. */
6530300016Sadrian#if 0
6531300016Sadrian	phy->channel = channel->ic_ieee;
6532300016Sadrian#endif
6533300016Sadrian
6534300016Sadrian#if 0
6535300016Sadrian	if (bwn_channel_type_is_40mhz(phy->channel_type) !=
6536300016Sadrian		bwn_channel_type_is_40mhz(channel_type))
6537300016Sadrian		; /* TODO: BMAC BW Set (channel_type) */
6538300016Sadrian#endif
6539300016Sadrian
6540300016Sadrian	if (channel_type == BWN_CHAN_TYPE_40_HT_U) {
6541300016Sadrian		BWN_PHY_SET(mac, BWN_NPHY_RXCTL, BWN_NPHY_RXCTL_BSELU20);
6542300016Sadrian		if (phy->rev >= 7)
6543300016Sadrian			BWN_PHY_SET(mac, 0x310, 0x8000);
6544300016Sadrian	} else if (channel_type == BWN_CHAN_TYPE_40_HT_D) {
6545300016Sadrian		BWN_PHY_MASK(mac, BWN_NPHY_RXCTL, ~BWN_NPHY_RXCTL_BSELU20);
6546300016Sadrian		if (phy->rev >= 7)
6547300016Sadrian			BWN_PHY_MASK(mac, 0x310, (uint16_t)~0x8000);
6548300016Sadrian	}
6549300016Sadrian
6550300016Sadrian	if (phy->rev >= 19) {
6551300016Sadrian		/* TODO */
6552300016Sadrian	} else if (phy->rev >= 7) {
6553300016Sadrian		const struct bwn_phy_n_sfo_cfg *phy_regs = tabent_r7 ?
6554300016Sadrian			&(tabent_r7->phy_regs) : &(tabent_r7_2g->phy_regs);
6555300016Sadrian
6556300016Sadrian		if (phy->rf_rev <= 4 || phy->rf_rev == 6) {
6557300016Sadrian			tmp = (bwn_channel_band(mac, channel) == BWN_BAND_5G) ? 2 : 0;
6558300016Sadrian			BWN_RF_SETMASK(mac, R2057_TIA_CONFIG_CORE0, ~2, tmp);
6559300016Sadrian			BWN_RF_SETMASK(mac, R2057_TIA_CONFIG_CORE1, ~2, tmp);
6560300016Sadrian		}
6561300016Sadrian
6562300016Sadrian		bwn_radio_2057_setup(mac, tabent_r7, tabent_r7_2g);
6563300016Sadrian		bwn_nphy_channel_setup(mac, phy_regs, channel);
6564300016Sadrian	} else if (phy->rev >= 3) {
6565300016Sadrian		tmp = (bwn_channel_band(mac, channel) == BWN_BAND_5G) ? 4 : 0;
6566300016Sadrian		BWN_RF_SETMASK(mac, 0x08, 0xFFFB, tmp);
6567300016Sadrian		bwn_radio_2056_setup(mac, tabent_r3);
6568300016Sadrian		bwn_nphy_channel_setup(mac, &(tabent_r3->phy_regs), channel);
6569300016Sadrian	} else {
6570300016Sadrian		tmp = (bwn_channel_band(mac, channel) == BWN_BAND_5G) ? 0x0020 : 0x0050;
6571300016Sadrian		BWN_RF_SETMASK(mac, B2055_MASTER1, 0xFF8F, tmp);
6572300016Sadrian		bwn_radio_2055_setup(mac, tabent_r2);
6573300016Sadrian		bwn_nphy_channel_setup(mac, &(tabent_r2->phy_regs), channel);
6574300016Sadrian	}
6575300016Sadrian
6576300016Sadrian	return 0;
6577300016Sadrian}
6578300016Sadrian
6579300016Sadrian/**************************************************
6580300016Sadrian * Basic PHY ops.
6581300016Sadrian **************************************************/
6582300016Sadrian
6583300016Sadrianint
6584300016Sadrianbwn_nphy_op_allocate(struct bwn_mac *mac)
6585300016Sadrian{
6586300016Sadrian	struct bwn_phy_n *nphy;
6587300016Sadrian
6588300016Sadrian	nphy = malloc(sizeof(*nphy), M_DEVBUF, M_ZERO | M_NOWAIT);
6589300016Sadrian	if (!nphy)
6590300016Sadrian		return -ENOMEM;
6591300016Sadrian
6592300016Sadrian	mac->mac_phy.phy_n = nphy;
6593300016Sadrian
6594300016Sadrian	return 0;
6595300016Sadrian}
6596300016Sadrian
6597300016Sadrianvoid
6598300016Sadrianbwn_nphy_op_prepare_structs(struct bwn_mac *mac)
6599300016Sadrian{
6600300016Sadrian	struct bwn_softc *sc = mac->mac_sc;
6601300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
6602300016Sadrian	struct bwn_phy_n *nphy = phy->phy_n;
6603300016Sadrian
6604300016Sadrian	memset(nphy, 0, sizeof(*nphy));
6605300016Sadrian
6606300016Sadrian	nphy->hang_avoid = (phy->rev == 3 || phy->rev == 4);
6607300016Sadrian	nphy->spur_avoid = (phy->rev >= 3) ?
6608300016Sadrian				BWN_SPUR_AVOID_AUTO : BWN_SPUR_AVOID_DISABLE;
6609300016Sadrian	nphy->gain_boost = true; /* this way we follow wl, assume it is true */
6610300016Sadrian	nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */
6611300016Sadrian	nphy->phyrxchain = 3; /* to avoid bwn_nphy_set_rx_core_state like wl */
6612300016Sadrian	nphy->perical = 2; /* avoid additional rssi cal on init (like wl) */
6613300016Sadrian	/* 128 can mean disabled-by-default state of TX pwr ctl. Max value is
6614300016Sadrian	 * 0x7f == 127 and we check for 128 when restoring TX pwr ctl. */
6615300016Sadrian	nphy->tx_pwr_idx[0] = 128;
6616300016Sadrian	nphy->tx_pwr_idx[1] = 128;
6617300016Sadrian
6618300016Sadrian	/* Hardware TX power control and 5GHz power gain */
6619300016Sadrian	nphy->txpwrctrl = false;
6620300016Sadrian	nphy->pwg_gain_5ghz = false;
6621300016Sadrian	if (mac->mac_phy.rev >= 3 ||
6622300016Sadrian	    (siba_get_pci_subvendor(sc->sc_dev) == PCI_VENDOR_APPLE &&
6623300016Sadrian	     (siba_get_revid(sc->sc_dev) == 11 || siba_get_revid(sc->sc_dev) == 12))) {
6624300016Sadrian		nphy->txpwrctrl = true;
6625300016Sadrian		nphy->pwg_gain_5ghz = true;
6626300016Sadrian	} else if (siba_sprom_get_rev(sc->sc_dev) >= 4) {
6627300016Sadrian		if (mac->mac_phy.rev >= 2 &&
6628300016Sadrian		    (siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_TXPWRCTRL_EN)) {
6629300016Sadrian			nphy->txpwrctrl = true;
6630300016Sadrian#ifdef CONFIG_BWN_SSB
6631300016Sadrian			if (dev->dev->bus_type == BWN_BUS_SSB &&
6632300016Sadrian			    dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI) {
6633300016Sadrian				struct pci_dev *pdev =
6634300016Sadrian					dev->dev->sdev->bus->host_pci;
6635300016Sadrian				if (pdev->device == 0x4328 ||
6636300016Sadrian				    pdev->device == 0x432a)
6637300016Sadrian					nphy->pwg_gain_5ghz = true;
6638300016Sadrian			}
6639300016Sadrian#endif
6640300016Sadrian		} else if (siba_sprom_get_bf2_lo(sc->sc_dev) & BWN_BFL2_5G_PWRGAIN) {
6641300016Sadrian			nphy->pwg_gain_5ghz = true;
6642300016Sadrian		}
6643300016Sadrian	}
6644300016Sadrian
6645300016Sadrian	if (mac->mac_phy.rev >= 3) {
6646300016Sadrian		nphy->ipa2g_on = siba_sprom_get_fem_2ghz_extpa_gain(sc->sc_dev) == 2;
6647300016Sadrian		nphy->ipa5g_on = siba_sprom_get_fem_5ghz_extpa_gain(sc->sc_dev) == 2;
6648300016Sadrian	}
6649300016Sadrian}
6650300016Sadrian
6651300016Sadrianvoid
6652300016Sadrianbwn_nphy_op_free(struct bwn_mac *mac)
6653300016Sadrian{
6654300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
6655300016Sadrian	struct bwn_phy_n *nphy = phy->phy_n;
6656300016Sadrian
6657300016Sadrian	free(nphy, M_DEVBUF);
6658300016Sadrian	phy->phy_n = NULL;
6659300016Sadrian}
6660300016Sadrian
6661300016Sadrianint
6662300016Sadrianbwn_nphy_op_init(struct bwn_mac *mac)
6663300016Sadrian{
6664300016Sadrian	return bwn_phy_initn(mac);
6665300016Sadrian}
6666300016Sadrian
6667300016Sadrianstatic inline void check_phyreg(struct bwn_mac *mac, uint16_t offset)
6668300016Sadrian{
6669300016Sadrian#ifdef	BWN_DEBUG
6670300016Sadrian	if ((offset & BWN_PHYROUTE_MASK) == BWN_PHYROUTE_OFDM_GPHY) {
6671300016Sadrian		/* OFDM registers are onnly available on A/G-PHYs */
6672300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "Invalid OFDM PHY access at "
6673300016Sadrian		       "0x%04X on N-PHY\n", offset);
6674300016Sadrian	}
6675300016Sadrian	if ((offset & BWN_PHYROUTE_MASK) == BWN_PHYROUTE_EXT_GPHY) {
6676300016Sadrian		/* Ext-G registers are only available on G-PHYs */
6677300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "Invalid EXT-G PHY access at "
6678300016Sadrian		       "0x%04X on N-PHY\n", offset);
6679300016Sadrian	}
6680300016Sadrian#endif /* BWN_DEBUG */
6681300016Sadrian}
6682300016Sadrian
6683300016Sadrianvoid
6684300016Sadrianbwn_nphy_op_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
6685300016Sadrian    uint16_t set)
6686300016Sadrian{
6687300016Sadrian	check_phyreg(mac, reg);
6688300016Sadrian	BWN_WRITE_2_F(mac, BWN_PHYCTL, reg);
6689300016Sadrian	BWN_WRITE_SETMASK2(mac, BWN_PHYDATA, mask, set);
6690300016Sadrian}
6691300016Sadrian
6692300016Sadrian#if 0
6693300016Sadrianuint16_t
6694300016Sadrianbwn_nphy_op_radio_read(struct bwn_mac *mac, uint16_t reg)
6695300016Sadrian{
6696300016Sadrian	/* Register 1 is a 32-bit register. */
6697300016Sadrian	if (mac->mac_phy.rev < 7 && reg == 1) {
6698300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: bad reg access\n", __func__);
6699300016Sadrian	}
6700300016Sadrian
6701300016Sadrian	if (mac->mac_phy.rev >= 7)
6702300016Sadrian		reg |= 0x200; /* Radio 0x2057 */
6703300016Sadrian	else
6704300016Sadrian		reg |= 0x100;
6705300016Sadrian
6706300016Sadrian	BWN_WRITE_2_F(mac, BWN_RFCTL, reg);
6707300016Sadrian	return BWN_READ_2(mac, BWN_RFDATALO);
6708300016Sadrian}
6709300016Sadrian#endif
6710300016Sadrian
6711300016Sadrian#if 0
6712300016Sadrianvoid
6713300016Sadrianbwn_nphy_op_radio_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
6714300016Sadrian{
6715300016Sadrian	/* Register 1 is a 32-bit register. */
6716300016Sadrian	if (mac->mac_phy.rev < 7 && reg == 1) {
6717300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "%s: bad reg access\n", __func__);
6718300016Sadrian	}
6719300016Sadrian
6720300016Sadrian	BWN_WRITE_2_F(mac, BWN_RFCTL, reg);
6721300016Sadrian	BWN_WRITE_2(mac, BWN_RFDATALO, value);
6722300016Sadrian}
6723300016Sadrian#endif
6724300016Sadrian
6725300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */
6726300016Sadrianvoid
6727300016Sadrianbwn_nphy_op_software_rfkill(struct bwn_mac *mac, bool active)
6728300016Sadrian{
6729300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
6730300016Sadrian
6731300016Sadrian	if (BWN_READ_4(mac, BWN_MACCTL) & BWN_MACCTL_ON)
6732300016Sadrian		BWN_ERRPRINTF(mac->mac_sc, "MAC not suspended\n");
6733300016Sadrian
6734300016Sadrian	if (active) {
6735300016Sadrian		DPRINTF(mac->mac_sc, BWN_DEBUG_RESET | BWN_DEBUG_PHY,
6736300016Sadrian		    "%s: called; rev=%d, rf_on=%d\n", __func__,
6737300016Sadrian		    phy->rev, mac->mac_phy.rf_on);
6738300016Sadrian		if (phy->rev >= 19) {
6739300016Sadrian			/* TODO */
6740300016Sadrian		} else if (phy->rev >= 7) {
6741300016Sadrian			if (!mac->mac_phy.rf_on)
6742300016Sadrian				bwn_radio_2057_init(mac);
6743300016Sadrian			bwn_switch_channel(mac, bwn_get_chan(mac));
6744300016Sadrian		} else if (phy->rev >= 3) {
6745300016Sadrian			if (!mac->mac_phy.rf_on)
6746300016Sadrian				bwn_radio_init2056(mac);
6747300016Sadrian			bwn_switch_channel(mac, bwn_get_chan(mac));
6748300016Sadrian		} else {
6749300016Sadrian			bwn_radio_init2055(mac);
6750300016Sadrian		}
6751300016Sadrian	} else {
6752300016Sadrian		if (phy->rev >= 19) {
6753300016Sadrian			/* TODO */
6754300016Sadrian		} else if (phy->rev >= 8) {
6755300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_CMD,
6756300016Sadrian				     ~BWN_NPHY_RFCTL_CMD_CHIP0PU);
6757300016Sadrian		} else if (phy->rev >= 7) {
6758300016Sadrian			/* Nothing needed */
6759300016Sadrian		} else if (phy->rev >= 3) {
6760300016Sadrian			BWN_PHY_MASK(mac, BWN_NPHY_RFCTL_CMD,
6761300016Sadrian				     ~BWN_NPHY_RFCTL_CMD_CHIP0PU);
6762300016Sadrian
6763300016Sadrian			BWN_RF_MASK(mac, 0x09, ~0x2);
6764300016Sadrian
6765300016Sadrian			BWN_RF_WRITE(mac, 0x204D, 0);
6766300016Sadrian			BWN_RF_WRITE(mac, 0x2053, 0);
6767300016Sadrian			BWN_RF_WRITE(mac, 0x2058, 0);
6768300016Sadrian			BWN_RF_WRITE(mac, 0x205E, 0);
6769300016Sadrian			BWN_RF_MASK(mac, 0x2062, ~0xF0);
6770300016Sadrian			BWN_RF_WRITE(mac, 0x2064, 0);
6771300016Sadrian
6772300016Sadrian			BWN_RF_WRITE(mac, 0x304D, 0);
6773300016Sadrian			BWN_RF_WRITE(mac, 0x3053, 0);
6774300016Sadrian			BWN_RF_WRITE(mac, 0x3058, 0);
6775300016Sadrian			BWN_RF_WRITE(mac, 0x305E, 0);
6776300016Sadrian			BWN_RF_MASK(mac, 0x3062, ~0xF0);
6777300016Sadrian			BWN_RF_WRITE(mac, 0x3064, 0);
6778300016Sadrian		}
6779300016Sadrian	}
6780300016Sadrian}
6781300016Sadrian
6782300016Sadrian/* http://bcm-v4.sipsolutions.net/802.11/PHY/Anacore */
6783300016Sadrianvoid
6784300016Sadrianbwn_nphy_op_switch_analog(struct bwn_mac *mac, bool on)
6785300016Sadrian{
6786300016Sadrian	struct bwn_phy *phy = &mac->mac_phy;
6787300016Sadrian	uint16_t override = on ? 0x0 : 0x7FFF;
6788300016Sadrian	uint16_t core = on ? 0xD : 0x00FD;
6789300016Sadrian
6790300016Sadrian	if (phy->rev >= 19) {
6791300016Sadrian		/* TODO */
6792300016Sadrian		device_printf(mac->mac_sc->sc_dev, "%s: TODO\n", __func__);
6793300016Sadrian	} else if (phy->rev >= 3) {
6794300016Sadrian		if (on) {
6795300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C1, core);
6796300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER1, override);
6797300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C2, core);
6798300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, override);
6799300016Sadrian		} else {
6800300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER1, override);
6801300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C1, core);
6802300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, override);
6803300016Sadrian			BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_C2, core);
6804300016Sadrian		}
6805300016Sadrian	} else {
6806300016Sadrian		BWN_PHY_WRITE(mac, BWN_NPHY_AFECTL_OVER, override);
6807300016Sadrian	}
6808300016Sadrian}
6809300016Sadrian
6810300016Sadrianint
6811300016Sadrianbwn_nphy_op_switch_channel(struct bwn_mac *mac, unsigned int new_channel)
6812300016Sadrian{
6813300016Sadrian	struct ieee80211_channel *channel = bwn_get_channel(mac);
6814300016Sadrian	bwn_chan_type_t channel_type = bwn_get_chan_type(mac, NULL);
6815300016Sadrian
6816300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G) {
6817300016Sadrian		if ((new_channel < 1) || (new_channel > 14))
6818300016Sadrian			return -EINVAL;
6819300016Sadrian	} else {
6820300016Sadrian		if (new_channel > 200)
6821300016Sadrian			return -EINVAL;
6822300016Sadrian	}
6823300016Sadrian
6824300016Sadrian	return bwn_nphy_set_channel(mac, channel, channel_type);
6825300016Sadrian}
6826300016Sadrian
6827300016Sadrian#if 0
6828300016Sadrianunsigned int
6829300016Sadrianbwn_nphy_op_get_default_chan(struct bwn_mac *mac)
6830300016Sadrian{
6831300016Sadrian	if (bwn_current_band(mac) == BWN_BAND_2G)
6832300016Sadrian		return 1;
6833300016Sadrian	return 36;
6834300016Sadrian}
6835300016Sadrian#endif
6836