if_bwn.c revision 210393
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 210393 2010-07-22 20:08:02Z 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_phy.h>
71206358Srpaulo#include <net80211/ieee80211_ratectl.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 *);
137204922Sweongyostatic void	bwn_sprom_bugfixes(device_t);
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_updateslot(struct ifnet *);
184203945Sweongyostatic void	bwn_update_promisc(struct ifnet *);
185203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
186203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
187203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
188203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
189203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
190203945Sweongyo		    const struct wmeParams *, uint16_t);
191203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
192203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
193203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
194203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
195203945Sweongyo		    const char [IFNAMSIZ], int, int,
196203945Sweongyo		    int, const uint8_t [IEEE80211_ADDR_LEN],
197203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
198203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
199203945Sweongyostatic void	bwn_stop(struct bwn_softc *, int);
200203945Sweongyostatic void	bwn_stop_locked(struct bwn_softc *, int);
201203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
202203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
203203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
204203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
205203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
206203945Sweongyostatic uint64_t	bwn_hf_read(struct bwn_mac *);
207203945Sweongyostatic void	bwn_hf_write(struct bwn_mac *, uint64_t);
208203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
209203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
210203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
211203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
212203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
213203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
214203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
215203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
216203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
217203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
218203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
219203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
220203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
221203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
222203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
223203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
224203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
225203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
226203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
227203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
228203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
229203945Sweongyo		    int);
230203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
231203945Sweongyo		    struct bwn_pio_rxqueue *, int);
232203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
233203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
234203945Sweongyo		    uint16_t);
235203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
236203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
237203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
238203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
239203945Sweongyo		    const struct bwn_txstatus *);
240203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
241203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
242203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
243203945Sweongyo		    uint16_t);
244203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
245203945Sweongyo		    uint32_t);
246203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
247203945Sweongyo		    struct mbuf *);
248203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
249203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
250203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
251203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
252203945Sweongyo		    uint16_t, uint32_t);
253203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
254203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
255203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
256203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
257203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
258203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
259203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
260203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
261203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
262203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
263203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
264203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
265203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
266203945Sweongyo		    int, struct bwn_dmadesc_generic **,
267203945Sweongyo		    struct bwn_dmadesc_meta **);
268203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
269203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
270203945Sweongyo		    int, int);
271203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
272203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
273203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
274203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
275203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
276203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
277203945Sweongyo		    int, struct bwn_dmadesc_generic **,
278203945Sweongyo		    struct bwn_dmadesc_meta **);
279203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
280203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
281203945Sweongyo		    int, int);
282203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
283203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
284203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
285203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
286203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
287203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
288203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
289203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
290203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
291203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
292203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
293203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
294203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
295203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
296203945Sweongyo		    struct bwn_dmadesc_meta *);
297203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
298203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
299203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
300203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
301203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
302203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
303203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
304203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
305203945Sweongyo		    int);
306203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
307203945Sweongyo		    bus_size_t, int);
308203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
309203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
310203945Sweongyo		    const struct bwn_txstatus *);
311203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
312203945Sweongyo		    struct mbuf *);
313203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
314203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
315203945Sweongyo		    uint8_t);
316203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
317203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
318203945Sweongyo		    int, int, int);
319203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
320203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
321203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
322203945Sweongyostatic void	bwn_phy_g_init_sub(struct bwn_mac *);
323203945Sweongyostatic uint8_t	bwn_has_hwpctl(struct bwn_mac *);
324203945Sweongyostatic void	bwn_phy_init_b5(struct bwn_mac *);
325203945Sweongyostatic void	bwn_phy_init_b6(struct bwn_mac *);
326203945Sweongyostatic void	bwn_phy_init_a(struct bwn_mac *);
327203945Sweongyostatic void	bwn_loopback_calcgain(struct bwn_mac *);
328203945Sweongyostatic uint16_t	bwn_rf_init_bcm2050(struct bwn_mac *);
329203945Sweongyostatic void	bwn_lo_g_init(struct bwn_mac *);
330203945Sweongyostatic void	bwn_lo_g_adjust(struct bwn_mac *);
331203945Sweongyostatic void	bwn_lo_get_powervector(struct bwn_mac *);
332203945Sweongyostatic struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
333203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *);
334203945Sweongyostatic void	bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
335203945Sweongyostatic void	bwn_phy_hwpctl_init(struct bwn_mac *);
336203945Sweongyostatic void	bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
337203945Sweongyostatic void	bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
338203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *,
339203945Sweongyo		    uint8_t);
340203945Sweongyostatic void	bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
341203945Sweongyostatic uint16_t	bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
342203945Sweongyostatic void	bwn_spu_workaround(struct bwn_mac *, uint8_t);
343203945Sweongyostatic void	bwn_wa_init(struct bwn_mac *);
344203945Sweongyostatic void	bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
345203945Sweongyo		    uint16_t);
346203945Sweongyostatic void	bwn_dummy_transmission(struct bwn_mac *, int, int);
347203945Sweongyostatic void	bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
348203945Sweongyo		    uint32_t);
349203945Sweongyostatic void	bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
350203945Sweongyo		    uint16_t);
351203945Sweongyostatic void	bwn_ram_write(struct bwn_mac *, uint16_t, uint32_t);
352203945Sweongyostatic void	bwn_mac_suspend(struct bwn_mac *);
353203945Sweongyostatic void	bwn_mac_enable(struct bwn_mac *);
354203945Sweongyostatic void	bwn_psctl(struct bwn_mac *, uint32_t);
355203945Sweongyostatic int16_t	bwn_nrssi_read(struct bwn_mac *, uint16_t);
356203945Sweongyostatic void	bwn_nrssi_offset(struct bwn_mac *);
357203945Sweongyostatic void	bwn_nrssi_threshold(struct bwn_mac *);
358203945Sweongyostatic void	bwn_nrssi_slope_11g(struct bwn_mac *);
359203945Sweongyostatic void	bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
360203945Sweongyo		    int16_t);
361203945Sweongyostatic void	bwn_set_original_gains(struct bwn_mac *);
362203945Sweongyostatic void	bwn_hwpctl_early_init(struct bwn_mac *);
363203945Sweongyostatic void	bwn_hwpctl_init_gphy(struct bwn_mac *);
364203945Sweongyostatic uint16_t	bwn_phy_g_chan2freq(uint8_t);
365203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
366203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
367203945Sweongyo		    const char *, struct bwn_fwfile *);
368203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
369203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
370203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
371203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
372203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
373203945Sweongyostatic int	bwn_switch_channel(struct bwn_mac *, int);
374203945Sweongyostatic uint16_t	bwn_ant2phy(int);
375203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
376203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
377203945Sweongyo		    const uint8_t *);
378203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
379203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
380203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
381203945Sweongyo		    const uint8_t *);
382203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
383203945Sweongyo		    const uint8_t *);
384203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
385203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
386203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
387203945Sweongyo		    struct ieee80211_channel *);
388203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
389203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
390203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
391203945Sweongyostatic int	bwn_intr(void *);
392203945Sweongyostatic void	bwn_intrtask(void *, int);
393203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
394203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
395203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
396203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
397203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
398203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
399203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
400203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
401203945Sweongyostatic void	bwn_hwreset(void *, int);
402203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
403203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
404203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
405203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
406203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
407203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
408203945Sweongyo		    const struct bwn_txstatus *);
409203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
410203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
411203945Sweongyostatic void	bwn_start_locked(struct ifnet *);
412203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
413203945Sweongyo		    struct mbuf *);
414203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
415203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
416203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
417203945Sweongyo		    uint16_t);
418203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
419203945Sweongyo		    const uint8_t);
420203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
421203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
422203945Sweongyostatic int	bwn_phy_shm_tssi_read(struct bwn_mac *, uint16_t);
423203945Sweongyostatic void	bwn_phy_g_setatt(struct bwn_mac *, int *, int *);
424203945Sweongyostatic void	bwn_phy_lock(struct bwn_mac *);
425203945Sweongyostatic void	bwn_phy_unlock(struct bwn_mac *);
426203945Sweongyostatic void	bwn_rf_lock(struct bwn_mac *);
427203945Sweongyostatic void	bwn_rf_unlock(struct bwn_mac *);
428203945Sweongyostatic void	bwn_txpwr(void *, int);
429203945Sweongyostatic void	bwn_tasks(void *);
430203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
431203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
432203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
433203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
434203945Sweongyo		    uint8_t);
435203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
436203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
437203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
438203945Sweongyo		    int, int);
439203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
440203945Sweongyostatic void	bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
441203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
442203945Sweongyostatic void	bwn_watchdog(void *);
443203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
444203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
445203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
446203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
447203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
448203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
449203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
450203945Sweongyostatic void	bwn_led_blink_next(void *);
451203945Sweongyostatic void	bwn_led_blink_end(void *);
452203945Sweongyostatic void	bwn_rfswitch(void *);
453203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
454203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
455203945Sweongyostatic void	bwn_phy_lp_init_pre(struct bwn_mac *);
456203945Sweongyostatic int	bwn_phy_lp_init(struct bwn_mac *);
457203945Sweongyostatic uint16_t	bwn_phy_lp_read(struct bwn_mac *, uint16_t);
458203945Sweongyostatic void	bwn_phy_lp_write(struct bwn_mac *, uint16_t, uint16_t);
459203945Sweongyostatic void	bwn_phy_lp_maskset(struct bwn_mac *, uint16_t, uint16_t,
460203945Sweongyo		    uint16_t);
461203945Sweongyostatic uint16_t	bwn_phy_lp_rf_read(struct bwn_mac *, uint16_t);
462203945Sweongyostatic void	bwn_phy_lp_rf_write(struct bwn_mac *, uint16_t, uint16_t);
463203945Sweongyostatic void	bwn_phy_lp_rf_onoff(struct bwn_mac *, int);
464203945Sweongyostatic int	bwn_phy_lp_switch_channel(struct bwn_mac *, uint32_t);
465203945Sweongyostatic uint32_t	bwn_phy_lp_get_default_chan(struct bwn_mac *);
466203945Sweongyostatic void	bwn_phy_lp_set_antenna(struct bwn_mac *, int);
467203945Sweongyostatic void	bwn_phy_lp_task_60s(struct bwn_mac *);
468203945Sweongyostatic void	bwn_phy_lp_readsprom(struct bwn_mac *);
469203945Sweongyostatic void	bwn_phy_lp_bbinit(struct bwn_mac *);
470203945Sweongyostatic void	bwn_phy_lp_txpctl_init(struct bwn_mac *);
471203945Sweongyostatic void	bwn_phy_lp_calib(struct bwn_mac *);
472203945Sweongyostatic void	bwn_phy_lp_switch_analog(struct bwn_mac *, int);
473203945Sweongyostatic int	bwn_phy_lp_b2062_switch_channel(struct bwn_mac *, uint8_t);
474203945Sweongyostatic int	bwn_phy_lp_b2063_switch_channel(struct bwn_mac *, uint8_t);
475203945Sweongyostatic void	bwn_phy_lp_set_anafilter(struct bwn_mac *, uint8_t);
476203945Sweongyostatic void	bwn_phy_lp_set_gaintbl(struct bwn_mac *, uint32_t);
477203945Sweongyostatic void	bwn_phy_lp_digflt_save(struct bwn_mac *);
478203945Sweongyostatic void	bwn_phy_lp_get_txpctlmode(struct bwn_mac *);
479203945Sweongyostatic void	bwn_phy_lp_set_txpctlmode(struct bwn_mac *, uint8_t);
480203945Sweongyostatic void	bwn_phy_lp_bugfix(struct bwn_mac *);
481203945Sweongyostatic void	bwn_phy_lp_digflt_restore(struct bwn_mac *);
482203945Sweongyostatic void	bwn_phy_lp_tblinit(struct bwn_mac *);
483203945Sweongyostatic void	bwn_phy_lp_bbinit_r2(struct bwn_mac *);
484203945Sweongyostatic void	bwn_phy_lp_bbinit_r01(struct bwn_mac *);
485203945Sweongyostatic void	bwn_phy_lp_b2062_init(struct bwn_mac *);
486203945Sweongyostatic void	bwn_phy_lp_b2063_init(struct bwn_mac *);
487203945Sweongyostatic void	bwn_phy_lp_rxcal_r2(struct bwn_mac *);
488203945Sweongyostatic void	bwn_phy_lp_rccal_r12(struct bwn_mac *);
489203945Sweongyostatic void	bwn_phy_lp_set_rccap(struct bwn_mac *);
490203945Sweongyostatic uint32_t	bwn_phy_lp_roundup(uint32_t, uint32_t, uint8_t);
491203945Sweongyostatic void	bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *);
492203945Sweongyostatic void	bwn_phy_lp_b2062_vco_calib(struct bwn_mac *);
493203945Sweongyostatic void	bwn_tab_write_multi(struct bwn_mac *, uint32_t, int,
494203945Sweongyo		    const void *);
495203945Sweongyostatic void	bwn_tab_read_multi(struct bwn_mac *, uint32_t, int, void *);
496203945Sweongyostatic struct bwn_txgain
497203945Sweongyo		bwn_phy_lp_get_txgain(struct bwn_mac *);
498203945Sweongyostatic uint8_t	bwn_phy_lp_get_bbmult(struct bwn_mac *);
499203945Sweongyostatic void	bwn_phy_lp_set_txgain(struct bwn_mac *, struct bwn_txgain *);
500203945Sweongyostatic void	bwn_phy_lp_set_bbmult(struct bwn_mac *, uint8_t);
501203945Sweongyostatic void	bwn_phy_lp_set_trsw_over(struct bwn_mac *, uint8_t, uint8_t);
502203945Sweongyostatic void	bwn_phy_lp_set_rxgain(struct bwn_mac *, uint32_t);
503203945Sweongyostatic void	bwn_phy_lp_set_deaf(struct bwn_mac *, uint8_t);
504203945Sweongyostatic int	bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *, uint16_t);
505203945Sweongyostatic void	bwn_phy_lp_clear_deaf(struct bwn_mac *, uint8_t);
506203945Sweongyostatic void	bwn_phy_lp_tblinit_r01(struct bwn_mac *);
507203945Sweongyostatic void	bwn_phy_lp_tblinit_r2(struct bwn_mac *);
508203945Sweongyostatic void	bwn_phy_lp_tblinit_txgain(struct bwn_mac *);
509203945Sweongyostatic void	bwn_tab_write(struct bwn_mac *, uint32_t, uint32_t);
510203945Sweongyostatic void	bwn_phy_lp_b2062_tblinit(struct bwn_mac *);
511203945Sweongyostatic void	bwn_phy_lp_b2063_tblinit(struct bwn_mac *);
512203945Sweongyostatic int	bwn_phy_lp_loopback(struct bwn_mac *);
513203945Sweongyostatic void	bwn_phy_lp_set_rxgain_idx(struct bwn_mac *, uint16_t);
514203945Sweongyostatic void	bwn_phy_lp_ddfs_turnon(struct bwn_mac *, int, int, int, int,
515203945Sweongyo		    int);
516203945Sweongyostatic uint8_t	bwn_phy_lp_rx_iq_est(struct bwn_mac *, uint16_t, uint8_t,
517203945Sweongyo		    struct bwn_phy_lp_iq_est *);
518203945Sweongyostatic void	bwn_phy_lp_ddfs_turnoff(struct bwn_mac *);
519203945Sweongyostatic uint32_t	bwn_tab_read(struct bwn_mac *, uint32_t);
520203945Sweongyostatic void	bwn_phy_lp_set_txgain_dac(struct bwn_mac *, uint16_t);
521203945Sweongyostatic void	bwn_phy_lp_set_txgain_pa(struct bwn_mac *, uint16_t);
522203945Sweongyostatic void	bwn_phy_lp_set_txgain_override(struct bwn_mac *);
523203945Sweongyostatic uint16_t	bwn_phy_lp_get_pa_gain(struct bwn_mac *);
524203945Sweongyostatic uint8_t	bwn_nbits(int32_t);
525203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *, int, int,
526203945Sweongyo		    struct bwn_txgain_entry *);
527203945Sweongyostatic void	bwn_phy_lp_gaintbl_write(struct bwn_mac *, int,
528203945Sweongyo		    struct bwn_txgain_entry);
529203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
530203945Sweongyo		    struct bwn_txgain_entry);
531203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
532203945Sweongyo		    struct bwn_txgain_entry);
533204257Sweongyostatic void	bwn_sysctl_node(struct bwn_softc *);
534203945Sweongyo
535203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
536203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
537203945Sweongyo	{ -1,			0,		0 }
538203945Sweongyo};
539203945Sweongyo
540203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
541203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
542203945Sweongyo	{ -1,			0,		0 }
543203945Sweongyo};
544203945Sweongyo
545203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
546203945Sweongyo	.channels = {
547203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
548203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
549203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
550203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
551203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
552203945Sweongyo	.nchannels = 14
553203945Sweongyo};
554203945Sweongyo
555203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
556203945Sweongyo	.channels = {
557203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
558203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
559203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
560203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
561203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
562203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
563203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
564203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
565203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
566203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
567203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
568203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
569203945Sweongyo		{ 6080, 216, 30 } },
570203945Sweongyo	.nchannels = 37
571203945Sweongyo};
572203945Sweongyo
573203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
574203945Sweongyo	.channels = {
575203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
576203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
577203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
578203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
579203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
580203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
581203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
582203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
583203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
584203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
585203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
586203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
587203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
588203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
589203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
590203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
591203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
592203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
593203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
594203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
595203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
596203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
597203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
598203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
599203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
600203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
601203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
602203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
603203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
604203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
605203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
606203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
607203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
608203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
609203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
610203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
611203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
612203945Sweongyo	.nchannels = 110
613203945Sweongyo};
614203945Sweongyo
615203945Sweongyostatic const uint8_t bwn_b2063_chantable_data[33][12] = {
616203945Sweongyo	{ 0x6f, 0x3c, 0x3c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
617203945Sweongyo	{ 0x6f, 0x2c, 0x2c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
618203945Sweongyo	{ 0x6f, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
619203945Sweongyo	{ 0x6e, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
620203945Sweongyo	{ 0x6e, 0xc, 0xc, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
621203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x2, 0x5, 0xd, 0xd, 0x77, 0x80, 0x20, 0 },
622203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x5, 0xd, 0xc, 0x77, 0x80, 0x20, 0 },
623203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x80, 0x20, 0 },
624203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x70, 0x20, 0 },
625203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xb, 0xc, 0x77, 0x70, 0x20, 0 },
626203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x4, 0xb, 0xb, 0x77, 0x60, 0x20, 0 },
627203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xb, 0x77, 0x60, 0x20, 0 },
628203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xa, 0x77, 0x60, 0x20, 0 },
629203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x2, 0x9, 0x9, 0x77, 0x60, 0x20, 0 },
630203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x1, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
631203945Sweongyo	{ 0x67, 0xc, 0xc, 0, 0, 0, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
632203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x2, 0x1, 0x77, 0x20, 0, 0 },
633203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x1, 0x1, 0x77, 0x20, 0, 0 },
634203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0x1, 0, 0x77, 0x10, 0, 0 },
635203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
636203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
637203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
638203945Sweongyo	{ 0x61, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
639203945Sweongyo	{ 0x60, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
640203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xe, 0xf, 0xf, 0x77, 0xc0, 0x50, 0 },
641203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xd, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
642203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
643203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
644203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xb, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
645203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xa, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
646203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x7, 0x9, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
647203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x6, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
648203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x5, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 }
649203945Sweongyo};
650203945Sweongyo
651203945Sweongyostatic const struct bwn_b206x_chan bwn_b2063_chantable[] = {
652203945Sweongyo	{ 1, 2412, bwn_b2063_chantable_data[0] },
653203945Sweongyo	{ 2, 2417, bwn_b2063_chantable_data[0] },
654203945Sweongyo	{ 3, 2422, bwn_b2063_chantable_data[0] },
655203945Sweongyo	{ 4, 2427, bwn_b2063_chantable_data[1] },
656203945Sweongyo	{ 5, 2432, bwn_b2063_chantable_data[1] },
657203945Sweongyo	{ 6, 2437, bwn_b2063_chantable_data[1] },
658203945Sweongyo	{ 7, 2442, bwn_b2063_chantable_data[1] },
659203945Sweongyo	{ 8, 2447, bwn_b2063_chantable_data[1] },
660203945Sweongyo	{ 9, 2452, bwn_b2063_chantable_data[2] },
661203945Sweongyo	{ 10, 2457, bwn_b2063_chantable_data[2] },
662203945Sweongyo	{ 11, 2462, bwn_b2063_chantable_data[3] },
663203945Sweongyo	{ 12, 2467, bwn_b2063_chantable_data[3] },
664203945Sweongyo	{ 13, 2472, bwn_b2063_chantable_data[3] },
665203945Sweongyo	{ 14, 2484, bwn_b2063_chantable_data[4] },
666203945Sweongyo	{ 34, 5170, bwn_b2063_chantable_data[5] },
667203945Sweongyo	{ 36, 5180, bwn_b2063_chantable_data[6] },
668203945Sweongyo	{ 38, 5190, bwn_b2063_chantable_data[7] },
669203945Sweongyo	{ 40, 5200, bwn_b2063_chantable_data[8] },
670203945Sweongyo	{ 42, 5210, bwn_b2063_chantable_data[9] },
671203945Sweongyo	{ 44, 5220, bwn_b2063_chantable_data[10] },
672203945Sweongyo	{ 46, 5230, bwn_b2063_chantable_data[11] },
673203945Sweongyo	{ 48, 5240, bwn_b2063_chantable_data[12] },
674203945Sweongyo	{ 52, 5260, bwn_b2063_chantable_data[13] },
675203945Sweongyo	{ 56, 5280, bwn_b2063_chantable_data[14] },
676203945Sweongyo	{ 60, 5300, bwn_b2063_chantable_data[14] },
677203945Sweongyo	{ 64, 5320, bwn_b2063_chantable_data[15] },
678203945Sweongyo	{ 100, 5500, bwn_b2063_chantable_data[16] },
679203945Sweongyo	{ 104, 5520, bwn_b2063_chantable_data[17] },
680203945Sweongyo	{ 108, 5540, bwn_b2063_chantable_data[18] },
681203945Sweongyo	{ 112, 5560, bwn_b2063_chantable_data[19] },
682203945Sweongyo	{ 116, 5580, bwn_b2063_chantable_data[20] },
683203945Sweongyo	{ 120, 5600, bwn_b2063_chantable_data[21] },
684203945Sweongyo	{ 124, 5620, bwn_b2063_chantable_data[21] },
685203945Sweongyo	{ 128, 5640, bwn_b2063_chantable_data[22] },
686203945Sweongyo	{ 132, 5660, bwn_b2063_chantable_data[22] },
687203945Sweongyo	{ 136, 5680, bwn_b2063_chantable_data[22] },
688203945Sweongyo	{ 140, 5700, bwn_b2063_chantable_data[23] },
689203945Sweongyo	{ 149, 5745, bwn_b2063_chantable_data[23] },
690203945Sweongyo	{ 153, 5765, bwn_b2063_chantable_data[23] },
691203945Sweongyo	{ 157, 5785, bwn_b2063_chantable_data[23] },
692203945Sweongyo	{ 161, 5805, bwn_b2063_chantable_data[23] },
693203945Sweongyo	{ 165, 5825, bwn_b2063_chantable_data[23] },
694203945Sweongyo	{ 184, 4920, bwn_b2063_chantable_data[24] },
695203945Sweongyo	{ 188, 4940, bwn_b2063_chantable_data[25] },
696203945Sweongyo	{ 192, 4960, bwn_b2063_chantable_data[26] },
697203945Sweongyo	{ 196, 4980, bwn_b2063_chantable_data[27] },
698203945Sweongyo	{ 200, 5000, bwn_b2063_chantable_data[28] },
699203945Sweongyo	{ 204, 5020, bwn_b2063_chantable_data[29] },
700203945Sweongyo	{ 208, 5040, bwn_b2063_chantable_data[30] },
701203945Sweongyo	{ 212, 5060, bwn_b2063_chantable_data[31] },
702203945Sweongyo	{ 216, 5080, bwn_b2063_chantable_data[32] }
703203945Sweongyo};
704203945Sweongyo
705203945Sweongyostatic const uint8_t bwn_b2062_chantable_data[22][12] = {
706203945Sweongyo	{ 0xff, 0xff, 0xb5, 0x1b, 0x24, 0x32, 0x32, 0x88, 0x88, 0, 0, 0 },
707203945Sweongyo	{ 0, 0x22, 0x20, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
708203945Sweongyo	{ 0, 0x11, 0x10, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
709203945Sweongyo	{ 0, 0, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
710203945Sweongyo	{ 0, 0x11, 0x20, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
711203945Sweongyo	{ 0, 0x11, 0x10, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
712203945Sweongyo	{ 0, 0x11, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
713203945Sweongyo	{ 0, 0, 0, 0x63, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
714203945Sweongyo	{ 0, 0, 0, 0x62, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
715203945Sweongyo	{ 0, 0, 0, 0x30, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
716203945Sweongyo	{ 0, 0, 0, 0x20, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
717203945Sweongyo	{ 0, 0, 0, 0x10, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
718203945Sweongyo	{ 0, 0, 0, 0, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
719203945Sweongyo	{ 0x55, 0x77, 0x90, 0xf7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
720203945Sweongyo	{ 0x44, 0x77, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
721203945Sweongyo	{ 0x44, 0x66, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
722203945Sweongyo	{ 0x33, 0x66, 0x70, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
723203945Sweongyo	{ 0x22, 0x55, 0x60, 0xd7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
724203945Sweongyo	{ 0x22, 0x55, 0x60, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
725203945Sweongyo	{ 0x22, 0x44, 0x50, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
726203945Sweongyo	{ 0x11, 0x44, 0x50, 0xa5, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
727203945Sweongyo	{ 0, 0x44, 0x40, 0xb6, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 }
728203945Sweongyo};
729203945Sweongyo
730203945Sweongyostatic const struct bwn_b206x_chan bwn_b2062_chantable[] = {
731203945Sweongyo	{ 1, 2412, bwn_b2062_chantable_data[0] },
732203945Sweongyo	{ 2, 2417, bwn_b2062_chantable_data[0] },
733203945Sweongyo	{ 3, 2422, bwn_b2062_chantable_data[0] },
734203945Sweongyo	{ 4, 2427, bwn_b2062_chantable_data[0] },
735203945Sweongyo	{ 5, 2432, bwn_b2062_chantable_data[0] },
736203945Sweongyo	{ 6, 2437, bwn_b2062_chantable_data[0] },
737203945Sweongyo	{ 7, 2442, bwn_b2062_chantable_data[0] },
738203945Sweongyo	{ 8, 2447, bwn_b2062_chantable_data[0] },
739203945Sweongyo	{ 9, 2452, bwn_b2062_chantable_data[0] },
740203945Sweongyo	{ 10, 2457, bwn_b2062_chantable_data[0] },
741203945Sweongyo	{ 11, 2462, bwn_b2062_chantable_data[0] },
742203945Sweongyo	{ 12, 2467, bwn_b2062_chantable_data[0] },
743203945Sweongyo	{ 13, 2472, bwn_b2062_chantable_data[0] },
744203945Sweongyo	{ 14, 2484, bwn_b2062_chantable_data[0] },
745203945Sweongyo	{ 34, 5170, bwn_b2062_chantable_data[1] },
746203945Sweongyo	{ 38, 5190, bwn_b2062_chantable_data[2] },
747203945Sweongyo	{ 42, 5210, bwn_b2062_chantable_data[2] },
748203945Sweongyo	{ 46, 5230, bwn_b2062_chantable_data[3] },
749203945Sweongyo	{ 36, 5180, bwn_b2062_chantable_data[4] },
750203945Sweongyo	{ 40, 5200, bwn_b2062_chantable_data[5] },
751203945Sweongyo	{ 44, 5220, bwn_b2062_chantable_data[6] },
752203945Sweongyo	{ 48, 5240, bwn_b2062_chantable_data[3] },
753203945Sweongyo	{ 52, 5260, bwn_b2062_chantable_data[3] },
754203945Sweongyo	{ 56, 5280, bwn_b2062_chantable_data[3] },
755203945Sweongyo	{ 60, 5300, bwn_b2062_chantable_data[7] },
756203945Sweongyo	{ 64, 5320, bwn_b2062_chantable_data[8] },
757203945Sweongyo	{ 100, 5500, bwn_b2062_chantable_data[9] },
758203945Sweongyo	{ 104, 5520, bwn_b2062_chantable_data[10] },
759203945Sweongyo	{ 108, 5540, bwn_b2062_chantable_data[10] },
760203945Sweongyo	{ 112, 5560, bwn_b2062_chantable_data[10] },
761203945Sweongyo	{ 116, 5580, bwn_b2062_chantable_data[11] },
762203945Sweongyo	{ 120, 5600, bwn_b2062_chantable_data[12] },
763203945Sweongyo	{ 124, 5620, bwn_b2062_chantable_data[12] },
764203945Sweongyo	{ 128, 5640, bwn_b2062_chantable_data[12] },
765203945Sweongyo	{ 132, 5660, bwn_b2062_chantable_data[12] },
766203945Sweongyo	{ 136, 5680, bwn_b2062_chantable_data[12] },
767203945Sweongyo	{ 140, 5700, bwn_b2062_chantable_data[12] },
768203945Sweongyo	{ 149, 5745, bwn_b2062_chantable_data[12] },
769203945Sweongyo	{ 153, 5765, bwn_b2062_chantable_data[12] },
770203945Sweongyo	{ 157, 5785, bwn_b2062_chantable_data[12] },
771203945Sweongyo	{ 161, 5805, bwn_b2062_chantable_data[12] },
772203945Sweongyo	{ 165, 5825, bwn_b2062_chantable_data[12] },
773203945Sweongyo	{ 184, 4920, bwn_b2062_chantable_data[13] },
774203945Sweongyo	{ 188, 4940, bwn_b2062_chantable_data[14] },
775203945Sweongyo	{ 192, 4960, bwn_b2062_chantable_data[15] },
776203945Sweongyo	{ 196, 4980, bwn_b2062_chantable_data[16] },
777203945Sweongyo	{ 200, 5000, bwn_b2062_chantable_data[17] },
778203945Sweongyo	{ 204, 5020, bwn_b2062_chantable_data[18] },
779203945Sweongyo	{ 208, 5040, bwn_b2062_chantable_data[19] },
780203945Sweongyo	{ 212, 5060, bwn_b2062_chantable_data[20] },
781203945Sweongyo	{ 216, 5080, bwn_b2062_chantable_data[21] }
782203945Sweongyo};
783203945Sweongyo
784203945Sweongyo/* for LP PHY */
785203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_5354[] = {
786203945Sweongyo	{  1, -66, 15 }, {  2, -66, 15 }, {  3, -66, 15 }, {  4, -66, 15 },
787203945Sweongyo	{  5, -66, 15 }, {  6, -66, 15 }, {  7, -66, 14 }, {  8, -66, 14 },
788203945Sweongyo	{  9, -66, 14 }, { 10, -66, 14 }, { 11, -66, 14 }, { 12, -66, 13 },
789203945Sweongyo	{ 13, -66, 13 }, { 14, -66, 13 },
790203945Sweongyo};
791203945Sweongyo
792203945Sweongyo/* for LP PHY */
793203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r12[] = {
794203945Sweongyo	{   1, -64, 13 }, {   2, -64, 13 }, {   3, -64, 13 }, {   4, -64, 13 },
795203945Sweongyo	{   5, -64, 12 }, {   6, -64, 12 }, {   7, -64, 12 }, {   8, -64, 12 },
796203945Sweongyo	{   9, -64, 12 }, {  10, -64, 11 }, {  11, -64, 11 }, {  12, -64, 11 },
797203945Sweongyo	{  13, -64, 11 }, {  14, -64, 10 }, {  34, -62, 24 }, {  38, -62, 24 },
798203945Sweongyo	{  42, -62, 24 }, {  46, -62, 23 }, {  36, -62, 24 }, {  40, -62, 24 },
799203945Sweongyo	{  44, -62, 23 }, {  48, -62, 23 }, {  52, -62, 23 }, {  56, -62, 22 },
800203945Sweongyo	{  60, -62, 22 }, {  64, -62, 22 }, { 100, -62, 16 }, { 104, -62, 16 },
801203945Sweongyo	{ 108, -62, 15 }, { 112, -62, 14 }, { 116, -62, 14 }, { 120, -62, 13 },
802203945Sweongyo	{ 124, -62, 12 }, { 128, -62, 12 }, { 132, -62, 12 }, { 136, -62, 11 },
803203945Sweongyo	{ 140, -62, 10 }, { 149, -61,  9 }, { 153, -61,  9 }, { 157, -61,  9 },
804203945Sweongyo	{ 161, -61,  8 }, { 165, -61,  8 }, { 184, -62, 25 }, { 188, -62, 25 },
805203945Sweongyo	{ 192, -62, 25 }, { 196, -62, 25 }, { 200, -62, 25 }, { 204, -62, 25 },
806203945Sweongyo	{ 208, -62, 25 }, { 212, -62, 25 }, { 216, -62, 26 },
807203945Sweongyo};
808203945Sweongyo
809203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r2 = { 0, -64, 0 };
810203945Sweongyo
811203945Sweongyostatic const uint8_t bwn_tab_sigsq_tbl[] = {
812203945Sweongyo	0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
813203945Sweongyo	0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
814203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
815203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
816203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
817203945Sweongyo	0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
818203945Sweongyo};
819203945Sweongyo
820203945Sweongyostatic const uint8_t bwn_tab_pllfrac_tbl[] = {
821203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
822203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
823203945Sweongyo};
824203945Sweongyo
825203945Sweongyostatic const uint16_t bwn_tabl_iqlocal_tbl[] = {
826203945Sweongyo	0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
827203945Sweongyo	0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
828203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
829203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
830203945Sweongyo	0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
831203945Sweongyo	0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
832203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
833203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
834203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
835203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
836203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
837203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
838203945Sweongyo};
839203945Sweongyo
840203945Sweongyostatic const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
841203945Sweongyostatic const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
842203945Sweongyostatic const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
843203945Sweongyostatic const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
844203945Sweongyostatic const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
845203945Sweongyoconst uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
846203945Sweongyo
847203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
848203945Sweongyo{							\
849203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
850203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
851203945Sweongyo}
852203945Sweongyo
853203945Sweongyostatic const struct {
854203945Sweongyo	uint16_t	vid;
855203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
856203945Sweongyo} bwn_vendor_led_act[] = {
857203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
858203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
859203945Sweongyo};
860203945Sweongyo
861203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
862203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
863203945Sweongyo
864203945Sweongyo#undef VENDOR_LED_ACT
865203945Sweongyo
866203945Sweongyostatic const struct {
867203945Sweongyo	int		on_dur;
868203945Sweongyo	int		off_dur;
869203945Sweongyo} bwn_led_duration[109] = {
870203945Sweongyo	[0]	= { 400, 100 },
871203945Sweongyo	[2]	= { 150, 75 },
872203945Sweongyo	[4]	= { 90, 45 },
873203945Sweongyo	[11]	= { 66, 34 },
874203945Sweongyo	[12]	= { 53, 26 },
875203945Sweongyo	[18]	= { 42, 21 },
876203945Sweongyo	[22]	= { 35, 17 },
877203945Sweongyo	[24]	= { 32, 16 },
878203945Sweongyo	[36]	= { 21, 10 },
879203945Sweongyo	[48]	= { 16, 8 },
880203945Sweongyo	[72]	= { 11, 5 },
881203945Sweongyo	[96]	= { 9, 4 },
882203945Sweongyo	[108]	= { 7, 3 }
883203945Sweongyo};
884203945Sweongyo
885203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
886203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
887203945Sweongyo	[1] = BWN_WME_BACKGROUND,
888203945Sweongyo	[2] = BWN_WME_VOICE,
889203945Sweongyo	[3] = BWN_WME_VIDEO,
890203945Sweongyo};
891203945Sweongyo
892203945Sweongyostatic const struct siba_devid bwn_devs[] = {
893203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
894203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
895203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
896203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
897203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
898203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
899203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
900203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
901203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
902203945Sweongyo};
903203945Sweongyo
904203945Sweongyostatic int
905203945Sweongyobwn_probe(device_t dev)
906203945Sweongyo{
907203945Sweongyo	int i;
908203945Sweongyo
909203945Sweongyo	for (i = 0; i < sizeof(bwn_devs) / sizeof(bwn_devs[0]); i++) {
910204922Sweongyo		if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor &&
911204922Sweongyo		    siba_get_device(dev) == bwn_devs[i].sd_device &&
912204922Sweongyo		    siba_get_revid(dev) == bwn_devs[i].sd_rev)
913203945Sweongyo			return (BUS_PROBE_DEFAULT);
914203945Sweongyo	}
915203945Sweongyo
916203945Sweongyo	return (ENXIO);
917203945Sweongyo}
918203945Sweongyo
919203945Sweongyostatic int
920203945Sweongyobwn_attach(device_t dev)
921203945Sweongyo{
922203945Sweongyo	struct bwn_mac *mac;
923203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
924203945Sweongyo	int error, i, msic, reg;
925203945Sweongyo
926203945Sweongyo	sc->sc_dev = dev;
927203945Sweongyo#ifdef BWN_DEBUG
928203945Sweongyo	sc->sc_debug = bwn_debug;
929203945Sweongyo#endif
930203945Sweongyo
931203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
932203945Sweongyo		error = bwn_attach_pre(sc);
933203945Sweongyo		if (error != 0)
934203945Sweongyo			return (error);
935204922Sweongyo		bwn_sprom_bugfixes(dev);
936203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
937203945Sweongyo	}
938203945Sweongyo
939203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
940204922Sweongyo		if (siba_get_pci_device(dev) != 0x4313 &&
941204922Sweongyo		    siba_get_pci_device(dev) != 0x431a &&
942204922Sweongyo		    siba_get_pci_device(dev) != 0x4321) {
943203945Sweongyo			device_printf(sc->sc_dev,
944203945Sweongyo			    "skip 802.11 cores\n");
945203945Sweongyo			return (ENODEV);
946203945Sweongyo		}
947203945Sweongyo	}
948203945Sweongyo
949203945Sweongyo	mac = (struct bwn_mac *)malloc(sizeof(*mac), M_DEVBUF,
950203945Sweongyo	    M_NOWAIT | M_ZERO);
951203945Sweongyo	if (mac == NULL)
952203945Sweongyo		return (ENOMEM);
953203945Sweongyo	mac->mac_sc = sc;
954203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
955203945Sweongyo	if (bwn_bfp != 0)
956203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
957203945Sweongyo
958203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
959203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
960203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
961203945Sweongyo
962203945Sweongyo	error = bwn_attach_core(mac);
963203945Sweongyo	if (error)
964203945Sweongyo		goto fail0;
965203945Sweongyo	bwn_led_attach(mac);
966203945Sweongyo
967203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
968203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
969204922Sweongyo	    siba_get_chipid(sc->sc_dev), siba_get_revid(sc->sc_dev),
970203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
971203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
972203945Sweongyo	    mac->mac_phy.rf_rev);
973203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
974203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
975203945Sweongyo		    mac->mac_method.dma.dmatype);
976203945Sweongyo	else
977203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
978203945Sweongyo
979203945Sweongyo	/*
980203945Sweongyo	 * setup PCI resources and interrupt.
981203945Sweongyo	 */
982203945Sweongyo	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
983203945Sweongyo		msic = pci_msi_count(dev);
984203945Sweongyo		if (bootverbose)
985203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
986203945Sweongyo	} else
987203945Sweongyo		msic = 0;
988203945Sweongyo
989203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
990203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
991203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
992203945Sweongyo			device_printf(sc->sc_dev,
993203945Sweongyo			    "Using %d MSI messages\n", msic);
994203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
995203945Sweongyo			mac->mac_msi = 1;
996203945Sweongyo		}
997203945Sweongyo	}
998203945Sweongyo
999203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
1000203945Sweongyo	    mac->mac_res_irq);
1001203945Sweongyo	if (error) {
1002203945Sweongyo		device_printf(sc->sc_dev,
1003203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
1004203945Sweongyo		goto fail1;
1005203945Sweongyo	}
1006203945Sweongyo
1007203945Sweongyo	if (mac->mac_msi == 0)
1008203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
1009203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1010203945Sweongyo		    &mac->mac_intrhand[0]);
1011203945Sweongyo	else {
1012203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1013203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
1014203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1015203945Sweongyo			    &mac->mac_intrhand[i]);
1016203945Sweongyo			if (error != 0) {
1017203945Sweongyo				device_printf(sc->sc_dev,
1018203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
1019203945Sweongyo				break;
1020203945Sweongyo			}
1021203945Sweongyo		}
1022203945Sweongyo	}
1023203945Sweongyo
1024203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
1025203945Sweongyo
1026203945Sweongyo	/*
1027203945Sweongyo	 * calls attach-post routine
1028203945Sweongyo	 */
1029203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
1030203945Sweongyo		bwn_attach_post(sc);
1031203945Sweongyo
1032203945Sweongyo	return (0);
1033203945Sweongyofail1:
1034203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
1035203945Sweongyo		pci_release_msi(dev);
1036203945Sweongyofail0:
1037203945Sweongyo	free(mac, M_DEVBUF);
1038203945Sweongyo	return (error);
1039203945Sweongyo}
1040203945Sweongyo
1041203945Sweongyostatic int
1042203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
1043203945Sweongyo{
1044203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
1045203945Sweongyo
1046203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
1047203945Sweongyo		return (FALSE);
1048203945Sweongyo
1049203945Sweongyo	return (TRUE);
1050203945Sweongyo}
1051203945Sweongyo
1052203945Sweongyostatic int
1053203945Sweongyobwn_attach_post(struct bwn_softc *sc)
1054203945Sweongyo{
1055203945Sweongyo	struct ieee80211com *ic;
1056203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1057203945Sweongyo
1058203945Sweongyo	ic = ifp->if_l2com;
1059203945Sweongyo	ic->ic_ifp = ifp;
1060203945Sweongyo	/* XXX not right but it's not used anywhere important */
1061203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
1062203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
1063203945Sweongyo	ic->ic_caps =
1064203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
1065203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
1066204436Sweongyo		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
1067203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
1068203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
1069203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
1070203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
1071203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
1072203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
1073203945Sweongyo		;
1074203945Sweongyo
1075205141Sweongyo	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;	/* s/w bmiss */
1076205141Sweongyo
1077203945Sweongyo	/* call MI attach routine. */
1078203945Sweongyo	ieee80211_ifattach(ic,
1079204922Sweongyo	    bwn_is_valid_ether_addr(siba_sprom_get_mac_80211a(sc->sc_dev)) ?
1080204922Sweongyo	    siba_sprom_get_mac_80211a(sc->sc_dev) :
1081204922Sweongyo	    siba_sprom_get_mac_80211bg(sc->sc_dev));
1082203945Sweongyo
1083203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
1084203945Sweongyo
1085203945Sweongyo	/* override default methods */
1086203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
1087203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
1088203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
1089203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
1090203945Sweongyo
1091203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
1092203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
1093203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
1094203945Sweongyo
1095203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
1096203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
1097203945Sweongyo
1098203945Sweongyo	ieee80211_radiotap_attach(ic,
1099203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
1100203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
1101203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
1102203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
1103203945Sweongyo
1104204257Sweongyo	bwn_sysctl_node(sc);
1105203945Sweongyo
1106203945Sweongyo	if (bootverbose)
1107203945Sweongyo		ieee80211_announce(ic);
1108203945Sweongyo	return (0);
1109203945Sweongyo}
1110203945Sweongyo
1111203945Sweongyostatic void
1112203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
1113203945Sweongyo{
1114203945Sweongyo
1115203945Sweongyo	if (mac->mac_phy.detach != NULL)
1116203945Sweongyo		mac->mac_phy.detach(mac);
1117203945Sweongyo}
1118203945Sweongyo
1119203945Sweongyostatic int
1120203945Sweongyobwn_detach(device_t dev)
1121203945Sweongyo{
1122203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
1123203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1124203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1125203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1126203945Sweongyo	int i;
1127203945Sweongyo
1128203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
1129203945Sweongyo
1130203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
1131203945Sweongyo		bwn_stop(sc, 1);
1132203945Sweongyo		bwn_dma_free(mac);
1133203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
1134203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
1135203945Sweongyo		callout_drain(&sc->sc_task_ch);
1136203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
1137203945Sweongyo		bwn_phy_detach(mac);
1138203945Sweongyo		if (ifp != NULL) {
1139203945Sweongyo			ieee80211_draintask(ic, &mac->mac_hwreset);
1140203945Sweongyo			ieee80211_draintask(ic, &mac->mac_txpower);
1141203945Sweongyo			ieee80211_ifdetach(ic);
1142203945Sweongyo			if_free(ifp);
1143203945Sweongyo		}
1144203945Sweongyo	}
1145203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
1146203945Sweongyo	taskqueue_free(sc->sc_tq);
1147203945Sweongyo
1148203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1149203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
1150203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
1151203945Sweongyo			    mac->mac_intrhand[i]);
1152203945Sweongyo			mac->mac_intrhand[i] = NULL;
1153203945Sweongyo		}
1154203945Sweongyo	}
1155203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
1156203945Sweongyo	if (mac->mac_msi != 0)
1157203945Sweongyo		pci_release_msi(dev);
1158203945Sweongyo
1159203945Sweongyo	BWN_LOCK_DESTROY(sc);
1160203945Sweongyo	return (0);
1161203945Sweongyo}
1162203945Sweongyo
1163203945Sweongyostatic int
1164203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
1165203945Sweongyo{
1166203945Sweongyo	struct ifnet *ifp;
1167203945Sweongyo	int error = 0;
1168203945Sweongyo
1169203945Sweongyo	BWN_LOCK_INIT(sc);
1170203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
1171203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
1172203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
1173203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
1174203945Sweongyo
1175203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
1176203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
1177203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
1178203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
1179203945Sweongyo
1180203945Sweongyo	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
1181203945Sweongyo	if (ifp == NULL) {
1182203945Sweongyo		device_printf(sc->sc_dev, "can not if_alloc()\n");
1183203945Sweongyo		error = ENOSPC;
1184203945Sweongyo		goto fail;
1185203945Sweongyo	}
1186203945Sweongyo
1187203945Sweongyo	/* set these up early for if_printf use */
1188203945Sweongyo	if_initname(ifp, device_get_name(sc->sc_dev),
1189203945Sweongyo	    device_get_unit(sc->sc_dev));
1190203945Sweongyo
1191203945Sweongyo	ifp->if_softc = sc;
1192203945Sweongyo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1193203945Sweongyo	ifp->if_init = bwn_init;
1194203945Sweongyo	ifp->if_ioctl = bwn_ioctl;
1195203945Sweongyo	ifp->if_start = bwn_start;
1196207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
1197207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
1198203945Sweongyo	IFQ_SET_READY(&ifp->if_snd);
1199203945Sweongyo
1200203945Sweongyo	return (0);
1201203945Sweongyo
1202203945Sweongyofail:	BWN_LOCK_DESTROY(sc);
1203203945Sweongyo	return (error);
1204203945Sweongyo}
1205203945Sweongyo
1206203945Sweongyostatic void
1207204922Sweongyobwn_sprom_bugfixes(device_t dev)
1208203945Sweongyo{
1209203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
1210204922Sweongyo	((siba_get_pci_vendor(dev) == PCI_VENDOR_##_vendor) &&		\
1211204922Sweongyo	 (siba_get_pci_device(dev) == _device) &&			\
1212204922Sweongyo	 (siba_get_pci_subvendor(dev) == PCI_VENDOR_##_subvendor) &&	\
1213204922Sweongyo	 (siba_get_pci_subdevice(dev) == _subdevice))
1214203945Sweongyo
1215204922Sweongyo	if (siba_get_pci_subvendor(dev) == PCI_VENDOR_APPLE &&
1216204922Sweongyo	    siba_get_pci_subdevice(dev) == 0x4e &&
1217204922Sweongyo	    siba_get_pci_revid(dev) > 0x40)
1218204922Sweongyo		siba_sprom_set_bf_lo(dev,
1219204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_PACTRL);
1220204922Sweongyo	if (siba_get_pci_subvendor(dev) == SIBA_BOARDVENDOR_DELL &&
1221204922Sweongyo	    siba_get_chipid(dev) == 0x4301 && siba_get_pci_revid(dev) == 0x74)
1222204922Sweongyo		siba_sprom_set_bf_lo(dev,
1223204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_BTCOEXIST);
1224204922Sweongyo	if (siba_get_type(dev) == SIBA_TYPE_PCI) {
1225203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
1226203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
1227203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
1228203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
1229203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
1230203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
1231203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
1232204922Sweongyo			siba_sprom_set_bf_lo(dev,
1233204922Sweongyo			    siba_sprom_get_bf_lo(dev) & ~BWN_BFL_BTCOEXIST);
1234203945Sweongyo	}
1235203945Sweongyo#undef	BWN_ISDEV
1236203945Sweongyo}
1237203945Sweongyo
1238203945Sweongyostatic int
1239203945Sweongyobwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1240203945Sweongyo{
1241203945Sweongyo#define	IS_RUNNING(ifp) \
1242203945Sweongyo	((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
1243203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1244203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1245203945Sweongyo	struct ifreq *ifr = (struct ifreq *)data;
1246203945Sweongyo	int error = 0, startall;
1247203945Sweongyo
1248203945Sweongyo	switch (cmd) {
1249203945Sweongyo	case SIOCSIFFLAGS:
1250203945Sweongyo		startall = 0;
1251203945Sweongyo		if (IS_RUNNING(ifp)) {
1252203945Sweongyo			bwn_update_promisc(ifp);
1253203945Sweongyo		} else if (ifp->if_flags & IFF_UP) {
1254203945Sweongyo			if ((sc->sc_flags & BWN_FLAG_INVALID) == 0) {
1255203945Sweongyo				bwn_init(sc);
1256203945Sweongyo				startall = 1;
1257203945Sweongyo			}
1258203945Sweongyo		} else
1259203945Sweongyo			bwn_stop(sc, 1);
1260203945Sweongyo		if (startall)
1261203945Sweongyo			ieee80211_start_all(ic);
1262203945Sweongyo		break;
1263203945Sweongyo	case SIOCGIFMEDIA:
1264203945Sweongyo		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1265203945Sweongyo		break;
1266203945Sweongyo	case SIOCGIFADDR:
1267203945Sweongyo		error = ether_ioctl(ifp, cmd, data);
1268203945Sweongyo		break;
1269203945Sweongyo	default:
1270203945Sweongyo		error = EINVAL;
1271203945Sweongyo		break;
1272203945Sweongyo	}
1273203945Sweongyo	return (error);
1274203945Sweongyo}
1275203945Sweongyo
1276203945Sweongyostatic void
1277203945Sweongyobwn_start(struct ifnet *ifp)
1278203945Sweongyo{
1279203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1280203945Sweongyo
1281203945Sweongyo	BWN_LOCK(sc);
1282203945Sweongyo	bwn_start_locked(ifp);
1283203945Sweongyo	BWN_UNLOCK(sc);
1284203945Sweongyo}
1285203945Sweongyo
1286203945Sweongyostatic void
1287203945Sweongyobwn_start_locked(struct ifnet *ifp)
1288203945Sweongyo{
1289203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1290203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1291203945Sweongyo	struct ieee80211_frame *wh;
1292203945Sweongyo	struct ieee80211_node *ni;
1293203945Sweongyo	struct ieee80211_key *k;
1294203945Sweongyo	struct mbuf *m;
1295203945Sweongyo
1296203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1297203945Sweongyo
1298203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || mac == NULL ||
1299203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
1300203945Sweongyo		return;
1301203945Sweongyo
1302203945Sweongyo	for (;;) {
1303203945Sweongyo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);	/* XXX: LOCK */
1304203945Sweongyo		if (m == NULL)
1305203945Sweongyo			break;
1306203945Sweongyo
1307203945Sweongyo		if (bwn_tx_isfull(sc, m))
1308203945Sweongyo			break;
1309203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
1310203945Sweongyo		if (ni == NULL) {
1311203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
1312203945Sweongyo			m_freem(m);
1313203945Sweongyo			ifp->if_oerrors++;
1314203945Sweongyo			continue;
1315203945Sweongyo		}
1316203945Sweongyo		KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__));
1317203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
1318203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1319203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
1320203945Sweongyo			if (k == NULL) {
1321203945Sweongyo				ieee80211_free_node(ni);
1322203945Sweongyo				m_freem(m);
1323203945Sweongyo				ifp->if_oerrors++;
1324203945Sweongyo				continue;
1325203945Sweongyo			}
1326203945Sweongyo		}
1327203945Sweongyo		wh = NULL;	/* Catch any invalid use */
1328203945Sweongyo
1329203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
1330203945Sweongyo			if (ni != NULL)
1331203945Sweongyo				ieee80211_free_node(ni);
1332203945Sweongyo			ifp->if_oerrors++;
1333203945Sweongyo			continue;
1334203945Sweongyo		}
1335203945Sweongyo
1336203945Sweongyo		sc->sc_watchdog_timer = 5;
1337203945Sweongyo	}
1338203945Sweongyo}
1339203945Sweongyo
1340203945Sweongyostatic int
1341203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
1342203945Sweongyo{
1343203945Sweongyo	struct bwn_dma_ring *dr;
1344203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1345203945Sweongyo	struct bwn_pio_txqueue *tq;
1346203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1347203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1348203945Sweongyo
1349203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1350203945Sweongyo
1351203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
1352203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
1353203945Sweongyo		if (dr->dr_stop == 1 ||
1354203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
1355203945Sweongyo			dr->dr_stop = 1;
1356203945Sweongyo			goto full;
1357203945Sweongyo		}
1358203945Sweongyo	} else {
1359203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
1360203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
1361203945Sweongyo		    pktlen > (tq->tq_size - tq->tq_used)) {
1362203945Sweongyo			tq->tq_stop = 1;
1363203945Sweongyo			goto full;
1364203945Sweongyo		}
1365203945Sweongyo	}
1366203945Sweongyo	return (0);
1367203945Sweongyofull:
1368203945Sweongyo	IFQ_DRV_PREPEND(&ifp->if_snd, m);
1369203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1370203945Sweongyo	return (1);
1371203945Sweongyo}
1372203945Sweongyo
1373203945Sweongyostatic int
1374203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
1375203945Sweongyo{
1376203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1377203945Sweongyo	int error;
1378203945Sweongyo
1379203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1380203945Sweongyo
1381203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
1382203945Sweongyo		m_freem(m);
1383203945Sweongyo		return (ENXIO);
1384203945Sweongyo	}
1385203945Sweongyo
1386203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
1387203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
1388203945Sweongyo	if (error) {
1389203945Sweongyo		m_freem(m);
1390203945Sweongyo		return (error);
1391203945Sweongyo	}
1392203945Sweongyo	return (0);
1393203945Sweongyo}
1394203945Sweongyo
1395203945Sweongyostatic int
1396203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1397203945Sweongyo{
1398203945Sweongyo	struct bwn_pio_txpkt *tp;
1399203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
1400203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1401203945Sweongyo	struct bwn_txhdr txhdr;
1402203945Sweongyo	struct mbuf *m_new;
1403203945Sweongyo	uint32_t ctl32;
1404203945Sweongyo	int error;
1405203945Sweongyo	uint16_t ctl16;
1406203945Sweongyo
1407203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1408203945Sweongyo
1409203945Sweongyo	/* XXX TODO send packets after DTIM */
1410203945Sweongyo
1411203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
1412203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
1413203945Sweongyo	tp->tp_ni = ni;
1414203945Sweongyo	tp->tp_m = m;
1415203945Sweongyo
1416203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
1417203945Sweongyo	if (error) {
1418203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
1419203945Sweongyo		return (error);
1420203945Sweongyo	}
1421203945Sweongyo
1422203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
1423203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1424203945Sweongyo	tq->tq_free--;
1425203945Sweongyo
1426204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8) {
1427203945Sweongyo		/*
1428203945Sweongyo		 * XXX please removes m_defrag(9)
1429203945Sweongyo		 */
1430203945Sweongyo		m_new = m_defrag(m, M_DONTWAIT);
1431203945Sweongyo		if (m_new == NULL) {
1432203945Sweongyo			device_printf(sc->sc_dev,
1433203945Sweongyo			    "%s: can't defrag TX buffer\n",
1434203945Sweongyo			    __func__);
1435203945Sweongyo			return (ENOBUFS);
1436203945Sweongyo		}
1437203945Sweongyo		if (m_new->m_next != NULL)
1438203945Sweongyo			device_printf(sc->sc_dev,
1439203945Sweongyo			    "TODO: fragmented packets for PIO\n");
1440203945Sweongyo		tp->tp_m = m_new;
1441203945Sweongyo
1442203945Sweongyo		/* send HEADER */
1443203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
1444203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
1445203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
1446203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1447203945Sweongyo		/* send BODY */
1448203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
1449203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
1450203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
1451203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
1452203945Sweongyo	} else {
1453203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
1454203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
1455203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
1456203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1457203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
1458203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
1459203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
1460203945Sweongyo	}
1461203945Sweongyo
1462203945Sweongyo	return (0);
1463203945Sweongyo}
1464203945Sweongyo
1465203945Sweongyostatic struct bwn_pio_txqueue *
1466203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1467203945Sweongyo{
1468203945Sweongyo
1469203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1470203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1471203945Sweongyo
1472203945Sweongyo	switch (prio) {
1473203945Sweongyo	case 0:
1474203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1475203945Sweongyo	case 1:
1476203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1477203945Sweongyo	case 2:
1478203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1479203945Sweongyo	case 3:
1480203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1481203945Sweongyo	}
1482203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1483204242Simp	return (NULL);
1484203945Sweongyo}
1485203945Sweongyo
1486203945Sweongyostatic int
1487203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1488203945Sweongyo{
1489203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1490203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1491203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1492203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1493203945Sweongyo	struct bwn_dmadesc_generic *desc;
1494203945Sweongyo	struct bwn_dmadesc_meta *mt;
1495203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1496203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1497203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1498203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1499203945Sweongyo
1500203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1501203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1502203945Sweongyo
1503203945Sweongyo	/* XXX send after DTIM */
1504203945Sweongyo
1505203945Sweongyo	slot = bwn_dma_getslot(dr);
1506203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1507203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1508203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1509203945Sweongyo
1510203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1511203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1512203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1513203945Sweongyo	if (error)
1514203945Sweongyo		goto fail;
1515203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1516203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1517203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1518203945Sweongyo	if (error) {
1519203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1520203945Sweongyo		    __func__, error);
1521203945Sweongyo		goto fail;
1522203945Sweongyo	}
1523203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1524203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1525203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1526203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1527203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1528203945Sweongyo
1529203945Sweongyo	slot = bwn_dma_getslot(dr);
1530203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1531203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1532203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1533203945Sweongyo	mt->mt_m = m;
1534203945Sweongyo	mt->mt_ni = ni;
1535203945Sweongyo
1536203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1537203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1538203945Sweongyo	if (error && error != EFBIG) {
1539203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1540203945Sweongyo		    __func__, error);
1541203945Sweongyo		goto fail;
1542203945Sweongyo	}
1543203945Sweongyo	if (error) {    /* error == EFBIG */
1544203945Sweongyo		struct mbuf *m_new;
1545203945Sweongyo
1546203945Sweongyo		m_new = m_defrag(m, M_DONTWAIT);
1547203945Sweongyo		if (m_new == NULL) {
1548203945Sweongyo			if_printf(ifp, "%s: can't defrag TX buffer\n",
1549203945Sweongyo			    __func__);
1550203945Sweongyo			error = ENOBUFS;
1551203945Sweongyo			goto fail;
1552203945Sweongyo		} else {
1553203945Sweongyo			m = m_new;
1554203945Sweongyo		}
1555203945Sweongyo
1556203945Sweongyo		mt->mt_m = m;
1557203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1558203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1559203945Sweongyo		if (error) {
1560203945Sweongyo			if_printf(ifp, "%s: can't load TX buffer (2) %d\n",
1561203945Sweongyo			    __func__, error);
1562203945Sweongyo			goto fail;
1563203945Sweongyo		}
1564203945Sweongyo	}
1565203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1566203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1567203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1568203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1569203945Sweongyo
1570203945Sweongyo	/* XXX send after DTIM */
1571203945Sweongyo
1572203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1573203945Sweongyo	return (0);
1574203945Sweongyofail:
1575203945Sweongyo	dr->dr_curslot = backup[0];
1576203945Sweongyo	dr->dr_usedslot = backup[1];
1577203945Sweongyo	return (error);
1578203945Sweongyo#undef BWN_GET_TXHDRCACHE
1579203945Sweongyo}
1580203945Sweongyo
1581203945Sweongyostatic void
1582203945Sweongyobwn_watchdog(void *arg)
1583203945Sweongyo{
1584203945Sweongyo	struct bwn_softc *sc = arg;
1585203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1586203945Sweongyo
1587203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1588203945Sweongyo		if_printf(ifp, "device timeout\n");
1589203945Sweongyo		ifp->if_oerrors++;
1590203945Sweongyo	}
1591203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1592203945Sweongyo}
1593203945Sweongyo
1594203945Sweongyostatic int
1595203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1596203945Sweongyo{
1597203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1598203945Sweongyo	int error, have_bg = 0, have_a = 0;
1599203945Sweongyo	uint32_t high;
1600203945Sweongyo
1601204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5,
1602204922Sweongyo	    ("unsupported revision %d", siba_get_revid(sc->sc_dev)));
1603203945Sweongyo
1604204922Sweongyo	siba_powerup(sc->sc_dev, 0);
1605203945Sweongyo
1606204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
1607203945Sweongyo	bwn_reset_core(mac,
1608203945Sweongyo	    (high & BWN_TGSHIGH_HAVE_2GHZ) ? BWN_TGSLOW_SUPPORT_G : 0);
1609203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1610203945Sweongyo	if (error)
1611203945Sweongyo		goto fail;
1612203945Sweongyo
1613203945Sweongyo	have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1614203945Sweongyo	have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1615204922Sweongyo	if (siba_get_pci_device(sc->sc_dev) != 0x4312 &&
1616204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4319 &&
1617204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4324) {
1618203945Sweongyo		have_a = have_bg = 0;
1619203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1620203945Sweongyo			have_a = 1;
1621203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1622203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1623203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1624203945Sweongyo			have_bg = 1;
1625203945Sweongyo		else
1626203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1627203945Sweongyo			    mac->mac_phy.type));
1628203945Sweongyo	}
1629203945Sweongyo	/* XXX turns off PHY A because it's not supported */
1630203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1631203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1632203945Sweongyo		have_a = 0;
1633203945Sweongyo		have_bg = 1;
1634203945Sweongyo	}
1635203945Sweongyo
1636203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1637203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1638203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1639203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1640203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1641203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1642203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1643203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1644203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1645203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1646203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1647203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1648203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1649203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1650203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1651203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1652203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1653203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1654203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1655203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1656203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1657203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1658203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1659203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1660203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1661203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1662203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1663203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1664203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1665203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1666203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1667203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1668203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1669203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1670203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1671203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1672203945Sweongyo	} else {
1673203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1674203945Sweongyo		    mac->mac_phy.type);
1675203945Sweongyo		error = ENXIO;
1676203945Sweongyo		goto fail;
1677203945Sweongyo	}
1678203945Sweongyo
1679203945Sweongyo	mac->mac_phy.gmode = have_bg;
1680203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1681203945Sweongyo		error = mac->mac_phy.attach(mac);
1682203945Sweongyo		if (error) {
1683203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1684203945Sweongyo			goto fail;
1685203945Sweongyo		}
1686203945Sweongyo	}
1687203945Sweongyo
1688203945Sweongyo	bwn_reset_core(mac, have_bg ? BWN_TGSLOW_SUPPORT_G : 0);
1689203945Sweongyo
1690203945Sweongyo	error = bwn_chiptest(mac);
1691203945Sweongyo	if (error)
1692203945Sweongyo		goto fail;
1693203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1694203945Sweongyo	if (error) {
1695203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1696203945Sweongyo		goto fail;
1697203945Sweongyo	}
1698203945Sweongyo
1699203945Sweongyo	if (sc->sc_curmac == NULL)
1700203945Sweongyo		sc->sc_curmac = mac;
1701203945Sweongyo
1702203945Sweongyo	error = bwn_dma_attach(mac);
1703203945Sweongyo	if (error != 0) {
1704203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1705203945Sweongyo		goto fail;
1706203945Sweongyo	}
1707203945Sweongyo
1708203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1709203945Sweongyo
1710204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
1711203945Sweongyofail:
1712204922Sweongyo	siba_powerdown(sc->sc_dev);
1713203945Sweongyo	return (error);
1714203945Sweongyo}
1715203945Sweongyo
1716203945Sweongyostatic void
1717203945Sweongyobwn_reset_core(struct bwn_mac *mac, uint32_t flags)
1718203945Sweongyo{
1719204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1720203945Sweongyo	uint32_t low, ctl;
1721203945Sweongyo
1722203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1723203945Sweongyo
1724204922Sweongyo	siba_dev_up(sc->sc_dev, flags);
1725203945Sweongyo	DELAY(2000);
1726203945Sweongyo
1727204922Sweongyo	low = (siba_read_4(sc->sc_dev, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1728203945Sweongyo	    ~BWN_TGSLOW_PHYRESET;
1729204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low);
1730204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1731203945Sweongyo	DELAY(1000);
1732204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
1733204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1734203945Sweongyo	DELAY(1000);
1735203945Sweongyo
1736203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1737203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1738203945Sweongyo
1739203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1740203945Sweongyo	if (flags & BWN_TGSLOW_SUPPORT_G)
1741203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1742203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1743203945Sweongyo}
1744203945Sweongyo
1745203945Sweongyostatic int
1746203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1747203945Sweongyo{
1748203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1749203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1750203945Sweongyo	uint32_t tmp;
1751203945Sweongyo
1752203945Sweongyo	/* PHY */
1753203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1754203945Sweongyo	phy->gmode = (tgshigh & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1755203945Sweongyo	phy->rf_on = 1;
1756203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1757203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1758203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1759203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1760203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1761203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1762203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1763203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1764203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1765203945Sweongyo		goto unsupphy;
1766203945Sweongyo
1767203945Sweongyo	/* RADIO */
1768204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4317) {
1769204922Sweongyo		if (siba_get_chiprev(sc->sc_dev) == 0)
1770203945Sweongyo			tmp = 0x3205017f;
1771204922Sweongyo		else if (siba_get_chiprev(sc->sc_dev) == 1)
1772203945Sweongyo			tmp = 0x4205017f;
1773203945Sweongyo		else
1774203945Sweongyo			tmp = 0x5205017f;
1775203945Sweongyo	} else {
1776203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1777203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1778203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1779203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1780203945Sweongyo	}
1781203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1782203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1783203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1784203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1785203945Sweongyo		goto unsupradio;
1786203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1787203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1788203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1789203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1790203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1791203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1792203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1793203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1794203945Sweongyo		goto unsupradio;
1795203945Sweongyo
1796203945Sweongyo	return (0);
1797203945Sweongyounsupphy:
1798203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1799203945Sweongyo	    "analog %#x)\n",
1800203945Sweongyo	    phy->type, phy->rev, phy->analog);
1801203945Sweongyo	return (ENXIO);
1802203945Sweongyounsupradio:
1803203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1804203945Sweongyo	    "rev %#x)\n",
1805203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1806203945Sweongyo	return (ENXIO);
1807203945Sweongyo}
1808203945Sweongyo
1809203945Sweongyostatic int
1810203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1811203945Sweongyo{
1812203945Sweongyo#define	TESTVAL0	0x55aaaa55
1813203945Sweongyo#define	TESTVAL1	0xaa5555aa
1814203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1815203945Sweongyo	uint32_t v, backup;
1816203945Sweongyo
1817203945Sweongyo	BWN_LOCK(sc);
1818203945Sweongyo
1819203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1820203945Sweongyo
1821203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1822203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1823203945Sweongyo		goto error;
1824203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1825203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1826203945Sweongyo		goto error;
1827203945Sweongyo
1828203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1829203945Sweongyo
1830204922Sweongyo	if ((siba_get_revid(sc->sc_dev) >= 3) &&
1831204922Sweongyo	    (siba_get_revid(sc->sc_dev) <= 10)) {
1832203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1833203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1834203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1835203945Sweongyo			goto error;
1836203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1837203945Sweongyo			goto error;
1838203945Sweongyo	}
1839203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1840203945Sweongyo
1841203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1842203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1843203945Sweongyo		goto error;
1844203945Sweongyo
1845203945Sweongyo	BWN_UNLOCK(sc);
1846203945Sweongyo	return (0);
1847203945Sweongyoerror:
1848203945Sweongyo	BWN_UNLOCK(sc);
1849203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1850203945Sweongyo	return (ENODEV);
1851203945Sweongyo}
1852203945Sweongyo
1853203945Sweongyo#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
1854203945Sweongyo#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
1855203945Sweongyo
1856203945Sweongyostatic int
1857203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1858203945Sweongyo{
1859203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1860203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1861203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1862203945Sweongyo
1863203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1864203945Sweongyo	ic->ic_nchans = 0;
1865203945Sweongyo
1866203945Sweongyo	if (have_bg)
1867203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1868203945Sweongyo		    &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
1869203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1870203945Sweongyo		if (have_a)
1871203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1872203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_n,
1873203945Sweongyo			    IEEE80211_CHAN_HTA);
1874203945Sweongyo	} else {
1875203945Sweongyo		if (have_a)
1876203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1877203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_a,
1878203945Sweongyo			    IEEE80211_CHAN_A);
1879203945Sweongyo	}
1880203945Sweongyo
1881203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1882203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1883203945Sweongyo
1884203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1885203945Sweongyo}
1886203945Sweongyo
1887203945Sweongyostatic uint32_t
1888203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1889203945Sweongyo{
1890203945Sweongyo	uint32_t ret;
1891203945Sweongyo
1892204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1893203945Sweongyo
1894203945Sweongyo	if (way == BWN_SHARED) {
1895203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1896203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1897203945Sweongyo		if (offset & 0x0003) {
1898203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1899203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1900203945Sweongyo			ret <<= 16;
1901203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1902203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1903203945Sweongyo			goto out;
1904203945Sweongyo		}
1905203945Sweongyo		offset >>= 2;
1906203945Sweongyo	}
1907203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1908203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1909203945Sweongyoout:
1910203945Sweongyo	return (ret);
1911203945Sweongyo}
1912203945Sweongyo
1913203945Sweongyostatic uint16_t
1914203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1915203945Sweongyo{
1916203945Sweongyo	uint16_t ret;
1917203945Sweongyo
1918204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1919203945Sweongyo
1920203945Sweongyo	if (way == BWN_SHARED) {
1921203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1922203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1923203945Sweongyo		if (offset & 0x0003) {
1924203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1925203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1926203945Sweongyo			goto out;
1927203945Sweongyo		}
1928203945Sweongyo		offset >>= 2;
1929203945Sweongyo	}
1930203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1931203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1932203945Sweongyoout:
1933203945Sweongyo
1934203945Sweongyo	return (ret);
1935203945Sweongyo}
1936203945Sweongyo
1937203945Sweongyostatic void
1938203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1939203945Sweongyo    uint16_t offset)
1940203945Sweongyo{
1941203945Sweongyo	uint32_t control;
1942203945Sweongyo
1943203945Sweongyo	control = way;
1944203945Sweongyo	control <<= 16;
1945203945Sweongyo	control |= offset;
1946203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1947203945Sweongyo}
1948203945Sweongyo
1949203945Sweongyostatic void
1950203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1951203945Sweongyo    uint32_t value)
1952203945Sweongyo{
1953204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1954203945Sweongyo
1955203945Sweongyo	if (way == BWN_SHARED) {
1956203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1957203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1958203945Sweongyo		if (offset & 0x0003) {
1959203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1960203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1961203945Sweongyo				    (value >> 16) & 0xffff);
1962203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1963203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1964203945Sweongyo			return;
1965203945Sweongyo		}
1966203945Sweongyo		offset >>= 2;
1967203945Sweongyo	}
1968203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1969203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1970203945Sweongyo}
1971203945Sweongyo
1972203945Sweongyostatic void
1973203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1974203945Sweongyo    uint16_t value)
1975203945Sweongyo{
1976204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1977203945Sweongyo
1978203945Sweongyo	if (way == BWN_SHARED) {
1979203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1980203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1981203945Sweongyo		if (offset & 0x0003) {
1982203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1983203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
1984203945Sweongyo			return;
1985203945Sweongyo		}
1986203945Sweongyo		offset >>= 2;
1987203945Sweongyo	}
1988203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1989203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
1990203945Sweongyo}
1991203945Sweongyo
1992203945Sweongyostatic void
1993203945Sweongyobwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
1994203945Sweongyo    int txpow)
1995203945Sweongyo{
1996203945Sweongyo
1997203945Sweongyo	c->ic_freq = freq;
1998203945Sweongyo	c->ic_flags = flags;
1999203945Sweongyo	c->ic_ieee = ieee;
2000203945Sweongyo	c->ic_minpower = 0;
2001203945Sweongyo	c->ic_maxpower = 2 * txpow;
2002203945Sweongyo	c->ic_maxregpower = txpow;
2003203945Sweongyo}
2004203945Sweongyo
2005203945Sweongyostatic void
2006203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
2007203945Sweongyo    const struct bwn_channelinfo *ci, int flags)
2008203945Sweongyo{
2009203945Sweongyo	struct ieee80211_channel *c;
2010203945Sweongyo	int i;
2011203945Sweongyo
2012203945Sweongyo	c = &chans[*nchans];
2013203945Sweongyo
2014203945Sweongyo	for (i = 0; i < ci->nchannels; i++) {
2015203945Sweongyo		const struct bwn_channel *hc;
2016203945Sweongyo
2017203945Sweongyo		hc = &ci->channels[i];
2018203945Sweongyo		if (*nchans >= maxchans)
2019203945Sweongyo			break;
2020203945Sweongyo		bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
2021203945Sweongyo		c++, (*nchans)++;
2022203945Sweongyo		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
2023203945Sweongyo			/* g channel have a separate b-only entry */
2024203945Sweongyo			if (*nchans >= maxchans)
2025203945Sweongyo				break;
2026203945Sweongyo			c[0] = c[-1];
2027203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_B;
2028203945Sweongyo			c++, (*nchans)++;
2029203945Sweongyo		}
2030203945Sweongyo		if (flags == IEEE80211_CHAN_HTG) {
2031203945Sweongyo			/* HT g channel have a separate g-only entry */
2032203945Sweongyo			if (*nchans >= maxchans)
2033203945Sweongyo				break;
2034203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_G;
2035203945Sweongyo			c[0] = c[-1];
2036203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2037203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2038203945Sweongyo			c++, (*nchans)++;
2039203945Sweongyo		}
2040203945Sweongyo		if (flags == IEEE80211_CHAN_HTA) {
2041203945Sweongyo			/* HT a channel have a separate a-only entry */
2042203945Sweongyo			if (*nchans >= maxchans)
2043203945Sweongyo				break;
2044203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_A;
2045203945Sweongyo			c[0] = c[-1];
2046203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2047203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2048203945Sweongyo			c++, (*nchans)++;
2049203945Sweongyo		}
2050203945Sweongyo	}
2051203945Sweongyo}
2052203945Sweongyo
2053203945Sweongyostatic int
2054203945Sweongyobwn_phy_g_attach(struct bwn_mac *mac)
2055203945Sweongyo{
2056203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2057203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2058203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2059203945Sweongyo	unsigned int i;
2060204922Sweongyo	int16_t pab0, pab1, pab2;
2061203945Sweongyo	static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
2062204922Sweongyo	int8_t bg;
2063203945Sweongyo
2064204922Sweongyo	bg = (int8_t)siba_sprom_get_tssi_bg(sc->sc_dev);
2065204922Sweongyo	pab0 = (int16_t)siba_sprom_get_pa0b0(sc->sc_dev);
2066204922Sweongyo	pab1 = (int16_t)siba_sprom_get_pa0b1(sc->sc_dev);
2067204922Sweongyo	pab2 = (int16_t)siba_sprom_get_pa0b2(sc->sc_dev);
2068204922Sweongyo
2069204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4301) && (phy->rf_ver != 0x2050))
2070203945Sweongyo		device_printf(sc->sc_dev, "not supported anymore\n");
2071203945Sweongyo
2072203945Sweongyo	pg->pg_flags = 0;
2073203945Sweongyo	if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
2074203945Sweongyo	    pab2 == -1) {
2075203945Sweongyo		pg->pg_idletssi = 52;
2076203945Sweongyo		pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
2077203945Sweongyo		return (0);
2078203945Sweongyo	}
2079203945Sweongyo
2080203945Sweongyo	pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
2081203945Sweongyo	pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
2082203945Sweongyo	if (pg->pg_tssi2dbm == NULL) {
2083203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer\n");
2084203945Sweongyo		return (ENOMEM);
2085203945Sweongyo	}
2086203945Sweongyo	for (i = 0; i < 64; i++) {
2087203945Sweongyo		int32_t m1, m2, f, q, delta;
2088203945Sweongyo		int8_t j = 0;
2089203945Sweongyo
2090203945Sweongyo		m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
2091203945Sweongyo		m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
2092203945Sweongyo		f = 256;
2093203945Sweongyo
2094203945Sweongyo		do {
2095203945Sweongyo			if (j > 15) {
2096203945Sweongyo				device_printf(sc->sc_dev,
2097203945Sweongyo				    "failed to generate tssi2dBm\n");
2098203945Sweongyo				free(pg->pg_tssi2dbm, M_DEVBUF);
2099203945Sweongyo				return (ENOMEM);
2100203945Sweongyo			}
2101203945Sweongyo			q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
2102203945Sweongyo			    f, 2048);
2103203945Sweongyo			delta = abs(q - f);
2104203945Sweongyo			f = q;
2105203945Sweongyo			j++;
2106203945Sweongyo		} while (delta >= 2);
2107203945Sweongyo
2108203945Sweongyo		pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
2109203945Sweongyo		    128);
2110203945Sweongyo	}
2111203945Sweongyo
2112203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
2113203945Sweongyo	return (0);
2114203945Sweongyo}
2115203945Sweongyo
2116203945Sweongyostatic void
2117203945Sweongyobwn_phy_g_detach(struct bwn_mac *mac)
2118203945Sweongyo{
2119203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
2120203945Sweongyo
2121203945Sweongyo	if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
2122203945Sweongyo		free(pg->pg_tssi2dbm, M_DEVBUF);
2123203945Sweongyo		pg->pg_tssi2dbm = NULL;
2124203945Sweongyo	}
2125203945Sweongyo	pg->pg_flags = 0;
2126203945Sweongyo}
2127203945Sweongyo
2128203945Sweongyostatic void
2129203945Sweongyobwn_phy_g_init_pre(struct bwn_mac *mac)
2130203945Sweongyo{
2131203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2132203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2133203945Sweongyo	void *tssi2dbm;
2134203945Sweongyo	int idletssi;
2135203945Sweongyo	unsigned int i;
2136203945Sweongyo
2137203945Sweongyo	tssi2dbm = pg->pg_tssi2dbm;
2138203945Sweongyo	idletssi = pg->pg_idletssi;
2139203945Sweongyo
2140203945Sweongyo	memset(pg, 0, sizeof(*pg));
2141203945Sweongyo
2142203945Sweongyo	pg->pg_tssi2dbm = tssi2dbm;
2143203945Sweongyo	pg->pg_idletssi = idletssi;
2144203945Sweongyo
2145203945Sweongyo	memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
2146203945Sweongyo
2147203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi); i++)
2148203945Sweongyo		pg->pg_nrssi[i] = -1000;
2149203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi_lt); i++)
2150203945Sweongyo		pg->pg_nrssi_lt[i] = i;
2151203945Sweongyo	pg->pg_lofcal = 0xffff;
2152203945Sweongyo	pg->pg_initval = 0xffff;
2153203945Sweongyo	pg->pg_immode = BWN_IMMODE_NONE;
2154203945Sweongyo	pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
2155203945Sweongyo	pg->pg_avgtssi = 0xff;
2156203945Sweongyo
2157203945Sweongyo	pg->pg_loctl.tx_bias = 0xff;
2158203945Sweongyo	TAILQ_INIT(&pg->pg_loctl.calib_list);
2159203945Sweongyo}
2160203945Sweongyo
2161203945Sweongyostatic int
2162203945Sweongyobwn_phy_g_prepare_hw(struct bwn_mac *mac)
2163203945Sweongyo{
2164203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2165203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2166204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2167203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2168203945Sweongyo	static const struct bwn_rfatt rfatt0[] = {
2169203945Sweongyo		{ 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 },	{ 9, 0 }, { 2, 0 },
2170203945Sweongyo		{ 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
2171203945Sweongyo		{ 3, 1 }, { 4, 1 }
2172203945Sweongyo	};
2173203945Sweongyo	static const struct bwn_rfatt rfatt1[] = {
2174203945Sweongyo		{ 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
2175203945Sweongyo		{ 14, 1 }
2176203945Sweongyo	};
2177203945Sweongyo	static const struct bwn_rfatt rfatt2[] = {
2178203945Sweongyo		{ 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
2179203945Sweongyo		{ 9, 1 }
2180203945Sweongyo	};
2181203945Sweongyo	static const struct bwn_bbatt bbatt_0[] = {
2182203945Sweongyo		{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
2183203945Sweongyo	};
2184203945Sweongyo
2185203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
2186203945Sweongyo
2187203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
2188203945Sweongyo		pg->pg_bbatt.att = 0;
2189203945Sweongyo	else
2190203945Sweongyo		pg->pg_bbatt.att = 2;
2191203945Sweongyo
2192203945Sweongyo	/* prepare Radio Attenuation */
2193203945Sweongyo	pg->pg_rfatt.padmix = 0;
2194203945Sweongyo
2195204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
2196204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BCM4309G) {
2197204922Sweongyo		if (siba_get_pci_revid(sc->sc_dev) < 0x43) {
2198203945Sweongyo			pg->pg_rfatt.att = 2;
2199203945Sweongyo			goto done;
2200204922Sweongyo		} else if (siba_get_pci_revid(sc->sc_dev) < 0x51) {
2201203945Sweongyo			pg->pg_rfatt.att = 3;
2202203945Sweongyo			goto done;
2203203945Sweongyo		}
2204203945Sweongyo	}
2205203945Sweongyo
2206203945Sweongyo	if (phy->type == BWN_PHYTYPE_A) {
2207203945Sweongyo		pg->pg_rfatt.att = 0x60;
2208203945Sweongyo		goto done;
2209203945Sweongyo	}
2210203945Sweongyo
2211203945Sweongyo	switch (phy->rf_ver) {
2212203945Sweongyo	case 0x2050:
2213203945Sweongyo		switch (phy->rf_rev) {
2214203945Sweongyo		case 0:
2215203945Sweongyo			pg->pg_rfatt.att = 5;
2216203945Sweongyo			goto done;
2217203945Sweongyo		case 1:
2218203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2219204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2220203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2221204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2222203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2223204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2224203945Sweongyo					pg->pg_rfatt.att = 3;
2225204922Sweongyo				else if (siba_get_pci_subvendor(sc->sc_dev) ==
2226203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2227204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2228204922Sweongyo				    SIBA_BOARD_BU4306)
2229203945Sweongyo					pg->pg_rfatt.att = 3;
2230203945Sweongyo				else
2231203945Sweongyo					pg->pg_rfatt.att = 1;
2232203945Sweongyo			} else {
2233204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2234203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2235204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2236203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2237204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2238203945Sweongyo					pg->pg_rfatt.att = 7;
2239203945Sweongyo				else
2240203945Sweongyo					pg->pg_rfatt.att = 6;
2241203945Sweongyo			}
2242203945Sweongyo			goto done;
2243203945Sweongyo		case 2:
2244203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2245204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2246203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2247204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2248203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2249204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2250203945Sweongyo					pg->pg_rfatt.att = 3;
2251204922Sweongyo				else if (siba_get_pci_subvendor(sc->sc_dev) ==
2252203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2253204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2254204922Sweongyo				    SIBA_BOARD_BU4306)
2255203945Sweongyo					pg->pg_rfatt.att = 5;
2256204922Sweongyo				else if (siba_get_chipid(sc->sc_dev) == 0x4320)
2257203945Sweongyo					pg->pg_rfatt.att = 4;
2258203945Sweongyo				else
2259203945Sweongyo					pg->pg_rfatt.att = 3;
2260203945Sweongyo			} else
2261203945Sweongyo				pg->pg_rfatt.att = 6;
2262203945Sweongyo			goto done;
2263203945Sweongyo		case 3:
2264203945Sweongyo			pg->pg_rfatt.att = 5;
2265203945Sweongyo			goto done;
2266203945Sweongyo		case 4:
2267203945Sweongyo		case 5:
2268203945Sweongyo			pg->pg_rfatt.att = 1;
2269203945Sweongyo			goto done;
2270203945Sweongyo		case 6:
2271203945Sweongyo		case 7:
2272203945Sweongyo			pg->pg_rfatt.att = 5;
2273203945Sweongyo			goto done;
2274203945Sweongyo		case 8:
2275203945Sweongyo			pg->pg_rfatt.att = 0xa;
2276203945Sweongyo			pg->pg_rfatt.padmix = 1;
2277203945Sweongyo			goto done;
2278203945Sweongyo		case 9:
2279203945Sweongyo		default:
2280203945Sweongyo			pg->pg_rfatt.att = 5;
2281203945Sweongyo			goto done;
2282203945Sweongyo		}
2283203945Sweongyo		break;
2284203945Sweongyo	case 0x2053:
2285203945Sweongyo		switch (phy->rf_rev) {
2286203945Sweongyo		case 1:
2287203945Sweongyo			pg->pg_rfatt.att = 6;
2288203945Sweongyo			goto done;
2289203945Sweongyo		}
2290203945Sweongyo		break;
2291203945Sweongyo	}
2292203945Sweongyo	pg->pg_rfatt.att = 5;
2293203945Sweongyodone:
2294203945Sweongyo	pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
2295203945Sweongyo
2296203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
2297203945Sweongyo		lo->rfatt.array = rfatt0;
2298203945Sweongyo		lo->rfatt.len = N(rfatt0);
2299203945Sweongyo		lo->rfatt.min = 0;
2300203945Sweongyo		lo->rfatt.max = 9;
2301203945Sweongyo		goto genbbatt;
2302203945Sweongyo	}
2303203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
2304203945Sweongyo		lo->rfatt.array = rfatt1;
2305203945Sweongyo		lo->rfatt.len = N(rfatt1);
2306203945Sweongyo		lo->rfatt.min = 0;
2307203945Sweongyo		lo->rfatt.max = 14;
2308203945Sweongyo		goto genbbatt;
2309203945Sweongyo	}
2310203945Sweongyo	lo->rfatt.array = rfatt2;
2311203945Sweongyo	lo->rfatt.len = N(rfatt2);
2312203945Sweongyo	lo->rfatt.min = 0;
2313203945Sweongyo	lo->rfatt.max = 9;
2314203945Sweongyogenbbatt:
2315203945Sweongyo	lo->bbatt.array = bbatt_0;
2316203945Sweongyo	lo->bbatt.len = N(bbatt_0);
2317203945Sweongyo	lo->bbatt.min = 0;
2318203945Sweongyo	lo->bbatt.max = 8;
2319203945Sweongyo
2320203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
2321203945Sweongyo	if (phy->rev == 1) {
2322203945Sweongyo		phy->gmode = 0;
2323203945Sweongyo		bwn_reset_core(mac, 0);
2324203945Sweongyo		bwn_phy_g_init_sub(mac);
2325203945Sweongyo		phy->gmode = 1;
2326203945Sweongyo		bwn_reset_core(mac, BWN_TGSLOW_SUPPORT_G);
2327203945Sweongyo	}
2328203945Sweongyo	return (0);
2329203945Sweongyo}
2330203945Sweongyo
2331203945Sweongyostatic uint16_t
2332203945Sweongyobwn_phy_g_txctl(struct bwn_mac *mac)
2333203945Sweongyo{
2334203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2335203945Sweongyo
2336203945Sweongyo	if (phy->rf_ver != 0x2050)
2337203945Sweongyo		return (0);
2338203945Sweongyo	if (phy->rf_rev == 1)
2339203945Sweongyo		return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
2340203945Sweongyo	if (phy->rf_rev < 6)
2341203945Sweongyo		return (BWN_TXCTL_PA2DB);
2342203945Sweongyo	if (phy->rf_rev == 8)
2343203945Sweongyo		return (BWN_TXCTL_TXMIX);
2344203945Sweongyo	return (0);
2345203945Sweongyo}
2346203945Sweongyo
2347203945Sweongyostatic int
2348203945Sweongyobwn_phy_g_init(struct bwn_mac *mac)
2349203945Sweongyo{
2350203945Sweongyo
2351203945Sweongyo	bwn_phy_g_init_sub(mac);
2352203945Sweongyo	return (0);
2353203945Sweongyo}
2354203945Sweongyo
2355203945Sweongyostatic void
2356203945Sweongyobwn_phy_g_exit(struct bwn_mac *mac)
2357203945Sweongyo{
2358203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
2359203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2360203945Sweongyo
2361203945Sweongyo	if (lo == NULL)
2362203945Sweongyo		return;
2363203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2364203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2365203945Sweongyo		free(cal, M_DEVBUF);
2366203945Sweongyo	}
2367203945Sweongyo}
2368203945Sweongyo
2369203945Sweongyostatic uint16_t
2370203945Sweongyobwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
2371203945Sweongyo{
2372203945Sweongyo
2373203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2374203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
2375203945Sweongyo}
2376203945Sweongyo
2377203945Sweongyostatic void
2378203945Sweongyobwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2379203945Sweongyo{
2380203945Sweongyo
2381203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2382203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
2383203945Sweongyo}
2384203945Sweongyo
2385203945Sweongyostatic uint16_t
2386203945Sweongyobwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
2387203945Sweongyo{
2388203945Sweongyo
2389203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2390203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
2391203945Sweongyo	return (BWN_READ_2(mac, BWN_RFDATALO));
2392203945Sweongyo}
2393203945Sweongyo
2394203945Sweongyostatic void
2395203945Sweongyobwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2396203945Sweongyo{
2397203945Sweongyo
2398203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2399203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
2400203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
2401203945Sweongyo}
2402203945Sweongyo
2403203945Sweongyostatic int
2404203945Sweongyobwn_phy_g_hwpctl(struct bwn_mac *mac)
2405203945Sweongyo{
2406203945Sweongyo
2407203945Sweongyo	return (mac->mac_phy.rev >= 6);
2408203945Sweongyo}
2409203945Sweongyo
2410203945Sweongyostatic void
2411203945Sweongyobwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
2412203945Sweongyo{
2413203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2414203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2415203945Sweongyo	unsigned int channel;
2416203945Sweongyo	uint16_t rfover, rfoverval;
2417203945Sweongyo
2418203945Sweongyo	if (on) {
2419203945Sweongyo		if (phy->rf_on)
2420203945Sweongyo			return;
2421203945Sweongyo
2422203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0x8000);
2423203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0xcc00);
2424203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
2425203945Sweongyo		if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
2426203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
2427203945Sweongyo			    pg->pg_radioctx_over);
2428203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
2429203945Sweongyo			    pg->pg_radioctx_overval);
2430203945Sweongyo			pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
2431203945Sweongyo		}
2432203945Sweongyo		channel = phy->chan;
2433203945Sweongyo		bwn_phy_g_switch_chan(mac, 6, 1);
2434203945Sweongyo		bwn_phy_g_switch_chan(mac, channel, 0);
2435203945Sweongyo		return;
2436203945Sweongyo	}
2437203945Sweongyo
2438203945Sweongyo	rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
2439203945Sweongyo	rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
2440203945Sweongyo	pg->pg_radioctx_over = rfover;
2441203945Sweongyo	pg->pg_radioctx_overval = rfoverval;
2442203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
2443203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
2444203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
2445203945Sweongyo}
2446203945Sweongyo
2447203945Sweongyostatic int
2448203945Sweongyobwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
2449203945Sweongyo{
2450203945Sweongyo
2451203945Sweongyo	if ((newchan < 1) || (newchan > 14))
2452203945Sweongyo		return (EINVAL);
2453203945Sweongyo	bwn_phy_g_switch_chan(mac, newchan, 0);
2454203945Sweongyo
2455203945Sweongyo	return (0);
2456203945Sweongyo}
2457203945Sweongyo
2458203945Sweongyostatic uint32_t
2459203945Sweongyobwn_phy_g_get_default_chan(struct bwn_mac *mac)
2460203945Sweongyo{
2461203945Sweongyo
2462203945Sweongyo	return (1);
2463203945Sweongyo}
2464203945Sweongyo
2465203945Sweongyostatic void
2466203945Sweongyobwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
2467203945Sweongyo{
2468203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2469203945Sweongyo	uint64_t hf;
2470203945Sweongyo	int autodiv = 0;
2471203945Sweongyo	uint16_t tmp;
2472203945Sweongyo
2473203945Sweongyo	if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
2474203945Sweongyo		autodiv = 1;
2475203945Sweongyo
2476203945Sweongyo	hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
2477203945Sweongyo	bwn_hf_write(mac, hf);
2478203945Sweongyo
2479203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
2480203945Sweongyo	    (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
2481203945Sweongyo	    ((autodiv ? BWN_ANTAUTO1 : antenna)
2482203945Sweongyo		<< BWN_PHY_BBANDCFG_RXANT_SHIFT));
2483203945Sweongyo
2484203945Sweongyo	if (autodiv) {
2485203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
2486203945Sweongyo		if (antenna == BWN_ANTAUTO1)
2487203945Sweongyo			tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
2488203945Sweongyo		else
2489203945Sweongyo			tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
2490203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
2491203945Sweongyo	}
2492203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
2493203945Sweongyo	if (autodiv)
2494203945Sweongyo		tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
2495203945Sweongyo	else
2496203945Sweongyo		tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
2497203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
2498203945Sweongyo	if (phy->rev >= 2) {
2499203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
2500203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
2501203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
2502203945Sweongyo		    (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
2503203945Sweongyo		    0x15);
2504203945Sweongyo		if (phy->rev == 2)
2505203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
2506203945Sweongyo		else
2507203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
2508203945Sweongyo			    (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
2509203945Sweongyo			    8);
2510203945Sweongyo	}
2511203945Sweongyo	if (phy->rev >= 6)
2512203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
2513203945Sweongyo
2514203945Sweongyo	hf |= BWN_HF_UCODE_ANTDIV_HELPER;
2515203945Sweongyo	bwn_hf_write(mac, hf);
2516203945Sweongyo}
2517203945Sweongyo
2518203945Sweongyostatic int
2519203945Sweongyobwn_phy_g_im(struct bwn_mac *mac, int mode)
2520203945Sweongyo{
2521203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2522203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2523203945Sweongyo
2524203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2525203945Sweongyo	KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
2526203945Sweongyo
2527203945Sweongyo	if (phy->rev == 0 || !phy->gmode)
2528203945Sweongyo		return (ENODEV);
2529203945Sweongyo
2530203945Sweongyo	pg->pg_aci_wlan_automatic = 0;
2531203945Sweongyo	return (0);
2532203945Sweongyo}
2533203945Sweongyo
2534203945Sweongyostatic int
2535203945Sweongyobwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
2536203945Sweongyo{
2537203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2538203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2539203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2540203945Sweongyo	unsigned int tssi;
2541203945Sweongyo	int cck, ofdm;
2542203945Sweongyo	int power;
2543203945Sweongyo	int rfatt, bbatt;
2544203945Sweongyo	unsigned int max;
2545203945Sweongyo
2546203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2547203945Sweongyo
2548203945Sweongyo	cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
2549203945Sweongyo	ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
2550203945Sweongyo	if (cck < 0 && ofdm < 0) {
2551203945Sweongyo		if (ignore_tssi == 0)
2552203945Sweongyo			return (BWN_TXPWR_RES_DONE);
2553203945Sweongyo		cck = 0;
2554203945Sweongyo		ofdm = 0;
2555203945Sweongyo	}
2556203945Sweongyo	tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
2557203945Sweongyo	if (pg->pg_avgtssi != 0xff)
2558203945Sweongyo		tssi = (tssi + pg->pg_avgtssi) / 2;
2559203945Sweongyo	pg->pg_avgtssi = tssi;
2560203945Sweongyo	KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
2561203945Sweongyo
2562204922Sweongyo	max = siba_sprom_get_maxpwr_bg(sc->sc_dev);
2563204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
2564203945Sweongyo		max -= 3;
2565203945Sweongyo	if (max >= 120) {
2566203945Sweongyo		device_printf(sc->sc_dev, "invalid max TX-power value\n");
2567204922Sweongyo		max = 80;
2568204922Sweongyo		siba_sprom_set_maxpwr_bg(sc->sc_dev, max);
2569203945Sweongyo	}
2570203945Sweongyo
2571203945Sweongyo	power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
2572203945Sweongyo	    (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
2573203945Sweongyo	     tssi, 0x00), 0x3f)]);
2574203945Sweongyo	if (power == 0)
2575203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2576203945Sweongyo
2577203945Sweongyo	rfatt = -((power + 7) / 8);
2578203945Sweongyo	bbatt = (-(power / 2)) - (4 * rfatt);
2579203945Sweongyo	if ((rfatt == 0) && (bbatt == 0))
2580203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2581203945Sweongyo	pg->pg_bbatt_delta = bbatt;
2582203945Sweongyo	pg->pg_rfatt_delta = rfatt;
2583203945Sweongyo	return (BWN_TXPWR_RES_NEED_ADJUST);
2584203945Sweongyo}
2585203945Sweongyo
2586203945Sweongyostatic void
2587203945Sweongyobwn_phy_g_set_txpwr(struct bwn_mac *mac)
2588203945Sweongyo{
2589203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2590203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2591203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2592203945Sweongyo	int rfatt, bbatt;
2593203945Sweongyo	uint8_t txctl;
2594203945Sweongyo
2595203945Sweongyo	bwn_mac_suspend(mac);
2596203945Sweongyo
2597203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2598203945Sweongyo
2599203945Sweongyo	bbatt = pg->pg_bbatt.att;
2600203945Sweongyo	bbatt += pg->pg_bbatt_delta;
2601203945Sweongyo	rfatt = pg->pg_rfatt.att;
2602203945Sweongyo	rfatt += pg->pg_rfatt_delta;
2603203945Sweongyo
2604203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2605203945Sweongyo	txctl = pg->pg_txctl;
2606203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
2607203945Sweongyo		if (rfatt <= 1) {
2608203945Sweongyo			if (txctl == 0) {
2609203945Sweongyo				txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
2610203945Sweongyo				rfatt += 2;
2611203945Sweongyo				bbatt += 2;
2612204922Sweongyo			} else if (siba_sprom_get_bf_lo(sc->sc_dev) &
2613204922Sweongyo			    BWN_BFL_PACTRL) {
2614203945Sweongyo				bbatt += 4 * (rfatt - 2);
2615203945Sweongyo				rfatt = 2;
2616203945Sweongyo			}
2617203945Sweongyo		} else if (rfatt > 4 && txctl) {
2618203945Sweongyo			txctl = 0;
2619203945Sweongyo			if (bbatt < 3) {
2620203945Sweongyo				rfatt -= 3;
2621203945Sweongyo				bbatt += 2;
2622203945Sweongyo			} else {
2623203945Sweongyo				rfatt -= 2;
2624203945Sweongyo				bbatt -= 2;
2625203945Sweongyo			}
2626203945Sweongyo		}
2627203945Sweongyo	}
2628203945Sweongyo	pg->pg_txctl = txctl;
2629203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2630203945Sweongyo	pg->pg_rfatt.att = rfatt;
2631203945Sweongyo	pg->pg_bbatt.att = bbatt;
2632203945Sweongyo
2633203945Sweongyo	DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
2634203945Sweongyo
2635203945Sweongyo	bwn_phy_lock(mac);
2636203945Sweongyo	bwn_rf_lock(mac);
2637203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
2638203945Sweongyo	    pg->pg_txctl);
2639203945Sweongyo	bwn_rf_unlock(mac);
2640203945Sweongyo	bwn_phy_unlock(mac);
2641203945Sweongyo
2642203945Sweongyo	bwn_mac_enable(mac);
2643203945Sweongyo}
2644203945Sweongyo
2645203945Sweongyostatic void
2646203945Sweongyobwn_phy_g_task_15s(struct bwn_mac *mac)
2647203945Sweongyo{
2648203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2649203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2650203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2651203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2652203945Sweongyo	unsigned long expire, now;
2653203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2654203945Sweongyo	uint8_t expired = 0;
2655203945Sweongyo
2656203945Sweongyo	bwn_mac_suspend(mac);
2657203945Sweongyo
2658203945Sweongyo	if (lo == NULL)
2659203945Sweongyo		goto fail;
2660203945Sweongyo
2661203945Sweongyo	BWN_GETTIME(now);
2662203945Sweongyo	if (bwn_has_hwpctl(mac)) {
2663203945Sweongyo		expire = now - BWN_LO_PWRVEC_EXPIRE;
2664203945Sweongyo		if (time_before(lo->pwr_vec_read_time, expire)) {
2665203945Sweongyo			bwn_lo_get_powervector(mac);
2666203945Sweongyo			bwn_phy_g_dc_lookup_init(mac, 0);
2667203945Sweongyo		}
2668203945Sweongyo		goto fail;
2669203945Sweongyo	}
2670203945Sweongyo
2671203945Sweongyo	expire = now - BWN_LO_CALIB_EXPIRE;
2672203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2673203945Sweongyo		if (!time_before(cal->calib_time, expire))
2674203945Sweongyo			continue;
2675203945Sweongyo		if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
2676203945Sweongyo		    BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
2677203945Sweongyo			KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
2678203945Sweongyo			expired = 1;
2679203945Sweongyo		}
2680203945Sweongyo
2681203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
2682203945Sweongyo		    cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
2683203945Sweongyo		    cal->ctl.i, cal->ctl.q);
2684203945Sweongyo
2685203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2686203945Sweongyo		free(cal, M_DEVBUF);
2687203945Sweongyo	}
2688203945Sweongyo	if (expired || TAILQ_EMPTY(&lo->calib_list)) {
2689203945Sweongyo		cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
2690203945Sweongyo		    &pg->pg_rfatt);
2691203945Sweongyo		if (cal == NULL) {
2692203945Sweongyo			device_printf(sc->sc_dev,
2693203945Sweongyo			    "failed to recalibrate LO\n");
2694203945Sweongyo			goto fail;
2695203945Sweongyo		}
2696203945Sweongyo		TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
2697203945Sweongyo		bwn_lo_write(mac, &cal->ctl);
2698203945Sweongyo	}
2699203945Sweongyo
2700203945Sweongyofail:
2701203945Sweongyo	bwn_mac_enable(mac);
2702203945Sweongyo}
2703203945Sweongyo
2704203945Sweongyostatic void
2705203945Sweongyobwn_phy_g_task_60s(struct bwn_mac *mac)
2706203945Sweongyo{
2707203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2708204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2709203945Sweongyo	uint8_t old = phy->chan;
2710203945Sweongyo
2711204922Sweongyo	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI))
2712203945Sweongyo		return;
2713203945Sweongyo
2714203945Sweongyo	bwn_mac_suspend(mac);
2715203945Sweongyo	bwn_nrssi_slope_11g(mac);
2716203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
2717203945Sweongyo		bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
2718203945Sweongyo		bwn_switch_channel(mac, old);
2719203945Sweongyo	}
2720203945Sweongyo	bwn_mac_enable(mac);
2721203945Sweongyo}
2722203945Sweongyo
2723203945Sweongyostatic void
2724203945Sweongyobwn_phy_switch_analog(struct bwn_mac *mac, int on)
2725203945Sweongyo{
2726203945Sweongyo
2727203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
2728203945Sweongyo}
2729203945Sweongyo
2730203945Sweongyostatic int
2731203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
2732203945Sweongyo	const struct ieee80211_bpf_params *params)
2733203945Sweongyo{
2734203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2735203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2736203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2737203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2738203945Sweongyo
2739203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
2740203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
2741203945Sweongyo		ieee80211_free_node(ni);
2742203945Sweongyo		m_freem(m);
2743203945Sweongyo		return (ENETDOWN);
2744203945Sweongyo	}
2745203945Sweongyo
2746203945Sweongyo	BWN_LOCK(sc);
2747203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
2748203945Sweongyo		ieee80211_free_node(ni);
2749203945Sweongyo		m_freem(m);
2750203945Sweongyo		ifp->if_oerrors++;
2751203945Sweongyo		BWN_UNLOCK(sc);
2752203945Sweongyo		return (ENOBUFS);
2753203945Sweongyo	}
2754203945Sweongyo
2755203945Sweongyo	if (bwn_tx_start(sc, ni, m) != 0) {
2756203945Sweongyo		if (ni != NULL)
2757203945Sweongyo			ieee80211_free_node(ni);
2758203945Sweongyo		ifp->if_oerrors++;
2759203945Sweongyo	}
2760203945Sweongyo	sc->sc_watchdog_timer = 5;
2761203945Sweongyo	BWN_UNLOCK(sc);
2762203945Sweongyo	return (0);
2763203945Sweongyo}
2764203945Sweongyo
2765203945Sweongyo/*
2766203945Sweongyo * Callback from the 802.11 layer to update the slot time
2767203945Sweongyo * based on the current setting.  We use it to notify the
2768203945Sweongyo * firmware of ERP changes and the f/w takes care of things
2769203945Sweongyo * like slot time and preamble.
2770203945Sweongyo */
2771203945Sweongyostatic void
2772203945Sweongyobwn_updateslot(struct ifnet *ifp)
2773203945Sweongyo{
2774203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2775203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
2776203945Sweongyo	struct bwn_mac *mac;
2777203945Sweongyo
2778203945Sweongyo	BWN_LOCK(sc);
2779203945Sweongyo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2780203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
2781203945Sweongyo		bwn_set_slot_time(mac,
2782203945Sweongyo		    (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20);
2783203945Sweongyo	}
2784203945Sweongyo	BWN_UNLOCK(sc);
2785203945Sweongyo}
2786203945Sweongyo
2787203945Sweongyo/*
2788203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
2789203945Sweongyo * Note this interface does not check the operating mode as this
2790203945Sweongyo * is an internal callback and we are expected to honor the current
2791203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
2792203945Sweongyo * mode when operating in hostap mode to do ACS).
2793203945Sweongyo */
2794203945Sweongyostatic void
2795203945Sweongyobwn_update_promisc(struct ifnet *ifp)
2796203945Sweongyo{
2797203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2798203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2799203945Sweongyo
2800203945Sweongyo	BWN_LOCK(sc);
2801203945Sweongyo	mac = sc->sc_curmac;
2802203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2803203945Sweongyo		if (ifp->if_flags & IFF_PROMISC)
2804203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
2805203945Sweongyo		else
2806203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
2807203945Sweongyo		bwn_set_opmode(mac);
2808203945Sweongyo	}
2809203945Sweongyo	BWN_UNLOCK(sc);
2810203945Sweongyo}
2811203945Sweongyo
2812203945Sweongyo/*
2813203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
2814203945Sweongyo */
2815203945Sweongyostatic int
2816203945Sweongyobwn_wme_update(struct ieee80211com *ic)
2817203945Sweongyo{
2818203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2819203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2820203945Sweongyo	struct wmeParams *wmep;
2821203945Sweongyo	int i;
2822203945Sweongyo
2823203945Sweongyo	BWN_LOCK(sc);
2824203945Sweongyo	mac = sc->sc_curmac;
2825203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2826203945Sweongyo		bwn_mac_suspend(mac);
2827203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
2828203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
2829203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
2830203945Sweongyo		}
2831203945Sweongyo		bwn_mac_enable(mac);
2832203945Sweongyo	}
2833203945Sweongyo	BWN_UNLOCK(sc);
2834203945Sweongyo	return (0);
2835203945Sweongyo}
2836203945Sweongyo
2837203945Sweongyostatic void
2838203945Sweongyobwn_scan_start(struct ieee80211com *ic)
2839203945Sweongyo{
2840203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2841203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2842203945Sweongyo	struct bwn_mac *mac;
2843203945Sweongyo
2844203945Sweongyo	BWN_LOCK(sc);
2845203945Sweongyo	mac = sc->sc_curmac;
2846203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2847203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
2848203945Sweongyo		bwn_set_opmode(mac);
2849203945Sweongyo		/* disable CFP update during scan */
2850203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
2851203945Sweongyo	}
2852203945Sweongyo	BWN_UNLOCK(sc);
2853203945Sweongyo}
2854203945Sweongyo
2855203945Sweongyostatic void
2856203945Sweongyobwn_scan_end(struct ieee80211com *ic)
2857203945Sweongyo{
2858203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2859203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2860203945Sweongyo	struct bwn_mac *mac;
2861203945Sweongyo
2862203945Sweongyo	BWN_LOCK(sc);
2863203945Sweongyo	mac = sc->sc_curmac;
2864203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2865203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
2866203945Sweongyo		bwn_set_opmode(mac);
2867203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
2868203945Sweongyo	}
2869203945Sweongyo	BWN_UNLOCK(sc);
2870203945Sweongyo}
2871203945Sweongyo
2872203945Sweongyostatic void
2873203945Sweongyobwn_set_channel(struct ieee80211com *ic)
2874203945Sweongyo{
2875203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2876203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2877203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2878203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2879203945Sweongyo	int chan, error;
2880203945Sweongyo
2881203945Sweongyo	BWN_LOCK(sc);
2882203945Sweongyo
2883203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
2884203945Sweongyo	if (error)
2885203945Sweongyo		goto fail;;
2886203945Sweongyo	bwn_mac_suspend(mac);
2887203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2888203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
2889203945Sweongyo	if (chan != phy->chan)
2890203945Sweongyo		bwn_switch_channel(mac, chan);
2891203945Sweongyo
2892203945Sweongyo	/* TX power level */
2893203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
2894203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
2895203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
2896203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
2897203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
2898203945Sweongyo	}
2899203945Sweongyo
2900203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2901203945Sweongyo	if (phy->set_antenna)
2902203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2903203945Sweongyo
2904203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
2905203945Sweongyo		if (sc->sc_rf_enabled) {
2906203945Sweongyo			bwn_rf_turnon(mac);
2907203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
2908203945Sweongyo				device_printf(sc->sc_dev,
2909203945Sweongyo				    "please turns on the RF switch\n");
2910203945Sweongyo		} else
2911203945Sweongyo			bwn_rf_turnoff(mac);
2912203945Sweongyo	}
2913203945Sweongyo
2914203945Sweongyo	bwn_mac_enable(mac);
2915203945Sweongyo
2916203945Sweongyofail:
2917203945Sweongyo	/*
2918203945Sweongyo	 * Setup radio tap channel freq and flags
2919203945Sweongyo	 */
2920203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
2921203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
2922203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
2923203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
2924203945Sweongyo
2925203945Sweongyo	BWN_UNLOCK(sc);
2926203945Sweongyo}
2927203945Sweongyo
2928203945Sweongyostatic struct ieee80211vap *
2929203945Sweongyobwn_vap_create(struct ieee80211com *ic,
2930203945Sweongyo	const char name[IFNAMSIZ], int unit, int opmode, int flags,
2931203945Sweongyo	const uint8_t bssid[IEEE80211_ADDR_LEN],
2932203945Sweongyo	const uint8_t mac0[IEEE80211_ADDR_LEN])
2933203945Sweongyo{
2934203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2935203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2936203945Sweongyo	struct ieee80211vap *vap;
2937203945Sweongyo	struct bwn_vap *bvp;
2938203945Sweongyo	uint8_t mac[IEEE80211_ADDR_LEN];
2939203945Sweongyo
2940203945Sweongyo	IEEE80211_ADDR_COPY(mac, mac0);
2941203945Sweongyo	switch (opmode) {
2942203945Sweongyo	case IEEE80211_M_HOSTAP:
2943203945Sweongyo	case IEEE80211_M_MBSS:
2944203945Sweongyo	case IEEE80211_M_STA:
2945203945Sweongyo	case IEEE80211_M_WDS:
2946203945Sweongyo	case IEEE80211_M_MONITOR:
2947203945Sweongyo	case IEEE80211_M_IBSS:
2948203945Sweongyo	case IEEE80211_M_AHDEMO:
2949203945Sweongyo		break;
2950203945Sweongyo	default:
2951203945Sweongyo		return (NULL);
2952203945Sweongyo	}
2953203945Sweongyo
2954203945Sweongyo	IEEE80211_ADDR_COPY(sc->sc_macaddr, mac0);
2955203945Sweongyo
2956203945Sweongyo	bvp = (struct bwn_vap *) malloc(sizeof(struct bwn_vap),
2957203945Sweongyo	    M_80211_VAP, M_NOWAIT | M_ZERO);
2958203945Sweongyo	if (bvp == NULL) {
2959203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate a buffer\n");
2960203945Sweongyo		return (NULL);
2961203945Sweongyo	}
2962203945Sweongyo	vap = &bvp->bv_vap;
2963203945Sweongyo	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
2964203945Sweongyo	IEEE80211_ADDR_COPY(vap->iv_myaddr, mac);
2965203945Sweongyo	/* override with driver methods */
2966203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
2967203945Sweongyo	vap->iv_newstate = bwn_newstate;
2968203945Sweongyo
2969203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
2970203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
2971203945Sweongyo
2972206358Srpaulo	ieee80211_ratectl_init(vap);
2973203945Sweongyo
2974203945Sweongyo	/* complete setup */
2975203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
2976203945Sweongyo	    ieee80211_media_status);
2977203945Sweongyo	return (vap);
2978203945Sweongyo}
2979203945Sweongyo
2980203945Sweongyostatic void
2981203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
2982203945Sweongyo{
2983203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
2984203945Sweongyo
2985206358Srpaulo	ieee80211_ratectl_deinit(vap);
2986203945Sweongyo	ieee80211_vap_detach(vap);
2987203945Sweongyo	free(bvp, M_80211_VAP);
2988203945Sweongyo}
2989203945Sweongyo
2990203945Sweongyostatic void
2991203945Sweongyobwn_init(void *arg)
2992203945Sweongyo{
2993203945Sweongyo	struct bwn_softc *sc = arg;
2994203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
2995203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
2996203945Sweongyo	int error = 0;
2997203945Sweongyo
2998203945Sweongyo	DPRINTF(sc, BWN_DEBUG_ANY, "%s: if_flags 0x%x\n",
2999203945Sweongyo		__func__, ifp->if_flags);
3000203945Sweongyo
3001203945Sweongyo	BWN_LOCK(sc);
3002203945Sweongyo	error = bwn_init_locked(sc);
3003203945Sweongyo	BWN_UNLOCK(sc);
3004203945Sweongyo
3005203945Sweongyo	if (error == 0)
3006203945Sweongyo		ieee80211_start_all(ic);	/* start all vap's */
3007203945Sweongyo}
3008203945Sweongyo
3009203945Sweongyostatic int
3010203945Sweongyobwn_init_locked(struct bwn_softc *sc)
3011203945Sweongyo{
3012203945Sweongyo	struct bwn_mac *mac;
3013203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3014203945Sweongyo	int error;
3015203945Sweongyo
3016203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3017203945Sweongyo
3018203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
3019203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
3020203945Sweongyo	sc->sc_filters = 0;
3021203945Sweongyo	bwn_wme_clear(sc);
3022203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
3023203945Sweongyo	sc->sc_rf_enabled = 1;
3024203945Sweongyo
3025203945Sweongyo	mac = sc->sc_curmac;
3026203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
3027203945Sweongyo		error = bwn_core_init(mac);
3028203945Sweongyo		if (error != 0)
3029203945Sweongyo			return (error);
3030203945Sweongyo	}
3031203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
3032203945Sweongyo		bwn_core_start(mac);
3033203945Sweongyo
3034203945Sweongyo	bwn_set_opmode(mac);
3035203945Sweongyo	bwn_set_pretbtt(mac);
3036203945Sweongyo	bwn_spu_setdelay(mac, 0);
3037203945Sweongyo	bwn_set_macaddr(mac);
3038203945Sweongyo
3039203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3040203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
3041203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
3042203945Sweongyo
3043203945Sweongyo	return (0);
3044203945Sweongyo}
3045203945Sweongyo
3046203945Sweongyostatic void
3047203945Sweongyobwn_stop(struct bwn_softc *sc, int statechg)
3048203945Sweongyo{
3049203945Sweongyo
3050203945Sweongyo	BWN_LOCK(sc);
3051203945Sweongyo	bwn_stop_locked(sc, statechg);
3052203945Sweongyo	BWN_UNLOCK(sc);
3053203945Sweongyo}
3054203945Sweongyo
3055203945Sweongyostatic void
3056203945Sweongyobwn_stop_locked(struct bwn_softc *sc, int statechg)
3057203945Sweongyo{
3058203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
3059203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3060203945Sweongyo
3061203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3062203945Sweongyo
3063203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
3064203945Sweongyo		/* XXX FIXME opmode not based on VAP */
3065203945Sweongyo		bwn_set_opmode(mac);
3066203945Sweongyo		bwn_set_macaddr(mac);
3067203945Sweongyo	}
3068203945Sweongyo
3069203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
3070203945Sweongyo		bwn_core_stop(mac);
3071203945Sweongyo
3072203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
3073203945Sweongyo	sc->sc_led_blinking = 0;
3074203945Sweongyo
3075203945Sweongyo	bwn_core_exit(mac);
3076203945Sweongyo	sc->sc_rf_enabled = 0;
3077203945Sweongyo
3078203945Sweongyo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3079203945Sweongyo}
3080203945Sweongyo
3081203945Sweongyostatic void
3082203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
3083203945Sweongyo{
3084203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
3085203945Sweongyo	struct wmeParams *p;
3086203945Sweongyo	unsigned int i;
3087203945Sweongyo
3088203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
3089203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3090203945Sweongyo
3091203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
3092203945Sweongyo		p = &(sc->sc_wmeParams[i]);
3093203945Sweongyo
3094203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
3095203945Sweongyo		case BWN_WME_VOICE:
3096203945Sweongyo			p->wmep_txopLimit = 0;
3097203945Sweongyo			p->wmep_aifsn = 2;
3098203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3099203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3100203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3101203945Sweongyo			break;
3102203945Sweongyo		case BWN_WME_VIDEO:
3103203945Sweongyo			p->wmep_txopLimit = 0;
3104203945Sweongyo			p->wmep_aifsn = 2;
3105203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3106203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3107203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3108203945Sweongyo			break;
3109203945Sweongyo		case BWN_WME_BESTEFFORT:
3110203945Sweongyo			p->wmep_txopLimit = 0;
3111203945Sweongyo			p->wmep_aifsn = 3;
3112203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3113203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3114203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3115203945Sweongyo			break;
3116203945Sweongyo		case BWN_WME_BACKGROUND:
3117203945Sweongyo			p->wmep_txopLimit = 0;
3118203945Sweongyo			p->wmep_aifsn = 7;
3119203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3120203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3121203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3122203945Sweongyo			break;
3123203945Sweongyo		default:
3124203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3125203945Sweongyo		}
3126203945Sweongyo	}
3127203945Sweongyo}
3128203945Sweongyo
3129203945Sweongyostatic int
3130203945Sweongyobwn_core_init(struct bwn_mac *mac)
3131203945Sweongyo{
3132203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3133203945Sweongyo	uint64_t hf;
3134203945Sweongyo	int error;
3135203945Sweongyo
3136203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3137203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3138203945Sweongyo
3139204922Sweongyo	siba_powerup(sc->sc_dev, 0);
3140204922Sweongyo	if (!siba_dev_isup(sc->sc_dev))
3141203945Sweongyo		bwn_reset_core(mac,
3142203945Sweongyo		    mac->mac_phy.gmode ? BWN_TGSLOW_SUPPORT_G : 0);
3143203945Sweongyo
3144203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
3145203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
3146203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
3147203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
3148203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
3149203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
3150203945Sweongyo	mac->mac_stats.link_noise = -95;
3151203945Sweongyo	mac->mac_reason_intr = 0;
3152203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
3153203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
3154203945Sweongyo#ifdef BWN_DEBUG
3155203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
3156203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
3157203945Sweongyo#endif
3158203945Sweongyo	mac->mac_suspended = 1;
3159203945Sweongyo	mac->mac_task_state = 0;
3160203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
3161203945Sweongyo
3162203945Sweongyo	mac->mac_phy.init_pre(mac);
3163203945Sweongyo
3164204922Sweongyo	siba_pcicore_intr(sc->sc_dev);
3165203945Sweongyo
3166204922Sweongyo	siba_fix_imcfglobug(sc->sc_dev);
3167203945Sweongyo	bwn_bt_disable(mac);
3168203945Sweongyo	if (mac->mac_phy.prepare_hw) {
3169203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
3170203945Sweongyo		if (error)
3171203945Sweongyo			goto fail0;
3172203945Sweongyo	}
3173203945Sweongyo	error = bwn_chip_init(mac);
3174203945Sweongyo	if (error)
3175203945Sweongyo		goto fail0;
3176203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
3177204922Sweongyo	    siba_get_revid(sc->sc_dev));
3178203945Sweongyo	hf = bwn_hf_read(mac);
3179203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
3180203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
3181204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
3182203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
3183203945Sweongyo		if (mac->mac_phy.rev == 1)
3184203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
3185203945Sweongyo	}
3186203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
3187203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
3188203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
3189203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
3190203945Sweongyo			hf |= BWN_HF_4318_TSSI;
3191203945Sweongyo	}
3192204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW)
3193203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
3194204922Sweongyo	if ((siba_get_type(sc->sc_dev) == SIBA_TYPE_PCI) &&
3195204922Sweongyo	    (siba_get_pcicore_revid(sc->sc_dev) <= 10))
3196203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
3197203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
3198203945Sweongyo	bwn_hf_write(mac, hf);
3199203945Sweongyo
3200203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
3201203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
3202203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
3203203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
3204203945Sweongyo
3205203945Sweongyo	bwn_rate_init(mac);
3206203945Sweongyo	bwn_set_phytxctl(mac);
3207203945Sweongyo
3208203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
3209203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
3210203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
3211203945Sweongyo
3212204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
3213203945Sweongyo		bwn_pio_init(mac);
3214203945Sweongyo	else
3215203945Sweongyo		bwn_dma_init(mac);
3216203945Sweongyo	if (error)
3217203945Sweongyo		goto fail1;
3218203945Sweongyo	bwn_wme_init(mac);
3219203945Sweongyo	bwn_spu_setdelay(mac, 1);
3220203945Sweongyo	bwn_bt_enable(mac);
3221203945Sweongyo
3222204922Sweongyo	siba_powerup(sc->sc_dev,
3223204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW));
3224203945Sweongyo	bwn_set_macaddr(mac);
3225203945Sweongyo	bwn_crypt_init(mac);
3226203945Sweongyo
3227203945Sweongyo	/* XXX LED initializatin */
3228203945Sweongyo
3229203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
3230203945Sweongyo
3231203945Sweongyo	return (error);
3232203945Sweongyo
3233203945Sweongyofail1:
3234203945Sweongyo	bwn_chip_exit(mac);
3235203945Sweongyofail0:
3236204922Sweongyo	siba_powerdown(sc->sc_dev);
3237203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3238203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3239203945Sweongyo	return (error);
3240203945Sweongyo}
3241203945Sweongyo
3242203945Sweongyostatic void
3243203945Sweongyobwn_core_start(struct bwn_mac *mac)
3244203945Sweongyo{
3245203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3246203945Sweongyo	uint32_t tmp;
3247203945Sweongyo
3248203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
3249203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3250203945Sweongyo
3251204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
3252203945Sweongyo		return;
3253203945Sweongyo
3254203945Sweongyo	while (1) {
3255203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
3256203945Sweongyo		if (!(tmp & 0x00000001))
3257203945Sweongyo			break;
3258203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
3259203945Sweongyo	}
3260203945Sweongyo
3261203945Sweongyo	bwn_mac_enable(mac);
3262203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
3263203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
3264203945Sweongyo
3265203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
3266203945Sweongyo}
3267203945Sweongyo
3268203945Sweongyostatic void
3269203945Sweongyobwn_core_exit(struct bwn_mac *mac)
3270203945Sweongyo{
3271204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3272203945Sweongyo	uint32_t macctl;
3273203945Sweongyo
3274204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
3275203945Sweongyo
3276203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
3277203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3278203945Sweongyo
3279203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
3280203945Sweongyo		return;
3281203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
3282203945Sweongyo
3283203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3284203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
3285203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
3286203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3287203945Sweongyo
3288203945Sweongyo	bwn_dma_stop(mac);
3289203945Sweongyo	bwn_pio_stop(mac);
3290203945Sweongyo	bwn_chip_exit(mac);
3291203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
3292204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
3293204922Sweongyo	siba_powerdown(sc->sc_dev);
3294203945Sweongyo}
3295203945Sweongyo
3296203945Sweongyostatic void
3297203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
3298203945Sweongyo{
3299203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3300203945Sweongyo
3301203945Sweongyo	(void)sc;
3302203945Sweongyo	/* XXX do nothing yet */
3303203945Sweongyo}
3304203945Sweongyo
3305203945Sweongyostatic int
3306203945Sweongyobwn_chip_init(struct bwn_mac *mac)
3307203945Sweongyo{
3308204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3309203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
3310203945Sweongyo	uint32_t macctl;
3311203945Sweongyo	int error;
3312203945Sweongyo
3313203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
3314203945Sweongyo	if (phy->gmode)
3315203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
3316203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3317203945Sweongyo
3318203945Sweongyo	error = bwn_fw_fillinfo(mac);
3319203945Sweongyo	if (error)
3320203945Sweongyo		return (error);
3321203945Sweongyo	error = bwn_fw_loaducode(mac);
3322203945Sweongyo	if (error)
3323203945Sweongyo		return (error);
3324203945Sweongyo
3325203945Sweongyo	error = bwn_gpio_init(mac);
3326203945Sweongyo	if (error)
3327203945Sweongyo		return (error);
3328203945Sweongyo
3329203945Sweongyo	error = bwn_fw_loadinitvals(mac);
3330203945Sweongyo	if (error) {
3331204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
3332203945Sweongyo		return (error);
3333203945Sweongyo	}
3334203945Sweongyo	phy->switch_analog(mac, 1);
3335203945Sweongyo	error = bwn_phy_init(mac);
3336203945Sweongyo	if (error) {
3337204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
3338203945Sweongyo		return (error);
3339203945Sweongyo	}
3340203945Sweongyo	if (phy->set_im)
3341203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
3342203945Sweongyo	if (phy->set_antenna)
3343203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
3344203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
3345203945Sweongyo
3346203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
3347203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
3348203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
3349204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
3350203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
3351203945Sweongyo
3352203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3353203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
3354203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3355203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
3356203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
3357203945Sweongyo
3358203945Sweongyo	bwn_set_opmode(mac);
3359204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 3) {
3360203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
3361203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
3362203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
3363203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
3364203945Sweongyo	} else {
3365203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
3366203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
3367203945Sweongyo	}
3368203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
3369203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
3370203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
3371203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
3372203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
3373203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
3374203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
3375204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
3376204922Sweongyo	    siba_read_4(sc->sc_dev, SIBA_TGSLOW) | 0x00100000);
3377204922Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev));
3378203945Sweongyo	return (error);
3379203945Sweongyo}
3380203945Sweongyo
3381203945Sweongyo/* read hostflags */
3382203945Sweongyostatic uint64_t
3383203945Sweongyobwn_hf_read(struct bwn_mac *mac)
3384203945Sweongyo{
3385203945Sweongyo	uint64_t ret;
3386203945Sweongyo
3387203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
3388203945Sweongyo	ret <<= 16;
3389203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
3390203945Sweongyo	ret <<= 16;
3391203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
3392203945Sweongyo	return (ret);
3393203945Sweongyo}
3394203945Sweongyo
3395203945Sweongyostatic void
3396203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
3397203945Sweongyo{
3398203945Sweongyo
3399203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
3400203945Sweongyo	    (value & 0x00000000ffffull));
3401203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
3402203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
3403203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
3404203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
3405203945Sweongyo}
3406203945Sweongyo
3407203945Sweongyostatic void
3408203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
3409203945Sweongyo{
3410203945Sweongyo
3411203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
3412203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
3413203945Sweongyo}
3414203945Sweongyo
3415203945Sweongyostatic void
3416203945Sweongyobwn_rate_init(struct bwn_mac *mac)
3417203945Sweongyo{
3418203945Sweongyo
3419203945Sweongyo	switch (mac->mac_phy.type) {
3420203945Sweongyo	case BWN_PHYTYPE_A:
3421203945Sweongyo	case BWN_PHYTYPE_G:
3422203945Sweongyo	case BWN_PHYTYPE_LP:
3423203945Sweongyo	case BWN_PHYTYPE_N:
3424203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
3425203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
3426203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
3427203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
3428203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
3429203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
3430203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
3431203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
3432203945Sweongyo			break;
3433203945Sweongyo		/* FALLTHROUGH */
3434203945Sweongyo	case BWN_PHYTYPE_B:
3435203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
3436203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
3437203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
3438203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
3439203945Sweongyo		break;
3440203945Sweongyo	default:
3441203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3442203945Sweongyo	}
3443203945Sweongyo}
3444203945Sweongyo
3445203945Sweongyostatic void
3446203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
3447203945Sweongyo{
3448203945Sweongyo	uint16_t offset;
3449203945Sweongyo
3450203945Sweongyo	if (ofdm) {
3451203945Sweongyo		offset = 0x480;
3452203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
3453203945Sweongyo	} else {
3454203945Sweongyo		offset = 0x4c0;
3455203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
3456203945Sweongyo	}
3457203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
3458203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
3459203945Sweongyo}
3460203945Sweongyo
3461203945Sweongyostatic uint8_t
3462203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
3463203945Sweongyo{
3464203945Sweongyo
3465203945Sweongyo	switch (bitrate) {
3466203945Sweongyo	case BWN_CCK_RATE_1MB:
3467203945Sweongyo		return (0x0a);
3468203945Sweongyo	case BWN_CCK_RATE_2MB:
3469203945Sweongyo		return (0x14);
3470203945Sweongyo	case BWN_CCK_RATE_5MB:
3471203945Sweongyo		return (0x37);
3472203945Sweongyo	case BWN_CCK_RATE_11MB:
3473203945Sweongyo		return (0x6e);
3474203945Sweongyo	}
3475203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3476203945Sweongyo	return (0);
3477203945Sweongyo}
3478203945Sweongyo
3479203945Sweongyostatic uint8_t
3480203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
3481203945Sweongyo{
3482203945Sweongyo
3483203945Sweongyo	switch (bitrate) {
3484203945Sweongyo	case BWN_OFDM_RATE_6MB:
3485203945Sweongyo		return (0xb);
3486203945Sweongyo	case BWN_OFDM_RATE_9MB:
3487203945Sweongyo		return (0xf);
3488203945Sweongyo	case BWN_OFDM_RATE_12MB:
3489203945Sweongyo		return (0xa);
3490203945Sweongyo	case BWN_OFDM_RATE_18MB:
3491203945Sweongyo		return (0xe);
3492203945Sweongyo	case BWN_OFDM_RATE_24MB:
3493203945Sweongyo		return (0x9);
3494203945Sweongyo	case BWN_OFDM_RATE_36MB:
3495203945Sweongyo		return (0xd);
3496203945Sweongyo	case BWN_OFDM_RATE_48MB:
3497203945Sweongyo		return (0x8);
3498203945Sweongyo	case BWN_OFDM_RATE_54MB:
3499203945Sweongyo		return (0xc);
3500203945Sweongyo	}
3501203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3502203945Sweongyo	return (0);
3503203945Sweongyo}
3504203945Sweongyo
3505203945Sweongyostatic void
3506203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
3507203945Sweongyo{
3508203945Sweongyo	uint16_t ctl;
3509203945Sweongyo
3510203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
3511203945Sweongyo	    BWN_TX_PHY_TXPWR);
3512203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
3513203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
3514203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
3515203945Sweongyo}
3516203945Sweongyo
3517203945Sweongyostatic void
3518203945Sweongyobwn_pio_init(struct bwn_mac *mac)
3519203945Sweongyo{
3520203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
3521203945Sweongyo
3522203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
3523203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
3524203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
3525203945Sweongyo
3526203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
3527203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
3528203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
3529203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
3530203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
3531203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
3532203945Sweongyo}
3533203945Sweongyo
3534203945Sweongyostatic void
3535203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3536203945Sweongyo    int index)
3537203945Sweongyo{
3538203945Sweongyo	struct bwn_pio_txpkt *tp;
3539204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3540203945Sweongyo	unsigned int i;
3541203945Sweongyo
3542203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
3543203945Sweongyo	tq->tq_index = index;
3544203945Sweongyo
3545203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
3546204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8)
3547203945Sweongyo		tq->tq_size = 1920;
3548203945Sweongyo	else {
3549203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
3550203945Sweongyo		tq->tq_size -= 80;
3551203945Sweongyo	}
3552203945Sweongyo
3553203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
3554203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3555203945Sweongyo		tp = &(tq->tq_pkts[i]);
3556203945Sweongyo		tp->tp_index = i;
3557203945Sweongyo		tp->tp_queue = tq;
3558203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
3559203945Sweongyo	}
3560203945Sweongyo}
3561203945Sweongyo
3562203945Sweongyostatic uint16_t
3563203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
3564203945Sweongyo{
3565203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3566203945Sweongyo	static const uint16_t bases[] = {
3567203945Sweongyo		BWN_PIO_BASE0,
3568203945Sweongyo		BWN_PIO_BASE1,
3569203945Sweongyo		BWN_PIO_BASE2,
3570203945Sweongyo		BWN_PIO_BASE3,
3571203945Sweongyo		BWN_PIO_BASE4,
3572203945Sweongyo		BWN_PIO_BASE5,
3573203945Sweongyo		BWN_PIO_BASE6,
3574203945Sweongyo		BWN_PIO_BASE7,
3575203945Sweongyo	};
3576203945Sweongyo	static const uint16_t bases_rev11[] = {
3577203945Sweongyo		BWN_PIO11_BASE0,
3578203945Sweongyo		BWN_PIO11_BASE1,
3579203945Sweongyo		BWN_PIO11_BASE2,
3580203945Sweongyo		BWN_PIO11_BASE3,
3581203945Sweongyo		BWN_PIO11_BASE4,
3582203945Sweongyo		BWN_PIO11_BASE5,
3583203945Sweongyo	};
3584203945Sweongyo
3585204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 11) {
3586203945Sweongyo		if (index >= N(bases_rev11))
3587203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
3588203945Sweongyo		return (bases_rev11[index]);
3589203945Sweongyo	}
3590203945Sweongyo	if (index >= N(bases))
3591203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
3592203945Sweongyo	return (bases[index]);
3593203945Sweongyo}
3594203945Sweongyo
3595203945Sweongyostatic void
3596203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
3597203945Sweongyo    int index)
3598203945Sweongyo{
3599204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3600203945Sweongyo
3601203945Sweongyo	prq->prq_mac = mac;
3602204922Sweongyo	prq->prq_rev = siba_get_revid(sc->sc_dev);
3603203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
3604203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
3605203945Sweongyo}
3606203945Sweongyo
3607203945Sweongyostatic void
3608203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
3609203945Sweongyo{
3610203945Sweongyo	if (tq == NULL)
3611203945Sweongyo		return;
3612203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
3613203945Sweongyo}
3614203945Sweongyo
3615203945Sweongyostatic void
3616203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
3617203945Sweongyo{
3618203945Sweongyo
3619203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
3620203945Sweongyo}
3621203945Sweongyo
3622203945Sweongyostatic uint16_t
3623203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3624203945Sweongyo    uint16_t offset)
3625203945Sweongyo{
3626203945Sweongyo
3627203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
3628203945Sweongyo}
3629203945Sweongyo
3630203945Sweongyostatic void
3631203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
3632203945Sweongyo{
3633203945Sweongyo	uint32_t ctl;
3634203945Sweongyo	int type;
3635203945Sweongyo	uint16_t base;
3636203945Sweongyo
3637203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
3638203945Sweongyo	base = bwn_dma_base(type, idx);
3639203945Sweongyo	if (type == BWN_DMA_64BIT) {
3640203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
3641203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
3642203945Sweongyo		if (enable)
3643203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
3644203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
3645203945Sweongyo	} else {
3646203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
3647203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
3648203945Sweongyo		if (enable)
3649203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
3650203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
3651203945Sweongyo	}
3652203945Sweongyo}
3653203945Sweongyo
3654203945Sweongyostatic uint64_t
3655203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
3656203945Sweongyo{
3657203945Sweongyo	uint32_t tmp;
3658203945Sweongyo	uint16_t base;
3659203945Sweongyo
3660203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3661203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3662203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
3663203945Sweongyo	base = bwn_dma_base(0, 0);
3664203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3665203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3666203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3667203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
3668203945Sweongyo
3669203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
3670203945Sweongyo}
3671203945Sweongyo
3672203945Sweongyostatic int
3673203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
3674203945Sweongyo{
3675203945Sweongyo
3676203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
3677203945Sweongyo		return (BWN_DMA_30BIT);
3678203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
3679203945Sweongyo		return (BWN_DMA_32BIT);
3680203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
3681203945Sweongyo		return (BWN_DMA_64BIT);
3682203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3683203945Sweongyo	return (BWN_DMA_30BIT);
3684203945Sweongyo}
3685203945Sweongyo
3686203945Sweongyostatic void
3687203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
3688203945Sweongyo{
3689203945Sweongyo	struct bwn_pio_txpkt *tp;
3690203945Sweongyo	unsigned int i;
3691203945Sweongyo
3692203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3693203945Sweongyo		tp = &(tq->tq_pkts[i]);
3694203945Sweongyo		if (tp->tp_m) {
3695203945Sweongyo			m_freem(tp->tp_m);
3696203945Sweongyo			tp->tp_m = NULL;
3697203945Sweongyo		}
3698203945Sweongyo	}
3699203945Sweongyo}
3700203945Sweongyo
3701203945Sweongyostatic uint16_t
3702203945Sweongyobwn_dma_base(int type, int controller_idx)
3703203945Sweongyo{
3704203945Sweongyo	static const uint16_t map64[] = {
3705203945Sweongyo		BWN_DMA64_BASE0,
3706203945Sweongyo		BWN_DMA64_BASE1,
3707203945Sweongyo		BWN_DMA64_BASE2,
3708203945Sweongyo		BWN_DMA64_BASE3,
3709203945Sweongyo		BWN_DMA64_BASE4,
3710203945Sweongyo		BWN_DMA64_BASE5,
3711203945Sweongyo	};
3712203945Sweongyo	static const uint16_t map32[] = {
3713203945Sweongyo		BWN_DMA32_BASE0,
3714203945Sweongyo		BWN_DMA32_BASE1,
3715203945Sweongyo		BWN_DMA32_BASE2,
3716203945Sweongyo		BWN_DMA32_BASE3,
3717203945Sweongyo		BWN_DMA32_BASE4,
3718203945Sweongyo		BWN_DMA32_BASE5,
3719203945Sweongyo	};
3720203945Sweongyo
3721203945Sweongyo	if (type == BWN_DMA_64BIT) {
3722203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
3723203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3724203945Sweongyo		return (map64[controller_idx]);
3725203945Sweongyo	}
3726203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
3727203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3728203945Sweongyo	return (map32[controller_idx]);
3729203945Sweongyo}
3730203945Sweongyo
3731203945Sweongyostatic void
3732203945Sweongyobwn_dma_init(struct bwn_mac *mac)
3733203945Sweongyo{
3734203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3735203945Sweongyo
3736203945Sweongyo	/* setup TX DMA channels. */
3737203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
3738203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
3739203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
3740203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
3741203945Sweongyo	bwn_dma_setup(dma->mcast);
3742203945Sweongyo	/* setup RX DMA channel. */
3743203945Sweongyo	bwn_dma_setup(dma->rx);
3744203945Sweongyo}
3745203945Sweongyo
3746203945Sweongyostatic struct bwn_dma_ring *
3747203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
3748203945Sweongyo    int for_tx, int type)
3749203945Sweongyo{
3750203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3751203945Sweongyo	struct bwn_dma_ring *dr;
3752203945Sweongyo	struct bwn_dmadesc_generic *desc;
3753203945Sweongyo	struct bwn_dmadesc_meta *mt;
3754203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3755203945Sweongyo	int error, i;
3756203945Sweongyo
3757203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
3758203945Sweongyo	if (dr == NULL)
3759203945Sweongyo		goto out;
3760203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
3761203945Sweongyo	if (for_tx)
3762203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
3763203945Sweongyo
3764203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
3765203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
3766203945Sweongyo	if (dr->dr_meta == NULL)
3767203945Sweongyo		goto fail0;
3768203945Sweongyo
3769203945Sweongyo	dr->dr_type = type;
3770203945Sweongyo	dr->dr_mac = mac;
3771203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
3772203945Sweongyo	dr->dr_index = controller_index;
3773203945Sweongyo	if (type == BWN_DMA_64BIT) {
3774203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
3775203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
3776203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
3777203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
3778203945Sweongyo		dr->resume = bwn_dma_64_resume;
3779203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
3780203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
3781203945Sweongyo	} else {
3782203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
3783203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
3784203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
3785203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
3786203945Sweongyo		dr->resume = bwn_dma_32_resume;
3787203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
3788203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
3789203945Sweongyo	}
3790203945Sweongyo	if (for_tx) {
3791203945Sweongyo		dr->dr_tx = 1;
3792203945Sweongyo		dr->dr_curslot = -1;
3793203945Sweongyo	} else {
3794203945Sweongyo		if (dr->dr_index == 0) {
3795203945Sweongyo			dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
3796203945Sweongyo			dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
3797203945Sweongyo		} else
3798203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3799203945Sweongyo	}
3800203945Sweongyo
3801203945Sweongyo	error = bwn_dma_allocringmemory(dr);
3802203945Sweongyo	if (error)
3803203945Sweongyo		goto fail2;
3804203945Sweongyo
3805203945Sweongyo	if (for_tx) {
3806203945Sweongyo		/*
3807203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
3808203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
3809203945Sweongyo		 */
3810203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
3811203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3812203945Sweongyo
3813203945Sweongyo		dr->dr_txhdr_cache =
3814203945Sweongyo		    malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
3815203945Sweongyo			BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
3816203945Sweongyo		KASSERT(dr->dr_txhdr_cache != NULL,
3817203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3818203945Sweongyo
3819203945Sweongyo		/*
3820203945Sweongyo		 * Create TX ring DMA stuffs
3821203945Sweongyo		 */
3822203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
3823203945Sweongyo				    BWN_ALIGN, 0,
3824203945Sweongyo				    BUS_SPACE_MAXADDR,
3825203945Sweongyo				    BUS_SPACE_MAXADDR,
3826203945Sweongyo				    NULL, NULL,
3827203945Sweongyo				    BWN_HDRSIZE(mac),
3828203945Sweongyo				    1,
3829203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
3830203945Sweongyo				    0,
3831203945Sweongyo				    NULL, NULL,
3832203945Sweongyo				    &dr->dr_txring_dtag);
3833203945Sweongyo		if (error) {
3834203945Sweongyo			device_printf(sc->sc_dev,
3835203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
3836203945Sweongyo			goto fail1;
3837203945Sweongyo		}
3838203945Sweongyo
3839203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
3840203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3841203945Sweongyo
3842203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
3843203945Sweongyo			mt->mt_m = NULL;
3844203945Sweongyo			mt->mt_ni = NULL;
3845203945Sweongyo			mt->mt_islast = 0;
3846203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
3847203945Sweongyo			    &mt->mt_dmap);
3848203945Sweongyo			if (error) {
3849203945Sweongyo				device_printf(sc->sc_dev,
3850203945Sweongyo				     "can't create RX buf DMA map\n");
3851203945Sweongyo				goto fail1;
3852203945Sweongyo			}
3853203945Sweongyo
3854203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
3855203945Sweongyo
3856203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
3857203945Sweongyo			mt->mt_m = NULL;
3858203945Sweongyo			mt->mt_ni = NULL;
3859203945Sweongyo			mt->mt_islast = 1;
3860203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
3861203945Sweongyo			    &mt->mt_dmap);
3862203945Sweongyo			if (error) {
3863203945Sweongyo				device_printf(sc->sc_dev,
3864203945Sweongyo				     "can't create RX buf DMA map\n");
3865203945Sweongyo				goto fail1;
3866203945Sweongyo			}
3867203945Sweongyo		}
3868203945Sweongyo	} else {
3869203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3870203945Sweongyo		    &dr->dr_spare_dmap);
3871203945Sweongyo		if (error) {
3872203945Sweongyo			device_printf(sc->sc_dev,
3873203945Sweongyo			    "can't create RX buf DMA map\n");
3874203945Sweongyo			goto out;		/* XXX wrong! */
3875203945Sweongyo		}
3876203945Sweongyo
3877203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
3878203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3879203945Sweongyo
3880203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3881203945Sweongyo			    &mt->mt_dmap);
3882203945Sweongyo			if (error) {
3883203945Sweongyo				device_printf(sc->sc_dev,
3884203945Sweongyo				    "can't create RX buf DMA map\n");
3885203945Sweongyo				goto out;	/* XXX wrong! */
3886203945Sweongyo			}
3887203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
3888203945Sweongyo			if (error) {
3889203945Sweongyo				device_printf(sc->sc_dev,
3890203945Sweongyo				    "failed to allocate RX buf\n");
3891203945Sweongyo				goto out;	/* XXX wrong! */
3892203945Sweongyo			}
3893203945Sweongyo		}
3894203945Sweongyo
3895203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
3896203945Sweongyo		    BUS_DMASYNC_PREWRITE);
3897203945Sweongyo
3898203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
3899203945Sweongyo	}
3900203945Sweongyo
3901203945Sweongyo      out:
3902203945Sweongyo	return (dr);
3903203945Sweongyo
3904203945Sweongyofail2:
3905203945Sweongyo	free(dr->dr_txhdr_cache, M_DEVBUF);
3906203945Sweongyofail1:
3907203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
3908203945Sweongyofail0:
3909203945Sweongyo	free(dr, M_DEVBUF);
3910203945Sweongyo	return (NULL);
3911203945Sweongyo}
3912203945Sweongyo
3913203945Sweongyostatic void
3914203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
3915203945Sweongyo{
3916203945Sweongyo
3917203945Sweongyo	if (dr == NULL)
3918203945Sweongyo		return;
3919203945Sweongyo
3920203945Sweongyo	bwn_dma_free_descbufs(*dr);
3921203945Sweongyo	bwn_dma_free_ringmemory(*dr);
3922203945Sweongyo
3923203945Sweongyo	free((*dr)->dr_txhdr_cache, M_DEVBUF);
3924203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
3925203945Sweongyo	free(*dr, M_DEVBUF);
3926203945Sweongyo
3927203945Sweongyo	*dr = NULL;
3928203945Sweongyo}
3929203945Sweongyo
3930203945Sweongyostatic void
3931203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
3932203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
3933203945Sweongyo{
3934203945Sweongyo	struct bwn_dmadesc32 *desc;
3935203945Sweongyo
3936203945Sweongyo	*meta = &(dr->dr_meta[slot]);
3937203945Sweongyo	desc = dr->dr_ring_descbase;
3938203945Sweongyo	desc = &(desc[slot]);
3939203945Sweongyo
3940203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
3941203945Sweongyo}
3942203945Sweongyo
3943203945Sweongyostatic void
3944203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
3945203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
3946203945Sweongyo    int start, int end, int irq)
3947203945Sweongyo{
3948203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
3949204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
3950203945Sweongyo	uint32_t addr, addrext, ctl;
3951203945Sweongyo	int slot;
3952203945Sweongyo
3953203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
3954203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
3955203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3956203945Sweongyo
3957203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
3958203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
3959204922Sweongyo	addr |= siba_dma_translation(sc->sc_dev);
3960203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
3961203945Sweongyo	if (slot == dr->dr_numslots - 1)
3962203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
3963203945Sweongyo	if (start)
3964203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
3965203945Sweongyo	if (end)
3966203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
3967203945Sweongyo	if (irq)
3968203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
3969203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
3970203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
3971203945Sweongyo
3972203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
3973203945Sweongyo	desc->dma.dma32.address = htole32(addr);
3974203945Sweongyo}
3975203945Sweongyo
3976203945Sweongyostatic void
3977203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
3978203945Sweongyo{
3979203945Sweongyo
3980203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
3981203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
3982203945Sweongyo}
3983203945Sweongyo
3984203945Sweongyostatic void
3985203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
3986203945Sweongyo{
3987203945Sweongyo
3988203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
3989203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
3990203945Sweongyo}
3991203945Sweongyo
3992203945Sweongyostatic void
3993203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
3994203945Sweongyo{
3995203945Sweongyo
3996203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
3997203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
3998203945Sweongyo}
3999203945Sweongyo
4000203945Sweongyostatic int
4001203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
4002203945Sweongyo{
4003203945Sweongyo	uint32_t val;
4004203945Sweongyo
4005203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
4006203945Sweongyo	val &= BWN_DMA32_RXDPTR;
4007203945Sweongyo
4008203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
4009203945Sweongyo}
4010203945Sweongyo
4011203945Sweongyostatic void
4012203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
4013203945Sweongyo{
4014203945Sweongyo
4015203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
4016203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
4017203945Sweongyo}
4018203945Sweongyo
4019203945Sweongyostatic void
4020203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
4021203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
4022203945Sweongyo{
4023203945Sweongyo	struct bwn_dmadesc64 *desc;
4024203945Sweongyo
4025203945Sweongyo	*meta = &(dr->dr_meta[slot]);
4026203945Sweongyo	desc = dr->dr_ring_descbase;
4027203945Sweongyo	desc = &(desc[slot]);
4028203945Sweongyo
4029203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
4030203945Sweongyo}
4031203945Sweongyo
4032203945Sweongyostatic void
4033203945Sweongyobwn_dma_64_setdesc(struct bwn_dma_ring *dr,
4034203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
4035203945Sweongyo    int start, int end, int irq)
4036203945Sweongyo{
4037203945Sweongyo	struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
4038204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
4039203945Sweongyo	int slot;
4040203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
4041203945Sweongyo	uint32_t addrlo, addrhi;
4042203945Sweongyo	uint32_t addrext;
4043203945Sweongyo
4044203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
4045203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
4046203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4047203945Sweongyo
4048203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
4049203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
4050203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
4051203945Sweongyo	    30;
4052204922Sweongyo	addrhi |= (siba_dma_translation(sc->sc_dev) << 1);
4053203945Sweongyo	if (slot == dr->dr_numslots - 1)
4054203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
4055203945Sweongyo	if (start)
4056203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
4057203945Sweongyo	if (end)
4058203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
4059203945Sweongyo	if (irq)
4060203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
4061203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
4062203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
4063203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
4064203945Sweongyo
4065203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
4066203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
4067203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
4068203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
4069203945Sweongyo}
4070203945Sweongyo
4071203945Sweongyostatic void
4072203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
4073203945Sweongyo{
4074203945Sweongyo
4075203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
4076203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4077203945Sweongyo}
4078203945Sweongyo
4079203945Sweongyostatic void
4080203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
4081203945Sweongyo{
4082203945Sweongyo
4083203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4084203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
4085203945Sweongyo}
4086203945Sweongyo
4087203945Sweongyostatic void
4088203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
4089203945Sweongyo{
4090203945Sweongyo
4091203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4092203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
4093203945Sweongyo}
4094203945Sweongyo
4095203945Sweongyostatic int
4096203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
4097203945Sweongyo{
4098203945Sweongyo	uint32_t val;
4099203945Sweongyo
4100203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
4101203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
4102203945Sweongyo
4103203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
4104203945Sweongyo}
4105203945Sweongyo
4106203945Sweongyostatic void
4107203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
4108203945Sweongyo{
4109203945Sweongyo
4110203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
4111203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4112203945Sweongyo}
4113203945Sweongyo
4114203945Sweongyostatic int
4115203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
4116203945Sweongyo{
4117203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4118203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4119203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4120203945Sweongyo	int error;
4121203945Sweongyo
4122203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
4123203945Sweongyo			    BWN_ALIGN, 0,
4124203945Sweongyo			    BUS_SPACE_MAXADDR,
4125203945Sweongyo			    BUS_SPACE_MAXADDR,
4126203945Sweongyo			    NULL, NULL,
4127203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
4128203945Sweongyo			    1,
4129203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
4130203945Sweongyo			    0,
4131203945Sweongyo			    NULL, NULL,
4132203945Sweongyo			    &dr->dr_ring_dtag);
4133203945Sweongyo	if (error) {
4134203945Sweongyo		device_printf(sc->sc_dev,
4135203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
4136203945Sweongyo		return (-1);
4137203945Sweongyo	}
4138203945Sweongyo
4139203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
4140203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
4141203945Sweongyo	    &dr->dr_ring_dmap);
4142203945Sweongyo	if (error) {
4143203945Sweongyo		device_printf(sc->sc_dev,
4144203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
4145203945Sweongyo		return (-1);
4146203945Sweongyo	}
4147203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
4148203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
4149203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
4150203945Sweongyo	if (error) {
4151203945Sweongyo		device_printf(sc->sc_dev,
4152203945Sweongyo		    "can't load DMA mem: TODO free\n");
4153203945Sweongyo		return (-1);
4154203945Sweongyo	}
4155203945Sweongyo
4156203945Sweongyo	return (0);
4157203945Sweongyo}
4158203945Sweongyo
4159203945Sweongyostatic void
4160203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
4161203945Sweongyo{
4162204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
4163203945Sweongyo	uint64_t ring64;
4164203945Sweongyo	uint32_t addrext, ring32, value;
4165204922Sweongyo	uint32_t trans = siba_dma_translation(sc->sc_dev);
4166203945Sweongyo
4167203945Sweongyo	if (dr->dr_tx) {
4168203945Sweongyo		dr->dr_curslot = -1;
4169203945Sweongyo
4170203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4171203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
4172203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
4173203945Sweongyo			    >> 30;
4174203945Sweongyo			value = BWN_DMA64_TXENABLE;
4175203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
4176203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
4177203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
4178203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
4179203945Sweongyo			    (ring64 & 0xffffffff));
4180203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
4181203945Sweongyo			    ((ring64 >> 32) &
4182203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
4183203945Sweongyo		} else {
4184203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
4185203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4186203945Sweongyo			value = BWN_DMA32_TXENABLE;
4187203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
4188203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
4189203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
4190203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
4191203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4192203945Sweongyo		}
4193203945Sweongyo		return;
4194203945Sweongyo	}
4195203945Sweongyo
4196203945Sweongyo	/*
4197203945Sweongyo	 * set for RX
4198203945Sweongyo	 */
4199203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
4200203945Sweongyo
4201203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
4202203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
4203203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
4204203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
4205203945Sweongyo		value |= BWN_DMA64_RXENABLE;
4206203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
4207203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
4208203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
4209203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
4210203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
4211203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
4212203945Sweongyo		    | (trans << 1));
4213203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
4214203945Sweongyo		    sizeof(struct bwn_dmadesc64));
4215203945Sweongyo	} else {
4216203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
4217203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4218203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
4219203945Sweongyo		value |= BWN_DMA32_RXENABLE;
4220203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
4221203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
4222203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
4223203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
4224203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4225203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
4226203945Sweongyo		    sizeof(struct bwn_dmadesc32));
4227203945Sweongyo	}
4228203945Sweongyo}
4229203945Sweongyo
4230203945Sweongyostatic void
4231203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
4232203945Sweongyo{
4233203945Sweongyo
4234203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
4235203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
4236203945Sweongyo	    dr->dr_ring_dmap);
4237203945Sweongyo}
4238203945Sweongyo
4239203945Sweongyostatic void
4240203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
4241203945Sweongyo{
4242203945Sweongyo
4243203945Sweongyo	if (dr->dr_tx) {
4244203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4245203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4246203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
4247203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
4248203945Sweongyo		} else
4249203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
4250203945Sweongyo	} else {
4251203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4252203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4253203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
4254203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
4255203945Sweongyo		} else
4256203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
4257203945Sweongyo	}
4258203945Sweongyo}
4259203945Sweongyo
4260203945Sweongyostatic void
4261203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
4262203945Sweongyo{
4263203945Sweongyo	struct bwn_dmadesc_generic *desc;
4264203945Sweongyo	struct bwn_dmadesc_meta *meta;
4265203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4266203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4267203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4268203945Sweongyo	int i;
4269203945Sweongyo
4270203945Sweongyo	if (!dr->dr_usedslot)
4271203945Sweongyo		return;
4272203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
4273203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
4274203945Sweongyo
4275203945Sweongyo		if (meta->mt_m == NULL) {
4276203945Sweongyo			if (!dr->dr_tx)
4277203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
4278203945Sweongyo				    __func__);
4279203945Sweongyo			continue;
4280203945Sweongyo		}
4281203945Sweongyo		if (dr->dr_tx) {
4282203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
4283203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
4284203945Sweongyo				    meta->mt_dmap);
4285203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
4286203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
4287203945Sweongyo				    meta->mt_dmap);
4288203945Sweongyo		} else
4289203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
4290203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
4291203945Sweongyo	}
4292203945Sweongyo}
4293203945Sweongyo
4294203945Sweongyostatic int
4295203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
4296203945Sweongyo    int type)
4297203945Sweongyo{
4298203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4299203945Sweongyo	uint32_t value;
4300203945Sweongyo	int i;
4301203945Sweongyo	uint16_t offset;
4302203945Sweongyo
4303203945Sweongyo	for (i = 0; i < 10; i++) {
4304203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4305203945Sweongyo		    BWN_DMA32_TXSTATUS;
4306203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4307203945Sweongyo		if (type == BWN_DMA_64BIT) {
4308203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4309203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
4310203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
4311203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
4312203945Sweongyo				break;
4313203945Sweongyo		} else {
4314203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4315203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
4316203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
4317203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
4318203945Sweongyo				break;
4319203945Sweongyo		}
4320203945Sweongyo		DELAY(1000);
4321203945Sweongyo	}
4322203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
4323203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4324203945Sweongyo	for (i = 0; i < 10; i++) {
4325203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4326203945Sweongyo						   BWN_DMA32_TXSTATUS;
4327203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4328203945Sweongyo		if (type == BWN_DMA_64BIT) {
4329203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4330203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
4331203945Sweongyo				i = -1;
4332203945Sweongyo				break;
4333203945Sweongyo			}
4334203945Sweongyo		} else {
4335203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4336203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
4337203945Sweongyo				i = -1;
4338203945Sweongyo				break;
4339203945Sweongyo			}
4340203945Sweongyo		}
4341203945Sweongyo		DELAY(1000);
4342203945Sweongyo	}
4343203945Sweongyo	if (i != -1) {
4344203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4345203945Sweongyo		return (ENODEV);
4346203945Sweongyo	}
4347203945Sweongyo	DELAY(1000);
4348203945Sweongyo
4349203945Sweongyo	return (0);
4350203945Sweongyo}
4351203945Sweongyo
4352203945Sweongyostatic int
4353203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
4354203945Sweongyo    int type)
4355203945Sweongyo{
4356203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4357203945Sweongyo	uint32_t value;
4358203945Sweongyo	int i;
4359203945Sweongyo	uint16_t offset;
4360203945Sweongyo
4361203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
4362203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4363203945Sweongyo	for (i = 0; i < 10; i++) {
4364203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
4365203945Sweongyo		    BWN_DMA32_RXSTATUS;
4366203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4367203945Sweongyo		if (type == BWN_DMA_64BIT) {
4368203945Sweongyo			value &= BWN_DMA64_RXSTAT;
4369203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
4370203945Sweongyo				i = -1;
4371203945Sweongyo				break;
4372203945Sweongyo			}
4373203945Sweongyo		} else {
4374203945Sweongyo			value &= BWN_DMA32_RXSTATE;
4375203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
4376203945Sweongyo				i = -1;
4377203945Sweongyo				break;
4378203945Sweongyo			}
4379203945Sweongyo		}
4380203945Sweongyo		DELAY(1000);
4381203945Sweongyo	}
4382203945Sweongyo	if (i != -1) {
4383203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4384203945Sweongyo		return (ENODEV);
4385203945Sweongyo	}
4386203945Sweongyo
4387203945Sweongyo	return (0);
4388203945Sweongyo}
4389203945Sweongyo
4390203945Sweongyostatic void
4391203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
4392203945Sweongyo    struct bwn_dmadesc_meta *meta)
4393203945Sweongyo{
4394203945Sweongyo
4395203945Sweongyo	if (meta->mt_m != NULL) {
4396203945Sweongyo		m_freem(meta->mt_m);
4397203945Sweongyo		meta->mt_m = NULL;
4398203945Sweongyo	}
4399203945Sweongyo	if (meta->mt_ni != NULL) {
4400203945Sweongyo		ieee80211_free_node(meta->mt_ni);
4401203945Sweongyo		meta->mt_ni = NULL;
4402203945Sweongyo	}
4403203945Sweongyo}
4404203945Sweongyo
4405203945Sweongyostatic void
4406203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4407203945Sweongyo{
4408203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
4409203945Sweongyo	unsigned char *frame;
4410203945Sweongyo
4411203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
4412203945Sweongyo	rxhdr->frame_len = 0;
4413203945Sweongyo
4414203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
4415203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
4416203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4417203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
4418203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
4419203945Sweongyo}
4420203945Sweongyo
4421203945Sweongyostatic uint8_t
4422203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4423203945Sweongyo{
4424203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
4425203945Sweongyo
4426203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
4427203945Sweongyo	    == 0xff);
4428203945Sweongyo}
4429203945Sweongyo
4430203945Sweongyostatic void
4431203945Sweongyobwn_wme_init(struct bwn_mac *mac)
4432203945Sweongyo{
4433203945Sweongyo
4434203945Sweongyo	bwn_wme_load(mac);
4435203945Sweongyo
4436203945Sweongyo	/* enable WME support. */
4437203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
4438203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
4439203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
4440203945Sweongyo}
4441203945Sweongyo
4442203945Sweongyostatic void
4443203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
4444203945Sweongyo{
4445203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4446203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4447203945Sweongyo	uint16_t delay;	/* microsec */
4448203945Sweongyo
4449203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
4450203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
4451203945Sweongyo		delay = 500;
4452203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
4453203945Sweongyo		delay = max(delay, (uint16_t)2400);
4454203945Sweongyo
4455203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
4456203945Sweongyo}
4457203945Sweongyo
4458203945Sweongyostatic void
4459203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
4460203945Sweongyo{
4461204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4462203945Sweongyo	uint64_t hf;
4463203945Sweongyo
4464203945Sweongyo	if (bwn_bluetooth == 0)
4465203945Sweongyo		return;
4466204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCOEXIST) == 0)
4467203945Sweongyo		return;
4468203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
4469203945Sweongyo		return;
4470203945Sweongyo
4471203945Sweongyo	hf = bwn_hf_read(mac);
4472204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCMOD)
4473203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
4474203945Sweongyo	else
4475203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
4476203945Sweongyo	bwn_hf_write(mac, hf);
4477203945Sweongyo}
4478203945Sweongyo
4479203945Sweongyostatic void
4480203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
4481203945Sweongyo{
4482203945Sweongyo
4483203945Sweongyo	bwn_mac_write_bssid(mac);
4484203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF, mac->mac_sc->sc_macaddr);
4485203945Sweongyo}
4486203945Sweongyo
4487203945Sweongyostatic void
4488203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
4489203945Sweongyo{
4490203945Sweongyo	int i;
4491203945Sweongyo
4492203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
4493203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
4494203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
4495203945Sweongyo
4496203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
4497203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
4498203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
4499203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
4500203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
4501203945Sweongyo		}
4502203945Sweongyo		mac->mac_key[i].keyconf = NULL;
4503203945Sweongyo	}
4504203945Sweongyo}
4505203945Sweongyo
4506203945Sweongyostatic void
4507203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
4508203945Sweongyo{
4509204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4510203945Sweongyo
4511204922Sweongyo	mac->mac_max_nr_keys = (siba_get_revid(sc->sc_dev) >= 5) ? 58 : 20;
4512203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
4513203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4514203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
4515203945Sweongyo	mac->mac_ktp *= 2;
4516204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5)
4517204922Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT, mac->mac_max_nr_keys - 8);
4518203945Sweongyo	bwn_clear_keys(mac);
4519203945Sweongyo}
4520203945Sweongyo
4521203945Sweongyostatic void
4522203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
4523203945Sweongyo{
4524204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4525203945Sweongyo
4526203945Sweongyo	bwn_phy_exit(mac);
4527204922Sweongyo	siba_gpio_set(sc->sc_dev, 0);
4528203945Sweongyo}
4529203945Sweongyo
4530203945Sweongyostatic int
4531203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
4532203945Sweongyo{
4533203945Sweongyo	int error;
4534203945Sweongyo
4535203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
4536203945Sweongyo	if (error == 0)
4537203945Sweongyo		return (0);
4538203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
4539203945Sweongyo	if (error == 0)
4540203945Sweongyo		return (0);
4541203945Sweongyo	return (error);
4542203945Sweongyo}
4543203945Sweongyo
4544203945Sweongyostatic int
4545203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
4546203945Sweongyo{
4547204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4548204922Sweongyo	uint32_t mask = 0x1f, set = 0xf, value;
4549203945Sweongyo
4550203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4551203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
4552203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
4553203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
4554203945Sweongyo
4555204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4301) {
4556203945Sweongyo		mask |= 0x0060;
4557203945Sweongyo		set |= 0x0060;
4558203945Sweongyo	}
4559204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL) {
4560203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
4561203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
4562203945Sweongyo		mask |= 0x0200;
4563203945Sweongyo		set |= 0x0200;
4564203945Sweongyo	}
4565204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 2)
4566203945Sweongyo		mask |= 0x0010;
4567204922Sweongyo
4568204922Sweongyo	value = siba_gpio_get(sc->sc_dev);
4569204922Sweongyo	if (value == -1)
4570203945Sweongyo		return (0);
4571204922Sweongyo	siba_gpio_set(sc->sc_dev, (value & mask) | set);
4572203945Sweongyo
4573203945Sweongyo	return (0);
4574203945Sweongyo}
4575203945Sweongyo
4576203945Sweongyostatic int
4577203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
4578203945Sweongyo{
4579203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
4580203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
4581203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
4582203945Sweongyo	const struct bwn_fwhdr *hdr;
4583203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
4584203945Sweongyo	int error;
4585203945Sweongyo
4586203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
4587203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
4588203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
4589203945Sweongyo	if (error)
4590203945Sweongyo		return (error);
4591203945Sweongyo	if (fw->initvals_band.fw) {
4592203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
4593203945Sweongyo		error = bwn_fwinitvals_write(mac,
4594203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
4595203945Sweongyo		    be32toh(hdr->size),
4596203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
4597203945Sweongyo	}
4598203945Sweongyo	return (error);
4599203945Sweongyo#undef GETFWOFFSET
4600203945Sweongyo}
4601203945Sweongyo
4602203945Sweongyostatic int
4603203945Sweongyobwn_phy_init(struct bwn_mac *mac)
4604203945Sweongyo{
4605203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4606203945Sweongyo	int error;
4607203945Sweongyo
4608203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
4609203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4610203945Sweongyo	error = mac->mac_phy.init(mac);
4611203945Sweongyo	if (error) {
4612203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
4613203945Sweongyo		goto fail0;
4614203945Sweongyo	}
4615203945Sweongyo	error = bwn_switch_channel(mac,
4616203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
4617203945Sweongyo	if (error) {
4618203945Sweongyo		device_printf(sc->sc_dev,
4619203945Sweongyo		    "failed to switch default channel\n");
4620203945Sweongyo		goto fail1;
4621203945Sweongyo	}
4622203945Sweongyo	return (0);
4623203945Sweongyofail1:
4624203945Sweongyo	if (mac->mac_phy.exit)
4625203945Sweongyo		mac->mac_phy.exit(mac);
4626203945Sweongyofail0:
4627203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4628203945Sweongyo
4629203945Sweongyo	return (error);
4630203945Sweongyo}
4631203945Sweongyo
4632203945Sweongyostatic void
4633203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
4634203945Sweongyo{
4635203945Sweongyo	uint16_t ant;
4636203945Sweongyo	uint16_t tmp;
4637203945Sweongyo
4638203945Sweongyo	ant = bwn_ant2phy(antenna);
4639203945Sweongyo
4640203945Sweongyo	/* For ACK/CTS */
4641203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
4642203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4643203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
4644203945Sweongyo	/* For Probe Resposes */
4645203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
4646203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4647203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
4648203945Sweongyo}
4649203945Sweongyo
4650203945Sweongyostatic void
4651203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
4652203945Sweongyo{
4653203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4654203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4655203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
4656203945Sweongyo	uint32_t ctl;
4657203945Sweongyo	uint16_t cfp_pretbtt;
4658203945Sweongyo
4659203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
4660203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
4661203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
4662203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
4663203945Sweongyo	ctl |= BWN_MACCTL_STA;
4664203945Sweongyo
4665203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4666203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
4667203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
4668203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
4669203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
4670203945Sweongyo	ctl |= sc->sc_filters;
4671203945Sweongyo
4672204922Sweongyo	if (siba_get_revid(sc->sc_dev) <= 4)
4673203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
4674203945Sweongyo
4675203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
4676203945Sweongyo
4677203945Sweongyo	cfp_pretbtt = 2;
4678203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
4679204922Sweongyo		if (siba_get_chipid(sc->sc_dev) == 0x4306 &&
4680204922Sweongyo		    siba_get_chiprev(sc->sc_dev) == 3)
4681203945Sweongyo			cfp_pretbtt = 100;
4682203945Sweongyo		else
4683203945Sweongyo			cfp_pretbtt = 50;
4684203945Sweongyo	}
4685203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
4686203945Sweongyo}
4687203945Sweongyo
4688203945Sweongyostatic int
4689203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
4690203945Sweongyo{
4691203945Sweongyo	uint32_t tmp;
4692203945Sweongyo	uint16_t base;
4693203945Sweongyo
4694203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
4695203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
4696203945Sweongyo		return (BWN_DMA_64BIT);
4697203945Sweongyo	base = bwn_dma_base(0, 0);
4698203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
4699203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
4700203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
4701203945Sweongyo		return (BWN_DMA_32BIT);
4702203945Sweongyo
4703203945Sweongyo	return (BWN_DMA_30BIT);
4704203945Sweongyo}
4705203945Sweongyo
4706203945Sweongyostatic void
4707203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
4708203945Sweongyo{
4709203945Sweongyo	if (!error) {
4710203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
4711203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
4712203945Sweongyo	}
4713203945Sweongyo}
4714203945Sweongyo
4715203945Sweongyostatic void
4716203945Sweongyobwn_phy_g_init_sub(struct bwn_mac *mac)
4717203945Sweongyo{
4718203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4719203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4720204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4721203945Sweongyo	uint16_t i, tmp;
4722203945Sweongyo
4723203945Sweongyo	if (phy->rev == 1)
4724203945Sweongyo		bwn_phy_init_b5(mac);
4725203945Sweongyo	else
4726203945Sweongyo		bwn_phy_init_b6(mac);
4727203945Sweongyo
4728203945Sweongyo	if (phy->rev >= 2 || phy->gmode)
4729203945Sweongyo		bwn_phy_init_a(mac);
4730203945Sweongyo
4731203945Sweongyo	if (phy->rev >= 2) {
4732203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
4733203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
4734203945Sweongyo	}
4735203945Sweongyo	if (phy->rev == 2) {
4736203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
4737203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4738203945Sweongyo	}
4739203945Sweongyo	if (phy->rev > 5) {
4740203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
4741203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4742203945Sweongyo	}
4743203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4744203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
4745203945Sweongyo		tmp &= BWN_PHYVER_VERSION;
4746203945Sweongyo		if (tmp == 3 || tmp == 5) {
4747203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
4748203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
4749203945Sweongyo		}
4750203945Sweongyo		if (tmp == 5) {
4751203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
4752203945Sweongyo			    0x1f00);
4753203945Sweongyo		}
4754203945Sweongyo	}
4755203945Sweongyo	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
4756203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
4757203945Sweongyo	if (phy->rf_rev == 8) {
4758203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
4759203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
4760203945Sweongyo	}
4761203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
4762203945Sweongyo		bwn_loopback_calcgain(mac);
4763203945Sweongyo
4764203945Sweongyo	if (phy->rf_rev != 8) {
4765203945Sweongyo		if (pg->pg_initval == 0xffff)
4766203945Sweongyo			pg->pg_initval = bwn_rf_init_bcm2050(mac);
4767203945Sweongyo		else
4768203945Sweongyo			BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
4769203945Sweongyo	}
4770203945Sweongyo	bwn_lo_g_init(mac);
4771203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
4772203945Sweongyo		BWN_RF_WRITE(mac, 0x52,
4773203945Sweongyo		    (BWN_RF_READ(mac, 0x52) & 0xff00)
4774203945Sweongyo		    | pg->pg_loctl.tx_bias |
4775203945Sweongyo		    pg->pg_loctl.tx_magn);
4776203945Sweongyo	} else {
4777203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
4778203945Sweongyo	}
4779203945Sweongyo	if (phy->rev >= 6) {
4780203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
4781203945Sweongyo		    (pg->pg_loctl.tx_bias << 12));
4782203945Sweongyo	}
4783204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
4784203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
4785203945Sweongyo	else
4786203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
4787203945Sweongyo	if (phy->rev < 2)
4788203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
4789203945Sweongyo	else
4790203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
4791203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4792203945Sweongyo		bwn_lo_g_adjust(mac);
4793203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
4794203945Sweongyo	}
4795203945Sweongyo
4796204922Sweongyo	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
4797203945Sweongyo		for (i = 0; i < 64; i++) {
4798203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
4799203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
4800203945Sweongyo			    (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
4801203945Sweongyo			    -32), 31));
4802203945Sweongyo		}
4803203945Sweongyo		bwn_nrssi_threshold(mac);
4804203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
4805203945Sweongyo		if (pg->pg_nrssi[0] == -1000) {
4806203945Sweongyo			KASSERT(pg->pg_nrssi[1] == -1000,
4807203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
4808203945Sweongyo			bwn_nrssi_slope_11g(mac);
4809203945Sweongyo		} else
4810203945Sweongyo			bwn_nrssi_threshold(mac);
4811203945Sweongyo	}
4812203945Sweongyo	if (phy->rf_rev == 8)
4813203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
4814203945Sweongyo	bwn_phy_hwpctl_init(mac);
4815204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4306
4816204922Sweongyo	     && siba_get_chippkg(sc->sc_dev) == 2) || 0) {
4817203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
4818203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
4819203945Sweongyo	}
4820203945Sweongyo}
4821203945Sweongyo
4822203945Sweongyostatic uint8_t
4823203945Sweongyobwn_has_hwpctl(struct bwn_mac *mac)
4824203945Sweongyo{
4825203945Sweongyo
4826203945Sweongyo	if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
4827203945Sweongyo		return (0);
4828203945Sweongyo	return (mac->mac_phy.use_hwpctl(mac));
4829203945Sweongyo}
4830203945Sweongyo
4831203945Sweongyostatic void
4832203945Sweongyobwn_phy_init_b5(struct bwn_mac *mac)
4833203945Sweongyo{
4834203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4835203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4836204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4837203945Sweongyo	uint16_t offset, value;
4838203945Sweongyo	uint8_t old_channel;
4839203945Sweongyo
4840203945Sweongyo	if (phy->analog == 1)
4841203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0050);
4842204922Sweongyo	if ((siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM) &&
4843204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306)) {
4844203945Sweongyo		value = 0x2120;
4845203945Sweongyo		for (offset = 0x00a8; offset < 0x00c7; offset++) {
4846203945Sweongyo			BWN_PHY_WRITE(mac, offset, value);
4847203945Sweongyo			value += 0x202;
4848203945Sweongyo		}
4849203945Sweongyo	}
4850203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
4851203945Sweongyo	if (phy->rf_ver == 0x2050)
4852203945Sweongyo		BWN_PHY_WRITE(mac, 0x0038, 0x0667);
4853203945Sweongyo
4854203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4855203945Sweongyo		if (phy->rf_ver == 0x2050) {
4856203945Sweongyo			BWN_RF_SET(mac, 0x007a, 0x0020);
4857203945Sweongyo			BWN_RF_SET(mac, 0x0051, 0x0004);
4858203945Sweongyo		}
4859203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
4860203945Sweongyo
4861203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
4862203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
4863203945Sweongyo
4864203945Sweongyo		BWN_PHY_WRITE(mac, 0x001c, 0x186a);
4865203945Sweongyo
4866203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
4867203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
4868203945Sweongyo		BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
4869203945Sweongyo	}
4870203945Sweongyo
4871203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
4872203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
4873203945Sweongyo
4874203945Sweongyo	if (phy->analog == 1) {
4875203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xce00);
4876203945Sweongyo		BWN_PHY_WRITE(mac, 0x0021, 0x3763);
4877203945Sweongyo		BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
4878203945Sweongyo		BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
4879203945Sweongyo		BWN_PHY_WRITE(mac, 0x0024, 0x037e);
4880203945Sweongyo	} else
4881203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
4882203945Sweongyo	BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
4883203945Sweongyo	BWN_WRITE_2(mac, 0x03ec, 0x3f22);
4884203945Sweongyo
4885203945Sweongyo	if (phy->analog == 1)
4886203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
4887203945Sweongyo	else
4888203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x301c);
4889203945Sweongyo
4890203945Sweongyo	if (phy->analog == 0)
4891203945Sweongyo		BWN_WRITE_2(mac, 0x03e4, 0x3000);
4892203945Sweongyo
4893203945Sweongyo	old_channel = phy->chan;
4894203945Sweongyo	bwn_phy_g_switch_chan(mac, 7, 0);
4895203945Sweongyo
4896203945Sweongyo	if (phy->rf_ver != 0x2050) {
4897203945Sweongyo		BWN_RF_WRITE(mac, 0x0075, 0x0080);
4898203945Sweongyo		BWN_RF_WRITE(mac, 0x0079, 0x0081);
4899203945Sweongyo	}
4900203945Sweongyo
4901203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
4902203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
4903203945Sweongyo
4904203945Sweongyo	if (phy->rf_ver == 0x2050) {
4905203945Sweongyo		BWN_RF_WRITE(mac, 0x0050, 0x0020);
4906203945Sweongyo		BWN_RF_WRITE(mac, 0x005a, 0x0070);
4907203945Sweongyo	}
4908203945Sweongyo
4909203945Sweongyo	BWN_RF_WRITE(mac, 0x005b, 0x007b);
4910203945Sweongyo	BWN_RF_WRITE(mac, 0x005c, 0x00b0);
4911203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0007);
4912203945Sweongyo
4913203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
4914203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0080);
4915203945Sweongyo	BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
4916203945Sweongyo	BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
4917203945Sweongyo
4918203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
4919203945Sweongyo	    pg->pg_txctl);
4920203945Sweongyo
4921203945Sweongyo	if (phy->rf_ver == 0x2050)
4922203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
4923203945Sweongyo
4924203945Sweongyo	BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
4925203945Sweongyo}
4926203945Sweongyo
4927203945Sweongyostatic void
4928203945Sweongyobwn_loopback_calcgain(struct bwn_mac *mac)
4929203945Sweongyo{
4930203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4931203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4932204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4933203945Sweongyo	uint16_t backup_phy[16] = { 0 };
4934203945Sweongyo	uint16_t backup_radio[3];
4935203945Sweongyo	uint16_t backup_bband;
4936203945Sweongyo	uint16_t i, j, loop_i_max;
4937203945Sweongyo	uint16_t trsw_rx;
4938203945Sweongyo	uint16_t loop1_outer_done, loop1_inner_done;
4939203945Sweongyo
4940203945Sweongyo	backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
4941203945Sweongyo	backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
4942203945Sweongyo	backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
4943203945Sweongyo	backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
4944203945Sweongyo	if (phy->rev != 1) {
4945203945Sweongyo		backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
4946203945Sweongyo		backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
4947203945Sweongyo	}
4948203945Sweongyo	backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
4949203945Sweongyo	backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
4950203945Sweongyo	backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
4951203945Sweongyo	backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
4952203945Sweongyo	backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
4953203945Sweongyo	backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
4954203945Sweongyo	backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
4955203945Sweongyo	backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
4956203945Sweongyo	backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
4957203945Sweongyo	backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
4958203945Sweongyo	backup_bband = pg->pg_bbatt.att;
4959203945Sweongyo	backup_radio[0] = BWN_RF_READ(mac, 0x52);
4960203945Sweongyo	backup_radio[1] = BWN_RF_READ(mac, 0x43);
4961203945Sweongyo	backup_radio[2] = BWN_RF_READ(mac, 0x7a);
4962203945Sweongyo
4963203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
4964203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
4965203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
4966203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
4967203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
4968203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
4969203945Sweongyo	if (phy->rev != 1) {
4970203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
4971203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
4972203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
4973203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
4974203945Sweongyo	}
4975203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
4976203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
4977203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
4978203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
4979203945Sweongyo
4980203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
4981203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
4982203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
4983203945Sweongyo
4984203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
4985203945Sweongyo	if (phy->rev != 1) {
4986203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
4987203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
4988203945Sweongyo	}
4989203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
4990203945Sweongyo
4991203945Sweongyo	if (phy->rf_rev == 8)
4992203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x000f);
4993203945Sweongyo	else {
4994203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
4995203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
4996203945Sweongyo	}
4997203945Sweongyo	bwn_phy_g_set_bbatt(mac, 11);
4998203945Sweongyo
4999203945Sweongyo	if (phy->rev >= 3)
5000203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5001203945Sweongyo	else
5002203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5003203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5004203945Sweongyo
5005203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
5006203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
5007203945Sweongyo
5008203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
5009203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
5010203945Sweongyo
5011204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) {
5012203945Sweongyo		if (phy->rev >= 7) {
5013203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
5014203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
5015203945Sweongyo		}
5016203945Sweongyo	}
5017203945Sweongyo	BWN_RF_MASK(mac, 0x7a, 0x00f7);
5018203945Sweongyo
5019203945Sweongyo	j = 0;
5020203945Sweongyo	loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
5021203945Sweongyo	for (i = 0; i < loop_i_max; i++) {
5022203945Sweongyo		for (j = 0; j < 16; j++) {
5023203945Sweongyo			BWN_RF_WRITE(mac, 0x43, i);
5024203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
5025203945Sweongyo			    (j << 8));
5026203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5027203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5028203945Sweongyo			DELAY(20);
5029203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5030203945Sweongyo				goto done0;
5031203945Sweongyo		}
5032203945Sweongyo	}
5033203945Sweongyodone0:
5034203945Sweongyo	loop1_outer_done = i;
5035203945Sweongyo	loop1_inner_done = j;
5036203945Sweongyo	if (j >= 8) {
5037203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
5038203945Sweongyo		trsw_rx = 0x1b;
5039203945Sweongyo		for (j = j - 8; j < 16; j++) {
5040203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
5041203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5042203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5043203945Sweongyo			DELAY(20);
5044203945Sweongyo			trsw_rx -= 3;
5045203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5046203945Sweongyo				goto done1;
5047203945Sweongyo		}
5048203945Sweongyo	} else
5049203945Sweongyo		trsw_rx = 0x18;
5050203945Sweongyodone1:
5051203945Sweongyo
5052203945Sweongyo	if (phy->rev != 1) {
5053203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
5054203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
5055203945Sweongyo	}
5056203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
5057203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
5058203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
5059203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
5060203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
5061203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
5062203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
5063203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
5064203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
5065203945Sweongyo
5066203945Sweongyo	bwn_phy_g_set_bbatt(mac, backup_bband);
5067203945Sweongyo
5068203945Sweongyo	BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
5069203945Sweongyo	BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
5070203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
5071203945Sweongyo
5072203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
5073203945Sweongyo	DELAY(10);
5074203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
5075203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
5076203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
5077203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
5078203945Sweongyo
5079203945Sweongyo	pg->pg_max_lb_gain =
5080203945Sweongyo	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
5081203945Sweongyo	pg->pg_trsw_rx_gain = trsw_rx * 2;
5082203945Sweongyo}
5083203945Sweongyo
5084203945Sweongyostatic uint16_t
5085203945Sweongyobwn_rf_init_bcm2050(struct bwn_mac *mac)
5086203945Sweongyo{
5087203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5088203945Sweongyo	uint32_t tmp1 = 0, tmp2 = 0;
5089203945Sweongyo	uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
5090203945Sweongyo	    analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
5091203945Sweongyo	    radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
5092203945Sweongyo	static const uint8_t rcc_table[] = {
5093203945Sweongyo		0x02, 0x03, 0x01, 0x0f,
5094203945Sweongyo		0x06, 0x07, 0x05, 0x0f,
5095203945Sweongyo		0x0a, 0x0b, 0x09, 0x0f,
5096203945Sweongyo		0x0e, 0x0f, 0x0d, 0x0f,
5097203945Sweongyo	};
5098203945Sweongyo
5099204242Simp	loctl = lomask = reg0 = classctl = crs0 = analogoverval = analogover =
5100204242Simp	    rfoverval = rfover = cck3 = 0;
5101203945Sweongyo	radio0 = BWN_RF_READ(mac, 0x43);
5102203945Sweongyo	radio1 = BWN_RF_READ(mac, 0x51);
5103203945Sweongyo	radio2 = BWN_RF_READ(mac, 0x52);
5104203945Sweongyo	pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5105203945Sweongyo	cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5106203945Sweongyo	cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5107203945Sweongyo	cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5108203945Sweongyo
5109203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5110203945Sweongyo		cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
5111203945Sweongyo		reg0 = BWN_READ_2(mac, 0x3ec);
5112203945Sweongyo
5113203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
5114203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
5115203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
5116203945Sweongyo		rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5117203945Sweongyo		rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5118203945Sweongyo		analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5119203945Sweongyo		analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5120203945Sweongyo		crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5121203945Sweongyo		classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
5122203945Sweongyo
5123203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
5124203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
5125203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
5126203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
5127203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5128203945Sweongyo			lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5129203945Sweongyo			loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5130203945Sweongyo			if (phy->rev >= 3)
5131203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5132203945Sweongyo			else
5133203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5134203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5135203945Sweongyo		}
5136203945Sweongyo
5137203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5138203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5139203945Sweongyo			BWN_LPD(0, 1, 1)));
5140203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
5141203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
5142203945Sweongyo	}
5143203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
5144203945Sweongyo
5145203945Sweongyo	syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
5146203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
5147203945Sweongyo	reg1 = BWN_READ_2(mac, 0x3e6);
5148203945Sweongyo	reg2 = BWN_READ_2(mac, 0x3f4);
5149203945Sweongyo
5150203945Sweongyo	if (phy->analog == 0)
5151203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0122);
5152203945Sweongyo	else {
5153203945Sweongyo		if (phy->analog >= 2)
5154203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
5155203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
5156203945Sweongyo		    (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
5157203945Sweongyo	}
5158203945Sweongyo
5159203945Sweongyo	reg = BWN_RF_READ(mac, 0x60);
5160203945Sweongyo	index = (reg & 0x001e) >> 1;
5161203945Sweongyo	rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
5162203945Sweongyo
5163203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5164203945Sweongyo		BWN_RF_WRITE(mac, 0x78, 0x26);
5165203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5166203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5167203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5168203945Sweongyo			BWN_LPD(0, 1, 1)));
5169203945Sweongyo	}
5170203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
5171203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
5172203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5173203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5174203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5175203945Sweongyo			BWN_LPD(0, 0, 1)));
5176203945Sweongyo	}
5177203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
5178203945Sweongyo	BWN_RF_SET(mac, 0x51, 0x0004);
5179203945Sweongyo	if (phy->rf_rev == 8)
5180203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x1f);
5181203945Sweongyo	else {
5182203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5183203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
5184203945Sweongyo	}
5185203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5186203945Sweongyo
5187203945Sweongyo	for (i = 0; i < 16; i++) {
5188203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
5189203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5190203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5191203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5192203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5193203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5194203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5195203945Sweongyo		}
5196203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5197203945Sweongyo		DELAY(10);
5198203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5199203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5200203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5201203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5202203945Sweongyo		}
5203203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5204203945Sweongyo		DELAY(10);
5205203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5206203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5207203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5208203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5209203945Sweongyo		}
5210203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5211203945Sweongyo		DELAY(20);
5212203945Sweongyo		tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5213203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5214203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5215203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5216203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5217203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5218203945Sweongyo		}
5219203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5220203945Sweongyo	}
5221203945Sweongyo	DELAY(10);
5222203945Sweongyo
5223203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5224203945Sweongyo	tmp1++;
5225203945Sweongyo	tmp1 >>= 9;
5226203945Sweongyo
5227203945Sweongyo	for (i = 0; i < 16; i++) {
5228203945Sweongyo		radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
5229203945Sweongyo		BWN_RF_WRITE(mac, 0x78, radio78);
5230203945Sweongyo		DELAY(10);
5231203945Sweongyo		for (j = 0; j < 16; j++) {
5232203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
5233203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5234203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5235203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5236203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5237203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5238203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5239203945Sweongyo			}
5240203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5241203945Sweongyo			DELAY(10);
5242203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5243203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5244203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5245203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5246203945Sweongyo			}
5247203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5248203945Sweongyo			DELAY(10);
5249203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5250203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5251203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5252203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5253203945Sweongyo			}
5254203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5255203945Sweongyo			DELAY(10);
5256203945Sweongyo			tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5257203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5258203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5259203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5260203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5261203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5262203945Sweongyo			}
5263203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5264203945Sweongyo		}
5265203945Sweongyo		tmp2++;
5266203945Sweongyo		tmp2 >>= 8;
5267203945Sweongyo		if (tmp1 < tmp2)
5268203945Sweongyo			break;
5269203945Sweongyo	}
5270203945Sweongyo
5271203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
5272203945Sweongyo	BWN_RF_WRITE(mac, 0x51, radio1);
5273203945Sweongyo	BWN_RF_WRITE(mac, 0x52, radio2);
5274203945Sweongyo	BWN_RF_WRITE(mac, 0x43, radio0);
5275203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
5276203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
5277203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
5278203945Sweongyo	BWN_WRITE_2(mac, 0x3e6, reg1);
5279203945Sweongyo	if (phy->analog != 0)
5280203945Sweongyo		BWN_WRITE_2(mac, 0x3f4, reg2);
5281203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
5282203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
5283203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5284203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
5285203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, reg0);
5286203945Sweongyo	} else if (phy->gmode) {
5287203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO,
5288203945Sweongyo			    BWN_READ_2(mac, BWN_PHY_RADIO)
5289203945Sweongyo			    & 0x7fff);
5290203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
5291203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
5292203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
5293203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
5294203945Sweongyo			      analogoverval);
5295203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
5296203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
5297203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5298203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
5299203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
5300203945Sweongyo		}
5301203945Sweongyo	}
5302203945Sweongyo
5303203945Sweongyo	return ((i > 15) ? radio78 : rcc);
5304203945Sweongyo}
5305203945Sweongyo
5306203945Sweongyostatic void
5307203945Sweongyobwn_phy_init_b6(struct bwn_mac *mac)
5308203945Sweongyo{
5309203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5310203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5311204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5312203945Sweongyo	uint16_t offset, val;
5313203945Sweongyo	uint8_t old_channel;
5314203945Sweongyo
5315203945Sweongyo	KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
5316203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5317203945Sweongyo
5318203945Sweongyo	BWN_PHY_WRITE(mac, 0x003e, 0x817a);
5319203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
5320203945Sweongyo	if (phy->rf_rev == 4 || phy->rf_rev == 5) {
5321203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0x37);
5322203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x70);
5323203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb3);
5324203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x9b);
5325203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5326203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x88);
5327203945Sweongyo		BWN_RF_WRITE(mac, 0x5d, 0x88);
5328203945Sweongyo		BWN_RF_WRITE(mac, 0x5e, 0x88);
5329203945Sweongyo		BWN_RF_WRITE(mac, 0x7d, 0x88);
5330203945Sweongyo		bwn_hf_write(mac,
5331203945Sweongyo		    bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
5332203945Sweongyo	}
5333203945Sweongyo	if (phy->rf_rev == 8) {
5334203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0);
5335203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x40);
5336203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb7);
5337203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x98);
5338203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5339203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x6b);
5340203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0x0f);
5341204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_ALTIQ) {
5342203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xfa);
5343203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xd8);
5344203945Sweongyo		} else {
5345203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xf5);
5346203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xb8);
5347203945Sweongyo		}
5348203945Sweongyo		BWN_RF_WRITE(mac, 0x0073, 0x0003);
5349203945Sweongyo		BWN_RF_WRITE(mac, 0x007d, 0x00a8);
5350203945Sweongyo		BWN_RF_WRITE(mac, 0x007c, 0x0001);
5351203945Sweongyo		BWN_RF_WRITE(mac, 0x007e, 0x0008);
5352203945Sweongyo	}
5353203945Sweongyo	for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
5354203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5355203945Sweongyo		val -= 0x0202;
5356203945Sweongyo	}
5357203945Sweongyo	for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
5358203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5359203945Sweongyo		val -= 0x0202;
5360203945Sweongyo	}
5361203945Sweongyo	for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
5362203945Sweongyo		BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
5363203945Sweongyo		val += 0x0202;
5364203945Sweongyo	}
5365203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
5366203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0020);
5367203945Sweongyo		BWN_RF_SET(mac, 0x0051, 0x0004);
5368203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
5369203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
5370203945Sweongyo		BWN_PHY_WRITE(mac, 0x5b, 0);
5371203945Sweongyo		BWN_PHY_WRITE(mac, 0x5c, 0);
5372203945Sweongyo	}
5373203945Sweongyo
5374203945Sweongyo	old_channel = phy->chan;
5375203945Sweongyo	bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
5376203945Sweongyo
5377203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
5378203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
5379203945Sweongyo	DELAY(40);
5380203945Sweongyo	if (phy->rf_rev < 6 || phy->rf_rev == 8) {
5381203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
5382203945Sweongyo		BWN_RF_WRITE(mac, 0x50, 0x20);
5383203945Sweongyo	}
5384203945Sweongyo	if (phy->rf_rev <= 2) {
5385203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, 0x20);
5386203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x70);
5387203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x7b);
5388203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0xb0);
5389203945Sweongyo	}
5390203945Sweongyo	BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
5391203945Sweongyo
5392203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5393203945Sweongyo
5394203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0200);
5395203945Sweongyo	if (phy->rf_rev >= 6)
5396203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
5397203945Sweongyo	else
5398203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
5399203945Sweongyo	BWN_PHY_WRITE(mac, 0x0038, 0x0668);
5400203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5401203945Sweongyo	    pg->pg_txctl);
5402203945Sweongyo	if (phy->rf_rev <= 5)
5403203945Sweongyo		BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
5404203945Sweongyo	if (phy->rf_rev <= 2)
5405203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5406203945Sweongyo
5407203945Sweongyo	if (phy->analog == 4) {
5408203945Sweongyo		BWN_WRITE_2(mac, 0x3e4, 9);
5409203945Sweongyo		BWN_PHY_MASK(mac, 0x61, 0x0fff);
5410203945Sweongyo	} else
5411203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
5412203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5413203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5414203945Sweongyo	else if (phy->type == BWN_PHYTYPE_G)
5415203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0);
5416203945Sweongyo}
5417203945Sweongyo
5418203945Sweongyostatic void
5419203945Sweongyobwn_phy_init_a(struct bwn_mac *mac)
5420203945Sweongyo{
5421203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5422204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5423203945Sweongyo
5424203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
5425203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5426203945Sweongyo
5427203945Sweongyo	if (phy->rev >= 6) {
5428203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5429203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
5430203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
5431203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
5432203945Sweongyo		else
5433203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
5434203945Sweongyo	}
5435203945Sweongyo
5436203945Sweongyo	bwn_wa_init(mac);
5437203945Sweongyo
5438203945Sweongyo	if (phy->type == BWN_PHYTYPE_G &&
5439204922Sweongyo	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL))
5440203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
5441203945Sweongyo}
5442203945Sweongyo
5443203945Sweongyostatic void
5444203945Sweongyobwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
5445203945Sweongyo{
5446203945Sweongyo	int i;
5447203945Sweongyo
5448203945Sweongyo	for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
5449203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
5450203945Sweongyo}
5451203945Sweongyo
5452203945Sweongyostatic void
5453203945Sweongyobwn_wa_agc(struct bwn_mac *mac)
5454203945Sweongyo{
5455203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5456203945Sweongyo
5457203945Sweongyo	if (phy->rev == 1) {
5458203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
5459203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
5460203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
5461203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
5462203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
5463203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
5464203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
5465203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
5466203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
5467203945Sweongyo	} else {
5468203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
5469203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
5470203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
5471203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
5472203945Sweongyo	}
5473203945Sweongyo
5474203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
5475203945Sweongyo	    0x5700);
5476203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
5477203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
5478203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
5479203945Sweongyo	BWN_RF_SET(mac, 0x7a, 0x0008);
5480203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
5481203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
5482203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
5483203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
5484203945Sweongyo	if (phy->rev == 1)
5485203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
5486203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
5487203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
5488203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
5489203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
5490203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
5491203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
5492203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
5493203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
5494203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
5495203945Sweongyo	if (phy->rev == 1) {
5496203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
5497203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
5498203945Sweongyo	} else {
5499203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
5500203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
5501203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
5502203945Sweongyo		if (phy->rev >= 6) {
5503203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
5504203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
5505203945Sweongyo			    (uint16_t)~0xf000, 0x3000);
5506203945Sweongyo		}
5507203945Sweongyo	}
5508203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
5509203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
5510203945Sweongyo	if (phy->rev == 1) {
5511203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
5512203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
5513203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
5514203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
5515203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
5516203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
5517203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
5518203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
5519203945Sweongyo	} else {
5520203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
5521203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
5522203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
5523203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
5524203945Sweongyo	}
5525203945Sweongyo	if (phy->rev >= 6) {
5526203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
5527203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
5528203945Sweongyo	}
5529203945Sweongyo	BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
5530203945Sweongyo}
5531203945Sweongyo
5532203945Sweongyostatic void
5533203945Sweongyobwn_wa_grev1(struct bwn_mac *mac)
5534203945Sweongyo{
5535203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5536203945Sweongyo	int i;
5537203945Sweongyo	static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
5538203945Sweongyo	static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
5539203945Sweongyo	static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
5540203945Sweongyo
5541203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5542203945Sweongyo
5543203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5544203945Sweongyo	if (phy->rev == 1) {
5545203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5546203945Sweongyo	} else if (phy->rev == 2) {
5547203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5548203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5549203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5550203945Sweongyo	} else {
5551203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5552203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5553203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5554203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5555203945Sweongyo	}
5556203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
5557203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
5558203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
5559203945Sweongyo
5560203945Sweongyo	/* XXX support PHY-A??? */
5561203945Sweongyo	for (i = 0; i < N(bwn_tab_finefreqg); i++)
5562203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
5563203945Sweongyo		    bwn_tab_finefreqg[i]);
5564203945Sweongyo
5565203945Sweongyo	/* XXX support PHY-A??? */
5566203945Sweongyo	if (phy->rev == 1)
5567203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5568203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5569203945Sweongyo			    bwn_tab_noise_g1[i]);
5570203945Sweongyo	else
5571203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5572203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5573203945Sweongyo			    bwn_tab_noise_g2[i]);
5574203945Sweongyo
5575203945Sweongyo
5576203945Sweongyo	for (i = 0; i < N(bwn_tab_rotor); i++)
5577203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
5578203945Sweongyo		    bwn_tab_rotor[i]);
5579203945Sweongyo
5580203945Sweongyo	/* XXX support PHY-A??? */
5581203945Sweongyo	if (phy->rev >= 6) {
5582203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5583203945Sweongyo		    BWN_PHY_ENCORE_EN)
5584203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5585203945Sweongyo		else
5586203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5587203945Sweongyo	} else
5588203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5589203945Sweongyo
5590203945Sweongyo	for (i = 0; i < N(bwn_tab_retard); i++)
5591203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
5592203945Sweongyo		    bwn_tab_retard[i]);
5593203945Sweongyo
5594203945Sweongyo	if (phy->rev == 1) {
5595203945Sweongyo		for (i = 0; i < 16; i++)
5596203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
5597203945Sweongyo			    i, 0x0020);
5598203945Sweongyo	} else {
5599203945Sweongyo		for (i = 0; i < 32; i++)
5600203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5601203945Sweongyo	}
5602203945Sweongyo
5603203945Sweongyo	bwn_wa_agc(mac);
5604203945Sweongyo}
5605203945Sweongyo
5606203945Sweongyostatic void
5607203945Sweongyobwn_wa_grev26789(struct bwn_mac *mac)
5608203945Sweongyo{
5609203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5610203945Sweongyo	int i;
5611203945Sweongyo	static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
5612203945Sweongyo	uint16_t ofdmrev;
5613203945Sweongyo
5614203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5615203945Sweongyo
5616203945Sweongyo	bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
5617203945Sweongyo
5618203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5619203945Sweongyo	if (phy->rev == 1)
5620203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5621203945Sweongyo	else if (phy->rev == 2) {
5622203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5623203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5624203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5625203945Sweongyo	} else {
5626203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5627203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5628203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5629203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5630203945Sweongyo	}
5631203945Sweongyo
5632203945Sweongyo	for (i = 0; i < 64; i++)
5633203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
5634203945Sweongyo
5635203945Sweongyo	/* XXX support PHY-A??? */
5636203945Sweongyo	if (phy->rev == 1)
5637203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5638203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5639203945Sweongyo			    bwn_tab_noise_g1[i]);
5640203945Sweongyo	else
5641203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5642203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5643203945Sweongyo			    bwn_tab_noise_g2[i]);
5644203945Sweongyo
5645203945Sweongyo	/* XXX support PHY-A??? */
5646203945Sweongyo	if (phy->rev >= 6) {
5647203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5648203945Sweongyo		    BWN_PHY_ENCORE_EN)
5649203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5650203945Sweongyo		else
5651203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5652203945Sweongyo	} else
5653203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5654203945Sweongyo
5655203945Sweongyo	for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
5656203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
5657203945Sweongyo		    bwn_tab_sigmasqr2[i]);
5658203945Sweongyo
5659203945Sweongyo	if (phy->rev == 1) {
5660203945Sweongyo		for (i = 0; i < 16; i++)
5661203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
5662203945Sweongyo			    0x0020);
5663203945Sweongyo	} else {
5664203945Sweongyo		for (i = 0; i < 32; i++)
5665203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5666203945Sweongyo	}
5667203945Sweongyo
5668203945Sweongyo	bwn_wa_agc(mac);
5669203945Sweongyo
5670203945Sweongyo	ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
5671203945Sweongyo	if (ofdmrev > 2) {
5672203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5673203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
5674203945Sweongyo		else
5675203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
5676203945Sweongyo	} else {
5677203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
5678203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
5679203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
5680203945Sweongyo	}
5681203945Sweongyo
5682203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
5683203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
5684203945Sweongyo}
5685203945Sweongyo
5686203945Sweongyostatic void
5687203945Sweongyobwn_wa_init(struct bwn_mac *mac)
5688203945Sweongyo{
5689203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5690204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5691203945Sweongyo
5692203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5693203945Sweongyo
5694203945Sweongyo	switch (phy->rev) {
5695203945Sweongyo	case 1:
5696203945Sweongyo		bwn_wa_grev1(mac);
5697203945Sweongyo		break;
5698203945Sweongyo	case 2:
5699203945Sweongyo	case 6:
5700203945Sweongyo	case 7:
5701203945Sweongyo	case 8:
5702203945Sweongyo	case 9:
5703203945Sweongyo		bwn_wa_grev26789(mac);
5704203945Sweongyo		break;
5705203945Sweongyo	default:
5706203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5707203945Sweongyo	}
5708203945Sweongyo
5709204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM ||
5710204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306 ||
5711204922Sweongyo	    siba_get_pci_revid(sc->sc_dev) != 0x17) {
5712203945Sweongyo		if (phy->rev < 2) {
5713203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
5714203945Sweongyo			    0x0002);
5715203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
5716203945Sweongyo			    0x0001);
5717203945Sweongyo		} else {
5718203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
5719203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
5720204922Sweongyo			if ((siba_sprom_get_bf_lo(sc->sc_dev) &
5721204922Sweongyo			     BWN_BFL_EXTLNA) &&
5722203945Sweongyo			    (phy->rev >= 7)) {
5723203945Sweongyo				BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
5724203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5725203945Sweongyo				    0x0020, 0x0001);
5726203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5727203945Sweongyo				    0x0021, 0x0001);
5728203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5729203945Sweongyo				    0x0022, 0x0001);
5730203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5731203945Sweongyo				    0x0023, 0x0000);
5732203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5733203945Sweongyo				    0x0000, 0x0000);
5734203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5735203945Sweongyo				    0x0003, 0x0002);
5736203945Sweongyo			}
5737203945Sweongyo		}
5738203945Sweongyo	}
5739204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) {
5740203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
5741203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
5742203945Sweongyo	}
5743203945Sweongyo
5744203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
5745203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
5746203945Sweongyo}
5747203945Sweongyo
5748203945Sweongyostatic void
5749203945Sweongyobwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5750203945Sweongyo    uint16_t value)
5751203945Sweongyo{
5752203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5753203945Sweongyo	uint16_t addr;
5754203945Sweongyo
5755203945Sweongyo	addr = table + offset;
5756203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5757203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5758203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5759203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5760203945Sweongyo	}
5761203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5762203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5763203945Sweongyo}
5764203945Sweongyo
5765203945Sweongyostatic void
5766203945Sweongyobwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5767203945Sweongyo    uint32_t value)
5768203945Sweongyo{
5769203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5770203945Sweongyo	uint16_t addr;
5771203945Sweongyo
5772203945Sweongyo	addr = table + offset;
5773203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5774203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5775203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5776203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5777203945Sweongyo	}
5778203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5779203945Sweongyo
5780203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5781203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
5782203945Sweongyo}
5783203945Sweongyo
5784203945Sweongyostatic void
5785203945Sweongyobwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5786203945Sweongyo    uint16_t value)
5787203945Sweongyo{
5788203945Sweongyo
5789203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
5790203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
5791203945Sweongyo}
5792203945Sweongyo
5793203945Sweongyostatic void
5794203945Sweongyobwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
5795203945Sweongyo{
5796203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5797204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5798203945Sweongyo	unsigned int i, max_loop;
5799203945Sweongyo	uint16_t value;
5800203945Sweongyo	uint32_t buffer[5] = {
5801203945Sweongyo		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
5802203945Sweongyo	};
5803203945Sweongyo
5804203945Sweongyo	if (ofdm) {
5805203945Sweongyo		max_loop = 0x1e;
5806203945Sweongyo		buffer[0] = 0x000201cc;
5807203945Sweongyo	} else {
5808203945Sweongyo		max_loop = 0xfa;
5809203945Sweongyo		buffer[0] = 0x000b846e;
5810203945Sweongyo	}
5811203945Sweongyo
5812204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
5813203945Sweongyo
5814203945Sweongyo	for (i = 0; i < 5; i++)
5815203945Sweongyo		bwn_ram_write(mac, i * 4, buffer[i]);
5816203945Sweongyo
5817203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0000);
5818203945Sweongyo	BWN_WRITE_2(mac, 0x07c0,
5819204922Sweongyo	    (siba_get_revid(sc->sc_dev) < 11) ? 0x0000 : 0x0100);
5820203945Sweongyo	value = ((phy->type == BWN_PHYTYPE_A) ? 0x41 : 0x40);
5821203945Sweongyo	BWN_WRITE_2(mac, 0x050c, value);
5822203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5823203945Sweongyo		BWN_WRITE_2(mac, 0x0514, 0x1a02);
5824203945Sweongyo	BWN_WRITE_2(mac, 0x0508, 0x0000);
5825203945Sweongyo	BWN_WRITE_2(mac, 0x050a, 0x0000);
5826203945Sweongyo	BWN_WRITE_2(mac, 0x054c, 0x0000);
5827203945Sweongyo	BWN_WRITE_2(mac, 0x056a, 0x0014);
5828203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0826);
5829203945Sweongyo	BWN_WRITE_2(mac, 0x0500, 0x0000);
5830203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5831203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0050);
5832203945Sweongyo	else
5833203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0030);
5834203945Sweongyo
5835203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5836203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0017);
5837203945Sweongyo	for (i = 0x00; i < max_loop; i++) {
5838203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5839203945Sweongyo		if (value & 0x0080)
5840203945Sweongyo			break;
5841203945Sweongyo		DELAY(10);
5842203945Sweongyo	}
5843203945Sweongyo	for (i = 0x00; i < 0x0a; i++) {
5844203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5845203945Sweongyo		if (value & 0x0400)
5846203945Sweongyo			break;
5847203945Sweongyo		DELAY(10);
5848203945Sweongyo	}
5849203945Sweongyo	for (i = 0x00; i < 0x19; i++) {
5850203945Sweongyo		value = BWN_READ_2(mac, 0x0690);
5851203945Sweongyo		if (!(value & 0x0100))
5852203945Sweongyo			break;
5853203945Sweongyo		DELAY(10);
5854203945Sweongyo	}
5855203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5856203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0037);
5857203945Sweongyo}
5858203945Sweongyo
5859203945Sweongyostatic void
5860203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
5861203945Sweongyo{
5862203945Sweongyo	uint32_t macctl;
5863203945Sweongyo
5864203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
5865203945Sweongyo
5866203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
5867203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
5868203945Sweongyo		printf("TODO: need swap\n");
5869203945Sweongyo
5870203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
5871203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
5872203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
5873203945Sweongyo}
5874203945Sweongyo
5875203945Sweongyostatic void
5876203945Sweongyobwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
5877203945Sweongyo{
5878203945Sweongyo	uint16_t value;
5879203945Sweongyo
5880204256Sweongyo	KASSERT(mac->mac_phy.type == BWN_PHYTYPE_G,
5881203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5882203945Sweongyo
5883203945Sweongyo	value = (uint8_t) (ctl->q);
5884203945Sweongyo	value |= ((uint8_t) (ctl->i)) << 8;
5885203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
5886203945Sweongyo}
5887203945Sweongyo
5888203945Sweongyostatic uint16_t
5889203945Sweongyobwn_lo_calcfeed(struct bwn_mac *mac,
5890203945Sweongyo    uint16_t lna, uint16_t pga, uint16_t trsw_rx)
5891203945Sweongyo{
5892203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5893204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5894203945Sweongyo	uint16_t rfover;
5895203945Sweongyo	uint16_t feedthrough;
5896203945Sweongyo
5897203945Sweongyo	if (phy->gmode) {
5898203945Sweongyo		lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
5899203945Sweongyo		pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
5900203945Sweongyo
5901203945Sweongyo		KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
5902203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5903203945Sweongyo		KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
5904203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5905203945Sweongyo
5906203945Sweongyo		trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
5907203945Sweongyo
5908203945Sweongyo		rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
5909204922Sweongyo		if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) &&
5910204922Sweongyo		    phy->rev > 6)
5911203945Sweongyo			rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
5912203945Sweongyo
5913203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
5914203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5915203945Sweongyo		DELAY(10);
5916203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
5917203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5918203945Sweongyo		DELAY(10);
5919203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
5920203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5921203945Sweongyo		DELAY(10);
5922203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
5923203945Sweongyo	} else {
5924203945Sweongyo		pga |= BWN_PHY_PGACTL_UNKNOWN;
5925203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5926203945Sweongyo		DELAY(10);
5927203945Sweongyo		pga |= BWN_PHY_PGACTL_LOWBANDW;
5928203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5929203945Sweongyo		DELAY(10);
5930203945Sweongyo		pga |= BWN_PHY_PGACTL_LPF;
5931203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5932203945Sweongyo	}
5933203945Sweongyo	DELAY(21);
5934203945Sweongyo	feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5935203945Sweongyo
5936203945Sweongyo	return (feedthrough);
5937203945Sweongyo}
5938203945Sweongyo
5939203945Sweongyostatic uint16_t
5940203945Sweongyobwn_lo_txctl_regtable(struct bwn_mac *mac,
5941203945Sweongyo    uint16_t *value, uint16_t *pad_mix_gain)
5942203945Sweongyo{
5943203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5944203945Sweongyo	uint16_t reg, v, padmix;
5945203945Sweongyo
5946203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5947203945Sweongyo		v = 0x30;
5948203945Sweongyo		if (phy->rf_rev <= 5) {
5949203945Sweongyo			reg = 0x43;
5950203945Sweongyo			padmix = 0;
5951203945Sweongyo		} else {
5952203945Sweongyo			reg = 0x52;
5953203945Sweongyo			padmix = 5;
5954203945Sweongyo		}
5955203945Sweongyo	} else {
5956203945Sweongyo		if (phy->rev >= 2 && phy->rf_rev == 8) {
5957203945Sweongyo			reg = 0x43;
5958203945Sweongyo			v = 0x10;
5959203945Sweongyo			padmix = 2;
5960203945Sweongyo		} else {
5961203945Sweongyo			reg = 0x52;
5962203945Sweongyo			v = 0x30;
5963203945Sweongyo			padmix = 5;
5964203945Sweongyo		}
5965203945Sweongyo	}
5966203945Sweongyo	if (value)
5967203945Sweongyo		*value = v;
5968203945Sweongyo	if (pad_mix_gain)
5969203945Sweongyo		*pad_mix_gain = padmix;
5970203945Sweongyo
5971203945Sweongyo	return (reg);
5972203945Sweongyo}
5973203945Sweongyo
5974203945Sweongyostatic void
5975203945Sweongyobwn_lo_measure_txctl_values(struct bwn_mac *mac)
5976203945Sweongyo{
5977203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5978203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5979203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
5980203945Sweongyo	uint16_t reg, mask;
5981203945Sweongyo	uint16_t trsw_rx, pga;
5982203945Sweongyo	uint16_t rf_pctl_reg;
5983203945Sweongyo
5984203945Sweongyo	static const uint8_t tx_bias_values[] = {
5985203945Sweongyo		0x09, 0x08, 0x0a, 0x01, 0x00,
5986203945Sweongyo		0x02, 0x05, 0x04, 0x06,
5987203945Sweongyo	};
5988203945Sweongyo	static const uint8_t tx_magn_values[] = {
5989203945Sweongyo		0x70, 0x40,
5990203945Sweongyo	};
5991203945Sweongyo
5992203945Sweongyo	if (!BWN_HAS_LOOPBACK(phy)) {
5993203945Sweongyo		rf_pctl_reg = 6;
5994203945Sweongyo		trsw_rx = 2;
5995203945Sweongyo		pga = 0;
5996203945Sweongyo	} else {
5997203945Sweongyo		int lb_gain;
5998203945Sweongyo
5999203945Sweongyo		trsw_rx = 0;
6000203945Sweongyo		lb_gain = pg->pg_max_lb_gain / 2;
6001203945Sweongyo		if (lb_gain > 10) {
6002203945Sweongyo			rf_pctl_reg = 0;
6003203945Sweongyo			pga = abs(10 - lb_gain) / 6;
6004203945Sweongyo			pga = MIN(MAX(pga, 0), 15);
6005203945Sweongyo		} else {
6006203945Sweongyo			int cmp_val;
6007203945Sweongyo			int tmp;
6008203945Sweongyo
6009203945Sweongyo			pga = 0;
6010203945Sweongyo			cmp_val = 0x24;
6011203945Sweongyo			if ((phy->rev >= 2) &&
6012203945Sweongyo			    (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
6013203945Sweongyo				cmp_val = 0x3c;
6014203945Sweongyo			tmp = lb_gain;
6015203945Sweongyo			if ((10 - lb_gain) < cmp_val)
6016203945Sweongyo				tmp = (10 - lb_gain);
6017203945Sweongyo			if (tmp < 0)
6018203945Sweongyo				tmp += 6;
6019203945Sweongyo			else
6020203945Sweongyo				tmp += 3;
6021203945Sweongyo			cmp_val /= 4;
6022203945Sweongyo			tmp /= 4;
6023203945Sweongyo			if (tmp >= cmp_val)
6024203945Sweongyo				rf_pctl_reg = cmp_val;
6025203945Sweongyo			else
6026203945Sweongyo				rf_pctl_reg = tmp;
6027203945Sweongyo		}
6028203945Sweongyo	}
6029203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
6030203945Sweongyo	bwn_phy_g_set_bbatt(mac, 2);
6031203945Sweongyo
6032203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
6033203945Sweongyo	mask = ~mask;
6034203945Sweongyo	BWN_RF_MASK(mac, reg, mask);
6035203945Sweongyo
6036203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
6037203945Sweongyo		int i, j;
6038203945Sweongyo		int feedthrough;
6039203945Sweongyo		int min_feedth = 0xffff;
6040203945Sweongyo		uint8_t tx_magn, tx_bias;
6041203945Sweongyo
6042203945Sweongyo		for (i = 0; i < N(tx_magn_values); i++) {
6043203945Sweongyo			tx_magn = tx_magn_values[i];
6044203945Sweongyo			BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
6045203945Sweongyo			for (j = 0; j < N(tx_bias_values); j++) {
6046203945Sweongyo				tx_bias = tx_bias_values[j];
6047203945Sweongyo				BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
6048203945Sweongyo				feedthrough = bwn_lo_calcfeed(mac, 0, pga,
6049203945Sweongyo				    trsw_rx);
6050203945Sweongyo				if (feedthrough < min_feedth) {
6051203945Sweongyo					lo->tx_bias = tx_bias;
6052203945Sweongyo					lo->tx_magn = tx_magn;
6053203945Sweongyo					min_feedth = feedthrough;
6054203945Sweongyo				}
6055203945Sweongyo				if (lo->tx_bias == 0)
6056203945Sweongyo					break;
6057203945Sweongyo			}
6058203945Sweongyo			BWN_RF_WRITE(mac, 0x52,
6059203945Sweongyo					  (BWN_RF_READ(mac, 0x52)
6060203945Sweongyo					   & 0xff00) | lo->tx_bias | lo->
6061203945Sweongyo					  tx_magn);
6062203945Sweongyo		}
6063203945Sweongyo	} else {
6064203945Sweongyo		lo->tx_magn = 0;
6065203945Sweongyo		lo->tx_bias = 0;
6066203945Sweongyo		BWN_RF_MASK(mac, 0x52, 0xfff0);
6067203945Sweongyo	}
6068203945Sweongyo
6069203945Sweongyo	BWN_GETTIME(lo->txctl_measured_time);
6070203945Sweongyo}
6071203945Sweongyo
6072203945Sweongyostatic void
6073203945Sweongyobwn_lo_get_powervector(struct bwn_mac *mac)
6074203945Sweongyo{
6075203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6076203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6077203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6078203945Sweongyo	int i;
6079203945Sweongyo	uint64_t tmp;
6080203945Sweongyo	uint64_t power_vector = 0;
6081203945Sweongyo
6082203945Sweongyo	for (i = 0; i < 8; i += 2) {
6083203945Sweongyo		tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
6084203945Sweongyo		power_vector |= (tmp << (i * 8));
6085203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
6086203945Sweongyo	}
6087203945Sweongyo	if (power_vector)
6088203945Sweongyo		lo->power_vector = power_vector;
6089203945Sweongyo
6090203945Sweongyo	BWN_GETTIME(lo->pwr_vec_read_time);
6091203945Sweongyo}
6092203945Sweongyo
6093203945Sweongyostatic void
6094203945Sweongyobwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
6095203945Sweongyo    int use_trsw_rx)
6096203945Sweongyo{
6097203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6098203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6099203945Sweongyo	uint16_t tmp;
6100203945Sweongyo
6101203945Sweongyo	if (max_rx_gain < 0)
6102203945Sweongyo		max_rx_gain = 0;
6103203945Sweongyo
6104203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
6105203945Sweongyo		int trsw_rx = 0;
6106203945Sweongyo		int trsw_rx_gain;
6107203945Sweongyo
6108203945Sweongyo		if (use_trsw_rx) {
6109203945Sweongyo			trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
6110203945Sweongyo			if (max_rx_gain >= trsw_rx_gain) {
6111203945Sweongyo				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
6112203945Sweongyo				trsw_rx = 0x20;
6113203945Sweongyo			}
6114203945Sweongyo		} else
6115203945Sweongyo			trsw_rx_gain = max_rx_gain;
6116203945Sweongyo		if (trsw_rx_gain < 9) {
6117203945Sweongyo			pg->pg_lna_lod_gain = 0;
6118203945Sweongyo		} else {
6119203945Sweongyo			pg->pg_lna_lod_gain = 1;
6120203945Sweongyo			trsw_rx_gain -= 8;
6121203945Sweongyo		}
6122203945Sweongyo		trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
6123203945Sweongyo		pg->pg_pga_gain = trsw_rx_gain / 3;
6124203945Sweongyo		if (pg->pg_pga_gain >= 5) {
6125203945Sweongyo			pg->pg_pga_gain -= 5;
6126203945Sweongyo			pg->pg_lna_gain = 2;
6127203945Sweongyo		} else
6128203945Sweongyo			pg->pg_lna_gain = 0;
6129203945Sweongyo	} else {
6130203945Sweongyo		pg->pg_lna_gain = 0;
6131203945Sweongyo		pg->pg_trsw_rx_gain = 0x20;
6132203945Sweongyo		if (max_rx_gain >= 0x14) {
6133203945Sweongyo			pg->pg_lna_lod_gain = 1;
6134203945Sweongyo			pg->pg_pga_gain = 2;
6135203945Sweongyo		} else if (max_rx_gain >= 0x12) {
6136203945Sweongyo			pg->pg_lna_lod_gain = 1;
6137203945Sweongyo			pg->pg_pga_gain = 1;
6138203945Sweongyo		} else if (max_rx_gain >= 0xf) {
6139203945Sweongyo			pg->pg_lna_lod_gain = 1;
6140203945Sweongyo			pg->pg_pga_gain = 0;
6141203945Sweongyo		} else {
6142203945Sweongyo			pg->pg_lna_lod_gain = 0;
6143203945Sweongyo			pg->pg_pga_gain = 0;
6144203945Sweongyo		}
6145203945Sweongyo	}
6146203945Sweongyo
6147203945Sweongyo	tmp = BWN_RF_READ(mac, 0x7a);
6148203945Sweongyo	if (pg->pg_lna_lod_gain == 0)
6149203945Sweongyo		tmp &= ~0x0008;
6150203945Sweongyo	else
6151203945Sweongyo		tmp |= 0x0008;
6152203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, tmp);
6153203945Sweongyo}
6154203945Sweongyo
6155203945Sweongyostatic void
6156203945Sweongyobwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6157203945Sweongyo{
6158203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6159203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6160204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6161203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6162203945Sweongyo	struct timespec ts;
6163203945Sweongyo	uint16_t tmp;
6164203945Sweongyo
6165203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6166203945Sweongyo		sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
6167203945Sweongyo		sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
6168203945Sweongyo		sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6169203945Sweongyo		sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
6170203945Sweongyo		sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
6171203945Sweongyo
6172203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
6173203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
6174203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
6175203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
6176203945Sweongyo	}
6177203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6178203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
6179203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
6180203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
6181203945Sweongyo	}
6182203945Sweongyo	if (phy->rev >= 2) {
6183203945Sweongyo		sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
6184203945Sweongyo		sav->phy_analogoverval =
6185203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
6186203945Sweongyo		sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
6187203945Sweongyo		sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
6188203945Sweongyo		sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
6189203945Sweongyo		sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
6190203945Sweongyo		sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
6191203945Sweongyo
6192203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
6193203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
6194203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
6195203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
6196203945Sweongyo		if (phy->type == BWN_PHYTYPE_G) {
6197203945Sweongyo			if ((phy->rev >= 7) &&
6198204922Sweongyo			    (siba_sprom_get_bf_lo(sc->sc_dev) &
6199204922Sweongyo			     BWN_BFL_EXTLNA)) {
6200203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
6201203945Sweongyo			} else {
6202203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
6203203945Sweongyo			}
6204203945Sweongyo		} else {
6205203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
6206203945Sweongyo		}
6207203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
6208203945Sweongyo	}
6209203945Sweongyo	sav->reg0 = BWN_READ_2(mac, 0x3f4);
6210203945Sweongyo	sav->reg1 = BWN_READ_2(mac, 0x3e2);
6211203945Sweongyo	sav->rf0 = BWN_RF_READ(mac, 0x43);
6212203945Sweongyo	sav->rf1 = BWN_RF_READ(mac, 0x7a);
6213203945Sweongyo	sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
6214203945Sweongyo	sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
6215203945Sweongyo	sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
6216203945Sweongyo	sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6217203945Sweongyo
6218203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6219203945Sweongyo		sav->rf2 = BWN_RF_READ(mac, 0x52);
6220203945Sweongyo		sav->rf2 &= 0x00f0;
6221203945Sweongyo	}
6222203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6223203945Sweongyo		sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
6224203945Sweongyo		sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
6225203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
6226203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
6227203945Sweongyo	} else {
6228203945Sweongyo		BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
6229203945Sweongyo			    | 0x8000);
6230203945Sweongyo	}
6231203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
6232203945Sweongyo		    & 0xf000);
6233203945Sweongyo
6234203945Sweongyo	tmp =
6235203945Sweongyo	    (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
6236203945Sweongyo	BWN_PHY_WRITE(mac, tmp, 0x007f);
6237203945Sweongyo
6238203945Sweongyo	tmp = sav->phy_syncctl;
6239203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
6240203945Sweongyo	tmp = sav->rf1;
6241203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
6242203945Sweongyo
6243203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
6244203945Sweongyo	if (phy->type == BWN_PHYTYPE_G ||
6245203945Sweongyo	    (phy->type == BWN_PHYTYPE_B &&
6246203945Sweongyo	     phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
6247203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
6248203945Sweongyo	} else
6249203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
6250203945Sweongyo	if (phy->rev >= 2)
6251203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
6252203945Sweongyo	bwn_phy_g_switch_chan(mac, 6, 0);
6253203945Sweongyo	BWN_RF_READ(mac, 0x51);
6254203945Sweongyo	if (phy->type == BWN_PHYTYPE_G)
6255203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
6256203945Sweongyo
6257203945Sweongyo	nanouptime(&ts);
6258203945Sweongyo	if (time_before(lo->txctl_measured_time,
6259203945Sweongyo	    (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
6260203945Sweongyo		bwn_lo_measure_txctl_values(mac);
6261203945Sweongyo
6262203945Sweongyo	if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
6263203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
6264203945Sweongyo	else {
6265203945Sweongyo		if (phy->type == BWN_PHYTYPE_B)
6266203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6267203945Sweongyo		else
6268203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
6269203945Sweongyo	}
6270203945Sweongyo}
6271203945Sweongyo
6272203945Sweongyostatic void
6273203945Sweongyobwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6274203945Sweongyo{
6275203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6276203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6277203945Sweongyo	uint16_t tmp;
6278203945Sweongyo
6279203945Sweongyo	if (phy->rev >= 2) {
6280203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6281203945Sweongyo		tmp = (pg->pg_pga_gain << 8);
6282203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
6283203945Sweongyo		DELAY(5);
6284203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
6285203945Sweongyo		DELAY(2);
6286203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
6287203945Sweongyo	} else {
6288203945Sweongyo		tmp = (pg->pg_pga_gain | 0xefa0);
6289203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
6290203945Sweongyo	}
6291203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
6292203945Sweongyo		if (phy->rev >= 3)
6293203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
6294203945Sweongyo		else
6295203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6296203945Sweongyo		if (phy->rev >= 2)
6297203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
6298203945Sweongyo		else
6299203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
6300203945Sweongyo	}
6301203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, sav->reg0);
6302203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
6303203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
6304203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
6305203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
6306203945Sweongyo	BWN_RF_WRITE(mac, 0x43, sav->rf0);
6307203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, sav->rf1);
6308203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6309203945Sweongyo		tmp = sav->rf2;
6310203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
6311203945Sweongyo	}
6312203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, sav->reg1);
6313203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6314203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
6315203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
6316203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
6317203945Sweongyo	}
6318203945Sweongyo	if (phy->rev >= 2) {
6319203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
6320203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
6321203945Sweongyo			      sav->phy_analogoverval);
6322203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
6323203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
6324203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
6325203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
6326203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
6327203945Sweongyo	}
6328203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6329203945Sweongyo		tmp = (sav->phy_lomask & 0xbfff);
6330203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
6331203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
6332203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
6333203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
6334203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
6335203945Sweongyo	}
6336203945Sweongyo	bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
6337203945Sweongyo}
6338203945Sweongyo
6339203945Sweongyostatic int
6340203945Sweongyobwn_lo_probe_loctl(struct bwn_mac *mac,
6341203945Sweongyo    struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
6342203945Sweongyo{
6343203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6344203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6345203945Sweongyo	struct bwn_loctl orig, test;
6346203945Sweongyo	struct bwn_loctl prev = { -100, -100 };
6347203945Sweongyo	static const struct bwn_loctl modifiers[] = {
6348203945Sweongyo		{  1,  1,}, {  1,  0,}, {  1, -1,}, {  0, -1,},
6349203945Sweongyo		{ -1, -1,}, { -1,  0,}, { -1,  1,}, {  0,  1,}
6350203945Sweongyo	};
6351203945Sweongyo	int begin, end, lower = 0, i;
6352203945Sweongyo	uint16_t feedth;
6353203945Sweongyo
6354203945Sweongyo	if (d->curstate == 0) {
6355203945Sweongyo		begin = 1;
6356203945Sweongyo		end = 8;
6357203945Sweongyo	} else if (d->curstate % 2 == 0) {
6358203945Sweongyo		begin = d->curstate - 1;
6359203945Sweongyo		end = d->curstate + 1;
6360203945Sweongyo	} else {
6361203945Sweongyo		begin = d->curstate - 2;
6362203945Sweongyo		end = d->curstate + 2;
6363203945Sweongyo	}
6364203945Sweongyo	if (begin < 1)
6365203945Sweongyo		begin += 8;
6366203945Sweongyo	if (end > 8)
6367203945Sweongyo		end -= 8;
6368203945Sweongyo
6369203945Sweongyo	memcpy(&orig, probe, sizeof(struct bwn_loctl));
6370203945Sweongyo	i = begin;
6371203945Sweongyo	d->curstate = i;
6372203945Sweongyo	while (1) {
6373203945Sweongyo		KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
6374203945Sweongyo		memcpy(&test, &orig, sizeof(struct bwn_loctl));
6375203945Sweongyo		test.i += modifiers[i - 1].i * d->multipler;
6376203945Sweongyo		test.q += modifiers[i - 1].q * d->multipler;
6377203945Sweongyo		if ((test.i != prev.i || test.q != prev.q) &&
6378203945Sweongyo		    (abs(test.i) <= 16 && abs(test.q) <= 16)) {
6379203945Sweongyo			bwn_lo_write(mac, &test);
6380203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6381203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6382203945Sweongyo			if (feedth < d->feedth) {
6383203945Sweongyo				memcpy(probe, &test,
6384203945Sweongyo				    sizeof(struct bwn_loctl));
6385203945Sweongyo				lower = 1;
6386203945Sweongyo				d->feedth = feedth;
6387203945Sweongyo				if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
6388203945Sweongyo					break;
6389203945Sweongyo			}
6390203945Sweongyo		}
6391203945Sweongyo		memcpy(&prev, &test, sizeof(prev));
6392203945Sweongyo		if (i == end)
6393203945Sweongyo			break;
6394203945Sweongyo		if (i == 8)
6395203945Sweongyo			i = 1;
6396203945Sweongyo		else
6397203945Sweongyo			i++;
6398203945Sweongyo		d->curstate = i;
6399203945Sweongyo	}
6400203945Sweongyo
6401203945Sweongyo	return (lower);
6402203945Sweongyo}
6403203945Sweongyo
6404203945Sweongyostatic void
6405203945Sweongyobwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
6406203945Sweongyo{
6407203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6408203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6409203945Sweongyo	struct bwn_lo_g_sm d;
6410203945Sweongyo	struct bwn_loctl probe;
6411203945Sweongyo	int lower, repeat, cnt = 0;
6412203945Sweongyo	uint16_t feedth;
6413203945Sweongyo
6414203945Sweongyo	d.nmeasure = 0;
6415203945Sweongyo	d.multipler = 1;
6416203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6417203945Sweongyo		d.multipler = 3;
6418203945Sweongyo
6419203945Sweongyo	memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
6420203945Sweongyo	repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
6421203945Sweongyo
6422203945Sweongyo	do {
6423203945Sweongyo		bwn_lo_write(mac, &d.loctl);
6424203945Sweongyo		feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6425203945Sweongyo		    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6426203945Sweongyo		if (feedth < 0x258) {
6427203945Sweongyo			if (feedth >= 0x12c)
6428203945Sweongyo				*rxgain += 6;
6429203945Sweongyo			else
6430203945Sweongyo				*rxgain += 3;
6431203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6432203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6433203945Sweongyo		}
6434203945Sweongyo		d.feedth = feedth;
6435203945Sweongyo		d.curstate = 0;
6436203945Sweongyo		do {
6437203945Sweongyo			KASSERT(d.curstate >= 0 && d.curstate <= 8,
6438203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
6439203945Sweongyo			memcpy(&probe, &d.loctl,
6440203945Sweongyo			       sizeof(struct bwn_loctl));
6441203945Sweongyo			lower = bwn_lo_probe_loctl(mac, &probe, &d);
6442203945Sweongyo			if (!lower)
6443203945Sweongyo				break;
6444203945Sweongyo			if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
6445203945Sweongyo				break;
6446203945Sweongyo			memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
6447203945Sweongyo			d.nmeasure++;
6448203945Sweongyo		} while (d.nmeasure < 24);
6449203945Sweongyo		memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
6450203945Sweongyo
6451203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
6452203945Sweongyo			if (d.feedth > 0x1194)
6453203945Sweongyo				*rxgain -= 6;
6454203945Sweongyo			else if (d.feedth < 0x5dc)
6455203945Sweongyo				*rxgain += 3;
6456203945Sweongyo			if (cnt == 0) {
6457203945Sweongyo				if (d.feedth <= 0x5dc) {
6458203945Sweongyo					d.multipler = 1;
6459203945Sweongyo					cnt++;
6460203945Sweongyo				} else
6461203945Sweongyo					d.multipler = 2;
6462203945Sweongyo			} else if (cnt == 2)
6463203945Sweongyo				d.multipler = 1;
6464203945Sweongyo		}
6465203945Sweongyo		bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
6466203945Sweongyo	} while (++cnt < repeat);
6467203945Sweongyo}
6468203945Sweongyo
6469203945Sweongyostatic struct bwn_lo_calib *
6470203945Sweongyobwn_lo_calibset(struct bwn_mac *mac,
6471203945Sweongyo    const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
6472203945Sweongyo{
6473203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6474203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6475203945Sweongyo	struct bwn_loctl loctl = { 0, 0 };
6476203945Sweongyo	struct bwn_lo_calib *cal;
6477204242Simp	struct bwn_lo_g_value sval = { 0 };
6478203945Sweongyo	int rxgain;
6479203945Sweongyo	uint16_t pad, reg, value;
6480203945Sweongyo
6481203945Sweongyo	sval.old_channel = phy->chan;
6482203945Sweongyo	bwn_mac_suspend(mac);
6483203945Sweongyo	bwn_lo_save(mac, &sval);
6484203945Sweongyo
6485203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &value, &pad);
6486203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
6487203945Sweongyo	BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
6488203945Sweongyo
6489203945Sweongyo	rxgain = (rfatt->att * 2) + (bbatt->att / 2);
6490203945Sweongyo	if (rfatt->padmix)
6491203945Sweongyo		rxgain -= pad;
6492203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6493203945Sweongyo		rxgain += pg->pg_max_lb_gain;
6494203945Sweongyo	bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
6495203945Sweongyo	bwn_phy_g_set_bbatt(mac, bbatt->att);
6496203945Sweongyo	bwn_lo_probe_sm(mac, &loctl, &rxgain);
6497203945Sweongyo
6498203945Sweongyo	bwn_lo_restore(mac, &sval);
6499203945Sweongyo	bwn_mac_enable(mac);
6500203945Sweongyo
6501203945Sweongyo	cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
6502203945Sweongyo	if (!cal) {
6503203945Sweongyo		device_printf(mac->mac_sc->sc_dev, "out of memory\n");
6504203945Sweongyo		return (NULL);
6505203945Sweongyo	}
6506203945Sweongyo	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
6507203945Sweongyo	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
6508203945Sweongyo	memcpy(&cal->ctl, &loctl, sizeof(loctl));
6509203945Sweongyo
6510203945Sweongyo	BWN_GETTIME(cal->calib_time);
6511203945Sweongyo
6512203945Sweongyo	return (cal);
6513203945Sweongyo}
6514203945Sweongyo
6515203945Sweongyostatic struct bwn_lo_calib *
6516203945Sweongyobwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
6517203945Sweongyo    const struct bwn_rfatt *rfatt)
6518203945Sweongyo{
6519203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
6520203945Sweongyo	struct bwn_lo_calib *c;
6521203945Sweongyo
6522203945Sweongyo	TAILQ_FOREACH(c, &lo->calib_list, list) {
6523203945Sweongyo		if (!BWN_BBATTCMP(&c->bbatt, bbatt))
6524203945Sweongyo			continue;
6525203945Sweongyo		if (!BWN_RFATTCMP(&c->rfatt, rfatt))
6526203945Sweongyo			continue;
6527203945Sweongyo		return (c);
6528203945Sweongyo	}
6529203945Sweongyo
6530203945Sweongyo	c = bwn_lo_calibset(mac, bbatt, rfatt);
6531203945Sweongyo	if (!c)
6532203945Sweongyo		return (NULL);
6533203945Sweongyo	TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
6534203945Sweongyo
6535203945Sweongyo	return (c);
6536203945Sweongyo}
6537203945Sweongyo
6538203945Sweongyostatic void
6539203945Sweongyobwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
6540203945Sweongyo{
6541203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6542203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6543203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6544203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6545203945Sweongyo	const struct bwn_rfatt *rfatt;
6546203945Sweongyo	const struct bwn_bbatt *bbatt;
6547203945Sweongyo	uint64_t pvector;
6548203945Sweongyo	int i;
6549203945Sweongyo	int rf_offset, bb_offset;
6550203945Sweongyo	uint8_t changed = 0;
6551203945Sweongyo
6552203945Sweongyo	KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
6553203945Sweongyo	KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
6554203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6555203945Sweongyo
6556203945Sweongyo	pvector = lo->power_vector;
6557203945Sweongyo	if (!update && !pvector)
6558203945Sweongyo		return;
6559203945Sweongyo
6560203945Sweongyo	bwn_mac_suspend(mac);
6561203945Sweongyo
6562203945Sweongyo	for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
6563203945Sweongyo		struct bwn_lo_calib *cal;
6564203945Sweongyo		int idx;
6565203945Sweongyo		uint16_t val;
6566203945Sweongyo
6567203945Sweongyo		if (!update && !(pvector & (((uint64_t)1ULL) << i)))
6568203945Sweongyo			continue;
6569203945Sweongyo		bb_offset = i / lo->rfatt.len;
6570203945Sweongyo		rf_offset = i % lo->rfatt.len;
6571203945Sweongyo		bbatt = &(lo->bbatt.array[bb_offset]);
6572203945Sweongyo		rfatt = &(lo->rfatt.array[rf_offset]);
6573203945Sweongyo
6574203945Sweongyo		cal = bwn_lo_calibset(mac, bbatt, rfatt);
6575203945Sweongyo		if (!cal) {
6576203945Sweongyo			device_printf(sc->sc_dev, "LO: Could not "
6577203945Sweongyo			    "calibrate DC table entry\n");
6578203945Sweongyo			continue;
6579203945Sweongyo		}
6580203945Sweongyo		val = (uint8_t)(cal->ctl.q);
6581203945Sweongyo		val |= ((uint8_t)(cal->ctl.i)) << 4;
6582203945Sweongyo		free(cal, M_DEVBUF);
6583203945Sweongyo
6584203945Sweongyo		idx = i / 2;
6585203945Sweongyo		if (i % 2)
6586203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
6587203945Sweongyo			    | ((val & 0x00ff) << 8);
6588203945Sweongyo		else
6589203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
6590203945Sweongyo			    | (val & 0x00ff);
6591203945Sweongyo		changed = 1;
6592203945Sweongyo	}
6593203945Sweongyo	if (changed) {
6594203945Sweongyo		for (i = 0; i < BWN_DC_LT_SIZE; i++)
6595203945Sweongyo			BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
6596203945Sweongyo	}
6597203945Sweongyo	bwn_mac_enable(mac);
6598203945Sweongyo}
6599203945Sweongyo
6600203945Sweongyostatic void
6601203945Sweongyobwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
6602203945Sweongyo{
6603203945Sweongyo
6604203945Sweongyo	if (!rf->padmix)
6605203945Sweongyo		return;
6606203945Sweongyo	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
6607203945Sweongyo		rf->att = 4;
6608203945Sweongyo}
6609203945Sweongyo
6610203945Sweongyostatic void
6611203945Sweongyobwn_lo_g_adjust(struct bwn_mac *mac)
6612203945Sweongyo{
6613203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
6614203945Sweongyo	struct bwn_lo_calib *cal;
6615203945Sweongyo	struct bwn_rfatt rf;
6616203945Sweongyo
6617203945Sweongyo	memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
6618203945Sweongyo	bwn_lo_fixup_rfatt(&rf);
6619203945Sweongyo
6620203945Sweongyo	cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
6621203945Sweongyo	if (!cal)
6622203945Sweongyo		return;
6623203945Sweongyo	bwn_lo_write(mac, &cal->ctl);
6624203945Sweongyo}
6625203945Sweongyo
6626203945Sweongyostatic void
6627203945Sweongyobwn_lo_g_init(struct bwn_mac *mac)
6628203945Sweongyo{
6629203945Sweongyo
6630203945Sweongyo	if (!bwn_has_hwpctl(mac))
6631203945Sweongyo		return;
6632203945Sweongyo
6633203945Sweongyo	bwn_lo_get_powervector(mac);
6634203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
6635203945Sweongyo}
6636203945Sweongyo
6637203945Sweongyostatic void
6638203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
6639203945Sweongyo{
6640203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6641203945Sweongyo	int i;
6642203945Sweongyo	uint32_t tmp;
6643203945Sweongyo
6644203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6645203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6646203945Sweongyo
6647203945Sweongyo	if (mac->mac_suspended == 0) {
6648203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
6649203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6650203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
6651203945Sweongyo			    & ~BWN_MACCTL_ON);
6652203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6653203945Sweongyo		for (i = 35; i; i--) {
6654203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6655203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6656203945Sweongyo				goto out;
6657203945Sweongyo			DELAY(10);
6658203945Sweongyo		}
6659203945Sweongyo		for (i = 40; i; i--) {
6660203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6661203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6662203945Sweongyo				goto out;
6663203945Sweongyo			DELAY(1000);
6664203945Sweongyo		}
6665203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
6666203945Sweongyo	}
6667203945Sweongyoout:
6668203945Sweongyo	mac->mac_suspended++;
6669203945Sweongyo}
6670203945Sweongyo
6671203945Sweongyostatic void
6672203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
6673203945Sweongyo{
6674203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6675203945Sweongyo	uint16_t state;
6676203945Sweongyo
6677203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
6678203945Sweongyo	    BWN_SHARED_UCODESTAT);
6679203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
6680203945Sweongyo	    state != BWN_SHARED_UCODESTAT_SLEEP)
6681203945Sweongyo		device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
6682203945Sweongyo
6683203945Sweongyo	mac->mac_suspended--;
6684203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6685203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6686203945Sweongyo	if (mac->mac_suspended == 0) {
6687203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6688203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
6689203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
6690203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6691203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
6692203945Sweongyo		bwn_psctl(mac, 0);
6693203945Sweongyo	}
6694203945Sweongyo}
6695203945Sweongyo
6696203945Sweongyostatic void
6697203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
6698203945Sweongyo{
6699204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6700203945Sweongyo	int i;
6701203945Sweongyo	uint16_t ucstat;
6702203945Sweongyo
6703203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
6704203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6705203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
6706203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6707203945Sweongyo
6708203945Sweongyo	/* XXX forcibly awake and hwps-off */
6709203945Sweongyo
6710203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
6711203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
6712203945Sweongyo	    ~BWN_MACCTL_HWPS);
6713203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
6714204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
6715203945Sweongyo		for (i = 0; i < 100; i++) {
6716203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
6717203945Sweongyo			    BWN_SHARED_UCODESTAT);
6718203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
6719203945Sweongyo				break;
6720203945Sweongyo			DELAY(10);
6721203945Sweongyo		}
6722203945Sweongyo	}
6723203945Sweongyo}
6724203945Sweongyo
6725203945Sweongyostatic int16_t
6726203945Sweongyobwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
6727203945Sweongyo{
6728203945Sweongyo
6729203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
6730203945Sweongyo	return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
6731203945Sweongyo}
6732203945Sweongyo
6733203945Sweongyostatic void
6734203945Sweongyobwn_nrssi_threshold(struct bwn_mac *mac)
6735203945Sweongyo{
6736203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6737203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6738204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6739203945Sweongyo	int32_t a, b;
6740203945Sweongyo	int16_t tmp16;
6741203945Sweongyo	uint16_t tmpu16;
6742203945Sweongyo
6743203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
6744203945Sweongyo
6745204922Sweongyo	if (phy->gmode && (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
6746203945Sweongyo		if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
6747203945Sweongyo			a = 0x13;
6748203945Sweongyo			b = 0x12;
6749203945Sweongyo		} else {
6750203945Sweongyo			a = 0xe;
6751203945Sweongyo			b = 0x11;
6752203945Sweongyo		}
6753203945Sweongyo
6754203945Sweongyo		a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6755203945Sweongyo		a += (pg->pg_nrssi[0] << 6);
6756203945Sweongyo		a += (a < 32) ? 31 : 32;
6757203945Sweongyo		a = a >> 6;
6758203945Sweongyo		a = MIN(MAX(a, -31), 31);
6759203945Sweongyo
6760203945Sweongyo		b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6761203945Sweongyo		b += (pg->pg_nrssi[0] << 6);
6762203945Sweongyo		if (b < 32)
6763203945Sweongyo			b += 31;
6764203945Sweongyo		else
6765203945Sweongyo			b += 32;
6766203945Sweongyo		b = b >> 6;
6767203945Sweongyo		b = MIN(MAX(b, -31), 31);
6768203945Sweongyo
6769203945Sweongyo		tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
6770203945Sweongyo		tmpu16 |= ((uint32_t)b & 0x0000003f);
6771203945Sweongyo		tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
6772203945Sweongyo		BWN_PHY_WRITE(mac, 0x048a, tmpu16);
6773203945Sweongyo		return;
6774203945Sweongyo	}
6775203945Sweongyo
6776203945Sweongyo	tmp16 = bwn_nrssi_read(mac, 0x20);
6777203945Sweongyo	if (tmp16 >= 0x20)
6778203945Sweongyo		tmp16 -= 0x40;
6779203945Sweongyo	BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
6780203945Sweongyo}
6781203945Sweongyo
6782203945Sweongyostatic void
6783203945Sweongyobwn_nrssi_slope_11g(struct bwn_mac *mac)
6784203945Sweongyo{
6785203945Sweongyo#define	SAVE_RF_MAX		3
6786203945Sweongyo#define	SAVE_PHY_COMM_MAX	4
6787203945Sweongyo#define	SAVE_PHY3_MAX		8
6788203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6789203945Sweongyo		{ 0x7a, 0x52, 0x43 };
6790203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
6791203945Sweongyo		{ 0x15, 0x5a, 0x59, 0x58 };
6792203945Sweongyo	static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
6793203945Sweongyo		0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
6794203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6795203945Sweongyo	};
6796203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6797203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6798203945Sweongyo	int32_t i, tmp32, phy3_idx = 0;
6799203945Sweongyo	uint16_t delta, tmp;
6800203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6801203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6802203945Sweongyo	uint16_t save_phy3[SAVE_PHY3_MAX];
6803203945Sweongyo	uint16_t ant_div, phy0, chan_ex;
6804203945Sweongyo	int16_t nrssi0, nrssi1;
6805203945Sweongyo
6806203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
6807203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6808203945Sweongyo
6809203945Sweongyo	if (phy->rf_rev >= 9)
6810203945Sweongyo		return;
6811203945Sweongyo	if (phy->rf_rev == 8)
6812203945Sweongyo		bwn_nrssi_offset(mac);
6813203945Sweongyo
6814203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
6815203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, 0xfffc);
6816203945Sweongyo
6817203945Sweongyo	/*
6818203945Sweongyo	 * Save RF/PHY registers for later restoration
6819203945Sweongyo	 */
6820203945Sweongyo	ant_div = BWN_READ_2(mac, 0x03e2);
6821203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
6822203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6823203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6824203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6825203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6826203945Sweongyo
6827203945Sweongyo	phy0 = BWN_READ_2(mac, BWN_PHY0);
6828203945Sweongyo	chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
6829203945Sweongyo	if (phy->rev >= 3) {
6830203945Sweongyo		for (i = 0; i < SAVE_PHY3_MAX; ++i)
6831203945Sweongyo			save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
6832203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6833203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
6834203945Sweongyo		switch (phy->rev) {
6835203945Sweongyo		case 4:
6836203945Sweongyo		case 6:
6837203945Sweongyo		case 7:
6838203945Sweongyo			BWN_PHY_SET(mac, 0x0478, 0x0100);
6839203945Sweongyo			BWN_PHY_SET(mac, 0x0801, 0x0040);
6840203945Sweongyo			break;
6841203945Sweongyo		case 3:
6842203945Sweongyo		case 5:
6843203945Sweongyo			BWN_PHY_MASK(mac, 0x0801, 0xffbf);
6844203945Sweongyo			break;
6845203945Sweongyo		}
6846203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
6847203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
6848203945Sweongyo	}
6849203945Sweongyo	/*
6850203945Sweongyo	 * Calculate nrssi0
6851203945Sweongyo	 */
6852203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
6853203945Sweongyo	bwn_set_all_gains(mac, 0, 8, 0);
6854203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x00f7);
6855203945Sweongyo	if (phy->rev >= 2) {
6856203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
6857203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
6858203945Sweongyo	}
6859203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
6860203945Sweongyo	DELAY(20);
6861203945Sweongyo
6862203945Sweongyo	nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6863203945Sweongyo	if (nrssi0 >= 0x0020)
6864203945Sweongyo		nrssi0 -= 0x0040;
6865203945Sweongyo
6866203945Sweongyo	/*
6867203945Sweongyo	 * Calculate nrssi1
6868203945Sweongyo	 */
6869203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x007f);
6870203945Sweongyo	if (phy->rev >= 2)
6871203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
6872203945Sweongyo
6873203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
6874203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
6875203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x000f);
6876203945Sweongyo	BWN_PHY_WRITE(mac, 0x0015, 0xf330);
6877203945Sweongyo	if (phy->rev >= 2) {
6878203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
6879203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
6880203945Sweongyo	}
6881203945Sweongyo
6882203945Sweongyo	bwn_set_all_gains(mac, 3, 0, 1);
6883203945Sweongyo	if (phy->rf_rev == 8) {
6884203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, 0x001f);
6885203945Sweongyo	} else {
6886203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
6887203945Sweongyo		BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
6888203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
6889203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
6890203945Sweongyo	}
6891203945Sweongyo	BWN_PHY_WRITE(mac, 0x005a, 0x0480);
6892203945Sweongyo	BWN_PHY_WRITE(mac, 0x0059, 0x0810);
6893203945Sweongyo	BWN_PHY_WRITE(mac, 0x0058, 0x000d);
6894203945Sweongyo	DELAY(20);
6895203945Sweongyo	nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6896203945Sweongyo
6897203945Sweongyo	/*
6898203945Sweongyo	 * Install calculated narrow RSSI values
6899203945Sweongyo	 */
6900203945Sweongyo	if (nrssi1 >= 0x0020)
6901203945Sweongyo		nrssi1 -= 0x0040;
6902203945Sweongyo	if (nrssi0 == nrssi1)
6903203945Sweongyo		pg->pg_nrssi_slope = 0x00010000;
6904203945Sweongyo	else
6905203945Sweongyo		pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
6906203945Sweongyo	if (nrssi0 >= -4) {
6907203945Sweongyo		pg->pg_nrssi[0] = nrssi1;
6908203945Sweongyo		pg->pg_nrssi[1] = nrssi0;
6909203945Sweongyo	}
6910203945Sweongyo
6911203945Sweongyo	/*
6912203945Sweongyo	 * Restore saved RF/PHY registers
6913203945Sweongyo	 */
6914203945Sweongyo	if (phy->rev >= 3) {
6915203945Sweongyo		for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
6916203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
6917203945Sweongyo			    save_phy3[phy3_idx]);
6918203945Sweongyo		}
6919203945Sweongyo	}
6920203945Sweongyo	if (phy->rev >= 2) {
6921203945Sweongyo		BWN_PHY_MASK(mac, 0x0812, 0xffcf);
6922203945Sweongyo		BWN_PHY_MASK(mac, 0x0811, 0xffcf);
6923203945Sweongyo	}
6924203945Sweongyo
6925203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6926203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
6927203945Sweongyo
6928203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, ant_div);
6929203945Sweongyo	BWN_WRITE_2(mac, 0x03e6, phy0);
6930203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
6931203945Sweongyo
6932203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6933203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
6934203945Sweongyo
6935203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
6936203945Sweongyo	BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
6937203945Sweongyo	bwn_set_original_gains(mac);
6938203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
6939203945Sweongyo	if (phy->rev >= 3) {
6940203945Sweongyo		for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
6941203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
6942203945Sweongyo			    save_phy3[phy3_idx]);
6943203945Sweongyo		}
6944203945Sweongyo	}
6945203945Sweongyo
6946203945Sweongyo	delta = 0x1f - pg->pg_nrssi[0];
6947203945Sweongyo	for (i = 0; i < 64; i++) {
6948203945Sweongyo		tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
6949203945Sweongyo		tmp32 = MIN(MAX(tmp32, 0), 0x3f);
6950203945Sweongyo		pg->pg_nrssi_lt[i] = tmp32;
6951203945Sweongyo	}
6952203945Sweongyo
6953203945Sweongyo	bwn_nrssi_threshold(mac);
6954203945Sweongyo#undef SAVE_RF_MAX
6955203945Sweongyo#undef SAVE_PHY_COMM_MAX
6956203945Sweongyo#undef SAVE_PHY3_MAX
6957203945Sweongyo}
6958203945Sweongyo
6959203945Sweongyostatic void
6960203945Sweongyobwn_nrssi_offset(struct bwn_mac *mac)
6961203945Sweongyo{
6962203945Sweongyo#define	SAVE_RF_MAX		2
6963203945Sweongyo#define	SAVE_PHY_COMM_MAX	10
6964203945Sweongyo#define	SAVE_PHY6_MAX		8
6965203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6966203945Sweongyo		{ 0x7a, 0x43 };
6967203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
6968203945Sweongyo		0x0001, 0x0811, 0x0812, 0x0814,
6969203945Sweongyo		0x0815, 0x005a, 0x0059, 0x0058,
6970203945Sweongyo		0x000a, 0x0003
6971203945Sweongyo	};
6972203945Sweongyo	static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
6973203945Sweongyo		0x002e, 0x002f, 0x080f, 0x0810,
6974203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6975203945Sweongyo	};
6976203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6977203945Sweongyo	int i, phy6_idx = 0;
6978203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6979203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6980203945Sweongyo	uint16_t save_phy6[SAVE_PHY6_MAX];
6981203945Sweongyo	int16_t nrssi;
6982203945Sweongyo	uint16_t saved = 0xffff;
6983203945Sweongyo
6984203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6985203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6986203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6987203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6988203945Sweongyo
6989203945Sweongyo	BWN_PHY_MASK(mac, 0x0429, 0x7fff);
6990203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
6991203945Sweongyo	BWN_PHY_SET(mac, 0x0811, 0x000c);
6992203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
6993203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
6994203945Sweongyo	if (phy->rev >= 6) {
6995203945Sweongyo		for (i = 0; i < SAVE_PHY6_MAX; ++i)
6996203945Sweongyo			save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
6997203945Sweongyo
6998203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6999203945Sweongyo		BWN_PHY_WRITE(mac, 0x002f, 0);
7000203945Sweongyo		BWN_PHY_WRITE(mac, 0x080f, 0);
7001203945Sweongyo		BWN_PHY_WRITE(mac, 0x0810, 0);
7002203945Sweongyo		BWN_PHY_SET(mac, 0x0478, 0x0100);
7003203945Sweongyo		BWN_PHY_SET(mac, 0x0801, 0x0040);
7004203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
7005203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
7006203945Sweongyo	}
7007203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
7008203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
7009203945Sweongyo	DELAY(30);
7010203945Sweongyo
7011203945Sweongyo	nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7012203945Sweongyo	if (nrssi >= 0x20)
7013203945Sweongyo		nrssi -= 0x40;
7014203945Sweongyo	if (nrssi == 31) {
7015203945Sweongyo		for (i = 7; i >= 4; i--) {
7016203945Sweongyo			BWN_RF_WRITE(mac, 0x007b, i);
7017203945Sweongyo			DELAY(20);
7018203945Sweongyo			nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
7019203945Sweongyo			    0x003f);
7020203945Sweongyo			if (nrssi >= 0x20)
7021203945Sweongyo				nrssi -= 0x40;
7022203945Sweongyo			if (nrssi < 31 && saved == 0xffff)
7023203945Sweongyo				saved = i;
7024203945Sweongyo		}
7025203945Sweongyo		if (saved == 0xffff)
7026203945Sweongyo			saved = 4;
7027203945Sweongyo	} else {
7028203945Sweongyo		BWN_RF_MASK(mac, 0x007a, 0x007f);
7029203945Sweongyo		if (phy->rev != 1) {
7030203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0001);
7031203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffe);
7032203945Sweongyo		}
7033203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x000c);
7034203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x000c);
7035203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x0030);
7036203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x0030);
7037203945Sweongyo		BWN_PHY_WRITE(mac, 0x005a, 0x0480);
7038203945Sweongyo		BWN_PHY_WRITE(mac, 0x0059, 0x0810);
7039203945Sweongyo		BWN_PHY_WRITE(mac, 0x0058, 0x000d);
7040203945Sweongyo		if (phy->rev == 0)
7041203945Sweongyo			BWN_PHY_WRITE(mac, 0x0003, 0x0122);
7042203945Sweongyo		else
7043203945Sweongyo			BWN_PHY_SET(mac, 0x000a, 0x2000);
7044203945Sweongyo		if (phy->rev != 1) {
7045203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0004);
7046203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffb);
7047203945Sweongyo		}
7048203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
7049203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x000f);
7050203945Sweongyo		bwn_set_all_gains(mac, 3, 0, 1);
7051203945Sweongyo		BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
7052203945Sweongyo		DELAY(30);
7053203945Sweongyo		nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7054203945Sweongyo		if (nrssi >= 0x20)
7055203945Sweongyo			nrssi -= 0x40;
7056203945Sweongyo		if (nrssi == -32) {
7057203945Sweongyo			for (i = 0; i < 4; i++) {
7058203945Sweongyo				BWN_RF_WRITE(mac, 0x007b, i);
7059203945Sweongyo				DELAY(20);
7060203945Sweongyo				nrssi = (int16_t)((BWN_PHY_READ(mac,
7061203945Sweongyo				    0x047f) >> 8) & 0x003f);
7062203945Sweongyo				if (nrssi >= 0x20)
7063203945Sweongyo					nrssi -= 0x40;
7064203945Sweongyo				if (nrssi > -31 && saved == 0xffff)
7065203945Sweongyo					saved = i;
7066203945Sweongyo			}
7067203945Sweongyo			if (saved == 0xffff)
7068203945Sweongyo				saved = 3;
7069203945Sweongyo		} else
7070203945Sweongyo			saved = 0;
7071203945Sweongyo	}
7072203945Sweongyo	BWN_RF_WRITE(mac, 0x007b, saved);
7073203945Sweongyo
7074203945Sweongyo	/*
7075203945Sweongyo	 * Restore saved RF/PHY registers
7076203945Sweongyo	 */
7077203945Sweongyo	if (phy->rev >= 6) {
7078203945Sweongyo		for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
7079203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7080203945Sweongyo			    save_phy6[phy6_idx]);
7081203945Sweongyo		}
7082203945Sweongyo	}
7083203945Sweongyo	if (phy->rev != 1) {
7084203945Sweongyo		for (i = 3; i < 5; i++)
7085203945Sweongyo			BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
7086203945Sweongyo			    save_phy_comm[i]);
7087203945Sweongyo	}
7088203945Sweongyo	for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
7089203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
7090203945Sweongyo
7091203945Sweongyo	for (i = SAVE_RF_MAX - 1; i >= 0; --i)
7092203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
7093203945Sweongyo
7094203945Sweongyo	BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
7095203945Sweongyo	BWN_PHY_SET(mac, 0x0429, 0x8000);
7096203945Sweongyo	bwn_set_original_gains(mac);
7097203945Sweongyo	if (phy->rev >= 6) {
7098203945Sweongyo		for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
7099203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7100203945Sweongyo			    save_phy6[phy6_idx]);
7101203945Sweongyo		}
7102203945Sweongyo	}
7103203945Sweongyo
7104203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
7105203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
7106203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
7107203945Sweongyo}
7108203945Sweongyo
7109203945Sweongyostatic void
7110203945Sweongyobwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
7111203945Sweongyo    int16_t third)
7112203945Sweongyo{
7113203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7114203945Sweongyo	uint16_t i;
7115203945Sweongyo	uint16_t start = 0x08, end = 0x18;
7116203945Sweongyo	uint16_t tmp;
7117203945Sweongyo	uint16_t table;
7118203945Sweongyo
7119203945Sweongyo	if (phy->rev <= 1) {
7120203945Sweongyo		start = 0x10;
7121203945Sweongyo		end = 0x20;
7122203945Sweongyo	}
7123203945Sweongyo
7124203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7125203945Sweongyo	if (phy->rev <= 1)
7126203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7127203945Sweongyo	for (i = 0; i < 4; i++)
7128203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, first);
7129203945Sweongyo
7130203945Sweongyo	for (i = start; i < end; i++)
7131203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, second);
7132203945Sweongyo
7133203945Sweongyo	if (third != -1) {
7134203945Sweongyo		tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
7135203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
7136203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
7137203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
7138203945Sweongyo	}
7139203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7140203945Sweongyo}
7141203945Sweongyo
7142203945Sweongyostatic void
7143203945Sweongyobwn_set_original_gains(struct bwn_mac *mac)
7144203945Sweongyo{
7145203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7146203945Sweongyo	uint16_t i, tmp;
7147203945Sweongyo	uint16_t table;
7148203945Sweongyo	uint16_t start = 0x0008, end = 0x0018;
7149203945Sweongyo
7150203945Sweongyo	if (phy->rev <= 1) {
7151203945Sweongyo		start = 0x0010;
7152203945Sweongyo		end = 0x0020;
7153203945Sweongyo	}
7154203945Sweongyo
7155203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7156203945Sweongyo	if (phy->rev <= 1)
7157203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7158203945Sweongyo	for (i = 0; i < 4; i++) {
7159203945Sweongyo		tmp = (i & 0xfffc);
7160203945Sweongyo		tmp |= (i & 0x0001) << 1;
7161203945Sweongyo		tmp |= (i & 0x0002) >> 1;
7162203945Sweongyo
7163203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, tmp);
7164203945Sweongyo	}
7165203945Sweongyo
7166203945Sweongyo	for (i = start; i < end; i++)
7167203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, i - start);
7168203945Sweongyo
7169203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
7170203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
7171203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
7172203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7173203945Sweongyo}
7174203945Sweongyo
7175203945Sweongyostatic void
7176203945Sweongyobwn_phy_hwpctl_init(struct bwn_mac *mac)
7177203945Sweongyo{
7178203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7179203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7180203945Sweongyo	struct bwn_rfatt old_rfatt, rfatt;
7181203945Sweongyo	struct bwn_bbatt old_bbatt, bbatt;
7182204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7183203945Sweongyo	uint8_t old_txctl = 0;
7184203945Sweongyo
7185203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
7186203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7187203945Sweongyo
7188204922Sweongyo	if ((siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM) &&
7189204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306))
7190203945Sweongyo		return;
7191203945Sweongyo
7192203945Sweongyo	BWN_PHY_WRITE(mac, 0x0028, 0x8018);
7193203945Sweongyo
7194203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
7195203945Sweongyo
7196203945Sweongyo	if (!phy->gmode)
7197203945Sweongyo		return;
7198203945Sweongyo	bwn_hwpctl_early_init(mac);
7199203945Sweongyo	if (pg->pg_curtssi == 0) {
7200203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0) {
7201203945Sweongyo			BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
7202203945Sweongyo		} else {
7203203945Sweongyo			memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
7204203945Sweongyo			memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
7205203945Sweongyo			old_txctl = pg->pg_txctl;
7206203945Sweongyo
7207203945Sweongyo			bbatt.att = 11;
7208203945Sweongyo			if (phy->rf_rev == 8) {
7209203945Sweongyo				rfatt.att = 15;
7210203945Sweongyo				rfatt.padmix = 1;
7211203945Sweongyo			} else {
7212203945Sweongyo				rfatt.att = 9;
7213203945Sweongyo				rfatt.padmix = 0;
7214203945Sweongyo			}
7215203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
7216203945Sweongyo		}
7217203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
7218203945Sweongyo		pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
7219203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0)
7220203945Sweongyo			BWN_RF_MASK(mac, 0x0076, 0xff7b);
7221203945Sweongyo		else
7222203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
7223203945Sweongyo			    &old_rfatt, old_txctl);
7224203945Sweongyo	}
7225203945Sweongyo	bwn_hwpctl_init_gphy(mac);
7226203945Sweongyo
7227203945Sweongyo	/* clear TSSI */
7228203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
7229203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
7230203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
7231203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
7232203945Sweongyo}
7233203945Sweongyo
7234203945Sweongyostatic void
7235203945Sweongyobwn_hwpctl_early_init(struct bwn_mac *mac)
7236203945Sweongyo{
7237203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7238203945Sweongyo
7239203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7240203945Sweongyo		BWN_PHY_WRITE(mac, 0x047a, 0xc111);
7241203945Sweongyo		return;
7242203945Sweongyo	}
7243203945Sweongyo
7244203945Sweongyo	BWN_PHY_MASK(mac, 0x0036, 0xfeff);
7245203945Sweongyo	BWN_PHY_WRITE(mac, 0x002f, 0x0202);
7246203945Sweongyo	BWN_PHY_SET(mac, 0x047c, 0x0002);
7247203945Sweongyo	BWN_PHY_SET(mac, 0x047a, 0xf000);
7248203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
7249203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7250203945Sweongyo		BWN_PHY_SET(mac, 0x005d, 0x8000);
7251203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7252203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7253203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7254203945Sweongyo	} else {
7255203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0200);
7256203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7257203945Sweongyo		BWN_PHY_MASK(mac, 0x005d, 0x7fff);
7258203945Sweongyo		BWN_PHY_MASK(mac, 0x004f, 0xfffe);
7259203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7260203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7261203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7262203945Sweongyo	}
7263203945Sweongyo}
7264203945Sweongyo
7265203945Sweongyostatic void
7266203945Sweongyobwn_hwpctl_init_gphy(struct bwn_mac *mac)
7267203945Sweongyo{
7268203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7269203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7270203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7271203945Sweongyo	int i;
7272203945Sweongyo	uint16_t nr_written = 0, tmp, value;
7273203945Sweongyo	uint8_t rf, bb;
7274203945Sweongyo
7275203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7276203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
7277203945Sweongyo		return;
7278203945Sweongyo	}
7279203945Sweongyo
7280203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
7281203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7282203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
7283203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7284203945Sweongyo
7285203945Sweongyo	for (i = 0; i < 32; i++)
7286203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
7287203945Sweongyo	for (i = 32; i < 64; i++)
7288203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
7289203945Sweongyo	for (i = 0; i < 64; i += 2) {
7290203945Sweongyo		value = (uint16_t) pg->pg_tssi2dbm[i];
7291203945Sweongyo		value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
7292203945Sweongyo		BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
7293203945Sweongyo	}
7294203945Sweongyo
7295203945Sweongyo	for (rf = 0; rf < lo->rfatt.len; rf++) {
7296203945Sweongyo		for (bb = 0; bb < lo->bbatt.len; bb++) {
7297203945Sweongyo			if (nr_written >= 0x40)
7298203945Sweongyo				return;
7299203945Sweongyo			tmp = lo->bbatt.array[bb].att;
7300203945Sweongyo			tmp <<= 8;
7301203945Sweongyo			if (phy->rf_rev == 8)
7302203945Sweongyo				tmp |= 0x50;
7303203945Sweongyo			else
7304203945Sweongyo				tmp |= 0x40;
7305203945Sweongyo			tmp |= lo->rfatt.array[rf].att;
7306203945Sweongyo			BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
7307203945Sweongyo			nr_written++;
7308203945Sweongyo		}
7309203945Sweongyo	}
7310203945Sweongyo
7311203945Sweongyo	BWN_PHY_MASK(mac, 0x0060, 0xffbf);
7312203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0000);
7313203945Sweongyo
7314203945Sweongyo	KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
7315203945Sweongyo	BWN_PHY_SET(mac, 0x0478, 0x0800);
7316203945Sweongyo	BWN_PHY_MASK(mac, 0x0478, 0xfeff);
7317203945Sweongyo	BWN_PHY_MASK(mac, 0x0801, 0xffbf);
7318203945Sweongyo
7319203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
7320203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
7321203945Sweongyo}
7322203945Sweongyo
7323203945Sweongyostatic void
7324203945Sweongyobwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
7325203945Sweongyo{
7326204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7327203945Sweongyo
7328203945Sweongyo	if (spu != 0)
7329203945Sweongyo		bwn_spu_workaround(mac, channel);
7330203945Sweongyo
7331203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7332203945Sweongyo
7333203945Sweongyo	if (channel == 14) {
7334204922Sweongyo		if (siba_sprom_get_ccode(sc->sc_dev) == SIBA_CCODE_JAPAN)
7335203945Sweongyo			bwn_hf_write(mac,
7336203945Sweongyo			    bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
7337203945Sweongyo		else
7338203945Sweongyo			bwn_hf_write(mac,
7339203945Sweongyo			    bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
7340203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7341203945Sweongyo		    BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
7342203945Sweongyo		return;
7343203945Sweongyo	}
7344203945Sweongyo
7345203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7346203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
7347203945Sweongyo}
7348203945Sweongyo
7349203945Sweongyostatic uint16_t
7350203945Sweongyobwn_phy_g_chan2freq(uint8_t channel)
7351203945Sweongyo{
7352203945Sweongyo	static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
7353203945Sweongyo
7354203945Sweongyo	KASSERT(channel >= 1 && channel <= 14,
7355203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7356203945Sweongyo
7357203945Sweongyo	return (bwn_phy_g_rf_channels[channel - 1]);
7358203945Sweongyo}
7359203945Sweongyo
7360203945Sweongyostatic void
7361203945Sweongyobwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
7362203945Sweongyo    const struct bwn_rfatt *rfatt, uint8_t txctl)
7363203945Sweongyo{
7364203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7365203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7366203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7367203945Sweongyo	uint16_t bb, rf;
7368203945Sweongyo	uint16_t tx_bias, tx_magn;
7369203945Sweongyo
7370203945Sweongyo	bb = bbatt->att;
7371203945Sweongyo	rf = rfatt->att;
7372203945Sweongyo	tx_bias = lo->tx_bias;
7373203945Sweongyo	tx_magn = lo->tx_magn;
7374203945Sweongyo	if (tx_bias == 0xff)
7375203945Sweongyo		tx_bias = 0;
7376203945Sweongyo
7377203945Sweongyo	pg->pg_txctl = txctl;
7378203945Sweongyo	memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
7379203945Sweongyo	pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
7380203945Sweongyo	memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
7381203945Sweongyo	bwn_phy_g_set_bbatt(mac, bb);
7382203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
7383203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
7384203945Sweongyo		BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
7385203945Sweongyo	else {
7386203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
7387203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
7388203945Sweongyo	}
7389203945Sweongyo	if (BWN_HAS_TXMAG(phy))
7390203945Sweongyo		BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
7391203945Sweongyo	else
7392203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
7393203945Sweongyo	bwn_lo_g_adjust(mac);
7394203945Sweongyo}
7395203945Sweongyo
7396203945Sweongyostatic void
7397203945Sweongyobwn_phy_g_set_bbatt(struct bwn_mac *mac,
7398203945Sweongyo    uint16_t bbatt)
7399203945Sweongyo{
7400203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7401203945Sweongyo
7402203945Sweongyo	if (phy->analog == 0) {
7403203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY0,
7404203945Sweongyo		    (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
7405203945Sweongyo		return;
7406203945Sweongyo	}
7407203945Sweongyo	if (phy->analog > 1) {
7408203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
7409203945Sweongyo		return;
7410203945Sweongyo	}
7411203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
7412203945Sweongyo}
7413203945Sweongyo
7414203945Sweongyostatic uint16_t
7415203945Sweongyobwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
7416203945Sweongyo{
7417203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7418203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7419204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7420203945Sweongyo	int max_lb_gain;
7421203945Sweongyo	uint16_t extlna;
7422203945Sweongyo	uint16_t i;
7423203945Sweongyo
7424203945Sweongyo	if (phy->gmode == 0)
7425203945Sweongyo		return (0);
7426203945Sweongyo
7427203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
7428203945Sweongyo		max_lb_gain = pg->pg_max_lb_gain;
7429203945Sweongyo		max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
7430203945Sweongyo		if (max_lb_gain >= 0x46) {
7431203945Sweongyo			extlna = 0x3000;
7432203945Sweongyo			max_lb_gain -= 0x46;
7433203945Sweongyo		} else if (max_lb_gain >= 0x3a) {
7434203945Sweongyo			extlna = 0x1000;
7435203945Sweongyo			max_lb_gain -= 0x3a;
7436203945Sweongyo		} else if (max_lb_gain >= 0x2e) {
7437203945Sweongyo			extlna = 0x2000;
7438203945Sweongyo			max_lb_gain -= 0x2e;
7439203945Sweongyo		} else {
7440203945Sweongyo			extlna = 0;
7441203945Sweongyo			max_lb_gain -= 0x10;
7442203945Sweongyo		}
7443203945Sweongyo
7444203945Sweongyo		for (i = 0; i < 16; i++) {
7445203945Sweongyo			max_lb_gain -= (i * 6);
7446203945Sweongyo			if (max_lb_gain < 6)
7447203945Sweongyo				break;
7448203945Sweongyo		}
7449203945Sweongyo
7450204922Sweongyo		if ((phy->rev < 7) ||
7451204922Sweongyo		    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
7452203945Sweongyo			if (reg == BWN_PHY_RFOVER) {
7453203945Sweongyo				return (0x1b3);
7454203945Sweongyo			} else if (reg == BWN_PHY_RFOVERVAL) {
7455203945Sweongyo				extlna |= (i << 8);
7456203945Sweongyo				switch (lpd) {
7457203945Sweongyo				case BWN_LPD(0, 1, 1):
7458203945Sweongyo					return (0x0f92);
7459203945Sweongyo				case BWN_LPD(0, 0, 1):
7460203945Sweongyo				case BWN_LPD(1, 0, 1):
7461203945Sweongyo					return (0x0092 | extlna);
7462203945Sweongyo				case BWN_LPD(1, 0, 0):
7463203945Sweongyo					return (0x0093 | extlna);
7464203945Sweongyo				}
7465203945Sweongyo				KASSERT(0 == 1,
7466203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7467203945Sweongyo			}
7468203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7469203945Sweongyo		} else {
7470203945Sweongyo			if (reg == BWN_PHY_RFOVER)
7471203945Sweongyo				return (0x9b3);
7472203945Sweongyo			if (reg == BWN_PHY_RFOVERVAL) {
7473203945Sweongyo				if (extlna)
7474203945Sweongyo					extlna |= 0x8000;
7475203945Sweongyo				extlna |= (i << 8);
7476203945Sweongyo				switch (lpd) {
7477203945Sweongyo				case BWN_LPD(0, 1, 1):
7478203945Sweongyo					return (0x8f92);
7479203945Sweongyo				case BWN_LPD(0, 0, 1):
7480203945Sweongyo					return (0x8092 | extlna);
7481203945Sweongyo				case BWN_LPD(1, 0, 1):
7482203945Sweongyo					return (0x2092 | extlna);
7483203945Sweongyo				case BWN_LPD(1, 0, 0):
7484203945Sweongyo					return (0x2093 | extlna);
7485203945Sweongyo				}
7486203945Sweongyo				KASSERT(0 == 1,
7487203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7488203945Sweongyo			}
7489203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7490203945Sweongyo		}
7491203945Sweongyo		return (0);
7492203945Sweongyo	}
7493203945Sweongyo
7494203945Sweongyo	if ((phy->rev < 7) ||
7495204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
7496203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7497203945Sweongyo			return (0x1b3);
7498203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7499203945Sweongyo			switch (lpd) {
7500203945Sweongyo			case BWN_LPD(0, 1, 1):
7501203945Sweongyo				return (0x0fb2);
7502203945Sweongyo			case BWN_LPD(0, 0, 1):
7503203945Sweongyo				return (0x00b2);
7504203945Sweongyo			case BWN_LPD(1, 0, 1):
7505203945Sweongyo				return (0x30b2);
7506203945Sweongyo			case BWN_LPD(1, 0, 0):
7507203945Sweongyo				return (0x30b3);
7508203945Sweongyo			}
7509203945Sweongyo			KASSERT(0 == 1,
7510203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7511203945Sweongyo		}
7512203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7513203945Sweongyo	} else {
7514203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7515203945Sweongyo			return (0x9b3);
7516203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7517203945Sweongyo			switch (lpd) {
7518203945Sweongyo			case BWN_LPD(0, 1, 1):
7519203945Sweongyo				return (0x8fb2);
7520203945Sweongyo			case BWN_LPD(0, 0, 1):
7521203945Sweongyo				return (0x80b2);
7522203945Sweongyo			case BWN_LPD(1, 0, 1):
7523203945Sweongyo				return (0x20b2);
7524203945Sweongyo			case BWN_LPD(1, 0, 0):
7525203945Sweongyo				return (0x20b3);
7526203945Sweongyo			}
7527203945Sweongyo			KASSERT(0 == 1,
7528203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7529203945Sweongyo		}
7530203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7531203945Sweongyo	}
7532203945Sweongyo	return (0);
7533203945Sweongyo}
7534203945Sweongyo
7535203945Sweongyostatic void
7536203945Sweongyobwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
7537203945Sweongyo{
7538203945Sweongyo
7539203945Sweongyo	if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
7540203945Sweongyo		return;
7541203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
7542203945Sweongyo	    bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
7543203945Sweongyo	DELAY(1000);
7544203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7545203945Sweongyo}
7546203945Sweongyo
7547203945Sweongyostatic int
7548203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
7549203945Sweongyo{
7550203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7551203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
7552204922Sweongyo	const uint8_t rev = siba_get_revid(sc->sc_dev);
7553203945Sweongyo	const char *filename;
7554203945Sweongyo	uint32_t high;
7555203945Sweongyo	int error;
7556203945Sweongyo
7557203945Sweongyo	/* microcode */
7558203945Sweongyo	if (rev >= 5 && rev <= 10)
7559203945Sweongyo		filename = "ucode5";
7560203945Sweongyo	else if (rev >= 11 && rev <= 12)
7561203945Sweongyo		filename = "ucode11";
7562203945Sweongyo	else if (rev == 13)
7563203945Sweongyo		filename = "ucode13";
7564203945Sweongyo	else if (rev == 14)
7565203945Sweongyo		filename = "ucode14";
7566203945Sweongyo	else if (rev >= 15)
7567203945Sweongyo		filename = "ucode15";
7568203945Sweongyo	else {
7569203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
7570203945Sweongyo		bwn_release_firmware(mac);
7571203945Sweongyo		return (EOPNOTSUPP);
7572203945Sweongyo	}
7573203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
7574203945Sweongyo	if (error) {
7575203945Sweongyo		bwn_release_firmware(mac);
7576203945Sweongyo		return (error);
7577203945Sweongyo	}
7578203945Sweongyo
7579203945Sweongyo	/* PCM */
7580203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
7581203945Sweongyo	if (rev >= 5 && rev <= 10) {
7582203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
7583203945Sweongyo		if (error == ENOENT)
7584203945Sweongyo			fw->no_pcmfile = 1;
7585203945Sweongyo		else if (error) {
7586203945Sweongyo			bwn_release_firmware(mac);
7587203945Sweongyo			return (error);
7588203945Sweongyo		}
7589203945Sweongyo	} else if (rev < 11) {
7590203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
7591203945Sweongyo		return (EOPNOTSUPP);
7592203945Sweongyo	}
7593203945Sweongyo
7594203945Sweongyo	/* initvals */
7595204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
7596203945Sweongyo	switch (mac->mac_phy.type) {
7597203945Sweongyo	case BWN_PHYTYPE_A:
7598203945Sweongyo		if (rev < 5 || rev > 10)
7599203945Sweongyo			goto fail1;
7600203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
7601203945Sweongyo			filename = "a0g1initvals5";
7602203945Sweongyo		else
7603203945Sweongyo			filename = "a0g0initvals5";
7604203945Sweongyo		break;
7605203945Sweongyo	case BWN_PHYTYPE_G:
7606203945Sweongyo		if (rev >= 5 && rev <= 10)
7607203945Sweongyo			filename = "b0g0initvals5";
7608203945Sweongyo		else if (rev >= 13)
7609203945Sweongyo			filename = "b0g0initvals13";
7610203945Sweongyo		else
7611203945Sweongyo			goto fail1;
7612203945Sweongyo		break;
7613203945Sweongyo	case BWN_PHYTYPE_LP:
7614203945Sweongyo		if (rev == 13)
7615203945Sweongyo			filename = "lp0initvals13";
7616203945Sweongyo		else if (rev == 14)
7617203945Sweongyo			filename = "lp0initvals14";
7618203945Sweongyo		else if (rev >= 15)
7619203945Sweongyo			filename = "lp0initvals15";
7620203945Sweongyo		else
7621203945Sweongyo			goto fail1;
7622203945Sweongyo		break;
7623203945Sweongyo	case BWN_PHYTYPE_N:
7624203945Sweongyo		if (rev >= 11 && rev <= 12)
7625203945Sweongyo			filename = "n0initvals11";
7626203945Sweongyo		else
7627203945Sweongyo			goto fail1;
7628203945Sweongyo		break;
7629203945Sweongyo	default:
7630203945Sweongyo		goto fail1;
7631203945Sweongyo	}
7632203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
7633203945Sweongyo	if (error) {
7634203945Sweongyo		bwn_release_firmware(mac);
7635203945Sweongyo		return (error);
7636203945Sweongyo	}
7637203945Sweongyo
7638203945Sweongyo	/* bandswitch initvals */
7639203945Sweongyo	switch (mac->mac_phy.type) {
7640203945Sweongyo	case BWN_PHYTYPE_A:
7641203945Sweongyo		if (rev >= 5 && rev <= 10) {
7642203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
7643203945Sweongyo				filename = "a0g1bsinitvals5";
7644203945Sweongyo			else
7645203945Sweongyo				filename = "a0g0bsinitvals5";
7646203945Sweongyo		} else if (rev >= 11)
7647203945Sweongyo			filename = NULL;
7648203945Sweongyo		else
7649203945Sweongyo			goto fail1;
7650203945Sweongyo		break;
7651203945Sweongyo	case BWN_PHYTYPE_G:
7652203945Sweongyo		if (rev >= 5 && rev <= 10)
7653203945Sweongyo			filename = "b0g0bsinitvals5";
7654203945Sweongyo		else if (rev >= 11)
7655203945Sweongyo			filename = NULL;
7656203945Sweongyo		else
7657203945Sweongyo			goto fail1;
7658203945Sweongyo		break;
7659203945Sweongyo	case BWN_PHYTYPE_LP:
7660203945Sweongyo		if (rev == 13)
7661203945Sweongyo			filename = "lp0bsinitvals13";
7662203945Sweongyo		else if (rev == 14)
7663203945Sweongyo			filename = "lp0bsinitvals14";
7664203945Sweongyo		else if (rev >= 15)
7665203945Sweongyo			filename = "lp0bsinitvals15";
7666203945Sweongyo		else
7667203945Sweongyo			goto fail1;
7668203945Sweongyo		break;
7669203945Sweongyo	case BWN_PHYTYPE_N:
7670203945Sweongyo		if (rev >= 11 && rev <= 12)
7671203945Sweongyo			filename = "n0bsinitvals11";
7672203945Sweongyo		else
7673203945Sweongyo			goto fail1;
7674203945Sweongyo		break;
7675203945Sweongyo	default:
7676203945Sweongyo		goto fail1;
7677203945Sweongyo	}
7678203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
7679203945Sweongyo	if (error) {
7680203945Sweongyo		bwn_release_firmware(mac);
7681203945Sweongyo		return (error);
7682203945Sweongyo	}
7683203945Sweongyo	return (0);
7684203945Sweongyofail1:
7685203945Sweongyo	device_printf(sc->sc_dev, "no INITVALS for rev %d\n", rev);
7686203945Sweongyo	bwn_release_firmware(mac);
7687203945Sweongyo	return (EOPNOTSUPP);
7688203945Sweongyo}
7689203945Sweongyo
7690203945Sweongyostatic int
7691203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
7692203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
7693203945Sweongyo{
7694203945Sweongyo	const struct bwn_fwhdr *hdr;
7695203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7696203945Sweongyo	const struct firmware *fw;
7697203945Sweongyo	char namebuf[64];
7698203945Sweongyo
7699203945Sweongyo	if (name == NULL) {
7700203945Sweongyo		bwn_do_release_fw(bfw);
7701203945Sweongyo		return (0);
7702203945Sweongyo	}
7703203945Sweongyo	if (bfw->filename != NULL) {
7704203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
7705203945Sweongyo			return (0);
7706203945Sweongyo		bwn_do_release_fw(bfw);
7707203945Sweongyo	}
7708203945Sweongyo
7709204437Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s%s",
7710204437Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "",
7711204437Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_LP) ? "lp_" : "", name);
7712203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
7713203945Sweongyo	fw = firmware_get(namebuf);
7714203945Sweongyo	if (fw == NULL) {
7715203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
7716203945Sweongyo		    namebuf);
7717203945Sweongyo		return (ENOENT);
7718203945Sweongyo	}
7719203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
7720203945Sweongyo		goto fail;
7721203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
7722203945Sweongyo	switch (hdr->type) {
7723203945Sweongyo	case BWN_FWTYPE_UCODE:
7724203945Sweongyo	case BWN_FWTYPE_PCM:
7725203945Sweongyo		if (be32toh(hdr->size) !=
7726203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
7727203945Sweongyo			goto fail;
7728203945Sweongyo		/* FALLTHROUGH */
7729203945Sweongyo	case BWN_FWTYPE_IV:
7730203945Sweongyo		if (hdr->ver != 1)
7731203945Sweongyo			goto fail;
7732203945Sweongyo		break;
7733203945Sweongyo	default:
7734203945Sweongyo		goto fail;
7735203945Sweongyo	}
7736203945Sweongyo	bfw->filename = name;
7737203945Sweongyo	bfw->fw = fw;
7738203945Sweongyo	bfw->type = type;
7739203945Sweongyo	return (0);
7740203945Sweongyofail:
7741203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
7742203945Sweongyo	if (fw != NULL)
7743203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
7744203945Sweongyo	return (EPROTO);
7745203945Sweongyo}
7746203945Sweongyo
7747203945Sweongyostatic void
7748203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
7749203945Sweongyo{
7750203945Sweongyo
7751203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
7752203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
7753203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
7754203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
7755203945Sweongyo}
7756203945Sweongyo
7757203945Sweongyostatic void
7758203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
7759203945Sweongyo{
7760203945Sweongyo
7761203945Sweongyo	if (bfw->fw != NULL)
7762203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
7763203945Sweongyo	bfw->fw = NULL;
7764203945Sweongyo	bfw->filename = NULL;
7765203945Sweongyo}
7766203945Sweongyo
7767203945Sweongyostatic int
7768203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
7769203945Sweongyo{
7770203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
7771203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
7772203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
7773203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
7774203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7775203945Sweongyo	const uint32_t *data;
7776203945Sweongyo	unsigned int i;
7777203945Sweongyo	uint32_t ctl;
7778203945Sweongyo	uint16_t date, fwcaps, time;
7779203945Sweongyo	int error = 0;
7780203945Sweongyo
7781203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
7782203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
7783203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
7784203945Sweongyo	    __LINE__));
7785203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
7786203945Sweongyo	for (i = 0; i < 64; i++)
7787203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
7788203945Sweongyo	for (i = 0; i < 4096; i += 2)
7789203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
7790203945Sweongyo
7791203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7792203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
7793203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7794203945Sweongyo	     i++) {
7795203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7796203945Sweongyo		DELAY(10);
7797203945Sweongyo	}
7798203945Sweongyo
7799203945Sweongyo	if (mac->mac_fw.pcm.fw) {
7800203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
7801203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
7802203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
7803203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
7804203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
7805203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
7806203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7807203945Sweongyo			DELAY(10);
7808203945Sweongyo		}
7809203945Sweongyo	}
7810203945Sweongyo
7811203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
7812203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7813203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
7814203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
7815203945Sweongyo
7816203945Sweongyo	for (i = 0; i < 21; i++) {
7817203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
7818203945Sweongyo			break;
7819203945Sweongyo		if (i >= 20) {
7820203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
7821203945Sweongyo			error = ENXIO;
7822203945Sweongyo			goto error;
7823203945Sweongyo		}
7824203945Sweongyo		DELAY(50000);
7825203945Sweongyo	}
7826203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
7827203945Sweongyo
7828203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
7829203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
7830203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
7831203945Sweongyo		error = EOPNOTSUPP;
7832203945Sweongyo		goto error;
7833203945Sweongyo	}
7834203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
7835203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
7836203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
7837203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
7838203945Sweongyo	if (bwn_wme != 0)
7839203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
7840203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
7841203945Sweongyo
7842203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
7843203945Sweongyo	if (mac->mac_fw.opensource == 0) {
7844203945Sweongyo		device_printf(sc->sc_dev,
7845203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
7846203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
7847203945Sweongyo		if (mac->mac_fw.no_pcmfile)
7848203945Sweongyo			device_printf(sc->sc_dev,
7849203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
7850203945Sweongyo	} else {
7851203945Sweongyo		mac->mac_fw.patch = time;
7852203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
7853203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
7854203945Sweongyo			device_printf(sc->sc_dev,
7855203945Sweongyo			    "disabling HW crypto acceleration\n");
7856203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
7857203945Sweongyo		}
7858203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
7859203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
7860203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
7861203945Sweongyo		}
7862203945Sweongyo	}
7863203945Sweongyo
7864203945Sweongyo	if (BWN_ISOLDFMT(mac))
7865203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
7866203945Sweongyo
7867203945Sweongyo	return (0);
7868203945Sweongyo
7869203945Sweongyoerror:
7870203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7871203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
7872203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
7873203945Sweongyo
7874203945Sweongyo	return (error);
7875203945Sweongyo#undef GETFWSIZE
7876203945Sweongyo#undef GETFWOFFSET
7877203945Sweongyo}
7878203945Sweongyo
7879203945Sweongyo/* OpenFirmware only */
7880203945Sweongyostatic uint16_t
7881203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
7882203945Sweongyo{
7883203945Sweongyo
7884203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
7885203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7886203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
7887203945Sweongyo}
7888203945Sweongyo
7889203945Sweongyostatic int
7890203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
7891203945Sweongyo    size_t count, size_t array_size)
7892203945Sweongyo{
7893203945Sweongyo#define	GET_NEXTIV16(iv)						\
7894203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7895203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
7896203945Sweongyo#define	GET_NEXTIV32(iv)						\
7897203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7898203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
7899203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7900203945Sweongyo	const struct bwn_fwinitvals *iv;
7901203945Sweongyo	uint16_t offset;
7902203945Sweongyo	size_t i;
7903203945Sweongyo	uint8_t bit32;
7904203945Sweongyo
7905203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
7906203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7907203945Sweongyo	iv = ivals;
7908203945Sweongyo	for (i = 0; i < count; i++) {
7909203945Sweongyo		if (array_size < sizeof(iv->offset_size))
7910203945Sweongyo			goto fail;
7911203945Sweongyo		array_size -= sizeof(iv->offset_size);
7912203945Sweongyo		offset = be16toh(iv->offset_size);
7913203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
7914203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
7915203945Sweongyo		if (offset >= 0x1000)
7916203945Sweongyo			goto fail;
7917203945Sweongyo		if (bit32) {
7918203945Sweongyo			if (array_size < sizeof(iv->data.d32))
7919203945Sweongyo				goto fail;
7920203945Sweongyo			array_size -= sizeof(iv->data.d32);
7921203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
7922203945Sweongyo			iv = GET_NEXTIV32(iv);
7923203945Sweongyo		} else {
7924203945Sweongyo
7925203945Sweongyo			if (array_size < sizeof(iv->data.d16))
7926203945Sweongyo				goto fail;
7927203945Sweongyo			array_size -= sizeof(iv->data.d16);
7928203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
7929203945Sweongyo
7930203945Sweongyo			iv = GET_NEXTIV16(iv);
7931203945Sweongyo		}
7932203945Sweongyo	}
7933203945Sweongyo	if (array_size != 0)
7934203945Sweongyo		goto fail;
7935203945Sweongyo	return (0);
7936203945Sweongyofail:
7937203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
7938203945Sweongyo	return (EPROTO);
7939203945Sweongyo#undef GET_NEXTIV16
7940203945Sweongyo#undef GET_NEXTIV32
7941203945Sweongyo}
7942203945Sweongyo
7943203945Sweongyostatic int
7944203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
7945203945Sweongyo{
7946203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
7947203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7948203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
7949203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
7950203945Sweongyo	uint16_t channelcookie, savedcookie;
7951203945Sweongyo	int error;
7952203945Sweongyo
7953203945Sweongyo	if (chan == 0xffff)
7954203945Sweongyo		chan = phy->get_default_chan(mac);
7955203945Sweongyo
7956203945Sweongyo	channelcookie = chan;
7957203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
7958203945Sweongyo		channelcookie |= 0x100;
7959203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
7960203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
7961203945Sweongyo	error = phy->switch_channel(mac, chan);
7962203945Sweongyo	if (error)
7963203945Sweongyo		goto fail;
7964203945Sweongyo
7965203945Sweongyo	mac->mac_phy.chan = chan;
7966203945Sweongyo	DELAY(8000);
7967203945Sweongyo	return (0);
7968203945Sweongyofail:
7969203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
7970203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
7971203945Sweongyo	return (error);
7972203945Sweongyo}
7973203945Sweongyo
7974203945Sweongyostatic uint16_t
7975203945Sweongyobwn_ant2phy(int antenna)
7976203945Sweongyo{
7977203945Sweongyo
7978203945Sweongyo	switch (antenna) {
7979203945Sweongyo	case BWN_ANT0:
7980203945Sweongyo		return (BWN_TX_PHY_ANT0);
7981203945Sweongyo	case BWN_ANT1:
7982203945Sweongyo		return (BWN_TX_PHY_ANT1);
7983203945Sweongyo	case BWN_ANT2:
7984203945Sweongyo		return (BWN_TX_PHY_ANT2);
7985203945Sweongyo	case BWN_ANT3:
7986203945Sweongyo		return (BWN_TX_PHY_ANT3);
7987203945Sweongyo	case BWN_ANTAUTO:
7988203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
7989203945Sweongyo	}
7990203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7991203945Sweongyo	return (0);
7992203945Sweongyo}
7993203945Sweongyo
7994203945Sweongyostatic void
7995203945Sweongyobwn_wme_load(struct bwn_mac *mac)
7996203945Sweongyo{
7997203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7998203945Sweongyo	int i;
7999203945Sweongyo
8000203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
8001203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8002203945Sweongyo
8003203945Sweongyo	bwn_mac_suspend(mac);
8004203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
8005203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
8006203945Sweongyo		    bwn_wme_shm_offsets[i]);
8007203945Sweongyo	bwn_mac_enable(mac);
8008203945Sweongyo}
8009203945Sweongyo
8010203945Sweongyostatic void
8011203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
8012203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
8013203945Sweongyo{
8014203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
8015203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8016203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
8017203945Sweongyo	int slot, tmp;
8018203945Sweongyo	unsigned int i;
8019203945Sweongyo
8020203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
8021203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8022203945Sweongyo
8023203945Sweongyo	memset(&params, 0, sizeof(params));
8024203945Sweongyo
8025203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
8026203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
8027203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
8028203945Sweongyo
8029203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
8030203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8031203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
8032203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8033203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
8034203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
8035203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
8036203945Sweongyo
8037203945Sweongyo	for (i = 0; i < N(params); i++) {
8038203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
8039203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
8040203945Sweongyo			    shm_offset + (i * 2));
8041203945Sweongyo			tmp |= 0x100;
8042203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8043203945Sweongyo			    tmp);
8044203945Sweongyo		} else {
8045203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8046203945Sweongyo			    params[i]);
8047203945Sweongyo		}
8048203945Sweongyo	}
8049203945Sweongyo}
8050203945Sweongyo
8051203945Sweongyostatic void
8052203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
8053203945Sweongyo{
8054203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8055203945Sweongyo	uint32_t tmp;
8056203945Sweongyo	int i;
8057203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
8058203945Sweongyo
8059203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
8060203945Sweongyo	memcpy(mac_bssid, sc->sc_macaddr, IEEE80211_ADDR_LEN);
8061203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
8062203945Sweongyo	    IEEE80211_ADDR_LEN);
8063203945Sweongyo
8064203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
8065203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
8066203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
8067203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
8068203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
8069203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
8070203945Sweongyo	}
8071203945Sweongyo}
8072203945Sweongyo
8073203945Sweongyostatic void
8074203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
8075203945Sweongyo    const uint8_t *macaddr)
8076203945Sweongyo{
8077203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
8078203945Sweongyo	uint16_t data;
8079203945Sweongyo
8080203945Sweongyo	if (!mac)
8081203945Sweongyo		macaddr = zero;
8082203945Sweongyo
8083203945Sweongyo	offset |= 0x0020;
8084203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
8085203945Sweongyo
8086203945Sweongyo	data = macaddr[0];
8087203945Sweongyo	data |= macaddr[1] << 8;
8088203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8089203945Sweongyo	data = macaddr[2];
8090203945Sweongyo	data |= macaddr[3] << 8;
8091203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8092203945Sweongyo	data = macaddr[4];
8093203945Sweongyo	data |= macaddr[5] << 8;
8094203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8095203945Sweongyo}
8096203945Sweongyo
8097203945Sweongyostatic void
8098203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8099203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
8100203945Sweongyo{
8101203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
8102203945Sweongyo	uint8_t per_sta_keys_start = 8;
8103203945Sweongyo
8104203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8105203945Sweongyo		per_sta_keys_start = 4;
8106203945Sweongyo
8107203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
8108203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8109203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
8110203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8111203945Sweongyo
8112203945Sweongyo	if (index >= per_sta_keys_start)
8113203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
8114203945Sweongyo	if (key)
8115203945Sweongyo		memcpy(buf, key, key_len);
8116203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
8117203945Sweongyo	if (index >= per_sta_keys_start)
8118203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
8119203945Sweongyo
8120203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
8121203945Sweongyo}
8122203945Sweongyo
8123203945Sweongyostatic void
8124203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
8125203945Sweongyo{
8126204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8127203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
8128203945Sweongyo	uint8_t start = 8;
8129203945Sweongyo
8130203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8131203945Sweongyo		start = 4;
8132203945Sweongyo
8133203945Sweongyo	KASSERT(index >= start,
8134203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8135203945Sweongyo	index -= start;
8136203945Sweongyo
8137203945Sweongyo	if (addr) {
8138203945Sweongyo		addrtmp[0] = addr[0];
8139203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
8140203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
8141203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
8142203945Sweongyo		addrtmp[1] = addr[4];
8143203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
8144203945Sweongyo	}
8145203945Sweongyo
8146204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
8147203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
8148203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
8149203945Sweongyo	} else {
8150203945Sweongyo		if (index >= 8) {
8151203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
8152203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
8153203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
8154203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
8155203945Sweongyo		}
8156203945Sweongyo	}
8157203945Sweongyo}
8158203945Sweongyo
8159203945Sweongyostatic void
8160203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8161203945Sweongyo    const uint8_t *key)
8162203945Sweongyo{
8163203945Sweongyo	unsigned int i;
8164203945Sweongyo	uint32_t offset;
8165203945Sweongyo	uint16_t kidx, value;
8166203945Sweongyo
8167203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
8168203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
8169203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
8170203945Sweongyo
8171203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
8172203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
8173203945Sweongyo		value = key[i];
8174203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
8175203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
8176203945Sweongyo	}
8177203945Sweongyo}
8178203945Sweongyo
8179203945Sweongyostatic void
8180203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
8181203945Sweongyo{
8182203945Sweongyo
8183203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8184203945Sweongyo	if (mac->mac_phy.exit != NULL)
8185203945Sweongyo		mac->mac_phy.exit(mac);
8186203945Sweongyo}
8187203945Sweongyo
8188203945Sweongyostatic void
8189203945Sweongyobwn_dma_free(struct bwn_mac *mac)
8190203945Sweongyo{
8191203945Sweongyo	struct bwn_dma *dma;
8192203945Sweongyo
8193203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
8194203945Sweongyo		return;
8195203945Sweongyo	dma = &mac->mac_method.dma;
8196203945Sweongyo
8197203945Sweongyo	bwn_dma_ringfree(&dma->rx);
8198203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
8199203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
8200203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
8201203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
8202203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
8203203945Sweongyo}
8204203945Sweongyo
8205203945Sweongyostatic void
8206203945Sweongyobwn_core_stop(struct bwn_mac *mac)
8207203945Sweongyo{
8208203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8209203945Sweongyo
8210203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8211203945Sweongyo
8212203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8213203945Sweongyo		return;
8214203945Sweongyo
8215203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
8216203945Sweongyo	callout_stop(&sc->sc_task_ch);
8217203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
8218203945Sweongyo	sc->sc_watchdog_timer = 0;
8219203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8220203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
8221203945Sweongyo	bwn_mac_suspend(mac);
8222203945Sweongyo
8223203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
8224203945Sweongyo}
8225203945Sweongyo
8226203945Sweongyostatic int
8227203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
8228203945Sweongyo{
8229203945Sweongyo	struct bwn_mac *up_dev = NULL;
8230203945Sweongyo	struct bwn_mac *down_dev;
8231203945Sweongyo	struct bwn_mac *mac;
8232203945Sweongyo	int err, status;
8233203945Sweongyo	uint8_t gmode;
8234203945Sweongyo
8235203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8236203945Sweongyo
8237203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
8238203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
8239203945Sweongyo		    mac->mac_phy.supports_2ghz) {
8240203945Sweongyo			up_dev = mac;
8241203945Sweongyo			gmode = 1;
8242203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
8243203945Sweongyo		    mac->mac_phy.supports_5ghz) {
8244203945Sweongyo			up_dev = mac;
8245203945Sweongyo			gmode = 0;
8246203945Sweongyo		} else {
8247203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8248203945Sweongyo			return (EINVAL);
8249203945Sweongyo		}
8250203945Sweongyo		if (up_dev != NULL)
8251203945Sweongyo			break;
8252203945Sweongyo	}
8253203945Sweongyo	if (up_dev == NULL) {
8254203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
8255203945Sweongyo		return (ENODEV);
8256203945Sweongyo	}
8257203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
8258203945Sweongyo		return (0);
8259203945Sweongyo
8260203945Sweongyo	device_printf(sc->sc_dev, "switching to %s-GHz band\n",
8261203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8262203945Sweongyo
8263203945Sweongyo	down_dev = sc->sc_curmac;;
8264203945Sweongyo	status = down_dev->mac_status;
8265203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8266203945Sweongyo		bwn_core_stop(down_dev);
8267203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
8268203945Sweongyo		bwn_core_exit(down_dev);
8269203945Sweongyo
8270203945Sweongyo	if (down_dev != up_dev)
8271203945Sweongyo		bwn_phy_reset(down_dev);
8272203945Sweongyo
8273203945Sweongyo	up_dev->mac_phy.gmode = gmode;
8274203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
8275203945Sweongyo		err = bwn_core_init(up_dev);
8276203945Sweongyo		if (err) {
8277203945Sweongyo			device_printf(sc->sc_dev,
8278203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
8279203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8280203945Sweongyo			goto fail;
8281203945Sweongyo		}
8282203945Sweongyo	}
8283203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8284203945Sweongyo		bwn_core_start(up_dev);
8285203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
8286203945Sweongyo	sc->sc_curmac = up_dev;
8287203945Sweongyo
8288203945Sweongyo	return (0);
8289203945Sweongyofail:
8290203945Sweongyo	sc->sc_curmac = NULL;
8291203945Sweongyo	return (err);
8292203945Sweongyo}
8293203945Sweongyo
8294203945Sweongyostatic void
8295203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
8296203945Sweongyo{
8297203945Sweongyo
8298203945Sweongyo	bwn_mac_suspend(mac);
8299203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
8300203945Sweongyo	mac->mac_phy.rf_on = 1;
8301203945Sweongyo	bwn_mac_enable(mac);
8302203945Sweongyo}
8303203945Sweongyo
8304203945Sweongyostatic void
8305203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
8306203945Sweongyo{
8307203945Sweongyo
8308203945Sweongyo	bwn_mac_suspend(mac);
8309203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8310203945Sweongyo	mac->mac_phy.rf_on = 0;
8311203945Sweongyo	bwn_mac_enable(mac);
8312203945Sweongyo}
8313203945Sweongyo
8314203945Sweongyostatic void
8315203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
8316203945Sweongyo{
8317204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8318203945Sweongyo
8319204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
8320204922Sweongyo	    ((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
8321203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
8322203945Sweongyo	DELAY(1000);
8323204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
8324204922Sweongyo	    (siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC) |
8325203945Sweongyo	    BWN_TGSLOW_PHYRESET);
8326203945Sweongyo	DELAY(1000);
8327203945Sweongyo}
8328203945Sweongyo
8329203945Sweongyostatic int
8330203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
8331203945Sweongyo{
8332208120Sweongyo	const struct ieee80211_txparam *tp;
8333203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
8334203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
8335203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
8336203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
8337203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
8338203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
8339203945Sweongyo	int error;
8340203945Sweongyo
8341203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
8342203945Sweongyo	    ieee80211_state_name[vap->iv_state],
8343203945Sweongyo	    ieee80211_state_name[nstate]);
8344203945Sweongyo
8345203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
8346203945Sweongyo	if (error != 0)
8347203945Sweongyo		return (error);
8348203945Sweongyo
8349203945Sweongyo	BWN_LOCK(sc);
8350203945Sweongyo
8351203945Sweongyo	bwn_led_newstate(mac, nstate);
8352203945Sweongyo
8353203945Sweongyo	/*
8354203945Sweongyo	 * Clear the BSSID when we stop a STA
8355203945Sweongyo	 */
8356203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
8357203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
8358203945Sweongyo			/*
8359203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
8360203945Sweongyo			 * the same AP, this will reinialize things
8361203945Sweongyo			 * correctly...
8362203945Sweongyo			 */
8363203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
8364203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
8365203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
8366203945Sweongyo				bwn_set_macaddr(mac);
8367203945Sweongyo			}
8368203945Sweongyo		}
8369203945Sweongyo	}
8370203945Sweongyo
8371204436Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR ||
8372204436Sweongyo	    vap->iv_opmode == IEEE80211_M_AHDEMO) {
8373203945Sweongyo		/* XXX nothing to do? */
8374203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
8375203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
8376203945Sweongyo		memcpy(sc->sc_macaddr, IF_LLADDR(ifp), IEEE80211_ADDR_LEN);
8377203945Sweongyo		bwn_set_opmode(mac);
8378203945Sweongyo		bwn_set_pretbtt(mac);
8379203945Sweongyo		bwn_spu_setdelay(mac, 0);
8380203945Sweongyo		bwn_set_macaddr(mac);
8381208120Sweongyo
8382208120Sweongyo		/* Initializes ratectl for a node. */
8383208120Sweongyo		tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
8384208120Sweongyo		if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
8385208120Sweongyo			ieee80211_ratectl_node_init(vap->iv_bss);
8386203945Sweongyo	}
8387203945Sweongyo
8388203945Sweongyo	BWN_UNLOCK(sc);
8389203945Sweongyo
8390203945Sweongyo	return (error);
8391203945Sweongyo}
8392203945Sweongyo
8393203945Sweongyostatic void
8394203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
8395203945Sweongyo{
8396203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8397203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8398203945Sweongyo	uint16_t pretbtt;
8399203945Sweongyo
8400203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8401203945Sweongyo		pretbtt = 2;
8402203945Sweongyo	else
8403203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
8404203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
8405203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
8406203945Sweongyo}
8407203945Sweongyo
8408203945Sweongyostatic int
8409203945Sweongyobwn_intr(void *arg)
8410203945Sweongyo{
8411203945Sweongyo	struct bwn_mac *mac = arg;
8412203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8413203945Sweongyo	uint32_t reason;
8414203945Sweongyo
8415204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
8416204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID))
8417203945Sweongyo		return (FILTER_STRAY);
8418203945Sweongyo
8419203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
8420203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
8421203945Sweongyo		return (FILTER_STRAY);
8422203945Sweongyo	reason &= mac->mac_intr_mask;
8423203945Sweongyo	if (reason == 0)
8424203945Sweongyo		return (FILTER_HANDLED);
8425203945Sweongyo
8426203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
8427203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
8428203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
8429203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
8430203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
8431203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
8432203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
8433203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
8434203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
8435203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
8436203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
8437203945Sweongyo
8438203945Sweongyo	/* Disable interrupts. */
8439203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8440203945Sweongyo
8441203945Sweongyo	mac->mac_reason_intr = reason;
8442203945Sweongyo
8443203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8444203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8445203945Sweongyo
8446203945Sweongyo	taskqueue_enqueue_fast(sc->sc_tq, &mac->mac_intrtask);
8447203945Sweongyo	return (FILTER_HANDLED);
8448203945Sweongyo}
8449203945Sweongyo
8450203945Sweongyostatic void
8451203945Sweongyobwn_intrtask(void *arg, int npending)
8452203945Sweongyo{
8453203945Sweongyo	struct bwn_mac *mac = arg;
8454203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8455203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8456203945Sweongyo	uint32_t merged = 0;
8457203945Sweongyo	int i, tx = 0, rx = 0;
8458203945Sweongyo
8459203945Sweongyo	BWN_LOCK(sc);
8460204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
8461204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID)) {
8462203945Sweongyo		BWN_UNLOCK(sc);
8463203945Sweongyo		return;
8464203945Sweongyo	}
8465203945Sweongyo
8466203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
8467203945Sweongyo		merged |= mac->mac_reason[i];
8468203945Sweongyo
8469203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
8470203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
8471203945Sweongyo
8472203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
8473203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
8474203945Sweongyo		mac->mac_phy.txerrors--;
8475203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
8476203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
8477203945Sweongyo			bwn_restart(mac, "PHY TX errors");
8478203945Sweongyo		}
8479203945Sweongyo	}
8480203945Sweongyo
8481203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
8482203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
8483203945Sweongyo			device_printf(sc->sc_dev,
8484203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
8485203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8486203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8487203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8488203945Sweongyo			bwn_restart(mac, "DMA error");
8489203945Sweongyo			BWN_UNLOCK(sc);
8490203945Sweongyo			return;
8491203945Sweongyo		}
8492203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
8493203945Sweongyo			device_printf(sc->sc_dev,
8494203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
8495203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8496203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8497203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8498203945Sweongyo		}
8499203945Sweongyo	}
8500203945Sweongyo
8501203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
8502203945Sweongyo		bwn_intr_ucode_debug(mac);
8503203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
8504203945Sweongyo		bwn_intr_tbtt_indication(mac);
8505203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
8506203945Sweongyo		bwn_intr_atim_end(mac);
8507203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
8508203945Sweongyo		bwn_intr_beacon(mac);
8509203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
8510203945Sweongyo		bwn_intr_pmq(mac);
8511203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
8512203945Sweongyo		bwn_intr_noise(mac);
8513203945Sweongyo
8514203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
8515203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
8516203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
8517203945Sweongyo			rx = 1;
8518203945Sweongyo		}
8519203945Sweongyo	} else
8520203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
8521203945Sweongyo
8522203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8523203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8524203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8525203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8526203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8527203945Sweongyo
8528203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
8529203945Sweongyo		bwn_intr_txeof(mac);
8530203945Sweongyo		tx = 1;
8531203945Sweongyo	}
8532203945Sweongyo
8533203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
8534203945Sweongyo
8535203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
8536203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
8537203945Sweongyo
8538203945Sweongyo		if (tx && rx) {
8539203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
8540203945Sweongyo				evt = BWN_LED_EVENT_RX;
8541203945Sweongyo			else
8542203945Sweongyo				evt = BWN_LED_EVENT_TX;
8543203945Sweongyo		} else if (tx) {
8544203945Sweongyo			evt = BWN_LED_EVENT_TX;
8545203945Sweongyo		} else if (rx) {
8546203945Sweongyo			evt = BWN_LED_EVENT_RX;
8547203945Sweongyo		} else if (rx == 0) {
8548203945Sweongyo			evt = BWN_LED_EVENT_POLL;
8549203945Sweongyo		}
8550203945Sweongyo
8551203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
8552203945Sweongyo			bwn_led_event(mac, evt);
8553203945Sweongyo       }
8554203945Sweongyo
8555203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
8556203945Sweongyo		if (!IFQ_IS_EMPTY(&ifp->if_snd))
8557203945Sweongyo			bwn_start_locked(ifp);
8558203945Sweongyo	}
8559203945Sweongyo
8560203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8561203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8562203945Sweongyo
8563203945Sweongyo	BWN_UNLOCK(sc);
8564203945Sweongyo}
8565203945Sweongyo
8566203945Sweongyostatic void
8567203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
8568203945Sweongyo{
8569203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8570203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8571203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
8572203945Sweongyo
8573203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
8574203945Sweongyo		return;
8575203945Sweongyo
8576203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
8577203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
8578203945Sweongyo}
8579203945Sweongyo
8580203945Sweongyostatic void
8581203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
8582203945Sweongyo{
8583203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8584203945Sweongyo	uint16_t reason;
8585203945Sweongyo
8586203945Sweongyo	if (mac->mac_fw.opensource == 0)
8587203945Sweongyo		return;
8588203945Sweongyo
8589203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
8590203945Sweongyo	switch (reason) {
8591203945Sweongyo	case BWN_DEBUGINTR_PANIC:
8592203945Sweongyo		bwn_handle_fwpanic(mac);
8593203945Sweongyo		break;
8594203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
8595203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
8596203945Sweongyo		break;
8597203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
8598203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
8599203945Sweongyo		break;
8600203945Sweongyo	case BWN_DEBUGINTR_MARKER:
8601203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
8602203945Sweongyo		break;
8603203945Sweongyo	default:
8604203945Sweongyo		device_printf(sc->sc_dev,
8605203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
8606203945Sweongyo	}
8607203945Sweongyo
8608203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
8609203945Sweongyo	    BWN_DEBUGINTR_ACK);
8610203945Sweongyo}
8611203945Sweongyo
8612203945Sweongyostatic void
8613203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
8614203945Sweongyo{
8615203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8616203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8617203945Sweongyo
8618203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
8619203945Sweongyo		bwn_psctl(mac, 0);
8620203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8621203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
8622203945Sweongyo}
8623203945Sweongyo
8624203945Sweongyostatic void
8625203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
8626203945Sweongyo{
8627203945Sweongyo
8628203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
8629203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
8630203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
8631203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
8632203945Sweongyo	}
8633203945Sweongyo}
8634203945Sweongyo
8635203945Sweongyostatic void
8636203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
8637203945Sweongyo{
8638203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8639203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8640203945Sweongyo	uint32_t cmd, beacon0, beacon1;
8641203945Sweongyo
8642203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
8643203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
8644203945Sweongyo		return;
8645203945Sweongyo
8646203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
8647203945Sweongyo
8648203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
8649203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
8650203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
8651203945Sweongyo
8652203945Sweongyo	if (beacon0 && beacon1) {
8653203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
8654203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
8655203945Sweongyo		return;
8656203945Sweongyo	}
8657203945Sweongyo
8658203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
8659203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
8660203945Sweongyo		bwn_load_beacon0(mac);
8661203945Sweongyo		bwn_load_beacon1(mac);
8662203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
8663203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
8664203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8665203945Sweongyo	} else {
8666203945Sweongyo		if (!beacon0) {
8667203945Sweongyo			bwn_load_beacon0(mac);
8668203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8669203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
8670203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8671203945Sweongyo		} else if (!beacon1) {
8672203945Sweongyo			bwn_load_beacon1(mac);
8673203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8674203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
8675203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8676203945Sweongyo		}
8677203945Sweongyo	}
8678203945Sweongyo}
8679203945Sweongyo
8680203945Sweongyostatic void
8681203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
8682203945Sweongyo{
8683203945Sweongyo	uint32_t tmp;
8684203945Sweongyo
8685203945Sweongyo	while (1) {
8686203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
8687203945Sweongyo		if (!(tmp & 0x00000008))
8688203945Sweongyo			break;
8689203945Sweongyo	}
8690203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
8691203945Sweongyo}
8692203945Sweongyo
8693203945Sweongyostatic void
8694203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
8695203945Sweongyo{
8696203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
8697203945Sweongyo	uint16_t tmp;
8698203945Sweongyo	uint8_t noise[4];
8699203945Sweongyo	uint8_t i, j;
8700203945Sweongyo	int32_t average;
8701203945Sweongyo
8702203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
8703203945Sweongyo		return;
8704203945Sweongyo
8705203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
8706203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
8707203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
8708203945Sweongyo	    noise[3] == 0x7f)
8709203945Sweongyo		goto new;
8710203945Sweongyo
8711203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
8712203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8713203945Sweongyo	i = mac->mac_noise.noi_nsamples;
8714203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
8715203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
8716203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
8717203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
8718203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
8719203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
8720203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
8721203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
8722203945Sweongyo	mac->mac_noise.noi_nsamples++;
8723203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
8724203945Sweongyo		average = 0;
8725203945Sweongyo		for (i = 0; i < 8; i++) {
8726203945Sweongyo			for (j = 0; j < 4; j++)
8727203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
8728203945Sweongyo		}
8729203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
8730203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
8731203945Sweongyo		if (tmp >= 8)
8732203945Sweongyo			average += 2;
8733203945Sweongyo		else
8734203945Sweongyo			average -= 25;
8735203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
8736203945Sweongyo
8737203945Sweongyo		mac->mac_stats.link_noise = average;
8738203945Sweongyo		mac->mac_noise.noi_running = 0;
8739203945Sweongyo		return;
8740203945Sweongyo	}
8741203945Sweongyonew:
8742203945Sweongyo	bwn_noise_gensample(mac);
8743203945Sweongyo}
8744203945Sweongyo
8745203945Sweongyostatic int
8746203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
8747203945Sweongyo{
8748203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
8749203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8750203945Sweongyo	unsigned int i;
8751203945Sweongyo
8752203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8753203945Sweongyo
8754203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8755203945Sweongyo		return (0);
8756203945Sweongyo
8757203945Sweongyo	for (i = 0; i < 5000; i++) {
8758203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
8759203945Sweongyo			break;
8760203945Sweongyo	}
8761203945Sweongyo	if (i >= 5000)
8762203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
8763203945Sweongyo	return ((i > 0) ? 1 : 0);
8764203945Sweongyo}
8765203945Sweongyo
8766203945Sweongyostatic void
8767203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
8768203945Sweongyo{
8769203945Sweongyo	int slot, curslot;
8770203945Sweongyo
8771203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
8772203945Sweongyo	curslot = dr->get_curslot(dr);
8773203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
8774203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8775203945Sweongyo
8776203945Sweongyo	slot = dr->dr_curslot;
8777203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
8778203945Sweongyo		bwn_dma_rxeof(dr, &slot);
8779203945Sweongyo
8780203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
8781203945Sweongyo	    BUS_DMASYNC_PREWRITE);
8782203945Sweongyo
8783203945Sweongyo	dr->set_curslot(dr, slot);
8784203945Sweongyo	dr->dr_curslot = slot;
8785203945Sweongyo}
8786203945Sweongyo
8787203945Sweongyostatic void
8788203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
8789203945Sweongyo{
8790203945Sweongyo	struct bwn_txstatus stat;
8791203945Sweongyo	uint32_t stat0, stat1;
8792203945Sweongyo	uint16_t tmp;
8793203945Sweongyo
8794203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8795203945Sweongyo
8796203945Sweongyo	while (1) {
8797203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
8798203945Sweongyo		if (!(stat0 & 0x00000001))
8799203945Sweongyo			break;
8800203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
8801203945Sweongyo
8802203945Sweongyo		stat.cookie = (stat0 >> 16);
8803203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
8804203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
8805203945Sweongyo		tmp = (stat0 & 0x0000ffff);
8806203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
8807203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
8808203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
8809203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
8810203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
8811203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
8812203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
8813203945Sweongyo
8814203945Sweongyo		bwn_handle_txeof(mac, &stat);
8815203945Sweongyo	}
8816203945Sweongyo}
8817203945Sweongyo
8818203945Sweongyostatic void
8819203945Sweongyobwn_hwreset(void *arg, int npending)
8820203945Sweongyo{
8821203945Sweongyo	struct bwn_mac *mac = arg;
8822203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8823203945Sweongyo	int error = 0;
8824203945Sweongyo	int prev_status;
8825203945Sweongyo
8826203945Sweongyo	BWN_LOCK(sc);
8827203945Sweongyo
8828203945Sweongyo	prev_status = mac->mac_status;
8829203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8830203945Sweongyo		bwn_core_stop(mac);
8831203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
8832203945Sweongyo		bwn_core_exit(mac);
8833203945Sweongyo
8834203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
8835203945Sweongyo		error = bwn_core_init(mac);
8836203945Sweongyo		if (error)
8837203945Sweongyo			goto out;
8838203945Sweongyo	}
8839203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8840203945Sweongyo		bwn_core_start(mac);
8841203945Sweongyoout:
8842203945Sweongyo	if (error) {
8843203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
8844203945Sweongyo		sc->sc_curmac = NULL;
8845203945Sweongyo	}
8846203945Sweongyo	BWN_UNLOCK(sc);
8847203945Sweongyo}
8848203945Sweongyo
8849203945Sweongyostatic void
8850203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
8851203945Sweongyo{
8852203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8853203945Sweongyo	uint16_t reason;
8854203945Sweongyo
8855203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
8856203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
8857203945Sweongyo
8858203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
8859203945Sweongyo		bwn_restart(mac, "ucode panic");
8860203945Sweongyo}
8861203945Sweongyo
8862203945Sweongyostatic void
8863203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
8864203945Sweongyo{
8865203945Sweongyo
8866203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8867203945Sweongyo}
8868203945Sweongyo
8869203945Sweongyostatic void
8870203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
8871203945Sweongyo{
8872203945Sweongyo
8873203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8874203945Sweongyo}
8875203945Sweongyo
8876203945Sweongyostatic uint32_t
8877203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
8878203945Sweongyo{
8879203945Sweongyo	uint32_t val = 0;
8880203945Sweongyo
8881203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
8882203945Sweongyo	val <<= 16;
8883203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
8884203945Sweongyo
8885203945Sweongyo	return (val);
8886203945Sweongyo}
8887203945Sweongyo
8888203945Sweongyostatic void
8889203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
8890203945Sweongyo{
8891203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
8892203945Sweongyo
8893203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
8894203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
8895203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
8896203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
8897203945Sweongyo}
8898203945Sweongyo
8899203945Sweongyostatic int
8900203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
8901203945Sweongyo{
8902204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8903203945Sweongyo
8904203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
8905203945Sweongyo}
8906203945Sweongyo
8907203945Sweongyostatic int
8908203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
8909203945Sweongyo{
8910204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8911203945Sweongyo
8912203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
8913203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8914203945Sweongyo	if (slot == dr->dr_numslots - 1)
8915203945Sweongyo		return (0);
8916203945Sweongyo	return (slot + 1);
8917203945Sweongyo}
8918203945Sweongyo
8919203945Sweongyostatic void
8920203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
8921203945Sweongyo{
8922203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
8923203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8924203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
8925203945Sweongyo	struct bwn_dmadesc_generic *desc;
8926203945Sweongyo	struct bwn_dmadesc_meta *meta;
8927203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
8928203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8929203945Sweongyo	struct mbuf *m;
8930203945Sweongyo	uint32_t macstat;
8931203945Sweongyo	int32_t tmp;
8932203945Sweongyo	int cnt = 0;
8933203945Sweongyo	uint16_t len;
8934203945Sweongyo
8935203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
8936203945Sweongyo
8937203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
8938203945Sweongyo	m = meta->mt_m;
8939203945Sweongyo
8940203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
8941203945Sweongyo		ifp->if_ierrors++;
8942203945Sweongyo		return;
8943203945Sweongyo	}
8944203945Sweongyo
8945203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
8946203945Sweongyo	len = le16toh(rxhdr->frame_len);
8947203945Sweongyo	if (len <= 0) {
8948203945Sweongyo		ifp->if_ierrors++;
8949203945Sweongyo		return;
8950203945Sweongyo	}
8951203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
8952203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
8953203945Sweongyo		bwn_dma_set_redzone(dr, m);
8954203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
8955203945Sweongyo		    BUS_DMASYNC_PREWRITE);
8956203945Sweongyo		return;
8957203945Sweongyo	}
8958203945Sweongyo	if (len > dr->dr_rx_bufsize) {
8959203945Sweongyo		tmp = len;
8960203945Sweongyo		while (1) {
8961203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
8962203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
8963203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
8964203945Sweongyo			    BUS_DMASYNC_PREWRITE);
8965203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
8966203945Sweongyo			cnt++;
8967203945Sweongyo			tmp -= dr->dr_rx_bufsize;
8968203945Sweongyo			if (tmp <= 0)
8969203945Sweongyo				break;
8970203945Sweongyo		}
8971203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
8972203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
8973203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
8974203945Sweongyo		return;
8975203945Sweongyo	}
8976203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
8977203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
8978203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
8979203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
8980203945Sweongyo			return;
8981203945Sweongyo		}
8982203945Sweongyo	}
8983203945Sweongyo
8984203945Sweongyo	m->m_pkthdr.rcvif = ifp;
8985203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
8986203945Sweongyo	m_adj(m, dr->dr_frameoffset);
8987203945Sweongyo
8988203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
8989203945Sweongyo}
8990203945Sweongyo
8991203945Sweongyostatic void
8992203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
8993203945Sweongyo{
8994203945Sweongyo	struct bwn_dma_ring *dr;
8995203945Sweongyo	struct bwn_dmadesc_generic *desc;
8996203945Sweongyo	struct bwn_dmadesc_meta *meta;
8997203945Sweongyo	struct bwn_pio_txqueue *tq;
8998203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
8999203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9000204257Sweongyo	struct bwn_stats *stats = &mac->mac_stats;
9001203945Sweongyo	struct ieee80211_node *ni;
9002206358Srpaulo	struct ieee80211vap *vap;
9003208120Sweongyo	int retrycnt = 0, slot;
9004203945Sweongyo
9005203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
9006203945Sweongyo
9007203945Sweongyo	if (status->im)
9008203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
9009203945Sweongyo	if (status->ampdu)
9010203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
9011203945Sweongyo	if (status->rtscnt) {
9012203945Sweongyo		if (status->rtscnt == 0xf)
9013204257Sweongyo			stats->rtsfail++;
9014203945Sweongyo		else
9015204257Sweongyo			stats->rts++;
9016203945Sweongyo	}
9017203945Sweongyo
9018203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
9019203945Sweongyo		if (status->ack) {
9020203945Sweongyo			dr = bwn_dma_parse_cookie(mac, status,
9021203945Sweongyo			    status->cookie, &slot);
9022203945Sweongyo			if (dr == NULL) {
9023203945Sweongyo				device_printf(sc->sc_dev,
9024203945Sweongyo				    "failed to parse cookie\n");
9025203945Sweongyo				return;
9026203945Sweongyo			}
9027203945Sweongyo			while (1) {
9028203945Sweongyo				dr->getdesc(dr, slot, &desc, &meta);
9029203945Sweongyo				if (meta->mt_islast) {
9030203945Sweongyo					ni = meta->mt_ni;
9031206358Srpaulo					vap = ni->ni_vap;
9032206358Srpaulo					ieee80211_ratectl_tx_complete(vap, ni,
9033206358Srpaulo					    status->ack ?
9034206358Srpaulo					      IEEE80211_RATECTL_TX_SUCCESS :
9035206358Srpaulo					      IEEE80211_RATECTL_TX_FAILURE,
9036208120Sweongyo					    &retrycnt, 0);
9037203945Sweongyo					break;
9038203945Sweongyo				}
9039203945Sweongyo				slot = bwn_dma_nextslot(dr, slot);
9040203945Sweongyo			}
9041203945Sweongyo		}
9042203945Sweongyo		bwn_dma_handle_txeof(mac, status);
9043203945Sweongyo	} else {
9044203945Sweongyo		if (status->ack) {
9045203945Sweongyo			tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9046203945Sweongyo			if (tq == NULL) {
9047203945Sweongyo				device_printf(sc->sc_dev,
9048203945Sweongyo				    "failed to parse cookie\n");
9049203945Sweongyo				return;
9050203945Sweongyo			}
9051203945Sweongyo			ni = tp->tp_ni;
9052206358Srpaulo			vap = ni->ni_vap;
9053206358Srpaulo			ieee80211_ratectl_tx_complete(vap, ni,
9054206358Srpaulo			    status->ack ?
9055206358Srpaulo			      IEEE80211_RATECTL_TX_SUCCESS :
9056206358Srpaulo			      IEEE80211_RATECTL_TX_FAILURE,
9057208120Sweongyo			    &retrycnt, 0);
9058203945Sweongyo		}
9059203945Sweongyo		bwn_pio_handle_txeof(mac, status);
9060203945Sweongyo	}
9061203945Sweongyo
9062203945Sweongyo	bwn_phy_txpower_check(mac, 0);
9063203945Sweongyo}
9064203945Sweongyo
9065203945Sweongyostatic uint8_t
9066203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
9067203945Sweongyo{
9068203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
9069203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9070203945Sweongyo	struct bwn_rxhdr4 rxhdr;
9071203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9072203945Sweongyo	struct mbuf *m;
9073203945Sweongyo	uint32_t ctl32, macstat, v32;
9074203945Sweongyo	unsigned int i, padding;
9075209888Sweongyo	uint16_t ctl16, len, totlen, v16;
9076203945Sweongyo	unsigned char *mp;
9077203945Sweongyo	char *data;
9078203945Sweongyo
9079203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
9080203945Sweongyo
9081203945Sweongyo	if (prq->prq_rev >= 8) {
9082203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9083203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
9084203945Sweongyo			return (0);
9085203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9086203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
9087203945Sweongyo		for (i = 0; i < 10; i++) {
9088203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9089203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
9090203945Sweongyo				goto ready;
9091203945Sweongyo			DELAY(10);
9092203945Sweongyo		}
9093203945Sweongyo	} else {
9094203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9095203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
9096203945Sweongyo			return (0);
9097203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
9098203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
9099203945Sweongyo		for (i = 0; i < 10; i++) {
9100203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9101203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
9102203945Sweongyo				goto ready;
9103203945Sweongyo			DELAY(10);
9104203945Sweongyo		}
9105203945Sweongyo	}
9106203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
9107203945Sweongyo	return (1);
9108203945Sweongyoready:
9109203945Sweongyo	if (prq->prq_rev >= 8)
9110204922Sweongyo		siba_read_multi_4(sc->sc_dev, &rxhdr, sizeof(rxhdr),
9111203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9112203945Sweongyo	else
9113204922Sweongyo		siba_read_multi_2(sc->sc_dev, &rxhdr, sizeof(rxhdr),
9114203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9115203945Sweongyo	len = le16toh(rxhdr.frame_len);
9116203945Sweongyo	if (len > 0x700) {
9117203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
9118203945Sweongyo		goto error;
9119203945Sweongyo	}
9120203945Sweongyo	if (len == 0) {
9121203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
9122203945Sweongyo		goto error;
9123203945Sweongyo	}
9124203945Sweongyo
9125203945Sweongyo	macstat = le32toh(rxhdr.mac_status);
9126203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9127203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9128203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
9129203945Sweongyo			goto error;
9130203945Sweongyo		}
9131203945Sweongyo	}
9132203945Sweongyo
9133203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9134209888Sweongyo	totlen = len + padding;
9135209888Sweongyo	KASSERT(totlen <= MCLBYTES, ("too big..\n"));
9136203945Sweongyo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
9137203945Sweongyo	if (m == NULL) {
9138203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
9139203945Sweongyo		goto error;
9140203945Sweongyo	}
9141203945Sweongyo	mp = mtod(m, unsigned char *);
9142203945Sweongyo	if (prq->prq_rev >= 8) {
9143209888Sweongyo		siba_read_multi_4(sc->sc_dev, mp, (totlen & ~3),
9144203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9145209888Sweongyo		if (totlen & 3) {
9146203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
9147209888Sweongyo			data = &(mp[totlen - 1]);
9148209888Sweongyo			switch (totlen & 3) {
9149203945Sweongyo			case 3:
9150203945Sweongyo				*data = (v32 >> 16);
9151203945Sweongyo				data--;
9152203945Sweongyo			case 2:
9153203945Sweongyo				*data = (v32 >> 8);
9154203945Sweongyo				data--;
9155203945Sweongyo			case 1:
9156203945Sweongyo				*data = v32;
9157203945Sweongyo			}
9158203945Sweongyo		}
9159203945Sweongyo	} else {
9160209888Sweongyo		siba_read_multi_2(sc->sc_dev, mp, (totlen & ~1),
9161203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9162209888Sweongyo		if (totlen & 1) {
9163203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
9164209888Sweongyo			mp[totlen - 1] = v16;
9165203945Sweongyo		}
9166203945Sweongyo	}
9167203945Sweongyo
9168203945Sweongyo	m->m_pkthdr.rcvif = ifp;
9169209888Sweongyo	m->m_len = m->m_pkthdr.len = totlen;
9170203945Sweongyo
9171203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
9172203945Sweongyo
9173203945Sweongyo	return (1);
9174203945Sweongyoerror:
9175203945Sweongyo	if (prq->prq_rev >= 8)
9176203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9177203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
9178203945Sweongyo	else
9179203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
9180203945Sweongyo	return (1);
9181203945Sweongyo}
9182203945Sweongyo
9183203945Sweongyostatic int
9184203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
9185203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
9186203945Sweongyo{
9187203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
9188203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9189203945Sweongyo	struct bwn_rxhdr4 *hdr;
9190203945Sweongyo	bus_dmamap_t map;
9191203945Sweongyo	bus_addr_t paddr;
9192203945Sweongyo	struct mbuf *m;
9193203945Sweongyo	int error;
9194203945Sweongyo
9195203945Sweongyo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
9196203945Sweongyo	if (m == NULL) {
9197203945Sweongyo		error = ENOBUFS;
9198203945Sweongyo
9199203945Sweongyo		/*
9200203945Sweongyo		 * If the NIC is up and running, we need to:
9201203945Sweongyo		 * - Clear RX buffer's header.
9202203945Sweongyo		 * - Restore RX descriptor settings.
9203203945Sweongyo		 */
9204203945Sweongyo		if (init)
9205203945Sweongyo			return (error);
9206203945Sweongyo		else
9207203945Sweongyo			goto back;
9208203945Sweongyo	}
9209203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
9210203945Sweongyo
9211203945Sweongyo	bwn_dma_set_redzone(dr, m);
9212203945Sweongyo
9213203945Sweongyo	/*
9214203945Sweongyo	 * Try to load RX buf into temporary DMA map
9215203945Sweongyo	 */
9216203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
9217203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
9218203945Sweongyo	if (error) {
9219203945Sweongyo		m_freem(m);
9220203945Sweongyo
9221203945Sweongyo		/*
9222203945Sweongyo		 * See the comment above
9223203945Sweongyo		 */
9224203945Sweongyo		if (init)
9225203945Sweongyo			return (error);
9226203945Sweongyo		else
9227203945Sweongyo			goto back;
9228203945Sweongyo	}
9229203945Sweongyo
9230203945Sweongyo	if (!init)
9231203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
9232203945Sweongyo	meta->mt_m = m;
9233203945Sweongyo	meta->mt_paddr = paddr;
9234203945Sweongyo
9235203945Sweongyo	/*
9236203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
9237203945Sweongyo	 */
9238203945Sweongyo	map = meta->mt_dmap;
9239203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
9240203945Sweongyo	dr->dr_spare_dmap = map;
9241203945Sweongyo
9242203945Sweongyoback:
9243203945Sweongyo	/*
9244203945Sweongyo	 * Clear RX buf header
9245203945Sweongyo	 */
9246203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
9247203945Sweongyo	bzero(hdr, sizeof(*hdr));
9248203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9249203945Sweongyo	    BUS_DMASYNC_PREWRITE);
9250203945Sweongyo
9251203945Sweongyo	/*
9252203945Sweongyo	 * Setup RX buf descriptor
9253203945Sweongyo	 */
9254203945Sweongyo	dr->setdesc(dr, desc, paddr, meta->mt_m->m_len -
9255203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
9256203945Sweongyo	return (error);
9257203945Sweongyo}
9258203945Sweongyo
9259203945Sweongyostatic void
9260203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
9261203945Sweongyo		 bus_size_t mapsz __unused, int error)
9262203945Sweongyo{
9263203945Sweongyo
9264203945Sweongyo	if (!error) {
9265203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
9266203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
9267203945Sweongyo	}
9268203945Sweongyo}
9269203945Sweongyo
9270203945Sweongyostatic int
9271203945Sweongyobwn_hwrate2ieeerate(int rate)
9272203945Sweongyo{
9273203945Sweongyo
9274203945Sweongyo	switch (rate) {
9275203945Sweongyo	case BWN_CCK_RATE_1MB:
9276203945Sweongyo		return (2);
9277203945Sweongyo	case BWN_CCK_RATE_2MB:
9278203945Sweongyo		return (4);
9279203945Sweongyo	case BWN_CCK_RATE_5MB:
9280203945Sweongyo		return (11);
9281203945Sweongyo	case BWN_CCK_RATE_11MB:
9282203945Sweongyo		return (22);
9283203945Sweongyo	case BWN_OFDM_RATE_6MB:
9284203945Sweongyo		return (12);
9285203945Sweongyo	case BWN_OFDM_RATE_9MB:
9286203945Sweongyo		return (18);
9287203945Sweongyo	case BWN_OFDM_RATE_12MB:
9288203945Sweongyo		return (24);
9289203945Sweongyo	case BWN_OFDM_RATE_18MB:
9290203945Sweongyo		return (36);
9291203945Sweongyo	case BWN_OFDM_RATE_24MB:
9292203945Sweongyo		return (48);
9293203945Sweongyo	case BWN_OFDM_RATE_36MB:
9294203945Sweongyo		return (72);
9295203945Sweongyo	case BWN_OFDM_RATE_48MB:
9296203945Sweongyo		return (96);
9297203945Sweongyo	case BWN_OFDM_RATE_54MB:
9298203945Sweongyo		return (108);
9299203945Sweongyo	default:
9300203945Sweongyo		printf("Ooops\n");
9301203945Sweongyo		return (0);
9302203945Sweongyo	}
9303203945Sweongyo}
9304203945Sweongyo
9305203945Sweongyostatic void
9306203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
9307203945Sweongyo{
9308203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
9309203945Sweongyo	struct bwn_plcp6 *plcp;
9310203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9311203945Sweongyo	struct ieee80211_frame_min *wh;
9312203945Sweongyo	struct ieee80211_node *ni;
9313203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9314203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9315203945Sweongyo	uint32_t macstat;
9316204242Simp	int padding, rate, rssi = 0, noise = 0, type;
9317203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
9318203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
9319204242Simp	static int rx_mac_dec_rpt = 0;
9320203945Sweongyo
9321203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9322203945Sweongyo
9323203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
9324203945Sweongyo	phystat3 = le16toh(rxhdr->phy_status3);
9325203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9326203945Sweongyo	chanstat = le16toh(rxhdr->channel);
9327203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
9328203945Sweongyo
9329203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
9330203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
9331203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
9332203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
9333203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
9334203945Sweongyo		goto drop;
9335203945Sweongyo
9336203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9337203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
9338204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9339204081Sweongyo		    m->m_pkthdr.len);
9340203945Sweongyo		goto drop;
9341203945Sweongyo	}
9342203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
9343203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
9344203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
9345204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9346204081Sweongyo		    m->m_pkthdr.len);
9347203945Sweongyo		goto drop;
9348203945Sweongyo	}
9349203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
9350203945Sweongyo
9351204242Simp	if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
9352204081Sweongyo		device_printf(sc->sc_dev,
9353204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
9354204081Sweongyo		    BWN_ISOLDFMT(mac),
9355204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
9356203945Sweongyo
9357203945Sweongyo	/* XXX calculating RSSI & noise & antenna */
9358203945Sweongyo
9359203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
9360203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
9361203945Sweongyo		    phytype == BWN_PHYTYPE_A);
9362203945Sweongyo	else
9363203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
9364203945Sweongyo	if (rate == -1) {
9365203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
9366203945Sweongyo			goto drop;
9367203945Sweongyo	}
9368203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
9369203945Sweongyo
9370203945Sweongyo	/* RX radio tap */
9371203945Sweongyo	if (ieee80211_radiotap_active(ic))
9372203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
9373203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
9374203945Sweongyo
9375203945Sweongyo	rssi = rxhdr->phy.abg.rssi;	/* XXX incorrect RSSI calculation? */
9376203945Sweongyo	noise = mac->mac_stats.link_noise;
9377203945Sweongyo
9378207176Sweongyo	ifp->if_ipackets++;
9379207176Sweongyo
9380203945Sweongyo	BWN_UNLOCK(sc);
9381203945Sweongyo
9382203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
9383203945Sweongyo	if (ni != NULL) {
9384203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
9385203945Sweongyo		ieee80211_free_node(ni);
9386203945Sweongyo	} else
9387203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
9388203945Sweongyo
9389203945Sweongyo	BWN_LOCK(sc);
9390203945Sweongyo	return;
9391203945Sweongyodrop:
9392203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
9393203945Sweongyo}
9394203945Sweongyo
9395203945Sweongyostatic void
9396203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
9397203945Sweongyo    const struct bwn_txstatus *status)
9398203945Sweongyo{
9399203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9400203945Sweongyo	struct bwn_dma_ring *dr;
9401203945Sweongyo	struct bwn_dmadesc_generic *desc;
9402203945Sweongyo	struct bwn_dmadesc_meta *meta;
9403203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9404203945Sweongyo	struct ieee80211_node *ni;
9405203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9406203945Sweongyo	struct mbuf *m;
9407203945Sweongyo	int slot;
9408203945Sweongyo
9409203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9410203945Sweongyo
9411203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
9412203945Sweongyo	if (dr == NULL) {
9413203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
9414203945Sweongyo		return;
9415203945Sweongyo	}
9416203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
9417203945Sweongyo
9418203945Sweongyo	while (1) {
9419203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
9420203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9421203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
9422203945Sweongyo
9423203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
9424203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
9425203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
9426203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
9427203945Sweongyo
9428203945Sweongyo		if (meta->mt_islast) {
9429203945Sweongyo			KASSERT(meta->mt_m != NULL,
9430203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9431203945Sweongyo
9432203945Sweongyo			ni = meta->mt_ni;
9433203945Sweongyo			m = meta->mt_m;
9434203945Sweongyo			if (ni != NULL) {
9435203945Sweongyo				/*
9436203945Sweongyo				 * Do any tx complete callback. Note this must
9437203945Sweongyo				 * be done before releasing the node reference.
9438203945Sweongyo				 */
9439203945Sweongyo				if (m->m_flags & M_TXCB)
9440203945Sweongyo					ieee80211_process_callback(ni, m, 0);
9441203945Sweongyo				ieee80211_free_node(ni);
9442203945Sweongyo				meta->mt_ni = NULL;
9443203945Sweongyo			}
9444203945Sweongyo			m_freem(m);
9445203945Sweongyo			meta->mt_m = NULL;
9446203945Sweongyo		} else {
9447203945Sweongyo			KASSERT(meta->mt_m == NULL,
9448203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9449203945Sweongyo		}
9450203945Sweongyo
9451203945Sweongyo		dr->dr_usedslot--;
9452203945Sweongyo		if (meta->mt_islast) {
9453203945Sweongyo			ifp->if_opackets++;
9454203945Sweongyo			break;
9455203945Sweongyo		}
9456203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
9457203945Sweongyo	}
9458203945Sweongyo	sc->sc_watchdog_timer = 0;
9459203945Sweongyo	if (dr->dr_stop) {
9460203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
9461203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9462203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9463203945Sweongyo		dr->dr_stop = 0;
9464203945Sweongyo	}
9465203945Sweongyo}
9466203945Sweongyo
9467203945Sweongyostatic void
9468203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
9469203945Sweongyo    const struct bwn_txstatus *status)
9470203945Sweongyo{
9471203945Sweongyo	struct bwn_pio_txqueue *tq;
9472203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9473203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9474203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9475203945Sweongyo
9476203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9477203945Sweongyo
9478203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9479203945Sweongyo	if (tq == NULL)
9480203945Sweongyo		return;
9481203945Sweongyo
9482203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
9483203945Sweongyo	tq->tq_free++;
9484203945Sweongyo
9485203945Sweongyo	if (tp->tp_ni != NULL) {
9486203945Sweongyo		/*
9487203945Sweongyo		 * Do any tx complete callback.  Note this must
9488203945Sweongyo		 * be done before releasing the node reference.
9489203945Sweongyo		 */
9490203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
9491203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
9492203945Sweongyo		ieee80211_free_node(tp->tp_ni);
9493203945Sweongyo		tp->tp_ni = NULL;
9494203945Sweongyo	}
9495203945Sweongyo	m_freem(tp->tp_m);
9496203945Sweongyo	tp->tp_m = NULL;
9497203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
9498203945Sweongyo
9499203945Sweongyo	ifp->if_opackets++;
9500203945Sweongyo
9501203945Sweongyo	sc->sc_watchdog_timer = 0;
9502203945Sweongyo	if (tq->tq_stop) {
9503203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9504203945Sweongyo		tq->tq_stop = 0;
9505203945Sweongyo	}
9506203945Sweongyo}
9507203945Sweongyo
9508203945Sweongyostatic void
9509203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
9510203945Sweongyo{
9511203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9512203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
9513203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9514203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9515203945Sweongyo	unsigned long now;
9516203945Sweongyo	int result;
9517203945Sweongyo
9518203945Sweongyo	BWN_GETTIME(now);
9519203945Sweongyo
9520203945Sweongyo	if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
9521203945Sweongyo		return;
9522203945Sweongyo	phy->nexttime = now + 2 * 1000;
9523203945Sweongyo
9524204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
9525204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306)
9526203945Sweongyo		return;
9527203945Sweongyo
9528203945Sweongyo	if (phy->recalc_txpwr != NULL) {
9529203945Sweongyo		result = phy->recalc_txpwr(mac,
9530203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
9531203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
9532203945Sweongyo			return;
9533203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
9534203945Sweongyo		    ("%s: fail", __func__));
9535203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
9536203945Sweongyo
9537203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
9538203945Sweongyo	}
9539203945Sweongyo}
9540203945Sweongyo
9541203945Sweongyostatic uint16_t
9542203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
9543203945Sweongyo{
9544203945Sweongyo
9545203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
9546203945Sweongyo}
9547203945Sweongyo
9548203945Sweongyostatic uint32_t
9549203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
9550203945Sweongyo{
9551203945Sweongyo
9552203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
9553203945Sweongyo}
9554203945Sweongyo
9555203945Sweongyostatic void
9556203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
9557203945Sweongyo{
9558203945Sweongyo
9559203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
9560203945Sweongyo}
9561203945Sweongyo
9562203945Sweongyostatic void
9563203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
9564203945Sweongyo{
9565203945Sweongyo
9566203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
9567203945Sweongyo}
9568203945Sweongyo
9569203945Sweongyostatic int
9570203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
9571203945Sweongyo{
9572203945Sweongyo
9573203945Sweongyo	switch (rate) {
9574203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
9575203945Sweongyo	case 12:
9576203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9577203945Sweongyo	case 18:
9578203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9579203945Sweongyo	case 24:
9580203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9581203945Sweongyo	case 36:
9582203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9583203945Sweongyo	case 48:
9584203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9585203945Sweongyo	case 72:
9586203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9587203945Sweongyo	case 96:
9588203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9589203945Sweongyo	case 108:
9590203945Sweongyo		return (BWN_OFDM_RATE_54MB);
9591203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
9592203945Sweongyo	case 2:
9593203945Sweongyo		return (BWN_CCK_RATE_1MB);
9594203945Sweongyo	case 4:
9595203945Sweongyo		return (BWN_CCK_RATE_2MB);
9596203945Sweongyo	case 11:
9597203945Sweongyo		return (BWN_CCK_RATE_5MB);
9598203945Sweongyo	case 22:
9599203945Sweongyo		return (BWN_CCK_RATE_11MB);
9600203945Sweongyo	}
9601203945Sweongyo
9602203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
9603203945Sweongyo	return (BWN_CCK_RATE_1MB);
9604203945Sweongyo}
9605203945Sweongyo
9606203945Sweongyostatic int
9607203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
9608203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
9609203945Sweongyo{
9610203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
9611203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9612203945Sweongyo	struct ieee80211_frame *wh;
9613203945Sweongyo	struct ieee80211_frame *protwh;
9614203945Sweongyo	struct ieee80211_frame_cts *cts;
9615203945Sweongyo	struct ieee80211_frame_rts *rts;
9616203945Sweongyo	const struct ieee80211_txparam *tp;
9617203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
9618203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9619203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9620203945Sweongyo	struct mbuf *mprot;
9621203945Sweongyo	unsigned int len;
9622203945Sweongyo	uint32_t macctl = 0;
9623203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
9624203945Sweongyo	uint16_t phyctl = 0;
9625203945Sweongyo	uint8_t rate, rate_fb;
9626203945Sweongyo
9627203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
9628203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
9629203945Sweongyo
9630203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
9631203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
9632203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
9633203945Sweongyo
9634203945Sweongyo	/*
9635203945Sweongyo	 * Find TX rate
9636203945Sweongyo	 */
9637203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
9638203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
9639203945Sweongyo		rate = rate_fb = tp->mgmtrate;
9640203945Sweongyo	else if (ismcast)
9641203945Sweongyo		rate = rate_fb = tp->mcastrate;
9642203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
9643203945Sweongyo		rate = rate_fb = tp->ucastrate;
9644203945Sweongyo	else {
9645206358Srpaulo		rix = ieee80211_ratectl_rate(ni, NULL, 0);
9646203945Sweongyo		rate = ni->ni_txrate;
9647203945Sweongyo
9648203945Sweongyo		if (rix > 0)
9649203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
9650203945Sweongyo			    IEEE80211_RATE_VAL;
9651203945Sweongyo		else
9652203945Sweongyo			rate_fb = rate;
9653203945Sweongyo	}
9654203945Sweongyo
9655203945Sweongyo	sc->sc_tx_rate = rate;
9656203945Sweongyo
9657203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
9658203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
9659203945Sweongyo
9660203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
9661203945Sweongyo	    bwn_plcp_getcck(rate);
9662203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
9663203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
9664203945Sweongyo
9665203945Sweongyo	if ((rate_fb == rate) ||
9666203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
9667203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
9668203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
9669203945Sweongyo	else
9670203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
9671203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
9672203945Sweongyo
9673203945Sweongyo	/* XXX TX encryption */
9674203945Sweongyo	bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
9675203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
9676203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
9677203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
9678203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
9679203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
9680203945Sweongyo
9681203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
9682203945Sweongyo	    BWN_TX_EFT_FB_CCK;
9683203945Sweongyo	txhdr->chan = phy->chan;
9684203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
9685203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
9686203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9687203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
9688203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
9689203945Sweongyo
9690203945Sweongyo	/* XXX TX antenna selection */
9691203945Sweongyo
9692203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
9693203945Sweongyo	case 0:
9694203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
9695203945Sweongyo		break;
9696203945Sweongyo	case 1:
9697203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
9698203945Sweongyo		break;
9699203945Sweongyo	case 2:
9700203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
9701203945Sweongyo		break;
9702203945Sweongyo	case 3:
9703203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
9704203945Sweongyo		break;
9705203945Sweongyo	case 4:
9706203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
9707203945Sweongyo		break;
9708203945Sweongyo	default:
9709203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9710203945Sweongyo	}
9711203945Sweongyo
9712203945Sweongyo	if (!ismcast)
9713203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
9714203945Sweongyo
9715203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
9716203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
9717203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
9718203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
9719203945Sweongyo
9720203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
9721203945Sweongyo		/* XXX RTS rate is always 1MB??? */
9722203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
9723203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
9724203945Sweongyo
9725203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
9726203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
9727203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
9728203945Sweongyo
9729203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
9730203945Sweongyo			cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
9731203945Sweongyo			    (txhdr->body.old.rts_frame) :
9732203945Sweongyo			    (txhdr->body.new.rts_frame));
9733203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
9734203945Sweongyo			    protdur);
9735203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9736203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
9737203945Sweongyo			    mprot->m_pkthdr.len);
9738203945Sweongyo			m_freem(mprot);
9739203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
9740203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
9741203945Sweongyo		} else {
9742203945Sweongyo			rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
9743203945Sweongyo			    (txhdr->body.old.rts_frame) :
9744203945Sweongyo			    (txhdr->body.new.rts_frame));
9745203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
9746203945Sweongyo			    isshort);
9747203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
9748203945Sweongyo			    wh->i_addr2, protdur);
9749203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9750203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
9751203945Sweongyo			    mprot->m_pkthdr.len);
9752203945Sweongyo			m_freem(mprot);
9753203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
9754203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
9755203945Sweongyo		}
9756203945Sweongyo		len += IEEE80211_CRC_LEN;
9757203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
9758203945Sweongyo		    &txhdr->body.old.rts_plcp :
9759203945Sweongyo		    &txhdr->body.new.rts_plcp), len, rts_rate);
9760203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
9761203945Sweongyo		    rts_rate_fb);
9762203945Sweongyo
9763203945Sweongyo		protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
9764203945Sweongyo		    (&txhdr->body.old.rts_frame) :
9765203945Sweongyo		    (&txhdr->body.new.rts_frame));
9766203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
9767203945Sweongyo
9768203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
9769203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
9770203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
9771203945Sweongyo		} else {
9772203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
9773203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
9774203945Sweongyo		}
9775203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
9776203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
9777203945Sweongyo	}
9778203945Sweongyo
9779203945Sweongyo	if (BWN_ISOLDFMT(mac))
9780203945Sweongyo		txhdr->body.old.cookie = htole16(cookie);
9781203945Sweongyo	else
9782203945Sweongyo		txhdr->body.new.cookie = htole16(cookie);
9783203945Sweongyo
9784203945Sweongyo	txhdr->macctl = htole32(macctl);
9785203945Sweongyo	txhdr->phyctl = htole16(phyctl);
9786203945Sweongyo
9787203945Sweongyo	/*
9788203945Sweongyo	 * TX radio tap
9789203945Sweongyo	 */
9790203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
9791203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
9792203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
9793203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
9794203945Sweongyo		if (isshort &&
9795203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9796203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
9797203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
9798203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
9799203945Sweongyo
9800203945Sweongyo		ieee80211_radiotap_tx(vap, m);
9801203945Sweongyo	}
9802203945Sweongyo
9803203945Sweongyo	return (0);
9804203945Sweongyo}
9805203945Sweongyo
9806203945Sweongyostatic void
9807203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
9808203945Sweongyo    const uint8_t rate)
9809203945Sweongyo{
9810203945Sweongyo	uint32_t d, plen;
9811203945Sweongyo	uint8_t *raw = plcp->o.raw;
9812203945Sweongyo
9813203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
9814203945Sweongyo		d = bwn_plcp_getofdm(rate);
9815203945Sweongyo		KASSERT(!(octets & 0xf000),
9816203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9817203945Sweongyo		d |= (octets << 5);
9818203945Sweongyo		plcp->o.data = htole32(d);
9819203945Sweongyo	} else {
9820203945Sweongyo		plen = octets * 16 / rate;
9821203945Sweongyo		if ((octets * 16 % rate) > 0) {
9822203945Sweongyo			plen++;
9823203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
9824203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
9825203945Sweongyo				raw[1] = 0x84;
9826203945Sweongyo			} else
9827203945Sweongyo				raw[1] = 0x04;
9828203945Sweongyo		} else
9829203945Sweongyo			raw[1] = 0x04;
9830203945Sweongyo		plcp->o.data |= htole32(plen << 16);
9831203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
9832203945Sweongyo	}
9833203945Sweongyo}
9834203945Sweongyo
9835203945Sweongyostatic uint8_t
9836203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
9837203945Sweongyo{
9838204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9839203945Sweongyo	uint8_t mask;
9840203945Sweongyo
9841203945Sweongyo	if (n == 0)
9842203945Sweongyo		return (0);
9843203945Sweongyo	if (mac->mac_phy.gmode)
9844204922Sweongyo		mask = siba_sprom_get_ant_bg(sc->sc_dev);
9845203945Sweongyo	else
9846204922Sweongyo		mask = siba_sprom_get_ant_a(sc->sc_dev);
9847203945Sweongyo	if (!(mask & (1 << (n - 1))))
9848203945Sweongyo		return (0);
9849203945Sweongyo	return (n);
9850203945Sweongyo}
9851203945Sweongyo
9852203945Sweongyostatic uint8_t
9853203945Sweongyobwn_get_fbrate(uint8_t bitrate)
9854203945Sweongyo{
9855203945Sweongyo	switch (bitrate) {
9856203945Sweongyo	case BWN_CCK_RATE_1MB:
9857203945Sweongyo		return (BWN_CCK_RATE_1MB);
9858203945Sweongyo	case BWN_CCK_RATE_2MB:
9859203945Sweongyo		return (BWN_CCK_RATE_1MB);
9860203945Sweongyo	case BWN_CCK_RATE_5MB:
9861203945Sweongyo		return (BWN_CCK_RATE_2MB);
9862203945Sweongyo	case BWN_CCK_RATE_11MB:
9863203945Sweongyo		return (BWN_CCK_RATE_5MB);
9864203945Sweongyo	case BWN_OFDM_RATE_6MB:
9865203945Sweongyo		return (BWN_CCK_RATE_5MB);
9866203945Sweongyo	case BWN_OFDM_RATE_9MB:
9867203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9868203945Sweongyo	case BWN_OFDM_RATE_12MB:
9869203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9870203945Sweongyo	case BWN_OFDM_RATE_18MB:
9871203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9872203945Sweongyo	case BWN_OFDM_RATE_24MB:
9873203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9874203945Sweongyo	case BWN_OFDM_RATE_36MB:
9875203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9876203945Sweongyo	case BWN_OFDM_RATE_48MB:
9877203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9878203945Sweongyo	case BWN_OFDM_RATE_54MB:
9879203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9880203945Sweongyo	}
9881203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9882203945Sweongyo	return (0);
9883203945Sweongyo}
9884203945Sweongyo
9885203945Sweongyostatic uint32_t
9886203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9887203945Sweongyo    uint32_t ctl, const void *_data, int len)
9888203945Sweongyo{
9889204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9890203945Sweongyo	uint32_t value = 0;
9891203945Sweongyo	const uint8_t *data = _data;
9892203945Sweongyo
9893203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
9894203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
9895203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9896203945Sweongyo
9897204922Sweongyo	siba_write_multi_4(sc->sc_dev, data, (len & ~3),
9898203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
9899203945Sweongyo	if (len & 3) {
9900203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
9901203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
9902203945Sweongyo		data = &(data[len - 1]);
9903203945Sweongyo		switch (len & 3) {
9904203945Sweongyo		case 3:
9905203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
9906203945Sweongyo			value |= (uint32_t)(*data) << 16;
9907203945Sweongyo			data--;
9908203945Sweongyo		case 2:
9909203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
9910203945Sweongyo			value |= (uint32_t)(*data) << 8;
9911203945Sweongyo			data--;
9912203945Sweongyo		case 1:
9913203945Sweongyo			value |= (uint32_t)(*data);
9914203945Sweongyo		}
9915203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9916203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
9917203945Sweongyo	}
9918203945Sweongyo
9919203945Sweongyo	return (ctl);
9920203945Sweongyo}
9921203945Sweongyo
9922203945Sweongyostatic void
9923203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9924203945Sweongyo    uint16_t offset, uint32_t value)
9925203945Sweongyo{
9926203945Sweongyo
9927203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
9928203945Sweongyo}
9929203945Sweongyo
9930203945Sweongyostatic uint16_t
9931203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9932203945Sweongyo    uint16_t ctl, const void *_data, int len)
9933203945Sweongyo{
9934204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9935203945Sweongyo	const uint8_t *data = _data;
9936203945Sweongyo
9937203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
9938203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9939203945Sweongyo
9940204922Sweongyo	siba_write_multi_2(sc->sc_dev, data, (len & ~1),
9941203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
9942203945Sweongyo	if (len & 1) {
9943203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
9944203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9945203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
9946203945Sweongyo	}
9947203945Sweongyo
9948203945Sweongyo	return (ctl);
9949203945Sweongyo}
9950203945Sweongyo
9951203945Sweongyostatic uint16_t
9952203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9953203945Sweongyo    uint16_t ctl, struct mbuf *m0)
9954203945Sweongyo{
9955203945Sweongyo	int i, j = 0;
9956203945Sweongyo	uint16_t data = 0;
9957203945Sweongyo	const uint8_t *buf;
9958203945Sweongyo	struct mbuf *m = m0;
9959203945Sweongyo
9960203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
9961203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9962203945Sweongyo
9963203945Sweongyo	for (; m != NULL; m = m->m_next) {
9964203945Sweongyo		buf = mtod(m, const uint8_t *);
9965203945Sweongyo		for (i = 0; i < m->m_len; i++) {
9966203945Sweongyo			if (!((j++) % 2))
9967203945Sweongyo				data |= buf[i];
9968203945Sweongyo			else {
9969203945Sweongyo				data |= (buf[i] << 8);
9970203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
9971203945Sweongyo				data = 0;
9972203945Sweongyo			}
9973203945Sweongyo		}
9974203945Sweongyo	}
9975203945Sweongyo	if (m0->m_pkthdr.len % 2) {
9976203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
9977203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9978203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
9979203945Sweongyo	}
9980203945Sweongyo
9981203945Sweongyo	return (ctl);
9982203945Sweongyo}
9983203945Sweongyo
9984203945Sweongyostatic void
9985203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
9986203945Sweongyo{
9987203945Sweongyo
9988203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
9989203945Sweongyo		return;
9990203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
9991203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
9992203945Sweongyo}
9993203945Sweongyo
9994203945Sweongyostatic struct bwn_dma_ring *
9995203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
9996203945Sweongyo{
9997203945Sweongyo
9998203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
9999203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
10000203945Sweongyo
10001203945Sweongyo	switch (prio) {
10002203945Sweongyo	case 3:
10003203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
10004203945Sweongyo	case 2:
10005203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
10006203945Sweongyo	case 0:
10007203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
10008203945Sweongyo	case 1:
10009203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
10010203945Sweongyo	}
10011203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
10012204242Simp	return (NULL);
10013203945Sweongyo}
10014203945Sweongyo
10015203945Sweongyostatic int
10016203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
10017203945Sweongyo{
10018203945Sweongyo	int slot;
10019203945Sweongyo
10020204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
10021203945Sweongyo
10022203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
10023203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
10024203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
10025203945Sweongyo
10026203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
10027203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
10028203945Sweongyo	dr->dr_curslot = slot;
10029203945Sweongyo	dr->dr_usedslot++;
10030203945Sweongyo
10031203945Sweongyo	return (slot);
10032203945Sweongyo}
10033203945Sweongyo
10034203945Sweongyostatic int
10035203945Sweongyobwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
10036203945Sweongyo{
10037203945Sweongyo	const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
10038203945Sweongyo	unsigned int a, b, c, d;
10039203945Sweongyo	unsigned int avg;
10040203945Sweongyo	uint32_t tmp;
10041203945Sweongyo
10042203945Sweongyo	tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
10043203945Sweongyo	a = tmp & 0xff;
10044203945Sweongyo	b = (tmp >> 8) & 0xff;
10045203945Sweongyo	c = (tmp >> 16) & 0xff;
10046203945Sweongyo	d = (tmp >> 24) & 0xff;
10047203945Sweongyo	if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
10048203945Sweongyo	    c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
10049203945Sweongyo		return (ENOENT);
10050203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
10051203945Sweongyo	    BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
10052203945Sweongyo	    (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
10053203945Sweongyo
10054203945Sweongyo	if (ofdm) {
10055203945Sweongyo		a = (a + 32) & 0x3f;
10056203945Sweongyo		b = (b + 32) & 0x3f;
10057203945Sweongyo		c = (c + 32) & 0x3f;
10058203945Sweongyo		d = (d + 32) & 0x3f;
10059203945Sweongyo	}
10060203945Sweongyo
10061203945Sweongyo	avg = (a + b + c + d + 2) / 4;
10062203945Sweongyo	if (ofdm) {
10063203945Sweongyo		if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
10064203945Sweongyo		    & BWN_HF_4DB_CCK_POWERBOOST)
10065203945Sweongyo			avg = (avg >= 13) ? (avg - 13) : 0;
10066203945Sweongyo	}
10067203945Sweongyo	return (avg);
10068203945Sweongyo}
10069203945Sweongyo
10070203945Sweongyostatic void
10071203945Sweongyobwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
10072203945Sweongyo{
10073203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
10074203945Sweongyo	int rfatt = *rfattp;
10075203945Sweongyo	int bbatt = *bbattp;
10076203945Sweongyo
10077203945Sweongyo	while (1) {
10078203945Sweongyo		if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
10079203945Sweongyo			break;
10080203945Sweongyo		if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
10081203945Sweongyo			break;
10082203945Sweongyo		if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
10083203945Sweongyo			break;
10084203945Sweongyo		if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
10085203945Sweongyo			break;
10086203945Sweongyo		if (bbatt > lo->bbatt.max) {
10087203945Sweongyo			bbatt -= 4;
10088203945Sweongyo			rfatt += 1;
10089203945Sweongyo			continue;
10090203945Sweongyo		}
10091203945Sweongyo		if (bbatt < lo->bbatt.min) {
10092203945Sweongyo			bbatt += 4;
10093203945Sweongyo			rfatt -= 1;
10094203945Sweongyo			continue;
10095203945Sweongyo		}
10096203945Sweongyo		if (rfatt > lo->rfatt.max) {
10097203945Sweongyo			rfatt -= 1;
10098203945Sweongyo			bbatt += 4;
10099203945Sweongyo			continue;
10100203945Sweongyo		}
10101203945Sweongyo		if (rfatt < lo->rfatt.min) {
10102203945Sweongyo			rfatt += 1;
10103203945Sweongyo			bbatt -= 4;
10104203945Sweongyo			continue;
10105203945Sweongyo		}
10106203945Sweongyo		break;
10107203945Sweongyo	}
10108203945Sweongyo
10109203945Sweongyo	*rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
10110203945Sweongyo	*bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
10111203945Sweongyo}
10112203945Sweongyo
10113203945Sweongyostatic void
10114203945Sweongyobwn_phy_lock(struct bwn_mac *mac)
10115203945Sweongyo{
10116203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10117203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10118203945Sweongyo
10119204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
10120204922Sweongyo	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
10121203945Sweongyo
10122203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10123203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
10124203945Sweongyo}
10125203945Sweongyo
10126203945Sweongyostatic void
10127203945Sweongyobwn_phy_unlock(struct bwn_mac *mac)
10128203945Sweongyo{
10129203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10130203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10131203945Sweongyo
10132204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
10133204922Sweongyo	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
10134203945Sweongyo
10135203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10136203945Sweongyo		bwn_psctl(mac, 0);
10137203945Sweongyo}
10138203945Sweongyo
10139203945Sweongyostatic void
10140203945Sweongyobwn_rf_lock(struct bwn_mac *mac)
10141203945Sweongyo{
10142203945Sweongyo
10143203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10144203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
10145203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
10146203945Sweongyo	DELAY(10);
10147203945Sweongyo}
10148203945Sweongyo
10149203945Sweongyostatic void
10150203945Sweongyobwn_rf_unlock(struct bwn_mac *mac)
10151203945Sweongyo{
10152203945Sweongyo
10153203945Sweongyo	BWN_READ_2(mac, BWN_PHYVER);
10154203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10155203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
10156203945Sweongyo}
10157203945Sweongyo
10158203945Sweongyostatic struct bwn_pio_txqueue *
10159203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
10160203945Sweongyo    struct bwn_pio_txpkt **pack)
10161203945Sweongyo{
10162203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
10163203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
10164203945Sweongyo	unsigned int index;
10165203945Sweongyo
10166203945Sweongyo	switch (cookie & 0xf000) {
10167203945Sweongyo	case 0x1000:
10168203945Sweongyo		tq = &pio->wme[WME_AC_BK];
10169203945Sweongyo		break;
10170203945Sweongyo	case 0x2000:
10171203945Sweongyo		tq = &pio->wme[WME_AC_BE];
10172203945Sweongyo		break;
10173203945Sweongyo	case 0x3000:
10174203945Sweongyo		tq = &pio->wme[WME_AC_VI];
10175203945Sweongyo		break;
10176203945Sweongyo	case 0x4000:
10177203945Sweongyo		tq = &pio->wme[WME_AC_VO];
10178203945Sweongyo		break;
10179203945Sweongyo	case 0x5000:
10180203945Sweongyo		tq = &pio->mcast;
10181203945Sweongyo		break;
10182203945Sweongyo	}
10183203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
10184203945Sweongyo	if (tq == NULL)
10185203945Sweongyo		return (NULL);
10186203945Sweongyo	index = (cookie & 0x0fff);
10187203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
10188203945Sweongyo	if (index >= N(tq->tq_pkts))
10189203945Sweongyo		return (NULL);
10190203945Sweongyo	*pack = &tq->tq_pkts[index];
10191203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
10192203945Sweongyo	return (tq);
10193203945Sweongyo}
10194203945Sweongyo
10195203945Sweongyostatic void
10196203945Sweongyobwn_txpwr(void *arg, int npending)
10197203945Sweongyo{
10198203945Sweongyo	struct bwn_mac *mac = arg;
10199203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10200203945Sweongyo
10201203945Sweongyo	BWN_LOCK(sc);
10202203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
10203203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
10204203945Sweongyo		mac->mac_phy.set_txpwr(mac);
10205203945Sweongyo	BWN_UNLOCK(sc);
10206203945Sweongyo}
10207203945Sweongyo
10208203945Sweongyostatic void
10209203945Sweongyobwn_task_15s(struct bwn_mac *mac)
10210203945Sweongyo{
10211203945Sweongyo	uint16_t reg;
10212203945Sweongyo
10213203945Sweongyo	if (mac->mac_fw.opensource) {
10214203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
10215203945Sweongyo		if (reg) {
10216203945Sweongyo			bwn_restart(mac, "fw watchdog");
10217203945Sweongyo			return;
10218203945Sweongyo		}
10219203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
10220203945Sweongyo	}
10221203945Sweongyo	if (mac->mac_phy.task_15s)
10222203945Sweongyo		mac->mac_phy.task_15s(mac);
10223203945Sweongyo
10224203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
10225203945Sweongyo}
10226203945Sweongyo
10227203945Sweongyostatic void
10228203945Sweongyobwn_task_30s(struct bwn_mac *mac)
10229203945Sweongyo{
10230203945Sweongyo
10231203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
10232203945Sweongyo		return;
10233203945Sweongyo	mac->mac_noise.noi_running = 1;
10234203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
10235203945Sweongyo
10236203945Sweongyo	bwn_noise_gensample(mac);
10237203945Sweongyo}
10238203945Sweongyo
10239203945Sweongyostatic void
10240203945Sweongyobwn_task_60s(struct bwn_mac *mac)
10241203945Sweongyo{
10242203945Sweongyo
10243203945Sweongyo	if (mac->mac_phy.task_60s)
10244203945Sweongyo		mac->mac_phy.task_60s(mac);
10245203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
10246203945Sweongyo}
10247203945Sweongyo
10248203945Sweongyostatic void
10249203945Sweongyobwn_tasks(void *arg)
10250203945Sweongyo{
10251203945Sweongyo	struct bwn_mac *mac = arg;
10252203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10253203945Sweongyo
10254203945Sweongyo	BWN_ASSERT_LOCKED(sc);
10255203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
10256203945Sweongyo		return;
10257203945Sweongyo
10258203945Sweongyo	if (mac->mac_task_state % 4 == 0)
10259203945Sweongyo		bwn_task_60s(mac);
10260203945Sweongyo	if (mac->mac_task_state % 2 == 0)
10261203945Sweongyo		bwn_task_30s(mac);
10262203945Sweongyo	bwn_task_15s(mac);
10263203945Sweongyo
10264203945Sweongyo	mac->mac_task_state++;
10265203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
10266203945Sweongyo}
10267203945Sweongyo
10268203945Sweongyostatic int
10269203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
10270203945Sweongyo{
10271203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10272203945Sweongyo
10273203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
10274203945Sweongyo
10275203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
10276203945Sweongyo	case 0xb:
10277203945Sweongyo		return (BWN_OFDM_RATE_6MB);
10278203945Sweongyo	case 0xf:
10279203945Sweongyo		return (BWN_OFDM_RATE_9MB);
10280203945Sweongyo	case 0xa:
10281203945Sweongyo		return (BWN_OFDM_RATE_12MB);
10282203945Sweongyo	case 0xe:
10283203945Sweongyo		return (BWN_OFDM_RATE_18MB);
10284203945Sweongyo	case 0x9:
10285203945Sweongyo		return (BWN_OFDM_RATE_24MB);
10286203945Sweongyo	case 0xd:
10287203945Sweongyo		return (BWN_OFDM_RATE_36MB);
10288203945Sweongyo	case 0x8:
10289203945Sweongyo		return (BWN_OFDM_RATE_48MB);
10290203945Sweongyo	case 0xc:
10291203945Sweongyo		return (BWN_OFDM_RATE_54MB);
10292203945Sweongyo	}
10293203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
10294203945Sweongyo	    plcp->o.raw[0] & 0xf);
10295203945Sweongyo	return (-1);
10296203945Sweongyo}
10297203945Sweongyo
10298203945Sweongyostatic int
10299203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
10300203945Sweongyo{
10301203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10302203945Sweongyo
10303203945Sweongyo	switch (plcp->o.raw[0]) {
10304203945Sweongyo	case 0x0a:
10305203945Sweongyo		return (BWN_CCK_RATE_1MB);
10306203945Sweongyo	case 0x14:
10307203945Sweongyo		return (BWN_CCK_RATE_2MB);
10308203945Sweongyo	case 0x37:
10309203945Sweongyo		return (BWN_CCK_RATE_5MB);
10310203945Sweongyo	case 0x6e:
10311203945Sweongyo		return (BWN_CCK_RATE_11MB);
10312203945Sweongyo	}
10313203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
10314203945Sweongyo	return (-1);
10315203945Sweongyo}
10316203945Sweongyo
10317203945Sweongyostatic void
10318203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
10319203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
10320203945Sweongyo    int rssi, int noise)
10321203945Sweongyo{
10322203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10323203945Sweongyo	const struct ieee80211_frame_min *wh;
10324203945Sweongyo	uint64_t tsf;
10325203945Sweongyo	uint16_t low_mactime_now;
10326203945Sweongyo
10327203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
10328203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
10329203945Sweongyo
10330203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
10331203945Sweongyo	if (wh->i_fc[1] & IEEE80211_FC1_WEP)
10332203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
10333203945Sweongyo
10334203945Sweongyo	bwn_tsf_read(mac, &tsf);
10335203945Sweongyo	low_mactime_now = tsf;
10336203945Sweongyo	tsf = tsf & ~0xffffULL;
10337203945Sweongyo	tsf += le16toh(rxhdr->mac_time);
10338203945Sweongyo	if (low_mactime_now < le16toh(rxhdr->mac_time))
10339203945Sweongyo		tsf -= 0x10000;
10340203945Sweongyo
10341203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
10342203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
10343203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
10344203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
10345203945Sweongyo}
10346203945Sweongyo
10347203945Sweongyostatic void
10348203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
10349203945Sweongyo{
10350203945Sweongyo	uint32_t low, high;
10351203945Sweongyo
10352204983Syongari	KASSERT(siba_get_revid(mac->mac_sc->sc_dev) >= 3,
10353203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
10354203945Sweongyo
10355203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
10356203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
10357203945Sweongyo	*tsf = high;
10358203945Sweongyo	*tsf <<= 32;
10359203945Sweongyo	*tsf |= low;
10360203945Sweongyo}
10361203945Sweongyo
10362203945Sweongyostatic int
10363203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
10364203945Sweongyo{
10365203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10366203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10367203945Sweongyo	bus_addr_t lowaddr = 0;
10368203945Sweongyo	int error;
10369203945Sweongyo
10370204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
10371203945Sweongyo		return (0);
10372203945Sweongyo
10373204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5, ("%s: fail", __func__));
10374203945Sweongyo
10375203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
10376203945Sweongyo
10377203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
10378203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
10379203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
10380203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
10381203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
10382203945Sweongyo	else
10383203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
10384203945Sweongyo
10385203945Sweongyo	/*
10386203945Sweongyo	 * Create top level DMA tag
10387203945Sweongyo	 */
10388203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
10389203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
10390203945Sweongyo			       lowaddr,			/* lowaddr */
10391203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
10392203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
10393203945Sweongyo			       MAXBSIZE,		/* maxsize */
10394203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
10395203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
10396203945Sweongyo			       0,			/* flags */
10397203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
10398203945Sweongyo			       &dma->parent_dtag);
10399203945Sweongyo	if (error) {
10400203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
10401203945Sweongyo		return (error);
10402203945Sweongyo	}
10403203945Sweongyo
10404203945Sweongyo	/*
10405203945Sweongyo	 * Create TX/RX mbuf DMA tag
10406203945Sweongyo	 */
10407203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10408203945Sweongyo				1,
10409203945Sweongyo				0,
10410203945Sweongyo				BUS_SPACE_MAXADDR,
10411203945Sweongyo				BUS_SPACE_MAXADDR,
10412203945Sweongyo				NULL, NULL,
10413203945Sweongyo				MCLBYTES,
10414203945Sweongyo				1,
10415203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10416203945Sweongyo				0,
10417203945Sweongyo				NULL, NULL,
10418203945Sweongyo				&dma->rxbuf_dtag);
10419203945Sweongyo	if (error) {
10420203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10421203945Sweongyo		goto fail0;
10422203945Sweongyo	}
10423203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10424203945Sweongyo				1,
10425203945Sweongyo				0,
10426203945Sweongyo				BUS_SPACE_MAXADDR,
10427203945Sweongyo				BUS_SPACE_MAXADDR,
10428203945Sweongyo				NULL, NULL,
10429203945Sweongyo				MCLBYTES,
10430203945Sweongyo				1,
10431203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10432203945Sweongyo				0,
10433203945Sweongyo				NULL, NULL,
10434203945Sweongyo				&dma->txbuf_dtag);
10435203945Sweongyo	if (error) {
10436203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10437203945Sweongyo		goto fail1;
10438203945Sweongyo	}
10439203945Sweongyo
10440203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
10441203945Sweongyo	if (!dma->wme[WME_AC_BK])
10442203945Sweongyo		goto fail2;
10443203945Sweongyo
10444203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
10445203945Sweongyo	if (!dma->wme[WME_AC_BE])
10446203945Sweongyo		goto fail3;
10447203945Sweongyo
10448203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
10449203945Sweongyo	if (!dma->wme[WME_AC_VI])
10450203945Sweongyo		goto fail4;
10451203945Sweongyo
10452203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
10453203945Sweongyo	if (!dma->wme[WME_AC_VO])
10454203945Sweongyo		goto fail5;
10455203945Sweongyo
10456203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
10457203945Sweongyo	if (!dma->mcast)
10458203945Sweongyo		goto fail6;
10459203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
10460203945Sweongyo	if (!dma->rx)
10461203945Sweongyo		goto fail7;
10462203945Sweongyo
10463203945Sweongyo	return (error);
10464203945Sweongyo
10465203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
10466203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
10467203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
10468203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
10469203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
10470203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
10471203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
10472203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
10473203945Sweongyo	return (error);
10474203945Sweongyo}
10475203945Sweongyo
10476203945Sweongyostatic struct bwn_dma_ring *
10477203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
10478203945Sweongyo    uint16_t cookie, int *slot)
10479203945Sweongyo{
10480203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10481203945Sweongyo	struct bwn_dma_ring *dr;
10482203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10483203945Sweongyo
10484203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
10485203945Sweongyo
10486203945Sweongyo	switch (cookie & 0xf000) {
10487203945Sweongyo	case 0x1000:
10488203945Sweongyo		dr = dma->wme[WME_AC_BK];
10489203945Sweongyo		break;
10490203945Sweongyo	case 0x2000:
10491203945Sweongyo		dr = dma->wme[WME_AC_BE];
10492203945Sweongyo		break;
10493203945Sweongyo	case 0x3000:
10494203945Sweongyo		dr = dma->wme[WME_AC_VI];
10495203945Sweongyo		break;
10496203945Sweongyo	case 0x4000:
10497203945Sweongyo		dr = dma->wme[WME_AC_VO];
10498203945Sweongyo		break;
10499203945Sweongyo	case 0x5000:
10500203945Sweongyo		dr = dma->mcast;
10501203945Sweongyo		break;
10502203945Sweongyo	default:
10503204242Simp		dr = NULL;
10504203945Sweongyo		KASSERT(0 == 1,
10505203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
10506203945Sweongyo	}
10507203945Sweongyo	*slot = (cookie & 0x0fff);
10508203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
10509203945Sweongyo		/*
10510203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
10511203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
10512203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
10513203945Sweongyo		 */
10514203945Sweongyo		KASSERT(status->seq == dma->lastseq,
10515203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
10516203945Sweongyo		device_printf(sc->sc_dev,
10517203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
10518203945Sweongyo		    dr->dr_numslots);
10519203945Sweongyo		return (NULL);
10520203945Sweongyo	}
10521203945Sweongyo	dma->lastseq = status->seq;
10522203945Sweongyo	return (dr);
10523203945Sweongyo}
10524203945Sweongyo
10525203945Sweongyostatic void
10526203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
10527203945Sweongyo{
10528203945Sweongyo	struct bwn_dma *dma;
10529203945Sweongyo
10530203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
10531203945Sweongyo		return;
10532203945Sweongyo	dma = &mac->mac_method.dma;
10533203945Sweongyo
10534203945Sweongyo	bwn_dma_ringstop(&dma->rx);
10535203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
10536203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
10537203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
10538203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
10539203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
10540203945Sweongyo}
10541203945Sweongyo
10542203945Sweongyostatic void
10543203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
10544203945Sweongyo{
10545203945Sweongyo
10546203945Sweongyo	if (dr == NULL)
10547203945Sweongyo		return;
10548203945Sweongyo
10549203945Sweongyo	bwn_dma_cleanup(*dr);
10550203945Sweongyo}
10551203945Sweongyo
10552203945Sweongyostatic void
10553203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
10554203945Sweongyo{
10555203945Sweongyo	struct bwn_pio *pio;
10556203945Sweongyo
10557203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
10558203945Sweongyo		return;
10559203945Sweongyo	pio = &mac->mac_method.pio;
10560203945Sweongyo
10561203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
10562203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
10563203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
10564203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
10565203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
10566203945Sweongyo}
10567203945Sweongyo
10568203945Sweongyostatic void
10569203945Sweongyobwn_led_attach(struct bwn_mac *mac)
10570203945Sweongyo{
10571203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10572203945Sweongyo	const uint8_t *led_act = NULL;
10573203945Sweongyo	uint16_t val[BWN_LED_MAX];
10574203945Sweongyo	int i;
10575203945Sweongyo
10576203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
10577203945Sweongyo	sc->sc_led_blink = 1;
10578203945Sweongyo
10579203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
10580204922Sweongyo		if (siba_get_pci_subvendor(sc->sc_dev) ==
10581204922Sweongyo		    bwn_vendor_led_act[i].vid) {
10582203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
10583203945Sweongyo			break;
10584203945Sweongyo		}
10585203945Sweongyo	}
10586203945Sweongyo	if (led_act == NULL)
10587203945Sweongyo		led_act = bwn_default_led_act;
10588203945Sweongyo
10589204922Sweongyo	val[0] = siba_sprom_get_gpio0(sc->sc_dev);
10590204922Sweongyo	val[1] = siba_sprom_get_gpio1(sc->sc_dev);
10591204922Sweongyo	val[2] = siba_sprom_get_gpio2(sc->sc_dev);
10592204922Sweongyo	val[3] = siba_sprom_get_gpio3(sc->sc_dev);
10593203945Sweongyo
10594203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10595203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10596203945Sweongyo
10597203945Sweongyo		if (val[i] == 0xff) {
10598203945Sweongyo			led->led_act = led_act[i];
10599203945Sweongyo		} else {
10600203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
10601203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
10602203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
10603203945Sweongyo		}
10604203945Sweongyo		led->led_mask = (1 << i);
10605203945Sweongyo
10606203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
10607203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
10608203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
10609203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
10610203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
10611203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
10612203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
10613203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
10614203945Sweongyo
10615203945Sweongyo			if (sc->sc_blink_led == NULL) {
10616203945Sweongyo				sc->sc_blink_led = led;
10617203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
10618203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
10619203945Sweongyo			}
10620203945Sweongyo		}
10621203945Sweongyo
10622203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
10623203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
10624203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
10625203945Sweongyo	}
10626203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
10627203945Sweongyo}
10628203945Sweongyo
10629203945Sweongyostatic __inline uint16_t
10630203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
10631203945Sweongyo{
10632203945Sweongyo
10633203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
10634203945Sweongyo		on = !on;
10635203945Sweongyo	if (on)
10636203945Sweongyo		val |= led->led_mask;
10637203945Sweongyo	else
10638203945Sweongyo		val &= ~led->led_mask;
10639203945Sweongyo	return val;
10640203945Sweongyo}
10641203945Sweongyo
10642203945Sweongyostatic void
10643203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
10644203945Sweongyo{
10645203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10646203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10647203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10648203945Sweongyo	uint16_t val;
10649203945Sweongyo	int i;
10650203945Sweongyo
10651203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
10652203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
10653203945Sweongyo		sc->sc_led_blinking = 0;
10654203945Sweongyo	}
10655203945Sweongyo
10656203945Sweongyo	if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
10657203945Sweongyo		return;
10658203945Sweongyo
10659203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10660203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10661203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10662203945Sweongyo		int on;
10663203945Sweongyo
10664203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
10665203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
10666203945Sweongyo			continue;
10667203945Sweongyo
10668203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
10669203945Sweongyo		    nstate != IEEE80211_S_INIT)
10670203945Sweongyo			continue;
10671203945Sweongyo
10672203945Sweongyo		switch (led->led_act) {
10673203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
10674203945Sweongyo			on = 1;
10675203945Sweongyo			break;
10676203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
10677203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
10678203945Sweongyo			on = 0;
10679203945Sweongyo			break;
10680203945Sweongyo		default:
10681203945Sweongyo			on = 1;
10682203945Sweongyo			switch (nstate) {
10683203945Sweongyo			case IEEE80211_S_INIT:
10684203945Sweongyo				on = 0;
10685203945Sweongyo				break;
10686203945Sweongyo			case IEEE80211_S_RUN:
10687203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
10688203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
10689203945Sweongyo					on = 0;
10690203945Sweongyo				break;
10691203945Sweongyo			default:
10692203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
10693203945Sweongyo					on = 0;
10694203945Sweongyo				break;
10695203945Sweongyo			}
10696203945Sweongyo			break;
10697203945Sweongyo		}
10698203945Sweongyo
10699203945Sweongyo		val = bwn_led_onoff(led, val, on);
10700203945Sweongyo	}
10701203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10702203945Sweongyo}
10703203945Sweongyo
10704203945Sweongyostatic void
10705203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
10706203945Sweongyo{
10707203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10708204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
10709204922Sweongyo	int rate;
10710203945Sweongyo
10711204922Sweongyo	if (event == BWN_LED_EVENT_POLL) {
10712204922Sweongyo		if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
10713204922Sweongyo			return;
10714204922Sweongyo		if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
10715204922Sweongyo			return;
10716204922Sweongyo	}
10717203945Sweongyo
10718204922Sweongyo	sc->sc_led_ticks = ticks;
10719204922Sweongyo	if (sc->sc_led_blinking)
10720204922Sweongyo		return;
10721203945Sweongyo
10722204922Sweongyo	switch (event) {
10723204922Sweongyo	case BWN_LED_EVENT_RX:
10724204922Sweongyo		rate = sc->sc_rx_rate;
10725204922Sweongyo		break;
10726204922Sweongyo	case BWN_LED_EVENT_TX:
10727204922Sweongyo		rate = sc->sc_tx_rate;
10728204922Sweongyo		break;
10729204922Sweongyo	case BWN_LED_EVENT_POLL:
10730204922Sweongyo		rate = 0;
10731204922Sweongyo		break;
10732204922Sweongyo	default:
10733204922Sweongyo		panic("unknown LED event %d\n", event);
10734204922Sweongyo		break;
10735204922Sweongyo	}
10736204922Sweongyo	bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
10737204922Sweongyo	    bwn_led_duration[rate].off_dur);
10738203945Sweongyo}
10739203945Sweongyo
10740203945Sweongyostatic void
10741203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
10742203945Sweongyo{
10743203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10744204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
10745204922Sweongyo	uint16_t val;
10746203945Sweongyo
10747204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10748204922Sweongyo	val = bwn_led_onoff(led, val, 1);
10749204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10750203945Sweongyo
10751204922Sweongyo	if (led->led_flags & BWN_LED_F_SLOW) {
10752204922Sweongyo		BWN_LED_SLOWDOWN(on_dur);
10753204922Sweongyo		BWN_LED_SLOWDOWN(off_dur);
10754204922Sweongyo	}
10755203945Sweongyo
10756204922Sweongyo	sc->sc_led_blinking = 1;
10757204922Sweongyo	sc->sc_led_blink_offdur = off_dur;
10758203945Sweongyo
10759204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
10760203945Sweongyo}
10761203945Sweongyo
10762203945Sweongyostatic void
10763203945Sweongyobwn_led_blink_next(void *arg)
10764203945Sweongyo{
10765203945Sweongyo	struct bwn_mac *mac = arg;
10766204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10767204922Sweongyo	uint16_t val;
10768203945Sweongyo
10769204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10770204922Sweongyo	val = bwn_led_onoff(sc->sc_blink_led, val, 0);
10771204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10772203945Sweongyo
10773204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
10774204922Sweongyo	    bwn_led_blink_end, mac);
10775203945Sweongyo}
10776203945Sweongyo
10777203945Sweongyostatic void
10778203945Sweongyobwn_led_blink_end(void *arg)
10779203945Sweongyo{
10780203945Sweongyo	struct bwn_mac *mac = arg;
10781204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10782203945Sweongyo
10783204922Sweongyo	sc->sc_led_blinking = 0;
10784203945Sweongyo}
10785203945Sweongyo
10786203945Sweongyostatic int
10787203945Sweongyobwn_suspend(device_t dev)
10788203945Sweongyo{
10789203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10790203945Sweongyo
10791203945Sweongyo	bwn_stop(sc, 1);
10792203945Sweongyo	return (0);
10793203945Sweongyo}
10794203945Sweongyo
10795203945Sweongyostatic int
10796203945Sweongyobwn_resume(device_t dev)
10797203945Sweongyo{
10798203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10799203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10800203945Sweongyo
10801203945Sweongyo	if (ifp->if_flags & IFF_UP)
10802203945Sweongyo		bwn_init(sc);
10803203945Sweongyo	return (0);
10804203945Sweongyo}
10805203945Sweongyo
10806203945Sweongyostatic void
10807203945Sweongyobwn_rfswitch(void *arg)
10808203945Sweongyo{
10809203945Sweongyo	struct bwn_softc *sc = arg;
10810203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
10811203945Sweongyo	int cur = 0, prev = 0;
10812203945Sweongyo
10813203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
10814203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
10815203945Sweongyo
10816203945Sweongyo	if (mac->mac_phy.rf_rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
10817203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
10818203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
10819203945Sweongyo			cur = 1;
10820203945Sweongyo	} else {
10821203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
10822203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
10823203945Sweongyo			cur = 1;
10824203945Sweongyo	}
10825203945Sweongyo
10826203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
10827203945Sweongyo		prev = 1;
10828203945Sweongyo
10829203945Sweongyo	if (cur != prev) {
10830203945Sweongyo		if (cur)
10831203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
10832203945Sweongyo		else
10833203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
10834203945Sweongyo
10835203945Sweongyo		device_printf(sc->sc_dev,
10836203945Sweongyo		    "status of RF switch is changed to %s\n",
10837203945Sweongyo		    cur ? "ON" : "OFF");
10838203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
10839203945Sweongyo			if (cur)
10840203945Sweongyo				bwn_rf_turnon(mac);
10841203945Sweongyo			else
10842203945Sweongyo				bwn_rf_turnoff(mac);
10843203945Sweongyo		}
10844203945Sweongyo	}
10845203945Sweongyo
10846203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
10847203945Sweongyo}
10848203945Sweongyo
10849203945Sweongyostatic void
10850203945Sweongyobwn_phy_lp_init_pre(struct bwn_mac *mac)
10851203945Sweongyo{
10852203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
10853203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
10854203945Sweongyo
10855203945Sweongyo	plp->plp_antenna = BWN_ANT_DEFAULT;
10856203945Sweongyo}
10857203945Sweongyo
10858203945Sweongyostatic int
10859203945Sweongyobwn_phy_lp_init(struct bwn_mac *mac)
10860203945Sweongyo{
10861203945Sweongyo	static const struct bwn_stxtable tables[] = {
10862203945Sweongyo		{ 2,  6, 0x3d, 3, 0x01 }, { 1, 12, 0x4c, 1, 0x01 },
10863203945Sweongyo		{ 1,  8, 0x50, 0, 0x7f }, { 0,  8, 0x44, 0, 0xff },
10864203945Sweongyo		{ 1,  0, 0x4a, 0, 0xff }, { 0,  4, 0x4d, 0, 0xff },
10865203945Sweongyo		{ 1,  4, 0x4e, 0, 0xff }, { 0, 12, 0x4f, 0, 0x0f },
10866203945Sweongyo		{ 1,  0, 0x4f, 4, 0x0f }, { 3,  0, 0x49, 0, 0x0f },
10867203945Sweongyo		{ 4,  3, 0x46, 4, 0x07 }, { 3, 15, 0x46, 0, 0x01 },
10868203945Sweongyo		{ 4,  0, 0x46, 1, 0x07 }, { 3,  8, 0x48, 4, 0x07 },
10869203945Sweongyo		{ 3, 11, 0x48, 0, 0x0f }, { 3,  4, 0x49, 4, 0x0f },
10870203945Sweongyo		{ 2, 15, 0x45, 0, 0x01 }, { 5, 13, 0x52, 4, 0x07 },
10871203945Sweongyo		{ 6,  0, 0x52, 7, 0x01 }, { 5,  3, 0x41, 5, 0x07 },
10872203945Sweongyo		{ 5,  6, 0x41, 0, 0x0f }, { 5, 10, 0x42, 5, 0x07 },
10873203945Sweongyo		{ 4, 15, 0x42, 0, 0x01 }, { 5,  0, 0x42, 1, 0x07 },
10874203945Sweongyo		{ 4, 11, 0x43, 4, 0x0f }, { 4,  7, 0x43, 0, 0x0f },
10875203945Sweongyo		{ 4,  6, 0x45, 1, 0x01 }, { 2,  7, 0x40, 4, 0x0f },
10876203945Sweongyo		{ 2, 11, 0x40, 0, 0x0f }
10877203945Sweongyo	};
10878203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
10879203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10880203945Sweongyo	const struct bwn_stxtable *st;
10881203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10882203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10883203945Sweongyo	int i, error;
10884203945Sweongyo	uint16_t tmp;
10885203945Sweongyo
10886203945Sweongyo	bwn_phy_lp_readsprom(mac);	/* XXX bad place */
10887203945Sweongyo	bwn_phy_lp_bbinit(mac);
10888203945Sweongyo
10889203945Sweongyo	/* initialize RF */
10890203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_4WIRECTL, 0x2);
10891203945Sweongyo	DELAY(1);
10892203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_4WIRECTL, 0xfffd);
10893203945Sweongyo	DELAY(1);
10894203945Sweongyo
10895203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2062)
10896203945Sweongyo		bwn_phy_lp_b2062_init(mac);
10897203945Sweongyo	else {
10898203945Sweongyo		bwn_phy_lp_b2063_init(mac);
10899203945Sweongyo
10900203945Sweongyo		/* synchronize stx table. */
10901203945Sweongyo		for (i = 0; i < N(tables); i++) {
10902203945Sweongyo			st = &tables[i];
10903203945Sweongyo			tmp = BWN_RF_READ(mac, st->st_rfaddr);
10904203945Sweongyo			tmp >>= st->st_rfshift;
10905203945Sweongyo			tmp <<= st->st_physhift;
10906203945Sweongyo			BWN_PHY_SETMASK(mac,
10907203945Sweongyo			    BWN_PHY_OFDM(0xf2 + st->st_phyoffset),
10908203945Sweongyo			    ~(st->st_mask << st->st_physhift), tmp);
10909203945Sweongyo		}
10910203945Sweongyo
10911203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf0), 0x5f80);
10912203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf1), 0);
10913203945Sweongyo	}
10914203945Sweongyo
10915203945Sweongyo	/* calibrate RC */
10916203945Sweongyo	if (mac->mac_phy.rev >= 2)
10917203945Sweongyo		bwn_phy_lp_rxcal_r2(mac);
10918203945Sweongyo	else if (!plp->plp_rccap) {
10919203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
10920203945Sweongyo			bwn_phy_lp_rccal_r12(mac);
10921203945Sweongyo	} else
10922203945Sweongyo		bwn_phy_lp_set_rccap(mac);
10923203945Sweongyo
10924203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
10925203945Sweongyo	if (error)
10926203945Sweongyo		device_printf(sc->sc_dev,
10927203945Sweongyo		    "failed to change channel 7 (%d)\n", error);
10928203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
10929203945Sweongyo	bwn_phy_lp_calib(mac);
10930203945Sweongyo	return (0);
10931203945Sweongyo}
10932203945Sweongyo
10933203945Sweongyostatic uint16_t
10934203945Sweongyobwn_phy_lp_read(struct bwn_mac *mac, uint16_t reg)
10935203945Sweongyo{
10936203945Sweongyo
10937203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10938203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
10939203945Sweongyo}
10940203945Sweongyo
10941203945Sweongyostatic void
10942203945Sweongyobwn_phy_lp_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
10943203945Sweongyo{
10944203945Sweongyo
10945203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10946203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
10947203945Sweongyo}
10948203945Sweongyo
10949203945Sweongyostatic void
10950203945Sweongyobwn_phy_lp_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
10951203945Sweongyo    uint16_t set)
10952203945Sweongyo{
10953203945Sweongyo
10954203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10955203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA,
10956203945Sweongyo	    (BWN_READ_2(mac, BWN_PHYDATA) & mask) | set);
10957203945Sweongyo}
10958203945Sweongyo
10959203945Sweongyostatic uint16_t
10960203945Sweongyobwn_phy_lp_rf_read(struct bwn_mac *mac, uint16_t reg)
10961203945Sweongyo{
10962203945Sweongyo
10963203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
10964203945Sweongyo	if (mac->mac_phy.rev < 2 && reg != 0x4001)
10965203945Sweongyo		reg |= 0x100;
10966203945Sweongyo	if (mac->mac_phy.rev >= 2)
10967203945Sweongyo		reg |= 0x200;
10968203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
10969203945Sweongyo	return BWN_READ_2(mac, BWN_RFDATALO);
10970203945Sweongyo}
10971203945Sweongyo
10972203945Sweongyostatic void
10973203945Sweongyobwn_phy_lp_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
10974203945Sweongyo{
10975203945Sweongyo
10976203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
10977203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
10978203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
10979203945Sweongyo}
10980203945Sweongyo
10981203945Sweongyostatic void
10982203945Sweongyobwn_phy_lp_rf_onoff(struct bwn_mac *mac, int on)
10983203945Sweongyo{
10984203945Sweongyo
10985203945Sweongyo	if (on) {
10986203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xe0ff);
10987203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2,
10988203945Sweongyo		    (mac->mac_phy.rev >= 2) ? 0xf7f7 : 0xffe7);
10989203945Sweongyo		return;
10990203945Sweongyo	}
10991203945Sweongyo
10992203945Sweongyo	if (mac->mac_phy.rev >= 2) {
10993203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x83ff);
10994203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
10995203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0x80ff);
10996203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xdfff);
10997203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0808);
10998203945Sweongyo		return;
10999203945Sweongyo	}
11000203945Sweongyo
11001203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xe0ff);
11002203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
11003203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfcff);
11004203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0018);
11005203945Sweongyo}
11006203945Sweongyo
11007203945Sweongyostatic int
11008203945Sweongyobwn_phy_lp_switch_channel(struct bwn_mac *mac, uint32_t chan)
11009203945Sweongyo{
11010203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11011203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11012203945Sweongyo	int error;
11013203945Sweongyo
11014203945Sweongyo	if (phy->rf_ver == 0x2063) {
11015203945Sweongyo		error = bwn_phy_lp_b2063_switch_channel(mac, chan);
11016203945Sweongyo		if (error)
11017203945Sweongyo			return (error);
11018203945Sweongyo	} else {
11019203945Sweongyo		error = bwn_phy_lp_b2062_switch_channel(mac, chan);
11020203945Sweongyo		if (error)
11021203945Sweongyo			return (error);
11022203945Sweongyo		bwn_phy_lp_set_anafilter(mac, chan);
11023203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, ieee80211_ieee2mhz(chan, 0));
11024203945Sweongyo	}
11025203945Sweongyo
11026203945Sweongyo	plp->plp_chan = chan;
11027203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, chan);
11028203945Sweongyo	return (0);
11029203945Sweongyo}
11030203945Sweongyo
11031203945Sweongyostatic uint32_t
11032203945Sweongyobwn_phy_lp_get_default_chan(struct bwn_mac *mac)
11033203945Sweongyo{
11034203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11035203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11036203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11037203945Sweongyo
11038203945Sweongyo	return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36);
11039203945Sweongyo}
11040203945Sweongyo
11041203945Sweongyostatic void
11042203945Sweongyobwn_phy_lp_set_antenna(struct bwn_mac *mac, int antenna)
11043203945Sweongyo{
11044203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11045203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11046203945Sweongyo
11047203945Sweongyo	if (phy->rev >= 2 || antenna > BWN_ANTAUTO1)
11048203945Sweongyo		return;
11049203945Sweongyo
11050203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER);
11051203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffd, antenna & 0x2);
11052203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffe, antenna & 0x1);
11053203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_UCODE_ANTDIV_HELPER);
11054203945Sweongyo	plp->plp_antenna = antenna;
11055203945Sweongyo}
11056203945Sweongyo
11057203945Sweongyostatic void
11058203945Sweongyobwn_phy_lp_task_60s(struct bwn_mac *mac)
11059203945Sweongyo{
11060203945Sweongyo
11061203945Sweongyo	bwn_phy_lp_calib(mac);
11062203945Sweongyo}
11063203945Sweongyo
11064203945Sweongyostatic void
11065203945Sweongyobwn_phy_lp_readsprom(struct bwn_mac *mac)
11066203945Sweongyo{
11067203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11068203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11069203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11070203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11071203945Sweongyo
11072203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11073204922Sweongyo		plp->plp_txisoband_m = siba_sprom_get_tri2g(sc->sc_dev);
11074204922Sweongyo		plp->plp_bxarch = siba_sprom_get_bxa2g(sc->sc_dev);
11075204922Sweongyo		plp->plp_rxpwroffset = siba_sprom_get_rxpo2g(sc->sc_dev);
11076204922Sweongyo		plp->plp_rssivf = siba_sprom_get_rssismf2g(sc->sc_dev);
11077204922Sweongyo		plp->plp_rssivc = siba_sprom_get_rssismc2g(sc->sc_dev);
11078204922Sweongyo		plp->plp_rssigs = siba_sprom_get_rssisav2g(sc->sc_dev);
11079203945Sweongyo		return;
11080203945Sweongyo	}
11081203945Sweongyo
11082204922Sweongyo	plp->plp_txisoband_l = siba_sprom_get_tri5gl(sc->sc_dev);
11083204922Sweongyo	plp->plp_txisoband_m = siba_sprom_get_tri5g(sc->sc_dev);
11084204922Sweongyo	plp->plp_txisoband_h = siba_sprom_get_tri5gh(sc->sc_dev);
11085204922Sweongyo	plp->plp_bxarch = siba_sprom_get_bxa5g(sc->sc_dev);
11086204922Sweongyo	plp->plp_rxpwroffset = siba_sprom_get_rxpo5g(sc->sc_dev);
11087204922Sweongyo	plp->plp_rssivf = siba_sprom_get_rssismf5g(sc->sc_dev);
11088204922Sweongyo	plp->plp_rssivc = siba_sprom_get_rssismc5g(sc->sc_dev);
11089204922Sweongyo	plp->plp_rssigs = siba_sprom_get_rssisav5g(sc->sc_dev);
11090203945Sweongyo}
11091203945Sweongyo
11092203945Sweongyostatic void
11093203945Sweongyobwn_phy_lp_bbinit(struct bwn_mac *mac)
11094203945Sweongyo{
11095203945Sweongyo
11096203945Sweongyo	bwn_phy_lp_tblinit(mac);
11097203945Sweongyo	if (mac->mac_phy.rev >= 2)
11098203945Sweongyo		bwn_phy_lp_bbinit_r2(mac);
11099203945Sweongyo	else
11100203945Sweongyo		bwn_phy_lp_bbinit_r01(mac);
11101203945Sweongyo}
11102203945Sweongyo
11103203945Sweongyostatic void
11104203945Sweongyobwn_phy_lp_txpctl_init(struct bwn_mac *mac)
11105203945Sweongyo{
11106203945Sweongyo	struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 };
11107203945Sweongyo	struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 };
11108203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11109203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11110203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11111203945Sweongyo
11112203945Sweongyo	bwn_phy_lp_set_txgain(mac,
11113203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz);
11114203945Sweongyo	bwn_phy_lp_set_bbmult(mac, 150);
11115203945Sweongyo}
11116203945Sweongyo
11117203945Sweongyostatic void
11118203945Sweongyobwn_phy_lp_calib(struct bwn_mac *mac)
11119203945Sweongyo{
11120203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11121203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11122203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11123203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11124203945Sweongyo	const struct bwn_rxcompco *rc = NULL;
11125203945Sweongyo	struct bwn_txgain ogain;
11126203945Sweongyo	int i, omode, oafeovr, orf, obbmult;
11127203945Sweongyo	uint8_t mode, fc = 0;
11128203945Sweongyo
11129203945Sweongyo	if (plp->plp_chanfullcal != plp->plp_chan) {
11130203945Sweongyo		plp->plp_chanfullcal = plp->plp_chan;
11131203945Sweongyo		fc = 1;
11132203945Sweongyo	}
11133203945Sweongyo
11134203945Sweongyo	bwn_mac_suspend(mac);
11135203945Sweongyo
11136203945Sweongyo	/* BlueTooth Coexistance Override */
11137203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_CTL, 0x3);
11138203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_TXCTL, 0xff);
11139203945Sweongyo
11140203945Sweongyo	if (mac->mac_phy.rev >= 2)
11141203945Sweongyo		bwn_phy_lp_digflt_save(mac);
11142203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11143203945Sweongyo	mode = plp->plp_txpctlmode;
11144203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11145203945Sweongyo	if (mac->mac_phy.rev == 0 && mode != BWN_PHYLP_TXPCTL_OFF)
11146203945Sweongyo		bwn_phy_lp_bugfix(mac);
11147203945Sweongyo	if (mac->mac_phy.rev >= 2 && fc == 1) {
11148203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11149203945Sweongyo		omode = plp->plp_txpctlmode;
11150203945Sweongyo		oafeovr = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40;
11151203945Sweongyo		if (oafeovr)
11152203945Sweongyo			ogain = bwn_phy_lp_get_txgain(mac);
11153203945Sweongyo		orf = BWN_PHY_READ(mac, BWN_PHY_RF_PWR_OVERRIDE) & 0xff;
11154203945Sweongyo		obbmult = bwn_phy_lp_get_bbmult(mac);
11155203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11156203945Sweongyo		if (oafeovr)
11157203945Sweongyo			bwn_phy_lp_set_txgain(mac, &ogain);
11158203945Sweongyo		bwn_phy_lp_set_bbmult(mac, obbmult);
11159203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, omode);
11160203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00, orf);
11161203945Sweongyo	}
11162203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11163203945Sweongyo	if (mac->mac_phy.rev >= 2)
11164203945Sweongyo		bwn_phy_lp_digflt_restore(mac);
11165203945Sweongyo
11166203945Sweongyo	/* do RX IQ Calculation; assumes that noise is true. */
11167204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x5354) {
11168203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_5354); i++) {
11169203945Sweongyo			if (bwn_rxcompco_5354[i].rc_chan == plp->plp_chan)
11170203945Sweongyo				rc = &bwn_rxcompco_5354[i];
11171203945Sweongyo		}
11172203945Sweongyo	} else if (mac->mac_phy.rev >= 2)
11173203945Sweongyo		rc = &bwn_rxcompco_r2;
11174203945Sweongyo	else {
11175203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_r12); i++) {
11176203945Sweongyo			if (bwn_rxcompco_r12[i].rc_chan == plp->plp_chan)
11177203945Sweongyo				rc = &bwn_rxcompco_r12[i];
11178203945Sweongyo		}
11179203945Sweongyo	}
11180203945Sweongyo	if (rc == NULL)
11181203945Sweongyo		goto fail;
11182203945Sweongyo
11183203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, rc->rc_c1);
11184203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, rc->rc_c0 << 8);
11185203945Sweongyo
11186203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1 /* TX */, 0 /* RX */);
11187203945Sweongyo
11188203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11189203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
11190203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7, 0);
11191203945Sweongyo	} else {
11192203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
11193203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf, 0);
11194203945Sweongyo	}
11195203945Sweongyo
11196203945Sweongyo	bwn_phy_lp_set_rxgain(mac, 0x2d5d);
11197203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11198203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
11199203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
11200203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
11201203945Sweongyo	bwn_phy_lp_set_deaf(mac, 0);
11202203945Sweongyo	/* XXX no checking return value? */
11203203945Sweongyo	(void)bwn_phy_lp_calc_rx_iq_comp(mac, 0xfff0);
11204203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 0);
11205203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffc);
11206203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfff7);
11207203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffdf);
11208203945Sweongyo
11209203945Sweongyo	/* disable RX GAIN override. */
11210203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffe);
11211203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffef);
11212203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffbf);
11213203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11214203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11215203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11216203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfbff);
11217203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xe5), 0xfff7);
11218203945Sweongyo		}
11219203945Sweongyo	} else {
11220203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfdff);
11221203945Sweongyo	}
11222203945Sweongyo
11223203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11224203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xf7ff);
11225203945Sweongyofail:
11226203945Sweongyo	bwn_mac_enable(mac);
11227203945Sweongyo}
11228203945Sweongyo
11229203945Sweongyostatic void
11230203945Sweongyobwn_phy_lp_switch_analog(struct bwn_mac *mac, int on)
11231203945Sweongyo{
11232203945Sweongyo
11233204922Sweongyo	if (on) {
11234204922Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfff8);
11235204922Sweongyo		return;
11236204922Sweongyo	}
11237203945Sweongyo
11238204922Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVRVAL, 0x0007);
11239204922Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x0007);
11240203945Sweongyo}
11241203945Sweongyo
11242203945Sweongyostatic int
11243203945Sweongyobwn_phy_lp_b2063_switch_channel(struct bwn_mac *mac, uint8_t chan)
11244203945Sweongyo{
11245203945Sweongyo	static const struct bwn_b206x_chan *bc = NULL;
11246204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11247203945Sweongyo	uint32_t count, freqref, freqvco, freqxtal, val[3], timeout, timeoutref,
11248203945Sweongyo	    tmp[6];
11249203945Sweongyo	uint16_t old, scale, tmp16;
11250203945Sweongyo	int i, div;
11251203945Sweongyo
11252203945Sweongyo	for (i = 0; i < N(bwn_b2063_chantable); i++) {
11253203945Sweongyo		if (bwn_b2063_chantable[i].bc_chan == chan) {
11254203945Sweongyo			bc = &bwn_b2063_chantable[i];
11255203945Sweongyo			break;
11256203945Sweongyo		}
11257203945Sweongyo	}
11258203945Sweongyo	if (bc == NULL)
11259203945Sweongyo		return (EINVAL);
11260203945Sweongyo
11261203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_VCOBUF1, bc->bc_data[0]);
11262203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_MIXER2, bc->bc_data[1]);
11263203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_BUF2, bc->bc_data[2]);
11264203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_RCCR1, bc->bc_data[3]);
11265203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_1ST3, bc->bc_data[4]);
11266203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND1, bc->bc_data[5]);
11267203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND4, bc->bc_data[6]);
11268203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND7, bc->bc_data[7]);
11269203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_PS6, bc->bc_data[8]);
11270203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL2, bc->bc_data[9]);
11271203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL5, bc->bc_data[10]);
11272203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_CTL11, bc->bc_data[11]);
11273203945Sweongyo
11274203945Sweongyo	old = BWN_RF_READ(mac, BWN_B2063_COM15);
11275203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM15, 0x1e);
11276203945Sweongyo
11277204922Sweongyo	freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
11278203945Sweongyo	freqvco = bc->bc_freq << ((bc->bc_freq > 4000) ? 1 : 2);
11279203945Sweongyo	freqref = freqxtal * 3;
11280203945Sweongyo	div = (freqxtal <= 26000000 ? 1 : 2);
11281203945Sweongyo	timeout = ((((8 * freqxtal) / (div * 5000000)) + 1) >> 1) - 1;
11282203945Sweongyo	timeoutref = ((((8 * freqxtal) / (div * (timeout + 1))) +
11283203945Sweongyo		999999) / 1000000) + 1;
11284203945Sweongyo
11285203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB3, 0x2);
11286203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB6,
11287203945Sweongyo	    0xfff8, timeout >> 2);
11288203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11289203945Sweongyo	    0xff9f,timeout << 5);
11290203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB5, timeoutref);
11291203945Sweongyo
11292203945Sweongyo	val[0] = bwn_phy_lp_roundup(freqxtal, 1000000, 16);
11293203945Sweongyo	val[1] = bwn_phy_lp_roundup(freqxtal, 1000000 * div, 16);
11294203945Sweongyo	val[2] = bwn_phy_lp_roundup(freqvco, 3, 16);
11295203945Sweongyo
11296203945Sweongyo	count = (bwn_phy_lp_roundup(val[2], val[1] + 16, 16) * (timeout + 1) *
11297203945Sweongyo	    (timeoutref + 1)) - 1;
11298203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11299203945Sweongyo	    0xf0, count >> 8);
11300203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB8, count & 0xff);
11301203945Sweongyo
11302203945Sweongyo	tmp[0] = ((val[2] * 62500) / freqref) << 4;
11303203945Sweongyo	tmp[1] = ((val[2] * 62500) % freqref) << 4;
11304203945Sweongyo	while (tmp[1] >= freqref) {
11305203945Sweongyo		tmp[0]++;
11306203945Sweongyo		tmp[1] -= freqref;
11307203945Sweongyo	}
11308203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG1, 0xffe0, tmp[0] >> 4);
11309203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfe0f, tmp[0] << 4);
11310203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfff0, tmp[0] >> 16);
11311203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG3, (tmp[1] >> 8) & 0xff);
11312203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG4, tmp[1] & 0xff);
11313203945Sweongyo
11314203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF1, 0xb9);
11315203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF2, 0x88);
11316203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF3, 0x28);
11317203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF4, 0x63);
11318203945Sweongyo
11319203945Sweongyo	tmp[2] = ((41 * (val[2] - 3000)) /1200) + 27;
11320203945Sweongyo	tmp[3] = bwn_phy_lp_roundup(132000 * tmp[0], 8451, 16);
11321203945Sweongyo
11322203945Sweongyo	if ((tmp[3] + tmp[2] - 1) / tmp[2] > 60) {
11323203945Sweongyo		scale = 1;
11324203945Sweongyo		tmp[4] = ((tmp[3] + tmp[2]) / (tmp[2] << 1)) - 8;
11325203945Sweongyo	} else {
11326203945Sweongyo		scale = 0;
11327203945Sweongyo		tmp[4] = ((tmp[3] + (tmp[2] >> 1)) / tmp[2]) - 8;
11328203945Sweongyo	}
11329203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffc0, tmp[4]);
11330203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffbf, scale << 6);
11331203945Sweongyo
11332203945Sweongyo	tmp[5] = bwn_phy_lp_roundup(100 * val[0], val[2], 16) * (tmp[4] * 8) *
11333203945Sweongyo	    (scale + 1);
11334203945Sweongyo	if (tmp[5] > 150)
11335203945Sweongyo		tmp[5] = 0;
11336203945Sweongyo
11337203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffe0, tmp[5]);
11338203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffdf, scale << 5);
11339203945Sweongyo
11340203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfffb, 0x4);
11341203945Sweongyo	if (freqxtal > 26000000)
11342203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_XTAL_12, 0x2);
11343203945Sweongyo	else
11344203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfd);
11345203945Sweongyo
11346203945Sweongyo	if (val[0] == 45)
11347203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_VCO1, 0x2);
11348203945Sweongyo	else
11349203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_VCO1, 0xfd);
11350203945Sweongyo
11351203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP2, 0x3);
11352203945Sweongyo	DELAY(1);
11353203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP2, 0xfffc);
11354203945Sweongyo
11355203945Sweongyo	/* VCO Calibration */
11356203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, ~0x40);
11357203945Sweongyo	tmp16 = BWN_RF_READ(mac, BWN_B2063_JTAG_CALNRST) & 0xf8;
11358203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16);
11359203945Sweongyo	DELAY(1);
11360203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x4);
11361203945Sweongyo	DELAY(1);
11362203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x6);
11363203945Sweongyo	DELAY(1);
11364203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x7);
11365203945Sweongyo	DELAY(300);
11366203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP1, 0x40);
11367203945Sweongyo
11368203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_COM15, old);
11369203945Sweongyo	return (0);
11370203945Sweongyo}
11371203945Sweongyo
11372203945Sweongyostatic int
11373203945Sweongyobwn_phy_lp_b2062_switch_channel(struct bwn_mac *mac, uint8_t chan)
11374203945Sweongyo{
11375204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11376203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11377203945Sweongyo	const struct bwn_b206x_chan *bc = NULL;
11378204922Sweongyo	uint32_t freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
11379203945Sweongyo	uint32_t tmp[9];
11380203945Sweongyo	int i;
11381203945Sweongyo
11382203945Sweongyo	for (i = 0; i < N(bwn_b2062_chantable); i++) {
11383203945Sweongyo		if (bwn_b2062_chantable[i].bc_chan == chan) {
11384203945Sweongyo			bc = &bwn_b2062_chantable[i];
11385203945Sweongyo			break;
11386203945Sweongyo		}
11387203945Sweongyo	}
11388203945Sweongyo
11389203945Sweongyo	if (bc == NULL)
11390203945Sweongyo		return (EINVAL);
11391203945Sweongyo
11392203945Sweongyo	BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL14, 0x04);
11393203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE0, bc->bc_data[0]);
11394203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE2, bc->bc_data[1]);
11395203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE3, bc->bc_data[2]);
11396203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_TUNE, bc->bc_data[3]);
11397203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_LGENG_CTL1, bc->bc_data[4]);
11398203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL5, bc->bc_data[5]);
11399203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL6, bc->bc_data[6]);
11400203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PGA, bc->bc_data[7]);
11401203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PAD, bc->bc_data[8]);
11402203945Sweongyo
11403203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xcc);
11404203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0x07);
11405203945Sweongyo	bwn_phy_lp_b2062_reset_pllbias(mac);
11406203945Sweongyo	tmp[0] = freqxtal / 1000;
11407203945Sweongyo	tmp[1] = plp->plp_div * 1000;
11408203945Sweongyo	tmp[2] = tmp[1] * ieee80211_ieee2mhz(chan, 0);
11409203945Sweongyo	if (ieee80211_ieee2mhz(chan, 0) < 4000)
11410203945Sweongyo		tmp[2] *= 2;
11411203945Sweongyo	tmp[3] = 48 * tmp[0];
11412203945Sweongyo	tmp[5] = tmp[2] / tmp[3];
11413203945Sweongyo	tmp[6] = tmp[2] % tmp[3];
11414203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL26, tmp[5]);
11415203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11416203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11417203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11418203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL27, tmp[5]);
11419203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11420203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11421203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11422203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL28, tmp[5]);
11423203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11424203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11425203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11426203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL29,
11427203945Sweongyo	    tmp[5] + ((2 * tmp[6]) / tmp[3]));
11428203945Sweongyo	tmp[7] = BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL19);
11429203945Sweongyo	tmp[8] = ((2 * tmp[2] * (tmp[7] + 1)) + (3 * tmp[0])) / (6 * tmp[0]);
11430203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL23, (tmp[8] >> 8) + 16);
11431203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL24, tmp[8] & 0xff);
11432203945Sweongyo
11433203945Sweongyo	bwn_phy_lp_b2062_vco_calib(mac);
11434203945Sweongyo	if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11435203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xfc);
11436203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0);
11437203945Sweongyo		bwn_phy_lp_b2062_reset_pllbias(mac);
11438203945Sweongyo		bwn_phy_lp_b2062_vco_calib(mac);
11439203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11440203945Sweongyo			BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11441203945Sweongyo			return (EIO);
11442203945Sweongyo		}
11443203945Sweongyo	}
11444203945Sweongyo	BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11445203945Sweongyo	return (0);
11446203945Sweongyo}
11447203945Sweongyo
11448203945Sweongyostatic void
11449203945Sweongyobwn_phy_lp_set_anafilter(struct bwn_mac *mac, uint8_t channel)
11450203945Sweongyo{
11451203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11452203945Sweongyo	uint16_t tmp = (channel == 14);
11453203945Sweongyo
11454203945Sweongyo	if (mac->mac_phy.rev < 2) {
11455203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xfcff, tmp << 9);
11456203945Sweongyo		if ((mac->mac_phy.rev == 1) && (plp->plp_rccap))
11457203945Sweongyo			bwn_phy_lp_set_rccap(mac);
11458203945Sweongyo		return;
11459203945Sweongyo	}
11460203945Sweongyo
11461203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, 0x3f);
11462203945Sweongyo}
11463203945Sweongyo
11464203945Sweongyostatic void
11465203945Sweongyobwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq)
11466203945Sweongyo{
11467203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11468203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11469203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11470203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11471203945Sweongyo	uint16_t iso, tmp[3];
11472203945Sweongyo
11473203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
11474203945Sweongyo
11475203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
11476203945Sweongyo		iso = plp->plp_txisoband_m;
11477203945Sweongyo	else if (freq <= 5320)
11478203945Sweongyo		iso = plp->plp_txisoband_l;
11479203945Sweongyo	else if (freq <= 5700)
11480203945Sweongyo		iso = plp->plp_txisoband_m;
11481203945Sweongyo	else
11482203945Sweongyo		iso = plp->plp_txisoband_h;
11483203945Sweongyo
11484203945Sweongyo	tmp[0] = ((iso - 26) / 12) << 12;
11485203945Sweongyo	tmp[1] = tmp[0] + 0x1000;
11486203945Sweongyo	tmp[2] = tmp[0] + 0x2000;
11487203945Sweongyo
11488203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), 3, tmp);
11489203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), 3, tmp);
11490203945Sweongyo}
11491203945Sweongyo
11492203945Sweongyostatic void
11493203945Sweongyobwn_phy_lp_digflt_save(struct bwn_mac *mac)
11494203945Sweongyo{
11495203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11496203945Sweongyo	int i;
11497203945Sweongyo	static const uint16_t addr[] = {
11498203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11499203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11500203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11501203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11502203945Sweongyo		BWN_PHY_OFDM(0xcf),
11503203945Sweongyo	};
11504203945Sweongyo	static const uint16_t val[] = {
11505203945Sweongyo		0xde5e, 0xe832, 0xe331, 0x4d26,
11506203945Sweongyo		0x0026, 0x1420, 0x0020, 0xfe08,
11507203945Sweongyo		0x0008,
11508203945Sweongyo	};
11509203945Sweongyo
11510203945Sweongyo	for (i = 0; i < N(addr); i++) {
11511203945Sweongyo		plp->plp_digfilt[i] = BWN_PHY_READ(mac, addr[i]);
11512203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], val[i]);
11513203945Sweongyo	}
11514203945Sweongyo}
11515203945Sweongyo
11516203945Sweongyostatic void
11517203945Sweongyobwn_phy_lp_get_txpctlmode(struct bwn_mac *mac)
11518203945Sweongyo{
11519203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11520203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11521203945Sweongyo	uint16_t ctl;
11522203945Sweongyo
11523203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_TX_PWR_CTL_CMD);
11524203945Sweongyo	switch (ctl & BWN_PHY_TX_PWR_CTL_CMD_MODE) {
11525203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF:
11526203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_OFF;
11527203945Sweongyo		break;
11528203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_SW:
11529203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_SW;
11530203945Sweongyo		break;
11531203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_HW:
11532203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_HW;
11533203945Sweongyo		break;
11534203945Sweongyo	default:
11535203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_UNKNOWN;
11536203945Sweongyo		device_printf(sc->sc_dev, "unknown command mode\n");
11537203945Sweongyo		break;
11538203945Sweongyo	}
11539203945Sweongyo}
11540203945Sweongyo
11541203945Sweongyostatic void
11542203945Sweongyobwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
11543203945Sweongyo{
11544203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11545203945Sweongyo	uint16_t ctl;
11546203945Sweongyo	uint8_t old;
11547203945Sweongyo
11548203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11549203945Sweongyo	old = plp->plp_txpctlmode;
11550203945Sweongyo	if (old == mode)
11551203945Sweongyo		return;
11552203945Sweongyo	plp->plp_txpctlmode = mode;
11553203945Sweongyo
11554203945Sweongyo	if (old != BWN_PHYLP_TXPCTL_ON_HW && mode == BWN_PHYLP_TXPCTL_ON_HW) {
11555203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD, 0xff80,
11556203945Sweongyo		    plp->plp_tssiidx);
11557203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_NNUM,
11558203945Sweongyo		    0x8fff, ((uint16_t)plp->plp_tssinpt << 16));
11559203945Sweongyo
11560203945Sweongyo		/* disable TX GAIN override */
11561203945Sweongyo		if (mac->mac_phy.rev < 2)
11562203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11563203945Sweongyo		else {
11564203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xff7f);
11565203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xbfff);
11566203945Sweongyo		}
11567203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xffbf);
11568203945Sweongyo
11569203945Sweongyo		plp->plp_txpwridx = -1;
11570203945Sweongyo	}
11571203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11572203945Sweongyo		if (mode == BWN_PHYLP_TXPCTL_ON_HW)
11573203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xd0), 0x2);
11574203945Sweongyo		else
11575203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xd0), 0xfffd);
11576203945Sweongyo	}
11577203945Sweongyo
11578203945Sweongyo	/* writes TX Power Control mode */
11579203945Sweongyo	switch (plp->plp_txpctlmode) {
11580203945Sweongyo	case BWN_PHYLP_TXPCTL_OFF:
11581203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF;
11582203945Sweongyo		break;
11583203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_HW:
11584203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_HW;
11585203945Sweongyo		break;
11586203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_SW:
11587203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
11588203945Sweongyo		break;
11589203945Sweongyo	default:
11590204242Simp		ctl = 0;
11591203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
11592203945Sweongyo	}
11593203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
11594203945Sweongyo	    (uint16_t)~BWN_PHY_TX_PWR_CTL_CMD_MODE, ctl);
11595203945Sweongyo}
11596203945Sweongyo
11597203945Sweongyostatic void
11598203945Sweongyobwn_phy_lp_bugfix(struct bwn_mac *mac)
11599203945Sweongyo{
11600203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11601203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11602203945Sweongyo	const unsigned int size = 256;
11603203945Sweongyo	struct bwn_txgain tg;
11604203945Sweongyo	uint32_t rxcomp, txgain, coeff, rfpwr, *tabs;
11605203945Sweongyo	uint16_t tssinpt, tssiidx, value[2];
11606203945Sweongyo	uint8_t mode;
11607203945Sweongyo	int8_t txpwridx;
11608203945Sweongyo
11609203945Sweongyo	tabs = (uint32_t *)malloc(sizeof(uint32_t) * size, M_DEVBUF,
11610203945Sweongyo	    M_NOWAIT | M_ZERO);
11611203945Sweongyo	if (tabs == NULL) {
11612203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer.\n");
11613203945Sweongyo		return;
11614203945Sweongyo	}
11615203945Sweongyo
11616203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11617203945Sweongyo	mode = plp->plp_txpctlmode;
11618203945Sweongyo	txpwridx = plp->plp_txpwridx;
11619203945Sweongyo	tssinpt = plp->plp_tssinpt;
11620203945Sweongyo	tssiidx = plp->plp_tssiidx;
11621203945Sweongyo
11622203945Sweongyo	bwn_tab_read_multi(mac,
11623203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11624203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11625203945Sweongyo
11626203945Sweongyo	bwn_phy_lp_tblinit(mac);
11627203945Sweongyo	bwn_phy_lp_bbinit(mac);
11628203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
11629203945Sweongyo	bwn_phy_lp_rf_onoff(mac, 1);
11630203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11631203945Sweongyo
11632203945Sweongyo	bwn_tab_write_multi(mac,
11633203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11634203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11635203945Sweongyo
11636203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, plp->plp_chan);
11637203945Sweongyo	plp->plp_tssinpt = tssinpt;
11638203945Sweongyo	plp->plp_tssiidx = tssiidx;
11639203945Sweongyo	bwn_phy_lp_set_anafilter(mac, plp->plp_chan);
11640203945Sweongyo	if (txpwridx != -1) {
11641203945Sweongyo		/* set TX power by index */
11642203945Sweongyo		plp->plp_txpwridx = txpwridx;
11643203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11644203945Sweongyo		if (plp->plp_txpctlmode != BWN_PHYLP_TXPCTL_OFF)
11645203945Sweongyo			bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_ON_SW);
11646203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11647203945Sweongyo			rxcomp = bwn_tab_read(mac,
11648203945Sweongyo			    BWN_TAB_4(7, txpwridx + 320));
11649203945Sweongyo			txgain = bwn_tab_read(mac,
11650203945Sweongyo			    BWN_TAB_4(7, txpwridx + 192));
11651203945Sweongyo			tg.tg_pad = (txgain >> 16) & 0xff;
11652203945Sweongyo			tg.tg_gm = txgain & 0xff;
11653203945Sweongyo			tg.tg_pga = (txgain >> 8) & 0xff;
11654203945Sweongyo			tg.tg_dac = (rxcomp >> 28) & 0xff;
11655203945Sweongyo			bwn_phy_lp_set_txgain(mac, &tg);
11656203945Sweongyo		} else {
11657203945Sweongyo			rxcomp = bwn_tab_read(mac,
11658203945Sweongyo			    BWN_TAB_4(10, txpwridx + 320));
11659203945Sweongyo			txgain = bwn_tab_read(mac,
11660203945Sweongyo			    BWN_TAB_4(10, txpwridx + 192));
11661203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
11662203945Sweongyo			    0xf800, (txgain >> 4) & 0x7fff);
11663203945Sweongyo			bwn_phy_lp_set_txgain_dac(mac, txgain & 0x7);
11664203945Sweongyo			bwn_phy_lp_set_txgain_pa(mac, (txgain >> 24) & 0x7f);
11665203945Sweongyo		}
11666203945Sweongyo		bwn_phy_lp_set_bbmult(mac, (rxcomp >> 20) & 0xff);
11667203945Sweongyo
11668203945Sweongyo		/* set TX IQCC */
11669203945Sweongyo		value[0] = (rxcomp >> 10) & 0x3ff;
11670203945Sweongyo		value[1] = rxcomp & 0x3ff;
11671203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(0, 80), 2, value);
11672203945Sweongyo
11673203945Sweongyo		coeff = bwn_tab_read(mac,
11674203945Sweongyo		    (mac->mac_phy.rev >= 2) ? BWN_TAB_4(7, txpwridx + 448) :
11675203945Sweongyo		    BWN_TAB_4(10, txpwridx + 448));
11676203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0, 85), coeff & 0xffff);
11677203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11678203945Sweongyo			rfpwr = bwn_tab_read(mac,
11679203945Sweongyo			    BWN_TAB_4(7, txpwridx + 576));
11680203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00,
11681203945Sweongyo			    rfpwr & 0xffff);
11682203945Sweongyo		}
11683203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
11684203945Sweongyo	}
11685203945Sweongyo	if (plp->plp_rccap)
11686203945Sweongyo		bwn_phy_lp_set_rccap(mac);
11687203945Sweongyo	bwn_phy_lp_set_antenna(mac, plp->plp_antenna);
11688203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11689203945Sweongyo	free(tabs, M_DEVBUF);
11690203945Sweongyo}
11691203945Sweongyo
11692203945Sweongyostatic void
11693203945Sweongyobwn_phy_lp_digflt_restore(struct bwn_mac *mac)
11694203945Sweongyo{
11695203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11696203945Sweongyo	int i;
11697203945Sweongyo	static const uint16_t addr[] = {
11698203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11699203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11700203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11701203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11702203945Sweongyo		BWN_PHY_OFDM(0xcf),
11703203945Sweongyo	};
11704203945Sweongyo
11705203945Sweongyo	for (i = 0; i < N(addr); i++)
11706203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], plp->plp_digfilt[i]);
11707203945Sweongyo}
11708203945Sweongyo
11709203945Sweongyostatic void
11710203945Sweongyobwn_phy_lp_tblinit(struct bwn_mac *mac)
11711203945Sweongyo{
11712203945Sweongyo	uint32_t freq = ieee80211_ieee2mhz(bwn_phy_lp_get_default_chan(mac), 0);
11713203945Sweongyo
11714203945Sweongyo	if (mac->mac_phy.rev < 2) {
11715203945Sweongyo		bwn_phy_lp_tblinit_r01(mac);
11716203945Sweongyo		bwn_phy_lp_tblinit_txgain(mac);
11717203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, freq);
11718203945Sweongyo		return;
11719203945Sweongyo	}
11720203945Sweongyo
11721203945Sweongyo	bwn_phy_lp_tblinit_r2(mac);
11722203945Sweongyo	bwn_phy_lp_tblinit_txgain(mac);
11723203945Sweongyo}
11724203945Sweongyo
11725203945Sweongyostruct bwn_wpair {
11726203945Sweongyo	uint16_t		reg;
11727203945Sweongyo	uint16_t		value;
11728203945Sweongyo};
11729203945Sweongyo
11730203945Sweongyostruct bwn_smpair {
11731203945Sweongyo	uint16_t		offset;
11732203945Sweongyo	uint16_t		mask;
11733203945Sweongyo	uint16_t		set;
11734203945Sweongyo};
11735203945Sweongyo
11736203945Sweongyostatic void
11737203945Sweongyobwn_phy_lp_bbinit_r2(struct bwn_mac *mac)
11738203945Sweongyo{
11739203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11740203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11741203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11742203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11743203945Sweongyo	static const struct bwn_wpair v1[] = {
11744203945Sweongyo		{ BWN_PHY_AFE_DAC_CTL, 0x50 },
11745203945Sweongyo		{ BWN_PHY_AFE_CTL, 0x8800 },
11746203945Sweongyo		{ BWN_PHY_AFE_CTL_OVR, 0 },
11747203945Sweongyo		{ BWN_PHY_AFE_CTL_OVRVAL, 0 },
11748203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_0, 0 },
11749203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_2, 0 },
11750203945Sweongyo		{ BWN_PHY_OFDM(0xf9), 0 },
11751203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0 }
11752203945Sweongyo	};
11753203945Sweongyo	static const struct bwn_smpair v2[] = {
11754203945Sweongyo		{ BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0xb4 },
11755203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xf8ff, 0x200 },
11756203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xff00, 0x7f },
11757203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xff0f, 0x40 },
11758203945Sweongyo		{ BWN_PHY_PREAMBLECONFIRMTO, 0xff00, 0x2 }
11759203945Sweongyo	};
11760203945Sweongyo	static const struct bwn_smpair v3[] = {
11761203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xffe0, 0x1f },
11762203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11763203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0xff00, 0x19 },
11764203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0x03ff, 0x3c00 },
11765203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xfc1f, 0x3e0 },
11766203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11767203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0x00ff, 0x1900 },
11768203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800 },
11769203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x12 },
11770203945Sweongyo		{ BWN_PHY_GAINMISMATCH, 0x0fff, 0x9000 },
11771204922Sweongyo
11772203945Sweongyo	};
11773203945Sweongyo	int i;
11774203945Sweongyo
11775203945Sweongyo	for (i = 0; i < N(v1); i++)
11776203945Sweongyo		BWN_PHY_WRITE(mac, v1[i].reg, v1[i].value);
11777203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x10);
11778203945Sweongyo	for (i = 0; i < N(v2); i++)
11779203945Sweongyo		BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask, v2[i].set);
11780203945Sweongyo
11781203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x4000);
11782203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x2000);
11783203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_OFDM(0x10a), 0x1);
11784204922Sweongyo	if (siba_get_pci_revid(sc->sc_dev) >= 0x18) {
11785203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(17, 65), 0xec);
11786203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x14);
11787203945Sweongyo	} else {
11788203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x10);
11789203945Sweongyo	}
11790203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0xff00, 0xf4);
11791203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0x00ff, 0xf100);
11792203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CLIPTHRESH, 0x48);
11793203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0xff00, 0x46);
11794203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe4), 0xff00, 0x10);
11795203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_PWR_THRESH1, 0xfff0, 0x9);
11796203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_GAINDIRECTMISMATCH, ~0xf);
11797203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5500);
11798203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0xa0);
11799203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_GAINDIRECTMISMATCH, 0xe0ff, 0x300);
11800203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2a00);
11801204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11802204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11803203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11804203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xa);
11805203945Sweongyo	} else {
11806203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x1e00);
11807203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xd);
11808203945Sweongyo	}
11809203945Sweongyo	for (i = 0; i < N(v3); i++)
11810203945Sweongyo		BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask, v3[i].set);
11811204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11812204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11813203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x14), 0);
11814203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x12), 0x40);
11815203945Sweongyo	}
11816203945Sweongyo
11817203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11818203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x40);
11819203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0xb00);
11820203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x6);
11821203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0x9d00);
11822203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0xff00, 0xa1);
11823203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11824203945Sweongyo	} else
11825203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x40);
11826203945Sweongyo
11827203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0xff00, 0xb3);
11828203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00);
11829203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB, 0xff00, plp->plp_rxpwroffset);
11830203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RESET_CTL, 0x44);
11831203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RESET_CTL, 0x80);
11832203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, 0xa954);
11833203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_1,
11834203945Sweongyo	    0x2000 | ((uint16_t)plp->plp_rssigs << 10) |
11835203945Sweongyo	    ((uint16_t)plp->plp_rssivc << 4) | plp->plp_rssivf);
11836203945Sweongyo
11837204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11838204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11839203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_AFE_ADC_CTL_0, 0x1c);
11840203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_CTL, 0x00ff, 0x8800);
11841203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_1, 0xfc3c, 0x0400);
11842203945Sweongyo	}
11843203945Sweongyo
11844203945Sweongyo	bwn_phy_lp_digflt_save(mac);
11845203945Sweongyo}
11846203945Sweongyo
11847203945Sweongyostatic void
11848203945Sweongyobwn_phy_lp_bbinit_r01(struct bwn_mac *mac)
11849203945Sweongyo{
11850203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11851203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11852203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11853203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11854203945Sweongyo	static const struct bwn_smpair v1[] = {
11855203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 },
11856203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 },
11857203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x3c00 },
11858203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xfff0, 0x0005 },
11859203945Sweongyo		{ BWN_PHY_GAIN_MISMATCH_LIMIT, 0xffc0, 0x001a },
11860203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0xff00, 0x00b3 },
11861203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00 }
11862203945Sweongyo	};
11863203945Sweongyo	static const struct bwn_smpair v2[] = {
11864203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11865203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0x3f00, 0x0900 },
11866203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11867203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11868203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x000a },
11869203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0400 },
11870203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x000a },
11871203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0b00 },
11872203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xffc0, 0x000a },
11873203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xc0ff, 0x0900 },
11874203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xffc0, 0x000a },
11875203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xc0ff, 0x0b00 },
11876203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xffc0, 0x000a },
11877203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xc0ff, 0x0900 },
11878203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xffc0, 0x000a },
11879203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xc0ff, 0x0b00 }
11880203945Sweongyo	};
11881203945Sweongyo	static const struct bwn_smpair v3[] = {
11882203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0001 },
11883203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0400 },
11884203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0001 },
11885203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0500 },
11886203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11887203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0800 },
11888203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11889203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0a00 }
11890203945Sweongyo	};
11891203945Sweongyo	static const struct bwn_smpair v4[] = {
11892203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0004 },
11893203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0800 },
11894203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0004 },
11895203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0c00 },
11896203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11897203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0100 },
11898203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11899203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0300 }
11900203945Sweongyo	};
11901203945Sweongyo	static const struct bwn_smpair v5[] = {
11902203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11903203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0900 },
11904203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11905203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11906203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0006 },
11907203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0500 },
11908203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0006 },
11909203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0700 }
11910203945Sweongyo	};
11911203945Sweongyo	int i;
11912203945Sweongyo	uint16_t tmp, tmp2;
11913203945Sweongyo
11914203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf7ff);
11915203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL, 0);
11916203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, 0);
11917203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, 0);
11918203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0);
11919203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DAC_CTL, 0x0004);
11920203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0x0078);
11921203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800);
11922203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x0016);
11923203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_0, 0xfff8, 0x0004);
11924203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5400);
11925203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2400);
11926203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11927203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0x0006);
11928203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_RADIO_CTL, 0xfffe);
11929203945Sweongyo	for (i = 0; i < N(v1); i++)
11930203945Sweongyo		BWN_PHY_SETMASK(mac, v1[i].offset, v1[i].mask, v1[i].set);
11931203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB,
11932203945Sweongyo	    0xff00, plp->plp_rxpwroffset);
11933204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) &&
11934203945Sweongyo	    ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
11935204922Sweongyo	   (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_PAREF))) {
11936204922Sweongyo		siba_cc_pmu_set_ldovolt(sc->sc_dev, SIBA_LDO_PAREF, 0x28);
11937204922Sweongyo		siba_cc_pmu_set_ldoparef(sc->sc_dev, 1);
11938203945Sweongyo		if (mac->mac_phy.rev == 0)
11939203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT,
11940203945Sweongyo			    0xffcf, 0x0010);
11941203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 60);
11942203945Sweongyo	} else {
11943204922Sweongyo		siba_cc_pmu_set_ldoparef(sc->sc_dev, 0);
11944203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT, 0xffcf, 0x0020);
11945203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 100);
11946203945Sweongyo	}
11947203945Sweongyo	tmp = plp->plp_rssivf | plp->plp_rssivc << 4 | 0xa000;
11948203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, tmp);
11949204922Sweongyo	if (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_RSSIINV)
11950203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x0aaa);
11951203945Sweongyo	else
11952203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x02aa);
11953203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(11, 1), 24);
11954203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_RADIO_CTL,
11955203945Sweongyo	    0xfff9, (plp->plp_bxarch << 1));
11956203945Sweongyo	if (mac->mac_phy.rev == 1 &&
11957204922Sweongyo	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_FEM_BT)) {
11958203945Sweongyo		for (i = 0; i < N(v2); i++)
11959203945Sweongyo			BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask,
11960203945Sweongyo			    v2[i].set);
11961203945Sweongyo	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ||
11962204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) == 0x048a) ||
11963204922Sweongyo	    ((mac->mac_phy.rev == 0) &&
11964204922Sweongyo	     (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM))) {
11965203945Sweongyo		for (i = 0; i < N(v3); i++)
11966203945Sweongyo			BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask,
11967203945Sweongyo			    v3[i].set);
11968203945Sweongyo	} else if (mac->mac_phy.rev == 1 ||
11969204922Sweongyo		  (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM)) {
11970203945Sweongyo		for (i = 0; i < N(v4); i++)
11971203945Sweongyo			BWN_PHY_SETMASK(mac, v4[i].offset, v4[i].mask,
11972203945Sweongyo			    v4[i].set);
11973203945Sweongyo	} else {
11974203945Sweongyo		for (i = 0; i < N(v5); i++)
11975203945Sweongyo			BWN_PHY_SETMASK(mac, v5[i].offset, v5[i].mask,
11976203945Sweongyo			    v5[i].set);
11977203945Sweongyo	}
11978203945Sweongyo	if (mac->mac_phy.rev == 1 &&
11979204922Sweongyo	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_PAREF)) {
11980203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_5, BWN_PHY_TR_LOOKUP_1);
11981203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_6, BWN_PHY_TR_LOOKUP_2);
11982203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_7, BWN_PHY_TR_LOOKUP_3);
11983203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_8, BWN_PHY_TR_LOOKUP_4);
11984203945Sweongyo	}
11985204922Sweongyo	if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_FEM_BT) &&
11986204922Sweongyo	    (siba_get_chipid(sc->sc_dev) == 0x5354) &&
11987204922Sweongyo	    (siba_get_chippkg(sc->sc_dev) == SIBA_CHIPPACK_BCM4712S)) {
11988203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0006);
11989203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_SELECT, 0x0005);
11990203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_OUTEN, 0xffff);
11991203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_PR45960W);
11992203945Sweongyo	}
11993203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11994203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x8000);
11995203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0040);
11996203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0xa400);
11997203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0x0b00);
11998203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x0007);
11999203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xfff8, 0x0003);
12000203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xffc7, 0x0020);
12001203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
12002203945Sweongyo	} else {
12003203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0x7fff);
12004203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xffbf);
12005203945Sweongyo	}
12006203945Sweongyo	if (mac->mac_phy.rev == 1) {
12007203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_CLIPCTRTHRESH);
12008203945Sweongyo		tmp2 = (tmp & 0x03e0) >> 5;
12009203945Sweongyo		tmp2 |= tmp2 << 5;
12010203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C3, tmp2);
12011203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_GAINDIRECTMISMATCH);
12012203945Sweongyo		tmp2 = (tmp & 0x1f00) >> 8;
12013203945Sweongyo		tmp2 |= tmp2 << 5;
12014203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C4, tmp2);
12015203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERYLOWGAINDB);
12016203945Sweongyo		tmp2 = tmp & 0x00ff;
12017203945Sweongyo		tmp2 |= tmp << 8;
12018203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C5, tmp2);
12019203945Sweongyo	}
12020203945Sweongyo}
12021203945Sweongyo
12022203945Sweongyostruct bwn_b2062_freq {
12023203945Sweongyo	uint16_t		freq;
12024203945Sweongyo	uint8_t			value[6];
12025203945Sweongyo};
12026203945Sweongyo
12027203945Sweongyostatic void
12028203945Sweongyobwn_phy_lp_b2062_init(struct bwn_mac *mac)
12029203945Sweongyo{
12030203945Sweongyo#define	CALC_CTL7(freq, div)						\
12031203945Sweongyo	(((800000000 * (div) + (freq)) / (2 * (freq)) - 8) & 0xff)
12032203945Sweongyo#define	CALC_CTL18(freq, div)						\
12033203945Sweongyo	((((100 * (freq) + 16000000 * (div)) / (32000000 * (div))) - 1) & 0xff)
12034203945Sweongyo#define	CALC_CTL19(freq, div)						\
12035203945Sweongyo	((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff)
12036203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12037203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12038203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12039203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12040203945Sweongyo	static const struct bwn_b2062_freq freqdata_tab[] = {
12041203945Sweongyo		{ 12000, { 6, 6, 6, 6, 10, 6 } },
12042203945Sweongyo		{ 13000, { 4, 4, 4, 4, 11, 7 } },
12043203945Sweongyo		{ 14400, { 3, 3, 3, 3, 12, 7 } },
12044203945Sweongyo		{ 16200, { 3, 3, 3, 3, 13, 8 } },
12045203945Sweongyo		{ 18000, { 2, 2, 2, 2, 14, 8 } },
12046203945Sweongyo		{ 19200, { 1, 1, 1, 1, 14, 9 } }
12047203945Sweongyo	};
12048203945Sweongyo	static const struct bwn_wpair v1[] = {
12049203945Sweongyo		{ BWN_B2062_N_TXCTL3, 0 },
12050203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0 },
12051203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0 },
12052203945Sweongyo		{ BWN_B2062_N_TXCTL6, 0 },
12053203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0x40 },
12054203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0 },
12055203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0x10 },
12056203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0 }
12057203945Sweongyo	};
12058203945Sweongyo	const struct bwn_b2062_freq *f = NULL;
12059203945Sweongyo	uint32_t xtalfreq, ref;
12060203945Sweongyo	unsigned int i;
12061203945Sweongyo
12062203945Sweongyo	bwn_phy_lp_b2062_tblinit(mac);
12063203945Sweongyo
12064203945Sweongyo	for (i = 0; i < N(v1); i++)
12065203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12066203945Sweongyo	if (mac->mac_phy.rev > 0)
12067203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_BG_CTL1,
12068203945Sweongyo		    (BWN_RF_READ(mac, BWN_B2062_N_COM2) >> 1) | 0x80);
12069203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12070203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_N_TSSI_CTL0, 0x1);
12071203945Sweongyo	else
12072203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_N_TSSI_CTL0, ~0x1);
12073203945Sweongyo
12074204922Sweongyo	KASSERT(siba_get_cc_caps(sc->sc_dev) & SIBA_CC_CAPS_PMU,
12075203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
12076204922Sweongyo	xtalfreq = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
12077203945Sweongyo	KASSERT(xtalfreq != 0, ("%s:%d: fail", __func__, __LINE__));
12078203945Sweongyo
12079203945Sweongyo	if (xtalfreq <= 30000000) {
12080203945Sweongyo		plp->plp_div = 1;
12081203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL1, 0xfffb);
12082203945Sweongyo	} else {
12083203945Sweongyo		plp->plp_div = 2;
12084203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL1, 0x4);
12085203945Sweongyo	}
12086203945Sweongyo
12087203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL7,
12088203945Sweongyo	    CALC_CTL7(xtalfreq, plp->plp_div));
12089203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL18,
12090203945Sweongyo	    CALC_CTL18(xtalfreq, plp->plp_div));
12091203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL19,
12092203945Sweongyo	    CALC_CTL19(xtalfreq, plp->plp_div));
12093203945Sweongyo
12094203945Sweongyo	ref = (1000 * plp->plp_div + 2 * xtalfreq) / (2000 * plp->plp_div);
12095203945Sweongyo	ref &= 0xffff;
12096203945Sweongyo	for (i = 0; i < N(freqdata_tab); i++) {
12097203945Sweongyo		if (ref < freqdata_tab[i].freq) {
12098203945Sweongyo			f = &freqdata_tab[i];
12099203945Sweongyo			break;
12100203945Sweongyo		}
12101203945Sweongyo	}
12102203945Sweongyo	if (f == NULL)
12103203945Sweongyo		f = &freqdata_tab[N(freqdata_tab) - 1];
12104203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL8,
12105203945Sweongyo	    ((uint16_t)(f->value[1]) << 4) | f->value[0]);
12106203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL9,
12107203945Sweongyo	    ((uint16_t)(f->value[3]) << 4) | f->value[2]);
12108203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL10, f->value[4]);
12109203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL11, f->value[5]);
12110203945Sweongyo#undef CALC_CTL7
12111203945Sweongyo#undef CALC_CTL18
12112203945Sweongyo#undef CALC_CTL19
12113203945Sweongyo}
12114203945Sweongyo
12115203945Sweongyostatic void
12116203945Sweongyobwn_phy_lp_b2063_init(struct bwn_mac *mac)
12117203945Sweongyo{
12118203945Sweongyo
12119203945Sweongyo	bwn_phy_lp_b2063_tblinit(mac);
12120203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_SP5, 0);
12121203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM8, 0x38);
12122203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_REG_SP1, 0x56);
12123203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_RX_BB_CTL2, ~0x2);
12124203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0);
12125203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP6, 0x20);
12126203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP9, 0x40);
12127203945Sweongyo	if (mac->mac_phy.rev == 2) {
12128203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0xa0);
12129203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP4, 0xa0);
12130203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x18);
12131203945Sweongyo	} else {
12132203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0x20);
12133203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x20);
12134203945Sweongyo	}
12135203945Sweongyo}
12136203945Sweongyo
12137203945Sweongyostatic void
12138203945Sweongyobwn_phy_lp_rxcal_r2(struct bwn_mac *mac)
12139203945Sweongyo{
12140204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12141203945Sweongyo	static const struct bwn_wpair v1[] = {
12142203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x0 },
12143203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12144203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12145203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x15 },
12146203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x70 },
12147203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL4, 0x52 },
12148203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL5, 0x1 },
12149203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7d }
12150203945Sweongyo	};
12151203945Sweongyo	static const struct bwn_wpair v2[] = {
12152203945Sweongyo		{ BWN_B2063_TX_BB_SP3, 0x0 },
12153203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12154203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12155203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x55 },
12156203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x76 }
12157203945Sweongyo	};
12158204922Sweongyo	uint32_t freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
12159203945Sweongyo	int i;
12160203945Sweongyo	uint8_t tmp;
12161203945Sweongyo
12162203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_RX_BB_SP8) & 0xff;
12163203945Sweongyo
12164203945Sweongyo	for (i = 0; i < 2; i++)
12165203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12166203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, 0xf7);
12167203945Sweongyo	for (i = 2; i < N(v1); i++)
12168203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12169203945Sweongyo	for (i = 0; i < 10000; i++) {
12170203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12171203945Sweongyo			break;
12172203945Sweongyo		DELAY(1000);
12173203945Sweongyo	}
12174203945Sweongyo
12175203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12176203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RX_BB_SP8, tmp);
12177203945Sweongyo
12178203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_TX_BB_SP3) & 0xff;
12179203945Sweongyo
12180203945Sweongyo	for (i = 0; i < N(v2); i++)
12181203945Sweongyo		BWN_RF_WRITE(mac, v2[i].reg, v2[i].value);
12182203945Sweongyo	if (freqxtal == 24000000) {
12183203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0xfc);
12184203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x0);
12185203945Sweongyo	} else {
12186203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0x13);
12187203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x1);
12188203945Sweongyo	}
12189203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0x7d);
12190203945Sweongyo	for (i = 0; i < 10000; i++) {
12191203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12192203945Sweongyo			break;
12193203945Sweongyo		DELAY(1000);
12194203945Sweongyo	}
12195203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12196203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, tmp);
12197203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL1, 0x7e);
12198203945Sweongyo}
12199203945Sweongyo
12200203945Sweongyostatic void
12201203945Sweongyobwn_phy_lp_rccal_r12(struct bwn_mac *mac)
12202203945Sweongyo{
12203203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12204203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12205203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12206203945Sweongyo	struct bwn_txgain tx_gains;
12207203945Sweongyo	static const uint32_t pwrtbl[21] = {
12208203945Sweongyo		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
12209203945Sweongyo		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
12210203945Sweongyo		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
12211203945Sweongyo		0x0004c, 0x0002c, 0x0001a,
12212203945Sweongyo	};
12213203945Sweongyo	uint32_t npwr, ipwr, sqpwr, tmp;
12214203945Sweongyo	int loopback, i, j, sum, error;
12215203945Sweongyo	uint16_t save[7];
12216203945Sweongyo	uint8_t txo, bbmult, txpctlmode;
12217203945Sweongyo
12218203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
12219203945Sweongyo	if (error)
12220203945Sweongyo		device_printf(sc->sc_dev,
12221203945Sweongyo		    "failed to change channel to 7 (%d)\n", error);
12222203945Sweongyo	txo = (BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40) ? 1 : 0;
12223203945Sweongyo	bbmult = bwn_phy_lp_get_bbmult(mac);
12224203945Sweongyo	if (txo)
12225203945Sweongyo		tx_gains = bwn_phy_lp_get_txgain(mac);
12226203945Sweongyo
12227203945Sweongyo	save[0] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_0);
12228203945Sweongyo	save[1] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_VAL_0);
12229203945Sweongyo	save[2] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR);
12230203945Sweongyo	save[3] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVRVAL);
12231203945Sweongyo	save[4] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2);
12232203945Sweongyo	save[5] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2_VAL);
12233203945Sweongyo	save[6] = BWN_PHY_READ(mac, BWN_PHY_LP_PHY_CTL);
12234203945Sweongyo
12235203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
12236203945Sweongyo	txpctlmode = plp->plp_txpctlmode;
12237203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
12238203945Sweongyo
12239203945Sweongyo	/* disable CRS */
12240203945Sweongyo	bwn_phy_lp_set_deaf(mac, 1);
12241203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 0, 1);
12242203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffb);
12243203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x4);
12244203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7);
12245203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
12246203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x10);
12247203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12248203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf);
12249203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
12250203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffbf);
12251203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12252203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x7);
12253203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x38);
12254203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f);
12255203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x100);
12256203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfdff);
12257203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL0, 0);
12258203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL1, 1);
12259203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL2, 0x20);
12260203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfbff);
12261203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xf7ff);
12262203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
12263203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45af);
12264203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0x3ff);
12265203945Sweongyo
12266203945Sweongyo	loopback = bwn_phy_lp_loopback(mac);
12267203945Sweongyo	if (loopback == -1)
12268203945Sweongyo		goto done;
12269203945Sweongyo	bwn_phy_lp_set_rxgain_idx(mac, loopback);
12270203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xffbf, 0x40);
12271203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfff8, 0x1);
12272203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xffc7, 0x8);
12273203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f, 0xc0);
12274203945Sweongyo
12275203945Sweongyo	tmp = 0;
12276203945Sweongyo	memset(&ie, 0, sizeof(ie));
12277203945Sweongyo	for (i = 128; i <= 159; i++) {
12278203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2, i);
12279203945Sweongyo		sum = 0;
12280203945Sweongyo		for (j = 5; j <= 25; j++) {
12281203945Sweongyo			bwn_phy_lp_ddfs_turnon(mac, 1, 1, j, j, 0);
12282203945Sweongyo			if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
12283203945Sweongyo				goto done;
12284203945Sweongyo			sqpwr = ie.ie_ipwr + ie.ie_qpwr;
12285203945Sweongyo			ipwr = ((pwrtbl[j - 5] >> 3) + 1) >> 1;
12286203945Sweongyo			npwr = bwn_phy_lp_roundup(sqpwr, (j == 5) ? sqpwr : 0,
12287203945Sweongyo			    12);
12288203945Sweongyo			sum += ((ipwr - npwr) * (ipwr - npwr));
12289203945Sweongyo			if ((i == 128) || (sum < tmp)) {
12290203945Sweongyo				plp->plp_rccap = i;
12291203945Sweongyo				tmp = sum;
12292203945Sweongyo			}
12293203945Sweongyo		}
12294203945Sweongyo	}
12295203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
12296203945Sweongyodone:
12297203945Sweongyo	/* restore CRS */
12298203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 1);
12299203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xff80);
12300203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfc00);
12301203945Sweongyo
12302203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_VAL_0, save[1]);
12303203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, save[0]);
12304203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVRVAL, save[3]);
12305203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, save[2]);
12306203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2_VAL, save[5]);
12307203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, save[4]);
12308203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LP_PHY_CTL, save[6]);
12309203945Sweongyo
12310203945Sweongyo	bwn_phy_lp_set_bbmult(mac, bbmult);
12311203945Sweongyo	if (txo)
12312203945Sweongyo		bwn_phy_lp_set_txgain(mac, &tx_gains);
12313203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, txpctlmode);
12314203945Sweongyo	if (plp->plp_rccap)
12315203945Sweongyo		bwn_phy_lp_set_rccap(mac);
12316203945Sweongyo}
12317203945Sweongyo
12318203945Sweongyostatic void
12319203945Sweongyobwn_phy_lp_set_rccap(struct bwn_mac *mac)
12320203945Sweongyo{
12321203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12322203945Sweongyo	uint8_t rc_cap = (plp->plp_rccap & 0x1f) >> 1;
12323203945Sweongyo
12324203945Sweongyo	if (mac->mac_phy.rev == 1)
12325203945Sweongyo		rc_cap = MIN(rc_cap + 5, 15);
12326203945Sweongyo
12327203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2,
12328203945Sweongyo	    MAX(plp->plp_rccap - 4, 0x80));
12329203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, rc_cap | 0x80);
12330203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RXG_CNT16,
12331203945Sweongyo	    ((plp->plp_rccap & 0x1f) >> 2) | 0x80);
12332203945Sweongyo}
12333203945Sweongyo
12334203945Sweongyostatic uint32_t
12335203945Sweongyobwn_phy_lp_roundup(uint32_t value, uint32_t div, uint8_t pre)
12336203945Sweongyo{
12337203945Sweongyo	uint32_t i, q, r;
12338203945Sweongyo
12339203945Sweongyo	if (div == 0)
12340203945Sweongyo		return (0);
12341203945Sweongyo
12342203945Sweongyo	for (i = 0, q = value / div, r = value % div; i < pre; i++) {
12343203945Sweongyo		q <<= 1;
12344203945Sweongyo		if (r << 1 >= div) {
12345203945Sweongyo			q++;
12346203945Sweongyo			r = (r << 1) - div;
12347203945Sweongyo		}
12348203945Sweongyo	}
12349203945Sweongyo	if (r << 1 >= div)
12350203945Sweongyo		q++;
12351203945Sweongyo	return (q);
12352203945Sweongyo}
12353203945Sweongyo
12354203945Sweongyostatic void
12355203945Sweongyobwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *mac)
12356203945Sweongyo{
12357204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12358203945Sweongyo
12359203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0xff);
12360203945Sweongyo	DELAY(20);
12361204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x5354) {
12362203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_COM1, 4);
12363203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 4);
12364203945Sweongyo	} else {
12365203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0);
12366203945Sweongyo	}
12367203945Sweongyo	DELAY(5);
12368203945Sweongyo}
12369203945Sweongyo
12370203945Sweongyostatic void
12371203945Sweongyobwn_phy_lp_b2062_vco_calib(struct bwn_mac *mac)
12372203945Sweongyo{
12373203945Sweongyo
12374203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x42);
12375203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x62);
12376203945Sweongyo	DELAY(200);
12377203945Sweongyo}
12378203945Sweongyo
12379203945Sweongyostatic void
12380203945Sweongyobwn_phy_lp_b2062_tblinit(struct bwn_mac *mac)
12381203945Sweongyo{
12382203945Sweongyo#define	FLAG_A	0x01
12383203945Sweongyo#define	FLAG_G	0x02
12384203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12385203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12386203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12387203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = {
12388203945Sweongyo		{ BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12389203945Sweongyo		{ BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, },
12390203945Sweongyo		{ BWN_B2062_N_PDNCTL3, 0x0, 0x0, FLAG_A | FLAG_G, },
12391203945Sweongyo		{ BWN_B2062_N_PDNCTL4, 0x15, 0x2a, FLAG_A | FLAG_G, },
12392203945Sweongyo		{ BWN_B2062_N_LGENC, 0xDB, 0xff, FLAG_A, },
12393203945Sweongyo		{ BWN_B2062_N_LGENATUNE0, 0xdd, 0x0, FLAG_A | FLAG_G, },
12394203945Sweongyo		{ BWN_B2062_N_LGENATUNE2, 0xdd, 0x0, FLAG_A | FLAG_G, },
12395203945Sweongyo		{ BWN_B2062_N_LGENATUNE3, 0x77, 0xB5, FLAG_A | FLAG_G, },
12396203945Sweongyo		{ BWN_B2062_N_LGENACTL3, 0x0, 0xff, FLAG_A | FLAG_G, },
12397203945Sweongyo		{ BWN_B2062_N_LGENACTL7, 0x33, 0x33, FLAG_A | FLAG_G, },
12398203945Sweongyo		{ BWN_B2062_N_RXA_CTL1, 0x0, 0x0, FLAG_G, },
12399203945Sweongyo		{ BWN_B2062_N_RXBB_CTL0, 0x82, 0x80, FLAG_A | FLAG_G, },
12400203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN1, 0x4, 0x4, FLAG_A | FLAG_G, },
12401203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN2, 0x0, 0x0, FLAG_A | FLAG_G, },
12402203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0x3, 0x3, FLAG_A | FLAG_G, },
12403203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0x2, 0x2, FLAG_A | FLAG_G, },
12404203945Sweongyo		{ BWN_B2062_N_TX_TUNE, 0x88, 0x1b, FLAG_A | FLAG_G, },
12405203945Sweongyo		{ BWN_B2062_S_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12406203945Sweongyo		{ BWN_B2062_S_PDS_CTL0, 0xff, 0xff, FLAG_A | FLAG_G, },
12407203945Sweongyo		{ BWN_B2062_S_LGENG_CTL0, 0xf8, 0xd8, FLAG_A | FLAG_G, },
12408203945Sweongyo		{ BWN_B2062_S_LGENG_CTL1, 0x3c, 0x24, FLAG_A | FLAG_G, },
12409203945Sweongyo		{ BWN_B2062_S_LGENG_CTL8, 0x88, 0x80, FLAG_A | FLAG_G, },
12410203945Sweongyo		{ BWN_B2062_S_LGENG_CTL10, 0x88, 0x80, FLAG_A | FLAG_G, },
12411203945Sweongyo		{ BWN_B2062_S_RFPLLCTL0, 0x98, 0x98, FLAG_A | FLAG_G, },
12412203945Sweongyo		{ BWN_B2062_S_RFPLLCTL1, 0x10, 0x10, FLAG_A | FLAG_G, },
12413203945Sweongyo		{ BWN_B2062_S_RFPLLCTL5, 0x43, 0x43, FLAG_A | FLAG_G, },
12414203945Sweongyo		{ BWN_B2062_S_RFPLLCTL6, 0x47, 0x47, FLAG_A | FLAG_G, },
12415203945Sweongyo		{ BWN_B2062_S_RFPLLCTL7, 0xc, 0xc, FLAG_A | FLAG_G, },
12416203945Sweongyo		{ BWN_B2062_S_RFPLLCTL8, 0x11, 0x11, FLAG_A | FLAG_G, },
12417203945Sweongyo		{ BWN_B2062_S_RFPLLCTL9, 0x11, 0x11, FLAG_A | FLAG_G, },
12418203945Sweongyo		{ BWN_B2062_S_RFPLLCTL10, 0xe, 0xe, FLAG_A | FLAG_G, },
12419203945Sweongyo		{ BWN_B2062_S_RFPLLCTL11, 0x8, 0x8, FLAG_A | FLAG_G, },
12420203945Sweongyo		{ BWN_B2062_S_RFPLLCTL12, 0x33, 0x33, FLAG_A | FLAG_G, },
12421203945Sweongyo		{ BWN_B2062_S_RFPLLCTL13, 0xa, 0xa, FLAG_A | FLAG_G, },
12422203945Sweongyo		{ BWN_B2062_S_RFPLLCTL14, 0x6, 0x6, FLAG_A | FLAG_G, },
12423203945Sweongyo		{ BWN_B2062_S_RFPLLCTL18, 0x3e, 0x3e, FLAG_A | FLAG_G, },
12424203945Sweongyo		{ BWN_B2062_S_RFPLLCTL19, 0x13, 0x13, FLAG_A | FLAG_G, },
12425203945Sweongyo		{ BWN_B2062_S_RFPLLCTL21, 0x62, 0x62, FLAG_A | FLAG_G, },
12426203945Sweongyo		{ BWN_B2062_S_RFPLLCTL22, 0x7, 0x7, FLAG_A | FLAG_G, },
12427203945Sweongyo		{ BWN_B2062_S_RFPLLCTL23, 0x16, 0x16, FLAG_A | FLAG_G, },
12428203945Sweongyo		{ BWN_B2062_S_RFPLLCTL24, 0x5c, 0x5c, FLAG_A | FLAG_G, },
12429203945Sweongyo		{ BWN_B2062_S_RFPLLCTL25, 0x95, 0x95, FLAG_A | FLAG_G, },
12430203945Sweongyo		{ BWN_B2062_S_RFPLLCTL30, 0xa0, 0xa0, FLAG_A | FLAG_G, },
12431203945Sweongyo		{ BWN_B2062_S_RFPLLCTL31, 0x4, 0x4, FLAG_A | FLAG_G, },
12432203945Sweongyo		{ BWN_B2062_S_RFPLLCTL33, 0xcc, 0xcc, FLAG_A | FLAG_G, },
12433203945Sweongyo		{ BWN_B2062_S_RFPLLCTL34, 0x7, 0x7, FLAG_A | FLAG_G, },
12434203945Sweongyo		{ BWN_B2062_S_RXG_CNT8, 0xf, 0xf, FLAG_A, },
12435203945Sweongyo	};
12436203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12437203945Sweongyo	unsigned int i;
12438203945Sweongyo
12439203945Sweongyo	for (i = 0; i < N(bwn_b2062_init_tab); i++) {
12440203945Sweongyo		br = &bwn_b2062_init_tab[i];
12441203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12442203945Sweongyo			if (br->br_flags & FLAG_G)
12443203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12444203945Sweongyo		} else {
12445203945Sweongyo			if (br->br_flags & FLAG_A)
12446203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12447203945Sweongyo		}
12448203945Sweongyo	}
12449203945Sweongyo#undef FLAG_A
12450203945Sweongyo#undef FLAG_B
12451203945Sweongyo}
12452203945Sweongyo
12453203945Sweongyostatic void
12454203945Sweongyobwn_phy_lp_b2063_tblinit(struct bwn_mac *mac)
12455203945Sweongyo{
12456203945Sweongyo#define	FLAG_A	0x01
12457203945Sweongyo#define	FLAG_G	0x02
12458203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12459203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12460203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12461203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = {
12462203945Sweongyo		{ BWN_B2063_COM1, 0x0, 0x0, FLAG_G, },
12463203945Sweongyo		{ BWN_B2063_COM10, 0x1, 0x0, FLAG_A, },
12464203945Sweongyo		{ BWN_B2063_COM16, 0x0, 0x0, FLAG_G, },
12465203945Sweongyo		{ BWN_B2063_COM17, 0x0, 0x0, FLAG_G, },
12466203945Sweongyo		{ BWN_B2063_COM18, 0x0, 0x0, FLAG_G, },
12467203945Sweongyo		{ BWN_B2063_COM19, 0x0, 0x0, FLAG_G, },
12468203945Sweongyo		{ BWN_B2063_COM20, 0x0, 0x0, FLAG_G, },
12469203945Sweongyo		{ BWN_B2063_COM21, 0x0, 0x0, FLAG_G, },
12470203945Sweongyo		{ BWN_B2063_COM22, 0x0, 0x0, FLAG_G, },
12471203945Sweongyo		{ BWN_B2063_COM23, 0x0, 0x0, FLAG_G, },
12472203945Sweongyo		{ BWN_B2063_COM24, 0x0, 0x0, FLAG_G, },
12473203945Sweongyo		{ BWN_B2063_LOGEN_SP1, 0xe8, 0xd4, FLAG_A | FLAG_G, },
12474203945Sweongyo		{ BWN_B2063_LOGEN_SP2, 0xa7, 0x53, FLAG_A | FLAG_G, },
12475203945Sweongyo		{ BWN_B2063_LOGEN_SP4, 0xf0, 0xf, FLAG_A | FLAG_G, },
12476203945Sweongyo		{ BWN_B2063_G_RX_SP1, 0x1f, 0x5e, FLAG_G, },
12477203945Sweongyo		{ BWN_B2063_G_RX_SP2, 0x7f, 0x7e, FLAG_G, },
12478203945Sweongyo		{ BWN_B2063_G_RX_SP3, 0x30, 0xf0, FLAG_G, },
12479203945Sweongyo		{ BWN_B2063_G_RX_SP7, 0x7f, 0x7f, FLAG_A | FLAG_G, },
12480203945Sweongyo		{ BWN_B2063_G_RX_SP10, 0xc, 0xc, FLAG_A | FLAG_G, },
12481203945Sweongyo		{ BWN_B2063_A_RX_SP1, 0x3c, 0x3f, FLAG_A, },
12482203945Sweongyo		{ BWN_B2063_A_RX_SP2, 0xfc, 0xfe, FLAG_A, },
12483203945Sweongyo		{ BWN_B2063_A_RX_SP7, 0x8, 0x8, FLAG_A | FLAG_G, },
12484203945Sweongyo		{ BWN_B2063_RX_BB_SP4, 0x60, 0x60, FLAG_A | FLAG_G, },
12485203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x30, 0x30, FLAG_A | FLAG_G, },
12486203945Sweongyo		{ BWN_B2063_TX_RF_SP3, 0xc, 0xb, FLAG_A | FLAG_G, },
12487203945Sweongyo		{ BWN_B2063_TX_RF_SP4, 0x10, 0xf, FLAG_A | FLAG_G, },
12488203945Sweongyo		{ BWN_B2063_PA_SP1, 0x3d, 0xfd, FLAG_A | FLAG_G, },
12489203945Sweongyo		{ BWN_B2063_TX_BB_SP1, 0x2, 0x2, FLAG_A | FLAG_G, },
12490203945Sweongyo		{ BWN_B2063_BANDGAP_CTL1, 0x56, 0x56, FLAG_A | FLAG_G, },
12491203945Sweongyo		{ BWN_B2063_JTAG_VCO2, 0xF7, 0xF7, FLAG_A | FLAG_G, },
12492203945Sweongyo		{ BWN_B2063_G_RX_MIX3, 0x71, 0x71, FLAG_A | FLAG_G, },
12493203945Sweongyo		{ BWN_B2063_G_RX_MIX4, 0x71, 0x71, FLAG_A | FLAG_G, },
12494203945Sweongyo		{ BWN_B2063_A_RX_1ST2, 0xf0, 0x30, FLAG_A, },
12495203945Sweongyo		{ BWN_B2063_A_RX_PS6, 0x77, 0x77, FLAG_A | FLAG_G, },
12496203945Sweongyo		{ BWN_B2063_A_RX_MIX4, 0x3, 0x3, FLAG_A | FLAG_G, },
12497203945Sweongyo		{ BWN_B2063_A_RX_MIX5, 0xf, 0xf, FLAG_A | FLAG_G, },
12498203945Sweongyo		{ BWN_B2063_A_RX_MIX6, 0xf, 0xf, FLAG_A | FLAG_G, },
12499203945Sweongyo		{ BWN_B2063_RX_TIA_CTL1, 0x77, 0x77, FLAG_A | FLAG_G, },
12500203945Sweongyo		{ BWN_B2063_RX_TIA_CTL3, 0x77, 0x77, FLAG_A | FLAG_G, },
12501203945Sweongyo		{ BWN_B2063_RX_BB_CTL2, 0x4, 0x4, FLAG_A | FLAG_G, },
12502203945Sweongyo		{ BWN_B2063_PA_CTL1, 0x0, 0x4, FLAG_A, },
12503203945Sweongyo		{ BWN_B2063_VREG_CTL1, 0x3, 0x3, FLAG_A | FLAG_G, },
12504203945Sweongyo	};
12505203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12506203945Sweongyo	unsigned int i;
12507203945Sweongyo
12508203945Sweongyo	for (i = 0; i < N(bwn_b2063_init_tab); i++) {
12509203945Sweongyo		br = &bwn_b2063_init_tab[i];
12510203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12511203945Sweongyo			if (br->br_flags & FLAG_G)
12512203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12513203945Sweongyo		} else {
12514203945Sweongyo			if (br->br_flags & FLAG_A)
12515203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12516203945Sweongyo		}
12517203945Sweongyo	}
12518203945Sweongyo#undef FLAG_A
12519203945Sweongyo#undef FLAG_B
12520203945Sweongyo}
12521203945Sweongyo
12522203945Sweongyostatic void
12523203945Sweongyobwn_tab_read_multi(struct bwn_mac *mac, uint32_t typenoffset,
12524203945Sweongyo    int count, void *_data)
12525203945Sweongyo{
12526203945Sweongyo	unsigned int i;
12527203945Sweongyo	uint32_t offset, type;
12528203945Sweongyo	uint8_t *data = _data;
12529203945Sweongyo
12530203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12531203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12532203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12533203945Sweongyo
12534203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12535203945Sweongyo
12536203945Sweongyo	for (i = 0; i < count; i++) {
12537203945Sweongyo		switch (type) {
12538203945Sweongyo		case BWN_TAB_8BIT:
12539203945Sweongyo			*data = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
12540203945Sweongyo			data++;
12541203945Sweongyo			break;
12542203945Sweongyo		case BWN_TAB_16BIT:
12543203945Sweongyo			*((uint16_t *)data) = BWN_PHY_READ(mac,
12544203945Sweongyo			    BWN_PHY_TABLEDATALO);
12545203945Sweongyo			data += 2;
12546203945Sweongyo			break;
12547203945Sweongyo		case BWN_TAB_32BIT:
12548203945Sweongyo			*((uint32_t *)data) = BWN_PHY_READ(mac,
12549203945Sweongyo			    BWN_PHY_TABLEDATAHI);
12550203945Sweongyo			*((uint32_t *)data) <<= 16;
12551203945Sweongyo			*((uint32_t *)data) |= BWN_PHY_READ(mac,
12552203945Sweongyo			    BWN_PHY_TABLEDATALO);
12553203945Sweongyo			data += 4;
12554203945Sweongyo			break;
12555203945Sweongyo		default:
12556203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12557203945Sweongyo		}
12558203945Sweongyo	}
12559203945Sweongyo}
12560203945Sweongyo
12561203945Sweongyostatic void
12562203945Sweongyobwn_tab_write_multi(struct bwn_mac *mac, uint32_t typenoffset,
12563203945Sweongyo    int count, const void *_data)
12564203945Sweongyo{
12565203945Sweongyo	uint32_t offset, type, value;
12566203945Sweongyo	const uint8_t *data = _data;
12567203945Sweongyo	unsigned int i;
12568203945Sweongyo
12569203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12570203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12571203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12572203945Sweongyo
12573203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12574203945Sweongyo
12575203945Sweongyo	for (i = 0; i < count; i++) {
12576203945Sweongyo		switch (type) {
12577203945Sweongyo		case BWN_TAB_8BIT:
12578203945Sweongyo			value = *data;
12579203945Sweongyo			data++;
12580203945Sweongyo			KASSERT(!(value & ~0xff),
12581203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12582203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12583203945Sweongyo			break;
12584203945Sweongyo		case BWN_TAB_16BIT:
12585203945Sweongyo			value = *((const uint16_t *)data);
12586203945Sweongyo			data += 2;
12587203945Sweongyo			KASSERT(!(value & ~0xffff),
12588203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12589203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12590203945Sweongyo			break;
12591203945Sweongyo		case BWN_TAB_32BIT:
12592203945Sweongyo			value = *((const uint32_t *)data);
12593203945Sweongyo			data += 4;
12594203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
12595203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12596203945Sweongyo			break;
12597203945Sweongyo		default:
12598203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12599203945Sweongyo		}
12600203945Sweongyo	}
12601203945Sweongyo}
12602203945Sweongyo
12603203945Sweongyostatic struct bwn_txgain
12604203945Sweongyobwn_phy_lp_get_txgain(struct bwn_mac *mac)
12605203945Sweongyo{
12606203945Sweongyo	struct bwn_txgain tg;
12607203945Sweongyo	uint16_t tmp;
12608203945Sweongyo
12609203945Sweongyo	tg.tg_dac = (BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0x380) >> 7;
12610203945Sweongyo	if (mac->mac_phy.rev < 2) {
12611203945Sweongyo		tmp = BWN_PHY_READ(mac,
12612203945Sweongyo		    BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7ff;
12613203945Sweongyo		tg.tg_gm = tmp & 0x0007;
12614203945Sweongyo		tg.tg_pga = (tmp & 0x0078) >> 3;
12615203945Sweongyo		tg.tg_pad = (tmp & 0x780) >> 7;
12616203945Sweongyo		return (tg);
12617203945Sweongyo	}
12618203945Sweongyo
12619203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL);
12620203945Sweongyo	tg.tg_pad = BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0xff;
12621203945Sweongyo	tg.tg_gm = tmp & 0xff;
12622203945Sweongyo	tg.tg_pga = (tmp >> 8) & 0xff;
12623203945Sweongyo	return (tg);
12624203945Sweongyo}
12625203945Sweongyo
12626203945Sweongyostatic uint8_t
12627203945Sweongyobwn_phy_lp_get_bbmult(struct bwn_mac *mac)
12628203945Sweongyo{
12629203945Sweongyo
12630203945Sweongyo	return (bwn_tab_read(mac, BWN_TAB_2(0, 87)) & 0xff00) >> 8;
12631203945Sweongyo}
12632203945Sweongyo
12633203945Sweongyostatic void
12634203945Sweongyobwn_phy_lp_set_txgain(struct bwn_mac *mac, struct bwn_txgain *tg)
12635203945Sweongyo{
12636203945Sweongyo	uint16_t pa;
12637203945Sweongyo
12638203945Sweongyo	if (mac->mac_phy.rev < 2) {
12639203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xf800,
12640203945Sweongyo		    (tg->tg_pad << 7) | (tg->tg_pga << 3) | tg->tg_gm);
12641203945Sweongyo		bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12642203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
12643203945Sweongyo		return;
12644203945Sweongyo	}
12645203945Sweongyo
12646203945Sweongyo	pa = bwn_phy_lp_get_pa_gain(mac);
12647203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
12648203945Sweongyo	    (tg->tg_pga << 8) | tg->tg_gm);
12649203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0x8000,
12650203945Sweongyo	    tg->tg_pad | (pa << 6));
12651203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xfc), (tg->tg_pga << 8) | tg->tg_gm);
12652203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x8000,
12653203945Sweongyo	    tg->tg_pad | (pa << 8));
12654203945Sweongyo	bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12655203945Sweongyo	bwn_phy_lp_set_txgain_override(mac);
12656203945Sweongyo}
12657203945Sweongyo
12658203945Sweongyostatic void
12659203945Sweongyobwn_phy_lp_set_bbmult(struct bwn_mac *mac, uint8_t bbmult)
12660203945Sweongyo{
12661203945Sweongyo
12662203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(0, 87), (uint16_t)bbmult << 8);
12663203945Sweongyo}
12664203945Sweongyo
12665203945Sweongyostatic void
12666203945Sweongyobwn_phy_lp_set_trsw_over(struct bwn_mac *mac, uint8_t tx, uint8_t rx)
12667203945Sweongyo{
12668203945Sweongyo	uint16_t trsw = (tx << 1) | rx;
12669203945Sweongyo
12670203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffc, trsw);
12671203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x3);
12672203945Sweongyo}
12673203945Sweongyo
12674203945Sweongyostatic void
12675203945Sweongyobwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain)
12676203945Sweongyo{
12677203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12678203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12679203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12680203945Sweongyo	uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp;
12681203945Sweongyo
12682203945Sweongyo	if (mac->mac_phy.rev < 2) {
12683203945Sweongyo		trsw = gain & 0x1;
12684203945Sweongyo		lna = (gain & 0xfffc) | ((gain & 0xc) >> 2);
12685203945Sweongyo		ext_lna = (gain & 2) >> 1;
12686203945Sweongyo
12687203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12688203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12689203945Sweongyo		    0xfbff, ext_lna << 10);
12690203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12691203945Sweongyo		    0xf7ff, ext_lna << 11);
12692203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
12693203945Sweongyo	} else {
12694203945Sweongyo		low_gain = gain & 0xffff;
12695203945Sweongyo		high_gain = (gain >> 16) & 0xf;
12696203945Sweongyo		ext_lna = (gain >> 21) & 0x1;
12697203945Sweongyo		trsw = ~(gain >> 20) & 0x1;
12698203945Sweongyo
12699203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12700203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12701203945Sweongyo		    0xfdff, ext_lna << 9);
12702203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12703203945Sweongyo		    0xfbff, ext_lna << 10);
12704203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
12705203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff0, high_gain);
12706203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12707203945Sweongyo			tmp = (gain >> 2) & 0x3;
12708203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12709203945Sweongyo			    0xe7ff, tmp<<11);
12710203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe6), 0xffe7,
12711203945Sweongyo			    tmp << 3);
12712203945Sweongyo		}
12713203945Sweongyo	}
12714203945Sweongyo
12715203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1);
12716203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12717203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12718203945Sweongyo	if (mac->mac_phy.rev >= 2) {
12719203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
12720203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12721203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x400);
12722203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xe5), 0x8);
12723203945Sweongyo		}
12724203945Sweongyo		return;
12725203945Sweongyo	}
12726203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x200);
12727203945Sweongyo}
12728203945Sweongyo
12729203945Sweongyostatic void
12730203945Sweongyobwn_phy_lp_set_deaf(struct bwn_mac *mac, uint8_t user)
12731203945Sweongyo{
12732203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12733203945Sweongyo
12734203945Sweongyo	if (user)
12735203945Sweongyo		plp->plp_crsusr_off = 1;
12736203945Sweongyo	else
12737203945Sweongyo		plp->plp_crssys_off = 1;
12738203945Sweongyo
12739203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x80);
12740203945Sweongyo}
12741203945Sweongyo
12742203945Sweongyostatic void
12743203945Sweongyobwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
12744203945Sweongyo{
12745203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12746203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12747203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12748203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12749203945Sweongyo
12750203945Sweongyo	if (user)
12751203945Sweongyo		plp->plp_crsusr_off = 0;
12752203945Sweongyo	else
12753203945Sweongyo		plp->plp_crssys_off = 0;
12754203945Sweongyo
12755203945Sweongyo	if (plp->plp_crsusr_off || plp->plp_crssys_off)
12756203945Sweongyo		return;
12757203945Sweongyo
12758203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12759203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x60);
12760203945Sweongyo	else
12761203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x20);
12762203945Sweongyo}
12763203945Sweongyo
12764203945Sweongyostatic unsigned int
12765203945Sweongyobwn_sqrt(struct bwn_mac *mac, unsigned int x)
12766203945Sweongyo{
12767203945Sweongyo	/* Table holding (10 * sqrt(x)) for x between 1 and 256. */
12768203945Sweongyo	static uint8_t sqrt_table[256] = {
12769203945Sweongyo		10, 14, 17, 20, 22, 24, 26, 28,
12770203945Sweongyo		30, 31, 33, 34, 36, 37, 38, 40,
12771203945Sweongyo		41, 42, 43, 44, 45, 46, 47, 48,
12772203945Sweongyo		50, 50, 51, 52, 53, 54, 55, 56,
12773203945Sweongyo		57, 58, 59, 60, 60, 61, 62, 63,
12774203945Sweongyo		64, 64, 65, 66, 67, 67, 68, 69,
12775203945Sweongyo		70, 70, 71, 72, 72, 73, 74, 74,
12776203945Sweongyo		75, 76, 76, 77, 78, 78, 79, 80,
12777203945Sweongyo		80, 81, 81, 82, 83, 83, 84, 84,
12778203945Sweongyo		85, 86, 86, 87, 87, 88, 88, 89,
12779203945Sweongyo		90, 90, 91, 91, 92, 92, 93, 93,
12780203945Sweongyo		94, 94, 95, 95, 96, 96, 97, 97,
12781203945Sweongyo		98, 98, 99, 100, 100, 100, 101, 101,
12782203945Sweongyo		102, 102, 103, 103, 104, 104, 105, 105,
12783203945Sweongyo		106, 106, 107, 107, 108, 108, 109, 109,
12784203945Sweongyo		110, 110, 110, 111, 111, 112, 112, 113,
12785203945Sweongyo		113, 114, 114, 114, 115, 115, 116, 116,
12786203945Sweongyo		117, 117, 117, 118, 118, 119, 119, 120,
12787203945Sweongyo		120, 120, 121, 121, 122, 122, 122, 123,
12788203945Sweongyo		123, 124, 124, 124, 125, 125, 126, 126,
12789203945Sweongyo		126, 127, 127, 128, 128, 128, 129, 129,
12790203945Sweongyo		130, 130, 130, 131, 131, 131, 132, 132,
12791203945Sweongyo		133, 133, 133, 134, 134, 134, 135, 135,
12792203945Sweongyo		136, 136, 136, 137, 137, 137, 138, 138,
12793203945Sweongyo		138, 139, 139, 140, 140, 140, 141, 141,
12794203945Sweongyo		141, 142, 142, 142, 143, 143, 143, 144,
12795203945Sweongyo		144, 144, 145, 145, 145, 146, 146, 146,
12796203945Sweongyo		147, 147, 147, 148, 148, 148, 149, 149,
12797203945Sweongyo		150, 150, 150, 150, 151, 151, 151, 152,
12798203945Sweongyo		152, 152, 153, 153, 153, 154, 154, 154,
12799203945Sweongyo		155, 155, 155, 156, 156, 156, 157, 157,
12800203945Sweongyo		157, 158, 158, 158, 159, 159, 159, 160
12801203945Sweongyo	};
12802203945Sweongyo
12803203945Sweongyo	if (x == 0)
12804203945Sweongyo		return (0);
12805203945Sweongyo	if (x >= 256) {
12806204542Sweongyo		unsigned int tmp;
12807204542Sweongyo
12808204542Sweongyo		for (tmp = 0; x >= (2 * tmp) + 1; x -= (2 * tmp++) + 1)
12809204542Sweongyo			/* do nothing */ ;
12810204542Sweongyo		return (tmp);
12811203945Sweongyo	}
12812203945Sweongyo	return (sqrt_table[x - 1] / 10);
12813203945Sweongyo}
12814203945Sweongyo
12815203945Sweongyostatic int
12816203945Sweongyobwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *mac, uint16_t sample)
12817203945Sweongyo{
12818203945Sweongyo#define	CALC_COEFF(_v, _x, _y, _z)	do {				\
12819203945Sweongyo	int _t;								\
12820203945Sweongyo	_t = _x - 20;							\
12821203945Sweongyo	if (_t >= 0) {							\
12822203945Sweongyo		_v = ((_y << (30 - _x)) + (_z >> (1 + _t))) / (_z >> _t); \
12823203945Sweongyo	} else {							\
12824203945Sweongyo		_v = ((_y << (30 - _x)) + (_z << (-1 - _t))) / (_z << -_t); \
12825203945Sweongyo	}								\
12826203945Sweongyo} while (0)
12827203945Sweongyo#define	CALC_COEFF2(_v, _x, _y, _z)	do {				\
12828203945Sweongyo	int _t;								\
12829203945Sweongyo	_t = _x - 11;							\
12830203945Sweongyo	if (_t >= 0)							\
12831210393Sweongyo		_v = (_y << (31 - _x)) / (_z >> _t);			\
12832203945Sweongyo	else								\
12833210393Sweongyo		_v = (_y << (31 - _x)) / (_z << -_t);			\
12834203945Sweongyo} while (0)
12835203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12836203945Sweongyo	uint16_t v0, v1;
12837203945Sweongyo	int tmp[2], ret;
12838203945Sweongyo
12839203945Sweongyo	v1 = BWN_PHY_READ(mac, BWN_PHY_RX_COMP_COEFF_S);
12840203945Sweongyo	v0 = v1 >> 8;
12841203945Sweongyo	v1 |= 0xff;
12842203945Sweongyo
12843203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, 0x00c0);
12844203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff);
12845203945Sweongyo
12846203945Sweongyo	ret = bwn_phy_lp_rx_iq_est(mac, sample, 32, &ie);
12847203945Sweongyo	if (ret == 0)
12848203945Sweongyo		goto done;
12849203945Sweongyo
12850203945Sweongyo	if (ie.ie_ipwr + ie.ie_qpwr < 2) {
12851203945Sweongyo		ret = 0;
12852203945Sweongyo		goto done;
12853203945Sweongyo	}
12854203945Sweongyo
12855203945Sweongyo	CALC_COEFF(tmp[0], bwn_nbits(ie.ie_iqprod), ie.ie_iqprod, ie.ie_ipwr);
12856203945Sweongyo	CALC_COEFF2(tmp[1], bwn_nbits(ie.ie_qpwr), ie.ie_qpwr, ie.ie_ipwr);
12857203945Sweongyo
12858203945Sweongyo	tmp[1] = -bwn_sqrt(mac, tmp[1] - (tmp[0] * tmp[0]));
12859203945Sweongyo	v0 = tmp[0] >> 3;
12860203945Sweongyo	v1 = tmp[1] >> 4;
12861203945Sweongyodone:
12862203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, v1);
12863203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, v0 << 8);
12864203945Sweongyo	return ret;
12865203945Sweongyo#undef CALC_COEFF
12866203945Sweongyo#undef CALC_COEFF2
12867203945Sweongyo}
12868203945Sweongyo
12869203945Sweongyostatic void
12870203945Sweongyobwn_phy_lp_tblinit_r01(struct bwn_mac *mac)
12871203945Sweongyo{
12872203945Sweongyo	static const uint16_t noisescale[] = {
12873203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12874203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4,
12875203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12876203945Sweongyo		0xa4a4, 0xa4a4, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12877203945Sweongyo		0x0000, 0x0000, 0x4c00, 0x2d36, 0x0000, 0x0000, 0x4c00, 0x2d36,
12878203945Sweongyo	};
12879203945Sweongyo	static const uint16_t crsgainnft[] = {
12880203945Sweongyo		0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f,
12881203945Sweongyo		0x036f, 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381,
12882203945Sweongyo		0x0374, 0x0381, 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f,
12883203945Sweongyo		0x0040, 0x005e, 0x007f, 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d,
12884203945Sweongyo		0x013d,
12885203945Sweongyo	};
12886203945Sweongyo	static const uint16_t filterctl[] = {
12887203945Sweongyo		0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077,
12888203945Sweongyo		0xff53, 0x0127,
12889203945Sweongyo	};
12890203945Sweongyo	static const uint32_t psctl[] = {
12891203945Sweongyo		0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101,
12892203945Sweongyo		0x00000080, 0x08080101, 0x00000040, 0x08080101, 0x000000c0,
12893203945Sweongyo		0x08a81501, 0x000000c0, 0x0fe8fd01, 0x000000c0, 0x08300105,
12894203945Sweongyo		0x000000c0, 0x08080201, 0x000000c0, 0x08280205, 0x000000c0,
12895203945Sweongyo		0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, 0x08080202,
12896203945Sweongyo		0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
12897203945Sweongyo		0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106,
12898203945Sweongyo		0x000000c0, 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
12899203945Sweongyo	};
12900203945Sweongyo	static const uint16_t ofdmcckgain_r0[] = {
12901203945Sweongyo		0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12902203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12903203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12904203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12905203945Sweongyo		0x755d,
12906203945Sweongyo	};
12907203945Sweongyo	static const uint16_t ofdmcckgain_r1[] = {
12908203945Sweongyo		0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12909203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12910203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12911203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12912203945Sweongyo		0x755d,
12913203945Sweongyo	};
12914203945Sweongyo	static const uint16_t gaindelta[] = {
12915203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12916203945Sweongyo		0x0000,
12917203945Sweongyo	};
12918203945Sweongyo	static const uint32_t txpwrctl[] = {
12919203945Sweongyo		0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c,
12920203945Sweongyo		0x0000004b, 0x0000004a, 0x00000049, 0x00000048, 0x00000047,
12921203945Sweongyo		0x00000046, 0x00000045, 0x00000044, 0x00000043, 0x00000042,
12922203945Sweongyo		0x00000041, 0x00000040, 0x0000003f, 0x0000003e, 0x0000003d,
12923203945Sweongyo		0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, 0x00000038,
12924203945Sweongyo		0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
12925203945Sweongyo		0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e,
12926203945Sweongyo		0x0000002d, 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029,
12927203945Sweongyo		0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
12928203945Sweongyo		0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001f,
12929203945Sweongyo		0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001a,
12930203945Sweongyo		0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
12931203945Sweongyo		0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000,
12932203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12933203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12934203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12935203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12936203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12937203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12938203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12939203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12940203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12941203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12942203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12943203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12944203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12945203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12946203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12947203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12948203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12949203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12950203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12951203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12952203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12953203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12954203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12955203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12956203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12957203945Sweongyo		0x00000000, 0x00000000, 0x000075a0, 0x000075a0, 0x000075a1,
12958203945Sweongyo		0x000075a1, 0x000075a2, 0x000075a2, 0x000075a3, 0x000075a3,
12959203945Sweongyo		0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, 0x000074b2,
12960203945Sweongyo		0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
12961203945Sweongyo		0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23,
12962203945Sweongyo		0x00006d23, 0x00004660, 0x00004660, 0x00004661, 0x00004661,
12963203945Sweongyo		0x00004662, 0x00004662, 0x00004663, 0x00004663, 0x00003e60,
12964203945Sweongyo		0x00003e60, 0x00003e61, 0x00003e61, 0x00003e62, 0x00003e62,
12965203945Sweongyo		0x00003e63, 0x00003e63, 0x00003660, 0x00003660, 0x00003661,
12966203945Sweongyo		0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
12967203945Sweongyo		0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62,
12968203945Sweongyo		0x00002e62, 0x00002e63, 0x00002e63, 0x00002660, 0x00002660,
12969203945Sweongyo		0x00002661, 0x00002661, 0x00002662, 0x00002662, 0x00002663,
12970203945Sweongyo		0x00002663, 0x000025e0, 0x000025e0, 0x000025e1, 0x000025e1,
12971203945Sweongyo		0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, 0x00001de0,
12972203945Sweongyo		0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
12973203945Sweongyo		0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61,
12974203945Sweongyo		0x00001d61, 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63,
12975203945Sweongyo		0x00001560, 0x00001560, 0x00001561, 0x00001561, 0x00001562,
12976203945Sweongyo		0x00001562, 0x00001563, 0x00001563, 0x00000d60, 0x00000d60,
12977203945Sweongyo		0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, 0x00000d63,
12978203945Sweongyo		0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
12979203945Sweongyo		0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10,
12980203945Sweongyo		0x00000e10, 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12,
12981203945Sweongyo		0x00000e13, 0x00000e13, 0x00000bf0, 0x00000bf0, 0x00000bf1,
12982203945Sweongyo		0x00000bf1, 0x00000bf2, 0x00000bf2, 0x00000bf3, 0x00000bf3,
12983203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12984203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12985203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12986203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12987203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12988203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12989203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12990203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12991203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12992203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12993203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12994203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12995203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12996203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12997203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12998203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12999203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13000203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13001203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13002203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13003203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13004203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13005203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13006203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13007203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13008203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc,
13009203945Sweongyo		0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04,
13010203945Sweongyo		0x0000fcff, 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006,
13011203945Sweongyo		0x0000ff03, 0x000007fc, 0x0000fc08, 0x00000203, 0x0000fffb,
13012203945Sweongyo		0x00000600, 0x0000fa01, 0x0000fc03, 0x0000fe06, 0x0000fe00,
13013203945Sweongyo		0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, 0x000004fd,
13014203945Sweongyo		0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
13015203945Sweongyo		0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa,
13016203945Sweongyo		0x00000700, 0x00000305, 0x000004ff, 0x00000801, 0x00000503,
13017203945Sweongyo		0x000005f9, 0x00000404, 0x0000fb08, 0x000005fd, 0x00000501,
13018203945Sweongyo		0x00000405, 0x0000fb03, 0x000007fc, 0x00000403, 0x00000303,
13019203945Sweongyo		0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, 0x0000fe01,
13020203945Sweongyo		0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
13021203945Sweongyo		0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa,
13022203945Sweongyo		0x000003fe, 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06,
13023203945Sweongyo		0x000008fc, 0x00000701, 0x00000504, 0x0000fdfe, 0x0000fdfc,
13024203945Sweongyo		0x000003fe, 0x00000704, 0x000002fc, 0x000004f9, 0x0000fdfd,
13025203945Sweongyo		0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, 0x000004f9,
13026203945Sweongyo		0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
13027203945Sweongyo		0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa,
13028203945Sweongyo		0x00000305, 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc,
13029203945Sweongyo		0x0000fe03, 0x00000701, 0x000001fb, 0x000001f9, 0x00000206,
13030203945Sweongyo		0x000006fd, 0x00000508, 0x00000700, 0x00000304, 0x000005fe,
13031203945Sweongyo		0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, 0x000007f9,
13032203945Sweongyo		0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
13033203945Sweongyo		0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb,
13034203945Sweongyo		0x00000702,
13035203945Sweongyo	};
13036203945Sweongyo
13037203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13038203945Sweongyo
13039203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13040203945Sweongyo	    bwn_tab_sigsq_tbl);
13041203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13042203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(crsgainnft), crsgainnft);
13043203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(8, 0), N(filterctl), filterctl);
13044203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(psctl), psctl);
13045203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13046203945Sweongyo	    bwn_tab_pllfrac_tbl);
13047203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13048203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13049203945Sweongyo	if (mac->mac_phy.rev == 0) {
13050203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r0),
13051203945Sweongyo		    ofdmcckgain_r0);
13052203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r0),
13053203945Sweongyo		    ofdmcckgain_r0);
13054203945Sweongyo	} else {
13055203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r1),
13056203945Sweongyo		    ofdmcckgain_r1);
13057203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r1),
13058203945Sweongyo		    ofdmcckgain_r1);
13059203945Sweongyo	}
13060203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(gaindelta), gaindelta);
13061203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(txpwrctl), txpwrctl);
13062203945Sweongyo}
13063203945Sweongyo
13064203945Sweongyostatic void
13065203945Sweongyobwn_phy_lp_tblinit_r2(struct bwn_mac *mac)
13066203945Sweongyo{
13067204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13068203945Sweongyo	int i;
13069203945Sweongyo	static const uint16_t noisescale[] = {
13070203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13071203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13072203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13073203945Sweongyo		0x00a4, 0x00a4, 0x0000, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13074203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13075203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13076203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4
13077203945Sweongyo	};
13078203945Sweongyo	static const uint32_t filterctl[] = {
13079203945Sweongyo		0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27,
13080203945Sweongyo		0x0000217f, 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f
13081203945Sweongyo	};
13082203945Sweongyo	static const uint32_t psctl[] = {
13083203945Sweongyo		0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000,
13084203945Sweongyo		0x00002080, 0x00006180, 0x00003002, 0x00000040, 0x00002042,
13085203945Sweongyo		0x00180047, 0x00080043, 0x00000041, 0x000020c1, 0x00046006,
13086203945Sweongyo		0x00042002, 0x00040000, 0x00002003, 0x00180006, 0x00080002
13087203945Sweongyo	};
13088203945Sweongyo	static const uint32_t gainidx[] = {
13089203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13090203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13091203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13092203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x10000001, 0x00000000,
13093203945Sweongyo		0x20000082, 0x00000000, 0x40000104, 0x00000000, 0x60004207,
13094203945Sweongyo		0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
13095203945Sweongyo		0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288,
13096203945Sweongyo		0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
13097203945Sweongyo		0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794,
13098203945Sweongyo		0x00000010, 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011,
13099203945Sweongyo		0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21,
13100203945Sweongyo		0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
13101203945Sweongyo		0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329,
13102203945Sweongyo		0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
13103203945Sweongyo		0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, 0x00000000,
13104203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13105203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13106203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13107203945Sweongyo		0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082,
13108203945Sweongyo		0x00000000, 0x40000104, 0x00000000, 0x60004207, 0x00000001,
13109203945Sweongyo		0x7000838a, 0x00000001, 0xd021050d, 0x00000001, 0xe041c683,
13110203945Sweongyo		0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
13111203945Sweongyo		0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711,
13112203945Sweongyo		0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
13113203945Sweongyo		0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c,
13114203945Sweongyo		0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019,
13115203945Sweongyo		0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, 0xb36811a6,
13116203945Sweongyo		0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
13117203945Sweongyo		0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c,
13118203945Sweongyo		0x0000001a, 0x64ca55ad, 0x0000001a
13119203945Sweongyo	};
13120203945Sweongyo	static const uint16_t auxgainidx[] = {
13121203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13122203945Sweongyo		0x0000, 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000,
13123203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002,
13124203945Sweongyo		0x0004, 0x0016
13125203945Sweongyo	};
13126203945Sweongyo	static const uint16_t swctl[] = {
13127203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13128203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13129203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13130203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
13131203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13132203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13133203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13134203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018
13135203945Sweongyo	};
13136203945Sweongyo	static const uint8_t hf[] = {
13137203945Sweongyo		0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
13138203945Sweongyo		0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17
13139203945Sweongyo	};
13140203945Sweongyo	static const uint32_t gainval[] = {
13141203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13142203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13143203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13144203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13145203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13146203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13147203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13148203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13149203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13150203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13151203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13152203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13153203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009,
13154203945Sweongyo		0x000000f1, 0x00000000, 0x00000000
13155203945Sweongyo	};
13156203945Sweongyo	static const uint16_t gain[] = {
13157203945Sweongyo		0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808,
13158203945Sweongyo		0x080a, 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813,
13159203945Sweongyo		0x0814, 0x0816, 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824,
13160203945Sweongyo		0x0830, 0x0834, 0x0837, 0x083b, 0x083f, 0x0840, 0x0844, 0x0857,
13161203945Sweongyo		0x085b, 0x085f, 0x08d7, 0x08db, 0x08df, 0x0957, 0x095b, 0x095f,
13162203945Sweongyo		0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, 0x175f, 0x0000, 0x0000,
13163203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13164203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13165203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13166203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13167203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13168203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13169203945Sweongyo	};
13170203945Sweongyo	static const uint32_t papdeps[] = {
13171203945Sweongyo		0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9,
13172203945Sweongyo		0x00021fdf, 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7,
13173203945Sweongyo		0x0004efc2, 0x00055fb5, 0x0005cfb0, 0x00063fa8, 0x00068fa3,
13174203945Sweongyo		0x00071f98, 0x0007ef92, 0x00084f8b, 0x0008df82, 0x00097f77,
13175203945Sweongyo		0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, 0x000bff41,
13176203945Sweongyo		0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
13177203945Sweongyo		0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15,
13178203945Sweongyo		0x00143f1c, 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f,
13179203945Sweongyo		0x001e6f7e, 0x0021cfa4, 0x0025bfd2, 0x002a2008, 0x002fb047,
13180203945Sweongyo		0x00360090, 0x003d40e0, 0x0045c135, 0x004fb189, 0x005ae1d7,
13181203945Sweongyo		0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, 0x007ff2e3,
13182203945Sweongyo		0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
13183203945Sweongyo		0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506
13184203945Sweongyo	};
13185203945Sweongyo	static const uint32_t papdmult[] = {
13186203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13187203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13188203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13189203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13190203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13191203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13192203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13193203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13194203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13195203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13196203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13197203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13198203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13199203945Sweongyo	};
13200203945Sweongyo	static const uint32_t gainidx_a0[] = {
13201203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13202203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13203203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13204203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13205203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13206203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13207203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13208203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13209203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13210203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13211203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13212203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13213203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13214203945Sweongyo	};
13215203945Sweongyo	static const uint16_t auxgainidx_a0[] = {
13216203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13217203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000,
13218203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13219203945Sweongyo		0x0002, 0x0014
13220203945Sweongyo	};
13221203945Sweongyo	static const uint32_t gainval_a0[] = {
13222203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13223203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13224203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13225203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13226203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13227203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13228203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13229203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13230203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13231203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13232203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13233203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13234203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f,
13235203945Sweongyo		0x000000f7, 0x00000000, 0x00000000
13236203945Sweongyo	};
13237203945Sweongyo	static const uint16_t gain_a0[] = {
13238203945Sweongyo		0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b,
13239203945Sweongyo		0x000c, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016,
13240203945Sweongyo		0x0017, 0x001a, 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034,
13241203945Sweongyo		0x0037, 0x003b, 0x003f, 0x0040, 0x0044, 0x0057, 0x005b, 0x005f,
13242203945Sweongyo		0x00d7, 0x00db, 0x00df, 0x0157, 0x015b, 0x015f, 0x0357, 0x035b,
13243203945Sweongyo		0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, 0x0000, 0x0000, 0x0000,
13244203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 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	};
13251203945Sweongyo
13252203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13253203945Sweongyo
13254203945Sweongyo	for (i = 0; i < 704; i++)
13255203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(7, i), 0);
13256203945Sweongyo
13257203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13258203945Sweongyo	    bwn_tab_sigsq_tbl);
13259203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13260203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(11, 0), N(filterctl), filterctl);
13261203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(12, 0), N(psctl), psctl);
13262203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx), gainidx);
13263203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx), auxgainidx);
13264203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(swctl), swctl);
13265203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(16, 0), N(hf), hf);
13266203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval), gainval);
13267203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain), gain);
13268203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13269203945Sweongyo	    bwn_tab_pllfrac_tbl);
13270203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13271203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13272203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(papdeps), papdeps);
13273203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(papdmult), papdmult);
13274203945Sweongyo
13275204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
13276204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
13277203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx_a0),
13278203945Sweongyo		    gainidx_a0);
13279203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx_a0),
13280203945Sweongyo		    auxgainidx_a0);
13281203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval_a0),
13282203945Sweongyo		    gainval_a0);
13283203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain_a0), gain_a0);
13284203945Sweongyo	}
13285203945Sweongyo}
13286203945Sweongyo
13287203945Sweongyostatic void
13288203945Sweongyobwn_phy_lp_tblinit_txgain(struct bwn_mac *mac)
13289203945Sweongyo{
13290203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13291203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
13292203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
13293203945Sweongyo	static struct bwn_txgain_entry txgain_r2[] = {
13294203945Sweongyo		{ 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 },
13295203945Sweongyo		{ 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 },
13296203945Sweongyo		{ 255, 255, 203, 0, 135 }, { 255, 255, 203, 0, 131 },
13297203945Sweongyo		{ 255, 255, 203, 0, 128 }, { 255, 255, 203, 0, 124 },
13298203945Sweongyo		{ 255, 255, 203, 0, 121 }, { 255, 255, 203, 0, 117 },
13299203945Sweongyo		{ 255, 255, 203, 0, 114 }, { 255, 255, 203, 0, 111 },
13300203945Sweongyo		{ 255, 255, 203, 0, 107 }, { 255, 255, 203, 0, 104 },
13301203945Sweongyo		{ 255, 255, 203, 0, 101 }, { 255, 255, 203, 0, 99 },
13302203945Sweongyo		{ 255, 255, 203, 0, 96 }, { 255, 255, 203, 0, 93 },
13303203945Sweongyo		{ 255, 255, 203, 0, 90 }, { 255, 255, 203, 0, 88 },
13304203945Sweongyo		{ 255, 255, 203, 0, 85 }, { 255, 255, 203, 0, 83 },
13305203945Sweongyo		{ 255, 255, 203, 0, 81 }, { 255, 255, 203, 0, 78 },
13306203945Sweongyo		{ 255, 255, 203, 0, 76 }, { 255, 255, 203, 0, 74 },
13307203945Sweongyo		{ 255, 255, 203, 0, 72 }, { 255, 255, 203, 0, 70 },
13308203945Sweongyo		{ 255, 255, 203, 0, 68 }, { 255, 255, 203, 0, 66 },
13309203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13310203945Sweongyo		{ 255, 255, 192, 0, 64 }, { 255, 255, 186, 0, 64 },
13311203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 176, 0, 64 },
13312203945Sweongyo		{ 255, 255, 171, 0, 64 }, { 255, 255, 166, 0, 64 },
13313203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 157, 0, 64 },
13314203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13315203945Sweongyo		{ 255, 255, 144, 0, 64 }, { 255, 255, 140, 0, 64 },
13316203945Sweongyo		{ 255, 255, 136, 0, 64 }, { 255, 255, 132, 0, 64 },
13317203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13318203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13319203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13320203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 105, 0, 64 },
13321203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13322203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13323203945Sweongyo		{ 255, 255, 91, 0, 64 }, { 255, 255, 88, 0, 64 },
13324203945Sweongyo		{ 255, 255, 86, 0, 64 }, { 255, 255, 83, 0, 64 },
13325203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 79, 0, 64 },
13326203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13327203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13328203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13329203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 248, 64, 0, 64 },
13330203945Sweongyo		{ 255, 248, 62, 0, 64 }, { 255, 241, 62, 0, 64 },
13331203945Sweongyo		{ 255, 241, 60, 0, 64 }, { 255, 234, 60, 0, 64 },
13332203945Sweongyo		{ 255, 234, 59, 0, 64 }, { 255, 227, 59, 0, 64 },
13333203945Sweongyo		{ 255, 227, 57, 0, 64 }, { 255, 221, 57, 0, 64 },
13334203945Sweongyo		{ 255, 221, 55, 0, 64 }, { 255, 215, 55, 0, 64 },
13335203945Sweongyo		{ 255, 215, 54, 0, 64 }, { 255, 208, 54, 0, 64 },
13336203945Sweongyo		{ 255, 208, 52, 0, 64 }, { 255, 203, 52, 0, 64 },
13337203945Sweongyo		{ 255, 203, 51, 0, 64 }, { 255, 197, 51, 0, 64 },
13338203945Sweongyo		{ 255, 197, 49, 0, 64 }, { 255, 191, 49, 0, 64 },
13339203945Sweongyo		{ 255, 191, 48, 0, 64 }, { 255, 186, 48, 0, 64 },
13340203945Sweongyo		{ 255, 186, 47, 0, 64 }, { 255, 181, 47, 0, 64 },
13341203945Sweongyo		{ 255, 181, 45, 0, 64 }, { 255, 175, 45, 0, 64 },
13342203945Sweongyo		{ 255, 175, 44, 0, 64 }, { 255, 170, 44, 0, 64 },
13343203945Sweongyo		{ 255, 170, 43, 0, 64 }, { 255, 166, 43, 0, 64 },
13344203945Sweongyo		{ 255, 166, 42, 0, 64 }, { 255, 161, 42, 0, 64 },
13345203945Sweongyo		{ 255, 161, 40, 0, 64 }, { 255, 156, 40, 0, 64 },
13346203945Sweongyo		{ 255, 156, 39, 0, 64 }, { 255, 152, 39, 0, 64 },
13347203945Sweongyo		{ 255, 152, 38, 0, 64 }, { 255, 148, 38, 0, 64 },
13348203945Sweongyo		{ 255, 148, 37, 0, 64 }, { 255, 143, 37, 0, 64 },
13349203945Sweongyo		{ 255, 143, 36, 0, 64 }, { 255, 139, 36, 0, 64 },
13350203945Sweongyo		{ 255, 139, 35, 0, 64 }, { 255, 135, 35, 0, 64 },
13351203945Sweongyo		{ 255, 135, 34, 0, 64 }, { 255, 132, 34, 0, 64 },
13352203945Sweongyo		{ 255, 132, 33, 0, 64 }, { 255, 128, 33, 0, 64 },
13353203945Sweongyo		{ 255, 128, 32, 0, 64 }, { 255, 124, 32, 0, 64 },
13354203945Sweongyo		{ 255, 124, 31, 0, 64 }, { 255, 121, 31, 0, 64 },
13355203945Sweongyo		{ 255, 121, 30, 0, 64 }, { 255, 117, 30, 0, 64 },
13356203945Sweongyo		{ 255, 117, 29, 0, 64 }, { 255, 114, 29, 0, 64 },
13357203945Sweongyo		{ 255, 114, 29, 0, 64 }, { 255, 111, 29, 0, 64 },
13358203945Sweongyo	};
13359203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r2[] = {
13360203945Sweongyo		{ 7, 99, 255, 0, 64 }, { 7, 96, 255, 0, 64 },
13361203945Sweongyo		{ 7, 93, 255, 0, 64 }, { 7, 90, 255, 0, 64 },
13362203945Sweongyo		{ 7, 88, 255, 0, 64 }, { 7, 85, 255, 0, 64 },
13363203945Sweongyo		{ 7, 83, 255, 0, 64 }, { 7, 81, 255, 0, 64 },
13364203945Sweongyo		{ 7, 78, 255, 0, 64 }, { 7, 76, 255, 0, 64 },
13365203945Sweongyo		{ 7, 74, 255, 0, 64 }, { 7, 72, 255, 0, 64 },
13366203945Sweongyo		{ 7, 70, 255, 0, 64 }, { 7, 68, 255, 0, 64 },
13367203945Sweongyo		{ 7, 66, 255, 0, 64 }, { 7, 64, 255, 0, 64 },
13368203945Sweongyo		{ 7, 64, 255, 0, 64 }, { 7, 62, 255, 0, 64 },
13369203945Sweongyo		{ 7, 62, 248, 0, 64 }, { 7, 60, 248, 0, 64 },
13370203945Sweongyo		{ 7, 60, 241, 0, 64 }, { 7, 59, 241, 0, 64 },
13371203945Sweongyo		{ 7, 59, 234, 0, 64 }, { 7, 57, 234, 0, 64 },
13372203945Sweongyo		{ 7, 57, 227, 0, 64 }, { 7, 55, 227, 0, 64 },
13373203945Sweongyo		{ 7, 55, 221, 0, 64 }, { 7, 54, 221, 0, 64 },
13374203945Sweongyo		{ 7, 54, 215, 0, 64 }, { 7, 52, 215, 0, 64 },
13375203945Sweongyo		{ 7, 52, 208, 0, 64 }, { 7, 51, 208, 0, 64 },
13376203945Sweongyo		{ 7, 51, 203, 0, 64 }, { 7, 49, 203, 0, 64 },
13377203945Sweongyo		{ 7, 49, 197, 0, 64 }, { 7, 48, 197, 0, 64 },
13378203945Sweongyo		{ 7, 48, 191, 0, 64 }, { 7, 47, 191, 0, 64 },
13379203945Sweongyo		{ 7, 47, 186, 0, 64 }, { 7, 45, 186, 0, 64 },
13380203945Sweongyo		{ 7, 45, 181, 0, 64 }, { 7, 44, 181, 0, 64 },
13381203945Sweongyo		{ 7, 44, 175, 0, 64 }, { 7, 43, 175, 0, 64 },
13382203945Sweongyo		{ 7, 43, 170, 0, 64 }, { 7, 42, 170, 0, 64 },
13383203945Sweongyo		{ 7, 42, 166, 0, 64 }, { 7, 40, 166, 0, 64 },
13384203945Sweongyo		{ 7, 40, 161, 0, 64 }, { 7, 39, 161, 0, 64 },
13385203945Sweongyo		{ 7, 39, 156, 0, 64 }, { 7, 38, 156, 0, 64 },
13386203945Sweongyo		{ 7, 38, 152, 0, 64 }, { 7, 37, 152, 0, 64 },
13387203945Sweongyo		{ 7, 37, 148, 0, 64 }, { 7, 36, 148, 0, 64 },
13388203945Sweongyo		{ 7, 36, 143, 0, 64 }, { 7, 35, 143, 0, 64 },
13389203945Sweongyo		{ 7, 35, 139, 0, 64 }, { 7, 34, 139, 0, 64 },
13390203945Sweongyo		{ 7, 34, 135, 0, 64 }, { 7, 33, 135, 0, 64 },
13391203945Sweongyo		{ 7, 33, 132, 0, 64 }, { 7, 32, 132, 0, 64 },
13392203945Sweongyo		{ 7, 32, 128, 0, 64 }, { 7, 31, 128, 0, 64 },
13393203945Sweongyo		{ 7, 31, 124, 0, 64 }, { 7, 30, 124, 0, 64 },
13394203945Sweongyo		{ 7, 30, 121, 0, 64 }, { 7, 29, 121, 0, 64 },
13395203945Sweongyo		{ 7, 29, 117, 0, 64 }, { 7, 29, 117, 0, 64 },
13396203945Sweongyo		{ 7, 29, 114, 0, 64 }, { 7, 28, 114, 0, 64 },
13397203945Sweongyo		{ 7, 28, 111, 0, 64 }, { 7, 27, 111, 0, 64 },
13398203945Sweongyo		{ 7, 27, 108, 0, 64 }, { 7, 26, 108, 0, 64 },
13399203945Sweongyo		{ 7, 26, 104, 0, 64 }, { 7, 25, 104, 0, 64 },
13400203945Sweongyo		{ 7, 25, 102, 0, 64 }, { 7, 25, 102, 0, 64 },
13401203945Sweongyo		{ 7, 25, 99, 0, 64 }, { 7, 24, 99, 0, 64 },
13402203945Sweongyo		{ 7, 24, 96, 0, 64 }, { 7, 23, 96, 0, 64 },
13403203945Sweongyo		{ 7, 23, 93, 0, 64 }, { 7, 23, 93, 0, 64 },
13404203945Sweongyo		{ 7, 23, 90, 0, 64 }, { 7, 22, 90, 0, 64 },
13405203945Sweongyo		{ 7, 22, 88, 0, 64 }, { 7, 21, 88, 0, 64 },
13406203945Sweongyo		{ 7, 21, 85, 0, 64 }, { 7, 21, 85, 0, 64 },
13407203945Sweongyo		{ 7, 21, 83, 0, 64 }, { 7, 20, 83, 0, 64 },
13408203945Sweongyo		{ 7, 20, 81, 0, 64 }, { 7, 20, 81, 0, 64 },
13409203945Sweongyo		{ 7, 20, 78, 0, 64 }, { 7, 19, 78, 0, 64 },
13410203945Sweongyo		{ 7, 19, 76, 0, 64 }, { 7, 19, 76, 0, 64 },
13411203945Sweongyo		{ 7, 19, 74, 0, 64 }, { 7, 18, 74, 0, 64 },
13412203945Sweongyo		{ 7, 18, 72, 0, 64 }, { 7, 18, 72, 0, 64 },
13413203945Sweongyo		{ 7, 18, 70, 0, 64 }, { 7, 17, 70, 0, 64 },
13414203945Sweongyo		{ 7, 17, 68, 0, 64 }, { 7, 17, 68, 0, 64 },
13415203945Sweongyo		{ 7, 17, 66, 0, 64 }, { 7, 16, 66, 0, 64 },
13416203945Sweongyo		{ 7, 16, 64, 0, 64 }, { 7, 16, 64, 0, 64 },
13417203945Sweongyo		{ 7, 16, 62, 0, 64 }, { 7, 15, 62, 0, 64 },
13418203945Sweongyo		{ 7, 15, 60, 0, 64 }, { 7, 15, 60, 0, 64 },
13419203945Sweongyo		{ 7, 15, 59, 0, 64 }, { 7, 14, 59, 0, 64 },
13420203945Sweongyo		{ 7, 14, 57, 0, 64 }, { 7, 14, 57, 0, 64 },
13421203945Sweongyo		{ 7, 14, 55, 0, 64 }, { 7, 14, 55, 0, 64 },
13422203945Sweongyo		{ 7, 14, 54, 0, 64 }, { 7, 13, 54, 0, 64 },
13423203945Sweongyo		{ 7, 13, 52, 0, 64 }, { 7, 13, 52, 0, 64 },
13424203945Sweongyo	};
13425203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r2[] = {
13426203945Sweongyo		{ 255, 255, 255, 0, 152 }, { 255, 255, 255, 0, 147 },
13427203945Sweongyo		{ 255, 255, 255, 0, 143 }, { 255, 255, 255, 0, 139 },
13428203945Sweongyo		{ 255, 255, 255, 0, 135 }, { 255, 255, 255, 0, 131 },
13429203945Sweongyo		{ 255, 255, 255, 0, 128 }, { 255, 255, 255, 0, 124 },
13430203945Sweongyo		{ 255, 255, 255, 0, 121 }, { 255, 255, 255, 0, 117 },
13431203945Sweongyo		{ 255, 255, 255, 0, 114 }, { 255, 255, 255, 0, 111 },
13432203945Sweongyo		{ 255, 255, 255, 0, 107 }, { 255, 255, 255, 0, 104 },
13433203945Sweongyo		{ 255, 255, 255, 0, 101 }, { 255, 255, 255, 0, 99 },
13434203945Sweongyo		{ 255, 255, 255, 0, 96 }, { 255, 255, 255, 0, 93 },
13435203945Sweongyo		{ 255, 255, 255, 0, 90 }, { 255, 255, 255, 0, 88 },
13436203945Sweongyo		{ 255, 255, 255, 0, 85 }, { 255, 255, 255, 0, 83 },
13437203945Sweongyo		{ 255, 255, 255, 0, 81 }, { 255, 255, 255, 0, 78 },
13438203945Sweongyo		{ 255, 255, 255, 0, 76 }, { 255, 255, 255, 0, 74 },
13439203945Sweongyo		{ 255, 255, 255, 0, 72 }, { 255, 255, 255, 0, 70 },
13440203945Sweongyo		{ 255, 255, 255, 0, 68 }, { 255, 255, 255, 0, 66 },
13441203945Sweongyo		{ 255, 255, 255, 0, 64 }, { 255, 255, 248, 0, 64 },
13442203945Sweongyo		{ 255, 255, 241, 0, 64 }, { 255, 255, 234, 0, 64 },
13443203945Sweongyo		{ 255, 255, 227, 0, 64 }, { 255, 255, 221, 0, 64 },
13444203945Sweongyo		{ 255, 255, 215, 0, 64 }, { 255, 255, 208, 0, 64 },
13445203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13446203945Sweongyo		{ 255, 255, 191, 0, 64 }, { 255, 255, 186, 0, 64 },
13447203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 175, 0, 64 },
13448203945Sweongyo		{ 255, 255, 170, 0, 64 }, { 255, 255, 166, 0, 64 },
13449203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 156, 0, 64 },
13450203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13451203945Sweongyo		{ 255, 255, 143, 0, 64 }, { 255, 255, 139, 0, 64 },
13452203945Sweongyo		{ 255, 255, 135, 0, 64 }, { 255, 255, 132, 0, 64 },
13453203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13454203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13455203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13456203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 104, 0, 64 },
13457203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13458203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13459203945Sweongyo		{ 255, 255, 90, 0, 64 }, { 255, 255, 88, 0, 64 },
13460203945Sweongyo		{ 255, 255, 85, 0, 64 }, { 255, 255, 83, 0, 64 },
13461203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 78, 0, 64 },
13462203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13463203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13464203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13465203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 255, 64, 0, 64 },
13466203945Sweongyo		{ 255, 255, 62, 0, 64 }, { 255, 248, 62, 0, 64 },
13467203945Sweongyo		{ 255, 248, 60, 0, 64 }, { 255, 241, 60, 0, 64 },
13468203945Sweongyo		{ 255, 241, 59, 0, 64 }, { 255, 234, 59, 0, 64 },
13469203945Sweongyo		{ 255, 234, 57, 0, 64 }, { 255, 227, 57, 0, 64 },
13470203945Sweongyo		{ 255, 227, 55, 0, 64 }, { 255, 221, 55, 0, 64 },
13471203945Sweongyo		{ 255, 221, 54, 0, 64 }, { 255, 215, 54, 0, 64 },
13472203945Sweongyo		{ 255, 215, 52, 0, 64 }, { 255, 208, 52, 0, 64 },
13473203945Sweongyo		{ 255, 208, 51, 0, 64 }, { 255, 203, 51, 0, 64 },
13474203945Sweongyo		{ 255, 203, 49, 0, 64 }, { 255, 197, 49, 0, 64 },
13475203945Sweongyo		{ 255, 197, 48, 0, 64 }, { 255, 191, 48, 0, 64 },
13476203945Sweongyo		{ 255, 191, 47, 0, 64 }, { 255, 186, 47, 0, 64 },
13477203945Sweongyo		{ 255, 186, 45, 0, 64 }, { 255, 181, 45, 0, 64 },
13478203945Sweongyo		{ 255, 181, 44, 0, 64 }, { 255, 175, 44, 0, 64 },
13479203945Sweongyo		{ 255, 175, 43, 0, 64 }, { 255, 170, 43, 0, 64 },
13480203945Sweongyo		{ 255, 170, 42, 0, 64 }, { 255, 166, 42, 0, 64 },
13481203945Sweongyo		{ 255, 166, 40, 0, 64 }, { 255, 161, 40, 0, 64 },
13482203945Sweongyo		{ 255, 161, 39, 0, 64 }, { 255, 156, 39, 0, 64 },
13483203945Sweongyo		{ 255, 156, 38, 0, 64 }, { 255, 152, 38, 0, 64 },
13484203945Sweongyo		{ 255, 152, 37, 0, 64 }, { 255, 148, 37, 0, 64 },
13485203945Sweongyo		{ 255, 148, 36, 0, 64 }, { 255, 143, 36, 0, 64 },
13486203945Sweongyo		{ 255, 143, 35, 0, 64 }, { 255, 139, 35, 0, 64 },
13487203945Sweongyo		{ 255, 139, 34, 0, 64 }, { 255, 135, 34, 0, 64 },
13488203945Sweongyo		{ 255, 135, 33, 0, 64 }, { 255, 132, 33, 0, 64 },
13489203945Sweongyo		{ 255, 132, 32, 0, 64 }, { 255, 128, 32, 0, 64 }
13490203945Sweongyo	};
13491203945Sweongyo	static struct bwn_txgain_entry txgain_r0[] = {
13492203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13493203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13494203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13495203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13496203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13497203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13498203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13499203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13500203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13501203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13502203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13503203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13504203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13505203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13506203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13507203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13508203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13509203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13510203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 13, 0, 68 },
13511203945Sweongyo		{ 7, 15, 13, 0, 66 }, { 7, 15, 13, 0, 64 },
13512203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13513203945Sweongyo		{ 7, 15, 13, 0, 59 }, { 7, 15, 13, 0, 57 },
13514203945Sweongyo		{ 7, 15, 12, 0, 71 }, { 7, 15, 12, 0, 69 },
13515203945Sweongyo		{ 7, 15, 12, 0, 67 }, { 7, 15, 12, 0, 65 },
13516203945Sweongyo		{ 7, 15, 12, 0, 63 }, { 7, 15, 12, 0, 62 },
13517203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 58 },
13518203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 70 },
13519203945Sweongyo		{ 7, 15, 11, 0, 68 }, { 7, 15, 11, 0, 66 },
13520203945Sweongyo		{ 7, 15, 11, 0, 65 }, { 7, 15, 11, 0, 63 },
13521203945Sweongyo		{ 7, 15, 11, 0, 61 }, { 7, 15, 11, 0, 59 },
13522203945Sweongyo		{ 7, 15, 11, 0, 58 }, { 7, 15, 10, 0, 71 },
13523203945Sweongyo		{ 7, 15, 10, 0, 69 }, { 7, 15, 10, 0, 67 },
13524203945Sweongyo		{ 7, 15, 10, 0, 65 }, { 7, 15, 10, 0, 63 },
13525203945Sweongyo		{ 7, 15, 10, 0, 61 }, { 7, 15, 10, 0, 60 },
13526203945Sweongyo		{ 7, 15, 10, 0, 58 }, { 7, 15, 10, 0, 56 },
13527203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13528203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13529203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 60 },
13530203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 14, 9, 0, 72 },
13531203945Sweongyo		{ 7, 14, 9, 0, 70 }, { 7, 14, 9, 0, 68 },
13532203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 64 },
13533203945Sweongyo		{ 7, 14, 9, 0, 62 }, { 7, 14, 9, 0, 60 },
13534203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 13, 9, 0, 72 },
13535203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13536203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13537203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13538203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13539203945Sweongyo		{ 7, 13, 8, 0, 72 }, { 7, 13, 8, 0, 70 },
13540203945Sweongyo		{ 7, 13, 8, 0, 68 }, { 7, 13, 8, 0, 66 },
13541203945Sweongyo		{ 7, 13, 8, 0, 64 }, { 7, 13, 8, 0, 62 },
13542203945Sweongyo		{ 7, 13, 8, 0, 60 }, { 7, 13, 8, 0, 59 },
13543203945Sweongyo		{ 7, 12, 8, 0, 72 }, { 7, 12, 8, 0, 70 },
13544203945Sweongyo		{ 7, 12, 8, 0, 68 }, { 7, 12, 8, 0, 66 },
13545203945Sweongyo		{ 7, 12, 8, 0, 64 }, { 7, 12, 8, 0, 62 },
13546203945Sweongyo		{ 7, 12, 8, 0, 61 }, { 7, 12, 8, 0, 59 },
13547203945Sweongyo		{ 7, 12, 7, 0, 73 }, { 7, 12, 7, 0, 71 },
13548203945Sweongyo		{ 7, 12, 7, 0, 69 }, { 7, 12, 7, 0, 67 },
13549203945Sweongyo		{ 7, 12, 7, 0, 65 }, { 7, 12, 7, 0, 63 },
13550203945Sweongyo		{ 7, 12, 7, 0, 61 }, { 7, 12, 7, 0, 59 },
13551203945Sweongyo		{ 7, 11, 7, 0, 72 }, { 7, 11, 7, 0, 70 },
13552203945Sweongyo		{ 7, 11, 7, 0, 68 }, { 7, 11, 7, 0, 66 },
13553203945Sweongyo		{ 7, 11, 7, 0, 65 }, { 7, 11, 7, 0, 63 },
13554203945Sweongyo		{ 7, 11, 7, 0, 61 }, { 7, 11, 7, 0, 59 },
13555203945Sweongyo		{ 7, 11, 6, 0, 73 }, { 7, 11, 6, 0, 71 }
13556203945Sweongyo	};
13557203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r0[] = {
13558203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13559203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13560203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13561203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13562203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13563203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13564203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13565203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13566203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13567203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13568203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13569203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13570203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13571203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13572203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13573203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13574203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13575203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13576203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13577203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13578203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13579203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13580203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13581203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13582203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13583203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13584203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13585203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13586203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13587203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13588203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13589203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13590203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13591203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 },
13592203945Sweongyo		{ 4, 10, 6, 0, 59 }, { 4, 10, 5, 0, 72 },
13593203945Sweongyo		{ 4, 10, 5, 0, 70 }, { 4, 10, 5, 0, 68 },
13594203945Sweongyo		{ 4, 10, 5, 0, 66 }, { 4, 10, 5, 0, 64 },
13595203945Sweongyo		{ 4, 10, 5, 0, 62 }, { 4, 10, 5, 0, 60 },
13596203945Sweongyo		{ 4, 10, 5, 0, 59 }, { 4, 9, 5, 0, 70 },
13597203945Sweongyo		{ 4, 9, 5, 0, 68 }, { 4, 9, 5, 0, 66 },
13598203945Sweongyo		{ 4, 9, 5, 0, 64 }, { 4, 9, 5, 0, 63 },
13599203945Sweongyo		{ 4, 9, 5, 0, 61 }, { 4, 9, 5, 0, 59 },
13600203945Sweongyo		{ 4, 9, 4, 0, 71 }, { 4, 9, 4, 0, 69 },
13601203945Sweongyo		{ 4, 9, 4, 0, 67 }, { 4, 9, 4, 0, 65 },
13602203945Sweongyo		{ 4, 9, 4, 0, 63 }, { 4, 9, 4, 0, 62 },
13603203945Sweongyo		{ 4, 9, 4, 0, 60 }, { 4, 9, 4, 0, 58 },
13604203945Sweongyo		{ 4, 8, 4, 0, 70 }, { 4, 8, 4, 0, 68 },
13605203945Sweongyo		{ 4, 8, 4, 0, 66 }, { 4, 8, 4, 0, 65 },
13606203945Sweongyo		{ 4, 8, 4, 0, 63 }, { 4, 8, 4, 0, 61 },
13607203945Sweongyo		{ 4, 8, 4, 0, 59 }, { 4, 7, 4, 0, 68 },
13608203945Sweongyo		{ 4, 7, 4, 0, 66 }, { 4, 7, 4, 0, 64 },
13609203945Sweongyo		{ 4, 7, 4, 0, 62 }, { 4, 7, 4, 0, 61 },
13610203945Sweongyo		{ 4, 7, 4, 0, 59 }, { 4, 7, 3, 0, 67 },
13611203945Sweongyo		{ 4, 7, 3, 0, 65 }, { 4, 7, 3, 0, 63 },
13612203945Sweongyo		{ 4, 7, 3, 0, 62 }, { 4, 7, 3, 0, 60 },
13613203945Sweongyo		{ 4, 6, 3, 0, 65 }, { 4, 6, 3, 0, 63 },
13614203945Sweongyo		{ 4, 6, 3, 0, 61 }, { 4, 6, 3, 0, 60 },
13615203945Sweongyo		{ 4, 6, 3, 0, 58 }, { 4, 5, 3, 0, 68 },
13616203945Sweongyo		{ 4, 5, 3, 0, 66 }, { 4, 5, 3, 0, 64 },
13617203945Sweongyo		{ 4, 5, 3, 0, 62 }, { 4, 5, 3, 0, 60 },
13618203945Sweongyo		{ 4, 5, 3, 0, 59 }, { 4, 5, 3, 0, 57 },
13619203945Sweongyo		{ 4, 4, 2, 0, 83 }, { 4, 4, 2, 0, 81 },
13620203945Sweongyo		{ 4, 4, 2, 0, 78 }, { 4, 4, 2, 0, 76 },
13621203945Sweongyo		{ 4, 4, 2, 0, 74 }, { 4, 4, 2, 0, 72 }
13622203945Sweongyo	};
13623203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r0[] = {
13624203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13625203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13626203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13627203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13628203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13629203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13630203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13631203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13632203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13633203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13634203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13635203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13636203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13637203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13638203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13639203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13640203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13641203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13642203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13643203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13644203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13645203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13646203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13647203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13648203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13649203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13650203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13651203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13652203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13653203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13654203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13655203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13656203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13657203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13658203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13659203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13660203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13661203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13662203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13663203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13664203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13665203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13666203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13667203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13668203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13669203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13670203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13671203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13672203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13673203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13674203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13675203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13676203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13677203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13678203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13679203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13680203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13681203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13682203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13683203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13684203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13685203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13686203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13687203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13688203945Sweongyo	};
13689203945Sweongyo	static struct bwn_txgain_entry txgain_r1[] = {
13690203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13691203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13692203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13693203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13694203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13695203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13696203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13697203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13698203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13699203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13700203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13701203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13702203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13703203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13704203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13705203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13706203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13707203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13708203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 14, 0, 68 },
13709203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13710203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13711203945Sweongyo		{ 7, 15, 14, 0, 59 }, { 7, 15, 14, 0, 57 },
13712203945Sweongyo		{ 7, 15, 13, 0, 72 }, { 7, 15, 13, 0, 70 },
13713203945Sweongyo		{ 7, 15, 13, 0, 68 }, { 7, 15, 13, 0, 66 },
13714203945Sweongyo		{ 7, 15, 13, 0, 64 }, { 7, 15, 13, 0, 62 },
13715203945Sweongyo		{ 7, 15, 13, 0, 60 }, { 7, 15, 13, 0, 59 },
13716203945Sweongyo		{ 7, 15, 13, 0, 57 }, { 7, 15, 12, 0, 71 },
13717203945Sweongyo		{ 7, 15, 12, 0, 69 }, { 7, 15, 12, 0, 67 },
13718203945Sweongyo		{ 7, 15, 12, 0, 65 }, { 7, 15, 12, 0, 63 },
13719203945Sweongyo		{ 7, 15, 12, 0, 62 }, { 7, 15, 12, 0, 60 },
13720203945Sweongyo		{ 7, 15, 12, 0, 58 }, { 7, 15, 12, 0, 57 },
13721203945Sweongyo		{ 7, 15, 11, 0, 70 }, { 7, 15, 11, 0, 68 },
13722203945Sweongyo		{ 7, 15, 11, 0, 66 }, { 7, 15, 11, 0, 65 },
13723203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13724203945Sweongyo		{ 7, 15, 11, 0, 59 }, { 7, 15, 11, 0, 58 },
13725203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13726203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13727203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13728203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13729203945Sweongyo		{ 7, 15, 10, 0, 56 }, { 7, 15, 9, 0, 70 },
13730203945Sweongyo		{ 7, 15, 9, 0, 68 }, { 7, 15, 9, 0, 66 },
13731203945Sweongyo		{ 7, 15, 9, 0, 64 }, { 7, 15, 9, 0, 62 },
13732203945Sweongyo		{ 7, 15, 9, 0, 60 }, { 7, 15, 9, 0, 59 },
13733203945Sweongyo		{ 7, 14, 9, 0, 72 }, { 7, 14, 9, 0, 70 },
13734203945Sweongyo		{ 7, 14, 9, 0, 68 }, { 7, 14, 9, 0, 66 },
13735203945Sweongyo		{ 7, 14, 9, 0, 64 }, { 7, 14, 9, 0, 62 },
13736203945Sweongyo		{ 7, 14, 9, 0, 60 }, { 7, 14, 9, 0, 59 },
13737203945Sweongyo		{ 7, 13, 9, 0, 72 }, { 7, 13, 9, 0, 70 },
13738203945Sweongyo		{ 7, 13, 9, 0, 68 }, { 7, 13, 9, 0, 66 },
13739203945Sweongyo		{ 7, 13, 9, 0, 64 }, { 7, 13, 9, 0, 63 },
13740203945Sweongyo		{ 7, 13, 9, 0, 61 }, { 7, 13, 9, 0, 59 },
13741203945Sweongyo		{ 7, 13, 9, 0, 57 }, { 7, 13, 8, 0, 72 },
13742203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13743203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13744203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13745203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 12, 8, 0, 72 },
13746203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13747203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13748203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13749203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 7, 0, 73 },
13750203945Sweongyo		{ 7, 12, 7, 0, 71 }, { 7, 12, 7, 0, 69 },
13751203945Sweongyo		{ 7, 12, 7, 0, 67 }, { 7, 12, 7, 0, 65 },
13752203945Sweongyo		{ 7, 12, 7, 0, 63 }, { 7, 12, 7, 0, 61 },
13753203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 11, 7, 0, 72 },
13754203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13755203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 65 },
13756203945Sweongyo		{ 7, 11, 7, 0, 63 }, { 7, 11, 7, 0, 61 },
13757203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 6, 0, 73 },
13758203945Sweongyo		{ 7, 11, 6, 0, 71 }
13759203945Sweongyo	};
13760203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r1[] = {
13761203945Sweongyo		{ 4, 15, 15, 0, 90 }, { 4, 15, 15, 0, 88 },
13762203945Sweongyo		{ 4, 15, 15, 0, 85 }, { 4, 15, 15, 0, 83 },
13763203945Sweongyo		{ 4, 15, 15, 0, 81 }, { 4, 15, 15, 0, 78 },
13764203945Sweongyo		{ 4, 15, 15, 0, 76 }, { 4, 15, 15, 0, 74 },
13765203945Sweongyo		{ 4, 15, 15, 0, 72 }, { 4, 15, 15, 0, 70 },
13766203945Sweongyo		{ 4, 15, 15, 0, 68 }, { 4, 15, 15, 0, 66 },
13767203945Sweongyo		{ 4, 15, 15, 0, 64 }, { 4, 15, 15, 0, 62 },
13768203945Sweongyo		{ 4, 15, 15, 0, 60 }, { 4, 15, 15, 0, 59 },
13769203945Sweongyo		{ 4, 15, 14, 0, 72 }, { 4, 15, 14, 0, 70 },
13770203945Sweongyo		{ 4, 15, 14, 0, 68 }, { 4, 15, 14, 0, 66 },
13771203945Sweongyo		{ 4, 15, 14, 0, 64 }, { 4, 15, 14, 0, 62 },
13772203945Sweongyo		{ 4, 15, 14, 0, 60 }, { 4, 15, 14, 0, 59 },
13773203945Sweongyo		{ 4, 15, 13, 0, 72 }, { 4, 15, 13, 0, 70 },
13774203945Sweongyo		{ 4, 15, 13, 0, 68 }, { 4, 15, 13, 0, 66 },
13775203945Sweongyo		{ 4, 15, 13, 0, 64 }, { 4, 15, 13, 0, 62 },
13776203945Sweongyo		{ 4, 15, 13, 0, 60 }, { 4, 15, 13, 0, 59 },
13777203945Sweongyo		{ 4, 15, 12, 0, 72 }, { 4, 15, 12, 0, 70 },
13778203945Sweongyo		{ 4, 15, 12, 0, 68 }, { 4, 15, 12, 0, 66 },
13779203945Sweongyo		{ 4, 15, 12, 0, 64 }, { 4, 15, 12, 0, 62 },
13780203945Sweongyo		{ 4, 15, 12, 0, 60 }, { 4, 15, 12, 0, 59 },
13781203945Sweongyo		{ 4, 15, 11, 0, 72 }, { 4, 15, 11, 0, 70 },
13782203945Sweongyo		{ 4, 15, 11, 0, 68 }, { 4, 15, 11, 0, 66 },
13783203945Sweongyo		{ 4, 15, 11, 0, 64 }, { 4, 15, 11, 0, 62 },
13784203945Sweongyo		{ 4, 15, 11, 0, 60 }, { 4, 15, 11, 0, 59 },
13785203945Sweongyo		{ 4, 15, 10, 0, 72 }, { 4, 15, 10, 0, 70 },
13786203945Sweongyo		{ 4, 15, 10, 0, 68 }, { 4, 15, 10, 0, 66 },
13787203945Sweongyo		{ 4, 15, 10, 0, 64 }, { 4, 15, 10, 0, 62 },
13788203945Sweongyo		{ 4, 15, 10, 0, 60 }, { 4, 15, 10, 0, 59 },
13789203945Sweongyo		{ 4, 15, 9, 0, 72 }, { 4, 15, 9, 0, 70 },
13790203945Sweongyo		{ 4, 15, 9, 0, 68 }, { 4, 15, 9, 0, 66 },
13791203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13792203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13793203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13794203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13795203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13796203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13797203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13798203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13799203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13800203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13801203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13802203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13803203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13804203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13805203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13806203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13807203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13808203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13809203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13810203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13811203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13812203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13813203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13814203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13815203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13816203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13817203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13818203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13819203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13820203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13821203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13822203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13823203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13824203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 }
13825203945Sweongyo	};
13826203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r1[] = {
13827203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13828203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13829203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13830203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13831203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13832203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13833203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13834203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13835203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13836203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13837203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13838203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13839203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13840203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13841203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13842203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13843203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13844203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13845203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13846203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13847203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13848203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13849203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13850203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13851203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13852203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13853203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13854203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13855203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13856203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13857203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13858203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13859203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13860203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13861203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13862203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13863203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13864203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13865203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13866203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13867203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13868203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13869203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13870203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13871203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13872203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13873203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13874203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13875203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13876203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13877203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13878203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13879203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13880203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13881203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13882203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13883203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13884203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13885203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13886203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13887203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13888203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13889203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13890203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13891203945Sweongyo	};
13892203945Sweongyo
13893203945Sweongyo	if (mac->mac_phy.rev != 0 && mac->mac_phy.rev != 1) {
13894204922Sweongyo		if (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA)
13895203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r2);
13896203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13897203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13898203945Sweongyo			    txgain_2ghz_r2);
13899203945Sweongyo		else
13900203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13901203945Sweongyo			    txgain_5ghz_r2);
13902203945Sweongyo		return;
13903203945Sweongyo	}
13904203945Sweongyo
13905203945Sweongyo	if (mac->mac_phy.rev == 0) {
13906204922Sweongyo		if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
13907204922Sweongyo		    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_HGPA))
13908203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r0);
13909203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13910203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13911203945Sweongyo			    txgain_2ghz_r0);
13912203945Sweongyo		else
13913203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13914203945Sweongyo			    txgain_5ghz_r0);
13915203945Sweongyo		return;
13916203945Sweongyo	}
13917203945Sweongyo
13918204922Sweongyo	if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
13919204922Sweongyo	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_HGPA))
13920203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r1);
13921203945Sweongyo	else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13922203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_2ghz_r1);
13923203945Sweongyo	else
13924203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_5ghz_r1);
13925203945Sweongyo}
13926203945Sweongyo
13927203945Sweongyostatic void
13928203945Sweongyobwn_tab_write(struct bwn_mac *mac, uint32_t typeoffset, uint32_t value)
13929203945Sweongyo{
13930203945Sweongyo	uint32_t offset, type;
13931203945Sweongyo
13932203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
13933203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
13934203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
13935203945Sweongyo
13936203945Sweongyo	switch (type) {
13937203945Sweongyo	case BWN_TAB_8BIT:
13938203945Sweongyo		KASSERT(!(value & ~0xff), ("%s:%d: fail", __func__, __LINE__));
13939203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13940203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13941203945Sweongyo		break;
13942203945Sweongyo	case BWN_TAB_16BIT:
13943203945Sweongyo		KASSERT(!(value & ~0xffff),
13944203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
13945203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13946203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13947203945Sweongyo		break;
13948203945Sweongyo	case BWN_TAB_32BIT:
13949203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13950203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
13951203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13952203945Sweongyo		break;
13953203945Sweongyo	default:
13954203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
13955203945Sweongyo	}
13956203945Sweongyo}
13957203945Sweongyo
13958203945Sweongyostatic int
13959203945Sweongyobwn_phy_lp_loopback(struct bwn_mac *mac)
13960203945Sweongyo{
13961203945Sweongyo	struct bwn_phy_lp_iq_est ie;
13962203945Sweongyo	int i, index = -1;
13963203945Sweongyo	uint32_t tmp;
13964203945Sweongyo
13965203945Sweongyo	memset(&ie, 0, sizeof(ie));
13966203945Sweongyo
13967203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1, 1);
13968203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 1);
13969203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
13970203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
13971203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
13972203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
13973203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x8);
13974203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, 0x80);
13975203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x80);
13976203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x80);
13977203945Sweongyo	for (i = 0; i < 32; i++) {
13978203945Sweongyo		bwn_phy_lp_set_rxgain_idx(mac, i);
13979203945Sweongyo		bwn_phy_lp_ddfs_turnon(mac, 1, 1, 5, 5, 0);
13980203945Sweongyo		if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
13981203945Sweongyo			continue;
13982203945Sweongyo		tmp = (ie.ie_ipwr + ie.ie_qpwr) / 1000;
13983203945Sweongyo		if ((tmp > 4000) && (tmp < 10000)) {
13984203945Sweongyo			index = i;
13985203945Sweongyo			break;
13986203945Sweongyo		}
13987203945Sweongyo	}
13988203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
13989203945Sweongyo	return (index);
13990203945Sweongyo}
13991203945Sweongyo
13992203945Sweongyostatic void
13993203945Sweongyobwn_phy_lp_set_rxgain_idx(struct bwn_mac *mac, uint16_t idx)
13994203945Sweongyo{
13995203945Sweongyo
13996203945Sweongyo	bwn_phy_lp_set_rxgain(mac, bwn_tab_read(mac, BWN_TAB_2(12, idx)));
13997203945Sweongyo}
13998203945Sweongyo
13999203945Sweongyostatic void
14000203945Sweongyobwn_phy_lp_ddfs_turnon(struct bwn_mac *mac, int i_on, int q_on,
14001203945Sweongyo    int incr1, int incr2, int scale_idx)
14002203945Sweongyo{
14003203945Sweongyo
14004203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
14005203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0xff80);
14006203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0x80ff);
14007203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0xff80, incr1);
14008203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0x80ff, incr2 << 8);
14009203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff7, i_on << 3);
14010203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xffef, q_on << 4);
14011203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xff9f, scale_idx << 5);
14012203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffb);
14013203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DDFS, 0x2);
14014203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x20);
14015203945Sweongyo}
14016203945Sweongyo
14017203945Sweongyostatic uint8_t
14018203945Sweongyobwn_phy_lp_rx_iq_est(struct bwn_mac *mac, uint16_t sample, uint8_t time,
14019203945Sweongyo    struct bwn_phy_lp_iq_est *ie)
14020203945Sweongyo{
14021203945Sweongyo	int i;
14022203945Sweongyo
14023203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfff7);
14024203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_IQ_NUM_SMPLS_ADDR, sample);
14025203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xff00, time);
14026203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xfeff);
14027203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
14028203945Sweongyo
14029203945Sweongyo	for (i = 0; i < 500; i++) {
14030203945Sweongyo		if (!(BWN_PHY_READ(mac,
14031203945Sweongyo		    BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
14032203945Sweongyo			break;
14033203945Sweongyo		DELAY(1000);
14034203945Sweongyo	}
14035203945Sweongyo	if ((BWN_PHY_READ(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
14036203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14037203945Sweongyo		return 0;
14038203945Sweongyo	}
14039203945Sweongyo
14040203945Sweongyo	ie->ie_iqprod = BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_HI_ADDR);
14041203945Sweongyo	ie->ie_iqprod <<= 16;
14042203945Sweongyo	ie->ie_iqprod |= BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_LO_ADDR);
14043203945Sweongyo	ie->ie_ipwr = BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_HI_ADDR);
14044203945Sweongyo	ie->ie_ipwr <<= 16;
14045203945Sweongyo	ie->ie_ipwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_LO_ADDR);
14046203945Sweongyo	ie->ie_qpwr = BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR);
14047203945Sweongyo	ie->ie_qpwr <<= 16;
14048203945Sweongyo	ie->ie_qpwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR);
14049203945Sweongyo
14050203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14051203945Sweongyo	return 1;
14052203945Sweongyo}
14053203945Sweongyo
14054203945Sweongyostatic uint32_t
14055203945Sweongyobwn_tab_read(struct bwn_mac *mac, uint32_t typeoffset)
14056203945Sweongyo{
14057203945Sweongyo	uint32_t offset, type, value;
14058203945Sweongyo
14059203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
14060203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
14061203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
14062203945Sweongyo
14063203945Sweongyo	switch (type) {
14064203945Sweongyo	case BWN_TAB_8BIT:
14065203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14066203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
14067203945Sweongyo		break;
14068203945Sweongyo	case BWN_TAB_16BIT:
14069203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14070203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14071203945Sweongyo		break;
14072203945Sweongyo	case BWN_TAB_32BIT:
14073203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14074203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATAHI);
14075203945Sweongyo		value <<= 16;
14076203945Sweongyo		value |= BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14077203945Sweongyo		break;
14078203945Sweongyo	default:
14079203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
14080203945Sweongyo		value = 0;
14081203945Sweongyo	}
14082203945Sweongyo
14083203945Sweongyo	return (value);
14084203945Sweongyo}
14085203945Sweongyo
14086203945Sweongyostatic void
14087203945Sweongyobwn_phy_lp_ddfs_turnoff(struct bwn_mac *mac)
14088203945Sweongyo{
14089203945Sweongyo
14090203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffd);
14091203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0xffdf);
14092203945Sweongyo}
14093203945Sweongyo
14094203945Sweongyostatic void
14095203945Sweongyobwn_phy_lp_set_txgain_dac(struct bwn_mac *mac, uint16_t dac)
14096203945Sweongyo{
14097203945Sweongyo	uint16_t ctl;
14098203945Sweongyo
14099203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0xc7f;
14100203945Sweongyo	ctl |= dac << 7;
14101203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf000, ctl);
14102203945Sweongyo}
14103203945Sweongyo
14104203945Sweongyostatic void
14105203945Sweongyobwn_phy_lp_set_txgain_pa(struct bwn_mac *mac, uint16_t gain)
14106203945Sweongyo{
14107203945Sweongyo
14108203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0xe03f, gain << 6);
14109203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x80ff, gain << 8);
14110203945Sweongyo}
14111203945Sweongyo
14112203945Sweongyostatic void
14113203945Sweongyobwn_phy_lp_set_txgain_override(struct bwn_mac *mac)
14114203945Sweongyo{
14115203945Sweongyo
14116203945Sweongyo	if (mac->mac_phy.rev < 2)
14117203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
14118203945Sweongyo	else {
14119203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x80);
14120203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x4000);
14121203945Sweongyo	}
14122203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x40);
14123203945Sweongyo}
14124203945Sweongyo
14125203945Sweongyostatic uint16_t
14126203945Sweongyobwn_phy_lp_get_pa_gain(struct bwn_mac *mac)
14127203945Sweongyo{
14128203945Sweongyo
14129203945Sweongyo	return BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0x7f;
14130203945Sweongyo}
14131203945Sweongyo
14132203945Sweongyostatic uint8_t
14133203945Sweongyobwn_nbits(int32_t val)
14134203945Sweongyo{
14135203945Sweongyo	uint32_t tmp;
14136203945Sweongyo	uint8_t nbits = 0;
14137203945Sweongyo
14138203945Sweongyo	for (tmp = abs(val); tmp != 0; tmp >>= 1)
14139203945Sweongyo		nbits++;
14140203945Sweongyo	return (nbits);
14141203945Sweongyo}
14142203945Sweongyo
14143203945Sweongyostatic void
14144203945Sweongyobwn_phy_lp_gaintbl_write_multi(struct bwn_mac *mac, int offset, int count,
14145203945Sweongyo    struct bwn_txgain_entry *table)
14146203945Sweongyo{
14147203945Sweongyo	int i;
14148203945Sweongyo
14149203945Sweongyo	for (i = offset; i < count; i++)
14150203945Sweongyo		bwn_phy_lp_gaintbl_write(mac, i, table[i]);
14151203945Sweongyo}
14152203945Sweongyo
14153203945Sweongyostatic void
14154203945Sweongyobwn_phy_lp_gaintbl_write(struct bwn_mac *mac, int offset,
14155203945Sweongyo    struct bwn_txgain_entry data)
14156203945Sweongyo{
14157203945Sweongyo
14158203945Sweongyo	if (mac->mac_phy.rev >= 2)
14159203945Sweongyo		bwn_phy_lp_gaintbl_write_r2(mac, offset, data);
14160203945Sweongyo	else
14161203945Sweongyo		bwn_phy_lp_gaintbl_write_r01(mac, offset, data);
14162203945Sweongyo}
14163203945Sweongyo
14164203945Sweongyostatic void
14165203945Sweongyobwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset,
14166203945Sweongyo    struct bwn_txgain_entry te)
14167203945Sweongyo{
14168203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
14169203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
14170203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
14171203945Sweongyo	uint32_t tmp;
14172203945Sweongyo
14173203945Sweongyo	KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__));
14174203945Sweongyo
14175203945Sweongyo	tmp = (te.te_pad << 16) | (te.te_pga << 8) | te.te_gm;
14176203945Sweongyo	if (mac->mac_phy.rev >= 3) {
14177203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14178203945Sweongyo		    (0x10 << 24) : (0x70 << 24));
14179203945Sweongyo	} else {
14180203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14181203945Sweongyo		    (0x14 << 24) : (0x7f << 24));
14182203945Sweongyo	}
14183203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0xc0 + offset), tmp);
14184203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0x140 + offset),
14185203945Sweongyo	    te.te_bbmult << 20 | te.te_dac << 28);
14186203945Sweongyo}
14187203945Sweongyo
14188203945Sweongyostatic void
14189203945Sweongyobwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
14190203945Sweongyo    struct bwn_txgain_entry te)
14191203945Sweongyo{
14192203945Sweongyo
14193203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
14194203945Sweongyo
14195203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0xc0 + offset),
14196203945Sweongyo	    (te.te_pad << 11) | (te.te_pga << 7) | (te.te_gm  << 4) |
14197203945Sweongyo	    te.te_dac);
14198203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0x140 + offset), te.te_bbmult << 20);
14199203945Sweongyo}
14200203945Sweongyo
14201203945Sweongyostatic void
14202204257Sweongyobwn_sysctl_node(struct bwn_softc *sc)
14203204257Sweongyo{
14204204257Sweongyo	device_t dev = sc->sc_dev;
14205204257Sweongyo	struct bwn_mac *mac;
14206204257Sweongyo	struct bwn_stats *stats;
14207204257Sweongyo
14208204257Sweongyo	/* XXX assume that count of MAC is only 1. */
14209204257Sweongyo
14210204257Sweongyo	if ((mac = sc->sc_curmac) == NULL)
14211204257Sweongyo		return;
14212204257Sweongyo	stats = &mac->mac_stats;
14213204257Sweongyo
14214204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14215204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14216204257Sweongyo	    "linknoise", CTLFLAG_RW, &stats->rts, 0, "Noise level");
14217204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14218204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14219204257Sweongyo	    "rts", CTLFLAG_RW, &stats->rts, 0, "RTS");
14220204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14221204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14222204257Sweongyo	    "rtsfail", CTLFLAG_RW, &stats->rtsfail, 0, "RTS failed to send");
14223204257Sweongyo
14224204257Sweongyo#ifdef BWN_DEBUG
14225204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14226204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14227204257Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
14228204257Sweongyo#endif
14229204257Sweongyo}
14230204257Sweongyo
14231203945Sweongyostatic device_method_t bwn_methods[] = {
14232203945Sweongyo	/* Device interface */
14233203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
14234203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
14235203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
14236203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
14237203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
14238204923Sweongyo	KOBJMETHOD_END
14239203945Sweongyo};
14240203945Sweongyostatic driver_t bwn_driver = {
14241203945Sweongyo	"bwn",
14242203945Sweongyo	bwn_methods,
14243203945Sweongyo	sizeof(struct bwn_softc)
14244203945Sweongyo};
14245203945Sweongyostatic devclass_t bwn_devclass;
14246203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
14247203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
14248203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
14249203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
14250203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
14251