if_bwn.c revision 283527
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 283527 2015-05-25 13:51:13Z glebius $");
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>
55257176Sglebius#include <net/if_var.h>
56203945Sweongyo#include <net/if_arp.h>
57203945Sweongyo#include <net/if_dl.h>
58203945Sweongyo#include <net/if_llc.h>
59203945Sweongyo#include <net/if_media.h>
60203945Sweongyo#include <net/if_types.h>
61203945Sweongyo
62203945Sweongyo#include <dev/pci/pcivar.h>
63203945Sweongyo#include <dev/pci/pcireg.h>
64203945Sweongyo#include <dev/siba/siba_ids.h>
65203945Sweongyo#include <dev/siba/sibareg.h>
66203945Sweongyo#include <dev/siba/sibavar.h>
67203945Sweongyo
68203945Sweongyo#include <net80211/ieee80211_var.h>
69203945Sweongyo#include <net80211/ieee80211_radiotap.h>
70203945Sweongyo#include <net80211/ieee80211_regdomain.h>
71203945Sweongyo#include <net80211/ieee80211_phy.h>
72206358Srpaulo#include <net80211/ieee80211_ratectl.h>
73203945Sweongyo
74203945Sweongyo#include <dev/bwn/if_bwnreg.h>
75203945Sweongyo#include <dev/bwn/if_bwnvar.h>
76203945Sweongyo
77227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0,
78227309Sed    "Broadcom driver parameters");
79203945Sweongyo
80203945Sweongyo/*
81203945Sweongyo * Tunable & sysctl variables.
82203945Sweongyo */
83203945Sweongyo
84203945Sweongyo#ifdef BWN_DEBUG
85203945Sweongyostatic	int bwn_debug = 0;
86267992ShselaskySYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RWTUN, &bwn_debug, 0,
87203945Sweongyo    "Broadcom debugging printfs");
88203945Sweongyoenum {
89203945Sweongyo	BWN_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
90203945Sweongyo	BWN_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
91203945Sweongyo	BWN_DEBUG_STATE		= 0x00000004,	/* 802.11 state transitions */
92203945Sweongyo	BWN_DEBUG_TXPOW		= 0x00000008,	/* tx power processing */
93203945Sweongyo	BWN_DEBUG_RESET		= 0x00000010,	/* reset processing */
94203945Sweongyo	BWN_DEBUG_OPS		= 0x00000020,	/* bwn_ops processing */
95203945Sweongyo	BWN_DEBUG_BEACON	= 0x00000040,	/* beacon handling */
96203945Sweongyo	BWN_DEBUG_WATCHDOG	= 0x00000080,	/* watchdog timeout */
97203945Sweongyo	BWN_DEBUG_INTR		= 0x00000100,	/* ISR */
98203945Sweongyo	BWN_DEBUG_CALIBRATE	= 0x00000200,	/* periodic calibration */
99203945Sweongyo	BWN_DEBUG_NODE		= 0x00000400,	/* node management */
100203945Sweongyo	BWN_DEBUG_LED		= 0x00000800,	/* led management */
101203945Sweongyo	BWN_DEBUG_CMD		= 0x00001000,	/* cmd submission */
102203945Sweongyo	BWN_DEBUG_LO		= 0x00002000,	/* LO */
103203945Sweongyo	BWN_DEBUG_FW		= 0x00004000,	/* firmware */
104203945Sweongyo	BWN_DEBUG_WME		= 0x00008000,	/* WME */
105203945Sweongyo	BWN_DEBUG_RF		= 0x00010000,	/* RF */
106203945Sweongyo	BWN_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
107203945Sweongyo	BWN_DEBUG_ANY		= 0xffffffff
108203945Sweongyo};
109203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do {			\
110203945Sweongyo	if (sc->sc_debug & (m))				\
111203945Sweongyo		printf(fmt, __VA_ARGS__);		\
112203945Sweongyo} while (0)
113203945Sweongyo#else
114203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
115203945Sweongyo#endif
116203945Sweongyo
117203945Sweongyostatic int	bwn_bfp = 0;		/* use "Bad Frames Preemption" */
118203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
119203945Sweongyo    "uses Bad Frames Preemption");
120203945Sweongyostatic int	bwn_bluetooth = 1;
121203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
122203945Sweongyo    "turns on Bluetooth Coexistence");
123203945Sweongyostatic int	bwn_hwpctl = 0;
124203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
125203945Sweongyo    "uses H/W power control");
126203945Sweongyostatic int	bwn_msi_disable = 0;		/* MSI disabled  */
127203945SweongyoTUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable);
128203945Sweongyostatic int	bwn_usedma = 1;
129203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
130203945Sweongyo    "uses DMA");
131203945SweongyoTUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
132203945Sweongyostatic int	bwn_wme = 1;
133203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
134203945Sweongyo    "uses WME support");
135203945Sweongyo
136203945Sweongyostatic int	bwn_attach_pre(struct bwn_softc *);
137203945Sweongyostatic int	bwn_attach_post(struct bwn_softc *);
138204922Sweongyostatic void	bwn_sprom_bugfixes(device_t);
139203945Sweongyostatic void	bwn_init(void *);
140203945Sweongyostatic int	bwn_init_locked(struct bwn_softc *);
141203945Sweongyostatic int	bwn_ioctl(struct ifnet *, u_long, caddr_t);
142203945Sweongyostatic void	bwn_start(struct ifnet *);
143203945Sweongyostatic int	bwn_attach_core(struct bwn_mac *);
144203945Sweongyostatic void	bwn_reset_core(struct bwn_mac *, uint32_t);
145203945Sweongyostatic int	bwn_phy_getinfo(struct bwn_mac *, int);
146203945Sweongyostatic int	bwn_chiptest(struct bwn_mac *);
147203945Sweongyostatic int	bwn_setup_channels(struct bwn_mac *, int, int);
148203945Sweongyostatic int	bwn_phy_g_attach(struct bwn_mac *);
149203945Sweongyostatic void	bwn_phy_g_detach(struct bwn_mac *);
150203945Sweongyostatic void	bwn_phy_g_init_pre(struct bwn_mac *);
151203945Sweongyostatic int	bwn_phy_g_prepare_hw(struct bwn_mac *);
152203945Sweongyostatic int	bwn_phy_g_init(struct bwn_mac *);
153203945Sweongyostatic void	bwn_phy_g_exit(struct bwn_mac *);
154203945Sweongyostatic uint16_t	bwn_phy_g_read(struct bwn_mac *, uint16_t);
155203945Sweongyostatic void	bwn_phy_g_write(struct bwn_mac *, uint16_t,
156203945Sweongyo		    uint16_t);
157203945Sweongyostatic uint16_t	bwn_phy_g_rf_read(struct bwn_mac *, uint16_t);
158203945Sweongyostatic void	bwn_phy_g_rf_write(struct bwn_mac *, uint16_t,
159203945Sweongyo		    uint16_t);
160203945Sweongyostatic int	bwn_phy_g_hwpctl(struct bwn_mac *);
161203945Sweongyostatic void	bwn_phy_g_rf_onoff(struct bwn_mac *, int);
162203945Sweongyostatic int	bwn_phy_g_switch_channel(struct bwn_mac *, uint32_t);
163203945Sweongyostatic uint32_t	bwn_phy_g_get_default_chan(struct bwn_mac *);
164203945Sweongyostatic void	bwn_phy_g_set_antenna(struct bwn_mac *, int);
165203945Sweongyostatic int	bwn_phy_g_im(struct bwn_mac *, int);
166203945Sweongyostatic int	bwn_phy_g_recalc_txpwr(struct bwn_mac *, int);
167203945Sweongyostatic void	bwn_phy_g_set_txpwr(struct bwn_mac *);
168203945Sweongyostatic void	bwn_phy_g_task_15s(struct bwn_mac *);
169203945Sweongyostatic void	bwn_phy_g_task_60s(struct bwn_mac *);
170203945Sweongyostatic uint16_t	bwn_phy_g_txctl(struct bwn_mac *);
171203945Sweongyostatic void	bwn_phy_switch_analog(struct bwn_mac *, int);
172203945Sweongyostatic uint16_t	bwn_shm_read_2(struct bwn_mac *, uint16_t, uint16_t);
173203945Sweongyostatic void	bwn_shm_write_2(struct bwn_mac *, uint16_t, uint16_t,
174203945Sweongyo		    uint16_t);
175203945Sweongyostatic uint32_t	bwn_shm_read_4(struct bwn_mac *, uint16_t, uint16_t);
176203945Sweongyostatic void	bwn_shm_write_4(struct bwn_mac *, uint16_t, uint16_t,
177203945Sweongyo		    uint32_t);
178203945Sweongyostatic void	bwn_shm_ctlword(struct bwn_mac *, uint16_t,
179203945Sweongyo		    uint16_t);
180203945Sweongyostatic void	bwn_addchannels(struct ieee80211_channel [], int, int *,
181203945Sweongyo		    const struct bwn_channelinfo *, int);
182203945Sweongyostatic int	bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
183203945Sweongyo		    const struct ieee80211_bpf_params *);
184203945Sweongyostatic void	bwn_updateslot(struct ifnet *);
185203945Sweongyostatic void	bwn_update_promisc(struct ifnet *);
186203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
187203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
188203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
189203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
190203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
191203945Sweongyo		    const struct wmeParams *, uint16_t);
192203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
193203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
194203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
195203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
196228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
197228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
198203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
199203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
200203945Sweongyostatic void	bwn_stop(struct bwn_softc *, int);
201203945Sweongyostatic void	bwn_stop_locked(struct bwn_softc *, int);
202203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
203203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
204203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
205203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
206203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
207203945Sweongyostatic uint64_t	bwn_hf_read(struct bwn_mac *);
208203945Sweongyostatic void	bwn_hf_write(struct bwn_mac *, uint64_t);
209203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
210203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
211203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
212203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
213203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
214203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
215203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
216203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
217203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
218203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
219203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
220203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
221203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
222203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
223203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
224203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
225203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
226203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
227203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
228203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
229203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
230203945Sweongyo		    int);
231203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
232203945Sweongyo		    struct bwn_pio_rxqueue *, int);
233203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
234203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
235203945Sweongyo		    uint16_t);
236203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
237203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
238203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
239203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
240203945Sweongyo		    const struct bwn_txstatus *);
241203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
242203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
243203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
244203945Sweongyo		    uint16_t);
245203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
246203945Sweongyo		    uint32_t);
247203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
248203945Sweongyo		    struct mbuf *);
249203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
250203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
251203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
252203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
253203945Sweongyo		    uint16_t, uint32_t);
254203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
255203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
256203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
257203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
258203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
259203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
260203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
261203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
262203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
263203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
264203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
265203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
266203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
267203945Sweongyo		    int, struct bwn_dmadesc_generic **,
268203945Sweongyo		    struct bwn_dmadesc_meta **);
269203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
270203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
271203945Sweongyo		    int, int);
272203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
273203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
274203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
275203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
276203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
277203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
278203945Sweongyo		    int, struct bwn_dmadesc_generic **,
279203945Sweongyo		    struct bwn_dmadesc_meta **);
280203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
281203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
282203945Sweongyo		    int, int);
283203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
284203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
285203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
286203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
287203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
288203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
289203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
290203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
291203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
292203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
293203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
294203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
295203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
296203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
297203945Sweongyo		    struct bwn_dmadesc_meta *);
298203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
299203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
300203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
301203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
302203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
303203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
304203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
305203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
306203945Sweongyo		    int);
307203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
308203945Sweongyo		    bus_size_t, int);
309203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
310203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
311203945Sweongyo		    const struct bwn_txstatus *);
312203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
313203945Sweongyo		    struct mbuf *);
314203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
315203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
316203945Sweongyo		    uint8_t);
317203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
318203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
319203945Sweongyo		    int, int, int);
320203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
321203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
322203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
323203945Sweongyostatic void	bwn_phy_g_init_sub(struct bwn_mac *);
324203945Sweongyostatic uint8_t	bwn_has_hwpctl(struct bwn_mac *);
325203945Sweongyostatic void	bwn_phy_init_b5(struct bwn_mac *);
326203945Sweongyostatic void	bwn_phy_init_b6(struct bwn_mac *);
327203945Sweongyostatic void	bwn_phy_init_a(struct bwn_mac *);
328203945Sweongyostatic void	bwn_loopback_calcgain(struct bwn_mac *);
329203945Sweongyostatic uint16_t	bwn_rf_init_bcm2050(struct bwn_mac *);
330203945Sweongyostatic void	bwn_lo_g_init(struct bwn_mac *);
331203945Sweongyostatic void	bwn_lo_g_adjust(struct bwn_mac *);
332203945Sweongyostatic void	bwn_lo_get_powervector(struct bwn_mac *);
333203945Sweongyostatic struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
334203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *);
335203945Sweongyostatic void	bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
336203945Sweongyostatic void	bwn_phy_hwpctl_init(struct bwn_mac *);
337203945Sweongyostatic void	bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
338203945Sweongyostatic void	bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
339203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *,
340203945Sweongyo		    uint8_t);
341203945Sweongyostatic void	bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
342203945Sweongyostatic uint16_t	bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
343203945Sweongyostatic void	bwn_spu_workaround(struct bwn_mac *, uint8_t);
344203945Sweongyostatic void	bwn_wa_init(struct bwn_mac *);
345203945Sweongyostatic void	bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
346203945Sweongyo		    uint16_t);
347203945Sweongyostatic void	bwn_dummy_transmission(struct bwn_mac *, int, int);
348203945Sweongyostatic void	bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
349203945Sweongyo		    uint32_t);
350203945Sweongyostatic void	bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
351203945Sweongyo		    uint16_t);
352203945Sweongyostatic void	bwn_ram_write(struct bwn_mac *, uint16_t, uint32_t);
353203945Sweongyostatic void	bwn_mac_suspend(struct bwn_mac *);
354203945Sweongyostatic void	bwn_mac_enable(struct bwn_mac *);
355203945Sweongyostatic void	bwn_psctl(struct bwn_mac *, uint32_t);
356203945Sweongyostatic int16_t	bwn_nrssi_read(struct bwn_mac *, uint16_t);
357203945Sweongyostatic void	bwn_nrssi_offset(struct bwn_mac *);
358203945Sweongyostatic void	bwn_nrssi_threshold(struct bwn_mac *);
359203945Sweongyostatic void	bwn_nrssi_slope_11g(struct bwn_mac *);
360203945Sweongyostatic void	bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
361203945Sweongyo		    int16_t);
362203945Sweongyostatic void	bwn_set_original_gains(struct bwn_mac *);
363203945Sweongyostatic void	bwn_hwpctl_early_init(struct bwn_mac *);
364203945Sweongyostatic void	bwn_hwpctl_init_gphy(struct bwn_mac *);
365203945Sweongyostatic uint16_t	bwn_phy_g_chan2freq(uint8_t);
366203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
367203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
368203945Sweongyo		    const char *, struct bwn_fwfile *);
369203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
370203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
371203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
372203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
373203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
374203945Sweongyostatic int	bwn_switch_channel(struct bwn_mac *, int);
375203945Sweongyostatic uint16_t	bwn_ant2phy(int);
376203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
377203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
378203945Sweongyo		    const uint8_t *);
379203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
380203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
381203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
382203945Sweongyo		    const uint8_t *);
383203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
384203945Sweongyo		    const uint8_t *);
385203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
386203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
387203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
388203945Sweongyo		    struct ieee80211_channel *);
389203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
390203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
391203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
392203945Sweongyostatic int	bwn_intr(void *);
393203945Sweongyostatic void	bwn_intrtask(void *, int);
394203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
395203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
396203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
397203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
398203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
399203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
400203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
401203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
402203945Sweongyostatic void	bwn_hwreset(void *, int);
403203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
404203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
405203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
406203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
407203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
408203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
409203945Sweongyo		    const struct bwn_txstatus *);
410203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
411203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
412203945Sweongyostatic void	bwn_start_locked(struct ifnet *);
413203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
414203945Sweongyo		    struct mbuf *);
415203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
416203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
417203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
418203945Sweongyo		    uint16_t);
419203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
420203945Sweongyo		    const uint8_t);
421203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
422203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
423203945Sweongyostatic int	bwn_phy_shm_tssi_read(struct bwn_mac *, uint16_t);
424203945Sweongyostatic void	bwn_phy_g_setatt(struct bwn_mac *, int *, int *);
425203945Sweongyostatic void	bwn_phy_lock(struct bwn_mac *);
426203945Sweongyostatic void	bwn_phy_unlock(struct bwn_mac *);
427203945Sweongyostatic void	bwn_rf_lock(struct bwn_mac *);
428203945Sweongyostatic void	bwn_rf_unlock(struct bwn_mac *);
429203945Sweongyostatic void	bwn_txpwr(void *, int);
430203945Sweongyostatic void	bwn_tasks(void *);
431203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
432203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
433203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
434203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
435203945Sweongyo		    uint8_t);
436203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
437203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
438203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
439203945Sweongyo		    int, int);
440203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
441203945Sweongyostatic void	bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
442203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
443203945Sweongyostatic void	bwn_watchdog(void *);
444203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
445203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
446203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
447203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
448203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
449203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
450203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
451203945Sweongyostatic void	bwn_led_blink_next(void *);
452203945Sweongyostatic void	bwn_led_blink_end(void *);
453203945Sweongyostatic void	bwn_rfswitch(void *);
454203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
455203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
456203945Sweongyostatic void	bwn_phy_lp_init_pre(struct bwn_mac *);
457203945Sweongyostatic int	bwn_phy_lp_init(struct bwn_mac *);
458203945Sweongyostatic uint16_t	bwn_phy_lp_read(struct bwn_mac *, uint16_t);
459203945Sweongyostatic void	bwn_phy_lp_write(struct bwn_mac *, uint16_t, uint16_t);
460203945Sweongyostatic void	bwn_phy_lp_maskset(struct bwn_mac *, uint16_t, uint16_t,
461203945Sweongyo		    uint16_t);
462203945Sweongyostatic uint16_t	bwn_phy_lp_rf_read(struct bwn_mac *, uint16_t);
463203945Sweongyostatic void	bwn_phy_lp_rf_write(struct bwn_mac *, uint16_t, uint16_t);
464203945Sweongyostatic void	bwn_phy_lp_rf_onoff(struct bwn_mac *, int);
465203945Sweongyostatic int	bwn_phy_lp_switch_channel(struct bwn_mac *, uint32_t);
466203945Sweongyostatic uint32_t	bwn_phy_lp_get_default_chan(struct bwn_mac *);
467203945Sweongyostatic void	bwn_phy_lp_set_antenna(struct bwn_mac *, int);
468203945Sweongyostatic void	bwn_phy_lp_task_60s(struct bwn_mac *);
469203945Sweongyostatic void	bwn_phy_lp_readsprom(struct bwn_mac *);
470203945Sweongyostatic void	bwn_phy_lp_bbinit(struct bwn_mac *);
471203945Sweongyostatic void	bwn_phy_lp_txpctl_init(struct bwn_mac *);
472203945Sweongyostatic void	bwn_phy_lp_calib(struct bwn_mac *);
473203945Sweongyostatic void	bwn_phy_lp_switch_analog(struct bwn_mac *, int);
474203945Sweongyostatic int	bwn_phy_lp_b2062_switch_channel(struct bwn_mac *, uint8_t);
475203945Sweongyostatic int	bwn_phy_lp_b2063_switch_channel(struct bwn_mac *, uint8_t);
476203945Sweongyostatic void	bwn_phy_lp_set_anafilter(struct bwn_mac *, uint8_t);
477203945Sweongyostatic void	bwn_phy_lp_set_gaintbl(struct bwn_mac *, uint32_t);
478203945Sweongyostatic void	bwn_phy_lp_digflt_save(struct bwn_mac *);
479203945Sweongyostatic void	bwn_phy_lp_get_txpctlmode(struct bwn_mac *);
480203945Sweongyostatic void	bwn_phy_lp_set_txpctlmode(struct bwn_mac *, uint8_t);
481203945Sweongyostatic void	bwn_phy_lp_bugfix(struct bwn_mac *);
482203945Sweongyostatic void	bwn_phy_lp_digflt_restore(struct bwn_mac *);
483203945Sweongyostatic void	bwn_phy_lp_tblinit(struct bwn_mac *);
484203945Sweongyostatic void	bwn_phy_lp_bbinit_r2(struct bwn_mac *);
485203945Sweongyostatic void	bwn_phy_lp_bbinit_r01(struct bwn_mac *);
486203945Sweongyostatic void	bwn_phy_lp_b2062_init(struct bwn_mac *);
487203945Sweongyostatic void	bwn_phy_lp_b2063_init(struct bwn_mac *);
488203945Sweongyostatic void	bwn_phy_lp_rxcal_r2(struct bwn_mac *);
489203945Sweongyostatic void	bwn_phy_lp_rccal_r12(struct bwn_mac *);
490203945Sweongyostatic void	bwn_phy_lp_set_rccap(struct bwn_mac *);
491203945Sweongyostatic uint32_t	bwn_phy_lp_roundup(uint32_t, uint32_t, uint8_t);
492203945Sweongyostatic void	bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *);
493203945Sweongyostatic void	bwn_phy_lp_b2062_vco_calib(struct bwn_mac *);
494203945Sweongyostatic void	bwn_tab_write_multi(struct bwn_mac *, uint32_t, int,
495203945Sweongyo		    const void *);
496203945Sweongyostatic void	bwn_tab_read_multi(struct bwn_mac *, uint32_t, int, void *);
497203945Sweongyostatic struct bwn_txgain
498203945Sweongyo		bwn_phy_lp_get_txgain(struct bwn_mac *);
499203945Sweongyostatic uint8_t	bwn_phy_lp_get_bbmult(struct bwn_mac *);
500203945Sweongyostatic void	bwn_phy_lp_set_txgain(struct bwn_mac *, struct bwn_txgain *);
501203945Sweongyostatic void	bwn_phy_lp_set_bbmult(struct bwn_mac *, uint8_t);
502203945Sweongyostatic void	bwn_phy_lp_set_trsw_over(struct bwn_mac *, uint8_t, uint8_t);
503203945Sweongyostatic void	bwn_phy_lp_set_rxgain(struct bwn_mac *, uint32_t);
504203945Sweongyostatic void	bwn_phy_lp_set_deaf(struct bwn_mac *, uint8_t);
505203945Sweongyostatic int	bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *, uint16_t);
506203945Sweongyostatic void	bwn_phy_lp_clear_deaf(struct bwn_mac *, uint8_t);
507203945Sweongyostatic void	bwn_phy_lp_tblinit_r01(struct bwn_mac *);
508203945Sweongyostatic void	bwn_phy_lp_tblinit_r2(struct bwn_mac *);
509203945Sweongyostatic void	bwn_phy_lp_tblinit_txgain(struct bwn_mac *);
510203945Sweongyostatic void	bwn_tab_write(struct bwn_mac *, uint32_t, uint32_t);
511203945Sweongyostatic void	bwn_phy_lp_b2062_tblinit(struct bwn_mac *);
512203945Sweongyostatic void	bwn_phy_lp_b2063_tblinit(struct bwn_mac *);
513203945Sweongyostatic int	bwn_phy_lp_loopback(struct bwn_mac *);
514203945Sweongyostatic void	bwn_phy_lp_set_rxgain_idx(struct bwn_mac *, uint16_t);
515203945Sweongyostatic void	bwn_phy_lp_ddfs_turnon(struct bwn_mac *, int, int, int, int,
516203945Sweongyo		    int);
517203945Sweongyostatic uint8_t	bwn_phy_lp_rx_iq_est(struct bwn_mac *, uint16_t, uint8_t,
518203945Sweongyo		    struct bwn_phy_lp_iq_est *);
519203945Sweongyostatic void	bwn_phy_lp_ddfs_turnoff(struct bwn_mac *);
520203945Sweongyostatic uint32_t	bwn_tab_read(struct bwn_mac *, uint32_t);
521203945Sweongyostatic void	bwn_phy_lp_set_txgain_dac(struct bwn_mac *, uint16_t);
522203945Sweongyostatic void	bwn_phy_lp_set_txgain_pa(struct bwn_mac *, uint16_t);
523203945Sweongyostatic void	bwn_phy_lp_set_txgain_override(struct bwn_mac *);
524203945Sweongyostatic uint16_t	bwn_phy_lp_get_pa_gain(struct bwn_mac *);
525203945Sweongyostatic uint8_t	bwn_nbits(int32_t);
526203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *, int, int,
527203945Sweongyo		    struct bwn_txgain_entry *);
528203945Sweongyostatic void	bwn_phy_lp_gaintbl_write(struct bwn_mac *, int,
529203945Sweongyo		    struct bwn_txgain_entry);
530203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
531203945Sweongyo		    struct bwn_txgain_entry);
532203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
533203945Sweongyo		    struct bwn_txgain_entry);
534204257Sweongyostatic void	bwn_sysctl_node(struct bwn_softc *);
535203945Sweongyo
536203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
537203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
538203945Sweongyo	{ -1,			0,		0 }
539203945Sweongyo};
540203945Sweongyo
541203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
542203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
543203945Sweongyo	{ -1,			0,		0 }
544203945Sweongyo};
545203945Sweongyo
546203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
547203945Sweongyo	.channels = {
548203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
549203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
550203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
551203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
552203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
553203945Sweongyo	.nchannels = 14
554203945Sweongyo};
555203945Sweongyo
556203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
557203945Sweongyo	.channels = {
558203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
559203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
560203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
561203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
562203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
563203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
564203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
565203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
566203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
567203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
568203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
569203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
570203945Sweongyo		{ 6080, 216, 30 } },
571203945Sweongyo	.nchannels = 37
572203945Sweongyo};
573203945Sweongyo
574203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
575203945Sweongyo	.channels = {
576203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
577203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
578203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
579203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
580203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
581203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
582203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
583203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
584203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
585203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
586203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
587203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
588203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
589203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
590203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
591203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
592203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
593203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
594203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
595203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
596203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
597203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
598203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
599203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
600203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
601203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
602203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
603203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
604203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
605203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
606203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
607203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
608203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
609203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
610203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
611203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
612203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
613203945Sweongyo	.nchannels = 110
614203945Sweongyo};
615203945Sweongyo
616203945Sweongyostatic const uint8_t bwn_b2063_chantable_data[33][12] = {
617203945Sweongyo	{ 0x6f, 0x3c, 0x3c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
618203945Sweongyo	{ 0x6f, 0x2c, 0x2c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
619203945Sweongyo	{ 0x6f, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
620203945Sweongyo	{ 0x6e, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
621203945Sweongyo	{ 0x6e, 0xc, 0xc, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
622203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x2, 0x5, 0xd, 0xd, 0x77, 0x80, 0x20, 0 },
623203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x5, 0xd, 0xc, 0x77, 0x80, 0x20, 0 },
624203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x80, 0x20, 0 },
625203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x70, 0x20, 0 },
626203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xb, 0xc, 0x77, 0x70, 0x20, 0 },
627203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x4, 0xb, 0xb, 0x77, 0x60, 0x20, 0 },
628203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xb, 0x77, 0x60, 0x20, 0 },
629203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xa, 0x77, 0x60, 0x20, 0 },
630203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x2, 0x9, 0x9, 0x77, 0x60, 0x20, 0 },
631203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x1, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
632203945Sweongyo	{ 0x67, 0xc, 0xc, 0, 0, 0, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
633203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x2, 0x1, 0x77, 0x20, 0, 0 },
634203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x1, 0x1, 0x77, 0x20, 0, 0 },
635203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0x1, 0, 0x77, 0x10, 0, 0 },
636203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
637203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
638203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
639203945Sweongyo	{ 0x61, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
640203945Sweongyo	{ 0x60, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
641203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xe, 0xf, 0xf, 0x77, 0xc0, 0x50, 0 },
642203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xd, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
643203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
644203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
645203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xb, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
646203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xa, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
647203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x7, 0x9, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
648203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x6, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
649203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x5, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 }
650203945Sweongyo};
651203945Sweongyo
652203945Sweongyostatic const struct bwn_b206x_chan bwn_b2063_chantable[] = {
653203945Sweongyo	{ 1, 2412, bwn_b2063_chantable_data[0] },
654203945Sweongyo	{ 2, 2417, bwn_b2063_chantable_data[0] },
655203945Sweongyo	{ 3, 2422, bwn_b2063_chantable_data[0] },
656203945Sweongyo	{ 4, 2427, bwn_b2063_chantable_data[1] },
657203945Sweongyo	{ 5, 2432, bwn_b2063_chantable_data[1] },
658203945Sweongyo	{ 6, 2437, bwn_b2063_chantable_data[1] },
659203945Sweongyo	{ 7, 2442, bwn_b2063_chantable_data[1] },
660203945Sweongyo	{ 8, 2447, bwn_b2063_chantable_data[1] },
661203945Sweongyo	{ 9, 2452, bwn_b2063_chantable_data[2] },
662203945Sweongyo	{ 10, 2457, bwn_b2063_chantable_data[2] },
663203945Sweongyo	{ 11, 2462, bwn_b2063_chantable_data[3] },
664203945Sweongyo	{ 12, 2467, bwn_b2063_chantable_data[3] },
665203945Sweongyo	{ 13, 2472, bwn_b2063_chantable_data[3] },
666203945Sweongyo	{ 14, 2484, bwn_b2063_chantable_data[4] },
667203945Sweongyo	{ 34, 5170, bwn_b2063_chantable_data[5] },
668203945Sweongyo	{ 36, 5180, bwn_b2063_chantable_data[6] },
669203945Sweongyo	{ 38, 5190, bwn_b2063_chantable_data[7] },
670203945Sweongyo	{ 40, 5200, bwn_b2063_chantable_data[8] },
671203945Sweongyo	{ 42, 5210, bwn_b2063_chantable_data[9] },
672203945Sweongyo	{ 44, 5220, bwn_b2063_chantable_data[10] },
673203945Sweongyo	{ 46, 5230, bwn_b2063_chantable_data[11] },
674203945Sweongyo	{ 48, 5240, bwn_b2063_chantable_data[12] },
675203945Sweongyo	{ 52, 5260, bwn_b2063_chantable_data[13] },
676203945Sweongyo	{ 56, 5280, bwn_b2063_chantable_data[14] },
677203945Sweongyo	{ 60, 5300, bwn_b2063_chantable_data[14] },
678203945Sweongyo	{ 64, 5320, bwn_b2063_chantable_data[15] },
679203945Sweongyo	{ 100, 5500, bwn_b2063_chantable_data[16] },
680203945Sweongyo	{ 104, 5520, bwn_b2063_chantable_data[17] },
681203945Sweongyo	{ 108, 5540, bwn_b2063_chantable_data[18] },
682203945Sweongyo	{ 112, 5560, bwn_b2063_chantable_data[19] },
683203945Sweongyo	{ 116, 5580, bwn_b2063_chantable_data[20] },
684203945Sweongyo	{ 120, 5600, bwn_b2063_chantable_data[21] },
685203945Sweongyo	{ 124, 5620, bwn_b2063_chantable_data[21] },
686203945Sweongyo	{ 128, 5640, bwn_b2063_chantable_data[22] },
687203945Sweongyo	{ 132, 5660, bwn_b2063_chantable_data[22] },
688203945Sweongyo	{ 136, 5680, bwn_b2063_chantable_data[22] },
689203945Sweongyo	{ 140, 5700, bwn_b2063_chantable_data[23] },
690203945Sweongyo	{ 149, 5745, bwn_b2063_chantable_data[23] },
691203945Sweongyo	{ 153, 5765, bwn_b2063_chantable_data[23] },
692203945Sweongyo	{ 157, 5785, bwn_b2063_chantable_data[23] },
693203945Sweongyo	{ 161, 5805, bwn_b2063_chantable_data[23] },
694203945Sweongyo	{ 165, 5825, bwn_b2063_chantable_data[23] },
695203945Sweongyo	{ 184, 4920, bwn_b2063_chantable_data[24] },
696203945Sweongyo	{ 188, 4940, bwn_b2063_chantable_data[25] },
697203945Sweongyo	{ 192, 4960, bwn_b2063_chantable_data[26] },
698203945Sweongyo	{ 196, 4980, bwn_b2063_chantable_data[27] },
699203945Sweongyo	{ 200, 5000, bwn_b2063_chantable_data[28] },
700203945Sweongyo	{ 204, 5020, bwn_b2063_chantable_data[29] },
701203945Sweongyo	{ 208, 5040, bwn_b2063_chantable_data[30] },
702203945Sweongyo	{ 212, 5060, bwn_b2063_chantable_data[31] },
703203945Sweongyo	{ 216, 5080, bwn_b2063_chantable_data[32] }
704203945Sweongyo};
705203945Sweongyo
706203945Sweongyostatic const uint8_t bwn_b2062_chantable_data[22][12] = {
707203945Sweongyo	{ 0xff, 0xff, 0xb5, 0x1b, 0x24, 0x32, 0x32, 0x88, 0x88, 0, 0, 0 },
708203945Sweongyo	{ 0, 0x22, 0x20, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
709203945Sweongyo	{ 0, 0x11, 0x10, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
710203945Sweongyo	{ 0, 0, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
711203945Sweongyo	{ 0, 0x11, 0x20, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
712203945Sweongyo	{ 0, 0x11, 0x10, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
713203945Sweongyo	{ 0, 0x11, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
714203945Sweongyo	{ 0, 0, 0, 0x63, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
715203945Sweongyo	{ 0, 0, 0, 0x62, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
716203945Sweongyo	{ 0, 0, 0, 0x30, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
717203945Sweongyo	{ 0, 0, 0, 0x20, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
718203945Sweongyo	{ 0, 0, 0, 0x10, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
719203945Sweongyo	{ 0, 0, 0, 0, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
720203945Sweongyo	{ 0x55, 0x77, 0x90, 0xf7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
721203945Sweongyo	{ 0x44, 0x77, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
722203945Sweongyo	{ 0x44, 0x66, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
723203945Sweongyo	{ 0x33, 0x66, 0x70, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
724203945Sweongyo	{ 0x22, 0x55, 0x60, 0xd7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
725203945Sweongyo	{ 0x22, 0x55, 0x60, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
726203945Sweongyo	{ 0x22, 0x44, 0x50, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
727203945Sweongyo	{ 0x11, 0x44, 0x50, 0xa5, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
728203945Sweongyo	{ 0, 0x44, 0x40, 0xb6, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 }
729203945Sweongyo};
730203945Sweongyo
731203945Sweongyostatic const struct bwn_b206x_chan bwn_b2062_chantable[] = {
732203945Sweongyo	{ 1, 2412, bwn_b2062_chantable_data[0] },
733203945Sweongyo	{ 2, 2417, bwn_b2062_chantable_data[0] },
734203945Sweongyo	{ 3, 2422, bwn_b2062_chantable_data[0] },
735203945Sweongyo	{ 4, 2427, bwn_b2062_chantable_data[0] },
736203945Sweongyo	{ 5, 2432, bwn_b2062_chantable_data[0] },
737203945Sweongyo	{ 6, 2437, bwn_b2062_chantable_data[0] },
738203945Sweongyo	{ 7, 2442, bwn_b2062_chantable_data[0] },
739203945Sweongyo	{ 8, 2447, bwn_b2062_chantable_data[0] },
740203945Sweongyo	{ 9, 2452, bwn_b2062_chantable_data[0] },
741203945Sweongyo	{ 10, 2457, bwn_b2062_chantable_data[0] },
742203945Sweongyo	{ 11, 2462, bwn_b2062_chantable_data[0] },
743203945Sweongyo	{ 12, 2467, bwn_b2062_chantable_data[0] },
744203945Sweongyo	{ 13, 2472, bwn_b2062_chantable_data[0] },
745203945Sweongyo	{ 14, 2484, bwn_b2062_chantable_data[0] },
746203945Sweongyo	{ 34, 5170, bwn_b2062_chantable_data[1] },
747203945Sweongyo	{ 38, 5190, bwn_b2062_chantable_data[2] },
748203945Sweongyo	{ 42, 5210, bwn_b2062_chantable_data[2] },
749203945Sweongyo	{ 46, 5230, bwn_b2062_chantable_data[3] },
750203945Sweongyo	{ 36, 5180, bwn_b2062_chantable_data[4] },
751203945Sweongyo	{ 40, 5200, bwn_b2062_chantable_data[5] },
752203945Sweongyo	{ 44, 5220, bwn_b2062_chantable_data[6] },
753203945Sweongyo	{ 48, 5240, bwn_b2062_chantable_data[3] },
754203945Sweongyo	{ 52, 5260, bwn_b2062_chantable_data[3] },
755203945Sweongyo	{ 56, 5280, bwn_b2062_chantable_data[3] },
756203945Sweongyo	{ 60, 5300, bwn_b2062_chantable_data[7] },
757203945Sweongyo	{ 64, 5320, bwn_b2062_chantable_data[8] },
758203945Sweongyo	{ 100, 5500, bwn_b2062_chantable_data[9] },
759203945Sweongyo	{ 104, 5520, bwn_b2062_chantable_data[10] },
760203945Sweongyo	{ 108, 5540, bwn_b2062_chantable_data[10] },
761203945Sweongyo	{ 112, 5560, bwn_b2062_chantable_data[10] },
762203945Sweongyo	{ 116, 5580, bwn_b2062_chantable_data[11] },
763203945Sweongyo	{ 120, 5600, bwn_b2062_chantable_data[12] },
764203945Sweongyo	{ 124, 5620, bwn_b2062_chantable_data[12] },
765203945Sweongyo	{ 128, 5640, bwn_b2062_chantable_data[12] },
766203945Sweongyo	{ 132, 5660, bwn_b2062_chantable_data[12] },
767203945Sweongyo	{ 136, 5680, bwn_b2062_chantable_data[12] },
768203945Sweongyo	{ 140, 5700, bwn_b2062_chantable_data[12] },
769203945Sweongyo	{ 149, 5745, bwn_b2062_chantable_data[12] },
770203945Sweongyo	{ 153, 5765, bwn_b2062_chantable_data[12] },
771203945Sweongyo	{ 157, 5785, bwn_b2062_chantable_data[12] },
772203945Sweongyo	{ 161, 5805, bwn_b2062_chantable_data[12] },
773203945Sweongyo	{ 165, 5825, bwn_b2062_chantable_data[12] },
774203945Sweongyo	{ 184, 4920, bwn_b2062_chantable_data[13] },
775203945Sweongyo	{ 188, 4940, bwn_b2062_chantable_data[14] },
776203945Sweongyo	{ 192, 4960, bwn_b2062_chantable_data[15] },
777203945Sweongyo	{ 196, 4980, bwn_b2062_chantable_data[16] },
778203945Sweongyo	{ 200, 5000, bwn_b2062_chantable_data[17] },
779203945Sweongyo	{ 204, 5020, bwn_b2062_chantable_data[18] },
780203945Sweongyo	{ 208, 5040, bwn_b2062_chantable_data[19] },
781203945Sweongyo	{ 212, 5060, bwn_b2062_chantable_data[20] },
782203945Sweongyo	{ 216, 5080, bwn_b2062_chantable_data[21] }
783203945Sweongyo};
784203945Sweongyo
785203945Sweongyo/* for LP PHY */
786203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_5354[] = {
787203945Sweongyo	{  1, -66, 15 }, {  2, -66, 15 }, {  3, -66, 15 }, {  4, -66, 15 },
788203945Sweongyo	{  5, -66, 15 }, {  6, -66, 15 }, {  7, -66, 14 }, {  8, -66, 14 },
789203945Sweongyo	{  9, -66, 14 }, { 10, -66, 14 }, { 11, -66, 14 }, { 12, -66, 13 },
790203945Sweongyo	{ 13, -66, 13 }, { 14, -66, 13 },
791203945Sweongyo};
792203945Sweongyo
793203945Sweongyo/* for LP PHY */
794203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r12[] = {
795203945Sweongyo	{   1, -64, 13 }, {   2, -64, 13 }, {   3, -64, 13 }, {   4, -64, 13 },
796203945Sweongyo	{   5, -64, 12 }, {   6, -64, 12 }, {   7, -64, 12 }, {   8, -64, 12 },
797203945Sweongyo	{   9, -64, 12 }, {  10, -64, 11 }, {  11, -64, 11 }, {  12, -64, 11 },
798203945Sweongyo	{  13, -64, 11 }, {  14, -64, 10 }, {  34, -62, 24 }, {  38, -62, 24 },
799203945Sweongyo	{  42, -62, 24 }, {  46, -62, 23 }, {  36, -62, 24 }, {  40, -62, 24 },
800203945Sweongyo	{  44, -62, 23 }, {  48, -62, 23 }, {  52, -62, 23 }, {  56, -62, 22 },
801203945Sweongyo	{  60, -62, 22 }, {  64, -62, 22 }, { 100, -62, 16 }, { 104, -62, 16 },
802203945Sweongyo	{ 108, -62, 15 }, { 112, -62, 14 }, { 116, -62, 14 }, { 120, -62, 13 },
803203945Sweongyo	{ 124, -62, 12 }, { 128, -62, 12 }, { 132, -62, 12 }, { 136, -62, 11 },
804203945Sweongyo	{ 140, -62, 10 }, { 149, -61,  9 }, { 153, -61,  9 }, { 157, -61,  9 },
805203945Sweongyo	{ 161, -61,  8 }, { 165, -61,  8 }, { 184, -62, 25 }, { 188, -62, 25 },
806203945Sweongyo	{ 192, -62, 25 }, { 196, -62, 25 }, { 200, -62, 25 }, { 204, -62, 25 },
807203945Sweongyo	{ 208, -62, 25 }, { 212, -62, 25 }, { 216, -62, 26 },
808203945Sweongyo};
809203945Sweongyo
810203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r2 = { 0, -64, 0 };
811203945Sweongyo
812203945Sweongyostatic const uint8_t bwn_tab_sigsq_tbl[] = {
813203945Sweongyo	0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
814203945Sweongyo	0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
815203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
816203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
817203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
818203945Sweongyo	0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
819203945Sweongyo};
820203945Sweongyo
821203945Sweongyostatic const uint8_t bwn_tab_pllfrac_tbl[] = {
822203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
823203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
824203945Sweongyo};
825203945Sweongyo
826203945Sweongyostatic const uint16_t bwn_tabl_iqlocal_tbl[] = {
827203945Sweongyo	0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
828203945Sweongyo	0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
829203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
830203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
831203945Sweongyo	0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
832203945Sweongyo	0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 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, 0x0000, 0x0000, 0x0000,
836203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
837203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
838203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
839203945Sweongyo};
840203945Sweongyo
841203945Sweongyostatic const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
842203945Sweongyostatic const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
843203945Sweongyostatic const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
844203945Sweongyostatic const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
845203945Sweongyostatic const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
846203945Sweongyoconst uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
847203945Sweongyo
848203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
849203945Sweongyo{							\
850203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
851203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
852203945Sweongyo}
853203945Sweongyo
854203945Sweongyostatic const struct {
855203945Sweongyo	uint16_t	vid;
856203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
857203945Sweongyo} bwn_vendor_led_act[] = {
858203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
859203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
860203945Sweongyo};
861203945Sweongyo
862203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
863203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
864203945Sweongyo
865203945Sweongyo#undef VENDOR_LED_ACT
866203945Sweongyo
867203945Sweongyostatic const struct {
868203945Sweongyo	int		on_dur;
869203945Sweongyo	int		off_dur;
870203945Sweongyo} bwn_led_duration[109] = {
871203945Sweongyo	[0]	= { 400, 100 },
872203945Sweongyo	[2]	= { 150, 75 },
873203945Sweongyo	[4]	= { 90, 45 },
874203945Sweongyo	[11]	= { 66, 34 },
875203945Sweongyo	[12]	= { 53, 26 },
876203945Sweongyo	[18]	= { 42, 21 },
877203945Sweongyo	[22]	= { 35, 17 },
878203945Sweongyo	[24]	= { 32, 16 },
879203945Sweongyo	[36]	= { 21, 10 },
880203945Sweongyo	[48]	= { 16, 8 },
881203945Sweongyo	[72]	= { 11, 5 },
882203945Sweongyo	[96]	= { 9, 4 },
883203945Sweongyo	[108]	= { 7, 3 }
884203945Sweongyo};
885203945Sweongyo
886203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
887203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
888203945Sweongyo	[1] = BWN_WME_BACKGROUND,
889203945Sweongyo	[2] = BWN_WME_VOICE,
890203945Sweongyo	[3] = BWN_WME_VIDEO,
891203945Sweongyo};
892203945Sweongyo
893203945Sweongyostatic const struct siba_devid bwn_devs[] = {
894203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
895203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
896203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
897203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
898203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
899203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
900203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
901203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
902203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
903203945Sweongyo};
904203945Sweongyo
905203945Sweongyostatic int
906203945Sweongyobwn_probe(device_t dev)
907203945Sweongyo{
908203945Sweongyo	int i;
909203945Sweongyo
910203945Sweongyo	for (i = 0; i < sizeof(bwn_devs) / sizeof(bwn_devs[0]); i++) {
911204922Sweongyo		if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor &&
912204922Sweongyo		    siba_get_device(dev) == bwn_devs[i].sd_device &&
913204922Sweongyo		    siba_get_revid(dev) == bwn_devs[i].sd_rev)
914203945Sweongyo			return (BUS_PROBE_DEFAULT);
915203945Sweongyo	}
916203945Sweongyo
917203945Sweongyo	return (ENXIO);
918203945Sweongyo}
919203945Sweongyo
920203945Sweongyostatic int
921203945Sweongyobwn_attach(device_t dev)
922203945Sweongyo{
923203945Sweongyo	struct bwn_mac *mac;
924203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
925203945Sweongyo	int error, i, msic, reg;
926203945Sweongyo
927203945Sweongyo	sc->sc_dev = dev;
928203945Sweongyo#ifdef BWN_DEBUG
929203945Sweongyo	sc->sc_debug = bwn_debug;
930203945Sweongyo#endif
931203945Sweongyo
932203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
933203945Sweongyo		error = bwn_attach_pre(sc);
934203945Sweongyo		if (error != 0)
935203945Sweongyo			return (error);
936204922Sweongyo		bwn_sprom_bugfixes(dev);
937203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
938203945Sweongyo	}
939203945Sweongyo
940203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
941204922Sweongyo		if (siba_get_pci_device(dev) != 0x4313 &&
942204922Sweongyo		    siba_get_pci_device(dev) != 0x431a &&
943204922Sweongyo		    siba_get_pci_device(dev) != 0x4321) {
944203945Sweongyo			device_printf(sc->sc_dev,
945203945Sweongyo			    "skip 802.11 cores\n");
946203945Sweongyo			return (ENODEV);
947203945Sweongyo		}
948203945Sweongyo	}
949203945Sweongyo
950203945Sweongyo	mac = (struct bwn_mac *)malloc(sizeof(*mac), M_DEVBUF,
951203945Sweongyo	    M_NOWAIT | M_ZERO);
952203945Sweongyo	if (mac == NULL)
953203945Sweongyo		return (ENOMEM);
954203945Sweongyo	mac->mac_sc = sc;
955203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
956203945Sweongyo	if (bwn_bfp != 0)
957203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
958203945Sweongyo
959203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
960203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
961203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
962203945Sweongyo
963203945Sweongyo	error = bwn_attach_core(mac);
964203945Sweongyo	if (error)
965203945Sweongyo		goto fail0;
966203945Sweongyo	bwn_led_attach(mac);
967203945Sweongyo
968203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
969203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
970204922Sweongyo	    siba_get_chipid(sc->sc_dev), siba_get_revid(sc->sc_dev),
971203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
972203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
973203945Sweongyo	    mac->mac_phy.rf_rev);
974203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
975203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
976203945Sweongyo		    mac->mac_method.dma.dmatype);
977203945Sweongyo	else
978203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
979203945Sweongyo
980203945Sweongyo	/*
981203945Sweongyo	 * setup PCI resources and interrupt.
982203945Sweongyo	 */
983219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
984203945Sweongyo		msic = pci_msi_count(dev);
985203945Sweongyo		if (bootverbose)
986203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
987203945Sweongyo	} else
988203945Sweongyo		msic = 0;
989203945Sweongyo
990203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
991203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
992203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
993203945Sweongyo			device_printf(sc->sc_dev,
994203945Sweongyo			    "Using %d MSI messages\n", msic);
995203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
996203945Sweongyo			mac->mac_msi = 1;
997203945Sweongyo		}
998203945Sweongyo	}
999203945Sweongyo
1000203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
1001203945Sweongyo	    mac->mac_res_irq);
1002203945Sweongyo	if (error) {
1003203945Sweongyo		device_printf(sc->sc_dev,
1004203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
1005203945Sweongyo		goto fail1;
1006203945Sweongyo	}
1007203945Sweongyo
1008203945Sweongyo	if (mac->mac_msi == 0)
1009203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
1010203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1011203945Sweongyo		    &mac->mac_intrhand[0]);
1012203945Sweongyo	else {
1013203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1014203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
1015203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1016203945Sweongyo			    &mac->mac_intrhand[i]);
1017203945Sweongyo			if (error != 0) {
1018203945Sweongyo				device_printf(sc->sc_dev,
1019203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
1020203945Sweongyo				break;
1021203945Sweongyo			}
1022203945Sweongyo		}
1023203945Sweongyo	}
1024203945Sweongyo
1025203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
1026203945Sweongyo
1027203945Sweongyo	/*
1028203945Sweongyo	 * calls attach-post routine
1029203945Sweongyo	 */
1030203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
1031203945Sweongyo		bwn_attach_post(sc);
1032203945Sweongyo
1033203945Sweongyo	return (0);
1034203945Sweongyofail1:
1035203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
1036203945Sweongyo		pci_release_msi(dev);
1037203945Sweongyofail0:
1038203945Sweongyo	free(mac, M_DEVBUF);
1039203945Sweongyo	return (error);
1040203945Sweongyo}
1041203945Sweongyo
1042203945Sweongyostatic int
1043203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
1044203945Sweongyo{
1045203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
1046203945Sweongyo
1047203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
1048203945Sweongyo		return (FALSE);
1049203945Sweongyo
1050203945Sweongyo	return (TRUE);
1051203945Sweongyo}
1052203945Sweongyo
1053203945Sweongyostatic int
1054203945Sweongyobwn_attach_post(struct bwn_softc *sc)
1055203945Sweongyo{
1056203945Sweongyo	struct ieee80211com *ic;
1057203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1058203945Sweongyo
1059203945Sweongyo	ic = ifp->if_l2com;
1060203945Sweongyo	ic->ic_ifp = ifp;
1061283527Sglebius	ic->ic_name = device_get_nameunit(sc->sc_dev);
1062203945Sweongyo	/* XXX not right but it's not used anywhere important */
1063203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
1064203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
1065203945Sweongyo	ic->ic_caps =
1066203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
1067203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
1068204436Sweongyo		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
1069203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
1070203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
1071203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
1072203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
1073203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
1074203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
1075203945Sweongyo		;
1076203945Sweongyo
1077205141Sweongyo	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;	/* s/w bmiss */
1078205141Sweongyo
1079203945Sweongyo	/* call MI attach routine. */
1080203945Sweongyo	ieee80211_ifattach(ic,
1081204922Sweongyo	    bwn_is_valid_ether_addr(siba_sprom_get_mac_80211a(sc->sc_dev)) ?
1082204922Sweongyo	    siba_sprom_get_mac_80211a(sc->sc_dev) :
1083204922Sweongyo	    siba_sprom_get_mac_80211bg(sc->sc_dev));
1084203945Sweongyo
1085203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
1086203945Sweongyo
1087203945Sweongyo	/* override default methods */
1088203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
1089203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
1090203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
1091203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
1092203945Sweongyo
1093203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
1094203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
1095203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
1096203945Sweongyo
1097203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
1098203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
1099203945Sweongyo
1100203945Sweongyo	ieee80211_radiotap_attach(ic,
1101203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
1102203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
1103203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
1104203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
1105203945Sweongyo
1106204257Sweongyo	bwn_sysctl_node(sc);
1107203945Sweongyo
1108203945Sweongyo	if (bootverbose)
1109203945Sweongyo		ieee80211_announce(ic);
1110203945Sweongyo	return (0);
1111203945Sweongyo}
1112203945Sweongyo
1113203945Sweongyostatic void
1114203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
1115203945Sweongyo{
1116203945Sweongyo
1117203945Sweongyo	if (mac->mac_phy.detach != NULL)
1118203945Sweongyo		mac->mac_phy.detach(mac);
1119203945Sweongyo}
1120203945Sweongyo
1121203945Sweongyostatic int
1122203945Sweongyobwn_detach(device_t dev)
1123203945Sweongyo{
1124203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
1125203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1126203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1127203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1128203945Sweongyo	int i;
1129203945Sweongyo
1130203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
1131203945Sweongyo
1132203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
1133203945Sweongyo		bwn_stop(sc, 1);
1134203945Sweongyo		bwn_dma_free(mac);
1135203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
1136203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
1137203945Sweongyo		callout_drain(&sc->sc_task_ch);
1138203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
1139203945Sweongyo		bwn_phy_detach(mac);
1140203945Sweongyo		if (ifp != NULL) {
1141203945Sweongyo			ieee80211_draintask(ic, &mac->mac_hwreset);
1142203945Sweongyo			ieee80211_draintask(ic, &mac->mac_txpower);
1143203945Sweongyo			ieee80211_ifdetach(ic);
1144203945Sweongyo			if_free(ifp);
1145203945Sweongyo		}
1146203945Sweongyo	}
1147203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
1148203945Sweongyo	taskqueue_free(sc->sc_tq);
1149203945Sweongyo
1150203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1151203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
1152203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
1153203945Sweongyo			    mac->mac_intrhand[i]);
1154203945Sweongyo			mac->mac_intrhand[i] = NULL;
1155203945Sweongyo		}
1156203945Sweongyo	}
1157203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
1158203945Sweongyo	if (mac->mac_msi != 0)
1159203945Sweongyo		pci_release_msi(dev);
1160203945Sweongyo
1161203945Sweongyo	BWN_LOCK_DESTROY(sc);
1162203945Sweongyo	return (0);
1163203945Sweongyo}
1164203945Sweongyo
1165203945Sweongyostatic int
1166203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
1167203945Sweongyo{
1168203945Sweongyo	struct ifnet *ifp;
1169203945Sweongyo	int error = 0;
1170203945Sweongyo
1171203945Sweongyo	BWN_LOCK_INIT(sc);
1172203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
1173203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
1174203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
1175203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
1176203945Sweongyo
1177203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
1178203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
1179203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
1180203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
1181203945Sweongyo
1182203945Sweongyo	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
1183203945Sweongyo	if (ifp == NULL) {
1184203945Sweongyo		device_printf(sc->sc_dev, "can not if_alloc()\n");
1185203945Sweongyo		error = ENOSPC;
1186203945Sweongyo		goto fail;
1187203945Sweongyo	}
1188203945Sweongyo
1189203945Sweongyo	/* set these up early for if_printf use */
1190203945Sweongyo	if_initname(ifp, device_get_name(sc->sc_dev),
1191203945Sweongyo	    device_get_unit(sc->sc_dev));
1192203945Sweongyo
1193203945Sweongyo	ifp->if_softc = sc;
1194203945Sweongyo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1195203945Sweongyo	ifp->if_init = bwn_init;
1196203945Sweongyo	ifp->if_ioctl = bwn_ioctl;
1197203945Sweongyo	ifp->if_start = bwn_start;
1198207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
1199207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
1200203945Sweongyo	IFQ_SET_READY(&ifp->if_snd);
1201203945Sweongyo
1202203945Sweongyo	return (0);
1203203945Sweongyo
1204203945Sweongyofail:	BWN_LOCK_DESTROY(sc);
1205203945Sweongyo	return (error);
1206203945Sweongyo}
1207203945Sweongyo
1208203945Sweongyostatic void
1209204922Sweongyobwn_sprom_bugfixes(device_t dev)
1210203945Sweongyo{
1211203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
1212204922Sweongyo	((siba_get_pci_vendor(dev) == PCI_VENDOR_##_vendor) &&		\
1213204922Sweongyo	 (siba_get_pci_device(dev) == _device) &&			\
1214204922Sweongyo	 (siba_get_pci_subvendor(dev) == PCI_VENDOR_##_subvendor) &&	\
1215204922Sweongyo	 (siba_get_pci_subdevice(dev) == _subdevice))
1216203945Sweongyo
1217204922Sweongyo	if (siba_get_pci_subvendor(dev) == PCI_VENDOR_APPLE &&
1218204922Sweongyo	    siba_get_pci_subdevice(dev) == 0x4e &&
1219204922Sweongyo	    siba_get_pci_revid(dev) > 0x40)
1220204922Sweongyo		siba_sprom_set_bf_lo(dev,
1221204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_PACTRL);
1222204922Sweongyo	if (siba_get_pci_subvendor(dev) == SIBA_BOARDVENDOR_DELL &&
1223204922Sweongyo	    siba_get_chipid(dev) == 0x4301 && siba_get_pci_revid(dev) == 0x74)
1224204922Sweongyo		siba_sprom_set_bf_lo(dev,
1225204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_BTCOEXIST);
1226204922Sweongyo	if (siba_get_type(dev) == SIBA_TYPE_PCI) {
1227203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
1228203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
1229203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
1230203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
1231203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
1232203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
1233203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
1234204922Sweongyo			siba_sprom_set_bf_lo(dev,
1235204922Sweongyo			    siba_sprom_get_bf_lo(dev) & ~BWN_BFL_BTCOEXIST);
1236203945Sweongyo	}
1237203945Sweongyo#undef	BWN_ISDEV
1238203945Sweongyo}
1239203945Sweongyo
1240203945Sweongyostatic int
1241203945Sweongyobwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1242203945Sweongyo{
1243203945Sweongyo#define	IS_RUNNING(ifp) \
1244203945Sweongyo	((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
1245203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1246203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1247203945Sweongyo	struct ifreq *ifr = (struct ifreq *)data;
1248203945Sweongyo	int error = 0, startall;
1249203945Sweongyo
1250203945Sweongyo	switch (cmd) {
1251203945Sweongyo	case SIOCSIFFLAGS:
1252203945Sweongyo		startall = 0;
1253203945Sweongyo		if (IS_RUNNING(ifp)) {
1254203945Sweongyo			bwn_update_promisc(ifp);
1255203945Sweongyo		} else if (ifp->if_flags & IFF_UP) {
1256203945Sweongyo			if ((sc->sc_flags & BWN_FLAG_INVALID) == 0) {
1257203945Sweongyo				bwn_init(sc);
1258203945Sweongyo				startall = 1;
1259203945Sweongyo			}
1260203945Sweongyo		} else
1261203945Sweongyo			bwn_stop(sc, 1);
1262203945Sweongyo		if (startall)
1263203945Sweongyo			ieee80211_start_all(ic);
1264203945Sweongyo		break;
1265203945Sweongyo	case SIOCGIFMEDIA:
1266203945Sweongyo		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1267203945Sweongyo		break;
1268203945Sweongyo	case SIOCGIFADDR:
1269203945Sweongyo		error = ether_ioctl(ifp, cmd, data);
1270203945Sweongyo		break;
1271203945Sweongyo	default:
1272203945Sweongyo		error = EINVAL;
1273203945Sweongyo		break;
1274203945Sweongyo	}
1275203945Sweongyo	return (error);
1276203945Sweongyo}
1277203945Sweongyo
1278203945Sweongyostatic void
1279203945Sweongyobwn_start(struct ifnet *ifp)
1280203945Sweongyo{
1281203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1282203945Sweongyo
1283203945Sweongyo	BWN_LOCK(sc);
1284203945Sweongyo	bwn_start_locked(ifp);
1285203945Sweongyo	BWN_UNLOCK(sc);
1286203945Sweongyo}
1287203945Sweongyo
1288203945Sweongyostatic void
1289203945Sweongyobwn_start_locked(struct ifnet *ifp)
1290203945Sweongyo{
1291203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1292203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1293203945Sweongyo	struct ieee80211_frame *wh;
1294203945Sweongyo	struct ieee80211_node *ni;
1295203945Sweongyo	struct ieee80211_key *k;
1296203945Sweongyo	struct mbuf *m;
1297203945Sweongyo
1298203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1299203945Sweongyo
1300203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || mac == NULL ||
1301203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
1302203945Sweongyo		return;
1303203945Sweongyo
1304203945Sweongyo	for (;;) {
1305203945Sweongyo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);	/* XXX: LOCK */
1306203945Sweongyo		if (m == NULL)
1307203945Sweongyo			break;
1308203945Sweongyo
1309203945Sweongyo		if (bwn_tx_isfull(sc, m))
1310203945Sweongyo			break;
1311203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
1312203945Sweongyo		if (ni == NULL) {
1313203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
1314203945Sweongyo			m_freem(m);
1315271849Sglebius			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1316203945Sweongyo			continue;
1317203945Sweongyo		}
1318203945Sweongyo		KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__));
1319203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
1320260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
1321203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
1322203945Sweongyo			if (k == NULL) {
1323203945Sweongyo				ieee80211_free_node(ni);
1324203945Sweongyo				m_freem(m);
1325271849Sglebius				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1326203945Sweongyo				continue;
1327203945Sweongyo			}
1328203945Sweongyo		}
1329203945Sweongyo		wh = NULL;	/* Catch any invalid use */
1330203945Sweongyo
1331203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
1332203945Sweongyo			if (ni != NULL)
1333203945Sweongyo				ieee80211_free_node(ni);
1334271849Sglebius			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1335203945Sweongyo			continue;
1336203945Sweongyo		}
1337203945Sweongyo
1338203945Sweongyo		sc->sc_watchdog_timer = 5;
1339203945Sweongyo	}
1340203945Sweongyo}
1341203945Sweongyo
1342203945Sweongyostatic int
1343203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
1344203945Sweongyo{
1345203945Sweongyo	struct bwn_dma_ring *dr;
1346203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1347203945Sweongyo	struct bwn_pio_txqueue *tq;
1348203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1349203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1350203945Sweongyo
1351203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1352203945Sweongyo
1353203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
1354203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
1355203945Sweongyo		if (dr->dr_stop == 1 ||
1356203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
1357203945Sweongyo			dr->dr_stop = 1;
1358203945Sweongyo			goto full;
1359203945Sweongyo		}
1360203945Sweongyo	} else {
1361203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
1362203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
1363203945Sweongyo		    pktlen > (tq->tq_size - tq->tq_used)) {
1364203945Sweongyo			tq->tq_stop = 1;
1365203945Sweongyo			goto full;
1366203945Sweongyo		}
1367203945Sweongyo	}
1368203945Sweongyo	return (0);
1369203945Sweongyofull:
1370203945Sweongyo	IFQ_DRV_PREPEND(&ifp->if_snd, m);
1371203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1372203945Sweongyo	return (1);
1373203945Sweongyo}
1374203945Sweongyo
1375203945Sweongyostatic int
1376203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
1377203945Sweongyo{
1378203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1379203945Sweongyo	int error;
1380203945Sweongyo
1381203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1382203945Sweongyo
1383203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
1384203945Sweongyo		m_freem(m);
1385203945Sweongyo		return (ENXIO);
1386203945Sweongyo	}
1387203945Sweongyo
1388203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
1389203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
1390203945Sweongyo	if (error) {
1391203945Sweongyo		m_freem(m);
1392203945Sweongyo		return (error);
1393203945Sweongyo	}
1394203945Sweongyo	return (0);
1395203945Sweongyo}
1396203945Sweongyo
1397203945Sweongyostatic int
1398203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1399203945Sweongyo{
1400203945Sweongyo	struct bwn_pio_txpkt *tp;
1401203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
1402203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1403203945Sweongyo	struct bwn_txhdr txhdr;
1404203945Sweongyo	struct mbuf *m_new;
1405203945Sweongyo	uint32_t ctl32;
1406203945Sweongyo	int error;
1407203945Sweongyo	uint16_t ctl16;
1408203945Sweongyo
1409203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1410203945Sweongyo
1411203945Sweongyo	/* XXX TODO send packets after DTIM */
1412203945Sweongyo
1413203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
1414203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
1415203945Sweongyo	tp->tp_ni = ni;
1416203945Sweongyo	tp->tp_m = m;
1417203945Sweongyo
1418203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
1419203945Sweongyo	if (error) {
1420203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
1421203945Sweongyo		return (error);
1422203945Sweongyo	}
1423203945Sweongyo
1424203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
1425203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1426203945Sweongyo	tq->tq_free--;
1427203945Sweongyo
1428204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8) {
1429203945Sweongyo		/*
1430203945Sweongyo		 * XXX please removes m_defrag(9)
1431203945Sweongyo		 */
1432243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
1433203945Sweongyo		if (m_new == NULL) {
1434203945Sweongyo			device_printf(sc->sc_dev,
1435203945Sweongyo			    "%s: can't defrag TX buffer\n",
1436203945Sweongyo			    __func__);
1437203945Sweongyo			return (ENOBUFS);
1438203945Sweongyo		}
1439203945Sweongyo		if (m_new->m_next != NULL)
1440203945Sweongyo			device_printf(sc->sc_dev,
1441203945Sweongyo			    "TODO: fragmented packets for PIO\n");
1442203945Sweongyo		tp->tp_m = m_new;
1443203945Sweongyo
1444203945Sweongyo		/* send HEADER */
1445203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
1446203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
1447203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
1448203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1449203945Sweongyo		/* send BODY */
1450203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
1451203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
1452203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
1453203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
1454203945Sweongyo	} else {
1455203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
1456203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
1457203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
1458203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1459203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
1460203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
1461203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
1462203945Sweongyo	}
1463203945Sweongyo
1464203945Sweongyo	return (0);
1465203945Sweongyo}
1466203945Sweongyo
1467203945Sweongyostatic struct bwn_pio_txqueue *
1468203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1469203945Sweongyo{
1470203945Sweongyo
1471203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1472203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1473203945Sweongyo
1474203945Sweongyo	switch (prio) {
1475203945Sweongyo	case 0:
1476203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1477203945Sweongyo	case 1:
1478203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1479203945Sweongyo	case 2:
1480203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1481203945Sweongyo	case 3:
1482203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1483203945Sweongyo	}
1484203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1485204242Simp	return (NULL);
1486203945Sweongyo}
1487203945Sweongyo
1488203945Sweongyostatic int
1489203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1490203945Sweongyo{
1491203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1492203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1493203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1494203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1495203945Sweongyo	struct bwn_dmadesc_generic *desc;
1496203945Sweongyo	struct bwn_dmadesc_meta *mt;
1497203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1498203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1499203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1500203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1501203945Sweongyo
1502203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1503203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1504203945Sweongyo
1505203945Sweongyo	/* XXX send after DTIM */
1506203945Sweongyo
1507203945Sweongyo	slot = bwn_dma_getslot(dr);
1508203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1509203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1510203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1511203945Sweongyo
1512203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1513203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1514203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1515203945Sweongyo	if (error)
1516203945Sweongyo		goto fail;
1517203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1518203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1519203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1520203945Sweongyo	if (error) {
1521203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1522203945Sweongyo		    __func__, error);
1523203945Sweongyo		goto fail;
1524203945Sweongyo	}
1525203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1526203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1527203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1528203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1529203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1530203945Sweongyo
1531203945Sweongyo	slot = bwn_dma_getslot(dr);
1532203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1533203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1534203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1535203945Sweongyo	mt->mt_m = m;
1536203945Sweongyo	mt->mt_ni = ni;
1537203945Sweongyo
1538203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1539203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1540203945Sweongyo	if (error && error != EFBIG) {
1541203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1542203945Sweongyo		    __func__, error);
1543203945Sweongyo		goto fail;
1544203945Sweongyo	}
1545203945Sweongyo	if (error) {    /* error == EFBIG */
1546203945Sweongyo		struct mbuf *m_new;
1547203945Sweongyo
1548243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
1549203945Sweongyo		if (m_new == NULL) {
1550203945Sweongyo			if_printf(ifp, "%s: can't defrag TX buffer\n",
1551203945Sweongyo			    __func__);
1552203945Sweongyo			error = ENOBUFS;
1553203945Sweongyo			goto fail;
1554203945Sweongyo		} else {
1555203945Sweongyo			m = m_new;
1556203945Sweongyo		}
1557203945Sweongyo
1558203945Sweongyo		mt->mt_m = m;
1559203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1560203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1561203945Sweongyo		if (error) {
1562203945Sweongyo			if_printf(ifp, "%s: can't load TX buffer (2) %d\n",
1563203945Sweongyo			    __func__, error);
1564203945Sweongyo			goto fail;
1565203945Sweongyo		}
1566203945Sweongyo	}
1567203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1568203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1569203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1570203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1571203945Sweongyo
1572203945Sweongyo	/* XXX send after DTIM */
1573203945Sweongyo
1574203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1575203945Sweongyo	return (0);
1576203945Sweongyofail:
1577203945Sweongyo	dr->dr_curslot = backup[0];
1578203945Sweongyo	dr->dr_usedslot = backup[1];
1579203945Sweongyo	return (error);
1580203945Sweongyo#undef BWN_GET_TXHDRCACHE
1581203945Sweongyo}
1582203945Sweongyo
1583203945Sweongyostatic void
1584203945Sweongyobwn_watchdog(void *arg)
1585203945Sweongyo{
1586203945Sweongyo	struct bwn_softc *sc = arg;
1587203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1588203945Sweongyo
1589203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1590203945Sweongyo		if_printf(ifp, "device timeout\n");
1591271849Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1592203945Sweongyo	}
1593203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1594203945Sweongyo}
1595203945Sweongyo
1596203945Sweongyostatic int
1597203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1598203945Sweongyo{
1599203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1600203945Sweongyo	int error, have_bg = 0, have_a = 0;
1601203945Sweongyo	uint32_t high;
1602203945Sweongyo
1603204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5,
1604204922Sweongyo	    ("unsupported revision %d", siba_get_revid(sc->sc_dev)));
1605203945Sweongyo
1606204922Sweongyo	siba_powerup(sc->sc_dev, 0);
1607203945Sweongyo
1608204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
1609203945Sweongyo	bwn_reset_core(mac,
1610203945Sweongyo	    (high & BWN_TGSHIGH_HAVE_2GHZ) ? BWN_TGSLOW_SUPPORT_G : 0);
1611203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1612203945Sweongyo	if (error)
1613203945Sweongyo		goto fail;
1614203945Sweongyo
1615203945Sweongyo	have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1616203945Sweongyo	have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1617204922Sweongyo	if (siba_get_pci_device(sc->sc_dev) != 0x4312 &&
1618204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4319 &&
1619204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4324) {
1620203945Sweongyo		have_a = have_bg = 0;
1621203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1622203945Sweongyo			have_a = 1;
1623203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1624203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1625203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1626203945Sweongyo			have_bg = 1;
1627203945Sweongyo		else
1628203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1629203945Sweongyo			    mac->mac_phy.type));
1630203945Sweongyo	}
1631203945Sweongyo	/* XXX turns off PHY A because it's not supported */
1632203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1633203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1634203945Sweongyo		have_a = 0;
1635203945Sweongyo		have_bg = 1;
1636203945Sweongyo	}
1637203945Sweongyo
1638203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1639203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1640203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1641203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1642203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1643203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1644203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1645203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1646203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1647203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1648203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1649203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1650203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1651203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1652203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1653203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1654203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1655203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1656203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1657203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1658203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1659203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1660203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1661203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1662203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1663203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1664203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1665203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1666203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1667203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1668203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1669203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1670203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1671203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1672203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1673203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1674203945Sweongyo	} else {
1675203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1676203945Sweongyo		    mac->mac_phy.type);
1677203945Sweongyo		error = ENXIO;
1678203945Sweongyo		goto fail;
1679203945Sweongyo	}
1680203945Sweongyo
1681203945Sweongyo	mac->mac_phy.gmode = have_bg;
1682203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1683203945Sweongyo		error = mac->mac_phy.attach(mac);
1684203945Sweongyo		if (error) {
1685203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1686203945Sweongyo			goto fail;
1687203945Sweongyo		}
1688203945Sweongyo	}
1689203945Sweongyo
1690203945Sweongyo	bwn_reset_core(mac, have_bg ? BWN_TGSLOW_SUPPORT_G : 0);
1691203945Sweongyo
1692203945Sweongyo	error = bwn_chiptest(mac);
1693203945Sweongyo	if (error)
1694203945Sweongyo		goto fail;
1695203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1696203945Sweongyo	if (error) {
1697203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1698203945Sweongyo		goto fail;
1699203945Sweongyo	}
1700203945Sweongyo
1701203945Sweongyo	if (sc->sc_curmac == NULL)
1702203945Sweongyo		sc->sc_curmac = mac;
1703203945Sweongyo
1704203945Sweongyo	error = bwn_dma_attach(mac);
1705203945Sweongyo	if (error != 0) {
1706203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1707203945Sweongyo		goto fail;
1708203945Sweongyo	}
1709203945Sweongyo
1710203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1711203945Sweongyo
1712204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
1713203945Sweongyofail:
1714204922Sweongyo	siba_powerdown(sc->sc_dev);
1715203945Sweongyo	return (error);
1716203945Sweongyo}
1717203945Sweongyo
1718203945Sweongyostatic void
1719203945Sweongyobwn_reset_core(struct bwn_mac *mac, uint32_t flags)
1720203945Sweongyo{
1721204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1722203945Sweongyo	uint32_t low, ctl;
1723203945Sweongyo
1724203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1725203945Sweongyo
1726204922Sweongyo	siba_dev_up(sc->sc_dev, flags);
1727203945Sweongyo	DELAY(2000);
1728203945Sweongyo
1729204922Sweongyo	low = (siba_read_4(sc->sc_dev, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1730203945Sweongyo	    ~BWN_TGSLOW_PHYRESET;
1731204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low);
1732204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1733203945Sweongyo	DELAY(1000);
1734204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
1735204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1736203945Sweongyo	DELAY(1000);
1737203945Sweongyo
1738203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1739203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1740203945Sweongyo
1741203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1742203945Sweongyo	if (flags & BWN_TGSLOW_SUPPORT_G)
1743203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1744203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1745203945Sweongyo}
1746203945Sweongyo
1747203945Sweongyostatic int
1748203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1749203945Sweongyo{
1750203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1751203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1752203945Sweongyo	uint32_t tmp;
1753203945Sweongyo
1754203945Sweongyo	/* PHY */
1755203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1756203945Sweongyo	phy->gmode = (tgshigh & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1757203945Sweongyo	phy->rf_on = 1;
1758203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1759203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1760203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1761203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1762203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1763203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1764203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1765203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1766203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1767203945Sweongyo		goto unsupphy;
1768203945Sweongyo
1769203945Sweongyo	/* RADIO */
1770204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4317) {
1771204922Sweongyo		if (siba_get_chiprev(sc->sc_dev) == 0)
1772203945Sweongyo			tmp = 0x3205017f;
1773204922Sweongyo		else if (siba_get_chiprev(sc->sc_dev) == 1)
1774203945Sweongyo			tmp = 0x4205017f;
1775203945Sweongyo		else
1776203945Sweongyo			tmp = 0x5205017f;
1777203945Sweongyo	} else {
1778203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1779203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1780203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1781203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1782203945Sweongyo	}
1783203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1784203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1785203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1786203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1787203945Sweongyo		goto unsupradio;
1788203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1789203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1790203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1791203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1792203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1793203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1794203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1795203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1796203945Sweongyo		goto unsupradio;
1797203945Sweongyo
1798203945Sweongyo	return (0);
1799203945Sweongyounsupphy:
1800203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1801203945Sweongyo	    "analog %#x)\n",
1802203945Sweongyo	    phy->type, phy->rev, phy->analog);
1803203945Sweongyo	return (ENXIO);
1804203945Sweongyounsupradio:
1805203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1806203945Sweongyo	    "rev %#x)\n",
1807203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1808203945Sweongyo	return (ENXIO);
1809203945Sweongyo}
1810203945Sweongyo
1811203945Sweongyostatic int
1812203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1813203945Sweongyo{
1814203945Sweongyo#define	TESTVAL0	0x55aaaa55
1815203945Sweongyo#define	TESTVAL1	0xaa5555aa
1816203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1817203945Sweongyo	uint32_t v, backup;
1818203945Sweongyo
1819203945Sweongyo	BWN_LOCK(sc);
1820203945Sweongyo
1821203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1822203945Sweongyo
1823203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1824203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1825203945Sweongyo		goto error;
1826203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1827203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1828203945Sweongyo		goto error;
1829203945Sweongyo
1830203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1831203945Sweongyo
1832204922Sweongyo	if ((siba_get_revid(sc->sc_dev) >= 3) &&
1833204922Sweongyo	    (siba_get_revid(sc->sc_dev) <= 10)) {
1834203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1835203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1836203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1837203945Sweongyo			goto error;
1838203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1839203945Sweongyo			goto error;
1840203945Sweongyo	}
1841203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1842203945Sweongyo
1843203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1844203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1845203945Sweongyo		goto error;
1846203945Sweongyo
1847203945Sweongyo	BWN_UNLOCK(sc);
1848203945Sweongyo	return (0);
1849203945Sweongyoerror:
1850203945Sweongyo	BWN_UNLOCK(sc);
1851203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1852203945Sweongyo	return (ENODEV);
1853203945Sweongyo}
1854203945Sweongyo
1855203945Sweongyo#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
1856203945Sweongyo#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
1857203945Sweongyo
1858203945Sweongyostatic int
1859203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1860203945Sweongyo{
1861203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1862203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1863203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1864203945Sweongyo
1865203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1866203945Sweongyo	ic->ic_nchans = 0;
1867203945Sweongyo
1868203945Sweongyo	if (have_bg)
1869203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1870203945Sweongyo		    &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
1871203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1872203945Sweongyo		if (have_a)
1873203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1874203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_n,
1875203945Sweongyo			    IEEE80211_CHAN_HTA);
1876203945Sweongyo	} else {
1877203945Sweongyo		if (have_a)
1878203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1879203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_a,
1880203945Sweongyo			    IEEE80211_CHAN_A);
1881203945Sweongyo	}
1882203945Sweongyo
1883203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1884203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1885203945Sweongyo
1886203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1887203945Sweongyo}
1888203945Sweongyo
1889203945Sweongyostatic uint32_t
1890203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1891203945Sweongyo{
1892203945Sweongyo	uint32_t ret;
1893203945Sweongyo
1894204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1895203945Sweongyo
1896203945Sweongyo	if (way == BWN_SHARED) {
1897203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1898203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1899203945Sweongyo		if (offset & 0x0003) {
1900203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1901203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1902203945Sweongyo			ret <<= 16;
1903203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1904203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1905203945Sweongyo			goto out;
1906203945Sweongyo		}
1907203945Sweongyo		offset >>= 2;
1908203945Sweongyo	}
1909203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1910203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1911203945Sweongyoout:
1912203945Sweongyo	return (ret);
1913203945Sweongyo}
1914203945Sweongyo
1915203945Sweongyostatic uint16_t
1916203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1917203945Sweongyo{
1918203945Sweongyo	uint16_t ret;
1919203945Sweongyo
1920204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1921203945Sweongyo
1922203945Sweongyo	if (way == BWN_SHARED) {
1923203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1924203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1925203945Sweongyo		if (offset & 0x0003) {
1926203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1927203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1928203945Sweongyo			goto out;
1929203945Sweongyo		}
1930203945Sweongyo		offset >>= 2;
1931203945Sweongyo	}
1932203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1933203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1934203945Sweongyoout:
1935203945Sweongyo
1936203945Sweongyo	return (ret);
1937203945Sweongyo}
1938203945Sweongyo
1939203945Sweongyostatic void
1940203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1941203945Sweongyo    uint16_t offset)
1942203945Sweongyo{
1943203945Sweongyo	uint32_t control;
1944203945Sweongyo
1945203945Sweongyo	control = way;
1946203945Sweongyo	control <<= 16;
1947203945Sweongyo	control |= offset;
1948203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1949203945Sweongyo}
1950203945Sweongyo
1951203945Sweongyostatic void
1952203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1953203945Sweongyo    uint32_t value)
1954203945Sweongyo{
1955204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1956203945Sweongyo
1957203945Sweongyo	if (way == BWN_SHARED) {
1958203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1959203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1960203945Sweongyo		if (offset & 0x0003) {
1961203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1962203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1963203945Sweongyo				    (value >> 16) & 0xffff);
1964203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1965203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1966203945Sweongyo			return;
1967203945Sweongyo		}
1968203945Sweongyo		offset >>= 2;
1969203945Sweongyo	}
1970203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1971203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1972203945Sweongyo}
1973203945Sweongyo
1974203945Sweongyostatic void
1975203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1976203945Sweongyo    uint16_t value)
1977203945Sweongyo{
1978204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1979203945Sweongyo
1980203945Sweongyo	if (way == BWN_SHARED) {
1981203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1982203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1983203945Sweongyo		if (offset & 0x0003) {
1984203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1985203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
1986203945Sweongyo			return;
1987203945Sweongyo		}
1988203945Sweongyo		offset >>= 2;
1989203945Sweongyo	}
1990203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1991203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
1992203945Sweongyo}
1993203945Sweongyo
1994203945Sweongyostatic void
1995203945Sweongyobwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
1996203945Sweongyo    int txpow)
1997203945Sweongyo{
1998203945Sweongyo
1999203945Sweongyo	c->ic_freq = freq;
2000203945Sweongyo	c->ic_flags = flags;
2001203945Sweongyo	c->ic_ieee = ieee;
2002203945Sweongyo	c->ic_minpower = 0;
2003203945Sweongyo	c->ic_maxpower = 2 * txpow;
2004203945Sweongyo	c->ic_maxregpower = txpow;
2005203945Sweongyo}
2006203945Sweongyo
2007203945Sweongyostatic void
2008203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
2009203945Sweongyo    const struct bwn_channelinfo *ci, int flags)
2010203945Sweongyo{
2011203945Sweongyo	struct ieee80211_channel *c;
2012203945Sweongyo	int i;
2013203945Sweongyo
2014203945Sweongyo	c = &chans[*nchans];
2015203945Sweongyo
2016203945Sweongyo	for (i = 0; i < ci->nchannels; i++) {
2017203945Sweongyo		const struct bwn_channel *hc;
2018203945Sweongyo
2019203945Sweongyo		hc = &ci->channels[i];
2020203945Sweongyo		if (*nchans >= maxchans)
2021203945Sweongyo			break;
2022203945Sweongyo		bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
2023203945Sweongyo		c++, (*nchans)++;
2024203945Sweongyo		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
2025203945Sweongyo			/* g channel have a separate b-only entry */
2026203945Sweongyo			if (*nchans >= maxchans)
2027203945Sweongyo				break;
2028203945Sweongyo			c[0] = c[-1];
2029203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_B;
2030203945Sweongyo			c++, (*nchans)++;
2031203945Sweongyo		}
2032203945Sweongyo		if (flags == IEEE80211_CHAN_HTG) {
2033203945Sweongyo			/* HT g channel have a separate g-only entry */
2034203945Sweongyo			if (*nchans >= maxchans)
2035203945Sweongyo				break;
2036203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_G;
2037203945Sweongyo			c[0] = c[-1];
2038203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2039203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2040203945Sweongyo			c++, (*nchans)++;
2041203945Sweongyo		}
2042203945Sweongyo		if (flags == IEEE80211_CHAN_HTA) {
2043203945Sweongyo			/* HT a channel have a separate a-only entry */
2044203945Sweongyo			if (*nchans >= maxchans)
2045203945Sweongyo				break;
2046203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_A;
2047203945Sweongyo			c[0] = c[-1];
2048203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2049203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2050203945Sweongyo			c++, (*nchans)++;
2051203945Sweongyo		}
2052203945Sweongyo	}
2053203945Sweongyo}
2054203945Sweongyo
2055203945Sweongyostatic int
2056203945Sweongyobwn_phy_g_attach(struct bwn_mac *mac)
2057203945Sweongyo{
2058203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2059203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2060203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2061203945Sweongyo	unsigned int i;
2062204922Sweongyo	int16_t pab0, pab1, pab2;
2063203945Sweongyo	static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
2064204922Sweongyo	int8_t bg;
2065203945Sweongyo
2066204922Sweongyo	bg = (int8_t)siba_sprom_get_tssi_bg(sc->sc_dev);
2067204922Sweongyo	pab0 = (int16_t)siba_sprom_get_pa0b0(sc->sc_dev);
2068204922Sweongyo	pab1 = (int16_t)siba_sprom_get_pa0b1(sc->sc_dev);
2069204922Sweongyo	pab2 = (int16_t)siba_sprom_get_pa0b2(sc->sc_dev);
2070204922Sweongyo
2071204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4301) && (phy->rf_ver != 0x2050))
2072203945Sweongyo		device_printf(sc->sc_dev, "not supported anymore\n");
2073203945Sweongyo
2074203945Sweongyo	pg->pg_flags = 0;
2075203945Sweongyo	if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
2076203945Sweongyo	    pab2 == -1) {
2077203945Sweongyo		pg->pg_idletssi = 52;
2078203945Sweongyo		pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
2079203945Sweongyo		return (0);
2080203945Sweongyo	}
2081203945Sweongyo
2082203945Sweongyo	pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
2083203945Sweongyo	pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
2084203945Sweongyo	if (pg->pg_tssi2dbm == NULL) {
2085203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer\n");
2086203945Sweongyo		return (ENOMEM);
2087203945Sweongyo	}
2088203945Sweongyo	for (i = 0; i < 64; i++) {
2089203945Sweongyo		int32_t m1, m2, f, q, delta;
2090203945Sweongyo		int8_t j = 0;
2091203945Sweongyo
2092203945Sweongyo		m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
2093203945Sweongyo		m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
2094203945Sweongyo		f = 256;
2095203945Sweongyo
2096203945Sweongyo		do {
2097203945Sweongyo			if (j > 15) {
2098203945Sweongyo				device_printf(sc->sc_dev,
2099203945Sweongyo				    "failed to generate tssi2dBm\n");
2100203945Sweongyo				free(pg->pg_tssi2dbm, M_DEVBUF);
2101203945Sweongyo				return (ENOMEM);
2102203945Sweongyo			}
2103203945Sweongyo			q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
2104203945Sweongyo			    f, 2048);
2105203945Sweongyo			delta = abs(q - f);
2106203945Sweongyo			f = q;
2107203945Sweongyo			j++;
2108203945Sweongyo		} while (delta >= 2);
2109203945Sweongyo
2110203945Sweongyo		pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
2111203945Sweongyo		    128);
2112203945Sweongyo	}
2113203945Sweongyo
2114203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
2115203945Sweongyo	return (0);
2116203945Sweongyo}
2117203945Sweongyo
2118203945Sweongyostatic void
2119203945Sweongyobwn_phy_g_detach(struct bwn_mac *mac)
2120203945Sweongyo{
2121203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
2122203945Sweongyo
2123203945Sweongyo	if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
2124203945Sweongyo		free(pg->pg_tssi2dbm, M_DEVBUF);
2125203945Sweongyo		pg->pg_tssi2dbm = NULL;
2126203945Sweongyo	}
2127203945Sweongyo	pg->pg_flags = 0;
2128203945Sweongyo}
2129203945Sweongyo
2130203945Sweongyostatic void
2131203945Sweongyobwn_phy_g_init_pre(struct bwn_mac *mac)
2132203945Sweongyo{
2133203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2134203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2135203945Sweongyo	void *tssi2dbm;
2136203945Sweongyo	int idletssi;
2137203945Sweongyo	unsigned int i;
2138203945Sweongyo
2139203945Sweongyo	tssi2dbm = pg->pg_tssi2dbm;
2140203945Sweongyo	idletssi = pg->pg_idletssi;
2141203945Sweongyo
2142203945Sweongyo	memset(pg, 0, sizeof(*pg));
2143203945Sweongyo
2144203945Sweongyo	pg->pg_tssi2dbm = tssi2dbm;
2145203945Sweongyo	pg->pg_idletssi = idletssi;
2146203945Sweongyo
2147203945Sweongyo	memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
2148203945Sweongyo
2149203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi); i++)
2150203945Sweongyo		pg->pg_nrssi[i] = -1000;
2151203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi_lt); i++)
2152203945Sweongyo		pg->pg_nrssi_lt[i] = i;
2153203945Sweongyo	pg->pg_lofcal = 0xffff;
2154203945Sweongyo	pg->pg_initval = 0xffff;
2155203945Sweongyo	pg->pg_immode = BWN_IMMODE_NONE;
2156203945Sweongyo	pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
2157203945Sweongyo	pg->pg_avgtssi = 0xff;
2158203945Sweongyo
2159203945Sweongyo	pg->pg_loctl.tx_bias = 0xff;
2160203945Sweongyo	TAILQ_INIT(&pg->pg_loctl.calib_list);
2161203945Sweongyo}
2162203945Sweongyo
2163203945Sweongyostatic int
2164203945Sweongyobwn_phy_g_prepare_hw(struct bwn_mac *mac)
2165203945Sweongyo{
2166203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2167203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2168204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2169203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2170203945Sweongyo	static const struct bwn_rfatt rfatt0[] = {
2171203945Sweongyo		{ 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 },	{ 9, 0 }, { 2, 0 },
2172203945Sweongyo		{ 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
2173203945Sweongyo		{ 3, 1 }, { 4, 1 }
2174203945Sweongyo	};
2175203945Sweongyo	static const struct bwn_rfatt rfatt1[] = {
2176203945Sweongyo		{ 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
2177203945Sweongyo		{ 14, 1 }
2178203945Sweongyo	};
2179203945Sweongyo	static const struct bwn_rfatt rfatt2[] = {
2180203945Sweongyo		{ 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
2181203945Sweongyo		{ 9, 1 }
2182203945Sweongyo	};
2183203945Sweongyo	static const struct bwn_bbatt bbatt_0[] = {
2184203945Sweongyo		{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
2185203945Sweongyo	};
2186203945Sweongyo
2187203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
2188203945Sweongyo
2189203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
2190203945Sweongyo		pg->pg_bbatt.att = 0;
2191203945Sweongyo	else
2192203945Sweongyo		pg->pg_bbatt.att = 2;
2193203945Sweongyo
2194203945Sweongyo	/* prepare Radio Attenuation */
2195203945Sweongyo	pg->pg_rfatt.padmix = 0;
2196203945Sweongyo
2197204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
2198204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BCM4309G) {
2199204922Sweongyo		if (siba_get_pci_revid(sc->sc_dev) < 0x43) {
2200203945Sweongyo			pg->pg_rfatt.att = 2;
2201203945Sweongyo			goto done;
2202204922Sweongyo		} else if (siba_get_pci_revid(sc->sc_dev) < 0x51) {
2203203945Sweongyo			pg->pg_rfatt.att = 3;
2204203945Sweongyo			goto done;
2205203945Sweongyo		}
2206203945Sweongyo	}
2207203945Sweongyo
2208203945Sweongyo	if (phy->type == BWN_PHYTYPE_A) {
2209203945Sweongyo		pg->pg_rfatt.att = 0x60;
2210203945Sweongyo		goto done;
2211203945Sweongyo	}
2212203945Sweongyo
2213203945Sweongyo	switch (phy->rf_ver) {
2214203945Sweongyo	case 0x2050:
2215203945Sweongyo		switch (phy->rf_rev) {
2216203945Sweongyo		case 0:
2217203945Sweongyo			pg->pg_rfatt.att = 5;
2218203945Sweongyo			goto done;
2219203945Sweongyo		case 1:
2220203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2221204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2222203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2223204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2224203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2225204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2226203945Sweongyo					pg->pg_rfatt.att = 3;
2227204922Sweongyo				else if (siba_get_pci_subvendor(sc->sc_dev) ==
2228203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2229204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2230204922Sweongyo				    SIBA_BOARD_BU4306)
2231203945Sweongyo					pg->pg_rfatt.att = 3;
2232203945Sweongyo				else
2233203945Sweongyo					pg->pg_rfatt.att = 1;
2234203945Sweongyo			} else {
2235204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2236203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2237204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2238203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2239204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2240203945Sweongyo					pg->pg_rfatt.att = 7;
2241203945Sweongyo				else
2242203945Sweongyo					pg->pg_rfatt.att = 6;
2243203945Sweongyo			}
2244203945Sweongyo			goto done;
2245203945Sweongyo		case 2:
2246203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2247204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2248203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2249204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2250203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2251204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2252203945Sweongyo					pg->pg_rfatt.att = 3;
2253204922Sweongyo				else if (siba_get_pci_subvendor(sc->sc_dev) ==
2254203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2255204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2256204922Sweongyo				    SIBA_BOARD_BU4306)
2257203945Sweongyo					pg->pg_rfatt.att = 5;
2258204922Sweongyo				else if (siba_get_chipid(sc->sc_dev) == 0x4320)
2259203945Sweongyo					pg->pg_rfatt.att = 4;
2260203945Sweongyo				else
2261203945Sweongyo					pg->pg_rfatt.att = 3;
2262203945Sweongyo			} else
2263203945Sweongyo				pg->pg_rfatt.att = 6;
2264203945Sweongyo			goto done;
2265203945Sweongyo		case 3:
2266203945Sweongyo			pg->pg_rfatt.att = 5;
2267203945Sweongyo			goto done;
2268203945Sweongyo		case 4:
2269203945Sweongyo		case 5:
2270203945Sweongyo			pg->pg_rfatt.att = 1;
2271203945Sweongyo			goto done;
2272203945Sweongyo		case 6:
2273203945Sweongyo		case 7:
2274203945Sweongyo			pg->pg_rfatt.att = 5;
2275203945Sweongyo			goto done;
2276203945Sweongyo		case 8:
2277203945Sweongyo			pg->pg_rfatt.att = 0xa;
2278203945Sweongyo			pg->pg_rfatt.padmix = 1;
2279203945Sweongyo			goto done;
2280203945Sweongyo		case 9:
2281203945Sweongyo		default:
2282203945Sweongyo			pg->pg_rfatt.att = 5;
2283203945Sweongyo			goto done;
2284203945Sweongyo		}
2285203945Sweongyo		break;
2286203945Sweongyo	case 0x2053:
2287203945Sweongyo		switch (phy->rf_rev) {
2288203945Sweongyo		case 1:
2289203945Sweongyo			pg->pg_rfatt.att = 6;
2290203945Sweongyo			goto done;
2291203945Sweongyo		}
2292203945Sweongyo		break;
2293203945Sweongyo	}
2294203945Sweongyo	pg->pg_rfatt.att = 5;
2295203945Sweongyodone:
2296203945Sweongyo	pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
2297203945Sweongyo
2298203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
2299203945Sweongyo		lo->rfatt.array = rfatt0;
2300203945Sweongyo		lo->rfatt.len = N(rfatt0);
2301203945Sweongyo		lo->rfatt.min = 0;
2302203945Sweongyo		lo->rfatt.max = 9;
2303203945Sweongyo		goto genbbatt;
2304203945Sweongyo	}
2305203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
2306203945Sweongyo		lo->rfatt.array = rfatt1;
2307203945Sweongyo		lo->rfatt.len = N(rfatt1);
2308203945Sweongyo		lo->rfatt.min = 0;
2309203945Sweongyo		lo->rfatt.max = 14;
2310203945Sweongyo		goto genbbatt;
2311203945Sweongyo	}
2312203945Sweongyo	lo->rfatt.array = rfatt2;
2313203945Sweongyo	lo->rfatt.len = N(rfatt2);
2314203945Sweongyo	lo->rfatt.min = 0;
2315203945Sweongyo	lo->rfatt.max = 9;
2316203945Sweongyogenbbatt:
2317203945Sweongyo	lo->bbatt.array = bbatt_0;
2318203945Sweongyo	lo->bbatt.len = N(bbatt_0);
2319203945Sweongyo	lo->bbatt.min = 0;
2320203945Sweongyo	lo->bbatt.max = 8;
2321203945Sweongyo
2322203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
2323203945Sweongyo	if (phy->rev == 1) {
2324203945Sweongyo		phy->gmode = 0;
2325203945Sweongyo		bwn_reset_core(mac, 0);
2326203945Sweongyo		bwn_phy_g_init_sub(mac);
2327203945Sweongyo		phy->gmode = 1;
2328203945Sweongyo		bwn_reset_core(mac, BWN_TGSLOW_SUPPORT_G);
2329203945Sweongyo	}
2330203945Sweongyo	return (0);
2331203945Sweongyo}
2332203945Sweongyo
2333203945Sweongyostatic uint16_t
2334203945Sweongyobwn_phy_g_txctl(struct bwn_mac *mac)
2335203945Sweongyo{
2336203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2337203945Sweongyo
2338203945Sweongyo	if (phy->rf_ver != 0x2050)
2339203945Sweongyo		return (0);
2340203945Sweongyo	if (phy->rf_rev == 1)
2341203945Sweongyo		return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
2342203945Sweongyo	if (phy->rf_rev < 6)
2343203945Sweongyo		return (BWN_TXCTL_PA2DB);
2344203945Sweongyo	if (phy->rf_rev == 8)
2345203945Sweongyo		return (BWN_TXCTL_TXMIX);
2346203945Sweongyo	return (0);
2347203945Sweongyo}
2348203945Sweongyo
2349203945Sweongyostatic int
2350203945Sweongyobwn_phy_g_init(struct bwn_mac *mac)
2351203945Sweongyo{
2352203945Sweongyo
2353203945Sweongyo	bwn_phy_g_init_sub(mac);
2354203945Sweongyo	return (0);
2355203945Sweongyo}
2356203945Sweongyo
2357203945Sweongyostatic void
2358203945Sweongyobwn_phy_g_exit(struct bwn_mac *mac)
2359203945Sweongyo{
2360203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
2361203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2362203945Sweongyo
2363203945Sweongyo	if (lo == NULL)
2364203945Sweongyo		return;
2365203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2366203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2367203945Sweongyo		free(cal, M_DEVBUF);
2368203945Sweongyo	}
2369203945Sweongyo}
2370203945Sweongyo
2371203945Sweongyostatic uint16_t
2372203945Sweongyobwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
2373203945Sweongyo{
2374203945Sweongyo
2375203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2376203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
2377203945Sweongyo}
2378203945Sweongyo
2379203945Sweongyostatic void
2380203945Sweongyobwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2381203945Sweongyo{
2382203945Sweongyo
2383203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2384203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
2385203945Sweongyo}
2386203945Sweongyo
2387203945Sweongyostatic uint16_t
2388203945Sweongyobwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
2389203945Sweongyo{
2390203945Sweongyo
2391203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2392203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
2393203945Sweongyo	return (BWN_READ_2(mac, BWN_RFDATALO));
2394203945Sweongyo}
2395203945Sweongyo
2396203945Sweongyostatic void
2397203945Sweongyobwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2398203945Sweongyo{
2399203945Sweongyo
2400203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2401203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
2402203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
2403203945Sweongyo}
2404203945Sweongyo
2405203945Sweongyostatic int
2406203945Sweongyobwn_phy_g_hwpctl(struct bwn_mac *mac)
2407203945Sweongyo{
2408203945Sweongyo
2409203945Sweongyo	return (mac->mac_phy.rev >= 6);
2410203945Sweongyo}
2411203945Sweongyo
2412203945Sweongyostatic void
2413203945Sweongyobwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
2414203945Sweongyo{
2415203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2416203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2417203945Sweongyo	unsigned int channel;
2418203945Sweongyo	uint16_t rfover, rfoverval;
2419203945Sweongyo
2420203945Sweongyo	if (on) {
2421203945Sweongyo		if (phy->rf_on)
2422203945Sweongyo			return;
2423203945Sweongyo
2424203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0x8000);
2425203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0xcc00);
2426203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
2427203945Sweongyo		if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
2428203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
2429203945Sweongyo			    pg->pg_radioctx_over);
2430203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
2431203945Sweongyo			    pg->pg_radioctx_overval);
2432203945Sweongyo			pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
2433203945Sweongyo		}
2434203945Sweongyo		channel = phy->chan;
2435203945Sweongyo		bwn_phy_g_switch_chan(mac, 6, 1);
2436203945Sweongyo		bwn_phy_g_switch_chan(mac, channel, 0);
2437203945Sweongyo		return;
2438203945Sweongyo	}
2439203945Sweongyo
2440203945Sweongyo	rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
2441203945Sweongyo	rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
2442203945Sweongyo	pg->pg_radioctx_over = rfover;
2443203945Sweongyo	pg->pg_radioctx_overval = rfoverval;
2444203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
2445203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
2446203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
2447203945Sweongyo}
2448203945Sweongyo
2449203945Sweongyostatic int
2450203945Sweongyobwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
2451203945Sweongyo{
2452203945Sweongyo
2453203945Sweongyo	if ((newchan < 1) || (newchan > 14))
2454203945Sweongyo		return (EINVAL);
2455203945Sweongyo	bwn_phy_g_switch_chan(mac, newchan, 0);
2456203945Sweongyo
2457203945Sweongyo	return (0);
2458203945Sweongyo}
2459203945Sweongyo
2460203945Sweongyostatic uint32_t
2461203945Sweongyobwn_phy_g_get_default_chan(struct bwn_mac *mac)
2462203945Sweongyo{
2463203945Sweongyo
2464203945Sweongyo	return (1);
2465203945Sweongyo}
2466203945Sweongyo
2467203945Sweongyostatic void
2468203945Sweongyobwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
2469203945Sweongyo{
2470203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2471203945Sweongyo	uint64_t hf;
2472203945Sweongyo	int autodiv = 0;
2473203945Sweongyo	uint16_t tmp;
2474203945Sweongyo
2475203945Sweongyo	if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
2476203945Sweongyo		autodiv = 1;
2477203945Sweongyo
2478203945Sweongyo	hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
2479203945Sweongyo	bwn_hf_write(mac, hf);
2480203945Sweongyo
2481203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
2482203945Sweongyo	    (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
2483203945Sweongyo	    ((autodiv ? BWN_ANTAUTO1 : antenna)
2484203945Sweongyo		<< BWN_PHY_BBANDCFG_RXANT_SHIFT));
2485203945Sweongyo
2486203945Sweongyo	if (autodiv) {
2487203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
2488203945Sweongyo		if (antenna == BWN_ANTAUTO1)
2489203945Sweongyo			tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
2490203945Sweongyo		else
2491203945Sweongyo			tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
2492203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
2493203945Sweongyo	}
2494203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
2495203945Sweongyo	if (autodiv)
2496203945Sweongyo		tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
2497203945Sweongyo	else
2498203945Sweongyo		tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
2499203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
2500203945Sweongyo	if (phy->rev >= 2) {
2501203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
2502203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
2503203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
2504203945Sweongyo		    (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
2505203945Sweongyo		    0x15);
2506203945Sweongyo		if (phy->rev == 2)
2507203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
2508203945Sweongyo		else
2509203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
2510203945Sweongyo			    (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
2511203945Sweongyo			    8);
2512203945Sweongyo	}
2513203945Sweongyo	if (phy->rev >= 6)
2514203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
2515203945Sweongyo
2516203945Sweongyo	hf |= BWN_HF_UCODE_ANTDIV_HELPER;
2517203945Sweongyo	bwn_hf_write(mac, hf);
2518203945Sweongyo}
2519203945Sweongyo
2520203945Sweongyostatic int
2521203945Sweongyobwn_phy_g_im(struct bwn_mac *mac, int mode)
2522203945Sweongyo{
2523203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2524203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2525203945Sweongyo
2526203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2527203945Sweongyo	KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
2528203945Sweongyo
2529203945Sweongyo	if (phy->rev == 0 || !phy->gmode)
2530203945Sweongyo		return (ENODEV);
2531203945Sweongyo
2532203945Sweongyo	pg->pg_aci_wlan_automatic = 0;
2533203945Sweongyo	return (0);
2534203945Sweongyo}
2535203945Sweongyo
2536203945Sweongyostatic int
2537203945Sweongyobwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
2538203945Sweongyo{
2539203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2540203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2541203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2542203945Sweongyo	unsigned int tssi;
2543203945Sweongyo	int cck, ofdm;
2544203945Sweongyo	int power;
2545203945Sweongyo	int rfatt, bbatt;
2546203945Sweongyo	unsigned int max;
2547203945Sweongyo
2548203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2549203945Sweongyo
2550203945Sweongyo	cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
2551203945Sweongyo	ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
2552203945Sweongyo	if (cck < 0 && ofdm < 0) {
2553203945Sweongyo		if (ignore_tssi == 0)
2554203945Sweongyo			return (BWN_TXPWR_RES_DONE);
2555203945Sweongyo		cck = 0;
2556203945Sweongyo		ofdm = 0;
2557203945Sweongyo	}
2558203945Sweongyo	tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
2559203945Sweongyo	if (pg->pg_avgtssi != 0xff)
2560203945Sweongyo		tssi = (tssi + pg->pg_avgtssi) / 2;
2561203945Sweongyo	pg->pg_avgtssi = tssi;
2562203945Sweongyo	KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
2563203945Sweongyo
2564204922Sweongyo	max = siba_sprom_get_maxpwr_bg(sc->sc_dev);
2565204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
2566203945Sweongyo		max -= 3;
2567203945Sweongyo	if (max >= 120) {
2568203945Sweongyo		device_printf(sc->sc_dev, "invalid max TX-power value\n");
2569204922Sweongyo		max = 80;
2570204922Sweongyo		siba_sprom_set_maxpwr_bg(sc->sc_dev, max);
2571203945Sweongyo	}
2572203945Sweongyo
2573203945Sweongyo	power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
2574203945Sweongyo	    (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
2575203945Sweongyo	     tssi, 0x00), 0x3f)]);
2576203945Sweongyo	if (power == 0)
2577203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2578203945Sweongyo
2579203945Sweongyo	rfatt = -((power + 7) / 8);
2580203945Sweongyo	bbatt = (-(power / 2)) - (4 * rfatt);
2581203945Sweongyo	if ((rfatt == 0) && (bbatt == 0))
2582203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2583203945Sweongyo	pg->pg_bbatt_delta = bbatt;
2584203945Sweongyo	pg->pg_rfatt_delta = rfatt;
2585203945Sweongyo	return (BWN_TXPWR_RES_NEED_ADJUST);
2586203945Sweongyo}
2587203945Sweongyo
2588203945Sweongyostatic void
2589203945Sweongyobwn_phy_g_set_txpwr(struct bwn_mac *mac)
2590203945Sweongyo{
2591203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2592203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2593203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2594203945Sweongyo	int rfatt, bbatt;
2595203945Sweongyo	uint8_t txctl;
2596203945Sweongyo
2597203945Sweongyo	bwn_mac_suspend(mac);
2598203945Sweongyo
2599203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2600203945Sweongyo
2601203945Sweongyo	bbatt = pg->pg_bbatt.att;
2602203945Sweongyo	bbatt += pg->pg_bbatt_delta;
2603203945Sweongyo	rfatt = pg->pg_rfatt.att;
2604203945Sweongyo	rfatt += pg->pg_rfatt_delta;
2605203945Sweongyo
2606203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2607203945Sweongyo	txctl = pg->pg_txctl;
2608203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
2609203945Sweongyo		if (rfatt <= 1) {
2610203945Sweongyo			if (txctl == 0) {
2611203945Sweongyo				txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
2612203945Sweongyo				rfatt += 2;
2613203945Sweongyo				bbatt += 2;
2614204922Sweongyo			} else if (siba_sprom_get_bf_lo(sc->sc_dev) &
2615204922Sweongyo			    BWN_BFL_PACTRL) {
2616203945Sweongyo				bbatt += 4 * (rfatt - 2);
2617203945Sweongyo				rfatt = 2;
2618203945Sweongyo			}
2619203945Sweongyo		} else if (rfatt > 4 && txctl) {
2620203945Sweongyo			txctl = 0;
2621203945Sweongyo			if (bbatt < 3) {
2622203945Sweongyo				rfatt -= 3;
2623203945Sweongyo				bbatt += 2;
2624203945Sweongyo			} else {
2625203945Sweongyo				rfatt -= 2;
2626203945Sweongyo				bbatt -= 2;
2627203945Sweongyo			}
2628203945Sweongyo		}
2629203945Sweongyo	}
2630203945Sweongyo	pg->pg_txctl = txctl;
2631203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2632203945Sweongyo	pg->pg_rfatt.att = rfatt;
2633203945Sweongyo	pg->pg_bbatt.att = bbatt;
2634203945Sweongyo
2635203945Sweongyo	DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
2636203945Sweongyo
2637203945Sweongyo	bwn_phy_lock(mac);
2638203945Sweongyo	bwn_rf_lock(mac);
2639203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
2640203945Sweongyo	    pg->pg_txctl);
2641203945Sweongyo	bwn_rf_unlock(mac);
2642203945Sweongyo	bwn_phy_unlock(mac);
2643203945Sweongyo
2644203945Sweongyo	bwn_mac_enable(mac);
2645203945Sweongyo}
2646203945Sweongyo
2647203945Sweongyostatic void
2648203945Sweongyobwn_phy_g_task_15s(struct bwn_mac *mac)
2649203945Sweongyo{
2650203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2651203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2652203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2653203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2654203945Sweongyo	unsigned long expire, now;
2655203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2656203945Sweongyo	uint8_t expired = 0;
2657203945Sweongyo
2658203945Sweongyo	bwn_mac_suspend(mac);
2659203945Sweongyo
2660203945Sweongyo	if (lo == NULL)
2661203945Sweongyo		goto fail;
2662203945Sweongyo
2663203945Sweongyo	BWN_GETTIME(now);
2664203945Sweongyo	if (bwn_has_hwpctl(mac)) {
2665203945Sweongyo		expire = now - BWN_LO_PWRVEC_EXPIRE;
2666203945Sweongyo		if (time_before(lo->pwr_vec_read_time, expire)) {
2667203945Sweongyo			bwn_lo_get_powervector(mac);
2668203945Sweongyo			bwn_phy_g_dc_lookup_init(mac, 0);
2669203945Sweongyo		}
2670203945Sweongyo		goto fail;
2671203945Sweongyo	}
2672203945Sweongyo
2673203945Sweongyo	expire = now - BWN_LO_CALIB_EXPIRE;
2674203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2675203945Sweongyo		if (!time_before(cal->calib_time, expire))
2676203945Sweongyo			continue;
2677203945Sweongyo		if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
2678203945Sweongyo		    BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
2679203945Sweongyo			KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
2680203945Sweongyo			expired = 1;
2681203945Sweongyo		}
2682203945Sweongyo
2683203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
2684203945Sweongyo		    cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
2685203945Sweongyo		    cal->ctl.i, cal->ctl.q);
2686203945Sweongyo
2687203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2688203945Sweongyo		free(cal, M_DEVBUF);
2689203945Sweongyo	}
2690203945Sweongyo	if (expired || TAILQ_EMPTY(&lo->calib_list)) {
2691203945Sweongyo		cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
2692203945Sweongyo		    &pg->pg_rfatt);
2693203945Sweongyo		if (cal == NULL) {
2694203945Sweongyo			device_printf(sc->sc_dev,
2695203945Sweongyo			    "failed to recalibrate LO\n");
2696203945Sweongyo			goto fail;
2697203945Sweongyo		}
2698203945Sweongyo		TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
2699203945Sweongyo		bwn_lo_write(mac, &cal->ctl);
2700203945Sweongyo	}
2701203945Sweongyo
2702203945Sweongyofail:
2703203945Sweongyo	bwn_mac_enable(mac);
2704203945Sweongyo}
2705203945Sweongyo
2706203945Sweongyostatic void
2707203945Sweongyobwn_phy_g_task_60s(struct bwn_mac *mac)
2708203945Sweongyo{
2709203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2710204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2711203945Sweongyo	uint8_t old = phy->chan;
2712203945Sweongyo
2713204922Sweongyo	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI))
2714203945Sweongyo		return;
2715203945Sweongyo
2716203945Sweongyo	bwn_mac_suspend(mac);
2717203945Sweongyo	bwn_nrssi_slope_11g(mac);
2718203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
2719203945Sweongyo		bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
2720203945Sweongyo		bwn_switch_channel(mac, old);
2721203945Sweongyo	}
2722203945Sweongyo	bwn_mac_enable(mac);
2723203945Sweongyo}
2724203945Sweongyo
2725203945Sweongyostatic void
2726203945Sweongyobwn_phy_switch_analog(struct bwn_mac *mac, int on)
2727203945Sweongyo{
2728203945Sweongyo
2729203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
2730203945Sweongyo}
2731203945Sweongyo
2732203945Sweongyostatic int
2733203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
2734203945Sweongyo	const struct ieee80211_bpf_params *params)
2735203945Sweongyo{
2736203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2737203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2738203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2739203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2740203945Sweongyo
2741203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
2742203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
2743203945Sweongyo		ieee80211_free_node(ni);
2744203945Sweongyo		m_freem(m);
2745203945Sweongyo		return (ENETDOWN);
2746203945Sweongyo	}
2747203945Sweongyo
2748203945Sweongyo	BWN_LOCK(sc);
2749203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
2750203945Sweongyo		ieee80211_free_node(ni);
2751203945Sweongyo		m_freem(m);
2752271849Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2753203945Sweongyo		BWN_UNLOCK(sc);
2754203945Sweongyo		return (ENOBUFS);
2755203945Sweongyo	}
2756203945Sweongyo
2757203945Sweongyo	if (bwn_tx_start(sc, ni, m) != 0) {
2758203945Sweongyo		if (ni != NULL)
2759203945Sweongyo			ieee80211_free_node(ni);
2760271849Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2761203945Sweongyo	}
2762203945Sweongyo	sc->sc_watchdog_timer = 5;
2763203945Sweongyo	BWN_UNLOCK(sc);
2764203945Sweongyo	return (0);
2765203945Sweongyo}
2766203945Sweongyo
2767203945Sweongyo/*
2768203945Sweongyo * Callback from the 802.11 layer to update the slot time
2769203945Sweongyo * based on the current setting.  We use it to notify the
2770203945Sweongyo * firmware of ERP changes and the f/w takes care of things
2771203945Sweongyo * like slot time and preamble.
2772203945Sweongyo */
2773203945Sweongyostatic void
2774203945Sweongyobwn_updateslot(struct ifnet *ifp)
2775203945Sweongyo{
2776203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2777203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
2778203945Sweongyo	struct bwn_mac *mac;
2779203945Sweongyo
2780203945Sweongyo	BWN_LOCK(sc);
2781203945Sweongyo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2782203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
2783203945Sweongyo		bwn_set_slot_time(mac,
2784203945Sweongyo		    (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20);
2785203945Sweongyo	}
2786203945Sweongyo	BWN_UNLOCK(sc);
2787203945Sweongyo}
2788203945Sweongyo
2789203945Sweongyo/*
2790203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
2791203945Sweongyo * Note this interface does not check the operating mode as this
2792203945Sweongyo * is an internal callback and we are expected to honor the current
2793203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
2794203945Sweongyo * mode when operating in hostap mode to do ACS).
2795203945Sweongyo */
2796203945Sweongyostatic void
2797203945Sweongyobwn_update_promisc(struct ifnet *ifp)
2798203945Sweongyo{
2799203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2800203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2801203945Sweongyo
2802203945Sweongyo	BWN_LOCK(sc);
2803203945Sweongyo	mac = sc->sc_curmac;
2804203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2805203945Sweongyo		if (ifp->if_flags & IFF_PROMISC)
2806203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
2807203945Sweongyo		else
2808203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
2809203945Sweongyo		bwn_set_opmode(mac);
2810203945Sweongyo	}
2811203945Sweongyo	BWN_UNLOCK(sc);
2812203945Sweongyo}
2813203945Sweongyo
2814203945Sweongyo/*
2815203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
2816203945Sweongyo */
2817203945Sweongyostatic int
2818203945Sweongyobwn_wme_update(struct ieee80211com *ic)
2819203945Sweongyo{
2820203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2821203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2822203945Sweongyo	struct wmeParams *wmep;
2823203945Sweongyo	int i;
2824203945Sweongyo
2825203945Sweongyo	BWN_LOCK(sc);
2826203945Sweongyo	mac = sc->sc_curmac;
2827203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2828203945Sweongyo		bwn_mac_suspend(mac);
2829203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
2830203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
2831203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
2832203945Sweongyo		}
2833203945Sweongyo		bwn_mac_enable(mac);
2834203945Sweongyo	}
2835203945Sweongyo	BWN_UNLOCK(sc);
2836203945Sweongyo	return (0);
2837203945Sweongyo}
2838203945Sweongyo
2839203945Sweongyostatic void
2840203945Sweongyobwn_scan_start(struct ieee80211com *ic)
2841203945Sweongyo{
2842203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2843203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2844203945Sweongyo	struct bwn_mac *mac;
2845203945Sweongyo
2846203945Sweongyo	BWN_LOCK(sc);
2847203945Sweongyo	mac = sc->sc_curmac;
2848203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2849203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
2850203945Sweongyo		bwn_set_opmode(mac);
2851203945Sweongyo		/* disable CFP update during scan */
2852203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
2853203945Sweongyo	}
2854203945Sweongyo	BWN_UNLOCK(sc);
2855203945Sweongyo}
2856203945Sweongyo
2857203945Sweongyostatic void
2858203945Sweongyobwn_scan_end(struct ieee80211com *ic)
2859203945Sweongyo{
2860203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2861203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2862203945Sweongyo	struct bwn_mac *mac;
2863203945Sweongyo
2864203945Sweongyo	BWN_LOCK(sc);
2865203945Sweongyo	mac = sc->sc_curmac;
2866203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2867203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
2868203945Sweongyo		bwn_set_opmode(mac);
2869203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
2870203945Sweongyo	}
2871203945Sweongyo	BWN_UNLOCK(sc);
2872203945Sweongyo}
2873203945Sweongyo
2874203945Sweongyostatic void
2875203945Sweongyobwn_set_channel(struct ieee80211com *ic)
2876203945Sweongyo{
2877203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2878203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2879203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2880203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2881203945Sweongyo	int chan, error;
2882203945Sweongyo
2883203945Sweongyo	BWN_LOCK(sc);
2884203945Sweongyo
2885203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
2886203945Sweongyo	if (error)
2887216227Skevlo		goto fail;
2888203945Sweongyo	bwn_mac_suspend(mac);
2889203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2890203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
2891203945Sweongyo	if (chan != phy->chan)
2892203945Sweongyo		bwn_switch_channel(mac, chan);
2893203945Sweongyo
2894203945Sweongyo	/* TX power level */
2895203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
2896203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
2897203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
2898203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
2899203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
2900203945Sweongyo	}
2901203945Sweongyo
2902203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2903203945Sweongyo	if (phy->set_antenna)
2904203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2905203945Sweongyo
2906203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
2907203945Sweongyo		if (sc->sc_rf_enabled) {
2908203945Sweongyo			bwn_rf_turnon(mac);
2909203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
2910203945Sweongyo				device_printf(sc->sc_dev,
2911213719Sjoel				    "please turn on the RF switch\n");
2912203945Sweongyo		} else
2913203945Sweongyo			bwn_rf_turnoff(mac);
2914203945Sweongyo	}
2915203945Sweongyo
2916203945Sweongyo	bwn_mac_enable(mac);
2917203945Sweongyo
2918203945Sweongyofail:
2919203945Sweongyo	/*
2920203945Sweongyo	 * Setup radio tap channel freq and flags
2921203945Sweongyo	 */
2922203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
2923203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
2924203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
2925203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
2926203945Sweongyo
2927203945Sweongyo	BWN_UNLOCK(sc);
2928203945Sweongyo}
2929203945Sweongyo
2930203945Sweongyostatic struct ieee80211vap *
2931228621Sbschmidtbwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
2932228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
2933228621Sbschmidt    const uint8_t bssid[IEEE80211_ADDR_LEN],
2934228621Sbschmidt    const uint8_t mac0[IEEE80211_ADDR_LEN])
2935203945Sweongyo{
2936203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2937203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2938203945Sweongyo	struct ieee80211vap *vap;
2939203945Sweongyo	struct bwn_vap *bvp;
2940203945Sweongyo	uint8_t mac[IEEE80211_ADDR_LEN];
2941203945Sweongyo
2942203945Sweongyo	IEEE80211_ADDR_COPY(mac, mac0);
2943203945Sweongyo	switch (opmode) {
2944203945Sweongyo	case IEEE80211_M_HOSTAP:
2945203945Sweongyo	case IEEE80211_M_MBSS:
2946203945Sweongyo	case IEEE80211_M_STA:
2947203945Sweongyo	case IEEE80211_M_WDS:
2948203945Sweongyo	case IEEE80211_M_MONITOR:
2949203945Sweongyo	case IEEE80211_M_IBSS:
2950203945Sweongyo	case IEEE80211_M_AHDEMO:
2951203945Sweongyo		break;
2952203945Sweongyo	default:
2953203945Sweongyo		return (NULL);
2954203945Sweongyo	}
2955203945Sweongyo
2956203945Sweongyo	IEEE80211_ADDR_COPY(sc->sc_macaddr, mac0);
2957203945Sweongyo
2958203945Sweongyo	bvp = (struct bwn_vap *) malloc(sizeof(struct bwn_vap),
2959203945Sweongyo	    M_80211_VAP, M_NOWAIT | M_ZERO);
2960203945Sweongyo	if (bvp == NULL) {
2961203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate a buffer\n");
2962203945Sweongyo		return (NULL);
2963203945Sweongyo	}
2964203945Sweongyo	vap = &bvp->bv_vap;
2965203945Sweongyo	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
2966203945Sweongyo	IEEE80211_ADDR_COPY(vap->iv_myaddr, mac);
2967203945Sweongyo	/* override with driver methods */
2968203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
2969203945Sweongyo	vap->iv_newstate = bwn_newstate;
2970203945Sweongyo
2971203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
2972203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
2973203945Sweongyo
2974206358Srpaulo	ieee80211_ratectl_init(vap);
2975203945Sweongyo
2976203945Sweongyo	/* complete setup */
2977203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
2978203945Sweongyo	    ieee80211_media_status);
2979203945Sweongyo	return (vap);
2980203945Sweongyo}
2981203945Sweongyo
2982203945Sweongyostatic void
2983203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
2984203945Sweongyo{
2985203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
2986203945Sweongyo
2987206358Srpaulo	ieee80211_ratectl_deinit(vap);
2988203945Sweongyo	ieee80211_vap_detach(vap);
2989203945Sweongyo	free(bvp, M_80211_VAP);
2990203945Sweongyo}
2991203945Sweongyo
2992203945Sweongyostatic void
2993203945Sweongyobwn_init(void *arg)
2994203945Sweongyo{
2995203945Sweongyo	struct bwn_softc *sc = arg;
2996203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
2997203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
2998203945Sweongyo	int error = 0;
2999203945Sweongyo
3000203945Sweongyo	DPRINTF(sc, BWN_DEBUG_ANY, "%s: if_flags 0x%x\n",
3001203945Sweongyo		__func__, ifp->if_flags);
3002203945Sweongyo
3003203945Sweongyo	BWN_LOCK(sc);
3004203945Sweongyo	error = bwn_init_locked(sc);
3005203945Sweongyo	BWN_UNLOCK(sc);
3006203945Sweongyo
3007203945Sweongyo	if (error == 0)
3008203945Sweongyo		ieee80211_start_all(ic);	/* start all vap's */
3009203945Sweongyo}
3010203945Sweongyo
3011203945Sweongyostatic int
3012203945Sweongyobwn_init_locked(struct bwn_softc *sc)
3013203945Sweongyo{
3014203945Sweongyo	struct bwn_mac *mac;
3015203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3016203945Sweongyo	int error;
3017203945Sweongyo
3018203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3019203945Sweongyo
3020203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
3021203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
3022203945Sweongyo	sc->sc_filters = 0;
3023203945Sweongyo	bwn_wme_clear(sc);
3024203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
3025203945Sweongyo	sc->sc_rf_enabled = 1;
3026203945Sweongyo
3027203945Sweongyo	mac = sc->sc_curmac;
3028203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
3029203945Sweongyo		error = bwn_core_init(mac);
3030203945Sweongyo		if (error != 0)
3031203945Sweongyo			return (error);
3032203945Sweongyo	}
3033203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
3034203945Sweongyo		bwn_core_start(mac);
3035203945Sweongyo
3036203945Sweongyo	bwn_set_opmode(mac);
3037203945Sweongyo	bwn_set_pretbtt(mac);
3038203945Sweongyo	bwn_spu_setdelay(mac, 0);
3039203945Sweongyo	bwn_set_macaddr(mac);
3040203945Sweongyo
3041203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3042203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
3043203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
3044203945Sweongyo
3045203945Sweongyo	return (0);
3046203945Sweongyo}
3047203945Sweongyo
3048203945Sweongyostatic void
3049203945Sweongyobwn_stop(struct bwn_softc *sc, int statechg)
3050203945Sweongyo{
3051203945Sweongyo
3052203945Sweongyo	BWN_LOCK(sc);
3053203945Sweongyo	bwn_stop_locked(sc, statechg);
3054203945Sweongyo	BWN_UNLOCK(sc);
3055203945Sweongyo}
3056203945Sweongyo
3057203945Sweongyostatic void
3058203945Sweongyobwn_stop_locked(struct bwn_softc *sc, int statechg)
3059203945Sweongyo{
3060203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
3061203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3062203945Sweongyo
3063203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3064203945Sweongyo
3065203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
3066203945Sweongyo		/* XXX FIXME opmode not based on VAP */
3067203945Sweongyo		bwn_set_opmode(mac);
3068203945Sweongyo		bwn_set_macaddr(mac);
3069203945Sweongyo	}
3070203945Sweongyo
3071203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
3072203945Sweongyo		bwn_core_stop(mac);
3073203945Sweongyo
3074203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
3075203945Sweongyo	sc->sc_led_blinking = 0;
3076203945Sweongyo
3077203945Sweongyo	bwn_core_exit(mac);
3078203945Sweongyo	sc->sc_rf_enabled = 0;
3079203945Sweongyo
3080203945Sweongyo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3081203945Sweongyo}
3082203945Sweongyo
3083203945Sweongyostatic void
3084203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
3085203945Sweongyo{
3086203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
3087203945Sweongyo	struct wmeParams *p;
3088203945Sweongyo	unsigned int i;
3089203945Sweongyo
3090203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
3091203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3092203945Sweongyo
3093203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
3094203945Sweongyo		p = &(sc->sc_wmeParams[i]);
3095203945Sweongyo
3096203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
3097203945Sweongyo		case BWN_WME_VOICE:
3098203945Sweongyo			p->wmep_txopLimit = 0;
3099203945Sweongyo			p->wmep_aifsn = 2;
3100203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3101203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3102203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3103203945Sweongyo			break;
3104203945Sweongyo		case BWN_WME_VIDEO:
3105203945Sweongyo			p->wmep_txopLimit = 0;
3106203945Sweongyo			p->wmep_aifsn = 2;
3107203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3108203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3109203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3110203945Sweongyo			break;
3111203945Sweongyo		case BWN_WME_BESTEFFORT:
3112203945Sweongyo			p->wmep_txopLimit = 0;
3113203945Sweongyo			p->wmep_aifsn = 3;
3114203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3115203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3116203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3117203945Sweongyo			break;
3118203945Sweongyo		case BWN_WME_BACKGROUND:
3119203945Sweongyo			p->wmep_txopLimit = 0;
3120203945Sweongyo			p->wmep_aifsn = 7;
3121203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3122203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3123203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3124203945Sweongyo			break;
3125203945Sweongyo		default:
3126203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3127203945Sweongyo		}
3128203945Sweongyo	}
3129203945Sweongyo}
3130203945Sweongyo
3131203945Sweongyostatic int
3132203945Sweongyobwn_core_init(struct bwn_mac *mac)
3133203945Sweongyo{
3134203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3135203945Sweongyo	uint64_t hf;
3136203945Sweongyo	int error;
3137203945Sweongyo
3138203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3139203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3140203945Sweongyo
3141204922Sweongyo	siba_powerup(sc->sc_dev, 0);
3142204922Sweongyo	if (!siba_dev_isup(sc->sc_dev))
3143203945Sweongyo		bwn_reset_core(mac,
3144203945Sweongyo		    mac->mac_phy.gmode ? BWN_TGSLOW_SUPPORT_G : 0);
3145203945Sweongyo
3146203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
3147203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
3148203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
3149203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
3150203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
3151203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
3152203945Sweongyo	mac->mac_stats.link_noise = -95;
3153203945Sweongyo	mac->mac_reason_intr = 0;
3154203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
3155203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
3156203945Sweongyo#ifdef BWN_DEBUG
3157203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
3158203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
3159203945Sweongyo#endif
3160203945Sweongyo	mac->mac_suspended = 1;
3161203945Sweongyo	mac->mac_task_state = 0;
3162203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
3163203945Sweongyo
3164203945Sweongyo	mac->mac_phy.init_pre(mac);
3165203945Sweongyo
3166204922Sweongyo	siba_pcicore_intr(sc->sc_dev);
3167203945Sweongyo
3168204922Sweongyo	siba_fix_imcfglobug(sc->sc_dev);
3169203945Sweongyo	bwn_bt_disable(mac);
3170203945Sweongyo	if (mac->mac_phy.prepare_hw) {
3171203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
3172203945Sweongyo		if (error)
3173203945Sweongyo			goto fail0;
3174203945Sweongyo	}
3175203945Sweongyo	error = bwn_chip_init(mac);
3176203945Sweongyo	if (error)
3177203945Sweongyo		goto fail0;
3178203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
3179204922Sweongyo	    siba_get_revid(sc->sc_dev));
3180203945Sweongyo	hf = bwn_hf_read(mac);
3181203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
3182203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
3183204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
3184203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
3185203945Sweongyo		if (mac->mac_phy.rev == 1)
3186203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
3187203945Sweongyo	}
3188203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
3189203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
3190203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
3191203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
3192203945Sweongyo			hf |= BWN_HF_4318_TSSI;
3193203945Sweongyo	}
3194204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW)
3195203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
3196204922Sweongyo	if ((siba_get_type(sc->sc_dev) == SIBA_TYPE_PCI) &&
3197204922Sweongyo	    (siba_get_pcicore_revid(sc->sc_dev) <= 10))
3198203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
3199203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
3200203945Sweongyo	bwn_hf_write(mac, hf);
3201203945Sweongyo
3202203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
3203203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
3204203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
3205203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
3206203945Sweongyo
3207203945Sweongyo	bwn_rate_init(mac);
3208203945Sweongyo	bwn_set_phytxctl(mac);
3209203945Sweongyo
3210203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
3211203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
3212203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
3213203945Sweongyo
3214204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
3215203945Sweongyo		bwn_pio_init(mac);
3216203945Sweongyo	else
3217203945Sweongyo		bwn_dma_init(mac);
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
3233203945Sweongyofail0:
3234204922Sweongyo	siba_powerdown(sc->sc_dev);
3235203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3236203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3237203945Sweongyo	return (error);
3238203945Sweongyo}
3239203945Sweongyo
3240203945Sweongyostatic void
3241203945Sweongyobwn_core_start(struct bwn_mac *mac)
3242203945Sweongyo{
3243203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3244203945Sweongyo	uint32_t tmp;
3245203945Sweongyo
3246203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
3247203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3248203945Sweongyo
3249204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
3250203945Sweongyo		return;
3251203945Sweongyo
3252203945Sweongyo	while (1) {
3253203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
3254203945Sweongyo		if (!(tmp & 0x00000001))
3255203945Sweongyo			break;
3256203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
3257203945Sweongyo	}
3258203945Sweongyo
3259203945Sweongyo	bwn_mac_enable(mac);
3260203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
3261203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
3262203945Sweongyo
3263203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
3264203945Sweongyo}
3265203945Sweongyo
3266203945Sweongyostatic void
3267203945Sweongyobwn_core_exit(struct bwn_mac *mac)
3268203945Sweongyo{
3269204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3270203945Sweongyo	uint32_t macctl;
3271203945Sweongyo
3272204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
3273203945Sweongyo
3274203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
3275203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3276203945Sweongyo
3277203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
3278203945Sweongyo		return;
3279203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
3280203945Sweongyo
3281203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3282203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
3283203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
3284203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3285203945Sweongyo
3286203945Sweongyo	bwn_dma_stop(mac);
3287203945Sweongyo	bwn_pio_stop(mac);
3288203945Sweongyo	bwn_chip_exit(mac);
3289203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
3290204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
3291204922Sweongyo	siba_powerdown(sc->sc_dev);
3292203945Sweongyo}
3293203945Sweongyo
3294203945Sweongyostatic void
3295203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
3296203945Sweongyo{
3297203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3298203945Sweongyo
3299203945Sweongyo	(void)sc;
3300203945Sweongyo	/* XXX do nothing yet */
3301203945Sweongyo}
3302203945Sweongyo
3303203945Sweongyostatic int
3304203945Sweongyobwn_chip_init(struct bwn_mac *mac)
3305203945Sweongyo{
3306204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3307203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
3308203945Sweongyo	uint32_t macctl;
3309203945Sweongyo	int error;
3310203945Sweongyo
3311203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
3312203945Sweongyo	if (phy->gmode)
3313203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
3314203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3315203945Sweongyo
3316203945Sweongyo	error = bwn_fw_fillinfo(mac);
3317203945Sweongyo	if (error)
3318203945Sweongyo		return (error);
3319203945Sweongyo	error = bwn_fw_loaducode(mac);
3320203945Sweongyo	if (error)
3321203945Sweongyo		return (error);
3322203945Sweongyo
3323203945Sweongyo	error = bwn_gpio_init(mac);
3324203945Sweongyo	if (error)
3325203945Sweongyo		return (error);
3326203945Sweongyo
3327203945Sweongyo	error = bwn_fw_loadinitvals(mac);
3328203945Sweongyo	if (error) {
3329204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
3330203945Sweongyo		return (error);
3331203945Sweongyo	}
3332203945Sweongyo	phy->switch_analog(mac, 1);
3333203945Sweongyo	error = bwn_phy_init(mac);
3334203945Sweongyo	if (error) {
3335204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
3336203945Sweongyo		return (error);
3337203945Sweongyo	}
3338203945Sweongyo	if (phy->set_im)
3339203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
3340203945Sweongyo	if (phy->set_antenna)
3341203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
3342203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
3343203945Sweongyo
3344203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
3345203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
3346203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
3347204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
3348203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
3349203945Sweongyo
3350203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3351203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
3352203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3353203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
3354203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
3355203945Sweongyo
3356203945Sweongyo	bwn_set_opmode(mac);
3357204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 3) {
3358203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
3359203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
3360203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
3361203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
3362203945Sweongyo	} else {
3363203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
3364203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
3365203945Sweongyo	}
3366203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
3367203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
3368203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
3369203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
3370203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
3371203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
3372203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
3373204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
3374204922Sweongyo	    siba_read_4(sc->sc_dev, SIBA_TGSLOW) | 0x00100000);
3375204922Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev));
3376203945Sweongyo	return (error);
3377203945Sweongyo}
3378203945Sweongyo
3379203945Sweongyo/* read hostflags */
3380203945Sweongyostatic uint64_t
3381203945Sweongyobwn_hf_read(struct bwn_mac *mac)
3382203945Sweongyo{
3383203945Sweongyo	uint64_t ret;
3384203945Sweongyo
3385203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
3386203945Sweongyo	ret <<= 16;
3387203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
3388203945Sweongyo	ret <<= 16;
3389203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
3390203945Sweongyo	return (ret);
3391203945Sweongyo}
3392203945Sweongyo
3393203945Sweongyostatic void
3394203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
3395203945Sweongyo{
3396203945Sweongyo
3397203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
3398203945Sweongyo	    (value & 0x00000000ffffull));
3399203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
3400203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
3401203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
3402203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
3403203945Sweongyo}
3404203945Sweongyo
3405203945Sweongyostatic void
3406203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
3407203945Sweongyo{
3408203945Sweongyo
3409203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
3410203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
3411203945Sweongyo}
3412203945Sweongyo
3413203945Sweongyostatic void
3414203945Sweongyobwn_rate_init(struct bwn_mac *mac)
3415203945Sweongyo{
3416203945Sweongyo
3417203945Sweongyo	switch (mac->mac_phy.type) {
3418203945Sweongyo	case BWN_PHYTYPE_A:
3419203945Sweongyo	case BWN_PHYTYPE_G:
3420203945Sweongyo	case BWN_PHYTYPE_LP:
3421203945Sweongyo	case BWN_PHYTYPE_N:
3422203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
3423203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
3424203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
3425203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
3426203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
3427203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
3428203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
3429203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
3430203945Sweongyo			break;
3431203945Sweongyo		/* FALLTHROUGH */
3432203945Sweongyo	case BWN_PHYTYPE_B:
3433203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
3434203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
3435203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
3436203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
3437203945Sweongyo		break;
3438203945Sweongyo	default:
3439203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3440203945Sweongyo	}
3441203945Sweongyo}
3442203945Sweongyo
3443203945Sweongyostatic void
3444203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
3445203945Sweongyo{
3446203945Sweongyo	uint16_t offset;
3447203945Sweongyo
3448203945Sweongyo	if (ofdm) {
3449203945Sweongyo		offset = 0x480;
3450203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
3451203945Sweongyo	} else {
3452203945Sweongyo		offset = 0x4c0;
3453203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
3454203945Sweongyo	}
3455203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
3456203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
3457203945Sweongyo}
3458203945Sweongyo
3459203945Sweongyostatic uint8_t
3460203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
3461203945Sweongyo{
3462203945Sweongyo
3463203945Sweongyo	switch (bitrate) {
3464203945Sweongyo	case BWN_CCK_RATE_1MB:
3465203945Sweongyo		return (0x0a);
3466203945Sweongyo	case BWN_CCK_RATE_2MB:
3467203945Sweongyo		return (0x14);
3468203945Sweongyo	case BWN_CCK_RATE_5MB:
3469203945Sweongyo		return (0x37);
3470203945Sweongyo	case BWN_CCK_RATE_11MB:
3471203945Sweongyo		return (0x6e);
3472203945Sweongyo	}
3473203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3474203945Sweongyo	return (0);
3475203945Sweongyo}
3476203945Sweongyo
3477203945Sweongyostatic uint8_t
3478203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
3479203945Sweongyo{
3480203945Sweongyo
3481203945Sweongyo	switch (bitrate) {
3482203945Sweongyo	case BWN_OFDM_RATE_6MB:
3483203945Sweongyo		return (0xb);
3484203945Sweongyo	case BWN_OFDM_RATE_9MB:
3485203945Sweongyo		return (0xf);
3486203945Sweongyo	case BWN_OFDM_RATE_12MB:
3487203945Sweongyo		return (0xa);
3488203945Sweongyo	case BWN_OFDM_RATE_18MB:
3489203945Sweongyo		return (0xe);
3490203945Sweongyo	case BWN_OFDM_RATE_24MB:
3491203945Sweongyo		return (0x9);
3492203945Sweongyo	case BWN_OFDM_RATE_36MB:
3493203945Sweongyo		return (0xd);
3494203945Sweongyo	case BWN_OFDM_RATE_48MB:
3495203945Sweongyo		return (0x8);
3496203945Sweongyo	case BWN_OFDM_RATE_54MB:
3497203945Sweongyo		return (0xc);
3498203945Sweongyo	}
3499203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3500203945Sweongyo	return (0);
3501203945Sweongyo}
3502203945Sweongyo
3503203945Sweongyostatic void
3504203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
3505203945Sweongyo{
3506203945Sweongyo	uint16_t ctl;
3507203945Sweongyo
3508203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
3509203945Sweongyo	    BWN_TX_PHY_TXPWR);
3510203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
3511203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
3512203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
3513203945Sweongyo}
3514203945Sweongyo
3515203945Sweongyostatic void
3516203945Sweongyobwn_pio_init(struct bwn_mac *mac)
3517203945Sweongyo{
3518203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
3519203945Sweongyo
3520203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
3521203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
3522203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
3523203945Sweongyo
3524203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
3525203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
3526203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
3527203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
3528203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
3529203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
3530203945Sweongyo}
3531203945Sweongyo
3532203945Sweongyostatic void
3533203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3534203945Sweongyo    int index)
3535203945Sweongyo{
3536203945Sweongyo	struct bwn_pio_txpkt *tp;
3537204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3538203945Sweongyo	unsigned int i;
3539203945Sweongyo
3540203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
3541203945Sweongyo	tq->tq_index = index;
3542203945Sweongyo
3543203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
3544204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8)
3545203945Sweongyo		tq->tq_size = 1920;
3546203945Sweongyo	else {
3547203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
3548203945Sweongyo		tq->tq_size -= 80;
3549203945Sweongyo	}
3550203945Sweongyo
3551203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
3552203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3553203945Sweongyo		tp = &(tq->tq_pkts[i]);
3554203945Sweongyo		tp->tp_index = i;
3555203945Sweongyo		tp->tp_queue = tq;
3556203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
3557203945Sweongyo	}
3558203945Sweongyo}
3559203945Sweongyo
3560203945Sweongyostatic uint16_t
3561203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
3562203945Sweongyo{
3563203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3564203945Sweongyo	static const uint16_t bases[] = {
3565203945Sweongyo		BWN_PIO_BASE0,
3566203945Sweongyo		BWN_PIO_BASE1,
3567203945Sweongyo		BWN_PIO_BASE2,
3568203945Sweongyo		BWN_PIO_BASE3,
3569203945Sweongyo		BWN_PIO_BASE4,
3570203945Sweongyo		BWN_PIO_BASE5,
3571203945Sweongyo		BWN_PIO_BASE6,
3572203945Sweongyo		BWN_PIO_BASE7,
3573203945Sweongyo	};
3574203945Sweongyo	static const uint16_t bases_rev11[] = {
3575203945Sweongyo		BWN_PIO11_BASE0,
3576203945Sweongyo		BWN_PIO11_BASE1,
3577203945Sweongyo		BWN_PIO11_BASE2,
3578203945Sweongyo		BWN_PIO11_BASE3,
3579203945Sweongyo		BWN_PIO11_BASE4,
3580203945Sweongyo		BWN_PIO11_BASE5,
3581203945Sweongyo	};
3582203945Sweongyo
3583204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 11) {
3584203945Sweongyo		if (index >= N(bases_rev11))
3585203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
3586203945Sweongyo		return (bases_rev11[index]);
3587203945Sweongyo	}
3588203945Sweongyo	if (index >= N(bases))
3589203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
3590203945Sweongyo	return (bases[index]);
3591203945Sweongyo}
3592203945Sweongyo
3593203945Sweongyostatic void
3594203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
3595203945Sweongyo    int index)
3596203945Sweongyo{
3597204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3598203945Sweongyo
3599203945Sweongyo	prq->prq_mac = mac;
3600204922Sweongyo	prq->prq_rev = siba_get_revid(sc->sc_dev);
3601203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
3602203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
3603203945Sweongyo}
3604203945Sweongyo
3605203945Sweongyostatic void
3606203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
3607203945Sweongyo{
3608203945Sweongyo	if (tq == NULL)
3609203945Sweongyo		return;
3610203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
3611203945Sweongyo}
3612203945Sweongyo
3613203945Sweongyostatic void
3614203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
3615203945Sweongyo{
3616203945Sweongyo
3617203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
3618203945Sweongyo}
3619203945Sweongyo
3620203945Sweongyostatic uint16_t
3621203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3622203945Sweongyo    uint16_t offset)
3623203945Sweongyo{
3624203945Sweongyo
3625203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
3626203945Sweongyo}
3627203945Sweongyo
3628203945Sweongyostatic void
3629203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
3630203945Sweongyo{
3631203945Sweongyo	uint32_t ctl;
3632203945Sweongyo	int type;
3633203945Sweongyo	uint16_t base;
3634203945Sweongyo
3635203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
3636203945Sweongyo	base = bwn_dma_base(type, idx);
3637203945Sweongyo	if (type == BWN_DMA_64BIT) {
3638203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
3639203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
3640203945Sweongyo		if (enable)
3641203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
3642203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
3643203945Sweongyo	} else {
3644203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
3645203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
3646203945Sweongyo		if (enable)
3647203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
3648203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
3649203945Sweongyo	}
3650203945Sweongyo}
3651203945Sweongyo
3652203945Sweongyostatic uint64_t
3653203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
3654203945Sweongyo{
3655203945Sweongyo	uint32_t tmp;
3656203945Sweongyo	uint16_t base;
3657203945Sweongyo
3658203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3659203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3660203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
3661203945Sweongyo	base = bwn_dma_base(0, 0);
3662203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3663203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3664203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3665203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
3666203945Sweongyo
3667203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
3668203945Sweongyo}
3669203945Sweongyo
3670203945Sweongyostatic int
3671203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
3672203945Sweongyo{
3673203945Sweongyo
3674203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
3675203945Sweongyo		return (BWN_DMA_30BIT);
3676203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
3677203945Sweongyo		return (BWN_DMA_32BIT);
3678203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
3679203945Sweongyo		return (BWN_DMA_64BIT);
3680203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3681203945Sweongyo	return (BWN_DMA_30BIT);
3682203945Sweongyo}
3683203945Sweongyo
3684203945Sweongyostatic void
3685203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
3686203945Sweongyo{
3687203945Sweongyo	struct bwn_pio_txpkt *tp;
3688203945Sweongyo	unsigned int i;
3689203945Sweongyo
3690203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3691203945Sweongyo		tp = &(tq->tq_pkts[i]);
3692203945Sweongyo		if (tp->tp_m) {
3693203945Sweongyo			m_freem(tp->tp_m);
3694203945Sweongyo			tp->tp_m = NULL;
3695203945Sweongyo		}
3696203945Sweongyo	}
3697203945Sweongyo}
3698203945Sweongyo
3699203945Sweongyostatic uint16_t
3700203945Sweongyobwn_dma_base(int type, int controller_idx)
3701203945Sweongyo{
3702203945Sweongyo	static const uint16_t map64[] = {
3703203945Sweongyo		BWN_DMA64_BASE0,
3704203945Sweongyo		BWN_DMA64_BASE1,
3705203945Sweongyo		BWN_DMA64_BASE2,
3706203945Sweongyo		BWN_DMA64_BASE3,
3707203945Sweongyo		BWN_DMA64_BASE4,
3708203945Sweongyo		BWN_DMA64_BASE5,
3709203945Sweongyo	};
3710203945Sweongyo	static const uint16_t map32[] = {
3711203945Sweongyo		BWN_DMA32_BASE0,
3712203945Sweongyo		BWN_DMA32_BASE1,
3713203945Sweongyo		BWN_DMA32_BASE2,
3714203945Sweongyo		BWN_DMA32_BASE3,
3715203945Sweongyo		BWN_DMA32_BASE4,
3716203945Sweongyo		BWN_DMA32_BASE5,
3717203945Sweongyo	};
3718203945Sweongyo
3719203945Sweongyo	if (type == BWN_DMA_64BIT) {
3720203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
3721203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3722203945Sweongyo		return (map64[controller_idx]);
3723203945Sweongyo	}
3724203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
3725203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3726203945Sweongyo	return (map32[controller_idx]);
3727203945Sweongyo}
3728203945Sweongyo
3729203945Sweongyostatic void
3730203945Sweongyobwn_dma_init(struct bwn_mac *mac)
3731203945Sweongyo{
3732203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3733203945Sweongyo
3734203945Sweongyo	/* setup TX DMA channels. */
3735203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
3736203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
3737203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
3738203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
3739203945Sweongyo	bwn_dma_setup(dma->mcast);
3740203945Sweongyo	/* setup RX DMA channel. */
3741203945Sweongyo	bwn_dma_setup(dma->rx);
3742203945Sweongyo}
3743203945Sweongyo
3744203945Sweongyostatic struct bwn_dma_ring *
3745203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
3746203945Sweongyo    int for_tx, int type)
3747203945Sweongyo{
3748203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3749203945Sweongyo	struct bwn_dma_ring *dr;
3750203945Sweongyo	struct bwn_dmadesc_generic *desc;
3751203945Sweongyo	struct bwn_dmadesc_meta *mt;
3752203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3753203945Sweongyo	int error, i;
3754203945Sweongyo
3755203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
3756203945Sweongyo	if (dr == NULL)
3757203945Sweongyo		goto out;
3758203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
3759203945Sweongyo	if (for_tx)
3760203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
3761203945Sweongyo
3762203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
3763203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
3764203945Sweongyo	if (dr->dr_meta == NULL)
3765203945Sweongyo		goto fail0;
3766203945Sweongyo
3767203945Sweongyo	dr->dr_type = type;
3768203945Sweongyo	dr->dr_mac = mac;
3769203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
3770203945Sweongyo	dr->dr_index = controller_index;
3771203945Sweongyo	if (type == BWN_DMA_64BIT) {
3772203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
3773203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
3774203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
3775203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
3776203945Sweongyo		dr->resume = bwn_dma_64_resume;
3777203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
3778203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
3779203945Sweongyo	} else {
3780203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
3781203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
3782203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
3783203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
3784203945Sweongyo		dr->resume = bwn_dma_32_resume;
3785203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
3786203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
3787203945Sweongyo	}
3788203945Sweongyo	if (for_tx) {
3789203945Sweongyo		dr->dr_tx = 1;
3790203945Sweongyo		dr->dr_curslot = -1;
3791203945Sweongyo	} else {
3792203945Sweongyo		if (dr->dr_index == 0) {
3793203945Sweongyo			dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
3794203945Sweongyo			dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
3795203945Sweongyo		} else
3796203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3797203945Sweongyo	}
3798203945Sweongyo
3799203945Sweongyo	error = bwn_dma_allocringmemory(dr);
3800203945Sweongyo	if (error)
3801203945Sweongyo		goto fail2;
3802203945Sweongyo
3803203945Sweongyo	if (for_tx) {
3804203945Sweongyo		/*
3805203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
3806203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
3807203945Sweongyo		 */
3808203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
3809203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3810203945Sweongyo
3811203945Sweongyo		dr->dr_txhdr_cache =
3812203945Sweongyo		    malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
3813203945Sweongyo			BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
3814203945Sweongyo		KASSERT(dr->dr_txhdr_cache != NULL,
3815203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3816203945Sweongyo
3817203945Sweongyo		/*
3818203945Sweongyo		 * Create TX ring DMA stuffs
3819203945Sweongyo		 */
3820203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
3821203945Sweongyo				    BWN_ALIGN, 0,
3822203945Sweongyo				    BUS_SPACE_MAXADDR,
3823203945Sweongyo				    BUS_SPACE_MAXADDR,
3824203945Sweongyo				    NULL, NULL,
3825203945Sweongyo				    BWN_HDRSIZE(mac),
3826203945Sweongyo				    1,
3827203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
3828203945Sweongyo				    0,
3829203945Sweongyo				    NULL, NULL,
3830203945Sweongyo				    &dr->dr_txring_dtag);
3831203945Sweongyo		if (error) {
3832203945Sweongyo			device_printf(sc->sc_dev,
3833203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
3834203945Sweongyo			goto fail1;
3835203945Sweongyo		}
3836203945Sweongyo
3837203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
3838203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3839203945Sweongyo
3840203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
3841203945Sweongyo			mt->mt_m = NULL;
3842203945Sweongyo			mt->mt_ni = NULL;
3843203945Sweongyo			mt->mt_islast = 0;
3844203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
3845203945Sweongyo			    &mt->mt_dmap);
3846203945Sweongyo			if (error) {
3847203945Sweongyo				device_printf(sc->sc_dev,
3848203945Sweongyo				     "can't create RX buf DMA map\n");
3849203945Sweongyo				goto fail1;
3850203945Sweongyo			}
3851203945Sweongyo
3852203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
3853203945Sweongyo
3854203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
3855203945Sweongyo			mt->mt_m = NULL;
3856203945Sweongyo			mt->mt_ni = NULL;
3857203945Sweongyo			mt->mt_islast = 1;
3858203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
3859203945Sweongyo			    &mt->mt_dmap);
3860203945Sweongyo			if (error) {
3861203945Sweongyo				device_printf(sc->sc_dev,
3862203945Sweongyo				     "can't create RX buf DMA map\n");
3863203945Sweongyo				goto fail1;
3864203945Sweongyo			}
3865203945Sweongyo		}
3866203945Sweongyo	} else {
3867203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3868203945Sweongyo		    &dr->dr_spare_dmap);
3869203945Sweongyo		if (error) {
3870203945Sweongyo			device_printf(sc->sc_dev,
3871203945Sweongyo			    "can't create RX buf DMA map\n");
3872203945Sweongyo			goto out;		/* XXX wrong! */
3873203945Sweongyo		}
3874203945Sweongyo
3875203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
3876203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3877203945Sweongyo
3878203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3879203945Sweongyo			    &mt->mt_dmap);
3880203945Sweongyo			if (error) {
3881203945Sweongyo				device_printf(sc->sc_dev,
3882203945Sweongyo				    "can't create RX buf DMA map\n");
3883203945Sweongyo				goto out;	/* XXX wrong! */
3884203945Sweongyo			}
3885203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
3886203945Sweongyo			if (error) {
3887203945Sweongyo				device_printf(sc->sc_dev,
3888203945Sweongyo				    "failed to allocate RX buf\n");
3889203945Sweongyo				goto out;	/* XXX wrong! */
3890203945Sweongyo			}
3891203945Sweongyo		}
3892203945Sweongyo
3893203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
3894203945Sweongyo		    BUS_DMASYNC_PREWRITE);
3895203945Sweongyo
3896203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
3897203945Sweongyo	}
3898203945Sweongyo
3899203945Sweongyo      out:
3900203945Sweongyo	return (dr);
3901203945Sweongyo
3902203945Sweongyofail2:
3903203945Sweongyo	free(dr->dr_txhdr_cache, M_DEVBUF);
3904203945Sweongyofail1:
3905203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
3906203945Sweongyofail0:
3907203945Sweongyo	free(dr, M_DEVBUF);
3908203945Sweongyo	return (NULL);
3909203945Sweongyo}
3910203945Sweongyo
3911203945Sweongyostatic void
3912203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
3913203945Sweongyo{
3914203945Sweongyo
3915203945Sweongyo	if (dr == NULL)
3916203945Sweongyo		return;
3917203945Sweongyo
3918203945Sweongyo	bwn_dma_free_descbufs(*dr);
3919203945Sweongyo	bwn_dma_free_ringmemory(*dr);
3920203945Sweongyo
3921203945Sweongyo	free((*dr)->dr_txhdr_cache, M_DEVBUF);
3922203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
3923203945Sweongyo	free(*dr, M_DEVBUF);
3924203945Sweongyo
3925203945Sweongyo	*dr = NULL;
3926203945Sweongyo}
3927203945Sweongyo
3928203945Sweongyostatic void
3929203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
3930203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
3931203945Sweongyo{
3932203945Sweongyo	struct bwn_dmadesc32 *desc;
3933203945Sweongyo
3934203945Sweongyo	*meta = &(dr->dr_meta[slot]);
3935203945Sweongyo	desc = dr->dr_ring_descbase;
3936203945Sweongyo	desc = &(desc[slot]);
3937203945Sweongyo
3938203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
3939203945Sweongyo}
3940203945Sweongyo
3941203945Sweongyostatic void
3942203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
3943203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
3944203945Sweongyo    int start, int end, int irq)
3945203945Sweongyo{
3946203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
3947204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
3948203945Sweongyo	uint32_t addr, addrext, ctl;
3949203945Sweongyo	int slot;
3950203945Sweongyo
3951203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
3952203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
3953203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3954203945Sweongyo
3955203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
3956203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
3957204922Sweongyo	addr |= siba_dma_translation(sc->sc_dev);
3958203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
3959203945Sweongyo	if (slot == dr->dr_numslots - 1)
3960203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
3961203945Sweongyo	if (start)
3962203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
3963203945Sweongyo	if (end)
3964203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
3965203945Sweongyo	if (irq)
3966203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
3967203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
3968203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
3969203945Sweongyo
3970203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
3971203945Sweongyo	desc->dma.dma32.address = htole32(addr);
3972203945Sweongyo}
3973203945Sweongyo
3974203945Sweongyostatic void
3975203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
3976203945Sweongyo{
3977203945Sweongyo
3978203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
3979203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
3980203945Sweongyo}
3981203945Sweongyo
3982203945Sweongyostatic void
3983203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
3984203945Sweongyo{
3985203945Sweongyo
3986203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
3987203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
3988203945Sweongyo}
3989203945Sweongyo
3990203945Sweongyostatic void
3991203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
3992203945Sweongyo{
3993203945Sweongyo
3994203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
3995203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
3996203945Sweongyo}
3997203945Sweongyo
3998203945Sweongyostatic int
3999203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
4000203945Sweongyo{
4001203945Sweongyo	uint32_t val;
4002203945Sweongyo
4003203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
4004203945Sweongyo	val &= BWN_DMA32_RXDPTR;
4005203945Sweongyo
4006203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
4007203945Sweongyo}
4008203945Sweongyo
4009203945Sweongyostatic void
4010203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
4011203945Sweongyo{
4012203945Sweongyo
4013203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
4014203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
4015203945Sweongyo}
4016203945Sweongyo
4017203945Sweongyostatic void
4018203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
4019203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
4020203945Sweongyo{
4021203945Sweongyo	struct bwn_dmadesc64 *desc;
4022203945Sweongyo
4023203945Sweongyo	*meta = &(dr->dr_meta[slot]);
4024203945Sweongyo	desc = dr->dr_ring_descbase;
4025203945Sweongyo	desc = &(desc[slot]);
4026203945Sweongyo
4027203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
4028203945Sweongyo}
4029203945Sweongyo
4030203945Sweongyostatic void
4031203945Sweongyobwn_dma_64_setdesc(struct bwn_dma_ring *dr,
4032203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
4033203945Sweongyo    int start, int end, int irq)
4034203945Sweongyo{
4035203945Sweongyo	struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
4036204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
4037203945Sweongyo	int slot;
4038203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
4039203945Sweongyo	uint32_t addrlo, addrhi;
4040203945Sweongyo	uint32_t addrext;
4041203945Sweongyo
4042203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
4043203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
4044203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4045203945Sweongyo
4046203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
4047203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
4048203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
4049203945Sweongyo	    30;
4050204922Sweongyo	addrhi |= (siba_dma_translation(sc->sc_dev) << 1);
4051203945Sweongyo	if (slot == dr->dr_numslots - 1)
4052203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
4053203945Sweongyo	if (start)
4054203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
4055203945Sweongyo	if (end)
4056203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
4057203945Sweongyo	if (irq)
4058203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
4059203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
4060203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
4061203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
4062203945Sweongyo
4063203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
4064203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
4065203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
4066203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
4067203945Sweongyo}
4068203945Sweongyo
4069203945Sweongyostatic void
4070203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
4071203945Sweongyo{
4072203945Sweongyo
4073203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
4074203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4075203945Sweongyo}
4076203945Sweongyo
4077203945Sweongyostatic void
4078203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
4079203945Sweongyo{
4080203945Sweongyo
4081203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4082203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
4083203945Sweongyo}
4084203945Sweongyo
4085203945Sweongyostatic void
4086203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
4087203945Sweongyo{
4088203945Sweongyo
4089203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4090203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
4091203945Sweongyo}
4092203945Sweongyo
4093203945Sweongyostatic int
4094203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
4095203945Sweongyo{
4096203945Sweongyo	uint32_t val;
4097203945Sweongyo
4098203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
4099203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
4100203945Sweongyo
4101203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
4102203945Sweongyo}
4103203945Sweongyo
4104203945Sweongyostatic void
4105203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
4106203945Sweongyo{
4107203945Sweongyo
4108203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
4109203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4110203945Sweongyo}
4111203945Sweongyo
4112203945Sweongyostatic int
4113203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
4114203945Sweongyo{
4115203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4116203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4117203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4118203945Sweongyo	int error;
4119203945Sweongyo
4120203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
4121203945Sweongyo			    BWN_ALIGN, 0,
4122203945Sweongyo			    BUS_SPACE_MAXADDR,
4123203945Sweongyo			    BUS_SPACE_MAXADDR,
4124203945Sweongyo			    NULL, NULL,
4125203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
4126203945Sweongyo			    1,
4127203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
4128203945Sweongyo			    0,
4129203945Sweongyo			    NULL, NULL,
4130203945Sweongyo			    &dr->dr_ring_dtag);
4131203945Sweongyo	if (error) {
4132203945Sweongyo		device_printf(sc->sc_dev,
4133203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
4134203945Sweongyo		return (-1);
4135203945Sweongyo	}
4136203945Sweongyo
4137203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
4138203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
4139203945Sweongyo	    &dr->dr_ring_dmap);
4140203945Sweongyo	if (error) {
4141203945Sweongyo		device_printf(sc->sc_dev,
4142203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
4143203945Sweongyo		return (-1);
4144203945Sweongyo	}
4145203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
4146203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
4147203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
4148203945Sweongyo	if (error) {
4149203945Sweongyo		device_printf(sc->sc_dev,
4150203945Sweongyo		    "can't load DMA mem: TODO free\n");
4151203945Sweongyo		return (-1);
4152203945Sweongyo	}
4153203945Sweongyo
4154203945Sweongyo	return (0);
4155203945Sweongyo}
4156203945Sweongyo
4157203945Sweongyostatic void
4158203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
4159203945Sweongyo{
4160204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
4161203945Sweongyo	uint64_t ring64;
4162203945Sweongyo	uint32_t addrext, ring32, value;
4163204922Sweongyo	uint32_t trans = siba_dma_translation(sc->sc_dev);
4164203945Sweongyo
4165203945Sweongyo	if (dr->dr_tx) {
4166203945Sweongyo		dr->dr_curslot = -1;
4167203945Sweongyo
4168203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4169203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
4170203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
4171203945Sweongyo			    >> 30;
4172203945Sweongyo			value = BWN_DMA64_TXENABLE;
4173203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
4174203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
4175203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
4176203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
4177203945Sweongyo			    (ring64 & 0xffffffff));
4178203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
4179203945Sweongyo			    ((ring64 >> 32) &
4180203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
4181203945Sweongyo		} else {
4182203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
4183203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4184203945Sweongyo			value = BWN_DMA32_TXENABLE;
4185203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
4186203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
4187203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
4188203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
4189203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4190203945Sweongyo		}
4191203945Sweongyo		return;
4192203945Sweongyo	}
4193203945Sweongyo
4194203945Sweongyo	/*
4195203945Sweongyo	 * set for RX
4196203945Sweongyo	 */
4197203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
4198203945Sweongyo
4199203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
4200203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
4201203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
4202203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
4203203945Sweongyo		value |= BWN_DMA64_RXENABLE;
4204203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
4205203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
4206203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
4207203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
4208203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
4209203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
4210203945Sweongyo		    | (trans << 1));
4211203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
4212203945Sweongyo		    sizeof(struct bwn_dmadesc64));
4213203945Sweongyo	} else {
4214203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
4215203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4216203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
4217203945Sweongyo		value |= BWN_DMA32_RXENABLE;
4218203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
4219203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
4220203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
4221203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
4222203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4223203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
4224203945Sweongyo		    sizeof(struct bwn_dmadesc32));
4225203945Sweongyo	}
4226203945Sweongyo}
4227203945Sweongyo
4228203945Sweongyostatic void
4229203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
4230203945Sweongyo{
4231203945Sweongyo
4232203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
4233203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
4234203945Sweongyo	    dr->dr_ring_dmap);
4235203945Sweongyo}
4236203945Sweongyo
4237203945Sweongyostatic void
4238203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
4239203945Sweongyo{
4240203945Sweongyo
4241203945Sweongyo	if (dr->dr_tx) {
4242203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4243203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4244203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
4245203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
4246203945Sweongyo		} else
4247203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
4248203945Sweongyo	} else {
4249203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4250203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4251203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
4252203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
4253203945Sweongyo		} else
4254203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
4255203945Sweongyo	}
4256203945Sweongyo}
4257203945Sweongyo
4258203945Sweongyostatic void
4259203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
4260203945Sweongyo{
4261203945Sweongyo	struct bwn_dmadesc_generic *desc;
4262203945Sweongyo	struct bwn_dmadesc_meta *meta;
4263203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4264203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4265203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4266203945Sweongyo	int i;
4267203945Sweongyo
4268203945Sweongyo	if (!dr->dr_usedslot)
4269203945Sweongyo		return;
4270203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
4271203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
4272203945Sweongyo
4273203945Sweongyo		if (meta->mt_m == NULL) {
4274203945Sweongyo			if (!dr->dr_tx)
4275203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
4276203945Sweongyo				    __func__);
4277203945Sweongyo			continue;
4278203945Sweongyo		}
4279203945Sweongyo		if (dr->dr_tx) {
4280203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
4281203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
4282203945Sweongyo				    meta->mt_dmap);
4283203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
4284203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
4285203945Sweongyo				    meta->mt_dmap);
4286203945Sweongyo		} else
4287203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
4288203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
4289203945Sweongyo	}
4290203945Sweongyo}
4291203945Sweongyo
4292203945Sweongyostatic int
4293203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
4294203945Sweongyo    int type)
4295203945Sweongyo{
4296203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4297203945Sweongyo	uint32_t value;
4298203945Sweongyo	int i;
4299203945Sweongyo	uint16_t offset;
4300203945Sweongyo
4301203945Sweongyo	for (i = 0; i < 10; i++) {
4302203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4303203945Sweongyo		    BWN_DMA32_TXSTATUS;
4304203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4305203945Sweongyo		if (type == BWN_DMA_64BIT) {
4306203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4307203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
4308203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
4309203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
4310203945Sweongyo				break;
4311203945Sweongyo		} else {
4312203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4313203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
4314203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
4315203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
4316203945Sweongyo				break;
4317203945Sweongyo		}
4318203945Sweongyo		DELAY(1000);
4319203945Sweongyo	}
4320203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
4321203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4322203945Sweongyo	for (i = 0; i < 10; i++) {
4323203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4324203945Sweongyo						   BWN_DMA32_TXSTATUS;
4325203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4326203945Sweongyo		if (type == BWN_DMA_64BIT) {
4327203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4328203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
4329203945Sweongyo				i = -1;
4330203945Sweongyo				break;
4331203945Sweongyo			}
4332203945Sweongyo		} else {
4333203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4334203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
4335203945Sweongyo				i = -1;
4336203945Sweongyo				break;
4337203945Sweongyo			}
4338203945Sweongyo		}
4339203945Sweongyo		DELAY(1000);
4340203945Sweongyo	}
4341203945Sweongyo	if (i != -1) {
4342203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4343203945Sweongyo		return (ENODEV);
4344203945Sweongyo	}
4345203945Sweongyo	DELAY(1000);
4346203945Sweongyo
4347203945Sweongyo	return (0);
4348203945Sweongyo}
4349203945Sweongyo
4350203945Sweongyostatic int
4351203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
4352203945Sweongyo    int type)
4353203945Sweongyo{
4354203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4355203945Sweongyo	uint32_t value;
4356203945Sweongyo	int i;
4357203945Sweongyo	uint16_t offset;
4358203945Sweongyo
4359203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
4360203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4361203945Sweongyo	for (i = 0; i < 10; i++) {
4362203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
4363203945Sweongyo		    BWN_DMA32_RXSTATUS;
4364203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4365203945Sweongyo		if (type == BWN_DMA_64BIT) {
4366203945Sweongyo			value &= BWN_DMA64_RXSTAT;
4367203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
4368203945Sweongyo				i = -1;
4369203945Sweongyo				break;
4370203945Sweongyo			}
4371203945Sweongyo		} else {
4372203945Sweongyo			value &= BWN_DMA32_RXSTATE;
4373203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
4374203945Sweongyo				i = -1;
4375203945Sweongyo				break;
4376203945Sweongyo			}
4377203945Sweongyo		}
4378203945Sweongyo		DELAY(1000);
4379203945Sweongyo	}
4380203945Sweongyo	if (i != -1) {
4381203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4382203945Sweongyo		return (ENODEV);
4383203945Sweongyo	}
4384203945Sweongyo
4385203945Sweongyo	return (0);
4386203945Sweongyo}
4387203945Sweongyo
4388203945Sweongyostatic void
4389203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
4390203945Sweongyo    struct bwn_dmadesc_meta *meta)
4391203945Sweongyo{
4392203945Sweongyo
4393203945Sweongyo	if (meta->mt_m != NULL) {
4394203945Sweongyo		m_freem(meta->mt_m);
4395203945Sweongyo		meta->mt_m = NULL;
4396203945Sweongyo	}
4397203945Sweongyo	if (meta->mt_ni != NULL) {
4398203945Sweongyo		ieee80211_free_node(meta->mt_ni);
4399203945Sweongyo		meta->mt_ni = NULL;
4400203945Sweongyo	}
4401203945Sweongyo}
4402203945Sweongyo
4403203945Sweongyostatic void
4404203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4405203945Sweongyo{
4406203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
4407203945Sweongyo	unsigned char *frame;
4408203945Sweongyo
4409203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
4410203945Sweongyo	rxhdr->frame_len = 0;
4411203945Sweongyo
4412203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
4413203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
4414203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4415203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
4416203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
4417203945Sweongyo}
4418203945Sweongyo
4419203945Sweongyostatic uint8_t
4420203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4421203945Sweongyo{
4422203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
4423203945Sweongyo
4424203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
4425203945Sweongyo	    == 0xff);
4426203945Sweongyo}
4427203945Sweongyo
4428203945Sweongyostatic void
4429203945Sweongyobwn_wme_init(struct bwn_mac *mac)
4430203945Sweongyo{
4431203945Sweongyo
4432203945Sweongyo	bwn_wme_load(mac);
4433203945Sweongyo
4434203945Sweongyo	/* enable WME support. */
4435203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
4436203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
4437203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
4438203945Sweongyo}
4439203945Sweongyo
4440203945Sweongyostatic void
4441203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
4442203945Sweongyo{
4443203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4444203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4445203945Sweongyo	uint16_t delay;	/* microsec */
4446203945Sweongyo
4447203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
4448203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
4449203945Sweongyo		delay = 500;
4450203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
4451203945Sweongyo		delay = max(delay, (uint16_t)2400);
4452203945Sweongyo
4453203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
4454203945Sweongyo}
4455203945Sweongyo
4456203945Sweongyostatic void
4457203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
4458203945Sweongyo{
4459204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4460203945Sweongyo	uint64_t hf;
4461203945Sweongyo
4462203945Sweongyo	if (bwn_bluetooth == 0)
4463203945Sweongyo		return;
4464204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCOEXIST) == 0)
4465203945Sweongyo		return;
4466203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
4467203945Sweongyo		return;
4468203945Sweongyo
4469203945Sweongyo	hf = bwn_hf_read(mac);
4470204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCMOD)
4471203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
4472203945Sweongyo	else
4473203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
4474203945Sweongyo	bwn_hf_write(mac, hf);
4475203945Sweongyo}
4476203945Sweongyo
4477203945Sweongyostatic void
4478203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
4479203945Sweongyo{
4480203945Sweongyo
4481203945Sweongyo	bwn_mac_write_bssid(mac);
4482203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF, mac->mac_sc->sc_macaddr);
4483203945Sweongyo}
4484203945Sweongyo
4485203945Sweongyostatic void
4486203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
4487203945Sweongyo{
4488203945Sweongyo	int i;
4489203945Sweongyo
4490203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
4491203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
4492203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
4493203945Sweongyo
4494203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
4495203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
4496203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
4497203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
4498203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
4499203945Sweongyo		}
4500203945Sweongyo		mac->mac_key[i].keyconf = NULL;
4501203945Sweongyo	}
4502203945Sweongyo}
4503203945Sweongyo
4504203945Sweongyostatic void
4505203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
4506203945Sweongyo{
4507204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4508203945Sweongyo
4509204922Sweongyo	mac->mac_max_nr_keys = (siba_get_revid(sc->sc_dev) >= 5) ? 58 : 20;
4510203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
4511203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4512203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
4513203945Sweongyo	mac->mac_ktp *= 2;
4514204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5)
4515204922Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT, mac->mac_max_nr_keys - 8);
4516203945Sweongyo	bwn_clear_keys(mac);
4517203945Sweongyo}
4518203945Sweongyo
4519203945Sweongyostatic void
4520203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
4521203945Sweongyo{
4522204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4523203945Sweongyo
4524203945Sweongyo	bwn_phy_exit(mac);
4525204922Sweongyo	siba_gpio_set(sc->sc_dev, 0);
4526203945Sweongyo}
4527203945Sweongyo
4528203945Sweongyostatic int
4529203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
4530203945Sweongyo{
4531203945Sweongyo	int error;
4532203945Sweongyo
4533203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
4534203945Sweongyo	if (error == 0)
4535203945Sweongyo		return (0);
4536203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
4537203945Sweongyo	if (error == 0)
4538203945Sweongyo		return (0);
4539203945Sweongyo	return (error);
4540203945Sweongyo}
4541203945Sweongyo
4542203945Sweongyostatic int
4543203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
4544203945Sweongyo{
4545204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4546204922Sweongyo	uint32_t mask = 0x1f, set = 0xf, value;
4547203945Sweongyo
4548203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4549203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
4550203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
4551203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
4552203945Sweongyo
4553204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4301) {
4554203945Sweongyo		mask |= 0x0060;
4555203945Sweongyo		set |= 0x0060;
4556203945Sweongyo	}
4557204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL) {
4558203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
4559203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
4560203945Sweongyo		mask |= 0x0200;
4561203945Sweongyo		set |= 0x0200;
4562203945Sweongyo	}
4563204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 2)
4564203945Sweongyo		mask |= 0x0010;
4565204922Sweongyo
4566204922Sweongyo	value = siba_gpio_get(sc->sc_dev);
4567204922Sweongyo	if (value == -1)
4568203945Sweongyo		return (0);
4569204922Sweongyo	siba_gpio_set(sc->sc_dev, (value & mask) | set);
4570203945Sweongyo
4571203945Sweongyo	return (0);
4572203945Sweongyo}
4573203945Sweongyo
4574203945Sweongyostatic int
4575203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
4576203945Sweongyo{
4577203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
4578203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
4579203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
4580203945Sweongyo	const struct bwn_fwhdr *hdr;
4581203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
4582203945Sweongyo	int error;
4583203945Sweongyo
4584203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
4585203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
4586203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
4587203945Sweongyo	if (error)
4588203945Sweongyo		return (error);
4589203945Sweongyo	if (fw->initvals_band.fw) {
4590203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
4591203945Sweongyo		error = bwn_fwinitvals_write(mac,
4592203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
4593203945Sweongyo		    be32toh(hdr->size),
4594203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
4595203945Sweongyo	}
4596203945Sweongyo	return (error);
4597203945Sweongyo#undef GETFWOFFSET
4598203945Sweongyo}
4599203945Sweongyo
4600203945Sweongyostatic int
4601203945Sweongyobwn_phy_init(struct bwn_mac *mac)
4602203945Sweongyo{
4603203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4604203945Sweongyo	int error;
4605203945Sweongyo
4606203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
4607203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4608203945Sweongyo	error = mac->mac_phy.init(mac);
4609203945Sweongyo	if (error) {
4610203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
4611203945Sweongyo		goto fail0;
4612203945Sweongyo	}
4613203945Sweongyo	error = bwn_switch_channel(mac,
4614203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
4615203945Sweongyo	if (error) {
4616203945Sweongyo		device_printf(sc->sc_dev,
4617203945Sweongyo		    "failed to switch default channel\n");
4618203945Sweongyo		goto fail1;
4619203945Sweongyo	}
4620203945Sweongyo	return (0);
4621203945Sweongyofail1:
4622203945Sweongyo	if (mac->mac_phy.exit)
4623203945Sweongyo		mac->mac_phy.exit(mac);
4624203945Sweongyofail0:
4625203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4626203945Sweongyo
4627203945Sweongyo	return (error);
4628203945Sweongyo}
4629203945Sweongyo
4630203945Sweongyostatic void
4631203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
4632203945Sweongyo{
4633203945Sweongyo	uint16_t ant;
4634203945Sweongyo	uint16_t tmp;
4635203945Sweongyo
4636203945Sweongyo	ant = bwn_ant2phy(antenna);
4637203945Sweongyo
4638203945Sweongyo	/* For ACK/CTS */
4639203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
4640203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4641203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
4642203945Sweongyo	/* For Probe Resposes */
4643203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
4644203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4645203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
4646203945Sweongyo}
4647203945Sweongyo
4648203945Sweongyostatic void
4649203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
4650203945Sweongyo{
4651203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4652203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4653203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
4654203945Sweongyo	uint32_t ctl;
4655203945Sweongyo	uint16_t cfp_pretbtt;
4656203945Sweongyo
4657203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
4658203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
4659203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
4660203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
4661203945Sweongyo	ctl |= BWN_MACCTL_STA;
4662203945Sweongyo
4663203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4664203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
4665203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
4666203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
4667203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
4668203945Sweongyo	ctl |= sc->sc_filters;
4669203945Sweongyo
4670204922Sweongyo	if (siba_get_revid(sc->sc_dev) <= 4)
4671203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
4672203945Sweongyo
4673203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
4674203945Sweongyo
4675203945Sweongyo	cfp_pretbtt = 2;
4676203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
4677204922Sweongyo		if (siba_get_chipid(sc->sc_dev) == 0x4306 &&
4678204922Sweongyo		    siba_get_chiprev(sc->sc_dev) == 3)
4679203945Sweongyo			cfp_pretbtt = 100;
4680203945Sweongyo		else
4681203945Sweongyo			cfp_pretbtt = 50;
4682203945Sweongyo	}
4683203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
4684203945Sweongyo}
4685203945Sweongyo
4686203945Sweongyostatic int
4687203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
4688203945Sweongyo{
4689203945Sweongyo	uint32_t tmp;
4690203945Sweongyo	uint16_t base;
4691203945Sweongyo
4692203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
4693203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
4694203945Sweongyo		return (BWN_DMA_64BIT);
4695203945Sweongyo	base = bwn_dma_base(0, 0);
4696203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
4697203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
4698203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
4699203945Sweongyo		return (BWN_DMA_32BIT);
4700203945Sweongyo
4701203945Sweongyo	return (BWN_DMA_30BIT);
4702203945Sweongyo}
4703203945Sweongyo
4704203945Sweongyostatic void
4705203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
4706203945Sweongyo{
4707203945Sweongyo	if (!error) {
4708203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
4709203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
4710203945Sweongyo	}
4711203945Sweongyo}
4712203945Sweongyo
4713203945Sweongyostatic void
4714203945Sweongyobwn_phy_g_init_sub(struct bwn_mac *mac)
4715203945Sweongyo{
4716203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4717203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4718204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4719203945Sweongyo	uint16_t i, tmp;
4720203945Sweongyo
4721203945Sweongyo	if (phy->rev == 1)
4722203945Sweongyo		bwn_phy_init_b5(mac);
4723203945Sweongyo	else
4724203945Sweongyo		bwn_phy_init_b6(mac);
4725203945Sweongyo
4726203945Sweongyo	if (phy->rev >= 2 || phy->gmode)
4727203945Sweongyo		bwn_phy_init_a(mac);
4728203945Sweongyo
4729203945Sweongyo	if (phy->rev >= 2) {
4730203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
4731203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
4732203945Sweongyo	}
4733203945Sweongyo	if (phy->rev == 2) {
4734203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
4735203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4736203945Sweongyo	}
4737203945Sweongyo	if (phy->rev > 5) {
4738203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
4739203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4740203945Sweongyo	}
4741203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4742203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
4743203945Sweongyo		tmp &= BWN_PHYVER_VERSION;
4744203945Sweongyo		if (tmp == 3 || tmp == 5) {
4745203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
4746203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
4747203945Sweongyo		}
4748203945Sweongyo		if (tmp == 5) {
4749203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
4750203945Sweongyo			    0x1f00);
4751203945Sweongyo		}
4752203945Sweongyo	}
4753203945Sweongyo	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
4754203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
4755203945Sweongyo	if (phy->rf_rev == 8) {
4756203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
4757203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
4758203945Sweongyo	}
4759203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
4760203945Sweongyo		bwn_loopback_calcgain(mac);
4761203945Sweongyo
4762203945Sweongyo	if (phy->rf_rev != 8) {
4763203945Sweongyo		if (pg->pg_initval == 0xffff)
4764203945Sweongyo			pg->pg_initval = bwn_rf_init_bcm2050(mac);
4765203945Sweongyo		else
4766203945Sweongyo			BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
4767203945Sweongyo	}
4768203945Sweongyo	bwn_lo_g_init(mac);
4769203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
4770203945Sweongyo		BWN_RF_WRITE(mac, 0x52,
4771203945Sweongyo		    (BWN_RF_READ(mac, 0x52) & 0xff00)
4772203945Sweongyo		    | pg->pg_loctl.tx_bias |
4773203945Sweongyo		    pg->pg_loctl.tx_magn);
4774203945Sweongyo	} else {
4775203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
4776203945Sweongyo	}
4777203945Sweongyo	if (phy->rev >= 6) {
4778203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
4779203945Sweongyo		    (pg->pg_loctl.tx_bias << 12));
4780203945Sweongyo	}
4781204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
4782203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
4783203945Sweongyo	else
4784203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
4785203945Sweongyo	if (phy->rev < 2)
4786203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
4787203945Sweongyo	else
4788203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
4789203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4790203945Sweongyo		bwn_lo_g_adjust(mac);
4791203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
4792203945Sweongyo	}
4793203945Sweongyo
4794204922Sweongyo	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
4795203945Sweongyo		for (i = 0; i < 64; i++) {
4796203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
4797203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
4798203945Sweongyo			    (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
4799203945Sweongyo			    -32), 31));
4800203945Sweongyo		}
4801203945Sweongyo		bwn_nrssi_threshold(mac);
4802203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
4803203945Sweongyo		if (pg->pg_nrssi[0] == -1000) {
4804203945Sweongyo			KASSERT(pg->pg_nrssi[1] == -1000,
4805203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
4806203945Sweongyo			bwn_nrssi_slope_11g(mac);
4807203945Sweongyo		} else
4808203945Sweongyo			bwn_nrssi_threshold(mac);
4809203945Sweongyo	}
4810203945Sweongyo	if (phy->rf_rev == 8)
4811203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
4812203945Sweongyo	bwn_phy_hwpctl_init(mac);
4813204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4306
4814204922Sweongyo	     && siba_get_chippkg(sc->sc_dev) == 2) || 0) {
4815203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
4816203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
4817203945Sweongyo	}
4818203945Sweongyo}
4819203945Sweongyo
4820203945Sweongyostatic uint8_t
4821203945Sweongyobwn_has_hwpctl(struct bwn_mac *mac)
4822203945Sweongyo{
4823203945Sweongyo
4824203945Sweongyo	if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
4825203945Sweongyo		return (0);
4826203945Sweongyo	return (mac->mac_phy.use_hwpctl(mac));
4827203945Sweongyo}
4828203945Sweongyo
4829203945Sweongyostatic void
4830203945Sweongyobwn_phy_init_b5(struct bwn_mac *mac)
4831203945Sweongyo{
4832203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4833203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4834204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4835203945Sweongyo	uint16_t offset, value;
4836203945Sweongyo	uint8_t old_channel;
4837203945Sweongyo
4838203945Sweongyo	if (phy->analog == 1)
4839203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0050);
4840204922Sweongyo	if ((siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM) &&
4841204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306)) {
4842203945Sweongyo		value = 0x2120;
4843203945Sweongyo		for (offset = 0x00a8; offset < 0x00c7; offset++) {
4844203945Sweongyo			BWN_PHY_WRITE(mac, offset, value);
4845203945Sweongyo			value += 0x202;
4846203945Sweongyo		}
4847203945Sweongyo	}
4848203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
4849203945Sweongyo	if (phy->rf_ver == 0x2050)
4850203945Sweongyo		BWN_PHY_WRITE(mac, 0x0038, 0x0667);
4851203945Sweongyo
4852203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4853203945Sweongyo		if (phy->rf_ver == 0x2050) {
4854203945Sweongyo			BWN_RF_SET(mac, 0x007a, 0x0020);
4855203945Sweongyo			BWN_RF_SET(mac, 0x0051, 0x0004);
4856203945Sweongyo		}
4857203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
4858203945Sweongyo
4859203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
4860203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
4861203945Sweongyo
4862203945Sweongyo		BWN_PHY_WRITE(mac, 0x001c, 0x186a);
4863203945Sweongyo
4864203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
4865203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
4866203945Sweongyo		BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
4867203945Sweongyo	}
4868203945Sweongyo
4869203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
4870203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
4871203945Sweongyo
4872203945Sweongyo	if (phy->analog == 1) {
4873203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xce00);
4874203945Sweongyo		BWN_PHY_WRITE(mac, 0x0021, 0x3763);
4875203945Sweongyo		BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
4876203945Sweongyo		BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
4877203945Sweongyo		BWN_PHY_WRITE(mac, 0x0024, 0x037e);
4878203945Sweongyo	} else
4879203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
4880203945Sweongyo	BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
4881203945Sweongyo	BWN_WRITE_2(mac, 0x03ec, 0x3f22);
4882203945Sweongyo
4883203945Sweongyo	if (phy->analog == 1)
4884203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
4885203945Sweongyo	else
4886203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x301c);
4887203945Sweongyo
4888203945Sweongyo	if (phy->analog == 0)
4889203945Sweongyo		BWN_WRITE_2(mac, 0x03e4, 0x3000);
4890203945Sweongyo
4891203945Sweongyo	old_channel = phy->chan;
4892203945Sweongyo	bwn_phy_g_switch_chan(mac, 7, 0);
4893203945Sweongyo
4894203945Sweongyo	if (phy->rf_ver != 0x2050) {
4895203945Sweongyo		BWN_RF_WRITE(mac, 0x0075, 0x0080);
4896203945Sweongyo		BWN_RF_WRITE(mac, 0x0079, 0x0081);
4897203945Sweongyo	}
4898203945Sweongyo
4899203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
4900203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
4901203945Sweongyo
4902203945Sweongyo	if (phy->rf_ver == 0x2050) {
4903203945Sweongyo		BWN_RF_WRITE(mac, 0x0050, 0x0020);
4904203945Sweongyo		BWN_RF_WRITE(mac, 0x005a, 0x0070);
4905203945Sweongyo	}
4906203945Sweongyo
4907203945Sweongyo	BWN_RF_WRITE(mac, 0x005b, 0x007b);
4908203945Sweongyo	BWN_RF_WRITE(mac, 0x005c, 0x00b0);
4909203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0007);
4910203945Sweongyo
4911203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
4912203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0080);
4913203945Sweongyo	BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
4914203945Sweongyo	BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
4915203945Sweongyo
4916203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
4917203945Sweongyo	    pg->pg_txctl);
4918203945Sweongyo
4919203945Sweongyo	if (phy->rf_ver == 0x2050)
4920203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
4921203945Sweongyo
4922203945Sweongyo	BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
4923203945Sweongyo}
4924203945Sweongyo
4925203945Sweongyostatic void
4926203945Sweongyobwn_loopback_calcgain(struct bwn_mac *mac)
4927203945Sweongyo{
4928203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4929203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4930204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4931203945Sweongyo	uint16_t backup_phy[16] = { 0 };
4932203945Sweongyo	uint16_t backup_radio[3];
4933203945Sweongyo	uint16_t backup_bband;
4934203945Sweongyo	uint16_t i, j, loop_i_max;
4935203945Sweongyo	uint16_t trsw_rx;
4936203945Sweongyo	uint16_t loop1_outer_done, loop1_inner_done;
4937203945Sweongyo
4938203945Sweongyo	backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
4939203945Sweongyo	backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
4940203945Sweongyo	backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
4941203945Sweongyo	backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
4942203945Sweongyo	if (phy->rev != 1) {
4943203945Sweongyo		backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
4944203945Sweongyo		backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
4945203945Sweongyo	}
4946203945Sweongyo	backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
4947203945Sweongyo	backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
4948203945Sweongyo	backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
4949203945Sweongyo	backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
4950203945Sweongyo	backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
4951203945Sweongyo	backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
4952203945Sweongyo	backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
4953203945Sweongyo	backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
4954203945Sweongyo	backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
4955203945Sweongyo	backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
4956203945Sweongyo	backup_bband = pg->pg_bbatt.att;
4957203945Sweongyo	backup_radio[0] = BWN_RF_READ(mac, 0x52);
4958203945Sweongyo	backup_radio[1] = BWN_RF_READ(mac, 0x43);
4959203945Sweongyo	backup_radio[2] = BWN_RF_READ(mac, 0x7a);
4960203945Sweongyo
4961203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
4962203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
4963203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
4964203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
4965203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
4966203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
4967203945Sweongyo	if (phy->rev != 1) {
4968203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
4969203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
4970203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
4971203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
4972203945Sweongyo	}
4973203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
4974203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
4975203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
4976203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
4977203945Sweongyo
4978203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
4979203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
4980203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
4981203945Sweongyo
4982203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
4983203945Sweongyo	if (phy->rev != 1) {
4984203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
4985203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
4986203945Sweongyo	}
4987203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
4988203945Sweongyo
4989203945Sweongyo	if (phy->rf_rev == 8)
4990203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x000f);
4991203945Sweongyo	else {
4992203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
4993203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
4994203945Sweongyo	}
4995203945Sweongyo	bwn_phy_g_set_bbatt(mac, 11);
4996203945Sweongyo
4997203945Sweongyo	if (phy->rev >= 3)
4998203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
4999203945Sweongyo	else
5000203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5001203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5002203945Sweongyo
5003203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
5004203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
5005203945Sweongyo
5006203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
5007203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
5008203945Sweongyo
5009204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) {
5010203945Sweongyo		if (phy->rev >= 7) {
5011203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
5012203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
5013203945Sweongyo		}
5014203945Sweongyo	}
5015203945Sweongyo	BWN_RF_MASK(mac, 0x7a, 0x00f7);
5016203945Sweongyo
5017203945Sweongyo	j = 0;
5018203945Sweongyo	loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
5019203945Sweongyo	for (i = 0; i < loop_i_max; i++) {
5020203945Sweongyo		for (j = 0; j < 16; j++) {
5021203945Sweongyo			BWN_RF_WRITE(mac, 0x43, i);
5022203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
5023203945Sweongyo			    (j << 8));
5024203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5025203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5026203945Sweongyo			DELAY(20);
5027203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5028203945Sweongyo				goto done0;
5029203945Sweongyo		}
5030203945Sweongyo	}
5031203945Sweongyodone0:
5032203945Sweongyo	loop1_outer_done = i;
5033203945Sweongyo	loop1_inner_done = j;
5034203945Sweongyo	if (j >= 8) {
5035203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
5036203945Sweongyo		trsw_rx = 0x1b;
5037203945Sweongyo		for (j = j - 8; j < 16; j++) {
5038203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
5039203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5040203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5041203945Sweongyo			DELAY(20);
5042203945Sweongyo			trsw_rx -= 3;
5043203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5044203945Sweongyo				goto done1;
5045203945Sweongyo		}
5046203945Sweongyo	} else
5047203945Sweongyo		trsw_rx = 0x18;
5048203945Sweongyodone1:
5049203945Sweongyo
5050203945Sweongyo	if (phy->rev != 1) {
5051203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
5052203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
5053203945Sweongyo	}
5054203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
5055203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
5056203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
5057203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
5058203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
5059203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
5060203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
5061203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
5062203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
5063203945Sweongyo
5064203945Sweongyo	bwn_phy_g_set_bbatt(mac, backup_bband);
5065203945Sweongyo
5066203945Sweongyo	BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
5067203945Sweongyo	BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
5068203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
5069203945Sweongyo
5070203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
5071203945Sweongyo	DELAY(10);
5072203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
5073203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
5074203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
5075203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
5076203945Sweongyo
5077203945Sweongyo	pg->pg_max_lb_gain =
5078203945Sweongyo	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
5079203945Sweongyo	pg->pg_trsw_rx_gain = trsw_rx * 2;
5080203945Sweongyo}
5081203945Sweongyo
5082203945Sweongyostatic uint16_t
5083203945Sweongyobwn_rf_init_bcm2050(struct bwn_mac *mac)
5084203945Sweongyo{
5085203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5086203945Sweongyo	uint32_t tmp1 = 0, tmp2 = 0;
5087203945Sweongyo	uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
5088203945Sweongyo	    analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
5089203945Sweongyo	    radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
5090203945Sweongyo	static const uint8_t rcc_table[] = {
5091203945Sweongyo		0x02, 0x03, 0x01, 0x0f,
5092203945Sweongyo		0x06, 0x07, 0x05, 0x0f,
5093203945Sweongyo		0x0a, 0x0b, 0x09, 0x0f,
5094203945Sweongyo		0x0e, 0x0f, 0x0d, 0x0f,
5095203945Sweongyo	};
5096203945Sweongyo
5097204242Simp	loctl = lomask = reg0 = classctl = crs0 = analogoverval = analogover =
5098204242Simp	    rfoverval = rfover = cck3 = 0;
5099203945Sweongyo	radio0 = BWN_RF_READ(mac, 0x43);
5100203945Sweongyo	radio1 = BWN_RF_READ(mac, 0x51);
5101203945Sweongyo	radio2 = BWN_RF_READ(mac, 0x52);
5102203945Sweongyo	pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5103203945Sweongyo	cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5104203945Sweongyo	cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5105203945Sweongyo	cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5106203945Sweongyo
5107203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5108203945Sweongyo		cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
5109203945Sweongyo		reg0 = BWN_READ_2(mac, 0x3ec);
5110203945Sweongyo
5111203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
5112203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
5113203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
5114203945Sweongyo		rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5115203945Sweongyo		rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5116203945Sweongyo		analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5117203945Sweongyo		analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5118203945Sweongyo		crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5119203945Sweongyo		classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
5120203945Sweongyo
5121203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
5122203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
5123203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
5124203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
5125203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5126203945Sweongyo			lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5127203945Sweongyo			loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5128203945Sweongyo			if (phy->rev >= 3)
5129203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5130203945Sweongyo			else
5131203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5132203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5133203945Sweongyo		}
5134203945Sweongyo
5135203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5136203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5137203945Sweongyo			BWN_LPD(0, 1, 1)));
5138203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
5139203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
5140203945Sweongyo	}
5141203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
5142203945Sweongyo
5143203945Sweongyo	syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
5144203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
5145203945Sweongyo	reg1 = BWN_READ_2(mac, 0x3e6);
5146203945Sweongyo	reg2 = BWN_READ_2(mac, 0x3f4);
5147203945Sweongyo
5148203945Sweongyo	if (phy->analog == 0)
5149203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0122);
5150203945Sweongyo	else {
5151203945Sweongyo		if (phy->analog >= 2)
5152203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
5153203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
5154203945Sweongyo		    (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
5155203945Sweongyo	}
5156203945Sweongyo
5157203945Sweongyo	reg = BWN_RF_READ(mac, 0x60);
5158203945Sweongyo	index = (reg & 0x001e) >> 1;
5159203945Sweongyo	rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
5160203945Sweongyo
5161203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5162203945Sweongyo		BWN_RF_WRITE(mac, 0x78, 0x26);
5163203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5164203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5165203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5166203945Sweongyo			BWN_LPD(0, 1, 1)));
5167203945Sweongyo	}
5168203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
5169203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
5170203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5171203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5172203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5173203945Sweongyo			BWN_LPD(0, 0, 1)));
5174203945Sweongyo	}
5175203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
5176203945Sweongyo	BWN_RF_SET(mac, 0x51, 0x0004);
5177203945Sweongyo	if (phy->rf_rev == 8)
5178203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x1f);
5179203945Sweongyo	else {
5180203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5181203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
5182203945Sweongyo	}
5183203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5184203945Sweongyo
5185203945Sweongyo	for (i = 0; i < 16; i++) {
5186203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
5187203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5188203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5189203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5190203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5191203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5192203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5193203945Sweongyo		}
5194203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5195203945Sweongyo		DELAY(10);
5196203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5197203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5198203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5199203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5200203945Sweongyo		}
5201203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5202203945Sweongyo		DELAY(10);
5203203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5204203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5205203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5206203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5207203945Sweongyo		}
5208203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5209203945Sweongyo		DELAY(20);
5210203945Sweongyo		tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5211203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5212203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5213203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5214203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5215203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5216203945Sweongyo		}
5217203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5218203945Sweongyo	}
5219203945Sweongyo	DELAY(10);
5220203945Sweongyo
5221203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5222203945Sweongyo	tmp1++;
5223203945Sweongyo	tmp1 >>= 9;
5224203945Sweongyo
5225203945Sweongyo	for (i = 0; i < 16; i++) {
5226203945Sweongyo		radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
5227203945Sweongyo		BWN_RF_WRITE(mac, 0x78, radio78);
5228203945Sweongyo		DELAY(10);
5229203945Sweongyo		for (j = 0; j < 16; j++) {
5230203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
5231203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5232203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5233203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5234203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5235203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5236203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5237203945Sweongyo			}
5238203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5239203945Sweongyo			DELAY(10);
5240203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5241203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5242203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5243203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5244203945Sweongyo			}
5245203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5246203945Sweongyo			DELAY(10);
5247203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5248203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5249203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5250203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5251203945Sweongyo			}
5252203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5253203945Sweongyo			DELAY(10);
5254203945Sweongyo			tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5255203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5256203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5257203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5258203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5259203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5260203945Sweongyo			}
5261203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5262203945Sweongyo		}
5263203945Sweongyo		tmp2++;
5264203945Sweongyo		tmp2 >>= 8;
5265203945Sweongyo		if (tmp1 < tmp2)
5266203945Sweongyo			break;
5267203945Sweongyo	}
5268203945Sweongyo
5269203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
5270203945Sweongyo	BWN_RF_WRITE(mac, 0x51, radio1);
5271203945Sweongyo	BWN_RF_WRITE(mac, 0x52, radio2);
5272203945Sweongyo	BWN_RF_WRITE(mac, 0x43, radio0);
5273203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
5274203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
5275203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
5276203945Sweongyo	BWN_WRITE_2(mac, 0x3e6, reg1);
5277203945Sweongyo	if (phy->analog != 0)
5278203945Sweongyo		BWN_WRITE_2(mac, 0x3f4, reg2);
5279203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
5280203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
5281203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5282203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
5283203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, reg0);
5284203945Sweongyo	} else if (phy->gmode) {
5285203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO,
5286203945Sweongyo			    BWN_READ_2(mac, BWN_PHY_RADIO)
5287203945Sweongyo			    & 0x7fff);
5288203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
5289203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
5290203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
5291203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
5292203945Sweongyo			      analogoverval);
5293203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
5294203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
5295203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5296203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
5297203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
5298203945Sweongyo		}
5299203945Sweongyo	}
5300203945Sweongyo
5301203945Sweongyo	return ((i > 15) ? radio78 : rcc);
5302203945Sweongyo}
5303203945Sweongyo
5304203945Sweongyostatic void
5305203945Sweongyobwn_phy_init_b6(struct bwn_mac *mac)
5306203945Sweongyo{
5307203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5308203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5309204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5310203945Sweongyo	uint16_t offset, val;
5311203945Sweongyo	uint8_t old_channel;
5312203945Sweongyo
5313203945Sweongyo	KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
5314203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5315203945Sweongyo
5316203945Sweongyo	BWN_PHY_WRITE(mac, 0x003e, 0x817a);
5317203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
5318203945Sweongyo	if (phy->rf_rev == 4 || phy->rf_rev == 5) {
5319203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0x37);
5320203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x70);
5321203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb3);
5322203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x9b);
5323203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5324203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x88);
5325203945Sweongyo		BWN_RF_WRITE(mac, 0x5d, 0x88);
5326203945Sweongyo		BWN_RF_WRITE(mac, 0x5e, 0x88);
5327203945Sweongyo		BWN_RF_WRITE(mac, 0x7d, 0x88);
5328203945Sweongyo		bwn_hf_write(mac,
5329203945Sweongyo		    bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
5330203945Sweongyo	}
5331203945Sweongyo	if (phy->rf_rev == 8) {
5332203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0);
5333203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x40);
5334203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb7);
5335203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x98);
5336203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5337203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x6b);
5338203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0x0f);
5339204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_ALTIQ) {
5340203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xfa);
5341203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xd8);
5342203945Sweongyo		} else {
5343203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xf5);
5344203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xb8);
5345203945Sweongyo		}
5346203945Sweongyo		BWN_RF_WRITE(mac, 0x0073, 0x0003);
5347203945Sweongyo		BWN_RF_WRITE(mac, 0x007d, 0x00a8);
5348203945Sweongyo		BWN_RF_WRITE(mac, 0x007c, 0x0001);
5349203945Sweongyo		BWN_RF_WRITE(mac, 0x007e, 0x0008);
5350203945Sweongyo	}
5351203945Sweongyo	for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
5352203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5353203945Sweongyo		val -= 0x0202;
5354203945Sweongyo	}
5355203945Sweongyo	for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
5356203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5357203945Sweongyo		val -= 0x0202;
5358203945Sweongyo	}
5359203945Sweongyo	for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
5360203945Sweongyo		BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
5361203945Sweongyo		val += 0x0202;
5362203945Sweongyo	}
5363203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
5364203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0020);
5365203945Sweongyo		BWN_RF_SET(mac, 0x0051, 0x0004);
5366203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
5367203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
5368203945Sweongyo		BWN_PHY_WRITE(mac, 0x5b, 0);
5369203945Sweongyo		BWN_PHY_WRITE(mac, 0x5c, 0);
5370203945Sweongyo	}
5371203945Sweongyo
5372203945Sweongyo	old_channel = phy->chan;
5373203945Sweongyo	bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
5374203945Sweongyo
5375203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
5376203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
5377203945Sweongyo	DELAY(40);
5378203945Sweongyo	if (phy->rf_rev < 6 || phy->rf_rev == 8) {
5379203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
5380203945Sweongyo		BWN_RF_WRITE(mac, 0x50, 0x20);
5381203945Sweongyo	}
5382203945Sweongyo	if (phy->rf_rev <= 2) {
5383203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, 0x20);
5384203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x70);
5385203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x7b);
5386203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0xb0);
5387203945Sweongyo	}
5388203945Sweongyo	BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
5389203945Sweongyo
5390203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5391203945Sweongyo
5392203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0200);
5393203945Sweongyo	if (phy->rf_rev >= 6)
5394203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
5395203945Sweongyo	else
5396203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
5397203945Sweongyo	BWN_PHY_WRITE(mac, 0x0038, 0x0668);
5398203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5399203945Sweongyo	    pg->pg_txctl);
5400203945Sweongyo	if (phy->rf_rev <= 5)
5401203945Sweongyo		BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
5402203945Sweongyo	if (phy->rf_rev <= 2)
5403203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5404203945Sweongyo
5405203945Sweongyo	if (phy->analog == 4) {
5406203945Sweongyo		BWN_WRITE_2(mac, 0x3e4, 9);
5407203945Sweongyo		BWN_PHY_MASK(mac, 0x61, 0x0fff);
5408203945Sweongyo	} else
5409203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
5410203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5411203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5412203945Sweongyo	else if (phy->type == BWN_PHYTYPE_G)
5413203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0);
5414203945Sweongyo}
5415203945Sweongyo
5416203945Sweongyostatic void
5417203945Sweongyobwn_phy_init_a(struct bwn_mac *mac)
5418203945Sweongyo{
5419203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5420204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5421203945Sweongyo
5422203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
5423203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5424203945Sweongyo
5425203945Sweongyo	if (phy->rev >= 6) {
5426203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5427203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
5428203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
5429203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
5430203945Sweongyo		else
5431203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
5432203945Sweongyo	}
5433203945Sweongyo
5434203945Sweongyo	bwn_wa_init(mac);
5435203945Sweongyo
5436203945Sweongyo	if (phy->type == BWN_PHYTYPE_G &&
5437204922Sweongyo	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL))
5438203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
5439203945Sweongyo}
5440203945Sweongyo
5441203945Sweongyostatic void
5442203945Sweongyobwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
5443203945Sweongyo{
5444203945Sweongyo	int i;
5445203945Sweongyo
5446203945Sweongyo	for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
5447203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
5448203945Sweongyo}
5449203945Sweongyo
5450203945Sweongyostatic void
5451203945Sweongyobwn_wa_agc(struct bwn_mac *mac)
5452203945Sweongyo{
5453203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5454203945Sweongyo
5455203945Sweongyo	if (phy->rev == 1) {
5456203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
5457203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
5458203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
5459203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
5460203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
5461203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
5462203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
5463203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
5464203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
5465203945Sweongyo	} else {
5466203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
5467203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
5468203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
5469203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
5470203945Sweongyo	}
5471203945Sweongyo
5472203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
5473203945Sweongyo	    0x5700);
5474203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
5475203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
5476203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
5477203945Sweongyo	BWN_RF_SET(mac, 0x7a, 0x0008);
5478203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
5479203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
5480203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
5481203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
5482203945Sweongyo	if (phy->rev == 1)
5483203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
5484203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
5485203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
5486203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
5487203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
5488203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
5489203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
5490203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
5491203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
5492203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
5493203945Sweongyo	if (phy->rev == 1) {
5494203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
5495203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
5496203945Sweongyo	} else {
5497203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
5498203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
5499203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
5500203945Sweongyo		if (phy->rev >= 6) {
5501203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
5502203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
5503203945Sweongyo			    (uint16_t)~0xf000, 0x3000);
5504203945Sweongyo		}
5505203945Sweongyo	}
5506203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
5507203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
5508203945Sweongyo	if (phy->rev == 1) {
5509203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
5510203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
5511203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
5512203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
5513203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
5514203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
5515203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
5516203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
5517203945Sweongyo	} else {
5518203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
5519203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
5520203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
5521203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
5522203945Sweongyo	}
5523203945Sweongyo	if (phy->rev >= 6) {
5524203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
5525203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
5526203945Sweongyo	}
5527203945Sweongyo	BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
5528203945Sweongyo}
5529203945Sweongyo
5530203945Sweongyostatic void
5531203945Sweongyobwn_wa_grev1(struct bwn_mac *mac)
5532203945Sweongyo{
5533203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5534203945Sweongyo	int i;
5535203945Sweongyo	static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
5536203945Sweongyo	static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
5537203945Sweongyo	static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
5538203945Sweongyo
5539203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5540203945Sweongyo
5541203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5542203945Sweongyo	if (phy->rev == 1) {
5543203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5544203945Sweongyo	} else if (phy->rev == 2) {
5545203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5546203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5547203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5548203945Sweongyo	} else {
5549203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5550203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5551203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5552203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5553203945Sweongyo	}
5554203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
5555203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
5556203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
5557203945Sweongyo
5558203945Sweongyo	/* XXX support PHY-A??? */
5559203945Sweongyo	for (i = 0; i < N(bwn_tab_finefreqg); i++)
5560203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
5561203945Sweongyo		    bwn_tab_finefreqg[i]);
5562203945Sweongyo
5563203945Sweongyo	/* XXX support PHY-A??? */
5564203945Sweongyo	if (phy->rev == 1)
5565203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5566203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5567203945Sweongyo			    bwn_tab_noise_g1[i]);
5568203945Sweongyo	else
5569203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5570203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5571203945Sweongyo			    bwn_tab_noise_g2[i]);
5572203945Sweongyo
5573203945Sweongyo
5574203945Sweongyo	for (i = 0; i < N(bwn_tab_rotor); i++)
5575203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
5576203945Sweongyo		    bwn_tab_rotor[i]);
5577203945Sweongyo
5578203945Sweongyo	/* XXX support PHY-A??? */
5579203945Sweongyo	if (phy->rev >= 6) {
5580203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5581203945Sweongyo		    BWN_PHY_ENCORE_EN)
5582203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5583203945Sweongyo		else
5584203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5585203945Sweongyo	} else
5586203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5587203945Sweongyo
5588203945Sweongyo	for (i = 0; i < N(bwn_tab_retard); i++)
5589203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
5590203945Sweongyo		    bwn_tab_retard[i]);
5591203945Sweongyo
5592203945Sweongyo	if (phy->rev == 1) {
5593203945Sweongyo		for (i = 0; i < 16; i++)
5594203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
5595203945Sweongyo			    i, 0x0020);
5596203945Sweongyo	} else {
5597203945Sweongyo		for (i = 0; i < 32; i++)
5598203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5599203945Sweongyo	}
5600203945Sweongyo
5601203945Sweongyo	bwn_wa_agc(mac);
5602203945Sweongyo}
5603203945Sweongyo
5604203945Sweongyostatic void
5605203945Sweongyobwn_wa_grev26789(struct bwn_mac *mac)
5606203945Sweongyo{
5607203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5608203945Sweongyo	int i;
5609203945Sweongyo	static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
5610203945Sweongyo	uint16_t ofdmrev;
5611203945Sweongyo
5612203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5613203945Sweongyo
5614203945Sweongyo	bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
5615203945Sweongyo
5616203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5617203945Sweongyo	if (phy->rev == 1)
5618203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5619203945Sweongyo	else if (phy->rev == 2) {
5620203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5621203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5622203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5623203945Sweongyo	} else {
5624203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5625203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5626203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5627203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5628203945Sweongyo	}
5629203945Sweongyo
5630203945Sweongyo	for (i = 0; i < 64; i++)
5631203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
5632203945Sweongyo
5633203945Sweongyo	/* XXX support PHY-A??? */
5634203945Sweongyo	if (phy->rev == 1)
5635203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5636203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5637203945Sweongyo			    bwn_tab_noise_g1[i]);
5638203945Sweongyo	else
5639203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5640203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5641203945Sweongyo			    bwn_tab_noise_g2[i]);
5642203945Sweongyo
5643203945Sweongyo	/* XXX support PHY-A??? */
5644203945Sweongyo	if (phy->rev >= 6) {
5645203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5646203945Sweongyo		    BWN_PHY_ENCORE_EN)
5647203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5648203945Sweongyo		else
5649203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5650203945Sweongyo	} else
5651203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5652203945Sweongyo
5653203945Sweongyo	for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
5654203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
5655203945Sweongyo		    bwn_tab_sigmasqr2[i]);
5656203945Sweongyo
5657203945Sweongyo	if (phy->rev == 1) {
5658203945Sweongyo		for (i = 0; i < 16; i++)
5659203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
5660203945Sweongyo			    0x0020);
5661203945Sweongyo	} else {
5662203945Sweongyo		for (i = 0; i < 32; i++)
5663203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5664203945Sweongyo	}
5665203945Sweongyo
5666203945Sweongyo	bwn_wa_agc(mac);
5667203945Sweongyo
5668203945Sweongyo	ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
5669203945Sweongyo	if (ofdmrev > 2) {
5670203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5671203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
5672203945Sweongyo		else
5673203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
5674203945Sweongyo	} else {
5675203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
5676203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
5677203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
5678203945Sweongyo	}
5679203945Sweongyo
5680203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
5681203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
5682203945Sweongyo}
5683203945Sweongyo
5684203945Sweongyostatic void
5685203945Sweongyobwn_wa_init(struct bwn_mac *mac)
5686203945Sweongyo{
5687203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5688204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5689203945Sweongyo
5690203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5691203945Sweongyo
5692203945Sweongyo	switch (phy->rev) {
5693203945Sweongyo	case 1:
5694203945Sweongyo		bwn_wa_grev1(mac);
5695203945Sweongyo		break;
5696203945Sweongyo	case 2:
5697203945Sweongyo	case 6:
5698203945Sweongyo	case 7:
5699203945Sweongyo	case 8:
5700203945Sweongyo	case 9:
5701203945Sweongyo		bwn_wa_grev26789(mac);
5702203945Sweongyo		break;
5703203945Sweongyo	default:
5704203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5705203945Sweongyo	}
5706203945Sweongyo
5707204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM ||
5708204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306 ||
5709204922Sweongyo	    siba_get_pci_revid(sc->sc_dev) != 0x17) {
5710203945Sweongyo		if (phy->rev < 2) {
5711203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
5712203945Sweongyo			    0x0002);
5713203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
5714203945Sweongyo			    0x0001);
5715203945Sweongyo		} else {
5716203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
5717203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
5718204922Sweongyo			if ((siba_sprom_get_bf_lo(sc->sc_dev) &
5719204922Sweongyo			     BWN_BFL_EXTLNA) &&
5720203945Sweongyo			    (phy->rev >= 7)) {
5721203945Sweongyo				BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
5722203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5723203945Sweongyo				    0x0020, 0x0001);
5724203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5725203945Sweongyo				    0x0021, 0x0001);
5726203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5727203945Sweongyo				    0x0022, 0x0001);
5728203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5729203945Sweongyo				    0x0023, 0x0000);
5730203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5731203945Sweongyo				    0x0000, 0x0000);
5732203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5733203945Sweongyo				    0x0003, 0x0002);
5734203945Sweongyo			}
5735203945Sweongyo		}
5736203945Sweongyo	}
5737204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) {
5738203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
5739203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
5740203945Sweongyo	}
5741203945Sweongyo
5742203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
5743203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
5744203945Sweongyo}
5745203945Sweongyo
5746203945Sweongyostatic void
5747203945Sweongyobwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5748203945Sweongyo    uint16_t value)
5749203945Sweongyo{
5750203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5751203945Sweongyo	uint16_t addr;
5752203945Sweongyo
5753203945Sweongyo	addr = table + offset;
5754203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5755203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5756203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5757203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5758203945Sweongyo	}
5759203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5760203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5761203945Sweongyo}
5762203945Sweongyo
5763203945Sweongyostatic void
5764203945Sweongyobwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5765203945Sweongyo    uint32_t value)
5766203945Sweongyo{
5767203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5768203945Sweongyo	uint16_t addr;
5769203945Sweongyo
5770203945Sweongyo	addr = table + offset;
5771203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5772203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5773203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5774203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5775203945Sweongyo	}
5776203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5777203945Sweongyo
5778203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5779203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
5780203945Sweongyo}
5781203945Sweongyo
5782203945Sweongyostatic void
5783203945Sweongyobwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5784203945Sweongyo    uint16_t value)
5785203945Sweongyo{
5786203945Sweongyo
5787203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
5788203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
5789203945Sweongyo}
5790203945Sweongyo
5791203945Sweongyostatic void
5792203945Sweongyobwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
5793203945Sweongyo{
5794203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5795204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5796203945Sweongyo	unsigned int i, max_loop;
5797203945Sweongyo	uint16_t value;
5798203945Sweongyo	uint32_t buffer[5] = {
5799203945Sweongyo		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
5800203945Sweongyo	};
5801203945Sweongyo
5802203945Sweongyo	if (ofdm) {
5803203945Sweongyo		max_loop = 0x1e;
5804203945Sweongyo		buffer[0] = 0x000201cc;
5805203945Sweongyo	} else {
5806203945Sweongyo		max_loop = 0xfa;
5807203945Sweongyo		buffer[0] = 0x000b846e;
5808203945Sweongyo	}
5809203945Sweongyo
5810204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
5811203945Sweongyo
5812203945Sweongyo	for (i = 0; i < 5; i++)
5813203945Sweongyo		bwn_ram_write(mac, i * 4, buffer[i]);
5814203945Sweongyo
5815203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0000);
5816203945Sweongyo	BWN_WRITE_2(mac, 0x07c0,
5817204922Sweongyo	    (siba_get_revid(sc->sc_dev) < 11) ? 0x0000 : 0x0100);
5818203945Sweongyo	value = ((phy->type == BWN_PHYTYPE_A) ? 0x41 : 0x40);
5819203945Sweongyo	BWN_WRITE_2(mac, 0x050c, value);
5820203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5821203945Sweongyo		BWN_WRITE_2(mac, 0x0514, 0x1a02);
5822203945Sweongyo	BWN_WRITE_2(mac, 0x0508, 0x0000);
5823203945Sweongyo	BWN_WRITE_2(mac, 0x050a, 0x0000);
5824203945Sweongyo	BWN_WRITE_2(mac, 0x054c, 0x0000);
5825203945Sweongyo	BWN_WRITE_2(mac, 0x056a, 0x0014);
5826203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0826);
5827203945Sweongyo	BWN_WRITE_2(mac, 0x0500, 0x0000);
5828203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5829203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0050);
5830203945Sweongyo	else
5831203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0030);
5832203945Sweongyo
5833203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5834203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0017);
5835203945Sweongyo	for (i = 0x00; i < max_loop; i++) {
5836203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5837203945Sweongyo		if (value & 0x0080)
5838203945Sweongyo			break;
5839203945Sweongyo		DELAY(10);
5840203945Sweongyo	}
5841203945Sweongyo	for (i = 0x00; i < 0x0a; i++) {
5842203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5843203945Sweongyo		if (value & 0x0400)
5844203945Sweongyo			break;
5845203945Sweongyo		DELAY(10);
5846203945Sweongyo	}
5847203945Sweongyo	for (i = 0x00; i < 0x19; i++) {
5848203945Sweongyo		value = BWN_READ_2(mac, 0x0690);
5849203945Sweongyo		if (!(value & 0x0100))
5850203945Sweongyo			break;
5851203945Sweongyo		DELAY(10);
5852203945Sweongyo	}
5853203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5854203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0037);
5855203945Sweongyo}
5856203945Sweongyo
5857203945Sweongyostatic void
5858203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
5859203945Sweongyo{
5860203945Sweongyo	uint32_t macctl;
5861203945Sweongyo
5862203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
5863203945Sweongyo
5864203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
5865203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
5866203945Sweongyo		printf("TODO: need swap\n");
5867203945Sweongyo
5868203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
5869203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
5870203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
5871203945Sweongyo}
5872203945Sweongyo
5873203945Sweongyostatic void
5874203945Sweongyobwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
5875203945Sweongyo{
5876203945Sweongyo	uint16_t value;
5877203945Sweongyo
5878204256Sweongyo	KASSERT(mac->mac_phy.type == BWN_PHYTYPE_G,
5879203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5880203945Sweongyo
5881203945Sweongyo	value = (uint8_t) (ctl->q);
5882203945Sweongyo	value |= ((uint8_t) (ctl->i)) << 8;
5883203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
5884203945Sweongyo}
5885203945Sweongyo
5886203945Sweongyostatic uint16_t
5887203945Sweongyobwn_lo_calcfeed(struct bwn_mac *mac,
5888203945Sweongyo    uint16_t lna, uint16_t pga, uint16_t trsw_rx)
5889203945Sweongyo{
5890203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5891204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5892203945Sweongyo	uint16_t rfover;
5893203945Sweongyo	uint16_t feedthrough;
5894203945Sweongyo
5895203945Sweongyo	if (phy->gmode) {
5896203945Sweongyo		lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
5897203945Sweongyo		pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
5898203945Sweongyo
5899203945Sweongyo		KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
5900203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5901203945Sweongyo		KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
5902203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5903203945Sweongyo
5904203945Sweongyo		trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
5905203945Sweongyo
5906203945Sweongyo		rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
5907204922Sweongyo		if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) &&
5908204922Sweongyo		    phy->rev > 6)
5909203945Sweongyo			rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
5910203945Sweongyo
5911203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
5912203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5913203945Sweongyo		DELAY(10);
5914203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
5915203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5916203945Sweongyo		DELAY(10);
5917203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
5918203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5919203945Sweongyo		DELAY(10);
5920203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
5921203945Sweongyo	} else {
5922203945Sweongyo		pga |= BWN_PHY_PGACTL_UNKNOWN;
5923203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5924203945Sweongyo		DELAY(10);
5925203945Sweongyo		pga |= BWN_PHY_PGACTL_LOWBANDW;
5926203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5927203945Sweongyo		DELAY(10);
5928203945Sweongyo		pga |= BWN_PHY_PGACTL_LPF;
5929203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5930203945Sweongyo	}
5931203945Sweongyo	DELAY(21);
5932203945Sweongyo	feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5933203945Sweongyo
5934203945Sweongyo	return (feedthrough);
5935203945Sweongyo}
5936203945Sweongyo
5937203945Sweongyostatic uint16_t
5938203945Sweongyobwn_lo_txctl_regtable(struct bwn_mac *mac,
5939203945Sweongyo    uint16_t *value, uint16_t *pad_mix_gain)
5940203945Sweongyo{
5941203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5942203945Sweongyo	uint16_t reg, v, padmix;
5943203945Sweongyo
5944203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5945203945Sweongyo		v = 0x30;
5946203945Sweongyo		if (phy->rf_rev <= 5) {
5947203945Sweongyo			reg = 0x43;
5948203945Sweongyo			padmix = 0;
5949203945Sweongyo		} else {
5950203945Sweongyo			reg = 0x52;
5951203945Sweongyo			padmix = 5;
5952203945Sweongyo		}
5953203945Sweongyo	} else {
5954203945Sweongyo		if (phy->rev >= 2 && phy->rf_rev == 8) {
5955203945Sweongyo			reg = 0x43;
5956203945Sweongyo			v = 0x10;
5957203945Sweongyo			padmix = 2;
5958203945Sweongyo		} else {
5959203945Sweongyo			reg = 0x52;
5960203945Sweongyo			v = 0x30;
5961203945Sweongyo			padmix = 5;
5962203945Sweongyo		}
5963203945Sweongyo	}
5964203945Sweongyo	if (value)
5965203945Sweongyo		*value = v;
5966203945Sweongyo	if (pad_mix_gain)
5967203945Sweongyo		*pad_mix_gain = padmix;
5968203945Sweongyo
5969203945Sweongyo	return (reg);
5970203945Sweongyo}
5971203945Sweongyo
5972203945Sweongyostatic void
5973203945Sweongyobwn_lo_measure_txctl_values(struct bwn_mac *mac)
5974203945Sweongyo{
5975203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5976203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5977203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
5978203945Sweongyo	uint16_t reg, mask;
5979203945Sweongyo	uint16_t trsw_rx, pga;
5980203945Sweongyo	uint16_t rf_pctl_reg;
5981203945Sweongyo
5982203945Sweongyo	static const uint8_t tx_bias_values[] = {
5983203945Sweongyo		0x09, 0x08, 0x0a, 0x01, 0x00,
5984203945Sweongyo		0x02, 0x05, 0x04, 0x06,
5985203945Sweongyo	};
5986203945Sweongyo	static const uint8_t tx_magn_values[] = {
5987203945Sweongyo		0x70, 0x40,
5988203945Sweongyo	};
5989203945Sweongyo
5990203945Sweongyo	if (!BWN_HAS_LOOPBACK(phy)) {
5991203945Sweongyo		rf_pctl_reg = 6;
5992203945Sweongyo		trsw_rx = 2;
5993203945Sweongyo		pga = 0;
5994203945Sweongyo	} else {
5995203945Sweongyo		int lb_gain;
5996203945Sweongyo
5997203945Sweongyo		trsw_rx = 0;
5998203945Sweongyo		lb_gain = pg->pg_max_lb_gain / 2;
5999203945Sweongyo		if (lb_gain > 10) {
6000203945Sweongyo			rf_pctl_reg = 0;
6001203945Sweongyo			pga = abs(10 - lb_gain) / 6;
6002203945Sweongyo			pga = MIN(MAX(pga, 0), 15);
6003203945Sweongyo		} else {
6004203945Sweongyo			int cmp_val;
6005203945Sweongyo			int tmp;
6006203945Sweongyo
6007203945Sweongyo			pga = 0;
6008203945Sweongyo			cmp_val = 0x24;
6009203945Sweongyo			if ((phy->rev >= 2) &&
6010203945Sweongyo			    (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
6011203945Sweongyo				cmp_val = 0x3c;
6012203945Sweongyo			tmp = lb_gain;
6013203945Sweongyo			if ((10 - lb_gain) < cmp_val)
6014203945Sweongyo				tmp = (10 - lb_gain);
6015203945Sweongyo			if (tmp < 0)
6016203945Sweongyo				tmp += 6;
6017203945Sweongyo			else
6018203945Sweongyo				tmp += 3;
6019203945Sweongyo			cmp_val /= 4;
6020203945Sweongyo			tmp /= 4;
6021203945Sweongyo			if (tmp >= cmp_val)
6022203945Sweongyo				rf_pctl_reg = cmp_val;
6023203945Sweongyo			else
6024203945Sweongyo				rf_pctl_reg = tmp;
6025203945Sweongyo		}
6026203945Sweongyo	}
6027203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
6028203945Sweongyo	bwn_phy_g_set_bbatt(mac, 2);
6029203945Sweongyo
6030203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
6031203945Sweongyo	mask = ~mask;
6032203945Sweongyo	BWN_RF_MASK(mac, reg, mask);
6033203945Sweongyo
6034203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
6035203945Sweongyo		int i, j;
6036203945Sweongyo		int feedthrough;
6037203945Sweongyo		int min_feedth = 0xffff;
6038203945Sweongyo		uint8_t tx_magn, tx_bias;
6039203945Sweongyo
6040203945Sweongyo		for (i = 0; i < N(tx_magn_values); i++) {
6041203945Sweongyo			tx_magn = tx_magn_values[i];
6042203945Sweongyo			BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
6043203945Sweongyo			for (j = 0; j < N(tx_bias_values); j++) {
6044203945Sweongyo				tx_bias = tx_bias_values[j];
6045203945Sweongyo				BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
6046203945Sweongyo				feedthrough = bwn_lo_calcfeed(mac, 0, pga,
6047203945Sweongyo				    trsw_rx);
6048203945Sweongyo				if (feedthrough < min_feedth) {
6049203945Sweongyo					lo->tx_bias = tx_bias;
6050203945Sweongyo					lo->tx_magn = tx_magn;
6051203945Sweongyo					min_feedth = feedthrough;
6052203945Sweongyo				}
6053203945Sweongyo				if (lo->tx_bias == 0)
6054203945Sweongyo					break;
6055203945Sweongyo			}
6056203945Sweongyo			BWN_RF_WRITE(mac, 0x52,
6057203945Sweongyo					  (BWN_RF_READ(mac, 0x52)
6058203945Sweongyo					   & 0xff00) | lo->tx_bias | lo->
6059203945Sweongyo					  tx_magn);
6060203945Sweongyo		}
6061203945Sweongyo	} else {
6062203945Sweongyo		lo->tx_magn = 0;
6063203945Sweongyo		lo->tx_bias = 0;
6064203945Sweongyo		BWN_RF_MASK(mac, 0x52, 0xfff0);
6065203945Sweongyo	}
6066203945Sweongyo
6067203945Sweongyo	BWN_GETTIME(lo->txctl_measured_time);
6068203945Sweongyo}
6069203945Sweongyo
6070203945Sweongyostatic void
6071203945Sweongyobwn_lo_get_powervector(struct bwn_mac *mac)
6072203945Sweongyo{
6073203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6074203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6075203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6076203945Sweongyo	int i;
6077203945Sweongyo	uint64_t tmp;
6078203945Sweongyo	uint64_t power_vector = 0;
6079203945Sweongyo
6080203945Sweongyo	for (i = 0; i < 8; i += 2) {
6081203945Sweongyo		tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
6082203945Sweongyo		power_vector |= (tmp << (i * 8));
6083203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
6084203945Sweongyo	}
6085203945Sweongyo	if (power_vector)
6086203945Sweongyo		lo->power_vector = power_vector;
6087203945Sweongyo
6088203945Sweongyo	BWN_GETTIME(lo->pwr_vec_read_time);
6089203945Sweongyo}
6090203945Sweongyo
6091203945Sweongyostatic void
6092203945Sweongyobwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
6093203945Sweongyo    int use_trsw_rx)
6094203945Sweongyo{
6095203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6096203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6097203945Sweongyo	uint16_t tmp;
6098203945Sweongyo
6099203945Sweongyo	if (max_rx_gain < 0)
6100203945Sweongyo		max_rx_gain = 0;
6101203945Sweongyo
6102203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
6103203945Sweongyo		int trsw_rx = 0;
6104203945Sweongyo		int trsw_rx_gain;
6105203945Sweongyo
6106203945Sweongyo		if (use_trsw_rx) {
6107203945Sweongyo			trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
6108203945Sweongyo			if (max_rx_gain >= trsw_rx_gain) {
6109203945Sweongyo				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
6110203945Sweongyo				trsw_rx = 0x20;
6111203945Sweongyo			}
6112203945Sweongyo		} else
6113203945Sweongyo			trsw_rx_gain = max_rx_gain;
6114203945Sweongyo		if (trsw_rx_gain < 9) {
6115203945Sweongyo			pg->pg_lna_lod_gain = 0;
6116203945Sweongyo		} else {
6117203945Sweongyo			pg->pg_lna_lod_gain = 1;
6118203945Sweongyo			trsw_rx_gain -= 8;
6119203945Sweongyo		}
6120203945Sweongyo		trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
6121203945Sweongyo		pg->pg_pga_gain = trsw_rx_gain / 3;
6122203945Sweongyo		if (pg->pg_pga_gain >= 5) {
6123203945Sweongyo			pg->pg_pga_gain -= 5;
6124203945Sweongyo			pg->pg_lna_gain = 2;
6125203945Sweongyo		} else
6126203945Sweongyo			pg->pg_lna_gain = 0;
6127203945Sweongyo	} else {
6128203945Sweongyo		pg->pg_lna_gain = 0;
6129203945Sweongyo		pg->pg_trsw_rx_gain = 0x20;
6130203945Sweongyo		if (max_rx_gain >= 0x14) {
6131203945Sweongyo			pg->pg_lna_lod_gain = 1;
6132203945Sweongyo			pg->pg_pga_gain = 2;
6133203945Sweongyo		} else if (max_rx_gain >= 0x12) {
6134203945Sweongyo			pg->pg_lna_lod_gain = 1;
6135203945Sweongyo			pg->pg_pga_gain = 1;
6136203945Sweongyo		} else if (max_rx_gain >= 0xf) {
6137203945Sweongyo			pg->pg_lna_lod_gain = 1;
6138203945Sweongyo			pg->pg_pga_gain = 0;
6139203945Sweongyo		} else {
6140203945Sweongyo			pg->pg_lna_lod_gain = 0;
6141203945Sweongyo			pg->pg_pga_gain = 0;
6142203945Sweongyo		}
6143203945Sweongyo	}
6144203945Sweongyo
6145203945Sweongyo	tmp = BWN_RF_READ(mac, 0x7a);
6146203945Sweongyo	if (pg->pg_lna_lod_gain == 0)
6147203945Sweongyo		tmp &= ~0x0008;
6148203945Sweongyo	else
6149203945Sweongyo		tmp |= 0x0008;
6150203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, tmp);
6151203945Sweongyo}
6152203945Sweongyo
6153203945Sweongyostatic void
6154203945Sweongyobwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6155203945Sweongyo{
6156203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6157203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6158204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6159203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6160203945Sweongyo	struct timespec ts;
6161203945Sweongyo	uint16_t tmp;
6162203945Sweongyo
6163203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6164203945Sweongyo		sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
6165203945Sweongyo		sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
6166203945Sweongyo		sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6167203945Sweongyo		sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
6168203945Sweongyo		sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
6169203945Sweongyo
6170203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
6171203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
6172203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
6173203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
6174203945Sweongyo	}
6175203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6176203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
6177203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
6178203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
6179203945Sweongyo	}
6180203945Sweongyo	if (phy->rev >= 2) {
6181203945Sweongyo		sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
6182203945Sweongyo		sav->phy_analogoverval =
6183203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
6184203945Sweongyo		sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
6185203945Sweongyo		sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
6186203945Sweongyo		sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
6187203945Sweongyo		sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
6188203945Sweongyo		sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
6189203945Sweongyo
6190203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
6191203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
6192203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
6193203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
6194203945Sweongyo		if (phy->type == BWN_PHYTYPE_G) {
6195203945Sweongyo			if ((phy->rev >= 7) &&
6196204922Sweongyo			    (siba_sprom_get_bf_lo(sc->sc_dev) &
6197204922Sweongyo			     BWN_BFL_EXTLNA)) {
6198203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
6199203945Sweongyo			} else {
6200203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
6201203945Sweongyo			}
6202203945Sweongyo		} else {
6203203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
6204203945Sweongyo		}
6205203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
6206203945Sweongyo	}
6207203945Sweongyo	sav->reg0 = BWN_READ_2(mac, 0x3f4);
6208203945Sweongyo	sav->reg1 = BWN_READ_2(mac, 0x3e2);
6209203945Sweongyo	sav->rf0 = BWN_RF_READ(mac, 0x43);
6210203945Sweongyo	sav->rf1 = BWN_RF_READ(mac, 0x7a);
6211203945Sweongyo	sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
6212203945Sweongyo	sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
6213203945Sweongyo	sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
6214203945Sweongyo	sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6215203945Sweongyo
6216203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6217203945Sweongyo		sav->rf2 = BWN_RF_READ(mac, 0x52);
6218203945Sweongyo		sav->rf2 &= 0x00f0;
6219203945Sweongyo	}
6220203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6221203945Sweongyo		sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
6222203945Sweongyo		sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
6223203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
6224203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
6225203945Sweongyo	} else {
6226203945Sweongyo		BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
6227203945Sweongyo			    | 0x8000);
6228203945Sweongyo	}
6229203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
6230203945Sweongyo		    & 0xf000);
6231203945Sweongyo
6232203945Sweongyo	tmp =
6233203945Sweongyo	    (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
6234203945Sweongyo	BWN_PHY_WRITE(mac, tmp, 0x007f);
6235203945Sweongyo
6236203945Sweongyo	tmp = sav->phy_syncctl;
6237203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
6238203945Sweongyo	tmp = sav->rf1;
6239203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
6240203945Sweongyo
6241203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
6242203945Sweongyo	if (phy->type == BWN_PHYTYPE_G ||
6243203945Sweongyo	    (phy->type == BWN_PHYTYPE_B &&
6244203945Sweongyo	     phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
6245203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
6246203945Sweongyo	} else
6247203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
6248203945Sweongyo	if (phy->rev >= 2)
6249203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
6250203945Sweongyo	bwn_phy_g_switch_chan(mac, 6, 0);
6251203945Sweongyo	BWN_RF_READ(mac, 0x51);
6252203945Sweongyo	if (phy->type == BWN_PHYTYPE_G)
6253203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
6254203945Sweongyo
6255203945Sweongyo	nanouptime(&ts);
6256203945Sweongyo	if (time_before(lo->txctl_measured_time,
6257203945Sweongyo	    (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
6258203945Sweongyo		bwn_lo_measure_txctl_values(mac);
6259203945Sweongyo
6260203945Sweongyo	if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
6261203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
6262203945Sweongyo	else {
6263203945Sweongyo		if (phy->type == BWN_PHYTYPE_B)
6264203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6265203945Sweongyo		else
6266203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
6267203945Sweongyo	}
6268203945Sweongyo}
6269203945Sweongyo
6270203945Sweongyostatic void
6271203945Sweongyobwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6272203945Sweongyo{
6273203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6274203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6275203945Sweongyo	uint16_t tmp;
6276203945Sweongyo
6277203945Sweongyo	if (phy->rev >= 2) {
6278203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6279203945Sweongyo		tmp = (pg->pg_pga_gain << 8);
6280203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
6281203945Sweongyo		DELAY(5);
6282203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
6283203945Sweongyo		DELAY(2);
6284203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
6285203945Sweongyo	} else {
6286203945Sweongyo		tmp = (pg->pg_pga_gain | 0xefa0);
6287203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
6288203945Sweongyo	}
6289203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
6290203945Sweongyo		if (phy->rev >= 3)
6291203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
6292203945Sweongyo		else
6293203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6294203945Sweongyo		if (phy->rev >= 2)
6295203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
6296203945Sweongyo		else
6297203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
6298203945Sweongyo	}
6299203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, sav->reg0);
6300203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
6301203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
6302203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
6303203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
6304203945Sweongyo	BWN_RF_WRITE(mac, 0x43, sav->rf0);
6305203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, sav->rf1);
6306203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6307203945Sweongyo		tmp = sav->rf2;
6308203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
6309203945Sweongyo	}
6310203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, sav->reg1);
6311203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6312203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
6313203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
6314203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
6315203945Sweongyo	}
6316203945Sweongyo	if (phy->rev >= 2) {
6317203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
6318203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
6319203945Sweongyo			      sav->phy_analogoverval);
6320203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
6321203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
6322203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
6323203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
6324203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
6325203945Sweongyo	}
6326203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6327203945Sweongyo		tmp = (sav->phy_lomask & 0xbfff);
6328203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
6329203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
6330203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
6331203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
6332203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
6333203945Sweongyo	}
6334203945Sweongyo	bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
6335203945Sweongyo}
6336203945Sweongyo
6337203945Sweongyostatic int
6338203945Sweongyobwn_lo_probe_loctl(struct bwn_mac *mac,
6339203945Sweongyo    struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
6340203945Sweongyo{
6341203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6342203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6343203945Sweongyo	struct bwn_loctl orig, test;
6344203945Sweongyo	struct bwn_loctl prev = { -100, -100 };
6345203945Sweongyo	static const struct bwn_loctl modifiers[] = {
6346203945Sweongyo		{  1,  1,}, {  1,  0,}, {  1, -1,}, {  0, -1,},
6347203945Sweongyo		{ -1, -1,}, { -1,  0,}, { -1,  1,}, {  0,  1,}
6348203945Sweongyo	};
6349203945Sweongyo	int begin, end, lower = 0, i;
6350203945Sweongyo	uint16_t feedth;
6351203945Sweongyo
6352203945Sweongyo	if (d->curstate == 0) {
6353203945Sweongyo		begin = 1;
6354203945Sweongyo		end = 8;
6355203945Sweongyo	} else if (d->curstate % 2 == 0) {
6356203945Sweongyo		begin = d->curstate - 1;
6357203945Sweongyo		end = d->curstate + 1;
6358203945Sweongyo	} else {
6359203945Sweongyo		begin = d->curstate - 2;
6360203945Sweongyo		end = d->curstate + 2;
6361203945Sweongyo	}
6362203945Sweongyo	if (begin < 1)
6363203945Sweongyo		begin += 8;
6364203945Sweongyo	if (end > 8)
6365203945Sweongyo		end -= 8;
6366203945Sweongyo
6367203945Sweongyo	memcpy(&orig, probe, sizeof(struct bwn_loctl));
6368203945Sweongyo	i = begin;
6369203945Sweongyo	d->curstate = i;
6370203945Sweongyo	while (1) {
6371203945Sweongyo		KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
6372203945Sweongyo		memcpy(&test, &orig, sizeof(struct bwn_loctl));
6373203945Sweongyo		test.i += modifiers[i - 1].i * d->multipler;
6374203945Sweongyo		test.q += modifiers[i - 1].q * d->multipler;
6375203945Sweongyo		if ((test.i != prev.i || test.q != prev.q) &&
6376203945Sweongyo		    (abs(test.i) <= 16 && abs(test.q) <= 16)) {
6377203945Sweongyo			bwn_lo_write(mac, &test);
6378203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6379203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6380203945Sweongyo			if (feedth < d->feedth) {
6381203945Sweongyo				memcpy(probe, &test,
6382203945Sweongyo				    sizeof(struct bwn_loctl));
6383203945Sweongyo				lower = 1;
6384203945Sweongyo				d->feedth = feedth;
6385203945Sweongyo				if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
6386203945Sweongyo					break;
6387203945Sweongyo			}
6388203945Sweongyo		}
6389203945Sweongyo		memcpy(&prev, &test, sizeof(prev));
6390203945Sweongyo		if (i == end)
6391203945Sweongyo			break;
6392203945Sweongyo		if (i == 8)
6393203945Sweongyo			i = 1;
6394203945Sweongyo		else
6395203945Sweongyo			i++;
6396203945Sweongyo		d->curstate = i;
6397203945Sweongyo	}
6398203945Sweongyo
6399203945Sweongyo	return (lower);
6400203945Sweongyo}
6401203945Sweongyo
6402203945Sweongyostatic void
6403203945Sweongyobwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
6404203945Sweongyo{
6405203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6406203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6407203945Sweongyo	struct bwn_lo_g_sm d;
6408203945Sweongyo	struct bwn_loctl probe;
6409203945Sweongyo	int lower, repeat, cnt = 0;
6410203945Sweongyo	uint16_t feedth;
6411203945Sweongyo
6412203945Sweongyo	d.nmeasure = 0;
6413203945Sweongyo	d.multipler = 1;
6414203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6415203945Sweongyo		d.multipler = 3;
6416203945Sweongyo
6417203945Sweongyo	memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
6418203945Sweongyo	repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
6419203945Sweongyo
6420203945Sweongyo	do {
6421203945Sweongyo		bwn_lo_write(mac, &d.loctl);
6422203945Sweongyo		feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6423203945Sweongyo		    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6424203945Sweongyo		if (feedth < 0x258) {
6425203945Sweongyo			if (feedth >= 0x12c)
6426203945Sweongyo				*rxgain += 6;
6427203945Sweongyo			else
6428203945Sweongyo				*rxgain += 3;
6429203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6430203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6431203945Sweongyo		}
6432203945Sweongyo		d.feedth = feedth;
6433203945Sweongyo		d.curstate = 0;
6434203945Sweongyo		do {
6435203945Sweongyo			KASSERT(d.curstate >= 0 && d.curstate <= 8,
6436203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
6437203945Sweongyo			memcpy(&probe, &d.loctl,
6438203945Sweongyo			       sizeof(struct bwn_loctl));
6439203945Sweongyo			lower = bwn_lo_probe_loctl(mac, &probe, &d);
6440203945Sweongyo			if (!lower)
6441203945Sweongyo				break;
6442203945Sweongyo			if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
6443203945Sweongyo				break;
6444203945Sweongyo			memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
6445203945Sweongyo			d.nmeasure++;
6446203945Sweongyo		} while (d.nmeasure < 24);
6447203945Sweongyo		memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
6448203945Sweongyo
6449203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
6450203945Sweongyo			if (d.feedth > 0x1194)
6451203945Sweongyo				*rxgain -= 6;
6452203945Sweongyo			else if (d.feedth < 0x5dc)
6453203945Sweongyo				*rxgain += 3;
6454203945Sweongyo			if (cnt == 0) {
6455203945Sweongyo				if (d.feedth <= 0x5dc) {
6456203945Sweongyo					d.multipler = 1;
6457203945Sweongyo					cnt++;
6458203945Sweongyo				} else
6459203945Sweongyo					d.multipler = 2;
6460203945Sweongyo			} else if (cnt == 2)
6461203945Sweongyo				d.multipler = 1;
6462203945Sweongyo		}
6463203945Sweongyo		bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
6464203945Sweongyo	} while (++cnt < repeat);
6465203945Sweongyo}
6466203945Sweongyo
6467203945Sweongyostatic struct bwn_lo_calib *
6468203945Sweongyobwn_lo_calibset(struct bwn_mac *mac,
6469203945Sweongyo    const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
6470203945Sweongyo{
6471203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6472203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6473203945Sweongyo	struct bwn_loctl loctl = { 0, 0 };
6474203945Sweongyo	struct bwn_lo_calib *cal;
6475204242Simp	struct bwn_lo_g_value sval = { 0 };
6476203945Sweongyo	int rxgain;
6477203945Sweongyo	uint16_t pad, reg, value;
6478203945Sweongyo
6479203945Sweongyo	sval.old_channel = phy->chan;
6480203945Sweongyo	bwn_mac_suspend(mac);
6481203945Sweongyo	bwn_lo_save(mac, &sval);
6482203945Sweongyo
6483203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &value, &pad);
6484203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
6485203945Sweongyo	BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
6486203945Sweongyo
6487203945Sweongyo	rxgain = (rfatt->att * 2) + (bbatt->att / 2);
6488203945Sweongyo	if (rfatt->padmix)
6489203945Sweongyo		rxgain -= pad;
6490203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6491203945Sweongyo		rxgain += pg->pg_max_lb_gain;
6492203945Sweongyo	bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
6493203945Sweongyo	bwn_phy_g_set_bbatt(mac, bbatt->att);
6494203945Sweongyo	bwn_lo_probe_sm(mac, &loctl, &rxgain);
6495203945Sweongyo
6496203945Sweongyo	bwn_lo_restore(mac, &sval);
6497203945Sweongyo	bwn_mac_enable(mac);
6498203945Sweongyo
6499203945Sweongyo	cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
6500203945Sweongyo	if (!cal) {
6501203945Sweongyo		device_printf(mac->mac_sc->sc_dev, "out of memory\n");
6502203945Sweongyo		return (NULL);
6503203945Sweongyo	}
6504203945Sweongyo	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
6505203945Sweongyo	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
6506203945Sweongyo	memcpy(&cal->ctl, &loctl, sizeof(loctl));
6507203945Sweongyo
6508203945Sweongyo	BWN_GETTIME(cal->calib_time);
6509203945Sweongyo
6510203945Sweongyo	return (cal);
6511203945Sweongyo}
6512203945Sweongyo
6513203945Sweongyostatic struct bwn_lo_calib *
6514203945Sweongyobwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
6515203945Sweongyo    const struct bwn_rfatt *rfatt)
6516203945Sweongyo{
6517203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
6518203945Sweongyo	struct bwn_lo_calib *c;
6519203945Sweongyo
6520203945Sweongyo	TAILQ_FOREACH(c, &lo->calib_list, list) {
6521203945Sweongyo		if (!BWN_BBATTCMP(&c->bbatt, bbatt))
6522203945Sweongyo			continue;
6523203945Sweongyo		if (!BWN_RFATTCMP(&c->rfatt, rfatt))
6524203945Sweongyo			continue;
6525203945Sweongyo		return (c);
6526203945Sweongyo	}
6527203945Sweongyo
6528203945Sweongyo	c = bwn_lo_calibset(mac, bbatt, rfatt);
6529203945Sweongyo	if (!c)
6530203945Sweongyo		return (NULL);
6531203945Sweongyo	TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
6532203945Sweongyo
6533203945Sweongyo	return (c);
6534203945Sweongyo}
6535203945Sweongyo
6536203945Sweongyostatic void
6537203945Sweongyobwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
6538203945Sweongyo{
6539203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6540203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6541203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6542203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6543203945Sweongyo	const struct bwn_rfatt *rfatt;
6544203945Sweongyo	const struct bwn_bbatt *bbatt;
6545203945Sweongyo	uint64_t pvector;
6546203945Sweongyo	int i;
6547203945Sweongyo	int rf_offset, bb_offset;
6548203945Sweongyo	uint8_t changed = 0;
6549203945Sweongyo
6550203945Sweongyo	KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
6551203945Sweongyo	KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
6552203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6553203945Sweongyo
6554203945Sweongyo	pvector = lo->power_vector;
6555203945Sweongyo	if (!update && !pvector)
6556203945Sweongyo		return;
6557203945Sweongyo
6558203945Sweongyo	bwn_mac_suspend(mac);
6559203945Sweongyo
6560203945Sweongyo	for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
6561203945Sweongyo		struct bwn_lo_calib *cal;
6562203945Sweongyo		int idx;
6563203945Sweongyo		uint16_t val;
6564203945Sweongyo
6565203945Sweongyo		if (!update && !(pvector & (((uint64_t)1ULL) << i)))
6566203945Sweongyo			continue;
6567203945Sweongyo		bb_offset = i / lo->rfatt.len;
6568203945Sweongyo		rf_offset = i % lo->rfatt.len;
6569203945Sweongyo		bbatt = &(lo->bbatt.array[bb_offset]);
6570203945Sweongyo		rfatt = &(lo->rfatt.array[rf_offset]);
6571203945Sweongyo
6572203945Sweongyo		cal = bwn_lo_calibset(mac, bbatt, rfatt);
6573203945Sweongyo		if (!cal) {
6574203945Sweongyo			device_printf(sc->sc_dev, "LO: Could not "
6575203945Sweongyo			    "calibrate DC table entry\n");
6576203945Sweongyo			continue;
6577203945Sweongyo		}
6578203945Sweongyo		val = (uint8_t)(cal->ctl.q);
6579203945Sweongyo		val |= ((uint8_t)(cal->ctl.i)) << 4;
6580203945Sweongyo		free(cal, M_DEVBUF);
6581203945Sweongyo
6582203945Sweongyo		idx = i / 2;
6583203945Sweongyo		if (i % 2)
6584203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
6585203945Sweongyo			    | ((val & 0x00ff) << 8);
6586203945Sweongyo		else
6587203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
6588203945Sweongyo			    | (val & 0x00ff);
6589203945Sweongyo		changed = 1;
6590203945Sweongyo	}
6591203945Sweongyo	if (changed) {
6592203945Sweongyo		for (i = 0; i < BWN_DC_LT_SIZE; i++)
6593203945Sweongyo			BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
6594203945Sweongyo	}
6595203945Sweongyo	bwn_mac_enable(mac);
6596203945Sweongyo}
6597203945Sweongyo
6598203945Sweongyostatic void
6599203945Sweongyobwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
6600203945Sweongyo{
6601203945Sweongyo
6602203945Sweongyo	if (!rf->padmix)
6603203945Sweongyo		return;
6604203945Sweongyo	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
6605203945Sweongyo		rf->att = 4;
6606203945Sweongyo}
6607203945Sweongyo
6608203945Sweongyostatic void
6609203945Sweongyobwn_lo_g_adjust(struct bwn_mac *mac)
6610203945Sweongyo{
6611203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
6612203945Sweongyo	struct bwn_lo_calib *cal;
6613203945Sweongyo	struct bwn_rfatt rf;
6614203945Sweongyo
6615203945Sweongyo	memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
6616203945Sweongyo	bwn_lo_fixup_rfatt(&rf);
6617203945Sweongyo
6618203945Sweongyo	cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
6619203945Sweongyo	if (!cal)
6620203945Sweongyo		return;
6621203945Sweongyo	bwn_lo_write(mac, &cal->ctl);
6622203945Sweongyo}
6623203945Sweongyo
6624203945Sweongyostatic void
6625203945Sweongyobwn_lo_g_init(struct bwn_mac *mac)
6626203945Sweongyo{
6627203945Sweongyo
6628203945Sweongyo	if (!bwn_has_hwpctl(mac))
6629203945Sweongyo		return;
6630203945Sweongyo
6631203945Sweongyo	bwn_lo_get_powervector(mac);
6632203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
6633203945Sweongyo}
6634203945Sweongyo
6635203945Sweongyostatic void
6636203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
6637203945Sweongyo{
6638203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6639203945Sweongyo	int i;
6640203945Sweongyo	uint32_t tmp;
6641203945Sweongyo
6642203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6643203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6644203945Sweongyo
6645203945Sweongyo	if (mac->mac_suspended == 0) {
6646203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
6647203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6648203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
6649203945Sweongyo			    & ~BWN_MACCTL_ON);
6650203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6651203945Sweongyo		for (i = 35; i; i--) {
6652203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6653203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6654203945Sweongyo				goto out;
6655203945Sweongyo			DELAY(10);
6656203945Sweongyo		}
6657203945Sweongyo		for (i = 40; i; i--) {
6658203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6659203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6660203945Sweongyo				goto out;
6661203945Sweongyo			DELAY(1000);
6662203945Sweongyo		}
6663203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
6664203945Sweongyo	}
6665203945Sweongyoout:
6666203945Sweongyo	mac->mac_suspended++;
6667203945Sweongyo}
6668203945Sweongyo
6669203945Sweongyostatic void
6670203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
6671203945Sweongyo{
6672203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6673203945Sweongyo	uint16_t state;
6674203945Sweongyo
6675203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
6676203945Sweongyo	    BWN_SHARED_UCODESTAT);
6677203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
6678203945Sweongyo	    state != BWN_SHARED_UCODESTAT_SLEEP)
6679203945Sweongyo		device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
6680203945Sweongyo
6681203945Sweongyo	mac->mac_suspended--;
6682203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6683203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6684203945Sweongyo	if (mac->mac_suspended == 0) {
6685203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6686203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
6687203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
6688203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6689203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
6690203945Sweongyo		bwn_psctl(mac, 0);
6691203945Sweongyo	}
6692203945Sweongyo}
6693203945Sweongyo
6694203945Sweongyostatic void
6695203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
6696203945Sweongyo{
6697204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6698203945Sweongyo	int i;
6699203945Sweongyo	uint16_t ucstat;
6700203945Sweongyo
6701203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
6702203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6703203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
6704203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6705203945Sweongyo
6706203945Sweongyo	/* XXX forcibly awake and hwps-off */
6707203945Sweongyo
6708203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
6709203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
6710203945Sweongyo	    ~BWN_MACCTL_HWPS);
6711203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
6712204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
6713203945Sweongyo		for (i = 0; i < 100; i++) {
6714203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
6715203945Sweongyo			    BWN_SHARED_UCODESTAT);
6716203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
6717203945Sweongyo				break;
6718203945Sweongyo			DELAY(10);
6719203945Sweongyo		}
6720203945Sweongyo	}
6721203945Sweongyo}
6722203945Sweongyo
6723203945Sweongyostatic int16_t
6724203945Sweongyobwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
6725203945Sweongyo{
6726203945Sweongyo
6727203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
6728203945Sweongyo	return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
6729203945Sweongyo}
6730203945Sweongyo
6731203945Sweongyostatic void
6732203945Sweongyobwn_nrssi_threshold(struct bwn_mac *mac)
6733203945Sweongyo{
6734203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6735203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6736204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6737203945Sweongyo	int32_t a, b;
6738203945Sweongyo	int16_t tmp16;
6739203945Sweongyo	uint16_t tmpu16;
6740203945Sweongyo
6741203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
6742203945Sweongyo
6743204922Sweongyo	if (phy->gmode && (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
6744203945Sweongyo		if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
6745203945Sweongyo			a = 0x13;
6746203945Sweongyo			b = 0x12;
6747203945Sweongyo		} else {
6748203945Sweongyo			a = 0xe;
6749203945Sweongyo			b = 0x11;
6750203945Sweongyo		}
6751203945Sweongyo
6752203945Sweongyo		a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6753203945Sweongyo		a += (pg->pg_nrssi[0] << 6);
6754203945Sweongyo		a += (a < 32) ? 31 : 32;
6755203945Sweongyo		a = a >> 6;
6756203945Sweongyo		a = MIN(MAX(a, -31), 31);
6757203945Sweongyo
6758203945Sweongyo		b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6759203945Sweongyo		b += (pg->pg_nrssi[0] << 6);
6760203945Sweongyo		if (b < 32)
6761203945Sweongyo			b += 31;
6762203945Sweongyo		else
6763203945Sweongyo			b += 32;
6764203945Sweongyo		b = b >> 6;
6765203945Sweongyo		b = MIN(MAX(b, -31), 31);
6766203945Sweongyo
6767203945Sweongyo		tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
6768203945Sweongyo		tmpu16 |= ((uint32_t)b & 0x0000003f);
6769203945Sweongyo		tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
6770203945Sweongyo		BWN_PHY_WRITE(mac, 0x048a, tmpu16);
6771203945Sweongyo		return;
6772203945Sweongyo	}
6773203945Sweongyo
6774203945Sweongyo	tmp16 = bwn_nrssi_read(mac, 0x20);
6775203945Sweongyo	if (tmp16 >= 0x20)
6776203945Sweongyo		tmp16 -= 0x40;
6777203945Sweongyo	BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
6778203945Sweongyo}
6779203945Sweongyo
6780203945Sweongyostatic void
6781203945Sweongyobwn_nrssi_slope_11g(struct bwn_mac *mac)
6782203945Sweongyo{
6783203945Sweongyo#define	SAVE_RF_MAX		3
6784203945Sweongyo#define	SAVE_PHY_COMM_MAX	4
6785203945Sweongyo#define	SAVE_PHY3_MAX		8
6786203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6787203945Sweongyo		{ 0x7a, 0x52, 0x43 };
6788203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
6789203945Sweongyo		{ 0x15, 0x5a, 0x59, 0x58 };
6790203945Sweongyo	static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
6791203945Sweongyo		0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
6792203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6793203945Sweongyo	};
6794203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6795203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6796203945Sweongyo	int32_t i, tmp32, phy3_idx = 0;
6797203945Sweongyo	uint16_t delta, tmp;
6798203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6799203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6800203945Sweongyo	uint16_t save_phy3[SAVE_PHY3_MAX];
6801203945Sweongyo	uint16_t ant_div, phy0, chan_ex;
6802203945Sweongyo	int16_t nrssi0, nrssi1;
6803203945Sweongyo
6804203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
6805203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6806203945Sweongyo
6807203945Sweongyo	if (phy->rf_rev >= 9)
6808203945Sweongyo		return;
6809203945Sweongyo	if (phy->rf_rev == 8)
6810203945Sweongyo		bwn_nrssi_offset(mac);
6811203945Sweongyo
6812203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
6813203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, 0xfffc);
6814203945Sweongyo
6815203945Sweongyo	/*
6816203945Sweongyo	 * Save RF/PHY registers for later restoration
6817203945Sweongyo	 */
6818203945Sweongyo	ant_div = BWN_READ_2(mac, 0x03e2);
6819203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
6820203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6821203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6822203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6823203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6824203945Sweongyo
6825203945Sweongyo	phy0 = BWN_READ_2(mac, BWN_PHY0);
6826203945Sweongyo	chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
6827203945Sweongyo	if (phy->rev >= 3) {
6828203945Sweongyo		for (i = 0; i < SAVE_PHY3_MAX; ++i)
6829203945Sweongyo			save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
6830203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6831203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
6832203945Sweongyo		switch (phy->rev) {
6833203945Sweongyo		case 4:
6834203945Sweongyo		case 6:
6835203945Sweongyo		case 7:
6836203945Sweongyo			BWN_PHY_SET(mac, 0x0478, 0x0100);
6837203945Sweongyo			BWN_PHY_SET(mac, 0x0801, 0x0040);
6838203945Sweongyo			break;
6839203945Sweongyo		case 3:
6840203945Sweongyo		case 5:
6841203945Sweongyo			BWN_PHY_MASK(mac, 0x0801, 0xffbf);
6842203945Sweongyo			break;
6843203945Sweongyo		}
6844203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
6845203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
6846203945Sweongyo	}
6847203945Sweongyo	/*
6848203945Sweongyo	 * Calculate nrssi0
6849203945Sweongyo	 */
6850203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
6851203945Sweongyo	bwn_set_all_gains(mac, 0, 8, 0);
6852203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x00f7);
6853203945Sweongyo	if (phy->rev >= 2) {
6854203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
6855203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
6856203945Sweongyo	}
6857203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
6858203945Sweongyo	DELAY(20);
6859203945Sweongyo
6860203945Sweongyo	nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6861203945Sweongyo	if (nrssi0 >= 0x0020)
6862203945Sweongyo		nrssi0 -= 0x0040;
6863203945Sweongyo
6864203945Sweongyo	/*
6865203945Sweongyo	 * Calculate nrssi1
6866203945Sweongyo	 */
6867203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x007f);
6868203945Sweongyo	if (phy->rev >= 2)
6869203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
6870203945Sweongyo
6871203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
6872203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
6873203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x000f);
6874203945Sweongyo	BWN_PHY_WRITE(mac, 0x0015, 0xf330);
6875203945Sweongyo	if (phy->rev >= 2) {
6876203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
6877203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
6878203945Sweongyo	}
6879203945Sweongyo
6880203945Sweongyo	bwn_set_all_gains(mac, 3, 0, 1);
6881203945Sweongyo	if (phy->rf_rev == 8) {
6882203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, 0x001f);
6883203945Sweongyo	} else {
6884203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
6885203945Sweongyo		BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
6886203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
6887203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
6888203945Sweongyo	}
6889203945Sweongyo	BWN_PHY_WRITE(mac, 0x005a, 0x0480);
6890203945Sweongyo	BWN_PHY_WRITE(mac, 0x0059, 0x0810);
6891203945Sweongyo	BWN_PHY_WRITE(mac, 0x0058, 0x000d);
6892203945Sweongyo	DELAY(20);
6893203945Sweongyo	nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6894203945Sweongyo
6895203945Sweongyo	/*
6896203945Sweongyo	 * Install calculated narrow RSSI values
6897203945Sweongyo	 */
6898203945Sweongyo	if (nrssi1 >= 0x0020)
6899203945Sweongyo		nrssi1 -= 0x0040;
6900203945Sweongyo	if (nrssi0 == nrssi1)
6901203945Sweongyo		pg->pg_nrssi_slope = 0x00010000;
6902203945Sweongyo	else
6903203945Sweongyo		pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
6904203945Sweongyo	if (nrssi0 >= -4) {
6905203945Sweongyo		pg->pg_nrssi[0] = nrssi1;
6906203945Sweongyo		pg->pg_nrssi[1] = nrssi0;
6907203945Sweongyo	}
6908203945Sweongyo
6909203945Sweongyo	/*
6910203945Sweongyo	 * Restore saved RF/PHY registers
6911203945Sweongyo	 */
6912203945Sweongyo	if (phy->rev >= 3) {
6913203945Sweongyo		for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
6914203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
6915203945Sweongyo			    save_phy3[phy3_idx]);
6916203945Sweongyo		}
6917203945Sweongyo	}
6918203945Sweongyo	if (phy->rev >= 2) {
6919203945Sweongyo		BWN_PHY_MASK(mac, 0x0812, 0xffcf);
6920203945Sweongyo		BWN_PHY_MASK(mac, 0x0811, 0xffcf);
6921203945Sweongyo	}
6922203945Sweongyo
6923203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6924203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
6925203945Sweongyo
6926203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, ant_div);
6927203945Sweongyo	BWN_WRITE_2(mac, 0x03e6, phy0);
6928203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
6929203945Sweongyo
6930203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6931203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
6932203945Sweongyo
6933203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
6934203945Sweongyo	BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
6935203945Sweongyo	bwn_set_original_gains(mac);
6936203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
6937203945Sweongyo	if (phy->rev >= 3) {
6938203945Sweongyo		for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
6939203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
6940203945Sweongyo			    save_phy3[phy3_idx]);
6941203945Sweongyo		}
6942203945Sweongyo	}
6943203945Sweongyo
6944203945Sweongyo	delta = 0x1f - pg->pg_nrssi[0];
6945203945Sweongyo	for (i = 0; i < 64; i++) {
6946203945Sweongyo		tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
6947203945Sweongyo		tmp32 = MIN(MAX(tmp32, 0), 0x3f);
6948203945Sweongyo		pg->pg_nrssi_lt[i] = tmp32;
6949203945Sweongyo	}
6950203945Sweongyo
6951203945Sweongyo	bwn_nrssi_threshold(mac);
6952203945Sweongyo#undef SAVE_RF_MAX
6953203945Sweongyo#undef SAVE_PHY_COMM_MAX
6954203945Sweongyo#undef SAVE_PHY3_MAX
6955203945Sweongyo}
6956203945Sweongyo
6957203945Sweongyostatic void
6958203945Sweongyobwn_nrssi_offset(struct bwn_mac *mac)
6959203945Sweongyo{
6960203945Sweongyo#define	SAVE_RF_MAX		2
6961203945Sweongyo#define	SAVE_PHY_COMM_MAX	10
6962203945Sweongyo#define	SAVE_PHY6_MAX		8
6963203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6964203945Sweongyo		{ 0x7a, 0x43 };
6965203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
6966203945Sweongyo		0x0001, 0x0811, 0x0812, 0x0814,
6967203945Sweongyo		0x0815, 0x005a, 0x0059, 0x0058,
6968203945Sweongyo		0x000a, 0x0003
6969203945Sweongyo	};
6970203945Sweongyo	static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
6971203945Sweongyo		0x002e, 0x002f, 0x080f, 0x0810,
6972203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6973203945Sweongyo	};
6974203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6975203945Sweongyo	int i, phy6_idx = 0;
6976203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6977203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6978203945Sweongyo	uint16_t save_phy6[SAVE_PHY6_MAX];
6979203945Sweongyo	int16_t nrssi;
6980203945Sweongyo	uint16_t saved = 0xffff;
6981203945Sweongyo
6982203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6983203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6984203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6985203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6986203945Sweongyo
6987203945Sweongyo	BWN_PHY_MASK(mac, 0x0429, 0x7fff);
6988203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
6989203945Sweongyo	BWN_PHY_SET(mac, 0x0811, 0x000c);
6990203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
6991203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
6992203945Sweongyo	if (phy->rev >= 6) {
6993203945Sweongyo		for (i = 0; i < SAVE_PHY6_MAX; ++i)
6994203945Sweongyo			save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
6995203945Sweongyo
6996203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6997203945Sweongyo		BWN_PHY_WRITE(mac, 0x002f, 0);
6998203945Sweongyo		BWN_PHY_WRITE(mac, 0x080f, 0);
6999203945Sweongyo		BWN_PHY_WRITE(mac, 0x0810, 0);
7000203945Sweongyo		BWN_PHY_SET(mac, 0x0478, 0x0100);
7001203945Sweongyo		BWN_PHY_SET(mac, 0x0801, 0x0040);
7002203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
7003203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
7004203945Sweongyo	}
7005203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
7006203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
7007203945Sweongyo	DELAY(30);
7008203945Sweongyo
7009203945Sweongyo	nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7010203945Sweongyo	if (nrssi >= 0x20)
7011203945Sweongyo		nrssi -= 0x40;
7012203945Sweongyo	if (nrssi == 31) {
7013203945Sweongyo		for (i = 7; i >= 4; i--) {
7014203945Sweongyo			BWN_RF_WRITE(mac, 0x007b, i);
7015203945Sweongyo			DELAY(20);
7016203945Sweongyo			nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
7017203945Sweongyo			    0x003f);
7018203945Sweongyo			if (nrssi >= 0x20)
7019203945Sweongyo				nrssi -= 0x40;
7020203945Sweongyo			if (nrssi < 31 && saved == 0xffff)
7021203945Sweongyo				saved = i;
7022203945Sweongyo		}
7023203945Sweongyo		if (saved == 0xffff)
7024203945Sweongyo			saved = 4;
7025203945Sweongyo	} else {
7026203945Sweongyo		BWN_RF_MASK(mac, 0x007a, 0x007f);
7027203945Sweongyo		if (phy->rev != 1) {
7028203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0001);
7029203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffe);
7030203945Sweongyo		}
7031203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x000c);
7032203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x000c);
7033203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x0030);
7034203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x0030);
7035203945Sweongyo		BWN_PHY_WRITE(mac, 0x005a, 0x0480);
7036203945Sweongyo		BWN_PHY_WRITE(mac, 0x0059, 0x0810);
7037203945Sweongyo		BWN_PHY_WRITE(mac, 0x0058, 0x000d);
7038203945Sweongyo		if (phy->rev == 0)
7039203945Sweongyo			BWN_PHY_WRITE(mac, 0x0003, 0x0122);
7040203945Sweongyo		else
7041203945Sweongyo			BWN_PHY_SET(mac, 0x000a, 0x2000);
7042203945Sweongyo		if (phy->rev != 1) {
7043203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0004);
7044203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffb);
7045203945Sweongyo		}
7046203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
7047203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x000f);
7048203945Sweongyo		bwn_set_all_gains(mac, 3, 0, 1);
7049203945Sweongyo		BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
7050203945Sweongyo		DELAY(30);
7051203945Sweongyo		nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7052203945Sweongyo		if (nrssi >= 0x20)
7053203945Sweongyo			nrssi -= 0x40;
7054203945Sweongyo		if (nrssi == -32) {
7055203945Sweongyo			for (i = 0; i < 4; i++) {
7056203945Sweongyo				BWN_RF_WRITE(mac, 0x007b, i);
7057203945Sweongyo				DELAY(20);
7058203945Sweongyo				nrssi = (int16_t)((BWN_PHY_READ(mac,
7059203945Sweongyo				    0x047f) >> 8) & 0x003f);
7060203945Sweongyo				if (nrssi >= 0x20)
7061203945Sweongyo					nrssi -= 0x40;
7062203945Sweongyo				if (nrssi > -31 && saved == 0xffff)
7063203945Sweongyo					saved = i;
7064203945Sweongyo			}
7065203945Sweongyo			if (saved == 0xffff)
7066203945Sweongyo				saved = 3;
7067203945Sweongyo		} else
7068203945Sweongyo			saved = 0;
7069203945Sweongyo	}
7070203945Sweongyo	BWN_RF_WRITE(mac, 0x007b, saved);
7071203945Sweongyo
7072203945Sweongyo	/*
7073203945Sweongyo	 * Restore saved RF/PHY registers
7074203945Sweongyo	 */
7075203945Sweongyo	if (phy->rev >= 6) {
7076203945Sweongyo		for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
7077203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7078203945Sweongyo			    save_phy6[phy6_idx]);
7079203945Sweongyo		}
7080203945Sweongyo	}
7081203945Sweongyo	if (phy->rev != 1) {
7082203945Sweongyo		for (i = 3; i < 5; i++)
7083203945Sweongyo			BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
7084203945Sweongyo			    save_phy_comm[i]);
7085203945Sweongyo	}
7086203945Sweongyo	for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
7087203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
7088203945Sweongyo
7089203945Sweongyo	for (i = SAVE_RF_MAX - 1; i >= 0; --i)
7090203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
7091203945Sweongyo
7092203945Sweongyo	BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
7093203945Sweongyo	BWN_PHY_SET(mac, 0x0429, 0x8000);
7094203945Sweongyo	bwn_set_original_gains(mac);
7095203945Sweongyo	if (phy->rev >= 6) {
7096203945Sweongyo		for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
7097203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7098203945Sweongyo			    save_phy6[phy6_idx]);
7099203945Sweongyo		}
7100203945Sweongyo	}
7101203945Sweongyo
7102203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
7103203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
7104203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
7105203945Sweongyo}
7106203945Sweongyo
7107203945Sweongyostatic void
7108203945Sweongyobwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
7109203945Sweongyo    int16_t third)
7110203945Sweongyo{
7111203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7112203945Sweongyo	uint16_t i;
7113203945Sweongyo	uint16_t start = 0x08, end = 0x18;
7114203945Sweongyo	uint16_t tmp;
7115203945Sweongyo	uint16_t table;
7116203945Sweongyo
7117203945Sweongyo	if (phy->rev <= 1) {
7118203945Sweongyo		start = 0x10;
7119203945Sweongyo		end = 0x20;
7120203945Sweongyo	}
7121203945Sweongyo
7122203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7123203945Sweongyo	if (phy->rev <= 1)
7124203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7125203945Sweongyo	for (i = 0; i < 4; i++)
7126203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, first);
7127203945Sweongyo
7128203945Sweongyo	for (i = start; i < end; i++)
7129203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, second);
7130203945Sweongyo
7131203945Sweongyo	if (third != -1) {
7132203945Sweongyo		tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
7133203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
7134203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
7135203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
7136203945Sweongyo	}
7137203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7138203945Sweongyo}
7139203945Sweongyo
7140203945Sweongyostatic void
7141203945Sweongyobwn_set_original_gains(struct bwn_mac *mac)
7142203945Sweongyo{
7143203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7144203945Sweongyo	uint16_t i, tmp;
7145203945Sweongyo	uint16_t table;
7146203945Sweongyo	uint16_t start = 0x0008, end = 0x0018;
7147203945Sweongyo
7148203945Sweongyo	if (phy->rev <= 1) {
7149203945Sweongyo		start = 0x0010;
7150203945Sweongyo		end = 0x0020;
7151203945Sweongyo	}
7152203945Sweongyo
7153203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7154203945Sweongyo	if (phy->rev <= 1)
7155203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7156203945Sweongyo	for (i = 0; i < 4; i++) {
7157203945Sweongyo		tmp = (i & 0xfffc);
7158203945Sweongyo		tmp |= (i & 0x0001) << 1;
7159203945Sweongyo		tmp |= (i & 0x0002) >> 1;
7160203945Sweongyo
7161203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, tmp);
7162203945Sweongyo	}
7163203945Sweongyo
7164203945Sweongyo	for (i = start; i < end; i++)
7165203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, i - start);
7166203945Sweongyo
7167203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
7168203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
7169203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
7170203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7171203945Sweongyo}
7172203945Sweongyo
7173203945Sweongyostatic void
7174203945Sweongyobwn_phy_hwpctl_init(struct bwn_mac *mac)
7175203945Sweongyo{
7176203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7177203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7178203945Sweongyo	struct bwn_rfatt old_rfatt, rfatt;
7179203945Sweongyo	struct bwn_bbatt old_bbatt, bbatt;
7180204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7181203945Sweongyo	uint8_t old_txctl = 0;
7182203945Sweongyo
7183203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
7184203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7185203945Sweongyo
7186204922Sweongyo	if ((siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM) &&
7187204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306))
7188203945Sweongyo		return;
7189203945Sweongyo
7190203945Sweongyo	BWN_PHY_WRITE(mac, 0x0028, 0x8018);
7191203945Sweongyo
7192203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
7193203945Sweongyo
7194203945Sweongyo	if (!phy->gmode)
7195203945Sweongyo		return;
7196203945Sweongyo	bwn_hwpctl_early_init(mac);
7197203945Sweongyo	if (pg->pg_curtssi == 0) {
7198203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0) {
7199203945Sweongyo			BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
7200203945Sweongyo		} else {
7201203945Sweongyo			memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
7202203945Sweongyo			memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
7203203945Sweongyo			old_txctl = pg->pg_txctl;
7204203945Sweongyo
7205203945Sweongyo			bbatt.att = 11;
7206203945Sweongyo			if (phy->rf_rev == 8) {
7207203945Sweongyo				rfatt.att = 15;
7208203945Sweongyo				rfatt.padmix = 1;
7209203945Sweongyo			} else {
7210203945Sweongyo				rfatt.att = 9;
7211203945Sweongyo				rfatt.padmix = 0;
7212203945Sweongyo			}
7213203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
7214203945Sweongyo		}
7215203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
7216203945Sweongyo		pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
7217203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0)
7218203945Sweongyo			BWN_RF_MASK(mac, 0x0076, 0xff7b);
7219203945Sweongyo		else
7220203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
7221203945Sweongyo			    &old_rfatt, old_txctl);
7222203945Sweongyo	}
7223203945Sweongyo	bwn_hwpctl_init_gphy(mac);
7224203945Sweongyo
7225203945Sweongyo	/* clear TSSI */
7226203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
7227203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
7228203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
7229203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
7230203945Sweongyo}
7231203945Sweongyo
7232203945Sweongyostatic void
7233203945Sweongyobwn_hwpctl_early_init(struct bwn_mac *mac)
7234203945Sweongyo{
7235203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7236203945Sweongyo
7237203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7238203945Sweongyo		BWN_PHY_WRITE(mac, 0x047a, 0xc111);
7239203945Sweongyo		return;
7240203945Sweongyo	}
7241203945Sweongyo
7242203945Sweongyo	BWN_PHY_MASK(mac, 0x0036, 0xfeff);
7243203945Sweongyo	BWN_PHY_WRITE(mac, 0x002f, 0x0202);
7244203945Sweongyo	BWN_PHY_SET(mac, 0x047c, 0x0002);
7245203945Sweongyo	BWN_PHY_SET(mac, 0x047a, 0xf000);
7246203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
7247203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7248203945Sweongyo		BWN_PHY_SET(mac, 0x005d, 0x8000);
7249203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7250203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7251203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7252203945Sweongyo	} else {
7253203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0200);
7254203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7255203945Sweongyo		BWN_PHY_MASK(mac, 0x005d, 0x7fff);
7256203945Sweongyo		BWN_PHY_MASK(mac, 0x004f, 0xfffe);
7257203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7258203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7259203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7260203945Sweongyo	}
7261203945Sweongyo}
7262203945Sweongyo
7263203945Sweongyostatic void
7264203945Sweongyobwn_hwpctl_init_gphy(struct bwn_mac *mac)
7265203945Sweongyo{
7266203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7267203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7268203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7269203945Sweongyo	int i;
7270203945Sweongyo	uint16_t nr_written = 0, tmp, value;
7271203945Sweongyo	uint8_t rf, bb;
7272203945Sweongyo
7273203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7274203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
7275203945Sweongyo		return;
7276203945Sweongyo	}
7277203945Sweongyo
7278203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
7279203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7280203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
7281203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7282203945Sweongyo
7283203945Sweongyo	for (i = 0; i < 32; i++)
7284203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
7285203945Sweongyo	for (i = 32; i < 64; i++)
7286203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
7287203945Sweongyo	for (i = 0; i < 64; i += 2) {
7288203945Sweongyo		value = (uint16_t) pg->pg_tssi2dbm[i];
7289203945Sweongyo		value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
7290203945Sweongyo		BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
7291203945Sweongyo	}
7292203945Sweongyo
7293203945Sweongyo	for (rf = 0; rf < lo->rfatt.len; rf++) {
7294203945Sweongyo		for (bb = 0; bb < lo->bbatt.len; bb++) {
7295203945Sweongyo			if (nr_written >= 0x40)
7296203945Sweongyo				return;
7297203945Sweongyo			tmp = lo->bbatt.array[bb].att;
7298203945Sweongyo			tmp <<= 8;
7299203945Sweongyo			if (phy->rf_rev == 8)
7300203945Sweongyo				tmp |= 0x50;
7301203945Sweongyo			else
7302203945Sweongyo				tmp |= 0x40;
7303203945Sweongyo			tmp |= lo->rfatt.array[rf].att;
7304203945Sweongyo			BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
7305203945Sweongyo			nr_written++;
7306203945Sweongyo		}
7307203945Sweongyo	}
7308203945Sweongyo
7309203945Sweongyo	BWN_PHY_MASK(mac, 0x0060, 0xffbf);
7310203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0000);
7311203945Sweongyo
7312203945Sweongyo	KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
7313203945Sweongyo	BWN_PHY_SET(mac, 0x0478, 0x0800);
7314203945Sweongyo	BWN_PHY_MASK(mac, 0x0478, 0xfeff);
7315203945Sweongyo	BWN_PHY_MASK(mac, 0x0801, 0xffbf);
7316203945Sweongyo
7317203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
7318203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
7319203945Sweongyo}
7320203945Sweongyo
7321203945Sweongyostatic void
7322203945Sweongyobwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
7323203945Sweongyo{
7324204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7325203945Sweongyo
7326203945Sweongyo	if (spu != 0)
7327203945Sweongyo		bwn_spu_workaround(mac, channel);
7328203945Sweongyo
7329203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7330203945Sweongyo
7331203945Sweongyo	if (channel == 14) {
7332204922Sweongyo		if (siba_sprom_get_ccode(sc->sc_dev) == SIBA_CCODE_JAPAN)
7333203945Sweongyo			bwn_hf_write(mac,
7334203945Sweongyo			    bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
7335203945Sweongyo		else
7336203945Sweongyo			bwn_hf_write(mac,
7337203945Sweongyo			    bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
7338203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7339203945Sweongyo		    BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
7340203945Sweongyo		return;
7341203945Sweongyo	}
7342203945Sweongyo
7343203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7344203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
7345203945Sweongyo}
7346203945Sweongyo
7347203945Sweongyostatic uint16_t
7348203945Sweongyobwn_phy_g_chan2freq(uint8_t channel)
7349203945Sweongyo{
7350203945Sweongyo	static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
7351203945Sweongyo
7352203945Sweongyo	KASSERT(channel >= 1 && channel <= 14,
7353203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7354203945Sweongyo
7355203945Sweongyo	return (bwn_phy_g_rf_channels[channel - 1]);
7356203945Sweongyo}
7357203945Sweongyo
7358203945Sweongyostatic void
7359203945Sweongyobwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
7360203945Sweongyo    const struct bwn_rfatt *rfatt, uint8_t txctl)
7361203945Sweongyo{
7362203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7363203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7364203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7365203945Sweongyo	uint16_t bb, rf;
7366203945Sweongyo	uint16_t tx_bias, tx_magn;
7367203945Sweongyo
7368203945Sweongyo	bb = bbatt->att;
7369203945Sweongyo	rf = rfatt->att;
7370203945Sweongyo	tx_bias = lo->tx_bias;
7371203945Sweongyo	tx_magn = lo->tx_magn;
7372203945Sweongyo	if (tx_bias == 0xff)
7373203945Sweongyo		tx_bias = 0;
7374203945Sweongyo
7375203945Sweongyo	pg->pg_txctl = txctl;
7376203945Sweongyo	memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
7377203945Sweongyo	pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
7378203945Sweongyo	memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
7379203945Sweongyo	bwn_phy_g_set_bbatt(mac, bb);
7380203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
7381203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
7382203945Sweongyo		BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
7383203945Sweongyo	else {
7384203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
7385203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
7386203945Sweongyo	}
7387203945Sweongyo	if (BWN_HAS_TXMAG(phy))
7388203945Sweongyo		BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
7389203945Sweongyo	else
7390203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
7391203945Sweongyo	bwn_lo_g_adjust(mac);
7392203945Sweongyo}
7393203945Sweongyo
7394203945Sweongyostatic void
7395203945Sweongyobwn_phy_g_set_bbatt(struct bwn_mac *mac,
7396203945Sweongyo    uint16_t bbatt)
7397203945Sweongyo{
7398203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7399203945Sweongyo
7400203945Sweongyo	if (phy->analog == 0) {
7401203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY0,
7402203945Sweongyo		    (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
7403203945Sweongyo		return;
7404203945Sweongyo	}
7405203945Sweongyo	if (phy->analog > 1) {
7406203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
7407203945Sweongyo		return;
7408203945Sweongyo	}
7409203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
7410203945Sweongyo}
7411203945Sweongyo
7412203945Sweongyostatic uint16_t
7413203945Sweongyobwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
7414203945Sweongyo{
7415203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7416203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7417204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7418203945Sweongyo	int max_lb_gain;
7419203945Sweongyo	uint16_t extlna;
7420203945Sweongyo	uint16_t i;
7421203945Sweongyo
7422203945Sweongyo	if (phy->gmode == 0)
7423203945Sweongyo		return (0);
7424203945Sweongyo
7425203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
7426203945Sweongyo		max_lb_gain = pg->pg_max_lb_gain;
7427203945Sweongyo		max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
7428203945Sweongyo		if (max_lb_gain >= 0x46) {
7429203945Sweongyo			extlna = 0x3000;
7430203945Sweongyo			max_lb_gain -= 0x46;
7431203945Sweongyo		} else if (max_lb_gain >= 0x3a) {
7432203945Sweongyo			extlna = 0x1000;
7433203945Sweongyo			max_lb_gain -= 0x3a;
7434203945Sweongyo		} else if (max_lb_gain >= 0x2e) {
7435203945Sweongyo			extlna = 0x2000;
7436203945Sweongyo			max_lb_gain -= 0x2e;
7437203945Sweongyo		} else {
7438203945Sweongyo			extlna = 0;
7439203945Sweongyo			max_lb_gain -= 0x10;
7440203945Sweongyo		}
7441203945Sweongyo
7442203945Sweongyo		for (i = 0; i < 16; i++) {
7443203945Sweongyo			max_lb_gain -= (i * 6);
7444203945Sweongyo			if (max_lb_gain < 6)
7445203945Sweongyo				break;
7446203945Sweongyo		}
7447203945Sweongyo
7448204922Sweongyo		if ((phy->rev < 7) ||
7449204922Sweongyo		    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
7450203945Sweongyo			if (reg == BWN_PHY_RFOVER) {
7451203945Sweongyo				return (0x1b3);
7452203945Sweongyo			} else if (reg == BWN_PHY_RFOVERVAL) {
7453203945Sweongyo				extlna |= (i << 8);
7454203945Sweongyo				switch (lpd) {
7455203945Sweongyo				case BWN_LPD(0, 1, 1):
7456203945Sweongyo					return (0x0f92);
7457203945Sweongyo				case BWN_LPD(0, 0, 1):
7458203945Sweongyo				case BWN_LPD(1, 0, 1):
7459203945Sweongyo					return (0x0092 | extlna);
7460203945Sweongyo				case BWN_LPD(1, 0, 0):
7461203945Sweongyo					return (0x0093 | extlna);
7462203945Sweongyo				}
7463203945Sweongyo				KASSERT(0 == 1,
7464203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7465203945Sweongyo			}
7466203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7467203945Sweongyo		} else {
7468203945Sweongyo			if (reg == BWN_PHY_RFOVER)
7469203945Sweongyo				return (0x9b3);
7470203945Sweongyo			if (reg == BWN_PHY_RFOVERVAL) {
7471203945Sweongyo				if (extlna)
7472203945Sweongyo					extlna |= 0x8000;
7473203945Sweongyo				extlna |= (i << 8);
7474203945Sweongyo				switch (lpd) {
7475203945Sweongyo				case BWN_LPD(0, 1, 1):
7476203945Sweongyo					return (0x8f92);
7477203945Sweongyo				case BWN_LPD(0, 0, 1):
7478203945Sweongyo					return (0x8092 | extlna);
7479203945Sweongyo				case BWN_LPD(1, 0, 1):
7480203945Sweongyo					return (0x2092 | extlna);
7481203945Sweongyo				case BWN_LPD(1, 0, 0):
7482203945Sweongyo					return (0x2093 | extlna);
7483203945Sweongyo				}
7484203945Sweongyo				KASSERT(0 == 1,
7485203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7486203945Sweongyo			}
7487203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7488203945Sweongyo		}
7489203945Sweongyo		return (0);
7490203945Sweongyo	}
7491203945Sweongyo
7492203945Sweongyo	if ((phy->rev < 7) ||
7493204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
7494203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7495203945Sweongyo			return (0x1b3);
7496203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7497203945Sweongyo			switch (lpd) {
7498203945Sweongyo			case BWN_LPD(0, 1, 1):
7499203945Sweongyo				return (0x0fb2);
7500203945Sweongyo			case BWN_LPD(0, 0, 1):
7501203945Sweongyo				return (0x00b2);
7502203945Sweongyo			case BWN_LPD(1, 0, 1):
7503203945Sweongyo				return (0x30b2);
7504203945Sweongyo			case BWN_LPD(1, 0, 0):
7505203945Sweongyo				return (0x30b3);
7506203945Sweongyo			}
7507203945Sweongyo			KASSERT(0 == 1,
7508203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7509203945Sweongyo		}
7510203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7511203945Sweongyo	} else {
7512203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7513203945Sweongyo			return (0x9b3);
7514203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7515203945Sweongyo			switch (lpd) {
7516203945Sweongyo			case BWN_LPD(0, 1, 1):
7517203945Sweongyo				return (0x8fb2);
7518203945Sweongyo			case BWN_LPD(0, 0, 1):
7519203945Sweongyo				return (0x80b2);
7520203945Sweongyo			case BWN_LPD(1, 0, 1):
7521203945Sweongyo				return (0x20b2);
7522203945Sweongyo			case BWN_LPD(1, 0, 0):
7523203945Sweongyo				return (0x20b3);
7524203945Sweongyo			}
7525203945Sweongyo			KASSERT(0 == 1,
7526203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7527203945Sweongyo		}
7528203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7529203945Sweongyo	}
7530203945Sweongyo	return (0);
7531203945Sweongyo}
7532203945Sweongyo
7533203945Sweongyostatic void
7534203945Sweongyobwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
7535203945Sweongyo{
7536203945Sweongyo
7537203945Sweongyo	if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
7538203945Sweongyo		return;
7539203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
7540203945Sweongyo	    bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
7541203945Sweongyo	DELAY(1000);
7542203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7543203945Sweongyo}
7544203945Sweongyo
7545203945Sweongyostatic int
7546203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
7547203945Sweongyo{
7548203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7549203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
7550204922Sweongyo	const uint8_t rev = siba_get_revid(sc->sc_dev);
7551203945Sweongyo	const char *filename;
7552203945Sweongyo	uint32_t high;
7553203945Sweongyo	int error;
7554203945Sweongyo
7555203945Sweongyo	/* microcode */
7556203945Sweongyo	if (rev >= 5 && rev <= 10)
7557203945Sweongyo		filename = "ucode5";
7558203945Sweongyo	else if (rev >= 11 && rev <= 12)
7559203945Sweongyo		filename = "ucode11";
7560203945Sweongyo	else if (rev == 13)
7561203945Sweongyo		filename = "ucode13";
7562203945Sweongyo	else if (rev == 14)
7563203945Sweongyo		filename = "ucode14";
7564203945Sweongyo	else if (rev >= 15)
7565203945Sweongyo		filename = "ucode15";
7566203945Sweongyo	else {
7567203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
7568203945Sweongyo		bwn_release_firmware(mac);
7569203945Sweongyo		return (EOPNOTSUPP);
7570203945Sweongyo	}
7571203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
7572203945Sweongyo	if (error) {
7573203945Sweongyo		bwn_release_firmware(mac);
7574203945Sweongyo		return (error);
7575203945Sweongyo	}
7576203945Sweongyo
7577203945Sweongyo	/* PCM */
7578203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
7579203945Sweongyo	if (rev >= 5 && rev <= 10) {
7580203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
7581203945Sweongyo		if (error == ENOENT)
7582203945Sweongyo			fw->no_pcmfile = 1;
7583203945Sweongyo		else if (error) {
7584203945Sweongyo			bwn_release_firmware(mac);
7585203945Sweongyo			return (error);
7586203945Sweongyo		}
7587203945Sweongyo	} else if (rev < 11) {
7588203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
7589203945Sweongyo		return (EOPNOTSUPP);
7590203945Sweongyo	}
7591203945Sweongyo
7592203945Sweongyo	/* initvals */
7593204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
7594203945Sweongyo	switch (mac->mac_phy.type) {
7595203945Sweongyo	case BWN_PHYTYPE_A:
7596203945Sweongyo		if (rev < 5 || rev > 10)
7597203945Sweongyo			goto fail1;
7598203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
7599203945Sweongyo			filename = "a0g1initvals5";
7600203945Sweongyo		else
7601203945Sweongyo			filename = "a0g0initvals5";
7602203945Sweongyo		break;
7603203945Sweongyo	case BWN_PHYTYPE_G:
7604203945Sweongyo		if (rev >= 5 && rev <= 10)
7605203945Sweongyo			filename = "b0g0initvals5";
7606203945Sweongyo		else if (rev >= 13)
7607203945Sweongyo			filename = "b0g0initvals13";
7608203945Sweongyo		else
7609203945Sweongyo			goto fail1;
7610203945Sweongyo		break;
7611203945Sweongyo	case BWN_PHYTYPE_LP:
7612203945Sweongyo		if (rev == 13)
7613203945Sweongyo			filename = "lp0initvals13";
7614203945Sweongyo		else if (rev == 14)
7615203945Sweongyo			filename = "lp0initvals14";
7616203945Sweongyo		else if (rev >= 15)
7617203945Sweongyo			filename = "lp0initvals15";
7618203945Sweongyo		else
7619203945Sweongyo			goto fail1;
7620203945Sweongyo		break;
7621203945Sweongyo	case BWN_PHYTYPE_N:
7622203945Sweongyo		if (rev >= 11 && rev <= 12)
7623203945Sweongyo			filename = "n0initvals11";
7624203945Sweongyo		else
7625203945Sweongyo			goto fail1;
7626203945Sweongyo		break;
7627203945Sweongyo	default:
7628203945Sweongyo		goto fail1;
7629203945Sweongyo	}
7630203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
7631203945Sweongyo	if (error) {
7632203945Sweongyo		bwn_release_firmware(mac);
7633203945Sweongyo		return (error);
7634203945Sweongyo	}
7635203945Sweongyo
7636203945Sweongyo	/* bandswitch initvals */
7637203945Sweongyo	switch (mac->mac_phy.type) {
7638203945Sweongyo	case BWN_PHYTYPE_A:
7639203945Sweongyo		if (rev >= 5 && rev <= 10) {
7640203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
7641203945Sweongyo				filename = "a0g1bsinitvals5";
7642203945Sweongyo			else
7643203945Sweongyo				filename = "a0g0bsinitvals5";
7644203945Sweongyo		} else if (rev >= 11)
7645203945Sweongyo			filename = NULL;
7646203945Sweongyo		else
7647203945Sweongyo			goto fail1;
7648203945Sweongyo		break;
7649203945Sweongyo	case BWN_PHYTYPE_G:
7650203945Sweongyo		if (rev >= 5 && rev <= 10)
7651203945Sweongyo			filename = "b0g0bsinitvals5";
7652203945Sweongyo		else if (rev >= 11)
7653203945Sweongyo			filename = NULL;
7654203945Sweongyo		else
7655203945Sweongyo			goto fail1;
7656203945Sweongyo		break;
7657203945Sweongyo	case BWN_PHYTYPE_LP:
7658203945Sweongyo		if (rev == 13)
7659203945Sweongyo			filename = "lp0bsinitvals13";
7660203945Sweongyo		else if (rev == 14)
7661203945Sweongyo			filename = "lp0bsinitvals14";
7662203945Sweongyo		else if (rev >= 15)
7663203945Sweongyo			filename = "lp0bsinitvals15";
7664203945Sweongyo		else
7665203945Sweongyo			goto fail1;
7666203945Sweongyo		break;
7667203945Sweongyo	case BWN_PHYTYPE_N:
7668203945Sweongyo		if (rev >= 11 && rev <= 12)
7669203945Sweongyo			filename = "n0bsinitvals11";
7670203945Sweongyo		else
7671203945Sweongyo			goto fail1;
7672203945Sweongyo		break;
7673203945Sweongyo	default:
7674203945Sweongyo		goto fail1;
7675203945Sweongyo	}
7676203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
7677203945Sweongyo	if (error) {
7678203945Sweongyo		bwn_release_firmware(mac);
7679203945Sweongyo		return (error);
7680203945Sweongyo	}
7681203945Sweongyo	return (0);
7682203945Sweongyofail1:
7683203945Sweongyo	device_printf(sc->sc_dev, "no INITVALS for rev %d\n", rev);
7684203945Sweongyo	bwn_release_firmware(mac);
7685203945Sweongyo	return (EOPNOTSUPP);
7686203945Sweongyo}
7687203945Sweongyo
7688203945Sweongyostatic int
7689203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
7690203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
7691203945Sweongyo{
7692203945Sweongyo	const struct bwn_fwhdr *hdr;
7693203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7694203945Sweongyo	const struct firmware *fw;
7695203945Sweongyo	char namebuf[64];
7696203945Sweongyo
7697203945Sweongyo	if (name == NULL) {
7698203945Sweongyo		bwn_do_release_fw(bfw);
7699203945Sweongyo		return (0);
7700203945Sweongyo	}
7701203945Sweongyo	if (bfw->filename != NULL) {
7702203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
7703203945Sweongyo			return (0);
7704203945Sweongyo		bwn_do_release_fw(bfw);
7705203945Sweongyo	}
7706203945Sweongyo
7707204437Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s%s",
7708204437Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "",
7709204437Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_LP) ? "lp_" : "", name);
7710203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
7711203945Sweongyo	fw = firmware_get(namebuf);
7712203945Sweongyo	if (fw == NULL) {
7713203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
7714203945Sweongyo		    namebuf);
7715203945Sweongyo		return (ENOENT);
7716203945Sweongyo	}
7717203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
7718203945Sweongyo		goto fail;
7719203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
7720203945Sweongyo	switch (hdr->type) {
7721203945Sweongyo	case BWN_FWTYPE_UCODE:
7722203945Sweongyo	case BWN_FWTYPE_PCM:
7723203945Sweongyo		if (be32toh(hdr->size) !=
7724203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
7725203945Sweongyo			goto fail;
7726203945Sweongyo		/* FALLTHROUGH */
7727203945Sweongyo	case BWN_FWTYPE_IV:
7728203945Sweongyo		if (hdr->ver != 1)
7729203945Sweongyo			goto fail;
7730203945Sweongyo		break;
7731203945Sweongyo	default:
7732203945Sweongyo		goto fail;
7733203945Sweongyo	}
7734203945Sweongyo	bfw->filename = name;
7735203945Sweongyo	bfw->fw = fw;
7736203945Sweongyo	bfw->type = type;
7737203945Sweongyo	return (0);
7738203945Sweongyofail:
7739203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
7740203945Sweongyo	if (fw != NULL)
7741203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
7742203945Sweongyo	return (EPROTO);
7743203945Sweongyo}
7744203945Sweongyo
7745203945Sweongyostatic void
7746203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
7747203945Sweongyo{
7748203945Sweongyo
7749203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
7750203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
7751203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
7752203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
7753203945Sweongyo}
7754203945Sweongyo
7755203945Sweongyostatic void
7756203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
7757203945Sweongyo{
7758203945Sweongyo
7759203945Sweongyo	if (bfw->fw != NULL)
7760203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
7761203945Sweongyo	bfw->fw = NULL;
7762203945Sweongyo	bfw->filename = NULL;
7763203945Sweongyo}
7764203945Sweongyo
7765203945Sweongyostatic int
7766203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
7767203945Sweongyo{
7768203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
7769203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
7770203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
7771203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
7772203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7773203945Sweongyo	const uint32_t *data;
7774203945Sweongyo	unsigned int i;
7775203945Sweongyo	uint32_t ctl;
7776203945Sweongyo	uint16_t date, fwcaps, time;
7777203945Sweongyo	int error = 0;
7778203945Sweongyo
7779203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
7780203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
7781203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
7782203945Sweongyo	    __LINE__));
7783203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
7784203945Sweongyo	for (i = 0; i < 64; i++)
7785203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
7786203945Sweongyo	for (i = 0; i < 4096; i += 2)
7787203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
7788203945Sweongyo
7789203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7790203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
7791203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7792203945Sweongyo	     i++) {
7793203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7794203945Sweongyo		DELAY(10);
7795203945Sweongyo	}
7796203945Sweongyo
7797203945Sweongyo	if (mac->mac_fw.pcm.fw) {
7798203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
7799203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
7800203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
7801203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
7802203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
7803203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
7804203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7805203945Sweongyo			DELAY(10);
7806203945Sweongyo		}
7807203945Sweongyo	}
7808203945Sweongyo
7809203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
7810203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7811203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
7812203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
7813203945Sweongyo
7814203945Sweongyo	for (i = 0; i < 21; i++) {
7815203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
7816203945Sweongyo			break;
7817203945Sweongyo		if (i >= 20) {
7818203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
7819203945Sweongyo			error = ENXIO;
7820203945Sweongyo			goto error;
7821203945Sweongyo		}
7822203945Sweongyo		DELAY(50000);
7823203945Sweongyo	}
7824203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
7825203945Sweongyo
7826203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
7827203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
7828203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
7829203945Sweongyo		error = EOPNOTSUPP;
7830203945Sweongyo		goto error;
7831203945Sweongyo	}
7832203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
7833203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
7834203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
7835203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
7836203945Sweongyo	if (bwn_wme != 0)
7837203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
7838203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
7839203945Sweongyo
7840203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
7841203945Sweongyo	if (mac->mac_fw.opensource == 0) {
7842203945Sweongyo		device_printf(sc->sc_dev,
7843203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
7844203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
7845203945Sweongyo		if (mac->mac_fw.no_pcmfile)
7846203945Sweongyo			device_printf(sc->sc_dev,
7847203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
7848203945Sweongyo	} else {
7849203945Sweongyo		mac->mac_fw.patch = time;
7850203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
7851203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
7852203945Sweongyo			device_printf(sc->sc_dev,
7853203945Sweongyo			    "disabling HW crypto acceleration\n");
7854203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
7855203945Sweongyo		}
7856203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
7857203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
7858203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
7859203945Sweongyo		}
7860203945Sweongyo	}
7861203945Sweongyo
7862203945Sweongyo	if (BWN_ISOLDFMT(mac))
7863203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
7864203945Sweongyo
7865203945Sweongyo	return (0);
7866203945Sweongyo
7867203945Sweongyoerror:
7868203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7869203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
7870203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
7871203945Sweongyo
7872203945Sweongyo	return (error);
7873203945Sweongyo#undef GETFWSIZE
7874203945Sweongyo#undef GETFWOFFSET
7875203945Sweongyo}
7876203945Sweongyo
7877203945Sweongyo/* OpenFirmware only */
7878203945Sweongyostatic uint16_t
7879203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
7880203945Sweongyo{
7881203945Sweongyo
7882203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
7883203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7884203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
7885203945Sweongyo}
7886203945Sweongyo
7887203945Sweongyostatic int
7888203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
7889203945Sweongyo    size_t count, size_t array_size)
7890203945Sweongyo{
7891203945Sweongyo#define	GET_NEXTIV16(iv)						\
7892203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7893203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
7894203945Sweongyo#define	GET_NEXTIV32(iv)						\
7895203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7896203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
7897203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7898203945Sweongyo	const struct bwn_fwinitvals *iv;
7899203945Sweongyo	uint16_t offset;
7900203945Sweongyo	size_t i;
7901203945Sweongyo	uint8_t bit32;
7902203945Sweongyo
7903203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
7904203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7905203945Sweongyo	iv = ivals;
7906203945Sweongyo	for (i = 0; i < count; i++) {
7907203945Sweongyo		if (array_size < sizeof(iv->offset_size))
7908203945Sweongyo			goto fail;
7909203945Sweongyo		array_size -= sizeof(iv->offset_size);
7910203945Sweongyo		offset = be16toh(iv->offset_size);
7911203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
7912203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
7913203945Sweongyo		if (offset >= 0x1000)
7914203945Sweongyo			goto fail;
7915203945Sweongyo		if (bit32) {
7916203945Sweongyo			if (array_size < sizeof(iv->data.d32))
7917203945Sweongyo				goto fail;
7918203945Sweongyo			array_size -= sizeof(iv->data.d32);
7919203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
7920203945Sweongyo			iv = GET_NEXTIV32(iv);
7921203945Sweongyo		} else {
7922203945Sweongyo
7923203945Sweongyo			if (array_size < sizeof(iv->data.d16))
7924203945Sweongyo				goto fail;
7925203945Sweongyo			array_size -= sizeof(iv->data.d16);
7926203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
7927203945Sweongyo
7928203945Sweongyo			iv = GET_NEXTIV16(iv);
7929203945Sweongyo		}
7930203945Sweongyo	}
7931203945Sweongyo	if (array_size != 0)
7932203945Sweongyo		goto fail;
7933203945Sweongyo	return (0);
7934203945Sweongyofail:
7935203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
7936203945Sweongyo	return (EPROTO);
7937203945Sweongyo#undef GET_NEXTIV16
7938203945Sweongyo#undef GET_NEXTIV32
7939203945Sweongyo}
7940203945Sweongyo
7941203945Sweongyostatic int
7942203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
7943203945Sweongyo{
7944203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
7945203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7946203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
7947203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
7948203945Sweongyo	uint16_t channelcookie, savedcookie;
7949203945Sweongyo	int error;
7950203945Sweongyo
7951203945Sweongyo	if (chan == 0xffff)
7952203945Sweongyo		chan = phy->get_default_chan(mac);
7953203945Sweongyo
7954203945Sweongyo	channelcookie = chan;
7955203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
7956203945Sweongyo		channelcookie |= 0x100;
7957203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
7958203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
7959203945Sweongyo	error = phy->switch_channel(mac, chan);
7960203945Sweongyo	if (error)
7961203945Sweongyo		goto fail;
7962203945Sweongyo
7963203945Sweongyo	mac->mac_phy.chan = chan;
7964203945Sweongyo	DELAY(8000);
7965203945Sweongyo	return (0);
7966203945Sweongyofail:
7967203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
7968203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
7969203945Sweongyo	return (error);
7970203945Sweongyo}
7971203945Sweongyo
7972203945Sweongyostatic uint16_t
7973203945Sweongyobwn_ant2phy(int antenna)
7974203945Sweongyo{
7975203945Sweongyo
7976203945Sweongyo	switch (antenna) {
7977203945Sweongyo	case BWN_ANT0:
7978203945Sweongyo		return (BWN_TX_PHY_ANT0);
7979203945Sweongyo	case BWN_ANT1:
7980203945Sweongyo		return (BWN_TX_PHY_ANT1);
7981203945Sweongyo	case BWN_ANT2:
7982203945Sweongyo		return (BWN_TX_PHY_ANT2);
7983203945Sweongyo	case BWN_ANT3:
7984203945Sweongyo		return (BWN_TX_PHY_ANT3);
7985203945Sweongyo	case BWN_ANTAUTO:
7986203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
7987203945Sweongyo	}
7988203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7989203945Sweongyo	return (0);
7990203945Sweongyo}
7991203945Sweongyo
7992203945Sweongyostatic void
7993203945Sweongyobwn_wme_load(struct bwn_mac *mac)
7994203945Sweongyo{
7995203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7996203945Sweongyo	int i;
7997203945Sweongyo
7998203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
7999203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8000203945Sweongyo
8001203945Sweongyo	bwn_mac_suspend(mac);
8002203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
8003203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
8004203945Sweongyo		    bwn_wme_shm_offsets[i]);
8005203945Sweongyo	bwn_mac_enable(mac);
8006203945Sweongyo}
8007203945Sweongyo
8008203945Sweongyostatic void
8009203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
8010203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
8011203945Sweongyo{
8012203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
8013203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8014203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
8015203945Sweongyo	int slot, tmp;
8016203945Sweongyo	unsigned int i;
8017203945Sweongyo
8018203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
8019203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8020203945Sweongyo
8021203945Sweongyo	memset(&params, 0, sizeof(params));
8022203945Sweongyo
8023203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
8024203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
8025203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
8026203945Sweongyo
8027203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
8028203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8029203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
8030203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8031203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
8032203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
8033203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
8034203945Sweongyo
8035203945Sweongyo	for (i = 0; i < N(params); i++) {
8036203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
8037203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
8038203945Sweongyo			    shm_offset + (i * 2));
8039203945Sweongyo			tmp |= 0x100;
8040203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8041203945Sweongyo			    tmp);
8042203945Sweongyo		} else {
8043203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8044203945Sweongyo			    params[i]);
8045203945Sweongyo		}
8046203945Sweongyo	}
8047203945Sweongyo}
8048203945Sweongyo
8049203945Sweongyostatic void
8050203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
8051203945Sweongyo{
8052203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8053203945Sweongyo	uint32_t tmp;
8054203945Sweongyo	int i;
8055203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
8056203945Sweongyo
8057203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
8058203945Sweongyo	memcpy(mac_bssid, sc->sc_macaddr, IEEE80211_ADDR_LEN);
8059203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
8060203945Sweongyo	    IEEE80211_ADDR_LEN);
8061203945Sweongyo
8062203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
8063203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
8064203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
8065203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
8066203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
8067203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
8068203945Sweongyo	}
8069203945Sweongyo}
8070203945Sweongyo
8071203945Sweongyostatic void
8072203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
8073203945Sweongyo    const uint8_t *macaddr)
8074203945Sweongyo{
8075203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
8076203945Sweongyo	uint16_t data;
8077203945Sweongyo
8078203945Sweongyo	if (!mac)
8079203945Sweongyo		macaddr = zero;
8080203945Sweongyo
8081203945Sweongyo	offset |= 0x0020;
8082203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
8083203945Sweongyo
8084203945Sweongyo	data = macaddr[0];
8085203945Sweongyo	data |= macaddr[1] << 8;
8086203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8087203945Sweongyo	data = macaddr[2];
8088203945Sweongyo	data |= macaddr[3] << 8;
8089203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8090203945Sweongyo	data = macaddr[4];
8091203945Sweongyo	data |= macaddr[5] << 8;
8092203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8093203945Sweongyo}
8094203945Sweongyo
8095203945Sweongyostatic void
8096203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8097203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
8098203945Sweongyo{
8099203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
8100203945Sweongyo	uint8_t per_sta_keys_start = 8;
8101203945Sweongyo
8102203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8103203945Sweongyo		per_sta_keys_start = 4;
8104203945Sweongyo
8105203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
8106203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8107203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
8108203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8109203945Sweongyo
8110203945Sweongyo	if (index >= per_sta_keys_start)
8111203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
8112203945Sweongyo	if (key)
8113203945Sweongyo		memcpy(buf, key, key_len);
8114203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
8115203945Sweongyo	if (index >= per_sta_keys_start)
8116203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
8117203945Sweongyo
8118203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
8119203945Sweongyo}
8120203945Sweongyo
8121203945Sweongyostatic void
8122203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
8123203945Sweongyo{
8124204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8125203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
8126203945Sweongyo	uint8_t start = 8;
8127203945Sweongyo
8128203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8129203945Sweongyo		start = 4;
8130203945Sweongyo
8131203945Sweongyo	KASSERT(index >= start,
8132203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8133203945Sweongyo	index -= start;
8134203945Sweongyo
8135203945Sweongyo	if (addr) {
8136203945Sweongyo		addrtmp[0] = addr[0];
8137203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
8138203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
8139203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
8140203945Sweongyo		addrtmp[1] = addr[4];
8141203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
8142203945Sweongyo	}
8143203945Sweongyo
8144204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
8145203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
8146203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
8147203945Sweongyo	} else {
8148203945Sweongyo		if (index >= 8) {
8149203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
8150203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
8151203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
8152203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
8153203945Sweongyo		}
8154203945Sweongyo	}
8155203945Sweongyo}
8156203945Sweongyo
8157203945Sweongyostatic void
8158203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8159203945Sweongyo    const uint8_t *key)
8160203945Sweongyo{
8161203945Sweongyo	unsigned int i;
8162203945Sweongyo	uint32_t offset;
8163203945Sweongyo	uint16_t kidx, value;
8164203945Sweongyo
8165203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
8166203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
8167203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
8168203945Sweongyo
8169203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
8170203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
8171203945Sweongyo		value = key[i];
8172203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
8173203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
8174203945Sweongyo	}
8175203945Sweongyo}
8176203945Sweongyo
8177203945Sweongyostatic void
8178203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
8179203945Sweongyo{
8180203945Sweongyo
8181203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8182203945Sweongyo	if (mac->mac_phy.exit != NULL)
8183203945Sweongyo		mac->mac_phy.exit(mac);
8184203945Sweongyo}
8185203945Sweongyo
8186203945Sweongyostatic void
8187203945Sweongyobwn_dma_free(struct bwn_mac *mac)
8188203945Sweongyo{
8189203945Sweongyo	struct bwn_dma *dma;
8190203945Sweongyo
8191203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
8192203945Sweongyo		return;
8193203945Sweongyo	dma = &mac->mac_method.dma;
8194203945Sweongyo
8195203945Sweongyo	bwn_dma_ringfree(&dma->rx);
8196203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
8197203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
8198203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
8199203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
8200203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
8201203945Sweongyo}
8202203945Sweongyo
8203203945Sweongyostatic void
8204203945Sweongyobwn_core_stop(struct bwn_mac *mac)
8205203945Sweongyo{
8206203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8207203945Sweongyo
8208203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8209203945Sweongyo
8210203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8211203945Sweongyo		return;
8212203945Sweongyo
8213203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
8214203945Sweongyo	callout_stop(&sc->sc_task_ch);
8215203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
8216203945Sweongyo	sc->sc_watchdog_timer = 0;
8217203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8218203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
8219203945Sweongyo	bwn_mac_suspend(mac);
8220203945Sweongyo
8221203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
8222203945Sweongyo}
8223203945Sweongyo
8224203945Sweongyostatic int
8225203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
8226203945Sweongyo{
8227203945Sweongyo	struct bwn_mac *up_dev = NULL;
8228203945Sweongyo	struct bwn_mac *down_dev;
8229203945Sweongyo	struct bwn_mac *mac;
8230203945Sweongyo	int err, status;
8231203945Sweongyo	uint8_t gmode;
8232203945Sweongyo
8233203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8234203945Sweongyo
8235203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
8236203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
8237203945Sweongyo		    mac->mac_phy.supports_2ghz) {
8238203945Sweongyo			up_dev = mac;
8239203945Sweongyo			gmode = 1;
8240203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
8241203945Sweongyo		    mac->mac_phy.supports_5ghz) {
8242203945Sweongyo			up_dev = mac;
8243203945Sweongyo			gmode = 0;
8244203945Sweongyo		} else {
8245203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8246203945Sweongyo			return (EINVAL);
8247203945Sweongyo		}
8248203945Sweongyo		if (up_dev != NULL)
8249203945Sweongyo			break;
8250203945Sweongyo	}
8251203945Sweongyo	if (up_dev == NULL) {
8252203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
8253203945Sweongyo		return (ENODEV);
8254203945Sweongyo	}
8255203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
8256203945Sweongyo		return (0);
8257203945Sweongyo
8258203945Sweongyo	device_printf(sc->sc_dev, "switching to %s-GHz band\n",
8259203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8260203945Sweongyo
8261216227Skevlo	down_dev = sc->sc_curmac;
8262203945Sweongyo	status = down_dev->mac_status;
8263203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8264203945Sweongyo		bwn_core_stop(down_dev);
8265203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
8266203945Sweongyo		bwn_core_exit(down_dev);
8267203945Sweongyo
8268203945Sweongyo	if (down_dev != up_dev)
8269203945Sweongyo		bwn_phy_reset(down_dev);
8270203945Sweongyo
8271203945Sweongyo	up_dev->mac_phy.gmode = gmode;
8272203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
8273203945Sweongyo		err = bwn_core_init(up_dev);
8274203945Sweongyo		if (err) {
8275203945Sweongyo			device_printf(sc->sc_dev,
8276203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
8277203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8278203945Sweongyo			goto fail;
8279203945Sweongyo		}
8280203945Sweongyo	}
8281203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8282203945Sweongyo		bwn_core_start(up_dev);
8283203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
8284203945Sweongyo	sc->sc_curmac = up_dev;
8285203945Sweongyo
8286203945Sweongyo	return (0);
8287203945Sweongyofail:
8288203945Sweongyo	sc->sc_curmac = NULL;
8289203945Sweongyo	return (err);
8290203945Sweongyo}
8291203945Sweongyo
8292203945Sweongyostatic void
8293203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
8294203945Sweongyo{
8295203945Sweongyo
8296203945Sweongyo	bwn_mac_suspend(mac);
8297203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
8298203945Sweongyo	mac->mac_phy.rf_on = 1;
8299203945Sweongyo	bwn_mac_enable(mac);
8300203945Sweongyo}
8301203945Sweongyo
8302203945Sweongyostatic void
8303203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
8304203945Sweongyo{
8305203945Sweongyo
8306203945Sweongyo	bwn_mac_suspend(mac);
8307203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8308203945Sweongyo	mac->mac_phy.rf_on = 0;
8309203945Sweongyo	bwn_mac_enable(mac);
8310203945Sweongyo}
8311203945Sweongyo
8312203945Sweongyostatic void
8313203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
8314203945Sweongyo{
8315204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8316203945Sweongyo
8317204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
8318204922Sweongyo	    ((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
8319203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
8320203945Sweongyo	DELAY(1000);
8321204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
8322204922Sweongyo	    (siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC) |
8323203945Sweongyo	    BWN_TGSLOW_PHYRESET);
8324203945Sweongyo	DELAY(1000);
8325203945Sweongyo}
8326203945Sweongyo
8327203945Sweongyostatic int
8328203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
8329203945Sweongyo{
8330203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
8331203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
8332203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
8333203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
8334203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
8335203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
8336203945Sweongyo	int error;
8337203945Sweongyo
8338203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
8339203945Sweongyo	    ieee80211_state_name[vap->iv_state],
8340203945Sweongyo	    ieee80211_state_name[nstate]);
8341203945Sweongyo
8342203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
8343203945Sweongyo	if (error != 0)
8344203945Sweongyo		return (error);
8345203945Sweongyo
8346203945Sweongyo	BWN_LOCK(sc);
8347203945Sweongyo
8348203945Sweongyo	bwn_led_newstate(mac, nstate);
8349203945Sweongyo
8350203945Sweongyo	/*
8351203945Sweongyo	 * Clear the BSSID when we stop a STA
8352203945Sweongyo	 */
8353203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
8354203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
8355203945Sweongyo			/*
8356203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
8357203945Sweongyo			 * the same AP, this will reinialize things
8358203945Sweongyo			 * correctly...
8359203945Sweongyo			 */
8360203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
8361203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
8362203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
8363203945Sweongyo				bwn_set_macaddr(mac);
8364203945Sweongyo			}
8365203945Sweongyo		}
8366203945Sweongyo	}
8367203945Sweongyo
8368204436Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR ||
8369204436Sweongyo	    vap->iv_opmode == IEEE80211_M_AHDEMO) {
8370203945Sweongyo		/* XXX nothing to do? */
8371203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
8372203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
8373203945Sweongyo		memcpy(sc->sc_macaddr, IF_LLADDR(ifp), IEEE80211_ADDR_LEN);
8374203945Sweongyo		bwn_set_opmode(mac);
8375203945Sweongyo		bwn_set_pretbtt(mac);
8376203945Sweongyo		bwn_spu_setdelay(mac, 0);
8377203945Sweongyo		bwn_set_macaddr(mac);
8378203945Sweongyo	}
8379203945Sweongyo
8380203945Sweongyo	BWN_UNLOCK(sc);
8381203945Sweongyo
8382203945Sweongyo	return (error);
8383203945Sweongyo}
8384203945Sweongyo
8385203945Sweongyostatic void
8386203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
8387203945Sweongyo{
8388203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8389203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8390203945Sweongyo	uint16_t pretbtt;
8391203945Sweongyo
8392203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8393203945Sweongyo		pretbtt = 2;
8394203945Sweongyo	else
8395203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
8396203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
8397203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
8398203945Sweongyo}
8399203945Sweongyo
8400203945Sweongyostatic int
8401203945Sweongyobwn_intr(void *arg)
8402203945Sweongyo{
8403203945Sweongyo	struct bwn_mac *mac = arg;
8404203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8405203945Sweongyo	uint32_t reason;
8406203945Sweongyo
8407204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
8408204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID))
8409203945Sweongyo		return (FILTER_STRAY);
8410203945Sweongyo
8411203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
8412203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
8413203945Sweongyo		return (FILTER_STRAY);
8414203945Sweongyo	reason &= mac->mac_intr_mask;
8415203945Sweongyo	if (reason == 0)
8416203945Sweongyo		return (FILTER_HANDLED);
8417203945Sweongyo
8418203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
8419203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
8420203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
8421203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
8422203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
8423203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
8424203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
8425203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
8426203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
8427203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
8428203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
8429203945Sweongyo
8430203945Sweongyo	/* Disable interrupts. */
8431203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8432203945Sweongyo
8433203945Sweongyo	mac->mac_reason_intr = reason;
8434203945Sweongyo
8435203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8436203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8437203945Sweongyo
8438203945Sweongyo	taskqueue_enqueue_fast(sc->sc_tq, &mac->mac_intrtask);
8439203945Sweongyo	return (FILTER_HANDLED);
8440203945Sweongyo}
8441203945Sweongyo
8442203945Sweongyostatic void
8443203945Sweongyobwn_intrtask(void *arg, int npending)
8444203945Sweongyo{
8445203945Sweongyo	struct bwn_mac *mac = arg;
8446203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8447203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8448203945Sweongyo	uint32_t merged = 0;
8449203945Sweongyo	int i, tx = 0, rx = 0;
8450203945Sweongyo
8451203945Sweongyo	BWN_LOCK(sc);
8452204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
8453204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID)) {
8454203945Sweongyo		BWN_UNLOCK(sc);
8455203945Sweongyo		return;
8456203945Sweongyo	}
8457203945Sweongyo
8458203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
8459203945Sweongyo		merged |= mac->mac_reason[i];
8460203945Sweongyo
8461203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
8462203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
8463203945Sweongyo
8464203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
8465203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
8466203945Sweongyo		mac->mac_phy.txerrors--;
8467203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
8468203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
8469203945Sweongyo			bwn_restart(mac, "PHY TX errors");
8470203945Sweongyo		}
8471203945Sweongyo	}
8472203945Sweongyo
8473203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
8474203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
8475203945Sweongyo			device_printf(sc->sc_dev,
8476203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
8477203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8478203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8479203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8480203945Sweongyo			bwn_restart(mac, "DMA error");
8481203945Sweongyo			BWN_UNLOCK(sc);
8482203945Sweongyo			return;
8483203945Sweongyo		}
8484203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
8485203945Sweongyo			device_printf(sc->sc_dev,
8486203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
8487203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8488203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8489203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8490203945Sweongyo		}
8491203945Sweongyo	}
8492203945Sweongyo
8493203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
8494203945Sweongyo		bwn_intr_ucode_debug(mac);
8495203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
8496203945Sweongyo		bwn_intr_tbtt_indication(mac);
8497203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
8498203945Sweongyo		bwn_intr_atim_end(mac);
8499203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
8500203945Sweongyo		bwn_intr_beacon(mac);
8501203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
8502203945Sweongyo		bwn_intr_pmq(mac);
8503203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
8504203945Sweongyo		bwn_intr_noise(mac);
8505203945Sweongyo
8506203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
8507203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
8508203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
8509203945Sweongyo			rx = 1;
8510203945Sweongyo		}
8511203945Sweongyo	} else
8512203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
8513203945Sweongyo
8514203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8515203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8516203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8517203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8518203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8519203945Sweongyo
8520203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
8521203945Sweongyo		bwn_intr_txeof(mac);
8522203945Sweongyo		tx = 1;
8523203945Sweongyo	}
8524203945Sweongyo
8525203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
8526203945Sweongyo
8527203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
8528203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
8529203945Sweongyo
8530203945Sweongyo		if (tx && rx) {
8531203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
8532203945Sweongyo				evt = BWN_LED_EVENT_RX;
8533203945Sweongyo			else
8534203945Sweongyo				evt = BWN_LED_EVENT_TX;
8535203945Sweongyo		} else if (tx) {
8536203945Sweongyo			evt = BWN_LED_EVENT_TX;
8537203945Sweongyo		} else if (rx) {
8538203945Sweongyo			evt = BWN_LED_EVENT_RX;
8539203945Sweongyo		} else if (rx == 0) {
8540203945Sweongyo			evt = BWN_LED_EVENT_POLL;
8541203945Sweongyo		}
8542203945Sweongyo
8543203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
8544203945Sweongyo			bwn_led_event(mac, evt);
8545203945Sweongyo       }
8546203945Sweongyo
8547203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
8548203945Sweongyo		if (!IFQ_IS_EMPTY(&ifp->if_snd))
8549203945Sweongyo			bwn_start_locked(ifp);
8550203945Sweongyo	}
8551203945Sweongyo
8552203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8553203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8554203945Sweongyo
8555203945Sweongyo	BWN_UNLOCK(sc);
8556203945Sweongyo}
8557203945Sweongyo
8558203945Sweongyostatic void
8559203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
8560203945Sweongyo{
8561203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8562203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8563203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
8564203945Sweongyo
8565203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
8566203945Sweongyo		return;
8567203945Sweongyo
8568203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
8569203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
8570203945Sweongyo}
8571203945Sweongyo
8572203945Sweongyostatic void
8573203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
8574203945Sweongyo{
8575203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8576203945Sweongyo	uint16_t reason;
8577203945Sweongyo
8578203945Sweongyo	if (mac->mac_fw.opensource == 0)
8579203945Sweongyo		return;
8580203945Sweongyo
8581203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
8582203945Sweongyo	switch (reason) {
8583203945Sweongyo	case BWN_DEBUGINTR_PANIC:
8584203945Sweongyo		bwn_handle_fwpanic(mac);
8585203945Sweongyo		break;
8586203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
8587203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
8588203945Sweongyo		break;
8589203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
8590203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
8591203945Sweongyo		break;
8592203945Sweongyo	case BWN_DEBUGINTR_MARKER:
8593203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
8594203945Sweongyo		break;
8595203945Sweongyo	default:
8596203945Sweongyo		device_printf(sc->sc_dev,
8597203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
8598203945Sweongyo	}
8599203945Sweongyo
8600203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
8601203945Sweongyo	    BWN_DEBUGINTR_ACK);
8602203945Sweongyo}
8603203945Sweongyo
8604203945Sweongyostatic void
8605203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
8606203945Sweongyo{
8607203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8608203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8609203945Sweongyo
8610203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
8611203945Sweongyo		bwn_psctl(mac, 0);
8612203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8613203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
8614203945Sweongyo}
8615203945Sweongyo
8616203945Sweongyostatic void
8617203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
8618203945Sweongyo{
8619203945Sweongyo
8620203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
8621203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
8622203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
8623203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
8624203945Sweongyo	}
8625203945Sweongyo}
8626203945Sweongyo
8627203945Sweongyostatic void
8628203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
8629203945Sweongyo{
8630203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8631203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8632203945Sweongyo	uint32_t cmd, beacon0, beacon1;
8633203945Sweongyo
8634203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
8635203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
8636203945Sweongyo		return;
8637203945Sweongyo
8638203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
8639203945Sweongyo
8640203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
8641203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
8642203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
8643203945Sweongyo
8644203945Sweongyo	if (beacon0 && beacon1) {
8645203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
8646203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
8647203945Sweongyo		return;
8648203945Sweongyo	}
8649203945Sweongyo
8650203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
8651203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
8652203945Sweongyo		bwn_load_beacon0(mac);
8653203945Sweongyo		bwn_load_beacon1(mac);
8654203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
8655203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
8656203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8657203945Sweongyo	} else {
8658203945Sweongyo		if (!beacon0) {
8659203945Sweongyo			bwn_load_beacon0(mac);
8660203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8661203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
8662203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8663203945Sweongyo		} else if (!beacon1) {
8664203945Sweongyo			bwn_load_beacon1(mac);
8665203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8666203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
8667203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8668203945Sweongyo		}
8669203945Sweongyo	}
8670203945Sweongyo}
8671203945Sweongyo
8672203945Sweongyostatic void
8673203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
8674203945Sweongyo{
8675203945Sweongyo	uint32_t tmp;
8676203945Sweongyo
8677203945Sweongyo	while (1) {
8678203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
8679203945Sweongyo		if (!(tmp & 0x00000008))
8680203945Sweongyo			break;
8681203945Sweongyo	}
8682203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
8683203945Sweongyo}
8684203945Sweongyo
8685203945Sweongyostatic void
8686203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
8687203945Sweongyo{
8688203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
8689203945Sweongyo	uint16_t tmp;
8690203945Sweongyo	uint8_t noise[4];
8691203945Sweongyo	uint8_t i, j;
8692203945Sweongyo	int32_t average;
8693203945Sweongyo
8694203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
8695203945Sweongyo		return;
8696203945Sweongyo
8697203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
8698203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
8699203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
8700203945Sweongyo	    noise[3] == 0x7f)
8701203945Sweongyo		goto new;
8702203945Sweongyo
8703203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
8704203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8705203945Sweongyo	i = mac->mac_noise.noi_nsamples;
8706203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
8707203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
8708203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
8709203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
8710203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
8711203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
8712203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
8713203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
8714203945Sweongyo	mac->mac_noise.noi_nsamples++;
8715203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
8716203945Sweongyo		average = 0;
8717203945Sweongyo		for (i = 0; i < 8; i++) {
8718203945Sweongyo			for (j = 0; j < 4; j++)
8719203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
8720203945Sweongyo		}
8721203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
8722203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
8723203945Sweongyo		if (tmp >= 8)
8724203945Sweongyo			average += 2;
8725203945Sweongyo		else
8726203945Sweongyo			average -= 25;
8727203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
8728203945Sweongyo
8729203945Sweongyo		mac->mac_stats.link_noise = average;
8730203945Sweongyo		mac->mac_noise.noi_running = 0;
8731203945Sweongyo		return;
8732203945Sweongyo	}
8733203945Sweongyonew:
8734203945Sweongyo	bwn_noise_gensample(mac);
8735203945Sweongyo}
8736203945Sweongyo
8737203945Sweongyostatic int
8738203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
8739203945Sweongyo{
8740203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
8741203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8742203945Sweongyo	unsigned int i;
8743203945Sweongyo
8744203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8745203945Sweongyo
8746203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8747203945Sweongyo		return (0);
8748203945Sweongyo
8749203945Sweongyo	for (i = 0; i < 5000; i++) {
8750203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
8751203945Sweongyo			break;
8752203945Sweongyo	}
8753203945Sweongyo	if (i >= 5000)
8754203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
8755203945Sweongyo	return ((i > 0) ? 1 : 0);
8756203945Sweongyo}
8757203945Sweongyo
8758203945Sweongyostatic void
8759203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
8760203945Sweongyo{
8761203945Sweongyo	int slot, curslot;
8762203945Sweongyo
8763203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
8764203945Sweongyo	curslot = dr->get_curslot(dr);
8765203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
8766203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8767203945Sweongyo
8768203945Sweongyo	slot = dr->dr_curslot;
8769203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
8770203945Sweongyo		bwn_dma_rxeof(dr, &slot);
8771203945Sweongyo
8772203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
8773203945Sweongyo	    BUS_DMASYNC_PREWRITE);
8774203945Sweongyo
8775203945Sweongyo	dr->set_curslot(dr, slot);
8776203945Sweongyo	dr->dr_curslot = slot;
8777203945Sweongyo}
8778203945Sweongyo
8779203945Sweongyostatic void
8780203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
8781203945Sweongyo{
8782203945Sweongyo	struct bwn_txstatus stat;
8783203945Sweongyo	uint32_t stat0, stat1;
8784203945Sweongyo	uint16_t tmp;
8785203945Sweongyo
8786203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8787203945Sweongyo
8788203945Sweongyo	while (1) {
8789203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
8790203945Sweongyo		if (!(stat0 & 0x00000001))
8791203945Sweongyo			break;
8792203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
8793203945Sweongyo
8794203945Sweongyo		stat.cookie = (stat0 >> 16);
8795203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
8796203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
8797203945Sweongyo		tmp = (stat0 & 0x0000ffff);
8798203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
8799203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
8800203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
8801203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
8802203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
8803203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
8804203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
8805203945Sweongyo
8806203945Sweongyo		bwn_handle_txeof(mac, &stat);
8807203945Sweongyo	}
8808203945Sweongyo}
8809203945Sweongyo
8810203945Sweongyostatic void
8811203945Sweongyobwn_hwreset(void *arg, int npending)
8812203945Sweongyo{
8813203945Sweongyo	struct bwn_mac *mac = arg;
8814203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8815203945Sweongyo	int error = 0;
8816203945Sweongyo	int prev_status;
8817203945Sweongyo
8818203945Sweongyo	BWN_LOCK(sc);
8819203945Sweongyo
8820203945Sweongyo	prev_status = mac->mac_status;
8821203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8822203945Sweongyo		bwn_core_stop(mac);
8823203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
8824203945Sweongyo		bwn_core_exit(mac);
8825203945Sweongyo
8826203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
8827203945Sweongyo		error = bwn_core_init(mac);
8828203945Sweongyo		if (error)
8829203945Sweongyo			goto out;
8830203945Sweongyo	}
8831203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8832203945Sweongyo		bwn_core_start(mac);
8833203945Sweongyoout:
8834203945Sweongyo	if (error) {
8835203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
8836203945Sweongyo		sc->sc_curmac = NULL;
8837203945Sweongyo	}
8838203945Sweongyo	BWN_UNLOCK(sc);
8839203945Sweongyo}
8840203945Sweongyo
8841203945Sweongyostatic void
8842203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
8843203945Sweongyo{
8844203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8845203945Sweongyo	uint16_t reason;
8846203945Sweongyo
8847203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
8848203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
8849203945Sweongyo
8850203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
8851203945Sweongyo		bwn_restart(mac, "ucode panic");
8852203945Sweongyo}
8853203945Sweongyo
8854203945Sweongyostatic void
8855203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
8856203945Sweongyo{
8857203945Sweongyo
8858203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8859203945Sweongyo}
8860203945Sweongyo
8861203945Sweongyostatic void
8862203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
8863203945Sweongyo{
8864203945Sweongyo
8865203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8866203945Sweongyo}
8867203945Sweongyo
8868203945Sweongyostatic uint32_t
8869203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
8870203945Sweongyo{
8871203945Sweongyo	uint32_t val = 0;
8872203945Sweongyo
8873203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
8874203945Sweongyo	val <<= 16;
8875203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
8876203945Sweongyo
8877203945Sweongyo	return (val);
8878203945Sweongyo}
8879203945Sweongyo
8880203945Sweongyostatic void
8881203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
8882203945Sweongyo{
8883203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
8884203945Sweongyo
8885203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
8886203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
8887203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
8888203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
8889203945Sweongyo}
8890203945Sweongyo
8891203945Sweongyostatic int
8892203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
8893203945Sweongyo{
8894204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8895203945Sweongyo
8896203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
8897203945Sweongyo}
8898203945Sweongyo
8899203945Sweongyostatic int
8900203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
8901203945Sweongyo{
8902204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8903203945Sweongyo
8904203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
8905203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8906203945Sweongyo	if (slot == dr->dr_numslots - 1)
8907203945Sweongyo		return (0);
8908203945Sweongyo	return (slot + 1);
8909203945Sweongyo}
8910203945Sweongyo
8911203945Sweongyostatic void
8912203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
8913203945Sweongyo{
8914203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
8915203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8916203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
8917203945Sweongyo	struct bwn_dmadesc_generic *desc;
8918203945Sweongyo	struct bwn_dmadesc_meta *meta;
8919203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
8920203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8921203945Sweongyo	struct mbuf *m;
8922203945Sweongyo	uint32_t macstat;
8923203945Sweongyo	int32_t tmp;
8924203945Sweongyo	int cnt = 0;
8925203945Sweongyo	uint16_t len;
8926203945Sweongyo
8927203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
8928203945Sweongyo
8929203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
8930203945Sweongyo	m = meta->mt_m;
8931203945Sweongyo
8932203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
8933271849Sglebius		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
8934203945Sweongyo		return;
8935203945Sweongyo	}
8936203945Sweongyo
8937203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
8938203945Sweongyo	len = le16toh(rxhdr->frame_len);
8939203945Sweongyo	if (len <= 0) {
8940271849Sglebius		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
8941203945Sweongyo		return;
8942203945Sweongyo	}
8943203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
8944203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
8945203945Sweongyo		bwn_dma_set_redzone(dr, m);
8946203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
8947203945Sweongyo		    BUS_DMASYNC_PREWRITE);
8948203945Sweongyo		return;
8949203945Sweongyo	}
8950203945Sweongyo	if (len > dr->dr_rx_bufsize) {
8951203945Sweongyo		tmp = len;
8952203945Sweongyo		while (1) {
8953203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
8954203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
8955203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
8956203945Sweongyo			    BUS_DMASYNC_PREWRITE);
8957203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
8958203945Sweongyo			cnt++;
8959203945Sweongyo			tmp -= dr->dr_rx_bufsize;
8960203945Sweongyo			if (tmp <= 0)
8961203945Sweongyo				break;
8962203945Sweongyo		}
8963203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
8964203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
8965203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
8966203945Sweongyo		return;
8967203945Sweongyo	}
8968203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
8969203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
8970203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
8971203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
8972203945Sweongyo			return;
8973203945Sweongyo		}
8974203945Sweongyo	}
8975203945Sweongyo
8976203945Sweongyo	m->m_pkthdr.rcvif = ifp;
8977203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
8978203945Sweongyo	m_adj(m, dr->dr_frameoffset);
8979203945Sweongyo
8980203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
8981203945Sweongyo}
8982203945Sweongyo
8983203945Sweongyostatic void
8984203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
8985203945Sweongyo{
8986203945Sweongyo	struct bwn_dma_ring *dr;
8987203945Sweongyo	struct bwn_dmadesc_generic *desc;
8988203945Sweongyo	struct bwn_dmadesc_meta *meta;
8989203945Sweongyo	struct bwn_pio_txqueue *tq;
8990203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
8991203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8992204257Sweongyo	struct bwn_stats *stats = &mac->mac_stats;
8993203945Sweongyo	struct ieee80211_node *ni;
8994206358Srpaulo	struct ieee80211vap *vap;
8995208120Sweongyo	int retrycnt = 0, slot;
8996203945Sweongyo
8997203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8998203945Sweongyo
8999203945Sweongyo	if (status->im)
9000203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
9001203945Sweongyo	if (status->ampdu)
9002203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
9003203945Sweongyo	if (status->rtscnt) {
9004203945Sweongyo		if (status->rtscnt == 0xf)
9005204257Sweongyo			stats->rtsfail++;
9006203945Sweongyo		else
9007204257Sweongyo			stats->rts++;
9008203945Sweongyo	}
9009203945Sweongyo
9010203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
9011203945Sweongyo		if (status->ack) {
9012203945Sweongyo			dr = bwn_dma_parse_cookie(mac, status,
9013203945Sweongyo			    status->cookie, &slot);
9014203945Sweongyo			if (dr == NULL) {
9015203945Sweongyo				device_printf(sc->sc_dev,
9016203945Sweongyo				    "failed to parse cookie\n");
9017203945Sweongyo				return;
9018203945Sweongyo			}
9019203945Sweongyo			while (1) {
9020203945Sweongyo				dr->getdesc(dr, slot, &desc, &meta);
9021203945Sweongyo				if (meta->mt_islast) {
9022203945Sweongyo					ni = meta->mt_ni;
9023206358Srpaulo					vap = ni->ni_vap;
9024206358Srpaulo					ieee80211_ratectl_tx_complete(vap, ni,
9025206358Srpaulo					    status->ack ?
9026206358Srpaulo					      IEEE80211_RATECTL_TX_SUCCESS :
9027206358Srpaulo					      IEEE80211_RATECTL_TX_FAILURE,
9028208120Sweongyo					    &retrycnt, 0);
9029203945Sweongyo					break;
9030203945Sweongyo				}
9031203945Sweongyo				slot = bwn_dma_nextslot(dr, slot);
9032203945Sweongyo			}
9033203945Sweongyo		}
9034203945Sweongyo		bwn_dma_handle_txeof(mac, status);
9035203945Sweongyo	} else {
9036203945Sweongyo		if (status->ack) {
9037203945Sweongyo			tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9038203945Sweongyo			if (tq == NULL) {
9039203945Sweongyo				device_printf(sc->sc_dev,
9040203945Sweongyo				    "failed to parse cookie\n");
9041203945Sweongyo				return;
9042203945Sweongyo			}
9043203945Sweongyo			ni = tp->tp_ni;
9044206358Srpaulo			vap = ni->ni_vap;
9045206358Srpaulo			ieee80211_ratectl_tx_complete(vap, ni,
9046206358Srpaulo			    status->ack ?
9047206358Srpaulo			      IEEE80211_RATECTL_TX_SUCCESS :
9048206358Srpaulo			      IEEE80211_RATECTL_TX_FAILURE,
9049208120Sweongyo			    &retrycnt, 0);
9050203945Sweongyo		}
9051203945Sweongyo		bwn_pio_handle_txeof(mac, status);
9052203945Sweongyo	}
9053203945Sweongyo
9054203945Sweongyo	bwn_phy_txpower_check(mac, 0);
9055203945Sweongyo}
9056203945Sweongyo
9057203945Sweongyostatic uint8_t
9058203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
9059203945Sweongyo{
9060203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
9061203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9062203945Sweongyo	struct bwn_rxhdr4 rxhdr;
9063203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9064203945Sweongyo	struct mbuf *m;
9065203945Sweongyo	uint32_t ctl32, macstat, v32;
9066203945Sweongyo	unsigned int i, padding;
9067209888Sweongyo	uint16_t ctl16, len, totlen, v16;
9068203945Sweongyo	unsigned char *mp;
9069203945Sweongyo	char *data;
9070203945Sweongyo
9071203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
9072203945Sweongyo
9073203945Sweongyo	if (prq->prq_rev >= 8) {
9074203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9075203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
9076203945Sweongyo			return (0);
9077203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9078203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
9079203945Sweongyo		for (i = 0; i < 10; i++) {
9080203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9081203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
9082203945Sweongyo				goto ready;
9083203945Sweongyo			DELAY(10);
9084203945Sweongyo		}
9085203945Sweongyo	} else {
9086203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9087203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
9088203945Sweongyo			return (0);
9089203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
9090203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
9091203945Sweongyo		for (i = 0; i < 10; i++) {
9092203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9093203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
9094203945Sweongyo				goto ready;
9095203945Sweongyo			DELAY(10);
9096203945Sweongyo		}
9097203945Sweongyo	}
9098203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
9099203945Sweongyo	return (1);
9100203945Sweongyoready:
9101203945Sweongyo	if (prq->prq_rev >= 8)
9102204922Sweongyo		siba_read_multi_4(sc->sc_dev, &rxhdr, sizeof(rxhdr),
9103203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9104203945Sweongyo	else
9105204922Sweongyo		siba_read_multi_2(sc->sc_dev, &rxhdr, sizeof(rxhdr),
9106203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9107203945Sweongyo	len = le16toh(rxhdr.frame_len);
9108203945Sweongyo	if (len > 0x700) {
9109203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
9110203945Sweongyo		goto error;
9111203945Sweongyo	}
9112203945Sweongyo	if (len == 0) {
9113203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
9114203945Sweongyo		goto error;
9115203945Sweongyo	}
9116203945Sweongyo
9117203945Sweongyo	macstat = le32toh(rxhdr.mac_status);
9118203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9119203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9120203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
9121203945Sweongyo			goto error;
9122203945Sweongyo		}
9123203945Sweongyo	}
9124203945Sweongyo
9125203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9126209888Sweongyo	totlen = len + padding;
9127209888Sweongyo	KASSERT(totlen <= MCLBYTES, ("too big..\n"));
9128243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
9129203945Sweongyo	if (m == NULL) {
9130203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
9131203945Sweongyo		goto error;
9132203945Sweongyo	}
9133203945Sweongyo	mp = mtod(m, unsigned char *);
9134203945Sweongyo	if (prq->prq_rev >= 8) {
9135209888Sweongyo		siba_read_multi_4(sc->sc_dev, mp, (totlen & ~3),
9136203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9137209888Sweongyo		if (totlen & 3) {
9138203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
9139209888Sweongyo			data = &(mp[totlen - 1]);
9140209888Sweongyo			switch (totlen & 3) {
9141203945Sweongyo			case 3:
9142203945Sweongyo				*data = (v32 >> 16);
9143203945Sweongyo				data--;
9144203945Sweongyo			case 2:
9145203945Sweongyo				*data = (v32 >> 8);
9146203945Sweongyo				data--;
9147203945Sweongyo			case 1:
9148203945Sweongyo				*data = v32;
9149203945Sweongyo			}
9150203945Sweongyo		}
9151203945Sweongyo	} else {
9152209888Sweongyo		siba_read_multi_2(sc->sc_dev, mp, (totlen & ~1),
9153203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9154209888Sweongyo		if (totlen & 1) {
9155203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
9156209888Sweongyo			mp[totlen - 1] = v16;
9157203945Sweongyo		}
9158203945Sweongyo	}
9159203945Sweongyo
9160203945Sweongyo	m->m_pkthdr.rcvif = ifp;
9161209888Sweongyo	m->m_len = m->m_pkthdr.len = totlen;
9162203945Sweongyo
9163203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
9164203945Sweongyo
9165203945Sweongyo	return (1);
9166203945Sweongyoerror:
9167203945Sweongyo	if (prq->prq_rev >= 8)
9168203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9169203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
9170203945Sweongyo	else
9171203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
9172203945Sweongyo	return (1);
9173203945Sweongyo}
9174203945Sweongyo
9175203945Sweongyostatic int
9176203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
9177203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
9178203945Sweongyo{
9179203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
9180203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9181203945Sweongyo	struct bwn_rxhdr4 *hdr;
9182203945Sweongyo	bus_dmamap_t map;
9183203945Sweongyo	bus_addr_t paddr;
9184203945Sweongyo	struct mbuf *m;
9185203945Sweongyo	int error;
9186203945Sweongyo
9187243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
9188203945Sweongyo	if (m == NULL) {
9189203945Sweongyo		error = ENOBUFS;
9190203945Sweongyo
9191203945Sweongyo		/*
9192203945Sweongyo		 * If the NIC is up and running, we need to:
9193203945Sweongyo		 * - Clear RX buffer's header.
9194203945Sweongyo		 * - Restore RX descriptor settings.
9195203945Sweongyo		 */
9196203945Sweongyo		if (init)
9197203945Sweongyo			return (error);
9198203945Sweongyo		else
9199203945Sweongyo			goto back;
9200203945Sweongyo	}
9201203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
9202203945Sweongyo
9203203945Sweongyo	bwn_dma_set_redzone(dr, m);
9204203945Sweongyo
9205203945Sweongyo	/*
9206203945Sweongyo	 * Try to load RX buf into temporary DMA map
9207203945Sweongyo	 */
9208203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
9209203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
9210203945Sweongyo	if (error) {
9211203945Sweongyo		m_freem(m);
9212203945Sweongyo
9213203945Sweongyo		/*
9214203945Sweongyo		 * See the comment above
9215203945Sweongyo		 */
9216203945Sweongyo		if (init)
9217203945Sweongyo			return (error);
9218203945Sweongyo		else
9219203945Sweongyo			goto back;
9220203945Sweongyo	}
9221203945Sweongyo
9222203945Sweongyo	if (!init)
9223203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
9224203945Sweongyo	meta->mt_m = m;
9225203945Sweongyo	meta->mt_paddr = paddr;
9226203945Sweongyo
9227203945Sweongyo	/*
9228203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
9229203945Sweongyo	 */
9230203945Sweongyo	map = meta->mt_dmap;
9231203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
9232203945Sweongyo	dr->dr_spare_dmap = map;
9233203945Sweongyo
9234203945Sweongyoback:
9235203945Sweongyo	/*
9236203945Sweongyo	 * Clear RX buf header
9237203945Sweongyo	 */
9238203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
9239203945Sweongyo	bzero(hdr, sizeof(*hdr));
9240203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9241203945Sweongyo	    BUS_DMASYNC_PREWRITE);
9242203945Sweongyo
9243203945Sweongyo	/*
9244203945Sweongyo	 * Setup RX buf descriptor
9245203945Sweongyo	 */
9246250314Shiren	dr->setdesc(dr, desc, meta->mt_paddr, meta->mt_m->m_len -
9247203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
9248203945Sweongyo	return (error);
9249203945Sweongyo}
9250203945Sweongyo
9251203945Sweongyostatic void
9252203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
9253203945Sweongyo		 bus_size_t mapsz __unused, int error)
9254203945Sweongyo{
9255203945Sweongyo
9256203945Sweongyo	if (!error) {
9257203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
9258203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
9259203945Sweongyo	}
9260203945Sweongyo}
9261203945Sweongyo
9262203945Sweongyostatic int
9263203945Sweongyobwn_hwrate2ieeerate(int rate)
9264203945Sweongyo{
9265203945Sweongyo
9266203945Sweongyo	switch (rate) {
9267203945Sweongyo	case BWN_CCK_RATE_1MB:
9268203945Sweongyo		return (2);
9269203945Sweongyo	case BWN_CCK_RATE_2MB:
9270203945Sweongyo		return (4);
9271203945Sweongyo	case BWN_CCK_RATE_5MB:
9272203945Sweongyo		return (11);
9273203945Sweongyo	case BWN_CCK_RATE_11MB:
9274203945Sweongyo		return (22);
9275203945Sweongyo	case BWN_OFDM_RATE_6MB:
9276203945Sweongyo		return (12);
9277203945Sweongyo	case BWN_OFDM_RATE_9MB:
9278203945Sweongyo		return (18);
9279203945Sweongyo	case BWN_OFDM_RATE_12MB:
9280203945Sweongyo		return (24);
9281203945Sweongyo	case BWN_OFDM_RATE_18MB:
9282203945Sweongyo		return (36);
9283203945Sweongyo	case BWN_OFDM_RATE_24MB:
9284203945Sweongyo		return (48);
9285203945Sweongyo	case BWN_OFDM_RATE_36MB:
9286203945Sweongyo		return (72);
9287203945Sweongyo	case BWN_OFDM_RATE_48MB:
9288203945Sweongyo		return (96);
9289203945Sweongyo	case BWN_OFDM_RATE_54MB:
9290203945Sweongyo		return (108);
9291203945Sweongyo	default:
9292203945Sweongyo		printf("Ooops\n");
9293203945Sweongyo		return (0);
9294203945Sweongyo	}
9295203945Sweongyo}
9296203945Sweongyo
9297203945Sweongyostatic void
9298203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
9299203945Sweongyo{
9300203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
9301203945Sweongyo	struct bwn_plcp6 *plcp;
9302203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9303203945Sweongyo	struct ieee80211_frame_min *wh;
9304203945Sweongyo	struct ieee80211_node *ni;
9305203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9306203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9307203945Sweongyo	uint32_t macstat;
9308204242Simp	int padding, rate, rssi = 0, noise = 0, type;
9309203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
9310203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
9311204242Simp	static int rx_mac_dec_rpt = 0;
9312203945Sweongyo
9313203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9314203945Sweongyo
9315203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
9316203945Sweongyo	phystat3 = le16toh(rxhdr->phy_status3);
9317203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9318203945Sweongyo	chanstat = le16toh(rxhdr->channel);
9319203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
9320203945Sweongyo
9321203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
9322203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
9323203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
9324203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
9325203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
9326203945Sweongyo		goto drop;
9327203945Sweongyo
9328203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9329203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
9330204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9331204081Sweongyo		    m->m_pkthdr.len);
9332203945Sweongyo		goto drop;
9333203945Sweongyo	}
9334203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
9335203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
9336203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
9337204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9338204081Sweongyo		    m->m_pkthdr.len);
9339203945Sweongyo		goto drop;
9340203945Sweongyo	}
9341203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
9342203945Sweongyo
9343204242Simp	if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
9344204081Sweongyo		device_printf(sc->sc_dev,
9345204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
9346204081Sweongyo		    BWN_ISOLDFMT(mac),
9347204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
9348203945Sweongyo
9349203945Sweongyo	/* XXX calculating RSSI & noise & antenna */
9350203945Sweongyo
9351203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
9352203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
9353203945Sweongyo		    phytype == BWN_PHYTYPE_A);
9354203945Sweongyo	else
9355203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
9356203945Sweongyo	if (rate == -1) {
9357203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
9358203945Sweongyo			goto drop;
9359203945Sweongyo	}
9360203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
9361203945Sweongyo
9362203945Sweongyo	/* RX radio tap */
9363203945Sweongyo	if (ieee80211_radiotap_active(ic))
9364203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
9365203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
9366203945Sweongyo
9367203945Sweongyo	rssi = rxhdr->phy.abg.rssi;	/* XXX incorrect RSSI calculation? */
9368203945Sweongyo	noise = mac->mac_stats.link_noise;
9369203945Sweongyo
9370271849Sglebius	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
9371207176Sweongyo
9372203945Sweongyo	BWN_UNLOCK(sc);
9373203945Sweongyo
9374203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
9375203945Sweongyo	if (ni != NULL) {
9376203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
9377203945Sweongyo		ieee80211_free_node(ni);
9378203945Sweongyo	} else
9379203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
9380203945Sweongyo
9381203945Sweongyo	BWN_LOCK(sc);
9382203945Sweongyo	return;
9383203945Sweongyodrop:
9384203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
9385203945Sweongyo}
9386203945Sweongyo
9387203945Sweongyostatic void
9388203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
9389203945Sweongyo    const struct bwn_txstatus *status)
9390203945Sweongyo{
9391203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9392203945Sweongyo	struct bwn_dma_ring *dr;
9393203945Sweongyo	struct bwn_dmadesc_generic *desc;
9394203945Sweongyo	struct bwn_dmadesc_meta *meta;
9395203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9396203945Sweongyo	struct ieee80211_node *ni;
9397203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9398203945Sweongyo	struct mbuf *m;
9399203945Sweongyo	int slot;
9400203945Sweongyo
9401203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9402203945Sweongyo
9403203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
9404203945Sweongyo	if (dr == NULL) {
9405203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
9406203945Sweongyo		return;
9407203945Sweongyo	}
9408203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
9409203945Sweongyo
9410203945Sweongyo	while (1) {
9411203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
9412203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9413203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
9414203945Sweongyo
9415203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
9416203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
9417203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
9418203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
9419203945Sweongyo
9420203945Sweongyo		if (meta->mt_islast) {
9421203945Sweongyo			KASSERT(meta->mt_m != NULL,
9422203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9423203945Sweongyo
9424203945Sweongyo			ni = meta->mt_ni;
9425203945Sweongyo			m = meta->mt_m;
9426203945Sweongyo			if (ni != NULL) {
9427203945Sweongyo				/*
9428203945Sweongyo				 * Do any tx complete callback. Note this must
9429203945Sweongyo				 * be done before releasing the node reference.
9430203945Sweongyo				 */
9431203945Sweongyo				if (m->m_flags & M_TXCB)
9432203945Sweongyo					ieee80211_process_callback(ni, m, 0);
9433203945Sweongyo				ieee80211_free_node(ni);
9434203945Sweongyo				meta->mt_ni = NULL;
9435203945Sweongyo			}
9436203945Sweongyo			m_freem(m);
9437203945Sweongyo			meta->mt_m = NULL;
9438203945Sweongyo		} else {
9439203945Sweongyo			KASSERT(meta->mt_m == NULL,
9440203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9441203945Sweongyo		}
9442203945Sweongyo
9443203945Sweongyo		dr->dr_usedslot--;
9444203945Sweongyo		if (meta->mt_islast) {
9445271849Sglebius			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
9446203945Sweongyo			break;
9447203945Sweongyo		}
9448203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
9449203945Sweongyo	}
9450203945Sweongyo	sc->sc_watchdog_timer = 0;
9451203945Sweongyo	if (dr->dr_stop) {
9452203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
9453203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9454203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9455203945Sweongyo		dr->dr_stop = 0;
9456203945Sweongyo	}
9457203945Sweongyo}
9458203945Sweongyo
9459203945Sweongyostatic void
9460203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
9461203945Sweongyo    const struct bwn_txstatus *status)
9462203945Sweongyo{
9463203945Sweongyo	struct bwn_pio_txqueue *tq;
9464203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9465203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9466203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9467203945Sweongyo
9468203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9469203945Sweongyo
9470203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9471203945Sweongyo	if (tq == NULL)
9472203945Sweongyo		return;
9473203945Sweongyo
9474203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
9475203945Sweongyo	tq->tq_free++;
9476203945Sweongyo
9477203945Sweongyo	if (tp->tp_ni != NULL) {
9478203945Sweongyo		/*
9479203945Sweongyo		 * Do any tx complete callback.  Note this must
9480203945Sweongyo		 * be done before releasing the node reference.
9481203945Sweongyo		 */
9482203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
9483203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
9484203945Sweongyo		ieee80211_free_node(tp->tp_ni);
9485203945Sweongyo		tp->tp_ni = NULL;
9486203945Sweongyo	}
9487203945Sweongyo	m_freem(tp->tp_m);
9488203945Sweongyo	tp->tp_m = NULL;
9489203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
9490203945Sweongyo
9491271849Sglebius	if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
9492203945Sweongyo
9493203945Sweongyo	sc->sc_watchdog_timer = 0;
9494203945Sweongyo	if (tq->tq_stop) {
9495203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9496203945Sweongyo		tq->tq_stop = 0;
9497203945Sweongyo	}
9498203945Sweongyo}
9499203945Sweongyo
9500203945Sweongyostatic void
9501203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
9502203945Sweongyo{
9503203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9504203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
9505203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9506203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9507203945Sweongyo	unsigned long now;
9508203945Sweongyo	int result;
9509203945Sweongyo
9510203945Sweongyo	BWN_GETTIME(now);
9511203945Sweongyo
9512203945Sweongyo	if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
9513203945Sweongyo		return;
9514203945Sweongyo	phy->nexttime = now + 2 * 1000;
9515203945Sweongyo
9516204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
9517204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306)
9518203945Sweongyo		return;
9519203945Sweongyo
9520203945Sweongyo	if (phy->recalc_txpwr != NULL) {
9521203945Sweongyo		result = phy->recalc_txpwr(mac,
9522203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
9523203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
9524203945Sweongyo			return;
9525203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
9526203945Sweongyo		    ("%s: fail", __func__));
9527203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
9528203945Sweongyo
9529203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
9530203945Sweongyo	}
9531203945Sweongyo}
9532203945Sweongyo
9533203945Sweongyostatic uint16_t
9534203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
9535203945Sweongyo{
9536203945Sweongyo
9537203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
9538203945Sweongyo}
9539203945Sweongyo
9540203945Sweongyostatic uint32_t
9541203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
9542203945Sweongyo{
9543203945Sweongyo
9544203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
9545203945Sweongyo}
9546203945Sweongyo
9547203945Sweongyostatic void
9548203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
9549203945Sweongyo{
9550203945Sweongyo
9551203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
9552203945Sweongyo}
9553203945Sweongyo
9554203945Sweongyostatic void
9555203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
9556203945Sweongyo{
9557203945Sweongyo
9558203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
9559203945Sweongyo}
9560203945Sweongyo
9561203945Sweongyostatic int
9562203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
9563203945Sweongyo{
9564203945Sweongyo
9565203945Sweongyo	switch (rate) {
9566203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
9567203945Sweongyo	case 12:
9568203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9569203945Sweongyo	case 18:
9570203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9571203945Sweongyo	case 24:
9572203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9573203945Sweongyo	case 36:
9574203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9575203945Sweongyo	case 48:
9576203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9577203945Sweongyo	case 72:
9578203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9579203945Sweongyo	case 96:
9580203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9581203945Sweongyo	case 108:
9582203945Sweongyo		return (BWN_OFDM_RATE_54MB);
9583203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
9584203945Sweongyo	case 2:
9585203945Sweongyo		return (BWN_CCK_RATE_1MB);
9586203945Sweongyo	case 4:
9587203945Sweongyo		return (BWN_CCK_RATE_2MB);
9588203945Sweongyo	case 11:
9589203945Sweongyo		return (BWN_CCK_RATE_5MB);
9590203945Sweongyo	case 22:
9591203945Sweongyo		return (BWN_CCK_RATE_11MB);
9592203945Sweongyo	}
9593203945Sweongyo
9594203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
9595203945Sweongyo	return (BWN_CCK_RATE_1MB);
9596203945Sweongyo}
9597203945Sweongyo
9598203945Sweongyostatic int
9599203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
9600203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
9601203945Sweongyo{
9602203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
9603203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9604203945Sweongyo	struct ieee80211_frame *wh;
9605203945Sweongyo	struct ieee80211_frame *protwh;
9606203945Sweongyo	struct ieee80211_frame_cts *cts;
9607203945Sweongyo	struct ieee80211_frame_rts *rts;
9608203945Sweongyo	const struct ieee80211_txparam *tp;
9609203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
9610203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9611203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9612203945Sweongyo	struct mbuf *mprot;
9613203945Sweongyo	unsigned int len;
9614203945Sweongyo	uint32_t macctl = 0;
9615203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
9616203945Sweongyo	uint16_t phyctl = 0;
9617203945Sweongyo	uint8_t rate, rate_fb;
9618203945Sweongyo
9619203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
9620203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
9621203945Sweongyo
9622203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
9623203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
9624203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
9625203945Sweongyo
9626203945Sweongyo	/*
9627203945Sweongyo	 * Find TX rate
9628203945Sweongyo	 */
9629203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
9630203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
9631203945Sweongyo		rate = rate_fb = tp->mgmtrate;
9632203945Sweongyo	else if (ismcast)
9633203945Sweongyo		rate = rate_fb = tp->mcastrate;
9634203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
9635203945Sweongyo		rate = rate_fb = tp->ucastrate;
9636203945Sweongyo	else {
9637206358Srpaulo		rix = ieee80211_ratectl_rate(ni, NULL, 0);
9638203945Sweongyo		rate = ni->ni_txrate;
9639203945Sweongyo
9640203945Sweongyo		if (rix > 0)
9641203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
9642203945Sweongyo			    IEEE80211_RATE_VAL;
9643203945Sweongyo		else
9644203945Sweongyo			rate_fb = rate;
9645203945Sweongyo	}
9646203945Sweongyo
9647203945Sweongyo	sc->sc_tx_rate = rate;
9648203945Sweongyo
9649203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
9650203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
9651203945Sweongyo
9652203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
9653203945Sweongyo	    bwn_plcp_getcck(rate);
9654203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
9655203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
9656203945Sweongyo
9657203945Sweongyo	if ((rate_fb == rate) ||
9658203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
9659203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
9660203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
9661203945Sweongyo	else
9662203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
9663203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
9664203945Sweongyo
9665203945Sweongyo	/* XXX TX encryption */
9666203945Sweongyo	bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
9667203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
9668203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
9669203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
9670203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
9671203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
9672203945Sweongyo
9673203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
9674203945Sweongyo	    BWN_TX_EFT_FB_CCK;
9675203945Sweongyo	txhdr->chan = phy->chan;
9676203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
9677203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
9678203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9679203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
9680203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
9681203945Sweongyo
9682203945Sweongyo	/* XXX TX antenna selection */
9683203945Sweongyo
9684203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
9685203945Sweongyo	case 0:
9686203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
9687203945Sweongyo		break;
9688203945Sweongyo	case 1:
9689203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
9690203945Sweongyo		break;
9691203945Sweongyo	case 2:
9692203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
9693203945Sweongyo		break;
9694203945Sweongyo	case 3:
9695203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
9696203945Sweongyo		break;
9697203945Sweongyo	case 4:
9698203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
9699203945Sweongyo		break;
9700203945Sweongyo	default:
9701203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9702203945Sweongyo	}
9703203945Sweongyo
9704203945Sweongyo	if (!ismcast)
9705203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
9706203945Sweongyo
9707203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
9708203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
9709203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
9710203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
9711203945Sweongyo
9712203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
9713203945Sweongyo		/* XXX RTS rate is always 1MB??? */
9714203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
9715203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
9716203945Sweongyo
9717203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
9718203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
9719203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
9720203945Sweongyo
9721203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
9722203945Sweongyo			cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
9723203945Sweongyo			    (txhdr->body.old.rts_frame) :
9724203945Sweongyo			    (txhdr->body.new.rts_frame));
9725203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
9726203945Sweongyo			    protdur);
9727203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9728203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
9729203945Sweongyo			    mprot->m_pkthdr.len);
9730203945Sweongyo			m_freem(mprot);
9731203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
9732203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
9733203945Sweongyo		} else {
9734203945Sweongyo			rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
9735203945Sweongyo			    (txhdr->body.old.rts_frame) :
9736203945Sweongyo			    (txhdr->body.new.rts_frame));
9737203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
9738203945Sweongyo			    isshort);
9739203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
9740203945Sweongyo			    wh->i_addr2, protdur);
9741203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9742203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
9743203945Sweongyo			    mprot->m_pkthdr.len);
9744203945Sweongyo			m_freem(mprot);
9745203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
9746203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
9747203945Sweongyo		}
9748203945Sweongyo		len += IEEE80211_CRC_LEN;
9749203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
9750203945Sweongyo		    &txhdr->body.old.rts_plcp :
9751203945Sweongyo		    &txhdr->body.new.rts_plcp), len, rts_rate);
9752203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
9753203945Sweongyo		    rts_rate_fb);
9754203945Sweongyo
9755203945Sweongyo		protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
9756203945Sweongyo		    (&txhdr->body.old.rts_frame) :
9757203945Sweongyo		    (&txhdr->body.new.rts_frame));
9758203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
9759203945Sweongyo
9760203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
9761203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
9762203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
9763203945Sweongyo		} else {
9764203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
9765203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
9766203945Sweongyo		}
9767203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
9768203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
9769203945Sweongyo	}
9770203945Sweongyo
9771203945Sweongyo	if (BWN_ISOLDFMT(mac))
9772203945Sweongyo		txhdr->body.old.cookie = htole16(cookie);
9773203945Sweongyo	else
9774203945Sweongyo		txhdr->body.new.cookie = htole16(cookie);
9775203945Sweongyo
9776203945Sweongyo	txhdr->macctl = htole32(macctl);
9777203945Sweongyo	txhdr->phyctl = htole16(phyctl);
9778203945Sweongyo
9779203945Sweongyo	/*
9780203945Sweongyo	 * TX radio tap
9781203945Sweongyo	 */
9782203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
9783203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
9784260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
9785203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
9786203945Sweongyo		if (isshort &&
9787203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9788203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
9789203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
9790203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
9791203945Sweongyo
9792203945Sweongyo		ieee80211_radiotap_tx(vap, m);
9793203945Sweongyo	}
9794203945Sweongyo
9795203945Sweongyo	return (0);
9796203945Sweongyo}
9797203945Sweongyo
9798203945Sweongyostatic void
9799203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
9800203945Sweongyo    const uint8_t rate)
9801203945Sweongyo{
9802203945Sweongyo	uint32_t d, plen;
9803203945Sweongyo	uint8_t *raw = plcp->o.raw;
9804203945Sweongyo
9805203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
9806203945Sweongyo		d = bwn_plcp_getofdm(rate);
9807203945Sweongyo		KASSERT(!(octets & 0xf000),
9808203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9809203945Sweongyo		d |= (octets << 5);
9810203945Sweongyo		plcp->o.data = htole32(d);
9811203945Sweongyo	} else {
9812203945Sweongyo		plen = octets * 16 / rate;
9813203945Sweongyo		if ((octets * 16 % rate) > 0) {
9814203945Sweongyo			plen++;
9815203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
9816203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
9817203945Sweongyo				raw[1] = 0x84;
9818203945Sweongyo			} else
9819203945Sweongyo				raw[1] = 0x04;
9820203945Sweongyo		} else
9821203945Sweongyo			raw[1] = 0x04;
9822203945Sweongyo		plcp->o.data |= htole32(plen << 16);
9823203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
9824203945Sweongyo	}
9825203945Sweongyo}
9826203945Sweongyo
9827203945Sweongyostatic uint8_t
9828203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
9829203945Sweongyo{
9830204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9831203945Sweongyo	uint8_t mask;
9832203945Sweongyo
9833203945Sweongyo	if (n == 0)
9834203945Sweongyo		return (0);
9835203945Sweongyo	if (mac->mac_phy.gmode)
9836204922Sweongyo		mask = siba_sprom_get_ant_bg(sc->sc_dev);
9837203945Sweongyo	else
9838204922Sweongyo		mask = siba_sprom_get_ant_a(sc->sc_dev);
9839203945Sweongyo	if (!(mask & (1 << (n - 1))))
9840203945Sweongyo		return (0);
9841203945Sweongyo	return (n);
9842203945Sweongyo}
9843203945Sweongyo
9844203945Sweongyostatic uint8_t
9845203945Sweongyobwn_get_fbrate(uint8_t bitrate)
9846203945Sweongyo{
9847203945Sweongyo	switch (bitrate) {
9848203945Sweongyo	case BWN_CCK_RATE_1MB:
9849203945Sweongyo		return (BWN_CCK_RATE_1MB);
9850203945Sweongyo	case BWN_CCK_RATE_2MB:
9851203945Sweongyo		return (BWN_CCK_RATE_1MB);
9852203945Sweongyo	case BWN_CCK_RATE_5MB:
9853203945Sweongyo		return (BWN_CCK_RATE_2MB);
9854203945Sweongyo	case BWN_CCK_RATE_11MB:
9855203945Sweongyo		return (BWN_CCK_RATE_5MB);
9856203945Sweongyo	case BWN_OFDM_RATE_6MB:
9857203945Sweongyo		return (BWN_CCK_RATE_5MB);
9858203945Sweongyo	case BWN_OFDM_RATE_9MB:
9859203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9860203945Sweongyo	case BWN_OFDM_RATE_12MB:
9861203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9862203945Sweongyo	case BWN_OFDM_RATE_18MB:
9863203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9864203945Sweongyo	case BWN_OFDM_RATE_24MB:
9865203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9866203945Sweongyo	case BWN_OFDM_RATE_36MB:
9867203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9868203945Sweongyo	case BWN_OFDM_RATE_48MB:
9869203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9870203945Sweongyo	case BWN_OFDM_RATE_54MB:
9871203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9872203945Sweongyo	}
9873203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9874203945Sweongyo	return (0);
9875203945Sweongyo}
9876203945Sweongyo
9877203945Sweongyostatic uint32_t
9878203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9879203945Sweongyo    uint32_t ctl, const void *_data, int len)
9880203945Sweongyo{
9881204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9882203945Sweongyo	uint32_t value = 0;
9883203945Sweongyo	const uint8_t *data = _data;
9884203945Sweongyo
9885203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
9886203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
9887203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9888203945Sweongyo
9889204922Sweongyo	siba_write_multi_4(sc->sc_dev, data, (len & ~3),
9890203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
9891203945Sweongyo	if (len & 3) {
9892203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
9893203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
9894203945Sweongyo		data = &(data[len - 1]);
9895203945Sweongyo		switch (len & 3) {
9896203945Sweongyo		case 3:
9897203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
9898203945Sweongyo			value |= (uint32_t)(*data) << 16;
9899203945Sweongyo			data--;
9900203945Sweongyo		case 2:
9901203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
9902203945Sweongyo			value |= (uint32_t)(*data) << 8;
9903203945Sweongyo			data--;
9904203945Sweongyo		case 1:
9905203945Sweongyo			value |= (uint32_t)(*data);
9906203945Sweongyo		}
9907203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9908203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
9909203945Sweongyo	}
9910203945Sweongyo
9911203945Sweongyo	return (ctl);
9912203945Sweongyo}
9913203945Sweongyo
9914203945Sweongyostatic void
9915203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9916203945Sweongyo    uint16_t offset, uint32_t value)
9917203945Sweongyo{
9918203945Sweongyo
9919203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
9920203945Sweongyo}
9921203945Sweongyo
9922203945Sweongyostatic uint16_t
9923203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9924203945Sweongyo    uint16_t ctl, const void *_data, int len)
9925203945Sweongyo{
9926204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9927203945Sweongyo	const uint8_t *data = _data;
9928203945Sweongyo
9929203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
9930203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9931203945Sweongyo
9932204922Sweongyo	siba_write_multi_2(sc->sc_dev, data, (len & ~1),
9933203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
9934203945Sweongyo	if (len & 1) {
9935203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
9936203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9937203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
9938203945Sweongyo	}
9939203945Sweongyo
9940203945Sweongyo	return (ctl);
9941203945Sweongyo}
9942203945Sweongyo
9943203945Sweongyostatic uint16_t
9944203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9945203945Sweongyo    uint16_t ctl, struct mbuf *m0)
9946203945Sweongyo{
9947203945Sweongyo	int i, j = 0;
9948203945Sweongyo	uint16_t data = 0;
9949203945Sweongyo	const uint8_t *buf;
9950203945Sweongyo	struct mbuf *m = m0;
9951203945Sweongyo
9952203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
9953203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9954203945Sweongyo
9955203945Sweongyo	for (; m != NULL; m = m->m_next) {
9956203945Sweongyo		buf = mtod(m, const uint8_t *);
9957203945Sweongyo		for (i = 0; i < m->m_len; i++) {
9958203945Sweongyo			if (!((j++) % 2))
9959203945Sweongyo				data |= buf[i];
9960203945Sweongyo			else {
9961203945Sweongyo				data |= (buf[i] << 8);
9962203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
9963203945Sweongyo				data = 0;
9964203945Sweongyo			}
9965203945Sweongyo		}
9966203945Sweongyo	}
9967203945Sweongyo	if (m0->m_pkthdr.len % 2) {
9968203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
9969203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9970203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
9971203945Sweongyo	}
9972203945Sweongyo
9973203945Sweongyo	return (ctl);
9974203945Sweongyo}
9975203945Sweongyo
9976203945Sweongyostatic void
9977203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
9978203945Sweongyo{
9979203945Sweongyo
9980203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
9981203945Sweongyo		return;
9982203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
9983203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
9984203945Sweongyo}
9985203945Sweongyo
9986203945Sweongyostatic struct bwn_dma_ring *
9987203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
9988203945Sweongyo{
9989203945Sweongyo
9990203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
9991203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
9992203945Sweongyo
9993203945Sweongyo	switch (prio) {
9994203945Sweongyo	case 3:
9995203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
9996203945Sweongyo	case 2:
9997203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
9998203945Sweongyo	case 0:
9999203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
10000203945Sweongyo	case 1:
10001203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
10002203945Sweongyo	}
10003203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
10004204242Simp	return (NULL);
10005203945Sweongyo}
10006203945Sweongyo
10007203945Sweongyostatic int
10008203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
10009203945Sweongyo{
10010203945Sweongyo	int slot;
10011203945Sweongyo
10012204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
10013203945Sweongyo
10014203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
10015203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
10016203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
10017203945Sweongyo
10018203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
10019203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
10020203945Sweongyo	dr->dr_curslot = slot;
10021203945Sweongyo	dr->dr_usedslot++;
10022203945Sweongyo
10023203945Sweongyo	return (slot);
10024203945Sweongyo}
10025203945Sweongyo
10026203945Sweongyostatic int
10027203945Sweongyobwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
10028203945Sweongyo{
10029203945Sweongyo	const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
10030203945Sweongyo	unsigned int a, b, c, d;
10031203945Sweongyo	unsigned int avg;
10032203945Sweongyo	uint32_t tmp;
10033203945Sweongyo
10034203945Sweongyo	tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
10035203945Sweongyo	a = tmp & 0xff;
10036203945Sweongyo	b = (tmp >> 8) & 0xff;
10037203945Sweongyo	c = (tmp >> 16) & 0xff;
10038203945Sweongyo	d = (tmp >> 24) & 0xff;
10039203945Sweongyo	if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
10040203945Sweongyo	    c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
10041203945Sweongyo		return (ENOENT);
10042203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
10043203945Sweongyo	    BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
10044203945Sweongyo	    (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
10045203945Sweongyo
10046203945Sweongyo	if (ofdm) {
10047203945Sweongyo		a = (a + 32) & 0x3f;
10048203945Sweongyo		b = (b + 32) & 0x3f;
10049203945Sweongyo		c = (c + 32) & 0x3f;
10050203945Sweongyo		d = (d + 32) & 0x3f;
10051203945Sweongyo	}
10052203945Sweongyo
10053203945Sweongyo	avg = (a + b + c + d + 2) / 4;
10054203945Sweongyo	if (ofdm) {
10055203945Sweongyo		if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
10056203945Sweongyo		    & BWN_HF_4DB_CCK_POWERBOOST)
10057203945Sweongyo			avg = (avg >= 13) ? (avg - 13) : 0;
10058203945Sweongyo	}
10059203945Sweongyo	return (avg);
10060203945Sweongyo}
10061203945Sweongyo
10062203945Sweongyostatic void
10063203945Sweongyobwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
10064203945Sweongyo{
10065203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
10066203945Sweongyo	int rfatt = *rfattp;
10067203945Sweongyo	int bbatt = *bbattp;
10068203945Sweongyo
10069203945Sweongyo	while (1) {
10070203945Sweongyo		if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
10071203945Sweongyo			break;
10072203945Sweongyo		if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
10073203945Sweongyo			break;
10074203945Sweongyo		if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
10075203945Sweongyo			break;
10076203945Sweongyo		if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
10077203945Sweongyo			break;
10078203945Sweongyo		if (bbatt > lo->bbatt.max) {
10079203945Sweongyo			bbatt -= 4;
10080203945Sweongyo			rfatt += 1;
10081203945Sweongyo			continue;
10082203945Sweongyo		}
10083203945Sweongyo		if (bbatt < lo->bbatt.min) {
10084203945Sweongyo			bbatt += 4;
10085203945Sweongyo			rfatt -= 1;
10086203945Sweongyo			continue;
10087203945Sweongyo		}
10088203945Sweongyo		if (rfatt > lo->rfatt.max) {
10089203945Sweongyo			rfatt -= 1;
10090203945Sweongyo			bbatt += 4;
10091203945Sweongyo			continue;
10092203945Sweongyo		}
10093203945Sweongyo		if (rfatt < lo->rfatt.min) {
10094203945Sweongyo			rfatt += 1;
10095203945Sweongyo			bbatt -= 4;
10096203945Sweongyo			continue;
10097203945Sweongyo		}
10098203945Sweongyo		break;
10099203945Sweongyo	}
10100203945Sweongyo
10101203945Sweongyo	*rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
10102203945Sweongyo	*bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
10103203945Sweongyo}
10104203945Sweongyo
10105203945Sweongyostatic void
10106203945Sweongyobwn_phy_lock(struct bwn_mac *mac)
10107203945Sweongyo{
10108203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10109203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10110203945Sweongyo
10111204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
10112204922Sweongyo	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
10113203945Sweongyo
10114203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10115203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
10116203945Sweongyo}
10117203945Sweongyo
10118203945Sweongyostatic void
10119203945Sweongyobwn_phy_unlock(struct bwn_mac *mac)
10120203945Sweongyo{
10121203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10122203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10123203945Sweongyo
10124204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
10125204922Sweongyo	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
10126203945Sweongyo
10127203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10128203945Sweongyo		bwn_psctl(mac, 0);
10129203945Sweongyo}
10130203945Sweongyo
10131203945Sweongyostatic void
10132203945Sweongyobwn_rf_lock(struct bwn_mac *mac)
10133203945Sweongyo{
10134203945Sweongyo
10135203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10136203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
10137203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
10138203945Sweongyo	DELAY(10);
10139203945Sweongyo}
10140203945Sweongyo
10141203945Sweongyostatic void
10142203945Sweongyobwn_rf_unlock(struct bwn_mac *mac)
10143203945Sweongyo{
10144203945Sweongyo
10145203945Sweongyo	BWN_READ_2(mac, BWN_PHYVER);
10146203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10147203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
10148203945Sweongyo}
10149203945Sweongyo
10150203945Sweongyostatic struct bwn_pio_txqueue *
10151203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
10152203945Sweongyo    struct bwn_pio_txpkt **pack)
10153203945Sweongyo{
10154203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
10155203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
10156203945Sweongyo	unsigned int index;
10157203945Sweongyo
10158203945Sweongyo	switch (cookie & 0xf000) {
10159203945Sweongyo	case 0x1000:
10160203945Sweongyo		tq = &pio->wme[WME_AC_BK];
10161203945Sweongyo		break;
10162203945Sweongyo	case 0x2000:
10163203945Sweongyo		tq = &pio->wme[WME_AC_BE];
10164203945Sweongyo		break;
10165203945Sweongyo	case 0x3000:
10166203945Sweongyo		tq = &pio->wme[WME_AC_VI];
10167203945Sweongyo		break;
10168203945Sweongyo	case 0x4000:
10169203945Sweongyo		tq = &pio->wme[WME_AC_VO];
10170203945Sweongyo		break;
10171203945Sweongyo	case 0x5000:
10172203945Sweongyo		tq = &pio->mcast;
10173203945Sweongyo		break;
10174203945Sweongyo	}
10175203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
10176203945Sweongyo	if (tq == NULL)
10177203945Sweongyo		return (NULL);
10178203945Sweongyo	index = (cookie & 0x0fff);
10179203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
10180203945Sweongyo	if (index >= N(tq->tq_pkts))
10181203945Sweongyo		return (NULL);
10182203945Sweongyo	*pack = &tq->tq_pkts[index];
10183203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
10184203945Sweongyo	return (tq);
10185203945Sweongyo}
10186203945Sweongyo
10187203945Sweongyostatic void
10188203945Sweongyobwn_txpwr(void *arg, int npending)
10189203945Sweongyo{
10190203945Sweongyo	struct bwn_mac *mac = arg;
10191203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10192203945Sweongyo
10193203945Sweongyo	BWN_LOCK(sc);
10194203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
10195203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
10196203945Sweongyo		mac->mac_phy.set_txpwr(mac);
10197203945Sweongyo	BWN_UNLOCK(sc);
10198203945Sweongyo}
10199203945Sweongyo
10200203945Sweongyostatic void
10201203945Sweongyobwn_task_15s(struct bwn_mac *mac)
10202203945Sweongyo{
10203203945Sweongyo	uint16_t reg;
10204203945Sweongyo
10205203945Sweongyo	if (mac->mac_fw.opensource) {
10206203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
10207203945Sweongyo		if (reg) {
10208203945Sweongyo			bwn_restart(mac, "fw watchdog");
10209203945Sweongyo			return;
10210203945Sweongyo		}
10211203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
10212203945Sweongyo	}
10213203945Sweongyo	if (mac->mac_phy.task_15s)
10214203945Sweongyo		mac->mac_phy.task_15s(mac);
10215203945Sweongyo
10216203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
10217203945Sweongyo}
10218203945Sweongyo
10219203945Sweongyostatic void
10220203945Sweongyobwn_task_30s(struct bwn_mac *mac)
10221203945Sweongyo{
10222203945Sweongyo
10223203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
10224203945Sweongyo		return;
10225203945Sweongyo	mac->mac_noise.noi_running = 1;
10226203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
10227203945Sweongyo
10228203945Sweongyo	bwn_noise_gensample(mac);
10229203945Sweongyo}
10230203945Sweongyo
10231203945Sweongyostatic void
10232203945Sweongyobwn_task_60s(struct bwn_mac *mac)
10233203945Sweongyo{
10234203945Sweongyo
10235203945Sweongyo	if (mac->mac_phy.task_60s)
10236203945Sweongyo		mac->mac_phy.task_60s(mac);
10237203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
10238203945Sweongyo}
10239203945Sweongyo
10240203945Sweongyostatic void
10241203945Sweongyobwn_tasks(void *arg)
10242203945Sweongyo{
10243203945Sweongyo	struct bwn_mac *mac = arg;
10244203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10245203945Sweongyo
10246203945Sweongyo	BWN_ASSERT_LOCKED(sc);
10247203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
10248203945Sweongyo		return;
10249203945Sweongyo
10250203945Sweongyo	if (mac->mac_task_state % 4 == 0)
10251203945Sweongyo		bwn_task_60s(mac);
10252203945Sweongyo	if (mac->mac_task_state % 2 == 0)
10253203945Sweongyo		bwn_task_30s(mac);
10254203945Sweongyo	bwn_task_15s(mac);
10255203945Sweongyo
10256203945Sweongyo	mac->mac_task_state++;
10257203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
10258203945Sweongyo}
10259203945Sweongyo
10260203945Sweongyostatic int
10261203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
10262203945Sweongyo{
10263203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10264203945Sweongyo
10265203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
10266203945Sweongyo
10267203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
10268203945Sweongyo	case 0xb:
10269203945Sweongyo		return (BWN_OFDM_RATE_6MB);
10270203945Sweongyo	case 0xf:
10271203945Sweongyo		return (BWN_OFDM_RATE_9MB);
10272203945Sweongyo	case 0xa:
10273203945Sweongyo		return (BWN_OFDM_RATE_12MB);
10274203945Sweongyo	case 0xe:
10275203945Sweongyo		return (BWN_OFDM_RATE_18MB);
10276203945Sweongyo	case 0x9:
10277203945Sweongyo		return (BWN_OFDM_RATE_24MB);
10278203945Sweongyo	case 0xd:
10279203945Sweongyo		return (BWN_OFDM_RATE_36MB);
10280203945Sweongyo	case 0x8:
10281203945Sweongyo		return (BWN_OFDM_RATE_48MB);
10282203945Sweongyo	case 0xc:
10283203945Sweongyo		return (BWN_OFDM_RATE_54MB);
10284203945Sweongyo	}
10285203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
10286203945Sweongyo	    plcp->o.raw[0] & 0xf);
10287203945Sweongyo	return (-1);
10288203945Sweongyo}
10289203945Sweongyo
10290203945Sweongyostatic int
10291203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
10292203945Sweongyo{
10293203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10294203945Sweongyo
10295203945Sweongyo	switch (plcp->o.raw[0]) {
10296203945Sweongyo	case 0x0a:
10297203945Sweongyo		return (BWN_CCK_RATE_1MB);
10298203945Sweongyo	case 0x14:
10299203945Sweongyo		return (BWN_CCK_RATE_2MB);
10300203945Sweongyo	case 0x37:
10301203945Sweongyo		return (BWN_CCK_RATE_5MB);
10302203945Sweongyo	case 0x6e:
10303203945Sweongyo		return (BWN_CCK_RATE_11MB);
10304203945Sweongyo	}
10305203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
10306203945Sweongyo	return (-1);
10307203945Sweongyo}
10308203945Sweongyo
10309203945Sweongyostatic void
10310203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
10311203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
10312203945Sweongyo    int rssi, int noise)
10313203945Sweongyo{
10314203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10315203945Sweongyo	const struct ieee80211_frame_min *wh;
10316203945Sweongyo	uint64_t tsf;
10317203945Sweongyo	uint16_t low_mactime_now;
10318203945Sweongyo
10319203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
10320203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
10321203945Sweongyo
10322203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
10323260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
10324203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
10325203945Sweongyo
10326203945Sweongyo	bwn_tsf_read(mac, &tsf);
10327203945Sweongyo	low_mactime_now = tsf;
10328203945Sweongyo	tsf = tsf & ~0xffffULL;
10329203945Sweongyo	tsf += le16toh(rxhdr->mac_time);
10330203945Sweongyo	if (low_mactime_now < le16toh(rxhdr->mac_time))
10331203945Sweongyo		tsf -= 0x10000;
10332203945Sweongyo
10333203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
10334203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
10335203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
10336203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
10337203945Sweongyo}
10338203945Sweongyo
10339203945Sweongyostatic void
10340203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
10341203945Sweongyo{
10342203945Sweongyo	uint32_t low, high;
10343203945Sweongyo
10344204983Syongari	KASSERT(siba_get_revid(mac->mac_sc->sc_dev) >= 3,
10345203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
10346203945Sweongyo
10347203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
10348203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
10349203945Sweongyo	*tsf = high;
10350203945Sweongyo	*tsf <<= 32;
10351203945Sweongyo	*tsf |= low;
10352203945Sweongyo}
10353203945Sweongyo
10354203945Sweongyostatic int
10355203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
10356203945Sweongyo{
10357203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10358203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10359203945Sweongyo	bus_addr_t lowaddr = 0;
10360203945Sweongyo	int error;
10361203945Sweongyo
10362204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
10363203945Sweongyo		return (0);
10364203945Sweongyo
10365204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5, ("%s: fail", __func__));
10366203945Sweongyo
10367203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
10368203945Sweongyo
10369203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
10370203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
10371203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
10372203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
10373203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
10374203945Sweongyo	else
10375203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
10376203945Sweongyo
10377203945Sweongyo	/*
10378203945Sweongyo	 * Create top level DMA tag
10379203945Sweongyo	 */
10380203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
10381203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
10382203945Sweongyo			       lowaddr,			/* lowaddr */
10383203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
10384203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
10385280347Smav			       BUS_SPACE_MAXSIZE,	/* maxsize */
10386203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
10387203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
10388203945Sweongyo			       0,			/* flags */
10389203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
10390203945Sweongyo			       &dma->parent_dtag);
10391203945Sweongyo	if (error) {
10392203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
10393203945Sweongyo		return (error);
10394203945Sweongyo	}
10395203945Sweongyo
10396203945Sweongyo	/*
10397203945Sweongyo	 * Create TX/RX mbuf DMA tag
10398203945Sweongyo	 */
10399203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10400203945Sweongyo				1,
10401203945Sweongyo				0,
10402203945Sweongyo				BUS_SPACE_MAXADDR,
10403203945Sweongyo				BUS_SPACE_MAXADDR,
10404203945Sweongyo				NULL, NULL,
10405203945Sweongyo				MCLBYTES,
10406203945Sweongyo				1,
10407203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10408203945Sweongyo				0,
10409203945Sweongyo				NULL, NULL,
10410203945Sweongyo				&dma->rxbuf_dtag);
10411203945Sweongyo	if (error) {
10412203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10413203945Sweongyo		goto fail0;
10414203945Sweongyo	}
10415203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10416203945Sweongyo				1,
10417203945Sweongyo				0,
10418203945Sweongyo				BUS_SPACE_MAXADDR,
10419203945Sweongyo				BUS_SPACE_MAXADDR,
10420203945Sweongyo				NULL, NULL,
10421203945Sweongyo				MCLBYTES,
10422203945Sweongyo				1,
10423203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10424203945Sweongyo				0,
10425203945Sweongyo				NULL, NULL,
10426203945Sweongyo				&dma->txbuf_dtag);
10427203945Sweongyo	if (error) {
10428203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10429203945Sweongyo		goto fail1;
10430203945Sweongyo	}
10431203945Sweongyo
10432203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
10433203945Sweongyo	if (!dma->wme[WME_AC_BK])
10434203945Sweongyo		goto fail2;
10435203945Sweongyo
10436203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
10437203945Sweongyo	if (!dma->wme[WME_AC_BE])
10438203945Sweongyo		goto fail3;
10439203945Sweongyo
10440203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
10441203945Sweongyo	if (!dma->wme[WME_AC_VI])
10442203945Sweongyo		goto fail4;
10443203945Sweongyo
10444203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
10445203945Sweongyo	if (!dma->wme[WME_AC_VO])
10446203945Sweongyo		goto fail5;
10447203945Sweongyo
10448203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
10449203945Sweongyo	if (!dma->mcast)
10450203945Sweongyo		goto fail6;
10451203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
10452203945Sweongyo	if (!dma->rx)
10453203945Sweongyo		goto fail7;
10454203945Sweongyo
10455203945Sweongyo	return (error);
10456203945Sweongyo
10457203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
10458203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
10459203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
10460203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
10461203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
10462203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
10463203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
10464203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
10465203945Sweongyo	return (error);
10466203945Sweongyo}
10467203945Sweongyo
10468203945Sweongyostatic struct bwn_dma_ring *
10469203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
10470203945Sweongyo    uint16_t cookie, int *slot)
10471203945Sweongyo{
10472203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10473203945Sweongyo	struct bwn_dma_ring *dr;
10474203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10475203945Sweongyo
10476203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
10477203945Sweongyo
10478203945Sweongyo	switch (cookie & 0xf000) {
10479203945Sweongyo	case 0x1000:
10480203945Sweongyo		dr = dma->wme[WME_AC_BK];
10481203945Sweongyo		break;
10482203945Sweongyo	case 0x2000:
10483203945Sweongyo		dr = dma->wme[WME_AC_BE];
10484203945Sweongyo		break;
10485203945Sweongyo	case 0x3000:
10486203945Sweongyo		dr = dma->wme[WME_AC_VI];
10487203945Sweongyo		break;
10488203945Sweongyo	case 0x4000:
10489203945Sweongyo		dr = dma->wme[WME_AC_VO];
10490203945Sweongyo		break;
10491203945Sweongyo	case 0x5000:
10492203945Sweongyo		dr = dma->mcast;
10493203945Sweongyo		break;
10494203945Sweongyo	default:
10495204242Simp		dr = NULL;
10496203945Sweongyo		KASSERT(0 == 1,
10497203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
10498203945Sweongyo	}
10499203945Sweongyo	*slot = (cookie & 0x0fff);
10500203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
10501203945Sweongyo		/*
10502203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
10503203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
10504203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
10505203945Sweongyo		 */
10506203945Sweongyo		KASSERT(status->seq == dma->lastseq,
10507203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
10508203945Sweongyo		device_printf(sc->sc_dev,
10509203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
10510203945Sweongyo		    dr->dr_numslots);
10511203945Sweongyo		return (NULL);
10512203945Sweongyo	}
10513203945Sweongyo	dma->lastseq = status->seq;
10514203945Sweongyo	return (dr);
10515203945Sweongyo}
10516203945Sweongyo
10517203945Sweongyostatic void
10518203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
10519203945Sweongyo{
10520203945Sweongyo	struct bwn_dma *dma;
10521203945Sweongyo
10522203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
10523203945Sweongyo		return;
10524203945Sweongyo	dma = &mac->mac_method.dma;
10525203945Sweongyo
10526203945Sweongyo	bwn_dma_ringstop(&dma->rx);
10527203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
10528203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
10529203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
10530203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
10531203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
10532203945Sweongyo}
10533203945Sweongyo
10534203945Sweongyostatic void
10535203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
10536203945Sweongyo{
10537203945Sweongyo
10538203945Sweongyo	if (dr == NULL)
10539203945Sweongyo		return;
10540203945Sweongyo
10541203945Sweongyo	bwn_dma_cleanup(*dr);
10542203945Sweongyo}
10543203945Sweongyo
10544203945Sweongyostatic void
10545203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
10546203945Sweongyo{
10547203945Sweongyo	struct bwn_pio *pio;
10548203945Sweongyo
10549203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
10550203945Sweongyo		return;
10551203945Sweongyo	pio = &mac->mac_method.pio;
10552203945Sweongyo
10553203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
10554203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
10555203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
10556203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
10557203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
10558203945Sweongyo}
10559203945Sweongyo
10560203945Sweongyostatic void
10561203945Sweongyobwn_led_attach(struct bwn_mac *mac)
10562203945Sweongyo{
10563203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10564203945Sweongyo	const uint8_t *led_act = NULL;
10565203945Sweongyo	uint16_t val[BWN_LED_MAX];
10566203945Sweongyo	int i;
10567203945Sweongyo
10568203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
10569203945Sweongyo	sc->sc_led_blink = 1;
10570203945Sweongyo
10571203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
10572204922Sweongyo		if (siba_get_pci_subvendor(sc->sc_dev) ==
10573204922Sweongyo		    bwn_vendor_led_act[i].vid) {
10574203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
10575203945Sweongyo			break;
10576203945Sweongyo		}
10577203945Sweongyo	}
10578203945Sweongyo	if (led_act == NULL)
10579203945Sweongyo		led_act = bwn_default_led_act;
10580203945Sweongyo
10581204922Sweongyo	val[0] = siba_sprom_get_gpio0(sc->sc_dev);
10582204922Sweongyo	val[1] = siba_sprom_get_gpio1(sc->sc_dev);
10583204922Sweongyo	val[2] = siba_sprom_get_gpio2(sc->sc_dev);
10584204922Sweongyo	val[3] = siba_sprom_get_gpio3(sc->sc_dev);
10585203945Sweongyo
10586203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10587203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10588203945Sweongyo
10589203945Sweongyo		if (val[i] == 0xff) {
10590203945Sweongyo			led->led_act = led_act[i];
10591203945Sweongyo		} else {
10592203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
10593203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
10594203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
10595203945Sweongyo		}
10596203945Sweongyo		led->led_mask = (1 << i);
10597203945Sweongyo
10598203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
10599203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
10600203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
10601203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
10602203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
10603203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
10604203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
10605203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
10606203945Sweongyo
10607203945Sweongyo			if (sc->sc_blink_led == NULL) {
10608203945Sweongyo				sc->sc_blink_led = led;
10609203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
10610203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
10611203945Sweongyo			}
10612203945Sweongyo		}
10613203945Sweongyo
10614203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
10615203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
10616203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
10617203945Sweongyo	}
10618203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
10619203945Sweongyo}
10620203945Sweongyo
10621203945Sweongyostatic __inline uint16_t
10622203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
10623203945Sweongyo{
10624203945Sweongyo
10625203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
10626203945Sweongyo		on = !on;
10627203945Sweongyo	if (on)
10628203945Sweongyo		val |= led->led_mask;
10629203945Sweongyo	else
10630203945Sweongyo		val &= ~led->led_mask;
10631203945Sweongyo	return val;
10632203945Sweongyo}
10633203945Sweongyo
10634203945Sweongyostatic void
10635203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
10636203945Sweongyo{
10637203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10638203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10639203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10640203945Sweongyo	uint16_t val;
10641203945Sweongyo	int i;
10642203945Sweongyo
10643203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
10644203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
10645203945Sweongyo		sc->sc_led_blinking = 0;
10646203945Sweongyo	}
10647203945Sweongyo
10648203945Sweongyo	if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
10649203945Sweongyo		return;
10650203945Sweongyo
10651203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10652203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10653203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10654203945Sweongyo		int on;
10655203945Sweongyo
10656203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
10657203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
10658203945Sweongyo			continue;
10659203945Sweongyo
10660203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
10661203945Sweongyo		    nstate != IEEE80211_S_INIT)
10662203945Sweongyo			continue;
10663203945Sweongyo
10664203945Sweongyo		switch (led->led_act) {
10665203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
10666203945Sweongyo			on = 1;
10667203945Sweongyo			break;
10668203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
10669203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
10670203945Sweongyo			on = 0;
10671203945Sweongyo			break;
10672203945Sweongyo		default:
10673203945Sweongyo			on = 1;
10674203945Sweongyo			switch (nstate) {
10675203945Sweongyo			case IEEE80211_S_INIT:
10676203945Sweongyo				on = 0;
10677203945Sweongyo				break;
10678203945Sweongyo			case IEEE80211_S_RUN:
10679203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
10680203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
10681203945Sweongyo					on = 0;
10682203945Sweongyo				break;
10683203945Sweongyo			default:
10684203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
10685203945Sweongyo					on = 0;
10686203945Sweongyo				break;
10687203945Sweongyo			}
10688203945Sweongyo			break;
10689203945Sweongyo		}
10690203945Sweongyo
10691203945Sweongyo		val = bwn_led_onoff(led, val, on);
10692203945Sweongyo	}
10693203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10694203945Sweongyo}
10695203945Sweongyo
10696203945Sweongyostatic void
10697203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
10698203945Sweongyo{
10699203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10700204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
10701204922Sweongyo	int rate;
10702203945Sweongyo
10703204922Sweongyo	if (event == BWN_LED_EVENT_POLL) {
10704204922Sweongyo		if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
10705204922Sweongyo			return;
10706204922Sweongyo		if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
10707204922Sweongyo			return;
10708204922Sweongyo	}
10709203945Sweongyo
10710204922Sweongyo	sc->sc_led_ticks = ticks;
10711204922Sweongyo	if (sc->sc_led_blinking)
10712204922Sweongyo		return;
10713203945Sweongyo
10714204922Sweongyo	switch (event) {
10715204922Sweongyo	case BWN_LED_EVENT_RX:
10716204922Sweongyo		rate = sc->sc_rx_rate;
10717204922Sweongyo		break;
10718204922Sweongyo	case BWN_LED_EVENT_TX:
10719204922Sweongyo		rate = sc->sc_tx_rate;
10720204922Sweongyo		break;
10721204922Sweongyo	case BWN_LED_EVENT_POLL:
10722204922Sweongyo		rate = 0;
10723204922Sweongyo		break;
10724204922Sweongyo	default:
10725204922Sweongyo		panic("unknown LED event %d\n", event);
10726204922Sweongyo		break;
10727204922Sweongyo	}
10728204922Sweongyo	bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
10729204922Sweongyo	    bwn_led_duration[rate].off_dur);
10730203945Sweongyo}
10731203945Sweongyo
10732203945Sweongyostatic void
10733203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
10734203945Sweongyo{
10735203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10736204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
10737204922Sweongyo	uint16_t val;
10738203945Sweongyo
10739204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10740204922Sweongyo	val = bwn_led_onoff(led, val, 1);
10741204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10742203945Sweongyo
10743204922Sweongyo	if (led->led_flags & BWN_LED_F_SLOW) {
10744204922Sweongyo		BWN_LED_SLOWDOWN(on_dur);
10745204922Sweongyo		BWN_LED_SLOWDOWN(off_dur);
10746204922Sweongyo	}
10747203945Sweongyo
10748204922Sweongyo	sc->sc_led_blinking = 1;
10749204922Sweongyo	sc->sc_led_blink_offdur = off_dur;
10750203945Sweongyo
10751204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
10752203945Sweongyo}
10753203945Sweongyo
10754203945Sweongyostatic void
10755203945Sweongyobwn_led_blink_next(void *arg)
10756203945Sweongyo{
10757203945Sweongyo	struct bwn_mac *mac = arg;
10758204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10759204922Sweongyo	uint16_t val;
10760203945Sweongyo
10761204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10762204922Sweongyo	val = bwn_led_onoff(sc->sc_blink_led, val, 0);
10763204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10764203945Sweongyo
10765204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
10766204922Sweongyo	    bwn_led_blink_end, mac);
10767203945Sweongyo}
10768203945Sweongyo
10769203945Sweongyostatic void
10770203945Sweongyobwn_led_blink_end(void *arg)
10771203945Sweongyo{
10772203945Sweongyo	struct bwn_mac *mac = arg;
10773204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10774203945Sweongyo
10775204922Sweongyo	sc->sc_led_blinking = 0;
10776203945Sweongyo}
10777203945Sweongyo
10778203945Sweongyostatic int
10779203945Sweongyobwn_suspend(device_t dev)
10780203945Sweongyo{
10781203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10782203945Sweongyo
10783203945Sweongyo	bwn_stop(sc, 1);
10784203945Sweongyo	return (0);
10785203945Sweongyo}
10786203945Sweongyo
10787203945Sweongyostatic int
10788203945Sweongyobwn_resume(device_t dev)
10789203945Sweongyo{
10790203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10791203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10792203945Sweongyo
10793203945Sweongyo	if (ifp->if_flags & IFF_UP)
10794203945Sweongyo		bwn_init(sc);
10795203945Sweongyo	return (0);
10796203945Sweongyo}
10797203945Sweongyo
10798203945Sweongyostatic void
10799203945Sweongyobwn_rfswitch(void *arg)
10800203945Sweongyo{
10801203945Sweongyo	struct bwn_softc *sc = arg;
10802203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
10803203945Sweongyo	int cur = 0, prev = 0;
10804203945Sweongyo
10805203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
10806203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
10807203945Sweongyo
10808203945Sweongyo	if (mac->mac_phy.rf_rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
10809203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
10810203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
10811203945Sweongyo			cur = 1;
10812203945Sweongyo	} else {
10813203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
10814203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
10815203945Sweongyo			cur = 1;
10816203945Sweongyo	}
10817203945Sweongyo
10818203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
10819203945Sweongyo		prev = 1;
10820203945Sweongyo
10821203945Sweongyo	if (cur != prev) {
10822203945Sweongyo		if (cur)
10823203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
10824203945Sweongyo		else
10825203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
10826203945Sweongyo
10827203945Sweongyo		device_printf(sc->sc_dev,
10828203945Sweongyo		    "status of RF switch is changed to %s\n",
10829203945Sweongyo		    cur ? "ON" : "OFF");
10830203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
10831203945Sweongyo			if (cur)
10832203945Sweongyo				bwn_rf_turnon(mac);
10833203945Sweongyo			else
10834203945Sweongyo				bwn_rf_turnoff(mac);
10835203945Sweongyo		}
10836203945Sweongyo	}
10837203945Sweongyo
10838203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
10839203945Sweongyo}
10840203945Sweongyo
10841203945Sweongyostatic void
10842203945Sweongyobwn_phy_lp_init_pre(struct bwn_mac *mac)
10843203945Sweongyo{
10844203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
10845203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
10846203945Sweongyo
10847203945Sweongyo	plp->plp_antenna = BWN_ANT_DEFAULT;
10848203945Sweongyo}
10849203945Sweongyo
10850203945Sweongyostatic int
10851203945Sweongyobwn_phy_lp_init(struct bwn_mac *mac)
10852203945Sweongyo{
10853203945Sweongyo	static const struct bwn_stxtable tables[] = {
10854203945Sweongyo		{ 2,  6, 0x3d, 3, 0x01 }, { 1, 12, 0x4c, 1, 0x01 },
10855203945Sweongyo		{ 1,  8, 0x50, 0, 0x7f }, { 0,  8, 0x44, 0, 0xff },
10856203945Sweongyo		{ 1,  0, 0x4a, 0, 0xff }, { 0,  4, 0x4d, 0, 0xff },
10857203945Sweongyo		{ 1,  4, 0x4e, 0, 0xff }, { 0, 12, 0x4f, 0, 0x0f },
10858203945Sweongyo		{ 1,  0, 0x4f, 4, 0x0f }, { 3,  0, 0x49, 0, 0x0f },
10859203945Sweongyo		{ 4,  3, 0x46, 4, 0x07 }, { 3, 15, 0x46, 0, 0x01 },
10860203945Sweongyo		{ 4,  0, 0x46, 1, 0x07 }, { 3,  8, 0x48, 4, 0x07 },
10861203945Sweongyo		{ 3, 11, 0x48, 0, 0x0f }, { 3,  4, 0x49, 4, 0x0f },
10862203945Sweongyo		{ 2, 15, 0x45, 0, 0x01 }, { 5, 13, 0x52, 4, 0x07 },
10863203945Sweongyo		{ 6,  0, 0x52, 7, 0x01 }, { 5,  3, 0x41, 5, 0x07 },
10864203945Sweongyo		{ 5,  6, 0x41, 0, 0x0f }, { 5, 10, 0x42, 5, 0x07 },
10865203945Sweongyo		{ 4, 15, 0x42, 0, 0x01 }, { 5,  0, 0x42, 1, 0x07 },
10866203945Sweongyo		{ 4, 11, 0x43, 4, 0x0f }, { 4,  7, 0x43, 0, 0x0f },
10867203945Sweongyo		{ 4,  6, 0x45, 1, 0x01 }, { 2,  7, 0x40, 4, 0x0f },
10868203945Sweongyo		{ 2, 11, 0x40, 0, 0x0f }
10869203945Sweongyo	};
10870203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
10871203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10872203945Sweongyo	const struct bwn_stxtable *st;
10873203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10874203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10875203945Sweongyo	int i, error;
10876203945Sweongyo	uint16_t tmp;
10877203945Sweongyo
10878203945Sweongyo	bwn_phy_lp_readsprom(mac);	/* XXX bad place */
10879203945Sweongyo	bwn_phy_lp_bbinit(mac);
10880203945Sweongyo
10881203945Sweongyo	/* initialize RF */
10882203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_4WIRECTL, 0x2);
10883203945Sweongyo	DELAY(1);
10884203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_4WIRECTL, 0xfffd);
10885203945Sweongyo	DELAY(1);
10886203945Sweongyo
10887203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2062)
10888203945Sweongyo		bwn_phy_lp_b2062_init(mac);
10889203945Sweongyo	else {
10890203945Sweongyo		bwn_phy_lp_b2063_init(mac);
10891203945Sweongyo
10892203945Sweongyo		/* synchronize stx table. */
10893203945Sweongyo		for (i = 0; i < N(tables); i++) {
10894203945Sweongyo			st = &tables[i];
10895203945Sweongyo			tmp = BWN_RF_READ(mac, st->st_rfaddr);
10896203945Sweongyo			tmp >>= st->st_rfshift;
10897203945Sweongyo			tmp <<= st->st_physhift;
10898203945Sweongyo			BWN_PHY_SETMASK(mac,
10899203945Sweongyo			    BWN_PHY_OFDM(0xf2 + st->st_phyoffset),
10900203945Sweongyo			    ~(st->st_mask << st->st_physhift), tmp);
10901203945Sweongyo		}
10902203945Sweongyo
10903203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf0), 0x5f80);
10904203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf1), 0);
10905203945Sweongyo	}
10906203945Sweongyo
10907203945Sweongyo	/* calibrate RC */
10908203945Sweongyo	if (mac->mac_phy.rev >= 2)
10909203945Sweongyo		bwn_phy_lp_rxcal_r2(mac);
10910203945Sweongyo	else if (!plp->plp_rccap) {
10911203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
10912203945Sweongyo			bwn_phy_lp_rccal_r12(mac);
10913203945Sweongyo	} else
10914203945Sweongyo		bwn_phy_lp_set_rccap(mac);
10915203945Sweongyo
10916203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
10917203945Sweongyo	if (error)
10918203945Sweongyo		device_printf(sc->sc_dev,
10919203945Sweongyo		    "failed to change channel 7 (%d)\n", error);
10920203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
10921203945Sweongyo	bwn_phy_lp_calib(mac);
10922203945Sweongyo	return (0);
10923203945Sweongyo}
10924203945Sweongyo
10925203945Sweongyostatic uint16_t
10926203945Sweongyobwn_phy_lp_read(struct bwn_mac *mac, uint16_t reg)
10927203945Sweongyo{
10928203945Sweongyo
10929203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10930203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
10931203945Sweongyo}
10932203945Sweongyo
10933203945Sweongyostatic void
10934203945Sweongyobwn_phy_lp_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
10935203945Sweongyo{
10936203945Sweongyo
10937203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10938203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
10939203945Sweongyo}
10940203945Sweongyo
10941203945Sweongyostatic void
10942203945Sweongyobwn_phy_lp_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
10943203945Sweongyo    uint16_t set)
10944203945Sweongyo{
10945203945Sweongyo
10946203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10947203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA,
10948203945Sweongyo	    (BWN_READ_2(mac, BWN_PHYDATA) & mask) | set);
10949203945Sweongyo}
10950203945Sweongyo
10951203945Sweongyostatic uint16_t
10952203945Sweongyobwn_phy_lp_rf_read(struct bwn_mac *mac, uint16_t reg)
10953203945Sweongyo{
10954203945Sweongyo
10955203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
10956203945Sweongyo	if (mac->mac_phy.rev < 2 && reg != 0x4001)
10957203945Sweongyo		reg |= 0x100;
10958203945Sweongyo	if (mac->mac_phy.rev >= 2)
10959203945Sweongyo		reg |= 0x200;
10960203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
10961203945Sweongyo	return BWN_READ_2(mac, BWN_RFDATALO);
10962203945Sweongyo}
10963203945Sweongyo
10964203945Sweongyostatic void
10965203945Sweongyobwn_phy_lp_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
10966203945Sweongyo{
10967203945Sweongyo
10968203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
10969203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
10970203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
10971203945Sweongyo}
10972203945Sweongyo
10973203945Sweongyostatic void
10974203945Sweongyobwn_phy_lp_rf_onoff(struct bwn_mac *mac, int on)
10975203945Sweongyo{
10976203945Sweongyo
10977203945Sweongyo	if (on) {
10978203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xe0ff);
10979203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2,
10980203945Sweongyo		    (mac->mac_phy.rev >= 2) ? 0xf7f7 : 0xffe7);
10981203945Sweongyo		return;
10982203945Sweongyo	}
10983203945Sweongyo
10984203945Sweongyo	if (mac->mac_phy.rev >= 2) {
10985203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x83ff);
10986203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
10987203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0x80ff);
10988203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xdfff);
10989203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0808);
10990203945Sweongyo		return;
10991203945Sweongyo	}
10992203945Sweongyo
10993203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xe0ff);
10994203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
10995203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfcff);
10996203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0018);
10997203945Sweongyo}
10998203945Sweongyo
10999203945Sweongyostatic int
11000203945Sweongyobwn_phy_lp_switch_channel(struct bwn_mac *mac, uint32_t chan)
11001203945Sweongyo{
11002203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11003203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11004203945Sweongyo	int error;
11005203945Sweongyo
11006203945Sweongyo	if (phy->rf_ver == 0x2063) {
11007203945Sweongyo		error = bwn_phy_lp_b2063_switch_channel(mac, chan);
11008203945Sweongyo		if (error)
11009203945Sweongyo			return (error);
11010203945Sweongyo	} else {
11011203945Sweongyo		error = bwn_phy_lp_b2062_switch_channel(mac, chan);
11012203945Sweongyo		if (error)
11013203945Sweongyo			return (error);
11014203945Sweongyo		bwn_phy_lp_set_anafilter(mac, chan);
11015203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, ieee80211_ieee2mhz(chan, 0));
11016203945Sweongyo	}
11017203945Sweongyo
11018203945Sweongyo	plp->plp_chan = chan;
11019203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, chan);
11020203945Sweongyo	return (0);
11021203945Sweongyo}
11022203945Sweongyo
11023203945Sweongyostatic uint32_t
11024203945Sweongyobwn_phy_lp_get_default_chan(struct bwn_mac *mac)
11025203945Sweongyo{
11026203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11027203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11028203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11029203945Sweongyo
11030203945Sweongyo	return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36);
11031203945Sweongyo}
11032203945Sweongyo
11033203945Sweongyostatic void
11034203945Sweongyobwn_phy_lp_set_antenna(struct bwn_mac *mac, int antenna)
11035203945Sweongyo{
11036203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11037203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11038203945Sweongyo
11039203945Sweongyo	if (phy->rev >= 2 || antenna > BWN_ANTAUTO1)
11040203945Sweongyo		return;
11041203945Sweongyo
11042203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER);
11043203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffd, antenna & 0x2);
11044203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffe, antenna & 0x1);
11045203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_UCODE_ANTDIV_HELPER);
11046203945Sweongyo	plp->plp_antenna = antenna;
11047203945Sweongyo}
11048203945Sweongyo
11049203945Sweongyostatic void
11050203945Sweongyobwn_phy_lp_task_60s(struct bwn_mac *mac)
11051203945Sweongyo{
11052203945Sweongyo
11053203945Sweongyo	bwn_phy_lp_calib(mac);
11054203945Sweongyo}
11055203945Sweongyo
11056203945Sweongyostatic void
11057203945Sweongyobwn_phy_lp_readsprom(struct bwn_mac *mac)
11058203945Sweongyo{
11059203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11060203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11061203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11062203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11063203945Sweongyo
11064203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11065204922Sweongyo		plp->plp_txisoband_m = siba_sprom_get_tri2g(sc->sc_dev);
11066204922Sweongyo		plp->plp_bxarch = siba_sprom_get_bxa2g(sc->sc_dev);
11067204922Sweongyo		plp->plp_rxpwroffset = siba_sprom_get_rxpo2g(sc->sc_dev);
11068204922Sweongyo		plp->plp_rssivf = siba_sprom_get_rssismf2g(sc->sc_dev);
11069204922Sweongyo		plp->plp_rssivc = siba_sprom_get_rssismc2g(sc->sc_dev);
11070204922Sweongyo		plp->plp_rssigs = siba_sprom_get_rssisav2g(sc->sc_dev);
11071203945Sweongyo		return;
11072203945Sweongyo	}
11073203945Sweongyo
11074204922Sweongyo	plp->plp_txisoband_l = siba_sprom_get_tri5gl(sc->sc_dev);
11075204922Sweongyo	plp->plp_txisoband_m = siba_sprom_get_tri5g(sc->sc_dev);
11076204922Sweongyo	plp->plp_txisoband_h = siba_sprom_get_tri5gh(sc->sc_dev);
11077204922Sweongyo	plp->plp_bxarch = siba_sprom_get_bxa5g(sc->sc_dev);
11078204922Sweongyo	plp->plp_rxpwroffset = siba_sprom_get_rxpo5g(sc->sc_dev);
11079204922Sweongyo	plp->plp_rssivf = siba_sprom_get_rssismf5g(sc->sc_dev);
11080204922Sweongyo	plp->plp_rssivc = siba_sprom_get_rssismc5g(sc->sc_dev);
11081204922Sweongyo	plp->plp_rssigs = siba_sprom_get_rssisav5g(sc->sc_dev);
11082203945Sweongyo}
11083203945Sweongyo
11084203945Sweongyostatic void
11085203945Sweongyobwn_phy_lp_bbinit(struct bwn_mac *mac)
11086203945Sweongyo{
11087203945Sweongyo
11088203945Sweongyo	bwn_phy_lp_tblinit(mac);
11089203945Sweongyo	if (mac->mac_phy.rev >= 2)
11090203945Sweongyo		bwn_phy_lp_bbinit_r2(mac);
11091203945Sweongyo	else
11092203945Sweongyo		bwn_phy_lp_bbinit_r01(mac);
11093203945Sweongyo}
11094203945Sweongyo
11095203945Sweongyostatic void
11096203945Sweongyobwn_phy_lp_txpctl_init(struct bwn_mac *mac)
11097203945Sweongyo{
11098203945Sweongyo	struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 };
11099203945Sweongyo	struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 };
11100203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11101203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11102203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11103203945Sweongyo
11104203945Sweongyo	bwn_phy_lp_set_txgain(mac,
11105203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz);
11106203945Sweongyo	bwn_phy_lp_set_bbmult(mac, 150);
11107203945Sweongyo}
11108203945Sweongyo
11109203945Sweongyostatic void
11110203945Sweongyobwn_phy_lp_calib(struct bwn_mac *mac)
11111203945Sweongyo{
11112203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11113203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11114203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11115203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11116203945Sweongyo	const struct bwn_rxcompco *rc = NULL;
11117203945Sweongyo	struct bwn_txgain ogain;
11118203945Sweongyo	int i, omode, oafeovr, orf, obbmult;
11119203945Sweongyo	uint8_t mode, fc = 0;
11120203945Sweongyo
11121203945Sweongyo	if (plp->plp_chanfullcal != plp->plp_chan) {
11122203945Sweongyo		plp->plp_chanfullcal = plp->plp_chan;
11123203945Sweongyo		fc = 1;
11124203945Sweongyo	}
11125203945Sweongyo
11126203945Sweongyo	bwn_mac_suspend(mac);
11127203945Sweongyo
11128203945Sweongyo	/* BlueTooth Coexistance Override */
11129203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_CTL, 0x3);
11130203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_TXCTL, 0xff);
11131203945Sweongyo
11132203945Sweongyo	if (mac->mac_phy.rev >= 2)
11133203945Sweongyo		bwn_phy_lp_digflt_save(mac);
11134203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11135203945Sweongyo	mode = plp->plp_txpctlmode;
11136203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11137203945Sweongyo	if (mac->mac_phy.rev == 0 && mode != BWN_PHYLP_TXPCTL_OFF)
11138203945Sweongyo		bwn_phy_lp_bugfix(mac);
11139203945Sweongyo	if (mac->mac_phy.rev >= 2 && fc == 1) {
11140203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11141203945Sweongyo		omode = plp->plp_txpctlmode;
11142203945Sweongyo		oafeovr = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40;
11143203945Sweongyo		if (oafeovr)
11144203945Sweongyo			ogain = bwn_phy_lp_get_txgain(mac);
11145203945Sweongyo		orf = BWN_PHY_READ(mac, BWN_PHY_RF_PWR_OVERRIDE) & 0xff;
11146203945Sweongyo		obbmult = bwn_phy_lp_get_bbmult(mac);
11147203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11148203945Sweongyo		if (oafeovr)
11149203945Sweongyo			bwn_phy_lp_set_txgain(mac, &ogain);
11150203945Sweongyo		bwn_phy_lp_set_bbmult(mac, obbmult);
11151203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, omode);
11152203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00, orf);
11153203945Sweongyo	}
11154203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11155203945Sweongyo	if (mac->mac_phy.rev >= 2)
11156203945Sweongyo		bwn_phy_lp_digflt_restore(mac);
11157203945Sweongyo
11158203945Sweongyo	/* do RX IQ Calculation; assumes that noise is true. */
11159204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x5354) {
11160203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_5354); i++) {
11161203945Sweongyo			if (bwn_rxcompco_5354[i].rc_chan == plp->plp_chan)
11162203945Sweongyo				rc = &bwn_rxcompco_5354[i];
11163203945Sweongyo		}
11164203945Sweongyo	} else if (mac->mac_phy.rev >= 2)
11165203945Sweongyo		rc = &bwn_rxcompco_r2;
11166203945Sweongyo	else {
11167203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_r12); i++) {
11168203945Sweongyo			if (bwn_rxcompco_r12[i].rc_chan == plp->plp_chan)
11169203945Sweongyo				rc = &bwn_rxcompco_r12[i];
11170203945Sweongyo		}
11171203945Sweongyo	}
11172203945Sweongyo	if (rc == NULL)
11173203945Sweongyo		goto fail;
11174203945Sweongyo
11175203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, rc->rc_c1);
11176203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, rc->rc_c0 << 8);
11177203945Sweongyo
11178203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1 /* TX */, 0 /* RX */);
11179203945Sweongyo
11180203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11181203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
11182203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7, 0);
11183203945Sweongyo	} else {
11184203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
11185203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf, 0);
11186203945Sweongyo	}
11187203945Sweongyo
11188203945Sweongyo	bwn_phy_lp_set_rxgain(mac, 0x2d5d);
11189203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11190203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
11191203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
11192203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
11193203945Sweongyo	bwn_phy_lp_set_deaf(mac, 0);
11194203945Sweongyo	/* XXX no checking return value? */
11195203945Sweongyo	(void)bwn_phy_lp_calc_rx_iq_comp(mac, 0xfff0);
11196203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 0);
11197203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffc);
11198203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfff7);
11199203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffdf);
11200203945Sweongyo
11201203945Sweongyo	/* disable RX GAIN override. */
11202203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffe);
11203203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffef);
11204203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffbf);
11205203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11206203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11207203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11208203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfbff);
11209203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xe5), 0xfff7);
11210203945Sweongyo		}
11211203945Sweongyo	} else {
11212203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfdff);
11213203945Sweongyo	}
11214203945Sweongyo
11215203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11216203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xf7ff);
11217203945Sweongyofail:
11218203945Sweongyo	bwn_mac_enable(mac);
11219203945Sweongyo}
11220203945Sweongyo
11221203945Sweongyostatic void
11222203945Sweongyobwn_phy_lp_switch_analog(struct bwn_mac *mac, int on)
11223203945Sweongyo{
11224203945Sweongyo
11225204922Sweongyo	if (on) {
11226204922Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfff8);
11227204922Sweongyo		return;
11228204922Sweongyo	}
11229203945Sweongyo
11230204922Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVRVAL, 0x0007);
11231204922Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x0007);
11232203945Sweongyo}
11233203945Sweongyo
11234203945Sweongyostatic int
11235203945Sweongyobwn_phy_lp_b2063_switch_channel(struct bwn_mac *mac, uint8_t chan)
11236203945Sweongyo{
11237203945Sweongyo	static const struct bwn_b206x_chan *bc = NULL;
11238204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11239203945Sweongyo	uint32_t count, freqref, freqvco, freqxtal, val[3], timeout, timeoutref,
11240203945Sweongyo	    tmp[6];
11241203945Sweongyo	uint16_t old, scale, tmp16;
11242203945Sweongyo	int i, div;
11243203945Sweongyo
11244203945Sweongyo	for (i = 0; i < N(bwn_b2063_chantable); i++) {
11245203945Sweongyo		if (bwn_b2063_chantable[i].bc_chan == chan) {
11246203945Sweongyo			bc = &bwn_b2063_chantable[i];
11247203945Sweongyo			break;
11248203945Sweongyo		}
11249203945Sweongyo	}
11250203945Sweongyo	if (bc == NULL)
11251203945Sweongyo		return (EINVAL);
11252203945Sweongyo
11253203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_VCOBUF1, bc->bc_data[0]);
11254203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_MIXER2, bc->bc_data[1]);
11255203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_BUF2, bc->bc_data[2]);
11256203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_RCCR1, bc->bc_data[3]);
11257203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_1ST3, bc->bc_data[4]);
11258203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND1, bc->bc_data[5]);
11259203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND4, bc->bc_data[6]);
11260203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND7, bc->bc_data[7]);
11261203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_PS6, bc->bc_data[8]);
11262203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL2, bc->bc_data[9]);
11263203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL5, bc->bc_data[10]);
11264203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_CTL11, bc->bc_data[11]);
11265203945Sweongyo
11266203945Sweongyo	old = BWN_RF_READ(mac, BWN_B2063_COM15);
11267203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM15, 0x1e);
11268203945Sweongyo
11269204922Sweongyo	freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
11270203945Sweongyo	freqvco = bc->bc_freq << ((bc->bc_freq > 4000) ? 1 : 2);
11271203945Sweongyo	freqref = freqxtal * 3;
11272203945Sweongyo	div = (freqxtal <= 26000000 ? 1 : 2);
11273203945Sweongyo	timeout = ((((8 * freqxtal) / (div * 5000000)) + 1) >> 1) - 1;
11274203945Sweongyo	timeoutref = ((((8 * freqxtal) / (div * (timeout + 1))) +
11275203945Sweongyo		999999) / 1000000) + 1;
11276203945Sweongyo
11277203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB3, 0x2);
11278203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB6,
11279203945Sweongyo	    0xfff8, timeout >> 2);
11280203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11281203945Sweongyo	    0xff9f,timeout << 5);
11282203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB5, timeoutref);
11283203945Sweongyo
11284203945Sweongyo	val[0] = bwn_phy_lp_roundup(freqxtal, 1000000, 16);
11285203945Sweongyo	val[1] = bwn_phy_lp_roundup(freqxtal, 1000000 * div, 16);
11286203945Sweongyo	val[2] = bwn_phy_lp_roundup(freqvco, 3, 16);
11287203945Sweongyo
11288203945Sweongyo	count = (bwn_phy_lp_roundup(val[2], val[1] + 16, 16) * (timeout + 1) *
11289203945Sweongyo	    (timeoutref + 1)) - 1;
11290203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11291203945Sweongyo	    0xf0, count >> 8);
11292203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB8, count & 0xff);
11293203945Sweongyo
11294203945Sweongyo	tmp[0] = ((val[2] * 62500) / freqref) << 4;
11295203945Sweongyo	tmp[1] = ((val[2] * 62500) % freqref) << 4;
11296203945Sweongyo	while (tmp[1] >= freqref) {
11297203945Sweongyo		tmp[0]++;
11298203945Sweongyo		tmp[1] -= freqref;
11299203945Sweongyo	}
11300203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG1, 0xffe0, tmp[0] >> 4);
11301203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfe0f, tmp[0] << 4);
11302203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfff0, tmp[0] >> 16);
11303203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG3, (tmp[1] >> 8) & 0xff);
11304203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG4, tmp[1] & 0xff);
11305203945Sweongyo
11306203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF1, 0xb9);
11307203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF2, 0x88);
11308203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF3, 0x28);
11309203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF4, 0x63);
11310203945Sweongyo
11311203945Sweongyo	tmp[2] = ((41 * (val[2] - 3000)) /1200) + 27;
11312203945Sweongyo	tmp[3] = bwn_phy_lp_roundup(132000 * tmp[0], 8451, 16);
11313203945Sweongyo
11314203945Sweongyo	if ((tmp[3] + tmp[2] - 1) / tmp[2] > 60) {
11315203945Sweongyo		scale = 1;
11316203945Sweongyo		tmp[4] = ((tmp[3] + tmp[2]) / (tmp[2] << 1)) - 8;
11317203945Sweongyo	} else {
11318203945Sweongyo		scale = 0;
11319203945Sweongyo		tmp[4] = ((tmp[3] + (tmp[2] >> 1)) / tmp[2]) - 8;
11320203945Sweongyo	}
11321203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffc0, tmp[4]);
11322203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffbf, scale << 6);
11323203945Sweongyo
11324203945Sweongyo	tmp[5] = bwn_phy_lp_roundup(100 * val[0], val[2], 16) * (tmp[4] * 8) *
11325203945Sweongyo	    (scale + 1);
11326203945Sweongyo	if (tmp[5] > 150)
11327203945Sweongyo		tmp[5] = 0;
11328203945Sweongyo
11329203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffe0, tmp[5]);
11330203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffdf, scale << 5);
11331203945Sweongyo
11332203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfffb, 0x4);
11333203945Sweongyo	if (freqxtal > 26000000)
11334203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_XTAL_12, 0x2);
11335203945Sweongyo	else
11336203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfd);
11337203945Sweongyo
11338203945Sweongyo	if (val[0] == 45)
11339203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_VCO1, 0x2);
11340203945Sweongyo	else
11341203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_VCO1, 0xfd);
11342203945Sweongyo
11343203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP2, 0x3);
11344203945Sweongyo	DELAY(1);
11345203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP2, 0xfffc);
11346203945Sweongyo
11347203945Sweongyo	/* VCO Calibration */
11348203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, ~0x40);
11349203945Sweongyo	tmp16 = BWN_RF_READ(mac, BWN_B2063_JTAG_CALNRST) & 0xf8;
11350203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16);
11351203945Sweongyo	DELAY(1);
11352203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x4);
11353203945Sweongyo	DELAY(1);
11354203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x6);
11355203945Sweongyo	DELAY(1);
11356203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x7);
11357203945Sweongyo	DELAY(300);
11358203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP1, 0x40);
11359203945Sweongyo
11360203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_COM15, old);
11361203945Sweongyo	return (0);
11362203945Sweongyo}
11363203945Sweongyo
11364203945Sweongyostatic int
11365203945Sweongyobwn_phy_lp_b2062_switch_channel(struct bwn_mac *mac, uint8_t chan)
11366203945Sweongyo{
11367204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11368203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11369203945Sweongyo	const struct bwn_b206x_chan *bc = NULL;
11370204922Sweongyo	uint32_t freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
11371203945Sweongyo	uint32_t tmp[9];
11372203945Sweongyo	int i;
11373203945Sweongyo
11374203945Sweongyo	for (i = 0; i < N(bwn_b2062_chantable); i++) {
11375203945Sweongyo		if (bwn_b2062_chantable[i].bc_chan == chan) {
11376203945Sweongyo			bc = &bwn_b2062_chantable[i];
11377203945Sweongyo			break;
11378203945Sweongyo		}
11379203945Sweongyo	}
11380203945Sweongyo
11381203945Sweongyo	if (bc == NULL)
11382203945Sweongyo		return (EINVAL);
11383203945Sweongyo
11384203945Sweongyo	BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL14, 0x04);
11385203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE0, bc->bc_data[0]);
11386203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE2, bc->bc_data[1]);
11387203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE3, bc->bc_data[2]);
11388203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_TUNE, bc->bc_data[3]);
11389203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_LGENG_CTL1, bc->bc_data[4]);
11390203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL5, bc->bc_data[5]);
11391203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL6, bc->bc_data[6]);
11392203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PGA, bc->bc_data[7]);
11393203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PAD, bc->bc_data[8]);
11394203945Sweongyo
11395203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xcc);
11396203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0x07);
11397203945Sweongyo	bwn_phy_lp_b2062_reset_pllbias(mac);
11398203945Sweongyo	tmp[0] = freqxtal / 1000;
11399203945Sweongyo	tmp[1] = plp->plp_div * 1000;
11400203945Sweongyo	tmp[2] = tmp[1] * ieee80211_ieee2mhz(chan, 0);
11401203945Sweongyo	if (ieee80211_ieee2mhz(chan, 0) < 4000)
11402203945Sweongyo		tmp[2] *= 2;
11403203945Sweongyo	tmp[3] = 48 * tmp[0];
11404203945Sweongyo	tmp[5] = tmp[2] / tmp[3];
11405203945Sweongyo	tmp[6] = tmp[2] % tmp[3];
11406203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL26, tmp[5]);
11407203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11408203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11409203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11410203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL27, tmp[5]);
11411203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11412203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11413203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11414203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL28, 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_RFPLLCTL29,
11419203945Sweongyo	    tmp[5] + ((2 * tmp[6]) / tmp[3]));
11420203945Sweongyo	tmp[7] = BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL19);
11421203945Sweongyo	tmp[8] = ((2 * tmp[2] * (tmp[7] + 1)) + (3 * tmp[0])) / (6 * tmp[0]);
11422203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL23, (tmp[8] >> 8) + 16);
11423203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL24, tmp[8] & 0xff);
11424203945Sweongyo
11425203945Sweongyo	bwn_phy_lp_b2062_vco_calib(mac);
11426203945Sweongyo	if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11427203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xfc);
11428203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0);
11429203945Sweongyo		bwn_phy_lp_b2062_reset_pllbias(mac);
11430203945Sweongyo		bwn_phy_lp_b2062_vco_calib(mac);
11431203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11432203945Sweongyo			BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11433203945Sweongyo			return (EIO);
11434203945Sweongyo		}
11435203945Sweongyo	}
11436203945Sweongyo	BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11437203945Sweongyo	return (0);
11438203945Sweongyo}
11439203945Sweongyo
11440203945Sweongyostatic void
11441203945Sweongyobwn_phy_lp_set_anafilter(struct bwn_mac *mac, uint8_t channel)
11442203945Sweongyo{
11443203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11444203945Sweongyo	uint16_t tmp = (channel == 14);
11445203945Sweongyo
11446203945Sweongyo	if (mac->mac_phy.rev < 2) {
11447203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xfcff, tmp << 9);
11448203945Sweongyo		if ((mac->mac_phy.rev == 1) && (plp->plp_rccap))
11449203945Sweongyo			bwn_phy_lp_set_rccap(mac);
11450203945Sweongyo		return;
11451203945Sweongyo	}
11452203945Sweongyo
11453203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, 0x3f);
11454203945Sweongyo}
11455203945Sweongyo
11456203945Sweongyostatic void
11457203945Sweongyobwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq)
11458203945Sweongyo{
11459203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11460203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11461203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11462203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11463203945Sweongyo	uint16_t iso, tmp[3];
11464203945Sweongyo
11465203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
11466203945Sweongyo
11467203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
11468203945Sweongyo		iso = plp->plp_txisoband_m;
11469203945Sweongyo	else if (freq <= 5320)
11470203945Sweongyo		iso = plp->plp_txisoband_l;
11471203945Sweongyo	else if (freq <= 5700)
11472203945Sweongyo		iso = plp->plp_txisoband_m;
11473203945Sweongyo	else
11474203945Sweongyo		iso = plp->plp_txisoband_h;
11475203945Sweongyo
11476203945Sweongyo	tmp[0] = ((iso - 26) / 12) << 12;
11477203945Sweongyo	tmp[1] = tmp[0] + 0x1000;
11478203945Sweongyo	tmp[2] = tmp[0] + 0x2000;
11479203945Sweongyo
11480203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), 3, tmp);
11481203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), 3, tmp);
11482203945Sweongyo}
11483203945Sweongyo
11484203945Sweongyostatic void
11485203945Sweongyobwn_phy_lp_digflt_save(struct bwn_mac *mac)
11486203945Sweongyo{
11487203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11488203945Sweongyo	int i;
11489203945Sweongyo	static const uint16_t addr[] = {
11490203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11491203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11492203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11493203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11494203945Sweongyo		BWN_PHY_OFDM(0xcf),
11495203945Sweongyo	};
11496203945Sweongyo	static const uint16_t val[] = {
11497203945Sweongyo		0xde5e, 0xe832, 0xe331, 0x4d26,
11498203945Sweongyo		0x0026, 0x1420, 0x0020, 0xfe08,
11499203945Sweongyo		0x0008,
11500203945Sweongyo	};
11501203945Sweongyo
11502203945Sweongyo	for (i = 0; i < N(addr); i++) {
11503203945Sweongyo		plp->plp_digfilt[i] = BWN_PHY_READ(mac, addr[i]);
11504203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], val[i]);
11505203945Sweongyo	}
11506203945Sweongyo}
11507203945Sweongyo
11508203945Sweongyostatic void
11509203945Sweongyobwn_phy_lp_get_txpctlmode(struct bwn_mac *mac)
11510203945Sweongyo{
11511203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11512203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11513203945Sweongyo	uint16_t ctl;
11514203945Sweongyo
11515203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_TX_PWR_CTL_CMD);
11516203945Sweongyo	switch (ctl & BWN_PHY_TX_PWR_CTL_CMD_MODE) {
11517203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF:
11518203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_OFF;
11519203945Sweongyo		break;
11520203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_SW:
11521203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_SW;
11522203945Sweongyo		break;
11523203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_HW:
11524203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_HW;
11525203945Sweongyo		break;
11526203945Sweongyo	default:
11527203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_UNKNOWN;
11528203945Sweongyo		device_printf(sc->sc_dev, "unknown command mode\n");
11529203945Sweongyo		break;
11530203945Sweongyo	}
11531203945Sweongyo}
11532203945Sweongyo
11533203945Sweongyostatic void
11534203945Sweongyobwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
11535203945Sweongyo{
11536203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11537203945Sweongyo	uint16_t ctl;
11538203945Sweongyo	uint8_t old;
11539203945Sweongyo
11540203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11541203945Sweongyo	old = plp->plp_txpctlmode;
11542203945Sweongyo	if (old == mode)
11543203945Sweongyo		return;
11544203945Sweongyo	plp->plp_txpctlmode = mode;
11545203945Sweongyo
11546203945Sweongyo	if (old != BWN_PHYLP_TXPCTL_ON_HW && mode == BWN_PHYLP_TXPCTL_ON_HW) {
11547203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD, 0xff80,
11548203945Sweongyo		    plp->plp_tssiidx);
11549203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_NNUM,
11550203945Sweongyo		    0x8fff, ((uint16_t)plp->plp_tssinpt << 16));
11551203945Sweongyo
11552203945Sweongyo		/* disable TX GAIN override */
11553203945Sweongyo		if (mac->mac_phy.rev < 2)
11554203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11555203945Sweongyo		else {
11556203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xff7f);
11557203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xbfff);
11558203945Sweongyo		}
11559203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xffbf);
11560203945Sweongyo
11561203945Sweongyo		plp->plp_txpwridx = -1;
11562203945Sweongyo	}
11563203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11564203945Sweongyo		if (mode == BWN_PHYLP_TXPCTL_ON_HW)
11565203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xd0), 0x2);
11566203945Sweongyo		else
11567203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xd0), 0xfffd);
11568203945Sweongyo	}
11569203945Sweongyo
11570203945Sweongyo	/* writes TX Power Control mode */
11571203945Sweongyo	switch (plp->plp_txpctlmode) {
11572203945Sweongyo	case BWN_PHYLP_TXPCTL_OFF:
11573203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF;
11574203945Sweongyo		break;
11575203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_HW:
11576203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_HW;
11577203945Sweongyo		break;
11578203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_SW:
11579203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
11580203945Sweongyo		break;
11581203945Sweongyo	default:
11582204242Simp		ctl = 0;
11583203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
11584203945Sweongyo	}
11585203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
11586203945Sweongyo	    (uint16_t)~BWN_PHY_TX_PWR_CTL_CMD_MODE, ctl);
11587203945Sweongyo}
11588203945Sweongyo
11589203945Sweongyostatic void
11590203945Sweongyobwn_phy_lp_bugfix(struct bwn_mac *mac)
11591203945Sweongyo{
11592203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11593203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11594203945Sweongyo	const unsigned int size = 256;
11595203945Sweongyo	struct bwn_txgain tg;
11596203945Sweongyo	uint32_t rxcomp, txgain, coeff, rfpwr, *tabs;
11597203945Sweongyo	uint16_t tssinpt, tssiidx, value[2];
11598203945Sweongyo	uint8_t mode;
11599203945Sweongyo	int8_t txpwridx;
11600203945Sweongyo
11601203945Sweongyo	tabs = (uint32_t *)malloc(sizeof(uint32_t) * size, M_DEVBUF,
11602203945Sweongyo	    M_NOWAIT | M_ZERO);
11603203945Sweongyo	if (tabs == NULL) {
11604203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer.\n");
11605203945Sweongyo		return;
11606203945Sweongyo	}
11607203945Sweongyo
11608203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11609203945Sweongyo	mode = plp->plp_txpctlmode;
11610203945Sweongyo	txpwridx = plp->plp_txpwridx;
11611203945Sweongyo	tssinpt = plp->plp_tssinpt;
11612203945Sweongyo	tssiidx = plp->plp_tssiidx;
11613203945Sweongyo
11614203945Sweongyo	bwn_tab_read_multi(mac,
11615203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11616203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11617203945Sweongyo
11618203945Sweongyo	bwn_phy_lp_tblinit(mac);
11619203945Sweongyo	bwn_phy_lp_bbinit(mac);
11620203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
11621203945Sweongyo	bwn_phy_lp_rf_onoff(mac, 1);
11622203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11623203945Sweongyo
11624203945Sweongyo	bwn_tab_write_multi(mac,
11625203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11626203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11627203945Sweongyo
11628203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, plp->plp_chan);
11629203945Sweongyo	plp->plp_tssinpt = tssinpt;
11630203945Sweongyo	plp->plp_tssiidx = tssiidx;
11631203945Sweongyo	bwn_phy_lp_set_anafilter(mac, plp->plp_chan);
11632203945Sweongyo	if (txpwridx != -1) {
11633203945Sweongyo		/* set TX power by index */
11634203945Sweongyo		plp->plp_txpwridx = txpwridx;
11635203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11636203945Sweongyo		if (plp->plp_txpctlmode != BWN_PHYLP_TXPCTL_OFF)
11637203945Sweongyo			bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_ON_SW);
11638203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11639203945Sweongyo			rxcomp = bwn_tab_read(mac,
11640203945Sweongyo			    BWN_TAB_4(7, txpwridx + 320));
11641203945Sweongyo			txgain = bwn_tab_read(mac,
11642203945Sweongyo			    BWN_TAB_4(7, txpwridx + 192));
11643203945Sweongyo			tg.tg_pad = (txgain >> 16) & 0xff;
11644203945Sweongyo			tg.tg_gm = txgain & 0xff;
11645203945Sweongyo			tg.tg_pga = (txgain >> 8) & 0xff;
11646203945Sweongyo			tg.tg_dac = (rxcomp >> 28) & 0xff;
11647203945Sweongyo			bwn_phy_lp_set_txgain(mac, &tg);
11648203945Sweongyo		} else {
11649203945Sweongyo			rxcomp = bwn_tab_read(mac,
11650203945Sweongyo			    BWN_TAB_4(10, txpwridx + 320));
11651203945Sweongyo			txgain = bwn_tab_read(mac,
11652203945Sweongyo			    BWN_TAB_4(10, txpwridx + 192));
11653203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
11654203945Sweongyo			    0xf800, (txgain >> 4) & 0x7fff);
11655203945Sweongyo			bwn_phy_lp_set_txgain_dac(mac, txgain & 0x7);
11656203945Sweongyo			bwn_phy_lp_set_txgain_pa(mac, (txgain >> 24) & 0x7f);
11657203945Sweongyo		}
11658203945Sweongyo		bwn_phy_lp_set_bbmult(mac, (rxcomp >> 20) & 0xff);
11659203945Sweongyo
11660203945Sweongyo		/* set TX IQCC */
11661203945Sweongyo		value[0] = (rxcomp >> 10) & 0x3ff;
11662203945Sweongyo		value[1] = rxcomp & 0x3ff;
11663203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(0, 80), 2, value);
11664203945Sweongyo
11665203945Sweongyo		coeff = bwn_tab_read(mac,
11666203945Sweongyo		    (mac->mac_phy.rev >= 2) ? BWN_TAB_4(7, txpwridx + 448) :
11667203945Sweongyo		    BWN_TAB_4(10, txpwridx + 448));
11668203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0, 85), coeff & 0xffff);
11669203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11670203945Sweongyo			rfpwr = bwn_tab_read(mac,
11671203945Sweongyo			    BWN_TAB_4(7, txpwridx + 576));
11672203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00,
11673203945Sweongyo			    rfpwr & 0xffff);
11674203945Sweongyo		}
11675203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
11676203945Sweongyo	}
11677203945Sweongyo	if (plp->plp_rccap)
11678203945Sweongyo		bwn_phy_lp_set_rccap(mac);
11679203945Sweongyo	bwn_phy_lp_set_antenna(mac, plp->plp_antenna);
11680203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11681203945Sweongyo	free(tabs, M_DEVBUF);
11682203945Sweongyo}
11683203945Sweongyo
11684203945Sweongyostatic void
11685203945Sweongyobwn_phy_lp_digflt_restore(struct bwn_mac *mac)
11686203945Sweongyo{
11687203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11688203945Sweongyo	int i;
11689203945Sweongyo	static const uint16_t addr[] = {
11690203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11691203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11692203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11693203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11694203945Sweongyo		BWN_PHY_OFDM(0xcf),
11695203945Sweongyo	};
11696203945Sweongyo
11697203945Sweongyo	for (i = 0; i < N(addr); i++)
11698203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], plp->plp_digfilt[i]);
11699203945Sweongyo}
11700203945Sweongyo
11701203945Sweongyostatic void
11702203945Sweongyobwn_phy_lp_tblinit(struct bwn_mac *mac)
11703203945Sweongyo{
11704203945Sweongyo	uint32_t freq = ieee80211_ieee2mhz(bwn_phy_lp_get_default_chan(mac), 0);
11705203945Sweongyo
11706203945Sweongyo	if (mac->mac_phy.rev < 2) {
11707203945Sweongyo		bwn_phy_lp_tblinit_r01(mac);
11708203945Sweongyo		bwn_phy_lp_tblinit_txgain(mac);
11709203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, freq);
11710203945Sweongyo		return;
11711203945Sweongyo	}
11712203945Sweongyo
11713203945Sweongyo	bwn_phy_lp_tblinit_r2(mac);
11714203945Sweongyo	bwn_phy_lp_tblinit_txgain(mac);
11715203945Sweongyo}
11716203945Sweongyo
11717203945Sweongyostruct bwn_wpair {
11718203945Sweongyo	uint16_t		reg;
11719203945Sweongyo	uint16_t		value;
11720203945Sweongyo};
11721203945Sweongyo
11722203945Sweongyostruct bwn_smpair {
11723203945Sweongyo	uint16_t		offset;
11724203945Sweongyo	uint16_t		mask;
11725203945Sweongyo	uint16_t		set;
11726203945Sweongyo};
11727203945Sweongyo
11728203945Sweongyostatic void
11729203945Sweongyobwn_phy_lp_bbinit_r2(struct bwn_mac *mac)
11730203945Sweongyo{
11731203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11732203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11733203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11734203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11735203945Sweongyo	static const struct bwn_wpair v1[] = {
11736203945Sweongyo		{ BWN_PHY_AFE_DAC_CTL, 0x50 },
11737203945Sweongyo		{ BWN_PHY_AFE_CTL, 0x8800 },
11738203945Sweongyo		{ BWN_PHY_AFE_CTL_OVR, 0 },
11739203945Sweongyo		{ BWN_PHY_AFE_CTL_OVRVAL, 0 },
11740203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_0, 0 },
11741203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_2, 0 },
11742203945Sweongyo		{ BWN_PHY_OFDM(0xf9), 0 },
11743203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0 }
11744203945Sweongyo	};
11745203945Sweongyo	static const struct bwn_smpair v2[] = {
11746203945Sweongyo		{ BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0xb4 },
11747203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xf8ff, 0x200 },
11748203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xff00, 0x7f },
11749203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xff0f, 0x40 },
11750203945Sweongyo		{ BWN_PHY_PREAMBLECONFIRMTO, 0xff00, 0x2 }
11751203945Sweongyo	};
11752203945Sweongyo	static const struct bwn_smpair v3[] = {
11753203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xffe0, 0x1f },
11754203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11755203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0xff00, 0x19 },
11756203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0x03ff, 0x3c00 },
11757203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xfc1f, 0x3e0 },
11758203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11759203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0x00ff, 0x1900 },
11760203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800 },
11761203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x12 },
11762203945Sweongyo		{ BWN_PHY_GAINMISMATCH, 0x0fff, 0x9000 },
11763204922Sweongyo
11764203945Sweongyo	};
11765203945Sweongyo	int i;
11766203945Sweongyo
11767203945Sweongyo	for (i = 0; i < N(v1); i++)
11768203945Sweongyo		BWN_PHY_WRITE(mac, v1[i].reg, v1[i].value);
11769203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x10);
11770203945Sweongyo	for (i = 0; i < N(v2); i++)
11771203945Sweongyo		BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask, v2[i].set);
11772203945Sweongyo
11773203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x4000);
11774203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x2000);
11775203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_OFDM(0x10a), 0x1);
11776204922Sweongyo	if (siba_get_pci_revid(sc->sc_dev) >= 0x18) {
11777203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(17, 65), 0xec);
11778203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x14);
11779203945Sweongyo	} else {
11780203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x10);
11781203945Sweongyo	}
11782203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0xff00, 0xf4);
11783203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0x00ff, 0xf100);
11784203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CLIPTHRESH, 0x48);
11785203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0xff00, 0x46);
11786203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe4), 0xff00, 0x10);
11787203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_PWR_THRESH1, 0xfff0, 0x9);
11788203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_GAINDIRECTMISMATCH, ~0xf);
11789203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5500);
11790203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0xa0);
11791203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_GAINDIRECTMISMATCH, 0xe0ff, 0x300);
11792203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2a00);
11793204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11794204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11795203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11796203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xa);
11797203945Sweongyo	} else {
11798203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x1e00);
11799203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xd);
11800203945Sweongyo	}
11801203945Sweongyo	for (i = 0; i < N(v3); i++)
11802203945Sweongyo		BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask, v3[i].set);
11803204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11804204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11805203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x14), 0);
11806203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x12), 0x40);
11807203945Sweongyo	}
11808203945Sweongyo
11809203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11810203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x40);
11811203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0xb00);
11812203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x6);
11813203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0x9d00);
11814203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0xff00, 0xa1);
11815203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11816203945Sweongyo	} else
11817203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x40);
11818203945Sweongyo
11819203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0xff00, 0xb3);
11820203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00);
11821203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB, 0xff00, plp->plp_rxpwroffset);
11822203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RESET_CTL, 0x44);
11823203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RESET_CTL, 0x80);
11824203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, 0xa954);
11825203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_1,
11826203945Sweongyo	    0x2000 | ((uint16_t)plp->plp_rssigs << 10) |
11827203945Sweongyo	    ((uint16_t)plp->plp_rssivc << 4) | plp->plp_rssivf);
11828203945Sweongyo
11829204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11830204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11831203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_AFE_ADC_CTL_0, 0x1c);
11832203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_CTL, 0x00ff, 0x8800);
11833203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_1, 0xfc3c, 0x0400);
11834203945Sweongyo	}
11835203945Sweongyo
11836203945Sweongyo	bwn_phy_lp_digflt_save(mac);
11837203945Sweongyo}
11838203945Sweongyo
11839203945Sweongyostatic void
11840203945Sweongyobwn_phy_lp_bbinit_r01(struct bwn_mac *mac)
11841203945Sweongyo{
11842203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11843203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11844203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11845203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11846203945Sweongyo	static const struct bwn_smpair v1[] = {
11847203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 },
11848203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 },
11849203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x3c00 },
11850203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xfff0, 0x0005 },
11851203945Sweongyo		{ BWN_PHY_GAIN_MISMATCH_LIMIT, 0xffc0, 0x001a },
11852203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0xff00, 0x00b3 },
11853203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00 }
11854203945Sweongyo	};
11855203945Sweongyo	static const struct bwn_smpair v2[] = {
11856203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11857203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0x3f00, 0x0900 },
11858203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11859203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11860203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x000a },
11861203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0400 },
11862203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x000a },
11863203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0b00 },
11864203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xffc0, 0x000a },
11865203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xc0ff, 0x0900 },
11866203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xffc0, 0x000a },
11867203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xc0ff, 0x0b00 },
11868203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xffc0, 0x000a },
11869203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xc0ff, 0x0900 },
11870203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xffc0, 0x000a },
11871203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xc0ff, 0x0b00 }
11872203945Sweongyo	};
11873203945Sweongyo	static const struct bwn_smpair v3[] = {
11874203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0001 },
11875203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0400 },
11876203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0001 },
11877203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0500 },
11878203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11879203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0800 },
11880203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11881203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0a00 }
11882203945Sweongyo	};
11883203945Sweongyo	static const struct bwn_smpair v4[] = {
11884203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0004 },
11885203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0800 },
11886203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0004 },
11887203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0c00 },
11888203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11889203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0100 },
11890203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11891203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0300 }
11892203945Sweongyo	};
11893203945Sweongyo	static const struct bwn_smpair v5[] = {
11894203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11895203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0900 },
11896203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11897203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11898203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0006 },
11899203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0500 },
11900203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0006 },
11901203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0700 }
11902203945Sweongyo	};
11903203945Sweongyo	int i;
11904203945Sweongyo	uint16_t tmp, tmp2;
11905203945Sweongyo
11906203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf7ff);
11907203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL, 0);
11908203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, 0);
11909203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, 0);
11910203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0);
11911203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DAC_CTL, 0x0004);
11912203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0x0078);
11913203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800);
11914203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x0016);
11915203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_0, 0xfff8, 0x0004);
11916203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5400);
11917203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2400);
11918203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11919203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0x0006);
11920203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_RADIO_CTL, 0xfffe);
11921203945Sweongyo	for (i = 0; i < N(v1); i++)
11922203945Sweongyo		BWN_PHY_SETMASK(mac, v1[i].offset, v1[i].mask, v1[i].set);
11923203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB,
11924203945Sweongyo	    0xff00, plp->plp_rxpwroffset);
11925204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) &&
11926203945Sweongyo	    ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
11927204922Sweongyo	   (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_PAREF))) {
11928204922Sweongyo		siba_cc_pmu_set_ldovolt(sc->sc_dev, SIBA_LDO_PAREF, 0x28);
11929204922Sweongyo		siba_cc_pmu_set_ldoparef(sc->sc_dev, 1);
11930203945Sweongyo		if (mac->mac_phy.rev == 0)
11931203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT,
11932203945Sweongyo			    0xffcf, 0x0010);
11933203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 60);
11934203945Sweongyo	} else {
11935204922Sweongyo		siba_cc_pmu_set_ldoparef(sc->sc_dev, 0);
11936203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT, 0xffcf, 0x0020);
11937203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 100);
11938203945Sweongyo	}
11939203945Sweongyo	tmp = plp->plp_rssivf | plp->plp_rssivc << 4 | 0xa000;
11940203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, tmp);
11941204922Sweongyo	if (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_RSSIINV)
11942203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x0aaa);
11943203945Sweongyo	else
11944203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x02aa);
11945203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(11, 1), 24);
11946203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_RADIO_CTL,
11947203945Sweongyo	    0xfff9, (plp->plp_bxarch << 1));
11948203945Sweongyo	if (mac->mac_phy.rev == 1 &&
11949204922Sweongyo	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_FEM_BT)) {
11950203945Sweongyo		for (i = 0; i < N(v2); i++)
11951203945Sweongyo			BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask,
11952203945Sweongyo			    v2[i].set);
11953203945Sweongyo	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ||
11954204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) == 0x048a) ||
11955204922Sweongyo	    ((mac->mac_phy.rev == 0) &&
11956204922Sweongyo	     (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM))) {
11957203945Sweongyo		for (i = 0; i < N(v3); i++)
11958203945Sweongyo			BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask,
11959203945Sweongyo			    v3[i].set);
11960203945Sweongyo	} else if (mac->mac_phy.rev == 1 ||
11961204922Sweongyo		  (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM)) {
11962203945Sweongyo		for (i = 0; i < N(v4); i++)
11963203945Sweongyo			BWN_PHY_SETMASK(mac, v4[i].offset, v4[i].mask,
11964203945Sweongyo			    v4[i].set);
11965203945Sweongyo	} else {
11966203945Sweongyo		for (i = 0; i < N(v5); i++)
11967203945Sweongyo			BWN_PHY_SETMASK(mac, v5[i].offset, v5[i].mask,
11968203945Sweongyo			    v5[i].set);
11969203945Sweongyo	}
11970203945Sweongyo	if (mac->mac_phy.rev == 1 &&
11971204922Sweongyo	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_PAREF)) {
11972203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_5, BWN_PHY_TR_LOOKUP_1);
11973203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_6, BWN_PHY_TR_LOOKUP_2);
11974203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_7, BWN_PHY_TR_LOOKUP_3);
11975203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_8, BWN_PHY_TR_LOOKUP_4);
11976203945Sweongyo	}
11977204922Sweongyo	if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_FEM_BT) &&
11978204922Sweongyo	    (siba_get_chipid(sc->sc_dev) == 0x5354) &&
11979204922Sweongyo	    (siba_get_chippkg(sc->sc_dev) == SIBA_CHIPPACK_BCM4712S)) {
11980203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0006);
11981203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_SELECT, 0x0005);
11982203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_OUTEN, 0xffff);
11983203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_PR45960W);
11984203945Sweongyo	}
11985203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11986203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x8000);
11987203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0040);
11988203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0xa400);
11989203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0x0b00);
11990203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x0007);
11991203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xfff8, 0x0003);
11992203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xffc7, 0x0020);
11993203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11994203945Sweongyo	} else {
11995203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0x7fff);
11996203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xffbf);
11997203945Sweongyo	}
11998203945Sweongyo	if (mac->mac_phy.rev == 1) {
11999203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_CLIPCTRTHRESH);
12000203945Sweongyo		tmp2 = (tmp & 0x03e0) >> 5;
12001203945Sweongyo		tmp2 |= tmp2 << 5;
12002203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C3, tmp2);
12003203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_GAINDIRECTMISMATCH);
12004203945Sweongyo		tmp2 = (tmp & 0x1f00) >> 8;
12005203945Sweongyo		tmp2 |= tmp2 << 5;
12006203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C4, tmp2);
12007203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERYLOWGAINDB);
12008203945Sweongyo		tmp2 = tmp & 0x00ff;
12009203945Sweongyo		tmp2 |= tmp << 8;
12010203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C5, tmp2);
12011203945Sweongyo	}
12012203945Sweongyo}
12013203945Sweongyo
12014203945Sweongyostruct bwn_b2062_freq {
12015203945Sweongyo	uint16_t		freq;
12016203945Sweongyo	uint8_t			value[6];
12017203945Sweongyo};
12018203945Sweongyo
12019203945Sweongyostatic void
12020203945Sweongyobwn_phy_lp_b2062_init(struct bwn_mac *mac)
12021203945Sweongyo{
12022203945Sweongyo#define	CALC_CTL7(freq, div)						\
12023203945Sweongyo	(((800000000 * (div) + (freq)) / (2 * (freq)) - 8) & 0xff)
12024203945Sweongyo#define	CALC_CTL18(freq, div)						\
12025203945Sweongyo	((((100 * (freq) + 16000000 * (div)) / (32000000 * (div))) - 1) & 0xff)
12026203945Sweongyo#define	CALC_CTL19(freq, div)						\
12027203945Sweongyo	((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff)
12028203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12029203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12030203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12031203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12032203945Sweongyo	static const struct bwn_b2062_freq freqdata_tab[] = {
12033203945Sweongyo		{ 12000, { 6, 6, 6, 6, 10, 6 } },
12034203945Sweongyo		{ 13000, { 4, 4, 4, 4, 11, 7 } },
12035203945Sweongyo		{ 14400, { 3, 3, 3, 3, 12, 7 } },
12036203945Sweongyo		{ 16200, { 3, 3, 3, 3, 13, 8 } },
12037203945Sweongyo		{ 18000, { 2, 2, 2, 2, 14, 8 } },
12038203945Sweongyo		{ 19200, { 1, 1, 1, 1, 14, 9 } }
12039203945Sweongyo	};
12040203945Sweongyo	static const struct bwn_wpair v1[] = {
12041203945Sweongyo		{ BWN_B2062_N_TXCTL3, 0 },
12042203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0 },
12043203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0 },
12044203945Sweongyo		{ BWN_B2062_N_TXCTL6, 0 },
12045203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0x40 },
12046203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0 },
12047203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0x10 },
12048203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0 }
12049203945Sweongyo	};
12050203945Sweongyo	const struct bwn_b2062_freq *f = NULL;
12051203945Sweongyo	uint32_t xtalfreq, ref;
12052203945Sweongyo	unsigned int i;
12053203945Sweongyo
12054203945Sweongyo	bwn_phy_lp_b2062_tblinit(mac);
12055203945Sweongyo
12056203945Sweongyo	for (i = 0; i < N(v1); i++)
12057203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12058203945Sweongyo	if (mac->mac_phy.rev > 0)
12059203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_BG_CTL1,
12060203945Sweongyo		    (BWN_RF_READ(mac, BWN_B2062_N_COM2) >> 1) | 0x80);
12061203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12062203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_N_TSSI_CTL0, 0x1);
12063203945Sweongyo	else
12064203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_N_TSSI_CTL0, ~0x1);
12065203945Sweongyo
12066204922Sweongyo	KASSERT(siba_get_cc_caps(sc->sc_dev) & SIBA_CC_CAPS_PMU,
12067203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
12068204922Sweongyo	xtalfreq = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
12069203945Sweongyo	KASSERT(xtalfreq != 0, ("%s:%d: fail", __func__, __LINE__));
12070203945Sweongyo
12071203945Sweongyo	if (xtalfreq <= 30000000) {
12072203945Sweongyo		plp->plp_div = 1;
12073203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL1, 0xfffb);
12074203945Sweongyo	} else {
12075203945Sweongyo		plp->plp_div = 2;
12076203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL1, 0x4);
12077203945Sweongyo	}
12078203945Sweongyo
12079203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL7,
12080203945Sweongyo	    CALC_CTL7(xtalfreq, plp->plp_div));
12081203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL18,
12082203945Sweongyo	    CALC_CTL18(xtalfreq, plp->plp_div));
12083203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL19,
12084203945Sweongyo	    CALC_CTL19(xtalfreq, plp->plp_div));
12085203945Sweongyo
12086203945Sweongyo	ref = (1000 * plp->plp_div + 2 * xtalfreq) / (2000 * plp->plp_div);
12087203945Sweongyo	ref &= 0xffff;
12088203945Sweongyo	for (i = 0; i < N(freqdata_tab); i++) {
12089203945Sweongyo		if (ref < freqdata_tab[i].freq) {
12090203945Sweongyo			f = &freqdata_tab[i];
12091203945Sweongyo			break;
12092203945Sweongyo		}
12093203945Sweongyo	}
12094203945Sweongyo	if (f == NULL)
12095203945Sweongyo		f = &freqdata_tab[N(freqdata_tab) - 1];
12096203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL8,
12097203945Sweongyo	    ((uint16_t)(f->value[1]) << 4) | f->value[0]);
12098203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL9,
12099203945Sweongyo	    ((uint16_t)(f->value[3]) << 4) | f->value[2]);
12100203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL10, f->value[4]);
12101203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL11, f->value[5]);
12102203945Sweongyo#undef CALC_CTL7
12103203945Sweongyo#undef CALC_CTL18
12104203945Sweongyo#undef CALC_CTL19
12105203945Sweongyo}
12106203945Sweongyo
12107203945Sweongyostatic void
12108203945Sweongyobwn_phy_lp_b2063_init(struct bwn_mac *mac)
12109203945Sweongyo{
12110203945Sweongyo
12111203945Sweongyo	bwn_phy_lp_b2063_tblinit(mac);
12112203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_SP5, 0);
12113203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM8, 0x38);
12114203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_REG_SP1, 0x56);
12115203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_RX_BB_CTL2, ~0x2);
12116203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0);
12117203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP6, 0x20);
12118203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP9, 0x40);
12119203945Sweongyo	if (mac->mac_phy.rev == 2) {
12120203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0xa0);
12121203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP4, 0xa0);
12122203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x18);
12123203945Sweongyo	} else {
12124203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0x20);
12125203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x20);
12126203945Sweongyo	}
12127203945Sweongyo}
12128203945Sweongyo
12129203945Sweongyostatic void
12130203945Sweongyobwn_phy_lp_rxcal_r2(struct bwn_mac *mac)
12131203945Sweongyo{
12132204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12133203945Sweongyo	static const struct bwn_wpair v1[] = {
12134203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x0 },
12135203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12136203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12137203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x15 },
12138203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x70 },
12139203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL4, 0x52 },
12140203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL5, 0x1 },
12141203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7d }
12142203945Sweongyo	};
12143203945Sweongyo	static const struct bwn_wpair v2[] = {
12144203945Sweongyo		{ BWN_B2063_TX_BB_SP3, 0x0 },
12145203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12146203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12147203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x55 },
12148203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x76 }
12149203945Sweongyo	};
12150204922Sweongyo	uint32_t freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
12151203945Sweongyo	int i;
12152203945Sweongyo	uint8_t tmp;
12153203945Sweongyo
12154203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_RX_BB_SP8) & 0xff;
12155203945Sweongyo
12156203945Sweongyo	for (i = 0; i < 2; i++)
12157203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12158203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, 0xf7);
12159203945Sweongyo	for (i = 2; i < N(v1); i++)
12160203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12161203945Sweongyo	for (i = 0; i < 10000; i++) {
12162203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12163203945Sweongyo			break;
12164203945Sweongyo		DELAY(1000);
12165203945Sweongyo	}
12166203945Sweongyo
12167203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12168203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RX_BB_SP8, tmp);
12169203945Sweongyo
12170203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_TX_BB_SP3) & 0xff;
12171203945Sweongyo
12172203945Sweongyo	for (i = 0; i < N(v2); i++)
12173203945Sweongyo		BWN_RF_WRITE(mac, v2[i].reg, v2[i].value);
12174203945Sweongyo	if (freqxtal == 24000000) {
12175203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0xfc);
12176203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x0);
12177203945Sweongyo	} else {
12178203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0x13);
12179203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x1);
12180203945Sweongyo	}
12181203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0x7d);
12182203945Sweongyo	for (i = 0; i < 10000; i++) {
12183203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12184203945Sweongyo			break;
12185203945Sweongyo		DELAY(1000);
12186203945Sweongyo	}
12187203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12188203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, tmp);
12189203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL1, 0x7e);
12190203945Sweongyo}
12191203945Sweongyo
12192203945Sweongyostatic void
12193203945Sweongyobwn_phy_lp_rccal_r12(struct bwn_mac *mac)
12194203945Sweongyo{
12195203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12196203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12197203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12198203945Sweongyo	struct bwn_txgain tx_gains;
12199203945Sweongyo	static const uint32_t pwrtbl[21] = {
12200203945Sweongyo		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
12201203945Sweongyo		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
12202203945Sweongyo		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
12203203945Sweongyo		0x0004c, 0x0002c, 0x0001a,
12204203945Sweongyo	};
12205203945Sweongyo	uint32_t npwr, ipwr, sqpwr, tmp;
12206203945Sweongyo	int loopback, i, j, sum, error;
12207203945Sweongyo	uint16_t save[7];
12208203945Sweongyo	uint8_t txo, bbmult, txpctlmode;
12209203945Sweongyo
12210203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
12211203945Sweongyo	if (error)
12212203945Sweongyo		device_printf(sc->sc_dev,
12213203945Sweongyo		    "failed to change channel to 7 (%d)\n", error);
12214203945Sweongyo	txo = (BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40) ? 1 : 0;
12215203945Sweongyo	bbmult = bwn_phy_lp_get_bbmult(mac);
12216203945Sweongyo	if (txo)
12217203945Sweongyo		tx_gains = bwn_phy_lp_get_txgain(mac);
12218203945Sweongyo
12219203945Sweongyo	save[0] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_0);
12220203945Sweongyo	save[1] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_VAL_0);
12221203945Sweongyo	save[2] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR);
12222203945Sweongyo	save[3] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVRVAL);
12223203945Sweongyo	save[4] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2);
12224203945Sweongyo	save[5] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2_VAL);
12225203945Sweongyo	save[6] = BWN_PHY_READ(mac, BWN_PHY_LP_PHY_CTL);
12226203945Sweongyo
12227203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
12228203945Sweongyo	txpctlmode = plp->plp_txpctlmode;
12229203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
12230203945Sweongyo
12231203945Sweongyo	/* disable CRS */
12232203945Sweongyo	bwn_phy_lp_set_deaf(mac, 1);
12233203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 0, 1);
12234203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffb);
12235203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x4);
12236203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7);
12237203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
12238203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x10);
12239203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12240203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf);
12241203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
12242203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffbf);
12243203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12244203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x7);
12245203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x38);
12246203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f);
12247203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x100);
12248203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfdff);
12249203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL0, 0);
12250203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL1, 1);
12251203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL2, 0x20);
12252203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfbff);
12253203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xf7ff);
12254203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
12255203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45af);
12256203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0x3ff);
12257203945Sweongyo
12258203945Sweongyo	loopback = bwn_phy_lp_loopback(mac);
12259203945Sweongyo	if (loopback == -1)
12260203945Sweongyo		goto done;
12261203945Sweongyo	bwn_phy_lp_set_rxgain_idx(mac, loopback);
12262203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xffbf, 0x40);
12263203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfff8, 0x1);
12264203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xffc7, 0x8);
12265203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f, 0xc0);
12266203945Sweongyo
12267203945Sweongyo	tmp = 0;
12268203945Sweongyo	memset(&ie, 0, sizeof(ie));
12269203945Sweongyo	for (i = 128; i <= 159; i++) {
12270203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2, i);
12271203945Sweongyo		sum = 0;
12272203945Sweongyo		for (j = 5; j <= 25; j++) {
12273203945Sweongyo			bwn_phy_lp_ddfs_turnon(mac, 1, 1, j, j, 0);
12274203945Sweongyo			if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
12275203945Sweongyo				goto done;
12276203945Sweongyo			sqpwr = ie.ie_ipwr + ie.ie_qpwr;
12277203945Sweongyo			ipwr = ((pwrtbl[j - 5] >> 3) + 1) >> 1;
12278203945Sweongyo			npwr = bwn_phy_lp_roundup(sqpwr, (j == 5) ? sqpwr : 0,
12279203945Sweongyo			    12);
12280203945Sweongyo			sum += ((ipwr - npwr) * (ipwr - npwr));
12281203945Sweongyo			if ((i == 128) || (sum < tmp)) {
12282203945Sweongyo				plp->plp_rccap = i;
12283203945Sweongyo				tmp = sum;
12284203945Sweongyo			}
12285203945Sweongyo		}
12286203945Sweongyo	}
12287203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
12288203945Sweongyodone:
12289203945Sweongyo	/* restore CRS */
12290203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 1);
12291203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xff80);
12292203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfc00);
12293203945Sweongyo
12294203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_VAL_0, save[1]);
12295203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, save[0]);
12296203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVRVAL, save[3]);
12297203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, save[2]);
12298203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2_VAL, save[5]);
12299203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, save[4]);
12300203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LP_PHY_CTL, save[6]);
12301203945Sweongyo
12302203945Sweongyo	bwn_phy_lp_set_bbmult(mac, bbmult);
12303203945Sweongyo	if (txo)
12304203945Sweongyo		bwn_phy_lp_set_txgain(mac, &tx_gains);
12305203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, txpctlmode);
12306203945Sweongyo	if (plp->plp_rccap)
12307203945Sweongyo		bwn_phy_lp_set_rccap(mac);
12308203945Sweongyo}
12309203945Sweongyo
12310203945Sweongyostatic void
12311203945Sweongyobwn_phy_lp_set_rccap(struct bwn_mac *mac)
12312203945Sweongyo{
12313203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12314203945Sweongyo	uint8_t rc_cap = (plp->plp_rccap & 0x1f) >> 1;
12315203945Sweongyo
12316203945Sweongyo	if (mac->mac_phy.rev == 1)
12317203945Sweongyo		rc_cap = MIN(rc_cap + 5, 15);
12318203945Sweongyo
12319203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2,
12320203945Sweongyo	    MAX(plp->plp_rccap - 4, 0x80));
12321203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, rc_cap | 0x80);
12322203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RXG_CNT16,
12323203945Sweongyo	    ((plp->plp_rccap & 0x1f) >> 2) | 0x80);
12324203945Sweongyo}
12325203945Sweongyo
12326203945Sweongyostatic uint32_t
12327203945Sweongyobwn_phy_lp_roundup(uint32_t value, uint32_t div, uint8_t pre)
12328203945Sweongyo{
12329203945Sweongyo	uint32_t i, q, r;
12330203945Sweongyo
12331203945Sweongyo	if (div == 0)
12332203945Sweongyo		return (0);
12333203945Sweongyo
12334203945Sweongyo	for (i = 0, q = value / div, r = value % div; i < pre; i++) {
12335203945Sweongyo		q <<= 1;
12336203945Sweongyo		if (r << 1 >= div) {
12337203945Sweongyo			q++;
12338203945Sweongyo			r = (r << 1) - div;
12339203945Sweongyo		}
12340203945Sweongyo	}
12341203945Sweongyo	if (r << 1 >= div)
12342203945Sweongyo		q++;
12343203945Sweongyo	return (q);
12344203945Sweongyo}
12345203945Sweongyo
12346203945Sweongyostatic void
12347203945Sweongyobwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *mac)
12348203945Sweongyo{
12349204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12350203945Sweongyo
12351203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0xff);
12352203945Sweongyo	DELAY(20);
12353204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x5354) {
12354203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_COM1, 4);
12355203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 4);
12356203945Sweongyo	} else {
12357203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0);
12358203945Sweongyo	}
12359203945Sweongyo	DELAY(5);
12360203945Sweongyo}
12361203945Sweongyo
12362203945Sweongyostatic void
12363203945Sweongyobwn_phy_lp_b2062_vco_calib(struct bwn_mac *mac)
12364203945Sweongyo{
12365203945Sweongyo
12366203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x42);
12367203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x62);
12368203945Sweongyo	DELAY(200);
12369203945Sweongyo}
12370203945Sweongyo
12371203945Sweongyostatic void
12372203945Sweongyobwn_phy_lp_b2062_tblinit(struct bwn_mac *mac)
12373203945Sweongyo{
12374203945Sweongyo#define	FLAG_A	0x01
12375203945Sweongyo#define	FLAG_G	0x02
12376203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12377203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12378203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12379203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = {
12380203945Sweongyo		{ BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12381203945Sweongyo		{ BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, },
12382203945Sweongyo		{ BWN_B2062_N_PDNCTL3, 0x0, 0x0, FLAG_A | FLAG_G, },
12383203945Sweongyo		{ BWN_B2062_N_PDNCTL4, 0x15, 0x2a, FLAG_A | FLAG_G, },
12384203945Sweongyo		{ BWN_B2062_N_LGENC, 0xDB, 0xff, FLAG_A, },
12385203945Sweongyo		{ BWN_B2062_N_LGENATUNE0, 0xdd, 0x0, FLAG_A | FLAG_G, },
12386203945Sweongyo		{ BWN_B2062_N_LGENATUNE2, 0xdd, 0x0, FLAG_A | FLAG_G, },
12387203945Sweongyo		{ BWN_B2062_N_LGENATUNE3, 0x77, 0xB5, FLAG_A | FLAG_G, },
12388203945Sweongyo		{ BWN_B2062_N_LGENACTL3, 0x0, 0xff, FLAG_A | FLAG_G, },
12389203945Sweongyo		{ BWN_B2062_N_LGENACTL7, 0x33, 0x33, FLAG_A | FLAG_G, },
12390203945Sweongyo		{ BWN_B2062_N_RXA_CTL1, 0x0, 0x0, FLAG_G, },
12391203945Sweongyo		{ BWN_B2062_N_RXBB_CTL0, 0x82, 0x80, FLAG_A | FLAG_G, },
12392203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN1, 0x4, 0x4, FLAG_A | FLAG_G, },
12393203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN2, 0x0, 0x0, FLAG_A | FLAG_G, },
12394203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0x3, 0x3, FLAG_A | FLAG_G, },
12395203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0x2, 0x2, FLAG_A | FLAG_G, },
12396203945Sweongyo		{ BWN_B2062_N_TX_TUNE, 0x88, 0x1b, FLAG_A | FLAG_G, },
12397203945Sweongyo		{ BWN_B2062_S_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12398203945Sweongyo		{ BWN_B2062_S_PDS_CTL0, 0xff, 0xff, FLAG_A | FLAG_G, },
12399203945Sweongyo		{ BWN_B2062_S_LGENG_CTL0, 0xf8, 0xd8, FLAG_A | FLAG_G, },
12400203945Sweongyo		{ BWN_B2062_S_LGENG_CTL1, 0x3c, 0x24, FLAG_A | FLAG_G, },
12401203945Sweongyo		{ BWN_B2062_S_LGENG_CTL8, 0x88, 0x80, FLAG_A | FLAG_G, },
12402203945Sweongyo		{ BWN_B2062_S_LGENG_CTL10, 0x88, 0x80, FLAG_A | FLAG_G, },
12403203945Sweongyo		{ BWN_B2062_S_RFPLLCTL0, 0x98, 0x98, FLAG_A | FLAG_G, },
12404203945Sweongyo		{ BWN_B2062_S_RFPLLCTL1, 0x10, 0x10, FLAG_A | FLAG_G, },
12405203945Sweongyo		{ BWN_B2062_S_RFPLLCTL5, 0x43, 0x43, FLAG_A | FLAG_G, },
12406203945Sweongyo		{ BWN_B2062_S_RFPLLCTL6, 0x47, 0x47, FLAG_A | FLAG_G, },
12407203945Sweongyo		{ BWN_B2062_S_RFPLLCTL7, 0xc, 0xc, FLAG_A | FLAG_G, },
12408203945Sweongyo		{ BWN_B2062_S_RFPLLCTL8, 0x11, 0x11, FLAG_A | FLAG_G, },
12409203945Sweongyo		{ BWN_B2062_S_RFPLLCTL9, 0x11, 0x11, FLAG_A | FLAG_G, },
12410203945Sweongyo		{ BWN_B2062_S_RFPLLCTL10, 0xe, 0xe, FLAG_A | FLAG_G, },
12411203945Sweongyo		{ BWN_B2062_S_RFPLLCTL11, 0x8, 0x8, FLAG_A | FLAG_G, },
12412203945Sweongyo		{ BWN_B2062_S_RFPLLCTL12, 0x33, 0x33, FLAG_A | FLAG_G, },
12413203945Sweongyo		{ BWN_B2062_S_RFPLLCTL13, 0xa, 0xa, FLAG_A | FLAG_G, },
12414203945Sweongyo		{ BWN_B2062_S_RFPLLCTL14, 0x6, 0x6, FLAG_A | FLAG_G, },
12415203945Sweongyo		{ BWN_B2062_S_RFPLLCTL18, 0x3e, 0x3e, FLAG_A | FLAG_G, },
12416203945Sweongyo		{ BWN_B2062_S_RFPLLCTL19, 0x13, 0x13, FLAG_A | FLAG_G, },
12417203945Sweongyo		{ BWN_B2062_S_RFPLLCTL21, 0x62, 0x62, FLAG_A | FLAG_G, },
12418203945Sweongyo		{ BWN_B2062_S_RFPLLCTL22, 0x7, 0x7, FLAG_A | FLAG_G, },
12419203945Sweongyo		{ BWN_B2062_S_RFPLLCTL23, 0x16, 0x16, FLAG_A | FLAG_G, },
12420203945Sweongyo		{ BWN_B2062_S_RFPLLCTL24, 0x5c, 0x5c, FLAG_A | FLAG_G, },
12421203945Sweongyo		{ BWN_B2062_S_RFPLLCTL25, 0x95, 0x95, FLAG_A | FLAG_G, },
12422203945Sweongyo		{ BWN_B2062_S_RFPLLCTL30, 0xa0, 0xa0, FLAG_A | FLAG_G, },
12423203945Sweongyo		{ BWN_B2062_S_RFPLLCTL31, 0x4, 0x4, FLAG_A | FLAG_G, },
12424203945Sweongyo		{ BWN_B2062_S_RFPLLCTL33, 0xcc, 0xcc, FLAG_A | FLAG_G, },
12425203945Sweongyo		{ BWN_B2062_S_RFPLLCTL34, 0x7, 0x7, FLAG_A | FLAG_G, },
12426203945Sweongyo		{ BWN_B2062_S_RXG_CNT8, 0xf, 0xf, FLAG_A, },
12427203945Sweongyo	};
12428203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12429203945Sweongyo	unsigned int i;
12430203945Sweongyo
12431203945Sweongyo	for (i = 0; i < N(bwn_b2062_init_tab); i++) {
12432203945Sweongyo		br = &bwn_b2062_init_tab[i];
12433203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12434203945Sweongyo			if (br->br_flags & FLAG_G)
12435203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12436203945Sweongyo		} else {
12437203945Sweongyo			if (br->br_flags & FLAG_A)
12438203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12439203945Sweongyo		}
12440203945Sweongyo	}
12441203945Sweongyo#undef FLAG_A
12442203945Sweongyo#undef FLAG_B
12443203945Sweongyo}
12444203945Sweongyo
12445203945Sweongyostatic void
12446203945Sweongyobwn_phy_lp_b2063_tblinit(struct bwn_mac *mac)
12447203945Sweongyo{
12448203945Sweongyo#define	FLAG_A	0x01
12449203945Sweongyo#define	FLAG_G	0x02
12450203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12451203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12452203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12453203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = {
12454203945Sweongyo		{ BWN_B2063_COM1, 0x0, 0x0, FLAG_G, },
12455203945Sweongyo		{ BWN_B2063_COM10, 0x1, 0x0, FLAG_A, },
12456203945Sweongyo		{ BWN_B2063_COM16, 0x0, 0x0, FLAG_G, },
12457203945Sweongyo		{ BWN_B2063_COM17, 0x0, 0x0, FLAG_G, },
12458203945Sweongyo		{ BWN_B2063_COM18, 0x0, 0x0, FLAG_G, },
12459203945Sweongyo		{ BWN_B2063_COM19, 0x0, 0x0, FLAG_G, },
12460203945Sweongyo		{ BWN_B2063_COM20, 0x0, 0x0, FLAG_G, },
12461203945Sweongyo		{ BWN_B2063_COM21, 0x0, 0x0, FLAG_G, },
12462203945Sweongyo		{ BWN_B2063_COM22, 0x0, 0x0, FLAG_G, },
12463203945Sweongyo		{ BWN_B2063_COM23, 0x0, 0x0, FLAG_G, },
12464203945Sweongyo		{ BWN_B2063_COM24, 0x0, 0x0, FLAG_G, },
12465203945Sweongyo		{ BWN_B2063_LOGEN_SP1, 0xe8, 0xd4, FLAG_A | FLAG_G, },
12466203945Sweongyo		{ BWN_B2063_LOGEN_SP2, 0xa7, 0x53, FLAG_A | FLAG_G, },
12467203945Sweongyo		{ BWN_B2063_LOGEN_SP4, 0xf0, 0xf, FLAG_A | FLAG_G, },
12468203945Sweongyo		{ BWN_B2063_G_RX_SP1, 0x1f, 0x5e, FLAG_G, },
12469203945Sweongyo		{ BWN_B2063_G_RX_SP2, 0x7f, 0x7e, FLAG_G, },
12470203945Sweongyo		{ BWN_B2063_G_RX_SP3, 0x30, 0xf0, FLAG_G, },
12471203945Sweongyo		{ BWN_B2063_G_RX_SP7, 0x7f, 0x7f, FLAG_A | FLAG_G, },
12472203945Sweongyo		{ BWN_B2063_G_RX_SP10, 0xc, 0xc, FLAG_A | FLAG_G, },
12473203945Sweongyo		{ BWN_B2063_A_RX_SP1, 0x3c, 0x3f, FLAG_A, },
12474203945Sweongyo		{ BWN_B2063_A_RX_SP2, 0xfc, 0xfe, FLAG_A, },
12475203945Sweongyo		{ BWN_B2063_A_RX_SP7, 0x8, 0x8, FLAG_A | FLAG_G, },
12476203945Sweongyo		{ BWN_B2063_RX_BB_SP4, 0x60, 0x60, FLAG_A | FLAG_G, },
12477203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x30, 0x30, FLAG_A | FLAG_G, },
12478203945Sweongyo		{ BWN_B2063_TX_RF_SP3, 0xc, 0xb, FLAG_A | FLAG_G, },
12479203945Sweongyo		{ BWN_B2063_TX_RF_SP4, 0x10, 0xf, FLAG_A | FLAG_G, },
12480203945Sweongyo		{ BWN_B2063_PA_SP1, 0x3d, 0xfd, FLAG_A | FLAG_G, },
12481203945Sweongyo		{ BWN_B2063_TX_BB_SP1, 0x2, 0x2, FLAG_A | FLAG_G, },
12482203945Sweongyo		{ BWN_B2063_BANDGAP_CTL1, 0x56, 0x56, FLAG_A | FLAG_G, },
12483203945Sweongyo		{ BWN_B2063_JTAG_VCO2, 0xF7, 0xF7, FLAG_A | FLAG_G, },
12484203945Sweongyo		{ BWN_B2063_G_RX_MIX3, 0x71, 0x71, FLAG_A | FLAG_G, },
12485203945Sweongyo		{ BWN_B2063_G_RX_MIX4, 0x71, 0x71, FLAG_A | FLAG_G, },
12486203945Sweongyo		{ BWN_B2063_A_RX_1ST2, 0xf0, 0x30, FLAG_A, },
12487203945Sweongyo		{ BWN_B2063_A_RX_PS6, 0x77, 0x77, FLAG_A | FLAG_G, },
12488203945Sweongyo		{ BWN_B2063_A_RX_MIX4, 0x3, 0x3, FLAG_A | FLAG_G, },
12489203945Sweongyo		{ BWN_B2063_A_RX_MIX5, 0xf, 0xf, FLAG_A | FLAG_G, },
12490203945Sweongyo		{ BWN_B2063_A_RX_MIX6, 0xf, 0xf, FLAG_A | FLAG_G, },
12491203945Sweongyo		{ BWN_B2063_RX_TIA_CTL1, 0x77, 0x77, FLAG_A | FLAG_G, },
12492203945Sweongyo		{ BWN_B2063_RX_TIA_CTL3, 0x77, 0x77, FLAG_A | FLAG_G, },
12493203945Sweongyo		{ BWN_B2063_RX_BB_CTL2, 0x4, 0x4, FLAG_A | FLAG_G, },
12494203945Sweongyo		{ BWN_B2063_PA_CTL1, 0x0, 0x4, FLAG_A, },
12495203945Sweongyo		{ BWN_B2063_VREG_CTL1, 0x3, 0x3, FLAG_A | FLAG_G, },
12496203945Sweongyo	};
12497203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12498203945Sweongyo	unsigned int i;
12499203945Sweongyo
12500203945Sweongyo	for (i = 0; i < N(bwn_b2063_init_tab); i++) {
12501203945Sweongyo		br = &bwn_b2063_init_tab[i];
12502203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12503203945Sweongyo			if (br->br_flags & FLAG_G)
12504203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12505203945Sweongyo		} else {
12506203945Sweongyo			if (br->br_flags & FLAG_A)
12507203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12508203945Sweongyo		}
12509203945Sweongyo	}
12510203945Sweongyo#undef FLAG_A
12511203945Sweongyo#undef FLAG_B
12512203945Sweongyo}
12513203945Sweongyo
12514203945Sweongyostatic void
12515203945Sweongyobwn_tab_read_multi(struct bwn_mac *mac, uint32_t typenoffset,
12516203945Sweongyo    int count, void *_data)
12517203945Sweongyo{
12518203945Sweongyo	unsigned int i;
12519203945Sweongyo	uint32_t offset, type;
12520203945Sweongyo	uint8_t *data = _data;
12521203945Sweongyo
12522203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12523203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12524203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12525203945Sweongyo
12526203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12527203945Sweongyo
12528203945Sweongyo	for (i = 0; i < count; i++) {
12529203945Sweongyo		switch (type) {
12530203945Sweongyo		case BWN_TAB_8BIT:
12531203945Sweongyo			*data = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
12532203945Sweongyo			data++;
12533203945Sweongyo			break;
12534203945Sweongyo		case BWN_TAB_16BIT:
12535203945Sweongyo			*((uint16_t *)data) = BWN_PHY_READ(mac,
12536203945Sweongyo			    BWN_PHY_TABLEDATALO);
12537203945Sweongyo			data += 2;
12538203945Sweongyo			break;
12539203945Sweongyo		case BWN_TAB_32BIT:
12540203945Sweongyo			*((uint32_t *)data) = BWN_PHY_READ(mac,
12541203945Sweongyo			    BWN_PHY_TABLEDATAHI);
12542203945Sweongyo			*((uint32_t *)data) <<= 16;
12543203945Sweongyo			*((uint32_t *)data) |= BWN_PHY_READ(mac,
12544203945Sweongyo			    BWN_PHY_TABLEDATALO);
12545203945Sweongyo			data += 4;
12546203945Sweongyo			break;
12547203945Sweongyo		default:
12548203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12549203945Sweongyo		}
12550203945Sweongyo	}
12551203945Sweongyo}
12552203945Sweongyo
12553203945Sweongyostatic void
12554203945Sweongyobwn_tab_write_multi(struct bwn_mac *mac, uint32_t typenoffset,
12555203945Sweongyo    int count, const void *_data)
12556203945Sweongyo{
12557203945Sweongyo	uint32_t offset, type, value;
12558203945Sweongyo	const uint8_t *data = _data;
12559203945Sweongyo	unsigned int i;
12560203945Sweongyo
12561203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12562203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12563203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12564203945Sweongyo
12565203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12566203945Sweongyo
12567203945Sweongyo	for (i = 0; i < count; i++) {
12568203945Sweongyo		switch (type) {
12569203945Sweongyo		case BWN_TAB_8BIT:
12570203945Sweongyo			value = *data;
12571203945Sweongyo			data++;
12572203945Sweongyo			KASSERT(!(value & ~0xff),
12573203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12574203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12575203945Sweongyo			break;
12576203945Sweongyo		case BWN_TAB_16BIT:
12577203945Sweongyo			value = *((const uint16_t *)data);
12578203945Sweongyo			data += 2;
12579203945Sweongyo			KASSERT(!(value & ~0xffff),
12580203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12581203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12582203945Sweongyo			break;
12583203945Sweongyo		case BWN_TAB_32BIT:
12584203945Sweongyo			value = *((const uint32_t *)data);
12585203945Sweongyo			data += 4;
12586203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
12587203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12588203945Sweongyo			break;
12589203945Sweongyo		default:
12590203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12591203945Sweongyo		}
12592203945Sweongyo	}
12593203945Sweongyo}
12594203945Sweongyo
12595203945Sweongyostatic struct bwn_txgain
12596203945Sweongyobwn_phy_lp_get_txgain(struct bwn_mac *mac)
12597203945Sweongyo{
12598203945Sweongyo	struct bwn_txgain tg;
12599203945Sweongyo	uint16_t tmp;
12600203945Sweongyo
12601203945Sweongyo	tg.tg_dac = (BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0x380) >> 7;
12602203945Sweongyo	if (mac->mac_phy.rev < 2) {
12603203945Sweongyo		tmp = BWN_PHY_READ(mac,
12604203945Sweongyo		    BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7ff;
12605203945Sweongyo		tg.tg_gm = tmp & 0x0007;
12606203945Sweongyo		tg.tg_pga = (tmp & 0x0078) >> 3;
12607203945Sweongyo		tg.tg_pad = (tmp & 0x780) >> 7;
12608203945Sweongyo		return (tg);
12609203945Sweongyo	}
12610203945Sweongyo
12611203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL);
12612203945Sweongyo	tg.tg_pad = BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0xff;
12613203945Sweongyo	tg.tg_gm = tmp & 0xff;
12614203945Sweongyo	tg.tg_pga = (tmp >> 8) & 0xff;
12615203945Sweongyo	return (tg);
12616203945Sweongyo}
12617203945Sweongyo
12618203945Sweongyostatic uint8_t
12619203945Sweongyobwn_phy_lp_get_bbmult(struct bwn_mac *mac)
12620203945Sweongyo{
12621203945Sweongyo
12622203945Sweongyo	return (bwn_tab_read(mac, BWN_TAB_2(0, 87)) & 0xff00) >> 8;
12623203945Sweongyo}
12624203945Sweongyo
12625203945Sweongyostatic void
12626203945Sweongyobwn_phy_lp_set_txgain(struct bwn_mac *mac, struct bwn_txgain *tg)
12627203945Sweongyo{
12628203945Sweongyo	uint16_t pa;
12629203945Sweongyo
12630203945Sweongyo	if (mac->mac_phy.rev < 2) {
12631203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xf800,
12632203945Sweongyo		    (tg->tg_pad << 7) | (tg->tg_pga << 3) | tg->tg_gm);
12633203945Sweongyo		bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12634203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
12635203945Sweongyo		return;
12636203945Sweongyo	}
12637203945Sweongyo
12638203945Sweongyo	pa = bwn_phy_lp_get_pa_gain(mac);
12639203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
12640203945Sweongyo	    (tg->tg_pga << 8) | tg->tg_gm);
12641203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0x8000,
12642203945Sweongyo	    tg->tg_pad | (pa << 6));
12643203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xfc), (tg->tg_pga << 8) | tg->tg_gm);
12644203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x8000,
12645203945Sweongyo	    tg->tg_pad | (pa << 8));
12646203945Sweongyo	bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12647203945Sweongyo	bwn_phy_lp_set_txgain_override(mac);
12648203945Sweongyo}
12649203945Sweongyo
12650203945Sweongyostatic void
12651203945Sweongyobwn_phy_lp_set_bbmult(struct bwn_mac *mac, uint8_t bbmult)
12652203945Sweongyo{
12653203945Sweongyo
12654203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(0, 87), (uint16_t)bbmult << 8);
12655203945Sweongyo}
12656203945Sweongyo
12657203945Sweongyostatic void
12658203945Sweongyobwn_phy_lp_set_trsw_over(struct bwn_mac *mac, uint8_t tx, uint8_t rx)
12659203945Sweongyo{
12660203945Sweongyo	uint16_t trsw = (tx << 1) | rx;
12661203945Sweongyo
12662203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffc, trsw);
12663203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x3);
12664203945Sweongyo}
12665203945Sweongyo
12666203945Sweongyostatic void
12667203945Sweongyobwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain)
12668203945Sweongyo{
12669203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12670203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12671203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12672203945Sweongyo	uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp;
12673203945Sweongyo
12674203945Sweongyo	if (mac->mac_phy.rev < 2) {
12675203945Sweongyo		trsw = gain & 0x1;
12676203945Sweongyo		lna = (gain & 0xfffc) | ((gain & 0xc) >> 2);
12677203945Sweongyo		ext_lna = (gain & 2) >> 1;
12678203945Sweongyo
12679203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12680203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12681203945Sweongyo		    0xfbff, ext_lna << 10);
12682203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12683203945Sweongyo		    0xf7ff, ext_lna << 11);
12684203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
12685203945Sweongyo	} else {
12686203945Sweongyo		low_gain = gain & 0xffff;
12687203945Sweongyo		high_gain = (gain >> 16) & 0xf;
12688203945Sweongyo		ext_lna = (gain >> 21) & 0x1;
12689203945Sweongyo		trsw = ~(gain >> 20) & 0x1;
12690203945Sweongyo
12691203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12692203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12693203945Sweongyo		    0xfdff, ext_lna << 9);
12694203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12695203945Sweongyo		    0xfbff, ext_lna << 10);
12696203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
12697203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff0, high_gain);
12698203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12699203945Sweongyo			tmp = (gain >> 2) & 0x3;
12700203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12701203945Sweongyo			    0xe7ff, tmp<<11);
12702203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe6), 0xffe7,
12703203945Sweongyo			    tmp << 3);
12704203945Sweongyo		}
12705203945Sweongyo	}
12706203945Sweongyo
12707203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1);
12708203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12709203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12710203945Sweongyo	if (mac->mac_phy.rev >= 2) {
12711203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
12712203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12713203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x400);
12714203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xe5), 0x8);
12715203945Sweongyo		}
12716203945Sweongyo		return;
12717203945Sweongyo	}
12718203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x200);
12719203945Sweongyo}
12720203945Sweongyo
12721203945Sweongyostatic void
12722203945Sweongyobwn_phy_lp_set_deaf(struct bwn_mac *mac, uint8_t user)
12723203945Sweongyo{
12724203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12725203945Sweongyo
12726203945Sweongyo	if (user)
12727203945Sweongyo		plp->plp_crsusr_off = 1;
12728203945Sweongyo	else
12729203945Sweongyo		plp->plp_crssys_off = 1;
12730203945Sweongyo
12731203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x80);
12732203945Sweongyo}
12733203945Sweongyo
12734203945Sweongyostatic void
12735203945Sweongyobwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
12736203945Sweongyo{
12737203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12738203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12739203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12740203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12741203945Sweongyo
12742203945Sweongyo	if (user)
12743203945Sweongyo		plp->plp_crsusr_off = 0;
12744203945Sweongyo	else
12745203945Sweongyo		plp->plp_crssys_off = 0;
12746203945Sweongyo
12747203945Sweongyo	if (plp->plp_crsusr_off || plp->plp_crssys_off)
12748203945Sweongyo		return;
12749203945Sweongyo
12750203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12751203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x60);
12752203945Sweongyo	else
12753203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x20);
12754203945Sweongyo}
12755203945Sweongyo
12756203945Sweongyostatic unsigned int
12757203945Sweongyobwn_sqrt(struct bwn_mac *mac, unsigned int x)
12758203945Sweongyo{
12759203945Sweongyo	/* Table holding (10 * sqrt(x)) for x between 1 and 256. */
12760203945Sweongyo	static uint8_t sqrt_table[256] = {
12761203945Sweongyo		10, 14, 17, 20, 22, 24, 26, 28,
12762203945Sweongyo		30, 31, 33, 34, 36, 37, 38, 40,
12763203945Sweongyo		41, 42, 43, 44, 45, 46, 47, 48,
12764203945Sweongyo		50, 50, 51, 52, 53, 54, 55, 56,
12765203945Sweongyo		57, 58, 59, 60, 60, 61, 62, 63,
12766203945Sweongyo		64, 64, 65, 66, 67, 67, 68, 69,
12767203945Sweongyo		70, 70, 71, 72, 72, 73, 74, 74,
12768203945Sweongyo		75, 76, 76, 77, 78, 78, 79, 80,
12769203945Sweongyo		80, 81, 81, 82, 83, 83, 84, 84,
12770203945Sweongyo		85, 86, 86, 87, 87, 88, 88, 89,
12771203945Sweongyo		90, 90, 91, 91, 92, 92, 93, 93,
12772203945Sweongyo		94, 94, 95, 95, 96, 96, 97, 97,
12773203945Sweongyo		98, 98, 99, 100, 100, 100, 101, 101,
12774203945Sweongyo		102, 102, 103, 103, 104, 104, 105, 105,
12775203945Sweongyo		106, 106, 107, 107, 108, 108, 109, 109,
12776203945Sweongyo		110, 110, 110, 111, 111, 112, 112, 113,
12777203945Sweongyo		113, 114, 114, 114, 115, 115, 116, 116,
12778203945Sweongyo		117, 117, 117, 118, 118, 119, 119, 120,
12779203945Sweongyo		120, 120, 121, 121, 122, 122, 122, 123,
12780203945Sweongyo		123, 124, 124, 124, 125, 125, 126, 126,
12781203945Sweongyo		126, 127, 127, 128, 128, 128, 129, 129,
12782203945Sweongyo		130, 130, 130, 131, 131, 131, 132, 132,
12783203945Sweongyo		133, 133, 133, 134, 134, 134, 135, 135,
12784203945Sweongyo		136, 136, 136, 137, 137, 137, 138, 138,
12785203945Sweongyo		138, 139, 139, 140, 140, 140, 141, 141,
12786203945Sweongyo		141, 142, 142, 142, 143, 143, 143, 144,
12787203945Sweongyo		144, 144, 145, 145, 145, 146, 146, 146,
12788203945Sweongyo		147, 147, 147, 148, 148, 148, 149, 149,
12789203945Sweongyo		150, 150, 150, 150, 151, 151, 151, 152,
12790203945Sweongyo		152, 152, 153, 153, 153, 154, 154, 154,
12791203945Sweongyo		155, 155, 155, 156, 156, 156, 157, 157,
12792203945Sweongyo		157, 158, 158, 158, 159, 159, 159, 160
12793203945Sweongyo	};
12794203945Sweongyo
12795203945Sweongyo	if (x == 0)
12796203945Sweongyo		return (0);
12797203945Sweongyo	if (x >= 256) {
12798204542Sweongyo		unsigned int tmp;
12799204542Sweongyo
12800204542Sweongyo		for (tmp = 0; x >= (2 * tmp) + 1; x -= (2 * tmp++) + 1)
12801204542Sweongyo			/* do nothing */ ;
12802204542Sweongyo		return (tmp);
12803203945Sweongyo	}
12804203945Sweongyo	return (sqrt_table[x - 1] / 10);
12805203945Sweongyo}
12806203945Sweongyo
12807203945Sweongyostatic int
12808203945Sweongyobwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *mac, uint16_t sample)
12809203945Sweongyo{
12810203945Sweongyo#define	CALC_COEFF(_v, _x, _y, _z)	do {				\
12811203945Sweongyo	int _t;								\
12812203945Sweongyo	_t = _x - 20;							\
12813203945Sweongyo	if (_t >= 0) {							\
12814203945Sweongyo		_v = ((_y << (30 - _x)) + (_z >> (1 + _t))) / (_z >> _t); \
12815203945Sweongyo	} else {							\
12816203945Sweongyo		_v = ((_y << (30 - _x)) + (_z << (-1 - _t))) / (_z << -_t); \
12817203945Sweongyo	}								\
12818203945Sweongyo} while (0)
12819203945Sweongyo#define	CALC_COEFF2(_v, _x, _y, _z)	do {				\
12820203945Sweongyo	int _t;								\
12821203945Sweongyo	_t = _x - 11;							\
12822203945Sweongyo	if (_t >= 0)							\
12823210393Sweongyo		_v = (_y << (31 - _x)) / (_z >> _t);			\
12824203945Sweongyo	else								\
12825210393Sweongyo		_v = (_y << (31 - _x)) / (_z << -_t);			\
12826203945Sweongyo} while (0)
12827203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12828203945Sweongyo	uint16_t v0, v1;
12829203945Sweongyo	int tmp[2], ret;
12830203945Sweongyo
12831203945Sweongyo	v1 = BWN_PHY_READ(mac, BWN_PHY_RX_COMP_COEFF_S);
12832203945Sweongyo	v0 = v1 >> 8;
12833203945Sweongyo	v1 |= 0xff;
12834203945Sweongyo
12835203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, 0x00c0);
12836203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff);
12837203945Sweongyo
12838203945Sweongyo	ret = bwn_phy_lp_rx_iq_est(mac, sample, 32, &ie);
12839203945Sweongyo	if (ret == 0)
12840203945Sweongyo		goto done;
12841203945Sweongyo
12842203945Sweongyo	if (ie.ie_ipwr + ie.ie_qpwr < 2) {
12843203945Sweongyo		ret = 0;
12844203945Sweongyo		goto done;
12845203945Sweongyo	}
12846203945Sweongyo
12847203945Sweongyo	CALC_COEFF(tmp[0], bwn_nbits(ie.ie_iqprod), ie.ie_iqprod, ie.ie_ipwr);
12848203945Sweongyo	CALC_COEFF2(tmp[1], bwn_nbits(ie.ie_qpwr), ie.ie_qpwr, ie.ie_ipwr);
12849203945Sweongyo
12850203945Sweongyo	tmp[1] = -bwn_sqrt(mac, tmp[1] - (tmp[0] * tmp[0]));
12851203945Sweongyo	v0 = tmp[0] >> 3;
12852203945Sweongyo	v1 = tmp[1] >> 4;
12853203945Sweongyodone:
12854203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, v1);
12855203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, v0 << 8);
12856203945Sweongyo	return ret;
12857203945Sweongyo#undef CALC_COEFF
12858203945Sweongyo#undef CALC_COEFF2
12859203945Sweongyo}
12860203945Sweongyo
12861203945Sweongyostatic void
12862203945Sweongyobwn_phy_lp_tblinit_r01(struct bwn_mac *mac)
12863203945Sweongyo{
12864203945Sweongyo	static const uint16_t noisescale[] = {
12865203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12866203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4,
12867203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12868203945Sweongyo		0xa4a4, 0xa4a4, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12869203945Sweongyo		0x0000, 0x0000, 0x4c00, 0x2d36, 0x0000, 0x0000, 0x4c00, 0x2d36,
12870203945Sweongyo	};
12871203945Sweongyo	static const uint16_t crsgainnft[] = {
12872203945Sweongyo		0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f,
12873203945Sweongyo		0x036f, 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381,
12874203945Sweongyo		0x0374, 0x0381, 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f,
12875203945Sweongyo		0x0040, 0x005e, 0x007f, 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d,
12876203945Sweongyo		0x013d,
12877203945Sweongyo	};
12878203945Sweongyo	static const uint16_t filterctl[] = {
12879203945Sweongyo		0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077,
12880203945Sweongyo		0xff53, 0x0127,
12881203945Sweongyo	};
12882203945Sweongyo	static const uint32_t psctl[] = {
12883203945Sweongyo		0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101,
12884203945Sweongyo		0x00000080, 0x08080101, 0x00000040, 0x08080101, 0x000000c0,
12885203945Sweongyo		0x08a81501, 0x000000c0, 0x0fe8fd01, 0x000000c0, 0x08300105,
12886203945Sweongyo		0x000000c0, 0x08080201, 0x000000c0, 0x08280205, 0x000000c0,
12887203945Sweongyo		0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, 0x08080202,
12888203945Sweongyo		0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
12889203945Sweongyo		0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106,
12890203945Sweongyo		0x000000c0, 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
12891203945Sweongyo	};
12892203945Sweongyo	static const uint16_t ofdmcckgain_r0[] = {
12893203945Sweongyo		0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12894203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12895203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12896203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12897203945Sweongyo		0x755d,
12898203945Sweongyo	};
12899203945Sweongyo	static const uint16_t ofdmcckgain_r1[] = {
12900203945Sweongyo		0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12901203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12902203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12903203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12904203945Sweongyo		0x755d,
12905203945Sweongyo	};
12906203945Sweongyo	static const uint16_t gaindelta[] = {
12907203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12908203945Sweongyo		0x0000,
12909203945Sweongyo	};
12910203945Sweongyo	static const uint32_t txpwrctl[] = {
12911203945Sweongyo		0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c,
12912203945Sweongyo		0x0000004b, 0x0000004a, 0x00000049, 0x00000048, 0x00000047,
12913203945Sweongyo		0x00000046, 0x00000045, 0x00000044, 0x00000043, 0x00000042,
12914203945Sweongyo		0x00000041, 0x00000040, 0x0000003f, 0x0000003e, 0x0000003d,
12915203945Sweongyo		0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, 0x00000038,
12916203945Sweongyo		0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
12917203945Sweongyo		0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e,
12918203945Sweongyo		0x0000002d, 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029,
12919203945Sweongyo		0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
12920203945Sweongyo		0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001f,
12921203945Sweongyo		0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001a,
12922203945Sweongyo		0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
12923203945Sweongyo		0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000,
12924203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12925203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12926203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12927203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12928203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12929203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12930203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12931203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 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, 0x000075a0, 0x000075a0, 0x000075a1,
12950203945Sweongyo		0x000075a1, 0x000075a2, 0x000075a2, 0x000075a3, 0x000075a3,
12951203945Sweongyo		0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, 0x000074b2,
12952203945Sweongyo		0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
12953203945Sweongyo		0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23,
12954203945Sweongyo		0x00006d23, 0x00004660, 0x00004660, 0x00004661, 0x00004661,
12955203945Sweongyo		0x00004662, 0x00004662, 0x00004663, 0x00004663, 0x00003e60,
12956203945Sweongyo		0x00003e60, 0x00003e61, 0x00003e61, 0x00003e62, 0x00003e62,
12957203945Sweongyo		0x00003e63, 0x00003e63, 0x00003660, 0x00003660, 0x00003661,
12958203945Sweongyo		0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
12959203945Sweongyo		0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62,
12960203945Sweongyo		0x00002e62, 0x00002e63, 0x00002e63, 0x00002660, 0x00002660,
12961203945Sweongyo		0x00002661, 0x00002661, 0x00002662, 0x00002662, 0x00002663,
12962203945Sweongyo		0x00002663, 0x000025e0, 0x000025e0, 0x000025e1, 0x000025e1,
12963203945Sweongyo		0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, 0x00001de0,
12964203945Sweongyo		0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
12965203945Sweongyo		0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61,
12966203945Sweongyo		0x00001d61, 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63,
12967203945Sweongyo		0x00001560, 0x00001560, 0x00001561, 0x00001561, 0x00001562,
12968203945Sweongyo		0x00001562, 0x00001563, 0x00001563, 0x00000d60, 0x00000d60,
12969203945Sweongyo		0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, 0x00000d63,
12970203945Sweongyo		0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
12971203945Sweongyo		0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10,
12972203945Sweongyo		0x00000e10, 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12,
12973203945Sweongyo		0x00000e13, 0x00000e13, 0x00000bf0, 0x00000bf0, 0x00000bf1,
12974203945Sweongyo		0x00000bf1, 0x00000bf2, 0x00000bf2, 0x00000bf3, 0x00000bf3,
12975203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12976203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12977203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12978203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12979203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12980203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12981203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12982203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
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, 0x000000ff, 0x000002fc,
13001203945Sweongyo		0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04,
13002203945Sweongyo		0x0000fcff, 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006,
13003203945Sweongyo		0x0000ff03, 0x000007fc, 0x0000fc08, 0x00000203, 0x0000fffb,
13004203945Sweongyo		0x00000600, 0x0000fa01, 0x0000fc03, 0x0000fe06, 0x0000fe00,
13005203945Sweongyo		0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, 0x000004fd,
13006203945Sweongyo		0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
13007203945Sweongyo		0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa,
13008203945Sweongyo		0x00000700, 0x00000305, 0x000004ff, 0x00000801, 0x00000503,
13009203945Sweongyo		0x000005f9, 0x00000404, 0x0000fb08, 0x000005fd, 0x00000501,
13010203945Sweongyo		0x00000405, 0x0000fb03, 0x000007fc, 0x00000403, 0x00000303,
13011203945Sweongyo		0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, 0x0000fe01,
13012203945Sweongyo		0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
13013203945Sweongyo		0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa,
13014203945Sweongyo		0x000003fe, 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06,
13015203945Sweongyo		0x000008fc, 0x00000701, 0x00000504, 0x0000fdfe, 0x0000fdfc,
13016203945Sweongyo		0x000003fe, 0x00000704, 0x000002fc, 0x000004f9, 0x0000fdfd,
13017203945Sweongyo		0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, 0x000004f9,
13018203945Sweongyo		0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
13019203945Sweongyo		0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa,
13020203945Sweongyo		0x00000305, 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc,
13021203945Sweongyo		0x0000fe03, 0x00000701, 0x000001fb, 0x000001f9, 0x00000206,
13022203945Sweongyo		0x000006fd, 0x00000508, 0x00000700, 0x00000304, 0x000005fe,
13023203945Sweongyo		0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, 0x000007f9,
13024203945Sweongyo		0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
13025203945Sweongyo		0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb,
13026203945Sweongyo		0x00000702,
13027203945Sweongyo	};
13028203945Sweongyo
13029203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13030203945Sweongyo
13031203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13032203945Sweongyo	    bwn_tab_sigsq_tbl);
13033203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13034203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(crsgainnft), crsgainnft);
13035203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(8, 0), N(filterctl), filterctl);
13036203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(psctl), psctl);
13037203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13038203945Sweongyo	    bwn_tab_pllfrac_tbl);
13039203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13040203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13041203945Sweongyo	if (mac->mac_phy.rev == 0) {
13042203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r0),
13043203945Sweongyo		    ofdmcckgain_r0);
13044203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r0),
13045203945Sweongyo		    ofdmcckgain_r0);
13046203945Sweongyo	} else {
13047203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r1),
13048203945Sweongyo		    ofdmcckgain_r1);
13049203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r1),
13050203945Sweongyo		    ofdmcckgain_r1);
13051203945Sweongyo	}
13052203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(gaindelta), gaindelta);
13053203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(txpwrctl), txpwrctl);
13054203945Sweongyo}
13055203945Sweongyo
13056203945Sweongyostatic void
13057203945Sweongyobwn_phy_lp_tblinit_r2(struct bwn_mac *mac)
13058203945Sweongyo{
13059204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13060203945Sweongyo	int i;
13061203945Sweongyo	static const uint16_t noisescale[] = {
13062203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13063203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13064203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13065203945Sweongyo		0x00a4, 0x00a4, 0x0000, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13066203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13067203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13068203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4
13069203945Sweongyo	};
13070203945Sweongyo	static const uint32_t filterctl[] = {
13071203945Sweongyo		0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27,
13072203945Sweongyo		0x0000217f, 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f
13073203945Sweongyo	};
13074203945Sweongyo	static const uint32_t psctl[] = {
13075203945Sweongyo		0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000,
13076203945Sweongyo		0x00002080, 0x00006180, 0x00003002, 0x00000040, 0x00002042,
13077203945Sweongyo		0x00180047, 0x00080043, 0x00000041, 0x000020c1, 0x00046006,
13078203945Sweongyo		0x00042002, 0x00040000, 0x00002003, 0x00180006, 0x00080002
13079203945Sweongyo	};
13080203945Sweongyo	static const uint32_t gainidx[] = {
13081203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13082203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13083203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13084203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x10000001, 0x00000000,
13085203945Sweongyo		0x20000082, 0x00000000, 0x40000104, 0x00000000, 0x60004207,
13086203945Sweongyo		0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
13087203945Sweongyo		0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288,
13088203945Sweongyo		0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
13089203945Sweongyo		0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794,
13090203945Sweongyo		0x00000010, 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011,
13091203945Sweongyo		0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21,
13092203945Sweongyo		0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
13093203945Sweongyo		0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329,
13094203945Sweongyo		0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
13095203945Sweongyo		0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, 0x00000000,
13096203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13097203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13098203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13099203945Sweongyo		0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082,
13100203945Sweongyo		0x00000000, 0x40000104, 0x00000000, 0x60004207, 0x00000001,
13101203945Sweongyo		0x7000838a, 0x00000001, 0xd021050d, 0x00000001, 0xe041c683,
13102203945Sweongyo		0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
13103203945Sweongyo		0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711,
13104203945Sweongyo		0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
13105203945Sweongyo		0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c,
13106203945Sweongyo		0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019,
13107203945Sweongyo		0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, 0xb36811a6,
13108203945Sweongyo		0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
13109203945Sweongyo		0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c,
13110203945Sweongyo		0x0000001a, 0x64ca55ad, 0x0000001a
13111203945Sweongyo	};
13112203945Sweongyo	static const uint16_t auxgainidx[] = {
13113203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13114203945Sweongyo		0x0000, 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000,
13115203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002,
13116203945Sweongyo		0x0004, 0x0016
13117203945Sweongyo	};
13118203945Sweongyo	static const uint16_t swctl[] = {
13119203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13120203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13121203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13122203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
13123203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13124203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13125203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13126203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018
13127203945Sweongyo	};
13128203945Sweongyo	static const uint8_t hf[] = {
13129203945Sweongyo		0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
13130203945Sweongyo		0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17
13131203945Sweongyo	};
13132203945Sweongyo	static const uint32_t gainval[] = {
13133203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13134203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13135203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13136203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13137203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13138203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13139203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13140203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13141203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13142203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13143203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13144203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13145203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009,
13146203945Sweongyo		0x000000f1, 0x00000000, 0x00000000
13147203945Sweongyo	};
13148203945Sweongyo	static const uint16_t gain[] = {
13149203945Sweongyo		0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808,
13150203945Sweongyo		0x080a, 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813,
13151203945Sweongyo		0x0814, 0x0816, 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824,
13152203945Sweongyo		0x0830, 0x0834, 0x0837, 0x083b, 0x083f, 0x0840, 0x0844, 0x0857,
13153203945Sweongyo		0x085b, 0x085f, 0x08d7, 0x08db, 0x08df, 0x0957, 0x095b, 0x095f,
13154203945Sweongyo		0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, 0x175f, 0x0000, 0x0000,
13155203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13156203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13157203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13158203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13159203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13160203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13161203945Sweongyo	};
13162203945Sweongyo	static const uint32_t papdeps[] = {
13163203945Sweongyo		0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9,
13164203945Sweongyo		0x00021fdf, 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7,
13165203945Sweongyo		0x0004efc2, 0x00055fb5, 0x0005cfb0, 0x00063fa8, 0x00068fa3,
13166203945Sweongyo		0x00071f98, 0x0007ef92, 0x00084f8b, 0x0008df82, 0x00097f77,
13167203945Sweongyo		0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, 0x000bff41,
13168203945Sweongyo		0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
13169203945Sweongyo		0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15,
13170203945Sweongyo		0x00143f1c, 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f,
13171203945Sweongyo		0x001e6f7e, 0x0021cfa4, 0x0025bfd2, 0x002a2008, 0x002fb047,
13172203945Sweongyo		0x00360090, 0x003d40e0, 0x0045c135, 0x004fb189, 0x005ae1d7,
13173203945Sweongyo		0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, 0x007ff2e3,
13174203945Sweongyo		0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
13175203945Sweongyo		0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506
13176203945Sweongyo	};
13177203945Sweongyo	static const uint32_t papdmult[] = {
13178203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13179203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13180203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13181203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13182203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13183203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13184203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13185203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13186203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13187203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13188203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13189203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13190203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13191203945Sweongyo	};
13192203945Sweongyo	static const uint32_t gainidx_a0[] = {
13193203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13194203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13195203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13196203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13197203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13198203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13199203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13200203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13201203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13202203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13203203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13204203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13205203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13206203945Sweongyo	};
13207203945Sweongyo	static const uint16_t auxgainidx_a0[] = {
13208203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13209203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000,
13210203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13211203945Sweongyo		0x0002, 0x0014
13212203945Sweongyo	};
13213203945Sweongyo	static const uint32_t gainval_a0[] = {
13214203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13215203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13216203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13217203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13218203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13219203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13220203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13221203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13222203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13223203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13224203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13225203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13226203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f,
13227203945Sweongyo		0x000000f7, 0x00000000, 0x00000000
13228203945Sweongyo	};
13229203945Sweongyo	static const uint16_t gain_a0[] = {
13230203945Sweongyo		0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b,
13231203945Sweongyo		0x000c, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016,
13232203945Sweongyo		0x0017, 0x001a, 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034,
13233203945Sweongyo		0x0037, 0x003b, 0x003f, 0x0040, 0x0044, 0x0057, 0x005b, 0x005f,
13234203945Sweongyo		0x00d7, 0x00db, 0x00df, 0x0157, 0x015b, 0x015f, 0x0357, 0x035b,
13235203945Sweongyo		0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, 0x0000, 0x0000, 0x0000,
13236203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13237203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13238203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13239203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13240203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13241203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13242203945Sweongyo	};
13243203945Sweongyo
13244203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13245203945Sweongyo
13246203945Sweongyo	for (i = 0; i < 704; i++)
13247203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(7, i), 0);
13248203945Sweongyo
13249203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13250203945Sweongyo	    bwn_tab_sigsq_tbl);
13251203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13252203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(11, 0), N(filterctl), filterctl);
13253203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(12, 0), N(psctl), psctl);
13254203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx), gainidx);
13255203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx), auxgainidx);
13256203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(swctl), swctl);
13257203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(16, 0), N(hf), hf);
13258203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval), gainval);
13259203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain), gain);
13260203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13261203945Sweongyo	    bwn_tab_pllfrac_tbl);
13262203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13263203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13264203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(papdeps), papdeps);
13265203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(papdmult), papdmult);
13266203945Sweongyo
13267204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
13268204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
13269203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx_a0),
13270203945Sweongyo		    gainidx_a0);
13271203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx_a0),
13272203945Sweongyo		    auxgainidx_a0);
13273203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval_a0),
13274203945Sweongyo		    gainval_a0);
13275203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain_a0), gain_a0);
13276203945Sweongyo	}
13277203945Sweongyo}
13278203945Sweongyo
13279203945Sweongyostatic void
13280203945Sweongyobwn_phy_lp_tblinit_txgain(struct bwn_mac *mac)
13281203945Sweongyo{
13282203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13283203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
13284203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
13285203945Sweongyo	static struct bwn_txgain_entry txgain_r2[] = {
13286203945Sweongyo		{ 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 },
13287203945Sweongyo		{ 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 },
13288203945Sweongyo		{ 255, 255, 203, 0, 135 }, { 255, 255, 203, 0, 131 },
13289203945Sweongyo		{ 255, 255, 203, 0, 128 }, { 255, 255, 203, 0, 124 },
13290203945Sweongyo		{ 255, 255, 203, 0, 121 }, { 255, 255, 203, 0, 117 },
13291203945Sweongyo		{ 255, 255, 203, 0, 114 }, { 255, 255, 203, 0, 111 },
13292203945Sweongyo		{ 255, 255, 203, 0, 107 }, { 255, 255, 203, 0, 104 },
13293203945Sweongyo		{ 255, 255, 203, 0, 101 }, { 255, 255, 203, 0, 99 },
13294203945Sweongyo		{ 255, 255, 203, 0, 96 }, { 255, 255, 203, 0, 93 },
13295203945Sweongyo		{ 255, 255, 203, 0, 90 }, { 255, 255, 203, 0, 88 },
13296203945Sweongyo		{ 255, 255, 203, 0, 85 }, { 255, 255, 203, 0, 83 },
13297203945Sweongyo		{ 255, 255, 203, 0, 81 }, { 255, 255, 203, 0, 78 },
13298203945Sweongyo		{ 255, 255, 203, 0, 76 }, { 255, 255, 203, 0, 74 },
13299203945Sweongyo		{ 255, 255, 203, 0, 72 }, { 255, 255, 203, 0, 70 },
13300203945Sweongyo		{ 255, 255, 203, 0, 68 }, { 255, 255, 203, 0, 66 },
13301203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13302203945Sweongyo		{ 255, 255, 192, 0, 64 }, { 255, 255, 186, 0, 64 },
13303203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 176, 0, 64 },
13304203945Sweongyo		{ 255, 255, 171, 0, 64 }, { 255, 255, 166, 0, 64 },
13305203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 157, 0, 64 },
13306203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13307203945Sweongyo		{ 255, 255, 144, 0, 64 }, { 255, 255, 140, 0, 64 },
13308203945Sweongyo		{ 255, 255, 136, 0, 64 }, { 255, 255, 132, 0, 64 },
13309203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13310203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13311203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13312203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 105, 0, 64 },
13313203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13314203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13315203945Sweongyo		{ 255, 255, 91, 0, 64 }, { 255, 255, 88, 0, 64 },
13316203945Sweongyo		{ 255, 255, 86, 0, 64 }, { 255, 255, 83, 0, 64 },
13317203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 79, 0, 64 },
13318203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13319203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13320203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13321203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 248, 64, 0, 64 },
13322203945Sweongyo		{ 255, 248, 62, 0, 64 }, { 255, 241, 62, 0, 64 },
13323203945Sweongyo		{ 255, 241, 60, 0, 64 }, { 255, 234, 60, 0, 64 },
13324203945Sweongyo		{ 255, 234, 59, 0, 64 }, { 255, 227, 59, 0, 64 },
13325203945Sweongyo		{ 255, 227, 57, 0, 64 }, { 255, 221, 57, 0, 64 },
13326203945Sweongyo		{ 255, 221, 55, 0, 64 }, { 255, 215, 55, 0, 64 },
13327203945Sweongyo		{ 255, 215, 54, 0, 64 }, { 255, 208, 54, 0, 64 },
13328203945Sweongyo		{ 255, 208, 52, 0, 64 }, { 255, 203, 52, 0, 64 },
13329203945Sweongyo		{ 255, 203, 51, 0, 64 }, { 255, 197, 51, 0, 64 },
13330203945Sweongyo		{ 255, 197, 49, 0, 64 }, { 255, 191, 49, 0, 64 },
13331203945Sweongyo		{ 255, 191, 48, 0, 64 }, { 255, 186, 48, 0, 64 },
13332203945Sweongyo		{ 255, 186, 47, 0, 64 }, { 255, 181, 47, 0, 64 },
13333203945Sweongyo		{ 255, 181, 45, 0, 64 }, { 255, 175, 45, 0, 64 },
13334203945Sweongyo		{ 255, 175, 44, 0, 64 }, { 255, 170, 44, 0, 64 },
13335203945Sweongyo		{ 255, 170, 43, 0, 64 }, { 255, 166, 43, 0, 64 },
13336203945Sweongyo		{ 255, 166, 42, 0, 64 }, { 255, 161, 42, 0, 64 },
13337203945Sweongyo		{ 255, 161, 40, 0, 64 }, { 255, 156, 40, 0, 64 },
13338203945Sweongyo		{ 255, 156, 39, 0, 64 }, { 255, 152, 39, 0, 64 },
13339203945Sweongyo		{ 255, 152, 38, 0, 64 }, { 255, 148, 38, 0, 64 },
13340203945Sweongyo		{ 255, 148, 37, 0, 64 }, { 255, 143, 37, 0, 64 },
13341203945Sweongyo		{ 255, 143, 36, 0, 64 }, { 255, 139, 36, 0, 64 },
13342203945Sweongyo		{ 255, 139, 35, 0, 64 }, { 255, 135, 35, 0, 64 },
13343203945Sweongyo		{ 255, 135, 34, 0, 64 }, { 255, 132, 34, 0, 64 },
13344203945Sweongyo		{ 255, 132, 33, 0, 64 }, { 255, 128, 33, 0, 64 },
13345203945Sweongyo		{ 255, 128, 32, 0, 64 }, { 255, 124, 32, 0, 64 },
13346203945Sweongyo		{ 255, 124, 31, 0, 64 }, { 255, 121, 31, 0, 64 },
13347203945Sweongyo		{ 255, 121, 30, 0, 64 }, { 255, 117, 30, 0, 64 },
13348203945Sweongyo		{ 255, 117, 29, 0, 64 }, { 255, 114, 29, 0, 64 },
13349203945Sweongyo		{ 255, 114, 29, 0, 64 }, { 255, 111, 29, 0, 64 },
13350203945Sweongyo	};
13351203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r2[] = {
13352203945Sweongyo		{ 7, 99, 255, 0, 64 }, { 7, 96, 255, 0, 64 },
13353203945Sweongyo		{ 7, 93, 255, 0, 64 }, { 7, 90, 255, 0, 64 },
13354203945Sweongyo		{ 7, 88, 255, 0, 64 }, { 7, 85, 255, 0, 64 },
13355203945Sweongyo		{ 7, 83, 255, 0, 64 }, { 7, 81, 255, 0, 64 },
13356203945Sweongyo		{ 7, 78, 255, 0, 64 }, { 7, 76, 255, 0, 64 },
13357203945Sweongyo		{ 7, 74, 255, 0, 64 }, { 7, 72, 255, 0, 64 },
13358203945Sweongyo		{ 7, 70, 255, 0, 64 }, { 7, 68, 255, 0, 64 },
13359203945Sweongyo		{ 7, 66, 255, 0, 64 }, { 7, 64, 255, 0, 64 },
13360203945Sweongyo		{ 7, 64, 255, 0, 64 }, { 7, 62, 255, 0, 64 },
13361203945Sweongyo		{ 7, 62, 248, 0, 64 }, { 7, 60, 248, 0, 64 },
13362203945Sweongyo		{ 7, 60, 241, 0, 64 }, { 7, 59, 241, 0, 64 },
13363203945Sweongyo		{ 7, 59, 234, 0, 64 }, { 7, 57, 234, 0, 64 },
13364203945Sweongyo		{ 7, 57, 227, 0, 64 }, { 7, 55, 227, 0, 64 },
13365203945Sweongyo		{ 7, 55, 221, 0, 64 }, { 7, 54, 221, 0, 64 },
13366203945Sweongyo		{ 7, 54, 215, 0, 64 }, { 7, 52, 215, 0, 64 },
13367203945Sweongyo		{ 7, 52, 208, 0, 64 }, { 7, 51, 208, 0, 64 },
13368203945Sweongyo		{ 7, 51, 203, 0, 64 }, { 7, 49, 203, 0, 64 },
13369203945Sweongyo		{ 7, 49, 197, 0, 64 }, { 7, 48, 197, 0, 64 },
13370203945Sweongyo		{ 7, 48, 191, 0, 64 }, { 7, 47, 191, 0, 64 },
13371203945Sweongyo		{ 7, 47, 186, 0, 64 }, { 7, 45, 186, 0, 64 },
13372203945Sweongyo		{ 7, 45, 181, 0, 64 }, { 7, 44, 181, 0, 64 },
13373203945Sweongyo		{ 7, 44, 175, 0, 64 }, { 7, 43, 175, 0, 64 },
13374203945Sweongyo		{ 7, 43, 170, 0, 64 }, { 7, 42, 170, 0, 64 },
13375203945Sweongyo		{ 7, 42, 166, 0, 64 }, { 7, 40, 166, 0, 64 },
13376203945Sweongyo		{ 7, 40, 161, 0, 64 }, { 7, 39, 161, 0, 64 },
13377203945Sweongyo		{ 7, 39, 156, 0, 64 }, { 7, 38, 156, 0, 64 },
13378203945Sweongyo		{ 7, 38, 152, 0, 64 }, { 7, 37, 152, 0, 64 },
13379203945Sweongyo		{ 7, 37, 148, 0, 64 }, { 7, 36, 148, 0, 64 },
13380203945Sweongyo		{ 7, 36, 143, 0, 64 }, { 7, 35, 143, 0, 64 },
13381203945Sweongyo		{ 7, 35, 139, 0, 64 }, { 7, 34, 139, 0, 64 },
13382203945Sweongyo		{ 7, 34, 135, 0, 64 }, { 7, 33, 135, 0, 64 },
13383203945Sweongyo		{ 7, 33, 132, 0, 64 }, { 7, 32, 132, 0, 64 },
13384203945Sweongyo		{ 7, 32, 128, 0, 64 }, { 7, 31, 128, 0, 64 },
13385203945Sweongyo		{ 7, 31, 124, 0, 64 }, { 7, 30, 124, 0, 64 },
13386203945Sweongyo		{ 7, 30, 121, 0, 64 }, { 7, 29, 121, 0, 64 },
13387203945Sweongyo		{ 7, 29, 117, 0, 64 }, { 7, 29, 117, 0, 64 },
13388203945Sweongyo		{ 7, 29, 114, 0, 64 }, { 7, 28, 114, 0, 64 },
13389203945Sweongyo		{ 7, 28, 111, 0, 64 }, { 7, 27, 111, 0, 64 },
13390203945Sweongyo		{ 7, 27, 108, 0, 64 }, { 7, 26, 108, 0, 64 },
13391203945Sweongyo		{ 7, 26, 104, 0, 64 }, { 7, 25, 104, 0, 64 },
13392203945Sweongyo		{ 7, 25, 102, 0, 64 }, { 7, 25, 102, 0, 64 },
13393203945Sweongyo		{ 7, 25, 99, 0, 64 }, { 7, 24, 99, 0, 64 },
13394203945Sweongyo		{ 7, 24, 96, 0, 64 }, { 7, 23, 96, 0, 64 },
13395203945Sweongyo		{ 7, 23, 93, 0, 64 }, { 7, 23, 93, 0, 64 },
13396203945Sweongyo		{ 7, 23, 90, 0, 64 }, { 7, 22, 90, 0, 64 },
13397203945Sweongyo		{ 7, 22, 88, 0, 64 }, { 7, 21, 88, 0, 64 },
13398203945Sweongyo		{ 7, 21, 85, 0, 64 }, { 7, 21, 85, 0, 64 },
13399203945Sweongyo		{ 7, 21, 83, 0, 64 }, { 7, 20, 83, 0, 64 },
13400203945Sweongyo		{ 7, 20, 81, 0, 64 }, { 7, 20, 81, 0, 64 },
13401203945Sweongyo		{ 7, 20, 78, 0, 64 }, { 7, 19, 78, 0, 64 },
13402203945Sweongyo		{ 7, 19, 76, 0, 64 }, { 7, 19, 76, 0, 64 },
13403203945Sweongyo		{ 7, 19, 74, 0, 64 }, { 7, 18, 74, 0, 64 },
13404203945Sweongyo		{ 7, 18, 72, 0, 64 }, { 7, 18, 72, 0, 64 },
13405203945Sweongyo		{ 7, 18, 70, 0, 64 }, { 7, 17, 70, 0, 64 },
13406203945Sweongyo		{ 7, 17, 68, 0, 64 }, { 7, 17, 68, 0, 64 },
13407203945Sweongyo		{ 7, 17, 66, 0, 64 }, { 7, 16, 66, 0, 64 },
13408203945Sweongyo		{ 7, 16, 64, 0, 64 }, { 7, 16, 64, 0, 64 },
13409203945Sweongyo		{ 7, 16, 62, 0, 64 }, { 7, 15, 62, 0, 64 },
13410203945Sweongyo		{ 7, 15, 60, 0, 64 }, { 7, 15, 60, 0, 64 },
13411203945Sweongyo		{ 7, 15, 59, 0, 64 }, { 7, 14, 59, 0, 64 },
13412203945Sweongyo		{ 7, 14, 57, 0, 64 }, { 7, 14, 57, 0, 64 },
13413203945Sweongyo		{ 7, 14, 55, 0, 64 }, { 7, 14, 55, 0, 64 },
13414203945Sweongyo		{ 7, 14, 54, 0, 64 }, { 7, 13, 54, 0, 64 },
13415203945Sweongyo		{ 7, 13, 52, 0, 64 }, { 7, 13, 52, 0, 64 },
13416203945Sweongyo	};
13417203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r2[] = {
13418203945Sweongyo		{ 255, 255, 255, 0, 152 }, { 255, 255, 255, 0, 147 },
13419203945Sweongyo		{ 255, 255, 255, 0, 143 }, { 255, 255, 255, 0, 139 },
13420203945Sweongyo		{ 255, 255, 255, 0, 135 }, { 255, 255, 255, 0, 131 },
13421203945Sweongyo		{ 255, 255, 255, 0, 128 }, { 255, 255, 255, 0, 124 },
13422203945Sweongyo		{ 255, 255, 255, 0, 121 }, { 255, 255, 255, 0, 117 },
13423203945Sweongyo		{ 255, 255, 255, 0, 114 }, { 255, 255, 255, 0, 111 },
13424203945Sweongyo		{ 255, 255, 255, 0, 107 }, { 255, 255, 255, 0, 104 },
13425203945Sweongyo		{ 255, 255, 255, 0, 101 }, { 255, 255, 255, 0, 99 },
13426203945Sweongyo		{ 255, 255, 255, 0, 96 }, { 255, 255, 255, 0, 93 },
13427203945Sweongyo		{ 255, 255, 255, 0, 90 }, { 255, 255, 255, 0, 88 },
13428203945Sweongyo		{ 255, 255, 255, 0, 85 }, { 255, 255, 255, 0, 83 },
13429203945Sweongyo		{ 255, 255, 255, 0, 81 }, { 255, 255, 255, 0, 78 },
13430203945Sweongyo		{ 255, 255, 255, 0, 76 }, { 255, 255, 255, 0, 74 },
13431203945Sweongyo		{ 255, 255, 255, 0, 72 }, { 255, 255, 255, 0, 70 },
13432203945Sweongyo		{ 255, 255, 255, 0, 68 }, { 255, 255, 255, 0, 66 },
13433203945Sweongyo		{ 255, 255, 255, 0, 64 }, { 255, 255, 248, 0, 64 },
13434203945Sweongyo		{ 255, 255, 241, 0, 64 }, { 255, 255, 234, 0, 64 },
13435203945Sweongyo		{ 255, 255, 227, 0, 64 }, { 255, 255, 221, 0, 64 },
13436203945Sweongyo		{ 255, 255, 215, 0, 64 }, { 255, 255, 208, 0, 64 },
13437203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13438203945Sweongyo		{ 255, 255, 191, 0, 64 }, { 255, 255, 186, 0, 64 },
13439203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 175, 0, 64 },
13440203945Sweongyo		{ 255, 255, 170, 0, 64 }, { 255, 255, 166, 0, 64 },
13441203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 156, 0, 64 },
13442203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13443203945Sweongyo		{ 255, 255, 143, 0, 64 }, { 255, 255, 139, 0, 64 },
13444203945Sweongyo		{ 255, 255, 135, 0, 64 }, { 255, 255, 132, 0, 64 },
13445203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13446203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13447203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13448203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 104, 0, 64 },
13449203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13450203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13451203945Sweongyo		{ 255, 255, 90, 0, 64 }, { 255, 255, 88, 0, 64 },
13452203945Sweongyo		{ 255, 255, 85, 0, 64 }, { 255, 255, 83, 0, 64 },
13453203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 78, 0, 64 },
13454203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13455203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13456203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13457203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 255, 64, 0, 64 },
13458203945Sweongyo		{ 255, 255, 62, 0, 64 }, { 255, 248, 62, 0, 64 },
13459203945Sweongyo		{ 255, 248, 60, 0, 64 }, { 255, 241, 60, 0, 64 },
13460203945Sweongyo		{ 255, 241, 59, 0, 64 }, { 255, 234, 59, 0, 64 },
13461203945Sweongyo		{ 255, 234, 57, 0, 64 }, { 255, 227, 57, 0, 64 },
13462203945Sweongyo		{ 255, 227, 55, 0, 64 }, { 255, 221, 55, 0, 64 },
13463203945Sweongyo		{ 255, 221, 54, 0, 64 }, { 255, 215, 54, 0, 64 },
13464203945Sweongyo		{ 255, 215, 52, 0, 64 }, { 255, 208, 52, 0, 64 },
13465203945Sweongyo		{ 255, 208, 51, 0, 64 }, { 255, 203, 51, 0, 64 },
13466203945Sweongyo		{ 255, 203, 49, 0, 64 }, { 255, 197, 49, 0, 64 },
13467203945Sweongyo		{ 255, 197, 48, 0, 64 }, { 255, 191, 48, 0, 64 },
13468203945Sweongyo		{ 255, 191, 47, 0, 64 }, { 255, 186, 47, 0, 64 },
13469203945Sweongyo		{ 255, 186, 45, 0, 64 }, { 255, 181, 45, 0, 64 },
13470203945Sweongyo		{ 255, 181, 44, 0, 64 }, { 255, 175, 44, 0, 64 },
13471203945Sweongyo		{ 255, 175, 43, 0, 64 }, { 255, 170, 43, 0, 64 },
13472203945Sweongyo		{ 255, 170, 42, 0, 64 }, { 255, 166, 42, 0, 64 },
13473203945Sweongyo		{ 255, 166, 40, 0, 64 }, { 255, 161, 40, 0, 64 },
13474203945Sweongyo		{ 255, 161, 39, 0, 64 }, { 255, 156, 39, 0, 64 },
13475203945Sweongyo		{ 255, 156, 38, 0, 64 }, { 255, 152, 38, 0, 64 },
13476203945Sweongyo		{ 255, 152, 37, 0, 64 }, { 255, 148, 37, 0, 64 },
13477203945Sweongyo		{ 255, 148, 36, 0, 64 }, { 255, 143, 36, 0, 64 },
13478203945Sweongyo		{ 255, 143, 35, 0, 64 }, { 255, 139, 35, 0, 64 },
13479203945Sweongyo		{ 255, 139, 34, 0, 64 }, { 255, 135, 34, 0, 64 },
13480203945Sweongyo		{ 255, 135, 33, 0, 64 }, { 255, 132, 33, 0, 64 },
13481203945Sweongyo		{ 255, 132, 32, 0, 64 }, { 255, 128, 32, 0, 64 }
13482203945Sweongyo	};
13483203945Sweongyo	static struct bwn_txgain_entry txgain_r0[] = {
13484203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13485203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13486203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13487203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13488203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13489203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13490203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13491203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13492203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13493203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13494203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13495203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13496203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13497203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13498203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13499203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13500203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13501203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13502203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 13, 0, 68 },
13503203945Sweongyo		{ 7, 15, 13, 0, 66 }, { 7, 15, 13, 0, 64 },
13504203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13505203945Sweongyo		{ 7, 15, 13, 0, 59 }, { 7, 15, 13, 0, 57 },
13506203945Sweongyo		{ 7, 15, 12, 0, 71 }, { 7, 15, 12, 0, 69 },
13507203945Sweongyo		{ 7, 15, 12, 0, 67 }, { 7, 15, 12, 0, 65 },
13508203945Sweongyo		{ 7, 15, 12, 0, 63 }, { 7, 15, 12, 0, 62 },
13509203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 58 },
13510203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 70 },
13511203945Sweongyo		{ 7, 15, 11, 0, 68 }, { 7, 15, 11, 0, 66 },
13512203945Sweongyo		{ 7, 15, 11, 0, 65 }, { 7, 15, 11, 0, 63 },
13513203945Sweongyo		{ 7, 15, 11, 0, 61 }, { 7, 15, 11, 0, 59 },
13514203945Sweongyo		{ 7, 15, 11, 0, 58 }, { 7, 15, 10, 0, 71 },
13515203945Sweongyo		{ 7, 15, 10, 0, 69 }, { 7, 15, 10, 0, 67 },
13516203945Sweongyo		{ 7, 15, 10, 0, 65 }, { 7, 15, 10, 0, 63 },
13517203945Sweongyo		{ 7, 15, 10, 0, 61 }, { 7, 15, 10, 0, 60 },
13518203945Sweongyo		{ 7, 15, 10, 0, 58 }, { 7, 15, 10, 0, 56 },
13519203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13520203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13521203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 60 },
13522203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 14, 9, 0, 72 },
13523203945Sweongyo		{ 7, 14, 9, 0, 70 }, { 7, 14, 9, 0, 68 },
13524203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 64 },
13525203945Sweongyo		{ 7, 14, 9, 0, 62 }, { 7, 14, 9, 0, 60 },
13526203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 13, 9, 0, 72 },
13527203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13528203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13529203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13530203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13531203945Sweongyo		{ 7, 13, 8, 0, 72 }, { 7, 13, 8, 0, 70 },
13532203945Sweongyo		{ 7, 13, 8, 0, 68 }, { 7, 13, 8, 0, 66 },
13533203945Sweongyo		{ 7, 13, 8, 0, 64 }, { 7, 13, 8, 0, 62 },
13534203945Sweongyo		{ 7, 13, 8, 0, 60 }, { 7, 13, 8, 0, 59 },
13535203945Sweongyo		{ 7, 12, 8, 0, 72 }, { 7, 12, 8, 0, 70 },
13536203945Sweongyo		{ 7, 12, 8, 0, 68 }, { 7, 12, 8, 0, 66 },
13537203945Sweongyo		{ 7, 12, 8, 0, 64 }, { 7, 12, 8, 0, 62 },
13538203945Sweongyo		{ 7, 12, 8, 0, 61 }, { 7, 12, 8, 0, 59 },
13539203945Sweongyo		{ 7, 12, 7, 0, 73 }, { 7, 12, 7, 0, 71 },
13540203945Sweongyo		{ 7, 12, 7, 0, 69 }, { 7, 12, 7, 0, 67 },
13541203945Sweongyo		{ 7, 12, 7, 0, 65 }, { 7, 12, 7, 0, 63 },
13542203945Sweongyo		{ 7, 12, 7, 0, 61 }, { 7, 12, 7, 0, 59 },
13543203945Sweongyo		{ 7, 11, 7, 0, 72 }, { 7, 11, 7, 0, 70 },
13544203945Sweongyo		{ 7, 11, 7, 0, 68 }, { 7, 11, 7, 0, 66 },
13545203945Sweongyo		{ 7, 11, 7, 0, 65 }, { 7, 11, 7, 0, 63 },
13546203945Sweongyo		{ 7, 11, 7, 0, 61 }, { 7, 11, 7, 0, 59 },
13547203945Sweongyo		{ 7, 11, 6, 0, 73 }, { 7, 11, 6, 0, 71 }
13548203945Sweongyo	};
13549203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r0[] = {
13550203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13551203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13552203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13553203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13554203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13555203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13556203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13557203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13558203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13559203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13560203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13561203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13562203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13563203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13564203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13565203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13566203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13567203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13568203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13569203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13570203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13571203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13572203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13573203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13574203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13575203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13576203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13577203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13578203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13579203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13580203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13581203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13582203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13583203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 },
13584203945Sweongyo		{ 4, 10, 6, 0, 59 }, { 4, 10, 5, 0, 72 },
13585203945Sweongyo		{ 4, 10, 5, 0, 70 }, { 4, 10, 5, 0, 68 },
13586203945Sweongyo		{ 4, 10, 5, 0, 66 }, { 4, 10, 5, 0, 64 },
13587203945Sweongyo		{ 4, 10, 5, 0, 62 }, { 4, 10, 5, 0, 60 },
13588203945Sweongyo		{ 4, 10, 5, 0, 59 }, { 4, 9, 5, 0, 70 },
13589203945Sweongyo		{ 4, 9, 5, 0, 68 }, { 4, 9, 5, 0, 66 },
13590203945Sweongyo		{ 4, 9, 5, 0, 64 }, { 4, 9, 5, 0, 63 },
13591203945Sweongyo		{ 4, 9, 5, 0, 61 }, { 4, 9, 5, 0, 59 },
13592203945Sweongyo		{ 4, 9, 4, 0, 71 }, { 4, 9, 4, 0, 69 },
13593203945Sweongyo		{ 4, 9, 4, 0, 67 }, { 4, 9, 4, 0, 65 },
13594203945Sweongyo		{ 4, 9, 4, 0, 63 }, { 4, 9, 4, 0, 62 },
13595203945Sweongyo		{ 4, 9, 4, 0, 60 }, { 4, 9, 4, 0, 58 },
13596203945Sweongyo		{ 4, 8, 4, 0, 70 }, { 4, 8, 4, 0, 68 },
13597203945Sweongyo		{ 4, 8, 4, 0, 66 }, { 4, 8, 4, 0, 65 },
13598203945Sweongyo		{ 4, 8, 4, 0, 63 }, { 4, 8, 4, 0, 61 },
13599203945Sweongyo		{ 4, 8, 4, 0, 59 }, { 4, 7, 4, 0, 68 },
13600203945Sweongyo		{ 4, 7, 4, 0, 66 }, { 4, 7, 4, 0, 64 },
13601203945Sweongyo		{ 4, 7, 4, 0, 62 }, { 4, 7, 4, 0, 61 },
13602203945Sweongyo		{ 4, 7, 4, 0, 59 }, { 4, 7, 3, 0, 67 },
13603203945Sweongyo		{ 4, 7, 3, 0, 65 }, { 4, 7, 3, 0, 63 },
13604203945Sweongyo		{ 4, 7, 3, 0, 62 }, { 4, 7, 3, 0, 60 },
13605203945Sweongyo		{ 4, 6, 3, 0, 65 }, { 4, 6, 3, 0, 63 },
13606203945Sweongyo		{ 4, 6, 3, 0, 61 }, { 4, 6, 3, 0, 60 },
13607203945Sweongyo		{ 4, 6, 3, 0, 58 }, { 4, 5, 3, 0, 68 },
13608203945Sweongyo		{ 4, 5, 3, 0, 66 }, { 4, 5, 3, 0, 64 },
13609203945Sweongyo		{ 4, 5, 3, 0, 62 }, { 4, 5, 3, 0, 60 },
13610203945Sweongyo		{ 4, 5, 3, 0, 59 }, { 4, 5, 3, 0, 57 },
13611203945Sweongyo		{ 4, 4, 2, 0, 83 }, { 4, 4, 2, 0, 81 },
13612203945Sweongyo		{ 4, 4, 2, 0, 78 }, { 4, 4, 2, 0, 76 },
13613203945Sweongyo		{ 4, 4, 2, 0, 74 }, { 4, 4, 2, 0, 72 }
13614203945Sweongyo	};
13615203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r0[] = {
13616203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13617203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13618203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13619203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13620203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13621203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13622203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13623203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13624203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13625203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13626203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13627203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13628203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13629203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13630203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13631203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13632203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13633203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13634203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13635203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13636203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13637203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13638203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13639203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13640203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13641203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13642203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13643203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13644203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13645203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13646203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13647203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13648203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13649203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13650203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13651203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13652203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13653203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13654203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13655203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13656203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13657203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13658203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13659203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13660203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13661203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13662203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13663203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13664203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13665203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13666203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13667203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13668203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13669203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13670203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13671203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13672203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13673203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13674203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13675203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13676203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13677203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13678203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13679203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13680203945Sweongyo	};
13681203945Sweongyo	static struct bwn_txgain_entry txgain_r1[] = {
13682203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13683203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13684203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13685203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13686203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13687203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13688203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13689203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13690203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13691203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13692203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13693203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13694203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13695203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13696203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13697203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13698203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13699203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13700203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 14, 0, 68 },
13701203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13702203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13703203945Sweongyo		{ 7, 15, 14, 0, 59 }, { 7, 15, 14, 0, 57 },
13704203945Sweongyo		{ 7, 15, 13, 0, 72 }, { 7, 15, 13, 0, 70 },
13705203945Sweongyo		{ 7, 15, 13, 0, 68 }, { 7, 15, 13, 0, 66 },
13706203945Sweongyo		{ 7, 15, 13, 0, 64 }, { 7, 15, 13, 0, 62 },
13707203945Sweongyo		{ 7, 15, 13, 0, 60 }, { 7, 15, 13, 0, 59 },
13708203945Sweongyo		{ 7, 15, 13, 0, 57 }, { 7, 15, 12, 0, 71 },
13709203945Sweongyo		{ 7, 15, 12, 0, 69 }, { 7, 15, 12, 0, 67 },
13710203945Sweongyo		{ 7, 15, 12, 0, 65 }, { 7, 15, 12, 0, 63 },
13711203945Sweongyo		{ 7, 15, 12, 0, 62 }, { 7, 15, 12, 0, 60 },
13712203945Sweongyo		{ 7, 15, 12, 0, 58 }, { 7, 15, 12, 0, 57 },
13713203945Sweongyo		{ 7, 15, 11, 0, 70 }, { 7, 15, 11, 0, 68 },
13714203945Sweongyo		{ 7, 15, 11, 0, 66 }, { 7, 15, 11, 0, 65 },
13715203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13716203945Sweongyo		{ 7, 15, 11, 0, 59 }, { 7, 15, 11, 0, 58 },
13717203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13718203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13719203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13720203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13721203945Sweongyo		{ 7, 15, 10, 0, 56 }, { 7, 15, 9, 0, 70 },
13722203945Sweongyo		{ 7, 15, 9, 0, 68 }, { 7, 15, 9, 0, 66 },
13723203945Sweongyo		{ 7, 15, 9, 0, 64 }, { 7, 15, 9, 0, 62 },
13724203945Sweongyo		{ 7, 15, 9, 0, 60 }, { 7, 15, 9, 0, 59 },
13725203945Sweongyo		{ 7, 14, 9, 0, 72 }, { 7, 14, 9, 0, 70 },
13726203945Sweongyo		{ 7, 14, 9, 0, 68 }, { 7, 14, 9, 0, 66 },
13727203945Sweongyo		{ 7, 14, 9, 0, 64 }, { 7, 14, 9, 0, 62 },
13728203945Sweongyo		{ 7, 14, 9, 0, 60 }, { 7, 14, 9, 0, 59 },
13729203945Sweongyo		{ 7, 13, 9, 0, 72 }, { 7, 13, 9, 0, 70 },
13730203945Sweongyo		{ 7, 13, 9, 0, 68 }, { 7, 13, 9, 0, 66 },
13731203945Sweongyo		{ 7, 13, 9, 0, 64 }, { 7, 13, 9, 0, 63 },
13732203945Sweongyo		{ 7, 13, 9, 0, 61 }, { 7, 13, 9, 0, 59 },
13733203945Sweongyo		{ 7, 13, 9, 0, 57 }, { 7, 13, 8, 0, 72 },
13734203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13735203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13736203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13737203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 12, 8, 0, 72 },
13738203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13739203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13740203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13741203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 7, 0, 73 },
13742203945Sweongyo		{ 7, 12, 7, 0, 71 }, { 7, 12, 7, 0, 69 },
13743203945Sweongyo		{ 7, 12, 7, 0, 67 }, { 7, 12, 7, 0, 65 },
13744203945Sweongyo		{ 7, 12, 7, 0, 63 }, { 7, 12, 7, 0, 61 },
13745203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 11, 7, 0, 72 },
13746203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13747203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 65 },
13748203945Sweongyo		{ 7, 11, 7, 0, 63 }, { 7, 11, 7, 0, 61 },
13749203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 6, 0, 73 },
13750203945Sweongyo		{ 7, 11, 6, 0, 71 }
13751203945Sweongyo	};
13752203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r1[] = {
13753203945Sweongyo		{ 4, 15, 15, 0, 90 }, { 4, 15, 15, 0, 88 },
13754203945Sweongyo		{ 4, 15, 15, 0, 85 }, { 4, 15, 15, 0, 83 },
13755203945Sweongyo		{ 4, 15, 15, 0, 81 }, { 4, 15, 15, 0, 78 },
13756203945Sweongyo		{ 4, 15, 15, 0, 76 }, { 4, 15, 15, 0, 74 },
13757203945Sweongyo		{ 4, 15, 15, 0, 72 }, { 4, 15, 15, 0, 70 },
13758203945Sweongyo		{ 4, 15, 15, 0, 68 }, { 4, 15, 15, 0, 66 },
13759203945Sweongyo		{ 4, 15, 15, 0, 64 }, { 4, 15, 15, 0, 62 },
13760203945Sweongyo		{ 4, 15, 15, 0, 60 }, { 4, 15, 15, 0, 59 },
13761203945Sweongyo		{ 4, 15, 14, 0, 72 }, { 4, 15, 14, 0, 70 },
13762203945Sweongyo		{ 4, 15, 14, 0, 68 }, { 4, 15, 14, 0, 66 },
13763203945Sweongyo		{ 4, 15, 14, 0, 64 }, { 4, 15, 14, 0, 62 },
13764203945Sweongyo		{ 4, 15, 14, 0, 60 }, { 4, 15, 14, 0, 59 },
13765203945Sweongyo		{ 4, 15, 13, 0, 72 }, { 4, 15, 13, 0, 70 },
13766203945Sweongyo		{ 4, 15, 13, 0, 68 }, { 4, 15, 13, 0, 66 },
13767203945Sweongyo		{ 4, 15, 13, 0, 64 }, { 4, 15, 13, 0, 62 },
13768203945Sweongyo		{ 4, 15, 13, 0, 60 }, { 4, 15, 13, 0, 59 },
13769203945Sweongyo		{ 4, 15, 12, 0, 72 }, { 4, 15, 12, 0, 70 },
13770203945Sweongyo		{ 4, 15, 12, 0, 68 }, { 4, 15, 12, 0, 66 },
13771203945Sweongyo		{ 4, 15, 12, 0, 64 }, { 4, 15, 12, 0, 62 },
13772203945Sweongyo		{ 4, 15, 12, 0, 60 }, { 4, 15, 12, 0, 59 },
13773203945Sweongyo		{ 4, 15, 11, 0, 72 }, { 4, 15, 11, 0, 70 },
13774203945Sweongyo		{ 4, 15, 11, 0, 68 }, { 4, 15, 11, 0, 66 },
13775203945Sweongyo		{ 4, 15, 11, 0, 64 }, { 4, 15, 11, 0, 62 },
13776203945Sweongyo		{ 4, 15, 11, 0, 60 }, { 4, 15, 11, 0, 59 },
13777203945Sweongyo		{ 4, 15, 10, 0, 72 }, { 4, 15, 10, 0, 70 },
13778203945Sweongyo		{ 4, 15, 10, 0, 68 }, { 4, 15, 10, 0, 66 },
13779203945Sweongyo		{ 4, 15, 10, 0, 64 }, { 4, 15, 10, 0, 62 },
13780203945Sweongyo		{ 4, 15, 10, 0, 60 }, { 4, 15, 10, 0, 59 },
13781203945Sweongyo		{ 4, 15, 9, 0, 72 }, { 4, 15, 9, 0, 70 },
13782203945Sweongyo		{ 4, 15, 9, 0, 68 }, { 4, 15, 9, 0, 66 },
13783203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13784203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13785203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13786203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13787203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13788203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13789203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13790203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13791203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13792203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13793203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13794203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13795203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13796203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13797203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13798203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13799203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13800203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13801203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13802203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13803203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13804203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13805203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13806203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13807203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13808203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13809203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13810203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13811203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13812203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13813203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13814203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13815203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13816203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 }
13817203945Sweongyo	};
13818203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r1[] = {
13819203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13820203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13821203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13822203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13823203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13824203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13825203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13826203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13827203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13828203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13829203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13830203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13831203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13832203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13833203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13834203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13835203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13836203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13837203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13838203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13839203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13840203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13841203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13842203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13843203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13844203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13845203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13846203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13847203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13848203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13849203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13850203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13851203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13852203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13853203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13854203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13855203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13856203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13857203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13858203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13859203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13860203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13861203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13862203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13863203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13864203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13865203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13866203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13867203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13868203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13869203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13870203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13871203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13872203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13873203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13874203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13875203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13876203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13877203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13878203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13879203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13880203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13881203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13882203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13883203945Sweongyo	};
13884203945Sweongyo
13885203945Sweongyo	if (mac->mac_phy.rev != 0 && mac->mac_phy.rev != 1) {
13886204922Sweongyo		if (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA)
13887203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r2);
13888203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13889203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13890203945Sweongyo			    txgain_2ghz_r2);
13891203945Sweongyo		else
13892203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13893203945Sweongyo			    txgain_5ghz_r2);
13894203945Sweongyo		return;
13895203945Sweongyo	}
13896203945Sweongyo
13897203945Sweongyo	if (mac->mac_phy.rev == 0) {
13898204922Sweongyo		if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
13899204922Sweongyo		    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_HGPA))
13900203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r0);
13901203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13902203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13903203945Sweongyo			    txgain_2ghz_r0);
13904203945Sweongyo		else
13905203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13906203945Sweongyo			    txgain_5ghz_r0);
13907203945Sweongyo		return;
13908203945Sweongyo	}
13909203945Sweongyo
13910204922Sweongyo	if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
13911204922Sweongyo	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_HGPA))
13912203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r1);
13913203945Sweongyo	else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13914203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_2ghz_r1);
13915203945Sweongyo	else
13916203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_5ghz_r1);
13917203945Sweongyo}
13918203945Sweongyo
13919203945Sweongyostatic void
13920203945Sweongyobwn_tab_write(struct bwn_mac *mac, uint32_t typeoffset, uint32_t value)
13921203945Sweongyo{
13922203945Sweongyo	uint32_t offset, type;
13923203945Sweongyo
13924203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
13925203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
13926203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
13927203945Sweongyo
13928203945Sweongyo	switch (type) {
13929203945Sweongyo	case BWN_TAB_8BIT:
13930203945Sweongyo		KASSERT(!(value & ~0xff), ("%s:%d: fail", __func__, __LINE__));
13931203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13932203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13933203945Sweongyo		break;
13934203945Sweongyo	case BWN_TAB_16BIT:
13935203945Sweongyo		KASSERT(!(value & ~0xffff),
13936203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
13937203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13938203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13939203945Sweongyo		break;
13940203945Sweongyo	case BWN_TAB_32BIT:
13941203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13942203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
13943203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13944203945Sweongyo		break;
13945203945Sweongyo	default:
13946203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
13947203945Sweongyo	}
13948203945Sweongyo}
13949203945Sweongyo
13950203945Sweongyostatic int
13951203945Sweongyobwn_phy_lp_loopback(struct bwn_mac *mac)
13952203945Sweongyo{
13953203945Sweongyo	struct bwn_phy_lp_iq_est ie;
13954203945Sweongyo	int i, index = -1;
13955203945Sweongyo	uint32_t tmp;
13956203945Sweongyo
13957203945Sweongyo	memset(&ie, 0, sizeof(ie));
13958203945Sweongyo
13959203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1, 1);
13960203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 1);
13961203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
13962203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
13963203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
13964203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
13965203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x8);
13966203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, 0x80);
13967203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x80);
13968203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x80);
13969203945Sweongyo	for (i = 0; i < 32; i++) {
13970203945Sweongyo		bwn_phy_lp_set_rxgain_idx(mac, i);
13971203945Sweongyo		bwn_phy_lp_ddfs_turnon(mac, 1, 1, 5, 5, 0);
13972203945Sweongyo		if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
13973203945Sweongyo			continue;
13974203945Sweongyo		tmp = (ie.ie_ipwr + ie.ie_qpwr) / 1000;
13975203945Sweongyo		if ((tmp > 4000) && (tmp < 10000)) {
13976203945Sweongyo			index = i;
13977203945Sweongyo			break;
13978203945Sweongyo		}
13979203945Sweongyo	}
13980203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
13981203945Sweongyo	return (index);
13982203945Sweongyo}
13983203945Sweongyo
13984203945Sweongyostatic void
13985203945Sweongyobwn_phy_lp_set_rxgain_idx(struct bwn_mac *mac, uint16_t idx)
13986203945Sweongyo{
13987203945Sweongyo
13988203945Sweongyo	bwn_phy_lp_set_rxgain(mac, bwn_tab_read(mac, BWN_TAB_2(12, idx)));
13989203945Sweongyo}
13990203945Sweongyo
13991203945Sweongyostatic void
13992203945Sweongyobwn_phy_lp_ddfs_turnon(struct bwn_mac *mac, int i_on, int q_on,
13993203945Sweongyo    int incr1, int incr2, int scale_idx)
13994203945Sweongyo{
13995203945Sweongyo
13996203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
13997203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0xff80);
13998203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0x80ff);
13999203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0xff80, incr1);
14000203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0x80ff, incr2 << 8);
14001203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff7, i_on << 3);
14002203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xffef, q_on << 4);
14003203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xff9f, scale_idx << 5);
14004203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffb);
14005203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DDFS, 0x2);
14006203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x20);
14007203945Sweongyo}
14008203945Sweongyo
14009203945Sweongyostatic uint8_t
14010203945Sweongyobwn_phy_lp_rx_iq_est(struct bwn_mac *mac, uint16_t sample, uint8_t time,
14011203945Sweongyo    struct bwn_phy_lp_iq_est *ie)
14012203945Sweongyo{
14013203945Sweongyo	int i;
14014203945Sweongyo
14015203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfff7);
14016203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_IQ_NUM_SMPLS_ADDR, sample);
14017203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xff00, time);
14018203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xfeff);
14019203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
14020203945Sweongyo
14021203945Sweongyo	for (i = 0; i < 500; i++) {
14022203945Sweongyo		if (!(BWN_PHY_READ(mac,
14023203945Sweongyo		    BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
14024203945Sweongyo			break;
14025203945Sweongyo		DELAY(1000);
14026203945Sweongyo	}
14027203945Sweongyo	if ((BWN_PHY_READ(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
14028203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14029203945Sweongyo		return 0;
14030203945Sweongyo	}
14031203945Sweongyo
14032203945Sweongyo	ie->ie_iqprod = BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_HI_ADDR);
14033203945Sweongyo	ie->ie_iqprod <<= 16;
14034203945Sweongyo	ie->ie_iqprod |= BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_LO_ADDR);
14035203945Sweongyo	ie->ie_ipwr = BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_HI_ADDR);
14036203945Sweongyo	ie->ie_ipwr <<= 16;
14037203945Sweongyo	ie->ie_ipwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_LO_ADDR);
14038203945Sweongyo	ie->ie_qpwr = BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR);
14039203945Sweongyo	ie->ie_qpwr <<= 16;
14040203945Sweongyo	ie->ie_qpwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR);
14041203945Sweongyo
14042203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14043203945Sweongyo	return 1;
14044203945Sweongyo}
14045203945Sweongyo
14046203945Sweongyostatic uint32_t
14047203945Sweongyobwn_tab_read(struct bwn_mac *mac, uint32_t typeoffset)
14048203945Sweongyo{
14049203945Sweongyo	uint32_t offset, type, value;
14050203945Sweongyo
14051203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
14052203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
14053203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
14054203945Sweongyo
14055203945Sweongyo	switch (type) {
14056203945Sweongyo	case BWN_TAB_8BIT:
14057203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14058203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
14059203945Sweongyo		break;
14060203945Sweongyo	case BWN_TAB_16BIT:
14061203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14062203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14063203945Sweongyo		break;
14064203945Sweongyo	case BWN_TAB_32BIT:
14065203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14066203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATAHI);
14067203945Sweongyo		value <<= 16;
14068203945Sweongyo		value |= BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14069203945Sweongyo		break;
14070203945Sweongyo	default:
14071203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
14072203945Sweongyo		value = 0;
14073203945Sweongyo	}
14074203945Sweongyo
14075203945Sweongyo	return (value);
14076203945Sweongyo}
14077203945Sweongyo
14078203945Sweongyostatic void
14079203945Sweongyobwn_phy_lp_ddfs_turnoff(struct bwn_mac *mac)
14080203945Sweongyo{
14081203945Sweongyo
14082203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffd);
14083203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0xffdf);
14084203945Sweongyo}
14085203945Sweongyo
14086203945Sweongyostatic void
14087203945Sweongyobwn_phy_lp_set_txgain_dac(struct bwn_mac *mac, uint16_t dac)
14088203945Sweongyo{
14089203945Sweongyo	uint16_t ctl;
14090203945Sweongyo
14091203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0xc7f;
14092203945Sweongyo	ctl |= dac << 7;
14093203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf000, ctl);
14094203945Sweongyo}
14095203945Sweongyo
14096203945Sweongyostatic void
14097203945Sweongyobwn_phy_lp_set_txgain_pa(struct bwn_mac *mac, uint16_t gain)
14098203945Sweongyo{
14099203945Sweongyo
14100203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0xe03f, gain << 6);
14101203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x80ff, gain << 8);
14102203945Sweongyo}
14103203945Sweongyo
14104203945Sweongyostatic void
14105203945Sweongyobwn_phy_lp_set_txgain_override(struct bwn_mac *mac)
14106203945Sweongyo{
14107203945Sweongyo
14108203945Sweongyo	if (mac->mac_phy.rev < 2)
14109203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
14110203945Sweongyo	else {
14111203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x80);
14112203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x4000);
14113203945Sweongyo	}
14114203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x40);
14115203945Sweongyo}
14116203945Sweongyo
14117203945Sweongyostatic uint16_t
14118203945Sweongyobwn_phy_lp_get_pa_gain(struct bwn_mac *mac)
14119203945Sweongyo{
14120203945Sweongyo
14121203945Sweongyo	return BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0x7f;
14122203945Sweongyo}
14123203945Sweongyo
14124203945Sweongyostatic uint8_t
14125203945Sweongyobwn_nbits(int32_t val)
14126203945Sweongyo{
14127203945Sweongyo	uint32_t tmp;
14128203945Sweongyo	uint8_t nbits = 0;
14129203945Sweongyo
14130203945Sweongyo	for (tmp = abs(val); tmp != 0; tmp >>= 1)
14131203945Sweongyo		nbits++;
14132203945Sweongyo	return (nbits);
14133203945Sweongyo}
14134203945Sweongyo
14135203945Sweongyostatic void
14136203945Sweongyobwn_phy_lp_gaintbl_write_multi(struct bwn_mac *mac, int offset, int count,
14137203945Sweongyo    struct bwn_txgain_entry *table)
14138203945Sweongyo{
14139203945Sweongyo	int i;
14140203945Sweongyo
14141203945Sweongyo	for (i = offset; i < count; i++)
14142203945Sweongyo		bwn_phy_lp_gaintbl_write(mac, i, table[i]);
14143203945Sweongyo}
14144203945Sweongyo
14145203945Sweongyostatic void
14146203945Sweongyobwn_phy_lp_gaintbl_write(struct bwn_mac *mac, int offset,
14147203945Sweongyo    struct bwn_txgain_entry data)
14148203945Sweongyo{
14149203945Sweongyo
14150203945Sweongyo	if (mac->mac_phy.rev >= 2)
14151203945Sweongyo		bwn_phy_lp_gaintbl_write_r2(mac, offset, data);
14152203945Sweongyo	else
14153203945Sweongyo		bwn_phy_lp_gaintbl_write_r01(mac, offset, data);
14154203945Sweongyo}
14155203945Sweongyo
14156203945Sweongyostatic void
14157203945Sweongyobwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset,
14158203945Sweongyo    struct bwn_txgain_entry te)
14159203945Sweongyo{
14160203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
14161203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
14162203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
14163203945Sweongyo	uint32_t tmp;
14164203945Sweongyo
14165203945Sweongyo	KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__));
14166203945Sweongyo
14167203945Sweongyo	tmp = (te.te_pad << 16) | (te.te_pga << 8) | te.te_gm;
14168203945Sweongyo	if (mac->mac_phy.rev >= 3) {
14169203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14170203945Sweongyo		    (0x10 << 24) : (0x70 << 24));
14171203945Sweongyo	} else {
14172203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14173203945Sweongyo		    (0x14 << 24) : (0x7f << 24));
14174203945Sweongyo	}
14175203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0xc0 + offset), tmp);
14176203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0x140 + offset),
14177203945Sweongyo	    te.te_bbmult << 20 | te.te_dac << 28);
14178203945Sweongyo}
14179203945Sweongyo
14180203945Sweongyostatic void
14181203945Sweongyobwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
14182203945Sweongyo    struct bwn_txgain_entry te)
14183203945Sweongyo{
14184203945Sweongyo
14185203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
14186203945Sweongyo
14187203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0xc0 + offset),
14188203945Sweongyo	    (te.te_pad << 11) | (te.te_pga << 7) | (te.te_gm  << 4) |
14189203945Sweongyo	    te.te_dac);
14190203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0x140 + offset), te.te_bbmult << 20);
14191203945Sweongyo}
14192203945Sweongyo
14193203945Sweongyostatic void
14194204257Sweongyobwn_sysctl_node(struct bwn_softc *sc)
14195204257Sweongyo{
14196204257Sweongyo	device_t dev = sc->sc_dev;
14197204257Sweongyo	struct bwn_mac *mac;
14198204257Sweongyo	struct bwn_stats *stats;
14199204257Sweongyo
14200204257Sweongyo	/* XXX assume that count of MAC is only 1. */
14201204257Sweongyo
14202204257Sweongyo	if ((mac = sc->sc_curmac) == NULL)
14203204257Sweongyo		return;
14204204257Sweongyo	stats = &mac->mac_stats;
14205204257Sweongyo
14206217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
14207204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14208204257Sweongyo	    "linknoise", CTLFLAG_RW, &stats->rts, 0, "Noise level");
14209217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
14210204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14211204257Sweongyo	    "rts", CTLFLAG_RW, &stats->rts, 0, "RTS");
14212217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
14213204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14214204257Sweongyo	    "rtsfail", CTLFLAG_RW, &stats->rtsfail, 0, "RTS failed to send");
14215204257Sweongyo
14216204257Sweongyo#ifdef BWN_DEBUG
14217204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14218204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14219204257Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
14220204257Sweongyo#endif
14221204257Sweongyo}
14222204257Sweongyo
14223203945Sweongyostatic device_method_t bwn_methods[] = {
14224203945Sweongyo	/* Device interface */
14225203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
14226203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
14227203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
14228203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
14229203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
14230227848Smarius	DEVMETHOD_END
14231203945Sweongyo};
14232203945Sweongyostatic driver_t bwn_driver = {
14233203945Sweongyo	"bwn",
14234203945Sweongyo	bwn_methods,
14235203945Sweongyo	sizeof(struct bwn_softc)
14236203945Sweongyo};
14237203945Sweongyostatic devclass_t bwn_devclass;
14238203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
14239203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
14240203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
14241203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
14242203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
14243