if_bwn.c revision 204437
1203945Sweongyo/*-
2203945Sweongyo * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
3203945Sweongyo * All rights reserved.
4203945Sweongyo *
5203945Sweongyo * Redistribution and use in source and binary forms, with or without
6203945Sweongyo * modification, are permitted provided that the following conditions
7203945Sweongyo * are met:
8203945Sweongyo * 1. Redistributions of source code must retain the above copyright
9203945Sweongyo *    notice, this list of conditions and the following disclaimer,
10203945Sweongyo *    without modification.
11203945Sweongyo * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12203945Sweongyo *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13203945Sweongyo *    redistribution must be conditioned upon including a substantially
14203945Sweongyo *    similar Disclaimer requirement for further binary redistribution.
15203945Sweongyo *
16203945Sweongyo * NO WARRANTY
17203945Sweongyo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18203945Sweongyo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19203945Sweongyo * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20203945Sweongyo * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21203945Sweongyo * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22203945Sweongyo * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23203945Sweongyo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24203945Sweongyo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25203945Sweongyo * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26203945Sweongyo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27203945Sweongyo * THE POSSIBILITY OF SUCH DAMAGES.
28203945Sweongyo */
29203945Sweongyo
30203945Sweongyo#include <sys/cdefs.h>
31203945Sweongyo__FBSDID("$FreeBSD: head/sys/dev/bwn/if_bwn.c 204437 2010-02-27 23:42:32Z weongyo $");
32203945Sweongyo
33203945Sweongyo/*
34203945Sweongyo * The Broadcom Wireless LAN controller driver.
35203945Sweongyo */
36203945Sweongyo
37203945Sweongyo#include <sys/param.h>
38203945Sweongyo#include <sys/systm.h>
39203945Sweongyo#include <sys/module.h>
40203945Sweongyo#include <sys/kernel.h>
41203945Sweongyo#include <sys/endian.h>
42203945Sweongyo#include <sys/errno.h>
43203945Sweongyo#include <sys/firmware.h>
44203945Sweongyo#include <sys/lock.h>
45203945Sweongyo#include <sys/mutex.h>
46203945Sweongyo#include <machine/bus.h>
47203945Sweongyo#include <machine/resource.h>
48203945Sweongyo#include <sys/bus.h>
49203945Sweongyo#include <sys/rman.h>
50203945Sweongyo#include <sys/socket.h>
51203945Sweongyo#include <sys/sockio.h>
52203945Sweongyo
53203945Sweongyo#include <net/ethernet.h>
54203945Sweongyo#include <net/if.h>
55203945Sweongyo#include <net/if_arp.h>
56203945Sweongyo#include <net/if_dl.h>
57203945Sweongyo#include <net/if_llc.h>
58203945Sweongyo#include <net/if_media.h>
59203945Sweongyo#include <net/if_types.h>
60203945Sweongyo
61203945Sweongyo#include <dev/pci/pcivar.h>
62203945Sweongyo#include <dev/pci/pcireg.h>
63203945Sweongyo#include <dev/siba/siba_ids.h>
64203945Sweongyo#include <dev/siba/sibareg.h>
65203945Sweongyo#include <dev/siba/sibavar.h>
66203945Sweongyo
67203945Sweongyo#include <net80211/ieee80211_var.h>
68203945Sweongyo#include <net80211/ieee80211_radiotap.h>
69203945Sweongyo#include <net80211/ieee80211_regdomain.h>
70203945Sweongyo#include <net80211/ieee80211_amrr.h>
71203945Sweongyo#include <net80211/ieee80211_phy.h>
72203945Sweongyo
73203945Sweongyo#include <dev/bwn/if_bwnreg.h>
74203945Sweongyo#include <dev/bwn/if_bwnvar.h>
75203945Sweongyo
76203945SweongyoSYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0, "Broadcom driver parameters");
77203945Sweongyo
78203945Sweongyo/*
79203945Sweongyo * Tunable & sysctl variables.
80203945Sweongyo */
81203945Sweongyo
82203945Sweongyo#ifdef BWN_DEBUG
83203945Sweongyostatic	int bwn_debug = 0;
84203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RW, &bwn_debug, 0,
85203945Sweongyo    "Broadcom debugging printfs");
86203945SweongyoTUNABLE_INT("hw.bwn.debug", &bwn_debug);
87203945Sweongyoenum {
88203945Sweongyo	BWN_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
89203945Sweongyo	BWN_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
90203945Sweongyo	BWN_DEBUG_STATE		= 0x00000004,	/* 802.11 state transitions */
91203945Sweongyo	BWN_DEBUG_TXPOW		= 0x00000008,	/* tx power processing */
92203945Sweongyo	BWN_DEBUG_RESET		= 0x00000010,	/* reset processing */
93203945Sweongyo	BWN_DEBUG_OPS		= 0x00000020,	/* bwn_ops processing */
94203945Sweongyo	BWN_DEBUG_BEACON	= 0x00000040,	/* beacon handling */
95203945Sweongyo	BWN_DEBUG_WATCHDOG	= 0x00000080,	/* watchdog timeout */
96203945Sweongyo	BWN_DEBUG_INTR		= 0x00000100,	/* ISR */
97203945Sweongyo	BWN_DEBUG_CALIBRATE	= 0x00000200,	/* periodic calibration */
98203945Sweongyo	BWN_DEBUG_NODE		= 0x00000400,	/* node management */
99203945Sweongyo	BWN_DEBUG_LED		= 0x00000800,	/* led management */
100203945Sweongyo	BWN_DEBUG_CMD		= 0x00001000,	/* cmd submission */
101203945Sweongyo	BWN_DEBUG_LO		= 0x00002000,	/* LO */
102203945Sweongyo	BWN_DEBUG_FW		= 0x00004000,	/* firmware */
103203945Sweongyo	BWN_DEBUG_WME		= 0x00008000,	/* WME */
104203945Sweongyo	BWN_DEBUG_RF		= 0x00010000,	/* RF */
105203945Sweongyo	BWN_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
106203945Sweongyo	BWN_DEBUG_ANY		= 0xffffffff
107203945Sweongyo};
108203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do {			\
109203945Sweongyo	if (sc->sc_debug & (m))				\
110203945Sweongyo		printf(fmt, __VA_ARGS__);		\
111203945Sweongyo} while (0)
112203945Sweongyo#else
113203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
114203945Sweongyo#endif
115203945Sweongyo
116203945Sweongyostatic int	bwn_bfp = 0;		/* use "Bad Frames Preemption" */
117203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
118203945Sweongyo    "uses Bad Frames Preemption");
119203945Sweongyostatic int	bwn_bluetooth = 1;
120203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
121203945Sweongyo    "turns on Bluetooth Coexistence");
122203945Sweongyostatic int	bwn_hwpctl = 0;
123203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
124203945Sweongyo    "uses H/W power control");
125203945Sweongyostatic int	bwn_msi_disable = 0;		/* MSI disabled  */
126203945SweongyoTUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable);
127203945Sweongyostatic int	bwn_usedma = 1;
128203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
129203945Sweongyo    "uses DMA");
130203945SweongyoTUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
131203945Sweongyostatic int	bwn_wme = 1;
132203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
133203945Sweongyo    "uses WME support");
134203945Sweongyo
135203945Sweongyostatic int	bwn_attach_pre(struct bwn_softc *);
136203945Sweongyostatic int	bwn_attach_post(struct bwn_softc *);
137203945Sweongyostatic void	bwn_sprom_bugfixes(struct siba_softc *);
138203945Sweongyostatic void	bwn_init(void *);
139203945Sweongyostatic int	bwn_init_locked(struct bwn_softc *);
140203945Sweongyostatic int	bwn_ioctl(struct ifnet *, u_long, caddr_t);
141203945Sweongyostatic void	bwn_start(struct ifnet *);
142203945Sweongyostatic int	bwn_attach_core(struct bwn_mac *);
143203945Sweongyostatic void	bwn_reset_core(struct bwn_mac *, uint32_t);
144203945Sweongyostatic int	bwn_phy_getinfo(struct bwn_mac *, int);
145203945Sweongyostatic int	bwn_chiptest(struct bwn_mac *);
146203945Sweongyostatic int	bwn_setup_channels(struct bwn_mac *, int, int);
147203945Sweongyostatic int	bwn_phy_g_attach(struct bwn_mac *);
148203945Sweongyostatic void	bwn_phy_g_detach(struct bwn_mac *);
149203945Sweongyostatic void	bwn_phy_g_init_pre(struct bwn_mac *);
150203945Sweongyostatic int	bwn_phy_g_prepare_hw(struct bwn_mac *);
151203945Sweongyostatic int	bwn_phy_g_init(struct bwn_mac *);
152203945Sweongyostatic void	bwn_phy_g_exit(struct bwn_mac *);
153203945Sweongyostatic uint16_t	bwn_phy_g_read(struct bwn_mac *, uint16_t);
154203945Sweongyostatic void	bwn_phy_g_write(struct bwn_mac *, uint16_t,
155203945Sweongyo		    uint16_t);
156203945Sweongyostatic uint16_t	bwn_phy_g_rf_read(struct bwn_mac *, uint16_t);
157203945Sweongyostatic void	bwn_phy_g_rf_write(struct bwn_mac *, uint16_t,
158203945Sweongyo		    uint16_t);
159203945Sweongyostatic int	bwn_phy_g_hwpctl(struct bwn_mac *);
160203945Sweongyostatic void	bwn_phy_g_rf_onoff(struct bwn_mac *, int);
161203945Sweongyostatic int	bwn_phy_g_switch_channel(struct bwn_mac *, uint32_t);
162203945Sweongyostatic uint32_t	bwn_phy_g_get_default_chan(struct bwn_mac *);
163203945Sweongyostatic void	bwn_phy_g_set_antenna(struct bwn_mac *, int);
164203945Sweongyostatic int	bwn_phy_g_im(struct bwn_mac *, int);
165203945Sweongyostatic int	bwn_phy_g_recalc_txpwr(struct bwn_mac *, int);
166203945Sweongyostatic void	bwn_phy_g_set_txpwr(struct bwn_mac *);
167203945Sweongyostatic void	bwn_phy_g_task_15s(struct bwn_mac *);
168203945Sweongyostatic void	bwn_phy_g_task_60s(struct bwn_mac *);
169203945Sweongyostatic uint16_t	bwn_phy_g_txctl(struct bwn_mac *);
170203945Sweongyostatic void	bwn_phy_switch_analog(struct bwn_mac *, int);
171203945Sweongyostatic uint16_t	bwn_shm_read_2(struct bwn_mac *, uint16_t, uint16_t);
172203945Sweongyostatic void	bwn_shm_write_2(struct bwn_mac *, uint16_t, uint16_t,
173203945Sweongyo		    uint16_t);
174203945Sweongyostatic uint32_t	bwn_shm_read_4(struct bwn_mac *, uint16_t, uint16_t);
175203945Sweongyostatic void	bwn_shm_write_4(struct bwn_mac *, uint16_t, uint16_t,
176203945Sweongyo		    uint32_t);
177203945Sweongyostatic void	bwn_shm_ctlword(struct bwn_mac *, uint16_t,
178203945Sweongyo		    uint16_t);
179203945Sweongyostatic void	bwn_addchannels(struct ieee80211_channel [], int, int *,
180203945Sweongyo		    const struct bwn_channelinfo *, int);
181203945Sweongyostatic int	bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
182203945Sweongyo		    const struct ieee80211_bpf_params *);
183203945Sweongyostatic void	bwn_newassoc(struct ieee80211_node *, int);
184203945Sweongyostatic void	bwn_updateslot(struct ifnet *);
185203945Sweongyostatic void	bwn_update_promisc(struct ifnet *);
186203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
187203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
188203945Sweongyostatic struct ieee80211_node *bwn_node_alloc(struct ieee80211vap *,
189203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
190203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
191203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
192203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
193203945Sweongyo		    const struct wmeParams *, uint16_t);
194203945Sweongyostatic void	bwn_node_cleanup(struct ieee80211_node *);
195203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
196203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
197203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
198203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
199203945Sweongyo		    const char [IFNAMSIZ], int, int,
200203945Sweongyo		    int, const uint8_t [IEEE80211_ADDR_LEN],
201203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
202203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
203203945Sweongyostatic void	bwn_stop(struct bwn_softc *, int);
204203945Sweongyostatic void	bwn_stop_locked(struct bwn_softc *, int);
205203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
206203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
207203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
208203945Sweongyostatic void	bwn_fix_imcfglobug(struct bwn_mac *);
209203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
210203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
211203945Sweongyostatic uint64_t	bwn_hf_read(struct bwn_mac *);
212203945Sweongyostatic void	bwn_hf_write(struct bwn_mac *, uint64_t);
213203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
214203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
215203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
216203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
217203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
218203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
219203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
220203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
221203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
222203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
223203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
224203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
225203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
226203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
227203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
228203945Sweongyostatic void	bwn_gpio_cleanup(struct bwn_mac *);
229203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
230203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
231203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
232203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
233203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
234203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
235203945Sweongyo		    int);
236203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
237203945Sweongyo		    struct bwn_pio_rxqueue *, int);
238203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
239203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
240203945Sweongyo		    uint16_t);
241203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
242203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
243203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
244203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
245203945Sweongyo		    const struct bwn_txstatus *);
246203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
247203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
248203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
249203945Sweongyo		    uint16_t);
250203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
251203945Sweongyo		    uint32_t);
252203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
253203945Sweongyo		    struct mbuf *);
254203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
255203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
256203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
257203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
258203945Sweongyo		    uint16_t, uint32_t);
259203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
260203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
261203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
262203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
263203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
264203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
265203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
266203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
267203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
268203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
269203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
270203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
271203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
272203945Sweongyo		    int, struct bwn_dmadesc_generic **,
273203945Sweongyo		    struct bwn_dmadesc_meta **);
274203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
275203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
276203945Sweongyo		    int, int);
277203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
278203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
279203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
280203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
281203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
282203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
283203945Sweongyo		    int, struct bwn_dmadesc_generic **,
284203945Sweongyo		    struct bwn_dmadesc_meta **);
285203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
286203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
287203945Sweongyo		    int, int);
288203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
289203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
290203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
291203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
292203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
293203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
294203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
295203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
296203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
297203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
298203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
299203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
300203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
301203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
302203945Sweongyo		    struct bwn_dmadesc_meta *);
303203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
304203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
305203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
306203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
307203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
308203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
309203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
310203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
311203945Sweongyo		    int);
312203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
313203945Sweongyo		    bus_size_t, int);
314203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
315203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
316203945Sweongyo		    const struct bwn_txstatus *);
317203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
318203945Sweongyo		    struct mbuf *);
319203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
320203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
321203945Sweongyo		    uint8_t);
322203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
323203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
324203945Sweongyo		    int, int, int);
325203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
326203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
327203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
328203945Sweongyostatic void	bwn_phy_g_init_sub(struct bwn_mac *);
329203945Sweongyostatic uint8_t	bwn_has_hwpctl(struct bwn_mac *);
330203945Sweongyostatic void	bwn_phy_init_b5(struct bwn_mac *);
331203945Sweongyostatic void	bwn_phy_init_b6(struct bwn_mac *);
332203945Sweongyostatic void	bwn_phy_init_a(struct bwn_mac *);
333203945Sweongyostatic void	bwn_loopback_calcgain(struct bwn_mac *);
334203945Sweongyostatic uint16_t	bwn_rf_init_bcm2050(struct bwn_mac *);
335203945Sweongyostatic void	bwn_lo_g_init(struct bwn_mac *);
336203945Sweongyostatic void	bwn_lo_g_adjust(struct bwn_mac *);
337203945Sweongyostatic void	bwn_lo_get_powervector(struct bwn_mac *);
338203945Sweongyostatic struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
339203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *);
340203945Sweongyostatic void	bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
341203945Sweongyostatic void	bwn_phy_hwpctl_init(struct bwn_mac *);
342203945Sweongyostatic void	bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
343203945Sweongyostatic void	bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
344203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *,
345203945Sweongyo		    uint8_t);
346203945Sweongyostatic void	bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
347203945Sweongyostatic uint16_t	bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
348203945Sweongyostatic void	bwn_spu_workaround(struct bwn_mac *, uint8_t);
349203945Sweongyostatic void	bwn_wa_init(struct bwn_mac *);
350203945Sweongyostatic void	bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
351203945Sweongyo		    uint16_t);
352203945Sweongyostatic void	bwn_dummy_transmission(struct bwn_mac *, int, int);
353203945Sweongyostatic void	bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
354203945Sweongyo		    uint32_t);
355203945Sweongyostatic void	bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
356203945Sweongyo		    uint16_t);
357203945Sweongyostatic void	bwn_ram_write(struct bwn_mac *, uint16_t, uint32_t);
358203945Sweongyostatic void	bwn_mac_suspend(struct bwn_mac *);
359203945Sweongyostatic void	bwn_mac_enable(struct bwn_mac *);
360203945Sweongyostatic void	bwn_psctl(struct bwn_mac *, uint32_t);
361203945Sweongyostatic int16_t	bwn_nrssi_read(struct bwn_mac *, uint16_t);
362203945Sweongyostatic void	bwn_nrssi_offset(struct bwn_mac *);
363203945Sweongyostatic void	bwn_nrssi_threshold(struct bwn_mac *);
364203945Sweongyostatic void	bwn_nrssi_slope_11g(struct bwn_mac *);
365203945Sweongyostatic void	bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
366203945Sweongyo		    int16_t);
367203945Sweongyostatic void	bwn_set_original_gains(struct bwn_mac *);
368203945Sweongyostatic void	bwn_hwpctl_early_init(struct bwn_mac *);
369203945Sweongyostatic void	bwn_hwpctl_init_gphy(struct bwn_mac *);
370203945Sweongyostatic uint16_t	bwn_phy_g_chan2freq(uint8_t);
371203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
372203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
373203945Sweongyo		    const char *, struct bwn_fwfile *);
374203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
375203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
376203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
377203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
378203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
379203945Sweongyostatic int	bwn_switch_channel(struct bwn_mac *, int);
380203945Sweongyostatic uint16_t	bwn_ant2phy(int);
381203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
382203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
383203945Sweongyo		    const uint8_t *);
384203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
385203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
386203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
387203945Sweongyo		    const uint8_t *);
388203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
389203945Sweongyo		    const uint8_t *);
390203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
391203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
392203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
393203945Sweongyo		    struct ieee80211_channel *);
394203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
395203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
396203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
397203945Sweongyostatic int	bwn_intr(void *);
398203945Sweongyostatic void	bwn_intrtask(void *, int);
399203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
400203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
401203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
402203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
403203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
404203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
405203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
406203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
407203945Sweongyostatic void	bwn_hwreset(void *, int);
408203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
409203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
410203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
411203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
412203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
413203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
414203945Sweongyo		    const struct bwn_txstatus *);
415203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
416203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
417203945Sweongyostatic void	bwn_start_locked(struct ifnet *);
418203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
419203945Sweongyo		    struct mbuf *);
420203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
421203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
422203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
423203945Sweongyo		    uint16_t);
424203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
425203945Sweongyo		    const uint8_t);
426203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
427203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
428203945Sweongyostatic int	bwn_phy_shm_tssi_read(struct bwn_mac *, uint16_t);
429203945Sweongyostatic void	bwn_phy_g_setatt(struct bwn_mac *, int *, int *);
430203945Sweongyostatic void	bwn_phy_lock(struct bwn_mac *);
431203945Sweongyostatic void	bwn_phy_unlock(struct bwn_mac *);
432203945Sweongyostatic void	bwn_rf_lock(struct bwn_mac *);
433203945Sweongyostatic void	bwn_rf_unlock(struct bwn_mac *);
434203945Sweongyostatic void	bwn_txpwr(void *, int);
435203945Sweongyostatic void	bwn_tasks(void *);
436203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
437203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
438203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
439203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
440203945Sweongyo		    uint8_t);
441203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
442203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
443203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
444203945Sweongyo		    int, int);
445203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
446203945Sweongyostatic void	bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
447203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
448203945Sweongyostatic void	bwn_watchdog(void *);
449203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
450203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
451203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
452203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
453203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
454203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
455203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
456203945Sweongyostatic void	bwn_led_blink_next(void *);
457203945Sweongyostatic void	bwn_led_blink_end(void *);
458203945Sweongyostatic void	bwn_rfswitch(void *);
459203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
460203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
461203945Sweongyostatic void	bwn_phy_lp_init_pre(struct bwn_mac *);
462203945Sweongyostatic int	bwn_phy_lp_init(struct bwn_mac *);
463203945Sweongyostatic uint16_t	bwn_phy_lp_read(struct bwn_mac *, uint16_t);
464203945Sweongyostatic void	bwn_phy_lp_write(struct bwn_mac *, uint16_t, uint16_t);
465203945Sweongyostatic void	bwn_phy_lp_maskset(struct bwn_mac *, uint16_t, uint16_t,
466203945Sweongyo		    uint16_t);
467203945Sweongyostatic uint16_t	bwn_phy_lp_rf_read(struct bwn_mac *, uint16_t);
468203945Sweongyostatic void	bwn_phy_lp_rf_write(struct bwn_mac *, uint16_t, uint16_t);
469203945Sweongyostatic void	bwn_phy_lp_rf_onoff(struct bwn_mac *, int);
470203945Sweongyostatic int	bwn_phy_lp_switch_channel(struct bwn_mac *, uint32_t);
471203945Sweongyostatic uint32_t	bwn_phy_lp_get_default_chan(struct bwn_mac *);
472203945Sweongyostatic void	bwn_phy_lp_set_antenna(struct bwn_mac *, int);
473203945Sweongyostatic void	bwn_phy_lp_task_60s(struct bwn_mac *);
474203945Sweongyostatic void	bwn_phy_lp_readsprom(struct bwn_mac *);
475203945Sweongyostatic void	bwn_phy_lp_bbinit(struct bwn_mac *);
476203945Sweongyostatic void	bwn_phy_lp_txpctl_init(struct bwn_mac *);
477203945Sweongyostatic void	bwn_phy_lp_calib(struct bwn_mac *);
478203945Sweongyostatic void	bwn_phy_lp_switch_analog(struct bwn_mac *, int);
479203945Sweongyostatic int	bwn_phy_lp_b2062_switch_channel(struct bwn_mac *, uint8_t);
480203945Sweongyostatic int	bwn_phy_lp_b2063_switch_channel(struct bwn_mac *, uint8_t);
481203945Sweongyostatic void	bwn_phy_lp_set_anafilter(struct bwn_mac *, uint8_t);
482203945Sweongyostatic void	bwn_phy_lp_set_gaintbl(struct bwn_mac *, uint32_t);
483203945Sweongyostatic void	bwn_phy_lp_digflt_save(struct bwn_mac *);
484203945Sweongyostatic void	bwn_phy_lp_get_txpctlmode(struct bwn_mac *);
485203945Sweongyostatic void	bwn_phy_lp_set_txpctlmode(struct bwn_mac *, uint8_t);
486203945Sweongyostatic void	bwn_phy_lp_bugfix(struct bwn_mac *);
487203945Sweongyostatic void	bwn_phy_lp_digflt_restore(struct bwn_mac *);
488203945Sweongyostatic void	bwn_phy_lp_tblinit(struct bwn_mac *);
489203945Sweongyostatic void	bwn_phy_lp_bbinit_r2(struct bwn_mac *);
490203945Sweongyostatic void	bwn_phy_lp_bbinit_r01(struct bwn_mac *);
491203945Sweongyostatic void	bwn_phy_lp_b2062_init(struct bwn_mac *);
492203945Sweongyostatic void	bwn_phy_lp_b2063_init(struct bwn_mac *);
493203945Sweongyostatic void	bwn_phy_lp_rxcal_r2(struct bwn_mac *);
494203945Sweongyostatic void	bwn_phy_lp_rccal_r12(struct bwn_mac *);
495203945Sweongyostatic void	bwn_phy_lp_set_rccap(struct bwn_mac *);
496203945Sweongyostatic uint32_t	bwn_phy_lp_roundup(uint32_t, uint32_t, uint8_t);
497203945Sweongyostatic void	bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *);
498203945Sweongyostatic void	bwn_phy_lp_b2062_vco_calib(struct bwn_mac *);
499203945Sweongyostatic void	bwn_tab_write_multi(struct bwn_mac *, uint32_t, int,
500203945Sweongyo		    const void *);
501203945Sweongyostatic void	bwn_tab_read_multi(struct bwn_mac *, uint32_t, int, void *);
502203945Sweongyostatic struct bwn_txgain
503203945Sweongyo		bwn_phy_lp_get_txgain(struct bwn_mac *);
504203945Sweongyostatic uint8_t	bwn_phy_lp_get_bbmult(struct bwn_mac *);
505203945Sweongyostatic void	bwn_phy_lp_set_txgain(struct bwn_mac *, struct bwn_txgain *);
506203945Sweongyostatic void	bwn_phy_lp_set_bbmult(struct bwn_mac *, uint8_t);
507203945Sweongyostatic void	bwn_phy_lp_set_trsw_over(struct bwn_mac *, uint8_t, uint8_t);
508203945Sweongyostatic void	bwn_phy_lp_set_rxgain(struct bwn_mac *, uint32_t);
509203945Sweongyostatic void	bwn_phy_lp_set_deaf(struct bwn_mac *, uint8_t);
510203945Sweongyostatic int	bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *, uint16_t);
511203945Sweongyostatic void	bwn_phy_lp_clear_deaf(struct bwn_mac *, uint8_t);
512203945Sweongyostatic void	bwn_phy_lp_tblinit_r01(struct bwn_mac *);
513203945Sweongyostatic void	bwn_phy_lp_tblinit_r2(struct bwn_mac *);
514203945Sweongyostatic void	bwn_phy_lp_tblinit_txgain(struct bwn_mac *);
515203945Sweongyostatic void	bwn_tab_write(struct bwn_mac *, uint32_t, uint32_t);
516203945Sweongyostatic void	bwn_phy_lp_b2062_tblinit(struct bwn_mac *);
517203945Sweongyostatic void	bwn_phy_lp_b2063_tblinit(struct bwn_mac *);
518203945Sweongyostatic int	bwn_phy_lp_loopback(struct bwn_mac *);
519203945Sweongyostatic void	bwn_phy_lp_set_rxgain_idx(struct bwn_mac *, uint16_t);
520203945Sweongyostatic void	bwn_phy_lp_ddfs_turnon(struct bwn_mac *, int, int, int, int,
521203945Sweongyo		    int);
522203945Sweongyostatic uint8_t	bwn_phy_lp_rx_iq_est(struct bwn_mac *, uint16_t, uint8_t,
523203945Sweongyo		    struct bwn_phy_lp_iq_est *);
524203945Sweongyostatic void	bwn_phy_lp_ddfs_turnoff(struct bwn_mac *);
525203945Sweongyostatic uint32_t	bwn_tab_read(struct bwn_mac *, uint32_t);
526203945Sweongyostatic void	bwn_phy_lp_set_txgain_dac(struct bwn_mac *, uint16_t);
527203945Sweongyostatic void	bwn_phy_lp_set_txgain_pa(struct bwn_mac *, uint16_t);
528203945Sweongyostatic void	bwn_phy_lp_set_txgain_override(struct bwn_mac *);
529203945Sweongyostatic uint16_t	bwn_phy_lp_get_pa_gain(struct bwn_mac *);
530203945Sweongyostatic uint8_t	bwn_nbits(int32_t);
531203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *, int, int,
532203945Sweongyo		    struct bwn_txgain_entry *);
533203945Sweongyostatic void	bwn_phy_lp_gaintbl_write(struct bwn_mac *, int,
534203945Sweongyo		    struct bwn_txgain_entry);
535203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
536203945Sweongyo		    struct bwn_txgain_entry);
537203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
538203945Sweongyo		    struct bwn_txgain_entry);
539204257Sweongyostatic void	bwn_sysctl_node(struct bwn_softc *);
540203945Sweongyo
541203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
542203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
543203945Sweongyo	{ -1,			0,		0 }
544203945Sweongyo};
545203945Sweongyo
546203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
547203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
548203945Sweongyo	{ -1,			0,		0 }
549203945Sweongyo};
550203945Sweongyo
551203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
552203945Sweongyo	.channels = {
553203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
554203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
555203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
556203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
557203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
558203945Sweongyo	.nchannels = 14
559203945Sweongyo};
560203945Sweongyo
561203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
562203945Sweongyo	.channels = {
563203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
564203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
565203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
566203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
567203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
568203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
569203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
570203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
571203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
572203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
573203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
574203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
575203945Sweongyo		{ 6080, 216, 30 } },
576203945Sweongyo	.nchannels = 37
577203945Sweongyo};
578203945Sweongyo
579203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
580203945Sweongyo	.channels = {
581203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
582203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
583203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
584203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
585203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
586203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
587203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
588203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
589203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
590203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
591203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
592203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
593203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
594203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
595203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
596203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
597203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
598203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
599203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
600203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
601203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
602203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
603203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
604203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
605203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
606203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
607203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
608203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
609203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
610203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
611203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
612203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
613203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
614203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
615203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
616203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
617203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
618203945Sweongyo	.nchannels = 110
619203945Sweongyo};
620203945Sweongyo
621203945Sweongyostatic const uint8_t bwn_b2063_chantable_data[33][12] = {
622203945Sweongyo	{ 0x6f, 0x3c, 0x3c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
623203945Sweongyo	{ 0x6f, 0x2c, 0x2c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
624203945Sweongyo	{ 0x6f, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
625203945Sweongyo	{ 0x6e, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
626203945Sweongyo	{ 0x6e, 0xc, 0xc, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
627203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x2, 0x5, 0xd, 0xd, 0x77, 0x80, 0x20, 0 },
628203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x5, 0xd, 0xc, 0x77, 0x80, 0x20, 0 },
629203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x80, 0x20, 0 },
630203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x70, 0x20, 0 },
631203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xb, 0xc, 0x77, 0x70, 0x20, 0 },
632203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x4, 0xb, 0xb, 0x77, 0x60, 0x20, 0 },
633203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xb, 0x77, 0x60, 0x20, 0 },
634203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xa, 0x77, 0x60, 0x20, 0 },
635203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x2, 0x9, 0x9, 0x77, 0x60, 0x20, 0 },
636203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x1, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
637203945Sweongyo	{ 0x67, 0xc, 0xc, 0, 0, 0, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
638203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x2, 0x1, 0x77, 0x20, 0, 0 },
639203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x1, 0x1, 0x77, 0x20, 0, 0 },
640203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0x1, 0, 0x77, 0x10, 0, 0 },
641203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
642203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
643203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
644203945Sweongyo	{ 0x61, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
645203945Sweongyo	{ 0x60, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
646203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xe, 0xf, 0xf, 0x77, 0xc0, 0x50, 0 },
647203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xd, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
648203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
649203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
650203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xb, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
651203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xa, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
652203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x7, 0x9, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
653203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x6, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
654203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x5, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 }
655203945Sweongyo};
656203945Sweongyo
657203945Sweongyostatic const struct bwn_b206x_chan bwn_b2063_chantable[] = {
658203945Sweongyo	{ 1, 2412, bwn_b2063_chantable_data[0] },
659203945Sweongyo	{ 2, 2417, bwn_b2063_chantable_data[0] },
660203945Sweongyo	{ 3, 2422, bwn_b2063_chantable_data[0] },
661203945Sweongyo	{ 4, 2427, bwn_b2063_chantable_data[1] },
662203945Sweongyo	{ 5, 2432, bwn_b2063_chantable_data[1] },
663203945Sweongyo	{ 6, 2437, bwn_b2063_chantable_data[1] },
664203945Sweongyo	{ 7, 2442, bwn_b2063_chantable_data[1] },
665203945Sweongyo	{ 8, 2447, bwn_b2063_chantable_data[1] },
666203945Sweongyo	{ 9, 2452, bwn_b2063_chantable_data[2] },
667203945Sweongyo	{ 10, 2457, bwn_b2063_chantable_data[2] },
668203945Sweongyo	{ 11, 2462, bwn_b2063_chantable_data[3] },
669203945Sweongyo	{ 12, 2467, bwn_b2063_chantable_data[3] },
670203945Sweongyo	{ 13, 2472, bwn_b2063_chantable_data[3] },
671203945Sweongyo	{ 14, 2484, bwn_b2063_chantable_data[4] },
672203945Sweongyo	{ 34, 5170, bwn_b2063_chantable_data[5] },
673203945Sweongyo	{ 36, 5180, bwn_b2063_chantable_data[6] },
674203945Sweongyo	{ 38, 5190, bwn_b2063_chantable_data[7] },
675203945Sweongyo	{ 40, 5200, bwn_b2063_chantable_data[8] },
676203945Sweongyo	{ 42, 5210, bwn_b2063_chantable_data[9] },
677203945Sweongyo	{ 44, 5220, bwn_b2063_chantable_data[10] },
678203945Sweongyo	{ 46, 5230, bwn_b2063_chantable_data[11] },
679203945Sweongyo	{ 48, 5240, bwn_b2063_chantable_data[12] },
680203945Sweongyo	{ 52, 5260, bwn_b2063_chantable_data[13] },
681203945Sweongyo	{ 56, 5280, bwn_b2063_chantable_data[14] },
682203945Sweongyo	{ 60, 5300, bwn_b2063_chantable_data[14] },
683203945Sweongyo	{ 64, 5320, bwn_b2063_chantable_data[15] },
684203945Sweongyo	{ 100, 5500, bwn_b2063_chantable_data[16] },
685203945Sweongyo	{ 104, 5520, bwn_b2063_chantable_data[17] },
686203945Sweongyo	{ 108, 5540, bwn_b2063_chantable_data[18] },
687203945Sweongyo	{ 112, 5560, bwn_b2063_chantable_data[19] },
688203945Sweongyo	{ 116, 5580, bwn_b2063_chantable_data[20] },
689203945Sweongyo	{ 120, 5600, bwn_b2063_chantable_data[21] },
690203945Sweongyo	{ 124, 5620, bwn_b2063_chantable_data[21] },
691203945Sweongyo	{ 128, 5640, bwn_b2063_chantable_data[22] },
692203945Sweongyo	{ 132, 5660, bwn_b2063_chantable_data[22] },
693203945Sweongyo	{ 136, 5680, bwn_b2063_chantable_data[22] },
694203945Sweongyo	{ 140, 5700, bwn_b2063_chantable_data[23] },
695203945Sweongyo	{ 149, 5745, bwn_b2063_chantable_data[23] },
696203945Sweongyo	{ 153, 5765, bwn_b2063_chantable_data[23] },
697203945Sweongyo	{ 157, 5785, bwn_b2063_chantable_data[23] },
698203945Sweongyo	{ 161, 5805, bwn_b2063_chantable_data[23] },
699203945Sweongyo	{ 165, 5825, bwn_b2063_chantable_data[23] },
700203945Sweongyo	{ 184, 4920, bwn_b2063_chantable_data[24] },
701203945Sweongyo	{ 188, 4940, bwn_b2063_chantable_data[25] },
702203945Sweongyo	{ 192, 4960, bwn_b2063_chantable_data[26] },
703203945Sweongyo	{ 196, 4980, bwn_b2063_chantable_data[27] },
704203945Sweongyo	{ 200, 5000, bwn_b2063_chantable_data[28] },
705203945Sweongyo	{ 204, 5020, bwn_b2063_chantable_data[29] },
706203945Sweongyo	{ 208, 5040, bwn_b2063_chantable_data[30] },
707203945Sweongyo	{ 212, 5060, bwn_b2063_chantable_data[31] },
708203945Sweongyo	{ 216, 5080, bwn_b2063_chantable_data[32] }
709203945Sweongyo};
710203945Sweongyo
711203945Sweongyostatic const uint8_t bwn_b2062_chantable_data[22][12] = {
712203945Sweongyo	{ 0xff, 0xff, 0xb5, 0x1b, 0x24, 0x32, 0x32, 0x88, 0x88, 0, 0, 0 },
713203945Sweongyo	{ 0, 0x22, 0x20, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
714203945Sweongyo	{ 0, 0x11, 0x10, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
715203945Sweongyo	{ 0, 0, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
716203945Sweongyo	{ 0, 0x11, 0x20, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
717203945Sweongyo	{ 0, 0x11, 0x10, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
718203945Sweongyo	{ 0, 0x11, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
719203945Sweongyo	{ 0, 0, 0, 0x63, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
720203945Sweongyo	{ 0, 0, 0, 0x62, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
721203945Sweongyo	{ 0, 0, 0, 0x30, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
722203945Sweongyo	{ 0, 0, 0, 0x20, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
723203945Sweongyo	{ 0, 0, 0, 0x10, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
724203945Sweongyo	{ 0, 0, 0, 0, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
725203945Sweongyo	{ 0x55, 0x77, 0x90, 0xf7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
726203945Sweongyo	{ 0x44, 0x77, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
727203945Sweongyo	{ 0x44, 0x66, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
728203945Sweongyo	{ 0x33, 0x66, 0x70, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
729203945Sweongyo	{ 0x22, 0x55, 0x60, 0xd7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
730203945Sweongyo	{ 0x22, 0x55, 0x60, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
731203945Sweongyo	{ 0x22, 0x44, 0x50, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
732203945Sweongyo	{ 0x11, 0x44, 0x50, 0xa5, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
733203945Sweongyo	{ 0, 0x44, 0x40, 0xb6, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 }
734203945Sweongyo};
735203945Sweongyo
736203945Sweongyostatic const struct bwn_b206x_chan bwn_b2062_chantable[] = {
737203945Sweongyo	{ 1, 2412, bwn_b2062_chantable_data[0] },
738203945Sweongyo	{ 2, 2417, bwn_b2062_chantable_data[0] },
739203945Sweongyo	{ 3, 2422, bwn_b2062_chantable_data[0] },
740203945Sweongyo	{ 4, 2427, bwn_b2062_chantable_data[0] },
741203945Sweongyo	{ 5, 2432, bwn_b2062_chantable_data[0] },
742203945Sweongyo	{ 6, 2437, bwn_b2062_chantable_data[0] },
743203945Sweongyo	{ 7, 2442, bwn_b2062_chantable_data[0] },
744203945Sweongyo	{ 8, 2447, bwn_b2062_chantable_data[0] },
745203945Sweongyo	{ 9, 2452, bwn_b2062_chantable_data[0] },
746203945Sweongyo	{ 10, 2457, bwn_b2062_chantable_data[0] },
747203945Sweongyo	{ 11, 2462, bwn_b2062_chantable_data[0] },
748203945Sweongyo	{ 12, 2467, bwn_b2062_chantable_data[0] },
749203945Sweongyo	{ 13, 2472, bwn_b2062_chantable_data[0] },
750203945Sweongyo	{ 14, 2484, bwn_b2062_chantable_data[0] },
751203945Sweongyo	{ 34, 5170, bwn_b2062_chantable_data[1] },
752203945Sweongyo	{ 38, 5190, bwn_b2062_chantable_data[2] },
753203945Sweongyo	{ 42, 5210, bwn_b2062_chantable_data[2] },
754203945Sweongyo	{ 46, 5230, bwn_b2062_chantable_data[3] },
755203945Sweongyo	{ 36, 5180, bwn_b2062_chantable_data[4] },
756203945Sweongyo	{ 40, 5200, bwn_b2062_chantable_data[5] },
757203945Sweongyo	{ 44, 5220, bwn_b2062_chantable_data[6] },
758203945Sweongyo	{ 48, 5240, bwn_b2062_chantable_data[3] },
759203945Sweongyo	{ 52, 5260, bwn_b2062_chantable_data[3] },
760203945Sweongyo	{ 56, 5280, bwn_b2062_chantable_data[3] },
761203945Sweongyo	{ 60, 5300, bwn_b2062_chantable_data[7] },
762203945Sweongyo	{ 64, 5320, bwn_b2062_chantable_data[8] },
763203945Sweongyo	{ 100, 5500, bwn_b2062_chantable_data[9] },
764203945Sweongyo	{ 104, 5520, bwn_b2062_chantable_data[10] },
765203945Sweongyo	{ 108, 5540, bwn_b2062_chantable_data[10] },
766203945Sweongyo	{ 112, 5560, bwn_b2062_chantable_data[10] },
767203945Sweongyo	{ 116, 5580, bwn_b2062_chantable_data[11] },
768203945Sweongyo	{ 120, 5600, bwn_b2062_chantable_data[12] },
769203945Sweongyo	{ 124, 5620, bwn_b2062_chantable_data[12] },
770203945Sweongyo	{ 128, 5640, bwn_b2062_chantable_data[12] },
771203945Sweongyo	{ 132, 5660, bwn_b2062_chantable_data[12] },
772203945Sweongyo	{ 136, 5680, bwn_b2062_chantable_data[12] },
773203945Sweongyo	{ 140, 5700, bwn_b2062_chantable_data[12] },
774203945Sweongyo	{ 149, 5745, bwn_b2062_chantable_data[12] },
775203945Sweongyo	{ 153, 5765, bwn_b2062_chantable_data[12] },
776203945Sweongyo	{ 157, 5785, bwn_b2062_chantable_data[12] },
777203945Sweongyo	{ 161, 5805, bwn_b2062_chantable_data[12] },
778203945Sweongyo	{ 165, 5825, bwn_b2062_chantable_data[12] },
779203945Sweongyo	{ 184, 4920, bwn_b2062_chantable_data[13] },
780203945Sweongyo	{ 188, 4940, bwn_b2062_chantable_data[14] },
781203945Sweongyo	{ 192, 4960, bwn_b2062_chantable_data[15] },
782203945Sweongyo	{ 196, 4980, bwn_b2062_chantable_data[16] },
783203945Sweongyo	{ 200, 5000, bwn_b2062_chantable_data[17] },
784203945Sweongyo	{ 204, 5020, bwn_b2062_chantable_data[18] },
785203945Sweongyo	{ 208, 5040, bwn_b2062_chantable_data[19] },
786203945Sweongyo	{ 212, 5060, bwn_b2062_chantable_data[20] },
787203945Sweongyo	{ 216, 5080, bwn_b2062_chantable_data[21] }
788203945Sweongyo};
789203945Sweongyo
790203945Sweongyo/* for LP PHY */
791203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_5354[] = {
792203945Sweongyo	{  1, -66, 15 }, {  2, -66, 15 }, {  3, -66, 15 }, {  4, -66, 15 },
793203945Sweongyo	{  5, -66, 15 }, {  6, -66, 15 }, {  7, -66, 14 }, {  8, -66, 14 },
794203945Sweongyo	{  9, -66, 14 }, { 10, -66, 14 }, { 11, -66, 14 }, { 12, -66, 13 },
795203945Sweongyo	{ 13, -66, 13 }, { 14, -66, 13 },
796203945Sweongyo};
797203945Sweongyo
798203945Sweongyo/* for LP PHY */
799203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r12[] = {
800203945Sweongyo	{   1, -64, 13 }, {   2, -64, 13 }, {   3, -64, 13 }, {   4, -64, 13 },
801203945Sweongyo	{   5, -64, 12 }, {   6, -64, 12 }, {   7, -64, 12 }, {   8, -64, 12 },
802203945Sweongyo	{   9, -64, 12 }, {  10, -64, 11 }, {  11, -64, 11 }, {  12, -64, 11 },
803203945Sweongyo	{  13, -64, 11 }, {  14, -64, 10 }, {  34, -62, 24 }, {  38, -62, 24 },
804203945Sweongyo	{  42, -62, 24 }, {  46, -62, 23 }, {  36, -62, 24 }, {  40, -62, 24 },
805203945Sweongyo	{  44, -62, 23 }, {  48, -62, 23 }, {  52, -62, 23 }, {  56, -62, 22 },
806203945Sweongyo	{  60, -62, 22 }, {  64, -62, 22 }, { 100, -62, 16 }, { 104, -62, 16 },
807203945Sweongyo	{ 108, -62, 15 }, { 112, -62, 14 }, { 116, -62, 14 }, { 120, -62, 13 },
808203945Sweongyo	{ 124, -62, 12 }, { 128, -62, 12 }, { 132, -62, 12 }, { 136, -62, 11 },
809203945Sweongyo	{ 140, -62, 10 }, { 149, -61,  9 }, { 153, -61,  9 }, { 157, -61,  9 },
810203945Sweongyo	{ 161, -61,  8 }, { 165, -61,  8 }, { 184, -62, 25 }, { 188, -62, 25 },
811203945Sweongyo	{ 192, -62, 25 }, { 196, -62, 25 }, { 200, -62, 25 }, { 204, -62, 25 },
812203945Sweongyo	{ 208, -62, 25 }, { 212, -62, 25 }, { 216, -62, 26 },
813203945Sweongyo};
814203945Sweongyo
815203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r2 = { 0, -64, 0 };
816203945Sweongyo
817203945Sweongyostatic const uint8_t bwn_tab_sigsq_tbl[] = {
818203945Sweongyo	0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
819203945Sweongyo	0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
820203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
821203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
822203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
823203945Sweongyo	0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
824203945Sweongyo};
825203945Sweongyo
826203945Sweongyostatic const uint8_t bwn_tab_pllfrac_tbl[] = {
827203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
828203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
829203945Sweongyo};
830203945Sweongyo
831203945Sweongyostatic const uint16_t bwn_tabl_iqlocal_tbl[] = {
832203945Sweongyo	0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
833203945Sweongyo	0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
834203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
835203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
836203945Sweongyo	0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
837203945Sweongyo	0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
838203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
839203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
840203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
841203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
842203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
843203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
844203945Sweongyo};
845203945Sweongyo
846203945Sweongyostatic const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
847203945Sweongyostatic const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
848203945Sweongyostatic const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
849203945Sweongyostatic const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
850203945Sweongyostatic const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
851203945Sweongyoconst uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
852203945Sweongyo
853203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
854203945Sweongyo{							\
855203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
856203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
857203945Sweongyo}
858203945Sweongyo
859203945Sweongyostatic const struct {
860203945Sweongyo	uint16_t	vid;
861203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
862203945Sweongyo} bwn_vendor_led_act[] = {
863203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
864203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
865203945Sweongyo};
866203945Sweongyo
867203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
868203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
869203945Sweongyo
870203945Sweongyo#undef VENDOR_LED_ACT
871203945Sweongyo
872203945Sweongyostatic const struct {
873203945Sweongyo	int		on_dur;
874203945Sweongyo	int		off_dur;
875203945Sweongyo} bwn_led_duration[109] = {
876203945Sweongyo	[0]	= { 400, 100 },
877203945Sweongyo	[2]	= { 150, 75 },
878203945Sweongyo	[4]	= { 90, 45 },
879203945Sweongyo	[11]	= { 66, 34 },
880203945Sweongyo	[12]	= { 53, 26 },
881203945Sweongyo	[18]	= { 42, 21 },
882203945Sweongyo	[22]	= { 35, 17 },
883203945Sweongyo	[24]	= { 32, 16 },
884203945Sweongyo	[36]	= { 21, 10 },
885203945Sweongyo	[48]	= { 16, 8 },
886203945Sweongyo	[72]	= { 11, 5 },
887203945Sweongyo	[96]	= { 9, 4 },
888203945Sweongyo	[108]	= { 7, 3 }
889203945Sweongyo};
890203945Sweongyo
891203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
892203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
893203945Sweongyo	[1] = BWN_WME_BACKGROUND,
894203945Sweongyo	[2] = BWN_WME_VOICE,
895203945Sweongyo	[3] = BWN_WME_VIDEO,
896203945Sweongyo};
897203945Sweongyo
898203945Sweongyostatic const struct siba_devid bwn_devs[] = {
899203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
900203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
901203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
902203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
903203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
904203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
905203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
906203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
907203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
908203945Sweongyo};
909203945Sweongyo
910203945Sweongyostatic int
911203945Sweongyobwn_probe(device_t dev)
912203945Sweongyo{
913203945Sweongyo	struct siba_dev_softc *sd = device_get_ivars(dev);
914203945Sweongyo	int i;
915203945Sweongyo
916203945Sweongyo	for (i = 0; i < sizeof(bwn_devs) / sizeof(bwn_devs[0]); i++) {
917203945Sweongyo		if (sd->sd_id.sd_vendor == bwn_devs[i].sd_vendor &&
918203945Sweongyo		    sd->sd_id.sd_device == bwn_devs[i].sd_device &&
919203945Sweongyo		    sd->sd_id.sd_rev == bwn_devs[i].sd_rev)
920203945Sweongyo			return (BUS_PROBE_DEFAULT);
921203945Sweongyo	}
922203945Sweongyo
923203945Sweongyo	return (ENXIO);
924203945Sweongyo}
925203945Sweongyo
926203945Sweongyostatic int
927203945Sweongyobwn_attach(device_t dev)
928203945Sweongyo{
929203945Sweongyo	struct bwn_mac *mac;
930203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
931203945Sweongyo	struct siba_dev_softc *sd = device_get_ivars(dev);
932203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
933203945Sweongyo	int error, i, msic, reg;
934203945Sweongyo
935203945Sweongyo	sc->sc_dev = dev;
936203945Sweongyo	sc->sc_sd = sd;
937203945Sweongyo#ifdef BWN_DEBUG
938203945Sweongyo	sc->sc_debug = bwn_debug;
939203945Sweongyo#endif
940203945Sweongyo
941203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
942203945Sweongyo		error = bwn_attach_pre(sc);
943203945Sweongyo		if (error != 0)
944203945Sweongyo			return (error);
945203945Sweongyo		bwn_sprom_bugfixes(sd->sd_bus);
946203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
947203945Sweongyo	}
948203945Sweongyo
949203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
950203945Sweongyo		if (siba->siba_pci_did != 0x4313 &&
951203945Sweongyo		    siba->siba_pci_did != 0x431a &&
952203945Sweongyo		    siba->siba_pci_did != 0x4321) {
953203945Sweongyo			device_printf(sc->sc_dev,
954203945Sweongyo			    "skip 802.11 cores\n");
955203945Sweongyo			return (ENODEV);
956203945Sweongyo		}
957203945Sweongyo	}
958203945Sweongyo
959203945Sweongyo	mac = (struct bwn_mac *)malloc(sizeof(*mac), M_DEVBUF,
960203945Sweongyo	    M_NOWAIT | M_ZERO);
961203945Sweongyo	if (mac == NULL)
962203945Sweongyo		return (ENOMEM);
963203945Sweongyo	mac->mac_sc = sc;
964203945Sweongyo	mac->mac_sd = sd;
965203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
966203945Sweongyo	if (bwn_bfp != 0)
967203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
968203945Sweongyo
969203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
970203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
971203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
972203945Sweongyo
973203945Sweongyo	error = bwn_attach_core(mac);
974203945Sweongyo	if (error)
975203945Sweongyo		goto fail0;
976203945Sweongyo	bwn_led_attach(mac);
977203945Sweongyo
978203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
979203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
980203945Sweongyo	    sd->sd_bus->siba_chipid, sd->sd_id.sd_rev,
981203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
982203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
983203945Sweongyo	    mac->mac_phy.rf_rev);
984203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
985203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
986203945Sweongyo		    mac->mac_method.dma.dmatype);
987203945Sweongyo	else
988203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
989203945Sweongyo
990203945Sweongyo	/*
991203945Sweongyo	 * setup PCI resources and interrupt.
992203945Sweongyo	 */
993203945Sweongyo	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
994203945Sweongyo		msic = pci_msi_count(dev);
995203945Sweongyo		if (bootverbose)
996203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
997203945Sweongyo	} else
998203945Sweongyo		msic = 0;
999203945Sweongyo
1000203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
1001203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
1002203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
1003203945Sweongyo			device_printf(sc->sc_dev,
1004203945Sweongyo			    "Using %d MSI messages\n", msic);
1005203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
1006203945Sweongyo			mac->mac_msi = 1;
1007203945Sweongyo		}
1008203945Sweongyo	}
1009203945Sweongyo
1010203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
1011203945Sweongyo	    mac->mac_res_irq);
1012203945Sweongyo	if (error) {
1013203945Sweongyo		device_printf(sc->sc_dev,
1014203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
1015203945Sweongyo		goto fail1;
1016203945Sweongyo	}
1017203945Sweongyo
1018203945Sweongyo	if (mac->mac_msi == 0)
1019203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
1020203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1021203945Sweongyo		    &mac->mac_intrhand[0]);
1022203945Sweongyo	else {
1023203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1024203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
1025203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1026203945Sweongyo			    &mac->mac_intrhand[i]);
1027203945Sweongyo			if (error != 0) {
1028203945Sweongyo				device_printf(sc->sc_dev,
1029203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
1030203945Sweongyo				break;
1031203945Sweongyo			}
1032203945Sweongyo		}
1033203945Sweongyo	}
1034203945Sweongyo
1035203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
1036203945Sweongyo
1037203945Sweongyo	/*
1038203945Sweongyo	 * calls attach-post routine
1039203945Sweongyo	 */
1040203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
1041203945Sweongyo		bwn_attach_post(sc);
1042203945Sweongyo
1043203945Sweongyo	return (0);
1044203945Sweongyofail1:
1045203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
1046203945Sweongyo		pci_release_msi(dev);
1047203945Sweongyofail0:
1048203945Sweongyo	free(mac, M_DEVBUF);
1049203945Sweongyo	return (error);
1050203945Sweongyo}
1051203945Sweongyo
1052203945Sweongyostatic int
1053203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
1054203945Sweongyo{
1055203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
1056203945Sweongyo
1057203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
1058203945Sweongyo		return (FALSE);
1059203945Sweongyo
1060203945Sweongyo	return (TRUE);
1061203945Sweongyo}
1062203945Sweongyo
1063203945Sweongyostatic int
1064203945Sweongyobwn_attach_post(struct bwn_softc *sc)
1065203945Sweongyo{
1066203945Sweongyo	struct ieee80211com *ic;
1067203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1068203945Sweongyo	struct siba_dev_softc *sd = sc->sc_sd;
1069203945Sweongyo	struct siba_sprom *sprom = &sd->sd_bus->siba_sprom;
1070203945Sweongyo
1071203945Sweongyo	ic = ifp->if_l2com;
1072203945Sweongyo	ic->ic_ifp = ifp;
1073203945Sweongyo	/* XXX not right but it's not used anywhere important */
1074203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
1075203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
1076203945Sweongyo	ic->ic_caps =
1077203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
1078203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
1079204436Sweongyo		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
1080203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
1081203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
1082203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
1083203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
1084203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
1085203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
1086203945Sweongyo		;
1087203945Sweongyo
1088203945Sweongyo	/* call MI attach routine. */
1089203945Sweongyo	ieee80211_ifattach(ic,
1090203945Sweongyo	    bwn_is_valid_ether_addr(sprom->mac_80211a) ? sprom->mac_80211a :
1091203945Sweongyo	    sprom->mac_80211bg);
1092203945Sweongyo
1093203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
1094203945Sweongyo
1095203945Sweongyo	/* override default methods */
1096203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
1097203945Sweongyo	ic->ic_newassoc = bwn_newassoc;
1098203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
1099203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
1100203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
1101203945Sweongyo
1102203945Sweongyo	ic->ic_node_alloc = bwn_node_alloc;
1103203945Sweongyo	sc->sc_node_cleanup = ic->ic_node_cleanup;
1104203945Sweongyo	ic->ic_node_cleanup = bwn_node_cleanup;
1105203945Sweongyo
1106203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
1107203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
1108203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
1109203945Sweongyo
1110203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
1111203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
1112203945Sweongyo
1113203945Sweongyo	ieee80211_radiotap_attach(ic,
1114203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
1115203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
1116203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
1117203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
1118203945Sweongyo
1119204257Sweongyo	bwn_sysctl_node(sc);
1120203945Sweongyo
1121203945Sweongyo	if (bootverbose)
1122203945Sweongyo		ieee80211_announce(ic);
1123203945Sweongyo	return (0);
1124203945Sweongyo}
1125203945Sweongyo
1126203945Sweongyostatic void
1127203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
1128203945Sweongyo{
1129203945Sweongyo
1130203945Sweongyo	if (mac->mac_phy.detach != NULL)
1131203945Sweongyo		mac->mac_phy.detach(mac);
1132203945Sweongyo}
1133203945Sweongyo
1134203945Sweongyostatic int
1135203945Sweongyobwn_detach(device_t dev)
1136203945Sweongyo{
1137203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
1138203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1139203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1140203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1141203945Sweongyo	int i;
1142203945Sweongyo
1143203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
1144203945Sweongyo
1145203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
1146203945Sweongyo		bwn_stop(sc, 1);
1147203945Sweongyo		bwn_dma_free(mac);
1148203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
1149203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
1150203945Sweongyo		callout_drain(&sc->sc_task_ch);
1151203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
1152203945Sweongyo		bwn_phy_detach(mac);
1153203945Sweongyo		if (ifp != NULL) {
1154203945Sweongyo			ieee80211_draintask(ic, &mac->mac_hwreset);
1155203945Sweongyo			ieee80211_draintask(ic, &mac->mac_txpower);
1156203945Sweongyo			ieee80211_ifdetach(ic);
1157203945Sweongyo			if_free(ifp);
1158203945Sweongyo		}
1159203945Sweongyo	}
1160203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
1161203945Sweongyo	taskqueue_free(sc->sc_tq);
1162203945Sweongyo
1163203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1164203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
1165203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
1166203945Sweongyo			    mac->mac_intrhand[i]);
1167203945Sweongyo			mac->mac_intrhand[i] = NULL;
1168203945Sweongyo		}
1169203945Sweongyo	}
1170203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
1171203945Sweongyo	if (mac->mac_msi != 0)
1172203945Sweongyo		pci_release_msi(dev);
1173203945Sweongyo
1174203945Sweongyo	BWN_LOCK_DESTROY(sc);
1175203945Sweongyo	return (0);
1176203945Sweongyo}
1177203945Sweongyo
1178203945Sweongyostatic int
1179203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
1180203945Sweongyo{
1181203945Sweongyo	struct ifnet *ifp;
1182203945Sweongyo	int error = 0;
1183203945Sweongyo
1184203945Sweongyo	BWN_LOCK_INIT(sc);
1185203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
1186203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
1187203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
1188203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
1189203945Sweongyo
1190203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
1191203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
1192203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
1193203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
1194203945Sweongyo
1195203945Sweongyo	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
1196203945Sweongyo	if (ifp == NULL) {
1197203945Sweongyo		device_printf(sc->sc_dev, "can not if_alloc()\n");
1198203945Sweongyo		error = ENOSPC;
1199203945Sweongyo		goto fail;
1200203945Sweongyo	}
1201203945Sweongyo
1202203945Sweongyo	/* set these up early for if_printf use */
1203203945Sweongyo	if_initname(ifp, device_get_name(sc->sc_dev),
1204203945Sweongyo	    device_get_unit(sc->sc_dev));
1205203945Sweongyo
1206203945Sweongyo	ifp->if_softc = sc;
1207203945Sweongyo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1208203945Sweongyo	ifp->if_init = bwn_init;
1209203945Sweongyo	ifp->if_ioctl = bwn_ioctl;
1210203945Sweongyo	ifp->if_start = bwn_start;
1211203945Sweongyo	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
1212203945Sweongyo	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
1213203945Sweongyo	IFQ_SET_READY(&ifp->if_snd);
1214203945Sweongyo
1215203945Sweongyo	return (0);
1216203945Sweongyo
1217203945Sweongyofail:	BWN_LOCK_DESTROY(sc);
1218203945Sweongyo	return (error);
1219203945Sweongyo}
1220203945Sweongyo
1221203945Sweongyostatic void
1222203945Sweongyobwn_sprom_bugfixes(struct siba_softc *siba)
1223203945Sweongyo{
1224203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
1225203945Sweongyo	((siba->siba_pci_vid == PCI_VENDOR_##_vendor) &&		\
1226203945Sweongyo	 (siba->siba_pci_did == _device) &&				\
1227203945Sweongyo	 (siba->siba_pci_subvid == PCI_VENDOR_##_subvendor) &&		\
1228203945Sweongyo	 (siba->siba_pci_subdid == _subdevice))
1229203945Sweongyo
1230203945Sweongyo	if (siba->siba_board_vendor == PCI_VENDOR_APPLE &&
1231203945Sweongyo	    siba->siba_board_type == 0x4e && siba->siba_board_rev > 0x40)
1232203945Sweongyo		siba->siba_sprom.bf_lo |= BWN_BFL_PACTRL;
1233203945Sweongyo	if (siba->siba_board_vendor == SIBA_BOARDVENDOR_DELL &&
1234203945Sweongyo	    siba->siba_chipid == 0x4301 && siba->siba_board_rev == 0x74)
1235203945Sweongyo		siba->siba_sprom.bf_lo |= BWN_BFL_BTCOEXIST;
1236203945Sweongyo	if (siba->siba_type == SIBA_TYPE_PCI) {
1237203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
1238203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
1239203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
1240203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
1241203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
1242203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
1243203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
1244203945Sweongyo			siba->siba_sprom.bf_lo &= ~BWN_BFL_BTCOEXIST;
1245203945Sweongyo	}
1246203945Sweongyo#undef	BWN_ISDEV
1247203945Sweongyo}
1248203945Sweongyo
1249203945Sweongyostatic int
1250203945Sweongyobwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1251203945Sweongyo{
1252203945Sweongyo#define	IS_RUNNING(ifp) \
1253203945Sweongyo	((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
1254203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1255203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1256203945Sweongyo	struct ifreq *ifr = (struct ifreq *)data;
1257203945Sweongyo	int error = 0, startall;
1258203945Sweongyo
1259203945Sweongyo	switch (cmd) {
1260203945Sweongyo	case SIOCSIFFLAGS:
1261203945Sweongyo		startall = 0;
1262203945Sweongyo		if (IS_RUNNING(ifp)) {
1263203945Sweongyo			bwn_update_promisc(ifp);
1264203945Sweongyo		} else if (ifp->if_flags & IFF_UP) {
1265203945Sweongyo			if ((sc->sc_flags & BWN_FLAG_INVALID) == 0) {
1266203945Sweongyo				bwn_init(sc);
1267203945Sweongyo				startall = 1;
1268203945Sweongyo			}
1269203945Sweongyo		} else
1270203945Sweongyo			bwn_stop(sc, 1);
1271203945Sweongyo		if (startall)
1272203945Sweongyo			ieee80211_start_all(ic);
1273203945Sweongyo		break;
1274203945Sweongyo	case SIOCGIFMEDIA:
1275203945Sweongyo		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1276203945Sweongyo		break;
1277203945Sweongyo	case SIOCGIFADDR:
1278203945Sweongyo		error = ether_ioctl(ifp, cmd, data);
1279203945Sweongyo		break;
1280203945Sweongyo	default:
1281203945Sweongyo		error = EINVAL;
1282203945Sweongyo		break;
1283203945Sweongyo	}
1284203945Sweongyo	return (error);
1285203945Sweongyo}
1286203945Sweongyo
1287203945Sweongyostatic void
1288203945Sweongyobwn_start(struct ifnet *ifp)
1289203945Sweongyo{
1290203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1291203945Sweongyo
1292203945Sweongyo	BWN_LOCK(sc);
1293203945Sweongyo	bwn_start_locked(ifp);
1294203945Sweongyo	BWN_UNLOCK(sc);
1295203945Sweongyo}
1296203945Sweongyo
1297203945Sweongyostatic void
1298203945Sweongyobwn_start_locked(struct ifnet *ifp)
1299203945Sweongyo{
1300203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1301203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1302203945Sweongyo	struct ieee80211_frame *wh;
1303203945Sweongyo	struct ieee80211_node *ni;
1304203945Sweongyo	struct ieee80211_key *k;
1305203945Sweongyo	struct mbuf *m;
1306203945Sweongyo
1307203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1308203945Sweongyo
1309203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || mac == NULL ||
1310203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
1311203945Sweongyo		return;
1312203945Sweongyo
1313203945Sweongyo	for (;;) {
1314203945Sweongyo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);	/* XXX: LOCK */
1315203945Sweongyo		if (m == NULL)
1316203945Sweongyo			break;
1317203945Sweongyo
1318203945Sweongyo		if (bwn_tx_isfull(sc, m))
1319203945Sweongyo			break;
1320203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
1321203945Sweongyo		if (ni == NULL) {
1322203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
1323203945Sweongyo			m_freem(m);
1324203945Sweongyo			ifp->if_oerrors++;
1325203945Sweongyo			continue;
1326203945Sweongyo		}
1327203945Sweongyo		KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__));
1328203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
1329203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1330203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
1331203945Sweongyo			if (k == NULL) {
1332203945Sweongyo				ieee80211_free_node(ni);
1333203945Sweongyo				m_freem(m);
1334203945Sweongyo				ifp->if_oerrors++;
1335203945Sweongyo				continue;
1336203945Sweongyo			}
1337203945Sweongyo		}
1338203945Sweongyo		wh = NULL;	/* Catch any invalid use */
1339203945Sweongyo
1340203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
1341203945Sweongyo			if (ni != NULL)
1342203945Sweongyo				ieee80211_free_node(ni);
1343203945Sweongyo			ifp->if_oerrors++;
1344203945Sweongyo			continue;
1345203945Sweongyo		}
1346203945Sweongyo
1347203945Sweongyo		sc->sc_watchdog_timer = 5;
1348203945Sweongyo	}
1349203945Sweongyo}
1350203945Sweongyo
1351203945Sweongyostatic int
1352203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
1353203945Sweongyo{
1354203945Sweongyo	struct bwn_dma_ring *dr;
1355203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1356203945Sweongyo	struct bwn_pio_txqueue *tq;
1357203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1358203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1359203945Sweongyo
1360203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1361203945Sweongyo
1362203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
1363203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
1364203945Sweongyo		if (dr->dr_stop == 1 ||
1365203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
1366203945Sweongyo			dr->dr_stop = 1;
1367203945Sweongyo			goto full;
1368203945Sweongyo		}
1369203945Sweongyo	} else {
1370203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
1371203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
1372203945Sweongyo		    pktlen > (tq->tq_size - tq->tq_used)) {
1373203945Sweongyo			tq->tq_stop = 1;
1374203945Sweongyo			goto full;
1375203945Sweongyo		}
1376203945Sweongyo	}
1377203945Sweongyo	return (0);
1378203945Sweongyofull:
1379203945Sweongyo	IFQ_DRV_PREPEND(&ifp->if_snd, m);
1380203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1381203945Sweongyo	return (1);
1382203945Sweongyo}
1383203945Sweongyo
1384203945Sweongyostatic int
1385203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
1386203945Sweongyo{
1387203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1388203945Sweongyo	int error;
1389203945Sweongyo
1390203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1391203945Sweongyo
1392203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
1393203945Sweongyo		m_freem(m);
1394203945Sweongyo		return (ENXIO);
1395203945Sweongyo	}
1396203945Sweongyo
1397203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
1398203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
1399203945Sweongyo	if (error) {
1400203945Sweongyo		m_freem(m);
1401203945Sweongyo		return (error);
1402203945Sweongyo	}
1403203945Sweongyo	return (0);
1404203945Sweongyo}
1405203945Sweongyo
1406203945Sweongyostatic int
1407203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1408203945Sweongyo{
1409203945Sweongyo	struct bwn_pio_txpkt *tp;
1410203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
1411203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1412203945Sweongyo	struct bwn_txhdr txhdr;
1413203945Sweongyo	struct mbuf *m_new;
1414203945Sweongyo	uint32_t ctl32;
1415203945Sweongyo	int error;
1416203945Sweongyo	uint16_t ctl16;
1417203945Sweongyo
1418203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1419203945Sweongyo
1420203945Sweongyo	/* XXX TODO send packets after DTIM */
1421203945Sweongyo
1422203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
1423203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
1424203945Sweongyo	tp->tp_ni = ni;
1425203945Sweongyo	tp->tp_m = m;
1426203945Sweongyo
1427203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
1428203945Sweongyo	if (error) {
1429203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
1430203945Sweongyo		return (error);
1431203945Sweongyo	}
1432203945Sweongyo
1433203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
1434203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1435203945Sweongyo	tq->tq_free--;
1436203945Sweongyo
1437203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 8) {
1438203945Sweongyo		/*
1439203945Sweongyo		 * XXX please removes m_defrag(9)
1440203945Sweongyo		 */
1441203945Sweongyo		m_new = m_defrag(m, M_DONTWAIT);
1442203945Sweongyo		if (m_new == NULL) {
1443203945Sweongyo			device_printf(sc->sc_dev,
1444203945Sweongyo			    "%s: can't defrag TX buffer\n",
1445203945Sweongyo			    __func__);
1446203945Sweongyo			return (ENOBUFS);
1447203945Sweongyo		}
1448203945Sweongyo		if (m_new->m_next != NULL)
1449203945Sweongyo			device_printf(sc->sc_dev,
1450203945Sweongyo			    "TODO: fragmented packets for PIO\n");
1451203945Sweongyo		tp->tp_m = m_new;
1452203945Sweongyo
1453203945Sweongyo		/* send HEADER */
1454203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
1455203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
1456203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
1457203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1458203945Sweongyo		/* send BODY */
1459203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
1460203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
1461203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
1462203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
1463203945Sweongyo	} else {
1464203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
1465203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
1466203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
1467203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1468203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
1469203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
1470203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
1471203945Sweongyo	}
1472203945Sweongyo
1473203945Sweongyo	return (0);
1474203945Sweongyo}
1475203945Sweongyo
1476203945Sweongyostatic struct bwn_pio_txqueue *
1477203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1478203945Sweongyo{
1479203945Sweongyo
1480203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1481203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1482203945Sweongyo
1483203945Sweongyo	switch (prio) {
1484203945Sweongyo	case 0:
1485203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1486203945Sweongyo	case 1:
1487203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1488203945Sweongyo	case 2:
1489203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1490203945Sweongyo	case 3:
1491203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1492203945Sweongyo	}
1493203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1494204242Simp	return (NULL);
1495203945Sweongyo}
1496203945Sweongyo
1497203945Sweongyostatic int
1498203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1499203945Sweongyo{
1500203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1501203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1502203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1503203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1504203945Sweongyo	struct bwn_dmadesc_generic *desc;
1505203945Sweongyo	struct bwn_dmadesc_meta *mt;
1506203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1507203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1508203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1509203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1510203945Sweongyo
1511203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1512203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1513203945Sweongyo
1514203945Sweongyo	/* XXX send after DTIM */
1515203945Sweongyo
1516203945Sweongyo	slot = bwn_dma_getslot(dr);
1517203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1518203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1519203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1520203945Sweongyo
1521203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1522203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1523203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1524203945Sweongyo	if (error)
1525203945Sweongyo		goto fail;
1526203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1527203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1528203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1529203945Sweongyo	if (error) {
1530203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1531203945Sweongyo		    __func__, error);
1532203945Sweongyo		goto fail;
1533203945Sweongyo	}
1534203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1535203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1536203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1537203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1538203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1539203945Sweongyo
1540203945Sweongyo	slot = bwn_dma_getslot(dr);
1541203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1542203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1543203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1544203945Sweongyo	mt->mt_m = m;
1545203945Sweongyo	mt->mt_ni = ni;
1546203945Sweongyo
1547203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1548203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1549203945Sweongyo	if (error && error != EFBIG) {
1550203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1551203945Sweongyo		    __func__, error);
1552203945Sweongyo		goto fail;
1553203945Sweongyo	}
1554203945Sweongyo	if (error) {    /* error == EFBIG */
1555203945Sweongyo		struct mbuf *m_new;
1556203945Sweongyo
1557203945Sweongyo		m_new = m_defrag(m, M_DONTWAIT);
1558203945Sweongyo		if (m_new == NULL) {
1559203945Sweongyo			if_printf(ifp, "%s: can't defrag TX buffer\n",
1560203945Sweongyo			    __func__);
1561203945Sweongyo			error = ENOBUFS;
1562203945Sweongyo			goto fail;
1563203945Sweongyo		} else {
1564203945Sweongyo			m = m_new;
1565203945Sweongyo		}
1566203945Sweongyo
1567203945Sweongyo		mt->mt_m = m;
1568203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1569203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1570203945Sweongyo		if (error) {
1571203945Sweongyo			if_printf(ifp, "%s: can't load TX buffer (2) %d\n",
1572203945Sweongyo			    __func__, error);
1573203945Sweongyo			goto fail;
1574203945Sweongyo		}
1575203945Sweongyo	}
1576203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1577203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1578203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1579203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1580203945Sweongyo
1581203945Sweongyo	/* XXX send after DTIM */
1582203945Sweongyo
1583203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1584203945Sweongyo	return (0);
1585203945Sweongyofail:
1586203945Sweongyo	dr->dr_curslot = backup[0];
1587203945Sweongyo	dr->dr_usedslot = backup[1];
1588203945Sweongyo	return (error);
1589203945Sweongyo#undef BWN_GET_TXHDRCACHE
1590203945Sweongyo}
1591203945Sweongyo
1592203945Sweongyostatic void
1593203945Sweongyobwn_watchdog(void *arg)
1594203945Sweongyo{
1595203945Sweongyo	struct bwn_softc *sc = arg;
1596203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1597203945Sweongyo
1598203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1599203945Sweongyo		if_printf(ifp, "device timeout\n");
1600203945Sweongyo		ifp->if_oerrors++;
1601203945Sweongyo	}
1602203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1603203945Sweongyo}
1604203945Sweongyo
1605203945Sweongyostatic int
1606203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1607203945Sweongyo{
1608203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1609203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1610203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
1611203945Sweongyo	int error, have_bg = 0, have_a = 0;
1612203945Sweongyo	uint32_t high;
1613203945Sweongyo
1614203945Sweongyo	KASSERT(sd->sd_id.sd_rev >= 5,
1615203945Sweongyo	    ("unsupported revision %d", sd->sd_id.sd_rev));
1616203945Sweongyo
1617203945Sweongyo	siba_powerup(siba, 0);
1618203945Sweongyo
1619203945Sweongyo	high = siba_read_4(sd, SIBA_TGSHIGH);
1620203945Sweongyo	bwn_reset_core(mac,
1621203945Sweongyo	    (high & BWN_TGSHIGH_HAVE_2GHZ) ? BWN_TGSLOW_SUPPORT_G : 0);
1622203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1623203945Sweongyo	if (error)
1624203945Sweongyo		goto fail;
1625203945Sweongyo
1626203945Sweongyo	have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1627203945Sweongyo	have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1628203945Sweongyo	if (siba->siba_pci_did != 0x4312 && siba->siba_pci_did != 0x4319 &&
1629203945Sweongyo	    siba->siba_pci_did != 0x4324) {
1630203945Sweongyo		have_a = have_bg = 0;
1631203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1632203945Sweongyo			have_a = 1;
1633203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1634203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1635203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1636203945Sweongyo			have_bg = 1;
1637203945Sweongyo		else
1638203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1639203945Sweongyo			    mac->mac_phy.type));
1640203945Sweongyo	}
1641203945Sweongyo	/* XXX turns off PHY A because it's not supported */
1642203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1643203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1644203945Sweongyo		have_a = 0;
1645203945Sweongyo		have_bg = 1;
1646203945Sweongyo	}
1647203945Sweongyo
1648203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1649203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1650203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1651203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1652203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1653203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1654203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1655203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1656203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1657203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1658203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1659203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1660203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1661203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1662203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1663203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1664203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1665203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1666203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1667203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1668203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1669203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1670203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1671203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1672203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1673203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1674203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1675203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1676203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1677203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1678203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1679203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1680203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1681203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1682203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1683203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1684203945Sweongyo	} else {
1685203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1686203945Sweongyo		    mac->mac_phy.type);
1687203945Sweongyo		error = ENXIO;
1688203945Sweongyo		goto fail;
1689203945Sweongyo	}
1690203945Sweongyo
1691203945Sweongyo	mac->mac_phy.gmode = have_bg;
1692203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1693203945Sweongyo		error = mac->mac_phy.attach(mac);
1694203945Sweongyo		if (error) {
1695203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1696203945Sweongyo			goto fail;
1697203945Sweongyo		}
1698203945Sweongyo	}
1699203945Sweongyo
1700203945Sweongyo	bwn_reset_core(mac, have_bg ? BWN_TGSLOW_SUPPORT_G : 0);
1701203945Sweongyo
1702203945Sweongyo	error = bwn_chiptest(mac);
1703203945Sweongyo	if (error)
1704203945Sweongyo		goto fail;
1705203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1706203945Sweongyo	if (error) {
1707203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1708203945Sweongyo		goto fail;
1709203945Sweongyo	}
1710203945Sweongyo
1711203945Sweongyo	if (sc->sc_curmac == NULL)
1712203945Sweongyo		sc->sc_curmac = mac;
1713203945Sweongyo
1714203945Sweongyo	error = bwn_dma_attach(mac);
1715203945Sweongyo	if (error != 0) {
1716203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1717203945Sweongyo		goto fail;
1718203945Sweongyo	}
1719203945Sweongyo
1720203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1721203945Sweongyo
1722203945Sweongyo	siba_dev_down(sd, 0);
1723203945Sweongyofail:
1724203945Sweongyo	siba_powerdown(siba);
1725203945Sweongyo	return (error);
1726203945Sweongyo}
1727203945Sweongyo
1728203945Sweongyostatic void
1729203945Sweongyobwn_reset_core(struct bwn_mac *mac, uint32_t flags)
1730203945Sweongyo{
1731203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1732203945Sweongyo	uint32_t low, ctl;
1733203945Sweongyo
1734203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1735203945Sweongyo
1736203945Sweongyo	siba_dev_up(sd, flags);
1737203945Sweongyo	DELAY(2000);
1738203945Sweongyo
1739203945Sweongyo	low = (siba_read_4(sd, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1740203945Sweongyo	    ~BWN_TGSLOW_PHYRESET;
1741203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW, low);
1742203945Sweongyo	siba_read_4(sd, SIBA_TGSLOW);
1743203945Sweongyo	DELAY(1000);
1744203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
1745203945Sweongyo	siba_read_4(sd, SIBA_TGSLOW);
1746203945Sweongyo	DELAY(1000);
1747203945Sweongyo
1748203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1749203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1750203945Sweongyo
1751203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1752203945Sweongyo	if (flags & BWN_TGSLOW_SUPPORT_G)
1753203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1754203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1755203945Sweongyo}
1756203945Sweongyo
1757203945Sweongyostatic int
1758203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1759203945Sweongyo{
1760203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1761203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1762203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1763203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
1764203945Sweongyo	uint32_t tmp;
1765203945Sweongyo
1766203945Sweongyo	/* PHY */
1767203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1768203945Sweongyo	phy->gmode = (tgshigh & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1769203945Sweongyo	phy->rf_on = 1;
1770203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1771203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1772203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1773203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1774203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1775203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1776203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1777203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1778203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1779203945Sweongyo		goto unsupphy;
1780203945Sweongyo
1781203945Sweongyo	/* RADIO */
1782203945Sweongyo	if (siba->siba_chipid == 0x4317) {
1783203945Sweongyo		if (siba->siba_chiprev == 0)
1784203945Sweongyo			tmp = 0x3205017f;
1785203945Sweongyo		else if (siba->siba_chiprev == 1)
1786203945Sweongyo			tmp = 0x4205017f;
1787203945Sweongyo		else
1788203945Sweongyo			tmp = 0x5205017f;
1789203945Sweongyo	} else {
1790203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1791203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1792203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1793203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1794203945Sweongyo	}
1795203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1796203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1797203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1798203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1799203945Sweongyo		goto unsupradio;
1800203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1801203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1802203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1803203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1804203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1805203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1806203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1807203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1808203945Sweongyo		goto unsupradio;
1809203945Sweongyo
1810203945Sweongyo	return (0);
1811203945Sweongyounsupphy:
1812203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1813203945Sweongyo	    "analog %#x)\n",
1814203945Sweongyo	    phy->type, phy->rev, phy->analog);
1815203945Sweongyo	return (ENXIO);
1816203945Sweongyounsupradio:
1817203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1818203945Sweongyo	    "rev %#x)\n",
1819203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1820203945Sweongyo	return (ENXIO);
1821203945Sweongyo}
1822203945Sweongyo
1823203945Sweongyostatic int
1824203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1825203945Sweongyo{
1826203945Sweongyo#define	TESTVAL0	0x55aaaa55
1827203945Sweongyo#define	TESTVAL1	0xaa5555aa
1828203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1829203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1830203945Sweongyo	uint32_t v, backup;
1831203945Sweongyo
1832203945Sweongyo	BWN_LOCK(sc);
1833203945Sweongyo
1834203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1835203945Sweongyo
1836203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1837203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1838203945Sweongyo		goto error;
1839203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1840203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1841203945Sweongyo		goto error;
1842203945Sweongyo
1843203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1844203945Sweongyo
1845203945Sweongyo	if ((sd->sd_id.sd_rev >= 3) && (sd->sd_id.sd_rev <= 10)) {
1846203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1847203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1848203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1849203945Sweongyo			goto error;
1850203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1851203945Sweongyo			goto error;
1852203945Sweongyo	}
1853203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1854203945Sweongyo
1855203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1856203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1857203945Sweongyo		goto error;
1858203945Sweongyo
1859203945Sweongyo	BWN_UNLOCK(sc);
1860203945Sweongyo	return (0);
1861203945Sweongyoerror:
1862203945Sweongyo	BWN_UNLOCK(sc);
1863203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1864203945Sweongyo	return (ENODEV);
1865203945Sweongyo}
1866203945Sweongyo
1867203945Sweongyo#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
1868203945Sweongyo#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
1869203945Sweongyo
1870203945Sweongyostatic int
1871203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1872203945Sweongyo{
1873203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1874203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1875203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1876203945Sweongyo
1877203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1878203945Sweongyo	ic->ic_nchans = 0;
1879203945Sweongyo
1880203945Sweongyo	if (have_bg)
1881203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1882203945Sweongyo		    &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
1883203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1884203945Sweongyo		if (have_a)
1885203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1886203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_n,
1887203945Sweongyo			    IEEE80211_CHAN_HTA);
1888203945Sweongyo	} else {
1889203945Sweongyo		if (have_a)
1890203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1891203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_a,
1892203945Sweongyo			    IEEE80211_CHAN_A);
1893203945Sweongyo	}
1894203945Sweongyo
1895203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1896203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1897203945Sweongyo
1898203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1899203945Sweongyo}
1900203945Sweongyo
1901203945Sweongyostatic uint32_t
1902203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1903203945Sweongyo{
1904203945Sweongyo	uint32_t ret;
1905203945Sweongyo
1906204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1907203945Sweongyo
1908203945Sweongyo	if (way == BWN_SHARED) {
1909203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1910203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1911203945Sweongyo		if (offset & 0x0003) {
1912203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1913203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1914203945Sweongyo			ret <<= 16;
1915203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1916203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1917203945Sweongyo			goto out;
1918203945Sweongyo		}
1919203945Sweongyo		offset >>= 2;
1920203945Sweongyo	}
1921203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1922203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1923203945Sweongyoout:
1924203945Sweongyo	return (ret);
1925203945Sweongyo}
1926203945Sweongyo
1927203945Sweongyostatic uint16_t
1928203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1929203945Sweongyo{
1930203945Sweongyo	uint16_t ret;
1931203945Sweongyo
1932204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1933203945Sweongyo
1934203945Sweongyo	if (way == BWN_SHARED) {
1935203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1936203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1937203945Sweongyo		if (offset & 0x0003) {
1938203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1939203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1940203945Sweongyo			goto out;
1941203945Sweongyo		}
1942203945Sweongyo		offset >>= 2;
1943203945Sweongyo	}
1944203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1945203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1946203945Sweongyoout:
1947203945Sweongyo
1948203945Sweongyo	return (ret);
1949203945Sweongyo}
1950203945Sweongyo
1951203945Sweongyostatic void
1952203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1953203945Sweongyo    uint16_t offset)
1954203945Sweongyo{
1955203945Sweongyo	uint32_t control;
1956203945Sweongyo
1957203945Sweongyo	control = way;
1958203945Sweongyo	control <<= 16;
1959203945Sweongyo	control |= offset;
1960203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1961203945Sweongyo}
1962203945Sweongyo
1963203945Sweongyostatic void
1964203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1965203945Sweongyo    uint32_t value)
1966203945Sweongyo{
1967204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1968203945Sweongyo
1969203945Sweongyo	if (way == BWN_SHARED) {
1970203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1971203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1972203945Sweongyo		if (offset & 0x0003) {
1973203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1974203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1975203945Sweongyo				    (value >> 16) & 0xffff);
1976203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1977203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1978203945Sweongyo			return;
1979203945Sweongyo		}
1980203945Sweongyo		offset >>= 2;
1981203945Sweongyo	}
1982203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1983203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1984203945Sweongyo}
1985203945Sweongyo
1986203945Sweongyostatic void
1987203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1988203945Sweongyo    uint16_t value)
1989203945Sweongyo{
1990204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1991203945Sweongyo
1992203945Sweongyo	if (way == BWN_SHARED) {
1993203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1994203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1995203945Sweongyo		if (offset & 0x0003) {
1996203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1997203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
1998203945Sweongyo			return;
1999203945Sweongyo		}
2000203945Sweongyo		offset >>= 2;
2001203945Sweongyo	}
2002203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
2003203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
2004203945Sweongyo}
2005203945Sweongyo
2006203945Sweongyostatic void
2007203945Sweongyobwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
2008203945Sweongyo    int txpow)
2009203945Sweongyo{
2010203945Sweongyo
2011203945Sweongyo	c->ic_freq = freq;
2012203945Sweongyo	c->ic_flags = flags;
2013203945Sweongyo	c->ic_ieee = ieee;
2014203945Sweongyo	c->ic_minpower = 0;
2015203945Sweongyo	c->ic_maxpower = 2 * txpow;
2016203945Sweongyo	c->ic_maxregpower = txpow;
2017203945Sweongyo}
2018203945Sweongyo
2019203945Sweongyostatic void
2020203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
2021203945Sweongyo    const struct bwn_channelinfo *ci, int flags)
2022203945Sweongyo{
2023203945Sweongyo	struct ieee80211_channel *c;
2024203945Sweongyo	int i;
2025203945Sweongyo
2026203945Sweongyo	c = &chans[*nchans];
2027203945Sweongyo
2028203945Sweongyo	for (i = 0; i < ci->nchannels; i++) {
2029203945Sweongyo		const struct bwn_channel *hc;
2030203945Sweongyo
2031203945Sweongyo		hc = &ci->channels[i];
2032203945Sweongyo		if (*nchans >= maxchans)
2033203945Sweongyo			break;
2034203945Sweongyo		bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
2035203945Sweongyo		c++, (*nchans)++;
2036203945Sweongyo		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
2037203945Sweongyo			/* g channel have a separate b-only entry */
2038203945Sweongyo			if (*nchans >= maxchans)
2039203945Sweongyo				break;
2040203945Sweongyo			c[0] = c[-1];
2041203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_B;
2042203945Sweongyo			c++, (*nchans)++;
2043203945Sweongyo		}
2044203945Sweongyo		if (flags == IEEE80211_CHAN_HTG) {
2045203945Sweongyo			/* HT g channel have a separate g-only entry */
2046203945Sweongyo			if (*nchans >= maxchans)
2047203945Sweongyo				break;
2048203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_G;
2049203945Sweongyo			c[0] = c[-1];
2050203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2051203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2052203945Sweongyo			c++, (*nchans)++;
2053203945Sweongyo		}
2054203945Sweongyo		if (flags == IEEE80211_CHAN_HTA) {
2055203945Sweongyo			/* HT a channel have a separate a-only entry */
2056203945Sweongyo			if (*nchans >= maxchans)
2057203945Sweongyo				break;
2058203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_A;
2059203945Sweongyo			c[0] = c[-1];
2060203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2061203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2062203945Sweongyo			c++, (*nchans)++;
2063203945Sweongyo		}
2064203945Sweongyo	}
2065203945Sweongyo}
2066203945Sweongyo
2067203945Sweongyostatic int
2068203945Sweongyobwn_phy_g_attach(struct bwn_mac *mac)
2069203945Sweongyo{
2070203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2071203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2072203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2073203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
2074203945Sweongyo	struct siba_sprom *sprom = &sd->sd_bus->siba_sprom;
2075203945Sweongyo	unsigned int i;
2076203945Sweongyo	int16_t pab0 = (int16_t)(sprom->pa0b0), pab1 = (int16_t)(sprom->pa0b1),
2077203945Sweongyo	    pab2 = (int16_t)(sprom->pa0b2);
2078203945Sweongyo	static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
2079203945Sweongyo	int8_t bg = (int8_t)sprom->tssi_bg;
2080203945Sweongyo
2081203945Sweongyo	if ((sd->sd_bus->siba_chipid == 0x4301) && (phy->rf_ver != 0x2050))
2082203945Sweongyo		device_printf(sc->sc_dev, "not supported anymore\n");
2083203945Sweongyo
2084203945Sweongyo	pg->pg_flags = 0;
2085203945Sweongyo	if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
2086203945Sweongyo	    pab2 == -1) {
2087203945Sweongyo		pg->pg_idletssi = 52;
2088203945Sweongyo		pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
2089203945Sweongyo		return (0);
2090203945Sweongyo	}
2091203945Sweongyo
2092203945Sweongyo	pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
2093203945Sweongyo	pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
2094203945Sweongyo	if (pg->pg_tssi2dbm == NULL) {
2095203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer\n");
2096203945Sweongyo		return (ENOMEM);
2097203945Sweongyo	}
2098203945Sweongyo	for (i = 0; i < 64; i++) {
2099203945Sweongyo		int32_t m1, m2, f, q, delta;
2100203945Sweongyo		int8_t j = 0;
2101203945Sweongyo
2102203945Sweongyo		m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
2103203945Sweongyo		m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
2104203945Sweongyo		f = 256;
2105203945Sweongyo
2106203945Sweongyo		do {
2107203945Sweongyo			if (j > 15) {
2108203945Sweongyo				device_printf(sc->sc_dev,
2109203945Sweongyo				    "failed to generate tssi2dBm\n");
2110203945Sweongyo				free(pg->pg_tssi2dbm, M_DEVBUF);
2111203945Sweongyo				return (ENOMEM);
2112203945Sweongyo			}
2113203945Sweongyo			q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
2114203945Sweongyo			    f, 2048);
2115203945Sweongyo			delta = abs(q - f);
2116203945Sweongyo			f = q;
2117203945Sweongyo			j++;
2118203945Sweongyo		} while (delta >= 2);
2119203945Sweongyo
2120203945Sweongyo		pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
2121203945Sweongyo		    128);
2122203945Sweongyo	}
2123203945Sweongyo
2124203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
2125203945Sweongyo	return (0);
2126203945Sweongyo}
2127203945Sweongyo
2128203945Sweongyostatic void
2129203945Sweongyobwn_phy_g_detach(struct bwn_mac *mac)
2130203945Sweongyo{
2131203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
2132203945Sweongyo
2133203945Sweongyo	if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
2134203945Sweongyo		free(pg->pg_tssi2dbm, M_DEVBUF);
2135203945Sweongyo		pg->pg_tssi2dbm = NULL;
2136203945Sweongyo	}
2137203945Sweongyo	pg->pg_flags = 0;
2138203945Sweongyo}
2139203945Sweongyo
2140203945Sweongyostatic void
2141203945Sweongyobwn_phy_g_init_pre(struct bwn_mac *mac)
2142203945Sweongyo{
2143203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2144203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2145203945Sweongyo	void *tssi2dbm;
2146203945Sweongyo	int idletssi;
2147203945Sweongyo	unsigned int i;
2148203945Sweongyo
2149203945Sweongyo	tssi2dbm = pg->pg_tssi2dbm;
2150203945Sweongyo	idletssi = pg->pg_idletssi;
2151203945Sweongyo
2152203945Sweongyo	memset(pg, 0, sizeof(*pg));
2153203945Sweongyo
2154203945Sweongyo	pg->pg_tssi2dbm = tssi2dbm;
2155203945Sweongyo	pg->pg_idletssi = idletssi;
2156203945Sweongyo
2157203945Sweongyo	memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
2158203945Sweongyo
2159203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi); i++)
2160203945Sweongyo		pg->pg_nrssi[i] = -1000;
2161203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi_lt); i++)
2162203945Sweongyo		pg->pg_nrssi_lt[i] = i;
2163203945Sweongyo	pg->pg_lofcal = 0xffff;
2164203945Sweongyo	pg->pg_initval = 0xffff;
2165203945Sweongyo	pg->pg_immode = BWN_IMMODE_NONE;
2166203945Sweongyo	pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
2167203945Sweongyo	pg->pg_avgtssi = 0xff;
2168203945Sweongyo
2169203945Sweongyo	pg->pg_loctl.tx_bias = 0xff;
2170203945Sweongyo	TAILQ_INIT(&pg->pg_loctl.calib_list);
2171203945Sweongyo}
2172203945Sweongyo
2173203945Sweongyostatic int
2174203945Sweongyobwn_phy_g_prepare_hw(struct bwn_mac *mac)
2175203945Sweongyo{
2176203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2177203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2178203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2179203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
2180203945Sweongyo	static const struct bwn_rfatt rfatt0[] = {
2181203945Sweongyo		{ 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 },	{ 9, 0 }, { 2, 0 },
2182203945Sweongyo		{ 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
2183203945Sweongyo		{ 3, 1 }, { 4, 1 }
2184203945Sweongyo	};
2185203945Sweongyo	static const struct bwn_rfatt rfatt1[] = {
2186203945Sweongyo		{ 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
2187203945Sweongyo		{ 14, 1 }
2188203945Sweongyo	};
2189203945Sweongyo	static const struct bwn_rfatt rfatt2[] = {
2190203945Sweongyo		{ 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
2191203945Sweongyo		{ 9, 1 }
2192203945Sweongyo	};
2193203945Sweongyo	static const struct bwn_bbatt bbatt_0[] = {
2194203945Sweongyo		{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
2195203945Sweongyo	};
2196203945Sweongyo
2197203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
2198203945Sweongyo
2199203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
2200203945Sweongyo		pg->pg_bbatt.att = 0;
2201203945Sweongyo	else
2202203945Sweongyo		pg->pg_bbatt.att = 2;
2203203945Sweongyo
2204203945Sweongyo	/* prepare Radio Attenuation */
2205203945Sweongyo	pg->pg_rfatt.padmix = 0;
2206203945Sweongyo
2207203945Sweongyo	if (bus->siba_board_vendor == SIBA_BOARDVENDOR_BCM &&
2208203945Sweongyo	    bus->siba_board_type == SIBA_BOARD_BCM4309G) {
2209203945Sweongyo		if (bus->siba_board_rev < 0x43) {
2210203945Sweongyo			pg->pg_rfatt.att = 2;
2211203945Sweongyo			goto done;
2212203945Sweongyo		} else if (bus->siba_board_rev < 0x51) {
2213203945Sweongyo			pg->pg_rfatt.att = 3;
2214203945Sweongyo			goto done;
2215203945Sweongyo		}
2216203945Sweongyo	}
2217203945Sweongyo
2218203945Sweongyo	if (phy->type == BWN_PHYTYPE_A) {
2219203945Sweongyo		pg->pg_rfatt.att = 0x60;
2220203945Sweongyo		goto done;
2221203945Sweongyo	}
2222203945Sweongyo
2223203945Sweongyo	switch (phy->rf_ver) {
2224203945Sweongyo	case 0x2050:
2225203945Sweongyo		switch (phy->rf_rev) {
2226203945Sweongyo		case 0:
2227203945Sweongyo			pg->pg_rfatt.att = 5;
2228203945Sweongyo			goto done;
2229203945Sweongyo		case 1:
2230203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2231203945Sweongyo				if (bus->siba_board_vendor ==
2232203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2233203945Sweongyo				    bus->siba_board_type ==
2234203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2235203945Sweongyo				    bus->siba_board_rev >= 30)
2236203945Sweongyo					pg->pg_rfatt.att = 3;
2237203945Sweongyo				else if (bus->siba_board_vendor ==
2238203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2239203945Sweongyo				    bus->siba_board_type == SIBA_BOARD_BU4306)
2240203945Sweongyo					pg->pg_rfatt.att = 3;
2241203945Sweongyo				else
2242203945Sweongyo					pg->pg_rfatt.att = 1;
2243203945Sweongyo			} else {
2244203945Sweongyo				if (bus->siba_board_vendor ==
2245203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2246203945Sweongyo				    bus->siba_board_type ==
2247203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2248203945Sweongyo				    bus->siba_board_rev >= 30)
2249203945Sweongyo					pg->pg_rfatt.att = 7;
2250203945Sweongyo				else
2251203945Sweongyo					pg->pg_rfatt.att = 6;
2252203945Sweongyo			}
2253203945Sweongyo			goto done;
2254203945Sweongyo		case 2:
2255203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2256203945Sweongyo				if (bus->siba_board_vendor ==
2257203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2258203945Sweongyo				    bus->siba_board_type ==
2259203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2260203945Sweongyo				    bus->siba_board_rev >= 30)
2261203945Sweongyo					pg->pg_rfatt.att = 3;
2262203945Sweongyo				else if (bus->siba_board_vendor ==
2263203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2264203945Sweongyo				    bus->siba_board_type == SIBA_BOARD_BU4306)
2265203945Sweongyo					pg->pg_rfatt.att = 5;
2266203945Sweongyo				else if (bus->siba_chipid == 0x4320)
2267203945Sweongyo					pg->pg_rfatt.att = 4;
2268203945Sweongyo				else
2269203945Sweongyo					pg->pg_rfatt.att = 3;
2270203945Sweongyo			} else
2271203945Sweongyo				pg->pg_rfatt.att = 6;
2272203945Sweongyo			goto done;
2273203945Sweongyo		case 3:
2274203945Sweongyo			pg->pg_rfatt.att = 5;
2275203945Sweongyo			goto done;
2276203945Sweongyo		case 4:
2277203945Sweongyo		case 5:
2278203945Sweongyo			pg->pg_rfatt.att = 1;
2279203945Sweongyo			goto done;
2280203945Sweongyo		case 6:
2281203945Sweongyo		case 7:
2282203945Sweongyo			pg->pg_rfatt.att = 5;
2283203945Sweongyo			goto done;
2284203945Sweongyo		case 8:
2285203945Sweongyo			pg->pg_rfatt.att = 0xa;
2286203945Sweongyo			pg->pg_rfatt.padmix = 1;
2287203945Sweongyo			goto done;
2288203945Sweongyo		case 9:
2289203945Sweongyo		default:
2290203945Sweongyo			pg->pg_rfatt.att = 5;
2291203945Sweongyo			goto done;
2292203945Sweongyo		}
2293203945Sweongyo		break;
2294203945Sweongyo	case 0x2053:
2295203945Sweongyo		switch (phy->rf_rev) {
2296203945Sweongyo		case 1:
2297203945Sweongyo			pg->pg_rfatt.att = 6;
2298203945Sweongyo			goto done;
2299203945Sweongyo		}
2300203945Sweongyo		break;
2301203945Sweongyo	}
2302203945Sweongyo	pg->pg_rfatt.att = 5;
2303203945Sweongyodone:
2304203945Sweongyo	pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
2305203945Sweongyo
2306203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
2307203945Sweongyo		lo->rfatt.array = rfatt0;
2308203945Sweongyo		lo->rfatt.len = N(rfatt0);
2309203945Sweongyo		lo->rfatt.min = 0;
2310203945Sweongyo		lo->rfatt.max = 9;
2311203945Sweongyo		goto genbbatt;
2312203945Sweongyo	}
2313203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
2314203945Sweongyo		lo->rfatt.array = rfatt1;
2315203945Sweongyo		lo->rfatt.len = N(rfatt1);
2316203945Sweongyo		lo->rfatt.min = 0;
2317203945Sweongyo		lo->rfatt.max = 14;
2318203945Sweongyo		goto genbbatt;
2319203945Sweongyo	}
2320203945Sweongyo	lo->rfatt.array = rfatt2;
2321203945Sweongyo	lo->rfatt.len = N(rfatt2);
2322203945Sweongyo	lo->rfatt.min = 0;
2323203945Sweongyo	lo->rfatt.max = 9;
2324203945Sweongyogenbbatt:
2325203945Sweongyo	lo->bbatt.array = bbatt_0;
2326203945Sweongyo	lo->bbatt.len = N(bbatt_0);
2327203945Sweongyo	lo->bbatt.min = 0;
2328203945Sweongyo	lo->bbatt.max = 8;
2329203945Sweongyo
2330203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
2331203945Sweongyo	if (phy->rev == 1) {
2332203945Sweongyo		phy->gmode = 0;
2333203945Sweongyo		bwn_reset_core(mac, 0);
2334203945Sweongyo		bwn_phy_g_init_sub(mac);
2335203945Sweongyo		phy->gmode = 1;
2336203945Sweongyo		bwn_reset_core(mac, BWN_TGSLOW_SUPPORT_G);
2337203945Sweongyo	}
2338203945Sweongyo	return (0);
2339203945Sweongyo}
2340203945Sweongyo
2341203945Sweongyostatic uint16_t
2342203945Sweongyobwn_phy_g_txctl(struct bwn_mac *mac)
2343203945Sweongyo{
2344203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2345203945Sweongyo
2346203945Sweongyo	if (phy->rf_ver != 0x2050)
2347203945Sweongyo		return (0);
2348203945Sweongyo	if (phy->rf_rev == 1)
2349203945Sweongyo		return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
2350203945Sweongyo	if (phy->rf_rev < 6)
2351203945Sweongyo		return (BWN_TXCTL_PA2DB);
2352203945Sweongyo	if (phy->rf_rev == 8)
2353203945Sweongyo		return (BWN_TXCTL_TXMIX);
2354203945Sweongyo	return (0);
2355203945Sweongyo}
2356203945Sweongyo
2357203945Sweongyostatic int
2358203945Sweongyobwn_phy_g_init(struct bwn_mac *mac)
2359203945Sweongyo{
2360203945Sweongyo
2361203945Sweongyo	bwn_phy_g_init_sub(mac);
2362203945Sweongyo	return (0);
2363203945Sweongyo}
2364203945Sweongyo
2365203945Sweongyostatic void
2366203945Sweongyobwn_phy_g_exit(struct bwn_mac *mac)
2367203945Sweongyo{
2368203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
2369203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2370203945Sweongyo
2371203945Sweongyo	if (lo == NULL)
2372203945Sweongyo		return;
2373203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2374203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2375203945Sweongyo		free(cal, M_DEVBUF);
2376203945Sweongyo	}
2377203945Sweongyo}
2378203945Sweongyo
2379203945Sweongyostatic uint16_t
2380203945Sweongyobwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
2381203945Sweongyo{
2382203945Sweongyo
2383203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2384203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
2385203945Sweongyo}
2386203945Sweongyo
2387203945Sweongyostatic void
2388203945Sweongyobwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2389203945Sweongyo{
2390203945Sweongyo
2391203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2392203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
2393203945Sweongyo}
2394203945Sweongyo
2395203945Sweongyostatic uint16_t
2396203945Sweongyobwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
2397203945Sweongyo{
2398203945Sweongyo
2399203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2400203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
2401203945Sweongyo	return (BWN_READ_2(mac, BWN_RFDATALO));
2402203945Sweongyo}
2403203945Sweongyo
2404203945Sweongyostatic void
2405203945Sweongyobwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2406203945Sweongyo{
2407203945Sweongyo
2408203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2409203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
2410203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
2411203945Sweongyo}
2412203945Sweongyo
2413203945Sweongyostatic int
2414203945Sweongyobwn_phy_g_hwpctl(struct bwn_mac *mac)
2415203945Sweongyo{
2416203945Sweongyo
2417203945Sweongyo	return (mac->mac_phy.rev >= 6);
2418203945Sweongyo}
2419203945Sweongyo
2420203945Sweongyostatic void
2421203945Sweongyobwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
2422203945Sweongyo{
2423203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2424203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2425203945Sweongyo	unsigned int channel;
2426203945Sweongyo	uint16_t rfover, rfoverval;
2427203945Sweongyo
2428203945Sweongyo	if (on) {
2429203945Sweongyo		if (phy->rf_on)
2430203945Sweongyo			return;
2431203945Sweongyo
2432203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0x8000);
2433203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0xcc00);
2434203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
2435203945Sweongyo		if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
2436203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
2437203945Sweongyo			    pg->pg_radioctx_over);
2438203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
2439203945Sweongyo			    pg->pg_radioctx_overval);
2440203945Sweongyo			pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
2441203945Sweongyo		}
2442203945Sweongyo		channel = phy->chan;
2443203945Sweongyo		bwn_phy_g_switch_chan(mac, 6, 1);
2444203945Sweongyo		bwn_phy_g_switch_chan(mac, channel, 0);
2445203945Sweongyo		return;
2446203945Sweongyo	}
2447203945Sweongyo
2448203945Sweongyo	rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
2449203945Sweongyo	rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
2450203945Sweongyo	pg->pg_radioctx_over = rfover;
2451203945Sweongyo	pg->pg_radioctx_overval = rfoverval;
2452203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
2453203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
2454203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
2455203945Sweongyo}
2456203945Sweongyo
2457203945Sweongyostatic int
2458203945Sweongyobwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
2459203945Sweongyo{
2460203945Sweongyo
2461203945Sweongyo	if ((newchan < 1) || (newchan > 14))
2462203945Sweongyo		return (EINVAL);
2463203945Sweongyo	bwn_phy_g_switch_chan(mac, newchan, 0);
2464203945Sweongyo
2465203945Sweongyo	return (0);
2466203945Sweongyo}
2467203945Sweongyo
2468203945Sweongyostatic uint32_t
2469203945Sweongyobwn_phy_g_get_default_chan(struct bwn_mac *mac)
2470203945Sweongyo{
2471203945Sweongyo
2472203945Sweongyo	return (1);
2473203945Sweongyo}
2474203945Sweongyo
2475203945Sweongyostatic void
2476203945Sweongyobwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
2477203945Sweongyo{
2478203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2479203945Sweongyo	uint64_t hf;
2480203945Sweongyo	int autodiv = 0;
2481203945Sweongyo	uint16_t tmp;
2482203945Sweongyo
2483203945Sweongyo	if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
2484203945Sweongyo		autodiv = 1;
2485203945Sweongyo
2486203945Sweongyo	hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
2487203945Sweongyo	bwn_hf_write(mac, hf);
2488203945Sweongyo
2489203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
2490203945Sweongyo	    (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
2491203945Sweongyo	    ((autodiv ? BWN_ANTAUTO1 : antenna)
2492203945Sweongyo		<< BWN_PHY_BBANDCFG_RXANT_SHIFT));
2493203945Sweongyo
2494203945Sweongyo	if (autodiv) {
2495203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
2496203945Sweongyo		if (antenna == BWN_ANTAUTO1)
2497203945Sweongyo			tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
2498203945Sweongyo		else
2499203945Sweongyo			tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
2500203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
2501203945Sweongyo	}
2502203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
2503203945Sweongyo	if (autodiv)
2504203945Sweongyo		tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
2505203945Sweongyo	else
2506203945Sweongyo		tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
2507203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
2508203945Sweongyo	if (phy->rev >= 2) {
2509203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
2510203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
2511203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
2512203945Sweongyo		    (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
2513203945Sweongyo		    0x15);
2514203945Sweongyo		if (phy->rev == 2)
2515203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
2516203945Sweongyo		else
2517203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
2518203945Sweongyo			    (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
2519203945Sweongyo			    8);
2520203945Sweongyo	}
2521203945Sweongyo	if (phy->rev >= 6)
2522203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
2523203945Sweongyo
2524203945Sweongyo	hf |= BWN_HF_UCODE_ANTDIV_HELPER;
2525203945Sweongyo	bwn_hf_write(mac, hf);
2526203945Sweongyo}
2527203945Sweongyo
2528203945Sweongyostatic int
2529203945Sweongyobwn_phy_g_im(struct bwn_mac *mac, int mode)
2530203945Sweongyo{
2531203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2532203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2533203945Sweongyo
2534203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2535203945Sweongyo	KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
2536203945Sweongyo
2537203945Sweongyo	if (phy->rev == 0 || !phy->gmode)
2538203945Sweongyo		return (ENODEV);
2539203945Sweongyo
2540203945Sweongyo	pg->pg_aci_wlan_automatic = 0;
2541203945Sweongyo	return (0);
2542203945Sweongyo}
2543203945Sweongyo
2544203945Sweongyostatic int
2545203945Sweongyobwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
2546203945Sweongyo{
2547203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2548203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2549203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2550203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
2551203945Sweongyo	unsigned int tssi;
2552203945Sweongyo	int cck, ofdm;
2553203945Sweongyo	int power;
2554203945Sweongyo	int rfatt, bbatt;
2555203945Sweongyo	unsigned int max;
2556203945Sweongyo
2557203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2558203945Sweongyo
2559203945Sweongyo	cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
2560203945Sweongyo	ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
2561203945Sweongyo	if (cck < 0 && ofdm < 0) {
2562203945Sweongyo		if (ignore_tssi == 0)
2563203945Sweongyo			return (BWN_TXPWR_RES_DONE);
2564203945Sweongyo		cck = 0;
2565203945Sweongyo		ofdm = 0;
2566203945Sweongyo	}
2567203945Sweongyo	tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
2568203945Sweongyo	if (pg->pg_avgtssi != 0xff)
2569203945Sweongyo		tssi = (tssi + pg->pg_avgtssi) / 2;
2570203945Sweongyo	pg->pg_avgtssi = tssi;
2571203945Sweongyo	KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
2572203945Sweongyo
2573203945Sweongyo	max = siba->siba_sprom.maxpwr_bg;
2574203945Sweongyo	if (siba->siba_sprom.bf_lo & BWN_BFL_PACTRL)
2575203945Sweongyo		max -= 3;
2576203945Sweongyo	if (max >= 120) {
2577203945Sweongyo		device_printf(sc->sc_dev, "invalid max TX-power value\n");
2578203945Sweongyo		siba->siba_sprom.maxpwr_bg = max = 80;
2579203945Sweongyo	}
2580203945Sweongyo
2581203945Sweongyo	power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
2582203945Sweongyo	    (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
2583203945Sweongyo	     tssi, 0x00), 0x3f)]);
2584203945Sweongyo	if (power == 0)
2585203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2586203945Sweongyo
2587203945Sweongyo	rfatt = -((power + 7) / 8);
2588203945Sweongyo	bbatt = (-(power / 2)) - (4 * rfatt);
2589203945Sweongyo	if ((rfatt == 0) && (bbatt == 0))
2590203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2591203945Sweongyo	pg->pg_bbatt_delta = bbatt;
2592203945Sweongyo	pg->pg_rfatt_delta = rfatt;
2593203945Sweongyo	return (BWN_TXPWR_RES_NEED_ADJUST);
2594203945Sweongyo}
2595203945Sweongyo
2596203945Sweongyostatic void
2597203945Sweongyobwn_phy_g_set_txpwr(struct bwn_mac *mac)
2598203945Sweongyo{
2599203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2600203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2601203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2602203945Sweongyo	int rfatt, bbatt;
2603203945Sweongyo	uint8_t txctl;
2604203945Sweongyo
2605203945Sweongyo	bwn_mac_suspend(mac);
2606203945Sweongyo
2607203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2608203945Sweongyo
2609203945Sweongyo	bbatt = pg->pg_bbatt.att;
2610203945Sweongyo	bbatt += pg->pg_bbatt_delta;
2611203945Sweongyo	rfatt = pg->pg_rfatt.att;
2612203945Sweongyo	rfatt += pg->pg_rfatt_delta;
2613203945Sweongyo
2614203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2615203945Sweongyo	txctl = pg->pg_txctl;
2616203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
2617203945Sweongyo		if (rfatt <= 1) {
2618203945Sweongyo			if (txctl == 0) {
2619203945Sweongyo				txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
2620203945Sweongyo				rfatt += 2;
2621203945Sweongyo				bbatt += 2;
2622203945Sweongyo			} else if (mac->mac_sd->sd_bus->siba_sprom.
2623203945Sweongyo				   bf_lo &
2624203945Sweongyo				   BWN_BFL_PACTRL) {
2625203945Sweongyo				bbatt += 4 * (rfatt - 2);
2626203945Sweongyo				rfatt = 2;
2627203945Sweongyo			}
2628203945Sweongyo		} else if (rfatt > 4 && txctl) {
2629203945Sweongyo			txctl = 0;
2630203945Sweongyo			if (bbatt < 3) {
2631203945Sweongyo				rfatt -= 3;
2632203945Sweongyo				bbatt += 2;
2633203945Sweongyo			} else {
2634203945Sweongyo				rfatt -= 2;
2635203945Sweongyo				bbatt -= 2;
2636203945Sweongyo			}
2637203945Sweongyo		}
2638203945Sweongyo	}
2639203945Sweongyo	pg->pg_txctl = txctl;
2640203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2641203945Sweongyo	pg->pg_rfatt.att = rfatt;
2642203945Sweongyo	pg->pg_bbatt.att = bbatt;
2643203945Sweongyo
2644203945Sweongyo	DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
2645203945Sweongyo
2646203945Sweongyo	bwn_phy_lock(mac);
2647203945Sweongyo	bwn_rf_lock(mac);
2648203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
2649203945Sweongyo	    pg->pg_txctl);
2650203945Sweongyo	bwn_rf_unlock(mac);
2651203945Sweongyo	bwn_phy_unlock(mac);
2652203945Sweongyo
2653203945Sweongyo	bwn_mac_enable(mac);
2654203945Sweongyo}
2655203945Sweongyo
2656203945Sweongyostatic void
2657203945Sweongyobwn_phy_g_task_15s(struct bwn_mac *mac)
2658203945Sweongyo{
2659203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2660203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2661203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2662203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2663203945Sweongyo	unsigned long expire, now;
2664203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2665203945Sweongyo	uint8_t expired = 0;
2666203945Sweongyo
2667203945Sweongyo	bwn_mac_suspend(mac);
2668203945Sweongyo
2669203945Sweongyo	if (lo == NULL)
2670203945Sweongyo		goto fail;
2671203945Sweongyo
2672203945Sweongyo	BWN_GETTIME(now);
2673203945Sweongyo	if (bwn_has_hwpctl(mac)) {
2674203945Sweongyo		expire = now - BWN_LO_PWRVEC_EXPIRE;
2675203945Sweongyo		if (time_before(lo->pwr_vec_read_time, expire)) {
2676203945Sweongyo			bwn_lo_get_powervector(mac);
2677203945Sweongyo			bwn_phy_g_dc_lookup_init(mac, 0);
2678203945Sweongyo		}
2679203945Sweongyo		goto fail;
2680203945Sweongyo	}
2681203945Sweongyo
2682203945Sweongyo	expire = now - BWN_LO_CALIB_EXPIRE;
2683203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2684203945Sweongyo		if (!time_before(cal->calib_time, expire))
2685203945Sweongyo			continue;
2686203945Sweongyo		if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
2687203945Sweongyo		    BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
2688203945Sweongyo			KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
2689203945Sweongyo			expired = 1;
2690203945Sweongyo		}
2691203945Sweongyo
2692203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
2693203945Sweongyo		    cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
2694203945Sweongyo		    cal->ctl.i, cal->ctl.q);
2695203945Sweongyo
2696203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2697203945Sweongyo		free(cal, M_DEVBUF);
2698203945Sweongyo	}
2699203945Sweongyo	if (expired || TAILQ_EMPTY(&lo->calib_list)) {
2700203945Sweongyo		cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
2701203945Sweongyo		    &pg->pg_rfatt);
2702203945Sweongyo		if (cal == NULL) {
2703203945Sweongyo			device_printf(sc->sc_dev,
2704203945Sweongyo			    "failed to recalibrate LO\n");
2705203945Sweongyo			goto fail;
2706203945Sweongyo		}
2707203945Sweongyo		TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
2708203945Sweongyo		bwn_lo_write(mac, &cal->ctl);
2709203945Sweongyo	}
2710203945Sweongyo
2711203945Sweongyofail:
2712203945Sweongyo	bwn_mac_enable(mac);
2713203945Sweongyo}
2714203945Sweongyo
2715203945Sweongyostatic void
2716203945Sweongyobwn_phy_g_task_60s(struct bwn_mac *mac)
2717203945Sweongyo{
2718203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2719203945Sweongyo	uint8_t old = phy->chan;
2720203945Sweongyo
2721203945Sweongyo	if (!(mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_RSSI))
2722203945Sweongyo		return;
2723203945Sweongyo
2724203945Sweongyo	bwn_mac_suspend(mac);
2725203945Sweongyo	bwn_nrssi_slope_11g(mac);
2726203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
2727203945Sweongyo		bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
2728203945Sweongyo		bwn_switch_channel(mac, old);
2729203945Sweongyo	}
2730203945Sweongyo	bwn_mac_enable(mac);
2731203945Sweongyo}
2732203945Sweongyo
2733203945Sweongyostatic void
2734203945Sweongyobwn_phy_switch_analog(struct bwn_mac *mac, int on)
2735203945Sweongyo{
2736203945Sweongyo
2737203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
2738203945Sweongyo}
2739203945Sweongyo
2740203945Sweongyostatic int
2741203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
2742203945Sweongyo	const struct ieee80211_bpf_params *params)
2743203945Sweongyo{
2744203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2745203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2746203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2747203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2748203945Sweongyo
2749203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
2750203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
2751203945Sweongyo		ieee80211_free_node(ni);
2752203945Sweongyo		m_freem(m);
2753203945Sweongyo		return (ENETDOWN);
2754203945Sweongyo	}
2755203945Sweongyo
2756203945Sweongyo	BWN_LOCK(sc);
2757203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
2758203945Sweongyo		ieee80211_free_node(ni);
2759203945Sweongyo		m_freem(m);
2760203945Sweongyo		ifp->if_oerrors++;
2761203945Sweongyo		BWN_UNLOCK(sc);
2762203945Sweongyo		return (ENOBUFS);
2763203945Sweongyo	}
2764203945Sweongyo
2765203945Sweongyo	if (bwn_tx_start(sc, ni, m) != 0) {
2766203945Sweongyo		if (ni != NULL)
2767203945Sweongyo			ieee80211_free_node(ni);
2768203945Sweongyo		ifp->if_oerrors++;
2769203945Sweongyo	}
2770203945Sweongyo	sc->sc_watchdog_timer = 5;
2771203945Sweongyo	BWN_UNLOCK(sc);
2772203945Sweongyo	return (0);
2773203945Sweongyo}
2774203945Sweongyo
2775203945Sweongyo/*
2776203945Sweongyo * Setup driver-specific state for a newly associated node.
2777203945Sweongyo * Note that we're called also on a re-associate, the isnew
2778203945Sweongyo * param tells us if this is the first time or not.
2779203945Sweongyo */
2780203945Sweongyostatic void
2781203945Sweongyobwn_newassoc(struct ieee80211_node *ni, int isnew)
2782203945Sweongyo{
2783203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
2784203945Sweongyo
2785203945Sweongyo	ieee80211_amrr_node_init(&BWN_VAP(vap)->bv_amrr,
2786203945Sweongyo	    &BWN_NODE(ni)->bn_amn, ni);
2787203945Sweongyo}
2788203945Sweongyo
2789203945Sweongyo/*
2790203945Sweongyo * Callback from the 802.11 layer to update the slot time
2791203945Sweongyo * based on the current setting.  We use it to notify the
2792203945Sweongyo * firmware of ERP changes and the f/w takes care of things
2793203945Sweongyo * like slot time and preamble.
2794203945Sweongyo */
2795203945Sweongyostatic void
2796203945Sweongyobwn_updateslot(struct ifnet *ifp)
2797203945Sweongyo{
2798203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2799203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
2800203945Sweongyo	struct bwn_mac *mac;
2801203945Sweongyo
2802203945Sweongyo	BWN_LOCK(sc);
2803203945Sweongyo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2804203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
2805203945Sweongyo		bwn_set_slot_time(mac,
2806203945Sweongyo		    (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20);
2807203945Sweongyo	}
2808203945Sweongyo	BWN_UNLOCK(sc);
2809203945Sweongyo}
2810203945Sweongyo
2811203945Sweongyo/*
2812203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
2813203945Sweongyo * Note this interface does not check the operating mode as this
2814203945Sweongyo * is an internal callback and we are expected to honor the current
2815203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
2816203945Sweongyo * mode when operating in hostap mode to do ACS).
2817203945Sweongyo */
2818203945Sweongyostatic void
2819203945Sweongyobwn_update_promisc(struct ifnet *ifp)
2820203945Sweongyo{
2821203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2822203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2823203945Sweongyo
2824203945Sweongyo	BWN_LOCK(sc);
2825203945Sweongyo	mac = sc->sc_curmac;
2826203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2827203945Sweongyo		if (ifp->if_flags & IFF_PROMISC)
2828203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
2829203945Sweongyo		else
2830203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
2831203945Sweongyo		bwn_set_opmode(mac);
2832203945Sweongyo	}
2833203945Sweongyo	BWN_UNLOCK(sc);
2834203945Sweongyo}
2835203945Sweongyo
2836203945Sweongyo/*
2837203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
2838203945Sweongyo */
2839203945Sweongyostatic int
2840203945Sweongyobwn_wme_update(struct ieee80211com *ic)
2841203945Sweongyo{
2842203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2843203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2844203945Sweongyo	struct wmeParams *wmep;
2845203945Sweongyo	int i;
2846203945Sweongyo
2847203945Sweongyo	BWN_LOCK(sc);
2848203945Sweongyo	mac = sc->sc_curmac;
2849203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2850203945Sweongyo		bwn_mac_suspend(mac);
2851203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
2852203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
2853203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
2854203945Sweongyo		}
2855203945Sweongyo		bwn_mac_enable(mac);
2856203945Sweongyo	}
2857203945Sweongyo	BWN_UNLOCK(sc);
2858203945Sweongyo	return (0);
2859203945Sweongyo}
2860203945Sweongyo
2861203945Sweongyostatic struct ieee80211_node *
2862203945Sweongyobwn_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
2863203945Sweongyo{
2864203945Sweongyo	struct ieee80211com *ic = vap->iv_ic;
2865203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2866203945Sweongyo	const size_t space = sizeof(struct bwn_node);
2867203945Sweongyo	struct bwn_node *bn;
2868203945Sweongyo
2869203945Sweongyo	bn = malloc(space, M_80211_NODE, M_NOWAIT|M_ZERO);
2870203945Sweongyo	if (bn == NULL) {
2871203945Sweongyo		/* XXX stat+msg */
2872203945Sweongyo		return (NULL);
2873203945Sweongyo	}
2874203945Sweongyo	DPRINTF(sc, BWN_DEBUG_NODE, "%s: bn %p\n", __func__, bn);
2875203945Sweongyo	return (&bn->bn_node);
2876203945Sweongyo}
2877203945Sweongyo
2878203945Sweongyostatic void
2879203945Sweongyobwn_node_cleanup(struct ieee80211_node *ni)
2880203945Sweongyo{
2881203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2882203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2883203945Sweongyo
2884203945Sweongyo	sc->sc_node_cleanup(ni);
2885203945Sweongyo}
2886203945Sweongyo
2887203945Sweongyostatic void
2888203945Sweongyobwn_scan_start(struct ieee80211com *ic)
2889203945Sweongyo{
2890203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2891203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2892203945Sweongyo	struct bwn_mac *mac;
2893203945Sweongyo
2894203945Sweongyo	BWN_LOCK(sc);
2895203945Sweongyo	mac = sc->sc_curmac;
2896203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2897203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
2898203945Sweongyo		bwn_set_opmode(mac);
2899203945Sweongyo		/* disable CFP update during scan */
2900203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
2901203945Sweongyo	}
2902203945Sweongyo	BWN_UNLOCK(sc);
2903203945Sweongyo}
2904203945Sweongyo
2905203945Sweongyostatic void
2906203945Sweongyobwn_scan_end(struct ieee80211com *ic)
2907203945Sweongyo{
2908203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2909203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2910203945Sweongyo	struct bwn_mac *mac;
2911203945Sweongyo
2912203945Sweongyo	BWN_LOCK(sc);
2913203945Sweongyo	mac = sc->sc_curmac;
2914203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2915203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
2916203945Sweongyo		bwn_set_opmode(mac);
2917203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
2918203945Sweongyo	}
2919203945Sweongyo	BWN_UNLOCK(sc);
2920203945Sweongyo}
2921203945Sweongyo
2922203945Sweongyostatic void
2923203945Sweongyobwn_set_channel(struct ieee80211com *ic)
2924203945Sweongyo{
2925203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2926203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2927203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2928203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2929203945Sweongyo	int chan, error;
2930203945Sweongyo
2931203945Sweongyo	BWN_LOCK(sc);
2932203945Sweongyo
2933203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
2934203945Sweongyo	if (error)
2935203945Sweongyo		goto fail;;
2936203945Sweongyo	bwn_mac_suspend(mac);
2937203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2938203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
2939203945Sweongyo	if (chan != phy->chan)
2940203945Sweongyo		bwn_switch_channel(mac, chan);
2941203945Sweongyo
2942203945Sweongyo	/* TX power level */
2943203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
2944203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
2945203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
2946203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
2947203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
2948203945Sweongyo	}
2949203945Sweongyo
2950203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2951203945Sweongyo	if (phy->set_antenna)
2952203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2953203945Sweongyo
2954203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
2955203945Sweongyo		if (sc->sc_rf_enabled) {
2956203945Sweongyo			bwn_rf_turnon(mac);
2957203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
2958203945Sweongyo				device_printf(sc->sc_dev,
2959203945Sweongyo				    "please turns on the RF switch\n");
2960203945Sweongyo		} else
2961203945Sweongyo			bwn_rf_turnoff(mac);
2962203945Sweongyo	}
2963203945Sweongyo
2964203945Sweongyo	bwn_mac_enable(mac);
2965203945Sweongyo
2966203945Sweongyofail:
2967203945Sweongyo	/*
2968203945Sweongyo	 * Setup radio tap channel freq and flags
2969203945Sweongyo	 */
2970203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
2971203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
2972203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
2973203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
2974203945Sweongyo
2975203945Sweongyo	BWN_UNLOCK(sc);
2976203945Sweongyo}
2977203945Sweongyo
2978203945Sweongyostatic struct ieee80211vap *
2979203945Sweongyobwn_vap_create(struct ieee80211com *ic,
2980203945Sweongyo	const char name[IFNAMSIZ], int unit, int opmode, int flags,
2981203945Sweongyo	const uint8_t bssid[IEEE80211_ADDR_LEN],
2982203945Sweongyo	const uint8_t mac0[IEEE80211_ADDR_LEN])
2983203945Sweongyo{
2984203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2985203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2986203945Sweongyo	struct ieee80211vap *vap;
2987203945Sweongyo	struct bwn_vap *bvp;
2988203945Sweongyo	uint8_t mac[IEEE80211_ADDR_LEN];
2989203945Sweongyo
2990203945Sweongyo	IEEE80211_ADDR_COPY(mac, mac0);
2991203945Sweongyo	switch (opmode) {
2992203945Sweongyo	case IEEE80211_M_HOSTAP:
2993203945Sweongyo	case IEEE80211_M_MBSS:
2994203945Sweongyo	case IEEE80211_M_STA:
2995203945Sweongyo	case IEEE80211_M_WDS:
2996203945Sweongyo	case IEEE80211_M_MONITOR:
2997203945Sweongyo	case IEEE80211_M_IBSS:
2998203945Sweongyo	case IEEE80211_M_AHDEMO:
2999203945Sweongyo		break;
3000203945Sweongyo	default:
3001203945Sweongyo		return (NULL);
3002203945Sweongyo	}
3003203945Sweongyo
3004203945Sweongyo	IEEE80211_ADDR_COPY(sc->sc_macaddr, mac0);
3005203945Sweongyo
3006203945Sweongyo	bvp = (struct bwn_vap *) malloc(sizeof(struct bwn_vap),
3007203945Sweongyo	    M_80211_VAP, M_NOWAIT | M_ZERO);
3008203945Sweongyo	if (bvp == NULL) {
3009203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate a buffer\n");
3010203945Sweongyo		return (NULL);
3011203945Sweongyo	}
3012203945Sweongyo	vap = &bvp->bv_vap;
3013203945Sweongyo	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
3014203945Sweongyo	IEEE80211_ADDR_COPY(vap->iv_myaddr, mac);
3015203945Sweongyo	/* override with driver methods */
3016203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
3017203945Sweongyo	vap->iv_newstate = bwn_newstate;
3018203945Sweongyo
3019203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
3020203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
3021203945Sweongyo
3022203945Sweongyo	ieee80211_amrr_init(&bvp->bv_amrr, vap,
3023203945Sweongyo	    IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
3024203945Sweongyo	    IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
3025203945Sweongyo	    500 /*ms*/);
3026203945Sweongyo
3027203945Sweongyo	/* complete setup */
3028203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
3029203945Sweongyo	    ieee80211_media_status);
3030203945Sweongyo	return (vap);
3031203945Sweongyo}
3032203945Sweongyo
3033203945Sweongyostatic void
3034203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
3035203945Sweongyo{
3036203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
3037203945Sweongyo
3038203945Sweongyo	ieee80211_amrr_cleanup(&bvp->bv_amrr);
3039203945Sweongyo	ieee80211_vap_detach(vap);
3040203945Sweongyo	free(bvp, M_80211_VAP);
3041203945Sweongyo}
3042203945Sweongyo
3043203945Sweongyostatic void
3044203945Sweongyobwn_init(void *arg)
3045203945Sweongyo{
3046203945Sweongyo	struct bwn_softc *sc = arg;
3047203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3048203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
3049203945Sweongyo	int error = 0;
3050203945Sweongyo
3051203945Sweongyo	DPRINTF(sc, BWN_DEBUG_ANY, "%s: if_flags 0x%x\n",
3052203945Sweongyo		__func__, ifp->if_flags);
3053203945Sweongyo
3054203945Sweongyo	BWN_LOCK(sc);
3055203945Sweongyo	error = bwn_init_locked(sc);
3056203945Sweongyo	BWN_UNLOCK(sc);
3057203945Sweongyo
3058203945Sweongyo	if (error == 0)
3059203945Sweongyo		ieee80211_start_all(ic);	/* start all vap's */
3060203945Sweongyo}
3061203945Sweongyo
3062203945Sweongyostatic int
3063203945Sweongyobwn_init_locked(struct bwn_softc *sc)
3064203945Sweongyo{
3065203945Sweongyo	struct bwn_mac *mac;
3066203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3067203945Sweongyo	int error;
3068203945Sweongyo
3069203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3070203945Sweongyo
3071203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
3072203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
3073203945Sweongyo	sc->sc_filters = 0;
3074203945Sweongyo	bwn_wme_clear(sc);
3075203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
3076203945Sweongyo	sc->sc_rf_enabled = 1;
3077203945Sweongyo
3078203945Sweongyo	mac = sc->sc_curmac;
3079203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
3080203945Sweongyo		error = bwn_core_init(mac);
3081203945Sweongyo		if (error != 0)
3082203945Sweongyo			return (error);
3083203945Sweongyo	}
3084203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
3085203945Sweongyo		bwn_core_start(mac);
3086203945Sweongyo
3087203945Sweongyo	bwn_set_opmode(mac);
3088203945Sweongyo	bwn_set_pretbtt(mac);
3089203945Sweongyo	bwn_spu_setdelay(mac, 0);
3090203945Sweongyo	bwn_set_macaddr(mac);
3091203945Sweongyo
3092203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3093203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
3094203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
3095203945Sweongyo
3096203945Sweongyo	return (0);
3097203945Sweongyo}
3098203945Sweongyo
3099203945Sweongyostatic void
3100203945Sweongyobwn_stop(struct bwn_softc *sc, int statechg)
3101203945Sweongyo{
3102203945Sweongyo
3103203945Sweongyo	BWN_LOCK(sc);
3104203945Sweongyo	bwn_stop_locked(sc, statechg);
3105203945Sweongyo	BWN_UNLOCK(sc);
3106203945Sweongyo}
3107203945Sweongyo
3108203945Sweongyostatic void
3109203945Sweongyobwn_stop_locked(struct bwn_softc *sc, int statechg)
3110203945Sweongyo{
3111203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
3112203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3113203945Sweongyo
3114203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3115203945Sweongyo
3116203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
3117203945Sweongyo		/* XXX FIXME opmode not based on VAP */
3118203945Sweongyo		bwn_set_opmode(mac);
3119203945Sweongyo		bwn_set_macaddr(mac);
3120203945Sweongyo	}
3121203945Sweongyo
3122203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
3123203945Sweongyo		bwn_core_stop(mac);
3124203945Sweongyo
3125203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
3126203945Sweongyo	sc->sc_led_blinking = 0;
3127203945Sweongyo
3128203945Sweongyo	bwn_core_exit(mac);
3129203945Sweongyo	sc->sc_rf_enabled = 0;
3130203945Sweongyo
3131203945Sweongyo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3132203945Sweongyo}
3133203945Sweongyo
3134203945Sweongyostatic void
3135203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
3136203945Sweongyo{
3137203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
3138203945Sweongyo	struct wmeParams *p;
3139203945Sweongyo	unsigned int i;
3140203945Sweongyo
3141203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
3142203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3143203945Sweongyo
3144203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
3145203945Sweongyo		p = &(sc->sc_wmeParams[i]);
3146203945Sweongyo
3147203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
3148203945Sweongyo		case BWN_WME_VOICE:
3149203945Sweongyo			p->wmep_txopLimit = 0;
3150203945Sweongyo			p->wmep_aifsn = 2;
3151203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3152203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3153203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3154203945Sweongyo			break;
3155203945Sweongyo		case BWN_WME_VIDEO:
3156203945Sweongyo			p->wmep_txopLimit = 0;
3157203945Sweongyo			p->wmep_aifsn = 2;
3158203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3159203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3160203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3161203945Sweongyo			break;
3162203945Sweongyo		case BWN_WME_BESTEFFORT:
3163203945Sweongyo			p->wmep_txopLimit = 0;
3164203945Sweongyo			p->wmep_aifsn = 3;
3165203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3166203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3167203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3168203945Sweongyo			break;
3169203945Sweongyo		case BWN_WME_BACKGROUND:
3170203945Sweongyo			p->wmep_txopLimit = 0;
3171203945Sweongyo			p->wmep_aifsn = 7;
3172203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3173203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3174203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3175203945Sweongyo			break;
3176203945Sweongyo		default:
3177203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3178203945Sweongyo		}
3179203945Sweongyo	}
3180203945Sweongyo}
3181203945Sweongyo
3182203945Sweongyostatic int
3183203945Sweongyobwn_core_init(struct bwn_mac *mac)
3184203945Sweongyo{
3185203945Sweongyo#ifdef BWN_DEBUG
3186203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3187203945Sweongyo#endif
3188203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
3189203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
3190203945Sweongyo	struct siba_sprom *sprom = &siba->siba_sprom;
3191203945Sweongyo	uint64_t hf;
3192203945Sweongyo	int error;
3193203945Sweongyo
3194203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3195203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3196203945Sweongyo
3197203945Sweongyo	siba_powerup(siba, 0);
3198203945Sweongyo	if (!siba_dev_isup(sd))
3199203945Sweongyo		bwn_reset_core(mac,
3200203945Sweongyo		    mac->mac_phy.gmode ? BWN_TGSLOW_SUPPORT_G : 0);
3201203945Sweongyo
3202203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
3203203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
3204203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
3205203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
3206203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
3207203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
3208203945Sweongyo	mac->mac_stats.link_noise = -95;
3209203945Sweongyo	mac->mac_reason_intr = 0;
3210203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
3211203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
3212203945Sweongyo#ifdef BWN_DEBUG
3213203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
3214203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
3215203945Sweongyo#endif
3216203945Sweongyo	mac->mac_suspended = 1;
3217203945Sweongyo	mac->mac_task_state = 0;
3218203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
3219203945Sweongyo
3220203945Sweongyo	mac->mac_phy.init_pre(mac);
3221203945Sweongyo
3222203945Sweongyo	siba_pcicore_intr(&siba->siba_pci, sd);
3223203945Sweongyo
3224203945Sweongyo	bwn_fix_imcfglobug(mac);
3225203945Sweongyo	bwn_bt_disable(mac);
3226203945Sweongyo	if (mac->mac_phy.prepare_hw) {
3227203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
3228203945Sweongyo		if (error)
3229203945Sweongyo			goto fail0;
3230203945Sweongyo	}
3231203945Sweongyo	error = bwn_chip_init(mac);
3232203945Sweongyo	if (error)
3233203945Sweongyo		goto fail0;
3234203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
3235203945Sweongyo	    mac->mac_sd->sd_id.sd_rev);
3236203945Sweongyo	hf = bwn_hf_read(mac);
3237203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
3238203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
3239203945Sweongyo		if (sprom->bf_lo & BWN_BFL_PACTRL)
3240203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
3241203945Sweongyo		if (mac->mac_phy.rev == 1)
3242203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
3243203945Sweongyo	}
3244203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
3245203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
3246203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
3247203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
3248203945Sweongyo			hf |= BWN_HF_4318_TSSI;
3249203945Sweongyo	}
3250203945Sweongyo	if (sprom->bf_lo & BWN_BFL_CRYSTAL_NOSLOW)
3251203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
3252203945Sweongyo	if ((siba->siba_type == SIBA_TYPE_PCI) &&
3253203945Sweongyo	    (siba->siba_pci.spc_dev->sd_id.sd_rev <= 10))
3254203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
3255203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
3256203945Sweongyo	bwn_hf_write(mac, hf);
3257203945Sweongyo
3258203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
3259203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
3260203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
3261203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
3262203945Sweongyo
3263203945Sweongyo	bwn_rate_init(mac);
3264203945Sweongyo	bwn_set_phytxctl(mac);
3265203945Sweongyo
3266203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
3267203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
3268203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
3269203945Sweongyo
3270203945Sweongyo	if (siba->siba_type == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
3271203945Sweongyo		bwn_pio_init(mac);
3272203945Sweongyo	else
3273203945Sweongyo		bwn_dma_init(mac);
3274203945Sweongyo	if (error)
3275203945Sweongyo		goto fail1;
3276203945Sweongyo	bwn_wme_init(mac);
3277203945Sweongyo	bwn_spu_setdelay(mac, 1);
3278203945Sweongyo	bwn_bt_enable(mac);
3279203945Sweongyo
3280203945Sweongyo	siba_powerup(siba, !(sprom->bf_lo & BWN_BFL_CRYSTAL_NOSLOW));
3281203945Sweongyo	bwn_set_macaddr(mac);
3282203945Sweongyo	bwn_crypt_init(mac);
3283203945Sweongyo
3284203945Sweongyo	/* XXX LED initializatin */
3285203945Sweongyo
3286203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
3287203945Sweongyo
3288203945Sweongyo	return (error);
3289203945Sweongyo
3290203945Sweongyofail1:
3291203945Sweongyo	bwn_chip_exit(mac);
3292203945Sweongyofail0:
3293203945Sweongyo	siba_powerdown(siba);
3294203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3295203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3296203945Sweongyo	return (error);
3297203945Sweongyo}
3298203945Sweongyo
3299203945Sweongyostatic void
3300203945Sweongyobwn_core_start(struct bwn_mac *mac)
3301203945Sweongyo{
3302203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3303203945Sweongyo	uint32_t tmp;
3304203945Sweongyo
3305203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
3306203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3307203945Sweongyo
3308203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev < 5)
3309203945Sweongyo		return;
3310203945Sweongyo
3311203945Sweongyo	while (1) {
3312203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
3313203945Sweongyo		if (!(tmp & 0x00000001))
3314203945Sweongyo			break;
3315203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
3316203945Sweongyo	}
3317203945Sweongyo
3318203945Sweongyo	bwn_mac_enable(mac);
3319203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
3320203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
3321203945Sweongyo
3322203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
3323203945Sweongyo}
3324203945Sweongyo
3325203945Sweongyostatic void
3326203945Sweongyobwn_core_exit(struct bwn_mac *mac)
3327203945Sweongyo{
3328203945Sweongyo	uint32_t macctl;
3329203945Sweongyo
3330204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
3331203945Sweongyo
3332203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
3333203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3334203945Sweongyo
3335203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
3336203945Sweongyo		return;
3337203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
3338203945Sweongyo
3339203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3340203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
3341203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
3342203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3343203945Sweongyo
3344203945Sweongyo	bwn_dma_stop(mac);
3345203945Sweongyo	bwn_pio_stop(mac);
3346203945Sweongyo	bwn_chip_exit(mac);
3347203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
3348203945Sweongyo	siba_dev_down(mac->mac_sd, 0);
3349203945Sweongyo	siba_powerdown(mac->mac_sd->sd_bus);
3350203945Sweongyo}
3351203945Sweongyo
3352203945Sweongyostatic void
3353203945Sweongyobwn_fix_imcfglobug(struct bwn_mac *mac)
3354203945Sweongyo{
3355203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
3356203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
3357203945Sweongyo	uint32_t tmp;
3358203945Sweongyo
3359203945Sweongyo	if (siba->siba_pci.spc_dev == NULL)
3360203945Sweongyo		return;
3361203945Sweongyo	if (siba->siba_pci.spc_dev->sd_id.sd_device != SIBA_DEVID_PCI ||
3362203945Sweongyo	    siba->siba_pci.spc_dev->sd_id.sd_rev > 5)
3363203945Sweongyo		return;
3364203945Sweongyo
3365203945Sweongyo	tmp = siba_read_4(sd, SIBA_IMCFGLO) &
3366203945Sweongyo	    ~(SIBA_IMCFGLO_REQTO | SIBA_IMCFGLO_SERTO);
3367203945Sweongyo	switch (siba->siba_type) {
3368203945Sweongyo	case SIBA_TYPE_PCI:
3369203945Sweongyo	case SIBA_TYPE_PCMCIA:
3370203945Sweongyo		tmp |= 0x32;
3371203945Sweongyo		break;
3372203945Sweongyo	case SIBA_TYPE_SSB:
3373203945Sweongyo		tmp |= 0x53;
3374203945Sweongyo		break;
3375203945Sweongyo	}
3376203945Sweongyo	siba_write_4(sd, SIBA_IMCFGLO, tmp);
3377203945Sweongyo}
3378203945Sweongyo
3379203945Sweongyostatic void
3380203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
3381203945Sweongyo{
3382203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3383203945Sweongyo
3384203945Sweongyo	(void)sc;
3385203945Sweongyo	/* XXX do nothing yet */
3386203945Sweongyo}
3387203945Sweongyo
3388203945Sweongyostatic int
3389203945Sweongyobwn_chip_init(struct bwn_mac *mac)
3390203945Sweongyo{
3391203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
3392203945Sweongyo	uint32_t macctl;
3393203945Sweongyo	int error;
3394203945Sweongyo
3395203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
3396203945Sweongyo	if (phy->gmode)
3397203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
3398203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3399203945Sweongyo
3400203945Sweongyo	error = bwn_fw_fillinfo(mac);
3401203945Sweongyo	if (error)
3402203945Sweongyo		return (error);
3403203945Sweongyo	error = bwn_fw_loaducode(mac);
3404203945Sweongyo	if (error)
3405203945Sweongyo		return (error);
3406203945Sweongyo
3407203945Sweongyo	error = bwn_gpio_init(mac);
3408203945Sweongyo	if (error)
3409203945Sweongyo		return (error);
3410203945Sweongyo
3411203945Sweongyo	error = bwn_fw_loadinitvals(mac);
3412203945Sweongyo	if (error) {
3413203945Sweongyo		bwn_gpio_cleanup(mac);
3414203945Sweongyo		return (error);
3415203945Sweongyo	}
3416203945Sweongyo	phy->switch_analog(mac, 1);
3417203945Sweongyo	error = bwn_phy_init(mac);
3418203945Sweongyo	if (error) {
3419203945Sweongyo		bwn_gpio_cleanup(mac);
3420203945Sweongyo		return (error);
3421203945Sweongyo	}
3422203945Sweongyo	if (phy->set_im)
3423203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
3424203945Sweongyo	if (phy->set_antenna)
3425203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
3426203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
3427203945Sweongyo
3428203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
3429203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
3430203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
3431203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev < 5)
3432203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
3433203945Sweongyo
3434203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3435203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
3436203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3437203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
3438203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
3439203945Sweongyo
3440203945Sweongyo	bwn_set_opmode(mac);
3441203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev < 3) {
3442203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
3443203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
3444203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
3445203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
3446203945Sweongyo	} else {
3447203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
3448203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
3449203945Sweongyo	}
3450203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
3451203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
3452203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
3453203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
3454203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
3455203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
3456203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
3457203945Sweongyo	siba_write_4(mac->mac_sd, SIBA_TGSLOW,
3458203945Sweongyo	    siba_read_4(mac->mac_sd, SIBA_TGSLOW) | 0x00100000);
3459203945Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY,
3460203945Sweongyo	    mac->mac_sd->sd_bus->siba_cc.scc_powerup_delay);
3461203945Sweongyo	return (error);
3462203945Sweongyo}
3463203945Sweongyo
3464203945Sweongyo/* read hostflags */
3465203945Sweongyostatic uint64_t
3466203945Sweongyobwn_hf_read(struct bwn_mac *mac)
3467203945Sweongyo{
3468203945Sweongyo	uint64_t ret;
3469203945Sweongyo
3470203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
3471203945Sweongyo	ret <<= 16;
3472203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
3473203945Sweongyo	ret <<= 16;
3474203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
3475203945Sweongyo	return (ret);
3476203945Sweongyo}
3477203945Sweongyo
3478203945Sweongyostatic void
3479203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
3480203945Sweongyo{
3481203945Sweongyo
3482203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
3483203945Sweongyo	    (value & 0x00000000ffffull));
3484203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
3485203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
3486203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
3487203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
3488203945Sweongyo}
3489203945Sweongyo
3490203945Sweongyostatic void
3491203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
3492203945Sweongyo{
3493203945Sweongyo
3494203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
3495203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
3496203945Sweongyo}
3497203945Sweongyo
3498203945Sweongyostatic void
3499203945Sweongyobwn_rate_init(struct bwn_mac *mac)
3500203945Sweongyo{
3501203945Sweongyo
3502203945Sweongyo	switch (mac->mac_phy.type) {
3503203945Sweongyo	case BWN_PHYTYPE_A:
3504203945Sweongyo	case BWN_PHYTYPE_G:
3505203945Sweongyo	case BWN_PHYTYPE_LP:
3506203945Sweongyo	case BWN_PHYTYPE_N:
3507203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
3508203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
3509203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
3510203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
3511203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
3512203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
3513203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
3514203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
3515203945Sweongyo			break;
3516203945Sweongyo		/* FALLTHROUGH */
3517203945Sweongyo	case BWN_PHYTYPE_B:
3518203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
3519203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
3520203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
3521203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
3522203945Sweongyo		break;
3523203945Sweongyo	default:
3524203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3525203945Sweongyo	}
3526203945Sweongyo}
3527203945Sweongyo
3528203945Sweongyostatic void
3529203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
3530203945Sweongyo{
3531203945Sweongyo	uint16_t offset;
3532203945Sweongyo
3533203945Sweongyo	if (ofdm) {
3534203945Sweongyo		offset = 0x480;
3535203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
3536203945Sweongyo	} else {
3537203945Sweongyo		offset = 0x4c0;
3538203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
3539203945Sweongyo	}
3540203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
3541203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
3542203945Sweongyo}
3543203945Sweongyo
3544203945Sweongyostatic uint8_t
3545203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
3546203945Sweongyo{
3547203945Sweongyo
3548203945Sweongyo	switch (bitrate) {
3549203945Sweongyo	case BWN_CCK_RATE_1MB:
3550203945Sweongyo		return (0x0a);
3551203945Sweongyo	case BWN_CCK_RATE_2MB:
3552203945Sweongyo		return (0x14);
3553203945Sweongyo	case BWN_CCK_RATE_5MB:
3554203945Sweongyo		return (0x37);
3555203945Sweongyo	case BWN_CCK_RATE_11MB:
3556203945Sweongyo		return (0x6e);
3557203945Sweongyo	}
3558203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3559203945Sweongyo	return (0);
3560203945Sweongyo}
3561203945Sweongyo
3562203945Sweongyostatic uint8_t
3563203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
3564203945Sweongyo{
3565203945Sweongyo
3566203945Sweongyo	switch (bitrate) {
3567203945Sweongyo	case BWN_OFDM_RATE_6MB:
3568203945Sweongyo		return (0xb);
3569203945Sweongyo	case BWN_OFDM_RATE_9MB:
3570203945Sweongyo		return (0xf);
3571203945Sweongyo	case BWN_OFDM_RATE_12MB:
3572203945Sweongyo		return (0xa);
3573203945Sweongyo	case BWN_OFDM_RATE_18MB:
3574203945Sweongyo		return (0xe);
3575203945Sweongyo	case BWN_OFDM_RATE_24MB:
3576203945Sweongyo		return (0x9);
3577203945Sweongyo	case BWN_OFDM_RATE_36MB:
3578203945Sweongyo		return (0xd);
3579203945Sweongyo	case BWN_OFDM_RATE_48MB:
3580203945Sweongyo		return (0x8);
3581203945Sweongyo	case BWN_OFDM_RATE_54MB:
3582203945Sweongyo		return (0xc);
3583203945Sweongyo	}
3584203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3585203945Sweongyo	return (0);
3586203945Sweongyo}
3587203945Sweongyo
3588203945Sweongyostatic void
3589203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
3590203945Sweongyo{
3591203945Sweongyo	uint16_t ctl;
3592203945Sweongyo
3593203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
3594203945Sweongyo	    BWN_TX_PHY_TXPWR);
3595203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
3596203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
3597203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
3598203945Sweongyo}
3599203945Sweongyo
3600203945Sweongyostatic void
3601203945Sweongyobwn_pio_init(struct bwn_mac *mac)
3602203945Sweongyo{
3603203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
3604203945Sweongyo
3605203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
3606203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
3607203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
3608203945Sweongyo
3609203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
3610203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
3611203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
3612203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
3613203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
3614203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
3615203945Sweongyo}
3616203945Sweongyo
3617203945Sweongyostatic void
3618203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3619203945Sweongyo    int index)
3620203945Sweongyo{
3621203945Sweongyo	struct bwn_pio_txpkt *tp;
3622203945Sweongyo	unsigned int i;
3623203945Sweongyo
3624203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
3625203945Sweongyo	tq->tq_index = index;
3626203945Sweongyo
3627203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
3628203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 8)
3629203945Sweongyo		tq->tq_size = 1920;
3630203945Sweongyo	else {
3631203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
3632203945Sweongyo		tq->tq_size -= 80;
3633203945Sweongyo	}
3634203945Sweongyo
3635203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
3636203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3637203945Sweongyo		tp = &(tq->tq_pkts[i]);
3638203945Sweongyo		tp->tp_index = i;
3639203945Sweongyo		tp->tp_queue = tq;
3640203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
3641203945Sweongyo	}
3642203945Sweongyo}
3643203945Sweongyo
3644203945Sweongyostatic uint16_t
3645203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
3646203945Sweongyo{
3647203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3648203945Sweongyo	static const uint16_t bases[] = {
3649203945Sweongyo		BWN_PIO_BASE0,
3650203945Sweongyo		BWN_PIO_BASE1,
3651203945Sweongyo		BWN_PIO_BASE2,
3652203945Sweongyo		BWN_PIO_BASE3,
3653203945Sweongyo		BWN_PIO_BASE4,
3654203945Sweongyo		BWN_PIO_BASE5,
3655203945Sweongyo		BWN_PIO_BASE6,
3656203945Sweongyo		BWN_PIO_BASE7,
3657203945Sweongyo	};
3658203945Sweongyo	static const uint16_t bases_rev11[] = {
3659203945Sweongyo		BWN_PIO11_BASE0,
3660203945Sweongyo		BWN_PIO11_BASE1,
3661203945Sweongyo		BWN_PIO11_BASE2,
3662203945Sweongyo		BWN_PIO11_BASE3,
3663203945Sweongyo		BWN_PIO11_BASE4,
3664203945Sweongyo		BWN_PIO11_BASE5,
3665203945Sweongyo	};
3666203945Sweongyo
3667203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 11) {
3668203945Sweongyo		if (index >= N(bases_rev11))
3669203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
3670203945Sweongyo		return (bases_rev11[index]);
3671203945Sweongyo	}
3672203945Sweongyo	if (index >= N(bases))
3673203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
3674203945Sweongyo	return (bases[index]);
3675203945Sweongyo}
3676203945Sweongyo
3677203945Sweongyostatic void
3678203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
3679203945Sweongyo    int index)
3680203945Sweongyo{
3681203945Sweongyo
3682203945Sweongyo	prq->prq_mac = mac;
3683203945Sweongyo	prq->prq_rev = mac->mac_sd->sd_id.sd_rev;
3684203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
3685203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
3686203945Sweongyo}
3687203945Sweongyo
3688203945Sweongyostatic void
3689203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
3690203945Sweongyo{
3691203945Sweongyo	if (tq == NULL)
3692203945Sweongyo		return;
3693203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
3694203945Sweongyo}
3695203945Sweongyo
3696203945Sweongyostatic void
3697203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
3698203945Sweongyo{
3699203945Sweongyo
3700203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
3701203945Sweongyo}
3702203945Sweongyo
3703203945Sweongyostatic uint16_t
3704203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3705203945Sweongyo    uint16_t offset)
3706203945Sweongyo{
3707203945Sweongyo
3708203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
3709203945Sweongyo}
3710203945Sweongyo
3711203945Sweongyostatic void
3712203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
3713203945Sweongyo{
3714203945Sweongyo	uint32_t ctl;
3715203945Sweongyo	int type;
3716203945Sweongyo	uint16_t base;
3717203945Sweongyo
3718203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
3719203945Sweongyo	base = bwn_dma_base(type, idx);
3720203945Sweongyo	if (type == BWN_DMA_64BIT) {
3721203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
3722203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
3723203945Sweongyo		if (enable)
3724203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
3725203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
3726203945Sweongyo	} else {
3727203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
3728203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
3729203945Sweongyo		if (enable)
3730203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
3731203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
3732203945Sweongyo	}
3733203945Sweongyo}
3734203945Sweongyo
3735203945Sweongyostatic uint64_t
3736203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
3737203945Sweongyo{
3738203945Sweongyo	uint32_t tmp;
3739203945Sweongyo	uint16_t base;
3740203945Sweongyo
3741203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3742203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3743203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
3744203945Sweongyo	base = bwn_dma_base(0, 0);
3745203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3746203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3747203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3748203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
3749203945Sweongyo
3750203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
3751203945Sweongyo}
3752203945Sweongyo
3753203945Sweongyostatic int
3754203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
3755203945Sweongyo{
3756203945Sweongyo
3757203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
3758203945Sweongyo		return (BWN_DMA_30BIT);
3759203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
3760203945Sweongyo		return (BWN_DMA_32BIT);
3761203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
3762203945Sweongyo		return (BWN_DMA_64BIT);
3763203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3764203945Sweongyo	return (BWN_DMA_30BIT);
3765203945Sweongyo}
3766203945Sweongyo
3767203945Sweongyostatic void
3768203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
3769203945Sweongyo{
3770203945Sweongyo	struct bwn_pio_txpkt *tp;
3771203945Sweongyo	unsigned int i;
3772203945Sweongyo
3773203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3774203945Sweongyo		tp = &(tq->tq_pkts[i]);
3775203945Sweongyo		if (tp->tp_m) {
3776203945Sweongyo			m_freem(tp->tp_m);
3777203945Sweongyo			tp->tp_m = NULL;
3778203945Sweongyo		}
3779203945Sweongyo	}
3780203945Sweongyo}
3781203945Sweongyo
3782203945Sweongyostatic uint16_t
3783203945Sweongyobwn_dma_base(int type, int controller_idx)
3784203945Sweongyo{
3785203945Sweongyo	static const uint16_t map64[] = {
3786203945Sweongyo		BWN_DMA64_BASE0,
3787203945Sweongyo		BWN_DMA64_BASE1,
3788203945Sweongyo		BWN_DMA64_BASE2,
3789203945Sweongyo		BWN_DMA64_BASE3,
3790203945Sweongyo		BWN_DMA64_BASE4,
3791203945Sweongyo		BWN_DMA64_BASE5,
3792203945Sweongyo	};
3793203945Sweongyo	static const uint16_t map32[] = {
3794203945Sweongyo		BWN_DMA32_BASE0,
3795203945Sweongyo		BWN_DMA32_BASE1,
3796203945Sweongyo		BWN_DMA32_BASE2,
3797203945Sweongyo		BWN_DMA32_BASE3,
3798203945Sweongyo		BWN_DMA32_BASE4,
3799203945Sweongyo		BWN_DMA32_BASE5,
3800203945Sweongyo	};
3801203945Sweongyo
3802203945Sweongyo	if (type == BWN_DMA_64BIT) {
3803203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
3804203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3805203945Sweongyo		return (map64[controller_idx]);
3806203945Sweongyo	}
3807203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
3808203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3809203945Sweongyo	return (map32[controller_idx]);
3810203945Sweongyo}
3811203945Sweongyo
3812203945Sweongyostatic void
3813203945Sweongyobwn_dma_init(struct bwn_mac *mac)
3814203945Sweongyo{
3815203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3816203945Sweongyo
3817203945Sweongyo	/* setup TX DMA channels. */
3818203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
3819203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
3820203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
3821203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
3822203945Sweongyo	bwn_dma_setup(dma->mcast);
3823203945Sweongyo	/* setup RX DMA channel. */
3824203945Sweongyo	bwn_dma_setup(dma->rx);
3825203945Sweongyo}
3826203945Sweongyo
3827203945Sweongyostatic struct bwn_dma_ring *
3828203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
3829203945Sweongyo    int for_tx, int type)
3830203945Sweongyo{
3831203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3832203945Sweongyo	struct bwn_dma_ring *dr;
3833203945Sweongyo	struct bwn_dmadesc_generic *desc;
3834203945Sweongyo	struct bwn_dmadesc_meta *mt;
3835203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3836203945Sweongyo	int error, i;
3837203945Sweongyo
3838203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
3839203945Sweongyo	if (dr == NULL)
3840203945Sweongyo		goto out;
3841203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
3842203945Sweongyo	if (for_tx)
3843203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
3844203945Sweongyo
3845203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
3846203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
3847203945Sweongyo	if (dr->dr_meta == NULL)
3848203945Sweongyo		goto fail0;
3849203945Sweongyo
3850203945Sweongyo	dr->dr_type = type;
3851203945Sweongyo	dr->dr_mac = mac;
3852203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
3853203945Sweongyo	dr->dr_index = controller_index;
3854203945Sweongyo	if (type == BWN_DMA_64BIT) {
3855203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
3856203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
3857203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
3858203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
3859203945Sweongyo		dr->resume = bwn_dma_64_resume;
3860203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
3861203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
3862203945Sweongyo	} else {
3863203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
3864203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
3865203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
3866203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
3867203945Sweongyo		dr->resume = bwn_dma_32_resume;
3868203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
3869203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
3870203945Sweongyo	}
3871203945Sweongyo	if (for_tx) {
3872203945Sweongyo		dr->dr_tx = 1;
3873203945Sweongyo		dr->dr_curslot = -1;
3874203945Sweongyo	} else {
3875203945Sweongyo		if (dr->dr_index == 0) {
3876203945Sweongyo			dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
3877203945Sweongyo			dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
3878203945Sweongyo		} else
3879203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3880203945Sweongyo	}
3881203945Sweongyo
3882203945Sweongyo	error = bwn_dma_allocringmemory(dr);
3883203945Sweongyo	if (error)
3884203945Sweongyo		goto fail2;
3885203945Sweongyo
3886203945Sweongyo	if (for_tx) {
3887203945Sweongyo		/*
3888203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
3889203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
3890203945Sweongyo		 */
3891203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
3892203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3893203945Sweongyo
3894203945Sweongyo		dr->dr_txhdr_cache =
3895203945Sweongyo		    malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
3896203945Sweongyo			BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
3897203945Sweongyo		KASSERT(dr->dr_txhdr_cache != NULL,
3898203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3899203945Sweongyo
3900203945Sweongyo		/*
3901203945Sweongyo		 * Create TX ring DMA stuffs
3902203945Sweongyo		 */
3903203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
3904203945Sweongyo				    BWN_ALIGN, 0,
3905203945Sweongyo				    BUS_SPACE_MAXADDR,
3906203945Sweongyo				    BUS_SPACE_MAXADDR,
3907203945Sweongyo				    NULL, NULL,
3908203945Sweongyo				    BWN_HDRSIZE(mac),
3909203945Sweongyo				    1,
3910203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
3911203945Sweongyo				    0,
3912203945Sweongyo				    NULL, NULL,
3913203945Sweongyo				    &dr->dr_txring_dtag);
3914203945Sweongyo		if (error) {
3915203945Sweongyo			device_printf(sc->sc_dev,
3916203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
3917203945Sweongyo			goto fail1;
3918203945Sweongyo		}
3919203945Sweongyo
3920203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
3921203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3922203945Sweongyo
3923203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
3924203945Sweongyo			mt->mt_m = NULL;
3925203945Sweongyo			mt->mt_ni = NULL;
3926203945Sweongyo			mt->mt_islast = 0;
3927203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
3928203945Sweongyo			    &mt->mt_dmap);
3929203945Sweongyo			if (error) {
3930203945Sweongyo				device_printf(sc->sc_dev,
3931203945Sweongyo				     "can't create RX buf DMA map\n");
3932203945Sweongyo				goto fail1;
3933203945Sweongyo			}
3934203945Sweongyo
3935203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
3936203945Sweongyo
3937203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
3938203945Sweongyo			mt->mt_m = NULL;
3939203945Sweongyo			mt->mt_ni = NULL;
3940203945Sweongyo			mt->mt_islast = 1;
3941203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
3942203945Sweongyo			    &mt->mt_dmap);
3943203945Sweongyo			if (error) {
3944203945Sweongyo				device_printf(sc->sc_dev,
3945203945Sweongyo				     "can't create RX buf DMA map\n");
3946203945Sweongyo				goto fail1;
3947203945Sweongyo			}
3948203945Sweongyo		}
3949203945Sweongyo	} else {
3950203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3951203945Sweongyo		    &dr->dr_spare_dmap);
3952203945Sweongyo		if (error) {
3953203945Sweongyo			device_printf(sc->sc_dev,
3954203945Sweongyo			    "can't create RX buf DMA map\n");
3955203945Sweongyo			goto out;		/* XXX wrong! */
3956203945Sweongyo		}
3957203945Sweongyo
3958203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
3959203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3960203945Sweongyo
3961203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3962203945Sweongyo			    &mt->mt_dmap);
3963203945Sweongyo			if (error) {
3964203945Sweongyo				device_printf(sc->sc_dev,
3965203945Sweongyo				    "can't create RX buf DMA map\n");
3966203945Sweongyo				goto out;	/* XXX wrong! */
3967203945Sweongyo			}
3968203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
3969203945Sweongyo			if (error) {
3970203945Sweongyo				device_printf(sc->sc_dev,
3971203945Sweongyo				    "failed to allocate RX buf\n");
3972203945Sweongyo				goto out;	/* XXX wrong! */
3973203945Sweongyo			}
3974203945Sweongyo		}
3975203945Sweongyo
3976203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
3977203945Sweongyo		    BUS_DMASYNC_PREWRITE);
3978203945Sweongyo
3979203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
3980203945Sweongyo	}
3981203945Sweongyo
3982203945Sweongyo      out:
3983203945Sweongyo	return (dr);
3984203945Sweongyo
3985203945Sweongyofail2:
3986203945Sweongyo	free(dr->dr_txhdr_cache, M_DEVBUF);
3987203945Sweongyofail1:
3988203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
3989203945Sweongyofail0:
3990203945Sweongyo	free(dr, M_DEVBUF);
3991203945Sweongyo	return (NULL);
3992203945Sweongyo}
3993203945Sweongyo
3994203945Sweongyostatic void
3995203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
3996203945Sweongyo{
3997203945Sweongyo
3998203945Sweongyo	if (dr == NULL)
3999203945Sweongyo		return;
4000203945Sweongyo
4001203945Sweongyo	bwn_dma_free_descbufs(*dr);
4002203945Sweongyo	bwn_dma_free_ringmemory(*dr);
4003203945Sweongyo
4004203945Sweongyo	free((*dr)->dr_txhdr_cache, M_DEVBUF);
4005203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
4006203945Sweongyo	free(*dr, M_DEVBUF);
4007203945Sweongyo
4008203945Sweongyo	*dr = NULL;
4009203945Sweongyo}
4010203945Sweongyo
4011203945Sweongyostatic void
4012203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
4013203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
4014203945Sweongyo{
4015203945Sweongyo	struct bwn_dmadesc32 *desc;
4016203945Sweongyo
4017203945Sweongyo	*meta = &(dr->dr_meta[slot]);
4018203945Sweongyo	desc = dr->dr_ring_descbase;
4019203945Sweongyo	desc = &(desc[slot]);
4020203945Sweongyo
4021203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
4022203945Sweongyo}
4023203945Sweongyo
4024203945Sweongyostatic void
4025203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
4026203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
4027203945Sweongyo    int start, int end, int irq)
4028203945Sweongyo{
4029203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
4030203945Sweongyo	uint32_t addr, addrext, ctl;
4031203945Sweongyo	int slot;
4032203945Sweongyo
4033203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
4034203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
4035203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4036203945Sweongyo
4037203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
4038203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
4039203945Sweongyo	addr |= siba_dma_translation(dr->dr_mac->mac_sd);
4040203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
4041203945Sweongyo	if (slot == dr->dr_numslots - 1)
4042203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
4043203945Sweongyo	if (start)
4044203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
4045203945Sweongyo	if (end)
4046203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
4047203945Sweongyo	if (irq)
4048203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
4049203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
4050203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
4051203945Sweongyo
4052203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
4053203945Sweongyo	desc->dma.dma32.address = htole32(addr);
4054203945Sweongyo}
4055203945Sweongyo
4056203945Sweongyostatic void
4057203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
4058203945Sweongyo{
4059203945Sweongyo
4060203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
4061203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
4062203945Sweongyo}
4063203945Sweongyo
4064203945Sweongyostatic void
4065203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
4066203945Sweongyo{
4067203945Sweongyo
4068203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
4069203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
4070203945Sweongyo}
4071203945Sweongyo
4072203945Sweongyostatic void
4073203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
4074203945Sweongyo{
4075203945Sweongyo
4076203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
4077203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
4078203945Sweongyo}
4079203945Sweongyo
4080203945Sweongyostatic int
4081203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
4082203945Sweongyo{
4083203945Sweongyo	uint32_t val;
4084203945Sweongyo
4085203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
4086203945Sweongyo	val &= BWN_DMA32_RXDPTR;
4087203945Sweongyo
4088203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
4089203945Sweongyo}
4090203945Sweongyo
4091203945Sweongyostatic void
4092203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
4093203945Sweongyo{
4094203945Sweongyo
4095203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
4096203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
4097203945Sweongyo}
4098203945Sweongyo
4099203945Sweongyostatic void
4100203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
4101203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
4102203945Sweongyo{
4103203945Sweongyo	struct bwn_dmadesc64 *desc;
4104203945Sweongyo
4105203945Sweongyo	*meta = &(dr->dr_meta[slot]);
4106203945Sweongyo	desc = dr->dr_ring_descbase;
4107203945Sweongyo	desc = &(desc[slot]);
4108203945Sweongyo
4109203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
4110203945Sweongyo}
4111203945Sweongyo
4112203945Sweongyostatic void
4113203945Sweongyobwn_dma_64_setdesc(struct bwn_dma_ring *dr,
4114203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
4115203945Sweongyo    int start, int end, int irq)
4116203945Sweongyo{
4117203945Sweongyo	struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
4118203945Sweongyo	int slot;
4119203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
4120203945Sweongyo	uint32_t addrlo, addrhi;
4121203945Sweongyo	uint32_t addrext;
4122203945Sweongyo
4123203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
4124203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
4125203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4126203945Sweongyo
4127203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
4128203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
4129203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
4130203945Sweongyo	    30;
4131203945Sweongyo	addrhi |= (siba_dma_translation(dr->dr_mac->mac_sd) << 1);
4132203945Sweongyo	if (slot == dr->dr_numslots - 1)
4133203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
4134203945Sweongyo	if (start)
4135203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
4136203945Sweongyo	if (end)
4137203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
4138203945Sweongyo	if (irq)
4139203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
4140203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
4141203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
4142203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
4143203945Sweongyo
4144203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
4145203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
4146203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
4147203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
4148203945Sweongyo}
4149203945Sweongyo
4150203945Sweongyostatic void
4151203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
4152203945Sweongyo{
4153203945Sweongyo
4154203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
4155203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4156203945Sweongyo}
4157203945Sweongyo
4158203945Sweongyostatic void
4159203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
4160203945Sweongyo{
4161203945Sweongyo
4162203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4163203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
4164203945Sweongyo}
4165203945Sweongyo
4166203945Sweongyostatic void
4167203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
4168203945Sweongyo{
4169203945Sweongyo
4170203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4171203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
4172203945Sweongyo}
4173203945Sweongyo
4174203945Sweongyostatic int
4175203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
4176203945Sweongyo{
4177203945Sweongyo	uint32_t val;
4178203945Sweongyo
4179203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
4180203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
4181203945Sweongyo
4182203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
4183203945Sweongyo}
4184203945Sweongyo
4185203945Sweongyostatic void
4186203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
4187203945Sweongyo{
4188203945Sweongyo
4189203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
4190203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4191203945Sweongyo}
4192203945Sweongyo
4193203945Sweongyostatic int
4194203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
4195203945Sweongyo{
4196203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4197203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4198203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4199203945Sweongyo	int error;
4200203945Sweongyo
4201203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
4202203945Sweongyo			    BWN_ALIGN, 0,
4203203945Sweongyo			    BUS_SPACE_MAXADDR,
4204203945Sweongyo			    BUS_SPACE_MAXADDR,
4205203945Sweongyo			    NULL, NULL,
4206203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
4207203945Sweongyo			    1,
4208203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
4209203945Sweongyo			    0,
4210203945Sweongyo			    NULL, NULL,
4211203945Sweongyo			    &dr->dr_ring_dtag);
4212203945Sweongyo	if (error) {
4213203945Sweongyo		device_printf(sc->sc_dev,
4214203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
4215203945Sweongyo		return (-1);
4216203945Sweongyo	}
4217203945Sweongyo
4218203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
4219203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
4220203945Sweongyo	    &dr->dr_ring_dmap);
4221203945Sweongyo	if (error) {
4222203945Sweongyo		device_printf(sc->sc_dev,
4223203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
4224203945Sweongyo		return (-1);
4225203945Sweongyo	}
4226203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
4227203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
4228203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
4229203945Sweongyo	if (error) {
4230203945Sweongyo		device_printf(sc->sc_dev,
4231203945Sweongyo		    "can't load DMA mem: TODO free\n");
4232203945Sweongyo		return (-1);
4233203945Sweongyo	}
4234203945Sweongyo
4235203945Sweongyo	return (0);
4236203945Sweongyo}
4237203945Sweongyo
4238203945Sweongyostatic void
4239203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
4240203945Sweongyo{
4241203945Sweongyo	uint64_t ring64;
4242203945Sweongyo	uint32_t addrext, ring32, value;
4243203945Sweongyo	uint32_t trans = siba_dma_translation(dr->dr_mac->mac_sd);
4244203945Sweongyo
4245203945Sweongyo	if (dr->dr_tx) {
4246203945Sweongyo		dr->dr_curslot = -1;
4247203945Sweongyo
4248203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4249203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
4250203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
4251203945Sweongyo			    >> 30;
4252203945Sweongyo			value = BWN_DMA64_TXENABLE;
4253203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
4254203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
4255203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
4256203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
4257203945Sweongyo			    (ring64 & 0xffffffff));
4258203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
4259203945Sweongyo			    ((ring64 >> 32) &
4260203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
4261203945Sweongyo		} else {
4262203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
4263203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4264203945Sweongyo			value = BWN_DMA32_TXENABLE;
4265203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
4266203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
4267203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
4268203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
4269203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4270203945Sweongyo		}
4271203945Sweongyo		return;
4272203945Sweongyo	}
4273203945Sweongyo
4274203945Sweongyo	/*
4275203945Sweongyo	 * set for RX
4276203945Sweongyo	 */
4277203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
4278203945Sweongyo
4279203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
4280203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
4281203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
4282203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
4283203945Sweongyo		value |= BWN_DMA64_RXENABLE;
4284203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
4285203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
4286203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
4287203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
4288203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
4289203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
4290203945Sweongyo		    | (trans << 1));
4291203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
4292203945Sweongyo		    sizeof(struct bwn_dmadesc64));
4293203945Sweongyo	} else {
4294203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
4295203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4296203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
4297203945Sweongyo		value |= BWN_DMA32_RXENABLE;
4298203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
4299203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
4300203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
4301203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
4302203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4303203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
4304203945Sweongyo		    sizeof(struct bwn_dmadesc32));
4305203945Sweongyo	}
4306203945Sweongyo}
4307203945Sweongyo
4308203945Sweongyostatic void
4309203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
4310203945Sweongyo{
4311203945Sweongyo
4312203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
4313203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
4314203945Sweongyo	    dr->dr_ring_dmap);
4315203945Sweongyo}
4316203945Sweongyo
4317203945Sweongyostatic void
4318203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
4319203945Sweongyo{
4320203945Sweongyo
4321203945Sweongyo	if (dr->dr_tx) {
4322203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4323203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4324203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
4325203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
4326203945Sweongyo		} else
4327203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
4328203945Sweongyo	} else {
4329203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4330203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4331203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
4332203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
4333203945Sweongyo		} else
4334203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
4335203945Sweongyo	}
4336203945Sweongyo}
4337203945Sweongyo
4338203945Sweongyostatic void
4339203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
4340203945Sweongyo{
4341203945Sweongyo	struct bwn_dmadesc_generic *desc;
4342203945Sweongyo	struct bwn_dmadesc_meta *meta;
4343203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4344203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4345203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4346203945Sweongyo	int i;
4347203945Sweongyo
4348203945Sweongyo	if (!dr->dr_usedslot)
4349203945Sweongyo		return;
4350203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
4351203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
4352203945Sweongyo
4353203945Sweongyo		if (meta->mt_m == NULL) {
4354203945Sweongyo			if (!dr->dr_tx)
4355203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
4356203945Sweongyo				    __func__);
4357203945Sweongyo			continue;
4358203945Sweongyo		}
4359203945Sweongyo		if (dr->dr_tx) {
4360203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
4361203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
4362203945Sweongyo				    meta->mt_dmap);
4363203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
4364203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
4365203945Sweongyo				    meta->mt_dmap);
4366203945Sweongyo		} else
4367203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
4368203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
4369203945Sweongyo	}
4370203945Sweongyo}
4371203945Sweongyo
4372203945Sweongyostatic int
4373203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
4374203945Sweongyo    int type)
4375203945Sweongyo{
4376203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4377203945Sweongyo	uint32_t value;
4378203945Sweongyo	int i;
4379203945Sweongyo	uint16_t offset;
4380203945Sweongyo
4381203945Sweongyo	for (i = 0; i < 10; i++) {
4382203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4383203945Sweongyo		    BWN_DMA32_TXSTATUS;
4384203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4385203945Sweongyo		if (type == BWN_DMA_64BIT) {
4386203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4387203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
4388203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
4389203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
4390203945Sweongyo				break;
4391203945Sweongyo		} else {
4392203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4393203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
4394203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
4395203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
4396203945Sweongyo				break;
4397203945Sweongyo		}
4398203945Sweongyo		DELAY(1000);
4399203945Sweongyo	}
4400203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
4401203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4402203945Sweongyo	for (i = 0; i < 10; i++) {
4403203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4404203945Sweongyo						   BWN_DMA32_TXSTATUS;
4405203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4406203945Sweongyo		if (type == BWN_DMA_64BIT) {
4407203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4408203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
4409203945Sweongyo				i = -1;
4410203945Sweongyo				break;
4411203945Sweongyo			}
4412203945Sweongyo		} else {
4413203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4414203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
4415203945Sweongyo				i = -1;
4416203945Sweongyo				break;
4417203945Sweongyo			}
4418203945Sweongyo		}
4419203945Sweongyo		DELAY(1000);
4420203945Sweongyo	}
4421203945Sweongyo	if (i != -1) {
4422203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4423203945Sweongyo		return (ENODEV);
4424203945Sweongyo	}
4425203945Sweongyo	DELAY(1000);
4426203945Sweongyo
4427203945Sweongyo	return (0);
4428203945Sweongyo}
4429203945Sweongyo
4430203945Sweongyostatic int
4431203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
4432203945Sweongyo    int type)
4433203945Sweongyo{
4434203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4435203945Sweongyo	uint32_t value;
4436203945Sweongyo	int i;
4437203945Sweongyo	uint16_t offset;
4438203945Sweongyo
4439203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
4440203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4441203945Sweongyo	for (i = 0; i < 10; i++) {
4442203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
4443203945Sweongyo		    BWN_DMA32_RXSTATUS;
4444203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4445203945Sweongyo		if (type == BWN_DMA_64BIT) {
4446203945Sweongyo			value &= BWN_DMA64_RXSTAT;
4447203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
4448203945Sweongyo				i = -1;
4449203945Sweongyo				break;
4450203945Sweongyo			}
4451203945Sweongyo		} else {
4452203945Sweongyo			value &= BWN_DMA32_RXSTATE;
4453203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
4454203945Sweongyo				i = -1;
4455203945Sweongyo				break;
4456203945Sweongyo			}
4457203945Sweongyo		}
4458203945Sweongyo		DELAY(1000);
4459203945Sweongyo	}
4460203945Sweongyo	if (i != -1) {
4461203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4462203945Sweongyo		return (ENODEV);
4463203945Sweongyo	}
4464203945Sweongyo
4465203945Sweongyo	return (0);
4466203945Sweongyo}
4467203945Sweongyo
4468203945Sweongyostatic void
4469203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
4470203945Sweongyo    struct bwn_dmadesc_meta *meta)
4471203945Sweongyo{
4472203945Sweongyo
4473203945Sweongyo	if (meta->mt_m != NULL) {
4474203945Sweongyo		m_freem(meta->mt_m);
4475203945Sweongyo		meta->mt_m = NULL;
4476203945Sweongyo	}
4477203945Sweongyo	if (meta->mt_ni != NULL) {
4478203945Sweongyo		ieee80211_free_node(meta->mt_ni);
4479203945Sweongyo		meta->mt_ni = NULL;
4480203945Sweongyo	}
4481203945Sweongyo}
4482203945Sweongyo
4483203945Sweongyostatic void
4484203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4485203945Sweongyo{
4486203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
4487203945Sweongyo	unsigned char *frame;
4488203945Sweongyo
4489203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
4490203945Sweongyo	rxhdr->frame_len = 0;
4491203945Sweongyo
4492203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
4493203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
4494203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4495203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
4496203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
4497203945Sweongyo}
4498203945Sweongyo
4499203945Sweongyostatic uint8_t
4500203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4501203945Sweongyo{
4502203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
4503203945Sweongyo
4504203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
4505203945Sweongyo	    == 0xff);
4506203945Sweongyo}
4507203945Sweongyo
4508203945Sweongyostatic void
4509203945Sweongyobwn_wme_init(struct bwn_mac *mac)
4510203945Sweongyo{
4511203945Sweongyo
4512203945Sweongyo	bwn_wme_load(mac);
4513203945Sweongyo
4514203945Sweongyo	/* enable WME support. */
4515203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
4516203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
4517203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
4518203945Sweongyo}
4519203945Sweongyo
4520203945Sweongyostatic void
4521203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
4522203945Sweongyo{
4523203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4524203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4525203945Sweongyo	uint16_t delay;	/* microsec */
4526203945Sweongyo
4527203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
4528203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
4529203945Sweongyo		delay = 500;
4530203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
4531203945Sweongyo		delay = max(delay, (uint16_t)2400);
4532203945Sweongyo
4533203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
4534203945Sweongyo}
4535203945Sweongyo
4536203945Sweongyostatic void
4537203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
4538203945Sweongyo{
4539203945Sweongyo	struct siba_sprom *sprom = &mac->mac_sd->sd_bus->siba_sprom;
4540203945Sweongyo	uint64_t hf;
4541203945Sweongyo
4542203945Sweongyo	if (bwn_bluetooth == 0)
4543203945Sweongyo		return;
4544203945Sweongyo	if ((sprom->bf_lo & BWN_BFL_BTCOEXIST) == 0)
4545203945Sweongyo		return;
4546203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
4547203945Sweongyo		return;
4548203945Sweongyo
4549203945Sweongyo	hf = bwn_hf_read(mac);
4550203945Sweongyo	if (sprom->bf_lo & BWN_BFL_BTCMOD)
4551203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
4552203945Sweongyo	else
4553203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
4554203945Sweongyo	bwn_hf_write(mac, hf);
4555203945Sweongyo}
4556203945Sweongyo
4557203945Sweongyostatic void
4558203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
4559203945Sweongyo{
4560203945Sweongyo
4561203945Sweongyo	bwn_mac_write_bssid(mac);
4562203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF, mac->mac_sc->sc_macaddr);
4563203945Sweongyo}
4564203945Sweongyo
4565203945Sweongyostatic void
4566203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
4567203945Sweongyo{
4568203945Sweongyo	int i;
4569203945Sweongyo
4570203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
4571203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
4572203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
4573203945Sweongyo
4574203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
4575203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
4576203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
4577203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
4578203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
4579203945Sweongyo		}
4580203945Sweongyo		mac->mac_key[i].keyconf = NULL;
4581203945Sweongyo	}
4582203945Sweongyo}
4583203945Sweongyo
4584203945Sweongyostatic void
4585203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
4586203945Sweongyo{
4587203945Sweongyo
4588203945Sweongyo	mac->mac_max_nr_keys = (mac->mac_sd->sd_id.sd_rev >= 5) ? 58 : 20;
4589203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
4590203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4591203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
4592203945Sweongyo	mac->mac_ktp *= 2;
4593203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 5) {
4594203945Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT,
4595203945Sweongyo		    mac->mac_max_nr_keys - 8);
4596203945Sweongyo	}
4597203945Sweongyo	bwn_clear_keys(mac);
4598203945Sweongyo}
4599203945Sweongyo
4600203945Sweongyostatic void
4601203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
4602203945Sweongyo{
4603203945Sweongyo
4604203945Sweongyo	bwn_phy_exit(mac);
4605203945Sweongyo	bwn_gpio_cleanup(mac);
4606203945Sweongyo}
4607203945Sweongyo
4608203945Sweongyostatic int
4609203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
4610203945Sweongyo{
4611203945Sweongyo	int error;
4612203945Sweongyo
4613203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
4614203945Sweongyo	if (error == 0)
4615203945Sweongyo		return (0);
4616203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
4617203945Sweongyo	if (error == 0)
4618203945Sweongyo		return (0);
4619203945Sweongyo	return (error);
4620203945Sweongyo}
4621203945Sweongyo
4622203945Sweongyostatic int
4623203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
4624203945Sweongyo{
4625203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
4626203945Sweongyo	struct siba_dev_softc *sd;
4627203945Sweongyo	uint32_t mask = 0x0000001f, set = 0x0000000f;
4628203945Sweongyo
4629203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4630203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
4631203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
4632203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
4633203945Sweongyo
4634203945Sweongyo	if (bus->siba_chipid == 0x4301) {
4635203945Sweongyo		mask |= 0x0060;
4636203945Sweongyo		set |= 0x0060;
4637203945Sweongyo	}
4638203945Sweongyo	if (bus->siba_sprom.bf_lo & BWN_BFL_PACTRL) {
4639203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
4640203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
4641203945Sweongyo		mask |= 0x0200;
4642203945Sweongyo		set |= 0x0200;
4643203945Sweongyo	}
4644203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 2)
4645203945Sweongyo		mask |= 0x0010;
4646203945Sweongyo	sd = (bus->siba_cc.scc_dev != NULL) ? bus->siba_cc.scc_dev :
4647203945Sweongyo	    bus->siba_pci.spc_dev;
4648203945Sweongyo	if (sd == NULL)
4649203945Sweongyo		return (0);
4650203945Sweongyo	siba_write_4(sd, BWN_GPIOCTL,
4651203945Sweongyo	    (siba_read_4(sd, BWN_GPIOCTL) & mask) | set);
4652203945Sweongyo
4653203945Sweongyo	return (0);
4654203945Sweongyo}
4655203945Sweongyo
4656203945Sweongyostatic int
4657203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
4658203945Sweongyo{
4659203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
4660203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
4661203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
4662203945Sweongyo	const struct bwn_fwhdr *hdr;
4663203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
4664203945Sweongyo	int error;
4665203945Sweongyo
4666203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
4667203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
4668203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
4669203945Sweongyo	if (error)
4670203945Sweongyo		return (error);
4671203945Sweongyo	if (fw->initvals_band.fw) {
4672203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
4673203945Sweongyo		error = bwn_fwinitvals_write(mac,
4674203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
4675203945Sweongyo		    be32toh(hdr->size),
4676203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
4677203945Sweongyo	}
4678203945Sweongyo	return (error);
4679203945Sweongyo#undef GETFWOFFSET
4680203945Sweongyo}
4681203945Sweongyo
4682203945Sweongyostatic int
4683203945Sweongyobwn_phy_init(struct bwn_mac *mac)
4684203945Sweongyo{
4685203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4686203945Sweongyo	int error;
4687203945Sweongyo
4688203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
4689203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4690203945Sweongyo	error = mac->mac_phy.init(mac);
4691203945Sweongyo	if (error) {
4692203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
4693203945Sweongyo		goto fail0;
4694203945Sweongyo	}
4695203945Sweongyo	error = bwn_switch_channel(mac,
4696203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
4697203945Sweongyo	if (error) {
4698203945Sweongyo		device_printf(sc->sc_dev,
4699203945Sweongyo		    "failed to switch default channel\n");
4700203945Sweongyo		goto fail1;
4701203945Sweongyo	}
4702203945Sweongyo	return (0);
4703203945Sweongyofail1:
4704203945Sweongyo	if (mac->mac_phy.exit)
4705203945Sweongyo		mac->mac_phy.exit(mac);
4706203945Sweongyofail0:
4707203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4708203945Sweongyo
4709203945Sweongyo	return (error);
4710203945Sweongyo}
4711203945Sweongyo
4712203945Sweongyostatic void
4713203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
4714203945Sweongyo{
4715203945Sweongyo	uint16_t ant;
4716203945Sweongyo	uint16_t tmp;
4717203945Sweongyo
4718203945Sweongyo	ant = bwn_ant2phy(antenna);
4719203945Sweongyo
4720203945Sweongyo	/* For ACK/CTS */
4721203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
4722203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4723203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
4724203945Sweongyo	/* For Probe Resposes */
4725203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
4726203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4727203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
4728203945Sweongyo}
4729203945Sweongyo
4730203945Sweongyostatic void
4731203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
4732203945Sweongyo{
4733203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4734203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4735203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
4736203945Sweongyo	uint32_t ctl;
4737203945Sweongyo	uint16_t cfp_pretbtt;
4738203945Sweongyo
4739203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
4740203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
4741203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
4742203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
4743203945Sweongyo	ctl |= BWN_MACCTL_STA;
4744203945Sweongyo
4745203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4746203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
4747203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
4748203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
4749203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
4750203945Sweongyo	ctl |= sc->sc_filters;
4751203945Sweongyo
4752203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev <= 4)
4753203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
4754203945Sweongyo
4755203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
4756203945Sweongyo
4757203945Sweongyo	cfp_pretbtt = 2;
4758203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
4759203945Sweongyo		if (mac->mac_sd->sd_bus->siba_chipid == 0x4306 &&
4760203945Sweongyo		    mac->mac_sd->sd_bus->siba_chiprev == 3)
4761203945Sweongyo			cfp_pretbtt = 100;
4762203945Sweongyo		else
4763203945Sweongyo			cfp_pretbtt = 50;
4764203945Sweongyo	}
4765203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
4766203945Sweongyo}
4767203945Sweongyo
4768203945Sweongyostatic void
4769203945Sweongyobwn_gpio_cleanup(struct bwn_mac *mac)
4770203945Sweongyo{
4771203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
4772203945Sweongyo	struct siba_dev_softc *gpiodev, *pcidev = NULL;
4773203945Sweongyo
4774203945Sweongyo	pcidev = bus->siba_pci.spc_dev;
4775203945Sweongyo	gpiodev = bus->siba_cc.scc_dev ? bus->siba_cc.scc_dev : pcidev;
4776203945Sweongyo	if (!gpiodev)
4777203945Sweongyo		return;
4778203945Sweongyo	siba_write_4(gpiodev, BWN_GPIOCTL, 0);
4779203945Sweongyo}
4780203945Sweongyo
4781203945Sweongyostatic int
4782203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
4783203945Sweongyo{
4784203945Sweongyo	uint32_t tmp;
4785203945Sweongyo	uint16_t base;
4786203945Sweongyo
4787203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
4788203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
4789203945Sweongyo		return (BWN_DMA_64BIT);
4790203945Sweongyo	base = bwn_dma_base(0, 0);
4791203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
4792203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
4793203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
4794203945Sweongyo		return (BWN_DMA_32BIT);
4795203945Sweongyo
4796203945Sweongyo	return (BWN_DMA_30BIT);
4797203945Sweongyo}
4798203945Sweongyo
4799203945Sweongyostatic void
4800203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
4801203945Sweongyo{
4802203945Sweongyo	if (!error) {
4803203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
4804203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
4805203945Sweongyo	}
4806203945Sweongyo}
4807203945Sweongyo
4808203945Sweongyostatic void
4809203945Sweongyobwn_phy_g_init_sub(struct bwn_mac *mac)
4810203945Sweongyo{
4811203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4812203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4813203945Sweongyo	uint16_t i, tmp;
4814203945Sweongyo
4815203945Sweongyo	if (phy->rev == 1)
4816203945Sweongyo		bwn_phy_init_b5(mac);
4817203945Sweongyo	else
4818203945Sweongyo		bwn_phy_init_b6(mac);
4819203945Sweongyo
4820203945Sweongyo	if (phy->rev >= 2 || phy->gmode)
4821203945Sweongyo		bwn_phy_init_a(mac);
4822203945Sweongyo
4823203945Sweongyo	if (phy->rev >= 2) {
4824203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
4825203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
4826203945Sweongyo	}
4827203945Sweongyo	if (phy->rev == 2) {
4828203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
4829203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4830203945Sweongyo	}
4831203945Sweongyo	if (phy->rev > 5) {
4832203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
4833203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4834203945Sweongyo	}
4835203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4836203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
4837203945Sweongyo		tmp &= BWN_PHYVER_VERSION;
4838203945Sweongyo		if (tmp == 3 || tmp == 5) {
4839203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
4840203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
4841203945Sweongyo		}
4842203945Sweongyo		if (tmp == 5) {
4843203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
4844203945Sweongyo			    0x1f00);
4845203945Sweongyo		}
4846203945Sweongyo	}
4847203945Sweongyo	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
4848203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
4849203945Sweongyo	if (phy->rf_rev == 8) {
4850203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
4851203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
4852203945Sweongyo	}
4853203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
4854203945Sweongyo		bwn_loopback_calcgain(mac);
4855203945Sweongyo
4856203945Sweongyo	if (phy->rf_rev != 8) {
4857203945Sweongyo		if (pg->pg_initval == 0xffff)
4858203945Sweongyo			pg->pg_initval = bwn_rf_init_bcm2050(mac);
4859203945Sweongyo		else
4860203945Sweongyo			BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
4861203945Sweongyo	}
4862203945Sweongyo	bwn_lo_g_init(mac);
4863203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
4864203945Sweongyo		BWN_RF_WRITE(mac, 0x52,
4865203945Sweongyo		    (BWN_RF_READ(mac, 0x52) & 0xff00)
4866203945Sweongyo		    | pg->pg_loctl.tx_bias |
4867203945Sweongyo		    pg->pg_loctl.tx_magn);
4868203945Sweongyo	} else {
4869203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
4870203945Sweongyo	}
4871203945Sweongyo	if (phy->rev >= 6) {
4872203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
4873203945Sweongyo		    (pg->pg_loctl.tx_bias << 12));
4874203945Sweongyo	}
4875203945Sweongyo	if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_PACTRL)
4876203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
4877203945Sweongyo	else
4878203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
4879203945Sweongyo	if (phy->rev < 2)
4880203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
4881203945Sweongyo	else
4882203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
4883203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4884203945Sweongyo		bwn_lo_g_adjust(mac);
4885203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
4886203945Sweongyo	}
4887203945Sweongyo
4888203945Sweongyo	if (!(mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_RSSI)) {
4889203945Sweongyo		for (i = 0; i < 64; i++) {
4890203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
4891203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
4892203945Sweongyo			    (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
4893203945Sweongyo			    -32), 31));
4894203945Sweongyo		}
4895203945Sweongyo		bwn_nrssi_threshold(mac);
4896203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
4897203945Sweongyo		if (pg->pg_nrssi[0] == -1000) {
4898203945Sweongyo			KASSERT(pg->pg_nrssi[1] == -1000,
4899203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
4900203945Sweongyo			bwn_nrssi_slope_11g(mac);
4901203945Sweongyo		} else
4902203945Sweongyo			bwn_nrssi_threshold(mac);
4903203945Sweongyo	}
4904203945Sweongyo	if (phy->rf_rev == 8)
4905203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
4906203945Sweongyo	bwn_phy_hwpctl_init(mac);
4907203945Sweongyo	if ((mac->mac_sd->sd_bus->siba_chipid == 0x4306
4908203945Sweongyo	     && mac->mac_sd->sd_bus->siba_chippkg == 2) || 0) {
4909203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
4910203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
4911203945Sweongyo	}
4912203945Sweongyo}
4913203945Sweongyo
4914203945Sweongyostatic uint8_t
4915203945Sweongyobwn_has_hwpctl(struct bwn_mac *mac)
4916203945Sweongyo{
4917203945Sweongyo
4918203945Sweongyo	if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
4919203945Sweongyo		return (0);
4920203945Sweongyo	return (mac->mac_phy.use_hwpctl(mac));
4921203945Sweongyo}
4922203945Sweongyo
4923203945Sweongyostatic void
4924203945Sweongyobwn_phy_init_b5(struct bwn_mac *mac)
4925203945Sweongyo{
4926203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
4927203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4928203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4929203945Sweongyo	uint16_t offset, value;
4930203945Sweongyo	uint8_t old_channel;
4931203945Sweongyo
4932203945Sweongyo	if (phy->analog == 1)
4933203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0050);
4934203945Sweongyo	if ((bus->siba_board_vendor != SIBA_BOARDVENDOR_BCM) &&
4935203945Sweongyo	    (bus->siba_board_type != SIBA_BOARD_BU4306)) {
4936203945Sweongyo		value = 0x2120;
4937203945Sweongyo		for (offset = 0x00a8; offset < 0x00c7; offset++) {
4938203945Sweongyo			BWN_PHY_WRITE(mac, offset, value);
4939203945Sweongyo			value += 0x202;
4940203945Sweongyo		}
4941203945Sweongyo	}
4942203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
4943203945Sweongyo	if (phy->rf_ver == 0x2050)
4944203945Sweongyo		BWN_PHY_WRITE(mac, 0x0038, 0x0667);
4945203945Sweongyo
4946203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4947203945Sweongyo		if (phy->rf_ver == 0x2050) {
4948203945Sweongyo			BWN_RF_SET(mac, 0x007a, 0x0020);
4949203945Sweongyo			BWN_RF_SET(mac, 0x0051, 0x0004);
4950203945Sweongyo		}
4951203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
4952203945Sweongyo
4953203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
4954203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
4955203945Sweongyo
4956203945Sweongyo		BWN_PHY_WRITE(mac, 0x001c, 0x186a);
4957203945Sweongyo
4958203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
4959203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
4960203945Sweongyo		BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
4961203945Sweongyo	}
4962203945Sweongyo
4963203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
4964203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
4965203945Sweongyo
4966203945Sweongyo	if (phy->analog == 1) {
4967203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xce00);
4968203945Sweongyo		BWN_PHY_WRITE(mac, 0x0021, 0x3763);
4969203945Sweongyo		BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
4970203945Sweongyo		BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
4971203945Sweongyo		BWN_PHY_WRITE(mac, 0x0024, 0x037e);
4972203945Sweongyo	} else
4973203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
4974203945Sweongyo	BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
4975203945Sweongyo	BWN_WRITE_2(mac, 0x03ec, 0x3f22);
4976203945Sweongyo
4977203945Sweongyo	if (phy->analog == 1)
4978203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
4979203945Sweongyo	else
4980203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x301c);
4981203945Sweongyo
4982203945Sweongyo	if (phy->analog == 0)
4983203945Sweongyo		BWN_WRITE_2(mac, 0x03e4, 0x3000);
4984203945Sweongyo
4985203945Sweongyo	old_channel = phy->chan;
4986203945Sweongyo	bwn_phy_g_switch_chan(mac, 7, 0);
4987203945Sweongyo
4988203945Sweongyo	if (phy->rf_ver != 0x2050) {
4989203945Sweongyo		BWN_RF_WRITE(mac, 0x0075, 0x0080);
4990203945Sweongyo		BWN_RF_WRITE(mac, 0x0079, 0x0081);
4991203945Sweongyo	}
4992203945Sweongyo
4993203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
4994203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
4995203945Sweongyo
4996203945Sweongyo	if (phy->rf_ver == 0x2050) {
4997203945Sweongyo		BWN_RF_WRITE(mac, 0x0050, 0x0020);
4998203945Sweongyo		BWN_RF_WRITE(mac, 0x005a, 0x0070);
4999203945Sweongyo	}
5000203945Sweongyo
5001203945Sweongyo	BWN_RF_WRITE(mac, 0x005b, 0x007b);
5002203945Sweongyo	BWN_RF_WRITE(mac, 0x005c, 0x00b0);
5003203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0007);
5004203945Sweongyo
5005203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5006203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0080);
5007203945Sweongyo	BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
5008203945Sweongyo	BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
5009203945Sweongyo
5010203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5011203945Sweongyo	    pg->pg_txctl);
5012203945Sweongyo
5013203945Sweongyo	if (phy->rf_ver == 0x2050)
5014203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5015203945Sweongyo
5016203945Sweongyo	BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
5017203945Sweongyo}
5018203945Sweongyo
5019203945Sweongyostatic void
5020203945Sweongyobwn_loopback_calcgain(struct bwn_mac *mac)
5021203945Sweongyo{
5022203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5023203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5024203945Sweongyo	uint16_t backup_phy[16] = { 0 };
5025203945Sweongyo	uint16_t backup_radio[3];
5026203945Sweongyo	uint16_t backup_bband;
5027203945Sweongyo	uint16_t i, j, loop_i_max;
5028203945Sweongyo	uint16_t trsw_rx;
5029203945Sweongyo	uint16_t loop1_outer_done, loop1_inner_done;
5030203945Sweongyo
5031203945Sweongyo	backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5032203945Sweongyo	backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
5033203945Sweongyo	backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5034203945Sweongyo	backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5035203945Sweongyo	if (phy->rev != 1) {
5036203945Sweongyo		backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5037203945Sweongyo		backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5038203945Sweongyo	}
5039203945Sweongyo	backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5040203945Sweongyo	backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5041203945Sweongyo	backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5042203945Sweongyo	backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
5043203945Sweongyo	backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
5044203945Sweongyo	backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5045203945Sweongyo	backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5046203945Sweongyo	backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
5047203945Sweongyo	backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5048203945Sweongyo	backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5049203945Sweongyo	backup_bband = pg->pg_bbatt.att;
5050203945Sweongyo	backup_radio[0] = BWN_RF_READ(mac, 0x52);
5051203945Sweongyo	backup_radio[1] = BWN_RF_READ(mac, 0x43);
5052203945Sweongyo	backup_radio[2] = BWN_RF_READ(mac, 0x7a);
5053203945Sweongyo
5054203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
5055203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
5056203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
5057203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
5058203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
5059203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
5060203945Sweongyo	if (phy->rev != 1) {
5061203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
5062203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
5063203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
5064203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
5065203945Sweongyo	}
5066203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
5067203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
5068203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
5069203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
5070203945Sweongyo
5071203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
5072203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5073203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5074203945Sweongyo
5075203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
5076203945Sweongyo	if (phy->rev != 1) {
5077203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
5078203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
5079203945Sweongyo	}
5080203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
5081203945Sweongyo
5082203945Sweongyo	if (phy->rf_rev == 8)
5083203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x000f);
5084203945Sweongyo	else {
5085203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5086203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
5087203945Sweongyo	}
5088203945Sweongyo	bwn_phy_g_set_bbatt(mac, 11);
5089203945Sweongyo
5090203945Sweongyo	if (phy->rev >= 3)
5091203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5092203945Sweongyo	else
5093203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5094203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5095203945Sweongyo
5096203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
5097203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
5098203945Sweongyo
5099203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
5100203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
5101203945Sweongyo
5102203945Sweongyo	if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA) {
5103203945Sweongyo		if (phy->rev >= 7) {
5104203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
5105203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
5106203945Sweongyo		}
5107203945Sweongyo	}
5108203945Sweongyo	BWN_RF_MASK(mac, 0x7a, 0x00f7);
5109203945Sweongyo
5110203945Sweongyo	j = 0;
5111203945Sweongyo	loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
5112203945Sweongyo	for (i = 0; i < loop_i_max; i++) {
5113203945Sweongyo		for (j = 0; j < 16; j++) {
5114203945Sweongyo			BWN_RF_WRITE(mac, 0x43, i);
5115203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
5116203945Sweongyo			    (j << 8));
5117203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5118203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5119203945Sweongyo			DELAY(20);
5120203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5121203945Sweongyo				goto done0;
5122203945Sweongyo		}
5123203945Sweongyo	}
5124203945Sweongyodone0:
5125203945Sweongyo	loop1_outer_done = i;
5126203945Sweongyo	loop1_inner_done = j;
5127203945Sweongyo	if (j >= 8) {
5128203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
5129203945Sweongyo		trsw_rx = 0x1b;
5130203945Sweongyo		for (j = j - 8; j < 16; j++) {
5131203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
5132203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5133203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5134203945Sweongyo			DELAY(20);
5135203945Sweongyo			trsw_rx -= 3;
5136203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5137203945Sweongyo				goto done1;
5138203945Sweongyo		}
5139203945Sweongyo	} else
5140203945Sweongyo		trsw_rx = 0x18;
5141203945Sweongyodone1:
5142203945Sweongyo
5143203945Sweongyo	if (phy->rev != 1) {
5144203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
5145203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
5146203945Sweongyo	}
5147203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
5148203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
5149203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
5150203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
5151203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
5152203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
5153203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
5154203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
5155203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
5156203945Sweongyo
5157203945Sweongyo	bwn_phy_g_set_bbatt(mac, backup_bband);
5158203945Sweongyo
5159203945Sweongyo	BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
5160203945Sweongyo	BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
5161203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
5162203945Sweongyo
5163203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
5164203945Sweongyo	DELAY(10);
5165203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
5166203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
5167203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
5168203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
5169203945Sweongyo
5170203945Sweongyo	pg->pg_max_lb_gain =
5171203945Sweongyo	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
5172203945Sweongyo	pg->pg_trsw_rx_gain = trsw_rx * 2;
5173203945Sweongyo}
5174203945Sweongyo
5175203945Sweongyostatic uint16_t
5176203945Sweongyobwn_rf_init_bcm2050(struct bwn_mac *mac)
5177203945Sweongyo{
5178203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5179203945Sweongyo	uint32_t tmp1 = 0, tmp2 = 0;
5180203945Sweongyo	uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
5181203945Sweongyo	    analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
5182203945Sweongyo	    radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
5183203945Sweongyo	static const uint8_t rcc_table[] = {
5184203945Sweongyo		0x02, 0x03, 0x01, 0x0f,
5185203945Sweongyo		0x06, 0x07, 0x05, 0x0f,
5186203945Sweongyo		0x0a, 0x0b, 0x09, 0x0f,
5187203945Sweongyo		0x0e, 0x0f, 0x0d, 0x0f,
5188203945Sweongyo	};
5189203945Sweongyo
5190204242Simp	loctl = lomask = reg0 = classctl = crs0 = analogoverval = analogover =
5191204242Simp	    rfoverval = rfover = cck3 = 0;
5192203945Sweongyo	radio0 = BWN_RF_READ(mac, 0x43);
5193203945Sweongyo	radio1 = BWN_RF_READ(mac, 0x51);
5194203945Sweongyo	radio2 = BWN_RF_READ(mac, 0x52);
5195203945Sweongyo	pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5196203945Sweongyo	cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5197203945Sweongyo	cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5198203945Sweongyo	cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5199203945Sweongyo
5200203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5201203945Sweongyo		cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
5202203945Sweongyo		reg0 = BWN_READ_2(mac, 0x3ec);
5203203945Sweongyo
5204203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
5205203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
5206203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
5207203945Sweongyo		rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5208203945Sweongyo		rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5209203945Sweongyo		analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5210203945Sweongyo		analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5211203945Sweongyo		crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5212203945Sweongyo		classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
5213203945Sweongyo
5214203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
5215203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
5216203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
5217203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
5218203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5219203945Sweongyo			lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5220203945Sweongyo			loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5221203945Sweongyo			if (phy->rev >= 3)
5222203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5223203945Sweongyo			else
5224203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5225203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5226203945Sweongyo		}
5227203945Sweongyo
5228203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5229203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5230203945Sweongyo			BWN_LPD(0, 1, 1)));
5231203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
5232203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
5233203945Sweongyo	}
5234203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
5235203945Sweongyo
5236203945Sweongyo	syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
5237203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
5238203945Sweongyo	reg1 = BWN_READ_2(mac, 0x3e6);
5239203945Sweongyo	reg2 = BWN_READ_2(mac, 0x3f4);
5240203945Sweongyo
5241203945Sweongyo	if (phy->analog == 0)
5242203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0122);
5243203945Sweongyo	else {
5244203945Sweongyo		if (phy->analog >= 2)
5245203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
5246203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
5247203945Sweongyo		    (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
5248203945Sweongyo	}
5249203945Sweongyo
5250203945Sweongyo	reg = BWN_RF_READ(mac, 0x60);
5251203945Sweongyo	index = (reg & 0x001e) >> 1;
5252203945Sweongyo	rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
5253203945Sweongyo
5254203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5255203945Sweongyo		BWN_RF_WRITE(mac, 0x78, 0x26);
5256203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5257203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5258203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5259203945Sweongyo			BWN_LPD(0, 1, 1)));
5260203945Sweongyo	}
5261203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
5262203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
5263203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5264203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5265203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5266203945Sweongyo			BWN_LPD(0, 0, 1)));
5267203945Sweongyo	}
5268203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
5269203945Sweongyo	BWN_RF_SET(mac, 0x51, 0x0004);
5270203945Sweongyo	if (phy->rf_rev == 8)
5271203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x1f);
5272203945Sweongyo	else {
5273203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5274203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
5275203945Sweongyo	}
5276203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5277203945Sweongyo
5278203945Sweongyo	for (i = 0; i < 16; i++) {
5279203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
5280203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5281203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5282203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5283203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5284203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5285203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5286203945Sweongyo		}
5287203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5288203945Sweongyo		DELAY(10);
5289203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5290203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5291203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5292203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5293203945Sweongyo		}
5294203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5295203945Sweongyo		DELAY(10);
5296203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5297203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5298203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5299203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5300203945Sweongyo		}
5301203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5302203945Sweongyo		DELAY(20);
5303203945Sweongyo		tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5304203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5305203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5306203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5307203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5308203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5309203945Sweongyo		}
5310203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5311203945Sweongyo	}
5312203945Sweongyo	DELAY(10);
5313203945Sweongyo
5314203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5315203945Sweongyo	tmp1++;
5316203945Sweongyo	tmp1 >>= 9;
5317203945Sweongyo
5318203945Sweongyo	for (i = 0; i < 16; i++) {
5319203945Sweongyo		radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
5320203945Sweongyo		BWN_RF_WRITE(mac, 0x78, radio78);
5321203945Sweongyo		DELAY(10);
5322203945Sweongyo		for (j = 0; j < 16; j++) {
5323203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
5324203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5325203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5326203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5327203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5328203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5329203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5330203945Sweongyo			}
5331203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5332203945Sweongyo			DELAY(10);
5333203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5334203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5335203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5336203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5337203945Sweongyo			}
5338203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5339203945Sweongyo			DELAY(10);
5340203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5341203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5342203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5343203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5344203945Sweongyo			}
5345203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5346203945Sweongyo			DELAY(10);
5347203945Sweongyo			tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5348203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5349203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5350203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5351203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5352203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5353203945Sweongyo			}
5354203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5355203945Sweongyo		}
5356203945Sweongyo		tmp2++;
5357203945Sweongyo		tmp2 >>= 8;
5358203945Sweongyo		if (tmp1 < tmp2)
5359203945Sweongyo			break;
5360203945Sweongyo	}
5361203945Sweongyo
5362203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
5363203945Sweongyo	BWN_RF_WRITE(mac, 0x51, radio1);
5364203945Sweongyo	BWN_RF_WRITE(mac, 0x52, radio2);
5365203945Sweongyo	BWN_RF_WRITE(mac, 0x43, radio0);
5366203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
5367203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
5368203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
5369203945Sweongyo	BWN_WRITE_2(mac, 0x3e6, reg1);
5370203945Sweongyo	if (phy->analog != 0)
5371203945Sweongyo		BWN_WRITE_2(mac, 0x3f4, reg2);
5372203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
5373203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
5374203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5375203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
5376203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, reg0);
5377203945Sweongyo	} else if (phy->gmode) {
5378203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO,
5379203945Sweongyo			    BWN_READ_2(mac, BWN_PHY_RADIO)
5380203945Sweongyo			    & 0x7fff);
5381203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
5382203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
5383203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
5384203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
5385203945Sweongyo			      analogoverval);
5386203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
5387203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
5388203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5389203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
5390203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
5391203945Sweongyo		}
5392203945Sweongyo	}
5393203945Sweongyo
5394203945Sweongyo	return ((i > 15) ? radio78 : rcc);
5395203945Sweongyo}
5396203945Sweongyo
5397203945Sweongyostatic void
5398203945Sweongyobwn_phy_init_b6(struct bwn_mac *mac)
5399203945Sweongyo{
5400203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5401203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5402203945Sweongyo	uint16_t offset, val;
5403203945Sweongyo	uint8_t old_channel;
5404203945Sweongyo
5405203945Sweongyo	KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
5406203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5407203945Sweongyo
5408203945Sweongyo	BWN_PHY_WRITE(mac, 0x003e, 0x817a);
5409203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
5410203945Sweongyo	if (phy->rf_rev == 4 || phy->rf_rev == 5) {
5411203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0x37);
5412203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x70);
5413203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb3);
5414203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x9b);
5415203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5416203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x88);
5417203945Sweongyo		BWN_RF_WRITE(mac, 0x5d, 0x88);
5418203945Sweongyo		BWN_RF_WRITE(mac, 0x5e, 0x88);
5419203945Sweongyo		BWN_RF_WRITE(mac, 0x7d, 0x88);
5420203945Sweongyo		bwn_hf_write(mac,
5421203945Sweongyo		    bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
5422203945Sweongyo	}
5423203945Sweongyo	if (phy->rf_rev == 8) {
5424203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0);
5425203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x40);
5426203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb7);
5427203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x98);
5428203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5429203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x6b);
5430203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0x0f);
5431203945Sweongyo		if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_ALTIQ) {
5432203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xfa);
5433203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xd8);
5434203945Sweongyo		} else {
5435203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xf5);
5436203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xb8);
5437203945Sweongyo		}
5438203945Sweongyo		BWN_RF_WRITE(mac, 0x0073, 0x0003);
5439203945Sweongyo		BWN_RF_WRITE(mac, 0x007d, 0x00a8);
5440203945Sweongyo		BWN_RF_WRITE(mac, 0x007c, 0x0001);
5441203945Sweongyo		BWN_RF_WRITE(mac, 0x007e, 0x0008);
5442203945Sweongyo	}
5443203945Sweongyo	for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
5444203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5445203945Sweongyo		val -= 0x0202;
5446203945Sweongyo	}
5447203945Sweongyo	for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
5448203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5449203945Sweongyo		val -= 0x0202;
5450203945Sweongyo	}
5451203945Sweongyo	for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
5452203945Sweongyo		BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
5453203945Sweongyo		val += 0x0202;
5454203945Sweongyo	}
5455203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
5456203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0020);
5457203945Sweongyo		BWN_RF_SET(mac, 0x0051, 0x0004);
5458203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
5459203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
5460203945Sweongyo		BWN_PHY_WRITE(mac, 0x5b, 0);
5461203945Sweongyo		BWN_PHY_WRITE(mac, 0x5c, 0);
5462203945Sweongyo	}
5463203945Sweongyo
5464203945Sweongyo	old_channel = phy->chan;
5465203945Sweongyo	bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
5466203945Sweongyo
5467203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
5468203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
5469203945Sweongyo	DELAY(40);
5470203945Sweongyo	if (phy->rf_rev < 6 || phy->rf_rev == 8) {
5471203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
5472203945Sweongyo		BWN_RF_WRITE(mac, 0x50, 0x20);
5473203945Sweongyo	}
5474203945Sweongyo	if (phy->rf_rev <= 2) {
5475203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, 0x20);
5476203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x70);
5477203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x7b);
5478203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0xb0);
5479203945Sweongyo	}
5480203945Sweongyo	BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
5481203945Sweongyo
5482203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5483203945Sweongyo
5484203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0200);
5485203945Sweongyo	if (phy->rf_rev >= 6)
5486203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
5487203945Sweongyo	else
5488203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
5489203945Sweongyo	BWN_PHY_WRITE(mac, 0x0038, 0x0668);
5490203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5491203945Sweongyo	    pg->pg_txctl);
5492203945Sweongyo	if (phy->rf_rev <= 5)
5493203945Sweongyo		BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
5494203945Sweongyo	if (phy->rf_rev <= 2)
5495203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5496203945Sweongyo
5497203945Sweongyo	if (phy->analog == 4) {
5498203945Sweongyo		BWN_WRITE_2(mac, 0x3e4, 9);
5499203945Sweongyo		BWN_PHY_MASK(mac, 0x61, 0x0fff);
5500203945Sweongyo	} else
5501203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
5502203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5503203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5504203945Sweongyo	else if (phy->type == BWN_PHYTYPE_G)
5505203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0);
5506203945Sweongyo}
5507203945Sweongyo
5508203945Sweongyostatic void
5509203945Sweongyobwn_phy_init_a(struct bwn_mac *mac)
5510203945Sweongyo{
5511203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5512203945Sweongyo
5513203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
5514203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5515203945Sweongyo
5516203945Sweongyo	if (phy->rev >= 6) {
5517203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5518203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
5519203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
5520203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
5521203945Sweongyo		else
5522203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
5523203945Sweongyo	}
5524203945Sweongyo
5525203945Sweongyo	bwn_wa_init(mac);
5526203945Sweongyo
5527203945Sweongyo	if (phy->type == BWN_PHYTYPE_G &&
5528203945Sweongyo	    (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_PACTRL))
5529203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
5530203945Sweongyo}
5531203945Sweongyo
5532203945Sweongyostatic void
5533203945Sweongyobwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
5534203945Sweongyo{
5535203945Sweongyo	int i;
5536203945Sweongyo
5537203945Sweongyo	for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
5538203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
5539203945Sweongyo}
5540203945Sweongyo
5541203945Sweongyostatic void
5542203945Sweongyobwn_wa_agc(struct bwn_mac *mac)
5543203945Sweongyo{
5544203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5545203945Sweongyo
5546203945Sweongyo	if (phy->rev == 1) {
5547203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
5548203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
5549203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
5550203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
5551203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
5552203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
5553203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
5554203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
5555203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
5556203945Sweongyo	} else {
5557203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
5558203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
5559203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
5560203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
5561203945Sweongyo	}
5562203945Sweongyo
5563203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
5564203945Sweongyo	    0x5700);
5565203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
5566203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
5567203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
5568203945Sweongyo	BWN_RF_SET(mac, 0x7a, 0x0008);
5569203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
5570203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
5571203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
5572203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
5573203945Sweongyo	if (phy->rev == 1)
5574203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
5575203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
5576203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
5577203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
5578203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
5579203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
5580203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
5581203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
5582203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
5583203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
5584203945Sweongyo	if (phy->rev == 1) {
5585203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
5586203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
5587203945Sweongyo	} else {
5588203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
5589203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
5590203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
5591203945Sweongyo		if (phy->rev >= 6) {
5592203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
5593203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
5594203945Sweongyo			    (uint16_t)~0xf000, 0x3000);
5595203945Sweongyo		}
5596203945Sweongyo	}
5597203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
5598203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
5599203945Sweongyo	if (phy->rev == 1) {
5600203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
5601203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
5602203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
5603203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
5604203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
5605203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
5606203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
5607203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
5608203945Sweongyo	} else {
5609203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
5610203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
5611203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
5612203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
5613203945Sweongyo	}
5614203945Sweongyo	if (phy->rev >= 6) {
5615203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
5616203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
5617203945Sweongyo	}
5618203945Sweongyo	BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
5619203945Sweongyo}
5620203945Sweongyo
5621203945Sweongyostatic void
5622203945Sweongyobwn_wa_grev1(struct bwn_mac *mac)
5623203945Sweongyo{
5624203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5625203945Sweongyo	int i;
5626203945Sweongyo	static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
5627203945Sweongyo	static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
5628203945Sweongyo	static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
5629203945Sweongyo
5630203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5631203945Sweongyo
5632203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5633203945Sweongyo	if (phy->rev == 1) {
5634203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5635203945Sweongyo	} else if (phy->rev == 2) {
5636203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5637203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5638203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5639203945Sweongyo	} else {
5640203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5641203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5642203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5643203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5644203945Sweongyo	}
5645203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
5646203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
5647203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
5648203945Sweongyo
5649203945Sweongyo	/* XXX support PHY-A??? */
5650203945Sweongyo	for (i = 0; i < N(bwn_tab_finefreqg); i++)
5651203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
5652203945Sweongyo		    bwn_tab_finefreqg[i]);
5653203945Sweongyo
5654203945Sweongyo	/* XXX support PHY-A??? */
5655203945Sweongyo	if (phy->rev == 1)
5656203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5657203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5658203945Sweongyo			    bwn_tab_noise_g1[i]);
5659203945Sweongyo	else
5660203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5661203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5662203945Sweongyo			    bwn_tab_noise_g2[i]);
5663203945Sweongyo
5664203945Sweongyo
5665203945Sweongyo	for (i = 0; i < N(bwn_tab_rotor); i++)
5666203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
5667203945Sweongyo		    bwn_tab_rotor[i]);
5668203945Sweongyo
5669203945Sweongyo	/* XXX support PHY-A??? */
5670203945Sweongyo	if (phy->rev >= 6) {
5671203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5672203945Sweongyo		    BWN_PHY_ENCORE_EN)
5673203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5674203945Sweongyo		else
5675203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5676203945Sweongyo	} else
5677203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5678203945Sweongyo
5679203945Sweongyo	for (i = 0; i < N(bwn_tab_retard); i++)
5680203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
5681203945Sweongyo		    bwn_tab_retard[i]);
5682203945Sweongyo
5683203945Sweongyo	if (phy->rev == 1) {
5684203945Sweongyo		for (i = 0; i < 16; i++)
5685203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
5686203945Sweongyo			    i, 0x0020);
5687203945Sweongyo	} else {
5688203945Sweongyo		for (i = 0; i < 32; i++)
5689203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5690203945Sweongyo	}
5691203945Sweongyo
5692203945Sweongyo	bwn_wa_agc(mac);
5693203945Sweongyo}
5694203945Sweongyo
5695203945Sweongyostatic void
5696203945Sweongyobwn_wa_grev26789(struct bwn_mac *mac)
5697203945Sweongyo{
5698203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5699203945Sweongyo	int i;
5700203945Sweongyo	static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
5701203945Sweongyo	uint16_t ofdmrev;
5702203945Sweongyo
5703203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5704203945Sweongyo
5705203945Sweongyo	bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
5706203945Sweongyo
5707203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5708203945Sweongyo	if (phy->rev == 1)
5709203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5710203945Sweongyo	else if (phy->rev == 2) {
5711203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5712203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5713203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5714203945Sweongyo	} else {
5715203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5716203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5717203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5718203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5719203945Sweongyo	}
5720203945Sweongyo
5721203945Sweongyo	for (i = 0; i < 64; i++)
5722203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
5723203945Sweongyo
5724203945Sweongyo	/* XXX support PHY-A??? */
5725203945Sweongyo	if (phy->rev == 1)
5726203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5727203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5728203945Sweongyo			    bwn_tab_noise_g1[i]);
5729203945Sweongyo	else
5730203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5731203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5732203945Sweongyo			    bwn_tab_noise_g2[i]);
5733203945Sweongyo
5734203945Sweongyo	/* XXX support PHY-A??? */
5735203945Sweongyo	if (phy->rev >= 6) {
5736203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5737203945Sweongyo		    BWN_PHY_ENCORE_EN)
5738203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5739203945Sweongyo		else
5740203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5741203945Sweongyo	} else
5742203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5743203945Sweongyo
5744203945Sweongyo	for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
5745203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
5746203945Sweongyo		    bwn_tab_sigmasqr2[i]);
5747203945Sweongyo
5748203945Sweongyo	if (phy->rev == 1) {
5749203945Sweongyo		for (i = 0; i < 16; i++)
5750203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
5751203945Sweongyo			    0x0020);
5752203945Sweongyo	} else {
5753203945Sweongyo		for (i = 0; i < 32; i++)
5754203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5755203945Sweongyo	}
5756203945Sweongyo
5757203945Sweongyo	bwn_wa_agc(mac);
5758203945Sweongyo
5759203945Sweongyo	ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
5760203945Sweongyo	if (ofdmrev > 2) {
5761203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5762203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
5763203945Sweongyo		else
5764203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
5765203945Sweongyo	} else {
5766203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
5767203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
5768203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
5769203945Sweongyo	}
5770203945Sweongyo
5771203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
5772203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
5773203945Sweongyo}
5774203945Sweongyo
5775203945Sweongyostatic void
5776203945Sweongyobwn_wa_init(struct bwn_mac *mac)
5777203945Sweongyo{
5778203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5779203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
5780203945Sweongyo
5781203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5782203945Sweongyo
5783203945Sweongyo	switch (phy->rev) {
5784203945Sweongyo	case 1:
5785203945Sweongyo		bwn_wa_grev1(mac);
5786203945Sweongyo		break;
5787203945Sweongyo	case 2:
5788203945Sweongyo	case 6:
5789203945Sweongyo	case 7:
5790203945Sweongyo	case 8:
5791203945Sweongyo	case 9:
5792203945Sweongyo		bwn_wa_grev26789(mac);
5793203945Sweongyo		break;
5794203945Sweongyo	default:
5795203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5796203945Sweongyo	}
5797203945Sweongyo
5798203945Sweongyo	if (bus->siba_board_vendor != SIBA_BOARDVENDOR_BCM ||
5799203945Sweongyo	    bus->siba_board_type != SIBA_BOARD_BU4306 ||
5800203945Sweongyo	    bus->siba_board_rev != 0x17) {
5801203945Sweongyo		if (phy->rev < 2) {
5802203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
5803203945Sweongyo			    0x0002);
5804203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
5805203945Sweongyo			    0x0001);
5806203945Sweongyo		} else {
5807203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
5808203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
5809203945Sweongyo			if ((bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA) &&
5810203945Sweongyo			    (phy->rev >= 7)) {
5811203945Sweongyo				BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
5812203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5813203945Sweongyo				    0x0020, 0x0001);
5814203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5815203945Sweongyo				    0x0021, 0x0001);
5816203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5817203945Sweongyo				    0x0022, 0x0001);
5818203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5819203945Sweongyo				    0x0023, 0x0000);
5820203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5821203945Sweongyo				    0x0000, 0x0000);
5822203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5823203945Sweongyo				    0x0003, 0x0002);
5824203945Sweongyo			}
5825203945Sweongyo		}
5826203945Sweongyo	}
5827203945Sweongyo	if (bus->siba_sprom.bf_lo & BWN_BFL_FEM) {
5828203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
5829203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
5830203945Sweongyo	}
5831203945Sweongyo
5832203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
5833203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
5834203945Sweongyo}
5835203945Sweongyo
5836203945Sweongyostatic void
5837203945Sweongyobwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5838203945Sweongyo    uint16_t value)
5839203945Sweongyo{
5840203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5841203945Sweongyo	uint16_t addr;
5842203945Sweongyo
5843203945Sweongyo	addr = table + offset;
5844203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5845203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5846203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5847203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5848203945Sweongyo	}
5849203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5850203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5851203945Sweongyo}
5852203945Sweongyo
5853203945Sweongyostatic void
5854203945Sweongyobwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5855203945Sweongyo    uint32_t value)
5856203945Sweongyo{
5857203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5858203945Sweongyo	uint16_t addr;
5859203945Sweongyo
5860203945Sweongyo	addr = table + offset;
5861203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5862203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5863203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5864203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5865203945Sweongyo	}
5866203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5867203945Sweongyo
5868203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5869203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
5870203945Sweongyo}
5871203945Sweongyo
5872203945Sweongyostatic void
5873203945Sweongyobwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5874203945Sweongyo    uint16_t value)
5875203945Sweongyo{
5876203945Sweongyo
5877203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
5878203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
5879203945Sweongyo}
5880203945Sweongyo
5881203945Sweongyostatic void
5882203945Sweongyobwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
5883203945Sweongyo{
5884203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5885203945Sweongyo	unsigned int i, max_loop;
5886203945Sweongyo	uint16_t value;
5887203945Sweongyo	uint32_t buffer[5] = {
5888203945Sweongyo		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
5889203945Sweongyo	};
5890203945Sweongyo
5891203945Sweongyo	if (ofdm) {
5892203945Sweongyo		max_loop = 0x1e;
5893203945Sweongyo		buffer[0] = 0x000201cc;
5894203945Sweongyo	} else {
5895203945Sweongyo		max_loop = 0xfa;
5896203945Sweongyo		buffer[0] = 0x000b846e;
5897203945Sweongyo	}
5898203945Sweongyo
5899204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
5900203945Sweongyo
5901203945Sweongyo	for (i = 0; i < 5; i++)
5902203945Sweongyo		bwn_ram_write(mac, i * 4, buffer[i]);
5903203945Sweongyo
5904203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0000);
5905203945Sweongyo	BWN_WRITE_2(mac, 0x07c0,
5906203945Sweongyo	    (mac->mac_sd->sd_id.sd_rev < 11) ? 0x0000 : 0x0100);
5907203945Sweongyo	value = ((phy->type == BWN_PHYTYPE_A) ? 0x41 : 0x40);
5908203945Sweongyo	BWN_WRITE_2(mac, 0x050c, value);
5909203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5910203945Sweongyo		BWN_WRITE_2(mac, 0x0514, 0x1a02);
5911203945Sweongyo	BWN_WRITE_2(mac, 0x0508, 0x0000);
5912203945Sweongyo	BWN_WRITE_2(mac, 0x050a, 0x0000);
5913203945Sweongyo	BWN_WRITE_2(mac, 0x054c, 0x0000);
5914203945Sweongyo	BWN_WRITE_2(mac, 0x056a, 0x0014);
5915203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0826);
5916203945Sweongyo	BWN_WRITE_2(mac, 0x0500, 0x0000);
5917203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5918203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0050);
5919203945Sweongyo	else
5920203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0030);
5921203945Sweongyo
5922203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5923203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0017);
5924203945Sweongyo	for (i = 0x00; i < max_loop; i++) {
5925203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5926203945Sweongyo		if (value & 0x0080)
5927203945Sweongyo			break;
5928203945Sweongyo		DELAY(10);
5929203945Sweongyo	}
5930203945Sweongyo	for (i = 0x00; i < 0x0a; i++) {
5931203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5932203945Sweongyo		if (value & 0x0400)
5933203945Sweongyo			break;
5934203945Sweongyo		DELAY(10);
5935203945Sweongyo	}
5936203945Sweongyo	for (i = 0x00; i < 0x19; i++) {
5937203945Sweongyo		value = BWN_READ_2(mac, 0x0690);
5938203945Sweongyo		if (!(value & 0x0100))
5939203945Sweongyo			break;
5940203945Sweongyo		DELAY(10);
5941203945Sweongyo	}
5942203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5943203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0037);
5944203945Sweongyo}
5945203945Sweongyo
5946203945Sweongyostatic void
5947203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
5948203945Sweongyo{
5949203945Sweongyo	uint32_t macctl;
5950203945Sweongyo
5951203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
5952203945Sweongyo
5953203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
5954203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
5955203945Sweongyo		printf("TODO: need swap\n");
5956203945Sweongyo
5957203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
5958203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
5959203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
5960203945Sweongyo}
5961203945Sweongyo
5962203945Sweongyostatic void
5963203945Sweongyobwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
5964203945Sweongyo{
5965203945Sweongyo	uint16_t value;
5966203945Sweongyo
5967204256Sweongyo	KASSERT(mac->mac_phy.type == BWN_PHYTYPE_G,
5968203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5969203945Sweongyo
5970203945Sweongyo	value = (uint8_t) (ctl->q);
5971203945Sweongyo	value |= ((uint8_t) (ctl->i)) << 8;
5972203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
5973203945Sweongyo}
5974203945Sweongyo
5975203945Sweongyostatic uint16_t
5976203945Sweongyobwn_lo_calcfeed(struct bwn_mac *mac,
5977203945Sweongyo    uint16_t lna, uint16_t pga, uint16_t trsw_rx)
5978203945Sweongyo{
5979203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5980203945Sweongyo	uint16_t rfover;
5981203945Sweongyo	uint16_t feedthrough;
5982203945Sweongyo
5983203945Sweongyo	if (phy->gmode) {
5984203945Sweongyo		lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
5985203945Sweongyo		pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
5986203945Sweongyo
5987203945Sweongyo		KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
5988203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5989203945Sweongyo		KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
5990203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5991203945Sweongyo
5992203945Sweongyo		trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
5993203945Sweongyo
5994203945Sweongyo		rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
5995203945Sweongyo		if ((mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA)
5996203945Sweongyo		    && phy->rev > 6)
5997203945Sweongyo			rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
5998203945Sweongyo
5999203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6000203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
6001203945Sweongyo		DELAY(10);
6002203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
6003203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
6004203945Sweongyo		DELAY(10);
6005203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
6006203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
6007203945Sweongyo		DELAY(10);
6008203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
6009203945Sweongyo	} else {
6010203945Sweongyo		pga |= BWN_PHY_PGACTL_UNKNOWN;
6011203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
6012203945Sweongyo		DELAY(10);
6013203945Sweongyo		pga |= BWN_PHY_PGACTL_LOWBANDW;
6014203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
6015203945Sweongyo		DELAY(10);
6016203945Sweongyo		pga |= BWN_PHY_PGACTL_LPF;
6017203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
6018203945Sweongyo	}
6019203945Sweongyo	DELAY(21);
6020203945Sweongyo	feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
6021203945Sweongyo
6022203945Sweongyo	return (feedthrough);
6023203945Sweongyo}
6024203945Sweongyo
6025203945Sweongyostatic uint16_t
6026203945Sweongyobwn_lo_txctl_regtable(struct bwn_mac *mac,
6027203945Sweongyo    uint16_t *value, uint16_t *pad_mix_gain)
6028203945Sweongyo{
6029203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6030203945Sweongyo	uint16_t reg, v, padmix;
6031203945Sweongyo
6032203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6033203945Sweongyo		v = 0x30;
6034203945Sweongyo		if (phy->rf_rev <= 5) {
6035203945Sweongyo			reg = 0x43;
6036203945Sweongyo			padmix = 0;
6037203945Sweongyo		} else {
6038203945Sweongyo			reg = 0x52;
6039203945Sweongyo			padmix = 5;
6040203945Sweongyo		}
6041203945Sweongyo	} else {
6042203945Sweongyo		if (phy->rev >= 2 && phy->rf_rev == 8) {
6043203945Sweongyo			reg = 0x43;
6044203945Sweongyo			v = 0x10;
6045203945Sweongyo			padmix = 2;
6046203945Sweongyo		} else {
6047203945Sweongyo			reg = 0x52;
6048203945Sweongyo			v = 0x30;
6049203945Sweongyo			padmix = 5;
6050203945Sweongyo		}
6051203945Sweongyo	}
6052203945Sweongyo	if (value)
6053203945Sweongyo		*value = v;
6054203945Sweongyo	if (pad_mix_gain)
6055203945Sweongyo		*pad_mix_gain = padmix;
6056203945Sweongyo
6057203945Sweongyo	return (reg);
6058203945Sweongyo}
6059203945Sweongyo
6060203945Sweongyostatic void
6061203945Sweongyobwn_lo_measure_txctl_values(struct bwn_mac *mac)
6062203945Sweongyo{
6063203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6064203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6065203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6066203945Sweongyo	uint16_t reg, mask;
6067203945Sweongyo	uint16_t trsw_rx, pga;
6068203945Sweongyo	uint16_t rf_pctl_reg;
6069203945Sweongyo
6070203945Sweongyo	static const uint8_t tx_bias_values[] = {
6071203945Sweongyo		0x09, 0x08, 0x0a, 0x01, 0x00,
6072203945Sweongyo		0x02, 0x05, 0x04, 0x06,
6073203945Sweongyo	};
6074203945Sweongyo	static const uint8_t tx_magn_values[] = {
6075203945Sweongyo		0x70, 0x40,
6076203945Sweongyo	};
6077203945Sweongyo
6078203945Sweongyo	if (!BWN_HAS_LOOPBACK(phy)) {
6079203945Sweongyo		rf_pctl_reg = 6;
6080203945Sweongyo		trsw_rx = 2;
6081203945Sweongyo		pga = 0;
6082203945Sweongyo	} else {
6083203945Sweongyo		int lb_gain;
6084203945Sweongyo
6085203945Sweongyo		trsw_rx = 0;
6086203945Sweongyo		lb_gain = pg->pg_max_lb_gain / 2;
6087203945Sweongyo		if (lb_gain > 10) {
6088203945Sweongyo			rf_pctl_reg = 0;
6089203945Sweongyo			pga = abs(10 - lb_gain) / 6;
6090203945Sweongyo			pga = MIN(MAX(pga, 0), 15);
6091203945Sweongyo		} else {
6092203945Sweongyo			int cmp_val;
6093203945Sweongyo			int tmp;
6094203945Sweongyo
6095203945Sweongyo			pga = 0;
6096203945Sweongyo			cmp_val = 0x24;
6097203945Sweongyo			if ((phy->rev >= 2) &&
6098203945Sweongyo			    (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
6099203945Sweongyo				cmp_val = 0x3c;
6100203945Sweongyo			tmp = lb_gain;
6101203945Sweongyo			if ((10 - lb_gain) < cmp_val)
6102203945Sweongyo				tmp = (10 - lb_gain);
6103203945Sweongyo			if (tmp < 0)
6104203945Sweongyo				tmp += 6;
6105203945Sweongyo			else
6106203945Sweongyo				tmp += 3;
6107203945Sweongyo			cmp_val /= 4;
6108203945Sweongyo			tmp /= 4;
6109203945Sweongyo			if (tmp >= cmp_val)
6110203945Sweongyo				rf_pctl_reg = cmp_val;
6111203945Sweongyo			else
6112203945Sweongyo				rf_pctl_reg = tmp;
6113203945Sweongyo		}
6114203945Sweongyo	}
6115203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
6116203945Sweongyo	bwn_phy_g_set_bbatt(mac, 2);
6117203945Sweongyo
6118203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
6119203945Sweongyo	mask = ~mask;
6120203945Sweongyo	BWN_RF_MASK(mac, reg, mask);
6121203945Sweongyo
6122203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
6123203945Sweongyo		int i, j;
6124203945Sweongyo		int feedthrough;
6125203945Sweongyo		int min_feedth = 0xffff;
6126203945Sweongyo		uint8_t tx_magn, tx_bias;
6127203945Sweongyo
6128203945Sweongyo		for (i = 0; i < N(tx_magn_values); i++) {
6129203945Sweongyo			tx_magn = tx_magn_values[i];
6130203945Sweongyo			BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
6131203945Sweongyo			for (j = 0; j < N(tx_bias_values); j++) {
6132203945Sweongyo				tx_bias = tx_bias_values[j];
6133203945Sweongyo				BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
6134203945Sweongyo				feedthrough = bwn_lo_calcfeed(mac, 0, pga,
6135203945Sweongyo				    trsw_rx);
6136203945Sweongyo				if (feedthrough < min_feedth) {
6137203945Sweongyo					lo->tx_bias = tx_bias;
6138203945Sweongyo					lo->tx_magn = tx_magn;
6139203945Sweongyo					min_feedth = feedthrough;
6140203945Sweongyo				}
6141203945Sweongyo				if (lo->tx_bias == 0)
6142203945Sweongyo					break;
6143203945Sweongyo			}
6144203945Sweongyo			BWN_RF_WRITE(mac, 0x52,
6145203945Sweongyo					  (BWN_RF_READ(mac, 0x52)
6146203945Sweongyo					   & 0xff00) | lo->tx_bias | lo->
6147203945Sweongyo					  tx_magn);
6148203945Sweongyo		}
6149203945Sweongyo	} else {
6150203945Sweongyo		lo->tx_magn = 0;
6151203945Sweongyo		lo->tx_bias = 0;
6152203945Sweongyo		BWN_RF_MASK(mac, 0x52, 0xfff0);
6153203945Sweongyo	}
6154203945Sweongyo
6155203945Sweongyo	BWN_GETTIME(lo->txctl_measured_time);
6156203945Sweongyo}
6157203945Sweongyo
6158203945Sweongyostatic void
6159203945Sweongyobwn_lo_get_powervector(struct bwn_mac *mac)
6160203945Sweongyo{
6161203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6162203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6163203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6164203945Sweongyo	int i;
6165203945Sweongyo	uint64_t tmp;
6166203945Sweongyo	uint64_t power_vector = 0;
6167203945Sweongyo
6168203945Sweongyo	for (i = 0; i < 8; i += 2) {
6169203945Sweongyo		tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
6170203945Sweongyo		power_vector |= (tmp << (i * 8));
6171203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
6172203945Sweongyo	}
6173203945Sweongyo	if (power_vector)
6174203945Sweongyo		lo->power_vector = power_vector;
6175203945Sweongyo
6176203945Sweongyo	BWN_GETTIME(lo->pwr_vec_read_time);
6177203945Sweongyo}
6178203945Sweongyo
6179203945Sweongyostatic void
6180203945Sweongyobwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
6181203945Sweongyo    int use_trsw_rx)
6182203945Sweongyo{
6183203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6184203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6185203945Sweongyo	uint16_t tmp;
6186203945Sweongyo
6187203945Sweongyo	if (max_rx_gain < 0)
6188203945Sweongyo		max_rx_gain = 0;
6189203945Sweongyo
6190203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
6191203945Sweongyo		int trsw_rx = 0;
6192203945Sweongyo		int trsw_rx_gain;
6193203945Sweongyo
6194203945Sweongyo		if (use_trsw_rx) {
6195203945Sweongyo			trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
6196203945Sweongyo			if (max_rx_gain >= trsw_rx_gain) {
6197203945Sweongyo				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
6198203945Sweongyo				trsw_rx = 0x20;
6199203945Sweongyo			}
6200203945Sweongyo		} else
6201203945Sweongyo			trsw_rx_gain = max_rx_gain;
6202203945Sweongyo		if (trsw_rx_gain < 9) {
6203203945Sweongyo			pg->pg_lna_lod_gain = 0;
6204203945Sweongyo		} else {
6205203945Sweongyo			pg->pg_lna_lod_gain = 1;
6206203945Sweongyo			trsw_rx_gain -= 8;
6207203945Sweongyo		}
6208203945Sweongyo		trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
6209203945Sweongyo		pg->pg_pga_gain = trsw_rx_gain / 3;
6210203945Sweongyo		if (pg->pg_pga_gain >= 5) {
6211203945Sweongyo			pg->pg_pga_gain -= 5;
6212203945Sweongyo			pg->pg_lna_gain = 2;
6213203945Sweongyo		} else
6214203945Sweongyo			pg->pg_lna_gain = 0;
6215203945Sweongyo	} else {
6216203945Sweongyo		pg->pg_lna_gain = 0;
6217203945Sweongyo		pg->pg_trsw_rx_gain = 0x20;
6218203945Sweongyo		if (max_rx_gain >= 0x14) {
6219203945Sweongyo			pg->pg_lna_lod_gain = 1;
6220203945Sweongyo			pg->pg_pga_gain = 2;
6221203945Sweongyo		} else if (max_rx_gain >= 0x12) {
6222203945Sweongyo			pg->pg_lna_lod_gain = 1;
6223203945Sweongyo			pg->pg_pga_gain = 1;
6224203945Sweongyo		} else if (max_rx_gain >= 0xf) {
6225203945Sweongyo			pg->pg_lna_lod_gain = 1;
6226203945Sweongyo			pg->pg_pga_gain = 0;
6227203945Sweongyo		} else {
6228203945Sweongyo			pg->pg_lna_lod_gain = 0;
6229203945Sweongyo			pg->pg_pga_gain = 0;
6230203945Sweongyo		}
6231203945Sweongyo	}
6232203945Sweongyo
6233203945Sweongyo	tmp = BWN_RF_READ(mac, 0x7a);
6234203945Sweongyo	if (pg->pg_lna_lod_gain == 0)
6235203945Sweongyo		tmp &= ~0x0008;
6236203945Sweongyo	else
6237203945Sweongyo		tmp |= 0x0008;
6238203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, tmp);
6239203945Sweongyo}
6240203945Sweongyo
6241203945Sweongyostatic void
6242203945Sweongyobwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6243203945Sweongyo{
6244203945Sweongyo	struct siba_sprom *sprom = &mac->mac_sd->sd_bus->siba_sprom;
6245203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6246203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6247203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6248203945Sweongyo	struct timespec ts;
6249203945Sweongyo	uint16_t tmp;
6250203945Sweongyo
6251203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6252203945Sweongyo		sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
6253203945Sweongyo		sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
6254203945Sweongyo		sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6255203945Sweongyo		sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
6256203945Sweongyo		sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
6257203945Sweongyo
6258203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
6259203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
6260203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
6261203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
6262203945Sweongyo	}
6263203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6264203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
6265203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
6266203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
6267203945Sweongyo	}
6268203945Sweongyo	if (phy->rev >= 2) {
6269203945Sweongyo		sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
6270203945Sweongyo		sav->phy_analogoverval =
6271203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
6272203945Sweongyo		sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
6273203945Sweongyo		sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
6274203945Sweongyo		sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
6275203945Sweongyo		sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
6276203945Sweongyo		sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
6277203945Sweongyo
6278203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
6279203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
6280203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
6281203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
6282203945Sweongyo		if (phy->type == BWN_PHYTYPE_G) {
6283203945Sweongyo			if ((phy->rev >= 7) &&
6284203945Sweongyo			    (sprom->bf_lo & BWN_BFL_EXTLNA)) {
6285203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
6286203945Sweongyo			} else {
6287203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
6288203945Sweongyo			}
6289203945Sweongyo		} else {
6290203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
6291203945Sweongyo		}
6292203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
6293203945Sweongyo	}
6294203945Sweongyo	sav->reg0 = BWN_READ_2(mac, 0x3f4);
6295203945Sweongyo	sav->reg1 = BWN_READ_2(mac, 0x3e2);
6296203945Sweongyo	sav->rf0 = BWN_RF_READ(mac, 0x43);
6297203945Sweongyo	sav->rf1 = BWN_RF_READ(mac, 0x7a);
6298203945Sweongyo	sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
6299203945Sweongyo	sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
6300203945Sweongyo	sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
6301203945Sweongyo	sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6302203945Sweongyo
6303203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6304203945Sweongyo		sav->rf2 = BWN_RF_READ(mac, 0x52);
6305203945Sweongyo		sav->rf2 &= 0x00f0;
6306203945Sweongyo	}
6307203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6308203945Sweongyo		sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
6309203945Sweongyo		sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
6310203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
6311203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
6312203945Sweongyo	} else {
6313203945Sweongyo		BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
6314203945Sweongyo			    | 0x8000);
6315203945Sweongyo	}
6316203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
6317203945Sweongyo		    & 0xf000);
6318203945Sweongyo
6319203945Sweongyo	tmp =
6320203945Sweongyo	    (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
6321203945Sweongyo	BWN_PHY_WRITE(mac, tmp, 0x007f);
6322203945Sweongyo
6323203945Sweongyo	tmp = sav->phy_syncctl;
6324203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
6325203945Sweongyo	tmp = sav->rf1;
6326203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
6327203945Sweongyo
6328203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
6329203945Sweongyo	if (phy->type == BWN_PHYTYPE_G ||
6330203945Sweongyo	    (phy->type == BWN_PHYTYPE_B &&
6331203945Sweongyo	     phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
6332203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
6333203945Sweongyo	} else
6334203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
6335203945Sweongyo	if (phy->rev >= 2)
6336203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
6337203945Sweongyo	bwn_phy_g_switch_chan(mac, 6, 0);
6338203945Sweongyo	BWN_RF_READ(mac, 0x51);
6339203945Sweongyo	if (phy->type == BWN_PHYTYPE_G)
6340203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
6341203945Sweongyo
6342203945Sweongyo	nanouptime(&ts);
6343203945Sweongyo	if (time_before(lo->txctl_measured_time,
6344203945Sweongyo	    (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
6345203945Sweongyo		bwn_lo_measure_txctl_values(mac);
6346203945Sweongyo
6347203945Sweongyo	if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
6348203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
6349203945Sweongyo	else {
6350203945Sweongyo		if (phy->type == BWN_PHYTYPE_B)
6351203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6352203945Sweongyo		else
6353203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
6354203945Sweongyo	}
6355203945Sweongyo}
6356203945Sweongyo
6357203945Sweongyostatic void
6358203945Sweongyobwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6359203945Sweongyo{
6360203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6361203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6362203945Sweongyo	uint16_t tmp;
6363203945Sweongyo
6364203945Sweongyo	if (phy->rev >= 2) {
6365203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6366203945Sweongyo		tmp = (pg->pg_pga_gain << 8);
6367203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
6368203945Sweongyo		DELAY(5);
6369203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
6370203945Sweongyo		DELAY(2);
6371203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
6372203945Sweongyo	} else {
6373203945Sweongyo		tmp = (pg->pg_pga_gain | 0xefa0);
6374203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
6375203945Sweongyo	}
6376203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
6377203945Sweongyo		if (phy->rev >= 3)
6378203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
6379203945Sweongyo		else
6380203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6381203945Sweongyo		if (phy->rev >= 2)
6382203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
6383203945Sweongyo		else
6384203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
6385203945Sweongyo	}
6386203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, sav->reg0);
6387203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
6388203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
6389203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
6390203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
6391203945Sweongyo	BWN_RF_WRITE(mac, 0x43, sav->rf0);
6392203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, sav->rf1);
6393203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6394203945Sweongyo		tmp = sav->rf2;
6395203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
6396203945Sweongyo	}
6397203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, sav->reg1);
6398203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6399203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
6400203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
6401203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
6402203945Sweongyo	}
6403203945Sweongyo	if (phy->rev >= 2) {
6404203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
6405203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
6406203945Sweongyo			      sav->phy_analogoverval);
6407203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
6408203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
6409203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
6410203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
6411203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
6412203945Sweongyo	}
6413203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6414203945Sweongyo		tmp = (sav->phy_lomask & 0xbfff);
6415203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
6416203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
6417203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
6418203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
6419203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
6420203945Sweongyo	}
6421203945Sweongyo	bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
6422203945Sweongyo}
6423203945Sweongyo
6424203945Sweongyostatic int
6425203945Sweongyobwn_lo_probe_loctl(struct bwn_mac *mac,
6426203945Sweongyo    struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
6427203945Sweongyo{
6428203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6429203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6430203945Sweongyo	struct bwn_loctl orig, test;
6431203945Sweongyo	struct bwn_loctl prev = { -100, -100 };
6432203945Sweongyo	static const struct bwn_loctl modifiers[] = {
6433203945Sweongyo		{  1,  1,}, {  1,  0,}, {  1, -1,}, {  0, -1,},
6434203945Sweongyo		{ -1, -1,}, { -1,  0,}, { -1,  1,}, {  0,  1,}
6435203945Sweongyo	};
6436203945Sweongyo	int begin, end, lower = 0, i;
6437203945Sweongyo	uint16_t feedth;
6438203945Sweongyo
6439203945Sweongyo	if (d->curstate == 0) {
6440203945Sweongyo		begin = 1;
6441203945Sweongyo		end = 8;
6442203945Sweongyo	} else if (d->curstate % 2 == 0) {
6443203945Sweongyo		begin = d->curstate - 1;
6444203945Sweongyo		end = d->curstate + 1;
6445203945Sweongyo	} else {
6446203945Sweongyo		begin = d->curstate - 2;
6447203945Sweongyo		end = d->curstate + 2;
6448203945Sweongyo	}
6449203945Sweongyo	if (begin < 1)
6450203945Sweongyo		begin += 8;
6451203945Sweongyo	if (end > 8)
6452203945Sweongyo		end -= 8;
6453203945Sweongyo
6454203945Sweongyo	memcpy(&orig, probe, sizeof(struct bwn_loctl));
6455203945Sweongyo	i = begin;
6456203945Sweongyo	d->curstate = i;
6457203945Sweongyo	while (1) {
6458203945Sweongyo		KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
6459203945Sweongyo		memcpy(&test, &orig, sizeof(struct bwn_loctl));
6460203945Sweongyo		test.i += modifiers[i - 1].i * d->multipler;
6461203945Sweongyo		test.q += modifiers[i - 1].q * d->multipler;
6462203945Sweongyo		if ((test.i != prev.i || test.q != prev.q) &&
6463203945Sweongyo		    (abs(test.i) <= 16 && abs(test.q) <= 16)) {
6464203945Sweongyo			bwn_lo_write(mac, &test);
6465203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6466203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6467203945Sweongyo			if (feedth < d->feedth) {
6468203945Sweongyo				memcpy(probe, &test,
6469203945Sweongyo				    sizeof(struct bwn_loctl));
6470203945Sweongyo				lower = 1;
6471203945Sweongyo				d->feedth = feedth;
6472203945Sweongyo				if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
6473203945Sweongyo					break;
6474203945Sweongyo			}
6475203945Sweongyo		}
6476203945Sweongyo		memcpy(&prev, &test, sizeof(prev));
6477203945Sweongyo		if (i == end)
6478203945Sweongyo			break;
6479203945Sweongyo		if (i == 8)
6480203945Sweongyo			i = 1;
6481203945Sweongyo		else
6482203945Sweongyo			i++;
6483203945Sweongyo		d->curstate = i;
6484203945Sweongyo	}
6485203945Sweongyo
6486203945Sweongyo	return (lower);
6487203945Sweongyo}
6488203945Sweongyo
6489203945Sweongyostatic void
6490203945Sweongyobwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
6491203945Sweongyo{
6492203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6493203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6494203945Sweongyo	struct bwn_lo_g_sm d;
6495203945Sweongyo	struct bwn_loctl probe;
6496203945Sweongyo	int lower, repeat, cnt = 0;
6497203945Sweongyo	uint16_t feedth;
6498203945Sweongyo
6499203945Sweongyo	d.nmeasure = 0;
6500203945Sweongyo	d.multipler = 1;
6501203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6502203945Sweongyo		d.multipler = 3;
6503203945Sweongyo
6504203945Sweongyo	memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
6505203945Sweongyo	repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
6506203945Sweongyo
6507203945Sweongyo	do {
6508203945Sweongyo		bwn_lo_write(mac, &d.loctl);
6509203945Sweongyo		feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6510203945Sweongyo		    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6511203945Sweongyo		if (feedth < 0x258) {
6512203945Sweongyo			if (feedth >= 0x12c)
6513203945Sweongyo				*rxgain += 6;
6514203945Sweongyo			else
6515203945Sweongyo				*rxgain += 3;
6516203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6517203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6518203945Sweongyo		}
6519203945Sweongyo		d.feedth = feedth;
6520203945Sweongyo		d.curstate = 0;
6521203945Sweongyo		do {
6522203945Sweongyo			KASSERT(d.curstate >= 0 && d.curstate <= 8,
6523203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
6524203945Sweongyo			memcpy(&probe, &d.loctl,
6525203945Sweongyo			       sizeof(struct bwn_loctl));
6526203945Sweongyo			lower = bwn_lo_probe_loctl(mac, &probe, &d);
6527203945Sweongyo			if (!lower)
6528203945Sweongyo				break;
6529203945Sweongyo			if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
6530203945Sweongyo				break;
6531203945Sweongyo			memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
6532203945Sweongyo			d.nmeasure++;
6533203945Sweongyo		} while (d.nmeasure < 24);
6534203945Sweongyo		memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
6535203945Sweongyo
6536203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
6537203945Sweongyo			if (d.feedth > 0x1194)
6538203945Sweongyo				*rxgain -= 6;
6539203945Sweongyo			else if (d.feedth < 0x5dc)
6540203945Sweongyo				*rxgain += 3;
6541203945Sweongyo			if (cnt == 0) {
6542203945Sweongyo				if (d.feedth <= 0x5dc) {
6543203945Sweongyo					d.multipler = 1;
6544203945Sweongyo					cnt++;
6545203945Sweongyo				} else
6546203945Sweongyo					d.multipler = 2;
6547203945Sweongyo			} else if (cnt == 2)
6548203945Sweongyo				d.multipler = 1;
6549203945Sweongyo		}
6550203945Sweongyo		bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
6551203945Sweongyo	} while (++cnt < repeat);
6552203945Sweongyo}
6553203945Sweongyo
6554203945Sweongyostatic struct bwn_lo_calib *
6555203945Sweongyobwn_lo_calibset(struct bwn_mac *mac,
6556203945Sweongyo    const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
6557203945Sweongyo{
6558203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6559203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6560203945Sweongyo	struct bwn_loctl loctl = { 0, 0 };
6561203945Sweongyo	struct bwn_lo_calib *cal;
6562204242Simp	struct bwn_lo_g_value sval = { 0 };
6563203945Sweongyo	int rxgain;
6564203945Sweongyo	uint16_t pad, reg, value;
6565203945Sweongyo
6566203945Sweongyo	sval.old_channel = phy->chan;
6567203945Sweongyo	bwn_mac_suspend(mac);
6568203945Sweongyo	bwn_lo_save(mac, &sval);
6569203945Sweongyo
6570203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &value, &pad);
6571203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
6572203945Sweongyo	BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
6573203945Sweongyo
6574203945Sweongyo	rxgain = (rfatt->att * 2) + (bbatt->att / 2);
6575203945Sweongyo	if (rfatt->padmix)
6576203945Sweongyo		rxgain -= pad;
6577203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6578203945Sweongyo		rxgain += pg->pg_max_lb_gain;
6579203945Sweongyo	bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
6580203945Sweongyo	bwn_phy_g_set_bbatt(mac, bbatt->att);
6581203945Sweongyo	bwn_lo_probe_sm(mac, &loctl, &rxgain);
6582203945Sweongyo
6583203945Sweongyo	bwn_lo_restore(mac, &sval);
6584203945Sweongyo	bwn_mac_enable(mac);
6585203945Sweongyo
6586203945Sweongyo	cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
6587203945Sweongyo	if (!cal) {
6588203945Sweongyo		device_printf(mac->mac_sc->sc_dev, "out of memory\n");
6589203945Sweongyo		return (NULL);
6590203945Sweongyo	}
6591203945Sweongyo	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
6592203945Sweongyo	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
6593203945Sweongyo	memcpy(&cal->ctl, &loctl, sizeof(loctl));
6594203945Sweongyo
6595203945Sweongyo	BWN_GETTIME(cal->calib_time);
6596203945Sweongyo
6597203945Sweongyo	return (cal);
6598203945Sweongyo}
6599203945Sweongyo
6600203945Sweongyostatic struct bwn_lo_calib *
6601203945Sweongyobwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
6602203945Sweongyo    const struct bwn_rfatt *rfatt)
6603203945Sweongyo{
6604203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
6605203945Sweongyo	struct bwn_lo_calib *c;
6606203945Sweongyo
6607203945Sweongyo	TAILQ_FOREACH(c, &lo->calib_list, list) {
6608203945Sweongyo		if (!BWN_BBATTCMP(&c->bbatt, bbatt))
6609203945Sweongyo			continue;
6610203945Sweongyo		if (!BWN_RFATTCMP(&c->rfatt, rfatt))
6611203945Sweongyo			continue;
6612203945Sweongyo		return (c);
6613203945Sweongyo	}
6614203945Sweongyo
6615203945Sweongyo	c = bwn_lo_calibset(mac, bbatt, rfatt);
6616203945Sweongyo	if (!c)
6617203945Sweongyo		return (NULL);
6618203945Sweongyo	TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
6619203945Sweongyo
6620203945Sweongyo	return (c);
6621203945Sweongyo}
6622203945Sweongyo
6623203945Sweongyostatic void
6624203945Sweongyobwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
6625203945Sweongyo{
6626203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6627203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6628203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6629203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6630203945Sweongyo	const struct bwn_rfatt *rfatt;
6631203945Sweongyo	const struct bwn_bbatt *bbatt;
6632203945Sweongyo	uint64_t pvector;
6633203945Sweongyo	int i;
6634203945Sweongyo	int rf_offset, bb_offset;
6635203945Sweongyo	uint8_t changed = 0;
6636203945Sweongyo
6637203945Sweongyo	KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
6638203945Sweongyo	KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
6639203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6640203945Sweongyo
6641203945Sweongyo	pvector = lo->power_vector;
6642203945Sweongyo	if (!update && !pvector)
6643203945Sweongyo		return;
6644203945Sweongyo
6645203945Sweongyo	bwn_mac_suspend(mac);
6646203945Sweongyo
6647203945Sweongyo	for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
6648203945Sweongyo		struct bwn_lo_calib *cal;
6649203945Sweongyo		int idx;
6650203945Sweongyo		uint16_t val;
6651203945Sweongyo
6652203945Sweongyo		if (!update && !(pvector & (((uint64_t)1ULL) << i)))
6653203945Sweongyo			continue;
6654203945Sweongyo		bb_offset = i / lo->rfatt.len;
6655203945Sweongyo		rf_offset = i % lo->rfatt.len;
6656203945Sweongyo		bbatt = &(lo->bbatt.array[bb_offset]);
6657203945Sweongyo		rfatt = &(lo->rfatt.array[rf_offset]);
6658203945Sweongyo
6659203945Sweongyo		cal = bwn_lo_calibset(mac, bbatt, rfatt);
6660203945Sweongyo		if (!cal) {
6661203945Sweongyo			device_printf(sc->sc_dev, "LO: Could not "
6662203945Sweongyo			    "calibrate DC table entry\n");
6663203945Sweongyo			continue;
6664203945Sweongyo		}
6665203945Sweongyo		val = (uint8_t)(cal->ctl.q);
6666203945Sweongyo		val |= ((uint8_t)(cal->ctl.i)) << 4;
6667203945Sweongyo		free(cal, M_DEVBUF);
6668203945Sweongyo
6669203945Sweongyo		idx = i / 2;
6670203945Sweongyo		if (i % 2)
6671203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
6672203945Sweongyo			    | ((val & 0x00ff) << 8);
6673203945Sweongyo		else
6674203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
6675203945Sweongyo			    | (val & 0x00ff);
6676203945Sweongyo		changed = 1;
6677203945Sweongyo	}
6678203945Sweongyo	if (changed) {
6679203945Sweongyo		for (i = 0; i < BWN_DC_LT_SIZE; i++)
6680203945Sweongyo			BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
6681203945Sweongyo	}
6682203945Sweongyo	bwn_mac_enable(mac);
6683203945Sweongyo}
6684203945Sweongyo
6685203945Sweongyostatic void
6686203945Sweongyobwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
6687203945Sweongyo{
6688203945Sweongyo
6689203945Sweongyo	if (!rf->padmix)
6690203945Sweongyo		return;
6691203945Sweongyo	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
6692203945Sweongyo		rf->att = 4;
6693203945Sweongyo}
6694203945Sweongyo
6695203945Sweongyostatic void
6696203945Sweongyobwn_lo_g_adjust(struct bwn_mac *mac)
6697203945Sweongyo{
6698203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
6699203945Sweongyo	struct bwn_lo_calib *cal;
6700203945Sweongyo	struct bwn_rfatt rf;
6701203945Sweongyo
6702203945Sweongyo	memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
6703203945Sweongyo	bwn_lo_fixup_rfatt(&rf);
6704203945Sweongyo
6705203945Sweongyo	cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
6706203945Sweongyo	if (!cal)
6707203945Sweongyo		return;
6708203945Sweongyo	bwn_lo_write(mac, &cal->ctl);
6709203945Sweongyo}
6710203945Sweongyo
6711203945Sweongyostatic void
6712203945Sweongyobwn_lo_g_init(struct bwn_mac *mac)
6713203945Sweongyo{
6714203945Sweongyo
6715203945Sweongyo	if (!bwn_has_hwpctl(mac))
6716203945Sweongyo		return;
6717203945Sweongyo
6718203945Sweongyo	bwn_lo_get_powervector(mac);
6719203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
6720203945Sweongyo}
6721203945Sweongyo
6722203945Sweongyostatic void
6723203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
6724203945Sweongyo{
6725203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6726203945Sweongyo	int i;
6727203945Sweongyo	uint32_t tmp;
6728203945Sweongyo
6729203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6730203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6731203945Sweongyo
6732203945Sweongyo	if (mac->mac_suspended == 0) {
6733203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
6734203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6735203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
6736203945Sweongyo			    & ~BWN_MACCTL_ON);
6737203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6738203945Sweongyo		for (i = 35; i; i--) {
6739203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6740203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6741203945Sweongyo				goto out;
6742203945Sweongyo			DELAY(10);
6743203945Sweongyo		}
6744203945Sweongyo		for (i = 40; i; i--) {
6745203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6746203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6747203945Sweongyo				goto out;
6748203945Sweongyo			DELAY(1000);
6749203945Sweongyo		}
6750203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
6751203945Sweongyo	}
6752203945Sweongyoout:
6753203945Sweongyo	mac->mac_suspended++;
6754203945Sweongyo}
6755203945Sweongyo
6756203945Sweongyostatic void
6757203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
6758203945Sweongyo{
6759203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6760203945Sweongyo	uint16_t state;
6761203945Sweongyo
6762203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
6763203945Sweongyo	    BWN_SHARED_UCODESTAT);
6764203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
6765203945Sweongyo	    state != BWN_SHARED_UCODESTAT_SLEEP)
6766203945Sweongyo		device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
6767203945Sweongyo
6768203945Sweongyo	mac->mac_suspended--;
6769203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6770203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6771203945Sweongyo	if (mac->mac_suspended == 0) {
6772203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6773203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
6774203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
6775203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6776203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
6777203945Sweongyo		bwn_psctl(mac, 0);
6778203945Sweongyo	}
6779203945Sweongyo}
6780203945Sweongyo
6781203945Sweongyostatic void
6782203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
6783203945Sweongyo{
6784203945Sweongyo	int i;
6785203945Sweongyo	uint16_t ucstat;
6786203945Sweongyo
6787203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
6788203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6789203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
6790203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6791203945Sweongyo
6792203945Sweongyo	/* XXX forcibly awake and hwps-off */
6793203945Sweongyo
6794203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
6795203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
6796203945Sweongyo	    ~BWN_MACCTL_HWPS);
6797203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
6798203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 5) {
6799203945Sweongyo		for (i = 0; i < 100; i++) {
6800203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
6801203945Sweongyo			    BWN_SHARED_UCODESTAT);
6802203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
6803203945Sweongyo				break;
6804203945Sweongyo			DELAY(10);
6805203945Sweongyo		}
6806203945Sweongyo	}
6807203945Sweongyo}
6808203945Sweongyo
6809203945Sweongyostatic int16_t
6810203945Sweongyobwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
6811203945Sweongyo{
6812203945Sweongyo
6813203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
6814203945Sweongyo	return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
6815203945Sweongyo}
6816203945Sweongyo
6817203945Sweongyostatic void
6818203945Sweongyobwn_nrssi_threshold(struct bwn_mac *mac)
6819203945Sweongyo{
6820203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6821203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6822203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
6823203945Sweongyo	int32_t a, b;
6824203945Sweongyo	int16_t tmp16;
6825203945Sweongyo	uint16_t tmpu16;
6826203945Sweongyo
6827203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
6828203945Sweongyo
6829203945Sweongyo	if (phy->gmode && (siba->siba_sprom.bf_lo & BWN_BFL_RSSI)) {
6830203945Sweongyo		if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
6831203945Sweongyo			a = 0x13;
6832203945Sweongyo			b = 0x12;
6833203945Sweongyo		} else {
6834203945Sweongyo			a = 0xe;
6835203945Sweongyo			b = 0x11;
6836203945Sweongyo		}
6837203945Sweongyo
6838203945Sweongyo		a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6839203945Sweongyo		a += (pg->pg_nrssi[0] << 6);
6840203945Sweongyo		a += (a < 32) ? 31 : 32;
6841203945Sweongyo		a = a >> 6;
6842203945Sweongyo		a = MIN(MAX(a, -31), 31);
6843203945Sweongyo
6844203945Sweongyo		b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6845203945Sweongyo		b += (pg->pg_nrssi[0] << 6);
6846203945Sweongyo		if (b < 32)
6847203945Sweongyo			b += 31;
6848203945Sweongyo		else
6849203945Sweongyo			b += 32;
6850203945Sweongyo		b = b >> 6;
6851203945Sweongyo		b = MIN(MAX(b, -31), 31);
6852203945Sweongyo
6853203945Sweongyo		tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
6854203945Sweongyo		tmpu16 |= ((uint32_t)b & 0x0000003f);
6855203945Sweongyo		tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
6856203945Sweongyo		BWN_PHY_WRITE(mac, 0x048a, tmpu16);
6857203945Sweongyo		return;
6858203945Sweongyo	}
6859203945Sweongyo
6860203945Sweongyo	tmp16 = bwn_nrssi_read(mac, 0x20);
6861203945Sweongyo	if (tmp16 >= 0x20)
6862203945Sweongyo		tmp16 -= 0x40;
6863203945Sweongyo	BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
6864203945Sweongyo}
6865203945Sweongyo
6866203945Sweongyostatic void
6867203945Sweongyobwn_nrssi_slope_11g(struct bwn_mac *mac)
6868203945Sweongyo{
6869203945Sweongyo#define	SAVE_RF_MAX		3
6870203945Sweongyo#define	SAVE_PHY_COMM_MAX	4
6871203945Sweongyo#define	SAVE_PHY3_MAX		8
6872203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6873203945Sweongyo		{ 0x7a, 0x52, 0x43 };
6874203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
6875203945Sweongyo		{ 0x15, 0x5a, 0x59, 0x58 };
6876203945Sweongyo	static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
6877203945Sweongyo		0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
6878203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6879203945Sweongyo	};
6880203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6881203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6882203945Sweongyo	int32_t i, tmp32, phy3_idx = 0;
6883203945Sweongyo	uint16_t delta, tmp;
6884203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6885203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6886203945Sweongyo	uint16_t save_phy3[SAVE_PHY3_MAX];
6887203945Sweongyo	uint16_t ant_div, phy0, chan_ex;
6888203945Sweongyo	int16_t nrssi0, nrssi1;
6889203945Sweongyo
6890203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
6891203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6892203945Sweongyo
6893203945Sweongyo	if (phy->rf_rev >= 9)
6894203945Sweongyo		return;
6895203945Sweongyo	if (phy->rf_rev == 8)
6896203945Sweongyo		bwn_nrssi_offset(mac);
6897203945Sweongyo
6898203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
6899203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, 0xfffc);
6900203945Sweongyo
6901203945Sweongyo	/*
6902203945Sweongyo	 * Save RF/PHY registers for later restoration
6903203945Sweongyo	 */
6904203945Sweongyo	ant_div = BWN_READ_2(mac, 0x03e2);
6905203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
6906203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6907203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6908203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6909203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6910203945Sweongyo
6911203945Sweongyo	phy0 = BWN_READ_2(mac, BWN_PHY0);
6912203945Sweongyo	chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
6913203945Sweongyo	if (phy->rev >= 3) {
6914203945Sweongyo		for (i = 0; i < SAVE_PHY3_MAX; ++i)
6915203945Sweongyo			save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
6916203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6917203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
6918203945Sweongyo		switch (phy->rev) {
6919203945Sweongyo		case 4:
6920203945Sweongyo		case 6:
6921203945Sweongyo		case 7:
6922203945Sweongyo			BWN_PHY_SET(mac, 0x0478, 0x0100);
6923203945Sweongyo			BWN_PHY_SET(mac, 0x0801, 0x0040);
6924203945Sweongyo			break;
6925203945Sweongyo		case 3:
6926203945Sweongyo		case 5:
6927203945Sweongyo			BWN_PHY_MASK(mac, 0x0801, 0xffbf);
6928203945Sweongyo			break;
6929203945Sweongyo		}
6930203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
6931203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
6932203945Sweongyo	}
6933203945Sweongyo	/*
6934203945Sweongyo	 * Calculate nrssi0
6935203945Sweongyo	 */
6936203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
6937203945Sweongyo	bwn_set_all_gains(mac, 0, 8, 0);
6938203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x00f7);
6939203945Sweongyo	if (phy->rev >= 2) {
6940203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
6941203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
6942203945Sweongyo	}
6943203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
6944203945Sweongyo	DELAY(20);
6945203945Sweongyo
6946203945Sweongyo	nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6947203945Sweongyo	if (nrssi0 >= 0x0020)
6948203945Sweongyo		nrssi0 -= 0x0040;
6949203945Sweongyo
6950203945Sweongyo	/*
6951203945Sweongyo	 * Calculate nrssi1
6952203945Sweongyo	 */
6953203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x007f);
6954203945Sweongyo	if (phy->rev >= 2)
6955203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
6956203945Sweongyo
6957203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
6958203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
6959203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x000f);
6960203945Sweongyo	BWN_PHY_WRITE(mac, 0x0015, 0xf330);
6961203945Sweongyo	if (phy->rev >= 2) {
6962203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
6963203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
6964203945Sweongyo	}
6965203945Sweongyo
6966203945Sweongyo	bwn_set_all_gains(mac, 3, 0, 1);
6967203945Sweongyo	if (phy->rf_rev == 8) {
6968203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, 0x001f);
6969203945Sweongyo	} else {
6970203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
6971203945Sweongyo		BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
6972203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
6973203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
6974203945Sweongyo	}
6975203945Sweongyo	BWN_PHY_WRITE(mac, 0x005a, 0x0480);
6976203945Sweongyo	BWN_PHY_WRITE(mac, 0x0059, 0x0810);
6977203945Sweongyo	BWN_PHY_WRITE(mac, 0x0058, 0x000d);
6978203945Sweongyo	DELAY(20);
6979203945Sweongyo	nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6980203945Sweongyo
6981203945Sweongyo	/*
6982203945Sweongyo	 * Install calculated narrow RSSI values
6983203945Sweongyo	 */
6984203945Sweongyo	if (nrssi1 >= 0x0020)
6985203945Sweongyo		nrssi1 -= 0x0040;
6986203945Sweongyo	if (nrssi0 == nrssi1)
6987203945Sweongyo		pg->pg_nrssi_slope = 0x00010000;
6988203945Sweongyo	else
6989203945Sweongyo		pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
6990203945Sweongyo	if (nrssi0 >= -4) {
6991203945Sweongyo		pg->pg_nrssi[0] = nrssi1;
6992203945Sweongyo		pg->pg_nrssi[1] = nrssi0;
6993203945Sweongyo	}
6994203945Sweongyo
6995203945Sweongyo	/*
6996203945Sweongyo	 * Restore saved RF/PHY registers
6997203945Sweongyo	 */
6998203945Sweongyo	if (phy->rev >= 3) {
6999203945Sweongyo		for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
7000203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
7001203945Sweongyo			    save_phy3[phy3_idx]);
7002203945Sweongyo		}
7003203945Sweongyo	}
7004203945Sweongyo	if (phy->rev >= 2) {
7005203945Sweongyo		BWN_PHY_MASK(mac, 0x0812, 0xffcf);
7006203945Sweongyo		BWN_PHY_MASK(mac, 0x0811, 0xffcf);
7007203945Sweongyo	}
7008203945Sweongyo
7009203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
7010203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
7011203945Sweongyo
7012203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, ant_div);
7013203945Sweongyo	BWN_WRITE_2(mac, 0x03e6, phy0);
7014203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
7015203945Sweongyo
7016203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
7017203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
7018203945Sweongyo
7019203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
7020203945Sweongyo	BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
7021203945Sweongyo	bwn_set_original_gains(mac);
7022203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
7023203945Sweongyo	if (phy->rev >= 3) {
7024203945Sweongyo		for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
7025203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
7026203945Sweongyo			    save_phy3[phy3_idx]);
7027203945Sweongyo		}
7028203945Sweongyo	}
7029203945Sweongyo
7030203945Sweongyo	delta = 0x1f - pg->pg_nrssi[0];
7031203945Sweongyo	for (i = 0; i < 64; i++) {
7032203945Sweongyo		tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
7033203945Sweongyo		tmp32 = MIN(MAX(tmp32, 0), 0x3f);
7034203945Sweongyo		pg->pg_nrssi_lt[i] = tmp32;
7035203945Sweongyo	}
7036203945Sweongyo
7037203945Sweongyo	bwn_nrssi_threshold(mac);
7038203945Sweongyo#undef SAVE_RF_MAX
7039203945Sweongyo#undef SAVE_PHY_COMM_MAX
7040203945Sweongyo#undef SAVE_PHY3_MAX
7041203945Sweongyo}
7042203945Sweongyo
7043203945Sweongyostatic void
7044203945Sweongyobwn_nrssi_offset(struct bwn_mac *mac)
7045203945Sweongyo{
7046203945Sweongyo#define	SAVE_RF_MAX		2
7047203945Sweongyo#define	SAVE_PHY_COMM_MAX	10
7048203945Sweongyo#define	SAVE_PHY6_MAX		8
7049203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
7050203945Sweongyo		{ 0x7a, 0x43 };
7051203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
7052203945Sweongyo		0x0001, 0x0811, 0x0812, 0x0814,
7053203945Sweongyo		0x0815, 0x005a, 0x0059, 0x0058,
7054203945Sweongyo		0x000a, 0x0003
7055203945Sweongyo	};
7056203945Sweongyo	static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
7057203945Sweongyo		0x002e, 0x002f, 0x080f, 0x0810,
7058203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
7059203945Sweongyo	};
7060203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7061203945Sweongyo	int i, phy6_idx = 0;
7062203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
7063203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
7064203945Sweongyo	uint16_t save_phy6[SAVE_PHY6_MAX];
7065203945Sweongyo	int16_t nrssi;
7066203945Sweongyo	uint16_t saved = 0xffff;
7067203945Sweongyo
7068203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
7069203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
7070203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
7071203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
7072203945Sweongyo
7073203945Sweongyo	BWN_PHY_MASK(mac, 0x0429, 0x7fff);
7074203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
7075203945Sweongyo	BWN_PHY_SET(mac, 0x0811, 0x000c);
7076203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
7077203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
7078203945Sweongyo	if (phy->rev >= 6) {
7079203945Sweongyo		for (i = 0; i < SAVE_PHY6_MAX; ++i)
7080203945Sweongyo			save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
7081203945Sweongyo
7082203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
7083203945Sweongyo		BWN_PHY_WRITE(mac, 0x002f, 0);
7084203945Sweongyo		BWN_PHY_WRITE(mac, 0x080f, 0);
7085203945Sweongyo		BWN_PHY_WRITE(mac, 0x0810, 0);
7086203945Sweongyo		BWN_PHY_SET(mac, 0x0478, 0x0100);
7087203945Sweongyo		BWN_PHY_SET(mac, 0x0801, 0x0040);
7088203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
7089203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
7090203945Sweongyo	}
7091203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
7092203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
7093203945Sweongyo	DELAY(30);
7094203945Sweongyo
7095203945Sweongyo	nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7096203945Sweongyo	if (nrssi >= 0x20)
7097203945Sweongyo		nrssi -= 0x40;
7098203945Sweongyo	if (nrssi == 31) {
7099203945Sweongyo		for (i = 7; i >= 4; i--) {
7100203945Sweongyo			BWN_RF_WRITE(mac, 0x007b, i);
7101203945Sweongyo			DELAY(20);
7102203945Sweongyo			nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
7103203945Sweongyo			    0x003f);
7104203945Sweongyo			if (nrssi >= 0x20)
7105203945Sweongyo				nrssi -= 0x40;
7106203945Sweongyo			if (nrssi < 31 && saved == 0xffff)
7107203945Sweongyo				saved = i;
7108203945Sweongyo		}
7109203945Sweongyo		if (saved == 0xffff)
7110203945Sweongyo			saved = 4;
7111203945Sweongyo	} else {
7112203945Sweongyo		BWN_RF_MASK(mac, 0x007a, 0x007f);
7113203945Sweongyo		if (phy->rev != 1) {
7114203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0001);
7115203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffe);
7116203945Sweongyo		}
7117203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x000c);
7118203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x000c);
7119203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x0030);
7120203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x0030);
7121203945Sweongyo		BWN_PHY_WRITE(mac, 0x005a, 0x0480);
7122203945Sweongyo		BWN_PHY_WRITE(mac, 0x0059, 0x0810);
7123203945Sweongyo		BWN_PHY_WRITE(mac, 0x0058, 0x000d);
7124203945Sweongyo		if (phy->rev == 0)
7125203945Sweongyo			BWN_PHY_WRITE(mac, 0x0003, 0x0122);
7126203945Sweongyo		else
7127203945Sweongyo			BWN_PHY_SET(mac, 0x000a, 0x2000);
7128203945Sweongyo		if (phy->rev != 1) {
7129203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0004);
7130203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffb);
7131203945Sweongyo		}
7132203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
7133203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x000f);
7134203945Sweongyo		bwn_set_all_gains(mac, 3, 0, 1);
7135203945Sweongyo		BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
7136203945Sweongyo		DELAY(30);
7137203945Sweongyo		nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7138203945Sweongyo		if (nrssi >= 0x20)
7139203945Sweongyo			nrssi -= 0x40;
7140203945Sweongyo		if (nrssi == -32) {
7141203945Sweongyo			for (i = 0; i < 4; i++) {
7142203945Sweongyo				BWN_RF_WRITE(mac, 0x007b, i);
7143203945Sweongyo				DELAY(20);
7144203945Sweongyo				nrssi = (int16_t)((BWN_PHY_READ(mac,
7145203945Sweongyo				    0x047f) >> 8) & 0x003f);
7146203945Sweongyo				if (nrssi >= 0x20)
7147203945Sweongyo					nrssi -= 0x40;
7148203945Sweongyo				if (nrssi > -31 && saved == 0xffff)
7149203945Sweongyo					saved = i;
7150203945Sweongyo			}
7151203945Sweongyo			if (saved == 0xffff)
7152203945Sweongyo				saved = 3;
7153203945Sweongyo		} else
7154203945Sweongyo			saved = 0;
7155203945Sweongyo	}
7156203945Sweongyo	BWN_RF_WRITE(mac, 0x007b, saved);
7157203945Sweongyo
7158203945Sweongyo	/*
7159203945Sweongyo	 * Restore saved RF/PHY registers
7160203945Sweongyo	 */
7161203945Sweongyo	if (phy->rev >= 6) {
7162203945Sweongyo		for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
7163203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7164203945Sweongyo			    save_phy6[phy6_idx]);
7165203945Sweongyo		}
7166203945Sweongyo	}
7167203945Sweongyo	if (phy->rev != 1) {
7168203945Sweongyo		for (i = 3; i < 5; i++)
7169203945Sweongyo			BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
7170203945Sweongyo			    save_phy_comm[i]);
7171203945Sweongyo	}
7172203945Sweongyo	for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
7173203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
7174203945Sweongyo
7175203945Sweongyo	for (i = SAVE_RF_MAX - 1; i >= 0; --i)
7176203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
7177203945Sweongyo
7178203945Sweongyo	BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
7179203945Sweongyo	BWN_PHY_SET(mac, 0x0429, 0x8000);
7180203945Sweongyo	bwn_set_original_gains(mac);
7181203945Sweongyo	if (phy->rev >= 6) {
7182203945Sweongyo		for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
7183203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7184203945Sweongyo			    save_phy6[phy6_idx]);
7185203945Sweongyo		}
7186203945Sweongyo	}
7187203945Sweongyo
7188203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
7189203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
7190203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
7191203945Sweongyo}
7192203945Sweongyo
7193203945Sweongyostatic void
7194203945Sweongyobwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
7195203945Sweongyo    int16_t third)
7196203945Sweongyo{
7197203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7198203945Sweongyo	uint16_t i;
7199203945Sweongyo	uint16_t start = 0x08, end = 0x18;
7200203945Sweongyo	uint16_t tmp;
7201203945Sweongyo	uint16_t table;
7202203945Sweongyo
7203203945Sweongyo	if (phy->rev <= 1) {
7204203945Sweongyo		start = 0x10;
7205203945Sweongyo		end = 0x20;
7206203945Sweongyo	}
7207203945Sweongyo
7208203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7209203945Sweongyo	if (phy->rev <= 1)
7210203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7211203945Sweongyo	for (i = 0; i < 4; i++)
7212203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, first);
7213203945Sweongyo
7214203945Sweongyo	for (i = start; i < end; i++)
7215203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, second);
7216203945Sweongyo
7217203945Sweongyo	if (third != -1) {
7218203945Sweongyo		tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
7219203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
7220203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
7221203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
7222203945Sweongyo	}
7223203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7224203945Sweongyo}
7225203945Sweongyo
7226203945Sweongyostatic void
7227203945Sweongyobwn_set_original_gains(struct bwn_mac *mac)
7228203945Sweongyo{
7229203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7230203945Sweongyo	uint16_t i, tmp;
7231203945Sweongyo	uint16_t table;
7232203945Sweongyo	uint16_t start = 0x0008, end = 0x0018;
7233203945Sweongyo
7234203945Sweongyo	if (phy->rev <= 1) {
7235203945Sweongyo		start = 0x0010;
7236203945Sweongyo		end = 0x0020;
7237203945Sweongyo	}
7238203945Sweongyo
7239203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7240203945Sweongyo	if (phy->rev <= 1)
7241203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7242203945Sweongyo	for (i = 0; i < 4; i++) {
7243203945Sweongyo		tmp = (i & 0xfffc);
7244203945Sweongyo		tmp |= (i & 0x0001) << 1;
7245203945Sweongyo		tmp |= (i & 0x0002) >> 1;
7246203945Sweongyo
7247203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, tmp);
7248203945Sweongyo	}
7249203945Sweongyo
7250203945Sweongyo	for (i = start; i < end; i++)
7251203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, i - start);
7252203945Sweongyo
7253203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
7254203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
7255203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
7256203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7257203945Sweongyo}
7258203945Sweongyo
7259203945Sweongyostatic void
7260203945Sweongyobwn_phy_hwpctl_init(struct bwn_mac *mac)
7261203945Sweongyo{
7262203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
7263203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7264203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7265203945Sweongyo	struct bwn_rfatt old_rfatt, rfatt;
7266203945Sweongyo	struct bwn_bbatt old_bbatt, bbatt;
7267203945Sweongyo	uint8_t old_txctl = 0;
7268203945Sweongyo
7269203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
7270203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7271203945Sweongyo
7272203945Sweongyo	if ((bus->siba_board_vendor == SIBA_BOARDVENDOR_BCM) &&
7273203945Sweongyo	    (bus->siba_board_type == SIBA_BOARD_BU4306))
7274203945Sweongyo		return;
7275203945Sweongyo
7276203945Sweongyo	BWN_PHY_WRITE(mac, 0x0028, 0x8018);
7277203945Sweongyo
7278203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
7279203945Sweongyo
7280203945Sweongyo	if (!phy->gmode)
7281203945Sweongyo		return;
7282203945Sweongyo	bwn_hwpctl_early_init(mac);
7283203945Sweongyo	if (pg->pg_curtssi == 0) {
7284203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0) {
7285203945Sweongyo			BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
7286203945Sweongyo		} else {
7287203945Sweongyo			memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
7288203945Sweongyo			memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
7289203945Sweongyo			old_txctl = pg->pg_txctl;
7290203945Sweongyo
7291203945Sweongyo			bbatt.att = 11;
7292203945Sweongyo			if (phy->rf_rev == 8) {
7293203945Sweongyo				rfatt.att = 15;
7294203945Sweongyo				rfatt.padmix = 1;
7295203945Sweongyo			} else {
7296203945Sweongyo				rfatt.att = 9;
7297203945Sweongyo				rfatt.padmix = 0;
7298203945Sweongyo			}
7299203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
7300203945Sweongyo		}
7301203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
7302203945Sweongyo		pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
7303203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0)
7304203945Sweongyo			BWN_RF_MASK(mac, 0x0076, 0xff7b);
7305203945Sweongyo		else
7306203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
7307203945Sweongyo			    &old_rfatt, old_txctl);
7308203945Sweongyo	}
7309203945Sweongyo	bwn_hwpctl_init_gphy(mac);
7310203945Sweongyo
7311203945Sweongyo	/* clear TSSI */
7312203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
7313203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
7314203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
7315203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
7316203945Sweongyo}
7317203945Sweongyo
7318203945Sweongyostatic void
7319203945Sweongyobwn_hwpctl_early_init(struct bwn_mac *mac)
7320203945Sweongyo{
7321203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7322203945Sweongyo
7323203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7324203945Sweongyo		BWN_PHY_WRITE(mac, 0x047a, 0xc111);
7325203945Sweongyo		return;
7326203945Sweongyo	}
7327203945Sweongyo
7328203945Sweongyo	BWN_PHY_MASK(mac, 0x0036, 0xfeff);
7329203945Sweongyo	BWN_PHY_WRITE(mac, 0x002f, 0x0202);
7330203945Sweongyo	BWN_PHY_SET(mac, 0x047c, 0x0002);
7331203945Sweongyo	BWN_PHY_SET(mac, 0x047a, 0xf000);
7332203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
7333203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7334203945Sweongyo		BWN_PHY_SET(mac, 0x005d, 0x8000);
7335203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7336203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7337203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7338203945Sweongyo	} else {
7339203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0200);
7340203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7341203945Sweongyo		BWN_PHY_MASK(mac, 0x005d, 0x7fff);
7342203945Sweongyo		BWN_PHY_MASK(mac, 0x004f, 0xfffe);
7343203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7344203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7345203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7346203945Sweongyo	}
7347203945Sweongyo}
7348203945Sweongyo
7349203945Sweongyostatic void
7350203945Sweongyobwn_hwpctl_init_gphy(struct bwn_mac *mac)
7351203945Sweongyo{
7352203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7353203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7354203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7355203945Sweongyo	int i;
7356203945Sweongyo	uint16_t nr_written = 0, tmp, value;
7357203945Sweongyo	uint8_t rf, bb;
7358203945Sweongyo
7359203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7360203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
7361203945Sweongyo		return;
7362203945Sweongyo	}
7363203945Sweongyo
7364203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
7365203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7366203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
7367203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7368203945Sweongyo
7369203945Sweongyo	for (i = 0; i < 32; i++)
7370203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
7371203945Sweongyo	for (i = 32; i < 64; i++)
7372203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
7373203945Sweongyo	for (i = 0; i < 64; i += 2) {
7374203945Sweongyo		value = (uint16_t) pg->pg_tssi2dbm[i];
7375203945Sweongyo		value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
7376203945Sweongyo		BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
7377203945Sweongyo	}
7378203945Sweongyo
7379203945Sweongyo	for (rf = 0; rf < lo->rfatt.len; rf++) {
7380203945Sweongyo		for (bb = 0; bb < lo->bbatt.len; bb++) {
7381203945Sweongyo			if (nr_written >= 0x40)
7382203945Sweongyo				return;
7383203945Sweongyo			tmp = lo->bbatt.array[bb].att;
7384203945Sweongyo			tmp <<= 8;
7385203945Sweongyo			if (phy->rf_rev == 8)
7386203945Sweongyo				tmp |= 0x50;
7387203945Sweongyo			else
7388203945Sweongyo				tmp |= 0x40;
7389203945Sweongyo			tmp |= lo->rfatt.array[rf].att;
7390203945Sweongyo			BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
7391203945Sweongyo			nr_written++;
7392203945Sweongyo		}
7393203945Sweongyo	}
7394203945Sweongyo
7395203945Sweongyo	BWN_PHY_MASK(mac, 0x0060, 0xffbf);
7396203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0000);
7397203945Sweongyo
7398203945Sweongyo	KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
7399203945Sweongyo	BWN_PHY_SET(mac, 0x0478, 0x0800);
7400203945Sweongyo	BWN_PHY_MASK(mac, 0x0478, 0xfeff);
7401203945Sweongyo	BWN_PHY_MASK(mac, 0x0801, 0xffbf);
7402203945Sweongyo
7403203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
7404203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
7405203945Sweongyo}
7406203945Sweongyo
7407203945Sweongyostatic void
7408203945Sweongyobwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
7409203945Sweongyo{
7410203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
7411203945Sweongyo
7412203945Sweongyo	if (spu != 0)
7413203945Sweongyo		bwn_spu_workaround(mac, channel);
7414203945Sweongyo
7415203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7416203945Sweongyo
7417203945Sweongyo	if (channel == 14) {
7418203945Sweongyo		if (siba->siba_sprom.ccode == SIBA_CCODE_JAPAN)
7419203945Sweongyo			bwn_hf_write(mac,
7420203945Sweongyo			    bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
7421203945Sweongyo		else
7422203945Sweongyo			bwn_hf_write(mac,
7423203945Sweongyo			    bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
7424203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7425203945Sweongyo		    BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
7426203945Sweongyo		return;
7427203945Sweongyo	}
7428203945Sweongyo
7429203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7430203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
7431203945Sweongyo}
7432203945Sweongyo
7433203945Sweongyostatic uint16_t
7434203945Sweongyobwn_phy_g_chan2freq(uint8_t channel)
7435203945Sweongyo{
7436203945Sweongyo	static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
7437203945Sweongyo
7438203945Sweongyo	KASSERT(channel >= 1 && channel <= 14,
7439203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7440203945Sweongyo
7441203945Sweongyo	return (bwn_phy_g_rf_channels[channel - 1]);
7442203945Sweongyo}
7443203945Sweongyo
7444203945Sweongyostatic void
7445203945Sweongyobwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
7446203945Sweongyo    const struct bwn_rfatt *rfatt, uint8_t txctl)
7447203945Sweongyo{
7448203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7449203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7450203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7451203945Sweongyo	uint16_t bb, rf;
7452203945Sweongyo	uint16_t tx_bias, tx_magn;
7453203945Sweongyo
7454203945Sweongyo	bb = bbatt->att;
7455203945Sweongyo	rf = rfatt->att;
7456203945Sweongyo	tx_bias = lo->tx_bias;
7457203945Sweongyo	tx_magn = lo->tx_magn;
7458203945Sweongyo	if (tx_bias == 0xff)
7459203945Sweongyo		tx_bias = 0;
7460203945Sweongyo
7461203945Sweongyo	pg->pg_txctl = txctl;
7462203945Sweongyo	memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
7463203945Sweongyo	pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
7464203945Sweongyo	memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
7465203945Sweongyo	bwn_phy_g_set_bbatt(mac, bb);
7466203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
7467203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
7468203945Sweongyo		BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
7469203945Sweongyo	else {
7470203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
7471203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
7472203945Sweongyo	}
7473203945Sweongyo	if (BWN_HAS_TXMAG(phy))
7474203945Sweongyo		BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
7475203945Sweongyo	else
7476203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
7477203945Sweongyo	bwn_lo_g_adjust(mac);
7478203945Sweongyo}
7479203945Sweongyo
7480203945Sweongyostatic void
7481203945Sweongyobwn_phy_g_set_bbatt(struct bwn_mac *mac,
7482203945Sweongyo    uint16_t bbatt)
7483203945Sweongyo{
7484203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7485203945Sweongyo
7486203945Sweongyo	if (phy->analog == 0) {
7487203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY0,
7488203945Sweongyo		    (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
7489203945Sweongyo		return;
7490203945Sweongyo	}
7491203945Sweongyo	if (phy->analog > 1) {
7492203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
7493203945Sweongyo		return;
7494203945Sweongyo	}
7495203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
7496203945Sweongyo}
7497203945Sweongyo
7498203945Sweongyostatic uint16_t
7499203945Sweongyobwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
7500203945Sweongyo{
7501203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7502203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7503203945Sweongyo	struct siba_sprom *sprom = &(mac->mac_sd->sd_bus->siba_sprom);
7504203945Sweongyo	int max_lb_gain;
7505203945Sweongyo	uint16_t extlna;
7506203945Sweongyo	uint16_t i;
7507203945Sweongyo
7508203945Sweongyo	if (phy->gmode == 0)
7509203945Sweongyo		return (0);
7510203945Sweongyo
7511203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
7512203945Sweongyo		max_lb_gain = pg->pg_max_lb_gain;
7513203945Sweongyo		max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
7514203945Sweongyo		if (max_lb_gain >= 0x46) {
7515203945Sweongyo			extlna = 0x3000;
7516203945Sweongyo			max_lb_gain -= 0x46;
7517203945Sweongyo		} else if (max_lb_gain >= 0x3a) {
7518203945Sweongyo			extlna = 0x1000;
7519203945Sweongyo			max_lb_gain -= 0x3a;
7520203945Sweongyo		} else if (max_lb_gain >= 0x2e) {
7521203945Sweongyo			extlna = 0x2000;
7522203945Sweongyo			max_lb_gain -= 0x2e;
7523203945Sweongyo		} else {
7524203945Sweongyo			extlna = 0;
7525203945Sweongyo			max_lb_gain -= 0x10;
7526203945Sweongyo		}
7527203945Sweongyo
7528203945Sweongyo		for (i = 0; i < 16; i++) {
7529203945Sweongyo			max_lb_gain -= (i * 6);
7530203945Sweongyo			if (max_lb_gain < 6)
7531203945Sweongyo				break;
7532203945Sweongyo		}
7533203945Sweongyo
7534203945Sweongyo		if ((phy->rev < 7) || !(sprom->bf_lo & BWN_BFL_EXTLNA)) {
7535203945Sweongyo			if (reg == BWN_PHY_RFOVER) {
7536203945Sweongyo				return (0x1b3);
7537203945Sweongyo			} else if (reg == BWN_PHY_RFOVERVAL) {
7538203945Sweongyo				extlna |= (i << 8);
7539203945Sweongyo				switch (lpd) {
7540203945Sweongyo				case BWN_LPD(0, 1, 1):
7541203945Sweongyo					return (0x0f92);
7542203945Sweongyo				case BWN_LPD(0, 0, 1):
7543203945Sweongyo				case BWN_LPD(1, 0, 1):
7544203945Sweongyo					return (0x0092 | extlna);
7545203945Sweongyo				case BWN_LPD(1, 0, 0):
7546203945Sweongyo					return (0x0093 | extlna);
7547203945Sweongyo				}
7548203945Sweongyo				KASSERT(0 == 1,
7549203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7550203945Sweongyo			}
7551203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7552203945Sweongyo		} else {
7553203945Sweongyo			if (reg == BWN_PHY_RFOVER)
7554203945Sweongyo				return (0x9b3);
7555203945Sweongyo			if (reg == BWN_PHY_RFOVERVAL) {
7556203945Sweongyo				if (extlna)
7557203945Sweongyo					extlna |= 0x8000;
7558203945Sweongyo				extlna |= (i << 8);
7559203945Sweongyo				switch (lpd) {
7560203945Sweongyo				case BWN_LPD(0, 1, 1):
7561203945Sweongyo					return (0x8f92);
7562203945Sweongyo				case BWN_LPD(0, 0, 1):
7563203945Sweongyo					return (0x8092 | extlna);
7564203945Sweongyo				case BWN_LPD(1, 0, 1):
7565203945Sweongyo					return (0x2092 | extlna);
7566203945Sweongyo				case BWN_LPD(1, 0, 0):
7567203945Sweongyo					return (0x2093 | extlna);
7568203945Sweongyo				}
7569203945Sweongyo				KASSERT(0 == 1,
7570203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7571203945Sweongyo			}
7572203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7573203945Sweongyo		}
7574203945Sweongyo		return (0);
7575203945Sweongyo	}
7576203945Sweongyo
7577203945Sweongyo	if ((phy->rev < 7) ||
7578203945Sweongyo	    !(sprom->bf_lo & BWN_BFL_EXTLNA)) {
7579203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7580203945Sweongyo			return (0x1b3);
7581203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7582203945Sweongyo			switch (lpd) {
7583203945Sweongyo			case BWN_LPD(0, 1, 1):
7584203945Sweongyo				return (0x0fb2);
7585203945Sweongyo			case BWN_LPD(0, 0, 1):
7586203945Sweongyo				return (0x00b2);
7587203945Sweongyo			case BWN_LPD(1, 0, 1):
7588203945Sweongyo				return (0x30b2);
7589203945Sweongyo			case BWN_LPD(1, 0, 0):
7590203945Sweongyo				return (0x30b3);
7591203945Sweongyo			}
7592203945Sweongyo			KASSERT(0 == 1,
7593203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7594203945Sweongyo		}
7595203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7596203945Sweongyo	} else {
7597203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7598203945Sweongyo			return (0x9b3);
7599203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7600203945Sweongyo			switch (lpd) {
7601203945Sweongyo			case BWN_LPD(0, 1, 1):
7602203945Sweongyo				return (0x8fb2);
7603203945Sweongyo			case BWN_LPD(0, 0, 1):
7604203945Sweongyo				return (0x80b2);
7605203945Sweongyo			case BWN_LPD(1, 0, 1):
7606203945Sweongyo				return (0x20b2);
7607203945Sweongyo			case BWN_LPD(1, 0, 0):
7608203945Sweongyo				return (0x20b3);
7609203945Sweongyo			}
7610203945Sweongyo			KASSERT(0 == 1,
7611203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7612203945Sweongyo		}
7613203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7614203945Sweongyo	}
7615203945Sweongyo	return (0);
7616203945Sweongyo}
7617203945Sweongyo
7618203945Sweongyostatic void
7619203945Sweongyobwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
7620203945Sweongyo{
7621203945Sweongyo
7622203945Sweongyo	if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
7623203945Sweongyo		return;
7624203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
7625203945Sweongyo	    bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
7626203945Sweongyo	DELAY(1000);
7627203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7628203945Sweongyo}
7629203945Sweongyo
7630203945Sweongyostatic int
7631203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
7632203945Sweongyo{
7633203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7634203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
7635203945Sweongyo	const uint8_t rev = mac->mac_sd->sd_id.sd_rev;
7636203945Sweongyo	const char *filename;
7637203945Sweongyo	uint32_t high;
7638203945Sweongyo	int error;
7639203945Sweongyo
7640203945Sweongyo	/* microcode */
7641203945Sweongyo	if (rev >= 5 && rev <= 10)
7642203945Sweongyo		filename = "ucode5";
7643203945Sweongyo	else if (rev >= 11 && rev <= 12)
7644203945Sweongyo		filename = "ucode11";
7645203945Sweongyo	else if (rev == 13)
7646203945Sweongyo		filename = "ucode13";
7647203945Sweongyo	else if (rev == 14)
7648203945Sweongyo		filename = "ucode14";
7649203945Sweongyo	else if (rev >= 15)
7650203945Sweongyo		filename = "ucode15";
7651203945Sweongyo	else {
7652203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
7653203945Sweongyo		bwn_release_firmware(mac);
7654203945Sweongyo		return (EOPNOTSUPP);
7655203945Sweongyo	}
7656203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
7657203945Sweongyo	if (error) {
7658203945Sweongyo		bwn_release_firmware(mac);
7659203945Sweongyo		return (error);
7660203945Sweongyo	}
7661203945Sweongyo
7662203945Sweongyo	/* PCM */
7663203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
7664203945Sweongyo	if (rev >= 5 && rev <= 10) {
7665203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
7666203945Sweongyo		if (error == ENOENT)
7667203945Sweongyo			fw->no_pcmfile = 1;
7668203945Sweongyo		else if (error) {
7669203945Sweongyo			bwn_release_firmware(mac);
7670203945Sweongyo			return (error);
7671203945Sweongyo		}
7672203945Sweongyo	} else if (rev < 11) {
7673203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
7674203945Sweongyo		return (EOPNOTSUPP);
7675203945Sweongyo	}
7676203945Sweongyo
7677203945Sweongyo	/* initvals */
7678203945Sweongyo	high = siba_read_4(mac->mac_sd, SIBA_TGSHIGH);
7679203945Sweongyo	switch (mac->mac_phy.type) {
7680203945Sweongyo	case BWN_PHYTYPE_A:
7681203945Sweongyo		if (rev < 5 || rev > 10)
7682203945Sweongyo			goto fail1;
7683203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
7684203945Sweongyo			filename = "a0g1initvals5";
7685203945Sweongyo		else
7686203945Sweongyo			filename = "a0g0initvals5";
7687203945Sweongyo		break;
7688203945Sweongyo	case BWN_PHYTYPE_G:
7689203945Sweongyo		if (rev >= 5 && rev <= 10)
7690203945Sweongyo			filename = "b0g0initvals5";
7691203945Sweongyo		else if (rev >= 13)
7692203945Sweongyo			filename = "b0g0initvals13";
7693203945Sweongyo		else
7694203945Sweongyo			goto fail1;
7695203945Sweongyo		break;
7696203945Sweongyo	case BWN_PHYTYPE_LP:
7697203945Sweongyo		if (rev == 13)
7698203945Sweongyo			filename = "lp0initvals13";
7699203945Sweongyo		else if (rev == 14)
7700203945Sweongyo			filename = "lp0initvals14";
7701203945Sweongyo		else if (rev >= 15)
7702203945Sweongyo			filename = "lp0initvals15";
7703203945Sweongyo		else
7704203945Sweongyo			goto fail1;
7705203945Sweongyo		break;
7706203945Sweongyo	case BWN_PHYTYPE_N:
7707203945Sweongyo		if (rev >= 11 && rev <= 12)
7708203945Sweongyo			filename = "n0initvals11";
7709203945Sweongyo		else
7710203945Sweongyo			goto fail1;
7711203945Sweongyo		break;
7712203945Sweongyo	default:
7713203945Sweongyo		goto fail1;
7714203945Sweongyo	}
7715203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
7716203945Sweongyo	if (error) {
7717203945Sweongyo		bwn_release_firmware(mac);
7718203945Sweongyo		return (error);
7719203945Sweongyo	}
7720203945Sweongyo
7721203945Sweongyo	/* bandswitch initvals */
7722203945Sweongyo	switch (mac->mac_phy.type) {
7723203945Sweongyo	case BWN_PHYTYPE_A:
7724203945Sweongyo		if (rev >= 5 && rev <= 10) {
7725203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
7726203945Sweongyo				filename = "a0g1bsinitvals5";
7727203945Sweongyo			else
7728203945Sweongyo				filename = "a0g0bsinitvals5";
7729203945Sweongyo		} else if (rev >= 11)
7730203945Sweongyo			filename = NULL;
7731203945Sweongyo		else
7732203945Sweongyo			goto fail1;
7733203945Sweongyo		break;
7734203945Sweongyo	case BWN_PHYTYPE_G:
7735203945Sweongyo		if (rev >= 5 && rev <= 10)
7736203945Sweongyo			filename = "b0g0bsinitvals5";
7737203945Sweongyo		else if (rev >= 11)
7738203945Sweongyo			filename = NULL;
7739203945Sweongyo		else
7740203945Sweongyo			goto fail1;
7741203945Sweongyo		break;
7742203945Sweongyo	case BWN_PHYTYPE_LP:
7743203945Sweongyo		if (rev == 13)
7744203945Sweongyo			filename = "lp0bsinitvals13";
7745203945Sweongyo		else if (rev == 14)
7746203945Sweongyo			filename = "lp0bsinitvals14";
7747203945Sweongyo		else if (rev >= 15)
7748203945Sweongyo			filename = "lp0bsinitvals15";
7749203945Sweongyo		else
7750203945Sweongyo			goto fail1;
7751203945Sweongyo		break;
7752203945Sweongyo	case BWN_PHYTYPE_N:
7753203945Sweongyo		if (rev >= 11 && rev <= 12)
7754203945Sweongyo			filename = "n0bsinitvals11";
7755203945Sweongyo		else
7756203945Sweongyo			goto fail1;
7757203945Sweongyo		break;
7758203945Sweongyo	default:
7759203945Sweongyo		goto fail1;
7760203945Sweongyo	}
7761203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
7762203945Sweongyo	if (error) {
7763203945Sweongyo		bwn_release_firmware(mac);
7764203945Sweongyo		return (error);
7765203945Sweongyo	}
7766203945Sweongyo	return (0);
7767203945Sweongyofail1:
7768203945Sweongyo	device_printf(sc->sc_dev, "no INITVALS for rev %d\n", rev);
7769203945Sweongyo	bwn_release_firmware(mac);
7770203945Sweongyo	return (EOPNOTSUPP);
7771203945Sweongyo}
7772203945Sweongyo
7773203945Sweongyostatic int
7774203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
7775203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
7776203945Sweongyo{
7777203945Sweongyo	const struct bwn_fwhdr *hdr;
7778203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7779203945Sweongyo	const struct firmware *fw;
7780203945Sweongyo	char namebuf[64];
7781203945Sweongyo
7782203945Sweongyo	if (name == NULL) {
7783203945Sweongyo		bwn_do_release_fw(bfw);
7784203945Sweongyo		return (0);
7785203945Sweongyo	}
7786203945Sweongyo	if (bfw->filename != NULL) {
7787203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
7788203945Sweongyo			return (0);
7789203945Sweongyo		bwn_do_release_fw(bfw);
7790203945Sweongyo	}
7791203945Sweongyo
7792204437Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s%s",
7793204437Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "",
7794204437Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_LP) ? "lp_" : "", name);
7795203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
7796203945Sweongyo	fw = firmware_get(namebuf);
7797203945Sweongyo	if (fw == NULL) {
7798203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
7799203945Sweongyo		    namebuf);
7800203945Sweongyo		return (ENOENT);
7801203945Sweongyo	}
7802203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
7803203945Sweongyo		goto fail;
7804203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
7805203945Sweongyo	switch (hdr->type) {
7806203945Sweongyo	case BWN_FWTYPE_UCODE:
7807203945Sweongyo	case BWN_FWTYPE_PCM:
7808203945Sweongyo		if (be32toh(hdr->size) !=
7809203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
7810203945Sweongyo			goto fail;
7811203945Sweongyo		/* FALLTHROUGH */
7812203945Sweongyo	case BWN_FWTYPE_IV:
7813203945Sweongyo		if (hdr->ver != 1)
7814203945Sweongyo			goto fail;
7815203945Sweongyo		break;
7816203945Sweongyo	default:
7817203945Sweongyo		goto fail;
7818203945Sweongyo	}
7819203945Sweongyo	bfw->filename = name;
7820203945Sweongyo	bfw->fw = fw;
7821203945Sweongyo	bfw->type = type;
7822203945Sweongyo	return (0);
7823203945Sweongyofail:
7824203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
7825203945Sweongyo	if (fw != NULL)
7826203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
7827203945Sweongyo	return (EPROTO);
7828203945Sweongyo}
7829203945Sweongyo
7830203945Sweongyostatic void
7831203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
7832203945Sweongyo{
7833203945Sweongyo
7834203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
7835203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
7836203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
7837203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
7838203945Sweongyo}
7839203945Sweongyo
7840203945Sweongyostatic void
7841203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
7842203945Sweongyo{
7843203945Sweongyo
7844203945Sweongyo	if (bfw->fw != NULL)
7845203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
7846203945Sweongyo	bfw->fw = NULL;
7847203945Sweongyo	bfw->filename = NULL;
7848203945Sweongyo}
7849203945Sweongyo
7850203945Sweongyostatic int
7851203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
7852203945Sweongyo{
7853203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
7854203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
7855203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
7856203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
7857203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7858203945Sweongyo	const uint32_t *data;
7859203945Sweongyo	unsigned int i;
7860203945Sweongyo	uint32_t ctl;
7861203945Sweongyo	uint16_t date, fwcaps, time;
7862203945Sweongyo	int error = 0;
7863203945Sweongyo
7864203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
7865203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
7866203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
7867203945Sweongyo	    __LINE__));
7868203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
7869203945Sweongyo	for (i = 0; i < 64; i++)
7870203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
7871203945Sweongyo	for (i = 0; i < 4096; i += 2)
7872203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
7873203945Sweongyo
7874203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7875203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
7876203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7877203945Sweongyo	     i++) {
7878203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7879203945Sweongyo		DELAY(10);
7880203945Sweongyo	}
7881203945Sweongyo
7882203945Sweongyo	if (mac->mac_fw.pcm.fw) {
7883203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
7884203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
7885203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
7886203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
7887203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
7888203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
7889203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7890203945Sweongyo			DELAY(10);
7891203945Sweongyo		}
7892203945Sweongyo	}
7893203945Sweongyo
7894203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
7895203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7896203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
7897203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
7898203945Sweongyo
7899203945Sweongyo	for (i = 0; i < 21; i++) {
7900203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
7901203945Sweongyo			break;
7902203945Sweongyo		if (i >= 20) {
7903203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
7904203945Sweongyo			error = ENXIO;
7905203945Sweongyo			goto error;
7906203945Sweongyo		}
7907203945Sweongyo		DELAY(50000);
7908203945Sweongyo	}
7909203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
7910203945Sweongyo
7911203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
7912203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
7913203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
7914203945Sweongyo		error = EOPNOTSUPP;
7915203945Sweongyo		goto error;
7916203945Sweongyo	}
7917203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
7918203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
7919203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
7920203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
7921203945Sweongyo	if (bwn_wme != 0)
7922203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
7923203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
7924203945Sweongyo
7925203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
7926203945Sweongyo	if (mac->mac_fw.opensource == 0) {
7927203945Sweongyo		device_printf(sc->sc_dev,
7928203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
7929203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
7930203945Sweongyo		if (mac->mac_fw.no_pcmfile)
7931203945Sweongyo			device_printf(sc->sc_dev,
7932203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
7933203945Sweongyo	} else {
7934203945Sweongyo		mac->mac_fw.patch = time;
7935203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
7936203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
7937203945Sweongyo			device_printf(sc->sc_dev,
7938203945Sweongyo			    "disabling HW crypto acceleration\n");
7939203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
7940203945Sweongyo		}
7941203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
7942203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
7943203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
7944203945Sweongyo		}
7945203945Sweongyo	}
7946203945Sweongyo
7947203945Sweongyo	if (BWN_ISOLDFMT(mac))
7948203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
7949203945Sweongyo
7950203945Sweongyo	return (0);
7951203945Sweongyo
7952203945Sweongyoerror:
7953203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7954203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
7955203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
7956203945Sweongyo
7957203945Sweongyo	return (error);
7958203945Sweongyo#undef GETFWSIZE
7959203945Sweongyo#undef GETFWOFFSET
7960203945Sweongyo}
7961203945Sweongyo
7962203945Sweongyo/* OpenFirmware only */
7963203945Sweongyostatic uint16_t
7964203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
7965203945Sweongyo{
7966203945Sweongyo
7967203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
7968203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7969203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
7970203945Sweongyo}
7971203945Sweongyo
7972203945Sweongyostatic int
7973203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
7974203945Sweongyo    size_t count, size_t array_size)
7975203945Sweongyo{
7976203945Sweongyo#define	GET_NEXTIV16(iv)						\
7977203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7978203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
7979203945Sweongyo#define	GET_NEXTIV32(iv)						\
7980203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7981203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
7982203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7983203945Sweongyo	const struct bwn_fwinitvals *iv;
7984203945Sweongyo	uint16_t offset;
7985203945Sweongyo	size_t i;
7986203945Sweongyo	uint8_t bit32;
7987203945Sweongyo
7988203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
7989203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7990203945Sweongyo	iv = ivals;
7991203945Sweongyo	for (i = 0; i < count; i++) {
7992203945Sweongyo		if (array_size < sizeof(iv->offset_size))
7993203945Sweongyo			goto fail;
7994203945Sweongyo		array_size -= sizeof(iv->offset_size);
7995203945Sweongyo		offset = be16toh(iv->offset_size);
7996203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
7997203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
7998203945Sweongyo		if (offset >= 0x1000)
7999203945Sweongyo			goto fail;
8000203945Sweongyo		if (bit32) {
8001203945Sweongyo			if (array_size < sizeof(iv->data.d32))
8002203945Sweongyo				goto fail;
8003203945Sweongyo			array_size -= sizeof(iv->data.d32);
8004203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
8005203945Sweongyo			iv = GET_NEXTIV32(iv);
8006203945Sweongyo		} else {
8007203945Sweongyo
8008203945Sweongyo			if (array_size < sizeof(iv->data.d16))
8009203945Sweongyo				goto fail;
8010203945Sweongyo			array_size -= sizeof(iv->data.d16);
8011203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
8012203945Sweongyo
8013203945Sweongyo			iv = GET_NEXTIV16(iv);
8014203945Sweongyo		}
8015203945Sweongyo	}
8016203945Sweongyo	if (array_size != 0)
8017203945Sweongyo		goto fail;
8018203945Sweongyo	return (0);
8019203945Sweongyofail:
8020203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
8021203945Sweongyo	return (EPROTO);
8022203945Sweongyo#undef GET_NEXTIV16
8023203945Sweongyo#undef GET_NEXTIV32
8024203945Sweongyo}
8025203945Sweongyo
8026203945Sweongyostatic int
8027203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
8028203945Sweongyo{
8029203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
8030203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8031203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8032203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
8033203945Sweongyo	uint16_t channelcookie, savedcookie;
8034203945Sweongyo	int error;
8035203945Sweongyo
8036203945Sweongyo	if (chan == 0xffff)
8037203945Sweongyo		chan = phy->get_default_chan(mac);
8038203945Sweongyo
8039203945Sweongyo	channelcookie = chan;
8040203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
8041203945Sweongyo		channelcookie |= 0x100;
8042203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
8043203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
8044203945Sweongyo	error = phy->switch_channel(mac, chan);
8045203945Sweongyo	if (error)
8046203945Sweongyo		goto fail;
8047203945Sweongyo
8048203945Sweongyo	mac->mac_phy.chan = chan;
8049203945Sweongyo	DELAY(8000);
8050203945Sweongyo	return (0);
8051203945Sweongyofail:
8052203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
8053203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
8054203945Sweongyo	return (error);
8055203945Sweongyo}
8056203945Sweongyo
8057203945Sweongyostatic uint16_t
8058203945Sweongyobwn_ant2phy(int antenna)
8059203945Sweongyo{
8060203945Sweongyo
8061203945Sweongyo	switch (antenna) {
8062203945Sweongyo	case BWN_ANT0:
8063203945Sweongyo		return (BWN_TX_PHY_ANT0);
8064203945Sweongyo	case BWN_ANT1:
8065203945Sweongyo		return (BWN_TX_PHY_ANT1);
8066203945Sweongyo	case BWN_ANT2:
8067203945Sweongyo		return (BWN_TX_PHY_ANT2);
8068203945Sweongyo	case BWN_ANT3:
8069203945Sweongyo		return (BWN_TX_PHY_ANT3);
8070203945Sweongyo	case BWN_ANTAUTO:
8071203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
8072203945Sweongyo	}
8073203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8074203945Sweongyo	return (0);
8075203945Sweongyo}
8076203945Sweongyo
8077203945Sweongyostatic void
8078203945Sweongyobwn_wme_load(struct bwn_mac *mac)
8079203945Sweongyo{
8080203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8081203945Sweongyo	int i;
8082203945Sweongyo
8083203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
8084203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8085203945Sweongyo
8086203945Sweongyo	bwn_mac_suspend(mac);
8087203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
8088203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
8089203945Sweongyo		    bwn_wme_shm_offsets[i]);
8090203945Sweongyo	bwn_mac_enable(mac);
8091203945Sweongyo}
8092203945Sweongyo
8093203945Sweongyostatic void
8094203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
8095203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
8096203945Sweongyo{
8097203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
8098203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8099203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
8100203945Sweongyo	int slot, tmp;
8101203945Sweongyo	unsigned int i;
8102203945Sweongyo
8103203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
8104203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8105203945Sweongyo
8106203945Sweongyo	memset(&params, 0, sizeof(params));
8107203945Sweongyo
8108203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
8109203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
8110203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
8111203945Sweongyo
8112203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
8113203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8114203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
8115203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8116203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
8117203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
8118203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
8119203945Sweongyo
8120203945Sweongyo	for (i = 0; i < N(params); i++) {
8121203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
8122203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
8123203945Sweongyo			    shm_offset + (i * 2));
8124203945Sweongyo			tmp |= 0x100;
8125203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8126203945Sweongyo			    tmp);
8127203945Sweongyo		} else {
8128203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8129203945Sweongyo			    params[i]);
8130203945Sweongyo		}
8131203945Sweongyo	}
8132203945Sweongyo}
8133203945Sweongyo
8134203945Sweongyostatic void
8135203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
8136203945Sweongyo{
8137203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8138203945Sweongyo	uint32_t tmp;
8139203945Sweongyo	int i;
8140203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
8141203945Sweongyo
8142203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
8143203945Sweongyo	memcpy(mac_bssid, sc->sc_macaddr, IEEE80211_ADDR_LEN);
8144203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
8145203945Sweongyo	    IEEE80211_ADDR_LEN);
8146203945Sweongyo
8147203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
8148203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
8149203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
8150203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
8151203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
8152203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
8153203945Sweongyo	}
8154203945Sweongyo}
8155203945Sweongyo
8156203945Sweongyostatic void
8157203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
8158203945Sweongyo    const uint8_t *macaddr)
8159203945Sweongyo{
8160203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
8161203945Sweongyo	uint16_t data;
8162203945Sweongyo
8163203945Sweongyo	if (!mac)
8164203945Sweongyo		macaddr = zero;
8165203945Sweongyo
8166203945Sweongyo	offset |= 0x0020;
8167203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
8168203945Sweongyo
8169203945Sweongyo	data = macaddr[0];
8170203945Sweongyo	data |= macaddr[1] << 8;
8171203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8172203945Sweongyo	data = macaddr[2];
8173203945Sweongyo	data |= macaddr[3] << 8;
8174203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8175203945Sweongyo	data = macaddr[4];
8176203945Sweongyo	data |= macaddr[5] << 8;
8177203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8178203945Sweongyo}
8179203945Sweongyo
8180203945Sweongyostatic void
8181203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8182203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
8183203945Sweongyo{
8184203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
8185203945Sweongyo	uint8_t per_sta_keys_start = 8;
8186203945Sweongyo
8187203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8188203945Sweongyo		per_sta_keys_start = 4;
8189203945Sweongyo
8190203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
8191203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8192203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
8193203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8194203945Sweongyo
8195203945Sweongyo	if (index >= per_sta_keys_start)
8196203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
8197203945Sweongyo	if (key)
8198203945Sweongyo		memcpy(buf, key, key_len);
8199203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
8200203945Sweongyo	if (index >= per_sta_keys_start)
8201203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
8202203945Sweongyo
8203203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
8204203945Sweongyo}
8205203945Sweongyo
8206203945Sweongyostatic void
8207203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
8208203945Sweongyo{
8209203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
8210203945Sweongyo	uint8_t start = 8;
8211203945Sweongyo
8212203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8213203945Sweongyo		start = 4;
8214203945Sweongyo
8215203945Sweongyo	KASSERT(index >= start,
8216203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8217203945Sweongyo	index -= start;
8218203945Sweongyo
8219203945Sweongyo	if (addr) {
8220203945Sweongyo		addrtmp[0] = addr[0];
8221203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
8222203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
8223203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
8224203945Sweongyo		addrtmp[1] = addr[4];
8225203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
8226203945Sweongyo	}
8227203945Sweongyo
8228203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 5) {
8229203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
8230203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
8231203945Sweongyo	} else {
8232203945Sweongyo		if (index >= 8) {
8233203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
8234203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
8235203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
8236203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
8237203945Sweongyo		}
8238203945Sweongyo	}
8239203945Sweongyo}
8240203945Sweongyo
8241203945Sweongyostatic void
8242203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8243203945Sweongyo    const uint8_t *key)
8244203945Sweongyo{
8245203945Sweongyo	unsigned int i;
8246203945Sweongyo	uint32_t offset;
8247203945Sweongyo	uint16_t kidx, value;
8248203945Sweongyo
8249203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
8250203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
8251203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
8252203945Sweongyo
8253203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
8254203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
8255203945Sweongyo		value = key[i];
8256203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
8257203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
8258203945Sweongyo	}
8259203945Sweongyo}
8260203945Sweongyo
8261203945Sweongyostatic void
8262203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
8263203945Sweongyo{
8264203945Sweongyo
8265203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8266203945Sweongyo	if (mac->mac_phy.exit != NULL)
8267203945Sweongyo		mac->mac_phy.exit(mac);
8268203945Sweongyo}
8269203945Sweongyo
8270203945Sweongyostatic void
8271203945Sweongyobwn_dma_free(struct bwn_mac *mac)
8272203945Sweongyo{
8273203945Sweongyo	struct bwn_dma *dma;
8274203945Sweongyo
8275203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
8276203945Sweongyo		return;
8277203945Sweongyo	dma = &mac->mac_method.dma;
8278203945Sweongyo
8279203945Sweongyo	bwn_dma_ringfree(&dma->rx);
8280203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
8281203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
8282203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
8283203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
8284203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
8285203945Sweongyo}
8286203945Sweongyo
8287203945Sweongyostatic void
8288203945Sweongyobwn_core_stop(struct bwn_mac *mac)
8289203945Sweongyo{
8290203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8291203945Sweongyo
8292203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8293203945Sweongyo
8294203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8295203945Sweongyo		return;
8296203945Sweongyo
8297203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
8298203945Sweongyo	callout_stop(&sc->sc_task_ch);
8299203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
8300203945Sweongyo	sc->sc_watchdog_timer = 0;
8301203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8302203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
8303203945Sweongyo	bwn_mac_suspend(mac);
8304203945Sweongyo
8305203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
8306203945Sweongyo}
8307203945Sweongyo
8308203945Sweongyostatic int
8309203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
8310203945Sweongyo{
8311203945Sweongyo	struct bwn_mac *up_dev = NULL;
8312203945Sweongyo	struct bwn_mac *down_dev;
8313203945Sweongyo	struct bwn_mac *mac;
8314203945Sweongyo	int err, status;
8315203945Sweongyo	uint8_t gmode;
8316203945Sweongyo
8317203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8318203945Sweongyo
8319203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
8320203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
8321203945Sweongyo		    mac->mac_phy.supports_2ghz) {
8322203945Sweongyo			up_dev = mac;
8323203945Sweongyo			gmode = 1;
8324203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
8325203945Sweongyo		    mac->mac_phy.supports_5ghz) {
8326203945Sweongyo			up_dev = mac;
8327203945Sweongyo			gmode = 0;
8328203945Sweongyo		} else {
8329203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8330203945Sweongyo			return (EINVAL);
8331203945Sweongyo		}
8332203945Sweongyo		if (up_dev != NULL)
8333203945Sweongyo			break;
8334203945Sweongyo	}
8335203945Sweongyo	if (up_dev == NULL) {
8336203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
8337203945Sweongyo		return (ENODEV);
8338203945Sweongyo	}
8339203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
8340203945Sweongyo		return (0);
8341203945Sweongyo
8342203945Sweongyo	device_printf(sc->sc_dev, "switching to %s-GHz band\n",
8343203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8344203945Sweongyo
8345203945Sweongyo	down_dev = sc->sc_curmac;;
8346203945Sweongyo	status = down_dev->mac_status;
8347203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8348203945Sweongyo		bwn_core_stop(down_dev);
8349203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
8350203945Sweongyo		bwn_core_exit(down_dev);
8351203945Sweongyo
8352203945Sweongyo	if (down_dev != up_dev)
8353203945Sweongyo		bwn_phy_reset(down_dev);
8354203945Sweongyo
8355203945Sweongyo	up_dev->mac_phy.gmode = gmode;
8356203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
8357203945Sweongyo		err = bwn_core_init(up_dev);
8358203945Sweongyo		if (err) {
8359203945Sweongyo			device_printf(sc->sc_dev,
8360203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
8361203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8362203945Sweongyo			goto fail;
8363203945Sweongyo		}
8364203945Sweongyo	}
8365203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8366203945Sweongyo		bwn_core_start(up_dev);
8367203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
8368203945Sweongyo	sc->sc_curmac = up_dev;
8369203945Sweongyo
8370203945Sweongyo	return (0);
8371203945Sweongyofail:
8372203945Sweongyo	sc->sc_curmac = NULL;
8373203945Sweongyo	return (err);
8374203945Sweongyo}
8375203945Sweongyo
8376203945Sweongyostatic void
8377203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
8378203945Sweongyo{
8379203945Sweongyo
8380203945Sweongyo	bwn_mac_suspend(mac);
8381203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
8382203945Sweongyo	mac->mac_phy.rf_on = 1;
8383203945Sweongyo	bwn_mac_enable(mac);
8384203945Sweongyo}
8385203945Sweongyo
8386203945Sweongyostatic void
8387203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
8388203945Sweongyo{
8389203945Sweongyo
8390203945Sweongyo	bwn_mac_suspend(mac);
8391203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8392203945Sweongyo	mac->mac_phy.rf_on = 0;
8393203945Sweongyo	bwn_mac_enable(mac);
8394203945Sweongyo}
8395203945Sweongyo
8396203945Sweongyostatic void
8397203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
8398203945Sweongyo{
8399203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
8400203945Sweongyo
8401203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW,
8402203945Sweongyo	    ((siba_read_4(sd, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
8403203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
8404203945Sweongyo	DELAY(1000);
8405203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW,
8406203945Sweongyo	    (siba_read_4(sd, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC) |
8407203945Sweongyo	    BWN_TGSLOW_PHYRESET);
8408203945Sweongyo	DELAY(1000);
8409203945Sweongyo}
8410203945Sweongyo
8411203945Sweongyostatic int
8412203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
8413203945Sweongyo{
8414203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
8415203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
8416203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
8417203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
8418203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
8419203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
8420203945Sweongyo	int error;
8421203945Sweongyo
8422203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
8423203945Sweongyo	    ieee80211_state_name[vap->iv_state],
8424203945Sweongyo	    ieee80211_state_name[nstate]);
8425203945Sweongyo
8426203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
8427203945Sweongyo	if (error != 0)
8428203945Sweongyo		return (error);
8429203945Sweongyo
8430203945Sweongyo	BWN_LOCK(sc);
8431203945Sweongyo
8432203945Sweongyo	bwn_led_newstate(mac, nstate);
8433203945Sweongyo
8434203945Sweongyo	/*
8435203945Sweongyo	 * Clear the BSSID when we stop a STA
8436203945Sweongyo	 */
8437203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
8438203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
8439203945Sweongyo			/*
8440203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
8441203945Sweongyo			 * the same AP, this will reinialize things
8442203945Sweongyo			 * correctly...
8443203945Sweongyo			 */
8444203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
8445203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
8446203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
8447203945Sweongyo				bwn_set_macaddr(mac);
8448203945Sweongyo			}
8449203945Sweongyo		}
8450203945Sweongyo	}
8451203945Sweongyo
8452204436Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR ||
8453204436Sweongyo	    vap->iv_opmode == IEEE80211_M_AHDEMO) {
8454203945Sweongyo		/* XXX nothing to do? */
8455203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
8456203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
8457203945Sweongyo		memcpy(sc->sc_macaddr, IF_LLADDR(ifp), IEEE80211_ADDR_LEN);
8458203945Sweongyo		bwn_set_opmode(mac);
8459203945Sweongyo		bwn_set_pretbtt(mac);
8460203945Sweongyo		bwn_spu_setdelay(mac, 0);
8461203945Sweongyo		bwn_set_macaddr(mac);
8462203945Sweongyo	}
8463203945Sweongyo
8464203945Sweongyo	BWN_UNLOCK(sc);
8465203945Sweongyo
8466203945Sweongyo	return (error);
8467203945Sweongyo}
8468203945Sweongyo
8469203945Sweongyostatic void
8470203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
8471203945Sweongyo{
8472203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8473203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8474203945Sweongyo	uint16_t pretbtt;
8475203945Sweongyo
8476203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8477203945Sweongyo		pretbtt = 2;
8478203945Sweongyo	else
8479203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
8480203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
8481203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
8482203945Sweongyo}
8483203945Sweongyo
8484203945Sweongyostatic int
8485203945Sweongyobwn_intr(void *arg)
8486203945Sweongyo{
8487203945Sweongyo	struct bwn_mac *mac = arg;
8488203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8489203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
8490203945Sweongyo	uint32_t reason;
8491203945Sweongyo
8492203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED || siba->siba_invalid)
8493203945Sweongyo		return (FILTER_STRAY);
8494203945Sweongyo
8495203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
8496203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
8497203945Sweongyo		return (FILTER_STRAY);
8498203945Sweongyo	reason &= mac->mac_intr_mask;
8499203945Sweongyo	if (reason == 0)
8500203945Sweongyo		return (FILTER_HANDLED);
8501203945Sweongyo
8502203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
8503203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
8504203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
8505203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
8506203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
8507203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
8508203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
8509203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
8510203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
8511203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
8512203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
8513203945Sweongyo
8514203945Sweongyo	/* Disable interrupts. */
8515203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8516203945Sweongyo
8517203945Sweongyo	mac->mac_reason_intr = reason;
8518203945Sweongyo
8519203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8520203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8521203945Sweongyo
8522203945Sweongyo	taskqueue_enqueue_fast(sc->sc_tq, &mac->mac_intrtask);
8523203945Sweongyo	return (FILTER_HANDLED);
8524203945Sweongyo}
8525203945Sweongyo
8526203945Sweongyostatic void
8527203945Sweongyobwn_intrtask(void *arg, int npending)
8528203945Sweongyo{
8529203945Sweongyo	struct bwn_mac *mac = arg;
8530203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8531203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8532203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
8533203945Sweongyo	uint32_t merged = 0;
8534203945Sweongyo	int i, tx = 0, rx = 0;
8535203945Sweongyo
8536203945Sweongyo	BWN_LOCK(sc);
8537203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED || siba->siba_invalid) {
8538203945Sweongyo		BWN_UNLOCK(sc);
8539203945Sweongyo		return;
8540203945Sweongyo	}
8541203945Sweongyo
8542203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
8543203945Sweongyo		merged |= mac->mac_reason[i];
8544203945Sweongyo
8545203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
8546203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
8547203945Sweongyo
8548203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
8549203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
8550203945Sweongyo		mac->mac_phy.txerrors--;
8551203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
8552203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
8553203945Sweongyo			bwn_restart(mac, "PHY TX errors");
8554203945Sweongyo		}
8555203945Sweongyo	}
8556203945Sweongyo
8557203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
8558203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
8559203945Sweongyo			device_printf(sc->sc_dev,
8560203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
8561203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8562203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8563203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8564203945Sweongyo			bwn_restart(mac, "DMA error");
8565203945Sweongyo			BWN_UNLOCK(sc);
8566203945Sweongyo			return;
8567203945Sweongyo		}
8568203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
8569203945Sweongyo			device_printf(sc->sc_dev,
8570203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
8571203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8572203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8573203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8574203945Sweongyo		}
8575203945Sweongyo	}
8576203945Sweongyo
8577203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
8578203945Sweongyo		bwn_intr_ucode_debug(mac);
8579203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
8580203945Sweongyo		bwn_intr_tbtt_indication(mac);
8581203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
8582203945Sweongyo		bwn_intr_atim_end(mac);
8583203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
8584203945Sweongyo		bwn_intr_beacon(mac);
8585203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
8586203945Sweongyo		bwn_intr_pmq(mac);
8587203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
8588203945Sweongyo		bwn_intr_noise(mac);
8589203945Sweongyo
8590203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
8591203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
8592203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
8593203945Sweongyo			rx = 1;
8594203945Sweongyo		}
8595203945Sweongyo	} else
8596203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
8597203945Sweongyo
8598203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8599203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8600203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8601203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8602203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8603203945Sweongyo
8604203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
8605203945Sweongyo		bwn_intr_txeof(mac);
8606203945Sweongyo		tx = 1;
8607203945Sweongyo	}
8608203945Sweongyo
8609203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
8610203945Sweongyo
8611203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
8612203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
8613203945Sweongyo
8614203945Sweongyo		if (tx && rx) {
8615203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
8616203945Sweongyo				evt = BWN_LED_EVENT_RX;
8617203945Sweongyo			else
8618203945Sweongyo				evt = BWN_LED_EVENT_TX;
8619203945Sweongyo		} else if (tx) {
8620203945Sweongyo			evt = BWN_LED_EVENT_TX;
8621203945Sweongyo		} else if (rx) {
8622203945Sweongyo			evt = BWN_LED_EVENT_RX;
8623203945Sweongyo		} else if (rx == 0) {
8624203945Sweongyo			evt = BWN_LED_EVENT_POLL;
8625203945Sweongyo		}
8626203945Sweongyo
8627203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
8628203945Sweongyo			bwn_led_event(mac, evt);
8629203945Sweongyo       }
8630203945Sweongyo
8631203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
8632203945Sweongyo		if (!IFQ_IS_EMPTY(&ifp->if_snd))
8633203945Sweongyo			bwn_start_locked(ifp);
8634203945Sweongyo	}
8635203945Sweongyo
8636203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8637203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8638203945Sweongyo
8639203945Sweongyo	BWN_UNLOCK(sc);
8640203945Sweongyo}
8641203945Sweongyo
8642203945Sweongyostatic void
8643203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
8644203945Sweongyo{
8645203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8646203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8647203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
8648203945Sweongyo
8649203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
8650203945Sweongyo		return;
8651203945Sweongyo
8652203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
8653203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
8654203945Sweongyo}
8655203945Sweongyo
8656203945Sweongyostatic void
8657203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
8658203945Sweongyo{
8659203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8660203945Sweongyo	uint16_t reason;
8661203945Sweongyo
8662203945Sweongyo	if (mac->mac_fw.opensource == 0)
8663203945Sweongyo		return;
8664203945Sweongyo
8665203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
8666203945Sweongyo	switch (reason) {
8667203945Sweongyo	case BWN_DEBUGINTR_PANIC:
8668203945Sweongyo		bwn_handle_fwpanic(mac);
8669203945Sweongyo		break;
8670203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
8671203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
8672203945Sweongyo		break;
8673203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
8674203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
8675203945Sweongyo		break;
8676203945Sweongyo	case BWN_DEBUGINTR_MARKER:
8677203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
8678203945Sweongyo		break;
8679203945Sweongyo	default:
8680203945Sweongyo		device_printf(sc->sc_dev,
8681203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
8682203945Sweongyo	}
8683203945Sweongyo
8684203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
8685203945Sweongyo	    BWN_DEBUGINTR_ACK);
8686203945Sweongyo}
8687203945Sweongyo
8688203945Sweongyostatic void
8689203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
8690203945Sweongyo{
8691203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8692203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8693203945Sweongyo
8694203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
8695203945Sweongyo		bwn_psctl(mac, 0);
8696203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8697203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
8698203945Sweongyo}
8699203945Sweongyo
8700203945Sweongyostatic void
8701203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
8702203945Sweongyo{
8703203945Sweongyo
8704203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
8705203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
8706203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
8707203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
8708203945Sweongyo	}
8709203945Sweongyo}
8710203945Sweongyo
8711203945Sweongyostatic void
8712203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
8713203945Sweongyo{
8714203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8715203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8716203945Sweongyo	uint32_t cmd, beacon0, beacon1;
8717203945Sweongyo
8718203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
8719203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
8720203945Sweongyo		return;
8721203945Sweongyo
8722203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
8723203945Sweongyo
8724203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
8725203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
8726203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
8727203945Sweongyo
8728203945Sweongyo	if (beacon0 && beacon1) {
8729203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
8730203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
8731203945Sweongyo		return;
8732203945Sweongyo	}
8733203945Sweongyo
8734203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
8735203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
8736203945Sweongyo		bwn_load_beacon0(mac);
8737203945Sweongyo		bwn_load_beacon1(mac);
8738203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
8739203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
8740203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8741203945Sweongyo	} else {
8742203945Sweongyo		if (!beacon0) {
8743203945Sweongyo			bwn_load_beacon0(mac);
8744203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8745203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
8746203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8747203945Sweongyo		} else if (!beacon1) {
8748203945Sweongyo			bwn_load_beacon1(mac);
8749203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8750203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
8751203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8752203945Sweongyo		}
8753203945Sweongyo	}
8754203945Sweongyo}
8755203945Sweongyo
8756203945Sweongyostatic void
8757203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
8758203945Sweongyo{
8759203945Sweongyo	uint32_t tmp;
8760203945Sweongyo
8761203945Sweongyo	while (1) {
8762203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
8763203945Sweongyo		if (!(tmp & 0x00000008))
8764203945Sweongyo			break;
8765203945Sweongyo	}
8766203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
8767203945Sweongyo}
8768203945Sweongyo
8769203945Sweongyostatic void
8770203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
8771203945Sweongyo{
8772203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
8773203945Sweongyo	uint16_t tmp;
8774203945Sweongyo	uint8_t noise[4];
8775203945Sweongyo	uint8_t i, j;
8776203945Sweongyo	int32_t average;
8777203945Sweongyo
8778203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
8779203945Sweongyo		return;
8780203945Sweongyo
8781203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
8782203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
8783203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
8784203945Sweongyo	    noise[3] == 0x7f)
8785203945Sweongyo		goto new;
8786203945Sweongyo
8787203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
8788203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8789203945Sweongyo	i = mac->mac_noise.noi_nsamples;
8790203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
8791203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
8792203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
8793203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
8794203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
8795203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
8796203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
8797203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
8798203945Sweongyo	mac->mac_noise.noi_nsamples++;
8799203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
8800203945Sweongyo		average = 0;
8801203945Sweongyo		for (i = 0; i < 8; i++) {
8802203945Sweongyo			for (j = 0; j < 4; j++)
8803203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
8804203945Sweongyo		}
8805203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
8806203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
8807203945Sweongyo		if (tmp >= 8)
8808203945Sweongyo			average += 2;
8809203945Sweongyo		else
8810203945Sweongyo			average -= 25;
8811203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
8812203945Sweongyo
8813203945Sweongyo		mac->mac_stats.link_noise = average;
8814203945Sweongyo		mac->mac_noise.noi_running = 0;
8815203945Sweongyo		return;
8816203945Sweongyo	}
8817203945Sweongyonew:
8818203945Sweongyo	bwn_noise_gensample(mac);
8819203945Sweongyo}
8820203945Sweongyo
8821203945Sweongyostatic int
8822203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
8823203945Sweongyo{
8824203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
8825203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8826203945Sweongyo	unsigned int i;
8827203945Sweongyo
8828203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8829203945Sweongyo
8830203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8831203945Sweongyo		return (0);
8832203945Sweongyo
8833203945Sweongyo	for (i = 0; i < 5000; i++) {
8834203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
8835203945Sweongyo			break;
8836203945Sweongyo	}
8837203945Sweongyo	if (i >= 5000)
8838203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
8839203945Sweongyo	return ((i > 0) ? 1 : 0);
8840203945Sweongyo}
8841203945Sweongyo
8842203945Sweongyostatic void
8843203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
8844203945Sweongyo{
8845203945Sweongyo	int slot, curslot;
8846203945Sweongyo
8847203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
8848203945Sweongyo	curslot = dr->get_curslot(dr);
8849203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
8850203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8851203945Sweongyo
8852203945Sweongyo	slot = dr->dr_curslot;
8853203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
8854203945Sweongyo		bwn_dma_rxeof(dr, &slot);
8855203945Sweongyo
8856203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
8857203945Sweongyo	    BUS_DMASYNC_PREWRITE);
8858203945Sweongyo
8859203945Sweongyo	dr->set_curslot(dr, slot);
8860203945Sweongyo	dr->dr_curslot = slot;
8861203945Sweongyo}
8862203945Sweongyo
8863203945Sweongyostatic void
8864203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
8865203945Sweongyo{
8866203945Sweongyo	struct bwn_txstatus stat;
8867203945Sweongyo	uint32_t stat0, stat1;
8868203945Sweongyo	uint16_t tmp;
8869203945Sweongyo
8870203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8871203945Sweongyo
8872203945Sweongyo	while (1) {
8873203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
8874203945Sweongyo		if (!(stat0 & 0x00000001))
8875203945Sweongyo			break;
8876203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
8877203945Sweongyo
8878203945Sweongyo		stat.cookie = (stat0 >> 16);
8879203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
8880203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
8881203945Sweongyo		tmp = (stat0 & 0x0000ffff);
8882203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
8883203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
8884203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
8885203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
8886203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
8887203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
8888203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
8889203945Sweongyo
8890203945Sweongyo		bwn_handle_txeof(mac, &stat);
8891203945Sweongyo	}
8892203945Sweongyo}
8893203945Sweongyo
8894203945Sweongyostatic void
8895203945Sweongyobwn_hwreset(void *arg, int npending)
8896203945Sweongyo{
8897203945Sweongyo	struct bwn_mac *mac = arg;
8898203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8899203945Sweongyo	int error = 0;
8900203945Sweongyo	int prev_status;
8901203945Sweongyo
8902203945Sweongyo	BWN_LOCK(sc);
8903203945Sweongyo
8904203945Sweongyo	prev_status = mac->mac_status;
8905203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8906203945Sweongyo		bwn_core_stop(mac);
8907203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
8908203945Sweongyo		bwn_core_exit(mac);
8909203945Sweongyo
8910203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
8911203945Sweongyo		error = bwn_core_init(mac);
8912203945Sweongyo		if (error)
8913203945Sweongyo			goto out;
8914203945Sweongyo	}
8915203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8916203945Sweongyo		bwn_core_start(mac);
8917203945Sweongyoout:
8918203945Sweongyo	if (error) {
8919203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
8920203945Sweongyo		sc->sc_curmac = NULL;
8921203945Sweongyo	}
8922203945Sweongyo	BWN_UNLOCK(sc);
8923203945Sweongyo}
8924203945Sweongyo
8925203945Sweongyostatic void
8926203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
8927203945Sweongyo{
8928203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8929203945Sweongyo	uint16_t reason;
8930203945Sweongyo
8931203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
8932203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
8933203945Sweongyo
8934203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
8935203945Sweongyo		bwn_restart(mac, "ucode panic");
8936203945Sweongyo}
8937203945Sweongyo
8938203945Sweongyostatic void
8939203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
8940203945Sweongyo{
8941203945Sweongyo
8942203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8943203945Sweongyo}
8944203945Sweongyo
8945203945Sweongyostatic void
8946203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
8947203945Sweongyo{
8948203945Sweongyo
8949203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8950203945Sweongyo}
8951203945Sweongyo
8952203945Sweongyostatic uint32_t
8953203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
8954203945Sweongyo{
8955203945Sweongyo	uint32_t val = 0;
8956203945Sweongyo
8957203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
8958203945Sweongyo	val <<= 16;
8959203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
8960203945Sweongyo
8961203945Sweongyo	return (val);
8962203945Sweongyo}
8963203945Sweongyo
8964203945Sweongyostatic void
8965203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
8966203945Sweongyo{
8967203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
8968203945Sweongyo
8969203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
8970203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
8971203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
8972203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
8973203945Sweongyo}
8974203945Sweongyo
8975203945Sweongyostatic int
8976203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
8977203945Sweongyo{
8978204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8979203945Sweongyo
8980203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
8981203945Sweongyo}
8982203945Sweongyo
8983203945Sweongyostatic int
8984203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
8985203945Sweongyo{
8986204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8987203945Sweongyo
8988203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
8989203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8990203945Sweongyo	if (slot == dr->dr_numslots - 1)
8991203945Sweongyo		return (0);
8992203945Sweongyo	return (slot + 1);
8993203945Sweongyo}
8994203945Sweongyo
8995203945Sweongyostatic void
8996203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
8997203945Sweongyo{
8998203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
8999203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9000203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9001203945Sweongyo	struct bwn_dmadesc_generic *desc;
9002203945Sweongyo	struct bwn_dmadesc_meta *meta;
9003203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
9004203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9005203945Sweongyo	struct mbuf *m;
9006203945Sweongyo	uint32_t macstat;
9007203945Sweongyo	int32_t tmp;
9008203945Sweongyo	int cnt = 0;
9009203945Sweongyo	uint16_t len;
9010203945Sweongyo
9011203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
9012203945Sweongyo
9013203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
9014203945Sweongyo	m = meta->mt_m;
9015203945Sweongyo
9016203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
9017203945Sweongyo		ifp->if_ierrors++;
9018203945Sweongyo		return;
9019203945Sweongyo	}
9020203945Sweongyo
9021203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
9022203945Sweongyo	len = le16toh(rxhdr->frame_len);
9023203945Sweongyo	if (len <= 0) {
9024203945Sweongyo		ifp->if_ierrors++;
9025203945Sweongyo		return;
9026203945Sweongyo	}
9027203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
9028203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
9029203945Sweongyo		bwn_dma_set_redzone(dr, m);
9030203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9031203945Sweongyo		    BUS_DMASYNC_PREWRITE);
9032203945Sweongyo		return;
9033203945Sweongyo	}
9034203945Sweongyo	if (len > dr->dr_rx_bufsize) {
9035203945Sweongyo		tmp = len;
9036203945Sweongyo		while (1) {
9037203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
9038203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
9039203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9040203945Sweongyo			    BUS_DMASYNC_PREWRITE);
9041203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
9042203945Sweongyo			cnt++;
9043203945Sweongyo			tmp -= dr->dr_rx_bufsize;
9044203945Sweongyo			if (tmp <= 0)
9045203945Sweongyo				break;
9046203945Sweongyo		}
9047203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
9048203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
9049203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
9050203945Sweongyo		return;
9051203945Sweongyo	}
9052203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9053203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9054203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9055203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
9056203945Sweongyo			return;
9057203945Sweongyo		}
9058203945Sweongyo	}
9059203945Sweongyo
9060203945Sweongyo	m->m_pkthdr.rcvif = ifp;
9061203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
9062203945Sweongyo	m_adj(m, dr->dr_frameoffset);
9063203945Sweongyo
9064203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
9065203945Sweongyo}
9066203945Sweongyo
9067203945Sweongyostatic void
9068203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
9069203945Sweongyo{
9070203945Sweongyo	struct bwn_dma_ring *dr;
9071203945Sweongyo	struct bwn_dmadesc_generic *desc;
9072203945Sweongyo	struct bwn_dmadesc_meta *meta;
9073203945Sweongyo	struct bwn_node *bn;
9074203945Sweongyo	struct bwn_pio_txqueue *tq;
9075203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9076203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9077204257Sweongyo	struct bwn_stats *stats = &mac->mac_stats;
9078203945Sweongyo	struct ieee80211_node *ni;
9079203945Sweongyo	int slot;
9080203945Sweongyo
9081203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
9082203945Sweongyo
9083203945Sweongyo	if (status->im)
9084203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
9085203945Sweongyo	if (status->ampdu)
9086203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
9087203945Sweongyo	if (status->rtscnt) {
9088203945Sweongyo		if (status->rtscnt == 0xf)
9089204257Sweongyo			stats->rtsfail++;
9090203945Sweongyo		else
9091204257Sweongyo			stats->rts++;
9092203945Sweongyo	}
9093203945Sweongyo
9094203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
9095203945Sweongyo		if (status->ack) {
9096203945Sweongyo			dr = bwn_dma_parse_cookie(mac, status,
9097203945Sweongyo			    status->cookie, &slot);
9098203945Sweongyo			if (dr == NULL) {
9099203945Sweongyo				device_printf(sc->sc_dev,
9100203945Sweongyo				    "failed to parse cookie\n");
9101203945Sweongyo				return;
9102203945Sweongyo			}
9103203945Sweongyo			while (1) {
9104203945Sweongyo				dr->getdesc(dr, slot, &desc, &meta);
9105203945Sweongyo				if (meta->mt_islast) {
9106203945Sweongyo					ni = meta->mt_ni;
9107203945Sweongyo					bn = (struct bwn_node *)ni;
9108203945Sweongyo					ieee80211_amrr_tx_complete(&bn->bn_amn,
9109203945Sweongyo					    status->ack, 0);
9110203945Sweongyo					break;
9111203945Sweongyo				}
9112203945Sweongyo				slot = bwn_dma_nextslot(dr, slot);
9113203945Sweongyo			}
9114203945Sweongyo		}
9115203945Sweongyo		bwn_dma_handle_txeof(mac, status);
9116203945Sweongyo	} else {
9117203945Sweongyo		if (status->ack) {
9118203945Sweongyo			tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9119203945Sweongyo			if (tq == NULL) {
9120203945Sweongyo				device_printf(sc->sc_dev,
9121203945Sweongyo				    "failed to parse cookie\n");
9122203945Sweongyo				return;
9123203945Sweongyo			}
9124203945Sweongyo			ni = tp->tp_ni;
9125203945Sweongyo			bn = (struct bwn_node *)ni;
9126203945Sweongyo			ieee80211_amrr_tx_complete(&bn->bn_amn, status->ack, 0);
9127203945Sweongyo		}
9128203945Sweongyo		bwn_pio_handle_txeof(mac, status);
9129203945Sweongyo	}
9130203945Sweongyo
9131203945Sweongyo	bwn_phy_txpower_check(mac, 0);
9132203945Sweongyo}
9133203945Sweongyo
9134203945Sweongyostatic uint8_t
9135203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
9136203945Sweongyo{
9137203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
9138203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9139203945Sweongyo	struct bwn_rxhdr4 rxhdr;
9140203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9141203945Sweongyo	struct mbuf *m;
9142203945Sweongyo	uint32_t ctl32, macstat, v32;
9143203945Sweongyo	unsigned int i, padding;
9144203945Sweongyo	uint16_t ctl16, len, v16;
9145203945Sweongyo	unsigned char *mp;
9146203945Sweongyo	char *data;
9147203945Sweongyo
9148203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
9149203945Sweongyo
9150203945Sweongyo	if (prq->prq_rev >= 8) {
9151203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9152203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
9153203945Sweongyo			return (0);
9154203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9155203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
9156203945Sweongyo		for (i = 0; i < 10; i++) {
9157203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9158203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
9159203945Sweongyo				goto ready;
9160203945Sweongyo			DELAY(10);
9161203945Sweongyo		}
9162203945Sweongyo	} else {
9163203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9164203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
9165203945Sweongyo			return (0);
9166203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
9167203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
9168203945Sweongyo		for (i = 0; i < 10; i++) {
9169203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9170203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
9171203945Sweongyo				goto ready;
9172203945Sweongyo			DELAY(10);
9173203945Sweongyo		}
9174203945Sweongyo	}
9175203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
9176203945Sweongyo	return (1);
9177203945Sweongyoready:
9178203945Sweongyo	if (prq->prq_rev >= 8)
9179203945Sweongyo		siba_read_multi_4(mac->mac_sd, &rxhdr, sizeof(rxhdr),
9180203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9181203945Sweongyo	else
9182203945Sweongyo		siba_read_multi_2(mac->mac_sd, &rxhdr, sizeof(rxhdr),
9183203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9184203945Sweongyo	len = le16toh(rxhdr.frame_len);
9185203945Sweongyo	if (len > 0x700) {
9186203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
9187203945Sweongyo		goto error;
9188203945Sweongyo	}
9189203945Sweongyo	if (len == 0) {
9190203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
9191203945Sweongyo		goto error;
9192203945Sweongyo	}
9193203945Sweongyo
9194203945Sweongyo	macstat = le32toh(rxhdr.mac_status);
9195203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9196203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9197203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
9198203945Sweongyo			goto error;
9199203945Sweongyo		}
9200203945Sweongyo	}
9201203945Sweongyo
9202203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9203203945Sweongyo	KASSERT(len + padding <= MCLBYTES, ("too big..\n"));
9204203945Sweongyo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
9205203945Sweongyo	if (m == NULL) {
9206203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
9207203945Sweongyo		goto error;
9208203945Sweongyo	}
9209203945Sweongyo	mp = mtod(m, unsigned char *);
9210203945Sweongyo	if (prq->prq_rev >= 8) {
9211203945Sweongyo		siba_read_multi_4(mac->mac_sd, mp + padding, (len & ~3),
9212203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9213203945Sweongyo		if (len & 3) {
9214203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
9215203945Sweongyo			data = &(mp[len + padding - 1]);
9216203945Sweongyo			switch (len & 3) {
9217203945Sweongyo			case 3:
9218203945Sweongyo				*data = (v32 >> 16);
9219203945Sweongyo				data--;
9220203945Sweongyo			case 2:
9221203945Sweongyo				*data = (v32 >> 8);
9222203945Sweongyo				data--;
9223203945Sweongyo			case 1:
9224203945Sweongyo				*data = v32;
9225203945Sweongyo			}
9226203945Sweongyo		}
9227203945Sweongyo	} else {
9228203945Sweongyo		siba_read_multi_2(mac->mac_sd, mp + padding, (len & ~1),
9229203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9230203945Sweongyo		if (len & 1) {
9231203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
9232203945Sweongyo			mp[len + padding - 1] = v16;
9233203945Sweongyo		}
9234203945Sweongyo	}
9235203945Sweongyo
9236203945Sweongyo	m->m_pkthdr.rcvif = ifp;
9237203945Sweongyo	m->m_len = m->m_pkthdr.len = len + padding;
9238203945Sweongyo
9239203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
9240203945Sweongyo
9241203945Sweongyo	return (1);
9242203945Sweongyoerror:
9243203945Sweongyo	if (prq->prq_rev >= 8)
9244203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9245203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
9246203945Sweongyo	else
9247203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
9248203945Sweongyo	return (1);
9249203945Sweongyo}
9250203945Sweongyo
9251203945Sweongyostatic int
9252203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
9253203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
9254203945Sweongyo{
9255203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
9256203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9257203945Sweongyo	struct bwn_rxhdr4 *hdr;
9258203945Sweongyo	bus_dmamap_t map;
9259203945Sweongyo	bus_addr_t paddr;
9260203945Sweongyo	struct mbuf *m;
9261203945Sweongyo	int error;
9262203945Sweongyo
9263203945Sweongyo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
9264203945Sweongyo	if (m == NULL) {
9265203945Sweongyo		error = ENOBUFS;
9266203945Sweongyo
9267203945Sweongyo		/*
9268203945Sweongyo		 * If the NIC is up and running, we need to:
9269203945Sweongyo		 * - Clear RX buffer's header.
9270203945Sweongyo		 * - Restore RX descriptor settings.
9271203945Sweongyo		 */
9272203945Sweongyo		if (init)
9273203945Sweongyo			return (error);
9274203945Sweongyo		else
9275203945Sweongyo			goto back;
9276203945Sweongyo	}
9277203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
9278203945Sweongyo
9279203945Sweongyo	bwn_dma_set_redzone(dr, m);
9280203945Sweongyo
9281203945Sweongyo	/*
9282203945Sweongyo	 * Try to load RX buf into temporary DMA map
9283203945Sweongyo	 */
9284203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
9285203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
9286203945Sweongyo	if (error) {
9287203945Sweongyo		m_freem(m);
9288203945Sweongyo
9289203945Sweongyo		/*
9290203945Sweongyo		 * See the comment above
9291203945Sweongyo		 */
9292203945Sweongyo		if (init)
9293203945Sweongyo			return (error);
9294203945Sweongyo		else
9295203945Sweongyo			goto back;
9296203945Sweongyo	}
9297203945Sweongyo
9298203945Sweongyo	if (!init)
9299203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
9300203945Sweongyo	meta->mt_m = m;
9301203945Sweongyo	meta->mt_paddr = paddr;
9302203945Sweongyo
9303203945Sweongyo	/*
9304203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
9305203945Sweongyo	 */
9306203945Sweongyo	map = meta->mt_dmap;
9307203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
9308203945Sweongyo	dr->dr_spare_dmap = map;
9309203945Sweongyo
9310203945Sweongyoback:
9311203945Sweongyo	/*
9312203945Sweongyo	 * Clear RX buf header
9313203945Sweongyo	 */
9314203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
9315203945Sweongyo	bzero(hdr, sizeof(*hdr));
9316203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9317203945Sweongyo	    BUS_DMASYNC_PREWRITE);
9318203945Sweongyo
9319203945Sweongyo	/*
9320203945Sweongyo	 * Setup RX buf descriptor
9321203945Sweongyo	 */
9322203945Sweongyo	dr->setdesc(dr, desc, paddr, meta->mt_m->m_len -
9323203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
9324203945Sweongyo	return (error);
9325203945Sweongyo}
9326203945Sweongyo
9327203945Sweongyostatic void
9328203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
9329203945Sweongyo		 bus_size_t mapsz __unused, int error)
9330203945Sweongyo{
9331203945Sweongyo
9332203945Sweongyo	if (!error) {
9333203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
9334203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
9335203945Sweongyo	}
9336203945Sweongyo}
9337203945Sweongyo
9338203945Sweongyostatic int
9339203945Sweongyobwn_hwrate2ieeerate(int rate)
9340203945Sweongyo{
9341203945Sweongyo
9342203945Sweongyo	switch (rate) {
9343203945Sweongyo	case BWN_CCK_RATE_1MB:
9344203945Sweongyo		return (2);
9345203945Sweongyo	case BWN_CCK_RATE_2MB:
9346203945Sweongyo		return (4);
9347203945Sweongyo	case BWN_CCK_RATE_5MB:
9348203945Sweongyo		return (11);
9349203945Sweongyo	case BWN_CCK_RATE_11MB:
9350203945Sweongyo		return (22);
9351203945Sweongyo	case BWN_OFDM_RATE_6MB:
9352203945Sweongyo		return (12);
9353203945Sweongyo	case BWN_OFDM_RATE_9MB:
9354203945Sweongyo		return (18);
9355203945Sweongyo	case BWN_OFDM_RATE_12MB:
9356203945Sweongyo		return (24);
9357203945Sweongyo	case BWN_OFDM_RATE_18MB:
9358203945Sweongyo		return (36);
9359203945Sweongyo	case BWN_OFDM_RATE_24MB:
9360203945Sweongyo		return (48);
9361203945Sweongyo	case BWN_OFDM_RATE_36MB:
9362203945Sweongyo		return (72);
9363203945Sweongyo	case BWN_OFDM_RATE_48MB:
9364203945Sweongyo		return (96);
9365203945Sweongyo	case BWN_OFDM_RATE_54MB:
9366203945Sweongyo		return (108);
9367203945Sweongyo	default:
9368203945Sweongyo		printf("Ooops\n");
9369203945Sweongyo		return (0);
9370203945Sweongyo	}
9371203945Sweongyo}
9372203945Sweongyo
9373203945Sweongyostatic void
9374203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
9375203945Sweongyo{
9376203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
9377203945Sweongyo	struct bwn_plcp6 *plcp;
9378203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9379203945Sweongyo	struct ieee80211_frame_min *wh;
9380203945Sweongyo	struct ieee80211_node *ni;
9381203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9382203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9383203945Sweongyo	uint32_t macstat;
9384204242Simp	int padding, rate, rssi = 0, noise = 0, type;
9385203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
9386203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
9387204242Simp	static int rx_mac_dec_rpt = 0;
9388203945Sweongyo
9389203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9390203945Sweongyo
9391203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
9392203945Sweongyo	phystat3 = le16toh(rxhdr->phy_status3);
9393203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9394203945Sweongyo	chanstat = le16toh(rxhdr->channel);
9395203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
9396203945Sweongyo
9397203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
9398203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
9399203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
9400203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
9401203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
9402203945Sweongyo		goto drop;
9403203945Sweongyo
9404203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9405203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
9406204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9407204081Sweongyo		    m->m_pkthdr.len);
9408203945Sweongyo		goto drop;
9409203945Sweongyo	}
9410203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
9411203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
9412203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
9413204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9414204081Sweongyo		    m->m_pkthdr.len);
9415203945Sweongyo		goto drop;
9416203945Sweongyo	}
9417203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
9418203945Sweongyo
9419204242Simp	if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
9420204081Sweongyo		device_printf(sc->sc_dev,
9421204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
9422204081Sweongyo		    BWN_ISOLDFMT(mac),
9423204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
9424203945Sweongyo
9425203945Sweongyo	/* XXX calculating RSSI & noise & antenna */
9426203945Sweongyo
9427203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
9428203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
9429203945Sweongyo		    phytype == BWN_PHYTYPE_A);
9430203945Sweongyo	else
9431203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
9432203945Sweongyo	if (rate == -1) {
9433203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
9434203945Sweongyo			goto drop;
9435203945Sweongyo	}
9436203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
9437203945Sweongyo
9438203945Sweongyo	/* RX radio tap */
9439203945Sweongyo	if (ieee80211_radiotap_active(ic))
9440203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
9441203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
9442203945Sweongyo
9443203945Sweongyo	rssi = rxhdr->phy.abg.rssi;	/* XXX incorrect RSSI calculation? */
9444203945Sweongyo	noise = mac->mac_stats.link_noise;
9445203945Sweongyo
9446203945Sweongyo	BWN_UNLOCK(sc);
9447203945Sweongyo
9448203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
9449203945Sweongyo	if (ni != NULL) {
9450203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
9451203945Sweongyo		ieee80211_free_node(ni);
9452203945Sweongyo	} else
9453203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
9454203945Sweongyo
9455203945Sweongyo	BWN_LOCK(sc);
9456203945Sweongyo	return;
9457203945Sweongyodrop:
9458203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
9459203945Sweongyo}
9460203945Sweongyo
9461203945Sweongyostatic void
9462203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
9463203945Sweongyo    const struct bwn_txstatus *status)
9464203945Sweongyo{
9465203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9466203945Sweongyo	struct bwn_dma_ring *dr;
9467203945Sweongyo	struct bwn_dmadesc_generic *desc;
9468203945Sweongyo	struct bwn_dmadesc_meta *meta;
9469203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9470203945Sweongyo	struct ieee80211_node *ni;
9471203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9472203945Sweongyo	struct mbuf *m;
9473203945Sweongyo	int slot;
9474203945Sweongyo
9475203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9476203945Sweongyo
9477203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
9478203945Sweongyo	if (dr == NULL) {
9479203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
9480203945Sweongyo		return;
9481203945Sweongyo	}
9482203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
9483203945Sweongyo
9484203945Sweongyo	while (1) {
9485203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
9486203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9487203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
9488203945Sweongyo
9489203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
9490203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
9491203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
9492203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
9493203945Sweongyo
9494203945Sweongyo		if (meta->mt_islast) {
9495203945Sweongyo			KASSERT(meta->mt_m != NULL,
9496203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9497203945Sweongyo
9498203945Sweongyo			ni = meta->mt_ni;
9499203945Sweongyo			m = meta->mt_m;
9500203945Sweongyo			if (ni != NULL) {
9501203945Sweongyo				/*
9502203945Sweongyo				 * Do any tx complete callback. Note this must
9503203945Sweongyo				 * be done before releasing the node reference.
9504203945Sweongyo				 */
9505203945Sweongyo				if (m->m_flags & M_TXCB)
9506203945Sweongyo					ieee80211_process_callback(ni, m, 0);
9507203945Sweongyo				ieee80211_free_node(ni);
9508203945Sweongyo				meta->mt_ni = NULL;
9509203945Sweongyo			}
9510203945Sweongyo			m_freem(m);
9511203945Sweongyo			meta->mt_m = NULL;
9512203945Sweongyo		} else {
9513203945Sweongyo			KASSERT(meta->mt_m == NULL,
9514203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9515203945Sweongyo		}
9516203945Sweongyo
9517203945Sweongyo		dr->dr_usedslot--;
9518203945Sweongyo		if (meta->mt_islast) {
9519203945Sweongyo			ifp->if_opackets++;
9520203945Sweongyo			break;
9521203945Sweongyo		}
9522203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
9523203945Sweongyo	}
9524203945Sweongyo	sc->sc_watchdog_timer = 0;
9525203945Sweongyo	if (dr->dr_stop) {
9526203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
9527203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9528203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9529203945Sweongyo		dr->dr_stop = 0;
9530203945Sweongyo	}
9531203945Sweongyo}
9532203945Sweongyo
9533203945Sweongyostatic void
9534203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
9535203945Sweongyo    const struct bwn_txstatus *status)
9536203945Sweongyo{
9537203945Sweongyo	struct bwn_pio_txqueue *tq;
9538203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9539203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9540203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9541203945Sweongyo
9542203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9543203945Sweongyo
9544203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9545203945Sweongyo	if (tq == NULL)
9546203945Sweongyo		return;
9547203945Sweongyo
9548203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
9549203945Sweongyo	tq->tq_free++;
9550203945Sweongyo
9551203945Sweongyo	if (tp->tp_ni != NULL) {
9552203945Sweongyo		/*
9553203945Sweongyo		 * Do any tx complete callback.  Note this must
9554203945Sweongyo		 * be done before releasing the node reference.
9555203945Sweongyo		 */
9556203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
9557203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
9558203945Sweongyo		ieee80211_free_node(tp->tp_ni);
9559203945Sweongyo		tp->tp_ni = NULL;
9560203945Sweongyo	}
9561203945Sweongyo	m_freem(tp->tp_m);
9562203945Sweongyo	tp->tp_m = NULL;
9563203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
9564203945Sweongyo
9565203945Sweongyo	ifp->if_opackets++;
9566203945Sweongyo
9567203945Sweongyo	sc->sc_watchdog_timer = 0;
9568203945Sweongyo	if (tq->tq_stop) {
9569203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9570203945Sweongyo		tq->tq_stop = 0;
9571203945Sweongyo	}
9572203945Sweongyo}
9573203945Sweongyo
9574203945Sweongyostatic void
9575203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
9576203945Sweongyo{
9577203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9578203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
9579203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9580203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9581203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
9582203945Sweongyo	unsigned long now;
9583203945Sweongyo	int result;
9584203945Sweongyo
9585203945Sweongyo	BWN_GETTIME(now);
9586203945Sweongyo
9587203945Sweongyo	if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
9588203945Sweongyo		return;
9589203945Sweongyo	phy->nexttime = now + 2 * 1000;
9590203945Sweongyo
9591203945Sweongyo	if (siba->siba_board_vendor == SIBA_BOARDVENDOR_BCM &&
9592203945Sweongyo	    siba->siba_board_type == SIBA_BOARD_BU4306)
9593203945Sweongyo		return;
9594203945Sweongyo
9595203945Sweongyo	if (phy->recalc_txpwr != NULL) {
9596203945Sweongyo		result = phy->recalc_txpwr(mac,
9597203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
9598203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
9599203945Sweongyo			return;
9600203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
9601203945Sweongyo		    ("%s: fail", __func__));
9602203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
9603203945Sweongyo
9604203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
9605203945Sweongyo	}
9606203945Sweongyo}
9607203945Sweongyo
9608203945Sweongyostatic uint16_t
9609203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
9610203945Sweongyo{
9611203945Sweongyo
9612203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
9613203945Sweongyo}
9614203945Sweongyo
9615203945Sweongyostatic uint32_t
9616203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
9617203945Sweongyo{
9618203945Sweongyo
9619203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
9620203945Sweongyo}
9621203945Sweongyo
9622203945Sweongyostatic void
9623203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
9624203945Sweongyo{
9625203945Sweongyo
9626203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
9627203945Sweongyo}
9628203945Sweongyo
9629203945Sweongyostatic void
9630203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
9631203945Sweongyo{
9632203945Sweongyo
9633203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
9634203945Sweongyo}
9635203945Sweongyo
9636203945Sweongyostatic int
9637203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
9638203945Sweongyo{
9639203945Sweongyo
9640203945Sweongyo	switch (rate) {
9641203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
9642203945Sweongyo	case 12:
9643203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9644203945Sweongyo	case 18:
9645203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9646203945Sweongyo	case 24:
9647203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9648203945Sweongyo	case 36:
9649203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9650203945Sweongyo	case 48:
9651203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9652203945Sweongyo	case 72:
9653203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9654203945Sweongyo	case 96:
9655203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9656203945Sweongyo	case 108:
9657203945Sweongyo		return (BWN_OFDM_RATE_54MB);
9658203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
9659203945Sweongyo	case 2:
9660203945Sweongyo		return (BWN_CCK_RATE_1MB);
9661203945Sweongyo	case 4:
9662203945Sweongyo		return (BWN_CCK_RATE_2MB);
9663203945Sweongyo	case 11:
9664203945Sweongyo		return (BWN_CCK_RATE_5MB);
9665203945Sweongyo	case 22:
9666203945Sweongyo		return (BWN_CCK_RATE_11MB);
9667203945Sweongyo	}
9668203945Sweongyo
9669203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
9670203945Sweongyo	return (BWN_CCK_RATE_1MB);
9671203945Sweongyo}
9672203945Sweongyo
9673203945Sweongyostatic int
9674203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
9675203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
9676203945Sweongyo{
9677203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
9678203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9679203945Sweongyo	struct ieee80211_frame *wh;
9680203945Sweongyo	struct ieee80211_frame *protwh;
9681203945Sweongyo	struct ieee80211_frame_cts *cts;
9682203945Sweongyo	struct ieee80211_frame_rts *rts;
9683203945Sweongyo	const struct ieee80211_txparam *tp;
9684203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
9685203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9686203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9687203945Sweongyo	struct mbuf *mprot;
9688203945Sweongyo	unsigned int len;
9689203945Sweongyo	uint32_t macctl = 0;
9690203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
9691203945Sweongyo	uint16_t phyctl = 0;
9692203945Sweongyo	uint8_t rate, rate_fb;
9693203945Sweongyo
9694203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
9695203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
9696203945Sweongyo
9697203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
9698203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
9699203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
9700203945Sweongyo
9701203945Sweongyo	/*
9702203945Sweongyo	 * Find TX rate
9703203945Sweongyo	 */
9704203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
9705203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
9706203945Sweongyo		rate = rate_fb = tp->mgmtrate;
9707203945Sweongyo	else if (ismcast)
9708203945Sweongyo		rate = rate_fb = tp->mcastrate;
9709203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
9710203945Sweongyo		rate = rate_fb = tp->ucastrate;
9711203945Sweongyo	else {
9712203945Sweongyo		rix = ieee80211_amrr_choose(ni, &BWN_NODE(ni)->bn_amn);
9713203945Sweongyo		rate = ni->ni_txrate;
9714203945Sweongyo
9715203945Sweongyo		if (rix > 0)
9716203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
9717203945Sweongyo			    IEEE80211_RATE_VAL;
9718203945Sweongyo		else
9719203945Sweongyo			rate_fb = rate;
9720203945Sweongyo	}
9721203945Sweongyo
9722203945Sweongyo	sc->sc_tx_rate = rate;
9723203945Sweongyo
9724203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
9725203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
9726203945Sweongyo
9727203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
9728203945Sweongyo	    bwn_plcp_getcck(rate);
9729203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
9730203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
9731203945Sweongyo
9732203945Sweongyo	if ((rate_fb == rate) ||
9733203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
9734203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
9735203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
9736203945Sweongyo	else
9737203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
9738203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
9739203945Sweongyo
9740203945Sweongyo	/* XXX TX encryption */
9741203945Sweongyo	bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
9742203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
9743203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
9744203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
9745203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
9746203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
9747203945Sweongyo
9748203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
9749203945Sweongyo	    BWN_TX_EFT_FB_CCK;
9750203945Sweongyo	txhdr->chan = phy->chan;
9751203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
9752203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
9753203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9754203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
9755203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
9756203945Sweongyo
9757203945Sweongyo	/* XXX TX antenna selection */
9758203945Sweongyo
9759203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
9760203945Sweongyo	case 0:
9761203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
9762203945Sweongyo		break;
9763203945Sweongyo	case 1:
9764203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
9765203945Sweongyo		break;
9766203945Sweongyo	case 2:
9767203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
9768203945Sweongyo		break;
9769203945Sweongyo	case 3:
9770203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
9771203945Sweongyo		break;
9772203945Sweongyo	case 4:
9773203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
9774203945Sweongyo		break;
9775203945Sweongyo	default:
9776203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9777203945Sweongyo	}
9778203945Sweongyo
9779203945Sweongyo	if (!ismcast)
9780203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
9781203945Sweongyo
9782203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
9783203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
9784203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
9785203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
9786203945Sweongyo
9787203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
9788203945Sweongyo		/* XXX RTS rate is always 1MB??? */
9789203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
9790203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
9791203945Sweongyo
9792203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
9793203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
9794203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
9795203945Sweongyo
9796203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
9797203945Sweongyo			cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
9798203945Sweongyo			    (txhdr->body.old.rts_frame) :
9799203945Sweongyo			    (txhdr->body.new.rts_frame));
9800203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
9801203945Sweongyo			    protdur);
9802203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9803203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
9804203945Sweongyo			    mprot->m_pkthdr.len);
9805203945Sweongyo			m_freem(mprot);
9806203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
9807203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
9808203945Sweongyo		} else {
9809203945Sweongyo			rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
9810203945Sweongyo			    (txhdr->body.old.rts_frame) :
9811203945Sweongyo			    (txhdr->body.new.rts_frame));
9812203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
9813203945Sweongyo			    isshort);
9814203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
9815203945Sweongyo			    wh->i_addr2, protdur);
9816203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9817203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
9818203945Sweongyo			    mprot->m_pkthdr.len);
9819203945Sweongyo			m_freem(mprot);
9820203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
9821203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
9822203945Sweongyo		}
9823203945Sweongyo		len += IEEE80211_CRC_LEN;
9824203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
9825203945Sweongyo		    &txhdr->body.old.rts_plcp :
9826203945Sweongyo		    &txhdr->body.new.rts_plcp), len, rts_rate);
9827203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
9828203945Sweongyo		    rts_rate_fb);
9829203945Sweongyo
9830203945Sweongyo		protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
9831203945Sweongyo		    (&txhdr->body.old.rts_frame) :
9832203945Sweongyo		    (&txhdr->body.new.rts_frame));
9833203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
9834203945Sweongyo
9835203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
9836203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
9837203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
9838203945Sweongyo		} else {
9839203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
9840203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
9841203945Sweongyo		}
9842203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
9843203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
9844203945Sweongyo	}
9845203945Sweongyo
9846203945Sweongyo	if (BWN_ISOLDFMT(mac))
9847203945Sweongyo		txhdr->body.old.cookie = htole16(cookie);
9848203945Sweongyo	else
9849203945Sweongyo		txhdr->body.new.cookie = htole16(cookie);
9850203945Sweongyo
9851203945Sweongyo	txhdr->macctl = htole32(macctl);
9852203945Sweongyo	txhdr->phyctl = htole16(phyctl);
9853203945Sweongyo
9854203945Sweongyo	/*
9855203945Sweongyo	 * TX radio tap
9856203945Sweongyo	 */
9857203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
9858203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
9859203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
9860203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
9861203945Sweongyo		if (isshort &&
9862203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9863203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
9864203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
9865203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
9866203945Sweongyo
9867203945Sweongyo		ieee80211_radiotap_tx(vap, m);
9868203945Sweongyo	}
9869203945Sweongyo
9870203945Sweongyo	return (0);
9871203945Sweongyo}
9872203945Sweongyo
9873203945Sweongyostatic void
9874203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
9875203945Sweongyo    const uint8_t rate)
9876203945Sweongyo{
9877203945Sweongyo	uint32_t d, plen;
9878203945Sweongyo	uint8_t *raw = plcp->o.raw;
9879203945Sweongyo
9880203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
9881203945Sweongyo		d = bwn_plcp_getofdm(rate);
9882203945Sweongyo		KASSERT(!(octets & 0xf000),
9883203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9884203945Sweongyo		d |= (octets << 5);
9885203945Sweongyo		plcp->o.data = htole32(d);
9886203945Sweongyo	} else {
9887203945Sweongyo		plen = octets * 16 / rate;
9888203945Sweongyo		if ((octets * 16 % rate) > 0) {
9889203945Sweongyo			plen++;
9890203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
9891203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
9892203945Sweongyo				raw[1] = 0x84;
9893203945Sweongyo			} else
9894203945Sweongyo				raw[1] = 0x04;
9895203945Sweongyo		} else
9896203945Sweongyo			raw[1] = 0x04;
9897203945Sweongyo		plcp->o.data |= htole32(plen << 16);
9898203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
9899203945Sweongyo	}
9900203945Sweongyo}
9901203945Sweongyo
9902203945Sweongyostatic uint8_t
9903203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
9904203945Sweongyo{
9905203945Sweongyo	uint8_t mask;
9906203945Sweongyo
9907203945Sweongyo	if (n == 0)
9908203945Sweongyo		return (0);
9909203945Sweongyo	if (mac->mac_phy.gmode)
9910203945Sweongyo		mask = mac->mac_sd->sd_bus->siba_sprom.ant_bg;
9911203945Sweongyo	else
9912203945Sweongyo		mask = mac->mac_sd->sd_bus->siba_sprom.ant_a;
9913203945Sweongyo	if (!(mask & (1 << (n - 1))))
9914203945Sweongyo		return (0);
9915203945Sweongyo	return (n);
9916203945Sweongyo}
9917203945Sweongyo
9918203945Sweongyostatic uint8_t
9919203945Sweongyobwn_get_fbrate(uint8_t bitrate)
9920203945Sweongyo{
9921203945Sweongyo	switch (bitrate) {
9922203945Sweongyo	case BWN_CCK_RATE_1MB:
9923203945Sweongyo		return (BWN_CCK_RATE_1MB);
9924203945Sweongyo	case BWN_CCK_RATE_2MB:
9925203945Sweongyo		return (BWN_CCK_RATE_1MB);
9926203945Sweongyo	case BWN_CCK_RATE_5MB:
9927203945Sweongyo		return (BWN_CCK_RATE_2MB);
9928203945Sweongyo	case BWN_CCK_RATE_11MB:
9929203945Sweongyo		return (BWN_CCK_RATE_5MB);
9930203945Sweongyo	case BWN_OFDM_RATE_6MB:
9931203945Sweongyo		return (BWN_CCK_RATE_5MB);
9932203945Sweongyo	case BWN_OFDM_RATE_9MB:
9933203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9934203945Sweongyo	case BWN_OFDM_RATE_12MB:
9935203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9936203945Sweongyo	case BWN_OFDM_RATE_18MB:
9937203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9938203945Sweongyo	case BWN_OFDM_RATE_24MB:
9939203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9940203945Sweongyo	case BWN_OFDM_RATE_36MB:
9941203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9942203945Sweongyo	case BWN_OFDM_RATE_48MB:
9943203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9944203945Sweongyo	case BWN_OFDM_RATE_54MB:
9945203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9946203945Sweongyo	}
9947203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9948203945Sweongyo	return (0);
9949203945Sweongyo}
9950203945Sweongyo
9951203945Sweongyostatic uint32_t
9952203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9953203945Sweongyo    uint32_t ctl, const void *_data, int len)
9954203945Sweongyo{
9955203945Sweongyo	uint32_t value = 0;
9956203945Sweongyo	const uint8_t *data = _data;
9957203945Sweongyo
9958203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
9959203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
9960203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9961203945Sweongyo
9962203945Sweongyo	siba_write_multi_4(mac->mac_sd, data, (len & ~3),
9963203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
9964203945Sweongyo	if (len & 3) {
9965203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
9966203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
9967203945Sweongyo		data = &(data[len - 1]);
9968203945Sweongyo		switch (len & 3) {
9969203945Sweongyo		case 3:
9970203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
9971203945Sweongyo			value |= (uint32_t)(*data) << 16;
9972203945Sweongyo			data--;
9973203945Sweongyo		case 2:
9974203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
9975203945Sweongyo			value |= (uint32_t)(*data) << 8;
9976203945Sweongyo			data--;
9977203945Sweongyo		case 1:
9978203945Sweongyo			value |= (uint32_t)(*data);
9979203945Sweongyo		}
9980203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9981203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
9982203945Sweongyo	}
9983203945Sweongyo
9984203945Sweongyo	return (ctl);
9985203945Sweongyo}
9986203945Sweongyo
9987203945Sweongyostatic void
9988203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9989203945Sweongyo    uint16_t offset, uint32_t value)
9990203945Sweongyo{
9991203945Sweongyo
9992203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
9993203945Sweongyo}
9994203945Sweongyo
9995203945Sweongyostatic uint16_t
9996203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9997203945Sweongyo    uint16_t ctl, const void *_data, int len)
9998203945Sweongyo{
9999203945Sweongyo	const uint8_t *data = _data;
10000203945Sweongyo
10001203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
10002203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10003203945Sweongyo
10004203945Sweongyo	siba_write_multi_2(mac->mac_sd, data, (len & ~1),
10005203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
10006203945Sweongyo	if (len & 1) {
10007203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
10008203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10009203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
10010203945Sweongyo	}
10011203945Sweongyo
10012203945Sweongyo	return (ctl);
10013203945Sweongyo}
10014203945Sweongyo
10015203945Sweongyostatic uint16_t
10016203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
10017203945Sweongyo    uint16_t ctl, struct mbuf *m0)
10018203945Sweongyo{
10019203945Sweongyo	int i, j = 0;
10020203945Sweongyo	uint16_t data = 0;
10021203945Sweongyo	const uint8_t *buf;
10022203945Sweongyo	struct mbuf *m = m0;
10023203945Sweongyo
10024203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
10025203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10026203945Sweongyo
10027203945Sweongyo	for (; m != NULL; m = m->m_next) {
10028203945Sweongyo		buf = mtod(m, const uint8_t *);
10029203945Sweongyo		for (i = 0; i < m->m_len; i++) {
10030203945Sweongyo			if (!((j++) % 2))
10031203945Sweongyo				data |= buf[i];
10032203945Sweongyo			else {
10033203945Sweongyo				data |= (buf[i] << 8);
10034203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
10035203945Sweongyo				data = 0;
10036203945Sweongyo			}
10037203945Sweongyo		}
10038203945Sweongyo	}
10039203945Sweongyo	if (m0->m_pkthdr.len % 2) {
10040203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
10041203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10042203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
10043203945Sweongyo	}
10044203945Sweongyo
10045203945Sweongyo	return (ctl);
10046203945Sweongyo}
10047203945Sweongyo
10048203945Sweongyostatic void
10049203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
10050203945Sweongyo{
10051203945Sweongyo
10052203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
10053203945Sweongyo		return;
10054203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
10055203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
10056203945Sweongyo}
10057203945Sweongyo
10058203945Sweongyostatic struct bwn_dma_ring *
10059203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
10060203945Sweongyo{
10061203945Sweongyo
10062203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
10063203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
10064203945Sweongyo
10065203945Sweongyo	switch (prio) {
10066203945Sweongyo	case 3:
10067203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
10068203945Sweongyo	case 2:
10069203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
10070203945Sweongyo	case 0:
10071203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
10072203945Sweongyo	case 1:
10073203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
10074203945Sweongyo	}
10075203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
10076204242Simp	return (NULL);
10077203945Sweongyo}
10078203945Sweongyo
10079203945Sweongyostatic int
10080203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
10081203945Sweongyo{
10082203945Sweongyo	int slot;
10083203945Sweongyo
10084204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
10085203945Sweongyo
10086203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
10087203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
10088203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
10089203945Sweongyo
10090203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
10091203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
10092203945Sweongyo	dr->dr_curslot = slot;
10093203945Sweongyo	dr->dr_usedslot++;
10094203945Sweongyo
10095203945Sweongyo	return (slot);
10096203945Sweongyo}
10097203945Sweongyo
10098203945Sweongyostatic int
10099203945Sweongyobwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
10100203945Sweongyo{
10101203945Sweongyo	const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
10102203945Sweongyo	unsigned int a, b, c, d;
10103203945Sweongyo	unsigned int avg;
10104203945Sweongyo	uint32_t tmp;
10105203945Sweongyo
10106203945Sweongyo	tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
10107203945Sweongyo	a = tmp & 0xff;
10108203945Sweongyo	b = (tmp >> 8) & 0xff;
10109203945Sweongyo	c = (tmp >> 16) & 0xff;
10110203945Sweongyo	d = (tmp >> 24) & 0xff;
10111203945Sweongyo	if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
10112203945Sweongyo	    c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
10113203945Sweongyo		return (ENOENT);
10114203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
10115203945Sweongyo	    BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
10116203945Sweongyo	    (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
10117203945Sweongyo
10118203945Sweongyo	if (ofdm) {
10119203945Sweongyo		a = (a + 32) & 0x3f;
10120203945Sweongyo		b = (b + 32) & 0x3f;
10121203945Sweongyo		c = (c + 32) & 0x3f;
10122203945Sweongyo		d = (d + 32) & 0x3f;
10123203945Sweongyo	}
10124203945Sweongyo
10125203945Sweongyo	avg = (a + b + c + d + 2) / 4;
10126203945Sweongyo	if (ofdm) {
10127203945Sweongyo		if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
10128203945Sweongyo		    & BWN_HF_4DB_CCK_POWERBOOST)
10129203945Sweongyo			avg = (avg >= 13) ? (avg - 13) : 0;
10130203945Sweongyo	}
10131203945Sweongyo	return (avg);
10132203945Sweongyo}
10133203945Sweongyo
10134203945Sweongyostatic void
10135203945Sweongyobwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
10136203945Sweongyo{
10137203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
10138203945Sweongyo	int rfatt = *rfattp;
10139203945Sweongyo	int bbatt = *bbattp;
10140203945Sweongyo
10141203945Sweongyo	while (1) {
10142203945Sweongyo		if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
10143203945Sweongyo			break;
10144203945Sweongyo		if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
10145203945Sweongyo			break;
10146203945Sweongyo		if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
10147203945Sweongyo			break;
10148203945Sweongyo		if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
10149203945Sweongyo			break;
10150203945Sweongyo		if (bbatt > lo->bbatt.max) {
10151203945Sweongyo			bbatt -= 4;
10152203945Sweongyo			rfatt += 1;
10153203945Sweongyo			continue;
10154203945Sweongyo		}
10155203945Sweongyo		if (bbatt < lo->bbatt.min) {
10156203945Sweongyo			bbatt += 4;
10157203945Sweongyo			rfatt -= 1;
10158203945Sweongyo			continue;
10159203945Sweongyo		}
10160203945Sweongyo		if (rfatt > lo->rfatt.max) {
10161203945Sweongyo			rfatt -= 1;
10162203945Sweongyo			bbatt += 4;
10163203945Sweongyo			continue;
10164203945Sweongyo		}
10165203945Sweongyo		if (rfatt < lo->rfatt.min) {
10166203945Sweongyo			rfatt += 1;
10167203945Sweongyo			bbatt -= 4;
10168203945Sweongyo			continue;
10169203945Sweongyo		}
10170203945Sweongyo		break;
10171203945Sweongyo	}
10172203945Sweongyo
10173203945Sweongyo	*rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
10174203945Sweongyo	*bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
10175203945Sweongyo}
10176203945Sweongyo
10177203945Sweongyostatic void
10178203945Sweongyobwn_phy_lock(struct bwn_mac *mac)
10179203945Sweongyo{
10180203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10181203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10182203945Sweongyo
10183203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
10184203945Sweongyo	    ("%s: unsupported rev %d", __func__, mac->mac_sd->sd_id.sd_rev));
10185203945Sweongyo
10186203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10187203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
10188203945Sweongyo}
10189203945Sweongyo
10190203945Sweongyostatic void
10191203945Sweongyobwn_phy_unlock(struct bwn_mac *mac)
10192203945Sweongyo{
10193203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10194203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10195203945Sweongyo
10196203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
10197203945Sweongyo	    ("%s: unsupported rev %d", __func__, mac->mac_sd->sd_id.sd_rev));
10198203945Sweongyo
10199203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10200203945Sweongyo		bwn_psctl(mac, 0);
10201203945Sweongyo}
10202203945Sweongyo
10203203945Sweongyostatic void
10204203945Sweongyobwn_rf_lock(struct bwn_mac *mac)
10205203945Sweongyo{
10206203945Sweongyo
10207203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10208203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
10209203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
10210203945Sweongyo	DELAY(10);
10211203945Sweongyo}
10212203945Sweongyo
10213203945Sweongyostatic void
10214203945Sweongyobwn_rf_unlock(struct bwn_mac *mac)
10215203945Sweongyo{
10216203945Sweongyo
10217203945Sweongyo	BWN_READ_2(mac, BWN_PHYVER);
10218203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10219203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
10220203945Sweongyo}
10221203945Sweongyo
10222203945Sweongyostatic struct bwn_pio_txqueue *
10223203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
10224203945Sweongyo    struct bwn_pio_txpkt **pack)
10225203945Sweongyo{
10226203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
10227203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
10228203945Sweongyo	unsigned int index;
10229203945Sweongyo
10230203945Sweongyo	switch (cookie & 0xf000) {
10231203945Sweongyo	case 0x1000:
10232203945Sweongyo		tq = &pio->wme[WME_AC_BK];
10233203945Sweongyo		break;
10234203945Sweongyo	case 0x2000:
10235203945Sweongyo		tq = &pio->wme[WME_AC_BE];
10236203945Sweongyo		break;
10237203945Sweongyo	case 0x3000:
10238203945Sweongyo		tq = &pio->wme[WME_AC_VI];
10239203945Sweongyo		break;
10240203945Sweongyo	case 0x4000:
10241203945Sweongyo		tq = &pio->wme[WME_AC_VO];
10242203945Sweongyo		break;
10243203945Sweongyo	case 0x5000:
10244203945Sweongyo		tq = &pio->mcast;
10245203945Sweongyo		break;
10246203945Sweongyo	}
10247203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
10248203945Sweongyo	if (tq == NULL)
10249203945Sweongyo		return (NULL);
10250203945Sweongyo	index = (cookie & 0x0fff);
10251203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
10252203945Sweongyo	if (index >= N(tq->tq_pkts))
10253203945Sweongyo		return (NULL);
10254203945Sweongyo	*pack = &tq->tq_pkts[index];
10255203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
10256203945Sweongyo	return (tq);
10257203945Sweongyo}
10258203945Sweongyo
10259203945Sweongyostatic void
10260203945Sweongyobwn_txpwr(void *arg, int npending)
10261203945Sweongyo{
10262203945Sweongyo	struct bwn_mac *mac = arg;
10263203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10264203945Sweongyo
10265203945Sweongyo	BWN_LOCK(sc);
10266203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
10267203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
10268203945Sweongyo		mac->mac_phy.set_txpwr(mac);
10269203945Sweongyo	BWN_UNLOCK(sc);
10270203945Sweongyo}
10271203945Sweongyo
10272203945Sweongyostatic void
10273203945Sweongyobwn_task_15s(struct bwn_mac *mac)
10274203945Sweongyo{
10275203945Sweongyo	uint16_t reg;
10276203945Sweongyo
10277203945Sweongyo	if (mac->mac_fw.opensource) {
10278203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
10279203945Sweongyo		if (reg) {
10280203945Sweongyo			bwn_restart(mac, "fw watchdog");
10281203945Sweongyo			return;
10282203945Sweongyo		}
10283203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
10284203945Sweongyo	}
10285203945Sweongyo	if (mac->mac_phy.task_15s)
10286203945Sweongyo		mac->mac_phy.task_15s(mac);
10287203945Sweongyo
10288203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
10289203945Sweongyo}
10290203945Sweongyo
10291203945Sweongyostatic void
10292203945Sweongyobwn_task_30s(struct bwn_mac *mac)
10293203945Sweongyo{
10294203945Sweongyo
10295203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
10296203945Sweongyo		return;
10297203945Sweongyo	mac->mac_noise.noi_running = 1;
10298203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
10299203945Sweongyo
10300203945Sweongyo	bwn_noise_gensample(mac);
10301203945Sweongyo}
10302203945Sweongyo
10303203945Sweongyostatic void
10304203945Sweongyobwn_task_60s(struct bwn_mac *mac)
10305203945Sweongyo{
10306203945Sweongyo
10307203945Sweongyo	if (mac->mac_phy.task_60s)
10308203945Sweongyo		mac->mac_phy.task_60s(mac);
10309203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
10310203945Sweongyo}
10311203945Sweongyo
10312203945Sweongyostatic void
10313203945Sweongyobwn_tasks(void *arg)
10314203945Sweongyo{
10315203945Sweongyo	struct bwn_mac *mac = arg;
10316203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10317203945Sweongyo
10318203945Sweongyo	BWN_ASSERT_LOCKED(sc);
10319203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
10320203945Sweongyo		return;
10321203945Sweongyo
10322203945Sweongyo	if (mac->mac_task_state % 4 == 0)
10323203945Sweongyo		bwn_task_60s(mac);
10324203945Sweongyo	if (mac->mac_task_state % 2 == 0)
10325203945Sweongyo		bwn_task_30s(mac);
10326203945Sweongyo	bwn_task_15s(mac);
10327203945Sweongyo
10328203945Sweongyo	mac->mac_task_state++;
10329203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
10330203945Sweongyo}
10331203945Sweongyo
10332203945Sweongyostatic int
10333203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
10334203945Sweongyo{
10335203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10336203945Sweongyo
10337203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
10338203945Sweongyo
10339203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
10340203945Sweongyo	case 0xb:
10341203945Sweongyo		return (BWN_OFDM_RATE_6MB);
10342203945Sweongyo	case 0xf:
10343203945Sweongyo		return (BWN_OFDM_RATE_9MB);
10344203945Sweongyo	case 0xa:
10345203945Sweongyo		return (BWN_OFDM_RATE_12MB);
10346203945Sweongyo	case 0xe:
10347203945Sweongyo		return (BWN_OFDM_RATE_18MB);
10348203945Sweongyo	case 0x9:
10349203945Sweongyo		return (BWN_OFDM_RATE_24MB);
10350203945Sweongyo	case 0xd:
10351203945Sweongyo		return (BWN_OFDM_RATE_36MB);
10352203945Sweongyo	case 0x8:
10353203945Sweongyo		return (BWN_OFDM_RATE_48MB);
10354203945Sweongyo	case 0xc:
10355203945Sweongyo		return (BWN_OFDM_RATE_54MB);
10356203945Sweongyo	}
10357203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
10358203945Sweongyo	    plcp->o.raw[0] & 0xf);
10359203945Sweongyo	return (-1);
10360203945Sweongyo}
10361203945Sweongyo
10362203945Sweongyostatic int
10363203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
10364203945Sweongyo{
10365203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10366203945Sweongyo
10367203945Sweongyo	switch (plcp->o.raw[0]) {
10368203945Sweongyo	case 0x0a:
10369203945Sweongyo		return (BWN_CCK_RATE_1MB);
10370203945Sweongyo	case 0x14:
10371203945Sweongyo		return (BWN_CCK_RATE_2MB);
10372203945Sweongyo	case 0x37:
10373203945Sweongyo		return (BWN_CCK_RATE_5MB);
10374203945Sweongyo	case 0x6e:
10375203945Sweongyo		return (BWN_CCK_RATE_11MB);
10376203945Sweongyo	}
10377203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
10378203945Sweongyo	return (-1);
10379203945Sweongyo}
10380203945Sweongyo
10381203945Sweongyostatic void
10382203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
10383203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
10384203945Sweongyo    int rssi, int noise)
10385203945Sweongyo{
10386203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10387203945Sweongyo	const struct ieee80211_frame_min *wh;
10388203945Sweongyo	uint64_t tsf;
10389203945Sweongyo	uint16_t low_mactime_now;
10390203945Sweongyo
10391203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
10392203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
10393203945Sweongyo
10394203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
10395203945Sweongyo	if (wh->i_fc[1] & IEEE80211_FC1_WEP)
10396203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
10397203945Sweongyo
10398203945Sweongyo	bwn_tsf_read(mac, &tsf);
10399203945Sweongyo	low_mactime_now = tsf;
10400203945Sweongyo	tsf = tsf & ~0xffffULL;
10401203945Sweongyo	tsf += le16toh(rxhdr->mac_time);
10402203945Sweongyo	if (low_mactime_now < le16toh(rxhdr->mac_time))
10403203945Sweongyo		tsf -= 0x10000;
10404203945Sweongyo
10405203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
10406203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
10407203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
10408203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
10409203945Sweongyo}
10410203945Sweongyo
10411203945Sweongyostatic void
10412203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
10413203945Sweongyo{
10414203945Sweongyo	uint32_t low, high;
10415203945Sweongyo
10416203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
10417203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
10418203945Sweongyo
10419203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
10420203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
10421203945Sweongyo	*tsf = high;
10422203945Sweongyo	*tsf <<= 32;
10423203945Sweongyo	*tsf |= low;
10424203945Sweongyo}
10425203945Sweongyo
10426203945Sweongyostatic int
10427203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
10428203945Sweongyo{
10429203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10430203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10431203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
10432203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
10433203945Sweongyo	bus_addr_t lowaddr = 0;
10434203945Sweongyo	int error;
10435203945Sweongyo
10436203945Sweongyo	if (siba->siba_type == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
10437203945Sweongyo		return (0);
10438203945Sweongyo
10439203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 5, ("%s: fail", __func__));
10440203945Sweongyo
10441203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
10442203945Sweongyo
10443203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
10444203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
10445203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
10446203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
10447203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
10448203945Sweongyo	else
10449203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
10450203945Sweongyo
10451203945Sweongyo	/*
10452203945Sweongyo	 * Create top level DMA tag
10453203945Sweongyo	 */
10454203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
10455203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
10456203945Sweongyo			       lowaddr,			/* lowaddr */
10457203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
10458203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
10459203945Sweongyo			       MAXBSIZE,		/* maxsize */
10460203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
10461203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
10462203945Sweongyo			       0,			/* flags */
10463203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
10464203945Sweongyo			       &dma->parent_dtag);
10465203945Sweongyo	if (error) {
10466203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
10467203945Sweongyo		return (error);
10468203945Sweongyo	}
10469203945Sweongyo
10470203945Sweongyo	/*
10471203945Sweongyo	 * Create TX/RX mbuf DMA tag
10472203945Sweongyo	 */
10473203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10474203945Sweongyo				1,
10475203945Sweongyo				0,
10476203945Sweongyo				BUS_SPACE_MAXADDR,
10477203945Sweongyo				BUS_SPACE_MAXADDR,
10478203945Sweongyo				NULL, NULL,
10479203945Sweongyo				MCLBYTES,
10480203945Sweongyo				1,
10481203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10482203945Sweongyo				0,
10483203945Sweongyo				NULL, NULL,
10484203945Sweongyo				&dma->rxbuf_dtag);
10485203945Sweongyo	if (error) {
10486203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10487203945Sweongyo		goto fail0;
10488203945Sweongyo	}
10489203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10490203945Sweongyo				1,
10491203945Sweongyo				0,
10492203945Sweongyo				BUS_SPACE_MAXADDR,
10493203945Sweongyo				BUS_SPACE_MAXADDR,
10494203945Sweongyo				NULL, NULL,
10495203945Sweongyo				MCLBYTES,
10496203945Sweongyo				1,
10497203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10498203945Sweongyo				0,
10499203945Sweongyo				NULL, NULL,
10500203945Sweongyo				&dma->txbuf_dtag);
10501203945Sweongyo	if (error) {
10502203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10503203945Sweongyo		goto fail1;
10504203945Sweongyo	}
10505203945Sweongyo
10506203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
10507203945Sweongyo	if (!dma->wme[WME_AC_BK])
10508203945Sweongyo		goto fail2;
10509203945Sweongyo
10510203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
10511203945Sweongyo	if (!dma->wme[WME_AC_BE])
10512203945Sweongyo		goto fail3;
10513203945Sweongyo
10514203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
10515203945Sweongyo	if (!dma->wme[WME_AC_VI])
10516203945Sweongyo		goto fail4;
10517203945Sweongyo
10518203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
10519203945Sweongyo	if (!dma->wme[WME_AC_VO])
10520203945Sweongyo		goto fail5;
10521203945Sweongyo
10522203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
10523203945Sweongyo	if (!dma->mcast)
10524203945Sweongyo		goto fail6;
10525203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
10526203945Sweongyo	if (!dma->rx)
10527203945Sweongyo		goto fail7;
10528203945Sweongyo
10529203945Sweongyo	return (error);
10530203945Sweongyo
10531203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
10532203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
10533203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
10534203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
10535203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
10536203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
10537203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
10538203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
10539203945Sweongyo	return (error);
10540203945Sweongyo}
10541203945Sweongyo
10542203945Sweongyostatic struct bwn_dma_ring *
10543203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
10544203945Sweongyo    uint16_t cookie, int *slot)
10545203945Sweongyo{
10546203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10547203945Sweongyo	struct bwn_dma_ring *dr;
10548203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10549203945Sweongyo
10550203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
10551203945Sweongyo
10552203945Sweongyo	switch (cookie & 0xf000) {
10553203945Sweongyo	case 0x1000:
10554203945Sweongyo		dr = dma->wme[WME_AC_BK];
10555203945Sweongyo		break;
10556203945Sweongyo	case 0x2000:
10557203945Sweongyo		dr = dma->wme[WME_AC_BE];
10558203945Sweongyo		break;
10559203945Sweongyo	case 0x3000:
10560203945Sweongyo		dr = dma->wme[WME_AC_VI];
10561203945Sweongyo		break;
10562203945Sweongyo	case 0x4000:
10563203945Sweongyo		dr = dma->wme[WME_AC_VO];
10564203945Sweongyo		break;
10565203945Sweongyo	case 0x5000:
10566203945Sweongyo		dr = dma->mcast;
10567203945Sweongyo		break;
10568203945Sweongyo	default:
10569204242Simp		dr = NULL;
10570203945Sweongyo		KASSERT(0 == 1,
10571203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
10572203945Sweongyo	}
10573203945Sweongyo	*slot = (cookie & 0x0fff);
10574203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
10575203945Sweongyo		/*
10576203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
10577203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
10578203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
10579203945Sweongyo		 */
10580203945Sweongyo		KASSERT(status->seq == dma->lastseq,
10581203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
10582203945Sweongyo		device_printf(sc->sc_dev,
10583203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
10584203945Sweongyo		    dr->dr_numslots);
10585203945Sweongyo		return (NULL);
10586203945Sweongyo	}
10587203945Sweongyo	dma->lastseq = status->seq;
10588203945Sweongyo	return (dr);
10589203945Sweongyo}
10590203945Sweongyo
10591203945Sweongyostatic void
10592203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
10593203945Sweongyo{
10594203945Sweongyo	struct bwn_dma *dma;
10595203945Sweongyo
10596203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
10597203945Sweongyo		return;
10598203945Sweongyo	dma = &mac->mac_method.dma;
10599203945Sweongyo
10600203945Sweongyo	bwn_dma_ringstop(&dma->rx);
10601203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
10602203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
10603203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
10604203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
10605203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
10606203945Sweongyo}
10607203945Sweongyo
10608203945Sweongyostatic void
10609203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
10610203945Sweongyo{
10611203945Sweongyo
10612203945Sweongyo	if (dr == NULL)
10613203945Sweongyo		return;
10614203945Sweongyo
10615203945Sweongyo	bwn_dma_cleanup(*dr);
10616203945Sweongyo}
10617203945Sweongyo
10618203945Sweongyostatic void
10619203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
10620203945Sweongyo{
10621203945Sweongyo	struct bwn_pio *pio;
10622203945Sweongyo
10623203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
10624203945Sweongyo		return;
10625203945Sweongyo	pio = &mac->mac_method.pio;
10626203945Sweongyo
10627203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
10628203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
10629203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
10630203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
10631203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
10632203945Sweongyo}
10633203945Sweongyo
10634203945Sweongyostatic void
10635203945Sweongyobwn_led_attach(struct bwn_mac *mac)
10636203945Sweongyo{
10637203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10638203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
10639203945Sweongyo	const uint8_t *led_act = NULL;
10640203945Sweongyo	uint16_t val[BWN_LED_MAX];
10641203945Sweongyo	int i;
10642203945Sweongyo
10643203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
10644203945Sweongyo	sc->sc_led_blink = 1;
10645203945Sweongyo
10646203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
10647203945Sweongyo		if (siba->siba_pci_subvid == bwn_vendor_led_act[i].vid) {
10648203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
10649203945Sweongyo			break;
10650203945Sweongyo		}
10651203945Sweongyo	}
10652203945Sweongyo	if (led_act == NULL)
10653203945Sweongyo		led_act = bwn_default_led_act;
10654203945Sweongyo
10655203945Sweongyo	val[0] = siba->siba_sprom.gpio0;
10656203945Sweongyo	val[1] = siba->siba_sprom.gpio1;
10657203945Sweongyo	val[2] = siba->siba_sprom.gpio2;
10658203945Sweongyo	val[3] = siba->siba_sprom.gpio3;
10659203945Sweongyo
10660203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10661203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10662203945Sweongyo
10663203945Sweongyo		if (val[i] == 0xff) {
10664203945Sweongyo			led->led_act = led_act[i];
10665203945Sweongyo		} else {
10666203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
10667203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
10668203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
10669203945Sweongyo		}
10670203945Sweongyo		led->led_mask = (1 << i);
10671203945Sweongyo
10672203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
10673203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
10674203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
10675203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
10676203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
10677203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
10678203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
10679203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
10680203945Sweongyo
10681203945Sweongyo			if (sc->sc_blink_led == NULL) {
10682203945Sweongyo				sc->sc_blink_led = led;
10683203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
10684203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
10685203945Sweongyo			}
10686203945Sweongyo		}
10687203945Sweongyo
10688203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
10689203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
10690203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
10691203945Sweongyo	}
10692203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
10693203945Sweongyo}
10694203945Sweongyo
10695203945Sweongyostatic __inline uint16_t
10696203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
10697203945Sweongyo{
10698203945Sweongyo
10699203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
10700203945Sweongyo		on = !on;
10701203945Sweongyo	if (on)
10702203945Sweongyo		val |= led->led_mask;
10703203945Sweongyo	else
10704203945Sweongyo		val &= ~led->led_mask;
10705203945Sweongyo	return val;
10706203945Sweongyo}
10707203945Sweongyo
10708203945Sweongyostatic void
10709203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
10710203945Sweongyo{
10711203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10712203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10713203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10714203945Sweongyo	uint16_t val;
10715203945Sweongyo	int i;
10716203945Sweongyo
10717203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
10718203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
10719203945Sweongyo		sc->sc_led_blinking = 0;
10720203945Sweongyo	}
10721203945Sweongyo
10722203945Sweongyo	if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
10723203945Sweongyo		return;
10724203945Sweongyo
10725203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10726203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10727203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10728203945Sweongyo		int on;
10729203945Sweongyo
10730203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
10731203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
10732203945Sweongyo			continue;
10733203945Sweongyo
10734203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
10735203945Sweongyo		    nstate != IEEE80211_S_INIT)
10736203945Sweongyo			continue;
10737203945Sweongyo
10738203945Sweongyo		switch (led->led_act) {
10739203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
10740203945Sweongyo			on = 1;
10741203945Sweongyo			break;
10742203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
10743203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
10744203945Sweongyo			on = 0;
10745203945Sweongyo			break;
10746203945Sweongyo		default:
10747203945Sweongyo			on = 1;
10748203945Sweongyo			switch (nstate) {
10749203945Sweongyo			case IEEE80211_S_INIT:
10750203945Sweongyo				on = 0;
10751203945Sweongyo				break;
10752203945Sweongyo			case IEEE80211_S_RUN:
10753203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
10754203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
10755203945Sweongyo					on = 0;
10756203945Sweongyo				break;
10757203945Sweongyo			default:
10758203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
10759203945Sweongyo					on = 0;
10760203945Sweongyo				break;
10761203945Sweongyo			}
10762203945Sweongyo			break;
10763203945Sweongyo		}
10764203945Sweongyo
10765203945Sweongyo		val = bwn_led_onoff(led, val, on);
10766203945Sweongyo	}
10767203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10768203945Sweongyo}
10769203945Sweongyo
10770203945Sweongyostatic void
10771203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
10772203945Sweongyo{
10773203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10774203945Sweongyo        struct bwn_led *led = sc->sc_blink_led;
10775203945Sweongyo        int rate;
10776203945Sweongyo
10777203945Sweongyo        if (event == BWN_LED_EVENT_POLL) {
10778203945Sweongyo                if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
10779203945Sweongyo                        return;
10780203945Sweongyo                if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
10781203945Sweongyo                        return;
10782203945Sweongyo        }
10783203945Sweongyo
10784203945Sweongyo        sc->sc_led_ticks = ticks;
10785203945Sweongyo        if (sc->sc_led_blinking)
10786203945Sweongyo                return;
10787203945Sweongyo
10788203945Sweongyo        switch (event) {
10789203945Sweongyo        case BWN_LED_EVENT_RX:
10790203945Sweongyo                rate = sc->sc_rx_rate;
10791203945Sweongyo                break;
10792203945Sweongyo        case BWN_LED_EVENT_TX:
10793203945Sweongyo                rate = sc->sc_tx_rate;
10794203945Sweongyo                break;
10795203945Sweongyo        case BWN_LED_EVENT_POLL:
10796203945Sweongyo                rate = 0;
10797203945Sweongyo                break;
10798203945Sweongyo        default:
10799203945Sweongyo                panic("unknown LED event %d\n", event);
10800203945Sweongyo                break;
10801203945Sweongyo        }
10802203945Sweongyo        bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
10803203945Sweongyo            bwn_led_duration[rate].off_dur);
10804203945Sweongyo}
10805203945Sweongyo
10806203945Sweongyostatic void
10807203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
10808203945Sweongyo{
10809203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10810203945Sweongyo        struct bwn_led *led = sc->sc_blink_led;
10811203945Sweongyo        uint16_t val;
10812203945Sweongyo
10813203945Sweongyo        val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10814203945Sweongyo        val = bwn_led_onoff(led, val, 1);
10815203945Sweongyo        BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10816203945Sweongyo
10817203945Sweongyo        if (led->led_flags & BWN_LED_F_SLOW) {
10818203945Sweongyo                BWN_LED_SLOWDOWN(on_dur);
10819203945Sweongyo                BWN_LED_SLOWDOWN(off_dur);
10820203945Sweongyo        }
10821203945Sweongyo
10822203945Sweongyo        sc->sc_led_blinking = 1;
10823203945Sweongyo        sc->sc_led_blink_offdur = off_dur;
10824203945Sweongyo
10825203945Sweongyo        callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
10826203945Sweongyo}
10827203945Sweongyo
10828203945Sweongyostatic void
10829203945Sweongyobwn_led_blink_next(void *arg)
10830203945Sweongyo{
10831203945Sweongyo	struct bwn_mac *mac = arg;
10832203945Sweongyo        struct bwn_softc *sc = mac->mac_sc;
10833203945Sweongyo        uint16_t val;
10834203945Sweongyo
10835203945Sweongyo        val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10836203945Sweongyo        val = bwn_led_onoff(sc->sc_blink_led, val, 0);
10837203945Sweongyo        BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10838203945Sweongyo
10839203945Sweongyo        callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
10840203945Sweongyo            bwn_led_blink_end, mac);
10841203945Sweongyo}
10842203945Sweongyo
10843203945Sweongyostatic void
10844203945Sweongyobwn_led_blink_end(void *arg)
10845203945Sweongyo{
10846203945Sweongyo	struct bwn_mac *mac = arg;
10847203945Sweongyo        struct bwn_softc *sc = mac->mac_sc;
10848203945Sweongyo
10849203945Sweongyo        sc->sc_led_blinking = 0;
10850203945Sweongyo}
10851203945Sweongyo
10852203945Sweongyostatic int
10853203945Sweongyobwn_suspend(device_t dev)
10854203945Sweongyo{
10855203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10856203945Sweongyo
10857203945Sweongyo	bwn_stop(sc, 1);
10858203945Sweongyo	return (0);
10859203945Sweongyo}
10860203945Sweongyo
10861203945Sweongyostatic int
10862203945Sweongyobwn_resume(device_t dev)
10863203945Sweongyo{
10864203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10865203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10866203945Sweongyo
10867203945Sweongyo	if (ifp->if_flags & IFF_UP)
10868203945Sweongyo		bwn_init(sc);
10869203945Sweongyo	return (0);
10870203945Sweongyo}
10871203945Sweongyo
10872203945Sweongyostatic void
10873203945Sweongyobwn_rfswitch(void *arg)
10874203945Sweongyo{
10875203945Sweongyo	struct bwn_softc *sc = arg;
10876203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
10877203945Sweongyo	int cur = 0, prev = 0;
10878203945Sweongyo
10879203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
10880203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
10881203945Sweongyo
10882203945Sweongyo	if (mac->mac_phy.rf_rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
10883203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
10884203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
10885203945Sweongyo			cur = 1;
10886203945Sweongyo	} else {
10887203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
10888203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
10889203945Sweongyo			cur = 1;
10890203945Sweongyo	}
10891203945Sweongyo
10892203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
10893203945Sweongyo		prev = 1;
10894203945Sweongyo
10895203945Sweongyo	if (cur != prev) {
10896203945Sweongyo		if (cur)
10897203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
10898203945Sweongyo		else
10899203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
10900203945Sweongyo
10901203945Sweongyo		device_printf(sc->sc_dev,
10902203945Sweongyo		    "status of RF switch is changed to %s\n",
10903203945Sweongyo		    cur ? "ON" : "OFF");
10904203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
10905203945Sweongyo			if (cur)
10906203945Sweongyo				bwn_rf_turnon(mac);
10907203945Sweongyo			else
10908203945Sweongyo				bwn_rf_turnoff(mac);
10909203945Sweongyo		}
10910203945Sweongyo	}
10911203945Sweongyo
10912203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
10913203945Sweongyo}
10914203945Sweongyo
10915203945Sweongyostatic void
10916203945Sweongyobwn_phy_lp_init_pre(struct bwn_mac *mac)
10917203945Sweongyo{
10918203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
10919203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
10920203945Sweongyo
10921203945Sweongyo	plp->plp_antenna = BWN_ANT_DEFAULT;
10922203945Sweongyo}
10923203945Sweongyo
10924203945Sweongyostatic int
10925203945Sweongyobwn_phy_lp_init(struct bwn_mac *mac)
10926203945Sweongyo{
10927203945Sweongyo	static const struct bwn_stxtable tables[] = {
10928203945Sweongyo		{ 2,  6, 0x3d, 3, 0x01 }, { 1, 12, 0x4c, 1, 0x01 },
10929203945Sweongyo		{ 1,  8, 0x50, 0, 0x7f }, { 0,  8, 0x44, 0, 0xff },
10930203945Sweongyo		{ 1,  0, 0x4a, 0, 0xff }, { 0,  4, 0x4d, 0, 0xff },
10931203945Sweongyo		{ 1,  4, 0x4e, 0, 0xff }, { 0, 12, 0x4f, 0, 0x0f },
10932203945Sweongyo		{ 1,  0, 0x4f, 4, 0x0f }, { 3,  0, 0x49, 0, 0x0f },
10933203945Sweongyo		{ 4,  3, 0x46, 4, 0x07 }, { 3, 15, 0x46, 0, 0x01 },
10934203945Sweongyo		{ 4,  0, 0x46, 1, 0x07 }, { 3,  8, 0x48, 4, 0x07 },
10935203945Sweongyo		{ 3, 11, 0x48, 0, 0x0f }, { 3,  4, 0x49, 4, 0x0f },
10936203945Sweongyo		{ 2, 15, 0x45, 0, 0x01 }, { 5, 13, 0x52, 4, 0x07 },
10937203945Sweongyo		{ 6,  0, 0x52, 7, 0x01 }, { 5,  3, 0x41, 5, 0x07 },
10938203945Sweongyo		{ 5,  6, 0x41, 0, 0x0f }, { 5, 10, 0x42, 5, 0x07 },
10939203945Sweongyo		{ 4, 15, 0x42, 0, 0x01 }, { 5,  0, 0x42, 1, 0x07 },
10940203945Sweongyo		{ 4, 11, 0x43, 4, 0x0f }, { 4,  7, 0x43, 0, 0x0f },
10941203945Sweongyo		{ 4,  6, 0x45, 1, 0x01 }, { 2,  7, 0x40, 4, 0x0f },
10942203945Sweongyo		{ 2, 11, 0x40, 0, 0x0f }
10943203945Sweongyo	};
10944203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
10945203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10946203945Sweongyo	const struct bwn_stxtable *st;
10947203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10948203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10949203945Sweongyo	int i, error;
10950203945Sweongyo	uint16_t tmp;
10951203945Sweongyo
10952203945Sweongyo	bwn_phy_lp_readsprom(mac);	/* XXX bad place */
10953203945Sweongyo	bwn_phy_lp_bbinit(mac);
10954203945Sweongyo
10955203945Sweongyo	/* initialize RF */
10956203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_4WIRECTL, 0x2);
10957203945Sweongyo	DELAY(1);
10958203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_4WIRECTL, 0xfffd);
10959203945Sweongyo	DELAY(1);
10960203945Sweongyo
10961203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2062)
10962203945Sweongyo		bwn_phy_lp_b2062_init(mac);
10963203945Sweongyo	else {
10964203945Sweongyo		bwn_phy_lp_b2063_init(mac);
10965203945Sweongyo
10966203945Sweongyo		/* synchronize stx table. */
10967203945Sweongyo		for (i = 0; i < N(tables); i++) {
10968203945Sweongyo			st = &tables[i];
10969203945Sweongyo			tmp = BWN_RF_READ(mac, st->st_rfaddr);
10970203945Sweongyo			tmp >>= st->st_rfshift;
10971203945Sweongyo			tmp <<= st->st_physhift;
10972203945Sweongyo			BWN_PHY_SETMASK(mac,
10973203945Sweongyo			    BWN_PHY_OFDM(0xf2 + st->st_phyoffset),
10974203945Sweongyo			    ~(st->st_mask << st->st_physhift), tmp);
10975203945Sweongyo		}
10976203945Sweongyo
10977203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf0), 0x5f80);
10978203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf1), 0);
10979203945Sweongyo	}
10980203945Sweongyo
10981203945Sweongyo	/* calibrate RC */
10982203945Sweongyo	if (mac->mac_phy.rev >= 2)
10983203945Sweongyo		bwn_phy_lp_rxcal_r2(mac);
10984203945Sweongyo	else if (!plp->plp_rccap) {
10985203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
10986203945Sweongyo			bwn_phy_lp_rccal_r12(mac);
10987203945Sweongyo	} else
10988203945Sweongyo		bwn_phy_lp_set_rccap(mac);
10989203945Sweongyo
10990203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
10991203945Sweongyo	if (error)
10992203945Sweongyo		device_printf(sc->sc_dev,
10993203945Sweongyo		    "failed to change channel 7 (%d)\n", error);
10994203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
10995203945Sweongyo	bwn_phy_lp_calib(mac);
10996203945Sweongyo	return (0);
10997203945Sweongyo}
10998203945Sweongyo
10999203945Sweongyostatic uint16_t
11000203945Sweongyobwn_phy_lp_read(struct bwn_mac *mac, uint16_t reg)
11001203945Sweongyo{
11002203945Sweongyo
11003203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
11004203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
11005203945Sweongyo}
11006203945Sweongyo
11007203945Sweongyostatic void
11008203945Sweongyobwn_phy_lp_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
11009203945Sweongyo{
11010203945Sweongyo
11011203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
11012203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
11013203945Sweongyo}
11014203945Sweongyo
11015203945Sweongyostatic void
11016203945Sweongyobwn_phy_lp_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
11017203945Sweongyo    uint16_t set)
11018203945Sweongyo{
11019203945Sweongyo
11020203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
11021203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA,
11022203945Sweongyo	    (BWN_READ_2(mac, BWN_PHYDATA) & mask) | set);
11023203945Sweongyo}
11024203945Sweongyo
11025203945Sweongyostatic uint16_t
11026203945Sweongyobwn_phy_lp_rf_read(struct bwn_mac *mac, uint16_t reg)
11027203945Sweongyo{
11028203945Sweongyo
11029203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
11030203945Sweongyo	if (mac->mac_phy.rev < 2 && reg != 0x4001)
11031203945Sweongyo		reg |= 0x100;
11032203945Sweongyo	if (mac->mac_phy.rev >= 2)
11033203945Sweongyo		reg |= 0x200;
11034203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
11035203945Sweongyo	return BWN_READ_2(mac, BWN_RFDATALO);
11036203945Sweongyo}
11037203945Sweongyo
11038203945Sweongyostatic void
11039203945Sweongyobwn_phy_lp_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
11040203945Sweongyo{
11041203945Sweongyo
11042203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
11043203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
11044203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
11045203945Sweongyo}
11046203945Sweongyo
11047203945Sweongyostatic void
11048203945Sweongyobwn_phy_lp_rf_onoff(struct bwn_mac *mac, int on)
11049203945Sweongyo{
11050203945Sweongyo
11051203945Sweongyo	if (on) {
11052203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xe0ff);
11053203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2,
11054203945Sweongyo		    (mac->mac_phy.rev >= 2) ? 0xf7f7 : 0xffe7);
11055203945Sweongyo		return;
11056203945Sweongyo	}
11057203945Sweongyo
11058203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11059203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x83ff);
11060203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
11061203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0x80ff);
11062203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xdfff);
11063203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0808);
11064203945Sweongyo		return;
11065203945Sweongyo	}
11066203945Sweongyo
11067203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xe0ff);
11068203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
11069203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfcff);
11070203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0018);
11071203945Sweongyo}
11072203945Sweongyo
11073203945Sweongyostatic int
11074203945Sweongyobwn_phy_lp_switch_channel(struct bwn_mac *mac, uint32_t chan)
11075203945Sweongyo{
11076203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11077203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11078203945Sweongyo	int error;
11079203945Sweongyo
11080203945Sweongyo	if (phy->rf_ver == 0x2063) {
11081203945Sweongyo		error = bwn_phy_lp_b2063_switch_channel(mac, chan);
11082203945Sweongyo		if (error)
11083203945Sweongyo			return (error);
11084203945Sweongyo	} else {
11085203945Sweongyo		error = bwn_phy_lp_b2062_switch_channel(mac, chan);
11086203945Sweongyo		if (error)
11087203945Sweongyo			return (error);
11088203945Sweongyo		bwn_phy_lp_set_anafilter(mac, chan);
11089203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, ieee80211_ieee2mhz(chan, 0));
11090203945Sweongyo	}
11091203945Sweongyo
11092203945Sweongyo	plp->plp_chan = chan;
11093203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, chan);
11094203945Sweongyo	return (0);
11095203945Sweongyo}
11096203945Sweongyo
11097203945Sweongyostatic uint32_t
11098203945Sweongyobwn_phy_lp_get_default_chan(struct bwn_mac *mac)
11099203945Sweongyo{
11100203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11101203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11102203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11103203945Sweongyo
11104203945Sweongyo	device_printf(sc->sc_dev, "correct?\n");
11105203945Sweongyo
11106203945Sweongyo	return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36);
11107203945Sweongyo}
11108203945Sweongyo
11109203945Sweongyostatic void
11110203945Sweongyobwn_phy_lp_set_antenna(struct bwn_mac *mac, int antenna)
11111203945Sweongyo{
11112203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11113203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11114203945Sweongyo
11115203945Sweongyo	if (phy->rev >= 2 || antenna > BWN_ANTAUTO1)
11116203945Sweongyo		return;
11117203945Sweongyo
11118203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER);
11119203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffd, antenna & 0x2);
11120203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffe, antenna & 0x1);
11121203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_UCODE_ANTDIV_HELPER);
11122203945Sweongyo	plp->plp_antenna = antenna;
11123203945Sweongyo}
11124203945Sweongyo
11125203945Sweongyostatic void
11126203945Sweongyobwn_phy_lp_task_60s(struct bwn_mac *mac)
11127203945Sweongyo{
11128203945Sweongyo
11129203945Sweongyo	bwn_phy_lp_calib(mac);
11130203945Sweongyo}
11131203945Sweongyo
11132203945Sweongyostatic void
11133203945Sweongyobwn_phy_lp_readsprom(struct bwn_mac *mac)
11134203945Sweongyo{
11135203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11136203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11137203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11138203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11139203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11140203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11141203945Sweongyo	struct siba_sprom *sprom = &siba->siba_sprom;
11142203945Sweongyo
11143203945Sweongyo	device_printf(sc->sc_dev, "XXX using %dghz\n",
11144203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2 : 5);
11145203945Sweongyo
11146203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11147203945Sweongyo		plp->plp_txisoband_m = sprom->tri2g;
11148203945Sweongyo		plp->plp_bxarch = sprom->bxa2g;
11149203945Sweongyo		plp->plp_rxpwroffset = sprom->rxpo2g;
11150203945Sweongyo		plp->plp_rssivf = sprom->rssismf2g;
11151203945Sweongyo		plp->plp_rssivc = sprom->rssismc2g;
11152203945Sweongyo		plp->plp_rssigs = sprom->rssisav2g;
11153203945Sweongyo		return;
11154203945Sweongyo	}
11155203945Sweongyo
11156203945Sweongyo	plp->plp_txisoband_l = sprom->tri5gl;
11157203945Sweongyo	plp->plp_txisoband_m = sprom->tri5g;
11158203945Sweongyo	plp->plp_txisoband_h = sprom->tri5gh;
11159203945Sweongyo	plp->plp_bxarch = sprom->bxa5g;
11160203945Sweongyo	plp->plp_rxpwroffset = sprom->rxpo5g;
11161203945Sweongyo	plp->plp_rssivf = sprom->rssismf5g;
11162203945Sweongyo	plp->plp_rssivc = sprom->rssismc5g;
11163203945Sweongyo	plp->plp_rssigs = sprom->rssisav5g;
11164203945Sweongyo}
11165203945Sweongyo
11166203945Sweongyostatic void
11167203945Sweongyobwn_phy_lp_bbinit(struct bwn_mac *mac)
11168203945Sweongyo{
11169203945Sweongyo
11170203945Sweongyo	bwn_phy_lp_tblinit(mac);
11171203945Sweongyo	if (mac->mac_phy.rev >= 2)
11172203945Sweongyo		bwn_phy_lp_bbinit_r2(mac);
11173203945Sweongyo	else
11174203945Sweongyo		bwn_phy_lp_bbinit_r01(mac);
11175203945Sweongyo}
11176203945Sweongyo
11177203945Sweongyostatic void
11178203945Sweongyobwn_phy_lp_txpctl_init(struct bwn_mac *mac)
11179203945Sweongyo{
11180203945Sweongyo	struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 };
11181203945Sweongyo	struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 };
11182203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11183203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11184203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11185203945Sweongyo
11186203945Sweongyo	bwn_phy_lp_set_txgain(mac,
11187203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz);
11188203945Sweongyo	bwn_phy_lp_set_bbmult(mac, 150);
11189203945Sweongyo}
11190203945Sweongyo
11191203945Sweongyostatic void
11192203945Sweongyobwn_phy_lp_calib(struct bwn_mac *mac)
11193203945Sweongyo{
11194203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11195203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11196203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11197203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11198203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11199203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11200203945Sweongyo	const struct bwn_rxcompco *rc = NULL;
11201203945Sweongyo	struct bwn_txgain ogain;
11202203945Sweongyo	int i, omode, oafeovr, orf, obbmult;
11203203945Sweongyo	uint8_t mode, fc = 0;
11204203945Sweongyo
11205203945Sweongyo	if (plp->plp_chanfullcal != plp->plp_chan) {
11206203945Sweongyo		plp->plp_chanfullcal = plp->plp_chan;
11207203945Sweongyo		fc = 1;
11208203945Sweongyo	}
11209203945Sweongyo
11210203945Sweongyo	bwn_mac_suspend(mac);
11211203945Sweongyo
11212203945Sweongyo	/* BlueTooth Coexistance Override */
11213203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_CTL, 0x3);
11214203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_TXCTL, 0xff);
11215203945Sweongyo
11216203945Sweongyo	if (mac->mac_phy.rev >= 2)
11217203945Sweongyo		bwn_phy_lp_digflt_save(mac);
11218203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11219203945Sweongyo	mode = plp->plp_txpctlmode;
11220203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11221203945Sweongyo	if (mac->mac_phy.rev == 0 && mode != BWN_PHYLP_TXPCTL_OFF)
11222203945Sweongyo		bwn_phy_lp_bugfix(mac);
11223203945Sweongyo	if (mac->mac_phy.rev >= 2 && fc == 1) {
11224203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11225203945Sweongyo		omode = plp->plp_txpctlmode;
11226203945Sweongyo		oafeovr = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40;
11227203945Sweongyo		if (oafeovr)
11228203945Sweongyo			ogain = bwn_phy_lp_get_txgain(mac);
11229203945Sweongyo		orf = BWN_PHY_READ(mac, BWN_PHY_RF_PWR_OVERRIDE) & 0xff;
11230203945Sweongyo		obbmult = bwn_phy_lp_get_bbmult(mac);
11231203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11232203945Sweongyo		if (oafeovr)
11233203945Sweongyo			bwn_phy_lp_set_txgain(mac, &ogain);
11234203945Sweongyo		bwn_phy_lp_set_bbmult(mac, obbmult);
11235203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, omode);
11236203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00, orf);
11237203945Sweongyo	}
11238203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11239203945Sweongyo	if (mac->mac_phy.rev >= 2)
11240203945Sweongyo		bwn_phy_lp_digflt_restore(mac);
11241203945Sweongyo
11242203945Sweongyo	/* do RX IQ Calculation; assumes that noise is true. */
11243203945Sweongyo	if (siba->siba_chipid == 0x5354) {
11244203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_5354); i++) {
11245203945Sweongyo			if (bwn_rxcompco_5354[i].rc_chan == plp->plp_chan)
11246203945Sweongyo				rc = &bwn_rxcompco_5354[i];
11247203945Sweongyo		}
11248203945Sweongyo	} else if (mac->mac_phy.rev >= 2)
11249203945Sweongyo		rc = &bwn_rxcompco_r2;
11250203945Sweongyo	else {
11251203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_r12); i++) {
11252203945Sweongyo			if (bwn_rxcompco_r12[i].rc_chan == plp->plp_chan)
11253203945Sweongyo				rc = &bwn_rxcompco_r12[i];
11254203945Sweongyo		}
11255203945Sweongyo	}
11256203945Sweongyo	if (rc == NULL)
11257203945Sweongyo		goto fail;
11258203945Sweongyo
11259203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, rc->rc_c1);
11260203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, rc->rc_c0 << 8);
11261203945Sweongyo
11262203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1 /* TX */, 0 /* RX */);
11263203945Sweongyo
11264203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11265203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
11266203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7, 0);
11267203945Sweongyo	} else {
11268203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
11269203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf, 0);
11270203945Sweongyo	}
11271203945Sweongyo
11272203945Sweongyo	bwn_phy_lp_set_rxgain(mac, 0x2d5d);
11273203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11274203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
11275203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
11276203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
11277203945Sweongyo	bwn_phy_lp_set_deaf(mac, 0);
11278203945Sweongyo	/* XXX no checking return value? */
11279203945Sweongyo	(void)bwn_phy_lp_calc_rx_iq_comp(mac, 0xfff0);
11280203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 0);
11281203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffc);
11282203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfff7);
11283203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffdf);
11284203945Sweongyo
11285203945Sweongyo	/* disable RX GAIN override. */
11286203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffe);
11287203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffef);
11288203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffbf);
11289203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11290203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11291203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11292203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfbff);
11293203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xe5), 0xfff7);
11294203945Sweongyo		}
11295203945Sweongyo	} else {
11296203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfdff);
11297203945Sweongyo	}
11298203945Sweongyo
11299203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11300203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xf7ff);
11301203945Sweongyofail:
11302203945Sweongyo	bwn_mac_enable(mac);
11303203945Sweongyo}
11304203945Sweongyo
11305203945Sweongyostatic void
11306203945Sweongyobwn_phy_lp_switch_analog(struct bwn_mac *mac, int on)
11307203945Sweongyo{
11308203945Sweongyo
11309203945Sweongyo       if (on) {
11310203945Sweongyo               BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfff8);
11311203945Sweongyo	       return;
11312203945Sweongyo       }
11313203945Sweongyo
11314203945Sweongyo       BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVRVAL, 0x0007);
11315203945Sweongyo       BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x0007);
11316203945Sweongyo}
11317203945Sweongyo
11318203945Sweongyostatic int
11319203945Sweongyobwn_phy_lp_b2063_switch_channel(struct bwn_mac *mac, uint8_t chan)
11320203945Sweongyo{
11321203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11322203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11323203945Sweongyo	static const struct bwn_b206x_chan *bc = NULL;
11324203945Sweongyo	uint32_t count, freqref, freqvco, freqxtal, val[3], timeout, timeoutref,
11325203945Sweongyo	    tmp[6];
11326203945Sweongyo	uint16_t old, scale, tmp16;
11327203945Sweongyo	int i, div;
11328203945Sweongyo
11329203945Sweongyo	for (i = 0; i < N(bwn_b2063_chantable); i++) {
11330203945Sweongyo		if (bwn_b2063_chantable[i].bc_chan == chan) {
11331203945Sweongyo			bc = &bwn_b2063_chantable[i];
11332203945Sweongyo			break;
11333203945Sweongyo		}
11334203945Sweongyo	}
11335203945Sweongyo	if (bc == NULL)
11336203945Sweongyo		return (EINVAL);
11337203945Sweongyo
11338203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_VCOBUF1, bc->bc_data[0]);
11339203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_MIXER2, bc->bc_data[1]);
11340203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_BUF2, bc->bc_data[2]);
11341203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_RCCR1, bc->bc_data[3]);
11342203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_1ST3, bc->bc_data[4]);
11343203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND1, bc->bc_data[5]);
11344203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND4, bc->bc_data[6]);
11345203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND7, bc->bc_data[7]);
11346203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_PS6, bc->bc_data[8]);
11347203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL2, bc->bc_data[9]);
11348203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL5, bc->bc_data[10]);
11349203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_CTL11, bc->bc_data[11]);
11350203945Sweongyo
11351203945Sweongyo	old = BWN_RF_READ(mac, BWN_B2063_COM15);
11352203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM15, 0x1e);
11353203945Sweongyo
11354203945Sweongyo	freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
11355203945Sweongyo	freqvco = bc->bc_freq << ((bc->bc_freq > 4000) ? 1 : 2);
11356203945Sweongyo	freqref = freqxtal * 3;
11357203945Sweongyo	div = (freqxtal <= 26000000 ? 1 : 2);
11358203945Sweongyo	timeout = ((((8 * freqxtal) / (div * 5000000)) + 1) >> 1) - 1;
11359203945Sweongyo	timeoutref = ((((8 * freqxtal) / (div * (timeout + 1))) +
11360203945Sweongyo		999999) / 1000000) + 1;
11361203945Sweongyo
11362203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB3, 0x2);
11363203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB6,
11364203945Sweongyo	    0xfff8, timeout >> 2);
11365203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11366203945Sweongyo	    0xff9f,timeout << 5);
11367203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB5, timeoutref);
11368203945Sweongyo
11369203945Sweongyo	val[0] = bwn_phy_lp_roundup(freqxtal, 1000000, 16);
11370203945Sweongyo	val[1] = bwn_phy_lp_roundup(freqxtal, 1000000 * div, 16);
11371203945Sweongyo	val[2] = bwn_phy_lp_roundup(freqvco, 3, 16);
11372203945Sweongyo
11373203945Sweongyo	count = (bwn_phy_lp_roundup(val[2], val[1] + 16, 16) * (timeout + 1) *
11374203945Sweongyo	    (timeoutref + 1)) - 1;
11375203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11376203945Sweongyo	    0xf0, count >> 8);
11377203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB8, count & 0xff);
11378203945Sweongyo
11379203945Sweongyo	tmp[0] = ((val[2] * 62500) / freqref) << 4;
11380203945Sweongyo	tmp[1] = ((val[2] * 62500) % freqref) << 4;
11381203945Sweongyo	while (tmp[1] >= freqref) {
11382203945Sweongyo		tmp[0]++;
11383203945Sweongyo		tmp[1] -= freqref;
11384203945Sweongyo	}
11385203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG1, 0xffe0, tmp[0] >> 4);
11386203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfe0f, tmp[0] << 4);
11387203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfff0, tmp[0] >> 16);
11388203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG3, (tmp[1] >> 8) & 0xff);
11389203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG4, tmp[1] & 0xff);
11390203945Sweongyo
11391203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF1, 0xb9);
11392203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF2, 0x88);
11393203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF3, 0x28);
11394203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF4, 0x63);
11395203945Sweongyo
11396203945Sweongyo	tmp[2] = ((41 * (val[2] - 3000)) /1200) + 27;
11397203945Sweongyo	tmp[3] = bwn_phy_lp_roundup(132000 * tmp[0], 8451, 16);
11398203945Sweongyo
11399203945Sweongyo	if ((tmp[3] + tmp[2] - 1) / tmp[2] > 60) {
11400203945Sweongyo		scale = 1;
11401203945Sweongyo		tmp[4] = ((tmp[3] + tmp[2]) / (tmp[2] << 1)) - 8;
11402203945Sweongyo	} else {
11403203945Sweongyo		scale = 0;
11404203945Sweongyo		tmp[4] = ((tmp[3] + (tmp[2] >> 1)) / tmp[2]) - 8;
11405203945Sweongyo	}
11406203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffc0, tmp[4]);
11407203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffbf, scale << 6);
11408203945Sweongyo
11409203945Sweongyo	tmp[5] = bwn_phy_lp_roundup(100 * val[0], val[2], 16) * (tmp[4] * 8) *
11410203945Sweongyo	    (scale + 1);
11411203945Sweongyo	if (tmp[5] > 150)
11412203945Sweongyo		tmp[5] = 0;
11413203945Sweongyo
11414203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffe0, tmp[5]);
11415203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffdf, scale << 5);
11416203945Sweongyo
11417203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfffb, 0x4);
11418203945Sweongyo	if (freqxtal > 26000000)
11419203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_XTAL_12, 0x2);
11420203945Sweongyo	else
11421203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfd);
11422203945Sweongyo
11423203945Sweongyo	if (val[0] == 45)
11424203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_VCO1, 0x2);
11425203945Sweongyo	else
11426203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_VCO1, 0xfd);
11427203945Sweongyo
11428203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP2, 0x3);
11429203945Sweongyo	DELAY(1);
11430203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP2, 0xfffc);
11431203945Sweongyo
11432203945Sweongyo	/* VCO Calibration */
11433203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, ~0x40);
11434203945Sweongyo	tmp16 = BWN_RF_READ(mac, BWN_B2063_JTAG_CALNRST) & 0xf8;
11435203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16);
11436203945Sweongyo	DELAY(1);
11437203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x4);
11438203945Sweongyo	DELAY(1);
11439203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x6);
11440203945Sweongyo	DELAY(1);
11441203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x7);
11442203945Sweongyo	DELAY(300);
11443203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP1, 0x40);
11444203945Sweongyo
11445203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_COM15, old);
11446203945Sweongyo	return (0);
11447203945Sweongyo}
11448203945Sweongyo
11449203945Sweongyostatic int
11450203945Sweongyobwn_phy_lp_b2062_switch_channel(struct bwn_mac *mac, uint8_t chan)
11451203945Sweongyo{
11452203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11453203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11454203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11455203945Sweongyo	const struct bwn_b206x_chan *bc = NULL;
11456203945Sweongyo	uint32_t freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
11457203945Sweongyo	uint32_t tmp[9];
11458203945Sweongyo	int i;
11459203945Sweongyo
11460203945Sweongyo	for (i = 0; i < N(bwn_b2062_chantable); i++) {
11461203945Sweongyo		if (bwn_b2062_chantable[i].bc_chan == chan) {
11462203945Sweongyo			bc = &bwn_b2062_chantable[i];
11463203945Sweongyo			break;
11464203945Sweongyo		}
11465203945Sweongyo	}
11466203945Sweongyo
11467203945Sweongyo	if (bc == NULL)
11468203945Sweongyo		return (EINVAL);
11469203945Sweongyo
11470203945Sweongyo	BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL14, 0x04);
11471203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE0, bc->bc_data[0]);
11472203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE2, bc->bc_data[1]);
11473203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE3, bc->bc_data[2]);
11474203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_TUNE, bc->bc_data[3]);
11475203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_LGENG_CTL1, bc->bc_data[4]);
11476203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL5, bc->bc_data[5]);
11477203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL6, bc->bc_data[6]);
11478203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PGA, bc->bc_data[7]);
11479203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PAD, bc->bc_data[8]);
11480203945Sweongyo
11481203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xcc);
11482203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0x07);
11483203945Sweongyo	bwn_phy_lp_b2062_reset_pllbias(mac);
11484203945Sweongyo	tmp[0] = freqxtal / 1000;
11485203945Sweongyo	tmp[1] = plp->plp_div * 1000;
11486203945Sweongyo	tmp[2] = tmp[1] * ieee80211_ieee2mhz(chan, 0);
11487203945Sweongyo	if (ieee80211_ieee2mhz(chan, 0) < 4000)
11488203945Sweongyo		tmp[2] *= 2;
11489203945Sweongyo	tmp[3] = 48 * tmp[0];
11490203945Sweongyo	tmp[5] = tmp[2] / tmp[3];
11491203945Sweongyo	tmp[6] = tmp[2] % tmp[3];
11492203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL26, tmp[5]);
11493203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11494203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11495203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11496203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL27, tmp[5]);
11497203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11498203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11499203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11500203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL28, tmp[5]);
11501203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11502203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11503203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11504203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL29,
11505203945Sweongyo	    tmp[5] + ((2 * tmp[6]) / tmp[3]));
11506203945Sweongyo	tmp[7] = BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL19);
11507203945Sweongyo	tmp[8] = ((2 * tmp[2] * (tmp[7] + 1)) + (3 * tmp[0])) / (6 * tmp[0]);
11508203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL23, (tmp[8] >> 8) + 16);
11509203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL24, tmp[8] & 0xff);
11510203945Sweongyo
11511203945Sweongyo	bwn_phy_lp_b2062_vco_calib(mac);
11512203945Sweongyo	if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11513203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xfc);
11514203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0);
11515203945Sweongyo		bwn_phy_lp_b2062_reset_pllbias(mac);
11516203945Sweongyo		bwn_phy_lp_b2062_vco_calib(mac);
11517203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11518203945Sweongyo			BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11519203945Sweongyo			return (EIO);
11520203945Sweongyo		}
11521203945Sweongyo	}
11522203945Sweongyo	BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11523203945Sweongyo	return (0);
11524203945Sweongyo}
11525203945Sweongyo
11526203945Sweongyostatic void
11527203945Sweongyobwn_phy_lp_set_anafilter(struct bwn_mac *mac, uint8_t channel)
11528203945Sweongyo{
11529203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11530203945Sweongyo	uint16_t tmp = (channel == 14);
11531203945Sweongyo
11532203945Sweongyo	if (mac->mac_phy.rev < 2) {
11533203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xfcff, tmp << 9);
11534203945Sweongyo		if ((mac->mac_phy.rev == 1) && (plp->plp_rccap))
11535203945Sweongyo			bwn_phy_lp_set_rccap(mac);
11536203945Sweongyo		return;
11537203945Sweongyo	}
11538203945Sweongyo
11539203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, 0x3f);
11540203945Sweongyo}
11541203945Sweongyo
11542203945Sweongyostatic void
11543203945Sweongyobwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq)
11544203945Sweongyo{
11545203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11546203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11547203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11548203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11549203945Sweongyo	uint16_t iso, tmp[3];
11550203945Sweongyo
11551203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
11552203945Sweongyo
11553203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
11554203945Sweongyo		iso = plp->plp_txisoband_m;
11555203945Sweongyo	else if (freq <= 5320)
11556203945Sweongyo		iso = plp->plp_txisoband_l;
11557203945Sweongyo	else if (freq <= 5700)
11558203945Sweongyo		iso = plp->plp_txisoband_m;
11559203945Sweongyo	else
11560203945Sweongyo		iso = plp->plp_txisoband_h;
11561203945Sweongyo
11562203945Sweongyo	tmp[0] = ((iso - 26) / 12) << 12;
11563203945Sweongyo	tmp[1] = tmp[0] + 0x1000;
11564203945Sweongyo	tmp[2] = tmp[0] + 0x2000;
11565203945Sweongyo
11566203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), 3, tmp);
11567203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), 3, tmp);
11568203945Sweongyo}
11569203945Sweongyo
11570203945Sweongyostatic void
11571203945Sweongyobwn_phy_lp_digflt_save(struct bwn_mac *mac)
11572203945Sweongyo{
11573203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11574203945Sweongyo	int i;
11575203945Sweongyo	static const uint16_t addr[] = {
11576203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11577203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11578203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11579203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11580203945Sweongyo		BWN_PHY_OFDM(0xcf),
11581203945Sweongyo	};
11582203945Sweongyo	static const uint16_t val[] = {
11583203945Sweongyo		0xde5e, 0xe832, 0xe331, 0x4d26,
11584203945Sweongyo		0x0026, 0x1420, 0x0020, 0xfe08,
11585203945Sweongyo		0x0008,
11586203945Sweongyo	};
11587203945Sweongyo
11588203945Sweongyo	for (i = 0; i < N(addr); i++) {
11589203945Sweongyo		plp->plp_digfilt[i] = BWN_PHY_READ(mac, addr[i]);
11590203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], val[i]);
11591203945Sweongyo	}
11592203945Sweongyo}
11593203945Sweongyo
11594203945Sweongyostatic void
11595203945Sweongyobwn_phy_lp_get_txpctlmode(struct bwn_mac *mac)
11596203945Sweongyo{
11597203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11598203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11599203945Sweongyo	uint16_t ctl;
11600203945Sweongyo
11601203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_TX_PWR_CTL_CMD);
11602203945Sweongyo	switch (ctl & BWN_PHY_TX_PWR_CTL_CMD_MODE) {
11603203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF:
11604203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_OFF;
11605203945Sweongyo		break;
11606203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_SW:
11607203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_SW;
11608203945Sweongyo		break;
11609203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_HW:
11610203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_HW;
11611203945Sweongyo		break;
11612203945Sweongyo	default:
11613203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_UNKNOWN;
11614203945Sweongyo		device_printf(sc->sc_dev, "unknown command mode\n");
11615203945Sweongyo		break;
11616203945Sweongyo	}
11617203945Sweongyo}
11618203945Sweongyo
11619203945Sweongyostatic void
11620203945Sweongyobwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
11621203945Sweongyo{
11622203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11623203945Sweongyo	uint16_t ctl;
11624203945Sweongyo	uint8_t old;
11625203945Sweongyo
11626203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11627203945Sweongyo	old = plp->plp_txpctlmode;
11628203945Sweongyo	if (old == mode)
11629203945Sweongyo		return;
11630203945Sweongyo	plp->plp_txpctlmode = mode;
11631203945Sweongyo
11632203945Sweongyo	if (old != BWN_PHYLP_TXPCTL_ON_HW && mode == BWN_PHYLP_TXPCTL_ON_HW) {
11633203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD, 0xff80,
11634203945Sweongyo		    plp->plp_tssiidx);
11635203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_NNUM,
11636203945Sweongyo		    0x8fff, ((uint16_t)plp->plp_tssinpt << 16));
11637203945Sweongyo
11638203945Sweongyo		/* disable TX GAIN override */
11639203945Sweongyo		if (mac->mac_phy.rev < 2)
11640203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11641203945Sweongyo		else {
11642203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xff7f);
11643203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xbfff);
11644203945Sweongyo		}
11645203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xffbf);
11646203945Sweongyo
11647203945Sweongyo		plp->plp_txpwridx = -1;
11648203945Sweongyo	}
11649203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11650203945Sweongyo		if (mode == BWN_PHYLP_TXPCTL_ON_HW)
11651203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xd0), 0x2);
11652203945Sweongyo		else
11653203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xd0), 0xfffd);
11654203945Sweongyo	}
11655203945Sweongyo
11656203945Sweongyo	/* writes TX Power Control mode */
11657203945Sweongyo	switch (plp->plp_txpctlmode) {
11658203945Sweongyo	case BWN_PHYLP_TXPCTL_OFF:
11659203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF;
11660203945Sweongyo		break;
11661203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_HW:
11662203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_HW;
11663203945Sweongyo		break;
11664203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_SW:
11665203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
11666203945Sweongyo		break;
11667203945Sweongyo	default:
11668204242Simp		ctl = 0;
11669203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
11670203945Sweongyo	}
11671203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
11672203945Sweongyo	    (uint16_t)~BWN_PHY_TX_PWR_CTL_CMD_MODE, ctl);
11673203945Sweongyo}
11674203945Sweongyo
11675203945Sweongyostatic void
11676203945Sweongyobwn_phy_lp_bugfix(struct bwn_mac *mac)
11677203945Sweongyo{
11678203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11679203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11680203945Sweongyo	const unsigned int size = 256;
11681203945Sweongyo	struct bwn_txgain tg;
11682203945Sweongyo	uint32_t rxcomp, txgain, coeff, rfpwr, *tabs;
11683203945Sweongyo	uint16_t tssinpt, tssiidx, value[2];
11684203945Sweongyo	uint8_t mode;
11685203945Sweongyo	int8_t txpwridx;
11686203945Sweongyo
11687203945Sweongyo	tabs = (uint32_t *)malloc(sizeof(uint32_t) * size, M_DEVBUF,
11688203945Sweongyo	    M_NOWAIT | M_ZERO);
11689203945Sweongyo	if (tabs == NULL) {
11690203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer.\n");
11691203945Sweongyo		return;
11692203945Sweongyo	}
11693203945Sweongyo
11694203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11695203945Sweongyo	mode = plp->plp_txpctlmode;
11696203945Sweongyo	txpwridx = plp->plp_txpwridx;
11697203945Sweongyo	tssinpt = plp->plp_tssinpt;
11698203945Sweongyo	tssiidx = plp->plp_tssiidx;
11699203945Sweongyo
11700203945Sweongyo	bwn_tab_read_multi(mac,
11701203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11702203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11703203945Sweongyo
11704203945Sweongyo	bwn_phy_lp_tblinit(mac);
11705203945Sweongyo	bwn_phy_lp_bbinit(mac);
11706203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
11707203945Sweongyo	bwn_phy_lp_rf_onoff(mac, 1);
11708203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11709203945Sweongyo
11710203945Sweongyo	bwn_tab_write_multi(mac,
11711203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11712203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11713203945Sweongyo
11714203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, plp->plp_chan);
11715203945Sweongyo	plp->plp_tssinpt = tssinpt;
11716203945Sweongyo	plp->plp_tssiidx = tssiidx;
11717203945Sweongyo	bwn_phy_lp_set_anafilter(mac, plp->plp_chan);
11718203945Sweongyo	if (txpwridx != -1) {
11719203945Sweongyo		/* set TX power by index */
11720203945Sweongyo		plp->plp_txpwridx = txpwridx;
11721203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11722203945Sweongyo		if (plp->plp_txpctlmode != BWN_PHYLP_TXPCTL_OFF)
11723203945Sweongyo			bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_ON_SW);
11724203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11725203945Sweongyo			rxcomp = bwn_tab_read(mac,
11726203945Sweongyo			    BWN_TAB_4(7, txpwridx + 320));
11727203945Sweongyo			txgain = bwn_tab_read(mac,
11728203945Sweongyo			    BWN_TAB_4(7, txpwridx + 192));
11729203945Sweongyo			tg.tg_pad = (txgain >> 16) & 0xff;
11730203945Sweongyo			tg.tg_gm = txgain & 0xff;
11731203945Sweongyo			tg.tg_pga = (txgain >> 8) & 0xff;
11732203945Sweongyo			tg.tg_dac = (rxcomp >> 28) & 0xff;
11733203945Sweongyo			bwn_phy_lp_set_txgain(mac, &tg);
11734203945Sweongyo		} else {
11735203945Sweongyo			rxcomp = bwn_tab_read(mac,
11736203945Sweongyo			    BWN_TAB_4(10, txpwridx + 320));
11737203945Sweongyo			txgain = bwn_tab_read(mac,
11738203945Sweongyo			    BWN_TAB_4(10, txpwridx + 192));
11739203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
11740203945Sweongyo			    0xf800, (txgain >> 4) & 0x7fff);
11741203945Sweongyo			bwn_phy_lp_set_txgain_dac(mac, txgain & 0x7);
11742203945Sweongyo			bwn_phy_lp_set_txgain_pa(mac, (txgain >> 24) & 0x7f);
11743203945Sweongyo		}
11744203945Sweongyo		bwn_phy_lp_set_bbmult(mac, (rxcomp >> 20) & 0xff);
11745203945Sweongyo
11746203945Sweongyo		/* set TX IQCC */
11747203945Sweongyo		value[0] = (rxcomp >> 10) & 0x3ff;
11748203945Sweongyo		value[1] = rxcomp & 0x3ff;
11749203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(0, 80), 2, value);
11750203945Sweongyo
11751203945Sweongyo		coeff = bwn_tab_read(mac,
11752203945Sweongyo		    (mac->mac_phy.rev >= 2) ? BWN_TAB_4(7, txpwridx + 448) :
11753203945Sweongyo		    BWN_TAB_4(10, txpwridx + 448));
11754203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0, 85), coeff & 0xffff);
11755203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11756203945Sweongyo			rfpwr = bwn_tab_read(mac,
11757203945Sweongyo			    BWN_TAB_4(7, txpwridx + 576));
11758203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00,
11759203945Sweongyo			    rfpwr & 0xffff);
11760203945Sweongyo		}
11761203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
11762203945Sweongyo	}
11763203945Sweongyo	if (plp->plp_rccap)
11764203945Sweongyo		bwn_phy_lp_set_rccap(mac);
11765203945Sweongyo	bwn_phy_lp_set_antenna(mac, plp->plp_antenna);
11766203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11767203945Sweongyo	free(tabs, M_DEVBUF);
11768203945Sweongyo}
11769203945Sweongyo
11770203945Sweongyostatic void
11771203945Sweongyobwn_phy_lp_digflt_restore(struct bwn_mac *mac)
11772203945Sweongyo{
11773203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11774203945Sweongyo	int i;
11775203945Sweongyo	static const uint16_t addr[] = {
11776203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11777203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11778203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11779203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11780203945Sweongyo		BWN_PHY_OFDM(0xcf),
11781203945Sweongyo	};
11782203945Sweongyo
11783203945Sweongyo	for (i = 0; i < N(addr); i++)
11784203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], plp->plp_digfilt[i]);
11785203945Sweongyo}
11786203945Sweongyo
11787203945Sweongyostatic void
11788203945Sweongyobwn_phy_lp_tblinit(struct bwn_mac *mac)
11789203945Sweongyo{
11790203945Sweongyo	uint32_t freq = ieee80211_ieee2mhz(bwn_phy_lp_get_default_chan(mac), 0);
11791203945Sweongyo
11792203945Sweongyo	if (mac->mac_phy.rev < 2) {
11793203945Sweongyo		bwn_phy_lp_tblinit_r01(mac);
11794203945Sweongyo		bwn_phy_lp_tblinit_txgain(mac);
11795203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, freq);
11796203945Sweongyo		return;
11797203945Sweongyo	}
11798203945Sweongyo
11799203945Sweongyo	bwn_phy_lp_tblinit_r2(mac);
11800203945Sweongyo	bwn_phy_lp_tblinit_txgain(mac);
11801203945Sweongyo}
11802203945Sweongyo
11803203945Sweongyostruct bwn_wpair {
11804203945Sweongyo	uint16_t		reg;
11805203945Sweongyo	uint16_t		value;
11806203945Sweongyo};
11807203945Sweongyo
11808203945Sweongyostruct bwn_smpair {
11809203945Sweongyo	uint16_t		offset;
11810203945Sweongyo	uint16_t		mask;
11811203945Sweongyo	uint16_t		set;
11812203945Sweongyo};
11813203945Sweongyo
11814203945Sweongyostatic void
11815203945Sweongyobwn_phy_lp_bbinit_r2(struct bwn_mac *mac)
11816203945Sweongyo{
11817203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11818203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11819203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11820203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11821203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11822203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11823203945Sweongyo	static const struct bwn_wpair v1[] = {
11824203945Sweongyo		{ BWN_PHY_AFE_DAC_CTL, 0x50 },
11825203945Sweongyo		{ BWN_PHY_AFE_CTL, 0x8800 },
11826203945Sweongyo		{ BWN_PHY_AFE_CTL_OVR, 0 },
11827203945Sweongyo		{ BWN_PHY_AFE_CTL_OVRVAL, 0 },
11828203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_0, 0 },
11829203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_2, 0 },
11830203945Sweongyo		{ BWN_PHY_OFDM(0xf9), 0 },
11831203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0 }
11832203945Sweongyo	};
11833203945Sweongyo	static const struct bwn_smpair v2[] = {
11834203945Sweongyo		{ BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0xb4 },
11835203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xf8ff, 0x200 },
11836203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xff00, 0x7f },
11837203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xff0f, 0x40 },
11838203945Sweongyo		{ BWN_PHY_PREAMBLECONFIRMTO, 0xff00, 0x2 }
11839203945Sweongyo	};
11840203945Sweongyo	static const struct bwn_smpair v3[] = {
11841203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xffe0, 0x1f },
11842203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11843203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0xff00, 0x19 },
11844203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0x03ff, 0x3c00 },
11845203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xfc1f, 0x3e0 },
11846203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11847203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0x00ff, 0x1900 },
11848203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800 },
11849203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x12 },
11850203945Sweongyo		{ BWN_PHY_GAINMISMATCH, 0x0fff, 0x9000 },
11851203945Sweongyo
11852203945Sweongyo	};
11853203945Sweongyo	int i;
11854203945Sweongyo
11855203945Sweongyo	for (i = 0; i < N(v1); i++)
11856203945Sweongyo		BWN_PHY_WRITE(mac, v1[i].reg, v1[i].value);
11857203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x10);
11858203945Sweongyo	for (i = 0; i < N(v2); i++)
11859203945Sweongyo		BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask, v2[i].set);
11860203945Sweongyo
11861203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x4000);
11862203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x2000);
11863203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_OFDM(0x10a), 0x1);
11864203945Sweongyo	if (siba->siba_board_rev >= 0x18) {
11865203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(17, 65), 0xec);
11866203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x14);
11867203945Sweongyo	} else {
11868203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x10);
11869203945Sweongyo	}
11870203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0xff00, 0xf4);
11871203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0x00ff, 0xf100);
11872203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CLIPTHRESH, 0x48);
11873203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0xff00, 0x46);
11874203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe4), 0xff00, 0x10);
11875203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_PWR_THRESH1, 0xfff0, 0x9);
11876203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_GAINDIRECTMISMATCH, ~0xf);
11877203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5500);
11878203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0xa0);
11879203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_GAINDIRECTMISMATCH, 0xe0ff, 0x300);
11880203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2a00);
11881203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
11882203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11883203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xa);
11884203945Sweongyo	} else {
11885203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x1e00);
11886203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xd);
11887203945Sweongyo	}
11888203945Sweongyo	for (i = 0; i < N(v3); i++)
11889203945Sweongyo		BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask, v3[i].set);
11890203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
11891203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x14), 0);
11892203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x12), 0x40);
11893203945Sweongyo	}
11894203945Sweongyo
11895203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11896203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x40);
11897203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0xb00);
11898203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x6);
11899203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0x9d00);
11900203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0xff00, 0xa1);
11901203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11902203945Sweongyo	} else
11903203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x40);
11904203945Sweongyo
11905203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0xff00, 0xb3);
11906203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00);
11907203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB, 0xff00, plp->plp_rxpwroffset);
11908203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RESET_CTL, 0x44);
11909203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RESET_CTL, 0x80);
11910203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, 0xa954);
11911203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_1,
11912203945Sweongyo	    0x2000 | ((uint16_t)plp->plp_rssigs << 10) |
11913203945Sweongyo	    ((uint16_t)plp->plp_rssivc << 4) | plp->plp_rssivf);
11914203945Sweongyo
11915203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
11916203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_AFE_ADC_CTL_0, 0x1c);
11917203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_CTL, 0x00ff, 0x8800);
11918203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_1, 0xfc3c, 0x0400);
11919203945Sweongyo	}
11920203945Sweongyo
11921203945Sweongyo	bwn_phy_lp_digflt_save(mac);
11922203945Sweongyo}
11923203945Sweongyo
11924203945Sweongyostatic void
11925203945Sweongyobwn_phy_lp_bbinit_r01(struct bwn_mac *mac)
11926203945Sweongyo{
11927203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11928203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11929203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11930203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11931203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11932203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11933203945Sweongyo	static const struct bwn_smpair v1[] = {
11934203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 },
11935203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 },
11936203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x3c00 },
11937203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xfff0, 0x0005 },
11938203945Sweongyo		{ BWN_PHY_GAIN_MISMATCH_LIMIT, 0xffc0, 0x001a },
11939203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0xff00, 0x00b3 },
11940203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00 }
11941203945Sweongyo	};
11942203945Sweongyo	static const struct bwn_smpair v2[] = {
11943203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11944203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0x3f00, 0x0900 },
11945203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11946203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11947203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x000a },
11948203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0400 },
11949203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x000a },
11950203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0b00 },
11951203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xffc0, 0x000a },
11952203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xc0ff, 0x0900 },
11953203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xffc0, 0x000a },
11954203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xc0ff, 0x0b00 },
11955203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xffc0, 0x000a },
11956203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xc0ff, 0x0900 },
11957203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xffc0, 0x000a },
11958203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xc0ff, 0x0b00 }
11959203945Sweongyo	};
11960203945Sweongyo	static const struct bwn_smpair v3[] = {
11961203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0001 },
11962203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0400 },
11963203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0001 },
11964203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0500 },
11965203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11966203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0800 },
11967203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11968203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0a00 }
11969203945Sweongyo	};
11970203945Sweongyo	static const struct bwn_smpair v4[] = {
11971203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0004 },
11972203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0800 },
11973203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0004 },
11974203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0c00 },
11975203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11976203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0100 },
11977203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11978203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0300 }
11979203945Sweongyo	};
11980203945Sweongyo	static const struct bwn_smpair v5[] = {
11981203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11982203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0900 },
11983203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11984203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11985203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0006 },
11986203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0500 },
11987203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0006 },
11988203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0700 }
11989203945Sweongyo	};
11990203945Sweongyo	int i;
11991203945Sweongyo	uint16_t tmp, tmp2;
11992203945Sweongyo
11993203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf7ff);
11994203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL, 0);
11995203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, 0);
11996203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, 0);
11997203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0);
11998203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DAC_CTL, 0x0004);
11999203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0x0078);
12000203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800);
12001203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x0016);
12002203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_0, 0xfff8, 0x0004);
12003203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5400);
12004203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2400);
12005203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
12006203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0x0006);
12007203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_RADIO_CTL, 0xfffe);
12008203945Sweongyo	for (i = 0; i < N(v1); i++)
12009203945Sweongyo		BWN_PHY_SETMASK(mac, v1[i].offset, v1[i].mask, v1[i].set);
12010203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB,
12011203945Sweongyo	    0xff00, plp->plp_rxpwroffset);
12012203945Sweongyo	if ((siba->siba_sprom.bf_lo & BWN_BFL_FEM) &&
12013203945Sweongyo	    ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
12014203945Sweongyo	   (siba->siba_sprom.bf_hi & BWN_BFH_LDO_PAREF))) {
12015203945Sweongyo		siba_cc_pmu_set_ldovolt(&siba->siba_cc, SIBA_LDO_PAREF, 0x28);
12016203945Sweongyo		siba_cc_pmu_set_ldoparef(&siba->siba_cc, 1);
12017203945Sweongyo		if (mac->mac_phy.rev == 0)
12018203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT,
12019203945Sweongyo			    0xffcf, 0x0010);
12020203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 60);
12021203945Sweongyo	} else {
12022203945Sweongyo		siba_cc_pmu_set_ldoparef(&siba->siba_cc, 0);
12023203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT, 0xffcf, 0x0020);
12024203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 100);
12025203945Sweongyo	}
12026203945Sweongyo	tmp = plp->plp_rssivf | plp->plp_rssivc << 4 | 0xa000;
12027203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, tmp);
12028203945Sweongyo	if (siba->siba_sprom.bf_hi & BWN_BFH_RSSIINV)
12029203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x0aaa);
12030203945Sweongyo	else
12031203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x02aa);
12032203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(11, 1), 24);
12033203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_RADIO_CTL,
12034203945Sweongyo	    0xfff9, (plp->plp_bxarch << 1));
12035203945Sweongyo	if (mac->mac_phy.rev == 1 &&
12036203945Sweongyo	    (siba->siba_sprom.bf_hi & BWN_BFH_FEM_BT)) {
12037203945Sweongyo		for (i = 0; i < N(v2); i++)
12038203945Sweongyo			BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask,
12039203945Sweongyo			    v2[i].set);
12040203945Sweongyo	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ||
12041203945Sweongyo	    (siba->siba_board_type == 0x048a) || ((mac->mac_phy.rev == 0) &&
12042203945Sweongyo	    (siba->siba_sprom.bf_lo & BWN_BFL_FEM))) {
12043203945Sweongyo		for (i = 0; i < N(v3); i++)
12044203945Sweongyo			BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask,
12045203945Sweongyo			    v3[i].set);
12046203945Sweongyo	} else if (mac->mac_phy.rev == 1 ||
12047203945Sweongyo		  (siba->siba_sprom.bf_lo & BWN_BFL_FEM)) {
12048203945Sweongyo		for (i = 0; i < N(v4); i++)
12049203945Sweongyo			BWN_PHY_SETMASK(mac, v4[i].offset, v4[i].mask,
12050203945Sweongyo			    v4[i].set);
12051203945Sweongyo	} else {
12052203945Sweongyo		for (i = 0; i < N(v5); i++)
12053203945Sweongyo			BWN_PHY_SETMASK(mac, v5[i].offset, v5[i].mask,
12054203945Sweongyo			    v5[i].set);
12055203945Sweongyo	}
12056203945Sweongyo	if (mac->mac_phy.rev == 1 &&
12057203945Sweongyo	    (siba->siba_sprom.bf_hi & BWN_BFH_LDO_PAREF)) {
12058203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_5, BWN_PHY_TR_LOOKUP_1);
12059203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_6, BWN_PHY_TR_LOOKUP_2);
12060203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_7, BWN_PHY_TR_LOOKUP_3);
12061203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_8, BWN_PHY_TR_LOOKUP_4);
12062203945Sweongyo	}
12063203945Sweongyo	if ((siba->siba_sprom.bf_hi & BWN_BFH_FEM_BT) &&
12064203945Sweongyo	    (siba->siba_chipid == 0x5354) &&
12065203945Sweongyo	    (siba->siba_chippkg == SIBA_CHIPPACK_BCM4712S)) {
12066203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0006);
12067203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_SELECT, 0x0005);
12068203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_OUTEN, 0xffff);
12069203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_PR45960W);
12070203945Sweongyo	}
12071203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12072203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x8000);
12073203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0040);
12074203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0xa400);
12075203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0x0b00);
12076203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x0007);
12077203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xfff8, 0x0003);
12078203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xffc7, 0x0020);
12079203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
12080203945Sweongyo	} else {
12081203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0x7fff);
12082203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xffbf);
12083203945Sweongyo	}
12084203945Sweongyo	if (mac->mac_phy.rev == 1) {
12085203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_CLIPCTRTHRESH);
12086203945Sweongyo		tmp2 = (tmp & 0x03e0) >> 5;
12087203945Sweongyo		tmp2 |= tmp2 << 5;
12088203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C3, tmp2);
12089203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_GAINDIRECTMISMATCH);
12090203945Sweongyo		tmp2 = (tmp & 0x1f00) >> 8;
12091203945Sweongyo		tmp2 |= tmp2 << 5;
12092203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C4, tmp2);
12093203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERYLOWGAINDB);
12094203945Sweongyo		tmp2 = tmp & 0x00ff;
12095203945Sweongyo		tmp2 |= tmp << 8;
12096203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C5, tmp2);
12097203945Sweongyo	}
12098203945Sweongyo}
12099203945Sweongyo
12100203945Sweongyostruct bwn_b2062_freq {
12101203945Sweongyo	uint16_t		freq;
12102203945Sweongyo	uint8_t			value[6];
12103203945Sweongyo};
12104203945Sweongyo
12105203945Sweongyostatic void
12106203945Sweongyobwn_phy_lp_b2062_init(struct bwn_mac *mac)
12107203945Sweongyo{
12108203945Sweongyo#define	CALC_CTL7(freq, div)						\
12109203945Sweongyo	(((800000000 * (div) + (freq)) / (2 * (freq)) - 8) & 0xff)
12110203945Sweongyo#define	CALC_CTL18(freq, div)						\
12111203945Sweongyo	((((100 * (freq) + 16000000 * (div)) / (32000000 * (div))) - 1) & 0xff)
12112203945Sweongyo#define	CALC_CTL19(freq, div)						\
12113203945Sweongyo	((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff)
12114203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12115203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
12116203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
12117203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12118203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12119203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12120203945Sweongyo	static const struct bwn_b2062_freq freqdata_tab[] = {
12121203945Sweongyo		{ 12000, { 6, 6, 6, 6, 10, 6 } },
12122203945Sweongyo		{ 13000, { 4, 4, 4, 4, 11, 7 } },
12123203945Sweongyo		{ 14400, { 3, 3, 3, 3, 12, 7 } },
12124203945Sweongyo		{ 16200, { 3, 3, 3, 3, 13, 8 } },
12125203945Sweongyo		{ 18000, { 2, 2, 2, 2, 14, 8 } },
12126203945Sweongyo		{ 19200, { 1, 1, 1, 1, 14, 9 } }
12127203945Sweongyo	};
12128203945Sweongyo	static const struct bwn_wpair v1[] = {
12129203945Sweongyo		{ BWN_B2062_N_TXCTL3, 0 },
12130203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0 },
12131203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0 },
12132203945Sweongyo		{ BWN_B2062_N_TXCTL6, 0 },
12133203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0x40 },
12134203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0 },
12135203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0x10 },
12136203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0 }
12137203945Sweongyo	};
12138203945Sweongyo	const struct bwn_b2062_freq *f = NULL;
12139203945Sweongyo	uint32_t xtalfreq, ref;
12140203945Sweongyo	unsigned int i;
12141203945Sweongyo
12142203945Sweongyo	bwn_phy_lp_b2062_tblinit(mac);
12143203945Sweongyo
12144203945Sweongyo	for (i = 0; i < N(v1); i++)
12145203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12146203945Sweongyo	if (mac->mac_phy.rev > 0)
12147203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_BG_CTL1,
12148203945Sweongyo		    (BWN_RF_READ(mac, BWN_B2062_N_COM2) >> 1) | 0x80);
12149203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12150203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_N_TSSI_CTL0, 0x1);
12151203945Sweongyo	else
12152203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_N_TSSI_CTL0, ~0x1);
12153203945Sweongyo
12154203945Sweongyo	KASSERT(siba->siba_cc.scc_caps & SIBA_CC_CAPS_PMU,
12155203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
12156203945Sweongyo	xtalfreq = siba->siba_cc.scc_pmu.freq * 1000;
12157203945Sweongyo	KASSERT(xtalfreq != 0, ("%s:%d: fail", __func__, __LINE__));
12158203945Sweongyo
12159203945Sweongyo	if (xtalfreq <= 30000000) {
12160203945Sweongyo		plp->plp_div = 1;
12161203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL1, 0xfffb);
12162203945Sweongyo	} else {
12163203945Sweongyo		plp->plp_div = 2;
12164203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL1, 0x4);
12165203945Sweongyo	}
12166203945Sweongyo
12167203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL7,
12168203945Sweongyo	    CALC_CTL7(xtalfreq, plp->plp_div));
12169203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL18,
12170203945Sweongyo	    CALC_CTL18(xtalfreq, plp->plp_div));
12171203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL19,
12172203945Sweongyo	    CALC_CTL19(xtalfreq, plp->plp_div));
12173203945Sweongyo
12174203945Sweongyo	ref = (1000 * plp->plp_div + 2 * xtalfreq) / (2000 * plp->plp_div);
12175203945Sweongyo	ref &= 0xffff;
12176203945Sweongyo	for (i = 0; i < N(freqdata_tab); i++) {
12177203945Sweongyo		if (ref < freqdata_tab[i].freq) {
12178203945Sweongyo			f = &freqdata_tab[i];
12179203945Sweongyo			break;
12180203945Sweongyo		}
12181203945Sweongyo	}
12182203945Sweongyo	if (f == NULL)
12183203945Sweongyo		f = &freqdata_tab[N(freqdata_tab) - 1];
12184203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL8,
12185203945Sweongyo	    ((uint16_t)(f->value[1]) << 4) | f->value[0]);
12186203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL9,
12187203945Sweongyo	    ((uint16_t)(f->value[3]) << 4) | f->value[2]);
12188203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL10, f->value[4]);
12189203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL11, f->value[5]);
12190203945Sweongyo#undef CALC_CTL7
12191203945Sweongyo#undef CALC_CTL18
12192203945Sweongyo#undef CALC_CTL19
12193203945Sweongyo}
12194203945Sweongyo
12195203945Sweongyostatic void
12196203945Sweongyobwn_phy_lp_b2063_init(struct bwn_mac *mac)
12197203945Sweongyo{
12198203945Sweongyo
12199203945Sweongyo	bwn_phy_lp_b2063_tblinit(mac);
12200203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_SP5, 0);
12201203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM8, 0x38);
12202203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_REG_SP1, 0x56);
12203203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_RX_BB_CTL2, ~0x2);
12204203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0);
12205203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP6, 0x20);
12206203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP9, 0x40);
12207203945Sweongyo	if (mac->mac_phy.rev == 2) {
12208203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0xa0);
12209203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP4, 0xa0);
12210203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x18);
12211203945Sweongyo	} else {
12212203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0x20);
12213203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x20);
12214203945Sweongyo	}
12215203945Sweongyo}
12216203945Sweongyo
12217203945Sweongyostatic void
12218203945Sweongyobwn_phy_lp_rxcal_r2(struct bwn_mac *mac)
12219203945Sweongyo{
12220203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
12221203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
12222203945Sweongyo	static const struct bwn_wpair v1[] = {
12223203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x0 },
12224203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12225203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12226203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x15 },
12227203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x70 },
12228203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL4, 0x52 },
12229203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL5, 0x1 },
12230203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7d }
12231203945Sweongyo	};
12232203945Sweongyo	static const struct bwn_wpair v2[] = {
12233203945Sweongyo		{ BWN_B2063_TX_BB_SP3, 0x0 },
12234203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12235203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12236203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x55 },
12237203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x76 }
12238203945Sweongyo	};
12239203945Sweongyo	uint32_t freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
12240203945Sweongyo	int i;
12241203945Sweongyo	uint8_t tmp;
12242203945Sweongyo
12243203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_RX_BB_SP8) & 0xff;
12244203945Sweongyo
12245203945Sweongyo	for (i = 0; i < 2; i++)
12246203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12247203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, 0xf7);
12248203945Sweongyo	for (i = 2; i < N(v1); i++)
12249203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12250203945Sweongyo	for (i = 0; i < 10000; i++) {
12251203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12252203945Sweongyo			break;
12253203945Sweongyo		DELAY(1000);
12254203945Sweongyo	}
12255203945Sweongyo
12256203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12257203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RX_BB_SP8, tmp);
12258203945Sweongyo
12259203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_TX_BB_SP3) & 0xff;
12260203945Sweongyo
12261203945Sweongyo	for (i = 0; i < N(v2); i++)
12262203945Sweongyo		BWN_RF_WRITE(mac, v2[i].reg, v2[i].value);
12263203945Sweongyo	if (freqxtal == 24000000) {
12264203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0xfc);
12265203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x0);
12266203945Sweongyo	} else {
12267203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0x13);
12268203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x1);
12269203945Sweongyo	}
12270203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0x7d);
12271203945Sweongyo	for (i = 0; i < 10000; i++) {
12272203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12273203945Sweongyo			break;
12274203945Sweongyo		DELAY(1000);
12275203945Sweongyo	}
12276203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12277203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, tmp);
12278203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL1, 0x7e);
12279203945Sweongyo}
12280203945Sweongyo
12281203945Sweongyostatic void
12282203945Sweongyobwn_phy_lp_rccal_r12(struct bwn_mac *mac)
12283203945Sweongyo{
12284203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12285203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12286203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12287203945Sweongyo	struct bwn_txgain tx_gains;
12288203945Sweongyo	static const uint32_t pwrtbl[21] = {
12289203945Sweongyo		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
12290203945Sweongyo		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
12291203945Sweongyo		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
12292203945Sweongyo		0x0004c, 0x0002c, 0x0001a,
12293203945Sweongyo	};
12294203945Sweongyo	uint32_t npwr, ipwr, sqpwr, tmp;
12295203945Sweongyo	int loopback, i, j, sum, error;
12296203945Sweongyo	uint16_t save[7];
12297203945Sweongyo	uint8_t txo, bbmult, txpctlmode;
12298203945Sweongyo
12299203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
12300203945Sweongyo	if (error)
12301203945Sweongyo		device_printf(sc->sc_dev,
12302203945Sweongyo		    "failed to change channel to 7 (%d)\n", error);
12303203945Sweongyo	txo = (BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40) ? 1 : 0;
12304203945Sweongyo	bbmult = bwn_phy_lp_get_bbmult(mac);
12305203945Sweongyo	if (txo)
12306203945Sweongyo		tx_gains = bwn_phy_lp_get_txgain(mac);
12307203945Sweongyo
12308203945Sweongyo	save[0] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_0);
12309203945Sweongyo	save[1] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_VAL_0);
12310203945Sweongyo	save[2] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR);
12311203945Sweongyo	save[3] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVRVAL);
12312203945Sweongyo	save[4] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2);
12313203945Sweongyo	save[5] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2_VAL);
12314203945Sweongyo	save[6] = BWN_PHY_READ(mac, BWN_PHY_LP_PHY_CTL);
12315203945Sweongyo
12316203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
12317203945Sweongyo	txpctlmode = plp->plp_txpctlmode;
12318203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
12319203945Sweongyo
12320203945Sweongyo	/* disable CRS */
12321203945Sweongyo	bwn_phy_lp_set_deaf(mac, 1);
12322203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 0, 1);
12323203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffb);
12324203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x4);
12325203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7);
12326203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
12327203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x10);
12328203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12329203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf);
12330203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
12331203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffbf);
12332203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12333203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x7);
12334203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x38);
12335203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f);
12336203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x100);
12337203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfdff);
12338203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL0, 0);
12339203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL1, 1);
12340203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL2, 0x20);
12341203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfbff);
12342203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xf7ff);
12343203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
12344203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45af);
12345203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0x3ff);
12346203945Sweongyo
12347203945Sweongyo	loopback = bwn_phy_lp_loopback(mac);
12348203945Sweongyo	if (loopback == -1)
12349203945Sweongyo		goto done;
12350203945Sweongyo	bwn_phy_lp_set_rxgain_idx(mac, loopback);
12351203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xffbf, 0x40);
12352203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfff8, 0x1);
12353203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xffc7, 0x8);
12354203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f, 0xc0);
12355203945Sweongyo
12356203945Sweongyo	tmp = 0;
12357203945Sweongyo	memset(&ie, 0, sizeof(ie));
12358203945Sweongyo	for (i = 128; i <= 159; i++) {
12359203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2, i);
12360203945Sweongyo		sum = 0;
12361203945Sweongyo		for (j = 5; j <= 25; j++) {
12362203945Sweongyo			bwn_phy_lp_ddfs_turnon(mac, 1, 1, j, j, 0);
12363203945Sweongyo			if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
12364203945Sweongyo				goto done;
12365203945Sweongyo			sqpwr = ie.ie_ipwr + ie.ie_qpwr;
12366203945Sweongyo			ipwr = ((pwrtbl[j - 5] >> 3) + 1) >> 1;
12367203945Sweongyo			npwr = bwn_phy_lp_roundup(sqpwr, (j == 5) ? sqpwr : 0,
12368203945Sweongyo			    12);
12369203945Sweongyo			sum += ((ipwr - npwr) * (ipwr - npwr));
12370203945Sweongyo			if ((i == 128) || (sum < tmp)) {
12371203945Sweongyo				plp->plp_rccap = i;
12372203945Sweongyo				tmp = sum;
12373203945Sweongyo			}
12374203945Sweongyo		}
12375203945Sweongyo	}
12376203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
12377203945Sweongyodone:
12378203945Sweongyo	/* restore CRS */
12379203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 1);
12380203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xff80);
12381203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfc00);
12382203945Sweongyo
12383203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_VAL_0, save[1]);
12384203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, save[0]);
12385203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVRVAL, save[3]);
12386203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, save[2]);
12387203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2_VAL, save[5]);
12388203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, save[4]);
12389203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LP_PHY_CTL, save[6]);
12390203945Sweongyo
12391203945Sweongyo	bwn_phy_lp_set_bbmult(mac, bbmult);
12392203945Sweongyo	if (txo)
12393203945Sweongyo		bwn_phy_lp_set_txgain(mac, &tx_gains);
12394203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, txpctlmode);
12395203945Sweongyo	if (plp->plp_rccap)
12396203945Sweongyo		bwn_phy_lp_set_rccap(mac);
12397203945Sweongyo}
12398203945Sweongyo
12399203945Sweongyostatic void
12400203945Sweongyobwn_phy_lp_set_rccap(struct bwn_mac *mac)
12401203945Sweongyo{
12402203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12403203945Sweongyo	uint8_t rc_cap = (plp->plp_rccap & 0x1f) >> 1;
12404203945Sweongyo
12405203945Sweongyo	if (mac->mac_phy.rev == 1)
12406203945Sweongyo		rc_cap = MIN(rc_cap + 5, 15);
12407203945Sweongyo
12408203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2,
12409203945Sweongyo	    MAX(plp->plp_rccap - 4, 0x80));
12410203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, rc_cap | 0x80);
12411203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RXG_CNT16,
12412203945Sweongyo	    ((plp->plp_rccap & 0x1f) >> 2) | 0x80);
12413203945Sweongyo}
12414203945Sweongyo
12415203945Sweongyostatic uint32_t
12416203945Sweongyobwn_phy_lp_roundup(uint32_t value, uint32_t div, uint8_t pre)
12417203945Sweongyo{
12418203945Sweongyo	uint32_t i, q, r;
12419203945Sweongyo
12420203945Sweongyo	if (div == 0)
12421203945Sweongyo		return (0);
12422203945Sweongyo
12423203945Sweongyo	for (i = 0, q = value / div, r = value % div; i < pre; i++) {
12424203945Sweongyo		q <<= 1;
12425203945Sweongyo		if (r << 1 >= div) {
12426203945Sweongyo			q++;
12427203945Sweongyo			r = (r << 1) - div;
12428203945Sweongyo		}
12429203945Sweongyo	}
12430203945Sweongyo	if (r << 1 >= div)
12431203945Sweongyo		q++;
12432203945Sweongyo	return (q);
12433203945Sweongyo}
12434203945Sweongyo
12435203945Sweongyostatic void
12436203945Sweongyobwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *mac)
12437203945Sweongyo{
12438203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
12439203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
12440203945Sweongyo
12441203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0xff);
12442203945Sweongyo	DELAY(20);
12443203945Sweongyo	if (siba->siba_chipid == 0x5354) {
12444203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_COM1, 4);
12445203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 4);
12446203945Sweongyo	} else {
12447203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0);
12448203945Sweongyo	}
12449203945Sweongyo	DELAY(5);
12450203945Sweongyo}
12451203945Sweongyo
12452203945Sweongyostatic void
12453203945Sweongyobwn_phy_lp_b2062_vco_calib(struct bwn_mac *mac)
12454203945Sweongyo{
12455203945Sweongyo
12456203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x42);
12457203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x62);
12458203945Sweongyo	DELAY(200);
12459203945Sweongyo}
12460203945Sweongyo
12461203945Sweongyostatic void
12462203945Sweongyobwn_phy_lp_b2062_tblinit(struct bwn_mac *mac)
12463203945Sweongyo{
12464203945Sweongyo#define	FLAG_A	0x01
12465203945Sweongyo#define	FLAG_G	0x02
12466203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12467203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12468203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12469203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = {
12470203945Sweongyo		{ BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12471203945Sweongyo		{ BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, },
12472203945Sweongyo		{ BWN_B2062_N_PDNCTL3, 0x0, 0x0, FLAG_A | FLAG_G, },
12473203945Sweongyo		{ BWN_B2062_N_PDNCTL4, 0x15, 0x2a, FLAG_A | FLAG_G, },
12474203945Sweongyo		{ BWN_B2062_N_LGENC, 0xDB, 0xff, FLAG_A, },
12475203945Sweongyo		{ BWN_B2062_N_LGENATUNE0, 0xdd, 0x0, FLAG_A | FLAG_G, },
12476203945Sweongyo		{ BWN_B2062_N_LGENATUNE2, 0xdd, 0x0, FLAG_A | FLAG_G, },
12477203945Sweongyo		{ BWN_B2062_N_LGENATUNE3, 0x77, 0xB5, FLAG_A | FLAG_G, },
12478203945Sweongyo		{ BWN_B2062_N_LGENACTL3, 0x0, 0xff, FLAG_A | FLAG_G, },
12479203945Sweongyo		{ BWN_B2062_N_LGENACTL7, 0x33, 0x33, FLAG_A | FLAG_G, },
12480203945Sweongyo		{ BWN_B2062_N_RXA_CTL1, 0x0, 0x0, FLAG_G, },
12481203945Sweongyo		{ BWN_B2062_N_RXBB_CTL0, 0x82, 0x80, FLAG_A | FLAG_G, },
12482203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN1, 0x4, 0x4, FLAG_A | FLAG_G, },
12483203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN2, 0x0, 0x0, FLAG_A | FLAG_G, },
12484203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0x3, 0x3, FLAG_A | FLAG_G, },
12485203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0x2, 0x2, FLAG_A | FLAG_G, },
12486203945Sweongyo		{ BWN_B2062_N_TX_TUNE, 0x88, 0x1b, FLAG_A | FLAG_G, },
12487203945Sweongyo		{ BWN_B2062_S_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12488203945Sweongyo		{ BWN_B2062_S_PDS_CTL0, 0xff, 0xff, FLAG_A | FLAG_G, },
12489203945Sweongyo		{ BWN_B2062_S_LGENG_CTL0, 0xf8, 0xd8, FLAG_A | FLAG_G, },
12490203945Sweongyo		{ BWN_B2062_S_LGENG_CTL1, 0x3c, 0x24, FLAG_A | FLAG_G, },
12491203945Sweongyo		{ BWN_B2062_S_LGENG_CTL8, 0x88, 0x80, FLAG_A | FLAG_G, },
12492203945Sweongyo		{ BWN_B2062_S_LGENG_CTL10, 0x88, 0x80, FLAG_A | FLAG_G, },
12493203945Sweongyo		{ BWN_B2062_S_RFPLLCTL0, 0x98, 0x98, FLAG_A | FLAG_G, },
12494203945Sweongyo		{ BWN_B2062_S_RFPLLCTL1, 0x10, 0x10, FLAG_A | FLAG_G, },
12495203945Sweongyo		{ BWN_B2062_S_RFPLLCTL5, 0x43, 0x43, FLAG_A | FLAG_G, },
12496203945Sweongyo		{ BWN_B2062_S_RFPLLCTL6, 0x47, 0x47, FLAG_A | FLAG_G, },
12497203945Sweongyo		{ BWN_B2062_S_RFPLLCTL7, 0xc, 0xc, FLAG_A | FLAG_G, },
12498203945Sweongyo		{ BWN_B2062_S_RFPLLCTL8, 0x11, 0x11, FLAG_A | FLAG_G, },
12499203945Sweongyo		{ BWN_B2062_S_RFPLLCTL9, 0x11, 0x11, FLAG_A | FLAG_G, },
12500203945Sweongyo		{ BWN_B2062_S_RFPLLCTL10, 0xe, 0xe, FLAG_A | FLAG_G, },
12501203945Sweongyo		{ BWN_B2062_S_RFPLLCTL11, 0x8, 0x8, FLAG_A | FLAG_G, },
12502203945Sweongyo		{ BWN_B2062_S_RFPLLCTL12, 0x33, 0x33, FLAG_A | FLAG_G, },
12503203945Sweongyo		{ BWN_B2062_S_RFPLLCTL13, 0xa, 0xa, FLAG_A | FLAG_G, },
12504203945Sweongyo		{ BWN_B2062_S_RFPLLCTL14, 0x6, 0x6, FLAG_A | FLAG_G, },
12505203945Sweongyo		{ BWN_B2062_S_RFPLLCTL18, 0x3e, 0x3e, FLAG_A | FLAG_G, },
12506203945Sweongyo		{ BWN_B2062_S_RFPLLCTL19, 0x13, 0x13, FLAG_A | FLAG_G, },
12507203945Sweongyo		{ BWN_B2062_S_RFPLLCTL21, 0x62, 0x62, FLAG_A | FLAG_G, },
12508203945Sweongyo		{ BWN_B2062_S_RFPLLCTL22, 0x7, 0x7, FLAG_A | FLAG_G, },
12509203945Sweongyo		{ BWN_B2062_S_RFPLLCTL23, 0x16, 0x16, FLAG_A | FLAG_G, },
12510203945Sweongyo		{ BWN_B2062_S_RFPLLCTL24, 0x5c, 0x5c, FLAG_A | FLAG_G, },
12511203945Sweongyo		{ BWN_B2062_S_RFPLLCTL25, 0x95, 0x95, FLAG_A | FLAG_G, },
12512203945Sweongyo		{ BWN_B2062_S_RFPLLCTL30, 0xa0, 0xa0, FLAG_A | FLAG_G, },
12513203945Sweongyo		{ BWN_B2062_S_RFPLLCTL31, 0x4, 0x4, FLAG_A | FLAG_G, },
12514203945Sweongyo		{ BWN_B2062_S_RFPLLCTL33, 0xcc, 0xcc, FLAG_A | FLAG_G, },
12515203945Sweongyo		{ BWN_B2062_S_RFPLLCTL34, 0x7, 0x7, FLAG_A | FLAG_G, },
12516203945Sweongyo		{ BWN_B2062_S_RXG_CNT8, 0xf, 0xf, FLAG_A, },
12517203945Sweongyo	};
12518203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12519203945Sweongyo	unsigned int i;
12520203945Sweongyo
12521203945Sweongyo	for (i = 0; i < N(bwn_b2062_init_tab); i++) {
12522203945Sweongyo		br = &bwn_b2062_init_tab[i];
12523203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12524203945Sweongyo			if (br->br_flags & FLAG_G)
12525203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12526203945Sweongyo		} else {
12527203945Sweongyo			if (br->br_flags & FLAG_A)
12528203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12529203945Sweongyo		}
12530203945Sweongyo	}
12531203945Sweongyo#undef FLAG_A
12532203945Sweongyo#undef FLAG_B
12533203945Sweongyo}
12534203945Sweongyo
12535203945Sweongyostatic void
12536203945Sweongyobwn_phy_lp_b2063_tblinit(struct bwn_mac *mac)
12537203945Sweongyo{
12538203945Sweongyo#define	FLAG_A	0x01
12539203945Sweongyo#define	FLAG_G	0x02
12540203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12541203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12542203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12543203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = {
12544203945Sweongyo		{ BWN_B2063_COM1, 0x0, 0x0, FLAG_G, },
12545203945Sweongyo		{ BWN_B2063_COM10, 0x1, 0x0, FLAG_A, },
12546203945Sweongyo		{ BWN_B2063_COM16, 0x0, 0x0, FLAG_G, },
12547203945Sweongyo		{ BWN_B2063_COM17, 0x0, 0x0, FLAG_G, },
12548203945Sweongyo		{ BWN_B2063_COM18, 0x0, 0x0, FLAG_G, },
12549203945Sweongyo		{ BWN_B2063_COM19, 0x0, 0x0, FLAG_G, },
12550203945Sweongyo		{ BWN_B2063_COM20, 0x0, 0x0, FLAG_G, },
12551203945Sweongyo		{ BWN_B2063_COM21, 0x0, 0x0, FLAG_G, },
12552203945Sweongyo		{ BWN_B2063_COM22, 0x0, 0x0, FLAG_G, },
12553203945Sweongyo		{ BWN_B2063_COM23, 0x0, 0x0, FLAG_G, },
12554203945Sweongyo		{ BWN_B2063_COM24, 0x0, 0x0, FLAG_G, },
12555203945Sweongyo		{ BWN_B2063_LOGEN_SP1, 0xe8, 0xd4, FLAG_A | FLAG_G, },
12556203945Sweongyo		{ BWN_B2063_LOGEN_SP2, 0xa7, 0x53, FLAG_A | FLAG_G, },
12557203945Sweongyo		{ BWN_B2063_LOGEN_SP4, 0xf0, 0xf, FLAG_A | FLAG_G, },
12558203945Sweongyo		{ BWN_B2063_G_RX_SP1, 0x1f, 0x5e, FLAG_G, },
12559203945Sweongyo		{ BWN_B2063_G_RX_SP2, 0x7f, 0x7e, FLAG_G, },
12560203945Sweongyo		{ BWN_B2063_G_RX_SP3, 0x30, 0xf0, FLAG_G, },
12561203945Sweongyo		{ BWN_B2063_G_RX_SP7, 0x7f, 0x7f, FLAG_A | FLAG_G, },
12562203945Sweongyo		{ BWN_B2063_G_RX_SP10, 0xc, 0xc, FLAG_A | FLAG_G, },
12563203945Sweongyo		{ BWN_B2063_A_RX_SP1, 0x3c, 0x3f, FLAG_A, },
12564203945Sweongyo		{ BWN_B2063_A_RX_SP2, 0xfc, 0xfe, FLAG_A, },
12565203945Sweongyo		{ BWN_B2063_A_RX_SP7, 0x8, 0x8, FLAG_A | FLAG_G, },
12566203945Sweongyo		{ BWN_B2063_RX_BB_SP4, 0x60, 0x60, FLAG_A | FLAG_G, },
12567203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x30, 0x30, FLAG_A | FLAG_G, },
12568203945Sweongyo		{ BWN_B2063_TX_RF_SP3, 0xc, 0xb, FLAG_A | FLAG_G, },
12569203945Sweongyo		{ BWN_B2063_TX_RF_SP4, 0x10, 0xf, FLAG_A | FLAG_G, },
12570203945Sweongyo		{ BWN_B2063_PA_SP1, 0x3d, 0xfd, FLAG_A | FLAG_G, },
12571203945Sweongyo		{ BWN_B2063_TX_BB_SP1, 0x2, 0x2, FLAG_A | FLAG_G, },
12572203945Sweongyo		{ BWN_B2063_BANDGAP_CTL1, 0x56, 0x56, FLAG_A | FLAG_G, },
12573203945Sweongyo		{ BWN_B2063_JTAG_VCO2, 0xF7, 0xF7, FLAG_A | FLAG_G, },
12574203945Sweongyo		{ BWN_B2063_G_RX_MIX3, 0x71, 0x71, FLAG_A | FLAG_G, },
12575203945Sweongyo		{ BWN_B2063_G_RX_MIX4, 0x71, 0x71, FLAG_A | FLAG_G, },
12576203945Sweongyo		{ BWN_B2063_A_RX_1ST2, 0xf0, 0x30, FLAG_A, },
12577203945Sweongyo		{ BWN_B2063_A_RX_PS6, 0x77, 0x77, FLAG_A | FLAG_G, },
12578203945Sweongyo		{ BWN_B2063_A_RX_MIX4, 0x3, 0x3, FLAG_A | FLAG_G, },
12579203945Sweongyo		{ BWN_B2063_A_RX_MIX5, 0xf, 0xf, FLAG_A | FLAG_G, },
12580203945Sweongyo		{ BWN_B2063_A_RX_MIX6, 0xf, 0xf, FLAG_A | FLAG_G, },
12581203945Sweongyo		{ BWN_B2063_RX_TIA_CTL1, 0x77, 0x77, FLAG_A | FLAG_G, },
12582203945Sweongyo		{ BWN_B2063_RX_TIA_CTL3, 0x77, 0x77, FLAG_A | FLAG_G, },
12583203945Sweongyo		{ BWN_B2063_RX_BB_CTL2, 0x4, 0x4, FLAG_A | FLAG_G, },
12584203945Sweongyo		{ BWN_B2063_PA_CTL1, 0x0, 0x4, FLAG_A, },
12585203945Sweongyo		{ BWN_B2063_VREG_CTL1, 0x3, 0x3, FLAG_A | FLAG_G, },
12586203945Sweongyo	};
12587203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12588203945Sweongyo	unsigned int i;
12589203945Sweongyo
12590203945Sweongyo	for (i = 0; i < N(bwn_b2063_init_tab); i++) {
12591203945Sweongyo		br = &bwn_b2063_init_tab[i];
12592203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12593203945Sweongyo			if (br->br_flags & FLAG_G)
12594203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12595203945Sweongyo		} else {
12596203945Sweongyo			if (br->br_flags & FLAG_A)
12597203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12598203945Sweongyo		}
12599203945Sweongyo	}
12600203945Sweongyo#undef FLAG_A
12601203945Sweongyo#undef FLAG_B
12602203945Sweongyo}
12603203945Sweongyo
12604203945Sweongyostatic void
12605203945Sweongyobwn_tab_read_multi(struct bwn_mac *mac, uint32_t typenoffset,
12606203945Sweongyo    int count, void *_data)
12607203945Sweongyo{
12608203945Sweongyo	unsigned int i;
12609203945Sweongyo	uint32_t offset, type;
12610203945Sweongyo	uint8_t *data = _data;
12611203945Sweongyo
12612203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12613203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12614203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12615203945Sweongyo
12616203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12617203945Sweongyo
12618203945Sweongyo	for (i = 0; i < count; i++) {
12619203945Sweongyo		switch (type) {
12620203945Sweongyo		case BWN_TAB_8BIT:
12621203945Sweongyo			*data = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
12622203945Sweongyo			data++;
12623203945Sweongyo			break;
12624203945Sweongyo		case BWN_TAB_16BIT:
12625203945Sweongyo			*((uint16_t *)data) = BWN_PHY_READ(mac,
12626203945Sweongyo			    BWN_PHY_TABLEDATALO);
12627203945Sweongyo			data += 2;
12628203945Sweongyo			break;
12629203945Sweongyo		case BWN_TAB_32BIT:
12630203945Sweongyo			*((uint32_t *)data) = BWN_PHY_READ(mac,
12631203945Sweongyo			    BWN_PHY_TABLEDATAHI);
12632203945Sweongyo			*((uint32_t *)data) <<= 16;
12633203945Sweongyo			*((uint32_t *)data) |= BWN_PHY_READ(mac,
12634203945Sweongyo			    BWN_PHY_TABLEDATALO);
12635203945Sweongyo			data += 4;
12636203945Sweongyo			break;
12637203945Sweongyo		default:
12638203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12639203945Sweongyo		}
12640203945Sweongyo	}
12641203945Sweongyo}
12642203945Sweongyo
12643203945Sweongyostatic void
12644203945Sweongyobwn_tab_write_multi(struct bwn_mac *mac, uint32_t typenoffset,
12645203945Sweongyo    int count, const void *_data)
12646203945Sweongyo{
12647203945Sweongyo	uint32_t offset, type, value;
12648203945Sweongyo	const uint8_t *data = _data;
12649203945Sweongyo	unsigned int i;
12650203945Sweongyo
12651203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12652203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12653203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12654203945Sweongyo
12655203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12656203945Sweongyo
12657203945Sweongyo	for (i = 0; i < count; i++) {
12658203945Sweongyo		switch (type) {
12659203945Sweongyo		case BWN_TAB_8BIT:
12660203945Sweongyo			value = *data;
12661203945Sweongyo			data++;
12662203945Sweongyo			KASSERT(!(value & ~0xff),
12663203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12664203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12665203945Sweongyo			break;
12666203945Sweongyo		case BWN_TAB_16BIT:
12667203945Sweongyo			value = *((const uint16_t *)data);
12668203945Sweongyo			data += 2;
12669203945Sweongyo			KASSERT(!(value & ~0xffff),
12670203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12671203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12672203945Sweongyo			break;
12673203945Sweongyo		case BWN_TAB_32BIT:
12674203945Sweongyo			value = *((const uint32_t *)data);
12675203945Sweongyo			data += 4;
12676203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
12677203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12678203945Sweongyo			break;
12679203945Sweongyo		default:
12680203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12681203945Sweongyo		}
12682203945Sweongyo	}
12683203945Sweongyo}
12684203945Sweongyo
12685203945Sweongyostatic struct bwn_txgain
12686203945Sweongyobwn_phy_lp_get_txgain(struct bwn_mac *mac)
12687203945Sweongyo{
12688203945Sweongyo	struct bwn_txgain tg;
12689203945Sweongyo	uint16_t tmp;
12690203945Sweongyo
12691203945Sweongyo	tg.tg_dac = (BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0x380) >> 7;
12692203945Sweongyo	if (mac->mac_phy.rev < 2) {
12693203945Sweongyo		tmp = BWN_PHY_READ(mac,
12694203945Sweongyo		    BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7ff;
12695203945Sweongyo		tg.tg_gm = tmp & 0x0007;
12696203945Sweongyo		tg.tg_pga = (tmp & 0x0078) >> 3;
12697203945Sweongyo		tg.tg_pad = (tmp & 0x780) >> 7;
12698203945Sweongyo		return (tg);
12699203945Sweongyo	}
12700203945Sweongyo
12701203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL);
12702203945Sweongyo	tg.tg_pad = BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0xff;
12703203945Sweongyo	tg.tg_gm = tmp & 0xff;
12704203945Sweongyo	tg.tg_pga = (tmp >> 8) & 0xff;
12705203945Sweongyo	return (tg);
12706203945Sweongyo}
12707203945Sweongyo
12708203945Sweongyostatic uint8_t
12709203945Sweongyobwn_phy_lp_get_bbmult(struct bwn_mac *mac)
12710203945Sweongyo{
12711203945Sweongyo
12712203945Sweongyo	return (bwn_tab_read(mac, BWN_TAB_2(0, 87)) & 0xff00) >> 8;
12713203945Sweongyo}
12714203945Sweongyo
12715203945Sweongyostatic void
12716203945Sweongyobwn_phy_lp_set_txgain(struct bwn_mac *mac, struct bwn_txgain *tg)
12717203945Sweongyo{
12718203945Sweongyo	uint16_t pa;
12719203945Sweongyo
12720203945Sweongyo	if (mac->mac_phy.rev < 2) {
12721203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xf800,
12722203945Sweongyo		    (tg->tg_pad << 7) | (tg->tg_pga << 3) | tg->tg_gm);
12723203945Sweongyo		bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12724203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
12725203945Sweongyo		return;
12726203945Sweongyo	}
12727203945Sweongyo
12728203945Sweongyo	pa = bwn_phy_lp_get_pa_gain(mac);
12729203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
12730203945Sweongyo	    (tg->tg_pga << 8) | tg->tg_gm);
12731203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0x8000,
12732203945Sweongyo	    tg->tg_pad | (pa << 6));
12733203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xfc), (tg->tg_pga << 8) | tg->tg_gm);
12734203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x8000,
12735203945Sweongyo	    tg->tg_pad | (pa << 8));
12736203945Sweongyo	bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12737203945Sweongyo	bwn_phy_lp_set_txgain_override(mac);
12738203945Sweongyo}
12739203945Sweongyo
12740203945Sweongyostatic void
12741203945Sweongyobwn_phy_lp_set_bbmult(struct bwn_mac *mac, uint8_t bbmult)
12742203945Sweongyo{
12743203945Sweongyo
12744203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(0, 87), (uint16_t)bbmult << 8);
12745203945Sweongyo}
12746203945Sweongyo
12747203945Sweongyostatic void
12748203945Sweongyobwn_phy_lp_set_trsw_over(struct bwn_mac *mac, uint8_t tx, uint8_t rx)
12749203945Sweongyo{
12750203945Sweongyo	uint16_t trsw = (tx << 1) | rx;
12751203945Sweongyo
12752203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffc, trsw);
12753203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x3);
12754203945Sweongyo}
12755203945Sweongyo
12756203945Sweongyostatic void
12757203945Sweongyobwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain)
12758203945Sweongyo{
12759203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12760203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12761203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12762203945Sweongyo	uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp;
12763203945Sweongyo
12764203945Sweongyo	if (mac->mac_phy.rev < 2) {
12765203945Sweongyo		trsw = gain & 0x1;
12766203945Sweongyo		lna = (gain & 0xfffc) | ((gain & 0xc) >> 2);
12767203945Sweongyo		ext_lna = (gain & 2) >> 1;
12768203945Sweongyo
12769203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12770203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12771203945Sweongyo		    0xfbff, ext_lna << 10);
12772203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12773203945Sweongyo		    0xf7ff, ext_lna << 11);
12774203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
12775203945Sweongyo	} else {
12776203945Sweongyo		low_gain = gain & 0xffff;
12777203945Sweongyo		high_gain = (gain >> 16) & 0xf;
12778203945Sweongyo		ext_lna = (gain >> 21) & 0x1;
12779203945Sweongyo		trsw = ~(gain >> 20) & 0x1;
12780203945Sweongyo
12781203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12782203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12783203945Sweongyo		    0xfdff, ext_lna << 9);
12784203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12785203945Sweongyo		    0xfbff, ext_lna << 10);
12786203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
12787203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff0, high_gain);
12788203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12789203945Sweongyo			tmp = (gain >> 2) & 0x3;
12790203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12791203945Sweongyo			    0xe7ff, tmp<<11);
12792203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe6), 0xffe7,
12793203945Sweongyo			    tmp << 3);
12794203945Sweongyo		}
12795203945Sweongyo	}
12796203945Sweongyo
12797203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1);
12798203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12799203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12800203945Sweongyo	if (mac->mac_phy.rev >= 2) {
12801203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
12802203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12803203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x400);
12804203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xe5), 0x8);
12805203945Sweongyo		}
12806203945Sweongyo		return;
12807203945Sweongyo	}
12808203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x200);
12809203945Sweongyo}
12810203945Sweongyo
12811203945Sweongyostatic void
12812203945Sweongyobwn_phy_lp_set_deaf(struct bwn_mac *mac, uint8_t user)
12813203945Sweongyo{
12814203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12815203945Sweongyo
12816203945Sweongyo	if (user)
12817203945Sweongyo		plp->plp_crsusr_off = 1;
12818203945Sweongyo	else
12819203945Sweongyo		plp->plp_crssys_off = 1;
12820203945Sweongyo
12821203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x80);
12822203945Sweongyo}
12823203945Sweongyo
12824203945Sweongyostatic void
12825203945Sweongyobwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
12826203945Sweongyo{
12827203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12828203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12829203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12830203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12831203945Sweongyo
12832203945Sweongyo	if (user)
12833203945Sweongyo		plp->plp_crsusr_off = 0;
12834203945Sweongyo	else
12835203945Sweongyo		plp->plp_crssys_off = 0;
12836203945Sweongyo
12837203945Sweongyo	if (plp->plp_crsusr_off || plp->plp_crssys_off)
12838203945Sweongyo		return;
12839203945Sweongyo
12840203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12841203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x60);
12842203945Sweongyo	else
12843203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x20);
12844203945Sweongyo}
12845203945Sweongyo
12846203945Sweongyostatic unsigned int
12847203945Sweongyobwn_sqrt(struct bwn_mac *mac, unsigned int x)
12848203945Sweongyo{
12849203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12850203945Sweongyo	/* Table holding (10 * sqrt(x)) for x between 1 and 256. */
12851203945Sweongyo	static uint8_t sqrt_table[256] = {
12852203945Sweongyo		10, 14, 17, 20, 22, 24, 26, 28,
12853203945Sweongyo		30, 31, 33, 34, 36, 37, 38, 40,
12854203945Sweongyo		41, 42, 43, 44, 45, 46, 47, 48,
12855203945Sweongyo		50, 50, 51, 52, 53, 54, 55, 56,
12856203945Sweongyo		57, 58, 59, 60, 60, 61, 62, 63,
12857203945Sweongyo		64, 64, 65, 66, 67, 67, 68, 69,
12858203945Sweongyo		70, 70, 71, 72, 72, 73, 74, 74,
12859203945Sweongyo		75, 76, 76, 77, 78, 78, 79, 80,
12860203945Sweongyo		80, 81, 81, 82, 83, 83, 84, 84,
12861203945Sweongyo		85, 86, 86, 87, 87, 88, 88, 89,
12862203945Sweongyo		90, 90, 91, 91, 92, 92, 93, 93,
12863203945Sweongyo		94, 94, 95, 95, 96, 96, 97, 97,
12864203945Sweongyo		98, 98, 99, 100, 100, 100, 101, 101,
12865203945Sweongyo		102, 102, 103, 103, 104, 104, 105, 105,
12866203945Sweongyo		106, 106, 107, 107, 108, 108, 109, 109,
12867203945Sweongyo		110, 110, 110, 111, 111, 112, 112, 113,
12868203945Sweongyo		113, 114, 114, 114, 115, 115, 116, 116,
12869203945Sweongyo		117, 117, 117, 118, 118, 119, 119, 120,
12870203945Sweongyo		120, 120, 121, 121, 122, 122, 122, 123,
12871203945Sweongyo		123, 124, 124, 124, 125, 125, 126, 126,
12872203945Sweongyo		126, 127, 127, 128, 128, 128, 129, 129,
12873203945Sweongyo		130, 130, 130, 131, 131, 131, 132, 132,
12874203945Sweongyo		133, 133, 133, 134, 134, 134, 135, 135,
12875203945Sweongyo		136, 136, 136, 137, 137, 137, 138, 138,
12876203945Sweongyo		138, 139, 139, 140, 140, 140, 141, 141,
12877203945Sweongyo		141, 142, 142, 142, 143, 143, 143, 144,
12878203945Sweongyo		144, 144, 145, 145, 145, 146, 146, 146,
12879203945Sweongyo		147, 147, 147, 148, 148, 148, 149, 149,
12880203945Sweongyo		150, 150, 150, 150, 151, 151, 151, 152,
12881203945Sweongyo		152, 152, 153, 153, 153, 154, 154, 154,
12882203945Sweongyo		155, 155, 155, 156, 156, 156, 157, 157,
12883203945Sweongyo		157, 158, 158, 158, 159, 159, 159, 160
12884203945Sweongyo	};
12885203945Sweongyo
12886203945Sweongyo	if (x == 0)
12887203945Sweongyo		return (0);
12888203945Sweongyo	if (x >= 256) {
12889203945Sweongyo		device_printf(sc->sc_dev,
12890203945Sweongyo		    "out of bounds of the square-root table (%d)\n", x);
12891203945Sweongyo		return (16);
12892203945Sweongyo	}
12893203945Sweongyo	return (sqrt_table[x - 1] / 10);
12894203945Sweongyo}
12895203945Sweongyo
12896203945Sweongyostatic int
12897203945Sweongyobwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *mac, uint16_t sample)
12898203945Sweongyo{
12899203945Sweongyo#define	CALC_COEFF(_v, _x, _y, _z)	do {				\
12900203945Sweongyo	int _t;								\
12901203945Sweongyo	_t = _x - 20;							\
12902203945Sweongyo	if (_t >= 0) {							\
12903203945Sweongyo		_v = ((_y << (30 - _x)) + (_z >> (1 + _t))) / (_z >> _t); \
12904203945Sweongyo	} else {							\
12905203945Sweongyo		_v = ((_y << (30 - _x)) + (_z << (-1 - _t))) / (_z << -_t); \
12906203945Sweongyo	}								\
12907203945Sweongyo} while (0)
12908203945Sweongyo#define	CALC_COEFF2(_v, _x, _y, _z)	do {				\
12909203945Sweongyo	int _t;								\
12910203945Sweongyo	_t = _x - 11;							\
12911203945Sweongyo	if (_t >= 0)							\
12912203945Sweongyo		tmp[3] = (_y << (31 - _x)) / (_z >> _t);		\
12913203945Sweongyo	else								\
12914203945Sweongyo		tmp[3] = (_y << (31 - _x)) / (_z << -_t);		\
12915203945Sweongyo} while (0)
12916203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12917203945Sweongyo	uint16_t v0, v1;
12918203945Sweongyo	int tmp[2], ret;
12919203945Sweongyo
12920203945Sweongyo	v1 = BWN_PHY_READ(mac, BWN_PHY_RX_COMP_COEFF_S);
12921203945Sweongyo	v0 = v1 >> 8;
12922203945Sweongyo	v1 |= 0xff;
12923203945Sweongyo
12924203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, 0x00c0);
12925203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff);
12926203945Sweongyo
12927203945Sweongyo	ret = bwn_phy_lp_rx_iq_est(mac, sample, 32, &ie);
12928203945Sweongyo	if (ret == 0)
12929203945Sweongyo		goto done;
12930203945Sweongyo
12931203945Sweongyo	if (ie.ie_ipwr + ie.ie_qpwr < 2) {
12932203945Sweongyo		ret = 0;
12933203945Sweongyo		goto done;
12934203945Sweongyo	}
12935203945Sweongyo
12936203945Sweongyo	CALC_COEFF(tmp[0], bwn_nbits(ie.ie_iqprod), ie.ie_iqprod, ie.ie_ipwr);
12937203945Sweongyo	CALC_COEFF2(tmp[1], bwn_nbits(ie.ie_qpwr), ie.ie_qpwr, ie.ie_ipwr);
12938203945Sweongyo
12939203945Sweongyo	tmp[1] = -bwn_sqrt(mac, tmp[1] - (tmp[0] * tmp[0]));
12940203945Sweongyo	v0 = tmp[0] >> 3;
12941203945Sweongyo	v1 = tmp[1] >> 4;
12942203945Sweongyodone:
12943203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, v1);
12944203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, v0 << 8);
12945203945Sweongyo	return ret;
12946203945Sweongyo#undef CALC_COEFF
12947203945Sweongyo#undef CALC_COEFF2
12948203945Sweongyo}
12949203945Sweongyo
12950203945Sweongyostatic void
12951203945Sweongyobwn_phy_lp_tblinit_r01(struct bwn_mac *mac)
12952203945Sweongyo{
12953203945Sweongyo	static const uint16_t noisescale[] = {
12954203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12955203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4,
12956203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12957203945Sweongyo		0xa4a4, 0xa4a4, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12958203945Sweongyo		0x0000, 0x0000, 0x4c00, 0x2d36, 0x0000, 0x0000, 0x4c00, 0x2d36,
12959203945Sweongyo	};
12960203945Sweongyo	static const uint16_t crsgainnft[] = {
12961203945Sweongyo		0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f,
12962203945Sweongyo		0x036f, 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381,
12963203945Sweongyo		0x0374, 0x0381, 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f,
12964203945Sweongyo		0x0040, 0x005e, 0x007f, 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d,
12965203945Sweongyo		0x013d,
12966203945Sweongyo	};
12967203945Sweongyo	static const uint16_t filterctl[] = {
12968203945Sweongyo		0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077,
12969203945Sweongyo		0xff53, 0x0127,
12970203945Sweongyo	};
12971203945Sweongyo	static const uint32_t psctl[] = {
12972203945Sweongyo		0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101,
12973203945Sweongyo		0x00000080, 0x08080101, 0x00000040, 0x08080101, 0x000000c0,
12974203945Sweongyo		0x08a81501, 0x000000c0, 0x0fe8fd01, 0x000000c0, 0x08300105,
12975203945Sweongyo		0x000000c0, 0x08080201, 0x000000c0, 0x08280205, 0x000000c0,
12976203945Sweongyo		0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, 0x08080202,
12977203945Sweongyo		0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
12978203945Sweongyo		0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106,
12979203945Sweongyo		0x000000c0, 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
12980203945Sweongyo	};
12981203945Sweongyo	static const uint16_t ofdmcckgain_r0[] = {
12982203945Sweongyo		0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12983203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12984203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12985203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12986203945Sweongyo		0x755d,
12987203945Sweongyo	};
12988203945Sweongyo	static const uint16_t ofdmcckgain_r1[] = {
12989203945Sweongyo		0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12990203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12991203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12992203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12993203945Sweongyo		0x755d,
12994203945Sweongyo	};
12995203945Sweongyo	static const uint16_t gaindelta[] = {
12996203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12997203945Sweongyo		0x0000,
12998203945Sweongyo	};
12999203945Sweongyo	static const uint32_t txpwrctl[] = {
13000203945Sweongyo		0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c,
13001203945Sweongyo		0x0000004b, 0x0000004a, 0x00000049, 0x00000048, 0x00000047,
13002203945Sweongyo		0x00000046, 0x00000045, 0x00000044, 0x00000043, 0x00000042,
13003203945Sweongyo		0x00000041, 0x00000040, 0x0000003f, 0x0000003e, 0x0000003d,
13004203945Sweongyo		0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, 0x00000038,
13005203945Sweongyo		0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
13006203945Sweongyo		0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e,
13007203945Sweongyo		0x0000002d, 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029,
13008203945Sweongyo		0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
13009203945Sweongyo		0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001f,
13010203945Sweongyo		0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001a,
13011203945Sweongyo		0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
13012203945Sweongyo		0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000,
13013203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13014203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13015203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13016203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13017203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13018203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13019203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13020203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13021203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13022203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13023203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13024203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13025203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13026203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13027203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13028203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13029203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13030203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13031203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13032203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13033203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13034203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13035203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13036203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13037203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13038203945Sweongyo		0x00000000, 0x00000000, 0x000075a0, 0x000075a0, 0x000075a1,
13039203945Sweongyo		0x000075a1, 0x000075a2, 0x000075a2, 0x000075a3, 0x000075a3,
13040203945Sweongyo		0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, 0x000074b2,
13041203945Sweongyo		0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
13042203945Sweongyo		0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23,
13043203945Sweongyo		0x00006d23, 0x00004660, 0x00004660, 0x00004661, 0x00004661,
13044203945Sweongyo		0x00004662, 0x00004662, 0x00004663, 0x00004663, 0x00003e60,
13045203945Sweongyo		0x00003e60, 0x00003e61, 0x00003e61, 0x00003e62, 0x00003e62,
13046203945Sweongyo		0x00003e63, 0x00003e63, 0x00003660, 0x00003660, 0x00003661,
13047203945Sweongyo		0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
13048203945Sweongyo		0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62,
13049203945Sweongyo		0x00002e62, 0x00002e63, 0x00002e63, 0x00002660, 0x00002660,
13050203945Sweongyo		0x00002661, 0x00002661, 0x00002662, 0x00002662, 0x00002663,
13051203945Sweongyo		0x00002663, 0x000025e0, 0x000025e0, 0x000025e1, 0x000025e1,
13052203945Sweongyo		0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, 0x00001de0,
13053203945Sweongyo		0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
13054203945Sweongyo		0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61,
13055203945Sweongyo		0x00001d61, 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63,
13056203945Sweongyo		0x00001560, 0x00001560, 0x00001561, 0x00001561, 0x00001562,
13057203945Sweongyo		0x00001562, 0x00001563, 0x00001563, 0x00000d60, 0x00000d60,
13058203945Sweongyo		0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, 0x00000d63,
13059203945Sweongyo		0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
13060203945Sweongyo		0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10,
13061203945Sweongyo		0x00000e10, 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12,
13062203945Sweongyo		0x00000e13, 0x00000e13, 0x00000bf0, 0x00000bf0, 0x00000bf1,
13063203945Sweongyo		0x00000bf1, 0x00000bf2, 0x00000bf2, 0x00000bf3, 0x00000bf3,
13064203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13065203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13066203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13067203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13068203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13069203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13070203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13071203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13072203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13073203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13074203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13075203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13076203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13077203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13078203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13079203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13080203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13081203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13082203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13083203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13084203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13085203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13086203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13087203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13088203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13089203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc,
13090203945Sweongyo		0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04,
13091203945Sweongyo		0x0000fcff, 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006,
13092203945Sweongyo		0x0000ff03, 0x000007fc, 0x0000fc08, 0x00000203, 0x0000fffb,
13093203945Sweongyo		0x00000600, 0x0000fa01, 0x0000fc03, 0x0000fe06, 0x0000fe00,
13094203945Sweongyo		0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, 0x000004fd,
13095203945Sweongyo		0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
13096203945Sweongyo		0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa,
13097203945Sweongyo		0x00000700, 0x00000305, 0x000004ff, 0x00000801, 0x00000503,
13098203945Sweongyo		0x000005f9, 0x00000404, 0x0000fb08, 0x000005fd, 0x00000501,
13099203945Sweongyo		0x00000405, 0x0000fb03, 0x000007fc, 0x00000403, 0x00000303,
13100203945Sweongyo		0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, 0x0000fe01,
13101203945Sweongyo		0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
13102203945Sweongyo		0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa,
13103203945Sweongyo		0x000003fe, 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06,
13104203945Sweongyo		0x000008fc, 0x00000701, 0x00000504, 0x0000fdfe, 0x0000fdfc,
13105203945Sweongyo		0x000003fe, 0x00000704, 0x000002fc, 0x000004f9, 0x0000fdfd,
13106203945Sweongyo		0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, 0x000004f9,
13107203945Sweongyo		0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
13108203945Sweongyo		0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa,
13109203945Sweongyo		0x00000305, 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc,
13110203945Sweongyo		0x0000fe03, 0x00000701, 0x000001fb, 0x000001f9, 0x00000206,
13111203945Sweongyo		0x000006fd, 0x00000508, 0x00000700, 0x00000304, 0x000005fe,
13112203945Sweongyo		0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, 0x000007f9,
13113203945Sweongyo		0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
13114203945Sweongyo		0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb,
13115203945Sweongyo		0x00000702,
13116203945Sweongyo	};
13117203945Sweongyo
13118203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13119203945Sweongyo
13120203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13121203945Sweongyo	    bwn_tab_sigsq_tbl);
13122203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13123203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(crsgainnft), crsgainnft);
13124203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(8, 0), N(filterctl), filterctl);
13125203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(psctl), psctl);
13126203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13127203945Sweongyo	    bwn_tab_pllfrac_tbl);
13128203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13129203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13130203945Sweongyo	if (mac->mac_phy.rev == 0) {
13131203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r0),
13132203945Sweongyo		    ofdmcckgain_r0);
13133203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r0),
13134203945Sweongyo		    ofdmcckgain_r0);
13135203945Sweongyo	} else {
13136203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r1),
13137203945Sweongyo		    ofdmcckgain_r1);
13138203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r1),
13139203945Sweongyo		    ofdmcckgain_r1);
13140203945Sweongyo	}
13141203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(gaindelta), gaindelta);
13142203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(txpwrctl), txpwrctl);
13143203945Sweongyo}
13144203945Sweongyo
13145203945Sweongyostatic void
13146203945Sweongyobwn_phy_lp_tblinit_r2(struct bwn_mac *mac)
13147203945Sweongyo{
13148203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
13149203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
13150203945Sweongyo	int i;
13151203945Sweongyo	static const uint16_t noisescale[] = {
13152203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13153203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13154203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13155203945Sweongyo		0x00a4, 0x00a4, 0x0000, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13156203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13157203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13158203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4
13159203945Sweongyo	};
13160203945Sweongyo	static const uint32_t filterctl[] = {
13161203945Sweongyo		0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27,
13162203945Sweongyo		0x0000217f, 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f
13163203945Sweongyo	};
13164203945Sweongyo	static const uint32_t psctl[] = {
13165203945Sweongyo		0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000,
13166203945Sweongyo		0x00002080, 0x00006180, 0x00003002, 0x00000040, 0x00002042,
13167203945Sweongyo		0x00180047, 0x00080043, 0x00000041, 0x000020c1, 0x00046006,
13168203945Sweongyo		0x00042002, 0x00040000, 0x00002003, 0x00180006, 0x00080002
13169203945Sweongyo	};
13170203945Sweongyo	static const uint32_t gainidx[] = {
13171203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13172203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13173203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13174203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x10000001, 0x00000000,
13175203945Sweongyo		0x20000082, 0x00000000, 0x40000104, 0x00000000, 0x60004207,
13176203945Sweongyo		0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
13177203945Sweongyo		0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288,
13178203945Sweongyo		0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
13179203945Sweongyo		0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794,
13180203945Sweongyo		0x00000010, 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011,
13181203945Sweongyo		0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21,
13182203945Sweongyo		0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
13183203945Sweongyo		0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329,
13184203945Sweongyo		0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
13185203945Sweongyo		0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, 0x00000000,
13186203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13187203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13188203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13189203945Sweongyo		0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082,
13190203945Sweongyo		0x00000000, 0x40000104, 0x00000000, 0x60004207, 0x00000001,
13191203945Sweongyo		0x7000838a, 0x00000001, 0xd021050d, 0x00000001, 0xe041c683,
13192203945Sweongyo		0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
13193203945Sweongyo		0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711,
13194203945Sweongyo		0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
13195203945Sweongyo		0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c,
13196203945Sweongyo		0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019,
13197203945Sweongyo		0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, 0xb36811a6,
13198203945Sweongyo		0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
13199203945Sweongyo		0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c,
13200203945Sweongyo		0x0000001a, 0x64ca55ad, 0x0000001a
13201203945Sweongyo	};
13202203945Sweongyo	static const uint16_t auxgainidx[] = {
13203203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13204203945Sweongyo		0x0000, 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000,
13205203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002,
13206203945Sweongyo		0x0004, 0x0016
13207203945Sweongyo	};
13208203945Sweongyo	static const uint16_t swctl[] = {
13209203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13210203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13211203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13212203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
13213203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13214203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13215203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13216203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018
13217203945Sweongyo	};
13218203945Sweongyo	static const uint8_t hf[] = {
13219203945Sweongyo		0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
13220203945Sweongyo		0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17
13221203945Sweongyo	};
13222203945Sweongyo	static const uint32_t gainval[] = {
13223203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13224203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13225203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13226203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13227203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13228203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13229203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13230203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13231203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13232203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13233203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13234203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13235203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009,
13236203945Sweongyo		0x000000f1, 0x00000000, 0x00000000
13237203945Sweongyo	};
13238203945Sweongyo	static const uint16_t gain[] = {
13239203945Sweongyo		0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808,
13240203945Sweongyo		0x080a, 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813,
13241203945Sweongyo		0x0814, 0x0816, 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824,
13242203945Sweongyo		0x0830, 0x0834, 0x0837, 0x083b, 0x083f, 0x0840, 0x0844, 0x0857,
13243203945Sweongyo		0x085b, 0x085f, 0x08d7, 0x08db, 0x08df, 0x0957, 0x095b, 0x095f,
13244203945Sweongyo		0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, 0x175f, 0x0000, 0x0000,
13245203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13246203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13247203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13248203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13249203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13250203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13251203945Sweongyo	};
13252203945Sweongyo	static const uint32_t papdeps[] = {
13253203945Sweongyo		0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9,
13254203945Sweongyo		0x00021fdf, 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7,
13255203945Sweongyo		0x0004efc2, 0x00055fb5, 0x0005cfb0, 0x00063fa8, 0x00068fa3,
13256203945Sweongyo		0x00071f98, 0x0007ef92, 0x00084f8b, 0x0008df82, 0x00097f77,
13257203945Sweongyo		0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, 0x000bff41,
13258203945Sweongyo		0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
13259203945Sweongyo		0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15,
13260203945Sweongyo		0x00143f1c, 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f,
13261203945Sweongyo		0x001e6f7e, 0x0021cfa4, 0x0025bfd2, 0x002a2008, 0x002fb047,
13262203945Sweongyo		0x00360090, 0x003d40e0, 0x0045c135, 0x004fb189, 0x005ae1d7,
13263203945Sweongyo		0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, 0x007ff2e3,
13264203945Sweongyo		0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
13265203945Sweongyo		0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506
13266203945Sweongyo	};
13267203945Sweongyo	static const uint32_t papdmult[] = {
13268203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13269203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13270203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13271203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13272203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13273203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13274203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13275203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13276203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13277203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13278203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13279203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13280203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13281203945Sweongyo	};
13282203945Sweongyo	static const uint32_t gainidx_a0[] = {
13283203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13284203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13285203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13286203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13287203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13288203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13289203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13290203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13291203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13292203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13293203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13294203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13295203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13296203945Sweongyo	};
13297203945Sweongyo	static const uint16_t auxgainidx_a0[] = {
13298203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13299203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000,
13300203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13301203945Sweongyo		0x0002, 0x0014
13302203945Sweongyo	};
13303203945Sweongyo	static const uint32_t gainval_a0[] = {
13304203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13305203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13306203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13307203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13308203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13309203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13310203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13311203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13312203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13313203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13314203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13315203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13316203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f,
13317203945Sweongyo		0x000000f7, 0x00000000, 0x00000000
13318203945Sweongyo	};
13319203945Sweongyo	static const uint16_t gain_a0[] = {
13320203945Sweongyo		0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b,
13321203945Sweongyo		0x000c, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016,
13322203945Sweongyo		0x0017, 0x001a, 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034,
13323203945Sweongyo		0x0037, 0x003b, 0x003f, 0x0040, 0x0044, 0x0057, 0x005b, 0x005f,
13324203945Sweongyo		0x00d7, 0x00db, 0x00df, 0x0157, 0x015b, 0x015f, 0x0357, 0x035b,
13325203945Sweongyo		0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, 0x0000, 0x0000, 0x0000,
13326203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13327203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13328203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13329203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13330203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13331203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13332203945Sweongyo	};
13333203945Sweongyo
13334203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13335203945Sweongyo
13336203945Sweongyo	for (i = 0; i < 704; i++)
13337203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(7, i), 0);
13338203945Sweongyo
13339203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13340203945Sweongyo	    bwn_tab_sigsq_tbl);
13341203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13342203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(11, 0), N(filterctl), filterctl);
13343203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(12, 0), N(psctl), psctl);
13344203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx), gainidx);
13345203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx), auxgainidx);
13346203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(swctl), swctl);
13347203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(16, 0), N(hf), hf);
13348203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval), gainval);
13349203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain), gain);
13350203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13351203945Sweongyo	    bwn_tab_pllfrac_tbl);
13352203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13353203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13354203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(papdeps), papdeps);
13355203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(papdmult), papdmult);
13356203945Sweongyo
13357203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
13358203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx_a0),
13359203945Sweongyo		    gainidx_a0);
13360203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx_a0),
13361203945Sweongyo		    auxgainidx_a0);
13362203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval_a0),
13363203945Sweongyo		    gainval_a0);
13364203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain_a0), gain_a0);
13365203945Sweongyo	}
13366203945Sweongyo}
13367203945Sweongyo
13368203945Sweongyostatic void
13369203945Sweongyobwn_phy_lp_tblinit_txgain(struct bwn_mac *mac)
13370203945Sweongyo{
13371203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
13372203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
13373203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13374203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
13375203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
13376203945Sweongyo	static struct bwn_txgain_entry txgain_r2[] = {
13377203945Sweongyo		{ 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 },
13378203945Sweongyo		{ 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 },
13379203945Sweongyo		{ 255, 255, 203, 0, 135 }, { 255, 255, 203, 0, 131 },
13380203945Sweongyo		{ 255, 255, 203, 0, 128 }, { 255, 255, 203, 0, 124 },
13381203945Sweongyo		{ 255, 255, 203, 0, 121 }, { 255, 255, 203, 0, 117 },
13382203945Sweongyo		{ 255, 255, 203, 0, 114 }, { 255, 255, 203, 0, 111 },
13383203945Sweongyo		{ 255, 255, 203, 0, 107 }, { 255, 255, 203, 0, 104 },
13384203945Sweongyo		{ 255, 255, 203, 0, 101 }, { 255, 255, 203, 0, 99 },
13385203945Sweongyo		{ 255, 255, 203, 0, 96 }, { 255, 255, 203, 0, 93 },
13386203945Sweongyo		{ 255, 255, 203, 0, 90 }, { 255, 255, 203, 0, 88 },
13387203945Sweongyo		{ 255, 255, 203, 0, 85 }, { 255, 255, 203, 0, 83 },
13388203945Sweongyo		{ 255, 255, 203, 0, 81 }, { 255, 255, 203, 0, 78 },
13389203945Sweongyo		{ 255, 255, 203, 0, 76 }, { 255, 255, 203, 0, 74 },
13390203945Sweongyo		{ 255, 255, 203, 0, 72 }, { 255, 255, 203, 0, 70 },
13391203945Sweongyo		{ 255, 255, 203, 0, 68 }, { 255, 255, 203, 0, 66 },
13392203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13393203945Sweongyo		{ 255, 255, 192, 0, 64 }, { 255, 255, 186, 0, 64 },
13394203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 176, 0, 64 },
13395203945Sweongyo		{ 255, 255, 171, 0, 64 }, { 255, 255, 166, 0, 64 },
13396203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 157, 0, 64 },
13397203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13398203945Sweongyo		{ 255, 255, 144, 0, 64 }, { 255, 255, 140, 0, 64 },
13399203945Sweongyo		{ 255, 255, 136, 0, 64 }, { 255, 255, 132, 0, 64 },
13400203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13401203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13402203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13403203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 105, 0, 64 },
13404203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13405203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13406203945Sweongyo		{ 255, 255, 91, 0, 64 }, { 255, 255, 88, 0, 64 },
13407203945Sweongyo		{ 255, 255, 86, 0, 64 }, { 255, 255, 83, 0, 64 },
13408203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 79, 0, 64 },
13409203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13410203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13411203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13412203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 248, 64, 0, 64 },
13413203945Sweongyo		{ 255, 248, 62, 0, 64 }, { 255, 241, 62, 0, 64 },
13414203945Sweongyo		{ 255, 241, 60, 0, 64 }, { 255, 234, 60, 0, 64 },
13415203945Sweongyo		{ 255, 234, 59, 0, 64 }, { 255, 227, 59, 0, 64 },
13416203945Sweongyo		{ 255, 227, 57, 0, 64 }, { 255, 221, 57, 0, 64 },
13417203945Sweongyo		{ 255, 221, 55, 0, 64 }, { 255, 215, 55, 0, 64 },
13418203945Sweongyo		{ 255, 215, 54, 0, 64 }, { 255, 208, 54, 0, 64 },
13419203945Sweongyo		{ 255, 208, 52, 0, 64 }, { 255, 203, 52, 0, 64 },
13420203945Sweongyo		{ 255, 203, 51, 0, 64 }, { 255, 197, 51, 0, 64 },
13421203945Sweongyo		{ 255, 197, 49, 0, 64 }, { 255, 191, 49, 0, 64 },
13422203945Sweongyo		{ 255, 191, 48, 0, 64 }, { 255, 186, 48, 0, 64 },
13423203945Sweongyo		{ 255, 186, 47, 0, 64 }, { 255, 181, 47, 0, 64 },
13424203945Sweongyo		{ 255, 181, 45, 0, 64 }, { 255, 175, 45, 0, 64 },
13425203945Sweongyo		{ 255, 175, 44, 0, 64 }, { 255, 170, 44, 0, 64 },
13426203945Sweongyo		{ 255, 170, 43, 0, 64 }, { 255, 166, 43, 0, 64 },
13427203945Sweongyo		{ 255, 166, 42, 0, 64 }, { 255, 161, 42, 0, 64 },
13428203945Sweongyo		{ 255, 161, 40, 0, 64 }, { 255, 156, 40, 0, 64 },
13429203945Sweongyo		{ 255, 156, 39, 0, 64 }, { 255, 152, 39, 0, 64 },
13430203945Sweongyo		{ 255, 152, 38, 0, 64 }, { 255, 148, 38, 0, 64 },
13431203945Sweongyo		{ 255, 148, 37, 0, 64 }, { 255, 143, 37, 0, 64 },
13432203945Sweongyo		{ 255, 143, 36, 0, 64 }, { 255, 139, 36, 0, 64 },
13433203945Sweongyo		{ 255, 139, 35, 0, 64 }, { 255, 135, 35, 0, 64 },
13434203945Sweongyo		{ 255, 135, 34, 0, 64 }, { 255, 132, 34, 0, 64 },
13435203945Sweongyo		{ 255, 132, 33, 0, 64 }, { 255, 128, 33, 0, 64 },
13436203945Sweongyo		{ 255, 128, 32, 0, 64 }, { 255, 124, 32, 0, 64 },
13437203945Sweongyo		{ 255, 124, 31, 0, 64 }, { 255, 121, 31, 0, 64 },
13438203945Sweongyo		{ 255, 121, 30, 0, 64 }, { 255, 117, 30, 0, 64 },
13439203945Sweongyo		{ 255, 117, 29, 0, 64 }, { 255, 114, 29, 0, 64 },
13440203945Sweongyo		{ 255, 114, 29, 0, 64 }, { 255, 111, 29, 0, 64 },
13441203945Sweongyo	};
13442203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r2[] = {
13443203945Sweongyo		{ 7, 99, 255, 0, 64 }, { 7, 96, 255, 0, 64 },
13444203945Sweongyo		{ 7, 93, 255, 0, 64 }, { 7, 90, 255, 0, 64 },
13445203945Sweongyo		{ 7, 88, 255, 0, 64 }, { 7, 85, 255, 0, 64 },
13446203945Sweongyo		{ 7, 83, 255, 0, 64 }, { 7, 81, 255, 0, 64 },
13447203945Sweongyo		{ 7, 78, 255, 0, 64 }, { 7, 76, 255, 0, 64 },
13448203945Sweongyo		{ 7, 74, 255, 0, 64 }, { 7, 72, 255, 0, 64 },
13449203945Sweongyo		{ 7, 70, 255, 0, 64 }, { 7, 68, 255, 0, 64 },
13450203945Sweongyo		{ 7, 66, 255, 0, 64 }, { 7, 64, 255, 0, 64 },
13451203945Sweongyo		{ 7, 64, 255, 0, 64 }, { 7, 62, 255, 0, 64 },
13452203945Sweongyo		{ 7, 62, 248, 0, 64 }, { 7, 60, 248, 0, 64 },
13453203945Sweongyo		{ 7, 60, 241, 0, 64 }, { 7, 59, 241, 0, 64 },
13454203945Sweongyo		{ 7, 59, 234, 0, 64 }, { 7, 57, 234, 0, 64 },
13455203945Sweongyo		{ 7, 57, 227, 0, 64 }, { 7, 55, 227, 0, 64 },
13456203945Sweongyo		{ 7, 55, 221, 0, 64 }, { 7, 54, 221, 0, 64 },
13457203945Sweongyo		{ 7, 54, 215, 0, 64 }, { 7, 52, 215, 0, 64 },
13458203945Sweongyo		{ 7, 52, 208, 0, 64 }, { 7, 51, 208, 0, 64 },
13459203945Sweongyo		{ 7, 51, 203, 0, 64 }, { 7, 49, 203, 0, 64 },
13460203945Sweongyo		{ 7, 49, 197, 0, 64 }, { 7, 48, 197, 0, 64 },
13461203945Sweongyo		{ 7, 48, 191, 0, 64 }, { 7, 47, 191, 0, 64 },
13462203945Sweongyo		{ 7, 47, 186, 0, 64 }, { 7, 45, 186, 0, 64 },
13463203945Sweongyo		{ 7, 45, 181, 0, 64 }, { 7, 44, 181, 0, 64 },
13464203945Sweongyo		{ 7, 44, 175, 0, 64 }, { 7, 43, 175, 0, 64 },
13465203945Sweongyo		{ 7, 43, 170, 0, 64 }, { 7, 42, 170, 0, 64 },
13466203945Sweongyo		{ 7, 42, 166, 0, 64 }, { 7, 40, 166, 0, 64 },
13467203945Sweongyo		{ 7, 40, 161, 0, 64 }, { 7, 39, 161, 0, 64 },
13468203945Sweongyo		{ 7, 39, 156, 0, 64 }, { 7, 38, 156, 0, 64 },
13469203945Sweongyo		{ 7, 38, 152, 0, 64 }, { 7, 37, 152, 0, 64 },
13470203945Sweongyo		{ 7, 37, 148, 0, 64 }, { 7, 36, 148, 0, 64 },
13471203945Sweongyo		{ 7, 36, 143, 0, 64 }, { 7, 35, 143, 0, 64 },
13472203945Sweongyo		{ 7, 35, 139, 0, 64 }, { 7, 34, 139, 0, 64 },
13473203945Sweongyo		{ 7, 34, 135, 0, 64 }, { 7, 33, 135, 0, 64 },
13474203945Sweongyo		{ 7, 33, 132, 0, 64 }, { 7, 32, 132, 0, 64 },
13475203945Sweongyo		{ 7, 32, 128, 0, 64 }, { 7, 31, 128, 0, 64 },
13476203945Sweongyo		{ 7, 31, 124, 0, 64 }, { 7, 30, 124, 0, 64 },
13477203945Sweongyo		{ 7, 30, 121, 0, 64 }, { 7, 29, 121, 0, 64 },
13478203945Sweongyo		{ 7, 29, 117, 0, 64 }, { 7, 29, 117, 0, 64 },
13479203945Sweongyo		{ 7, 29, 114, 0, 64 }, { 7, 28, 114, 0, 64 },
13480203945Sweongyo		{ 7, 28, 111, 0, 64 }, { 7, 27, 111, 0, 64 },
13481203945Sweongyo		{ 7, 27, 108, 0, 64 }, { 7, 26, 108, 0, 64 },
13482203945Sweongyo		{ 7, 26, 104, 0, 64 }, { 7, 25, 104, 0, 64 },
13483203945Sweongyo		{ 7, 25, 102, 0, 64 }, { 7, 25, 102, 0, 64 },
13484203945Sweongyo		{ 7, 25, 99, 0, 64 }, { 7, 24, 99, 0, 64 },
13485203945Sweongyo		{ 7, 24, 96, 0, 64 }, { 7, 23, 96, 0, 64 },
13486203945Sweongyo		{ 7, 23, 93, 0, 64 }, { 7, 23, 93, 0, 64 },
13487203945Sweongyo		{ 7, 23, 90, 0, 64 }, { 7, 22, 90, 0, 64 },
13488203945Sweongyo		{ 7, 22, 88, 0, 64 }, { 7, 21, 88, 0, 64 },
13489203945Sweongyo		{ 7, 21, 85, 0, 64 }, { 7, 21, 85, 0, 64 },
13490203945Sweongyo		{ 7, 21, 83, 0, 64 }, { 7, 20, 83, 0, 64 },
13491203945Sweongyo		{ 7, 20, 81, 0, 64 }, { 7, 20, 81, 0, 64 },
13492203945Sweongyo		{ 7, 20, 78, 0, 64 }, { 7, 19, 78, 0, 64 },
13493203945Sweongyo		{ 7, 19, 76, 0, 64 }, { 7, 19, 76, 0, 64 },
13494203945Sweongyo		{ 7, 19, 74, 0, 64 }, { 7, 18, 74, 0, 64 },
13495203945Sweongyo		{ 7, 18, 72, 0, 64 }, { 7, 18, 72, 0, 64 },
13496203945Sweongyo		{ 7, 18, 70, 0, 64 }, { 7, 17, 70, 0, 64 },
13497203945Sweongyo		{ 7, 17, 68, 0, 64 }, { 7, 17, 68, 0, 64 },
13498203945Sweongyo		{ 7, 17, 66, 0, 64 }, { 7, 16, 66, 0, 64 },
13499203945Sweongyo		{ 7, 16, 64, 0, 64 }, { 7, 16, 64, 0, 64 },
13500203945Sweongyo		{ 7, 16, 62, 0, 64 }, { 7, 15, 62, 0, 64 },
13501203945Sweongyo		{ 7, 15, 60, 0, 64 }, { 7, 15, 60, 0, 64 },
13502203945Sweongyo		{ 7, 15, 59, 0, 64 }, { 7, 14, 59, 0, 64 },
13503203945Sweongyo		{ 7, 14, 57, 0, 64 }, { 7, 14, 57, 0, 64 },
13504203945Sweongyo		{ 7, 14, 55, 0, 64 }, { 7, 14, 55, 0, 64 },
13505203945Sweongyo		{ 7, 14, 54, 0, 64 }, { 7, 13, 54, 0, 64 },
13506203945Sweongyo		{ 7, 13, 52, 0, 64 }, { 7, 13, 52, 0, 64 },
13507203945Sweongyo	};
13508203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r2[] = {
13509203945Sweongyo		{ 255, 255, 255, 0, 152 }, { 255, 255, 255, 0, 147 },
13510203945Sweongyo		{ 255, 255, 255, 0, 143 }, { 255, 255, 255, 0, 139 },
13511203945Sweongyo		{ 255, 255, 255, 0, 135 }, { 255, 255, 255, 0, 131 },
13512203945Sweongyo		{ 255, 255, 255, 0, 128 }, { 255, 255, 255, 0, 124 },
13513203945Sweongyo		{ 255, 255, 255, 0, 121 }, { 255, 255, 255, 0, 117 },
13514203945Sweongyo		{ 255, 255, 255, 0, 114 }, { 255, 255, 255, 0, 111 },
13515203945Sweongyo		{ 255, 255, 255, 0, 107 }, { 255, 255, 255, 0, 104 },
13516203945Sweongyo		{ 255, 255, 255, 0, 101 }, { 255, 255, 255, 0, 99 },
13517203945Sweongyo		{ 255, 255, 255, 0, 96 }, { 255, 255, 255, 0, 93 },
13518203945Sweongyo		{ 255, 255, 255, 0, 90 }, { 255, 255, 255, 0, 88 },
13519203945Sweongyo		{ 255, 255, 255, 0, 85 }, { 255, 255, 255, 0, 83 },
13520203945Sweongyo		{ 255, 255, 255, 0, 81 }, { 255, 255, 255, 0, 78 },
13521203945Sweongyo		{ 255, 255, 255, 0, 76 }, { 255, 255, 255, 0, 74 },
13522203945Sweongyo		{ 255, 255, 255, 0, 72 }, { 255, 255, 255, 0, 70 },
13523203945Sweongyo		{ 255, 255, 255, 0, 68 }, { 255, 255, 255, 0, 66 },
13524203945Sweongyo		{ 255, 255, 255, 0, 64 }, { 255, 255, 248, 0, 64 },
13525203945Sweongyo		{ 255, 255, 241, 0, 64 }, { 255, 255, 234, 0, 64 },
13526203945Sweongyo		{ 255, 255, 227, 0, 64 }, { 255, 255, 221, 0, 64 },
13527203945Sweongyo		{ 255, 255, 215, 0, 64 }, { 255, 255, 208, 0, 64 },
13528203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13529203945Sweongyo		{ 255, 255, 191, 0, 64 }, { 255, 255, 186, 0, 64 },
13530203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 175, 0, 64 },
13531203945Sweongyo		{ 255, 255, 170, 0, 64 }, { 255, 255, 166, 0, 64 },
13532203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 156, 0, 64 },
13533203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13534203945Sweongyo		{ 255, 255, 143, 0, 64 }, { 255, 255, 139, 0, 64 },
13535203945Sweongyo		{ 255, 255, 135, 0, 64 }, { 255, 255, 132, 0, 64 },
13536203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13537203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13538203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13539203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 104, 0, 64 },
13540203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13541203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13542203945Sweongyo		{ 255, 255, 90, 0, 64 }, { 255, 255, 88, 0, 64 },
13543203945Sweongyo		{ 255, 255, 85, 0, 64 }, { 255, 255, 83, 0, 64 },
13544203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 78, 0, 64 },
13545203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13546203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13547203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13548203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 255, 64, 0, 64 },
13549203945Sweongyo		{ 255, 255, 62, 0, 64 }, { 255, 248, 62, 0, 64 },
13550203945Sweongyo		{ 255, 248, 60, 0, 64 }, { 255, 241, 60, 0, 64 },
13551203945Sweongyo		{ 255, 241, 59, 0, 64 }, { 255, 234, 59, 0, 64 },
13552203945Sweongyo		{ 255, 234, 57, 0, 64 }, { 255, 227, 57, 0, 64 },
13553203945Sweongyo		{ 255, 227, 55, 0, 64 }, { 255, 221, 55, 0, 64 },
13554203945Sweongyo		{ 255, 221, 54, 0, 64 }, { 255, 215, 54, 0, 64 },
13555203945Sweongyo		{ 255, 215, 52, 0, 64 }, { 255, 208, 52, 0, 64 },
13556203945Sweongyo		{ 255, 208, 51, 0, 64 }, { 255, 203, 51, 0, 64 },
13557203945Sweongyo		{ 255, 203, 49, 0, 64 }, { 255, 197, 49, 0, 64 },
13558203945Sweongyo		{ 255, 197, 48, 0, 64 }, { 255, 191, 48, 0, 64 },
13559203945Sweongyo		{ 255, 191, 47, 0, 64 }, { 255, 186, 47, 0, 64 },
13560203945Sweongyo		{ 255, 186, 45, 0, 64 }, { 255, 181, 45, 0, 64 },
13561203945Sweongyo		{ 255, 181, 44, 0, 64 }, { 255, 175, 44, 0, 64 },
13562203945Sweongyo		{ 255, 175, 43, 0, 64 }, { 255, 170, 43, 0, 64 },
13563203945Sweongyo		{ 255, 170, 42, 0, 64 }, { 255, 166, 42, 0, 64 },
13564203945Sweongyo		{ 255, 166, 40, 0, 64 }, { 255, 161, 40, 0, 64 },
13565203945Sweongyo		{ 255, 161, 39, 0, 64 }, { 255, 156, 39, 0, 64 },
13566203945Sweongyo		{ 255, 156, 38, 0, 64 }, { 255, 152, 38, 0, 64 },
13567203945Sweongyo		{ 255, 152, 37, 0, 64 }, { 255, 148, 37, 0, 64 },
13568203945Sweongyo		{ 255, 148, 36, 0, 64 }, { 255, 143, 36, 0, 64 },
13569203945Sweongyo		{ 255, 143, 35, 0, 64 }, { 255, 139, 35, 0, 64 },
13570203945Sweongyo		{ 255, 139, 34, 0, 64 }, { 255, 135, 34, 0, 64 },
13571203945Sweongyo		{ 255, 135, 33, 0, 64 }, { 255, 132, 33, 0, 64 },
13572203945Sweongyo		{ 255, 132, 32, 0, 64 }, { 255, 128, 32, 0, 64 }
13573203945Sweongyo	};
13574203945Sweongyo	static struct bwn_txgain_entry txgain_r0[] = {
13575203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13576203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13577203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13578203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13579203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13580203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13581203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13582203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13583203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13584203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13585203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13586203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13587203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13588203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13589203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13590203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13591203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13592203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13593203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 13, 0, 68 },
13594203945Sweongyo		{ 7, 15, 13, 0, 66 }, { 7, 15, 13, 0, 64 },
13595203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13596203945Sweongyo		{ 7, 15, 13, 0, 59 }, { 7, 15, 13, 0, 57 },
13597203945Sweongyo		{ 7, 15, 12, 0, 71 }, { 7, 15, 12, 0, 69 },
13598203945Sweongyo		{ 7, 15, 12, 0, 67 }, { 7, 15, 12, 0, 65 },
13599203945Sweongyo		{ 7, 15, 12, 0, 63 }, { 7, 15, 12, 0, 62 },
13600203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 58 },
13601203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 70 },
13602203945Sweongyo		{ 7, 15, 11, 0, 68 }, { 7, 15, 11, 0, 66 },
13603203945Sweongyo		{ 7, 15, 11, 0, 65 }, { 7, 15, 11, 0, 63 },
13604203945Sweongyo		{ 7, 15, 11, 0, 61 }, { 7, 15, 11, 0, 59 },
13605203945Sweongyo		{ 7, 15, 11, 0, 58 }, { 7, 15, 10, 0, 71 },
13606203945Sweongyo		{ 7, 15, 10, 0, 69 }, { 7, 15, 10, 0, 67 },
13607203945Sweongyo		{ 7, 15, 10, 0, 65 }, { 7, 15, 10, 0, 63 },
13608203945Sweongyo		{ 7, 15, 10, 0, 61 }, { 7, 15, 10, 0, 60 },
13609203945Sweongyo		{ 7, 15, 10, 0, 58 }, { 7, 15, 10, 0, 56 },
13610203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13611203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13612203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 60 },
13613203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 14, 9, 0, 72 },
13614203945Sweongyo		{ 7, 14, 9, 0, 70 }, { 7, 14, 9, 0, 68 },
13615203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 64 },
13616203945Sweongyo		{ 7, 14, 9, 0, 62 }, { 7, 14, 9, 0, 60 },
13617203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 13, 9, 0, 72 },
13618203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13619203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13620203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13621203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13622203945Sweongyo		{ 7, 13, 8, 0, 72 }, { 7, 13, 8, 0, 70 },
13623203945Sweongyo		{ 7, 13, 8, 0, 68 }, { 7, 13, 8, 0, 66 },
13624203945Sweongyo		{ 7, 13, 8, 0, 64 }, { 7, 13, 8, 0, 62 },
13625203945Sweongyo		{ 7, 13, 8, 0, 60 }, { 7, 13, 8, 0, 59 },
13626203945Sweongyo		{ 7, 12, 8, 0, 72 }, { 7, 12, 8, 0, 70 },
13627203945Sweongyo		{ 7, 12, 8, 0, 68 }, { 7, 12, 8, 0, 66 },
13628203945Sweongyo		{ 7, 12, 8, 0, 64 }, { 7, 12, 8, 0, 62 },
13629203945Sweongyo		{ 7, 12, 8, 0, 61 }, { 7, 12, 8, 0, 59 },
13630203945Sweongyo		{ 7, 12, 7, 0, 73 }, { 7, 12, 7, 0, 71 },
13631203945Sweongyo		{ 7, 12, 7, 0, 69 }, { 7, 12, 7, 0, 67 },
13632203945Sweongyo		{ 7, 12, 7, 0, 65 }, { 7, 12, 7, 0, 63 },
13633203945Sweongyo		{ 7, 12, 7, 0, 61 }, { 7, 12, 7, 0, 59 },
13634203945Sweongyo		{ 7, 11, 7, 0, 72 }, { 7, 11, 7, 0, 70 },
13635203945Sweongyo		{ 7, 11, 7, 0, 68 }, { 7, 11, 7, 0, 66 },
13636203945Sweongyo		{ 7, 11, 7, 0, 65 }, { 7, 11, 7, 0, 63 },
13637203945Sweongyo		{ 7, 11, 7, 0, 61 }, { 7, 11, 7, 0, 59 },
13638203945Sweongyo		{ 7, 11, 6, 0, 73 }, { 7, 11, 6, 0, 71 }
13639203945Sweongyo	};
13640203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r0[] = {
13641203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13642203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13643203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13644203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13645203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13646203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13647203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13648203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13649203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13650203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13651203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13652203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13653203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13654203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13655203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13656203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13657203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13658203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13659203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13660203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13661203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13662203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13663203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13664203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13665203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13666203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13667203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13668203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13669203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13670203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13671203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13672203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13673203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13674203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 },
13675203945Sweongyo		{ 4, 10, 6, 0, 59 }, { 4, 10, 5, 0, 72 },
13676203945Sweongyo		{ 4, 10, 5, 0, 70 }, { 4, 10, 5, 0, 68 },
13677203945Sweongyo		{ 4, 10, 5, 0, 66 }, { 4, 10, 5, 0, 64 },
13678203945Sweongyo		{ 4, 10, 5, 0, 62 }, { 4, 10, 5, 0, 60 },
13679203945Sweongyo		{ 4, 10, 5, 0, 59 }, { 4, 9, 5, 0, 70 },
13680203945Sweongyo		{ 4, 9, 5, 0, 68 }, { 4, 9, 5, 0, 66 },
13681203945Sweongyo		{ 4, 9, 5, 0, 64 }, { 4, 9, 5, 0, 63 },
13682203945Sweongyo		{ 4, 9, 5, 0, 61 }, { 4, 9, 5, 0, 59 },
13683203945Sweongyo		{ 4, 9, 4, 0, 71 }, { 4, 9, 4, 0, 69 },
13684203945Sweongyo		{ 4, 9, 4, 0, 67 }, { 4, 9, 4, 0, 65 },
13685203945Sweongyo		{ 4, 9, 4, 0, 63 }, { 4, 9, 4, 0, 62 },
13686203945Sweongyo		{ 4, 9, 4, 0, 60 }, { 4, 9, 4, 0, 58 },
13687203945Sweongyo		{ 4, 8, 4, 0, 70 }, { 4, 8, 4, 0, 68 },
13688203945Sweongyo		{ 4, 8, 4, 0, 66 }, { 4, 8, 4, 0, 65 },
13689203945Sweongyo		{ 4, 8, 4, 0, 63 }, { 4, 8, 4, 0, 61 },
13690203945Sweongyo		{ 4, 8, 4, 0, 59 }, { 4, 7, 4, 0, 68 },
13691203945Sweongyo		{ 4, 7, 4, 0, 66 }, { 4, 7, 4, 0, 64 },
13692203945Sweongyo		{ 4, 7, 4, 0, 62 }, { 4, 7, 4, 0, 61 },
13693203945Sweongyo		{ 4, 7, 4, 0, 59 }, { 4, 7, 3, 0, 67 },
13694203945Sweongyo		{ 4, 7, 3, 0, 65 }, { 4, 7, 3, 0, 63 },
13695203945Sweongyo		{ 4, 7, 3, 0, 62 }, { 4, 7, 3, 0, 60 },
13696203945Sweongyo		{ 4, 6, 3, 0, 65 }, { 4, 6, 3, 0, 63 },
13697203945Sweongyo		{ 4, 6, 3, 0, 61 }, { 4, 6, 3, 0, 60 },
13698203945Sweongyo		{ 4, 6, 3, 0, 58 }, { 4, 5, 3, 0, 68 },
13699203945Sweongyo		{ 4, 5, 3, 0, 66 }, { 4, 5, 3, 0, 64 },
13700203945Sweongyo		{ 4, 5, 3, 0, 62 }, { 4, 5, 3, 0, 60 },
13701203945Sweongyo		{ 4, 5, 3, 0, 59 }, { 4, 5, 3, 0, 57 },
13702203945Sweongyo		{ 4, 4, 2, 0, 83 }, { 4, 4, 2, 0, 81 },
13703203945Sweongyo		{ 4, 4, 2, 0, 78 }, { 4, 4, 2, 0, 76 },
13704203945Sweongyo		{ 4, 4, 2, 0, 74 }, { 4, 4, 2, 0, 72 }
13705203945Sweongyo	};
13706203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r0[] = {
13707203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13708203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13709203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13710203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13711203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13712203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13713203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13714203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13715203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13716203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13717203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13718203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13719203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13720203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13721203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13722203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13723203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13724203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13725203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13726203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13727203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13728203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13729203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13730203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13731203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13732203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13733203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13734203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13735203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13736203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13737203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13738203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13739203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13740203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13741203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13742203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13743203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13744203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13745203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13746203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13747203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13748203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13749203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13750203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13751203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13752203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13753203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13754203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13755203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13756203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13757203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13758203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13759203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13760203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13761203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13762203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13763203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13764203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13765203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13766203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13767203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13768203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13769203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13770203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13771203945Sweongyo	};
13772203945Sweongyo	static struct bwn_txgain_entry txgain_r1[] = {
13773203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13774203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13775203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13776203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13777203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13778203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13779203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13780203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13781203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13782203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13783203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13784203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13785203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13786203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13787203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13788203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13789203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13790203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13791203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 14, 0, 68 },
13792203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13793203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13794203945Sweongyo		{ 7, 15, 14, 0, 59 }, { 7, 15, 14, 0, 57 },
13795203945Sweongyo		{ 7, 15, 13, 0, 72 }, { 7, 15, 13, 0, 70 },
13796203945Sweongyo		{ 7, 15, 13, 0, 68 }, { 7, 15, 13, 0, 66 },
13797203945Sweongyo		{ 7, 15, 13, 0, 64 }, { 7, 15, 13, 0, 62 },
13798203945Sweongyo		{ 7, 15, 13, 0, 60 }, { 7, 15, 13, 0, 59 },
13799203945Sweongyo		{ 7, 15, 13, 0, 57 }, { 7, 15, 12, 0, 71 },
13800203945Sweongyo		{ 7, 15, 12, 0, 69 }, { 7, 15, 12, 0, 67 },
13801203945Sweongyo		{ 7, 15, 12, 0, 65 }, { 7, 15, 12, 0, 63 },
13802203945Sweongyo		{ 7, 15, 12, 0, 62 }, { 7, 15, 12, 0, 60 },
13803203945Sweongyo		{ 7, 15, 12, 0, 58 }, { 7, 15, 12, 0, 57 },
13804203945Sweongyo		{ 7, 15, 11, 0, 70 }, { 7, 15, 11, 0, 68 },
13805203945Sweongyo		{ 7, 15, 11, 0, 66 }, { 7, 15, 11, 0, 65 },
13806203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13807203945Sweongyo		{ 7, 15, 11, 0, 59 }, { 7, 15, 11, 0, 58 },
13808203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13809203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13810203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13811203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13812203945Sweongyo		{ 7, 15, 10, 0, 56 }, { 7, 15, 9, 0, 70 },
13813203945Sweongyo		{ 7, 15, 9, 0, 68 }, { 7, 15, 9, 0, 66 },
13814203945Sweongyo		{ 7, 15, 9, 0, 64 }, { 7, 15, 9, 0, 62 },
13815203945Sweongyo		{ 7, 15, 9, 0, 60 }, { 7, 15, 9, 0, 59 },
13816203945Sweongyo		{ 7, 14, 9, 0, 72 }, { 7, 14, 9, 0, 70 },
13817203945Sweongyo		{ 7, 14, 9, 0, 68 }, { 7, 14, 9, 0, 66 },
13818203945Sweongyo		{ 7, 14, 9, 0, 64 }, { 7, 14, 9, 0, 62 },
13819203945Sweongyo		{ 7, 14, 9, 0, 60 }, { 7, 14, 9, 0, 59 },
13820203945Sweongyo		{ 7, 13, 9, 0, 72 }, { 7, 13, 9, 0, 70 },
13821203945Sweongyo		{ 7, 13, 9, 0, 68 }, { 7, 13, 9, 0, 66 },
13822203945Sweongyo		{ 7, 13, 9, 0, 64 }, { 7, 13, 9, 0, 63 },
13823203945Sweongyo		{ 7, 13, 9, 0, 61 }, { 7, 13, 9, 0, 59 },
13824203945Sweongyo		{ 7, 13, 9, 0, 57 }, { 7, 13, 8, 0, 72 },
13825203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13826203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13827203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13828203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 12, 8, 0, 72 },
13829203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13830203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13831203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13832203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 7, 0, 73 },
13833203945Sweongyo		{ 7, 12, 7, 0, 71 }, { 7, 12, 7, 0, 69 },
13834203945Sweongyo		{ 7, 12, 7, 0, 67 }, { 7, 12, 7, 0, 65 },
13835203945Sweongyo		{ 7, 12, 7, 0, 63 }, { 7, 12, 7, 0, 61 },
13836203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 11, 7, 0, 72 },
13837203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13838203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 65 },
13839203945Sweongyo		{ 7, 11, 7, 0, 63 }, { 7, 11, 7, 0, 61 },
13840203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 6, 0, 73 },
13841203945Sweongyo		{ 7, 11, 6, 0, 71 }
13842203945Sweongyo	};
13843203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r1[] = {
13844203945Sweongyo		{ 4, 15, 15, 0, 90 }, { 4, 15, 15, 0, 88 },
13845203945Sweongyo		{ 4, 15, 15, 0, 85 }, { 4, 15, 15, 0, 83 },
13846203945Sweongyo		{ 4, 15, 15, 0, 81 }, { 4, 15, 15, 0, 78 },
13847203945Sweongyo		{ 4, 15, 15, 0, 76 }, { 4, 15, 15, 0, 74 },
13848203945Sweongyo		{ 4, 15, 15, 0, 72 }, { 4, 15, 15, 0, 70 },
13849203945Sweongyo		{ 4, 15, 15, 0, 68 }, { 4, 15, 15, 0, 66 },
13850203945Sweongyo		{ 4, 15, 15, 0, 64 }, { 4, 15, 15, 0, 62 },
13851203945Sweongyo		{ 4, 15, 15, 0, 60 }, { 4, 15, 15, 0, 59 },
13852203945Sweongyo		{ 4, 15, 14, 0, 72 }, { 4, 15, 14, 0, 70 },
13853203945Sweongyo		{ 4, 15, 14, 0, 68 }, { 4, 15, 14, 0, 66 },
13854203945Sweongyo		{ 4, 15, 14, 0, 64 }, { 4, 15, 14, 0, 62 },
13855203945Sweongyo		{ 4, 15, 14, 0, 60 }, { 4, 15, 14, 0, 59 },
13856203945Sweongyo		{ 4, 15, 13, 0, 72 }, { 4, 15, 13, 0, 70 },
13857203945Sweongyo		{ 4, 15, 13, 0, 68 }, { 4, 15, 13, 0, 66 },
13858203945Sweongyo		{ 4, 15, 13, 0, 64 }, { 4, 15, 13, 0, 62 },
13859203945Sweongyo		{ 4, 15, 13, 0, 60 }, { 4, 15, 13, 0, 59 },
13860203945Sweongyo		{ 4, 15, 12, 0, 72 }, { 4, 15, 12, 0, 70 },
13861203945Sweongyo		{ 4, 15, 12, 0, 68 }, { 4, 15, 12, 0, 66 },
13862203945Sweongyo		{ 4, 15, 12, 0, 64 }, { 4, 15, 12, 0, 62 },
13863203945Sweongyo		{ 4, 15, 12, 0, 60 }, { 4, 15, 12, 0, 59 },
13864203945Sweongyo		{ 4, 15, 11, 0, 72 }, { 4, 15, 11, 0, 70 },
13865203945Sweongyo		{ 4, 15, 11, 0, 68 }, { 4, 15, 11, 0, 66 },
13866203945Sweongyo		{ 4, 15, 11, 0, 64 }, { 4, 15, 11, 0, 62 },
13867203945Sweongyo		{ 4, 15, 11, 0, 60 }, { 4, 15, 11, 0, 59 },
13868203945Sweongyo		{ 4, 15, 10, 0, 72 }, { 4, 15, 10, 0, 70 },
13869203945Sweongyo		{ 4, 15, 10, 0, 68 }, { 4, 15, 10, 0, 66 },
13870203945Sweongyo		{ 4, 15, 10, 0, 64 }, { 4, 15, 10, 0, 62 },
13871203945Sweongyo		{ 4, 15, 10, 0, 60 }, { 4, 15, 10, 0, 59 },
13872203945Sweongyo		{ 4, 15, 9, 0, 72 }, { 4, 15, 9, 0, 70 },
13873203945Sweongyo		{ 4, 15, 9, 0, 68 }, { 4, 15, 9, 0, 66 },
13874203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13875203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13876203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13877203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13878203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13879203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13880203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13881203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13882203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13883203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13884203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13885203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13886203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13887203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13888203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13889203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13890203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13891203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13892203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13893203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13894203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13895203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13896203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13897203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13898203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13899203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13900203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13901203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13902203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13903203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13904203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13905203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13906203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13907203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 }
13908203945Sweongyo	};
13909203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r1[] = {
13910203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13911203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13912203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13913203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13914203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13915203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13916203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13917203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13918203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13919203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13920203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13921203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13922203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13923203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13924203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13925203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13926203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13927203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13928203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13929203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13930203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13931203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13932203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13933203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13934203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13935203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13936203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13937203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13938203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13939203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13940203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13941203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13942203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13943203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13944203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13945203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13946203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13947203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13948203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13949203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13950203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13951203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13952203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13953203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13954203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13955203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13956203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13957203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13958203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13959203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13960203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13961203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13962203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13963203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13964203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13965203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13966203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13967203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13968203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13969203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13970203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13971203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13972203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13973203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13974203945Sweongyo	};
13975203945Sweongyo
13976203945Sweongyo	if (mac->mac_phy.rev != 0 && mac->mac_phy.rev != 1) {
13977203945Sweongyo		if (siba->siba_sprom.bf_hi & BWN_BFH_NOPA)
13978203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r2);
13979203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13980203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13981203945Sweongyo			    txgain_2ghz_r2);
13982203945Sweongyo		else
13983203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13984203945Sweongyo			    txgain_5ghz_r2);
13985203945Sweongyo		return;
13986203945Sweongyo	}
13987203945Sweongyo
13988203945Sweongyo	if (mac->mac_phy.rev == 0) {
13989203945Sweongyo		if ((siba->siba_sprom.bf_hi & BWN_BFH_NOPA) ||
13990203945Sweongyo		    (siba->siba_sprom.bf_lo & BWN_BFL_HGPA))
13991203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r0);
13992203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13993203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13994203945Sweongyo			    txgain_2ghz_r0);
13995203945Sweongyo		else
13996203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13997203945Sweongyo			    txgain_5ghz_r0);
13998203945Sweongyo		return;
13999203945Sweongyo	}
14000203945Sweongyo
14001203945Sweongyo	if ((siba->siba_sprom.bf_hi & BWN_BFH_NOPA) ||
14002203945Sweongyo	    (siba->siba_sprom.bf_lo & BWN_BFL_HGPA))
14003203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r1);
14004203945Sweongyo	else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
14005203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_2ghz_r1);
14006203945Sweongyo	else
14007203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_5ghz_r1);
14008203945Sweongyo}
14009203945Sweongyo
14010203945Sweongyostatic void
14011203945Sweongyobwn_tab_write(struct bwn_mac *mac, uint32_t typeoffset, uint32_t value)
14012203945Sweongyo{
14013203945Sweongyo	uint32_t offset, type;
14014203945Sweongyo
14015203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
14016203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
14017203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
14018203945Sweongyo
14019203945Sweongyo	switch (type) {
14020203945Sweongyo	case BWN_TAB_8BIT:
14021203945Sweongyo		KASSERT(!(value & ~0xff), ("%s:%d: fail", __func__, __LINE__));
14022203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14023203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
14024203945Sweongyo		break;
14025203945Sweongyo	case BWN_TAB_16BIT:
14026203945Sweongyo		KASSERT(!(value & ~0xffff),
14027203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
14028203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14029203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
14030203945Sweongyo		break;
14031203945Sweongyo	case BWN_TAB_32BIT:
14032203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14033203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
14034203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
14035203945Sweongyo		break;
14036203945Sweongyo	default:
14037203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
14038203945Sweongyo	}
14039203945Sweongyo}
14040203945Sweongyo
14041203945Sweongyostatic int
14042203945Sweongyobwn_phy_lp_loopback(struct bwn_mac *mac)
14043203945Sweongyo{
14044203945Sweongyo	struct bwn_phy_lp_iq_est ie;
14045203945Sweongyo	int i, index = -1;
14046203945Sweongyo	uint32_t tmp;
14047203945Sweongyo
14048203945Sweongyo	memset(&ie, 0, sizeof(ie));
14049203945Sweongyo
14050203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1, 1);
14051203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 1);
14052203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
14053203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
14054203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
14055203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
14056203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x8);
14057203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, 0x80);
14058203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x80);
14059203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x80);
14060203945Sweongyo	for (i = 0; i < 32; i++) {
14061203945Sweongyo		bwn_phy_lp_set_rxgain_idx(mac, i);
14062203945Sweongyo		bwn_phy_lp_ddfs_turnon(mac, 1, 1, 5, 5, 0);
14063203945Sweongyo		if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
14064203945Sweongyo			continue;
14065203945Sweongyo		tmp = (ie.ie_ipwr + ie.ie_qpwr) / 1000;
14066203945Sweongyo		if ((tmp > 4000) && (tmp < 10000)) {
14067203945Sweongyo			index = i;
14068203945Sweongyo			break;
14069203945Sweongyo		}
14070203945Sweongyo	}
14071203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
14072203945Sweongyo	return (index);
14073203945Sweongyo}
14074203945Sweongyo
14075203945Sweongyostatic void
14076203945Sweongyobwn_phy_lp_set_rxgain_idx(struct bwn_mac *mac, uint16_t idx)
14077203945Sweongyo{
14078203945Sweongyo
14079203945Sweongyo	bwn_phy_lp_set_rxgain(mac, bwn_tab_read(mac, BWN_TAB_2(12, idx)));
14080203945Sweongyo}
14081203945Sweongyo
14082203945Sweongyostatic void
14083203945Sweongyobwn_phy_lp_ddfs_turnon(struct bwn_mac *mac, int i_on, int q_on,
14084203945Sweongyo    int incr1, int incr2, int scale_idx)
14085203945Sweongyo{
14086203945Sweongyo
14087203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
14088203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0xff80);
14089203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0x80ff);
14090203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0xff80, incr1);
14091203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0x80ff, incr2 << 8);
14092203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff7, i_on << 3);
14093203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xffef, q_on << 4);
14094203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xff9f, scale_idx << 5);
14095203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffb);
14096203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DDFS, 0x2);
14097203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x20);
14098203945Sweongyo}
14099203945Sweongyo
14100203945Sweongyostatic uint8_t
14101203945Sweongyobwn_phy_lp_rx_iq_est(struct bwn_mac *mac, uint16_t sample, uint8_t time,
14102203945Sweongyo    struct bwn_phy_lp_iq_est *ie)
14103203945Sweongyo{
14104203945Sweongyo	int i;
14105203945Sweongyo
14106203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfff7);
14107203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_IQ_NUM_SMPLS_ADDR, sample);
14108203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xff00, time);
14109203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xfeff);
14110203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
14111203945Sweongyo
14112203945Sweongyo	for (i = 0; i < 500; i++) {
14113203945Sweongyo		if (!(BWN_PHY_READ(mac,
14114203945Sweongyo		    BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
14115203945Sweongyo			break;
14116203945Sweongyo		DELAY(1000);
14117203945Sweongyo	}
14118203945Sweongyo	if ((BWN_PHY_READ(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
14119203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14120203945Sweongyo		return 0;
14121203945Sweongyo	}
14122203945Sweongyo
14123203945Sweongyo	ie->ie_iqprod = BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_HI_ADDR);
14124203945Sweongyo	ie->ie_iqprod <<= 16;
14125203945Sweongyo	ie->ie_iqprod |= BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_LO_ADDR);
14126203945Sweongyo	ie->ie_ipwr = BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_HI_ADDR);
14127203945Sweongyo	ie->ie_ipwr <<= 16;
14128203945Sweongyo	ie->ie_ipwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_LO_ADDR);
14129203945Sweongyo	ie->ie_qpwr = BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR);
14130203945Sweongyo	ie->ie_qpwr <<= 16;
14131203945Sweongyo	ie->ie_qpwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR);
14132203945Sweongyo
14133203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14134203945Sweongyo	return 1;
14135203945Sweongyo}
14136203945Sweongyo
14137203945Sweongyostatic uint32_t
14138203945Sweongyobwn_tab_read(struct bwn_mac *mac, uint32_t typeoffset)
14139203945Sweongyo{
14140203945Sweongyo	uint32_t offset, type, value;
14141203945Sweongyo
14142203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
14143203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
14144203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
14145203945Sweongyo
14146203945Sweongyo	switch (type) {
14147203945Sweongyo	case BWN_TAB_8BIT:
14148203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14149203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
14150203945Sweongyo		break;
14151203945Sweongyo	case BWN_TAB_16BIT:
14152203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14153203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14154203945Sweongyo		break;
14155203945Sweongyo	case BWN_TAB_32BIT:
14156203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14157203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATAHI);
14158203945Sweongyo		value <<= 16;
14159203945Sweongyo		value |= BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14160203945Sweongyo		break;
14161203945Sweongyo	default:
14162203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
14163203945Sweongyo		value = 0;
14164203945Sweongyo	}
14165203945Sweongyo
14166203945Sweongyo	return (value);
14167203945Sweongyo}
14168203945Sweongyo
14169203945Sweongyostatic void
14170203945Sweongyobwn_phy_lp_ddfs_turnoff(struct bwn_mac *mac)
14171203945Sweongyo{
14172203945Sweongyo
14173203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffd);
14174203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0xffdf);
14175203945Sweongyo}
14176203945Sweongyo
14177203945Sweongyostatic void
14178203945Sweongyobwn_phy_lp_set_txgain_dac(struct bwn_mac *mac, uint16_t dac)
14179203945Sweongyo{
14180203945Sweongyo	uint16_t ctl;
14181203945Sweongyo
14182203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0xc7f;
14183203945Sweongyo	ctl |= dac << 7;
14184203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf000, ctl);
14185203945Sweongyo}
14186203945Sweongyo
14187203945Sweongyostatic void
14188203945Sweongyobwn_phy_lp_set_txgain_pa(struct bwn_mac *mac, uint16_t gain)
14189203945Sweongyo{
14190203945Sweongyo
14191203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0xe03f, gain << 6);
14192203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x80ff, gain << 8);
14193203945Sweongyo}
14194203945Sweongyo
14195203945Sweongyostatic void
14196203945Sweongyobwn_phy_lp_set_txgain_override(struct bwn_mac *mac)
14197203945Sweongyo{
14198203945Sweongyo
14199203945Sweongyo	if (mac->mac_phy.rev < 2)
14200203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
14201203945Sweongyo	else {
14202203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x80);
14203203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x4000);
14204203945Sweongyo	}
14205203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x40);
14206203945Sweongyo}
14207203945Sweongyo
14208203945Sweongyostatic uint16_t
14209203945Sweongyobwn_phy_lp_get_pa_gain(struct bwn_mac *mac)
14210203945Sweongyo{
14211203945Sweongyo
14212203945Sweongyo	return BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0x7f;
14213203945Sweongyo}
14214203945Sweongyo
14215203945Sweongyostatic uint8_t
14216203945Sweongyobwn_nbits(int32_t val)
14217203945Sweongyo{
14218203945Sweongyo	uint32_t tmp;
14219203945Sweongyo	uint8_t nbits = 0;
14220203945Sweongyo
14221203945Sweongyo	for (tmp = abs(val); tmp != 0; tmp >>= 1)
14222203945Sweongyo		nbits++;
14223203945Sweongyo	return (nbits);
14224203945Sweongyo}
14225203945Sweongyo
14226203945Sweongyostatic void
14227203945Sweongyobwn_phy_lp_gaintbl_write_multi(struct bwn_mac *mac, int offset, int count,
14228203945Sweongyo    struct bwn_txgain_entry *table)
14229203945Sweongyo{
14230203945Sweongyo	int i;
14231203945Sweongyo
14232203945Sweongyo	for (i = offset; i < count; i++)
14233203945Sweongyo		bwn_phy_lp_gaintbl_write(mac, i, table[i]);
14234203945Sweongyo}
14235203945Sweongyo
14236203945Sweongyostatic void
14237203945Sweongyobwn_phy_lp_gaintbl_write(struct bwn_mac *mac, int offset,
14238203945Sweongyo    struct bwn_txgain_entry data)
14239203945Sweongyo{
14240203945Sweongyo
14241203945Sweongyo	if (mac->mac_phy.rev >= 2)
14242203945Sweongyo		bwn_phy_lp_gaintbl_write_r2(mac, offset, data);
14243203945Sweongyo	else
14244203945Sweongyo		bwn_phy_lp_gaintbl_write_r01(mac, offset, data);
14245203945Sweongyo}
14246203945Sweongyo
14247203945Sweongyostatic void
14248203945Sweongyobwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset,
14249203945Sweongyo    struct bwn_txgain_entry te)
14250203945Sweongyo{
14251203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
14252203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
14253203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
14254203945Sweongyo	uint32_t tmp;
14255203945Sweongyo
14256203945Sweongyo	KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__));
14257203945Sweongyo
14258203945Sweongyo	tmp = (te.te_pad << 16) | (te.te_pga << 8) | te.te_gm;
14259203945Sweongyo	if (mac->mac_phy.rev >= 3) {
14260203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14261203945Sweongyo		    (0x10 << 24) : (0x70 << 24));
14262203945Sweongyo	} else {
14263203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14264203945Sweongyo		    (0x14 << 24) : (0x7f << 24));
14265203945Sweongyo	}
14266203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0xc0 + offset), tmp);
14267203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0x140 + offset),
14268203945Sweongyo	    te.te_bbmult << 20 | te.te_dac << 28);
14269203945Sweongyo}
14270203945Sweongyo
14271203945Sweongyostatic void
14272203945Sweongyobwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
14273203945Sweongyo    struct bwn_txgain_entry te)
14274203945Sweongyo{
14275203945Sweongyo
14276203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
14277203945Sweongyo
14278203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0xc0 + offset),
14279203945Sweongyo	    (te.te_pad << 11) | (te.te_pga << 7) | (te.te_gm  << 4) |
14280203945Sweongyo	    te.te_dac);
14281203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0x140 + offset), te.te_bbmult << 20);
14282203945Sweongyo}
14283203945Sweongyo
14284203945Sweongyostatic void
14285204257Sweongyobwn_sysctl_node(struct bwn_softc *sc)
14286204257Sweongyo{
14287204257Sweongyo	device_t dev = sc->sc_dev;
14288204257Sweongyo	struct bwn_mac *mac;
14289204257Sweongyo	struct bwn_stats *stats;
14290204257Sweongyo
14291204257Sweongyo	/* XXX assume that count of MAC is only 1. */
14292204257Sweongyo
14293204257Sweongyo	if ((mac = sc->sc_curmac) == NULL)
14294204257Sweongyo		return;
14295204257Sweongyo	stats = &mac->mac_stats;
14296204257Sweongyo
14297204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14298204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14299204257Sweongyo	    "linknoise", CTLFLAG_RW, &stats->rts, 0, "Noise level");
14300204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14301204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14302204257Sweongyo	    "rts", CTLFLAG_RW, &stats->rts, 0, "RTS");
14303204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14304204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14305204257Sweongyo	    "rtsfail", CTLFLAG_RW, &stats->rtsfail, 0, "RTS failed to send");
14306204257Sweongyo
14307204257Sweongyo#ifdef BWN_DEBUG
14308204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14309204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14310204257Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
14311204257Sweongyo#endif
14312204257Sweongyo}
14313204257Sweongyo
14314204257Sweongyostatic void
14315203945Sweongyobwn_identify(driver_t *driver, device_t parent)
14316203945Sweongyo{
14317203945Sweongyo
14318203945Sweongyo	BUS_ADD_CHILD(parent, 0, "bwn", -1);
14319203945Sweongyo}
14320203945Sweongyo
14321203945Sweongyostatic device_method_t bwn_methods[] = {
14322203945Sweongyo	/* Device interface */
14323203945Sweongyo	DEVMETHOD(device_identify,	bwn_identify),
14324203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
14325203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
14326203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
14327203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
14328203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
14329203945Sweongyo	{ 0,0 }
14330203945Sweongyo};
14331203945Sweongyostatic driver_t bwn_driver = {
14332203945Sweongyo	"bwn",
14333203945Sweongyo	bwn_methods,
14334203945Sweongyo	sizeof(struct bwn_softc)
14335203945Sweongyo};
14336203945Sweongyostatic devclass_t bwn_devclass;
14337203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
14338203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
14339203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
14340203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
14341203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
14342