13aaffc27SAugustin Cavalier/*-
23aaffc27SAugustin Cavalier * SPDX-License-Identifier: BSD-3-Clause
33aaffc27SAugustin Cavalier *
4783c4cd1SColin Günther * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
5783c4cd1SColin Günther *
6783c4cd1SColin Günther * This code is derived from software contributed to The DragonFly Project
7783c4cd1SColin Günther * by Sepherosa Ziehau <sepherosa@gmail.com>
8783c4cd1SColin Günther *
9783c4cd1SColin Günther * Redistribution and use in source and binary forms, with or without
10783c4cd1SColin Günther * modification, are permitted provided that the following conditions
11783c4cd1SColin Günther * are met:
12783c4cd1SColin Günther *
13783c4cd1SColin Günther * 1. Redistributions of source code must retain the above copyright
14783c4cd1SColin Günther *    notice, this list of conditions and the following disclaimer.
15783c4cd1SColin Günther * 2. Redistributions in binary form must reproduce the above copyright
16783c4cd1SColin Günther *    notice, this list of conditions and the following disclaimer in
17783c4cd1SColin Günther *    the documentation and/or other materials provided with the
18783c4cd1SColin Günther *    distribution.
19783c4cd1SColin Günther * 3. Neither the name of The DragonFly Project nor the names of its
20783c4cd1SColin Günther *    contributors may be used to endorse or promote products derived
21783c4cd1SColin Günther *    from this software without specific, prior written permission.
22783c4cd1SColin Günther *
23783c4cd1SColin Günther * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24783c4cd1SColin Günther * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25783c4cd1SColin Günther * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26783c4cd1SColin Günther * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27783c4cd1SColin Günther * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28783c4cd1SColin Günther * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29783c4cd1SColin Günther * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30783c4cd1SColin Günther * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31783c4cd1SColin Günther * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32783c4cd1SColin Günther * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33783c4cd1SColin Günther * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34783c4cd1SColin Günther * SUCH DAMAGE.
35783c4cd1SColin Günther *
36783c4cd1SColin Günther * $DragonFly: src/sys/dev/netif/bwi/bwirf.c,v 1.9 2008/08/21 12:19:33 swildner Exp $
37783c4cd1SColin Günther */
38783c4cd1SColin Günther
39783c4cd1SColin Günther#include <sys/cdefs.h>
403aaffc27SAugustin Cavalier__FBSDID("$FreeBSD: releng/12.0/sys/dev/bwi/bwirf.c 326022 2017-11-20 19:36:21Z pfg $");
41783c4cd1SColin Günther
42783c4cd1SColin Günther#include "opt_inet.h"
43783c4cd1SColin Günther#include "opt_bwi.h"
44fd893db8SAugustin Cavalier#include "opt_wlan.h"
45783c4cd1SColin Günther
46783c4cd1SColin Günther#include <sys/param.h>
47783c4cd1SColin Günther#include <sys/endian.h>
48783c4cd1SColin Günther#include <sys/kernel.h>
49783c4cd1SColin Günther#include <sys/bus.h>
50783c4cd1SColin Günther#include <sys/malloc.h>
51783c4cd1SColin Günther#include <sys/proc.h>
52783c4cd1SColin Günther#include <sys/rman.h>
53783c4cd1SColin Günther#include <sys/socket.h>
54783c4cd1SColin Günther#include <sys/sockio.h>
55783c4cd1SColin Günther#include <sys/sysctl.h>
56783c4cd1SColin Günther#include <sys/systm.h>
57783c4cd1SColin Günther
58783c4cd1SColin Günther#include <net/if.h>
59fd893db8SAugustin Cavalier#include <net/if_var.h>
60783c4cd1SColin Günther#include <net/if_dl.h>
61783c4cd1SColin Günther#include <net/if_media.h>
62783c4cd1SColin Günther#include <net/if_types.h>
63783c4cd1SColin Günther#include <net/if_arp.h>
64783c4cd1SColin Günther#include <net/ethernet.h>
65783c4cd1SColin Günther#include <net/if_llc.h>
66783c4cd1SColin Günther
67783c4cd1SColin Günther#include <net80211/ieee80211_var.h>
68783c4cd1SColin Günther#include <net80211/ieee80211_radiotap.h>
69783c4cd1SColin Günther#include <net80211/ieee80211_amrr.h>
70783c4cd1SColin Günther
71783c4cd1SColin Günther#include <machine/bus.h>
72783c4cd1SColin Günther
73783c4cd1SColin Günther#include <dev/bwi/bitops.h>
74783c4cd1SColin Günther#include <dev/bwi/if_bwireg.h>
75783c4cd1SColin Günther#include <dev/bwi/if_bwivar.h>
76783c4cd1SColin Günther#include <dev/bwi/bwimac.h>
77783c4cd1SColin Günther#include <dev/bwi/bwirf.h>
78783c4cd1SColin Günther#include <dev/bwi/bwiphy.h>
79783c4cd1SColin Günther
80783c4cd1SColin Günther#define RF_LO_WRITE(mac, lo)	bwi_rf_lo_write((mac), (lo))
81783c4cd1SColin Günther
82783c4cd1SColin Günther#define BWI_RF_2GHZ_CHAN(chan)			\
83783c4cd1SColin Günther	(ieee80211_ieee2mhz((chan), IEEE80211_CHAN_2GHZ) - 2400)
84783c4cd1SColin Günther
85783c4cd1SColin Günther#define BWI_DEFAULT_IDLE_TSSI	52
86783c4cd1SColin Günther
87783c4cd1SColin Güntherstruct rf_saveregs {
88783c4cd1SColin Günther	uint16_t	phy_01;
89783c4cd1SColin Günther	uint16_t	phy_03;
90783c4cd1SColin Günther	uint16_t	phy_0a;
91783c4cd1SColin Günther	uint16_t	phy_15;
92783c4cd1SColin Günther	uint16_t	phy_2a;
93783c4cd1SColin Günther	uint16_t	phy_30;
94783c4cd1SColin Günther	uint16_t	phy_35;
95783c4cd1SColin Günther	uint16_t	phy_60;
96783c4cd1SColin Günther	uint16_t	phy_429;
97783c4cd1SColin Günther	uint16_t	phy_802;
98783c4cd1SColin Günther	uint16_t	phy_811;
99783c4cd1SColin Günther	uint16_t	phy_812;
100783c4cd1SColin Günther	uint16_t	phy_814;
101783c4cd1SColin Günther	uint16_t	phy_815;
102783c4cd1SColin Günther
103783c4cd1SColin Günther	uint16_t	rf_43;
104783c4cd1SColin Günther	uint16_t	rf_52;
105783c4cd1SColin Günther	uint16_t	rf_7a;
106783c4cd1SColin Günther};
107783c4cd1SColin Günther
108783c4cd1SColin Günther#define SAVE_RF_REG(mac, regs, n)	(regs)->rf_##n = RF_READ((mac), 0x##n)
109783c4cd1SColin Günther#define RESTORE_RF_REG(mac, regs, n)	RF_WRITE((mac), 0x##n, (regs)->rf_##n)
110783c4cd1SColin Günther
111783c4cd1SColin Günther#define SAVE_PHY_REG(mac, regs, n)	(regs)->phy_##n = PHY_READ((mac), 0x##n)
112783c4cd1SColin Günther#define RESTORE_PHY_REG(mac, regs, n)	PHY_WRITE((mac), 0x##n, (regs)->phy_##n)
113783c4cd1SColin Günther
114783c4cd1SColin Güntherstatic int	bwi_rf_calc_txpower(int8_t *, uint8_t, const int16_t[]);
115783c4cd1SColin Güntherstatic void	bwi_rf_work_around(struct bwi_mac *, u_int);
116783c4cd1SColin Güntherstatic int	bwi_rf_gain_max_reached(struct bwi_mac *, int);
117783c4cd1SColin Güntherstatic uint16_t	bwi_rf_calibval(struct bwi_mac *);
118783c4cd1SColin Güntherstatic uint16_t	bwi_rf_get_tp_ctrl2(struct bwi_mac *);
119783c4cd1SColin Günther
120783c4cd1SColin Güntherstatic void	bwi_rf_lo_update_11b(struct bwi_mac *);
121783c4cd1SColin Güntherstatic uint16_t	bwi_rf_lo_measure_11b(struct bwi_mac *);
122783c4cd1SColin Günther
123783c4cd1SColin Güntherstatic void	bwi_rf_lo_update_11g(struct bwi_mac *);
124783c4cd1SColin Güntherstatic uint32_t	bwi_rf_lo_devi_measure(struct bwi_mac *, uint16_t);
125783c4cd1SColin Güntherstatic void	bwi_rf_lo_measure_11g(struct bwi_mac *,
126783c4cd1SColin Günther			const struct bwi_rf_lo *, struct bwi_rf_lo *, uint8_t);
127783c4cd1SColin Güntherstatic uint8_t	_bwi_rf_lo_update_11g(struct bwi_mac *, uint16_t);
128783c4cd1SColin Güntherstatic void	bwi_rf_lo_write(struct bwi_mac *, const struct bwi_rf_lo *);
129783c4cd1SColin Günther
130783c4cd1SColin Güntherstatic void	bwi_rf_set_nrssi_ofs_11g(struct bwi_mac *);
131783c4cd1SColin Güntherstatic void	bwi_rf_calc_nrssi_slope_11b(struct bwi_mac *);
132783c4cd1SColin Güntherstatic void	bwi_rf_calc_nrssi_slope_11g(struct bwi_mac *);
133783c4cd1SColin Güntherstatic void	bwi_rf_set_nrssi_thr_11b(struct bwi_mac *);
134783c4cd1SColin Güntherstatic void	bwi_rf_set_nrssi_thr_11g(struct bwi_mac *);
135783c4cd1SColin Günther
136783c4cd1SColin Güntherstatic void	bwi_rf_init_sw_nrssi_table(struct bwi_mac *);
137783c4cd1SColin Günther
138783c4cd1SColin Güntherstatic int	bwi_rf_calc_rssi_bcm2050(struct bwi_mac *,
139783c4cd1SColin Günther			const struct bwi_rxbuf_hdr *);
140783c4cd1SColin Güntherstatic int	bwi_rf_calc_rssi_bcm2053(struct bwi_mac *,
141783c4cd1SColin Günther			const struct bwi_rxbuf_hdr *);
142783c4cd1SColin Güntherstatic int	bwi_rf_calc_rssi_bcm2060(struct bwi_mac *,
143783c4cd1SColin Günther			const struct bwi_rxbuf_hdr *);
144783c4cd1SColin Güntherstatic int	bwi_rf_calc_noise_bcm2050(struct bwi_mac *);
145783c4cd1SColin Güntherstatic int	bwi_rf_calc_noise_bcm2053(struct bwi_mac *);
146783c4cd1SColin Güntherstatic int	bwi_rf_calc_noise_bcm2060(struct bwi_mac *);
147783c4cd1SColin Günther
148783c4cd1SColin Güntherstatic void	bwi_rf_on_11a(struct bwi_mac *);
149783c4cd1SColin Güntherstatic void	bwi_rf_on_11bg(struct bwi_mac *);
150783c4cd1SColin Günther
151783c4cd1SColin Güntherstatic void	bwi_rf_off_11a(struct bwi_mac *);
152783c4cd1SColin Güntherstatic void	bwi_rf_off_11bg(struct bwi_mac *);
153783c4cd1SColin Güntherstatic void	bwi_rf_off_11g_rev5(struct bwi_mac *);
154783c4cd1SColin Günther
155783c4cd1SColin Güntherstatic const int8_t	bwi_txpower_map_11b[BWI_TSSI_MAX] =
156783c4cd1SColin Günther	{ BWI_TXPOWER_MAP_11B };
157783c4cd1SColin Güntherstatic const int8_t	bwi_txpower_map_11g[BWI_TSSI_MAX] =
158783c4cd1SColin Günther	{ BWI_TXPOWER_MAP_11G };
159783c4cd1SColin Günther
160783c4cd1SColin Güntherstatic __inline int16_t
161783c4cd1SColin Güntherbwi_nrssi_11g(struct bwi_mac *mac)
162783c4cd1SColin Günther{
163783c4cd1SColin Günther	int16_t val;
164783c4cd1SColin Günther
165783c4cd1SColin Günther#define NRSSI_11G_MASK		__BITS(13, 8)
166783c4cd1SColin Günther
167783c4cd1SColin Günther	val = (int16_t)__SHIFTOUT(PHY_READ(mac, 0x47f), NRSSI_11G_MASK);
168783c4cd1SColin Günther	if (val >= 32)
169783c4cd1SColin Günther		val -= 64;
170783c4cd1SColin Günther	return val;
171783c4cd1SColin Günther
172783c4cd1SColin Günther#undef NRSSI_11G_MASK
173783c4cd1SColin Günther}
174783c4cd1SColin Günther
175783c4cd1SColin Güntherstatic __inline struct bwi_rf_lo *
176783c4cd1SColin Güntherbwi_get_rf_lo(struct bwi_mac *mac, uint16_t rf_atten, uint16_t bbp_atten)
177783c4cd1SColin Günther{
178783c4cd1SColin Günther	int n;
179783c4cd1SColin Günther
180783c4cd1SColin Günther	n = rf_atten + (14 * (bbp_atten / 2));
181783c4cd1SColin Günther	KASSERT(n < BWI_RFLO_MAX, ("n %d", n));
182783c4cd1SColin Günther
183783c4cd1SColin Günther	return &mac->mac_rf.rf_lo[n];
184783c4cd1SColin Günther}
185783c4cd1SColin Günther
186783c4cd1SColin Güntherstatic __inline int
187783c4cd1SColin Güntherbwi_rf_lo_isused(struct bwi_mac *mac, const struct bwi_rf_lo *lo)
188783c4cd1SColin Günther{
189783c4cd1SColin Günther	struct bwi_rf *rf = &mac->mac_rf;
190783c4cd1SColin Günther	int idx;
191783c4cd1SColin Günther
192783c4cd1SColin Günther	idx = lo - rf->rf_lo;
193783c4cd1SColin Günther	KASSERT(idx >= 0 && idx < BWI_RFLO_MAX, ("idx %d", idx));
194783c4cd1SColin Günther
195783c4cd1SColin Günther	return isset(rf->rf_lo_used, idx);
196783c4cd1SColin Günther}
197783c4cd1SColin Günther
198783c4cd1SColin Günthervoid
199783c4cd1SColin Güntherbwi_rf_write(struct bwi_mac *mac, uint16_t ctrl, uint16_t data)
200783c4cd1SColin Günther{
201783c4cd1SColin Günther	struct bwi_softc *sc = mac->mac_sc;
202783c4cd1SColin Günther
203783c4cd1SColin Günther	CSR_WRITE_2(sc, BWI_RF_CTRL, ctrl);
204783c4cd1SColin Günther	CSR_WRITE_2(sc, BWI_RF_DATA_LO, data);
205783c4cd1SColin Günther}
206783c4cd1SColin Günther
207783c4cd1SColin Güntheruint16_t
208783c4cd1SColin Güntherbwi_rf_read(struct bwi_mac *mac, uint16_t ctrl)
209783c4cd1SColin Günther{
210783c4cd1SColin Günther	struct bwi_rf *rf = &mac->mac_rf;
211783c4cd1SColin Günther	struct bwi_softc *sc = mac->mac_sc;
212783c4cd1SColin Günther
213783c4cd1SColin Günther	ctrl |= rf->rf_ctrl_rd;
214783c4cd1SColin Günther	if (rf->rf_ctrl_adj) {
215783c4cd1SColin Günther		/* XXX */
216783c4cd1SColin Günther		if (ctrl < 0x70)
217783c4cd1SColin Günther			ctrl += 0x80;
218783c4cd1SColin Günther		else if (ctrl < 0x80)
219783c4cd1SColin Günther			ctrl += 0x70;
220783c4cd1SColin Günther	}
221783c4cd1SColin Günther
222783c4cd1SColin Günther	CSR_WRITE_2(sc, BWI_RF_CTRL, ctrl);
223783c4cd1SColin Günther	return CSR_READ_2(sc, BWI_RF_DATA_LO);
224783c4cd1SColin Günther}
225783c4cd1SColin Günther
226783c4cd1SColin Güntherint
227783c4cd1SColin Güntherbwi_rf_attach(struct bwi_mac *mac)
228783c4cd1SColin Günther{
229783c4cd1SColin Günther	struct bwi_softc *sc = mac->mac_sc;
230783c4cd1SColin Günther	struct bwi_phy *phy = &mac->mac_phy;
231783c4cd1SColin Günther	struct bwi_rf *rf = &mac->mac_rf;
232783c4cd1SColin Günther	uint16_t type, manu;
233783c4cd1SColin Günther	uint8_t rev;
234783c4cd1SColin Günther
235783c4cd1SColin Günther	/*
236783c4cd1SColin Günther	 * Get RF manufacture/type/revision
237783c4cd1SColin Günther	 */
238783c4cd1SColin Günther	if (sc->sc_bbp_id == BWI_BBPID_BCM4317) {
239783c4cd1SColin Günther		/*
240783c4cd1SColin Günther		 * Fake a BCM2050 RF
241783c4cd1SColin Günther		 */
242783c4cd1SColin Günther		manu = BWI_RF_MANUFACT_BCM;
243783c4cd1SColin Günther		type = BWI_RF_T_BCM2050;
244783c4cd1SColin Günther		if (sc->sc_bbp_rev == 0)
245783c4cd1SColin Günther			rev = 3;
246783c4cd1SColin Günther		else if (sc->sc_bbp_rev == 1)
247783c4cd1SColin Günther			rev = 4;
248783c4cd1SColin Günther		else
249783c4cd1SColin Günther			rev = 5;
250783c4cd1SColin Günther	} else {
251783c4cd1SColin Günther		uint32_t val;
252783c4cd1SColin Günther
253783c4cd1SColin Günther		CSR_WRITE_2(sc, BWI_RF_CTRL, BWI_RF_CTRL_RFINFO);
254783c4cd1SColin Günther		val = CSR_READ_2(sc, BWI_RF_DATA_HI);
255783c4cd1SColin Günther		val <<= 16;
256783c4cd1SColin Günther
257783c4cd1SColin Günther		CSR_WRITE_2(sc, BWI_RF_CTRL, BWI_RF_CTRL_RFINFO);
258783c4cd1SColin Günther		val |= CSR_READ_2(sc, BWI_RF_DATA_LO);
259783c4cd1SColin Günther
260783c4cd1SColin Günther		manu = __SHIFTOUT(val, BWI_RFINFO_MANUFACT_MASK);
261783c4cd1SColin Günther		type = __SHIFTOUT(val, BWI_RFINFO_TYPE_MASK);
262783c4cd1SColin Günther		rev = __SHIFTOUT(val, BWI_RFINFO_REV_MASK);
263783c4cd1SColin Günther	}
264783c4cd1SColin Günther	device_printf(sc->sc_dev, "RF: manu 0x%03x, type 0x%04x, rev %u\n",
265783c4cd1SColin Günther		      manu, type, rev);
266783c4cd1SColin Günther
267783c4cd1SColin Günther	/*
268783c4cd1SColin Günther	 * Verify whether the RF is supported
269783c4cd1SColin Günther	 */
270783c4cd1SColin Günther	rf->rf_ctrl_rd = 0;
271783c4cd1SColin Günther	rf->rf_ctrl_adj = 0;
272783c4cd1SColin Günther	switch (phy->phy_mode) {
273783c4cd1SColin Günther	case IEEE80211_MODE_11A:
274783c4cd1SColin Günther		if (manu != BWI_RF_MANUFACT_BCM ||
275783c4cd1SColin Günther		    type != BWI_RF_T_BCM2060 ||
276783c4cd1SColin Günther		    rev != 1) {
277783c4cd1SColin Günther			device_printf(sc->sc_dev, "only BCM2060 rev 1 RF "
278783c4cd1SColin Günther				      "is supported for 11A PHY\n");
279783c4cd1SColin Günther			return ENXIO;
280783c4cd1SColin Günther		}
281783c4cd1SColin Günther		rf->rf_ctrl_rd = BWI_RF_CTRL_RD_11A;
282783c4cd1SColin Günther		rf->rf_on = bwi_rf_on_11a;
283783c4cd1SColin Günther		rf->rf_off = bwi_rf_off_11a;
284783c4cd1SColin Günther		rf->rf_calc_rssi = bwi_rf_calc_rssi_bcm2060;
285783c4cd1SColin Günther		rf->rf_calc_noise = bwi_rf_calc_noise_bcm2060;
286783c4cd1SColin Günther		break;
287783c4cd1SColin Günther	case IEEE80211_MODE_11B:
288783c4cd1SColin Günther		if (type == BWI_RF_T_BCM2050) {
289783c4cd1SColin Günther			rf->rf_ctrl_rd = BWI_RF_CTRL_RD_11BG;
290783c4cd1SColin Günther			rf->rf_calc_rssi = bwi_rf_calc_rssi_bcm2050;
291783c4cd1SColin Günther			rf->rf_calc_noise = bwi_rf_calc_noise_bcm2050;
292783c4cd1SColin Günther		} else if (type == BWI_RF_T_BCM2053) {
293783c4cd1SColin Günther			rf->rf_ctrl_adj = 1;
294783c4cd1SColin Günther			rf->rf_calc_rssi = bwi_rf_calc_rssi_bcm2053;
295783c4cd1SColin Günther			rf->rf_calc_noise = bwi_rf_calc_noise_bcm2053;
296783c4cd1SColin Günther		} else {
297783c4cd1SColin Günther			device_printf(sc->sc_dev, "only BCM2050/BCM2053 RF "
298783c4cd1SColin Günther				      "is supported for 11B PHY\n");
299783c4cd1SColin Günther			return ENXIO;
300783c4cd1SColin Günther		}
301783c4cd1SColin Günther		rf->rf_on = bwi_rf_on_11bg;
302783c4cd1SColin Günther		rf->rf_off = bwi_rf_off_11bg;
303783c4cd1SColin Günther		rf->rf_calc_nrssi_slope = bwi_rf_calc_nrssi_slope_11b;
304783c4cd1SColin Günther		rf->rf_set_nrssi_thr = bwi_rf_set_nrssi_thr_11b;
305783c4cd1SColin Günther		if (phy->phy_rev == 6)
306783c4cd1SColin Günther			rf->rf_lo_update = bwi_rf_lo_update_11g;
307783c4cd1SColin Günther		else
308783c4cd1SColin Günther			rf->rf_lo_update = bwi_rf_lo_update_11b;
309783c4cd1SColin Günther		break;
310783c4cd1SColin Günther	case IEEE80211_MODE_11G:
311783c4cd1SColin Günther		if (type != BWI_RF_T_BCM2050) {
312783c4cd1SColin Günther			device_printf(sc->sc_dev, "only BCM2050 RF "
313783c4cd1SColin Günther				      "is supported for 11G PHY\n");
314783c4cd1SColin Günther			return ENXIO;
315783c4cd1SColin Günther		}
316783c4cd1SColin Günther		rf->rf_ctrl_rd = BWI_RF_CTRL_RD_11BG;
317783c4cd1SColin Günther		rf->rf_on = bwi_rf_on_11bg;
318783c4cd1SColin Günther		if (mac->mac_rev >= 5)
319783c4cd1SColin Günther			rf->rf_off = bwi_rf_off_11g_rev5;
320783c4cd1SColin Günther		else
321783c4cd1SColin Günther			rf->rf_off = bwi_rf_off_11bg;
322783c4cd1SColin Günther		rf->rf_calc_nrssi_slope = bwi_rf_calc_nrssi_slope_11g;
323783c4cd1SColin Günther		rf->rf_set_nrssi_thr = bwi_rf_set_nrssi_thr_11g;
324783c4cd1SColin Günther		rf->rf_calc_rssi = bwi_rf_calc_rssi_bcm2050;
325783c4cd1SColin Günther		rf->rf_calc_noise = bwi_rf_calc_noise_bcm2050;
326783c4cd1SColin Günther		rf->rf_lo_update = bwi_rf_lo_update_11g;
327783c4cd1SColin Günther		break;
328783c4cd1SColin Günther	default:
329783c4cd1SColin Günther		device_printf(sc->sc_dev, "unsupported PHY mode\n");
330783c4cd1SColin Günther		return ENXIO;
331783c4cd1SColin Günther	}
332783c4cd1SColin Günther
333783c4cd1SColin Günther	rf->rf_type = type;
334783c4cd1SColin Günther	rf->rf_rev = rev;
335783c4cd1SColin Günther	rf->rf_manu = manu;
336783c4cd1SColin Günther	rf->rf_curchan = IEEE80211_CHAN_ANY;
337783c4cd1SColin Günther	rf->rf_ant_mode = BWI_ANT_MODE_AUTO;
338783c4cd1SColin Günther	return 0;
339783c4cd1SColin Günther}
340783c4cd1SColin Günther
341783c4cd1SColin Günthervoid
342783c4cd1SColin Güntherbwi_rf_set_chan(struct bwi_mac *mac, u_int chan, int work_around)
343783c4cd1SColin Günther{
344783c4cd1SColin Günther	struct bwi_softc *sc = mac->mac_sc;
345783c4cd1SColin Günther
346783c4cd1SColin Günther	if (chan == IEEE80211_CHAN_ANY)
347783c4cd1SColin Günther		return;
348783c4cd1SColin Günther
349783c4cd1SColin Günther	MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_CHAN, chan);
350783c4cd1SColin Günther
351783c4cd1SColin Günther	/* TODO: 11A */
352783c4cd1SColin Günther
353783c4cd1SColin Günther	if (work_around)
354783c4cd1SColin Günther		bwi_rf_work_around(mac, chan);
355783c4cd1SColin Günther
356783c4cd1SColin Günther	CSR_WRITE_2(sc, BWI_RF_CHAN, BWI_RF_2GHZ_CHAN(chan));
357783c4cd1SColin Günther
358783c4cd1SColin Günther	if (chan == 14) {
359783c4cd1SColin Günther		if (sc->sc_locale == BWI_SPROM_LOCALE_JAPAN)
360783c4cd1SColin Günther			HFLAGS_CLRBITS(mac, BWI_HFLAG_NOT_JAPAN);
361783c4cd1SColin Günther		else
362783c4cd1SColin Günther			HFLAGS_SETBITS(mac, BWI_HFLAG_NOT_JAPAN);
363783c4cd1SColin Günther		CSR_SETBITS_2(sc, BWI_RF_CHAN_EX, (1 << 11)); /* XXX */
364783c4cd1SColin Günther	} else {
365783c4cd1SColin Günther		CSR_CLRBITS_2(sc, BWI_RF_CHAN_EX, 0x840); /* XXX */
366783c4cd1SColin Günther	}
367783c4cd1SColin Günther	DELAY(8000);	/* DELAY(2000); */
368783c4cd1SColin Günther
369783c4cd1SColin Günther	mac->mac_rf.rf_curchan = chan;
370783c4cd1SColin Günther}
371783c4cd1SColin Günther
372783c4cd1SColin Günthervoid
373783c4cd1SColin Güntherbwi_rf_get_gains(struct bwi_mac *mac)
374783c4cd1SColin Günther{
375783c4cd1SColin Günther#define SAVE_PHY_MAX	15
376783c4cd1SColin Günther#define SAVE_RF_MAX	3
377783c4cd1SColin Günther
378783c4cd1SColin Günther	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
379783c4cd1SColin Günther	{ 0x52, 0x43, 0x7a };
380783c4cd1SColin Günther	static const uint16_t save_phy_regs[SAVE_PHY_MAX] = {
381783c4cd1SColin Günther		0x0429, 0x0001, 0x0811, 0x0812,
382783c4cd1SColin Günther		0x0814, 0x0815, 0x005a, 0x0059,
383783c4cd1SColin Günther		0x0058, 0x000a, 0x0003, 0x080f,
384783c4cd1SColin Günther		0x0810, 0x002b, 0x0015
385783c4cd1SColin Günther	};
386783c4cd1SColin Günther
387783c4cd1SColin Günther	struct bwi_softc *sc = mac->mac_sc;
388783c4cd1SColin Günther	struct bwi_phy *phy = &mac->mac_phy;
389783c4cd1SColin Günther	struct bwi_rf *rf = &mac->mac_rf;
390783c4cd1SColin Günther	uint16_t save_phy[SAVE_PHY_MAX];
391783c4cd1SColin Günther	uint16_t save_rf[SAVE_RF_MAX];
392783c4cd1SColin Günther	uint16_t trsw;
393783c4cd1SColin Günther	int i, j, loop1_max, loop1, loop2;
394783c4cd1SColin Günther
395783c4cd1SColin Günther	/*
396783c4cd1SColin Günther	 * Save PHY/RF registers for later restoration
397783c4cd1SColin Günther	 */
398783c4cd1SColin Günther	for (i = 0; i < SAVE_PHY_MAX; ++i)
399783c4cd1SColin Günther		save_phy[i] = PHY_READ(mac, save_phy_regs[i]);
400783c4cd1SColin Günther	PHY_READ(mac, 0x2d); /* dummy read */
401783c4cd1SColin Günther
402783c4cd1SColin Günther	for (i = 0; i < SAVE_RF_MAX; ++i)
403783c4cd1SColin Günther		save_rf[i] = RF_READ(mac, save_rf_regs[i]);
404783c4cd1SColin Günther
405783c4cd1SColin Günther	PHY_CLRBITS(mac, 0x429, 0xc000);
406783c4cd1SColin Günther	PHY_SETBITS(mac, 0x1, 0x8000);
407783c4cd1SColin Günther
408783c4cd1SColin Günther	PHY_SETBITS(mac, 0x811, 0x2);
409783c4cd1SColin Günther	PHY_CLRBITS(mac, 0x812, 0x2);
410783c4cd1SColin Günther	PHY_SETBITS(mac, 0x811, 0x1);
411783c4cd1SColin Günther	PHY_CLRBITS(mac, 0x812, 0x1);
412783c4cd1SColin Günther
413783c4cd1SColin Günther	PHY_SETBITS(mac, 0x814, 0x1);
414783c4cd1SColin Günther	PHY_CLRBITS(mac, 0x815, 0x1);
415783c4cd1SColin Günther	PHY_SETBITS(mac, 0x814, 0x2);
416783c4cd1SColin Günther	PHY_CLRBITS(mac, 0x815, 0x2);
417783c4cd1SColin Günther
418783c4cd1SColin Günther	PHY_SETBITS(mac, 0x811, 0xc);
419783c4cd1SColin Günther	PHY_SETBITS(mac, 0x812, 0xc);
420783c4cd1SColin Günther	PHY_SETBITS(mac, 0x811, 0x30);
421783c4cd1SColin Günther	PHY_FILT_SETBITS(mac, 0x812, 0xffcf, 0x10);
422783c4cd1SColin Günther
423783c4cd1SColin Günther	PHY_WRITE(mac, 0x5a, 0x780);
424783c4cd1SColin Günther	PHY_WRITE(mac, 0x59, 0xc810);
425783c4cd1SColin Günther	PHY_WRITE(mac, 0x58, 0xd);
426783c4cd1SColin Günther	PHY_SETBITS(mac, 0xa, 0x2000);
427783c4cd1SColin Günther
428783c4cd1SColin Günther	PHY_SETBITS(mac, 0x814, 0x4);
429783c4cd1SColin Günther	PHY_CLRBITS(mac, 0x815, 0x4);
430783c4cd1SColin Günther
431783c4cd1SColin Günther	PHY_FILT_SETBITS(mac, 0x3, 0xff9f, 0x40);
432783c4cd1SColin Günther
433783c4cd1SColin Günther	if (rf->rf_rev == 8) {
434783c4cd1SColin Günther		loop1_max = 15;
435783c4cd1SColin Günther		RF_WRITE(mac, 0x43, loop1_max);
436783c4cd1SColin Günther	} else {
437783c4cd1SColin Günther		loop1_max = 9;
438783c4cd1SColin Günther	    	RF_WRITE(mac, 0x52, 0x0);
439783c4cd1SColin Günther		RF_FILT_SETBITS(mac, 0x43, 0xfff0, loop1_max);
440783c4cd1SColin Günther	}
441783c4cd1SColin Günther
442783c4cd1SColin Günther	bwi_phy_set_bbp_atten(mac, 11);
443783c4cd1SColin Günther
444783c4cd1SColin Günther	if (phy->phy_rev >= 3)
445783c4cd1SColin Günther		PHY_WRITE(mac, 0x80f, 0xc020);
446783c4cd1SColin Günther	else
447783c4cd1SColin Günther		PHY_WRITE(mac, 0x80f, 0x8020);
448783c4cd1SColin Günther	PHY_WRITE(mac, 0x810, 0);
449783c4cd1SColin Günther
450783c4cd1SColin Günther	PHY_FILT_SETBITS(mac, 0x2b, 0xffc0, 0x1);
451783c4cd1SColin Günther	PHY_FILT_SETBITS(mac, 0x2b, 0xc0ff, 0x800);
452783c4cd1SColin Günther	PHY_SETBITS(mac, 0x811, 0x100);
453783c4cd1SColin Günther	PHY_CLRBITS(mac, 0x812, 0x3000);
454783c4cd1SColin Günther
455783c4cd1SColin Günther	if ((sc->sc_card_flags & BWI_CARD_F_EXT_LNA) &&
456783c4cd1SColin Günther	    phy->phy_rev >= 7) {
457783c4cd1SColin Günther		PHY_SETBITS(mac, 0x811, 0x800);
458783c4cd1SColin Günther		PHY_SETBITS(mac, 0x812, 0x8000);
459783c4cd1SColin Günther	}
460783c4cd1SColin Günther	RF_CLRBITS(mac, 0x7a, 0xff08);
461783c4cd1SColin Günther
462783c4cd1SColin Günther	/*
463783c4cd1SColin Günther	 * Find out 'loop1/loop2', which will be used to calculate
464783c4cd1SColin Günther	 * max loopback gain later
465783c4cd1SColin Günther	 */
466783c4cd1SColin Günther	j = 0;
467783c4cd1SColin Günther	for (i = 0; i < loop1_max; ++i) {
468783c4cd1SColin Günther		for (j = 0; j < 16; ++j) {
469783c4cd1SColin Günther			RF_WRITE(mac, 0x43, i);
470783c4cd1SColin Günther
471783c4cd1SColin Günther			if (bwi_rf_gain_max_reached(mac, j))
472783c4cd1SColin Günther				goto loop1_exit;
473783c4cd1SColin Günther		}
474783c4cd1SColin Günther	}
475783c4cd1SColin Güntherloop1_exit:
476783c4cd1SColin Günther	loop1 = i;
477783c4cd1SColin Günther	loop2 = j;
478783c4cd1SColin Günther
479783c4cd1SColin Günther	/*
480783c4cd1SColin Günther	 * Find out 'trsw', which will be used to calculate
481783c4cd1SColin Günther	 * TRSW(TX/RX switch) RX gain later
482783c4cd1SColin Günther	 */
483783c4cd1SColin Günther	if (loop2 >= 8) {
484783c4cd1SColin Günther		PHY_SETBITS(mac, 0x812, 0x30);
485783c4cd1SColin Günther		trsw = 0x1b;
486783c4cd1SColin Günther		for (i = loop2 - 8; i < 16; ++i) {
487783c4cd1SColin Günther			trsw -= 3;
488783c4cd1SColin Günther			if (bwi_rf_gain_max_reached(mac, i))
489783c4cd1SColin Günther				break;
490783c4cd1SColin Günther		}
491783c4cd1SColin Günther	} else {
492783c4cd1SColin Günther		trsw = 0x18;
493783c4cd1SColin Günther	}
494783c4cd1SColin Günther
495783c4cd1SColin Günther	/*
496783c4cd1SColin Günther	 * Restore saved PHY/RF registers
497783c4cd1SColin Günther	 */
498783c4cd1SColin Günther	/* First 4 saved PHY registers need special processing */
499783c4cd1SColin Günther	for (i = 4; i < SAVE_PHY_MAX; ++i)
500783c4cd1SColin Günther		PHY_WRITE(mac, save_phy_regs[i], save_phy[i]);
501783c4cd1SColin Günther
502783c4cd1SColin Günther	bwi_phy_set_bbp_atten(mac, mac->mac_tpctl.bbp_atten);
503783c4cd1SColin Günther
504783c4cd1SColin Günther	for (i = 0; i < SAVE_RF_MAX; ++i)
505783c4cd1SColin Günther		RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
506783c4cd1SColin Günther
507783c4cd1SColin Günther	PHY_WRITE(mac, save_phy_regs[2], save_phy[2] | 0x3);
508783c4cd1SColin Günther	DELAY(10);
509783c4cd1SColin Günther	PHY_WRITE(mac, save_phy_regs[2], save_phy[2]);
510783c4cd1SColin Günther	PHY_WRITE(mac, save_phy_regs[3], save_phy[3]);
511783c4cd1SColin Günther	PHY_WRITE(mac, save_phy_regs[0], save_phy[0]);
512783c4cd1SColin Günther	PHY_WRITE(mac, save_phy_regs[1], save_phy[1]);
513783c4cd1SColin Günther
514783c4cd1SColin Günther	/*
515783c4cd1SColin Günther	 * Calculate gains
516783c4cd1SColin Günther	 */
517783c4cd1SColin Günther	rf->rf_lo_gain = (loop2 * 6) - (loop1 * 4) - 11;
518