if_bwn.c revision 204242
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 204242 2010-02-23 05:02:10Z imp $");
32203945Sweongyo
33203945Sweongyo/*
34203945Sweongyo * The Broadcom Wireless LAN controller driver.
35203945Sweongyo */
36203945Sweongyo
37203945Sweongyo#include <sys/param.h>
38203945Sweongyo#include <sys/systm.h>
39203945Sweongyo#include <sys/module.h>
40203945Sweongyo#include <sys/kernel.h>
41203945Sweongyo#include <sys/endian.h>
42203945Sweongyo#include <sys/errno.h>
43203945Sweongyo#include <sys/firmware.h>
44203945Sweongyo#include <sys/lock.h>
45203945Sweongyo#include <sys/mutex.h>
46203945Sweongyo#include <machine/bus.h>
47203945Sweongyo#include <machine/resource.h>
48203945Sweongyo#include <sys/bus.h>
49203945Sweongyo#include <sys/rman.h>
50203945Sweongyo#include <sys/socket.h>
51203945Sweongyo#include <sys/sockio.h>
52203945Sweongyo
53203945Sweongyo#include <net/ethernet.h>
54203945Sweongyo#include <net/if.h>
55203945Sweongyo#include <net/if_arp.h>
56203945Sweongyo#include <net/if_dl.h>
57203945Sweongyo#include <net/if_llc.h>
58203945Sweongyo#include <net/if_media.h>
59203945Sweongyo#include <net/if_types.h>
60203945Sweongyo
61203945Sweongyo#include <dev/pci/pcivar.h>
62203945Sweongyo#include <dev/pci/pcireg.h>
63203945Sweongyo#include <dev/siba/siba_ids.h>
64203945Sweongyo#include <dev/siba/sibareg.h>
65203945Sweongyo#include <dev/siba/sibavar.h>
66203945Sweongyo
67203945Sweongyo#include <net80211/ieee80211_var.h>
68203945Sweongyo#include <net80211/ieee80211_radiotap.h>
69203945Sweongyo#include <net80211/ieee80211_regdomain.h>
70203945Sweongyo#include <net80211/ieee80211_amrr.h>
71203945Sweongyo#include <net80211/ieee80211_phy.h>
72203945Sweongyo
73203945Sweongyo#include <dev/bwn/if_bwnreg.h>
74203945Sweongyo#include <dev/bwn/if_bwnvar.h>
75203945Sweongyo
76203945SweongyoSYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0, "Broadcom driver parameters");
77203945Sweongyo
78203945Sweongyo/*
79203945Sweongyo * Tunable & sysctl variables.
80203945Sweongyo */
81203945Sweongyo
82203945Sweongyo#ifdef BWN_DEBUG
83203945Sweongyostatic	int bwn_debug = 0;
84203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RW, &bwn_debug, 0,
85203945Sweongyo    "Broadcom debugging printfs");
86203945SweongyoTUNABLE_INT("hw.bwn.debug", &bwn_debug);
87203945Sweongyoenum {
88203945Sweongyo	BWN_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
89203945Sweongyo	BWN_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
90203945Sweongyo	BWN_DEBUG_STATE		= 0x00000004,	/* 802.11 state transitions */
91203945Sweongyo	BWN_DEBUG_TXPOW		= 0x00000008,	/* tx power processing */
92203945Sweongyo	BWN_DEBUG_RESET		= 0x00000010,	/* reset processing */
93203945Sweongyo	BWN_DEBUG_OPS		= 0x00000020,	/* bwn_ops processing */
94203945Sweongyo	BWN_DEBUG_BEACON	= 0x00000040,	/* beacon handling */
95203945Sweongyo	BWN_DEBUG_WATCHDOG	= 0x00000080,	/* watchdog timeout */
96203945Sweongyo	BWN_DEBUG_INTR		= 0x00000100,	/* ISR */
97203945Sweongyo	BWN_DEBUG_CALIBRATE	= 0x00000200,	/* periodic calibration */
98203945Sweongyo	BWN_DEBUG_NODE		= 0x00000400,	/* node management */
99203945Sweongyo	BWN_DEBUG_LED		= 0x00000800,	/* led management */
100203945Sweongyo	BWN_DEBUG_CMD		= 0x00001000,	/* cmd submission */
101203945Sweongyo	BWN_DEBUG_LO		= 0x00002000,	/* LO */
102203945Sweongyo	BWN_DEBUG_FW		= 0x00004000,	/* firmware */
103203945Sweongyo	BWN_DEBUG_WME		= 0x00008000,	/* WME */
104203945Sweongyo	BWN_DEBUG_RF		= 0x00010000,	/* RF */
105203945Sweongyo	BWN_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
106203945Sweongyo	BWN_DEBUG_ANY		= 0xffffffff
107203945Sweongyo};
108203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do {			\
109203945Sweongyo	if (sc->sc_debug & (m))				\
110203945Sweongyo		printf(fmt, __VA_ARGS__);		\
111203945Sweongyo} while (0)
112203945Sweongyo#else
113203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
114203945Sweongyo#endif
115203945Sweongyo
116203945Sweongyostatic int	bwn_bfp = 0;		/* use "Bad Frames Preemption" */
117203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
118203945Sweongyo    "uses Bad Frames Preemption");
119203945Sweongyostatic int	bwn_bluetooth = 1;
120203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
121203945Sweongyo    "turns on Bluetooth Coexistence");
122203945Sweongyostatic int	bwn_hwpctl = 0;
123203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
124203945Sweongyo    "uses H/W power control");
125203945Sweongyostatic int	bwn_msi_disable = 0;		/* MSI disabled  */
126203945SweongyoTUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable);
127203945Sweongyostatic int	bwn_usedma = 1;
128203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
129203945Sweongyo    "uses DMA");
130203945SweongyoTUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
131203945Sweongyostatic int	bwn_wme = 1;
132203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
133203945Sweongyo    "uses WME support");
134203945Sweongyo
135203945Sweongyostatic int	bwn_attach_pre(struct bwn_softc *);
136203945Sweongyostatic int	bwn_attach_post(struct bwn_softc *);
137203945Sweongyostatic void	bwn_sprom_bugfixes(struct siba_softc *);
138203945Sweongyostatic void	bwn_init(void *);
139203945Sweongyostatic int	bwn_init_locked(struct bwn_softc *);
140203945Sweongyostatic int	bwn_ioctl(struct ifnet *, u_long, caddr_t);
141203945Sweongyostatic void	bwn_start(struct ifnet *);
142203945Sweongyostatic int	bwn_attach_core(struct bwn_mac *);
143203945Sweongyostatic void	bwn_reset_core(struct bwn_mac *, uint32_t);
144203945Sweongyostatic int	bwn_phy_getinfo(struct bwn_mac *, int);
145203945Sweongyostatic int	bwn_chiptest(struct bwn_mac *);
146203945Sweongyostatic int	bwn_setup_channels(struct bwn_mac *, int, int);
147203945Sweongyostatic int	bwn_phy_g_attach(struct bwn_mac *);
148203945Sweongyostatic void	bwn_phy_g_detach(struct bwn_mac *);
149203945Sweongyostatic void	bwn_phy_g_init_pre(struct bwn_mac *);
150203945Sweongyostatic int	bwn_phy_g_prepare_hw(struct bwn_mac *);
151203945Sweongyostatic int	bwn_phy_g_init(struct bwn_mac *);
152203945Sweongyostatic void	bwn_phy_g_exit(struct bwn_mac *);
153203945Sweongyostatic uint16_t	bwn_phy_g_read(struct bwn_mac *, uint16_t);
154203945Sweongyostatic void	bwn_phy_g_write(struct bwn_mac *, uint16_t,
155203945Sweongyo		    uint16_t);
156203945Sweongyostatic uint16_t	bwn_phy_g_rf_read(struct bwn_mac *, uint16_t);
157203945Sweongyostatic void	bwn_phy_g_rf_write(struct bwn_mac *, uint16_t,
158203945Sweongyo		    uint16_t);
159203945Sweongyostatic int	bwn_phy_g_hwpctl(struct bwn_mac *);
160203945Sweongyostatic void	bwn_phy_g_rf_onoff(struct bwn_mac *, int);
161203945Sweongyostatic int	bwn_phy_g_switch_channel(struct bwn_mac *, uint32_t);
162203945Sweongyostatic uint32_t	bwn_phy_g_get_default_chan(struct bwn_mac *);
163203945Sweongyostatic void	bwn_phy_g_set_antenna(struct bwn_mac *, int);
164203945Sweongyostatic int	bwn_phy_g_im(struct bwn_mac *, int);
165203945Sweongyostatic int	bwn_phy_g_recalc_txpwr(struct bwn_mac *, int);
166203945Sweongyostatic void	bwn_phy_g_set_txpwr(struct bwn_mac *);
167203945Sweongyostatic void	bwn_phy_g_task_15s(struct bwn_mac *);
168203945Sweongyostatic void	bwn_phy_g_task_60s(struct bwn_mac *);
169203945Sweongyostatic uint16_t	bwn_phy_g_txctl(struct bwn_mac *);
170203945Sweongyostatic void	bwn_phy_switch_analog(struct bwn_mac *, int);
171203945Sweongyostatic uint16_t	bwn_shm_read_2(struct bwn_mac *, uint16_t, uint16_t);
172203945Sweongyostatic void	bwn_shm_write_2(struct bwn_mac *, uint16_t, uint16_t,
173203945Sweongyo		    uint16_t);
174203945Sweongyostatic uint32_t	bwn_shm_read_4(struct bwn_mac *, uint16_t, uint16_t);
175203945Sweongyostatic void	bwn_shm_write_4(struct bwn_mac *, uint16_t, uint16_t,
176203945Sweongyo		    uint32_t);
177203945Sweongyostatic void	bwn_shm_ctlword(struct bwn_mac *, uint16_t,
178203945Sweongyo		    uint16_t);
179203945Sweongyostatic void	bwn_addchannels(struct ieee80211_channel [], int, int *,
180203945Sweongyo		    const struct bwn_channelinfo *, int);
181203945Sweongyostatic int	bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
182203945Sweongyo		    const struct ieee80211_bpf_params *);
183203945Sweongyostatic void	bwn_newassoc(struct ieee80211_node *, int);
184203945Sweongyostatic void	bwn_updateslot(struct ifnet *);
185203945Sweongyostatic void	bwn_update_promisc(struct ifnet *);
186203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
187203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
188203945Sweongyostatic struct ieee80211_node *bwn_node_alloc(struct ieee80211vap *,
189203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
190203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
191203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
192203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
193203945Sweongyo		    const struct wmeParams *, uint16_t);
194203945Sweongyostatic void	bwn_node_cleanup(struct ieee80211_node *);
195203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
196203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
197203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
198203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
199203945Sweongyo		    const char [IFNAMSIZ], int, int,
200203945Sweongyo		    int, const uint8_t [IEEE80211_ADDR_LEN],
201203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
202203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
203203945Sweongyostatic void	bwn_stop(struct bwn_softc *, int);
204203945Sweongyostatic void	bwn_stop_locked(struct bwn_softc *, int);
205203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
206203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
207203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
208203945Sweongyostatic void	bwn_fix_imcfglobug(struct bwn_mac *);
209203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
210203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
211203945Sweongyostatic uint64_t	bwn_hf_read(struct bwn_mac *);
212203945Sweongyostatic void	bwn_hf_write(struct bwn_mac *, uint64_t);
213203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
214203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
215203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
216203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
217203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
218203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
219203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
220203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
221203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
222203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
223203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
224203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
225203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
226203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
227203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
228203945Sweongyostatic void	bwn_gpio_cleanup(struct bwn_mac *);
229203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
230203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
231203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
232203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
233203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
234203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
235203945Sweongyo		    int);
236203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
237203945Sweongyo		    struct bwn_pio_rxqueue *, int);
238203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
239203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
240203945Sweongyo		    uint16_t);
241203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
242203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
243203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
244203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
245203945Sweongyo		    const struct bwn_txstatus *);
246203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
247203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
248203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
249203945Sweongyo		    uint16_t);
250203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
251203945Sweongyo		    uint32_t);
252203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
253203945Sweongyo		    struct mbuf *);
254203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
255203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
256203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
257203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
258203945Sweongyo		    uint16_t, uint32_t);
259203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
260203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
261203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
262203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
263203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
264203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
265203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
266203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
267203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
268203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
269203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
270203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
271203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
272203945Sweongyo		    int, struct bwn_dmadesc_generic **,
273203945Sweongyo		    struct bwn_dmadesc_meta **);
274203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
275203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
276203945Sweongyo		    int, int);
277203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
278203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
279203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
280203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
281203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
282203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
283203945Sweongyo		    int, struct bwn_dmadesc_generic **,
284203945Sweongyo		    struct bwn_dmadesc_meta **);
285203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
286203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
287203945Sweongyo		    int, int);
288203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
289203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
290203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
291203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
292203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
293203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
294203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
295203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
296203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
297203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
298203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
299203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
300203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
301203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
302203945Sweongyo		    struct bwn_dmadesc_meta *);
303203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
304203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
305203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
306203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
307203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
308203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
309203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
310203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
311203945Sweongyo		    int);
312203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
313203945Sweongyo		    bus_size_t, int);
314203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
315203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
316203945Sweongyo		    const struct bwn_txstatus *);
317203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
318203945Sweongyo		    struct mbuf *);
319203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
320203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
321203945Sweongyo		    uint8_t);
322203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
323203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
324203945Sweongyo		    int, int, int);
325203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
326203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
327203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
328203945Sweongyostatic void	bwn_phy_g_init_sub(struct bwn_mac *);
329203945Sweongyostatic uint8_t	bwn_has_hwpctl(struct bwn_mac *);
330203945Sweongyostatic void	bwn_phy_init_b5(struct bwn_mac *);
331203945Sweongyostatic void	bwn_phy_init_b6(struct bwn_mac *);
332203945Sweongyostatic void	bwn_phy_init_a(struct bwn_mac *);
333203945Sweongyostatic void	bwn_loopback_calcgain(struct bwn_mac *);
334203945Sweongyostatic uint16_t	bwn_rf_init_bcm2050(struct bwn_mac *);
335203945Sweongyostatic void	bwn_lo_g_init(struct bwn_mac *);
336203945Sweongyostatic void	bwn_lo_g_adjust(struct bwn_mac *);
337203945Sweongyostatic void	bwn_lo_get_powervector(struct bwn_mac *);
338203945Sweongyostatic struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
339203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *);
340203945Sweongyostatic void	bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
341203945Sweongyostatic void	bwn_phy_hwpctl_init(struct bwn_mac *);
342203945Sweongyostatic void	bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
343203945Sweongyostatic void	bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
344203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *,
345203945Sweongyo		    uint8_t);
346203945Sweongyostatic void	bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
347203945Sweongyostatic uint16_t	bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
348203945Sweongyostatic void	bwn_spu_workaround(struct bwn_mac *, uint8_t);
349203945Sweongyostatic void	bwn_wa_init(struct bwn_mac *);
350203945Sweongyostatic void	bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
351203945Sweongyo		    uint16_t);
352203945Sweongyostatic void	bwn_dummy_transmission(struct bwn_mac *, int, int);
353203945Sweongyostatic void	bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
354203945Sweongyo		    uint32_t);
355203945Sweongyostatic void	bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
356203945Sweongyo		    uint16_t);
357203945Sweongyostatic void	bwn_ram_write(struct bwn_mac *, uint16_t, uint32_t);
358203945Sweongyostatic void	bwn_mac_suspend(struct bwn_mac *);
359203945Sweongyostatic void	bwn_mac_enable(struct bwn_mac *);
360203945Sweongyostatic void	bwn_psctl(struct bwn_mac *, uint32_t);
361203945Sweongyostatic int16_t	bwn_nrssi_read(struct bwn_mac *, uint16_t);
362203945Sweongyostatic void	bwn_nrssi_offset(struct bwn_mac *);
363203945Sweongyostatic void	bwn_nrssi_threshold(struct bwn_mac *);
364203945Sweongyostatic void	bwn_nrssi_slope_11g(struct bwn_mac *);
365203945Sweongyostatic void	bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
366203945Sweongyo		    int16_t);
367203945Sweongyostatic void	bwn_set_original_gains(struct bwn_mac *);
368203945Sweongyostatic void	bwn_hwpctl_early_init(struct bwn_mac *);
369203945Sweongyostatic void	bwn_hwpctl_init_gphy(struct bwn_mac *);
370203945Sweongyostatic uint16_t	bwn_phy_g_chan2freq(uint8_t);
371203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
372203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
373203945Sweongyo		    const char *, struct bwn_fwfile *);
374203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
375203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
376203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
377203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
378203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
379203945Sweongyostatic int	bwn_switch_channel(struct bwn_mac *, int);
380203945Sweongyostatic uint16_t	bwn_ant2phy(int);
381203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
382203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
383203945Sweongyo		    const uint8_t *);
384203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
385203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
386203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
387203945Sweongyo		    const uint8_t *);
388203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
389203945Sweongyo		    const uint8_t *);
390203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
391203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
392203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
393203945Sweongyo		    struct ieee80211_channel *);
394203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
395203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
396203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
397203945Sweongyostatic int	bwn_intr(void *);
398203945Sweongyostatic void	bwn_intrtask(void *, int);
399203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
400203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
401203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
402203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
403203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
404203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
405203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
406203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
407203945Sweongyostatic void	bwn_hwreset(void *, int);
408203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
409203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
410203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
411203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
412203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
413203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
414203945Sweongyo		    const struct bwn_txstatus *);
415203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
416203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
417203945Sweongyostatic void	bwn_start_locked(struct ifnet *);
418203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
419203945Sweongyo		    struct mbuf *);
420203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
421203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
422203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
423203945Sweongyo		    uint16_t);
424203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
425203945Sweongyo		    const uint8_t);
426203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
427203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
428203945Sweongyostatic int	bwn_phy_shm_tssi_read(struct bwn_mac *, uint16_t);
429203945Sweongyostatic void	bwn_phy_g_setatt(struct bwn_mac *, int *, int *);
430203945Sweongyostatic void	bwn_phy_lock(struct bwn_mac *);
431203945Sweongyostatic void	bwn_phy_unlock(struct bwn_mac *);
432203945Sweongyostatic void	bwn_rf_lock(struct bwn_mac *);
433203945Sweongyostatic void	bwn_rf_unlock(struct bwn_mac *);
434203945Sweongyostatic void	bwn_txpwr(void *, int);
435203945Sweongyostatic void	bwn_tasks(void *);
436203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
437203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
438203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
439203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
440203945Sweongyo		    uint8_t);
441203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
442203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
443203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
444203945Sweongyo		    int, int);
445203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
446203945Sweongyostatic void	bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
447203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
448203945Sweongyostatic void	bwn_watchdog(void *);
449203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
450203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
451203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
452203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
453203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
454203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
455203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
456203945Sweongyostatic void	bwn_led_blink_next(void *);
457203945Sweongyostatic void	bwn_led_blink_end(void *);
458203945Sweongyostatic void	bwn_rfswitch(void *);
459203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
460203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
461203945Sweongyostatic void	bwn_phy_lp_init_pre(struct bwn_mac *);
462203945Sweongyostatic int	bwn_phy_lp_init(struct bwn_mac *);
463203945Sweongyostatic uint16_t	bwn_phy_lp_read(struct bwn_mac *, uint16_t);
464203945Sweongyostatic void	bwn_phy_lp_write(struct bwn_mac *, uint16_t, uint16_t);
465203945Sweongyostatic void	bwn_phy_lp_maskset(struct bwn_mac *, uint16_t, uint16_t,
466203945Sweongyo		    uint16_t);
467203945Sweongyostatic uint16_t	bwn_phy_lp_rf_read(struct bwn_mac *, uint16_t);
468203945Sweongyostatic void	bwn_phy_lp_rf_write(struct bwn_mac *, uint16_t, uint16_t);
469203945Sweongyostatic void	bwn_phy_lp_rf_onoff(struct bwn_mac *, int);
470203945Sweongyostatic int	bwn_phy_lp_switch_channel(struct bwn_mac *, uint32_t);
471203945Sweongyostatic uint32_t	bwn_phy_lp_get_default_chan(struct bwn_mac *);
472203945Sweongyostatic void	bwn_phy_lp_set_antenna(struct bwn_mac *, int);
473203945Sweongyostatic void	bwn_phy_lp_task_60s(struct bwn_mac *);
474203945Sweongyostatic void	bwn_phy_lp_readsprom(struct bwn_mac *);
475203945Sweongyostatic void	bwn_phy_lp_bbinit(struct bwn_mac *);
476203945Sweongyostatic void	bwn_phy_lp_txpctl_init(struct bwn_mac *);
477203945Sweongyostatic void	bwn_phy_lp_calib(struct bwn_mac *);
478203945Sweongyostatic void	bwn_phy_lp_switch_analog(struct bwn_mac *, int);
479203945Sweongyostatic int	bwn_phy_lp_b2062_switch_channel(struct bwn_mac *, uint8_t);
480203945Sweongyostatic int	bwn_phy_lp_b2063_switch_channel(struct bwn_mac *, uint8_t);
481203945Sweongyostatic void	bwn_phy_lp_set_anafilter(struct bwn_mac *, uint8_t);
482203945Sweongyostatic void	bwn_phy_lp_set_gaintbl(struct bwn_mac *, uint32_t);
483203945Sweongyostatic void	bwn_phy_lp_digflt_save(struct bwn_mac *);
484203945Sweongyostatic void	bwn_phy_lp_get_txpctlmode(struct bwn_mac *);
485203945Sweongyostatic void	bwn_phy_lp_set_txpctlmode(struct bwn_mac *, uint8_t);
486203945Sweongyostatic void	bwn_phy_lp_bugfix(struct bwn_mac *);
487203945Sweongyostatic void	bwn_phy_lp_digflt_restore(struct bwn_mac *);
488203945Sweongyostatic void	bwn_phy_lp_tblinit(struct bwn_mac *);
489203945Sweongyostatic void	bwn_phy_lp_bbinit_r2(struct bwn_mac *);
490203945Sweongyostatic void	bwn_phy_lp_bbinit_r01(struct bwn_mac *);
491203945Sweongyostatic void	bwn_phy_lp_b2062_init(struct bwn_mac *);
492203945Sweongyostatic void	bwn_phy_lp_b2063_init(struct bwn_mac *);
493203945Sweongyostatic void	bwn_phy_lp_rxcal_r2(struct bwn_mac *);
494203945Sweongyostatic void	bwn_phy_lp_rccal_r12(struct bwn_mac *);
495203945Sweongyostatic void	bwn_phy_lp_set_rccap(struct bwn_mac *);
496203945Sweongyostatic uint32_t	bwn_phy_lp_roundup(uint32_t, uint32_t, uint8_t);
497203945Sweongyostatic void	bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *);
498203945Sweongyostatic void	bwn_phy_lp_b2062_vco_calib(struct bwn_mac *);
499203945Sweongyostatic void	bwn_tab_write_multi(struct bwn_mac *, uint32_t, int,
500203945Sweongyo		    const void *);
501203945Sweongyostatic void	bwn_tab_read_multi(struct bwn_mac *, uint32_t, int, void *);
502203945Sweongyostatic struct bwn_txgain
503203945Sweongyo		bwn_phy_lp_get_txgain(struct bwn_mac *);
504203945Sweongyostatic uint8_t	bwn_phy_lp_get_bbmult(struct bwn_mac *);
505203945Sweongyostatic void	bwn_phy_lp_set_txgain(struct bwn_mac *, struct bwn_txgain *);
506203945Sweongyostatic void	bwn_phy_lp_set_bbmult(struct bwn_mac *, uint8_t);
507203945Sweongyostatic void	bwn_phy_lp_set_trsw_over(struct bwn_mac *, uint8_t, uint8_t);
508203945Sweongyostatic void	bwn_phy_lp_set_rxgain(struct bwn_mac *, uint32_t);
509203945Sweongyostatic void	bwn_phy_lp_set_deaf(struct bwn_mac *, uint8_t);
510203945Sweongyostatic int	bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *, uint16_t);
511203945Sweongyostatic void	bwn_phy_lp_clear_deaf(struct bwn_mac *, uint8_t);
512203945Sweongyostatic void	bwn_phy_lp_tblinit_r01(struct bwn_mac *);
513203945Sweongyostatic void	bwn_phy_lp_tblinit_r2(struct bwn_mac *);
514203945Sweongyostatic void	bwn_phy_lp_tblinit_txgain(struct bwn_mac *);
515203945Sweongyostatic void	bwn_tab_write(struct bwn_mac *, uint32_t, uint32_t);
516203945Sweongyostatic void	bwn_phy_lp_b2062_tblinit(struct bwn_mac *);
517203945Sweongyostatic void	bwn_phy_lp_b2063_tblinit(struct bwn_mac *);
518203945Sweongyostatic int	bwn_phy_lp_loopback(struct bwn_mac *);
519203945Sweongyostatic void	bwn_phy_lp_set_rxgain_idx(struct bwn_mac *, uint16_t);
520203945Sweongyostatic void	bwn_phy_lp_ddfs_turnon(struct bwn_mac *, int, int, int, int,
521203945Sweongyo		    int);
522203945Sweongyostatic uint8_t	bwn_phy_lp_rx_iq_est(struct bwn_mac *, uint16_t, uint8_t,
523203945Sweongyo		    struct bwn_phy_lp_iq_est *);
524203945Sweongyostatic void	bwn_phy_lp_ddfs_turnoff(struct bwn_mac *);
525203945Sweongyostatic uint32_t	bwn_tab_read(struct bwn_mac *, uint32_t);
526203945Sweongyostatic void	bwn_phy_lp_set_txgain_dac(struct bwn_mac *, uint16_t);
527203945Sweongyostatic void	bwn_phy_lp_set_txgain_pa(struct bwn_mac *, uint16_t);
528203945Sweongyostatic void	bwn_phy_lp_set_txgain_override(struct bwn_mac *);
529203945Sweongyostatic uint16_t	bwn_phy_lp_get_pa_gain(struct bwn_mac *);
530203945Sweongyostatic uint8_t	bwn_nbits(int32_t);
531203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *, int, int,
532203945Sweongyo		    struct bwn_txgain_entry *);
533203945Sweongyostatic void	bwn_phy_lp_gaintbl_write(struct bwn_mac *, int,
534203945Sweongyo		    struct bwn_txgain_entry);
535203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
536203945Sweongyo		    struct bwn_txgain_entry);
537203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
538203945Sweongyo		    struct bwn_txgain_entry);
539203945Sweongyo
540203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
541203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
542203945Sweongyo	{ -1,			0,		0 }
543203945Sweongyo};
544203945Sweongyo
545203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
546203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
547203945Sweongyo	{ -1,			0,		0 }
548203945Sweongyo};
549203945Sweongyo
550203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
551203945Sweongyo	.channels = {
552203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
553203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
554203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
555203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
556203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
557203945Sweongyo	.nchannels = 14
558203945Sweongyo};
559203945Sweongyo
560203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
561203945Sweongyo	.channels = {
562203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
563203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
564203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
565203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
566203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
567203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
568203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
569203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
570203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
571203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
572203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
573203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
574203945Sweongyo		{ 6080, 216, 30 } },
575203945Sweongyo	.nchannels = 37
576203945Sweongyo};
577203945Sweongyo
578203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
579203945Sweongyo	.channels = {
580203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
581203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
582203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
583203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
584203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
585203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
586203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
587203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
588203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
589203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
590203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
591203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
592203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
593203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
594203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
595203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
596203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
597203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
598203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
599203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
600203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
601203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
602203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
603203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
604203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
605203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
606203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
607203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
608203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
609203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
610203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
611203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
612203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
613203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
614203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
615203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
616203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
617203945Sweongyo	.nchannels = 110
618203945Sweongyo};
619203945Sweongyo
620203945Sweongyostatic const uint8_t bwn_b2063_chantable_data[33][12] = {
621203945Sweongyo	{ 0x6f, 0x3c, 0x3c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
622203945Sweongyo	{ 0x6f, 0x2c, 0x2c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
623203945Sweongyo	{ 0x6f, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
624203945Sweongyo	{ 0x6e, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
625203945Sweongyo	{ 0x6e, 0xc, 0xc, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
626203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x2, 0x5, 0xd, 0xd, 0x77, 0x80, 0x20, 0 },
627203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x5, 0xd, 0xc, 0x77, 0x80, 0x20, 0 },
628203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x80, 0x20, 0 },
629203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x70, 0x20, 0 },
630203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xb, 0xc, 0x77, 0x70, 0x20, 0 },
631203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x4, 0xb, 0xb, 0x77, 0x60, 0x20, 0 },
632203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xb, 0x77, 0x60, 0x20, 0 },
633203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xa, 0x77, 0x60, 0x20, 0 },
634203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x2, 0x9, 0x9, 0x77, 0x60, 0x20, 0 },
635203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x1, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
636203945Sweongyo	{ 0x67, 0xc, 0xc, 0, 0, 0, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
637203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x2, 0x1, 0x77, 0x20, 0, 0 },
638203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x1, 0x1, 0x77, 0x20, 0, 0 },
639203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0x1, 0, 0x77, 0x10, 0, 0 },
640203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
641203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
642203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
643203945Sweongyo	{ 0x61, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
644203945Sweongyo	{ 0x60, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
645203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xe, 0xf, 0xf, 0x77, 0xc0, 0x50, 0 },
646203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xd, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
647203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
648203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
649203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xb, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
650203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xa, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
651203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x7, 0x9, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
652203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x6, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
653203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x5, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 }
654203945Sweongyo};
655203945Sweongyo
656203945Sweongyostatic const struct bwn_b206x_chan bwn_b2063_chantable[] = {
657203945Sweongyo	{ 1, 2412, bwn_b2063_chantable_data[0] },
658203945Sweongyo	{ 2, 2417, bwn_b2063_chantable_data[0] },
659203945Sweongyo	{ 3, 2422, bwn_b2063_chantable_data[0] },
660203945Sweongyo	{ 4, 2427, bwn_b2063_chantable_data[1] },
661203945Sweongyo	{ 5, 2432, bwn_b2063_chantable_data[1] },
662203945Sweongyo	{ 6, 2437, bwn_b2063_chantable_data[1] },
663203945Sweongyo	{ 7, 2442, bwn_b2063_chantable_data[1] },
664203945Sweongyo	{ 8, 2447, bwn_b2063_chantable_data[1] },
665203945Sweongyo	{ 9, 2452, bwn_b2063_chantable_data[2] },
666203945Sweongyo	{ 10, 2457, bwn_b2063_chantable_data[2] },
667203945Sweongyo	{ 11, 2462, bwn_b2063_chantable_data[3] },
668203945Sweongyo	{ 12, 2467, bwn_b2063_chantable_data[3] },
669203945Sweongyo	{ 13, 2472, bwn_b2063_chantable_data[3] },
670203945Sweongyo	{ 14, 2484, bwn_b2063_chantable_data[4] },
671203945Sweongyo	{ 34, 5170, bwn_b2063_chantable_data[5] },
672203945Sweongyo	{ 36, 5180, bwn_b2063_chantable_data[6] },
673203945Sweongyo	{ 38, 5190, bwn_b2063_chantable_data[7] },
674203945Sweongyo	{ 40, 5200, bwn_b2063_chantable_data[8] },
675203945Sweongyo	{ 42, 5210, bwn_b2063_chantable_data[9] },
676203945Sweongyo	{ 44, 5220, bwn_b2063_chantable_data[10] },
677203945Sweongyo	{ 46, 5230, bwn_b2063_chantable_data[11] },
678203945Sweongyo	{ 48, 5240, bwn_b2063_chantable_data[12] },
679203945Sweongyo	{ 52, 5260, bwn_b2063_chantable_data[13] },
680203945Sweongyo	{ 56, 5280, bwn_b2063_chantable_data[14] },
681203945Sweongyo	{ 60, 5300, bwn_b2063_chantable_data[14] },
682203945Sweongyo	{ 64, 5320, bwn_b2063_chantable_data[15] },
683203945Sweongyo	{ 100, 5500, bwn_b2063_chantable_data[16] },
684203945Sweongyo	{ 104, 5520, bwn_b2063_chantable_data[17] },
685203945Sweongyo	{ 108, 5540, bwn_b2063_chantable_data[18] },
686203945Sweongyo	{ 112, 5560, bwn_b2063_chantable_data[19] },
687203945Sweongyo	{ 116, 5580, bwn_b2063_chantable_data[20] },
688203945Sweongyo	{ 120, 5600, bwn_b2063_chantable_data[21] },
689203945Sweongyo	{ 124, 5620, bwn_b2063_chantable_data[21] },
690203945Sweongyo	{ 128, 5640, bwn_b2063_chantable_data[22] },
691203945Sweongyo	{ 132, 5660, bwn_b2063_chantable_data[22] },
692203945Sweongyo	{ 136, 5680, bwn_b2063_chantable_data[22] },
693203945Sweongyo	{ 140, 5700, bwn_b2063_chantable_data[23] },
694203945Sweongyo	{ 149, 5745, bwn_b2063_chantable_data[23] },
695203945Sweongyo	{ 153, 5765, bwn_b2063_chantable_data[23] },
696203945Sweongyo	{ 157, 5785, bwn_b2063_chantable_data[23] },
697203945Sweongyo	{ 161, 5805, bwn_b2063_chantable_data[23] },
698203945Sweongyo	{ 165, 5825, bwn_b2063_chantable_data[23] },
699203945Sweongyo	{ 184, 4920, bwn_b2063_chantable_data[24] },
700203945Sweongyo	{ 188, 4940, bwn_b2063_chantable_data[25] },
701203945Sweongyo	{ 192, 4960, bwn_b2063_chantable_data[26] },
702203945Sweongyo	{ 196, 4980, bwn_b2063_chantable_data[27] },
703203945Sweongyo	{ 200, 5000, bwn_b2063_chantable_data[28] },
704203945Sweongyo	{ 204, 5020, bwn_b2063_chantable_data[29] },
705203945Sweongyo	{ 208, 5040, bwn_b2063_chantable_data[30] },
706203945Sweongyo	{ 212, 5060, bwn_b2063_chantable_data[31] },
707203945Sweongyo	{ 216, 5080, bwn_b2063_chantable_data[32] }
708203945Sweongyo};
709203945Sweongyo
710203945Sweongyostatic const uint8_t bwn_b2062_chantable_data[22][12] = {
711203945Sweongyo	{ 0xff, 0xff, 0xb5, 0x1b, 0x24, 0x32, 0x32, 0x88, 0x88, 0, 0, 0 },
712203945Sweongyo	{ 0, 0x22, 0x20, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
713203945Sweongyo	{ 0, 0x11, 0x10, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
714203945Sweongyo	{ 0, 0, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
715203945Sweongyo	{ 0, 0x11, 0x20, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
716203945Sweongyo	{ 0, 0x11, 0x10, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
717203945Sweongyo	{ 0, 0x11, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
718203945Sweongyo	{ 0, 0, 0, 0x63, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
719203945Sweongyo	{ 0, 0, 0, 0x62, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
720203945Sweongyo	{ 0, 0, 0, 0x30, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
721203945Sweongyo	{ 0, 0, 0, 0x20, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
722203945Sweongyo	{ 0, 0, 0, 0x10, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
723203945Sweongyo	{ 0, 0, 0, 0, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
724203945Sweongyo	{ 0x55, 0x77, 0x90, 0xf7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
725203945Sweongyo	{ 0x44, 0x77, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
726203945Sweongyo	{ 0x44, 0x66, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
727203945Sweongyo	{ 0x33, 0x66, 0x70, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
728203945Sweongyo	{ 0x22, 0x55, 0x60, 0xd7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
729203945Sweongyo	{ 0x22, 0x55, 0x60, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
730203945Sweongyo	{ 0x22, 0x44, 0x50, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
731203945Sweongyo	{ 0x11, 0x44, 0x50, 0xa5, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
732203945Sweongyo	{ 0, 0x44, 0x40, 0xb6, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 }
733203945Sweongyo};
734203945Sweongyo
735203945Sweongyostatic const struct bwn_b206x_chan bwn_b2062_chantable[] = {
736203945Sweongyo	{ 1, 2412, bwn_b2062_chantable_data[0] },
737203945Sweongyo	{ 2, 2417, bwn_b2062_chantable_data[0] },
738203945Sweongyo	{ 3, 2422, bwn_b2062_chantable_data[0] },
739203945Sweongyo	{ 4, 2427, bwn_b2062_chantable_data[0] },
740203945Sweongyo	{ 5, 2432, bwn_b2062_chantable_data[0] },
741203945Sweongyo	{ 6, 2437, bwn_b2062_chantable_data[0] },
742203945Sweongyo	{ 7, 2442, bwn_b2062_chantable_data[0] },
743203945Sweongyo	{ 8, 2447, bwn_b2062_chantable_data[0] },
744203945Sweongyo	{ 9, 2452, bwn_b2062_chantable_data[0] },
745203945Sweongyo	{ 10, 2457, bwn_b2062_chantable_data[0] },
746203945Sweongyo	{ 11, 2462, bwn_b2062_chantable_data[0] },
747203945Sweongyo	{ 12, 2467, bwn_b2062_chantable_data[0] },
748203945Sweongyo	{ 13, 2472, bwn_b2062_chantable_data[0] },
749203945Sweongyo	{ 14, 2484, bwn_b2062_chantable_data[0] },
750203945Sweongyo	{ 34, 5170, bwn_b2062_chantable_data[1] },
751203945Sweongyo	{ 38, 5190, bwn_b2062_chantable_data[2] },
752203945Sweongyo	{ 42, 5210, bwn_b2062_chantable_data[2] },
753203945Sweongyo	{ 46, 5230, bwn_b2062_chantable_data[3] },
754203945Sweongyo	{ 36, 5180, bwn_b2062_chantable_data[4] },
755203945Sweongyo	{ 40, 5200, bwn_b2062_chantable_data[5] },
756203945Sweongyo	{ 44, 5220, bwn_b2062_chantable_data[6] },
757203945Sweongyo	{ 48, 5240, bwn_b2062_chantable_data[3] },
758203945Sweongyo	{ 52, 5260, bwn_b2062_chantable_data[3] },
759203945Sweongyo	{ 56, 5280, bwn_b2062_chantable_data[3] },
760203945Sweongyo	{ 60, 5300, bwn_b2062_chantable_data[7] },
761203945Sweongyo	{ 64, 5320, bwn_b2062_chantable_data[8] },
762203945Sweongyo	{ 100, 5500, bwn_b2062_chantable_data[9] },
763203945Sweongyo	{ 104, 5520, bwn_b2062_chantable_data[10] },
764203945Sweongyo	{ 108, 5540, bwn_b2062_chantable_data[10] },
765203945Sweongyo	{ 112, 5560, bwn_b2062_chantable_data[10] },
766203945Sweongyo	{ 116, 5580, bwn_b2062_chantable_data[11] },
767203945Sweongyo	{ 120, 5600, bwn_b2062_chantable_data[12] },
768203945Sweongyo	{ 124, 5620, bwn_b2062_chantable_data[12] },
769203945Sweongyo	{ 128, 5640, bwn_b2062_chantable_data[12] },
770203945Sweongyo	{ 132, 5660, bwn_b2062_chantable_data[12] },
771203945Sweongyo	{ 136, 5680, bwn_b2062_chantable_data[12] },
772203945Sweongyo	{ 140, 5700, bwn_b2062_chantable_data[12] },
773203945Sweongyo	{ 149, 5745, bwn_b2062_chantable_data[12] },
774203945Sweongyo	{ 153, 5765, bwn_b2062_chantable_data[12] },
775203945Sweongyo	{ 157, 5785, bwn_b2062_chantable_data[12] },
776203945Sweongyo	{ 161, 5805, bwn_b2062_chantable_data[12] },
777203945Sweongyo	{ 165, 5825, bwn_b2062_chantable_data[12] },
778203945Sweongyo	{ 184, 4920, bwn_b2062_chantable_data[13] },
779203945Sweongyo	{ 188, 4940, bwn_b2062_chantable_data[14] },
780203945Sweongyo	{ 192, 4960, bwn_b2062_chantable_data[15] },
781203945Sweongyo	{ 196, 4980, bwn_b2062_chantable_data[16] },
782203945Sweongyo	{ 200, 5000, bwn_b2062_chantable_data[17] },
783203945Sweongyo	{ 204, 5020, bwn_b2062_chantable_data[18] },
784203945Sweongyo	{ 208, 5040, bwn_b2062_chantable_data[19] },
785203945Sweongyo	{ 212, 5060, bwn_b2062_chantable_data[20] },
786203945Sweongyo	{ 216, 5080, bwn_b2062_chantable_data[21] }
787203945Sweongyo};
788203945Sweongyo
789203945Sweongyo/* for LP PHY */
790203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_5354[] = {
791203945Sweongyo	{  1, -66, 15 }, {  2, -66, 15 }, {  3, -66, 15 }, {  4, -66, 15 },
792203945Sweongyo	{  5, -66, 15 }, {  6, -66, 15 }, {  7, -66, 14 }, {  8, -66, 14 },
793203945Sweongyo	{  9, -66, 14 }, { 10, -66, 14 }, { 11, -66, 14 }, { 12, -66, 13 },
794203945Sweongyo	{ 13, -66, 13 }, { 14, -66, 13 },
795203945Sweongyo};
796203945Sweongyo
797203945Sweongyo/* for LP PHY */
798203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r12[] = {
799203945Sweongyo	{   1, -64, 13 }, {   2, -64, 13 }, {   3, -64, 13 }, {   4, -64, 13 },
800203945Sweongyo	{   5, -64, 12 }, {   6, -64, 12 }, {   7, -64, 12 }, {   8, -64, 12 },
801203945Sweongyo	{   9, -64, 12 }, {  10, -64, 11 }, {  11, -64, 11 }, {  12, -64, 11 },
802203945Sweongyo	{  13, -64, 11 }, {  14, -64, 10 }, {  34, -62, 24 }, {  38, -62, 24 },
803203945Sweongyo	{  42, -62, 24 }, {  46, -62, 23 }, {  36, -62, 24 }, {  40, -62, 24 },
804203945Sweongyo	{  44, -62, 23 }, {  48, -62, 23 }, {  52, -62, 23 }, {  56, -62, 22 },
805203945Sweongyo	{  60, -62, 22 }, {  64, -62, 22 }, { 100, -62, 16 }, { 104, -62, 16 },
806203945Sweongyo	{ 108, -62, 15 }, { 112, -62, 14 }, { 116, -62, 14 }, { 120, -62, 13 },
807203945Sweongyo	{ 124, -62, 12 }, { 128, -62, 12 }, { 132, -62, 12 }, { 136, -62, 11 },
808203945Sweongyo	{ 140, -62, 10 }, { 149, -61,  9 }, { 153, -61,  9 }, { 157, -61,  9 },
809203945Sweongyo	{ 161, -61,  8 }, { 165, -61,  8 }, { 184, -62, 25 }, { 188, -62, 25 },
810203945Sweongyo	{ 192, -62, 25 }, { 196, -62, 25 }, { 200, -62, 25 }, { 204, -62, 25 },
811203945Sweongyo	{ 208, -62, 25 }, { 212, -62, 25 }, { 216, -62, 26 },
812203945Sweongyo};
813203945Sweongyo
814203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r2 = { 0, -64, 0 };
815203945Sweongyo
816203945Sweongyostatic const uint8_t bwn_tab_sigsq_tbl[] = {
817203945Sweongyo	0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
818203945Sweongyo	0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
819203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
820203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
821203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
822203945Sweongyo	0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
823203945Sweongyo};
824203945Sweongyo
825203945Sweongyostatic const uint8_t bwn_tab_pllfrac_tbl[] = {
826203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
827203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
828203945Sweongyo};
829203945Sweongyo
830203945Sweongyostatic const uint16_t bwn_tabl_iqlocal_tbl[] = {
831203945Sweongyo	0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
832203945Sweongyo	0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
833203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
834203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
835203945Sweongyo	0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
836203945Sweongyo	0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
837203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
838203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
839203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
840203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
841203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
842203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
843203945Sweongyo};
844203945Sweongyo
845203945Sweongyostatic const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
846203945Sweongyostatic const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
847203945Sweongyostatic const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
848203945Sweongyostatic const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
849203945Sweongyostatic const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
850203945Sweongyoconst uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
851203945Sweongyo
852203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
853203945Sweongyo{							\
854203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
855203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
856203945Sweongyo}
857203945Sweongyo
858203945Sweongyostatic const struct {
859203945Sweongyo	uint16_t	vid;
860203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
861203945Sweongyo} bwn_vendor_led_act[] = {
862203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
863203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
864203945Sweongyo};
865203945Sweongyo
866203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
867203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
868203945Sweongyo
869203945Sweongyo#undef VENDOR_LED_ACT
870203945Sweongyo
871203945Sweongyostatic const struct {
872203945Sweongyo	int		on_dur;
873203945Sweongyo	int		off_dur;
874203945Sweongyo} bwn_led_duration[109] = {
875203945Sweongyo	[0]	= { 400, 100 },
876203945Sweongyo	[2]	= { 150, 75 },
877203945Sweongyo	[4]	= { 90, 45 },
878203945Sweongyo	[11]	= { 66, 34 },
879203945Sweongyo	[12]	= { 53, 26 },
880203945Sweongyo	[18]	= { 42, 21 },
881203945Sweongyo	[22]	= { 35, 17 },
882203945Sweongyo	[24]	= { 32, 16 },
883203945Sweongyo	[36]	= { 21, 10 },
884203945Sweongyo	[48]	= { 16, 8 },
885203945Sweongyo	[72]	= { 11, 5 },
886203945Sweongyo	[96]	= { 9, 4 },
887203945Sweongyo	[108]	= { 7, 3 }
888203945Sweongyo};
889203945Sweongyo
890203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
891203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
892203945Sweongyo	[1] = BWN_WME_BACKGROUND,
893203945Sweongyo	[2] = BWN_WME_VOICE,
894203945Sweongyo	[3] = BWN_WME_VIDEO,
895203945Sweongyo};
896203945Sweongyo
897203945Sweongyostatic const struct siba_devid bwn_devs[] = {
898203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
899203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
900203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
901203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
902203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
903203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
904203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
905203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
906203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
907203945Sweongyo};
908203945Sweongyo
909203945Sweongyostatic int
910203945Sweongyobwn_probe(device_t dev)
911203945Sweongyo{
912203945Sweongyo	struct siba_dev_softc *sd = device_get_ivars(dev);
913203945Sweongyo	int i;
914203945Sweongyo
915203945Sweongyo	for (i = 0; i < sizeof(bwn_devs) / sizeof(bwn_devs[0]); i++) {
916203945Sweongyo		if (sd->sd_id.sd_vendor == bwn_devs[i].sd_vendor &&
917203945Sweongyo		    sd->sd_id.sd_device == bwn_devs[i].sd_device &&
918203945Sweongyo		    sd->sd_id.sd_rev == bwn_devs[i].sd_rev)
919203945Sweongyo			return (BUS_PROBE_DEFAULT);
920203945Sweongyo	}
921203945Sweongyo
922203945Sweongyo	return (ENXIO);
923203945Sweongyo}
924203945Sweongyo
925203945Sweongyostatic int
926203945Sweongyobwn_attach(device_t dev)
927203945Sweongyo{
928203945Sweongyo	struct bwn_mac *mac;
929203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
930203945Sweongyo	struct siba_dev_softc *sd = device_get_ivars(dev);
931203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
932203945Sweongyo	int error, i, msic, reg;
933203945Sweongyo
934203945Sweongyo	sc->sc_dev = dev;
935203945Sweongyo	sc->sc_sd = sd;
936203945Sweongyo#ifdef BWN_DEBUG
937203945Sweongyo	sc->sc_debug = bwn_debug;
938203945Sweongyo#endif
939203945Sweongyo
940203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
941203945Sweongyo		error = bwn_attach_pre(sc);
942203945Sweongyo		if (error != 0)
943203945Sweongyo			return (error);
944203945Sweongyo		bwn_sprom_bugfixes(sd->sd_bus);
945203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
946203945Sweongyo	}
947203945Sweongyo
948203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
949203945Sweongyo		if (siba->siba_pci_did != 0x4313 &&
950203945Sweongyo		    siba->siba_pci_did != 0x431a &&
951203945Sweongyo		    siba->siba_pci_did != 0x4321) {
952203945Sweongyo			device_printf(sc->sc_dev,
953203945Sweongyo			    "skip 802.11 cores\n");
954203945Sweongyo			return (ENODEV);
955203945Sweongyo		}
956203945Sweongyo	}
957203945Sweongyo
958203945Sweongyo	mac = (struct bwn_mac *)malloc(sizeof(*mac), M_DEVBUF,
959203945Sweongyo	    M_NOWAIT | M_ZERO);
960203945Sweongyo	if (mac == NULL)
961203945Sweongyo		return (ENOMEM);
962203945Sweongyo	mac->mac_sc = sc;
963203945Sweongyo	mac->mac_sd = sd;
964203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
965203945Sweongyo	if (bwn_bfp != 0)
966203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
967203945Sweongyo
968203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
969203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
970203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
971203945Sweongyo
972203945Sweongyo	error = bwn_attach_core(mac);
973203945Sweongyo	if (error)
974203945Sweongyo		goto fail0;
975203945Sweongyo	bwn_led_attach(mac);
976203945Sweongyo
977203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
978203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
979203945Sweongyo	    sd->sd_bus->siba_chipid, sd->sd_id.sd_rev,
980203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
981203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
982203945Sweongyo	    mac->mac_phy.rf_rev);
983203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
984203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
985203945Sweongyo		    mac->mac_method.dma.dmatype);
986203945Sweongyo	else
987203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
988203945Sweongyo
989203945Sweongyo	/*
990203945Sweongyo	 * setup PCI resources and interrupt.
991203945Sweongyo	 */
992203945Sweongyo	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
993203945Sweongyo		msic = pci_msi_count(dev);
994203945Sweongyo		if (bootverbose)
995203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
996203945Sweongyo	} else
997203945Sweongyo		msic = 0;
998203945Sweongyo
999203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
1000203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
1001203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
1002203945Sweongyo			device_printf(sc->sc_dev,
1003203945Sweongyo			    "Using %d MSI messages\n", msic);
1004203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
1005203945Sweongyo			mac->mac_msi = 1;
1006203945Sweongyo		}
1007203945Sweongyo	}
1008203945Sweongyo
1009203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
1010203945Sweongyo	    mac->mac_res_irq);
1011203945Sweongyo	if (error) {
1012203945Sweongyo		device_printf(sc->sc_dev,
1013203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
1014203945Sweongyo		goto fail1;
1015203945Sweongyo	}
1016203945Sweongyo
1017203945Sweongyo	if (mac->mac_msi == 0)
1018203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
1019203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1020203945Sweongyo		    &mac->mac_intrhand[0]);
1021203945Sweongyo	else {
1022203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1023203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
1024203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1025203945Sweongyo			    &mac->mac_intrhand[i]);
1026203945Sweongyo			if (error != 0) {
1027203945Sweongyo				device_printf(sc->sc_dev,
1028203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
1029203945Sweongyo				break;
1030203945Sweongyo			}
1031203945Sweongyo		}
1032203945Sweongyo	}
1033203945Sweongyo
1034203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
1035203945Sweongyo
1036203945Sweongyo	/*
1037203945Sweongyo	 * calls attach-post routine
1038203945Sweongyo	 */
1039203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
1040203945Sweongyo		bwn_attach_post(sc);
1041203945Sweongyo
1042203945Sweongyo	return (0);
1043203945Sweongyofail1:
1044203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
1045203945Sweongyo		pci_release_msi(dev);
1046203945Sweongyofail0:
1047203945Sweongyo	free(mac, M_DEVBUF);
1048203945Sweongyo	return (error);
1049203945Sweongyo}
1050203945Sweongyo
1051203945Sweongyostatic int
1052203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
1053203945Sweongyo{
1054203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
1055203945Sweongyo
1056203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
1057203945Sweongyo		return (FALSE);
1058203945Sweongyo
1059203945Sweongyo	return (TRUE);
1060203945Sweongyo}
1061203945Sweongyo
1062203945Sweongyostatic int
1063203945Sweongyobwn_attach_post(struct bwn_softc *sc)
1064203945Sweongyo{
1065203945Sweongyo	struct ieee80211com *ic;
1066203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1067203945Sweongyo	struct siba_dev_softc *sd = sc->sc_sd;
1068203945Sweongyo	struct siba_sprom *sprom = &sd->sd_bus->siba_sprom;
1069203945Sweongyo#ifdef BWN_DEBUG
1070203945Sweongyo	device_t dev = sc->sc_dev;
1071203945Sweongyo#endif
1072203945Sweongyo
1073203945Sweongyo	ic = ifp->if_l2com;
1074203945Sweongyo	ic->ic_ifp = ifp;
1075203945Sweongyo	/* XXX not right but it's not used anywhere important */
1076203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
1077203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
1078203945Sweongyo	ic->ic_caps =
1079203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
1080203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
1081203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
1082203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
1083203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
1084203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
1085203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
1086203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
1087203945Sweongyo		;
1088203945Sweongyo
1089203945Sweongyo	/* call MI attach routine. */
1090203945Sweongyo	ieee80211_ifattach(ic,
1091203945Sweongyo	    bwn_is_valid_ether_addr(sprom->mac_80211a) ? sprom->mac_80211a :
1092203945Sweongyo	    sprom->mac_80211bg);
1093203945Sweongyo
1094203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
1095203945Sweongyo
1096203945Sweongyo	/* override default methods */
1097203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
1098203945Sweongyo	ic->ic_newassoc = bwn_newassoc;
1099203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
1100203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
1101203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
1102203945Sweongyo
1103203945Sweongyo	ic->ic_node_alloc = bwn_node_alloc;
1104203945Sweongyo	sc->sc_node_cleanup = ic->ic_node_cleanup;
1105203945Sweongyo	ic->ic_node_cleanup = bwn_node_cleanup;
1106203945Sweongyo
1107203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
1108203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
1109203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
1110203945Sweongyo
1111203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
1112203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
1113203945Sweongyo
1114203945Sweongyo	ieee80211_radiotap_attach(ic,
1115203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
1116203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
1117203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
1118203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
1119203945Sweongyo
1120203945Sweongyo#ifdef BWN_DEBUG
1121203945Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1122203945Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1123203945Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
1124203945Sweongyo#endif
1125203945Sweongyo
1126203945Sweongyo	if (bootverbose)
1127203945Sweongyo		ieee80211_announce(ic);
1128203945Sweongyo	return (0);
1129203945Sweongyo}
1130203945Sweongyo
1131203945Sweongyostatic void
1132203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
1133203945Sweongyo{
1134203945Sweongyo
1135203945Sweongyo	if (mac->mac_phy.detach != NULL)
1136203945Sweongyo		mac->mac_phy.detach(mac);
1137203945Sweongyo}
1138203945Sweongyo
1139203945Sweongyostatic int
1140203945Sweongyobwn_detach(device_t dev)
1141203945Sweongyo{
1142203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
1143203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1144203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1145203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1146203945Sweongyo	int i;
1147203945Sweongyo
1148203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
1149203945Sweongyo
1150203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
1151203945Sweongyo		bwn_stop(sc, 1);
1152203945Sweongyo		bwn_dma_free(mac);
1153203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
1154203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
1155203945Sweongyo		callout_drain(&sc->sc_task_ch);
1156203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
1157203945Sweongyo		bwn_phy_detach(mac);
1158203945Sweongyo		if (ifp != NULL) {
1159203945Sweongyo			ieee80211_draintask(ic, &mac->mac_hwreset);
1160203945Sweongyo			ieee80211_draintask(ic, &mac->mac_txpower);
1161203945Sweongyo			ieee80211_ifdetach(ic);
1162203945Sweongyo			if_free(ifp);
1163203945Sweongyo		}
1164203945Sweongyo	}
1165203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
1166203945Sweongyo	taskqueue_free(sc->sc_tq);
1167203945Sweongyo
1168203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1169203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
1170203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
1171203945Sweongyo			    mac->mac_intrhand[i]);
1172203945Sweongyo			mac->mac_intrhand[i] = NULL;
1173203945Sweongyo		}
1174203945Sweongyo	}
1175203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
1176203945Sweongyo	if (mac->mac_msi != 0)
1177203945Sweongyo		pci_release_msi(dev);
1178203945Sweongyo
1179203945Sweongyo	BWN_LOCK_DESTROY(sc);
1180203945Sweongyo	return (0);
1181203945Sweongyo}
1182203945Sweongyo
1183203945Sweongyostatic int
1184203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
1185203945Sweongyo{
1186203945Sweongyo	struct ifnet *ifp;
1187203945Sweongyo	int error = 0;
1188203945Sweongyo
1189203945Sweongyo	BWN_LOCK_INIT(sc);
1190203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
1191203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
1192203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
1193203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
1194203945Sweongyo
1195203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
1196203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
1197203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
1198203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
1199203945Sweongyo
1200203945Sweongyo	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
1201203945Sweongyo	if (ifp == NULL) {
1202203945Sweongyo		device_printf(sc->sc_dev, "can not if_alloc()\n");
1203203945Sweongyo		error = ENOSPC;
1204203945Sweongyo		goto fail;
1205203945Sweongyo	}
1206203945Sweongyo
1207203945Sweongyo	/* set these up early for if_printf use */
1208203945Sweongyo	if_initname(ifp, device_get_name(sc->sc_dev),
1209203945Sweongyo	    device_get_unit(sc->sc_dev));
1210203945Sweongyo
1211203945Sweongyo	ifp->if_softc = sc;
1212203945Sweongyo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1213203945Sweongyo	ifp->if_init = bwn_init;
1214203945Sweongyo	ifp->if_ioctl = bwn_ioctl;
1215203945Sweongyo	ifp->if_start = bwn_start;
1216203945Sweongyo	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
1217203945Sweongyo	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
1218203945Sweongyo	IFQ_SET_READY(&ifp->if_snd);
1219203945Sweongyo
1220203945Sweongyo	return (0);
1221203945Sweongyo
1222203945Sweongyofail:	BWN_LOCK_DESTROY(sc);
1223203945Sweongyo	return (error);
1224203945Sweongyo}
1225203945Sweongyo
1226203945Sweongyostatic void
1227203945Sweongyobwn_sprom_bugfixes(struct siba_softc *siba)
1228203945Sweongyo{
1229203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
1230203945Sweongyo	((siba->siba_pci_vid == PCI_VENDOR_##_vendor) &&		\
1231203945Sweongyo	 (siba->siba_pci_did == _device) &&				\
1232203945Sweongyo	 (siba->siba_pci_subvid == PCI_VENDOR_##_subvendor) &&		\
1233203945Sweongyo	 (siba->siba_pci_subdid == _subdevice))
1234203945Sweongyo
1235203945Sweongyo	if (siba->siba_board_vendor == PCI_VENDOR_APPLE &&
1236203945Sweongyo	    siba->siba_board_type == 0x4e && siba->siba_board_rev > 0x40)
1237203945Sweongyo		siba->siba_sprom.bf_lo |= BWN_BFL_PACTRL;
1238203945Sweongyo	if (siba->siba_board_vendor == SIBA_BOARDVENDOR_DELL &&
1239203945Sweongyo	    siba->siba_chipid == 0x4301 && siba->siba_board_rev == 0x74)
1240203945Sweongyo		siba->siba_sprom.bf_lo |= BWN_BFL_BTCOEXIST;
1241203945Sweongyo	if (siba->siba_type == SIBA_TYPE_PCI) {
1242203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
1243203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
1244203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
1245203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
1246203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
1247203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
1248203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
1249203945Sweongyo			siba->siba_sprom.bf_lo &= ~BWN_BFL_BTCOEXIST;
1250203945Sweongyo	}
1251203945Sweongyo#undef	BWN_ISDEV
1252203945Sweongyo}
1253203945Sweongyo
1254203945Sweongyostatic int
1255203945Sweongyobwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1256203945Sweongyo{
1257203945Sweongyo#define	IS_RUNNING(ifp) \
1258203945Sweongyo	((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
1259203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1260203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1261203945Sweongyo	struct ifreq *ifr = (struct ifreq *)data;
1262203945Sweongyo	int error = 0, startall;
1263203945Sweongyo
1264203945Sweongyo	switch (cmd) {
1265203945Sweongyo	case SIOCSIFFLAGS:
1266203945Sweongyo		startall = 0;
1267203945Sweongyo		if (IS_RUNNING(ifp)) {
1268203945Sweongyo			bwn_update_promisc(ifp);
1269203945Sweongyo		} else if (ifp->if_flags & IFF_UP) {
1270203945Sweongyo			if ((sc->sc_flags & BWN_FLAG_INVALID) == 0) {
1271203945Sweongyo				bwn_init(sc);
1272203945Sweongyo				startall = 1;
1273203945Sweongyo			}
1274203945Sweongyo		} else
1275203945Sweongyo			bwn_stop(sc, 1);
1276203945Sweongyo		if (startall)
1277203945Sweongyo			ieee80211_start_all(ic);
1278203945Sweongyo		break;
1279203945Sweongyo	case SIOCGIFMEDIA:
1280203945Sweongyo		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1281203945Sweongyo		break;
1282203945Sweongyo	case SIOCGIFADDR:
1283203945Sweongyo		error = ether_ioctl(ifp, cmd, data);
1284203945Sweongyo		break;
1285203945Sweongyo	default:
1286203945Sweongyo		error = EINVAL;
1287203945Sweongyo		break;
1288203945Sweongyo	}
1289203945Sweongyo	return (error);
1290203945Sweongyo}
1291203945Sweongyo
1292203945Sweongyostatic void
1293203945Sweongyobwn_start(struct ifnet *ifp)
1294203945Sweongyo{
1295203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1296203945Sweongyo
1297203945Sweongyo	BWN_LOCK(sc);
1298203945Sweongyo	bwn_start_locked(ifp);
1299203945Sweongyo	BWN_UNLOCK(sc);
1300203945Sweongyo}
1301203945Sweongyo
1302203945Sweongyostatic void
1303203945Sweongyobwn_start_locked(struct ifnet *ifp)
1304203945Sweongyo{
1305203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1306203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1307203945Sweongyo	struct ieee80211_frame *wh;
1308203945Sweongyo	struct ieee80211_node *ni;
1309203945Sweongyo	struct ieee80211_key *k;
1310203945Sweongyo	struct mbuf *m;
1311203945Sweongyo
1312203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1313203945Sweongyo
1314203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || mac == NULL ||
1315203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
1316203945Sweongyo		return;
1317203945Sweongyo
1318203945Sweongyo	for (;;) {
1319203945Sweongyo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);	/* XXX: LOCK */
1320203945Sweongyo		if (m == NULL)
1321203945Sweongyo			break;
1322203945Sweongyo
1323203945Sweongyo		if (bwn_tx_isfull(sc, m))
1324203945Sweongyo			break;
1325203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
1326203945Sweongyo		if (ni == NULL) {
1327203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
1328203945Sweongyo			m_freem(m);
1329203945Sweongyo			ifp->if_oerrors++;
1330203945Sweongyo			continue;
1331203945Sweongyo		}
1332203945Sweongyo		KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__));
1333203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
1334203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1335203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
1336203945Sweongyo			if (k == NULL) {
1337203945Sweongyo				ieee80211_free_node(ni);
1338203945Sweongyo				m_freem(m);
1339203945Sweongyo				ifp->if_oerrors++;
1340203945Sweongyo				continue;
1341203945Sweongyo			}
1342203945Sweongyo		}
1343203945Sweongyo		wh = NULL;	/* Catch any invalid use */
1344203945Sweongyo
1345203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
1346203945Sweongyo			if (ni != NULL)
1347203945Sweongyo				ieee80211_free_node(ni);
1348203945Sweongyo			ifp->if_oerrors++;
1349203945Sweongyo			continue;
1350203945Sweongyo		}
1351203945Sweongyo
1352203945Sweongyo		sc->sc_watchdog_timer = 5;
1353203945Sweongyo	}
1354203945Sweongyo}
1355203945Sweongyo
1356203945Sweongyostatic int
1357203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
1358203945Sweongyo{
1359203945Sweongyo	struct bwn_dma_ring *dr;
1360203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1361203945Sweongyo	struct bwn_pio_txqueue *tq;
1362203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1363203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1364203945Sweongyo
1365203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1366203945Sweongyo
1367203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
1368203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
1369203945Sweongyo		if (dr->dr_stop == 1 ||
1370203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
1371203945Sweongyo			dr->dr_stop = 1;
1372203945Sweongyo			goto full;
1373203945Sweongyo		}
1374203945Sweongyo	} else {
1375203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
1376203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
1377203945Sweongyo		    pktlen > (tq->tq_size - tq->tq_used)) {
1378203945Sweongyo			tq->tq_stop = 1;
1379203945Sweongyo			goto full;
1380203945Sweongyo		}
1381203945Sweongyo	}
1382203945Sweongyo	return (0);
1383203945Sweongyofull:
1384203945Sweongyo	IFQ_DRV_PREPEND(&ifp->if_snd, m);
1385203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1386203945Sweongyo	return (1);
1387203945Sweongyo}
1388203945Sweongyo
1389203945Sweongyostatic int
1390203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
1391203945Sweongyo{
1392203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1393203945Sweongyo	int error;
1394203945Sweongyo
1395203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1396203945Sweongyo
1397203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
1398203945Sweongyo		m_freem(m);
1399203945Sweongyo		return (ENXIO);
1400203945Sweongyo	}
1401203945Sweongyo
1402203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
1403203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
1404203945Sweongyo	if (error) {
1405203945Sweongyo		m_freem(m);
1406203945Sweongyo		return (error);
1407203945Sweongyo	}
1408203945Sweongyo	return (0);
1409203945Sweongyo}
1410203945Sweongyo
1411203945Sweongyostatic int
1412203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1413203945Sweongyo{
1414203945Sweongyo	struct bwn_pio_txpkt *tp;
1415203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
1416203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1417203945Sweongyo	struct bwn_txhdr txhdr;
1418203945Sweongyo	struct mbuf *m_new;
1419203945Sweongyo	uint32_t ctl32;
1420203945Sweongyo	int error;
1421203945Sweongyo	uint16_t ctl16;
1422203945Sweongyo
1423203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1424203945Sweongyo
1425203945Sweongyo	/* XXX TODO send packets after DTIM */
1426203945Sweongyo
1427203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
1428203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
1429203945Sweongyo	tp->tp_ni = ni;
1430203945Sweongyo	tp->tp_m = m;
1431203945Sweongyo
1432203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
1433203945Sweongyo	if (error) {
1434203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
1435203945Sweongyo		return (error);
1436203945Sweongyo	}
1437203945Sweongyo
1438203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
1439203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1440203945Sweongyo	tq->tq_free--;
1441203945Sweongyo
1442203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 8) {
1443203945Sweongyo		/*
1444203945Sweongyo		 * XXX please removes m_defrag(9)
1445203945Sweongyo		 */
1446203945Sweongyo		m_new = m_defrag(m, M_DONTWAIT);
1447203945Sweongyo		if (m_new == NULL) {
1448203945Sweongyo			device_printf(sc->sc_dev,
1449203945Sweongyo			    "%s: can't defrag TX buffer\n",
1450203945Sweongyo			    __func__);
1451203945Sweongyo			return (ENOBUFS);
1452203945Sweongyo		}
1453203945Sweongyo		if (m_new->m_next != NULL)
1454203945Sweongyo			device_printf(sc->sc_dev,
1455203945Sweongyo			    "TODO: fragmented packets for PIO\n");
1456203945Sweongyo		tp->tp_m = m_new;
1457203945Sweongyo
1458203945Sweongyo		/* send HEADER */
1459203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
1460203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
1461203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
1462203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1463203945Sweongyo		/* send BODY */
1464203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
1465203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
1466203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
1467203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
1468203945Sweongyo	} else {
1469203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
1470203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
1471203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
1472203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1473203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
1474203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
1475203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
1476203945Sweongyo	}
1477203945Sweongyo
1478203945Sweongyo	return (0);
1479203945Sweongyo}
1480203945Sweongyo
1481203945Sweongyostatic struct bwn_pio_txqueue *
1482203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1483203945Sweongyo{
1484203945Sweongyo
1485203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1486203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1487203945Sweongyo
1488203945Sweongyo	switch (prio) {
1489203945Sweongyo	case 0:
1490203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1491203945Sweongyo	case 1:
1492203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1493203945Sweongyo	case 2:
1494203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1495203945Sweongyo	case 3:
1496203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1497203945Sweongyo	}
1498203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1499204242Simp	return (NULL);
1500203945Sweongyo}
1501203945Sweongyo
1502203945Sweongyostatic int
1503203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1504203945Sweongyo{
1505203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1506203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1507203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1508203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1509203945Sweongyo	struct bwn_dmadesc_generic *desc;
1510203945Sweongyo	struct bwn_dmadesc_meta *mt;
1511203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1512203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1513203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1514203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1515203945Sweongyo
1516203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1517203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1518203945Sweongyo
1519203945Sweongyo	/* XXX send after DTIM */
1520203945Sweongyo
1521203945Sweongyo	slot = bwn_dma_getslot(dr);
1522203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1523203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1524203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1525203945Sweongyo
1526203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1527203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1528203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1529203945Sweongyo	if (error)
1530203945Sweongyo		goto fail;
1531203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1532203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1533203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1534203945Sweongyo	if (error) {
1535203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1536203945Sweongyo		    __func__, error);
1537203945Sweongyo		goto fail;
1538203945Sweongyo	}
1539203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1540203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1541203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1542203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1543203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1544203945Sweongyo
1545203945Sweongyo	slot = bwn_dma_getslot(dr);
1546203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1547203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1548203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1549203945Sweongyo	mt->mt_m = m;
1550203945Sweongyo	mt->mt_ni = ni;
1551203945Sweongyo
1552203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1553203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1554203945Sweongyo	if (error && error != EFBIG) {
1555203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1556203945Sweongyo		    __func__, error);
1557203945Sweongyo		goto fail;
1558203945Sweongyo	}
1559203945Sweongyo	if (error) {    /* error == EFBIG */
1560203945Sweongyo		struct mbuf *m_new;
1561203945Sweongyo
1562203945Sweongyo		m_new = m_defrag(m, M_DONTWAIT);
1563203945Sweongyo		if (m_new == NULL) {
1564203945Sweongyo			if_printf(ifp, "%s: can't defrag TX buffer\n",
1565203945Sweongyo			    __func__);
1566203945Sweongyo			error = ENOBUFS;
1567203945Sweongyo			goto fail;
1568203945Sweongyo		} else {
1569203945Sweongyo			m = m_new;
1570203945Sweongyo		}
1571203945Sweongyo
1572203945Sweongyo		mt->mt_m = m;
1573203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1574203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1575203945Sweongyo		if (error) {
1576203945Sweongyo			if_printf(ifp, "%s: can't load TX buffer (2) %d\n",
1577203945Sweongyo			    __func__, error);
1578203945Sweongyo			goto fail;
1579203945Sweongyo		}
1580203945Sweongyo	}
1581203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1582203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1583203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1584203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1585203945Sweongyo
1586203945Sweongyo	/* XXX send after DTIM */
1587203945Sweongyo
1588203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1589203945Sweongyo	return (0);
1590203945Sweongyofail:
1591203945Sweongyo	dr->dr_curslot = backup[0];
1592203945Sweongyo	dr->dr_usedslot = backup[1];
1593203945Sweongyo	return (error);
1594203945Sweongyo#undef BWN_GET_TXHDRCACHE
1595203945Sweongyo}
1596203945Sweongyo
1597203945Sweongyostatic void
1598203945Sweongyobwn_watchdog(void *arg)
1599203945Sweongyo{
1600203945Sweongyo	struct bwn_softc *sc = arg;
1601203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1602203945Sweongyo
1603203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1604203945Sweongyo		if_printf(ifp, "device timeout\n");
1605203945Sweongyo		ifp->if_oerrors++;
1606203945Sweongyo	}
1607203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1608203945Sweongyo}
1609203945Sweongyo
1610203945Sweongyostatic int
1611203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1612203945Sweongyo{
1613203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1614203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1615203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
1616203945Sweongyo	int error, have_bg = 0, have_a = 0;
1617203945Sweongyo	uint32_t high;
1618203945Sweongyo
1619203945Sweongyo	KASSERT(sd->sd_id.sd_rev >= 5,
1620203945Sweongyo	    ("unsupported revision %d", sd->sd_id.sd_rev));
1621203945Sweongyo
1622203945Sweongyo	siba_powerup(siba, 0);
1623203945Sweongyo
1624203945Sweongyo	high = siba_read_4(sd, SIBA_TGSHIGH);
1625203945Sweongyo	bwn_reset_core(mac,
1626203945Sweongyo	    (high & BWN_TGSHIGH_HAVE_2GHZ) ? BWN_TGSLOW_SUPPORT_G : 0);
1627203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1628203945Sweongyo	if (error)
1629203945Sweongyo		goto fail;
1630203945Sweongyo
1631203945Sweongyo	have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1632203945Sweongyo	have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1633203945Sweongyo	if (siba->siba_pci_did != 0x4312 && siba->siba_pci_did != 0x4319 &&
1634203945Sweongyo	    siba->siba_pci_did != 0x4324) {
1635203945Sweongyo		have_a = have_bg = 0;
1636203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1637203945Sweongyo			have_a = 1;
1638203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1639203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1640203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1641203945Sweongyo			have_bg = 1;
1642203945Sweongyo		else
1643203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1644203945Sweongyo			    mac->mac_phy.type));
1645203945Sweongyo	}
1646203945Sweongyo	/* XXX turns off PHY A because it's not supported */
1647203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1648203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1649203945Sweongyo		have_a = 0;
1650203945Sweongyo		have_bg = 1;
1651203945Sweongyo	}
1652203945Sweongyo
1653203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1654203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1655203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1656203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1657203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1658203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1659203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1660203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1661203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1662203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1663203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1664203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1665203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1666203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1667203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1668203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1669203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1670203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1671203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1672203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1673203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1674203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1675203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1676203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1677203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1678203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1679203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1680203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1681203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1682203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1683203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1684203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1685203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1686203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1687203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1688203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1689203945Sweongyo	} else {
1690203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1691203945Sweongyo		    mac->mac_phy.type);
1692203945Sweongyo		error = ENXIO;
1693203945Sweongyo		goto fail;
1694203945Sweongyo	}
1695203945Sweongyo
1696203945Sweongyo	mac->mac_phy.gmode = have_bg;
1697203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1698203945Sweongyo		error = mac->mac_phy.attach(mac);
1699203945Sweongyo		if (error) {
1700203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1701203945Sweongyo			goto fail;
1702203945Sweongyo		}
1703203945Sweongyo	}
1704203945Sweongyo
1705203945Sweongyo	bwn_reset_core(mac, have_bg ? BWN_TGSLOW_SUPPORT_G : 0);
1706203945Sweongyo
1707203945Sweongyo	error = bwn_chiptest(mac);
1708203945Sweongyo	if (error)
1709203945Sweongyo		goto fail;
1710203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1711203945Sweongyo	if (error) {
1712203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1713203945Sweongyo		goto fail;
1714203945Sweongyo	}
1715203945Sweongyo
1716203945Sweongyo	if (sc->sc_curmac == NULL)
1717203945Sweongyo		sc->sc_curmac = mac;
1718203945Sweongyo
1719203945Sweongyo	error = bwn_dma_attach(mac);
1720203945Sweongyo	if (error != 0) {
1721203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1722203945Sweongyo		goto fail;
1723203945Sweongyo	}
1724203945Sweongyo
1725203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1726203945Sweongyo
1727203945Sweongyo	siba_dev_down(sd, 0);
1728203945Sweongyofail:
1729203945Sweongyo	siba_powerdown(siba);
1730203945Sweongyo	return (error);
1731203945Sweongyo}
1732203945Sweongyo
1733203945Sweongyostatic void
1734203945Sweongyobwn_reset_core(struct bwn_mac *mac, uint32_t flags)
1735203945Sweongyo{
1736203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1737203945Sweongyo	uint32_t low, ctl;
1738203945Sweongyo
1739203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1740203945Sweongyo
1741203945Sweongyo	siba_dev_up(sd, flags);
1742203945Sweongyo	DELAY(2000);
1743203945Sweongyo
1744203945Sweongyo	low = (siba_read_4(sd, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1745203945Sweongyo	    ~BWN_TGSLOW_PHYRESET;
1746203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW, low);
1747203945Sweongyo	siba_read_4(sd, SIBA_TGSLOW);
1748203945Sweongyo	DELAY(1000);
1749203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
1750203945Sweongyo	siba_read_4(sd, SIBA_TGSLOW);
1751203945Sweongyo	DELAY(1000);
1752203945Sweongyo
1753203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1754203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1755203945Sweongyo
1756203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1757203945Sweongyo	if (flags & BWN_TGSLOW_SUPPORT_G)
1758203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1759203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1760203945Sweongyo}
1761203945Sweongyo
1762203945Sweongyostatic int
1763203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1764203945Sweongyo{
1765203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1766203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1767203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1768203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
1769203945Sweongyo	uint32_t tmp;
1770203945Sweongyo
1771203945Sweongyo	/* PHY */
1772203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1773203945Sweongyo	phy->gmode = (tgshigh & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1774203945Sweongyo	phy->rf_on = 1;
1775203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1776203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1777203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1778203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1779203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1780203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1781203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1782203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1783203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1784203945Sweongyo		goto unsupphy;
1785203945Sweongyo
1786203945Sweongyo	/* RADIO */
1787203945Sweongyo	if (siba->siba_chipid == 0x4317) {
1788203945Sweongyo		if (siba->siba_chiprev == 0)
1789203945Sweongyo			tmp = 0x3205017f;
1790203945Sweongyo		else if (siba->siba_chiprev == 1)
1791203945Sweongyo			tmp = 0x4205017f;
1792203945Sweongyo		else
1793203945Sweongyo			tmp = 0x5205017f;
1794203945Sweongyo	} else {
1795203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1796203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1797203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1798203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1799203945Sweongyo	}
1800203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1801203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1802203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1803203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1804203945Sweongyo		goto unsupradio;
1805203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1806203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1807203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1808203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1809203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1810203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1811203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1812203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1813203945Sweongyo		goto unsupradio;
1814203945Sweongyo
1815203945Sweongyo	return (0);
1816203945Sweongyounsupphy:
1817203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1818203945Sweongyo	    "analog %#x)\n",
1819203945Sweongyo	    phy->type, phy->rev, phy->analog);
1820203945Sweongyo	return (ENXIO);
1821203945Sweongyounsupradio:
1822203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1823203945Sweongyo	    "rev %#x)\n",
1824203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1825203945Sweongyo	return (ENXIO);
1826203945Sweongyo}
1827203945Sweongyo
1828203945Sweongyostatic int
1829203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1830203945Sweongyo{
1831203945Sweongyo#define	TESTVAL0	0x55aaaa55
1832203945Sweongyo#define	TESTVAL1	0xaa5555aa
1833203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1834203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1835203945Sweongyo	uint32_t v, backup;
1836203945Sweongyo
1837203945Sweongyo	BWN_LOCK(sc);
1838203945Sweongyo
1839203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1840203945Sweongyo
1841203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1842203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1843203945Sweongyo		goto error;
1844203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1845203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1846203945Sweongyo		goto error;
1847203945Sweongyo
1848203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1849203945Sweongyo
1850203945Sweongyo	if ((sd->sd_id.sd_rev >= 3) && (sd->sd_id.sd_rev <= 10)) {
1851203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1852203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1853203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1854203945Sweongyo			goto error;
1855203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1856203945Sweongyo			goto error;
1857203945Sweongyo	}
1858203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1859203945Sweongyo
1860203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1861203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1862203945Sweongyo		goto error;
1863203945Sweongyo
1864203945Sweongyo	BWN_UNLOCK(sc);
1865203945Sweongyo	return (0);
1866203945Sweongyoerror:
1867203945Sweongyo	BWN_UNLOCK(sc);
1868203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1869203945Sweongyo	return (ENODEV);
1870203945Sweongyo}
1871203945Sweongyo
1872203945Sweongyo#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
1873203945Sweongyo#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
1874203945Sweongyo
1875203945Sweongyostatic int
1876203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1877203945Sweongyo{
1878203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1879203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1880203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1881203945Sweongyo
1882203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1883203945Sweongyo	ic->ic_nchans = 0;
1884203945Sweongyo
1885203945Sweongyo	if (have_bg)
1886203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1887203945Sweongyo		    &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
1888203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1889203945Sweongyo		if (have_a)
1890203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1891203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_n,
1892203945Sweongyo			    IEEE80211_CHAN_HTA);
1893203945Sweongyo	} else {
1894203945Sweongyo		if (have_a)
1895203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1896203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_a,
1897203945Sweongyo			    IEEE80211_CHAN_A);
1898203945Sweongyo	}
1899203945Sweongyo
1900203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1901203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1902203945Sweongyo
1903203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1904203945Sweongyo}
1905203945Sweongyo
1906203945Sweongyostatic uint32_t
1907203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1908203945Sweongyo{
1909203945Sweongyo	uint32_t ret;
1910203945Sweongyo
1911204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1912203945Sweongyo
1913203945Sweongyo	if (way == BWN_SHARED) {
1914203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1915203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1916203945Sweongyo		if (offset & 0x0003) {
1917203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1918203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1919203945Sweongyo			ret <<= 16;
1920203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1921203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1922203945Sweongyo			goto out;
1923203945Sweongyo		}
1924203945Sweongyo		offset >>= 2;
1925203945Sweongyo	}
1926203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1927203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1928203945Sweongyoout:
1929203945Sweongyo	return (ret);
1930203945Sweongyo}
1931203945Sweongyo
1932203945Sweongyostatic uint16_t
1933203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1934203945Sweongyo{
1935203945Sweongyo	uint16_t ret;
1936203945Sweongyo
1937204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1938203945Sweongyo
1939203945Sweongyo	if (way == BWN_SHARED) {
1940203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1941203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1942203945Sweongyo		if (offset & 0x0003) {
1943203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1944203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1945203945Sweongyo			goto out;
1946203945Sweongyo		}
1947203945Sweongyo		offset >>= 2;
1948203945Sweongyo	}
1949203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1950203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1951203945Sweongyoout:
1952203945Sweongyo
1953203945Sweongyo	return (ret);
1954203945Sweongyo}
1955203945Sweongyo
1956203945Sweongyostatic void
1957203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1958203945Sweongyo    uint16_t offset)
1959203945Sweongyo{
1960203945Sweongyo	uint32_t control;
1961203945Sweongyo
1962203945Sweongyo	control = way;
1963203945Sweongyo	control <<= 16;
1964203945Sweongyo	control |= offset;
1965203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1966203945Sweongyo}
1967203945Sweongyo
1968203945Sweongyostatic void
1969203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1970203945Sweongyo    uint32_t value)
1971203945Sweongyo{
1972204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1973203945Sweongyo
1974203945Sweongyo	if (way == BWN_SHARED) {
1975203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1976203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1977203945Sweongyo		if (offset & 0x0003) {
1978203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1979203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1980203945Sweongyo				    (value >> 16) & 0xffff);
1981203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1982203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1983203945Sweongyo			return;
1984203945Sweongyo		}
1985203945Sweongyo		offset >>= 2;
1986203945Sweongyo	}
1987203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1988203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1989203945Sweongyo}
1990203945Sweongyo
1991203945Sweongyostatic void
1992203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1993203945Sweongyo    uint16_t value)
1994203945Sweongyo{
1995204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1996203945Sweongyo
1997203945Sweongyo	if (way == BWN_SHARED) {
1998203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1999203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
2000203945Sweongyo		if (offset & 0x0003) {
2001203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
2002203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
2003203945Sweongyo			return;
2004203945Sweongyo		}
2005203945Sweongyo		offset >>= 2;
2006203945Sweongyo	}
2007203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
2008203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
2009203945Sweongyo}
2010203945Sweongyo
2011203945Sweongyostatic void
2012203945Sweongyobwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
2013203945Sweongyo    int txpow)
2014203945Sweongyo{
2015203945Sweongyo
2016203945Sweongyo	c->ic_freq = freq;
2017203945Sweongyo	c->ic_flags = flags;
2018203945Sweongyo	c->ic_ieee = ieee;
2019203945Sweongyo	c->ic_minpower = 0;
2020203945Sweongyo	c->ic_maxpower = 2 * txpow;
2021203945Sweongyo	c->ic_maxregpower = txpow;
2022203945Sweongyo}
2023203945Sweongyo
2024203945Sweongyostatic void
2025203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
2026203945Sweongyo    const struct bwn_channelinfo *ci, int flags)
2027203945Sweongyo{
2028203945Sweongyo	struct ieee80211_channel *c;
2029203945Sweongyo	int i;
2030203945Sweongyo
2031203945Sweongyo	c = &chans[*nchans];
2032203945Sweongyo
2033203945Sweongyo	for (i = 0; i < ci->nchannels; i++) {
2034203945Sweongyo		const struct bwn_channel *hc;
2035203945Sweongyo
2036203945Sweongyo		hc = &ci->channels[i];
2037203945Sweongyo		if (*nchans >= maxchans)
2038203945Sweongyo			break;
2039203945Sweongyo		bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
2040203945Sweongyo		c++, (*nchans)++;
2041203945Sweongyo		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
2042203945Sweongyo			/* g channel have a separate b-only entry */
2043203945Sweongyo			if (*nchans >= maxchans)
2044203945Sweongyo				break;
2045203945Sweongyo			c[0] = c[-1];
2046203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_B;
2047203945Sweongyo			c++, (*nchans)++;
2048203945Sweongyo		}
2049203945Sweongyo		if (flags == IEEE80211_CHAN_HTG) {
2050203945Sweongyo			/* HT g channel have a separate g-only entry */
2051203945Sweongyo			if (*nchans >= maxchans)
2052203945Sweongyo				break;
2053203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_G;
2054203945Sweongyo			c[0] = c[-1];
2055203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2056203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2057203945Sweongyo			c++, (*nchans)++;
2058203945Sweongyo		}
2059203945Sweongyo		if (flags == IEEE80211_CHAN_HTA) {
2060203945Sweongyo			/* HT a channel have a separate a-only entry */
2061203945Sweongyo			if (*nchans >= maxchans)
2062203945Sweongyo				break;
2063203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_A;
2064203945Sweongyo			c[0] = c[-1];
2065203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2066203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2067203945Sweongyo			c++, (*nchans)++;
2068203945Sweongyo		}
2069203945Sweongyo	}
2070203945Sweongyo}
2071203945Sweongyo
2072203945Sweongyostatic int
2073203945Sweongyobwn_phy_g_attach(struct bwn_mac *mac)
2074203945Sweongyo{
2075203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2076203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2077203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2078203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
2079203945Sweongyo	struct siba_sprom *sprom = &sd->sd_bus->siba_sprom;
2080203945Sweongyo	unsigned int i;
2081203945Sweongyo	int16_t pab0 = (int16_t)(sprom->pa0b0), pab1 = (int16_t)(sprom->pa0b1),
2082203945Sweongyo	    pab2 = (int16_t)(sprom->pa0b2);
2083203945Sweongyo	static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
2084203945Sweongyo	int8_t bg = (int8_t)sprom->tssi_bg;
2085203945Sweongyo
2086203945Sweongyo	if ((sd->sd_bus->siba_chipid == 0x4301) && (phy->rf_ver != 0x2050))
2087203945Sweongyo		device_printf(sc->sc_dev, "not supported anymore\n");
2088203945Sweongyo
2089203945Sweongyo	pg->pg_flags = 0;
2090203945Sweongyo	if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
2091203945Sweongyo	    pab2 == -1) {
2092203945Sweongyo		pg->pg_idletssi = 52;
2093203945Sweongyo		pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
2094203945Sweongyo		return (0);
2095203945Sweongyo	}
2096203945Sweongyo
2097203945Sweongyo	pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
2098203945Sweongyo	pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
2099203945Sweongyo	if (pg->pg_tssi2dbm == NULL) {
2100203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer\n");
2101203945Sweongyo		return (ENOMEM);
2102203945Sweongyo	}
2103203945Sweongyo	for (i = 0; i < 64; i++) {
2104203945Sweongyo		int32_t m1, m2, f, q, delta;
2105203945Sweongyo		int8_t j = 0;
2106203945Sweongyo
2107203945Sweongyo		m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
2108203945Sweongyo		m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
2109203945Sweongyo		f = 256;
2110203945Sweongyo
2111203945Sweongyo		do {
2112203945Sweongyo			if (j > 15) {
2113203945Sweongyo				device_printf(sc->sc_dev,
2114203945Sweongyo				    "failed to generate tssi2dBm\n");
2115203945Sweongyo				free(pg->pg_tssi2dbm, M_DEVBUF);
2116203945Sweongyo				return (ENOMEM);
2117203945Sweongyo			}
2118203945Sweongyo			q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
2119203945Sweongyo			    f, 2048);
2120203945Sweongyo			delta = abs(q - f);
2121203945Sweongyo			f = q;
2122203945Sweongyo			j++;
2123203945Sweongyo		} while (delta >= 2);
2124203945Sweongyo
2125203945Sweongyo		pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
2126203945Sweongyo		    128);
2127203945Sweongyo	}
2128203945Sweongyo
2129203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
2130203945Sweongyo	return (0);
2131203945Sweongyo}
2132203945Sweongyo
2133203945Sweongyostatic void
2134203945Sweongyobwn_phy_g_detach(struct bwn_mac *mac)
2135203945Sweongyo{
2136203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
2137203945Sweongyo
2138203945Sweongyo	if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
2139203945Sweongyo		free(pg->pg_tssi2dbm, M_DEVBUF);
2140203945Sweongyo		pg->pg_tssi2dbm = NULL;
2141203945Sweongyo	}
2142203945Sweongyo	pg->pg_flags = 0;
2143203945Sweongyo}
2144203945Sweongyo
2145203945Sweongyostatic void
2146203945Sweongyobwn_phy_g_init_pre(struct bwn_mac *mac)
2147203945Sweongyo{
2148203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2149203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2150203945Sweongyo	void *tssi2dbm;
2151203945Sweongyo	int idletssi;
2152203945Sweongyo	unsigned int i;
2153203945Sweongyo
2154203945Sweongyo	tssi2dbm = pg->pg_tssi2dbm;
2155203945Sweongyo	idletssi = pg->pg_idletssi;
2156203945Sweongyo
2157203945Sweongyo	memset(pg, 0, sizeof(*pg));
2158203945Sweongyo
2159203945Sweongyo	pg->pg_tssi2dbm = tssi2dbm;
2160203945Sweongyo	pg->pg_idletssi = idletssi;
2161203945Sweongyo
2162203945Sweongyo	memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
2163203945Sweongyo
2164203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi); i++)
2165203945Sweongyo		pg->pg_nrssi[i] = -1000;
2166203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi_lt); i++)
2167203945Sweongyo		pg->pg_nrssi_lt[i] = i;
2168203945Sweongyo	pg->pg_lofcal = 0xffff;
2169203945Sweongyo	pg->pg_initval = 0xffff;
2170203945Sweongyo	pg->pg_immode = BWN_IMMODE_NONE;
2171203945Sweongyo	pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
2172203945Sweongyo	pg->pg_avgtssi = 0xff;
2173203945Sweongyo
2174203945Sweongyo	pg->pg_loctl.tx_bias = 0xff;
2175203945Sweongyo	TAILQ_INIT(&pg->pg_loctl.calib_list);
2176203945Sweongyo}
2177203945Sweongyo
2178203945Sweongyostatic int
2179203945Sweongyobwn_phy_g_prepare_hw(struct bwn_mac *mac)
2180203945Sweongyo{
2181203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2182203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2183203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2184203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
2185203945Sweongyo	static const struct bwn_rfatt rfatt0[] = {
2186203945Sweongyo		{ 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 },	{ 9, 0 }, { 2, 0 },
2187203945Sweongyo		{ 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
2188203945Sweongyo		{ 3, 1 }, { 4, 1 }
2189203945Sweongyo	};
2190203945Sweongyo	static const struct bwn_rfatt rfatt1[] = {
2191203945Sweongyo		{ 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
2192203945Sweongyo		{ 14, 1 }
2193203945Sweongyo	};
2194203945Sweongyo	static const struct bwn_rfatt rfatt2[] = {
2195203945Sweongyo		{ 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
2196203945Sweongyo		{ 9, 1 }
2197203945Sweongyo	};
2198203945Sweongyo	static const struct bwn_bbatt bbatt_0[] = {
2199203945Sweongyo		{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
2200203945Sweongyo	};
2201203945Sweongyo
2202203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
2203203945Sweongyo
2204203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
2205203945Sweongyo		pg->pg_bbatt.att = 0;
2206203945Sweongyo	else
2207203945Sweongyo		pg->pg_bbatt.att = 2;
2208203945Sweongyo
2209203945Sweongyo	/* prepare Radio Attenuation */
2210203945Sweongyo	pg->pg_rfatt.padmix = 0;
2211203945Sweongyo
2212203945Sweongyo	if (bus->siba_board_vendor == SIBA_BOARDVENDOR_BCM &&
2213203945Sweongyo	    bus->siba_board_type == SIBA_BOARD_BCM4309G) {
2214203945Sweongyo		if (bus->siba_board_rev < 0x43) {
2215203945Sweongyo			pg->pg_rfatt.att = 2;
2216203945Sweongyo			goto done;
2217203945Sweongyo		} else if (bus->siba_board_rev < 0x51) {
2218203945Sweongyo			pg->pg_rfatt.att = 3;
2219203945Sweongyo			goto done;
2220203945Sweongyo		}
2221203945Sweongyo	}
2222203945Sweongyo
2223203945Sweongyo	if (phy->type == BWN_PHYTYPE_A) {
2224203945Sweongyo		pg->pg_rfatt.att = 0x60;
2225203945Sweongyo		goto done;
2226203945Sweongyo	}
2227203945Sweongyo
2228203945Sweongyo	switch (phy->rf_ver) {
2229203945Sweongyo	case 0x2050:
2230203945Sweongyo		switch (phy->rf_rev) {
2231203945Sweongyo		case 0:
2232203945Sweongyo			pg->pg_rfatt.att = 5;
2233203945Sweongyo			goto done;
2234203945Sweongyo		case 1:
2235203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2236203945Sweongyo				if (bus->siba_board_vendor ==
2237203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2238203945Sweongyo				    bus->siba_board_type ==
2239203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2240203945Sweongyo				    bus->siba_board_rev >= 30)
2241203945Sweongyo					pg->pg_rfatt.att = 3;
2242203945Sweongyo				else if (bus->siba_board_vendor ==
2243203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2244203945Sweongyo				    bus->siba_board_type == SIBA_BOARD_BU4306)
2245203945Sweongyo					pg->pg_rfatt.att = 3;
2246203945Sweongyo				else
2247203945Sweongyo					pg->pg_rfatt.att = 1;
2248203945Sweongyo			} else {
2249203945Sweongyo				if (bus->siba_board_vendor ==
2250203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2251203945Sweongyo				    bus->siba_board_type ==
2252203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2253203945Sweongyo				    bus->siba_board_rev >= 30)
2254203945Sweongyo					pg->pg_rfatt.att = 7;
2255203945Sweongyo				else
2256203945Sweongyo					pg->pg_rfatt.att = 6;
2257203945Sweongyo			}
2258203945Sweongyo			goto done;
2259203945Sweongyo		case 2:
2260203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2261203945Sweongyo				if (bus->siba_board_vendor ==
2262203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2263203945Sweongyo				    bus->siba_board_type ==
2264203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2265203945Sweongyo				    bus->siba_board_rev >= 30)
2266203945Sweongyo					pg->pg_rfatt.att = 3;
2267203945Sweongyo				else if (bus->siba_board_vendor ==
2268203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2269203945Sweongyo				    bus->siba_board_type == SIBA_BOARD_BU4306)
2270203945Sweongyo					pg->pg_rfatt.att = 5;
2271203945Sweongyo				else if (bus->siba_chipid == 0x4320)
2272203945Sweongyo					pg->pg_rfatt.att = 4;
2273203945Sweongyo				else
2274203945Sweongyo					pg->pg_rfatt.att = 3;
2275203945Sweongyo			} else
2276203945Sweongyo				pg->pg_rfatt.att = 6;
2277203945Sweongyo			goto done;
2278203945Sweongyo		case 3:
2279203945Sweongyo			pg->pg_rfatt.att = 5;
2280203945Sweongyo			goto done;
2281203945Sweongyo		case 4:
2282203945Sweongyo		case 5:
2283203945Sweongyo			pg->pg_rfatt.att = 1;
2284203945Sweongyo			goto done;
2285203945Sweongyo		case 6:
2286203945Sweongyo		case 7:
2287203945Sweongyo			pg->pg_rfatt.att = 5;
2288203945Sweongyo			goto done;
2289203945Sweongyo		case 8:
2290203945Sweongyo			pg->pg_rfatt.att = 0xa;
2291203945Sweongyo			pg->pg_rfatt.padmix = 1;
2292203945Sweongyo			goto done;
2293203945Sweongyo		case 9:
2294203945Sweongyo		default:
2295203945Sweongyo			pg->pg_rfatt.att = 5;
2296203945Sweongyo			goto done;
2297203945Sweongyo		}
2298203945Sweongyo		break;
2299203945Sweongyo	case 0x2053:
2300203945Sweongyo		switch (phy->rf_rev) {
2301203945Sweongyo		case 1:
2302203945Sweongyo			pg->pg_rfatt.att = 6;
2303203945Sweongyo			goto done;
2304203945Sweongyo		}
2305203945Sweongyo		break;
2306203945Sweongyo	}
2307203945Sweongyo	pg->pg_rfatt.att = 5;
2308203945Sweongyodone:
2309203945Sweongyo	pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
2310203945Sweongyo
2311203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
2312203945Sweongyo		lo->rfatt.array = rfatt0;
2313203945Sweongyo		lo->rfatt.len = N(rfatt0);
2314203945Sweongyo		lo->rfatt.min = 0;
2315203945Sweongyo		lo->rfatt.max = 9;
2316203945Sweongyo		goto genbbatt;
2317203945Sweongyo	}
2318203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
2319203945Sweongyo		lo->rfatt.array = rfatt1;
2320203945Sweongyo		lo->rfatt.len = N(rfatt1);
2321203945Sweongyo		lo->rfatt.min = 0;
2322203945Sweongyo		lo->rfatt.max = 14;
2323203945Sweongyo		goto genbbatt;
2324203945Sweongyo	}
2325203945Sweongyo	lo->rfatt.array = rfatt2;
2326203945Sweongyo	lo->rfatt.len = N(rfatt2);
2327203945Sweongyo	lo->rfatt.min = 0;
2328203945Sweongyo	lo->rfatt.max = 9;
2329203945Sweongyogenbbatt:
2330203945Sweongyo	lo->bbatt.array = bbatt_0;
2331203945Sweongyo	lo->bbatt.len = N(bbatt_0);
2332203945Sweongyo	lo->bbatt.min = 0;
2333203945Sweongyo	lo->bbatt.max = 8;
2334203945Sweongyo
2335203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
2336203945Sweongyo	if (phy->rev == 1) {
2337203945Sweongyo		phy->gmode = 0;
2338203945Sweongyo		bwn_reset_core(mac, 0);
2339203945Sweongyo		bwn_phy_g_init_sub(mac);
2340203945Sweongyo		phy->gmode = 1;
2341203945Sweongyo		bwn_reset_core(mac, BWN_TGSLOW_SUPPORT_G);
2342203945Sweongyo	}
2343203945Sweongyo	return (0);
2344203945Sweongyo}
2345203945Sweongyo
2346203945Sweongyostatic uint16_t
2347203945Sweongyobwn_phy_g_txctl(struct bwn_mac *mac)
2348203945Sweongyo{
2349203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2350203945Sweongyo
2351203945Sweongyo	if (phy->rf_ver != 0x2050)
2352203945Sweongyo		return (0);
2353203945Sweongyo	if (phy->rf_rev == 1)
2354203945Sweongyo		return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
2355203945Sweongyo	if (phy->rf_rev < 6)
2356203945Sweongyo		return (BWN_TXCTL_PA2DB);
2357203945Sweongyo	if (phy->rf_rev == 8)
2358203945Sweongyo		return (BWN_TXCTL_TXMIX);
2359203945Sweongyo	return (0);
2360203945Sweongyo}
2361203945Sweongyo
2362203945Sweongyostatic int
2363203945Sweongyobwn_phy_g_init(struct bwn_mac *mac)
2364203945Sweongyo{
2365203945Sweongyo
2366203945Sweongyo	bwn_phy_g_init_sub(mac);
2367203945Sweongyo	return (0);
2368203945Sweongyo}
2369203945Sweongyo
2370203945Sweongyostatic void
2371203945Sweongyobwn_phy_g_exit(struct bwn_mac *mac)
2372203945Sweongyo{
2373203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
2374203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2375203945Sweongyo
2376203945Sweongyo	if (lo == NULL)
2377203945Sweongyo		return;
2378203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2379203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2380203945Sweongyo		free(cal, M_DEVBUF);
2381203945Sweongyo	}
2382203945Sweongyo}
2383203945Sweongyo
2384203945Sweongyostatic uint16_t
2385203945Sweongyobwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
2386203945Sweongyo{
2387203945Sweongyo
2388203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2389203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
2390203945Sweongyo}
2391203945Sweongyo
2392203945Sweongyostatic void
2393203945Sweongyobwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2394203945Sweongyo{
2395203945Sweongyo
2396203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2397203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
2398203945Sweongyo}
2399203945Sweongyo
2400203945Sweongyostatic uint16_t
2401203945Sweongyobwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
2402203945Sweongyo{
2403203945Sweongyo
2404203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2405203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
2406203945Sweongyo	return (BWN_READ_2(mac, BWN_RFDATALO));
2407203945Sweongyo}
2408203945Sweongyo
2409203945Sweongyostatic void
2410203945Sweongyobwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2411203945Sweongyo{
2412203945Sweongyo
2413203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2414203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
2415203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
2416203945Sweongyo}
2417203945Sweongyo
2418203945Sweongyostatic int
2419203945Sweongyobwn_phy_g_hwpctl(struct bwn_mac *mac)
2420203945Sweongyo{
2421203945Sweongyo
2422203945Sweongyo	return (mac->mac_phy.rev >= 6);
2423203945Sweongyo}
2424203945Sweongyo
2425203945Sweongyostatic void
2426203945Sweongyobwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
2427203945Sweongyo{
2428203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2429203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2430203945Sweongyo	unsigned int channel;
2431203945Sweongyo	uint16_t rfover, rfoverval;
2432203945Sweongyo
2433203945Sweongyo	if (on) {
2434203945Sweongyo		if (phy->rf_on)
2435203945Sweongyo			return;
2436203945Sweongyo
2437203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0x8000);
2438203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0xcc00);
2439203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
2440203945Sweongyo		if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
2441203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
2442203945Sweongyo			    pg->pg_radioctx_over);
2443203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
2444203945Sweongyo			    pg->pg_radioctx_overval);
2445203945Sweongyo			pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
2446203945Sweongyo		}
2447203945Sweongyo		channel = phy->chan;
2448203945Sweongyo		bwn_phy_g_switch_chan(mac, 6, 1);
2449203945Sweongyo		bwn_phy_g_switch_chan(mac, channel, 0);
2450203945Sweongyo		return;
2451203945Sweongyo	}
2452203945Sweongyo
2453203945Sweongyo	rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
2454203945Sweongyo	rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
2455203945Sweongyo	pg->pg_radioctx_over = rfover;
2456203945Sweongyo	pg->pg_radioctx_overval = rfoverval;
2457203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
2458203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
2459203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
2460203945Sweongyo}
2461203945Sweongyo
2462203945Sweongyostatic int
2463203945Sweongyobwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
2464203945Sweongyo{
2465203945Sweongyo
2466203945Sweongyo	if ((newchan < 1) || (newchan > 14))
2467203945Sweongyo		return (EINVAL);
2468203945Sweongyo	bwn_phy_g_switch_chan(mac, newchan, 0);
2469203945Sweongyo
2470203945Sweongyo	return (0);
2471203945Sweongyo}
2472203945Sweongyo
2473203945Sweongyostatic uint32_t
2474203945Sweongyobwn_phy_g_get_default_chan(struct bwn_mac *mac)
2475203945Sweongyo{
2476203945Sweongyo
2477203945Sweongyo	return (1);
2478203945Sweongyo}
2479203945Sweongyo
2480203945Sweongyostatic void
2481203945Sweongyobwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
2482203945Sweongyo{
2483203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2484203945Sweongyo	uint64_t hf;
2485203945Sweongyo	int autodiv = 0;
2486203945Sweongyo	uint16_t tmp;
2487203945Sweongyo
2488203945Sweongyo	if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
2489203945Sweongyo		autodiv = 1;
2490203945Sweongyo
2491203945Sweongyo	hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
2492203945Sweongyo	bwn_hf_write(mac, hf);
2493203945Sweongyo
2494203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
2495203945Sweongyo	    (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
2496203945Sweongyo	    ((autodiv ? BWN_ANTAUTO1 : antenna)
2497203945Sweongyo		<< BWN_PHY_BBANDCFG_RXANT_SHIFT));
2498203945Sweongyo
2499203945Sweongyo	if (autodiv) {
2500203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
2501203945Sweongyo		if (antenna == BWN_ANTAUTO1)
2502203945Sweongyo			tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
2503203945Sweongyo		else
2504203945Sweongyo			tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
2505203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
2506203945Sweongyo	}
2507203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
2508203945Sweongyo	if (autodiv)
2509203945Sweongyo		tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
2510203945Sweongyo	else
2511203945Sweongyo		tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
2512203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
2513203945Sweongyo	if (phy->rev >= 2) {
2514203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
2515203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
2516203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
2517203945Sweongyo		    (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
2518203945Sweongyo		    0x15);
2519203945Sweongyo		if (phy->rev == 2)
2520203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
2521203945Sweongyo		else
2522203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
2523203945Sweongyo			    (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
2524203945Sweongyo			    8);
2525203945Sweongyo	}
2526203945Sweongyo	if (phy->rev >= 6)
2527203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
2528203945Sweongyo
2529203945Sweongyo	hf |= BWN_HF_UCODE_ANTDIV_HELPER;
2530203945Sweongyo	bwn_hf_write(mac, hf);
2531203945Sweongyo}
2532203945Sweongyo
2533203945Sweongyostatic int
2534203945Sweongyobwn_phy_g_im(struct bwn_mac *mac, int mode)
2535203945Sweongyo{
2536203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2537203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2538203945Sweongyo
2539203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2540203945Sweongyo	KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
2541203945Sweongyo
2542203945Sweongyo	if (phy->rev == 0 || !phy->gmode)
2543203945Sweongyo		return (ENODEV);
2544203945Sweongyo
2545203945Sweongyo	pg->pg_aci_wlan_automatic = 0;
2546203945Sweongyo	return (0);
2547203945Sweongyo}
2548203945Sweongyo
2549203945Sweongyostatic int
2550203945Sweongyobwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
2551203945Sweongyo{
2552203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2553203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2554203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2555203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
2556203945Sweongyo	unsigned int tssi;
2557203945Sweongyo	int cck, ofdm;
2558203945Sweongyo	int power;
2559203945Sweongyo	int rfatt, bbatt;
2560203945Sweongyo	unsigned int max;
2561203945Sweongyo
2562203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2563203945Sweongyo
2564203945Sweongyo	cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
2565203945Sweongyo	ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
2566203945Sweongyo	if (cck < 0 && ofdm < 0) {
2567203945Sweongyo		if (ignore_tssi == 0)
2568203945Sweongyo			return (BWN_TXPWR_RES_DONE);
2569203945Sweongyo		cck = 0;
2570203945Sweongyo		ofdm = 0;
2571203945Sweongyo	}
2572203945Sweongyo	tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
2573203945Sweongyo	if (pg->pg_avgtssi != 0xff)
2574203945Sweongyo		tssi = (tssi + pg->pg_avgtssi) / 2;
2575203945Sweongyo	pg->pg_avgtssi = tssi;
2576203945Sweongyo	KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
2577203945Sweongyo
2578203945Sweongyo	max = siba->siba_sprom.maxpwr_bg;
2579203945Sweongyo	if (siba->siba_sprom.bf_lo & BWN_BFL_PACTRL)
2580203945Sweongyo		max -= 3;
2581203945Sweongyo	if (max >= 120) {
2582203945Sweongyo		device_printf(sc->sc_dev, "invalid max TX-power value\n");
2583203945Sweongyo		siba->siba_sprom.maxpwr_bg = max = 80;
2584203945Sweongyo	}
2585203945Sweongyo
2586203945Sweongyo	power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
2587203945Sweongyo	    (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
2588203945Sweongyo	     tssi, 0x00), 0x3f)]);
2589203945Sweongyo	if (power == 0)
2590203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2591203945Sweongyo
2592203945Sweongyo	rfatt = -((power + 7) / 8);
2593203945Sweongyo	bbatt = (-(power / 2)) - (4 * rfatt);
2594203945Sweongyo	if ((rfatt == 0) && (bbatt == 0))
2595203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2596203945Sweongyo	pg->pg_bbatt_delta = bbatt;
2597203945Sweongyo	pg->pg_rfatt_delta = rfatt;
2598203945Sweongyo	return (BWN_TXPWR_RES_NEED_ADJUST);
2599203945Sweongyo}
2600203945Sweongyo
2601203945Sweongyostatic void
2602203945Sweongyobwn_phy_g_set_txpwr(struct bwn_mac *mac)
2603203945Sweongyo{
2604203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2605203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2606203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2607203945Sweongyo	int rfatt, bbatt;
2608203945Sweongyo	uint8_t txctl;
2609203945Sweongyo
2610203945Sweongyo	bwn_mac_suspend(mac);
2611203945Sweongyo
2612203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2613203945Sweongyo
2614203945Sweongyo	bbatt = pg->pg_bbatt.att;
2615203945Sweongyo	bbatt += pg->pg_bbatt_delta;
2616203945Sweongyo	rfatt = pg->pg_rfatt.att;
2617203945Sweongyo	rfatt += pg->pg_rfatt_delta;
2618203945Sweongyo
2619203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2620203945Sweongyo	txctl = pg->pg_txctl;
2621203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
2622203945Sweongyo		if (rfatt <= 1) {
2623203945Sweongyo			if (txctl == 0) {
2624203945Sweongyo				txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
2625203945Sweongyo				rfatt += 2;
2626203945Sweongyo				bbatt += 2;
2627203945Sweongyo			} else if (mac->mac_sd->sd_bus->siba_sprom.
2628203945Sweongyo				   bf_lo &
2629203945Sweongyo				   BWN_BFL_PACTRL) {
2630203945Sweongyo				bbatt += 4 * (rfatt - 2);
2631203945Sweongyo				rfatt = 2;
2632203945Sweongyo			}
2633203945Sweongyo		} else if (rfatt > 4 && txctl) {
2634203945Sweongyo			txctl = 0;
2635203945Sweongyo			if (bbatt < 3) {
2636203945Sweongyo				rfatt -= 3;
2637203945Sweongyo				bbatt += 2;
2638203945Sweongyo			} else {
2639203945Sweongyo				rfatt -= 2;
2640203945Sweongyo				bbatt -= 2;
2641203945Sweongyo			}
2642203945Sweongyo		}
2643203945Sweongyo	}
2644203945Sweongyo	pg->pg_txctl = txctl;
2645203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2646203945Sweongyo	pg->pg_rfatt.att = rfatt;
2647203945Sweongyo	pg->pg_bbatt.att = bbatt;
2648203945Sweongyo
2649203945Sweongyo	DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
2650203945Sweongyo
2651203945Sweongyo	bwn_phy_lock(mac);
2652203945Sweongyo	bwn_rf_lock(mac);
2653203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
2654203945Sweongyo	    pg->pg_txctl);
2655203945Sweongyo	bwn_rf_unlock(mac);
2656203945Sweongyo	bwn_phy_unlock(mac);
2657203945Sweongyo
2658203945Sweongyo	bwn_mac_enable(mac);
2659203945Sweongyo}
2660203945Sweongyo
2661203945Sweongyostatic void
2662203945Sweongyobwn_phy_g_task_15s(struct bwn_mac *mac)
2663203945Sweongyo{
2664203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2665203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2666203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2667203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2668203945Sweongyo	unsigned long expire, now;
2669203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2670203945Sweongyo	uint8_t expired = 0;
2671203945Sweongyo
2672203945Sweongyo	bwn_mac_suspend(mac);
2673203945Sweongyo
2674203945Sweongyo	if (lo == NULL)
2675203945Sweongyo		goto fail;
2676203945Sweongyo
2677203945Sweongyo	BWN_GETTIME(now);
2678203945Sweongyo	if (bwn_has_hwpctl(mac)) {
2679203945Sweongyo		expire = now - BWN_LO_PWRVEC_EXPIRE;
2680203945Sweongyo		if (time_before(lo->pwr_vec_read_time, expire)) {
2681203945Sweongyo			bwn_lo_get_powervector(mac);
2682203945Sweongyo			bwn_phy_g_dc_lookup_init(mac, 0);
2683203945Sweongyo		}
2684203945Sweongyo		goto fail;
2685203945Sweongyo	}
2686203945Sweongyo
2687203945Sweongyo	expire = now - BWN_LO_CALIB_EXPIRE;
2688203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2689203945Sweongyo		if (!time_before(cal->calib_time, expire))
2690203945Sweongyo			continue;
2691203945Sweongyo		if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
2692203945Sweongyo		    BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
2693203945Sweongyo			KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
2694203945Sweongyo			expired = 1;
2695203945Sweongyo		}
2696203945Sweongyo
2697203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
2698203945Sweongyo		    cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
2699203945Sweongyo		    cal->ctl.i, cal->ctl.q);
2700203945Sweongyo
2701203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2702203945Sweongyo		free(cal, M_DEVBUF);
2703203945Sweongyo	}
2704203945Sweongyo	if (expired || TAILQ_EMPTY(&lo->calib_list)) {
2705203945Sweongyo		cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
2706203945Sweongyo		    &pg->pg_rfatt);
2707203945Sweongyo		if (cal == NULL) {
2708203945Sweongyo			device_printf(sc->sc_dev,
2709203945Sweongyo			    "failed to recalibrate LO\n");
2710203945Sweongyo			goto fail;
2711203945Sweongyo		}
2712203945Sweongyo		TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
2713203945Sweongyo		bwn_lo_write(mac, &cal->ctl);
2714203945Sweongyo	}
2715203945Sweongyo
2716203945Sweongyofail:
2717203945Sweongyo	bwn_mac_enable(mac);
2718203945Sweongyo}
2719203945Sweongyo
2720203945Sweongyostatic void
2721203945Sweongyobwn_phy_g_task_60s(struct bwn_mac *mac)
2722203945Sweongyo{
2723203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2724203945Sweongyo	uint8_t old = phy->chan;
2725203945Sweongyo
2726203945Sweongyo	if (!(mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_RSSI))
2727203945Sweongyo		return;
2728203945Sweongyo
2729203945Sweongyo	bwn_mac_suspend(mac);
2730203945Sweongyo	bwn_nrssi_slope_11g(mac);
2731203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
2732203945Sweongyo		bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
2733203945Sweongyo		bwn_switch_channel(mac, old);
2734203945Sweongyo	}
2735203945Sweongyo	bwn_mac_enable(mac);
2736203945Sweongyo}
2737203945Sweongyo
2738203945Sweongyostatic void
2739203945Sweongyobwn_phy_switch_analog(struct bwn_mac *mac, int on)
2740203945Sweongyo{
2741203945Sweongyo
2742203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
2743203945Sweongyo}
2744203945Sweongyo
2745203945Sweongyostatic int
2746203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
2747203945Sweongyo	const struct ieee80211_bpf_params *params)
2748203945Sweongyo{
2749203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2750203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2751203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2752203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2753203945Sweongyo
2754203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
2755203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
2756203945Sweongyo		ieee80211_free_node(ni);
2757203945Sweongyo		m_freem(m);
2758203945Sweongyo		return (ENETDOWN);
2759203945Sweongyo	}
2760203945Sweongyo
2761203945Sweongyo	BWN_LOCK(sc);
2762203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
2763203945Sweongyo		ieee80211_free_node(ni);
2764203945Sweongyo		m_freem(m);
2765203945Sweongyo		ifp->if_oerrors++;
2766203945Sweongyo		BWN_UNLOCK(sc);
2767203945Sweongyo		return (ENOBUFS);
2768203945Sweongyo	}
2769203945Sweongyo
2770203945Sweongyo	if (bwn_tx_start(sc, ni, m) != 0) {
2771203945Sweongyo		if (ni != NULL)
2772203945Sweongyo			ieee80211_free_node(ni);
2773203945Sweongyo		ifp->if_oerrors++;
2774203945Sweongyo	}
2775203945Sweongyo	sc->sc_watchdog_timer = 5;
2776203945Sweongyo	BWN_UNLOCK(sc);
2777203945Sweongyo	return (0);
2778203945Sweongyo}
2779203945Sweongyo
2780203945Sweongyo/*
2781203945Sweongyo * Setup driver-specific state for a newly associated node.
2782203945Sweongyo * Note that we're called also on a re-associate, the isnew
2783203945Sweongyo * param tells us if this is the first time or not.
2784203945Sweongyo */
2785203945Sweongyostatic void
2786203945Sweongyobwn_newassoc(struct ieee80211_node *ni, int isnew)
2787203945Sweongyo{
2788203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
2789203945Sweongyo
2790203945Sweongyo	ieee80211_amrr_node_init(&BWN_VAP(vap)->bv_amrr,
2791203945Sweongyo	    &BWN_NODE(ni)->bn_amn, ni);
2792203945Sweongyo}
2793203945Sweongyo
2794203945Sweongyo/*
2795203945Sweongyo * Callback from the 802.11 layer to update the slot time
2796203945Sweongyo * based on the current setting.  We use it to notify the
2797203945Sweongyo * firmware of ERP changes and the f/w takes care of things
2798203945Sweongyo * like slot time and preamble.
2799203945Sweongyo */
2800203945Sweongyostatic void
2801203945Sweongyobwn_updateslot(struct ifnet *ifp)
2802203945Sweongyo{
2803203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2804203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
2805203945Sweongyo	struct bwn_mac *mac;
2806203945Sweongyo
2807203945Sweongyo	BWN_LOCK(sc);
2808203945Sweongyo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2809203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
2810203945Sweongyo		bwn_set_slot_time(mac,
2811203945Sweongyo		    (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20);
2812203945Sweongyo	}
2813203945Sweongyo	BWN_UNLOCK(sc);
2814203945Sweongyo}
2815203945Sweongyo
2816203945Sweongyo/*
2817203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
2818203945Sweongyo * Note this interface does not check the operating mode as this
2819203945Sweongyo * is an internal callback and we are expected to honor the current
2820203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
2821203945Sweongyo * mode when operating in hostap mode to do ACS).
2822203945Sweongyo */
2823203945Sweongyostatic void
2824203945Sweongyobwn_update_promisc(struct ifnet *ifp)
2825203945Sweongyo{
2826203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2827203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2828203945Sweongyo
2829203945Sweongyo	BWN_LOCK(sc);
2830203945Sweongyo	mac = sc->sc_curmac;
2831203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2832203945Sweongyo		if (ifp->if_flags & IFF_PROMISC)
2833203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
2834203945Sweongyo		else
2835203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
2836203945Sweongyo		bwn_set_opmode(mac);
2837203945Sweongyo	}
2838203945Sweongyo	BWN_UNLOCK(sc);
2839203945Sweongyo}
2840203945Sweongyo
2841203945Sweongyo/*
2842203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
2843203945Sweongyo */
2844203945Sweongyostatic int
2845203945Sweongyobwn_wme_update(struct ieee80211com *ic)
2846203945Sweongyo{
2847203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2848203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2849203945Sweongyo	struct wmeParams *wmep;
2850203945Sweongyo	int i;
2851203945Sweongyo
2852203945Sweongyo	BWN_LOCK(sc);
2853203945Sweongyo	mac = sc->sc_curmac;
2854203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2855203945Sweongyo		bwn_mac_suspend(mac);
2856203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
2857203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
2858203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
2859203945Sweongyo		}
2860203945Sweongyo		bwn_mac_enable(mac);
2861203945Sweongyo	}
2862203945Sweongyo	BWN_UNLOCK(sc);
2863203945Sweongyo	return (0);
2864203945Sweongyo}
2865203945Sweongyo
2866203945Sweongyostatic struct ieee80211_node *
2867203945Sweongyobwn_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
2868203945Sweongyo{
2869203945Sweongyo	struct ieee80211com *ic = vap->iv_ic;
2870203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2871203945Sweongyo	const size_t space = sizeof(struct bwn_node);
2872203945Sweongyo	struct bwn_node *bn;
2873203945Sweongyo
2874203945Sweongyo	bn = malloc(space, M_80211_NODE, M_NOWAIT|M_ZERO);
2875203945Sweongyo	if (bn == NULL) {
2876203945Sweongyo		/* XXX stat+msg */
2877203945Sweongyo		return (NULL);
2878203945Sweongyo	}
2879203945Sweongyo	DPRINTF(sc, BWN_DEBUG_NODE, "%s: bn %p\n", __func__, bn);
2880203945Sweongyo	return (&bn->bn_node);
2881203945Sweongyo}
2882203945Sweongyo
2883203945Sweongyostatic void
2884203945Sweongyobwn_node_cleanup(struct ieee80211_node *ni)
2885203945Sweongyo{
2886203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2887203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2888203945Sweongyo
2889203945Sweongyo	sc->sc_node_cleanup(ni);
2890203945Sweongyo}
2891203945Sweongyo
2892203945Sweongyostatic void
2893203945Sweongyobwn_scan_start(struct ieee80211com *ic)
2894203945Sweongyo{
2895203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2896203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2897203945Sweongyo	struct bwn_mac *mac;
2898203945Sweongyo
2899203945Sweongyo	BWN_LOCK(sc);
2900203945Sweongyo	mac = sc->sc_curmac;
2901203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2902203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
2903203945Sweongyo		bwn_set_opmode(mac);
2904203945Sweongyo		/* disable CFP update during scan */
2905203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
2906203945Sweongyo	}
2907203945Sweongyo	BWN_UNLOCK(sc);
2908203945Sweongyo}
2909203945Sweongyo
2910203945Sweongyostatic void
2911203945Sweongyobwn_scan_end(struct ieee80211com *ic)
2912203945Sweongyo{
2913203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2914203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2915203945Sweongyo	struct bwn_mac *mac;
2916203945Sweongyo
2917203945Sweongyo	BWN_LOCK(sc);
2918203945Sweongyo	mac = sc->sc_curmac;
2919203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2920203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
2921203945Sweongyo		bwn_set_opmode(mac);
2922203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
2923203945Sweongyo	}
2924203945Sweongyo	BWN_UNLOCK(sc);
2925203945Sweongyo}
2926203945Sweongyo
2927203945Sweongyostatic void
2928203945Sweongyobwn_set_channel(struct ieee80211com *ic)
2929203945Sweongyo{
2930203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2931203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2932203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2933203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2934203945Sweongyo	int chan, error;
2935203945Sweongyo
2936203945Sweongyo	BWN_LOCK(sc);
2937203945Sweongyo
2938203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
2939203945Sweongyo	if (error)
2940203945Sweongyo		goto fail;;
2941203945Sweongyo	bwn_mac_suspend(mac);
2942203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2943203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
2944203945Sweongyo	if (chan != phy->chan)
2945203945Sweongyo		bwn_switch_channel(mac, chan);
2946203945Sweongyo
2947203945Sweongyo	/* TX power level */
2948203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
2949203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
2950203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
2951203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
2952203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
2953203945Sweongyo	}
2954203945Sweongyo
2955203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2956203945Sweongyo	if (phy->set_antenna)
2957203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2958203945Sweongyo
2959203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
2960203945Sweongyo		if (sc->sc_rf_enabled) {
2961203945Sweongyo			bwn_rf_turnon(mac);
2962203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
2963203945Sweongyo				device_printf(sc->sc_dev,
2964203945Sweongyo				    "please turns on the RF switch\n");
2965203945Sweongyo		} else
2966203945Sweongyo			bwn_rf_turnoff(mac);
2967203945Sweongyo	}
2968203945Sweongyo
2969203945Sweongyo	bwn_mac_enable(mac);
2970203945Sweongyo
2971203945Sweongyofail:
2972203945Sweongyo	/*
2973203945Sweongyo	 * Setup radio tap channel freq and flags
2974203945Sweongyo	 */
2975203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
2976203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
2977203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
2978203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
2979203945Sweongyo
2980203945Sweongyo	BWN_UNLOCK(sc);
2981203945Sweongyo}
2982203945Sweongyo
2983203945Sweongyostatic struct ieee80211vap *
2984203945Sweongyobwn_vap_create(struct ieee80211com *ic,
2985203945Sweongyo	const char name[IFNAMSIZ], int unit, int opmode, int flags,
2986203945Sweongyo	const uint8_t bssid[IEEE80211_ADDR_LEN],
2987203945Sweongyo	const uint8_t mac0[IEEE80211_ADDR_LEN])
2988203945Sweongyo{
2989203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2990203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2991203945Sweongyo	struct ieee80211vap *vap;
2992203945Sweongyo	struct bwn_vap *bvp;
2993203945Sweongyo	uint8_t mac[IEEE80211_ADDR_LEN];
2994203945Sweongyo
2995203945Sweongyo	IEEE80211_ADDR_COPY(mac, mac0);
2996203945Sweongyo	switch (opmode) {
2997203945Sweongyo	case IEEE80211_M_HOSTAP:
2998203945Sweongyo	case IEEE80211_M_MBSS:
2999203945Sweongyo	case IEEE80211_M_STA:
3000203945Sweongyo	case IEEE80211_M_WDS:
3001203945Sweongyo	case IEEE80211_M_MONITOR:
3002203945Sweongyo	case IEEE80211_M_IBSS:
3003203945Sweongyo	case IEEE80211_M_AHDEMO:
3004203945Sweongyo		break;
3005203945Sweongyo	default:
3006203945Sweongyo		return (NULL);
3007203945Sweongyo	}
3008203945Sweongyo
3009203945Sweongyo	IEEE80211_ADDR_COPY(sc->sc_macaddr, mac0);
3010203945Sweongyo
3011203945Sweongyo	bvp = (struct bwn_vap *) malloc(sizeof(struct bwn_vap),
3012203945Sweongyo	    M_80211_VAP, M_NOWAIT | M_ZERO);
3013203945Sweongyo	if (bvp == NULL) {
3014203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate a buffer\n");
3015203945Sweongyo		return (NULL);
3016203945Sweongyo	}
3017203945Sweongyo	vap = &bvp->bv_vap;
3018203945Sweongyo	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
3019203945Sweongyo	IEEE80211_ADDR_COPY(vap->iv_myaddr, mac);
3020203945Sweongyo	/* override with driver methods */
3021203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
3022203945Sweongyo	vap->iv_newstate = bwn_newstate;
3023203945Sweongyo
3024203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
3025203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
3026203945Sweongyo
3027203945Sweongyo	ieee80211_amrr_init(&bvp->bv_amrr, vap,
3028203945Sweongyo	    IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
3029203945Sweongyo	    IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
3030203945Sweongyo	    500 /*ms*/);
3031203945Sweongyo
3032203945Sweongyo	/* complete setup */
3033203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
3034203945Sweongyo	    ieee80211_media_status);
3035203945Sweongyo	return (vap);
3036203945Sweongyo}
3037203945Sweongyo
3038203945Sweongyostatic void
3039203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
3040203945Sweongyo{
3041203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
3042203945Sweongyo
3043203945Sweongyo	ieee80211_amrr_cleanup(&bvp->bv_amrr);
3044203945Sweongyo	ieee80211_vap_detach(vap);
3045203945Sweongyo	free(bvp, M_80211_VAP);
3046203945Sweongyo}
3047203945Sweongyo
3048203945Sweongyostatic void
3049203945Sweongyobwn_init(void *arg)
3050203945Sweongyo{
3051203945Sweongyo	struct bwn_softc *sc = arg;
3052203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3053203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
3054203945Sweongyo	int error = 0;
3055203945Sweongyo
3056203945Sweongyo	DPRINTF(sc, BWN_DEBUG_ANY, "%s: if_flags 0x%x\n",
3057203945Sweongyo		__func__, ifp->if_flags);
3058203945Sweongyo
3059203945Sweongyo	BWN_LOCK(sc);
3060203945Sweongyo	error = bwn_init_locked(sc);
3061203945Sweongyo	BWN_UNLOCK(sc);
3062203945Sweongyo
3063203945Sweongyo	if (error == 0)
3064203945Sweongyo		ieee80211_start_all(ic);	/* start all vap's */
3065203945Sweongyo}
3066203945Sweongyo
3067203945Sweongyostatic int
3068203945Sweongyobwn_init_locked(struct bwn_softc *sc)
3069203945Sweongyo{
3070203945Sweongyo	struct bwn_mac *mac;
3071203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3072203945Sweongyo	int error;
3073203945Sweongyo
3074203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3075203945Sweongyo
3076203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
3077203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
3078203945Sweongyo	sc->sc_filters = 0;
3079203945Sweongyo	bwn_wme_clear(sc);
3080203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
3081203945Sweongyo	sc->sc_rf_enabled = 1;
3082203945Sweongyo
3083203945Sweongyo	mac = sc->sc_curmac;
3084203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
3085203945Sweongyo		error = bwn_core_init(mac);
3086203945Sweongyo		if (error != 0)
3087203945Sweongyo			return (error);
3088203945Sweongyo	}
3089203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
3090203945Sweongyo		bwn_core_start(mac);
3091203945Sweongyo
3092203945Sweongyo	bwn_set_opmode(mac);
3093203945Sweongyo	bwn_set_pretbtt(mac);
3094203945Sweongyo	bwn_spu_setdelay(mac, 0);
3095203945Sweongyo	bwn_set_macaddr(mac);
3096203945Sweongyo
3097203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3098203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
3099203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
3100203945Sweongyo
3101203945Sweongyo	return (0);
3102203945Sweongyo}
3103203945Sweongyo
3104203945Sweongyostatic void
3105203945Sweongyobwn_stop(struct bwn_softc *sc, int statechg)
3106203945Sweongyo{
3107203945Sweongyo
3108203945Sweongyo	BWN_LOCK(sc);
3109203945Sweongyo	bwn_stop_locked(sc, statechg);
3110203945Sweongyo	BWN_UNLOCK(sc);
3111203945Sweongyo}
3112203945Sweongyo
3113203945Sweongyostatic void
3114203945Sweongyobwn_stop_locked(struct bwn_softc *sc, int statechg)
3115203945Sweongyo{
3116203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
3117203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3118203945Sweongyo
3119203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3120203945Sweongyo
3121203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
3122203945Sweongyo		/* XXX FIXME opmode not based on VAP */
3123203945Sweongyo		bwn_set_opmode(mac);
3124203945Sweongyo		bwn_set_macaddr(mac);
3125203945Sweongyo	}
3126203945Sweongyo
3127203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
3128203945Sweongyo		bwn_core_stop(mac);
3129203945Sweongyo
3130203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
3131203945Sweongyo	sc->sc_led_blinking = 0;
3132203945Sweongyo
3133203945Sweongyo	bwn_core_exit(mac);
3134203945Sweongyo	sc->sc_rf_enabled = 0;
3135203945Sweongyo
3136203945Sweongyo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3137203945Sweongyo}
3138203945Sweongyo
3139203945Sweongyostatic void
3140203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
3141203945Sweongyo{
3142203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
3143203945Sweongyo	struct wmeParams *p;
3144203945Sweongyo	unsigned int i;
3145203945Sweongyo
3146203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
3147203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3148203945Sweongyo
3149203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
3150203945Sweongyo		p = &(sc->sc_wmeParams[i]);
3151203945Sweongyo
3152203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
3153203945Sweongyo		case BWN_WME_VOICE:
3154203945Sweongyo			p->wmep_txopLimit = 0;
3155203945Sweongyo			p->wmep_aifsn = 2;
3156203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3157203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3158203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3159203945Sweongyo			break;
3160203945Sweongyo		case BWN_WME_VIDEO:
3161203945Sweongyo			p->wmep_txopLimit = 0;
3162203945Sweongyo			p->wmep_aifsn = 2;
3163203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3164203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3165203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3166203945Sweongyo			break;
3167203945Sweongyo		case BWN_WME_BESTEFFORT:
3168203945Sweongyo			p->wmep_txopLimit = 0;
3169203945Sweongyo			p->wmep_aifsn = 3;
3170203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3171203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3172203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3173203945Sweongyo			break;
3174203945Sweongyo		case BWN_WME_BACKGROUND:
3175203945Sweongyo			p->wmep_txopLimit = 0;
3176203945Sweongyo			p->wmep_aifsn = 7;
3177203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3178203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3179203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3180203945Sweongyo			break;
3181203945Sweongyo		default:
3182203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3183203945Sweongyo		}
3184203945Sweongyo	}
3185203945Sweongyo}
3186203945Sweongyo
3187203945Sweongyostatic int
3188203945Sweongyobwn_core_init(struct bwn_mac *mac)
3189203945Sweongyo{
3190203945Sweongyo#ifdef BWN_DEBUG
3191203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3192203945Sweongyo#endif
3193203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
3194203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
3195203945Sweongyo	struct siba_sprom *sprom = &siba->siba_sprom;
3196203945Sweongyo	uint64_t hf;
3197203945Sweongyo	int error;
3198203945Sweongyo
3199203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3200203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3201203945Sweongyo
3202203945Sweongyo	siba_powerup(siba, 0);
3203203945Sweongyo	if (!siba_dev_isup(sd))
3204203945Sweongyo		bwn_reset_core(mac,
3205203945Sweongyo		    mac->mac_phy.gmode ? BWN_TGSLOW_SUPPORT_G : 0);
3206203945Sweongyo
3207203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
3208203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
3209203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
3210203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
3211203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
3212203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
3213203945Sweongyo	mac->mac_stats.link_noise = -95;
3214203945Sweongyo	mac->mac_reason_intr = 0;
3215203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
3216203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
3217203945Sweongyo#ifdef BWN_DEBUG
3218203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
3219203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
3220203945Sweongyo#endif
3221203945Sweongyo	mac->mac_suspended = 1;
3222203945Sweongyo	mac->mac_task_state = 0;
3223203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
3224203945Sweongyo
3225203945Sweongyo	mac->mac_phy.init_pre(mac);
3226203945Sweongyo
3227203945Sweongyo	siba_pcicore_intr(&siba->siba_pci, sd);
3228203945Sweongyo
3229203945Sweongyo	bwn_fix_imcfglobug(mac);
3230203945Sweongyo	bwn_bt_disable(mac);
3231203945Sweongyo	if (mac->mac_phy.prepare_hw) {
3232203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
3233203945Sweongyo		if (error)
3234203945Sweongyo			goto fail0;
3235203945Sweongyo	}
3236203945Sweongyo	error = bwn_chip_init(mac);
3237203945Sweongyo	if (error)
3238203945Sweongyo		goto fail0;
3239203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
3240203945Sweongyo	    mac->mac_sd->sd_id.sd_rev);
3241203945Sweongyo	hf = bwn_hf_read(mac);
3242203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
3243203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
3244203945Sweongyo		if (sprom->bf_lo & BWN_BFL_PACTRL)
3245203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
3246203945Sweongyo		if (mac->mac_phy.rev == 1)
3247203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
3248203945Sweongyo	}
3249203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
3250203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
3251203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
3252203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
3253203945Sweongyo			hf |= BWN_HF_4318_TSSI;
3254203945Sweongyo	}
3255203945Sweongyo	if (sprom->bf_lo & BWN_BFL_CRYSTAL_NOSLOW)
3256203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
3257203945Sweongyo	if ((siba->siba_type == SIBA_TYPE_PCI) &&
3258203945Sweongyo	    (siba->siba_pci.spc_dev->sd_id.sd_rev <= 10))
3259203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
3260203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
3261203945Sweongyo	bwn_hf_write(mac, hf);
3262203945Sweongyo
3263203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
3264203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
3265203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
3266203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
3267203945Sweongyo
3268203945Sweongyo	bwn_rate_init(mac);
3269203945Sweongyo	bwn_set_phytxctl(mac);
3270203945Sweongyo
3271203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
3272203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
3273203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
3274203945Sweongyo
3275203945Sweongyo	if (siba->siba_type == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
3276203945Sweongyo		bwn_pio_init(mac);
3277203945Sweongyo	else
3278203945Sweongyo		bwn_dma_init(mac);
3279203945Sweongyo	if (error)
3280203945Sweongyo		goto fail1;
3281203945Sweongyo	bwn_wme_init(mac);
3282203945Sweongyo	bwn_spu_setdelay(mac, 1);
3283203945Sweongyo	bwn_bt_enable(mac);
3284203945Sweongyo
3285203945Sweongyo	siba_powerup(siba, !(sprom->bf_lo & BWN_BFL_CRYSTAL_NOSLOW));
3286203945Sweongyo	bwn_set_macaddr(mac);
3287203945Sweongyo	bwn_crypt_init(mac);
3288203945Sweongyo
3289203945Sweongyo	/* XXX LED initializatin */
3290203945Sweongyo
3291203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
3292203945Sweongyo
3293203945Sweongyo	return (error);
3294203945Sweongyo
3295203945Sweongyofail1:
3296203945Sweongyo	bwn_chip_exit(mac);
3297203945Sweongyofail0:
3298203945Sweongyo	siba_powerdown(siba);
3299203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3300203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3301203945Sweongyo	return (error);
3302203945Sweongyo}
3303203945Sweongyo
3304203945Sweongyostatic void
3305203945Sweongyobwn_core_start(struct bwn_mac *mac)
3306203945Sweongyo{
3307203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3308203945Sweongyo	uint32_t tmp;
3309203945Sweongyo
3310203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
3311203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3312203945Sweongyo
3313203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev < 5)
3314203945Sweongyo		return;
3315203945Sweongyo
3316203945Sweongyo	while (1) {
3317203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
3318203945Sweongyo		if (!(tmp & 0x00000001))
3319203945Sweongyo			break;
3320203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
3321203945Sweongyo	}
3322203945Sweongyo
3323203945Sweongyo	bwn_mac_enable(mac);
3324203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
3325203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
3326203945Sweongyo
3327203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
3328203945Sweongyo}
3329203945Sweongyo
3330203945Sweongyostatic void
3331203945Sweongyobwn_core_exit(struct bwn_mac *mac)
3332203945Sweongyo{
3333203945Sweongyo	uint32_t macctl;
3334203945Sweongyo
3335204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
3336203945Sweongyo
3337203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
3338203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3339203945Sweongyo
3340203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
3341203945Sweongyo		return;
3342203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
3343203945Sweongyo
3344203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3345203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
3346203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
3347203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3348203945Sweongyo
3349203945Sweongyo	bwn_dma_stop(mac);
3350203945Sweongyo	bwn_pio_stop(mac);
3351203945Sweongyo	bwn_chip_exit(mac);
3352203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
3353203945Sweongyo	siba_dev_down(mac->mac_sd, 0);
3354203945Sweongyo	siba_powerdown(mac->mac_sd->sd_bus);
3355203945Sweongyo}
3356203945Sweongyo
3357203945Sweongyostatic void
3358203945Sweongyobwn_fix_imcfglobug(struct bwn_mac *mac)
3359203945Sweongyo{
3360203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
3361203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
3362203945Sweongyo	uint32_t tmp;
3363203945Sweongyo
3364203945Sweongyo	if (siba->siba_pci.spc_dev == NULL)
3365203945Sweongyo		return;
3366203945Sweongyo	if (siba->siba_pci.spc_dev->sd_id.sd_device != SIBA_DEVID_PCI ||
3367203945Sweongyo	    siba->siba_pci.spc_dev->sd_id.sd_rev > 5)
3368203945Sweongyo		return;
3369203945Sweongyo
3370203945Sweongyo	tmp = siba_read_4(sd, SIBA_IMCFGLO) &
3371203945Sweongyo	    ~(SIBA_IMCFGLO_REQTO | SIBA_IMCFGLO_SERTO);
3372203945Sweongyo	switch (siba->siba_type) {
3373203945Sweongyo	case SIBA_TYPE_PCI:
3374203945Sweongyo	case SIBA_TYPE_PCMCIA:
3375203945Sweongyo		tmp |= 0x32;
3376203945Sweongyo		break;
3377203945Sweongyo	case SIBA_TYPE_SSB:
3378203945Sweongyo		tmp |= 0x53;
3379203945Sweongyo		break;
3380203945Sweongyo	}
3381203945Sweongyo	siba_write_4(sd, SIBA_IMCFGLO, tmp);
3382203945Sweongyo}
3383203945Sweongyo
3384203945Sweongyostatic void
3385203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
3386203945Sweongyo{
3387203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3388203945Sweongyo
3389203945Sweongyo	(void)sc;
3390203945Sweongyo	/* XXX do nothing yet */
3391203945Sweongyo}
3392203945Sweongyo
3393203945Sweongyostatic int
3394203945Sweongyobwn_chip_init(struct bwn_mac *mac)
3395203945Sweongyo{
3396203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
3397203945Sweongyo	uint32_t macctl;
3398203945Sweongyo	int error;
3399203945Sweongyo
3400203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
3401203945Sweongyo	if (phy->gmode)
3402203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
3403203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3404203945Sweongyo
3405203945Sweongyo	error = bwn_fw_fillinfo(mac);
3406203945Sweongyo	if (error)
3407203945Sweongyo		return (error);
3408203945Sweongyo	error = bwn_fw_loaducode(mac);
3409203945Sweongyo	if (error)
3410203945Sweongyo		return (error);
3411203945Sweongyo
3412203945Sweongyo	error = bwn_gpio_init(mac);
3413203945Sweongyo	if (error)
3414203945Sweongyo		return (error);
3415203945Sweongyo
3416203945Sweongyo	error = bwn_fw_loadinitvals(mac);
3417203945Sweongyo	if (error) {
3418203945Sweongyo		bwn_gpio_cleanup(mac);
3419203945Sweongyo		return (error);
3420203945Sweongyo	}
3421203945Sweongyo	phy->switch_analog(mac, 1);
3422203945Sweongyo	error = bwn_phy_init(mac);
3423203945Sweongyo	if (error) {
3424203945Sweongyo		bwn_gpio_cleanup(mac);
3425203945Sweongyo		return (error);
3426203945Sweongyo	}
3427203945Sweongyo	if (phy->set_im)
3428203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
3429203945Sweongyo	if (phy->set_antenna)
3430203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
3431203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
3432203945Sweongyo
3433203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
3434203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
3435203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
3436203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev < 5)
3437203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
3438203945Sweongyo
3439203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3440203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
3441203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3442203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
3443203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
3444203945Sweongyo
3445203945Sweongyo	bwn_set_opmode(mac);
3446203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev < 3) {
3447203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
3448203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
3449203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
3450203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
3451203945Sweongyo	} else {
3452203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
3453203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
3454203945Sweongyo	}
3455203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
3456203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
3457203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
3458203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
3459203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
3460203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
3461203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
3462203945Sweongyo	siba_write_4(mac->mac_sd, SIBA_TGSLOW,
3463203945Sweongyo	    siba_read_4(mac->mac_sd, SIBA_TGSLOW) | 0x00100000);
3464203945Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY,
3465203945Sweongyo	    mac->mac_sd->sd_bus->siba_cc.scc_powerup_delay);
3466203945Sweongyo	return (error);
3467203945Sweongyo}
3468203945Sweongyo
3469203945Sweongyo/* read hostflags */
3470203945Sweongyostatic uint64_t
3471203945Sweongyobwn_hf_read(struct bwn_mac *mac)
3472203945Sweongyo{
3473203945Sweongyo	uint64_t ret;
3474203945Sweongyo
3475203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
3476203945Sweongyo	ret <<= 16;
3477203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
3478203945Sweongyo	ret <<= 16;
3479203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
3480203945Sweongyo	return (ret);
3481203945Sweongyo}
3482203945Sweongyo
3483203945Sweongyostatic void
3484203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
3485203945Sweongyo{
3486203945Sweongyo
3487203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
3488203945Sweongyo	    (value & 0x00000000ffffull));
3489203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
3490203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
3491203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
3492203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
3493203945Sweongyo}
3494203945Sweongyo
3495203945Sweongyostatic void
3496203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
3497203945Sweongyo{
3498203945Sweongyo
3499203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
3500203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
3501203945Sweongyo}
3502203945Sweongyo
3503203945Sweongyostatic void
3504203945Sweongyobwn_rate_init(struct bwn_mac *mac)
3505203945Sweongyo{
3506203945Sweongyo
3507203945Sweongyo	switch (mac->mac_phy.type) {
3508203945Sweongyo	case BWN_PHYTYPE_A:
3509203945Sweongyo	case BWN_PHYTYPE_G:
3510203945Sweongyo	case BWN_PHYTYPE_LP:
3511203945Sweongyo	case BWN_PHYTYPE_N:
3512203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
3513203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
3514203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
3515203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
3516203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
3517203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
3518203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
3519203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
3520203945Sweongyo			break;
3521203945Sweongyo		/* FALLTHROUGH */
3522203945Sweongyo	case BWN_PHYTYPE_B:
3523203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
3524203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
3525203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
3526203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
3527203945Sweongyo		break;
3528203945Sweongyo	default:
3529203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3530203945Sweongyo	}
3531203945Sweongyo}
3532203945Sweongyo
3533203945Sweongyostatic void
3534203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
3535203945Sweongyo{
3536203945Sweongyo	uint16_t offset;
3537203945Sweongyo
3538203945Sweongyo	if (ofdm) {
3539203945Sweongyo		offset = 0x480;
3540203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
3541203945Sweongyo	} else {
3542203945Sweongyo		offset = 0x4c0;
3543203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
3544203945Sweongyo	}
3545203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
3546203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
3547203945Sweongyo}
3548203945Sweongyo
3549203945Sweongyostatic uint8_t
3550203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
3551203945Sweongyo{
3552203945Sweongyo
3553203945Sweongyo	switch (bitrate) {
3554203945Sweongyo	case BWN_CCK_RATE_1MB:
3555203945Sweongyo		return (0x0a);
3556203945Sweongyo	case BWN_CCK_RATE_2MB:
3557203945Sweongyo		return (0x14);
3558203945Sweongyo	case BWN_CCK_RATE_5MB:
3559203945Sweongyo		return (0x37);
3560203945Sweongyo	case BWN_CCK_RATE_11MB:
3561203945Sweongyo		return (0x6e);
3562203945Sweongyo	}
3563203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3564203945Sweongyo	return (0);
3565203945Sweongyo}
3566203945Sweongyo
3567203945Sweongyostatic uint8_t
3568203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
3569203945Sweongyo{
3570203945Sweongyo
3571203945Sweongyo	switch (bitrate) {
3572203945Sweongyo	case BWN_OFDM_RATE_6MB:
3573203945Sweongyo		return (0xb);
3574203945Sweongyo	case BWN_OFDM_RATE_9MB:
3575203945Sweongyo		return (0xf);
3576203945Sweongyo	case BWN_OFDM_RATE_12MB:
3577203945Sweongyo		return (0xa);
3578203945Sweongyo	case BWN_OFDM_RATE_18MB:
3579203945Sweongyo		return (0xe);
3580203945Sweongyo	case BWN_OFDM_RATE_24MB:
3581203945Sweongyo		return (0x9);
3582203945Sweongyo	case BWN_OFDM_RATE_36MB:
3583203945Sweongyo		return (0xd);
3584203945Sweongyo	case BWN_OFDM_RATE_48MB:
3585203945Sweongyo		return (0x8);
3586203945Sweongyo	case BWN_OFDM_RATE_54MB:
3587203945Sweongyo		return (0xc);
3588203945Sweongyo	}
3589203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3590203945Sweongyo	return (0);
3591203945Sweongyo}
3592203945Sweongyo
3593203945Sweongyostatic void
3594203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
3595203945Sweongyo{
3596203945Sweongyo	uint16_t ctl;
3597203945Sweongyo
3598203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
3599203945Sweongyo	    BWN_TX_PHY_TXPWR);
3600203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
3601203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
3602203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
3603203945Sweongyo}
3604203945Sweongyo
3605203945Sweongyostatic void
3606203945Sweongyobwn_pio_init(struct bwn_mac *mac)
3607203945Sweongyo{
3608203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
3609203945Sweongyo
3610203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
3611203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
3612203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
3613203945Sweongyo
3614203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
3615203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
3616203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
3617203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
3618203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
3619203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
3620203945Sweongyo}
3621203945Sweongyo
3622203945Sweongyostatic void
3623203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3624203945Sweongyo    int index)
3625203945Sweongyo{
3626203945Sweongyo	struct bwn_pio_txpkt *tp;
3627203945Sweongyo	unsigned int i;
3628203945Sweongyo
3629203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
3630203945Sweongyo	tq->tq_index = index;
3631203945Sweongyo
3632203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
3633203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 8)
3634203945Sweongyo		tq->tq_size = 1920;
3635203945Sweongyo	else {
3636203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
3637203945Sweongyo		tq->tq_size -= 80;
3638203945Sweongyo	}
3639203945Sweongyo
3640203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
3641203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3642203945Sweongyo		tp = &(tq->tq_pkts[i]);
3643203945Sweongyo		tp->tp_index = i;
3644203945Sweongyo		tp->tp_queue = tq;
3645203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
3646203945Sweongyo	}
3647203945Sweongyo}
3648203945Sweongyo
3649203945Sweongyostatic uint16_t
3650203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
3651203945Sweongyo{
3652203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3653203945Sweongyo	static const uint16_t bases[] = {
3654203945Sweongyo		BWN_PIO_BASE0,
3655203945Sweongyo		BWN_PIO_BASE1,
3656203945Sweongyo		BWN_PIO_BASE2,
3657203945Sweongyo		BWN_PIO_BASE3,
3658203945Sweongyo		BWN_PIO_BASE4,
3659203945Sweongyo		BWN_PIO_BASE5,
3660203945Sweongyo		BWN_PIO_BASE6,
3661203945Sweongyo		BWN_PIO_BASE7,
3662203945Sweongyo	};
3663203945Sweongyo	static const uint16_t bases_rev11[] = {
3664203945Sweongyo		BWN_PIO11_BASE0,
3665203945Sweongyo		BWN_PIO11_BASE1,
3666203945Sweongyo		BWN_PIO11_BASE2,
3667203945Sweongyo		BWN_PIO11_BASE3,
3668203945Sweongyo		BWN_PIO11_BASE4,
3669203945Sweongyo		BWN_PIO11_BASE5,
3670203945Sweongyo	};
3671203945Sweongyo
3672203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 11) {
3673203945Sweongyo		if (index >= N(bases_rev11))
3674203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
3675203945Sweongyo		return (bases_rev11[index]);
3676203945Sweongyo	}
3677203945Sweongyo	if (index >= N(bases))
3678203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
3679203945Sweongyo	return (bases[index]);
3680203945Sweongyo}
3681203945Sweongyo
3682203945Sweongyostatic void
3683203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
3684203945Sweongyo    int index)
3685203945Sweongyo{
3686203945Sweongyo
3687203945Sweongyo	prq->prq_mac = mac;
3688203945Sweongyo	prq->prq_rev = mac->mac_sd->sd_id.sd_rev;
3689203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
3690203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
3691203945Sweongyo}
3692203945Sweongyo
3693203945Sweongyostatic void
3694203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
3695203945Sweongyo{
3696203945Sweongyo	if (tq == NULL)
3697203945Sweongyo		return;
3698203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
3699203945Sweongyo}
3700203945Sweongyo
3701203945Sweongyostatic void
3702203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
3703203945Sweongyo{
3704203945Sweongyo
3705203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
3706203945Sweongyo}
3707203945Sweongyo
3708203945Sweongyostatic uint16_t
3709203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3710203945Sweongyo    uint16_t offset)
3711203945Sweongyo{
3712203945Sweongyo
3713203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
3714203945Sweongyo}
3715203945Sweongyo
3716203945Sweongyostatic void
3717203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
3718203945Sweongyo{
3719203945Sweongyo	uint32_t ctl;
3720203945Sweongyo	int type;
3721203945Sweongyo	uint16_t base;
3722203945Sweongyo
3723203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
3724203945Sweongyo	base = bwn_dma_base(type, idx);
3725203945Sweongyo	if (type == BWN_DMA_64BIT) {
3726203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
3727203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
3728203945Sweongyo		if (enable)
3729203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
3730203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
3731203945Sweongyo	} else {
3732203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
3733203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
3734203945Sweongyo		if (enable)
3735203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
3736203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
3737203945Sweongyo	}
3738203945Sweongyo}
3739203945Sweongyo
3740203945Sweongyostatic uint64_t
3741203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
3742203945Sweongyo{
3743203945Sweongyo	uint32_t tmp;
3744203945Sweongyo	uint16_t base;
3745203945Sweongyo
3746203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3747203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3748203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
3749203945Sweongyo	base = bwn_dma_base(0, 0);
3750203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3751203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3752203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3753203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
3754203945Sweongyo
3755203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
3756203945Sweongyo}
3757203945Sweongyo
3758203945Sweongyostatic int
3759203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
3760203945Sweongyo{
3761203945Sweongyo
3762203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
3763203945Sweongyo		return (BWN_DMA_30BIT);
3764203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
3765203945Sweongyo		return (BWN_DMA_32BIT);
3766203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
3767203945Sweongyo		return (BWN_DMA_64BIT);
3768203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3769203945Sweongyo	return (BWN_DMA_30BIT);
3770203945Sweongyo}
3771203945Sweongyo
3772203945Sweongyostatic void
3773203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
3774203945Sweongyo{
3775203945Sweongyo	struct bwn_pio_txpkt *tp;
3776203945Sweongyo	unsigned int i;
3777203945Sweongyo
3778203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3779203945Sweongyo		tp = &(tq->tq_pkts[i]);
3780203945Sweongyo		if (tp->tp_m) {
3781203945Sweongyo			m_freem(tp->tp_m);
3782203945Sweongyo			tp->tp_m = NULL;
3783203945Sweongyo		}
3784203945Sweongyo	}
3785203945Sweongyo}
3786203945Sweongyo
3787203945Sweongyostatic uint16_t
3788203945Sweongyobwn_dma_base(int type, int controller_idx)
3789203945Sweongyo{
3790203945Sweongyo	static const uint16_t map64[] = {
3791203945Sweongyo		BWN_DMA64_BASE0,
3792203945Sweongyo		BWN_DMA64_BASE1,
3793203945Sweongyo		BWN_DMA64_BASE2,
3794203945Sweongyo		BWN_DMA64_BASE3,
3795203945Sweongyo		BWN_DMA64_BASE4,
3796203945Sweongyo		BWN_DMA64_BASE5,
3797203945Sweongyo	};
3798203945Sweongyo	static const uint16_t map32[] = {
3799203945Sweongyo		BWN_DMA32_BASE0,
3800203945Sweongyo		BWN_DMA32_BASE1,
3801203945Sweongyo		BWN_DMA32_BASE2,
3802203945Sweongyo		BWN_DMA32_BASE3,
3803203945Sweongyo		BWN_DMA32_BASE4,
3804203945Sweongyo		BWN_DMA32_BASE5,
3805203945Sweongyo	};
3806203945Sweongyo
3807203945Sweongyo	if (type == BWN_DMA_64BIT) {
3808203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
3809203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3810203945Sweongyo		return (map64[controller_idx]);
3811203945Sweongyo	}
3812203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
3813203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3814203945Sweongyo	return (map32[controller_idx]);
3815203945Sweongyo}
3816203945Sweongyo
3817203945Sweongyostatic void
3818203945Sweongyobwn_dma_init(struct bwn_mac *mac)
3819203945Sweongyo{
3820203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3821203945Sweongyo
3822203945Sweongyo	/* setup TX DMA channels. */
3823203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
3824203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
3825203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
3826203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
3827203945Sweongyo	bwn_dma_setup(dma->mcast);
3828203945Sweongyo	/* setup RX DMA channel. */
3829203945Sweongyo	bwn_dma_setup(dma->rx);
3830203945Sweongyo}
3831203945Sweongyo
3832203945Sweongyostatic struct bwn_dma_ring *
3833203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
3834203945Sweongyo    int for_tx, int type)
3835203945Sweongyo{
3836203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3837203945Sweongyo	struct bwn_dma_ring *dr;
3838203945Sweongyo	struct bwn_dmadesc_generic *desc;
3839203945Sweongyo	struct bwn_dmadesc_meta *mt;
3840203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3841203945Sweongyo	int error, i;
3842203945Sweongyo
3843203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
3844203945Sweongyo	if (dr == NULL)
3845203945Sweongyo		goto out;
3846203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
3847203945Sweongyo	if (for_tx)
3848203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
3849203945Sweongyo
3850203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
3851203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
3852203945Sweongyo	if (dr->dr_meta == NULL)
3853203945Sweongyo		goto fail0;
3854203945Sweongyo
3855203945Sweongyo	dr->dr_type = type;
3856203945Sweongyo	dr->dr_mac = mac;
3857203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
3858203945Sweongyo	dr->dr_index = controller_index;
3859203945Sweongyo	if (type == BWN_DMA_64BIT) {
3860203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
3861203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
3862203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
3863203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
3864203945Sweongyo		dr->resume = bwn_dma_64_resume;
3865203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
3866203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
3867203945Sweongyo	} else {
3868203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
3869203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
3870203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
3871203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
3872203945Sweongyo		dr->resume = bwn_dma_32_resume;
3873203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
3874203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
3875203945Sweongyo	}
3876203945Sweongyo	if (for_tx) {
3877203945Sweongyo		dr->dr_tx = 1;
3878203945Sweongyo		dr->dr_curslot = -1;
3879203945Sweongyo	} else {
3880203945Sweongyo		if (dr->dr_index == 0) {
3881203945Sweongyo			dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
3882203945Sweongyo			dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
3883203945Sweongyo		} else
3884203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3885203945Sweongyo	}
3886203945Sweongyo
3887203945Sweongyo	error = bwn_dma_allocringmemory(dr);
3888203945Sweongyo	if (error)
3889203945Sweongyo		goto fail2;
3890203945Sweongyo
3891203945Sweongyo	if (for_tx) {
3892203945Sweongyo		/*
3893203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
3894203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
3895203945Sweongyo		 */
3896203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
3897203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3898203945Sweongyo
3899203945Sweongyo		dr->dr_txhdr_cache =
3900203945Sweongyo		    malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
3901203945Sweongyo			BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
3902203945Sweongyo		KASSERT(dr->dr_txhdr_cache != NULL,
3903203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3904203945Sweongyo
3905203945Sweongyo		/*
3906203945Sweongyo		 * Create TX ring DMA stuffs
3907203945Sweongyo		 */
3908203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
3909203945Sweongyo				    BWN_ALIGN, 0,
3910203945Sweongyo				    BUS_SPACE_MAXADDR,
3911203945Sweongyo				    BUS_SPACE_MAXADDR,
3912203945Sweongyo				    NULL, NULL,
3913203945Sweongyo				    BWN_HDRSIZE(mac),
3914203945Sweongyo				    1,
3915203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
3916203945Sweongyo				    0,
3917203945Sweongyo				    NULL, NULL,
3918203945Sweongyo				    &dr->dr_txring_dtag);
3919203945Sweongyo		if (error) {
3920203945Sweongyo			device_printf(sc->sc_dev,
3921203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
3922203945Sweongyo			goto fail1;
3923203945Sweongyo		}
3924203945Sweongyo
3925203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
3926203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3927203945Sweongyo
3928203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
3929203945Sweongyo			mt->mt_m = NULL;
3930203945Sweongyo			mt->mt_ni = NULL;
3931203945Sweongyo			mt->mt_islast = 0;
3932203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
3933203945Sweongyo			    &mt->mt_dmap);
3934203945Sweongyo			if (error) {
3935203945Sweongyo				device_printf(sc->sc_dev,
3936203945Sweongyo				     "can't create RX buf DMA map\n");
3937203945Sweongyo				goto fail1;
3938203945Sweongyo			}
3939203945Sweongyo
3940203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
3941203945Sweongyo
3942203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
3943203945Sweongyo			mt->mt_m = NULL;
3944203945Sweongyo			mt->mt_ni = NULL;
3945203945Sweongyo			mt->mt_islast = 1;
3946203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
3947203945Sweongyo			    &mt->mt_dmap);
3948203945Sweongyo			if (error) {
3949203945Sweongyo				device_printf(sc->sc_dev,
3950203945Sweongyo				     "can't create RX buf DMA map\n");
3951203945Sweongyo				goto fail1;
3952203945Sweongyo			}
3953203945Sweongyo		}
3954203945Sweongyo	} else {
3955203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3956203945Sweongyo		    &dr->dr_spare_dmap);
3957203945Sweongyo		if (error) {
3958203945Sweongyo			device_printf(sc->sc_dev,
3959203945Sweongyo			    "can't create RX buf DMA map\n");
3960203945Sweongyo			goto out;		/* XXX wrong! */
3961203945Sweongyo		}
3962203945Sweongyo
3963203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
3964203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3965203945Sweongyo
3966203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3967203945Sweongyo			    &mt->mt_dmap);
3968203945Sweongyo			if (error) {
3969203945Sweongyo				device_printf(sc->sc_dev,
3970203945Sweongyo				    "can't create RX buf DMA map\n");
3971203945Sweongyo				goto out;	/* XXX wrong! */
3972203945Sweongyo			}
3973203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
3974203945Sweongyo			if (error) {
3975203945Sweongyo				device_printf(sc->sc_dev,
3976203945Sweongyo				    "failed to allocate RX buf\n");
3977203945Sweongyo				goto out;	/* XXX wrong! */
3978203945Sweongyo			}
3979203945Sweongyo		}
3980203945Sweongyo
3981203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
3982203945Sweongyo		    BUS_DMASYNC_PREWRITE);
3983203945Sweongyo
3984203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
3985203945Sweongyo	}
3986203945Sweongyo
3987203945Sweongyo      out:
3988203945Sweongyo	return (dr);
3989203945Sweongyo
3990203945Sweongyofail2:
3991203945Sweongyo	free(dr->dr_txhdr_cache, M_DEVBUF);
3992203945Sweongyofail1:
3993203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
3994203945Sweongyofail0:
3995203945Sweongyo	free(dr, M_DEVBUF);
3996203945Sweongyo	return (NULL);
3997203945Sweongyo}
3998203945Sweongyo
3999203945Sweongyostatic void
4000203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
4001203945Sweongyo{
4002203945Sweongyo
4003203945Sweongyo	if (dr == NULL)
4004203945Sweongyo		return;
4005203945Sweongyo
4006203945Sweongyo	bwn_dma_free_descbufs(*dr);
4007203945Sweongyo	bwn_dma_free_ringmemory(*dr);
4008203945Sweongyo
4009203945Sweongyo	free((*dr)->dr_txhdr_cache, M_DEVBUF);
4010203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
4011203945Sweongyo	free(*dr, M_DEVBUF);
4012203945Sweongyo
4013203945Sweongyo	*dr = NULL;
4014203945Sweongyo}
4015203945Sweongyo
4016203945Sweongyostatic void
4017203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
4018203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
4019203945Sweongyo{
4020203945Sweongyo	struct bwn_dmadesc32 *desc;
4021203945Sweongyo
4022203945Sweongyo	*meta = &(dr->dr_meta[slot]);
4023203945Sweongyo	desc = dr->dr_ring_descbase;
4024203945Sweongyo	desc = &(desc[slot]);
4025203945Sweongyo
4026203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
4027203945Sweongyo}
4028203945Sweongyo
4029203945Sweongyostatic void
4030203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
4031203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
4032203945Sweongyo    int start, int end, int irq)
4033203945Sweongyo{
4034203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
4035203945Sweongyo	uint32_t addr, addrext, ctl;
4036203945Sweongyo	int slot;
4037203945Sweongyo
4038203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
4039203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
4040203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4041203945Sweongyo
4042203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
4043203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
4044203945Sweongyo	addr |= siba_dma_translation(dr->dr_mac->mac_sd);
4045203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
4046203945Sweongyo	if (slot == dr->dr_numslots - 1)
4047203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
4048203945Sweongyo	if (start)
4049203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
4050203945Sweongyo	if (end)
4051203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
4052203945Sweongyo	if (irq)
4053203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
4054203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
4055203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
4056203945Sweongyo
4057203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
4058203945Sweongyo	desc->dma.dma32.address = htole32(addr);
4059203945Sweongyo}
4060203945Sweongyo
4061203945Sweongyostatic void
4062203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
4063203945Sweongyo{
4064203945Sweongyo
4065203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
4066203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
4067203945Sweongyo}
4068203945Sweongyo
4069203945Sweongyostatic void
4070203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
4071203945Sweongyo{
4072203945Sweongyo
4073203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
4074203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
4075203945Sweongyo}
4076203945Sweongyo
4077203945Sweongyostatic void
4078203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
4079203945Sweongyo{
4080203945Sweongyo
4081203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
4082203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
4083203945Sweongyo}
4084203945Sweongyo
4085203945Sweongyostatic int
4086203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
4087203945Sweongyo{
4088203945Sweongyo	uint32_t val;
4089203945Sweongyo
4090203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
4091203945Sweongyo	val &= BWN_DMA32_RXDPTR;
4092203945Sweongyo
4093203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
4094203945Sweongyo}
4095203945Sweongyo
4096203945Sweongyostatic void
4097203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
4098203945Sweongyo{
4099203945Sweongyo
4100203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
4101203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
4102203945Sweongyo}
4103203945Sweongyo
4104203945Sweongyostatic void
4105203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
4106203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
4107203945Sweongyo{
4108203945Sweongyo	struct bwn_dmadesc64 *desc;
4109203945Sweongyo
4110203945Sweongyo	*meta = &(dr->dr_meta[slot]);
4111203945Sweongyo	desc = dr->dr_ring_descbase;
4112203945Sweongyo	desc = &(desc[slot]);
4113203945Sweongyo
4114203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
4115203945Sweongyo}
4116203945Sweongyo
4117203945Sweongyostatic void
4118203945Sweongyobwn_dma_64_setdesc(struct bwn_dma_ring *dr,
4119203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
4120203945Sweongyo    int start, int end, int irq)
4121203945Sweongyo{
4122203945Sweongyo	struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
4123203945Sweongyo	int slot;
4124203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
4125203945Sweongyo	uint32_t addrlo, addrhi;
4126203945Sweongyo	uint32_t addrext;
4127203945Sweongyo
4128203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
4129203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
4130203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4131203945Sweongyo
4132203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
4133203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
4134203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
4135203945Sweongyo	    30;
4136203945Sweongyo	addrhi |= (siba_dma_translation(dr->dr_mac->mac_sd) << 1);
4137203945Sweongyo	if (slot == dr->dr_numslots - 1)
4138203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
4139203945Sweongyo	if (start)
4140203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
4141203945Sweongyo	if (end)
4142203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
4143203945Sweongyo	if (irq)
4144203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
4145203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
4146203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
4147203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
4148203945Sweongyo
4149203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
4150203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
4151203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
4152203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
4153203945Sweongyo}
4154203945Sweongyo
4155203945Sweongyostatic void
4156203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
4157203945Sweongyo{
4158203945Sweongyo
4159203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
4160203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4161203945Sweongyo}
4162203945Sweongyo
4163203945Sweongyostatic void
4164203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
4165203945Sweongyo{
4166203945Sweongyo
4167203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4168203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
4169203945Sweongyo}
4170203945Sweongyo
4171203945Sweongyostatic void
4172203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
4173203945Sweongyo{
4174203945Sweongyo
4175203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4176203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
4177203945Sweongyo}
4178203945Sweongyo
4179203945Sweongyostatic int
4180203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
4181203945Sweongyo{
4182203945Sweongyo	uint32_t val;
4183203945Sweongyo
4184203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
4185203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
4186203945Sweongyo
4187203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
4188203945Sweongyo}
4189203945Sweongyo
4190203945Sweongyostatic void
4191203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
4192203945Sweongyo{
4193203945Sweongyo
4194203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
4195203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4196203945Sweongyo}
4197203945Sweongyo
4198203945Sweongyostatic int
4199203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
4200203945Sweongyo{
4201203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4202203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4203203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4204203945Sweongyo	int error;
4205203945Sweongyo
4206203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
4207203945Sweongyo			    BWN_ALIGN, 0,
4208203945Sweongyo			    BUS_SPACE_MAXADDR,
4209203945Sweongyo			    BUS_SPACE_MAXADDR,
4210203945Sweongyo			    NULL, NULL,
4211203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
4212203945Sweongyo			    1,
4213203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
4214203945Sweongyo			    0,
4215203945Sweongyo			    NULL, NULL,
4216203945Sweongyo			    &dr->dr_ring_dtag);
4217203945Sweongyo	if (error) {
4218203945Sweongyo		device_printf(sc->sc_dev,
4219203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
4220203945Sweongyo		return (-1);
4221203945Sweongyo	}
4222203945Sweongyo
4223203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
4224203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
4225203945Sweongyo	    &dr->dr_ring_dmap);
4226203945Sweongyo	if (error) {
4227203945Sweongyo		device_printf(sc->sc_dev,
4228203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
4229203945Sweongyo		return (-1);
4230203945Sweongyo	}
4231203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
4232203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
4233203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
4234203945Sweongyo	if (error) {
4235203945Sweongyo		device_printf(sc->sc_dev,
4236203945Sweongyo		    "can't load DMA mem: TODO free\n");
4237203945Sweongyo		return (-1);
4238203945Sweongyo	}
4239203945Sweongyo
4240203945Sweongyo	return (0);
4241203945Sweongyo}
4242203945Sweongyo
4243203945Sweongyostatic void
4244203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
4245203945Sweongyo{
4246203945Sweongyo	uint64_t ring64;
4247203945Sweongyo	uint32_t addrext, ring32, value;
4248203945Sweongyo	uint32_t trans = siba_dma_translation(dr->dr_mac->mac_sd);
4249203945Sweongyo
4250203945Sweongyo	if (dr->dr_tx) {
4251203945Sweongyo		dr->dr_curslot = -1;
4252203945Sweongyo
4253203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4254203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
4255203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
4256203945Sweongyo			    >> 30;
4257203945Sweongyo			value = BWN_DMA64_TXENABLE;
4258203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
4259203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
4260203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
4261203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
4262203945Sweongyo			    (ring64 & 0xffffffff));
4263203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
4264203945Sweongyo			    ((ring64 >> 32) &
4265203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
4266203945Sweongyo		} else {
4267203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
4268203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4269203945Sweongyo			value = BWN_DMA32_TXENABLE;
4270203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
4271203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
4272203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
4273203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
4274203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4275203945Sweongyo		}
4276203945Sweongyo		return;
4277203945Sweongyo	}
4278203945Sweongyo
4279203945Sweongyo	/*
4280203945Sweongyo	 * set for RX
4281203945Sweongyo	 */
4282203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
4283203945Sweongyo
4284203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
4285203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
4286203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
4287203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
4288203945Sweongyo		value |= BWN_DMA64_RXENABLE;
4289203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
4290203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
4291203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
4292203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
4293203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
4294203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
4295203945Sweongyo		    | (trans << 1));
4296203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
4297203945Sweongyo		    sizeof(struct bwn_dmadesc64));
4298203945Sweongyo	} else {
4299203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
4300203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4301203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
4302203945Sweongyo		value |= BWN_DMA32_RXENABLE;
4303203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
4304203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
4305203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
4306203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
4307203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4308203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
4309203945Sweongyo		    sizeof(struct bwn_dmadesc32));
4310203945Sweongyo	}
4311203945Sweongyo}
4312203945Sweongyo
4313203945Sweongyostatic void
4314203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
4315203945Sweongyo{
4316203945Sweongyo
4317203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
4318203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
4319203945Sweongyo	    dr->dr_ring_dmap);
4320203945Sweongyo}
4321203945Sweongyo
4322203945Sweongyostatic void
4323203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
4324203945Sweongyo{
4325203945Sweongyo
4326203945Sweongyo	if (dr->dr_tx) {
4327203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4328203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4329203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
4330203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
4331203945Sweongyo		} else
4332203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
4333203945Sweongyo	} else {
4334203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4335203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4336203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
4337203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
4338203945Sweongyo		} else
4339203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
4340203945Sweongyo	}
4341203945Sweongyo}
4342203945Sweongyo
4343203945Sweongyostatic void
4344203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
4345203945Sweongyo{
4346203945Sweongyo	struct bwn_dmadesc_generic *desc;
4347203945Sweongyo	struct bwn_dmadesc_meta *meta;
4348203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4349203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4350203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4351203945Sweongyo	int i;
4352203945Sweongyo
4353203945Sweongyo	if (!dr->dr_usedslot)
4354203945Sweongyo		return;
4355203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
4356203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
4357203945Sweongyo
4358203945Sweongyo		if (meta->mt_m == NULL) {
4359203945Sweongyo			if (!dr->dr_tx)
4360203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
4361203945Sweongyo				    __func__);
4362203945Sweongyo			continue;
4363203945Sweongyo		}
4364203945Sweongyo		if (dr->dr_tx) {
4365203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
4366203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
4367203945Sweongyo				    meta->mt_dmap);
4368203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
4369203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
4370203945Sweongyo				    meta->mt_dmap);
4371203945Sweongyo		} else
4372203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
4373203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
4374203945Sweongyo	}
4375203945Sweongyo}
4376203945Sweongyo
4377203945Sweongyostatic int
4378203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
4379203945Sweongyo    int type)
4380203945Sweongyo{
4381203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4382203945Sweongyo	uint32_t value;
4383203945Sweongyo	int i;
4384203945Sweongyo	uint16_t offset;
4385203945Sweongyo
4386203945Sweongyo	for (i = 0; i < 10; i++) {
4387203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4388203945Sweongyo		    BWN_DMA32_TXSTATUS;
4389203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4390203945Sweongyo		if (type == BWN_DMA_64BIT) {
4391203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4392203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
4393203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
4394203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
4395203945Sweongyo				break;
4396203945Sweongyo		} else {
4397203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4398203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
4399203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
4400203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
4401203945Sweongyo				break;
4402203945Sweongyo		}
4403203945Sweongyo		DELAY(1000);
4404203945Sweongyo	}
4405203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
4406203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4407203945Sweongyo	for (i = 0; i < 10; i++) {
4408203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4409203945Sweongyo						   BWN_DMA32_TXSTATUS;
4410203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4411203945Sweongyo		if (type == BWN_DMA_64BIT) {
4412203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4413203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
4414203945Sweongyo				i = -1;
4415203945Sweongyo				break;
4416203945Sweongyo			}
4417203945Sweongyo		} else {
4418203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4419203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
4420203945Sweongyo				i = -1;
4421203945Sweongyo				break;
4422203945Sweongyo			}
4423203945Sweongyo		}
4424203945Sweongyo		DELAY(1000);
4425203945Sweongyo	}
4426203945Sweongyo	if (i != -1) {
4427203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4428203945Sweongyo		return (ENODEV);
4429203945Sweongyo	}
4430203945Sweongyo	DELAY(1000);
4431203945Sweongyo
4432203945Sweongyo	return (0);
4433203945Sweongyo}
4434203945Sweongyo
4435203945Sweongyostatic int
4436203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
4437203945Sweongyo    int type)
4438203945Sweongyo{
4439203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4440203945Sweongyo	uint32_t value;
4441203945Sweongyo	int i;
4442203945Sweongyo	uint16_t offset;
4443203945Sweongyo
4444203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
4445203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4446203945Sweongyo	for (i = 0; i < 10; i++) {
4447203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
4448203945Sweongyo		    BWN_DMA32_RXSTATUS;
4449203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4450203945Sweongyo		if (type == BWN_DMA_64BIT) {
4451203945Sweongyo			value &= BWN_DMA64_RXSTAT;
4452203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
4453203945Sweongyo				i = -1;
4454203945Sweongyo				break;
4455203945Sweongyo			}
4456203945Sweongyo		} else {
4457203945Sweongyo			value &= BWN_DMA32_RXSTATE;
4458203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
4459203945Sweongyo				i = -1;
4460203945Sweongyo				break;
4461203945Sweongyo			}
4462203945Sweongyo		}
4463203945Sweongyo		DELAY(1000);
4464203945Sweongyo	}
4465203945Sweongyo	if (i != -1) {
4466203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4467203945Sweongyo		return (ENODEV);
4468203945Sweongyo	}
4469203945Sweongyo
4470203945Sweongyo	return (0);
4471203945Sweongyo}
4472203945Sweongyo
4473203945Sweongyostatic void
4474203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
4475203945Sweongyo    struct bwn_dmadesc_meta *meta)
4476203945Sweongyo{
4477203945Sweongyo
4478203945Sweongyo	if (meta->mt_m != NULL) {
4479203945Sweongyo		m_freem(meta->mt_m);
4480203945Sweongyo		meta->mt_m = NULL;
4481203945Sweongyo	}
4482203945Sweongyo	if (meta->mt_ni != NULL) {
4483203945Sweongyo		ieee80211_free_node(meta->mt_ni);
4484203945Sweongyo		meta->mt_ni = NULL;
4485203945Sweongyo	}
4486203945Sweongyo}
4487203945Sweongyo
4488203945Sweongyostatic void
4489203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4490203945Sweongyo{
4491203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
4492203945Sweongyo	unsigned char *frame;
4493203945Sweongyo
4494203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
4495203945Sweongyo	rxhdr->frame_len = 0;
4496203945Sweongyo
4497203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
4498203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
4499203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4500203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
4501203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
4502203945Sweongyo}
4503203945Sweongyo
4504203945Sweongyostatic uint8_t
4505203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4506203945Sweongyo{
4507203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
4508203945Sweongyo
4509203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
4510203945Sweongyo	    == 0xff);
4511203945Sweongyo}
4512203945Sweongyo
4513203945Sweongyostatic void
4514203945Sweongyobwn_wme_init(struct bwn_mac *mac)
4515203945Sweongyo{
4516203945Sweongyo
4517203945Sweongyo	bwn_wme_load(mac);
4518203945Sweongyo
4519203945Sweongyo	/* enable WME support. */
4520203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
4521203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
4522203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
4523203945Sweongyo}
4524203945Sweongyo
4525203945Sweongyostatic void
4526203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
4527203945Sweongyo{
4528203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4529203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4530203945Sweongyo	uint16_t delay;	/* microsec */
4531203945Sweongyo
4532203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
4533203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
4534203945Sweongyo		delay = 500;
4535203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
4536203945Sweongyo		delay = max(delay, (uint16_t)2400);
4537203945Sweongyo
4538203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
4539203945Sweongyo}
4540203945Sweongyo
4541203945Sweongyostatic void
4542203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
4543203945Sweongyo{
4544203945Sweongyo	struct siba_sprom *sprom = &mac->mac_sd->sd_bus->siba_sprom;
4545203945Sweongyo	uint64_t hf;
4546203945Sweongyo
4547203945Sweongyo	if (bwn_bluetooth == 0)
4548203945Sweongyo		return;
4549203945Sweongyo	if ((sprom->bf_lo & BWN_BFL_BTCOEXIST) == 0)
4550203945Sweongyo		return;
4551203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
4552203945Sweongyo		return;
4553203945Sweongyo
4554203945Sweongyo	hf = bwn_hf_read(mac);
4555203945Sweongyo	if (sprom->bf_lo & BWN_BFL_BTCMOD)
4556203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
4557203945Sweongyo	else
4558203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
4559203945Sweongyo	bwn_hf_write(mac, hf);
4560203945Sweongyo}
4561203945Sweongyo
4562203945Sweongyostatic void
4563203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
4564203945Sweongyo{
4565203945Sweongyo
4566203945Sweongyo	bwn_mac_write_bssid(mac);
4567203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF, mac->mac_sc->sc_macaddr);
4568203945Sweongyo}
4569203945Sweongyo
4570203945Sweongyostatic void
4571203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
4572203945Sweongyo{
4573203945Sweongyo	int i;
4574203945Sweongyo
4575203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
4576203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
4577203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
4578203945Sweongyo
4579203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
4580203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
4581203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
4582203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
4583203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
4584203945Sweongyo		}
4585203945Sweongyo		mac->mac_key[i].keyconf = NULL;
4586203945Sweongyo	}
4587203945Sweongyo}
4588203945Sweongyo
4589203945Sweongyostatic void
4590203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
4591203945Sweongyo{
4592203945Sweongyo
4593203945Sweongyo	mac->mac_max_nr_keys = (mac->mac_sd->sd_id.sd_rev >= 5) ? 58 : 20;
4594203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
4595203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4596203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
4597203945Sweongyo	mac->mac_ktp *= 2;
4598203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 5) {
4599203945Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT,
4600203945Sweongyo		    mac->mac_max_nr_keys - 8);
4601203945Sweongyo	}
4602203945Sweongyo	bwn_clear_keys(mac);
4603203945Sweongyo}
4604203945Sweongyo
4605203945Sweongyostatic void
4606203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
4607203945Sweongyo{
4608203945Sweongyo
4609203945Sweongyo	bwn_phy_exit(mac);
4610203945Sweongyo	bwn_gpio_cleanup(mac);
4611203945Sweongyo}
4612203945Sweongyo
4613203945Sweongyostatic int
4614203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
4615203945Sweongyo{
4616203945Sweongyo	int error;
4617203945Sweongyo
4618203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
4619203945Sweongyo	if (error == 0)
4620203945Sweongyo		return (0);
4621203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
4622203945Sweongyo	if (error == 0)
4623203945Sweongyo		return (0);
4624203945Sweongyo	return (error);
4625203945Sweongyo}
4626203945Sweongyo
4627203945Sweongyostatic int
4628203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
4629203945Sweongyo{
4630203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
4631203945Sweongyo	struct siba_dev_softc *sd;
4632203945Sweongyo	uint32_t mask = 0x0000001f, set = 0x0000000f;
4633203945Sweongyo
4634203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4635203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
4636203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
4637203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
4638203945Sweongyo
4639203945Sweongyo	if (bus->siba_chipid == 0x4301) {
4640203945Sweongyo		mask |= 0x0060;
4641203945Sweongyo		set |= 0x0060;
4642203945Sweongyo	}
4643203945Sweongyo	if (bus->siba_sprom.bf_lo & BWN_BFL_PACTRL) {
4644203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
4645203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
4646203945Sweongyo		mask |= 0x0200;
4647203945Sweongyo		set |= 0x0200;
4648203945Sweongyo	}
4649203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 2)
4650203945Sweongyo		mask |= 0x0010;
4651203945Sweongyo	sd = (bus->siba_cc.scc_dev != NULL) ? bus->siba_cc.scc_dev :
4652203945Sweongyo	    bus->siba_pci.spc_dev;
4653203945Sweongyo	if (sd == NULL)
4654203945Sweongyo		return (0);
4655203945Sweongyo	siba_write_4(sd, BWN_GPIOCTL,
4656203945Sweongyo	    (siba_read_4(sd, BWN_GPIOCTL) & mask) | set);
4657203945Sweongyo
4658203945Sweongyo	return (0);
4659203945Sweongyo}
4660203945Sweongyo
4661203945Sweongyostatic int
4662203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
4663203945Sweongyo{
4664203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
4665203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
4666203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
4667203945Sweongyo	const struct bwn_fwhdr *hdr;
4668203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
4669203945Sweongyo	int error;
4670203945Sweongyo
4671203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
4672203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
4673203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
4674203945Sweongyo	if (error)
4675203945Sweongyo		return (error);
4676203945Sweongyo	if (fw->initvals_band.fw) {
4677203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
4678203945Sweongyo		error = bwn_fwinitvals_write(mac,
4679203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
4680203945Sweongyo		    be32toh(hdr->size),
4681203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
4682203945Sweongyo	}
4683203945Sweongyo	return (error);
4684203945Sweongyo#undef GETFWOFFSET
4685203945Sweongyo}
4686203945Sweongyo
4687203945Sweongyostatic int
4688203945Sweongyobwn_phy_init(struct bwn_mac *mac)
4689203945Sweongyo{
4690203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4691203945Sweongyo	int error;
4692203945Sweongyo
4693203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
4694203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4695203945Sweongyo	error = mac->mac_phy.init(mac);
4696203945Sweongyo	if (error) {
4697203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
4698203945Sweongyo		goto fail0;
4699203945Sweongyo	}
4700203945Sweongyo	error = bwn_switch_channel(mac,
4701203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
4702203945Sweongyo	if (error) {
4703203945Sweongyo		device_printf(sc->sc_dev,
4704203945Sweongyo		    "failed to switch default channel\n");
4705203945Sweongyo		goto fail1;
4706203945Sweongyo	}
4707203945Sweongyo	return (0);
4708203945Sweongyofail1:
4709203945Sweongyo	if (mac->mac_phy.exit)
4710203945Sweongyo		mac->mac_phy.exit(mac);
4711203945Sweongyofail0:
4712203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4713203945Sweongyo
4714203945Sweongyo	return (error);
4715203945Sweongyo}
4716203945Sweongyo
4717203945Sweongyostatic void
4718203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
4719203945Sweongyo{
4720203945Sweongyo	uint16_t ant;
4721203945Sweongyo	uint16_t tmp;
4722203945Sweongyo
4723203945Sweongyo	ant = bwn_ant2phy(antenna);
4724203945Sweongyo
4725203945Sweongyo	/* For ACK/CTS */
4726203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
4727203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4728203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
4729203945Sweongyo	/* For Probe Resposes */
4730203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
4731203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4732203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
4733203945Sweongyo}
4734203945Sweongyo
4735203945Sweongyostatic void
4736203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
4737203945Sweongyo{
4738203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4739203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4740203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
4741203945Sweongyo	uint32_t ctl;
4742203945Sweongyo	uint16_t cfp_pretbtt;
4743203945Sweongyo
4744203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
4745203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
4746203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
4747203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
4748203945Sweongyo	ctl |= BWN_MACCTL_STA;
4749203945Sweongyo
4750203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4751203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
4752203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
4753203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
4754203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
4755203945Sweongyo	ctl |= sc->sc_filters;
4756203945Sweongyo
4757203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev <= 4)
4758203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
4759203945Sweongyo
4760203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
4761203945Sweongyo
4762203945Sweongyo	cfp_pretbtt = 2;
4763203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
4764203945Sweongyo		if (mac->mac_sd->sd_bus->siba_chipid == 0x4306 &&
4765203945Sweongyo		    mac->mac_sd->sd_bus->siba_chiprev == 3)
4766203945Sweongyo			cfp_pretbtt = 100;
4767203945Sweongyo		else
4768203945Sweongyo			cfp_pretbtt = 50;
4769203945Sweongyo	}
4770203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
4771203945Sweongyo}
4772203945Sweongyo
4773203945Sweongyostatic void
4774203945Sweongyobwn_gpio_cleanup(struct bwn_mac *mac)
4775203945Sweongyo{
4776203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
4777203945Sweongyo	struct siba_dev_softc *gpiodev, *pcidev = NULL;
4778203945Sweongyo
4779203945Sweongyo	pcidev = bus->siba_pci.spc_dev;
4780203945Sweongyo	gpiodev = bus->siba_cc.scc_dev ? bus->siba_cc.scc_dev : pcidev;
4781203945Sweongyo	if (!gpiodev)
4782203945Sweongyo		return;
4783203945Sweongyo	siba_write_4(gpiodev, BWN_GPIOCTL, 0);
4784203945Sweongyo}
4785203945Sweongyo
4786203945Sweongyostatic int
4787203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
4788203945Sweongyo{
4789203945Sweongyo	uint32_t tmp;
4790203945Sweongyo	uint16_t base;
4791203945Sweongyo
4792203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
4793203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
4794203945Sweongyo		return (BWN_DMA_64BIT);
4795203945Sweongyo	base = bwn_dma_base(0, 0);
4796203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
4797203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
4798203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
4799203945Sweongyo		return (BWN_DMA_32BIT);
4800203945Sweongyo
4801203945Sweongyo	return (BWN_DMA_30BIT);
4802203945Sweongyo}
4803203945Sweongyo
4804203945Sweongyostatic void
4805203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
4806203945Sweongyo{
4807203945Sweongyo	if (!error) {
4808203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
4809203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
4810203945Sweongyo	}
4811203945Sweongyo}
4812203945Sweongyo
4813203945Sweongyostatic void
4814203945Sweongyobwn_phy_g_init_sub(struct bwn_mac *mac)
4815203945Sweongyo{
4816203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4817203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4818203945Sweongyo	uint16_t i, tmp;
4819203945Sweongyo
4820203945Sweongyo	if (phy->rev == 1)
4821203945Sweongyo		bwn_phy_init_b5(mac);
4822203945Sweongyo	else
4823203945Sweongyo		bwn_phy_init_b6(mac);
4824203945Sweongyo
4825203945Sweongyo	if (phy->rev >= 2 || phy->gmode)
4826203945Sweongyo		bwn_phy_init_a(mac);
4827203945Sweongyo
4828203945Sweongyo	if (phy->rev >= 2) {
4829203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
4830203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
4831203945Sweongyo	}
4832203945Sweongyo	if (phy->rev == 2) {
4833203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
4834203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4835203945Sweongyo	}
4836203945Sweongyo	if (phy->rev > 5) {
4837203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
4838203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4839203945Sweongyo	}
4840203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4841203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
4842203945Sweongyo		tmp &= BWN_PHYVER_VERSION;
4843203945Sweongyo		if (tmp == 3 || tmp == 5) {
4844203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
4845203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
4846203945Sweongyo		}
4847203945Sweongyo		if (tmp == 5) {
4848203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
4849203945Sweongyo			    0x1f00);
4850203945Sweongyo		}
4851203945Sweongyo	}
4852203945Sweongyo	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
4853203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
4854203945Sweongyo	if (phy->rf_rev == 8) {
4855203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
4856203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
4857203945Sweongyo	}
4858203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
4859203945Sweongyo		bwn_loopback_calcgain(mac);
4860203945Sweongyo
4861203945Sweongyo	if (phy->rf_rev != 8) {
4862203945Sweongyo		if (pg->pg_initval == 0xffff)
4863203945Sweongyo			pg->pg_initval = bwn_rf_init_bcm2050(mac);
4864203945Sweongyo		else
4865203945Sweongyo			BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
4866203945Sweongyo	}
4867203945Sweongyo	bwn_lo_g_init(mac);
4868203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
4869203945Sweongyo		BWN_RF_WRITE(mac, 0x52,
4870203945Sweongyo		    (BWN_RF_READ(mac, 0x52) & 0xff00)
4871203945Sweongyo		    | pg->pg_loctl.tx_bias |
4872203945Sweongyo		    pg->pg_loctl.tx_magn);
4873203945Sweongyo	} else {
4874203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
4875203945Sweongyo	}
4876203945Sweongyo	if (phy->rev >= 6) {
4877203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
4878203945Sweongyo		    (pg->pg_loctl.tx_bias << 12));
4879203945Sweongyo	}
4880203945Sweongyo	if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_PACTRL)
4881203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
4882203945Sweongyo	else
4883203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
4884203945Sweongyo	if (phy->rev < 2)
4885203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
4886203945Sweongyo	else
4887203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
4888203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4889203945Sweongyo		bwn_lo_g_adjust(mac);
4890203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
4891203945Sweongyo	}
4892203945Sweongyo
4893203945Sweongyo	if (!(mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_RSSI)) {
4894203945Sweongyo		for (i = 0; i < 64; i++) {
4895203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
4896203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
4897203945Sweongyo			    (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
4898203945Sweongyo			    -32), 31));
4899203945Sweongyo		}
4900203945Sweongyo		bwn_nrssi_threshold(mac);
4901203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
4902203945Sweongyo		if (pg->pg_nrssi[0] == -1000) {
4903203945Sweongyo			KASSERT(pg->pg_nrssi[1] == -1000,
4904203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
4905203945Sweongyo			bwn_nrssi_slope_11g(mac);
4906203945Sweongyo		} else
4907203945Sweongyo			bwn_nrssi_threshold(mac);
4908203945Sweongyo	}
4909203945Sweongyo	if (phy->rf_rev == 8)
4910203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
4911203945Sweongyo	bwn_phy_hwpctl_init(mac);
4912203945Sweongyo	if ((mac->mac_sd->sd_bus->siba_chipid == 0x4306
4913203945Sweongyo	     && mac->mac_sd->sd_bus->siba_chippkg == 2) || 0) {
4914203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
4915203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
4916203945Sweongyo	}
4917203945Sweongyo}
4918203945Sweongyo
4919203945Sweongyostatic uint8_t
4920203945Sweongyobwn_has_hwpctl(struct bwn_mac *mac)
4921203945Sweongyo{
4922203945Sweongyo
4923203945Sweongyo	if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
4924203945Sweongyo		return (0);
4925203945Sweongyo	return (mac->mac_phy.use_hwpctl(mac));
4926203945Sweongyo}
4927203945Sweongyo
4928203945Sweongyostatic void
4929203945Sweongyobwn_phy_init_b5(struct bwn_mac *mac)
4930203945Sweongyo{
4931203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
4932203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4933203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4934203945Sweongyo	uint16_t offset, value;
4935203945Sweongyo	uint8_t old_channel;
4936203945Sweongyo
4937203945Sweongyo	if (phy->analog == 1)
4938203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0050);
4939203945Sweongyo	if ((bus->siba_board_vendor != SIBA_BOARDVENDOR_BCM) &&
4940203945Sweongyo	    (bus->siba_board_type != SIBA_BOARD_BU4306)) {
4941203945Sweongyo		value = 0x2120;
4942203945Sweongyo		for (offset = 0x00a8; offset < 0x00c7; offset++) {
4943203945Sweongyo			BWN_PHY_WRITE(mac, offset, value);
4944203945Sweongyo			value += 0x202;
4945203945Sweongyo		}
4946203945Sweongyo	}
4947203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
4948203945Sweongyo	if (phy->rf_ver == 0x2050)
4949203945Sweongyo		BWN_PHY_WRITE(mac, 0x0038, 0x0667);
4950203945Sweongyo
4951203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4952203945Sweongyo		if (phy->rf_ver == 0x2050) {
4953203945Sweongyo			BWN_RF_SET(mac, 0x007a, 0x0020);
4954203945Sweongyo			BWN_RF_SET(mac, 0x0051, 0x0004);
4955203945Sweongyo		}
4956203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
4957203945Sweongyo
4958203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
4959203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
4960203945Sweongyo
4961203945Sweongyo		BWN_PHY_WRITE(mac, 0x001c, 0x186a);
4962203945Sweongyo
4963203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
4964203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
4965203945Sweongyo		BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
4966203945Sweongyo	}
4967203945Sweongyo
4968203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
4969203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
4970203945Sweongyo
4971203945Sweongyo	if (phy->analog == 1) {
4972203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xce00);
4973203945Sweongyo		BWN_PHY_WRITE(mac, 0x0021, 0x3763);
4974203945Sweongyo		BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
4975203945Sweongyo		BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
4976203945Sweongyo		BWN_PHY_WRITE(mac, 0x0024, 0x037e);
4977203945Sweongyo	} else
4978203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
4979203945Sweongyo	BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
4980203945Sweongyo	BWN_WRITE_2(mac, 0x03ec, 0x3f22);
4981203945Sweongyo
4982203945Sweongyo	if (phy->analog == 1)
4983203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
4984203945Sweongyo	else
4985203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x301c);
4986203945Sweongyo
4987203945Sweongyo	if (phy->analog == 0)
4988203945Sweongyo		BWN_WRITE_2(mac, 0x03e4, 0x3000);
4989203945Sweongyo
4990203945Sweongyo	old_channel = phy->chan;
4991203945Sweongyo	bwn_phy_g_switch_chan(mac, 7, 0);
4992203945Sweongyo
4993203945Sweongyo	if (phy->rf_ver != 0x2050) {
4994203945Sweongyo		BWN_RF_WRITE(mac, 0x0075, 0x0080);
4995203945Sweongyo		BWN_RF_WRITE(mac, 0x0079, 0x0081);
4996203945Sweongyo	}
4997203945Sweongyo
4998203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
4999203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
5000203945Sweongyo
5001203945Sweongyo	if (phy->rf_ver == 0x2050) {
5002203945Sweongyo		BWN_RF_WRITE(mac, 0x0050, 0x0020);
5003203945Sweongyo		BWN_RF_WRITE(mac, 0x005a, 0x0070);
5004203945Sweongyo	}
5005203945Sweongyo
5006203945Sweongyo	BWN_RF_WRITE(mac, 0x005b, 0x007b);
5007203945Sweongyo	BWN_RF_WRITE(mac, 0x005c, 0x00b0);
5008203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0007);
5009203945Sweongyo
5010203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5011203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0080);
5012203945Sweongyo	BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
5013203945Sweongyo	BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
5014203945Sweongyo
5015203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5016203945Sweongyo	    pg->pg_txctl);
5017203945Sweongyo
5018203945Sweongyo	if (phy->rf_ver == 0x2050)
5019203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5020203945Sweongyo
5021203945Sweongyo	BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
5022203945Sweongyo}
5023203945Sweongyo
5024203945Sweongyostatic void
5025203945Sweongyobwn_loopback_calcgain(struct bwn_mac *mac)
5026203945Sweongyo{
5027203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5028203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5029203945Sweongyo	uint16_t backup_phy[16] = { 0 };
5030203945Sweongyo	uint16_t backup_radio[3];
5031203945Sweongyo	uint16_t backup_bband;
5032203945Sweongyo	uint16_t i, j, loop_i_max;
5033203945Sweongyo	uint16_t trsw_rx;
5034203945Sweongyo	uint16_t loop1_outer_done, loop1_inner_done;
5035203945Sweongyo
5036203945Sweongyo	backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5037203945Sweongyo	backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
5038203945Sweongyo	backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5039203945Sweongyo	backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5040203945Sweongyo	if (phy->rev != 1) {
5041203945Sweongyo		backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5042203945Sweongyo		backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5043203945Sweongyo	}
5044203945Sweongyo	backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5045203945Sweongyo	backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5046203945Sweongyo	backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5047203945Sweongyo	backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
5048203945Sweongyo	backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
5049203945Sweongyo	backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5050203945Sweongyo	backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5051203945Sweongyo	backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
5052203945Sweongyo	backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5053203945Sweongyo	backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5054203945Sweongyo	backup_bband = pg->pg_bbatt.att;
5055203945Sweongyo	backup_radio[0] = BWN_RF_READ(mac, 0x52);
5056203945Sweongyo	backup_radio[1] = BWN_RF_READ(mac, 0x43);
5057203945Sweongyo	backup_radio[2] = BWN_RF_READ(mac, 0x7a);
5058203945Sweongyo
5059203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
5060203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
5061203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
5062203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
5063203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
5064203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
5065203945Sweongyo	if (phy->rev != 1) {
5066203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
5067203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
5068203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
5069203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
5070203945Sweongyo	}
5071203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
5072203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
5073203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
5074203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
5075203945Sweongyo
5076203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
5077203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5078203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5079203945Sweongyo
5080203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
5081203945Sweongyo	if (phy->rev != 1) {
5082203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
5083203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
5084203945Sweongyo	}
5085203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
5086203945Sweongyo
5087203945Sweongyo	if (phy->rf_rev == 8)
5088203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x000f);
5089203945Sweongyo	else {
5090203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5091203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
5092203945Sweongyo	}
5093203945Sweongyo	bwn_phy_g_set_bbatt(mac, 11);
5094203945Sweongyo
5095203945Sweongyo	if (phy->rev >= 3)
5096203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5097203945Sweongyo	else
5098203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5099203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5100203945Sweongyo
5101203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
5102203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
5103203945Sweongyo
5104203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
5105203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
5106203945Sweongyo
5107203945Sweongyo	if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA) {
5108203945Sweongyo		if (phy->rev >= 7) {
5109203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
5110203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
5111203945Sweongyo		}
5112203945Sweongyo	}
5113203945Sweongyo	BWN_RF_MASK(mac, 0x7a, 0x00f7);
5114203945Sweongyo
5115203945Sweongyo	j = 0;
5116203945Sweongyo	loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
5117203945Sweongyo	for (i = 0; i < loop_i_max; i++) {
5118203945Sweongyo		for (j = 0; j < 16; j++) {
5119203945Sweongyo			BWN_RF_WRITE(mac, 0x43, i);
5120203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
5121203945Sweongyo			    (j << 8));
5122203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5123203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5124203945Sweongyo			DELAY(20);
5125203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5126203945Sweongyo				goto done0;
5127203945Sweongyo		}
5128203945Sweongyo	}
5129203945Sweongyodone0:
5130203945Sweongyo	loop1_outer_done = i;
5131203945Sweongyo	loop1_inner_done = j;
5132203945Sweongyo	if (j >= 8) {
5133203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
5134203945Sweongyo		trsw_rx = 0x1b;
5135203945Sweongyo		for (j = j - 8; j < 16; j++) {
5136203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
5137203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5138203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5139203945Sweongyo			DELAY(20);
5140203945Sweongyo			trsw_rx -= 3;
5141203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5142203945Sweongyo				goto done1;
5143203945Sweongyo		}
5144203945Sweongyo	} else
5145203945Sweongyo		trsw_rx = 0x18;
5146203945Sweongyodone1:
5147203945Sweongyo
5148203945Sweongyo	if (phy->rev != 1) {
5149203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
5150203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
5151203945Sweongyo	}
5152203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
5153203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
5154203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
5155203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
5156203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
5157203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
5158203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
5159203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
5160203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
5161203945Sweongyo
5162203945Sweongyo	bwn_phy_g_set_bbatt(mac, backup_bband);
5163203945Sweongyo
5164203945Sweongyo	BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
5165203945Sweongyo	BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
5166203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
5167203945Sweongyo
5168203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
5169203945Sweongyo	DELAY(10);
5170203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
5171203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
5172203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
5173203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
5174203945Sweongyo
5175203945Sweongyo	pg->pg_max_lb_gain =
5176203945Sweongyo	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
5177203945Sweongyo	pg->pg_trsw_rx_gain = trsw_rx * 2;
5178203945Sweongyo}
5179203945Sweongyo
5180203945Sweongyostatic uint16_t
5181203945Sweongyobwn_rf_init_bcm2050(struct bwn_mac *mac)
5182203945Sweongyo{
5183203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5184203945Sweongyo	uint32_t tmp1 = 0, tmp2 = 0;
5185203945Sweongyo	uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
5186203945Sweongyo	    analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
5187203945Sweongyo	    radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
5188203945Sweongyo	static const uint8_t rcc_table[] = {
5189203945Sweongyo		0x02, 0x03, 0x01, 0x0f,
5190203945Sweongyo		0x06, 0x07, 0x05, 0x0f,
5191203945Sweongyo		0x0a, 0x0b, 0x09, 0x0f,
5192203945Sweongyo		0x0e, 0x0f, 0x0d, 0x0f,
5193203945Sweongyo	};
5194203945Sweongyo
5195204242Simp	loctl = lomask = reg0 = classctl = crs0 = analogoverval = analogover =
5196204242Simp	    rfoverval = rfover = cck3 = 0;
5197203945Sweongyo	radio0 = BWN_RF_READ(mac, 0x43);
5198203945Sweongyo	radio1 = BWN_RF_READ(mac, 0x51);
5199203945Sweongyo	radio2 = BWN_RF_READ(mac, 0x52);
5200203945Sweongyo	pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5201203945Sweongyo	cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5202203945Sweongyo	cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5203203945Sweongyo	cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5204203945Sweongyo
5205203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5206203945Sweongyo		cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
5207203945Sweongyo		reg0 = BWN_READ_2(mac, 0x3ec);
5208203945Sweongyo
5209203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
5210203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
5211203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
5212203945Sweongyo		rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5213203945Sweongyo		rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5214203945Sweongyo		analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5215203945Sweongyo		analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5216203945Sweongyo		crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5217203945Sweongyo		classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
5218203945Sweongyo
5219203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
5220203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
5221203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
5222203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
5223203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5224203945Sweongyo			lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5225203945Sweongyo			loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5226203945Sweongyo			if (phy->rev >= 3)
5227203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5228203945Sweongyo			else
5229203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5230203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5231203945Sweongyo		}
5232203945Sweongyo
5233203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5234203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5235203945Sweongyo			BWN_LPD(0, 1, 1)));
5236203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
5237203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
5238203945Sweongyo	}
5239203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
5240203945Sweongyo
5241203945Sweongyo	syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
5242203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
5243203945Sweongyo	reg1 = BWN_READ_2(mac, 0x3e6);
5244203945Sweongyo	reg2 = BWN_READ_2(mac, 0x3f4);
5245203945Sweongyo
5246203945Sweongyo	if (phy->analog == 0)
5247203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0122);
5248203945Sweongyo	else {
5249203945Sweongyo		if (phy->analog >= 2)
5250203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
5251203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
5252203945Sweongyo		    (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
5253203945Sweongyo	}
5254203945Sweongyo
5255203945Sweongyo	reg = BWN_RF_READ(mac, 0x60);
5256203945Sweongyo	index = (reg & 0x001e) >> 1;
5257203945Sweongyo	rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
5258203945Sweongyo
5259203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5260203945Sweongyo		BWN_RF_WRITE(mac, 0x78, 0x26);
5261203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5262203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5263203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5264203945Sweongyo			BWN_LPD(0, 1, 1)));
5265203945Sweongyo	}
5266203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
5267203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
5268203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5269203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5270203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5271203945Sweongyo			BWN_LPD(0, 0, 1)));
5272203945Sweongyo	}
5273203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
5274203945Sweongyo	BWN_RF_SET(mac, 0x51, 0x0004);
5275203945Sweongyo	if (phy->rf_rev == 8)
5276203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x1f);
5277203945Sweongyo	else {
5278203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5279203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
5280203945Sweongyo	}
5281203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5282203945Sweongyo
5283203945Sweongyo	for (i = 0; i < 16; i++) {
5284203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
5285203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5286203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5287203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5288203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5289203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5290203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5291203945Sweongyo		}
5292203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5293203945Sweongyo		DELAY(10);
5294203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5295203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5296203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5297203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5298203945Sweongyo		}
5299203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5300203945Sweongyo		DELAY(10);
5301203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5302203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5303203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5304203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5305203945Sweongyo		}
5306203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5307203945Sweongyo		DELAY(20);
5308203945Sweongyo		tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5309203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5310203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5311203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5312203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5313203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5314203945Sweongyo		}
5315203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5316203945Sweongyo	}
5317203945Sweongyo	DELAY(10);
5318203945Sweongyo
5319203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5320203945Sweongyo	tmp1++;
5321203945Sweongyo	tmp1 >>= 9;
5322203945Sweongyo
5323203945Sweongyo	for (i = 0; i < 16; i++) {
5324203945Sweongyo		radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
5325203945Sweongyo		BWN_RF_WRITE(mac, 0x78, radio78);
5326203945Sweongyo		DELAY(10);
5327203945Sweongyo		for (j = 0; j < 16; j++) {
5328203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
5329203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5330203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5331203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5332203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5333203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5334203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5335203945Sweongyo			}
5336203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5337203945Sweongyo			DELAY(10);
5338203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5339203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5340203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5341203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5342203945Sweongyo			}
5343203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5344203945Sweongyo			DELAY(10);
5345203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5346203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5347203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5348203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5349203945Sweongyo			}
5350203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5351203945Sweongyo			DELAY(10);
5352203945Sweongyo			tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5353203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5354203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5355203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5356203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5357203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5358203945Sweongyo			}
5359203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5360203945Sweongyo		}
5361203945Sweongyo		tmp2++;
5362203945Sweongyo		tmp2 >>= 8;
5363203945Sweongyo		if (tmp1 < tmp2)
5364203945Sweongyo			break;
5365203945Sweongyo	}
5366203945Sweongyo
5367203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
5368203945Sweongyo	BWN_RF_WRITE(mac, 0x51, radio1);
5369203945Sweongyo	BWN_RF_WRITE(mac, 0x52, radio2);
5370203945Sweongyo	BWN_RF_WRITE(mac, 0x43, radio0);
5371203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
5372203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
5373203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
5374203945Sweongyo	BWN_WRITE_2(mac, 0x3e6, reg1);
5375203945Sweongyo	if (phy->analog != 0)
5376203945Sweongyo		BWN_WRITE_2(mac, 0x3f4, reg2);
5377203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
5378203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
5379203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5380203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
5381203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, reg0);
5382203945Sweongyo	} else if (phy->gmode) {
5383203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO,
5384203945Sweongyo			    BWN_READ_2(mac, BWN_PHY_RADIO)
5385203945Sweongyo			    & 0x7fff);
5386203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
5387203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
5388203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
5389203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
5390203945Sweongyo			      analogoverval);
5391203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
5392203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
5393203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5394203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
5395203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
5396203945Sweongyo		}
5397203945Sweongyo	}
5398203945Sweongyo
5399203945Sweongyo	return ((i > 15) ? radio78 : rcc);
5400203945Sweongyo}
5401203945Sweongyo
5402203945Sweongyostatic void
5403203945Sweongyobwn_phy_init_b6(struct bwn_mac *mac)
5404203945Sweongyo{
5405203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5406203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5407203945Sweongyo	uint16_t offset, val;
5408203945Sweongyo	uint8_t old_channel;
5409203945Sweongyo
5410203945Sweongyo	KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
5411203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5412203945Sweongyo
5413203945Sweongyo	BWN_PHY_WRITE(mac, 0x003e, 0x817a);
5414203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
5415203945Sweongyo	if (phy->rf_rev == 4 || phy->rf_rev == 5) {
5416203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0x37);
5417203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x70);
5418203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb3);
5419203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x9b);
5420203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5421203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x88);
5422203945Sweongyo		BWN_RF_WRITE(mac, 0x5d, 0x88);
5423203945Sweongyo		BWN_RF_WRITE(mac, 0x5e, 0x88);
5424203945Sweongyo		BWN_RF_WRITE(mac, 0x7d, 0x88);
5425203945Sweongyo		bwn_hf_write(mac,
5426203945Sweongyo		    bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
5427203945Sweongyo	}
5428203945Sweongyo	if (phy->rf_rev == 8) {
5429203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0);
5430203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x40);
5431203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb7);
5432203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x98);
5433203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5434203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x6b);
5435203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0x0f);
5436203945Sweongyo		if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_ALTIQ) {
5437203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xfa);
5438203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xd8);
5439203945Sweongyo		} else {
5440203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xf5);
5441203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xb8);
5442203945Sweongyo		}
5443203945Sweongyo		BWN_RF_WRITE(mac, 0x0073, 0x0003);
5444203945Sweongyo		BWN_RF_WRITE(mac, 0x007d, 0x00a8);
5445203945Sweongyo		BWN_RF_WRITE(mac, 0x007c, 0x0001);
5446203945Sweongyo		BWN_RF_WRITE(mac, 0x007e, 0x0008);
5447203945Sweongyo	}
5448203945Sweongyo	for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
5449203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5450203945Sweongyo		val -= 0x0202;
5451203945Sweongyo	}
5452203945Sweongyo	for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
5453203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5454203945Sweongyo		val -= 0x0202;
5455203945Sweongyo	}
5456203945Sweongyo	for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
5457203945Sweongyo		BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
5458203945Sweongyo		val += 0x0202;
5459203945Sweongyo	}
5460203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
5461203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0020);
5462203945Sweongyo		BWN_RF_SET(mac, 0x0051, 0x0004);
5463203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
5464203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
5465203945Sweongyo		BWN_PHY_WRITE(mac, 0x5b, 0);
5466203945Sweongyo		BWN_PHY_WRITE(mac, 0x5c, 0);
5467203945Sweongyo	}
5468203945Sweongyo
5469203945Sweongyo	old_channel = phy->chan;
5470203945Sweongyo	bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
5471203945Sweongyo
5472203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
5473203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
5474203945Sweongyo	DELAY(40);
5475203945Sweongyo	if (phy->rf_rev < 6 || phy->rf_rev == 8) {
5476203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
5477203945Sweongyo		BWN_RF_WRITE(mac, 0x50, 0x20);
5478203945Sweongyo	}
5479203945Sweongyo	if (phy->rf_rev <= 2) {
5480203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, 0x20);
5481203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x70);
5482203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x7b);
5483203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0xb0);
5484203945Sweongyo	}
5485203945Sweongyo	BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
5486203945Sweongyo
5487203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5488203945Sweongyo
5489203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0200);
5490203945Sweongyo	if (phy->rf_rev >= 6)
5491203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
5492203945Sweongyo	else
5493203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
5494203945Sweongyo	BWN_PHY_WRITE(mac, 0x0038, 0x0668);
5495203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5496203945Sweongyo	    pg->pg_txctl);
5497203945Sweongyo	if (phy->rf_rev <= 5)
5498203945Sweongyo		BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
5499203945Sweongyo	if (phy->rf_rev <= 2)
5500203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5501203945Sweongyo
5502203945Sweongyo	if (phy->analog == 4) {
5503203945Sweongyo		BWN_WRITE_2(mac, 0x3e4, 9);
5504203945Sweongyo		BWN_PHY_MASK(mac, 0x61, 0x0fff);
5505203945Sweongyo	} else
5506203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
5507203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5508203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5509203945Sweongyo	else if (phy->type == BWN_PHYTYPE_G)
5510203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0);
5511203945Sweongyo}
5512203945Sweongyo
5513203945Sweongyostatic void
5514203945Sweongyobwn_phy_init_a(struct bwn_mac *mac)
5515203945Sweongyo{
5516203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5517203945Sweongyo
5518203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
5519203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5520203945Sweongyo
5521203945Sweongyo	if (phy->rev >= 6) {
5522203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5523203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
5524203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
5525203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
5526203945Sweongyo		else
5527203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
5528203945Sweongyo	}
5529203945Sweongyo
5530203945Sweongyo	bwn_wa_init(mac);
5531203945Sweongyo
5532203945Sweongyo	if (phy->type == BWN_PHYTYPE_G &&
5533203945Sweongyo	    (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_PACTRL))
5534203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
5535203945Sweongyo}
5536203945Sweongyo
5537203945Sweongyostatic void
5538203945Sweongyobwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
5539203945Sweongyo{
5540203945Sweongyo	int i;
5541203945Sweongyo
5542203945Sweongyo	for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
5543203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
5544203945Sweongyo}
5545203945Sweongyo
5546203945Sweongyostatic void
5547203945Sweongyobwn_wa_agc(struct bwn_mac *mac)
5548203945Sweongyo{
5549203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5550203945Sweongyo
5551203945Sweongyo	if (phy->rev == 1) {
5552203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
5553203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
5554203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
5555203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
5556203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
5557203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
5558203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
5559203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
5560203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
5561203945Sweongyo	} else {
5562203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
5563203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
5564203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
5565203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
5566203945Sweongyo	}
5567203945Sweongyo
5568203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
5569203945Sweongyo	    0x5700);
5570203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
5571203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
5572203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
5573203945Sweongyo	BWN_RF_SET(mac, 0x7a, 0x0008);
5574203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
5575203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
5576203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
5577203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
5578203945Sweongyo	if (phy->rev == 1)
5579203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
5580203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
5581203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
5582203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
5583203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
5584203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
5585203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
5586203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
5587203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
5588203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
5589203945Sweongyo	if (phy->rev == 1) {
5590203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
5591203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
5592203945Sweongyo	} else {
5593203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
5594203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
5595203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
5596203945Sweongyo		if (phy->rev >= 6) {
5597203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
5598203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
5599203945Sweongyo			    (uint16_t)~0xf000, 0x3000);
5600203945Sweongyo		}
5601203945Sweongyo	}
5602203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
5603203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
5604203945Sweongyo	if (phy->rev == 1) {
5605203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
5606203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
5607203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
5608203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
5609203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
5610203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
5611203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
5612203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
5613203945Sweongyo	} else {
5614203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
5615203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
5616203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
5617203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
5618203945Sweongyo	}
5619203945Sweongyo	if (phy->rev >= 6) {
5620203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
5621203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
5622203945Sweongyo	}
5623203945Sweongyo	BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
5624203945Sweongyo}
5625203945Sweongyo
5626203945Sweongyostatic void
5627203945Sweongyobwn_wa_grev1(struct bwn_mac *mac)
5628203945Sweongyo{
5629203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5630203945Sweongyo	int i;
5631203945Sweongyo	static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
5632203945Sweongyo	static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
5633203945Sweongyo	static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
5634203945Sweongyo
5635203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5636203945Sweongyo
5637203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5638203945Sweongyo	if (phy->rev == 1) {
5639203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5640203945Sweongyo	} else if (phy->rev == 2) {
5641203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5642203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5643203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5644203945Sweongyo	} else {
5645203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5646203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5647203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5648203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5649203945Sweongyo	}
5650203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
5651203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
5652203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
5653203945Sweongyo
5654203945Sweongyo	/* XXX support PHY-A??? */
5655203945Sweongyo	for (i = 0; i < N(bwn_tab_finefreqg); i++)
5656203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
5657203945Sweongyo		    bwn_tab_finefreqg[i]);
5658203945Sweongyo
5659203945Sweongyo	/* XXX support PHY-A??? */
5660203945Sweongyo	if (phy->rev == 1)
5661203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5662203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5663203945Sweongyo			    bwn_tab_noise_g1[i]);
5664203945Sweongyo	else
5665203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5666203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5667203945Sweongyo			    bwn_tab_noise_g2[i]);
5668203945Sweongyo
5669203945Sweongyo
5670203945Sweongyo	for (i = 0; i < N(bwn_tab_rotor); i++)
5671203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
5672203945Sweongyo		    bwn_tab_rotor[i]);
5673203945Sweongyo
5674203945Sweongyo	/* XXX support PHY-A??? */
5675203945Sweongyo	if (phy->rev >= 6) {
5676203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5677203945Sweongyo		    BWN_PHY_ENCORE_EN)
5678203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5679203945Sweongyo		else
5680203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5681203945Sweongyo	} else
5682203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5683203945Sweongyo
5684203945Sweongyo	for (i = 0; i < N(bwn_tab_retard); i++)
5685203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
5686203945Sweongyo		    bwn_tab_retard[i]);
5687203945Sweongyo
5688203945Sweongyo	if (phy->rev == 1) {
5689203945Sweongyo		for (i = 0; i < 16; i++)
5690203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
5691203945Sweongyo			    i, 0x0020);
5692203945Sweongyo	} else {
5693203945Sweongyo		for (i = 0; i < 32; i++)
5694203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5695203945Sweongyo	}
5696203945Sweongyo
5697203945Sweongyo	bwn_wa_agc(mac);
5698203945Sweongyo}
5699203945Sweongyo
5700203945Sweongyostatic void
5701203945Sweongyobwn_wa_grev26789(struct bwn_mac *mac)
5702203945Sweongyo{
5703203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5704203945Sweongyo	int i;
5705203945Sweongyo	static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
5706203945Sweongyo	uint16_t ofdmrev;
5707203945Sweongyo
5708203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5709203945Sweongyo
5710203945Sweongyo	bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
5711203945Sweongyo
5712203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5713203945Sweongyo	if (phy->rev == 1)
5714203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5715203945Sweongyo	else if (phy->rev == 2) {
5716203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5717203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5718203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5719203945Sweongyo	} else {
5720203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5721203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5722203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5723203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5724203945Sweongyo	}
5725203945Sweongyo
5726203945Sweongyo	for (i = 0; i < 64; i++)
5727203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
5728203945Sweongyo
5729203945Sweongyo	/* XXX support PHY-A??? */
5730203945Sweongyo	if (phy->rev == 1)
5731203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5732203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5733203945Sweongyo			    bwn_tab_noise_g1[i]);
5734203945Sweongyo	else
5735203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5736203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5737203945Sweongyo			    bwn_tab_noise_g2[i]);
5738203945Sweongyo
5739203945Sweongyo	/* XXX support PHY-A??? */
5740203945Sweongyo	if (phy->rev >= 6) {
5741203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5742203945Sweongyo		    BWN_PHY_ENCORE_EN)
5743203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5744203945Sweongyo		else
5745203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5746203945Sweongyo	} else
5747203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5748203945Sweongyo
5749203945Sweongyo	for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
5750203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
5751203945Sweongyo		    bwn_tab_sigmasqr2[i]);
5752203945Sweongyo
5753203945Sweongyo	if (phy->rev == 1) {
5754203945Sweongyo		for (i = 0; i < 16; i++)
5755203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
5756203945Sweongyo			    0x0020);
5757203945Sweongyo	} else {
5758203945Sweongyo		for (i = 0; i < 32; i++)
5759203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5760203945Sweongyo	}
5761203945Sweongyo
5762203945Sweongyo	bwn_wa_agc(mac);
5763203945Sweongyo
5764203945Sweongyo	ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
5765203945Sweongyo	if (ofdmrev > 2) {
5766203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5767203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
5768203945Sweongyo		else
5769203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
5770203945Sweongyo	} else {
5771203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
5772203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
5773203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
5774203945Sweongyo	}
5775203945Sweongyo
5776203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
5777203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
5778203945Sweongyo}
5779203945Sweongyo
5780203945Sweongyostatic void
5781203945Sweongyobwn_wa_init(struct bwn_mac *mac)
5782203945Sweongyo{
5783203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5784203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
5785203945Sweongyo
5786203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5787203945Sweongyo
5788203945Sweongyo	switch (phy->rev) {
5789203945Sweongyo	case 1:
5790203945Sweongyo		bwn_wa_grev1(mac);
5791203945Sweongyo		break;
5792203945Sweongyo	case 2:
5793203945Sweongyo	case 6:
5794203945Sweongyo	case 7:
5795203945Sweongyo	case 8:
5796203945Sweongyo	case 9:
5797203945Sweongyo		bwn_wa_grev26789(mac);
5798203945Sweongyo		break;
5799203945Sweongyo	default:
5800203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5801203945Sweongyo	}
5802203945Sweongyo
5803203945Sweongyo	if (bus->siba_board_vendor != SIBA_BOARDVENDOR_BCM ||
5804203945Sweongyo	    bus->siba_board_type != SIBA_BOARD_BU4306 ||
5805203945Sweongyo	    bus->siba_board_rev != 0x17) {
5806203945Sweongyo		if (phy->rev < 2) {
5807203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
5808203945Sweongyo			    0x0002);
5809203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
5810203945Sweongyo			    0x0001);
5811203945Sweongyo		} else {
5812203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
5813203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
5814203945Sweongyo			if ((bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA) &&
5815203945Sweongyo			    (phy->rev >= 7)) {
5816203945Sweongyo				BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
5817203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5818203945Sweongyo				    0x0020, 0x0001);
5819203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5820203945Sweongyo				    0x0021, 0x0001);
5821203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5822203945Sweongyo				    0x0022, 0x0001);
5823203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5824203945Sweongyo				    0x0023, 0x0000);
5825203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5826203945Sweongyo				    0x0000, 0x0000);
5827203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5828203945Sweongyo				    0x0003, 0x0002);
5829203945Sweongyo			}
5830203945Sweongyo		}
5831203945Sweongyo	}
5832203945Sweongyo	if (bus->siba_sprom.bf_lo & BWN_BFL_FEM) {
5833203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
5834203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
5835203945Sweongyo	}
5836203945Sweongyo
5837203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
5838203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
5839203945Sweongyo}
5840203945Sweongyo
5841203945Sweongyostatic void
5842203945Sweongyobwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5843203945Sweongyo    uint16_t value)
5844203945Sweongyo{
5845203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5846203945Sweongyo	uint16_t addr;
5847203945Sweongyo
5848203945Sweongyo	addr = table + offset;
5849203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5850203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5851203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5852203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5853203945Sweongyo	}
5854203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5855203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5856203945Sweongyo}
5857203945Sweongyo
5858203945Sweongyostatic void
5859203945Sweongyobwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5860203945Sweongyo    uint32_t value)
5861203945Sweongyo{
5862203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5863203945Sweongyo	uint16_t addr;
5864203945Sweongyo
5865203945Sweongyo	addr = table + offset;
5866203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5867203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5868203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5869203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5870203945Sweongyo	}
5871203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5872203945Sweongyo
5873203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5874203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
5875203945Sweongyo}
5876203945Sweongyo
5877203945Sweongyostatic void
5878203945Sweongyobwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5879203945Sweongyo    uint16_t value)
5880203945Sweongyo{
5881203945Sweongyo
5882203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
5883203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
5884203945Sweongyo}
5885203945Sweongyo
5886203945Sweongyostatic void
5887203945Sweongyobwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
5888203945Sweongyo{
5889203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5890203945Sweongyo	unsigned int i, max_loop;
5891203945Sweongyo	uint16_t value;
5892203945Sweongyo	uint32_t buffer[5] = {
5893203945Sweongyo		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
5894203945Sweongyo	};
5895203945Sweongyo
5896203945Sweongyo	if (ofdm) {
5897203945Sweongyo		max_loop = 0x1e;
5898203945Sweongyo		buffer[0] = 0x000201cc;
5899203945Sweongyo	} else {
5900203945Sweongyo		max_loop = 0xfa;
5901203945Sweongyo		buffer[0] = 0x000b846e;
5902203945Sweongyo	}
5903203945Sweongyo
5904204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
5905203945Sweongyo
5906203945Sweongyo	for (i = 0; i < 5; i++)
5907203945Sweongyo		bwn_ram_write(mac, i * 4, buffer[i]);
5908203945Sweongyo
5909203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0000);
5910203945Sweongyo	BWN_WRITE_2(mac, 0x07c0,
5911203945Sweongyo	    (mac->mac_sd->sd_id.sd_rev < 11) ? 0x0000 : 0x0100);
5912203945Sweongyo	value = ((phy->type == BWN_PHYTYPE_A) ? 0x41 : 0x40);
5913203945Sweongyo	BWN_WRITE_2(mac, 0x050c, value);
5914203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5915203945Sweongyo		BWN_WRITE_2(mac, 0x0514, 0x1a02);
5916203945Sweongyo	BWN_WRITE_2(mac, 0x0508, 0x0000);
5917203945Sweongyo	BWN_WRITE_2(mac, 0x050a, 0x0000);
5918203945Sweongyo	BWN_WRITE_2(mac, 0x054c, 0x0000);
5919203945Sweongyo	BWN_WRITE_2(mac, 0x056a, 0x0014);
5920203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0826);
5921203945Sweongyo	BWN_WRITE_2(mac, 0x0500, 0x0000);
5922203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5923203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0050);
5924203945Sweongyo	else
5925203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0030);
5926203945Sweongyo
5927203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5928203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0017);
5929203945Sweongyo	for (i = 0x00; i < max_loop; i++) {
5930203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5931203945Sweongyo		if (value & 0x0080)
5932203945Sweongyo			break;
5933203945Sweongyo		DELAY(10);
5934203945Sweongyo	}
5935203945Sweongyo	for (i = 0x00; i < 0x0a; i++) {
5936203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5937203945Sweongyo		if (value & 0x0400)
5938203945Sweongyo			break;
5939203945Sweongyo		DELAY(10);
5940203945Sweongyo	}
5941203945Sweongyo	for (i = 0x00; i < 0x19; i++) {
5942203945Sweongyo		value = BWN_READ_2(mac, 0x0690);
5943203945Sweongyo		if (!(value & 0x0100))
5944203945Sweongyo			break;
5945203945Sweongyo		DELAY(10);
5946203945Sweongyo	}
5947203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5948203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0037);
5949203945Sweongyo}
5950203945Sweongyo
5951203945Sweongyostatic void
5952203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
5953203945Sweongyo{
5954203945Sweongyo	uint32_t macctl;
5955203945Sweongyo
5956203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
5957203945Sweongyo
5958203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
5959203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
5960203945Sweongyo		printf("TODO: need swap\n");
5961203945Sweongyo
5962203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
5963203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
5964203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
5965203945Sweongyo}
5966203945Sweongyo
5967203945Sweongyostatic void
5968203945Sweongyobwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
5969203945Sweongyo{
5970203945Sweongyo	uint16_t value;
5971203945Sweongyo
5972204242Simp	KASSERT(mac->mac_phy->type == BWN_PHYTYPE_G,
5973203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5974203945Sweongyo
5975203945Sweongyo	value = (uint8_t) (ctl->q);
5976203945Sweongyo	value |= ((uint8_t) (ctl->i)) << 8;
5977203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
5978203945Sweongyo}
5979203945Sweongyo
5980203945Sweongyostatic uint16_t
5981203945Sweongyobwn_lo_calcfeed(struct bwn_mac *mac,
5982203945Sweongyo    uint16_t lna, uint16_t pga, uint16_t trsw_rx)
5983203945Sweongyo{
5984203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5985203945Sweongyo	uint16_t rfover;
5986203945Sweongyo	uint16_t feedthrough;
5987203945Sweongyo
5988203945Sweongyo	if (phy->gmode) {
5989203945Sweongyo		lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
5990203945Sweongyo		pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
5991203945Sweongyo
5992203945Sweongyo		KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
5993203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5994203945Sweongyo		KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
5995203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5996203945Sweongyo
5997203945Sweongyo		trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
5998203945Sweongyo
5999203945Sweongyo		rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
6000203945Sweongyo		if ((mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA)
6001203945Sweongyo		    && phy->rev > 6)
6002203945Sweongyo			rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
6003203945Sweongyo
6004203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6005203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
6006203945Sweongyo		DELAY(10);
6007203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
6008203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
6009203945Sweongyo		DELAY(10);
6010203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
6011203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
6012203945Sweongyo		DELAY(10);
6013203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
6014203945Sweongyo	} else {
6015203945Sweongyo		pga |= BWN_PHY_PGACTL_UNKNOWN;
6016203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
6017203945Sweongyo		DELAY(10);
6018203945Sweongyo		pga |= BWN_PHY_PGACTL_LOWBANDW;
6019203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
6020203945Sweongyo		DELAY(10);
6021203945Sweongyo		pga |= BWN_PHY_PGACTL_LPF;
6022203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
6023203945Sweongyo	}
6024203945Sweongyo	DELAY(21);
6025203945Sweongyo	feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
6026203945Sweongyo
6027203945Sweongyo	return (feedthrough);
6028203945Sweongyo}
6029203945Sweongyo
6030203945Sweongyostatic uint16_t
6031203945Sweongyobwn_lo_txctl_regtable(struct bwn_mac *mac,
6032203945Sweongyo    uint16_t *value, uint16_t *pad_mix_gain)
6033203945Sweongyo{
6034203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6035203945Sweongyo	uint16_t reg, v, padmix;
6036203945Sweongyo
6037203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6038203945Sweongyo		v = 0x30;
6039203945Sweongyo		if (phy->rf_rev <= 5) {
6040203945Sweongyo			reg = 0x43;
6041203945Sweongyo			padmix = 0;
6042203945Sweongyo		} else {
6043203945Sweongyo			reg = 0x52;
6044203945Sweongyo			padmix = 5;
6045203945Sweongyo		}
6046203945Sweongyo	} else {
6047203945Sweongyo		if (phy->rev >= 2 && phy->rf_rev == 8) {
6048203945Sweongyo			reg = 0x43;
6049203945Sweongyo			v = 0x10;
6050203945Sweongyo			padmix = 2;
6051203945Sweongyo		} else {
6052203945Sweongyo			reg = 0x52;
6053203945Sweongyo			v = 0x30;
6054203945Sweongyo			padmix = 5;
6055203945Sweongyo		}
6056203945Sweongyo	}
6057203945Sweongyo	if (value)
6058203945Sweongyo		*value = v;
6059203945Sweongyo	if (pad_mix_gain)
6060203945Sweongyo		*pad_mix_gain = padmix;
6061203945Sweongyo
6062203945Sweongyo	return (reg);
6063203945Sweongyo}
6064203945Sweongyo
6065203945Sweongyostatic void
6066203945Sweongyobwn_lo_measure_txctl_values(struct bwn_mac *mac)
6067203945Sweongyo{
6068203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6069203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6070203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6071203945Sweongyo	uint16_t reg, mask;
6072203945Sweongyo	uint16_t trsw_rx, pga;
6073203945Sweongyo	uint16_t rf_pctl_reg;
6074203945Sweongyo
6075203945Sweongyo	static const uint8_t tx_bias_values[] = {
6076203945Sweongyo		0x09, 0x08, 0x0a, 0x01, 0x00,
6077203945Sweongyo		0x02, 0x05, 0x04, 0x06,
6078203945Sweongyo	};
6079203945Sweongyo	static const uint8_t tx_magn_values[] = {
6080203945Sweongyo		0x70, 0x40,
6081203945Sweongyo	};
6082203945Sweongyo
6083203945Sweongyo	if (!BWN_HAS_LOOPBACK(phy)) {
6084203945Sweongyo		rf_pctl_reg = 6;
6085203945Sweongyo		trsw_rx = 2;
6086203945Sweongyo		pga = 0;
6087203945Sweongyo	} else {
6088203945Sweongyo		int lb_gain;
6089203945Sweongyo
6090203945Sweongyo		trsw_rx = 0;
6091203945Sweongyo		lb_gain = pg->pg_max_lb_gain / 2;
6092203945Sweongyo		if (lb_gain > 10) {
6093203945Sweongyo			rf_pctl_reg = 0;
6094203945Sweongyo			pga = abs(10 - lb_gain) / 6;
6095203945Sweongyo			pga = MIN(MAX(pga, 0), 15);
6096203945Sweongyo		} else {
6097203945Sweongyo			int cmp_val;
6098203945Sweongyo			int tmp;
6099203945Sweongyo
6100203945Sweongyo			pga = 0;
6101203945Sweongyo			cmp_val = 0x24;
6102203945Sweongyo			if ((phy->rev >= 2) &&
6103203945Sweongyo			    (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
6104203945Sweongyo				cmp_val = 0x3c;
6105203945Sweongyo			tmp = lb_gain;
6106203945Sweongyo			if ((10 - lb_gain) < cmp_val)
6107203945Sweongyo				tmp = (10 - lb_gain);
6108203945Sweongyo			if (tmp < 0)
6109203945Sweongyo				tmp += 6;
6110203945Sweongyo			else
6111203945Sweongyo				tmp += 3;
6112203945Sweongyo			cmp_val /= 4;
6113203945Sweongyo			tmp /= 4;
6114203945Sweongyo			if (tmp >= cmp_val)
6115203945Sweongyo				rf_pctl_reg = cmp_val;
6116203945Sweongyo			else
6117203945Sweongyo				rf_pctl_reg = tmp;
6118203945Sweongyo		}
6119203945Sweongyo	}
6120203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
6121203945Sweongyo	bwn_phy_g_set_bbatt(mac, 2);
6122203945Sweongyo
6123203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
6124203945Sweongyo	mask = ~mask;
6125203945Sweongyo	BWN_RF_MASK(mac, reg, mask);
6126203945Sweongyo
6127203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
6128203945Sweongyo		int i, j;
6129203945Sweongyo		int feedthrough;
6130203945Sweongyo		int min_feedth = 0xffff;
6131203945Sweongyo		uint8_t tx_magn, tx_bias;
6132203945Sweongyo
6133203945Sweongyo		for (i = 0; i < N(tx_magn_values); i++) {
6134203945Sweongyo			tx_magn = tx_magn_values[i];
6135203945Sweongyo			BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
6136203945Sweongyo			for (j = 0; j < N(tx_bias_values); j++) {
6137203945Sweongyo				tx_bias = tx_bias_values[j];
6138203945Sweongyo				BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
6139203945Sweongyo				feedthrough = bwn_lo_calcfeed(mac, 0, pga,
6140203945Sweongyo				    trsw_rx);
6141203945Sweongyo				if (feedthrough < min_feedth) {
6142203945Sweongyo					lo->tx_bias = tx_bias;
6143203945Sweongyo					lo->tx_magn = tx_magn;
6144203945Sweongyo					min_feedth = feedthrough;
6145203945Sweongyo				}
6146203945Sweongyo				if (lo->tx_bias == 0)
6147203945Sweongyo					break;
6148203945Sweongyo			}
6149203945Sweongyo			BWN_RF_WRITE(mac, 0x52,
6150203945Sweongyo					  (BWN_RF_READ(mac, 0x52)
6151203945Sweongyo					   & 0xff00) | lo->tx_bias | lo->
6152203945Sweongyo					  tx_magn);
6153203945Sweongyo		}
6154203945Sweongyo	} else {
6155203945Sweongyo		lo->tx_magn = 0;
6156203945Sweongyo		lo->tx_bias = 0;
6157203945Sweongyo		BWN_RF_MASK(mac, 0x52, 0xfff0);
6158203945Sweongyo	}
6159203945Sweongyo
6160203945Sweongyo	BWN_GETTIME(lo->txctl_measured_time);
6161203945Sweongyo}
6162203945Sweongyo
6163203945Sweongyostatic void
6164203945Sweongyobwn_lo_get_powervector(struct bwn_mac *mac)
6165203945Sweongyo{
6166203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6167203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6168203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6169203945Sweongyo	int i;
6170203945Sweongyo	uint64_t tmp;
6171203945Sweongyo	uint64_t power_vector = 0;
6172203945Sweongyo
6173203945Sweongyo	for (i = 0; i < 8; i += 2) {
6174203945Sweongyo		tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
6175203945Sweongyo		power_vector |= (tmp << (i * 8));
6176203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
6177203945Sweongyo	}
6178203945Sweongyo	if (power_vector)
6179203945Sweongyo		lo->power_vector = power_vector;
6180203945Sweongyo
6181203945Sweongyo	BWN_GETTIME(lo->pwr_vec_read_time);
6182203945Sweongyo}
6183203945Sweongyo
6184203945Sweongyostatic void
6185203945Sweongyobwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
6186203945Sweongyo    int use_trsw_rx)
6187203945Sweongyo{
6188203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6189203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6190203945Sweongyo	uint16_t tmp;
6191203945Sweongyo
6192203945Sweongyo	if (max_rx_gain < 0)
6193203945Sweongyo		max_rx_gain = 0;
6194203945Sweongyo
6195203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
6196203945Sweongyo		int trsw_rx = 0;
6197203945Sweongyo		int trsw_rx_gain;
6198203945Sweongyo
6199203945Sweongyo		if (use_trsw_rx) {
6200203945Sweongyo			trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
6201203945Sweongyo			if (max_rx_gain >= trsw_rx_gain) {
6202203945Sweongyo				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
6203203945Sweongyo				trsw_rx = 0x20;
6204203945Sweongyo			}
6205203945Sweongyo		} else
6206203945Sweongyo			trsw_rx_gain = max_rx_gain;
6207203945Sweongyo		if (trsw_rx_gain < 9) {
6208203945Sweongyo			pg->pg_lna_lod_gain = 0;
6209203945Sweongyo		} else {
6210203945Sweongyo			pg->pg_lna_lod_gain = 1;
6211203945Sweongyo			trsw_rx_gain -= 8;
6212203945Sweongyo		}
6213203945Sweongyo		trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
6214203945Sweongyo		pg->pg_pga_gain = trsw_rx_gain / 3;
6215203945Sweongyo		if (pg->pg_pga_gain >= 5) {
6216203945Sweongyo			pg->pg_pga_gain -= 5;
6217203945Sweongyo			pg->pg_lna_gain = 2;
6218203945Sweongyo		} else
6219203945Sweongyo			pg->pg_lna_gain = 0;
6220203945Sweongyo	} else {
6221203945Sweongyo		pg->pg_lna_gain = 0;
6222203945Sweongyo		pg->pg_trsw_rx_gain = 0x20;
6223203945Sweongyo		if (max_rx_gain >= 0x14) {
6224203945Sweongyo			pg->pg_lna_lod_gain = 1;
6225203945Sweongyo			pg->pg_pga_gain = 2;
6226203945Sweongyo		} else if (max_rx_gain >= 0x12) {
6227203945Sweongyo			pg->pg_lna_lod_gain = 1;
6228203945Sweongyo			pg->pg_pga_gain = 1;
6229203945Sweongyo		} else if (max_rx_gain >= 0xf) {
6230203945Sweongyo			pg->pg_lna_lod_gain = 1;
6231203945Sweongyo			pg->pg_pga_gain = 0;
6232203945Sweongyo		} else {
6233203945Sweongyo			pg->pg_lna_lod_gain = 0;
6234203945Sweongyo			pg->pg_pga_gain = 0;
6235203945Sweongyo		}
6236203945Sweongyo	}
6237203945Sweongyo
6238203945Sweongyo	tmp = BWN_RF_READ(mac, 0x7a);
6239203945Sweongyo	if (pg->pg_lna_lod_gain == 0)
6240203945Sweongyo		tmp &= ~0x0008;
6241203945Sweongyo	else
6242203945Sweongyo		tmp |= 0x0008;
6243203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, tmp);
6244203945Sweongyo}
6245203945Sweongyo
6246203945Sweongyostatic void
6247203945Sweongyobwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6248203945Sweongyo{
6249203945Sweongyo	struct siba_sprom *sprom = &mac->mac_sd->sd_bus->siba_sprom;
6250203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6251203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6252203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6253203945Sweongyo	struct timespec ts;
6254203945Sweongyo	uint16_t tmp;
6255203945Sweongyo
6256203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6257203945Sweongyo		sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
6258203945Sweongyo		sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
6259203945Sweongyo		sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6260203945Sweongyo		sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
6261203945Sweongyo		sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
6262203945Sweongyo
6263203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
6264203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
6265203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
6266203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
6267203945Sweongyo	}
6268203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6269203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
6270203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
6271203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
6272203945Sweongyo	}
6273203945Sweongyo	if (phy->rev >= 2) {
6274203945Sweongyo		sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
6275203945Sweongyo		sav->phy_analogoverval =
6276203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
6277203945Sweongyo		sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
6278203945Sweongyo		sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
6279203945Sweongyo		sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
6280203945Sweongyo		sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
6281203945Sweongyo		sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
6282203945Sweongyo
6283203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
6284203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
6285203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
6286203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
6287203945Sweongyo		if (phy->type == BWN_PHYTYPE_G) {
6288203945Sweongyo			if ((phy->rev >= 7) &&
6289203945Sweongyo			    (sprom->bf_lo & BWN_BFL_EXTLNA)) {
6290203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
6291203945Sweongyo			} else {
6292203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
6293203945Sweongyo			}
6294203945Sweongyo		} else {
6295203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
6296203945Sweongyo		}
6297203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
6298203945Sweongyo	}
6299203945Sweongyo	sav->reg0 = BWN_READ_2(mac, 0x3f4);
6300203945Sweongyo	sav->reg1 = BWN_READ_2(mac, 0x3e2);
6301203945Sweongyo	sav->rf0 = BWN_RF_READ(mac, 0x43);
6302203945Sweongyo	sav->rf1 = BWN_RF_READ(mac, 0x7a);
6303203945Sweongyo	sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
6304203945Sweongyo	sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
6305203945Sweongyo	sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
6306203945Sweongyo	sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6307203945Sweongyo
6308203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6309203945Sweongyo		sav->rf2 = BWN_RF_READ(mac, 0x52);
6310203945Sweongyo		sav->rf2 &= 0x00f0;
6311203945Sweongyo	}
6312203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6313203945Sweongyo		sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
6314203945Sweongyo		sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
6315203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
6316203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
6317203945Sweongyo	} else {
6318203945Sweongyo		BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
6319203945Sweongyo			    | 0x8000);
6320203945Sweongyo	}
6321203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
6322203945Sweongyo		    & 0xf000);
6323203945Sweongyo
6324203945Sweongyo	tmp =
6325203945Sweongyo	    (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
6326203945Sweongyo	BWN_PHY_WRITE(mac, tmp, 0x007f);
6327203945Sweongyo
6328203945Sweongyo	tmp = sav->phy_syncctl;
6329203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
6330203945Sweongyo	tmp = sav->rf1;
6331203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
6332203945Sweongyo
6333203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
6334203945Sweongyo	if (phy->type == BWN_PHYTYPE_G ||
6335203945Sweongyo	    (phy->type == BWN_PHYTYPE_B &&
6336203945Sweongyo	     phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
6337203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
6338203945Sweongyo	} else
6339203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
6340203945Sweongyo	if (phy->rev >= 2)
6341203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
6342203945Sweongyo	bwn_phy_g_switch_chan(mac, 6, 0);
6343203945Sweongyo	BWN_RF_READ(mac, 0x51);
6344203945Sweongyo	if (phy->type == BWN_PHYTYPE_G)
6345203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
6346203945Sweongyo
6347203945Sweongyo	nanouptime(&ts);
6348203945Sweongyo	if (time_before(lo->txctl_measured_time,
6349203945Sweongyo	    (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
6350203945Sweongyo		bwn_lo_measure_txctl_values(mac);
6351203945Sweongyo
6352203945Sweongyo	if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
6353203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
6354203945Sweongyo	else {
6355203945Sweongyo		if (phy->type == BWN_PHYTYPE_B)
6356203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6357203945Sweongyo		else
6358203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
6359203945Sweongyo	}
6360203945Sweongyo}
6361203945Sweongyo
6362203945Sweongyostatic void
6363203945Sweongyobwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6364203945Sweongyo{
6365203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6366203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6367203945Sweongyo	uint16_t tmp;
6368203945Sweongyo
6369203945Sweongyo	if (phy->rev >= 2) {
6370203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6371203945Sweongyo		tmp = (pg->pg_pga_gain << 8);
6372203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
6373203945Sweongyo		DELAY(5);
6374203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
6375203945Sweongyo		DELAY(2);
6376203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
6377203945Sweongyo	} else {
6378203945Sweongyo		tmp = (pg->pg_pga_gain | 0xefa0);
6379203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
6380203945Sweongyo	}
6381203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
6382203945Sweongyo		if (phy->rev >= 3)
6383203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
6384203945Sweongyo		else
6385203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6386203945Sweongyo		if (phy->rev >= 2)
6387203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
6388203945Sweongyo		else
6389203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
6390203945Sweongyo	}
6391203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, sav->reg0);
6392203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
6393203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
6394203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
6395203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
6396203945Sweongyo	BWN_RF_WRITE(mac, 0x43, sav->rf0);
6397203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, sav->rf1);
6398203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6399203945Sweongyo		tmp = sav->rf2;
6400203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
6401203945Sweongyo	}
6402203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, sav->reg1);
6403203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6404203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
6405203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
6406203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
6407203945Sweongyo	}
6408203945Sweongyo	if (phy->rev >= 2) {
6409203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
6410203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
6411203945Sweongyo			      sav->phy_analogoverval);
6412203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
6413203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
6414203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
6415203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
6416203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
6417203945Sweongyo	}
6418203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6419203945Sweongyo		tmp = (sav->phy_lomask & 0xbfff);
6420203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
6421203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
6422203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
6423203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
6424203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
6425203945Sweongyo	}
6426203945Sweongyo	bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
6427203945Sweongyo}
6428203945Sweongyo
6429203945Sweongyostatic int
6430203945Sweongyobwn_lo_probe_loctl(struct bwn_mac *mac,
6431203945Sweongyo    struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
6432203945Sweongyo{
6433203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6434203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6435203945Sweongyo	struct bwn_loctl orig, test;
6436203945Sweongyo	struct bwn_loctl prev = { -100, -100 };
6437203945Sweongyo	static const struct bwn_loctl modifiers[] = {
6438203945Sweongyo		{  1,  1,}, {  1,  0,}, {  1, -1,}, {  0, -1,},
6439203945Sweongyo		{ -1, -1,}, { -1,  0,}, { -1,  1,}, {  0,  1,}
6440203945Sweongyo	};
6441203945Sweongyo	int begin, end, lower = 0, i;
6442203945Sweongyo	uint16_t feedth;
6443203945Sweongyo
6444203945Sweongyo	if (d->curstate == 0) {
6445203945Sweongyo		begin = 1;
6446203945Sweongyo		end = 8;
6447203945Sweongyo	} else if (d->curstate % 2 == 0) {
6448203945Sweongyo		begin = d->curstate - 1;
6449203945Sweongyo		end = d->curstate + 1;
6450203945Sweongyo	} else {
6451203945Sweongyo		begin = d->curstate - 2;
6452203945Sweongyo		end = d->curstate + 2;
6453203945Sweongyo	}
6454203945Sweongyo	if (begin < 1)
6455203945Sweongyo		begin += 8;
6456203945Sweongyo	if (end > 8)
6457203945Sweongyo		end -= 8;
6458203945Sweongyo
6459203945Sweongyo	memcpy(&orig, probe, sizeof(struct bwn_loctl));
6460203945Sweongyo	i = begin;
6461203945Sweongyo	d->curstate = i;
6462203945Sweongyo	while (1) {
6463203945Sweongyo		KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
6464203945Sweongyo		memcpy(&test, &orig, sizeof(struct bwn_loctl));
6465203945Sweongyo		test.i += modifiers[i - 1].i * d->multipler;
6466203945Sweongyo		test.q += modifiers[i - 1].q * d->multipler;
6467203945Sweongyo		if ((test.i != prev.i || test.q != prev.q) &&
6468203945Sweongyo		    (abs(test.i) <= 16 && abs(test.q) <= 16)) {
6469203945Sweongyo			bwn_lo_write(mac, &test);
6470203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6471203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6472203945Sweongyo			if (feedth < d->feedth) {
6473203945Sweongyo				memcpy(probe, &test,
6474203945Sweongyo				    sizeof(struct bwn_loctl));
6475203945Sweongyo				lower = 1;
6476203945Sweongyo				d->feedth = feedth;
6477203945Sweongyo				if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
6478203945Sweongyo					break;
6479203945Sweongyo			}
6480203945Sweongyo		}
6481203945Sweongyo		memcpy(&prev, &test, sizeof(prev));
6482203945Sweongyo		if (i == end)
6483203945Sweongyo			break;
6484203945Sweongyo		if (i == 8)
6485203945Sweongyo			i = 1;
6486203945Sweongyo		else
6487203945Sweongyo			i++;
6488203945Sweongyo		d->curstate = i;
6489203945Sweongyo	}
6490203945Sweongyo
6491203945Sweongyo	return (lower);
6492203945Sweongyo}
6493203945Sweongyo
6494203945Sweongyostatic void
6495203945Sweongyobwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
6496203945Sweongyo{
6497203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6498203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6499203945Sweongyo	struct bwn_lo_g_sm d;
6500203945Sweongyo	struct bwn_loctl probe;
6501203945Sweongyo	int lower, repeat, cnt = 0;
6502203945Sweongyo	uint16_t feedth;
6503203945Sweongyo
6504203945Sweongyo	d.nmeasure = 0;
6505203945Sweongyo	d.multipler = 1;
6506203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6507203945Sweongyo		d.multipler = 3;
6508203945Sweongyo
6509203945Sweongyo	memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
6510203945Sweongyo	repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
6511203945Sweongyo
6512203945Sweongyo	do {
6513203945Sweongyo		bwn_lo_write(mac, &d.loctl);
6514203945Sweongyo		feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6515203945Sweongyo		    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6516203945Sweongyo		if (feedth < 0x258) {
6517203945Sweongyo			if (feedth >= 0x12c)
6518203945Sweongyo				*rxgain += 6;
6519203945Sweongyo			else
6520203945Sweongyo				*rxgain += 3;
6521203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6522203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6523203945Sweongyo		}
6524203945Sweongyo		d.feedth = feedth;
6525203945Sweongyo		d.curstate = 0;
6526203945Sweongyo		do {
6527203945Sweongyo			KASSERT(d.curstate >= 0 && d.curstate <= 8,
6528203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
6529203945Sweongyo			memcpy(&probe, &d.loctl,
6530203945Sweongyo			       sizeof(struct bwn_loctl));
6531203945Sweongyo			lower = bwn_lo_probe_loctl(mac, &probe, &d);
6532203945Sweongyo			if (!lower)
6533203945Sweongyo				break;
6534203945Sweongyo			if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
6535203945Sweongyo				break;
6536203945Sweongyo			memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
6537203945Sweongyo			d.nmeasure++;
6538203945Sweongyo		} while (d.nmeasure < 24);
6539203945Sweongyo		memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
6540203945Sweongyo
6541203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
6542203945Sweongyo			if (d.feedth > 0x1194)
6543203945Sweongyo				*rxgain -= 6;
6544203945Sweongyo			else if (d.feedth < 0x5dc)
6545203945Sweongyo				*rxgain += 3;
6546203945Sweongyo			if (cnt == 0) {
6547203945Sweongyo				if (d.feedth <= 0x5dc) {
6548203945Sweongyo					d.multipler = 1;
6549203945Sweongyo					cnt++;
6550203945Sweongyo				} else
6551203945Sweongyo					d.multipler = 2;
6552203945Sweongyo			} else if (cnt == 2)
6553203945Sweongyo				d.multipler = 1;
6554203945Sweongyo		}
6555203945Sweongyo		bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
6556203945Sweongyo	} while (++cnt < repeat);
6557203945Sweongyo}
6558203945Sweongyo
6559203945Sweongyostatic struct bwn_lo_calib *
6560203945Sweongyobwn_lo_calibset(struct bwn_mac *mac,
6561203945Sweongyo    const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
6562203945Sweongyo{
6563203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6564203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6565203945Sweongyo	struct bwn_loctl loctl = { 0, 0 };
6566203945Sweongyo	struct bwn_lo_calib *cal;
6567204242Simp	struct bwn_lo_g_value sval = { 0 };
6568203945Sweongyo	int rxgain;
6569203945Sweongyo	uint16_t pad, reg, value;
6570203945Sweongyo
6571203945Sweongyo	sval.old_channel = phy->chan;
6572203945Sweongyo	bwn_mac_suspend(mac);
6573203945Sweongyo	bwn_lo_save(mac, &sval);
6574203945Sweongyo
6575203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &value, &pad);
6576203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
6577203945Sweongyo	BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
6578203945Sweongyo
6579203945Sweongyo	rxgain = (rfatt->att * 2) + (bbatt->att / 2);
6580203945Sweongyo	if (rfatt->padmix)
6581203945Sweongyo		rxgain -= pad;
6582203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6583203945Sweongyo		rxgain += pg->pg_max_lb_gain;
6584203945Sweongyo	bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
6585203945Sweongyo	bwn_phy_g_set_bbatt(mac, bbatt->att);
6586203945Sweongyo	bwn_lo_probe_sm(mac, &loctl, &rxgain);
6587203945Sweongyo
6588203945Sweongyo	bwn_lo_restore(mac, &sval);
6589203945Sweongyo	bwn_mac_enable(mac);
6590203945Sweongyo
6591203945Sweongyo	cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
6592203945Sweongyo	if (!cal) {
6593203945Sweongyo		device_printf(mac->mac_sc->sc_dev, "out of memory\n");
6594203945Sweongyo		return (NULL);
6595203945Sweongyo	}
6596203945Sweongyo	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
6597203945Sweongyo	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
6598203945Sweongyo	memcpy(&cal->ctl, &loctl, sizeof(loctl));
6599203945Sweongyo
6600203945Sweongyo	BWN_GETTIME(cal->calib_time);
6601203945Sweongyo
6602203945Sweongyo	return (cal);
6603203945Sweongyo}
6604203945Sweongyo
6605203945Sweongyostatic struct bwn_lo_calib *
6606203945Sweongyobwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
6607203945Sweongyo    const struct bwn_rfatt *rfatt)
6608203945Sweongyo{
6609203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
6610203945Sweongyo	struct bwn_lo_calib *c;
6611203945Sweongyo
6612203945Sweongyo	TAILQ_FOREACH(c, &lo->calib_list, list) {
6613203945Sweongyo		if (!BWN_BBATTCMP(&c->bbatt, bbatt))
6614203945Sweongyo			continue;
6615203945Sweongyo		if (!BWN_RFATTCMP(&c->rfatt, rfatt))
6616203945Sweongyo			continue;
6617203945Sweongyo		return (c);
6618203945Sweongyo	}
6619203945Sweongyo
6620203945Sweongyo	c = bwn_lo_calibset(mac, bbatt, rfatt);
6621203945Sweongyo	if (!c)
6622203945Sweongyo		return (NULL);
6623203945Sweongyo	TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
6624203945Sweongyo
6625203945Sweongyo	return (c);
6626203945Sweongyo}
6627203945Sweongyo
6628203945Sweongyostatic void
6629203945Sweongyobwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
6630203945Sweongyo{
6631203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6632203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6633203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6634203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6635203945Sweongyo	const struct bwn_rfatt *rfatt;
6636203945Sweongyo	const struct bwn_bbatt *bbatt;
6637203945Sweongyo	uint64_t pvector;
6638203945Sweongyo	int i;
6639203945Sweongyo	int rf_offset, bb_offset;
6640203945Sweongyo	uint8_t changed = 0;
6641203945Sweongyo
6642203945Sweongyo	KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
6643203945Sweongyo	KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
6644203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6645203945Sweongyo
6646203945Sweongyo	pvector = lo->power_vector;
6647203945Sweongyo	if (!update && !pvector)
6648203945Sweongyo		return;
6649203945Sweongyo
6650203945Sweongyo	bwn_mac_suspend(mac);
6651203945Sweongyo
6652203945Sweongyo	for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
6653203945Sweongyo		struct bwn_lo_calib *cal;
6654203945Sweongyo		int idx;
6655203945Sweongyo		uint16_t val;
6656203945Sweongyo
6657203945Sweongyo		if (!update && !(pvector & (((uint64_t)1ULL) << i)))
6658203945Sweongyo			continue;
6659203945Sweongyo		bb_offset = i / lo->rfatt.len;
6660203945Sweongyo		rf_offset = i % lo->rfatt.len;
6661203945Sweongyo		bbatt = &(lo->bbatt.array[bb_offset]);
6662203945Sweongyo		rfatt = &(lo->rfatt.array[rf_offset]);
6663203945Sweongyo
6664203945Sweongyo		cal = bwn_lo_calibset(mac, bbatt, rfatt);
6665203945Sweongyo		if (!cal) {
6666203945Sweongyo			device_printf(sc->sc_dev, "LO: Could not "
6667203945Sweongyo			    "calibrate DC table entry\n");
6668203945Sweongyo			continue;
6669203945Sweongyo		}
6670203945Sweongyo		val = (uint8_t)(cal->ctl.q);
6671203945Sweongyo		val |= ((uint8_t)(cal->ctl.i)) << 4;
6672203945Sweongyo		free(cal, M_DEVBUF);
6673203945Sweongyo
6674203945Sweongyo		idx = i / 2;
6675203945Sweongyo		if (i % 2)
6676203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
6677203945Sweongyo			    | ((val & 0x00ff) << 8);
6678203945Sweongyo		else
6679203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
6680203945Sweongyo			    | (val & 0x00ff);
6681203945Sweongyo		changed = 1;
6682203945Sweongyo	}
6683203945Sweongyo	if (changed) {
6684203945Sweongyo		for (i = 0; i < BWN_DC_LT_SIZE; i++)
6685203945Sweongyo			BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
6686203945Sweongyo	}
6687203945Sweongyo	bwn_mac_enable(mac);
6688203945Sweongyo}
6689203945Sweongyo
6690203945Sweongyostatic void
6691203945Sweongyobwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
6692203945Sweongyo{
6693203945Sweongyo
6694203945Sweongyo	if (!rf->padmix)
6695203945Sweongyo		return;
6696203945Sweongyo	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
6697203945Sweongyo		rf->att = 4;
6698203945Sweongyo}
6699203945Sweongyo
6700203945Sweongyostatic void
6701203945Sweongyobwn_lo_g_adjust(struct bwn_mac *mac)
6702203945Sweongyo{
6703203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
6704203945Sweongyo	struct bwn_lo_calib *cal;
6705203945Sweongyo	struct bwn_rfatt rf;
6706203945Sweongyo
6707203945Sweongyo	memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
6708203945Sweongyo	bwn_lo_fixup_rfatt(&rf);
6709203945Sweongyo
6710203945Sweongyo	cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
6711203945Sweongyo	if (!cal)
6712203945Sweongyo		return;
6713203945Sweongyo	bwn_lo_write(mac, &cal->ctl);
6714203945Sweongyo}
6715203945Sweongyo
6716203945Sweongyostatic void
6717203945Sweongyobwn_lo_g_init(struct bwn_mac *mac)
6718203945Sweongyo{
6719203945Sweongyo
6720203945Sweongyo	if (!bwn_has_hwpctl(mac))
6721203945Sweongyo		return;
6722203945Sweongyo
6723203945Sweongyo	bwn_lo_get_powervector(mac);
6724203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
6725203945Sweongyo}
6726203945Sweongyo
6727203945Sweongyostatic void
6728203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
6729203945Sweongyo{
6730203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6731203945Sweongyo	int i;
6732203945Sweongyo	uint32_t tmp;
6733203945Sweongyo
6734203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6735203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6736203945Sweongyo
6737203945Sweongyo	if (mac->mac_suspended == 0) {
6738203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
6739203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6740203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
6741203945Sweongyo			    & ~BWN_MACCTL_ON);
6742203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6743203945Sweongyo		for (i = 35; i; i--) {
6744203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6745203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6746203945Sweongyo				goto out;
6747203945Sweongyo			DELAY(10);
6748203945Sweongyo		}
6749203945Sweongyo		for (i = 40; i; i--) {
6750203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6751203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6752203945Sweongyo				goto out;
6753203945Sweongyo			DELAY(1000);
6754203945Sweongyo		}
6755203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
6756203945Sweongyo	}
6757203945Sweongyoout:
6758203945Sweongyo	mac->mac_suspended++;
6759203945Sweongyo}
6760203945Sweongyo
6761203945Sweongyostatic void
6762203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
6763203945Sweongyo{
6764203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6765203945Sweongyo	uint16_t state;
6766203945Sweongyo
6767203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
6768203945Sweongyo	    BWN_SHARED_UCODESTAT);
6769203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
6770203945Sweongyo	    state != BWN_SHARED_UCODESTAT_SLEEP)
6771203945Sweongyo		device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
6772203945Sweongyo
6773203945Sweongyo	mac->mac_suspended--;
6774203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6775203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6776203945Sweongyo	if (mac->mac_suspended == 0) {
6777203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6778203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
6779203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
6780203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6781203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
6782203945Sweongyo		bwn_psctl(mac, 0);
6783203945Sweongyo	}
6784203945Sweongyo}
6785203945Sweongyo
6786203945Sweongyostatic void
6787203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
6788203945Sweongyo{
6789203945Sweongyo	int i;
6790203945Sweongyo	uint16_t ucstat;
6791203945Sweongyo
6792203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
6793203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6794203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
6795203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6796203945Sweongyo
6797203945Sweongyo	/* XXX forcibly awake and hwps-off */
6798203945Sweongyo
6799203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
6800203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
6801203945Sweongyo	    ~BWN_MACCTL_HWPS);
6802203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
6803203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 5) {
6804203945Sweongyo		for (i = 0; i < 100; i++) {
6805203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
6806203945Sweongyo			    BWN_SHARED_UCODESTAT);
6807203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
6808203945Sweongyo				break;
6809203945Sweongyo			DELAY(10);
6810203945Sweongyo		}
6811203945Sweongyo	}
6812203945Sweongyo}
6813203945Sweongyo
6814203945Sweongyostatic int16_t
6815203945Sweongyobwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
6816203945Sweongyo{
6817203945Sweongyo
6818203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
6819203945Sweongyo	return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
6820203945Sweongyo}
6821203945Sweongyo
6822203945Sweongyostatic void
6823203945Sweongyobwn_nrssi_threshold(struct bwn_mac *mac)
6824203945Sweongyo{
6825203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6826203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6827203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
6828203945Sweongyo	int32_t a, b;
6829203945Sweongyo	int16_t tmp16;
6830203945Sweongyo	uint16_t tmpu16;
6831203945Sweongyo
6832203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
6833203945Sweongyo
6834203945Sweongyo	if (phy->gmode && (siba->siba_sprom.bf_lo & BWN_BFL_RSSI)) {
6835203945Sweongyo		if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
6836203945Sweongyo			a = 0x13;
6837203945Sweongyo			b = 0x12;
6838203945Sweongyo		} else {
6839203945Sweongyo			a = 0xe;
6840203945Sweongyo			b = 0x11;
6841203945Sweongyo		}
6842203945Sweongyo
6843203945Sweongyo		a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6844203945Sweongyo		a += (pg->pg_nrssi[0] << 6);
6845203945Sweongyo		a += (a < 32) ? 31 : 32;
6846203945Sweongyo		a = a >> 6;
6847203945Sweongyo		a = MIN(MAX(a, -31), 31);
6848203945Sweongyo
6849203945Sweongyo		b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6850203945Sweongyo		b += (pg->pg_nrssi[0] << 6);
6851203945Sweongyo		if (b < 32)
6852203945Sweongyo			b += 31;
6853203945Sweongyo		else
6854203945Sweongyo			b += 32;
6855203945Sweongyo		b = b >> 6;
6856203945Sweongyo		b = MIN(MAX(b, -31), 31);
6857203945Sweongyo
6858203945Sweongyo		tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
6859203945Sweongyo		tmpu16 |= ((uint32_t)b & 0x0000003f);
6860203945Sweongyo		tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
6861203945Sweongyo		BWN_PHY_WRITE(mac, 0x048a, tmpu16);
6862203945Sweongyo		return;
6863203945Sweongyo	}
6864203945Sweongyo
6865203945Sweongyo	tmp16 = bwn_nrssi_read(mac, 0x20);
6866203945Sweongyo	if (tmp16 >= 0x20)
6867203945Sweongyo		tmp16 -= 0x40;
6868203945Sweongyo	BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
6869203945Sweongyo}
6870203945Sweongyo
6871203945Sweongyostatic void
6872203945Sweongyobwn_nrssi_slope_11g(struct bwn_mac *mac)
6873203945Sweongyo{
6874203945Sweongyo#define	SAVE_RF_MAX		3
6875203945Sweongyo#define	SAVE_PHY_COMM_MAX	4
6876203945Sweongyo#define	SAVE_PHY3_MAX		8
6877203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6878203945Sweongyo		{ 0x7a, 0x52, 0x43 };
6879203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
6880203945Sweongyo		{ 0x15, 0x5a, 0x59, 0x58 };
6881203945Sweongyo	static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
6882203945Sweongyo		0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
6883203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6884203945Sweongyo	};
6885203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6886203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6887203945Sweongyo	int32_t i, tmp32, phy3_idx = 0;
6888203945Sweongyo	uint16_t delta, tmp;
6889203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6890203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6891203945Sweongyo	uint16_t save_phy3[SAVE_PHY3_MAX];
6892203945Sweongyo	uint16_t ant_div, phy0, chan_ex;
6893203945Sweongyo	int16_t nrssi0, nrssi1;
6894203945Sweongyo
6895203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
6896203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6897203945Sweongyo
6898203945Sweongyo	if (phy->rf_rev >= 9)
6899203945Sweongyo		return;
6900203945Sweongyo	if (phy->rf_rev == 8)
6901203945Sweongyo		bwn_nrssi_offset(mac);
6902203945Sweongyo
6903203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
6904203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, 0xfffc);
6905203945Sweongyo
6906203945Sweongyo	/*
6907203945Sweongyo	 * Save RF/PHY registers for later restoration
6908203945Sweongyo	 */
6909203945Sweongyo	ant_div = BWN_READ_2(mac, 0x03e2);
6910203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
6911203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6912203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6913203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6914203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6915203945Sweongyo
6916203945Sweongyo	phy0 = BWN_READ_2(mac, BWN_PHY0);
6917203945Sweongyo	chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
6918203945Sweongyo	if (phy->rev >= 3) {
6919203945Sweongyo		for (i = 0; i < SAVE_PHY3_MAX; ++i)
6920203945Sweongyo			save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
6921203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6922203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
6923203945Sweongyo		switch (phy->rev) {
6924203945Sweongyo		case 4:
6925203945Sweongyo		case 6:
6926203945Sweongyo		case 7:
6927203945Sweongyo			BWN_PHY_SET(mac, 0x0478, 0x0100);
6928203945Sweongyo			BWN_PHY_SET(mac, 0x0801, 0x0040);
6929203945Sweongyo			break;
6930203945Sweongyo		case 3:
6931203945Sweongyo		case 5:
6932203945Sweongyo			BWN_PHY_MASK(mac, 0x0801, 0xffbf);
6933203945Sweongyo			break;
6934203945Sweongyo		}
6935203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
6936203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
6937203945Sweongyo	}
6938203945Sweongyo	/*
6939203945Sweongyo	 * Calculate nrssi0
6940203945Sweongyo	 */
6941203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
6942203945Sweongyo	bwn_set_all_gains(mac, 0, 8, 0);
6943203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x00f7);
6944203945Sweongyo	if (phy->rev >= 2) {
6945203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
6946203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
6947203945Sweongyo	}
6948203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
6949203945Sweongyo	DELAY(20);
6950203945Sweongyo
6951203945Sweongyo	nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6952203945Sweongyo	if (nrssi0 >= 0x0020)
6953203945Sweongyo		nrssi0 -= 0x0040;
6954203945Sweongyo
6955203945Sweongyo	/*
6956203945Sweongyo	 * Calculate nrssi1
6957203945Sweongyo	 */
6958203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x007f);
6959203945Sweongyo	if (phy->rev >= 2)
6960203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
6961203945Sweongyo
6962203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
6963203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
6964203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x000f);
6965203945Sweongyo	BWN_PHY_WRITE(mac, 0x0015, 0xf330);
6966203945Sweongyo	if (phy->rev >= 2) {
6967203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
6968203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
6969203945Sweongyo	}
6970203945Sweongyo
6971203945Sweongyo	bwn_set_all_gains(mac, 3, 0, 1);
6972203945Sweongyo	if (phy->rf_rev == 8) {
6973203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, 0x001f);
6974203945Sweongyo	} else {
6975203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
6976203945Sweongyo		BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
6977203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
6978203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
6979203945Sweongyo	}
6980203945Sweongyo	BWN_PHY_WRITE(mac, 0x005a, 0x0480);
6981203945Sweongyo	BWN_PHY_WRITE(mac, 0x0059, 0x0810);
6982203945Sweongyo	BWN_PHY_WRITE(mac, 0x0058, 0x000d);
6983203945Sweongyo	DELAY(20);
6984203945Sweongyo	nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6985203945Sweongyo
6986203945Sweongyo	/*
6987203945Sweongyo	 * Install calculated narrow RSSI values
6988203945Sweongyo	 */
6989203945Sweongyo	if (nrssi1 >= 0x0020)
6990203945Sweongyo		nrssi1 -= 0x0040;
6991203945Sweongyo	if (nrssi0 == nrssi1)
6992203945Sweongyo		pg->pg_nrssi_slope = 0x00010000;
6993203945Sweongyo	else
6994203945Sweongyo		pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
6995203945Sweongyo	if (nrssi0 >= -4) {
6996203945Sweongyo		pg->pg_nrssi[0] = nrssi1;
6997203945Sweongyo		pg->pg_nrssi[1] = nrssi0;
6998203945Sweongyo	}
6999203945Sweongyo
7000203945Sweongyo	/*
7001203945Sweongyo	 * Restore saved RF/PHY registers
7002203945Sweongyo	 */
7003203945Sweongyo	if (phy->rev >= 3) {
7004203945Sweongyo		for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
7005203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
7006203945Sweongyo			    save_phy3[phy3_idx]);
7007203945Sweongyo		}
7008203945Sweongyo	}
7009203945Sweongyo	if (phy->rev >= 2) {
7010203945Sweongyo		BWN_PHY_MASK(mac, 0x0812, 0xffcf);
7011203945Sweongyo		BWN_PHY_MASK(mac, 0x0811, 0xffcf);
7012203945Sweongyo	}
7013203945Sweongyo
7014203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
7015203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
7016203945Sweongyo
7017203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, ant_div);
7018203945Sweongyo	BWN_WRITE_2(mac, 0x03e6, phy0);
7019203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
7020203945Sweongyo
7021203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
7022203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
7023203945Sweongyo
7024203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
7025203945Sweongyo	BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
7026203945Sweongyo	bwn_set_original_gains(mac);
7027203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
7028203945Sweongyo	if (phy->rev >= 3) {
7029203945Sweongyo		for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
7030203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
7031203945Sweongyo			    save_phy3[phy3_idx]);
7032203945Sweongyo		}
7033203945Sweongyo	}
7034203945Sweongyo
7035203945Sweongyo	delta = 0x1f - pg->pg_nrssi[0];
7036203945Sweongyo	for (i = 0; i < 64; i++) {
7037203945Sweongyo		tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
7038203945Sweongyo		tmp32 = MIN(MAX(tmp32, 0), 0x3f);
7039203945Sweongyo		pg->pg_nrssi_lt[i] = tmp32;
7040203945Sweongyo	}
7041203945Sweongyo
7042203945Sweongyo	bwn_nrssi_threshold(mac);
7043203945Sweongyo#undef SAVE_RF_MAX
7044203945Sweongyo#undef SAVE_PHY_COMM_MAX
7045203945Sweongyo#undef SAVE_PHY3_MAX
7046203945Sweongyo}
7047203945Sweongyo
7048203945Sweongyostatic void
7049203945Sweongyobwn_nrssi_offset(struct bwn_mac *mac)
7050203945Sweongyo{
7051203945Sweongyo#define	SAVE_RF_MAX		2
7052203945Sweongyo#define	SAVE_PHY_COMM_MAX	10
7053203945Sweongyo#define	SAVE_PHY6_MAX		8
7054203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
7055203945Sweongyo		{ 0x7a, 0x43 };
7056203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
7057203945Sweongyo		0x0001, 0x0811, 0x0812, 0x0814,
7058203945Sweongyo		0x0815, 0x005a, 0x0059, 0x0058,
7059203945Sweongyo		0x000a, 0x0003
7060203945Sweongyo	};
7061203945Sweongyo	static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
7062203945Sweongyo		0x002e, 0x002f, 0x080f, 0x0810,
7063203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
7064203945Sweongyo	};
7065203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7066203945Sweongyo	int i, phy6_idx = 0;
7067203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
7068203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
7069203945Sweongyo	uint16_t save_phy6[SAVE_PHY6_MAX];
7070203945Sweongyo	int16_t nrssi;
7071203945Sweongyo	uint16_t saved = 0xffff;
7072203945Sweongyo
7073203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
7074203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
7075203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
7076203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
7077203945Sweongyo
7078203945Sweongyo	BWN_PHY_MASK(mac, 0x0429, 0x7fff);
7079203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
7080203945Sweongyo	BWN_PHY_SET(mac, 0x0811, 0x000c);
7081203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
7082203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
7083203945Sweongyo	if (phy->rev >= 6) {
7084203945Sweongyo		for (i = 0; i < SAVE_PHY6_MAX; ++i)
7085203945Sweongyo			save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
7086203945Sweongyo
7087203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
7088203945Sweongyo		BWN_PHY_WRITE(mac, 0x002f, 0);
7089203945Sweongyo		BWN_PHY_WRITE(mac, 0x080f, 0);
7090203945Sweongyo		BWN_PHY_WRITE(mac, 0x0810, 0);
7091203945Sweongyo		BWN_PHY_SET(mac, 0x0478, 0x0100);
7092203945Sweongyo		BWN_PHY_SET(mac, 0x0801, 0x0040);
7093203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
7094203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
7095203945Sweongyo	}
7096203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
7097203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
7098203945Sweongyo	DELAY(30);
7099203945Sweongyo
7100203945Sweongyo	nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7101203945Sweongyo	if (nrssi >= 0x20)
7102203945Sweongyo		nrssi -= 0x40;
7103203945Sweongyo	if (nrssi == 31) {
7104203945Sweongyo		for (i = 7; i >= 4; i--) {
7105203945Sweongyo			BWN_RF_WRITE(mac, 0x007b, i);
7106203945Sweongyo			DELAY(20);
7107203945Sweongyo			nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
7108203945Sweongyo			    0x003f);
7109203945Sweongyo			if (nrssi >= 0x20)
7110203945Sweongyo				nrssi -= 0x40;
7111203945Sweongyo			if (nrssi < 31 && saved == 0xffff)
7112203945Sweongyo				saved = i;
7113203945Sweongyo		}
7114203945Sweongyo		if (saved == 0xffff)
7115203945Sweongyo			saved = 4;
7116203945Sweongyo	} else {
7117203945Sweongyo		BWN_RF_MASK(mac, 0x007a, 0x007f);
7118203945Sweongyo		if (phy->rev != 1) {
7119203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0001);
7120203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffe);
7121203945Sweongyo		}
7122203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x000c);
7123203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x000c);
7124203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x0030);
7125203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x0030);
7126203945Sweongyo		BWN_PHY_WRITE(mac, 0x005a, 0x0480);
7127203945Sweongyo		BWN_PHY_WRITE(mac, 0x0059, 0x0810);
7128203945Sweongyo		BWN_PHY_WRITE(mac, 0x0058, 0x000d);
7129203945Sweongyo		if (phy->rev == 0)
7130203945Sweongyo			BWN_PHY_WRITE(mac, 0x0003, 0x0122);
7131203945Sweongyo		else
7132203945Sweongyo			BWN_PHY_SET(mac, 0x000a, 0x2000);
7133203945Sweongyo		if (phy->rev != 1) {
7134203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0004);
7135203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffb);
7136203945Sweongyo		}
7137203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
7138203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x000f);
7139203945Sweongyo		bwn_set_all_gains(mac, 3, 0, 1);
7140203945Sweongyo		BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
7141203945Sweongyo		DELAY(30);
7142203945Sweongyo		nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7143203945Sweongyo		if (nrssi >= 0x20)
7144203945Sweongyo			nrssi -= 0x40;
7145203945Sweongyo		if (nrssi == -32) {
7146203945Sweongyo			for (i = 0; i < 4; i++) {
7147203945Sweongyo				BWN_RF_WRITE(mac, 0x007b, i);
7148203945Sweongyo				DELAY(20);
7149203945Sweongyo				nrssi = (int16_t)((BWN_PHY_READ(mac,
7150203945Sweongyo				    0x047f) >> 8) & 0x003f);
7151203945Sweongyo				if (nrssi >= 0x20)
7152203945Sweongyo					nrssi -= 0x40;
7153203945Sweongyo				if (nrssi > -31 && saved == 0xffff)
7154203945Sweongyo					saved = i;
7155203945Sweongyo			}
7156203945Sweongyo			if (saved == 0xffff)
7157203945Sweongyo				saved = 3;
7158203945Sweongyo		} else
7159203945Sweongyo			saved = 0;
7160203945Sweongyo	}
7161203945Sweongyo	BWN_RF_WRITE(mac, 0x007b, saved);
7162203945Sweongyo
7163203945Sweongyo	/*
7164203945Sweongyo	 * Restore saved RF/PHY registers
7165203945Sweongyo	 */
7166203945Sweongyo	if (phy->rev >= 6) {
7167203945Sweongyo		for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
7168203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7169203945Sweongyo			    save_phy6[phy6_idx]);
7170203945Sweongyo		}
7171203945Sweongyo	}
7172203945Sweongyo	if (phy->rev != 1) {
7173203945Sweongyo		for (i = 3; i < 5; i++)
7174203945Sweongyo			BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
7175203945Sweongyo			    save_phy_comm[i]);
7176203945Sweongyo	}
7177203945Sweongyo	for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
7178203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
7179203945Sweongyo
7180203945Sweongyo	for (i = SAVE_RF_MAX - 1; i >= 0; --i)
7181203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
7182203945Sweongyo
7183203945Sweongyo	BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
7184203945Sweongyo	BWN_PHY_SET(mac, 0x0429, 0x8000);
7185203945Sweongyo	bwn_set_original_gains(mac);
7186203945Sweongyo	if (phy->rev >= 6) {
7187203945Sweongyo		for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
7188203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7189203945Sweongyo			    save_phy6[phy6_idx]);
7190203945Sweongyo		}
7191203945Sweongyo	}
7192203945Sweongyo
7193203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
7194203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
7195203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
7196203945Sweongyo}
7197203945Sweongyo
7198203945Sweongyostatic void
7199203945Sweongyobwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
7200203945Sweongyo    int16_t third)
7201203945Sweongyo{
7202203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7203203945Sweongyo	uint16_t i;
7204203945Sweongyo	uint16_t start = 0x08, end = 0x18;
7205203945Sweongyo	uint16_t tmp;
7206203945Sweongyo	uint16_t table;
7207203945Sweongyo
7208203945Sweongyo	if (phy->rev <= 1) {
7209203945Sweongyo		start = 0x10;
7210203945Sweongyo		end = 0x20;
7211203945Sweongyo	}
7212203945Sweongyo
7213203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7214203945Sweongyo	if (phy->rev <= 1)
7215203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7216203945Sweongyo	for (i = 0; i < 4; i++)
7217203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, first);
7218203945Sweongyo
7219203945Sweongyo	for (i = start; i < end; i++)
7220203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, second);
7221203945Sweongyo
7222203945Sweongyo	if (third != -1) {
7223203945Sweongyo		tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
7224203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
7225203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
7226203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
7227203945Sweongyo	}
7228203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7229203945Sweongyo}
7230203945Sweongyo
7231203945Sweongyostatic void
7232203945Sweongyobwn_set_original_gains(struct bwn_mac *mac)
7233203945Sweongyo{
7234203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7235203945Sweongyo	uint16_t i, tmp;
7236203945Sweongyo	uint16_t table;
7237203945Sweongyo	uint16_t start = 0x0008, end = 0x0018;
7238203945Sweongyo
7239203945Sweongyo	if (phy->rev <= 1) {
7240203945Sweongyo		start = 0x0010;
7241203945Sweongyo		end = 0x0020;
7242203945Sweongyo	}
7243203945Sweongyo
7244203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7245203945Sweongyo	if (phy->rev <= 1)
7246203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7247203945Sweongyo	for (i = 0; i < 4; i++) {
7248203945Sweongyo		tmp = (i & 0xfffc);
7249203945Sweongyo		tmp |= (i & 0x0001) << 1;
7250203945Sweongyo		tmp |= (i & 0x0002) >> 1;
7251203945Sweongyo
7252203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, tmp);
7253203945Sweongyo	}
7254203945Sweongyo
7255203945Sweongyo	for (i = start; i < end; i++)
7256203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, i - start);
7257203945Sweongyo
7258203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
7259203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
7260203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
7261203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7262203945Sweongyo}
7263203945Sweongyo
7264203945Sweongyostatic void
7265203945Sweongyobwn_phy_hwpctl_init(struct bwn_mac *mac)
7266203945Sweongyo{
7267203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
7268203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7269203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7270203945Sweongyo	struct bwn_rfatt old_rfatt, rfatt;
7271203945Sweongyo	struct bwn_bbatt old_bbatt, bbatt;
7272203945Sweongyo	uint8_t old_txctl = 0;
7273203945Sweongyo
7274203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
7275203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7276203945Sweongyo
7277203945Sweongyo	if ((bus->siba_board_vendor == SIBA_BOARDVENDOR_BCM) &&
7278203945Sweongyo	    (bus->siba_board_type == SIBA_BOARD_BU4306))
7279203945Sweongyo		return;
7280203945Sweongyo
7281203945Sweongyo	BWN_PHY_WRITE(mac, 0x0028, 0x8018);
7282203945Sweongyo
7283203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
7284203945Sweongyo
7285203945Sweongyo	if (!phy->gmode)
7286203945Sweongyo		return;
7287203945Sweongyo	bwn_hwpctl_early_init(mac);
7288203945Sweongyo	if (pg->pg_curtssi == 0) {
7289203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0) {
7290203945Sweongyo			BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
7291203945Sweongyo		} else {
7292203945Sweongyo			memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
7293203945Sweongyo			memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
7294203945Sweongyo			old_txctl = pg->pg_txctl;
7295203945Sweongyo
7296203945Sweongyo			bbatt.att = 11;
7297203945Sweongyo			if (phy->rf_rev == 8) {
7298203945Sweongyo				rfatt.att = 15;
7299203945Sweongyo				rfatt.padmix = 1;
7300203945Sweongyo			} else {
7301203945Sweongyo				rfatt.att = 9;
7302203945Sweongyo				rfatt.padmix = 0;
7303203945Sweongyo			}
7304203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
7305203945Sweongyo		}
7306203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
7307203945Sweongyo		pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
7308203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0)
7309203945Sweongyo			BWN_RF_MASK(mac, 0x0076, 0xff7b);
7310203945Sweongyo		else
7311203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
7312203945Sweongyo			    &old_rfatt, old_txctl);
7313203945Sweongyo	}
7314203945Sweongyo	bwn_hwpctl_init_gphy(mac);
7315203945Sweongyo
7316203945Sweongyo	/* clear TSSI */
7317203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
7318203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
7319203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
7320203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
7321203945Sweongyo}
7322203945Sweongyo
7323203945Sweongyostatic void
7324203945Sweongyobwn_hwpctl_early_init(struct bwn_mac *mac)
7325203945Sweongyo{
7326203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7327203945Sweongyo
7328203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7329203945Sweongyo		BWN_PHY_WRITE(mac, 0x047a, 0xc111);
7330203945Sweongyo		return;
7331203945Sweongyo	}
7332203945Sweongyo
7333203945Sweongyo	BWN_PHY_MASK(mac, 0x0036, 0xfeff);
7334203945Sweongyo	BWN_PHY_WRITE(mac, 0x002f, 0x0202);
7335203945Sweongyo	BWN_PHY_SET(mac, 0x047c, 0x0002);
7336203945Sweongyo	BWN_PHY_SET(mac, 0x047a, 0xf000);
7337203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
7338203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7339203945Sweongyo		BWN_PHY_SET(mac, 0x005d, 0x8000);
7340203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7341203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7342203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7343203945Sweongyo	} else {
7344203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0200);
7345203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7346203945Sweongyo		BWN_PHY_MASK(mac, 0x005d, 0x7fff);
7347203945Sweongyo		BWN_PHY_MASK(mac, 0x004f, 0xfffe);
7348203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7349203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7350203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7351203945Sweongyo	}
7352203945Sweongyo}
7353203945Sweongyo
7354203945Sweongyostatic void
7355203945Sweongyobwn_hwpctl_init_gphy(struct bwn_mac *mac)
7356203945Sweongyo{
7357203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7358203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7359203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7360203945Sweongyo	int i;
7361203945Sweongyo	uint16_t nr_written = 0, tmp, value;
7362203945Sweongyo	uint8_t rf, bb;
7363203945Sweongyo
7364203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7365203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
7366203945Sweongyo		return;
7367203945Sweongyo	}
7368203945Sweongyo
7369203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
7370203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7371203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
7372203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7373203945Sweongyo
7374203945Sweongyo	for (i = 0; i < 32; i++)
7375203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
7376203945Sweongyo	for (i = 32; i < 64; i++)
7377203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
7378203945Sweongyo	for (i = 0; i < 64; i += 2) {
7379203945Sweongyo		value = (uint16_t) pg->pg_tssi2dbm[i];
7380203945Sweongyo		value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
7381203945Sweongyo		BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
7382203945Sweongyo	}
7383203945Sweongyo
7384203945Sweongyo	for (rf = 0; rf < lo->rfatt.len; rf++) {
7385203945Sweongyo		for (bb = 0; bb < lo->bbatt.len; bb++) {
7386203945Sweongyo			if (nr_written >= 0x40)
7387203945Sweongyo				return;
7388203945Sweongyo			tmp = lo->bbatt.array[bb].att;
7389203945Sweongyo			tmp <<= 8;
7390203945Sweongyo			if (phy->rf_rev == 8)
7391203945Sweongyo				tmp |= 0x50;
7392203945Sweongyo			else
7393203945Sweongyo				tmp |= 0x40;
7394203945Sweongyo			tmp |= lo->rfatt.array[rf].att;
7395203945Sweongyo			BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
7396203945Sweongyo			nr_written++;
7397203945Sweongyo		}
7398203945Sweongyo	}
7399203945Sweongyo
7400203945Sweongyo	BWN_PHY_MASK(mac, 0x0060, 0xffbf);
7401203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0000);
7402203945Sweongyo
7403203945Sweongyo	KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
7404203945Sweongyo	BWN_PHY_SET(mac, 0x0478, 0x0800);
7405203945Sweongyo	BWN_PHY_MASK(mac, 0x0478, 0xfeff);
7406203945Sweongyo	BWN_PHY_MASK(mac, 0x0801, 0xffbf);
7407203945Sweongyo
7408203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
7409203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
7410203945Sweongyo}
7411203945Sweongyo
7412203945Sweongyostatic void
7413203945Sweongyobwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
7414203945Sweongyo{
7415203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
7416203945Sweongyo
7417203945Sweongyo	if (spu != 0)
7418203945Sweongyo		bwn_spu_workaround(mac, channel);
7419203945Sweongyo
7420203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7421203945Sweongyo
7422203945Sweongyo	if (channel == 14) {
7423203945Sweongyo		if (siba->siba_sprom.ccode == SIBA_CCODE_JAPAN)
7424203945Sweongyo			bwn_hf_write(mac,
7425203945Sweongyo			    bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
7426203945Sweongyo		else
7427203945Sweongyo			bwn_hf_write(mac,
7428203945Sweongyo			    bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
7429203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7430203945Sweongyo		    BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
7431203945Sweongyo		return;
7432203945Sweongyo	}
7433203945Sweongyo
7434203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7435203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
7436203945Sweongyo}
7437203945Sweongyo
7438203945Sweongyostatic uint16_t
7439203945Sweongyobwn_phy_g_chan2freq(uint8_t channel)
7440203945Sweongyo{
7441203945Sweongyo	static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
7442203945Sweongyo
7443203945Sweongyo	KASSERT(channel >= 1 && channel <= 14,
7444203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7445203945Sweongyo
7446203945Sweongyo	return (bwn_phy_g_rf_channels[channel - 1]);
7447203945Sweongyo}
7448203945Sweongyo
7449203945Sweongyostatic void
7450203945Sweongyobwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
7451203945Sweongyo    const struct bwn_rfatt *rfatt, uint8_t txctl)
7452203945Sweongyo{
7453203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7454203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7455203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7456203945Sweongyo	uint16_t bb, rf;
7457203945Sweongyo	uint16_t tx_bias, tx_magn;
7458203945Sweongyo
7459203945Sweongyo	bb = bbatt->att;
7460203945Sweongyo	rf = rfatt->att;
7461203945Sweongyo	tx_bias = lo->tx_bias;
7462203945Sweongyo	tx_magn = lo->tx_magn;
7463203945Sweongyo	if (tx_bias == 0xff)
7464203945Sweongyo		tx_bias = 0;
7465203945Sweongyo
7466203945Sweongyo	pg->pg_txctl = txctl;
7467203945Sweongyo	memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
7468203945Sweongyo	pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
7469203945Sweongyo	memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
7470203945Sweongyo	bwn_phy_g_set_bbatt(mac, bb);
7471203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
7472203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
7473203945Sweongyo		BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
7474203945Sweongyo	else {
7475203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
7476203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
7477203945Sweongyo	}
7478203945Sweongyo	if (BWN_HAS_TXMAG(phy))
7479203945Sweongyo		BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
7480203945Sweongyo	else
7481203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
7482203945Sweongyo	bwn_lo_g_adjust(mac);
7483203945Sweongyo}
7484203945Sweongyo
7485203945Sweongyostatic void
7486203945Sweongyobwn_phy_g_set_bbatt(struct bwn_mac *mac,
7487203945Sweongyo    uint16_t bbatt)
7488203945Sweongyo{
7489203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7490203945Sweongyo
7491203945Sweongyo	if (phy->analog == 0) {
7492203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY0,
7493203945Sweongyo		    (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
7494203945Sweongyo		return;
7495203945Sweongyo	}
7496203945Sweongyo	if (phy->analog > 1) {
7497203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
7498203945Sweongyo		return;
7499203945Sweongyo	}
7500203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
7501203945Sweongyo}
7502203945Sweongyo
7503203945Sweongyostatic uint16_t
7504203945Sweongyobwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
7505203945Sweongyo{
7506203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7507203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7508203945Sweongyo	struct siba_sprom *sprom = &(mac->mac_sd->sd_bus->siba_sprom);
7509203945Sweongyo	int max_lb_gain;
7510203945Sweongyo	uint16_t extlna;
7511203945Sweongyo	uint16_t i;
7512203945Sweongyo
7513203945Sweongyo	if (phy->gmode == 0)
7514203945Sweongyo		return (0);
7515203945Sweongyo
7516203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
7517203945Sweongyo		max_lb_gain = pg->pg_max_lb_gain;
7518203945Sweongyo		max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
7519203945Sweongyo		if (max_lb_gain >= 0x46) {
7520203945Sweongyo			extlna = 0x3000;
7521203945Sweongyo			max_lb_gain -= 0x46;
7522203945Sweongyo		} else if (max_lb_gain >= 0x3a) {
7523203945Sweongyo			extlna = 0x1000;
7524203945Sweongyo			max_lb_gain -= 0x3a;
7525203945Sweongyo		} else if (max_lb_gain >= 0x2e) {
7526203945Sweongyo			extlna = 0x2000;
7527203945Sweongyo			max_lb_gain -= 0x2e;
7528203945Sweongyo		} else {
7529203945Sweongyo			extlna = 0;
7530203945Sweongyo			max_lb_gain -= 0x10;
7531203945Sweongyo		}
7532203945Sweongyo
7533203945Sweongyo		for (i = 0; i < 16; i++) {
7534203945Sweongyo			max_lb_gain -= (i * 6);
7535203945Sweongyo			if (max_lb_gain < 6)
7536203945Sweongyo				break;
7537203945Sweongyo		}
7538203945Sweongyo
7539203945Sweongyo		if ((phy->rev < 7) || !(sprom->bf_lo & BWN_BFL_EXTLNA)) {
7540203945Sweongyo			if (reg == BWN_PHY_RFOVER) {
7541203945Sweongyo				return (0x1b3);
7542203945Sweongyo			} else if (reg == BWN_PHY_RFOVERVAL) {
7543203945Sweongyo				extlna |= (i << 8);
7544203945Sweongyo				switch (lpd) {
7545203945Sweongyo				case BWN_LPD(0, 1, 1):
7546203945Sweongyo					return (0x0f92);
7547203945Sweongyo				case BWN_LPD(0, 0, 1):
7548203945Sweongyo				case BWN_LPD(1, 0, 1):
7549203945Sweongyo					return (0x0092 | extlna);
7550203945Sweongyo				case BWN_LPD(1, 0, 0):
7551203945Sweongyo					return (0x0093 | extlna);
7552203945Sweongyo				}
7553203945Sweongyo				KASSERT(0 == 1,
7554203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7555203945Sweongyo			}
7556203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7557203945Sweongyo		} else {
7558203945Sweongyo			if (reg == BWN_PHY_RFOVER)
7559203945Sweongyo				return (0x9b3);
7560203945Sweongyo			if (reg == BWN_PHY_RFOVERVAL) {
7561203945Sweongyo				if (extlna)
7562203945Sweongyo					extlna |= 0x8000;
7563203945Sweongyo				extlna |= (i << 8);
7564203945Sweongyo				switch (lpd) {
7565203945Sweongyo				case BWN_LPD(0, 1, 1):
7566203945Sweongyo					return (0x8f92);
7567203945Sweongyo				case BWN_LPD(0, 0, 1):
7568203945Sweongyo					return (0x8092 | extlna);
7569203945Sweongyo				case BWN_LPD(1, 0, 1):
7570203945Sweongyo					return (0x2092 | extlna);
7571203945Sweongyo				case BWN_LPD(1, 0, 0):
7572203945Sweongyo					return (0x2093 | extlna);
7573203945Sweongyo				}
7574203945Sweongyo				KASSERT(0 == 1,
7575203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7576203945Sweongyo			}
7577203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7578203945Sweongyo		}
7579203945Sweongyo		return (0);
7580203945Sweongyo	}
7581203945Sweongyo
7582203945Sweongyo	if ((phy->rev < 7) ||
7583203945Sweongyo	    !(sprom->bf_lo & BWN_BFL_EXTLNA)) {
7584203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7585203945Sweongyo			return (0x1b3);
7586203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7587203945Sweongyo			switch (lpd) {
7588203945Sweongyo			case BWN_LPD(0, 1, 1):
7589203945Sweongyo				return (0x0fb2);
7590203945Sweongyo			case BWN_LPD(0, 0, 1):
7591203945Sweongyo				return (0x00b2);
7592203945Sweongyo			case BWN_LPD(1, 0, 1):
7593203945Sweongyo				return (0x30b2);
7594203945Sweongyo			case BWN_LPD(1, 0, 0):
7595203945Sweongyo				return (0x30b3);
7596203945Sweongyo			}
7597203945Sweongyo			KASSERT(0 == 1,
7598203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7599203945Sweongyo		}
7600203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7601203945Sweongyo	} else {
7602203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7603203945Sweongyo			return (0x9b3);
7604203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7605203945Sweongyo			switch (lpd) {
7606203945Sweongyo			case BWN_LPD(0, 1, 1):
7607203945Sweongyo				return (0x8fb2);
7608203945Sweongyo			case BWN_LPD(0, 0, 1):
7609203945Sweongyo				return (0x80b2);
7610203945Sweongyo			case BWN_LPD(1, 0, 1):
7611203945Sweongyo				return (0x20b2);
7612203945Sweongyo			case BWN_LPD(1, 0, 0):
7613203945Sweongyo				return (0x20b3);
7614203945Sweongyo			}
7615203945Sweongyo			KASSERT(0 == 1,
7616203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7617203945Sweongyo		}
7618203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7619203945Sweongyo	}
7620203945Sweongyo	return (0);
7621203945Sweongyo}
7622203945Sweongyo
7623203945Sweongyostatic void
7624203945Sweongyobwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
7625203945Sweongyo{
7626203945Sweongyo
7627203945Sweongyo	if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
7628203945Sweongyo		return;
7629203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
7630203945Sweongyo	    bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
7631203945Sweongyo	DELAY(1000);
7632203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7633203945Sweongyo}
7634203945Sweongyo
7635203945Sweongyostatic int
7636203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
7637203945Sweongyo{
7638203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7639203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
7640203945Sweongyo	const uint8_t rev = mac->mac_sd->sd_id.sd_rev;
7641203945Sweongyo	const char *filename;
7642203945Sweongyo	uint32_t high;
7643203945Sweongyo	int error;
7644203945Sweongyo
7645203945Sweongyo	/* microcode */
7646203945Sweongyo	if (rev >= 5 && rev <= 10)
7647203945Sweongyo		filename = "ucode5";
7648203945Sweongyo	else if (rev >= 11 && rev <= 12)
7649203945Sweongyo		filename = "ucode11";
7650203945Sweongyo	else if (rev == 13)
7651203945Sweongyo		filename = "ucode13";
7652203945Sweongyo	else if (rev == 14)
7653203945Sweongyo		filename = "ucode14";
7654203945Sweongyo	else if (rev >= 15)
7655203945Sweongyo		filename = "ucode15";
7656203945Sweongyo	else {
7657203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
7658203945Sweongyo		bwn_release_firmware(mac);
7659203945Sweongyo		return (EOPNOTSUPP);
7660203945Sweongyo	}
7661203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
7662203945Sweongyo	if (error) {
7663203945Sweongyo		bwn_release_firmware(mac);
7664203945Sweongyo		return (error);
7665203945Sweongyo	}
7666203945Sweongyo
7667203945Sweongyo	/* PCM */
7668203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
7669203945Sweongyo	if (rev >= 5 && rev <= 10) {
7670203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
7671203945Sweongyo		if (error == ENOENT)
7672203945Sweongyo			fw->no_pcmfile = 1;
7673203945Sweongyo		else if (error) {
7674203945Sweongyo			bwn_release_firmware(mac);
7675203945Sweongyo			return (error);
7676203945Sweongyo		}
7677203945Sweongyo	} else if (rev < 11) {
7678203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
7679203945Sweongyo		return (EOPNOTSUPP);
7680203945Sweongyo	}
7681203945Sweongyo
7682203945Sweongyo	/* initvals */
7683203945Sweongyo	high = siba_read_4(mac->mac_sd, SIBA_TGSHIGH);
7684203945Sweongyo	switch (mac->mac_phy.type) {
7685203945Sweongyo	case BWN_PHYTYPE_A:
7686203945Sweongyo		if (rev < 5 || rev > 10)
7687203945Sweongyo			goto fail1;
7688203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
7689203945Sweongyo			filename = "a0g1initvals5";
7690203945Sweongyo		else
7691203945Sweongyo			filename = "a0g0initvals5";
7692203945Sweongyo		break;
7693203945Sweongyo	case BWN_PHYTYPE_G:
7694203945Sweongyo		if (rev >= 5 && rev <= 10)
7695203945Sweongyo			filename = "b0g0initvals5";
7696203945Sweongyo		else if (rev >= 13)
7697203945Sweongyo			filename = "b0g0initvals13";
7698203945Sweongyo		else
7699203945Sweongyo			goto fail1;
7700203945Sweongyo		break;
7701203945Sweongyo	case BWN_PHYTYPE_LP:
7702203945Sweongyo		if (rev == 13)
7703203945Sweongyo			filename = "lp0initvals13";
7704203945Sweongyo		else if (rev == 14)
7705203945Sweongyo			filename = "lp0initvals14";
7706203945Sweongyo		else if (rev >= 15)
7707203945Sweongyo			filename = "lp0initvals15";
7708203945Sweongyo		else
7709203945Sweongyo			goto fail1;
7710203945Sweongyo		break;
7711203945Sweongyo	case BWN_PHYTYPE_N:
7712203945Sweongyo		if (rev >= 11 && rev <= 12)
7713203945Sweongyo			filename = "n0initvals11";
7714203945Sweongyo		else
7715203945Sweongyo			goto fail1;
7716203945Sweongyo		break;
7717203945Sweongyo	default:
7718203945Sweongyo		goto fail1;
7719203945Sweongyo	}
7720203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
7721203945Sweongyo	if (error) {
7722203945Sweongyo		bwn_release_firmware(mac);
7723203945Sweongyo		return (error);
7724203945Sweongyo	}
7725203945Sweongyo
7726203945Sweongyo	/* bandswitch initvals */
7727203945Sweongyo	switch (mac->mac_phy.type) {
7728203945Sweongyo	case BWN_PHYTYPE_A:
7729203945Sweongyo		if (rev >= 5 && rev <= 10) {
7730203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
7731203945Sweongyo				filename = "a0g1bsinitvals5";
7732203945Sweongyo			else
7733203945Sweongyo				filename = "a0g0bsinitvals5";
7734203945Sweongyo		} else if (rev >= 11)
7735203945Sweongyo			filename = NULL;
7736203945Sweongyo		else
7737203945Sweongyo			goto fail1;
7738203945Sweongyo		break;
7739203945Sweongyo	case BWN_PHYTYPE_G:
7740203945Sweongyo		if (rev >= 5 && rev <= 10)
7741203945Sweongyo			filename = "b0g0bsinitvals5";
7742203945Sweongyo		else if (rev >= 11)
7743203945Sweongyo			filename = NULL;
7744203945Sweongyo		else
7745203945Sweongyo			goto fail1;
7746203945Sweongyo		break;
7747203945Sweongyo	case BWN_PHYTYPE_LP:
7748203945Sweongyo		if (rev == 13)
7749203945Sweongyo			filename = "lp0bsinitvals13";
7750203945Sweongyo		else if (rev == 14)
7751203945Sweongyo			filename = "lp0bsinitvals14";
7752203945Sweongyo		else if (rev >= 15)
7753203945Sweongyo			filename = "lp0bsinitvals15";
7754203945Sweongyo		else
7755203945Sweongyo			goto fail1;
7756203945Sweongyo		break;
7757203945Sweongyo	case BWN_PHYTYPE_N:
7758203945Sweongyo		if (rev >= 11 && rev <= 12)
7759203945Sweongyo			filename = "n0bsinitvals11";
7760203945Sweongyo		else
7761203945Sweongyo			goto fail1;
7762203945Sweongyo		break;
7763203945Sweongyo	default:
7764203945Sweongyo		goto fail1;
7765203945Sweongyo	}
7766203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
7767203945Sweongyo	if (error) {
7768203945Sweongyo		bwn_release_firmware(mac);
7769203945Sweongyo		return (error);
7770203945Sweongyo	}
7771203945Sweongyo	return (0);
7772203945Sweongyofail1:
7773203945Sweongyo	device_printf(sc->sc_dev, "no INITVALS for rev %d\n", rev);
7774203945Sweongyo	bwn_release_firmware(mac);
7775203945Sweongyo	return (EOPNOTSUPP);
7776203945Sweongyo}
7777203945Sweongyo
7778203945Sweongyostatic int
7779203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
7780203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
7781203945Sweongyo{
7782203945Sweongyo	const struct bwn_fwhdr *hdr;
7783203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7784203945Sweongyo	const struct firmware *fw;
7785203945Sweongyo	char namebuf[64];
7786203945Sweongyo
7787203945Sweongyo	if (name == NULL) {
7788203945Sweongyo		bwn_do_release_fw(bfw);
7789203945Sweongyo		return (0);
7790203945Sweongyo	}
7791203945Sweongyo	if (bfw->filename != NULL) {
7792203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
7793203945Sweongyo			return (0);
7794203945Sweongyo		bwn_do_release_fw(bfw);
7795203945Sweongyo	}
7796203945Sweongyo
7797203945Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s",
7798203945Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "", name);
7799203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
7800203945Sweongyo	fw = firmware_get(namebuf);
7801203945Sweongyo	if (fw == NULL) {
7802203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
7803203945Sweongyo		    namebuf);
7804203945Sweongyo		return (ENOENT);
7805203945Sweongyo	}
7806203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
7807203945Sweongyo		goto fail;
7808203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
7809203945Sweongyo	switch (hdr->type) {
7810203945Sweongyo	case BWN_FWTYPE_UCODE:
7811203945Sweongyo	case BWN_FWTYPE_PCM:
7812203945Sweongyo		if (be32toh(hdr->size) !=
7813203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
7814203945Sweongyo			goto fail;
7815203945Sweongyo		/* FALLTHROUGH */
7816203945Sweongyo	case BWN_FWTYPE_IV:
7817203945Sweongyo		if (hdr->ver != 1)
7818203945Sweongyo			goto fail;
7819203945Sweongyo		break;
7820203945Sweongyo	default:
7821203945Sweongyo		goto fail;
7822203945Sweongyo	}
7823203945Sweongyo	bfw->filename = name;
7824203945Sweongyo	bfw->fw = fw;
7825203945Sweongyo	bfw->type = type;
7826203945Sweongyo	return (0);
7827203945Sweongyofail:
7828203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
7829203945Sweongyo	if (fw != NULL)
7830203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
7831203945Sweongyo	return (EPROTO);
7832203945Sweongyo}
7833203945Sweongyo
7834203945Sweongyostatic void
7835203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
7836203945Sweongyo{
7837203945Sweongyo
7838203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
7839203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
7840203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
7841203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
7842203945Sweongyo}
7843203945Sweongyo
7844203945Sweongyostatic void
7845203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
7846203945Sweongyo{
7847203945Sweongyo
7848203945Sweongyo	if (bfw->fw != NULL)
7849203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
7850203945Sweongyo	bfw->fw = NULL;
7851203945Sweongyo	bfw->filename = NULL;
7852203945Sweongyo}
7853203945Sweongyo
7854203945Sweongyostatic int
7855203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
7856203945Sweongyo{
7857203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
7858203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
7859203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
7860203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
7861203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7862203945Sweongyo	const uint32_t *data;
7863203945Sweongyo	unsigned int i;
7864203945Sweongyo	uint32_t ctl;
7865203945Sweongyo	uint16_t date, fwcaps, time;
7866203945Sweongyo	int error = 0;
7867203945Sweongyo
7868203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
7869203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
7870203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
7871203945Sweongyo	    __LINE__));
7872203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
7873203945Sweongyo	for (i = 0; i < 64; i++)
7874203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
7875203945Sweongyo	for (i = 0; i < 4096; i += 2)
7876203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
7877203945Sweongyo
7878203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7879203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
7880203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7881203945Sweongyo	     i++) {
7882203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7883203945Sweongyo		DELAY(10);
7884203945Sweongyo	}
7885203945Sweongyo
7886203945Sweongyo	if (mac->mac_fw.pcm.fw) {
7887203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
7888203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
7889203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
7890203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
7891203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
7892203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
7893203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7894203945Sweongyo			DELAY(10);
7895203945Sweongyo		}
7896203945Sweongyo	}
7897203945Sweongyo
7898203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
7899203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7900203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
7901203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
7902203945Sweongyo
7903203945Sweongyo	for (i = 0; i < 21; i++) {
7904203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
7905203945Sweongyo			break;
7906203945Sweongyo		if (i >= 20) {
7907203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
7908203945Sweongyo			error = ENXIO;
7909203945Sweongyo			goto error;
7910203945Sweongyo		}
7911203945Sweongyo		DELAY(50000);
7912203945Sweongyo	}
7913203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
7914203945Sweongyo
7915203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
7916203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
7917203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
7918203945Sweongyo		error = EOPNOTSUPP;
7919203945Sweongyo		goto error;
7920203945Sweongyo	}
7921203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
7922203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
7923203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
7924203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
7925203945Sweongyo	if (bwn_wme != 0)
7926203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
7927203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
7928203945Sweongyo
7929203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
7930203945Sweongyo	if (mac->mac_fw.opensource == 0) {
7931203945Sweongyo		device_printf(sc->sc_dev,
7932203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
7933203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
7934203945Sweongyo		if (mac->mac_fw.no_pcmfile)
7935203945Sweongyo			device_printf(sc->sc_dev,
7936203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
7937203945Sweongyo	} else {
7938203945Sweongyo		mac->mac_fw.patch = time;
7939203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
7940203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
7941203945Sweongyo			device_printf(sc->sc_dev,
7942203945Sweongyo			    "disabling HW crypto acceleration\n");
7943203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
7944203945Sweongyo		}
7945203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
7946203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
7947203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
7948203945Sweongyo		}
7949203945Sweongyo	}
7950203945Sweongyo
7951203945Sweongyo	if (BWN_ISOLDFMT(mac))
7952203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
7953203945Sweongyo
7954203945Sweongyo	return (0);
7955203945Sweongyo
7956203945Sweongyoerror:
7957203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7958203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
7959203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
7960203945Sweongyo
7961203945Sweongyo	return (error);
7962203945Sweongyo#undef GETFWSIZE
7963203945Sweongyo#undef GETFWOFFSET
7964203945Sweongyo}
7965203945Sweongyo
7966203945Sweongyo/* OpenFirmware only */
7967203945Sweongyostatic uint16_t
7968203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
7969203945Sweongyo{
7970203945Sweongyo
7971203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
7972203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7973203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
7974203945Sweongyo}
7975203945Sweongyo
7976203945Sweongyostatic int
7977203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
7978203945Sweongyo    size_t count, size_t array_size)
7979203945Sweongyo{
7980203945Sweongyo#define	GET_NEXTIV16(iv)						\
7981203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7982203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
7983203945Sweongyo#define	GET_NEXTIV32(iv)						\
7984203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7985203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
7986203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7987203945Sweongyo	const struct bwn_fwinitvals *iv;
7988203945Sweongyo	uint16_t offset;
7989203945Sweongyo	size_t i;
7990203945Sweongyo	uint8_t bit32;
7991203945Sweongyo
7992203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
7993203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7994203945Sweongyo	iv = ivals;
7995203945Sweongyo	for (i = 0; i < count; i++) {
7996203945Sweongyo		if (array_size < sizeof(iv->offset_size))
7997203945Sweongyo			goto fail;
7998203945Sweongyo		array_size -= sizeof(iv->offset_size);
7999203945Sweongyo		offset = be16toh(iv->offset_size);
8000203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
8001203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
8002203945Sweongyo		if (offset >= 0x1000)
8003203945Sweongyo			goto fail;
8004203945Sweongyo		if (bit32) {
8005203945Sweongyo			if (array_size < sizeof(iv->data.d32))
8006203945Sweongyo				goto fail;
8007203945Sweongyo			array_size -= sizeof(iv->data.d32);
8008203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
8009203945Sweongyo			iv = GET_NEXTIV32(iv);
8010203945Sweongyo		} else {
8011203945Sweongyo
8012203945Sweongyo			if (array_size < sizeof(iv->data.d16))
8013203945Sweongyo				goto fail;
8014203945Sweongyo			array_size -= sizeof(iv->data.d16);
8015203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
8016203945Sweongyo
8017203945Sweongyo			iv = GET_NEXTIV16(iv);
8018203945Sweongyo		}
8019203945Sweongyo	}
8020203945Sweongyo	if (array_size != 0)
8021203945Sweongyo		goto fail;
8022203945Sweongyo	return (0);
8023203945Sweongyofail:
8024203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
8025203945Sweongyo	return (EPROTO);
8026203945Sweongyo#undef GET_NEXTIV16
8027203945Sweongyo#undef GET_NEXTIV32
8028203945Sweongyo}
8029203945Sweongyo
8030203945Sweongyostatic int
8031203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
8032203945Sweongyo{
8033203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
8034203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8035203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8036203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
8037203945Sweongyo	uint16_t channelcookie, savedcookie;
8038203945Sweongyo	int error;
8039203945Sweongyo
8040203945Sweongyo	if (chan == 0xffff)
8041203945Sweongyo		chan = phy->get_default_chan(mac);
8042203945Sweongyo
8043203945Sweongyo	channelcookie = chan;
8044203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
8045203945Sweongyo		channelcookie |= 0x100;
8046203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
8047203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
8048203945Sweongyo	error = phy->switch_channel(mac, chan);
8049203945Sweongyo	if (error)
8050203945Sweongyo		goto fail;
8051203945Sweongyo
8052203945Sweongyo	mac->mac_phy.chan = chan;
8053203945Sweongyo	DELAY(8000);
8054203945Sweongyo	return (0);
8055203945Sweongyofail:
8056203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
8057203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
8058203945Sweongyo	return (error);
8059203945Sweongyo}
8060203945Sweongyo
8061203945Sweongyostatic uint16_t
8062203945Sweongyobwn_ant2phy(int antenna)
8063203945Sweongyo{
8064203945Sweongyo
8065203945Sweongyo	switch (antenna) {
8066203945Sweongyo	case BWN_ANT0:
8067203945Sweongyo		return (BWN_TX_PHY_ANT0);
8068203945Sweongyo	case BWN_ANT1:
8069203945Sweongyo		return (BWN_TX_PHY_ANT1);
8070203945Sweongyo	case BWN_ANT2:
8071203945Sweongyo		return (BWN_TX_PHY_ANT2);
8072203945Sweongyo	case BWN_ANT3:
8073203945Sweongyo		return (BWN_TX_PHY_ANT3);
8074203945Sweongyo	case BWN_ANTAUTO:
8075203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
8076203945Sweongyo	}
8077203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8078203945Sweongyo	return (0);
8079203945Sweongyo}
8080203945Sweongyo
8081203945Sweongyostatic void
8082203945Sweongyobwn_wme_load(struct bwn_mac *mac)
8083203945Sweongyo{
8084203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8085203945Sweongyo	int i;
8086203945Sweongyo
8087203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
8088203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8089203945Sweongyo
8090203945Sweongyo	bwn_mac_suspend(mac);
8091203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
8092203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
8093203945Sweongyo		    bwn_wme_shm_offsets[i]);
8094203945Sweongyo	bwn_mac_enable(mac);
8095203945Sweongyo}
8096203945Sweongyo
8097203945Sweongyostatic void
8098203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
8099203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
8100203945Sweongyo{
8101203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
8102203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8103203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
8104203945Sweongyo	int slot, tmp;
8105203945Sweongyo	unsigned int i;
8106203945Sweongyo
8107203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
8108203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8109203945Sweongyo
8110203945Sweongyo	memset(&params, 0, sizeof(params));
8111203945Sweongyo
8112203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
8113203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
8114203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
8115203945Sweongyo
8116203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
8117203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8118203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
8119203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8120203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
8121203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
8122203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
8123203945Sweongyo
8124203945Sweongyo	for (i = 0; i < N(params); i++) {
8125203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
8126203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
8127203945Sweongyo			    shm_offset + (i * 2));
8128203945Sweongyo			tmp |= 0x100;
8129203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8130203945Sweongyo			    tmp);
8131203945Sweongyo		} else {
8132203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8133203945Sweongyo			    params[i]);
8134203945Sweongyo		}
8135203945Sweongyo	}
8136203945Sweongyo}
8137203945Sweongyo
8138203945Sweongyostatic void
8139203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
8140203945Sweongyo{
8141203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8142203945Sweongyo	uint32_t tmp;
8143203945Sweongyo	int i;
8144203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
8145203945Sweongyo
8146203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
8147203945Sweongyo	memcpy(mac_bssid, sc->sc_macaddr, IEEE80211_ADDR_LEN);
8148203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
8149203945Sweongyo	    IEEE80211_ADDR_LEN);
8150203945Sweongyo
8151203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
8152203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
8153203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
8154203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
8155203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
8156203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
8157203945Sweongyo	}
8158203945Sweongyo}
8159203945Sweongyo
8160203945Sweongyostatic void
8161203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
8162203945Sweongyo    const uint8_t *macaddr)
8163203945Sweongyo{
8164203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
8165203945Sweongyo	uint16_t data;
8166203945Sweongyo
8167203945Sweongyo	if (!mac)
8168203945Sweongyo		macaddr = zero;
8169203945Sweongyo
8170203945Sweongyo	offset |= 0x0020;
8171203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
8172203945Sweongyo
8173203945Sweongyo	data = macaddr[0];
8174203945Sweongyo	data |= macaddr[1] << 8;
8175203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8176203945Sweongyo	data = macaddr[2];
8177203945Sweongyo	data |= macaddr[3] << 8;
8178203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8179203945Sweongyo	data = macaddr[4];
8180203945Sweongyo	data |= macaddr[5] << 8;
8181203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8182203945Sweongyo}
8183203945Sweongyo
8184203945Sweongyostatic void
8185203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8186203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
8187203945Sweongyo{
8188203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
8189203945Sweongyo	uint8_t per_sta_keys_start = 8;
8190203945Sweongyo
8191203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8192203945Sweongyo		per_sta_keys_start = 4;
8193203945Sweongyo
8194203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
8195203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8196203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
8197203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8198203945Sweongyo
8199203945Sweongyo	if (index >= per_sta_keys_start)
8200203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
8201203945Sweongyo	if (key)
8202203945Sweongyo		memcpy(buf, key, key_len);
8203203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
8204203945Sweongyo	if (index >= per_sta_keys_start)
8205203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
8206203945Sweongyo
8207203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
8208203945Sweongyo}
8209203945Sweongyo
8210203945Sweongyostatic void
8211203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
8212203945Sweongyo{
8213203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
8214203945Sweongyo	uint8_t start = 8;
8215203945Sweongyo
8216203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8217203945Sweongyo		start = 4;
8218203945Sweongyo
8219203945Sweongyo	KASSERT(index >= start,
8220203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8221203945Sweongyo	index -= start;
8222203945Sweongyo
8223203945Sweongyo	if (addr) {
8224203945Sweongyo		addrtmp[0] = addr[0];
8225203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
8226203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
8227203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
8228203945Sweongyo		addrtmp[1] = addr[4];
8229203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
8230203945Sweongyo	}
8231203945Sweongyo
8232203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 5) {
8233203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
8234203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
8235203945Sweongyo	} else {
8236203945Sweongyo		if (index >= 8) {
8237203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
8238203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
8239203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
8240203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
8241203945Sweongyo		}
8242203945Sweongyo	}
8243203945Sweongyo}
8244203945Sweongyo
8245203945Sweongyostatic void
8246203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8247203945Sweongyo    const uint8_t *key)
8248203945Sweongyo{
8249203945Sweongyo	unsigned int i;
8250203945Sweongyo	uint32_t offset;
8251203945Sweongyo	uint16_t kidx, value;
8252203945Sweongyo
8253203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
8254203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
8255203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
8256203945Sweongyo
8257203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
8258203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
8259203945Sweongyo		value = key[i];
8260203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
8261203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
8262203945Sweongyo	}
8263203945Sweongyo}
8264203945Sweongyo
8265203945Sweongyostatic void
8266203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
8267203945Sweongyo{
8268203945Sweongyo
8269203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8270203945Sweongyo	if (mac->mac_phy.exit != NULL)
8271203945Sweongyo		mac->mac_phy.exit(mac);
8272203945Sweongyo}
8273203945Sweongyo
8274203945Sweongyostatic void
8275203945Sweongyobwn_dma_free(struct bwn_mac *mac)
8276203945Sweongyo{
8277203945Sweongyo	struct bwn_dma *dma;
8278203945Sweongyo
8279203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
8280203945Sweongyo		return;
8281203945Sweongyo	dma = &mac->mac_method.dma;
8282203945Sweongyo
8283203945Sweongyo	bwn_dma_ringfree(&dma->rx);
8284203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
8285203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
8286203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
8287203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
8288203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
8289203945Sweongyo}
8290203945Sweongyo
8291203945Sweongyostatic void
8292203945Sweongyobwn_core_stop(struct bwn_mac *mac)
8293203945Sweongyo{
8294203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8295203945Sweongyo
8296203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8297203945Sweongyo
8298203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8299203945Sweongyo		return;
8300203945Sweongyo
8301203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
8302203945Sweongyo	callout_stop(&sc->sc_task_ch);
8303203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
8304203945Sweongyo	sc->sc_watchdog_timer = 0;
8305203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8306203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
8307203945Sweongyo	bwn_mac_suspend(mac);
8308203945Sweongyo
8309203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
8310203945Sweongyo}
8311203945Sweongyo
8312203945Sweongyostatic int
8313203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
8314203945Sweongyo{
8315203945Sweongyo	struct bwn_mac *up_dev = NULL;
8316203945Sweongyo	struct bwn_mac *down_dev;
8317203945Sweongyo	struct bwn_mac *mac;
8318203945Sweongyo	int err, status;
8319203945Sweongyo	uint8_t gmode;
8320203945Sweongyo
8321203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8322203945Sweongyo
8323203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
8324203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
8325203945Sweongyo		    mac->mac_phy.supports_2ghz) {
8326203945Sweongyo			up_dev = mac;
8327203945Sweongyo			gmode = 1;
8328203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
8329203945Sweongyo		    mac->mac_phy.supports_5ghz) {
8330203945Sweongyo			up_dev = mac;
8331203945Sweongyo			gmode = 0;
8332203945Sweongyo		} else {
8333203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8334203945Sweongyo			return (EINVAL);
8335203945Sweongyo		}
8336203945Sweongyo		if (up_dev != NULL)
8337203945Sweongyo			break;
8338203945Sweongyo	}
8339203945Sweongyo	if (up_dev == NULL) {
8340203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
8341203945Sweongyo		return (ENODEV);
8342203945Sweongyo	}
8343203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
8344203945Sweongyo		return (0);
8345203945Sweongyo
8346203945Sweongyo	device_printf(sc->sc_dev, "switching to %s-GHz band\n",
8347203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8348203945Sweongyo
8349203945Sweongyo	down_dev = sc->sc_curmac;;
8350203945Sweongyo	status = down_dev->mac_status;
8351203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8352203945Sweongyo		bwn_core_stop(down_dev);
8353203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
8354203945Sweongyo		bwn_core_exit(down_dev);
8355203945Sweongyo
8356203945Sweongyo	if (down_dev != up_dev)
8357203945Sweongyo		bwn_phy_reset(down_dev);
8358203945Sweongyo
8359203945Sweongyo	up_dev->mac_phy.gmode = gmode;
8360203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
8361203945Sweongyo		err = bwn_core_init(up_dev);
8362203945Sweongyo		if (err) {
8363203945Sweongyo			device_printf(sc->sc_dev,
8364203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
8365203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8366203945Sweongyo			goto fail;
8367203945Sweongyo		}
8368203945Sweongyo	}
8369203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8370203945Sweongyo		bwn_core_start(up_dev);
8371203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
8372203945Sweongyo	sc->sc_curmac = up_dev;
8373203945Sweongyo
8374203945Sweongyo	return (0);
8375203945Sweongyofail:
8376203945Sweongyo	sc->sc_curmac = NULL;
8377203945Sweongyo	return (err);
8378203945Sweongyo}
8379203945Sweongyo
8380203945Sweongyostatic void
8381203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
8382203945Sweongyo{
8383203945Sweongyo
8384203945Sweongyo	bwn_mac_suspend(mac);
8385203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
8386203945Sweongyo	mac->mac_phy.rf_on = 1;
8387203945Sweongyo	bwn_mac_enable(mac);
8388203945Sweongyo}
8389203945Sweongyo
8390203945Sweongyostatic void
8391203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
8392203945Sweongyo{
8393203945Sweongyo
8394203945Sweongyo	bwn_mac_suspend(mac);
8395203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8396203945Sweongyo	mac->mac_phy.rf_on = 0;
8397203945Sweongyo	bwn_mac_enable(mac);
8398203945Sweongyo}
8399203945Sweongyo
8400203945Sweongyostatic void
8401203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
8402203945Sweongyo{
8403203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
8404203945Sweongyo
8405203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW,
8406203945Sweongyo	    ((siba_read_4(sd, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
8407203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
8408203945Sweongyo	DELAY(1000);
8409203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW,
8410203945Sweongyo	    (siba_read_4(sd, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC) |
8411203945Sweongyo	    BWN_TGSLOW_PHYRESET);
8412203945Sweongyo	DELAY(1000);
8413203945Sweongyo}
8414203945Sweongyo
8415203945Sweongyostatic int
8416203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
8417203945Sweongyo{
8418203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
8419203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
8420203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
8421203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
8422203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
8423203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
8424203945Sweongyo	int error;
8425203945Sweongyo
8426203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
8427203945Sweongyo	    ieee80211_state_name[vap->iv_state],
8428203945Sweongyo	    ieee80211_state_name[nstate]);
8429203945Sweongyo
8430203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
8431203945Sweongyo	if (error != 0)
8432203945Sweongyo		return (error);
8433203945Sweongyo
8434203945Sweongyo	BWN_LOCK(sc);
8435203945Sweongyo
8436203945Sweongyo	bwn_led_newstate(mac, nstate);
8437203945Sweongyo
8438203945Sweongyo	/*
8439203945Sweongyo	 * Clear the BSSID when we stop a STA
8440203945Sweongyo	 */
8441203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
8442203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
8443203945Sweongyo			/*
8444203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
8445203945Sweongyo			 * the same AP, this will reinialize things
8446203945Sweongyo			 * correctly...
8447203945Sweongyo			 */
8448203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
8449203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
8450203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
8451203945Sweongyo				bwn_set_macaddr(mac);
8452203945Sweongyo			}
8453203945Sweongyo		}
8454203945Sweongyo	}
8455203945Sweongyo
8456203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR) {
8457203945Sweongyo		/* XXX nothing to do? */
8458203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
8459203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
8460203945Sweongyo		memcpy(sc->sc_macaddr, IF_LLADDR(ifp), IEEE80211_ADDR_LEN);
8461203945Sweongyo		bwn_set_opmode(mac);
8462203945Sweongyo		bwn_set_pretbtt(mac);
8463203945Sweongyo		bwn_spu_setdelay(mac, 0);
8464203945Sweongyo		bwn_set_macaddr(mac);
8465203945Sweongyo	}
8466203945Sweongyo
8467203945Sweongyo	BWN_UNLOCK(sc);
8468203945Sweongyo
8469203945Sweongyo	return (error);
8470203945Sweongyo}
8471203945Sweongyo
8472203945Sweongyostatic void
8473203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
8474203945Sweongyo{
8475203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8476203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8477203945Sweongyo	uint16_t pretbtt;
8478203945Sweongyo
8479203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8480203945Sweongyo		pretbtt = 2;
8481203945Sweongyo	else
8482203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
8483203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
8484203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
8485203945Sweongyo}
8486203945Sweongyo
8487203945Sweongyostatic int
8488203945Sweongyobwn_intr(void *arg)
8489203945Sweongyo{
8490203945Sweongyo	struct bwn_mac *mac = arg;
8491203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8492203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
8493203945Sweongyo	uint32_t reason;
8494203945Sweongyo
8495203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED || siba->siba_invalid)
8496203945Sweongyo		return (FILTER_STRAY);
8497203945Sweongyo
8498203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
8499203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
8500203945Sweongyo		return (FILTER_STRAY);
8501203945Sweongyo	reason &= mac->mac_intr_mask;
8502203945Sweongyo	if (reason == 0)
8503203945Sweongyo		return (FILTER_HANDLED);
8504203945Sweongyo
8505203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
8506203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
8507203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
8508203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
8509203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
8510203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
8511203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
8512203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
8513203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
8514203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
8515203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
8516203945Sweongyo
8517203945Sweongyo	/* Disable interrupts. */
8518203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8519203945Sweongyo
8520203945Sweongyo	mac->mac_reason_intr = reason;
8521203945Sweongyo
8522203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8523203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8524203945Sweongyo
8525203945Sweongyo	taskqueue_enqueue_fast(sc->sc_tq, &mac->mac_intrtask);
8526203945Sweongyo	return (FILTER_HANDLED);
8527203945Sweongyo}
8528203945Sweongyo
8529203945Sweongyostatic void
8530203945Sweongyobwn_intrtask(void *arg, int npending)
8531203945Sweongyo{
8532203945Sweongyo	struct bwn_mac *mac = arg;
8533203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8534203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8535203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
8536203945Sweongyo	uint32_t merged = 0;
8537203945Sweongyo	int i, tx = 0, rx = 0;
8538203945Sweongyo
8539203945Sweongyo	BWN_LOCK(sc);
8540203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED || siba->siba_invalid) {
8541203945Sweongyo		BWN_UNLOCK(sc);
8542203945Sweongyo		return;
8543203945Sweongyo	}
8544203945Sweongyo
8545203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
8546203945Sweongyo		merged |= mac->mac_reason[i];
8547203945Sweongyo
8548203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
8549203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
8550203945Sweongyo
8551203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
8552203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
8553203945Sweongyo		mac->mac_phy.txerrors--;
8554203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
8555203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
8556203945Sweongyo			bwn_restart(mac, "PHY TX errors");
8557203945Sweongyo		}
8558203945Sweongyo	}
8559203945Sweongyo
8560203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
8561203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
8562203945Sweongyo			device_printf(sc->sc_dev,
8563203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
8564203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8565203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8566203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8567203945Sweongyo			bwn_restart(mac, "DMA error");
8568203945Sweongyo			BWN_UNLOCK(sc);
8569203945Sweongyo			return;
8570203945Sweongyo		}
8571203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
8572203945Sweongyo			device_printf(sc->sc_dev,
8573203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
8574203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8575203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8576203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8577203945Sweongyo		}
8578203945Sweongyo	}
8579203945Sweongyo
8580203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
8581203945Sweongyo		bwn_intr_ucode_debug(mac);
8582203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
8583203945Sweongyo		bwn_intr_tbtt_indication(mac);
8584203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
8585203945Sweongyo		bwn_intr_atim_end(mac);
8586203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
8587203945Sweongyo		bwn_intr_beacon(mac);
8588203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
8589203945Sweongyo		bwn_intr_pmq(mac);
8590203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
8591203945Sweongyo		bwn_intr_noise(mac);
8592203945Sweongyo
8593203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
8594203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
8595203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
8596203945Sweongyo			rx = 1;
8597203945Sweongyo		}
8598203945Sweongyo	} else
8599203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
8600203945Sweongyo
8601203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8602203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8603203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8604203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8605203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8606203945Sweongyo
8607203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
8608203945Sweongyo		bwn_intr_txeof(mac);
8609203945Sweongyo		tx = 1;
8610203945Sweongyo	}
8611203945Sweongyo
8612203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
8613203945Sweongyo
8614203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
8615203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
8616203945Sweongyo
8617203945Sweongyo		if (tx && rx) {
8618203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
8619203945Sweongyo				evt = BWN_LED_EVENT_RX;
8620203945Sweongyo			else
8621203945Sweongyo				evt = BWN_LED_EVENT_TX;
8622203945Sweongyo		} else if (tx) {
8623203945Sweongyo			evt = BWN_LED_EVENT_TX;
8624203945Sweongyo		} else if (rx) {
8625203945Sweongyo			evt = BWN_LED_EVENT_RX;
8626203945Sweongyo		} else if (rx == 0) {
8627203945Sweongyo			evt = BWN_LED_EVENT_POLL;
8628203945Sweongyo		}
8629203945Sweongyo
8630203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
8631203945Sweongyo			bwn_led_event(mac, evt);
8632203945Sweongyo       }
8633203945Sweongyo
8634203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
8635203945Sweongyo		if (!IFQ_IS_EMPTY(&ifp->if_snd))
8636203945Sweongyo			bwn_start_locked(ifp);
8637203945Sweongyo	}
8638203945Sweongyo
8639203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8640203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8641203945Sweongyo
8642203945Sweongyo	BWN_UNLOCK(sc);
8643203945Sweongyo}
8644203945Sweongyo
8645203945Sweongyostatic void
8646203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
8647203945Sweongyo{
8648203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8649203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8650203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
8651203945Sweongyo
8652203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
8653203945Sweongyo		return;
8654203945Sweongyo
8655203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
8656203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
8657203945Sweongyo}
8658203945Sweongyo
8659203945Sweongyostatic void
8660203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
8661203945Sweongyo{
8662203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8663203945Sweongyo	uint16_t reason;
8664203945Sweongyo
8665203945Sweongyo	if (mac->mac_fw.opensource == 0)
8666203945Sweongyo		return;
8667203945Sweongyo
8668203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
8669203945Sweongyo	switch (reason) {
8670203945Sweongyo	case BWN_DEBUGINTR_PANIC:
8671203945Sweongyo		bwn_handle_fwpanic(mac);
8672203945Sweongyo		break;
8673203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
8674203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
8675203945Sweongyo		break;
8676203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
8677203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
8678203945Sweongyo		break;
8679203945Sweongyo	case BWN_DEBUGINTR_MARKER:
8680203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
8681203945Sweongyo		break;
8682203945Sweongyo	default:
8683203945Sweongyo		device_printf(sc->sc_dev,
8684203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
8685203945Sweongyo	}
8686203945Sweongyo
8687203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
8688203945Sweongyo	    BWN_DEBUGINTR_ACK);
8689203945Sweongyo}
8690203945Sweongyo
8691203945Sweongyostatic void
8692203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
8693203945Sweongyo{
8694203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8695203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8696203945Sweongyo
8697203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
8698203945Sweongyo		bwn_psctl(mac, 0);
8699203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8700203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
8701203945Sweongyo}
8702203945Sweongyo
8703203945Sweongyostatic void
8704203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
8705203945Sweongyo{
8706203945Sweongyo
8707203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
8708203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
8709203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
8710203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
8711203945Sweongyo	}
8712203945Sweongyo}
8713203945Sweongyo
8714203945Sweongyostatic void
8715203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
8716203945Sweongyo{
8717203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8718203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8719203945Sweongyo	uint32_t cmd, beacon0, beacon1;
8720203945Sweongyo
8721203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
8722203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
8723203945Sweongyo		return;
8724203945Sweongyo
8725203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
8726203945Sweongyo
8727203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
8728203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
8729203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
8730203945Sweongyo
8731203945Sweongyo	if (beacon0 && beacon1) {
8732203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
8733203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
8734203945Sweongyo		return;
8735203945Sweongyo	}
8736203945Sweongyo
8737203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
8738203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
8739203945Sweongyo		bwn_load_beacon0(mac);
8740203945Sweongyo		bwn_load_beacon1(mac);
8741203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
8742203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
8743203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8744203945Sweongyo	} else {
8745203945Sweongyo		if (!beacon0) {
8746203945Sweongyo			bwn_load_beacon0(mac);
8747203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8748203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
8749203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8750203945Sweongyo		} else if (!beacon1) {
8751203945Sweongyo			bwn_load_beacon1(mac);
8752203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8753203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
8754203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8755203945Sweongyo		}
8756203945Sweongyo	}
8757203945Sweongyo}
8758203945Sweongyo
8759203945Sweongyostatic void
8760203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
8761203945Sweongyo{
8762203945Sweongyo	uint32_t tmp;
8763203945Sweongyo
8764203945Sweongyo	while (1) {
8765203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
8766203945Sweongyo		if (!(tmp & 0x00000008))
8767203945Sweongyo			break;
8768203945Sweongyo	}
8769203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
8770203945Sweongyo}
8771203945Sweongyo
8772203945Sweongyostatic void
8773203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
8774203945Sweongyo{
8775203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
8776203945Sweongyo	uint16_t tmp;
8777203945Sweongyo	uint8_t noise[4];
8778203945Sweongyo	uint8_t i, j;
8779203945Sweongyo	int32_t average;
8780203945Sweongyo
8781203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
8782203945Sweongyo		return;
8783203945Sweongyo
8784203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
8785203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
8786203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
8787203945Sweongyo	    noise[3] == 0x7f)
8788203945Sweongyo		goto new;
8789203945Sweongyo
8790203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
8791203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8792203945Sweongyo	i = mac->mac_noise.noi_nsamples;
8793203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
8794203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
8795203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
8796203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
8797203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
8798203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
8799203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
8800203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
8801203945Sweongyo	mac->mac_noise.noi_nsamples++;
8802203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
8803203945Sweongyo		average = 0;
8804203945Sweongyo		for (i = 0; i < 8; i++) {
8805203945Sweongyo			for (j = 0; j < 4; j++)
8806203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
8807203945Sweongyo		}
8808203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
8809203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
8810203945Sweongyo		if (tmp >= 8)
8811203945Sweongyo			average += 2;
8812203945Sweongyo		else
8813203945Sweongyo			average -= 25;
8814203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
8815203945Sweongyo
8816203945Sweongyo		mac->mac_stats.link_noise = average;
8817203945Sweongyo		mac->mac_noise.noi_running = 0;
8818203945Sweongyo		return;
8819203945Sweongyo	}
8820203945Sweongyonew:
8821203945Sweongyo	bwn_noise_gensample(mac);
8822203945Sweongyo}
8823203945Sweongyo
8824203945Sweongyostatic int
8825203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
8826203945Sweongyo{
8827203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
8828203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8829203945Sweongyo	unsigned int i;
8830203945Sweongyo
8831203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8832203945Sweongyo
8833203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8834203945Sweongyo		return (0);
8835203945Sweongyo
8836203945Sweongyo	for (i = 0; i < 5000; i++) {
8837203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
8838203945Sweongyo			break;
8839203945Sweongyo	}
8840203945Sweongyo	if (i >= 5000)
8841203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
8842203945Sweongyo	return ((i > 0) ? 1 : 0);
8843203945Sweongyo}
8844203945Sweongyo
8845203945Sweongyostatic void
8846203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
8847203945Sweongyo{
8848203945Sweongyo	int slot, curslot;
8849203945Sweongyo
8850203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
8851203945Sweongyo	curslot = dr->get_curslot(dr);
8852203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
8853203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8854203945Sweongyo
8855203945Sweongyo	slot = dr->dr_curslot;
8856203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
8857203945Sweongyo		bwn_dma_rxeof(dr, &slot);
8858203945Sweongyo
8859203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
8860203945Sweongyo	    BUS_DMASYNC_PREWRITE);
8861203945Sweongyo
8862203945Sweongyo	dr->set_curslot(dr, slot);
8863203945Sweongyo	dr->dr_curslot = slot;
8864203945Sweongyo}
8865203945Sweongyo
8866203945Sweongyostatic void
8867203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
8868203945Sweongyo{
8869203945Sweongyo	struct bwn_txstatus stat;
8870203945Sweongyo	uint32_t stat0, stat1;
8871203945Sweongyo	uint16_t tmp;
8872203945Sweongyo
8873203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8874203945Sweongyo
8875203945Sweongyo	while (1) {
8876203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
8877203945Sweongyo		if (!(stat0 & 0x00000001))
8878203945Sweongyo			break;
8879203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
8880203945Sweongyo
8881203945Sweongyo		stat.cookie = (stat0 >> 16);
8882203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
8883203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
8884203945Sweongyo		tmp = (stat0 & 0x0000ffff);
8885203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
8886203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
8887203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
8888203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
8889203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
8890203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
8891203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
8892203945Sweongyo
8893203945Sweongyo		bwn_handle_txeof(mac, &stat);
8894203945Sweongyo	}
8895203945Sweongyo}
8896203945Sweongyo
8897203945Sweongyostatic void
8898203945Sweongyobwn_hwreset(void *arg, int npending)
8899203945Sweongyo{
8900203945Sweongyo	struct bwn_mac *mac = arg;
8901203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8902203945Sweongyo	int error = 0;
8903203945Sweongyo	int prev_status;
8904203945Sweongyo
8905203945Sweongyo	BWN_LOCK(sc);
8906203945Sweongyo
8907203945Sweongyo	prev_status = mac->mac_status;
8908203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8909203945Sweongyo		bwn_core_stop(mac);
8910203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
8911203945Sweongyo		bwn_core_exit(mac);
8912203945Sweongyo
8913203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
8914203945Sweongyo		error = bwn_core_init(mac);
8915203945Sweongyo		if (error)
8916203945Sweongyo			goto out;
8917203945Sweongyo	}
8918203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8919203945Sweongyo		bwn_core_start(mac);
8920203945Sweongyoout:
8921203945Sweongyo	if (error) {
8922203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
8923203945Sweongyo		sc->sc_curmac = NULL;
8924203945Sweongyo	}
8925203945Sweongyo	BWN_UNLOCK(sc);
8926203945Sweongyo}
8927203945Sweongyo
8928203945Sweongyostatic void
8929203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
8930203945Sweongyo{
8931203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8932203945Sweongyo	uint16_t reason;
8933203945Sweongyo
8934203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
8935203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
8936203945Sweongyo
8937203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
8938203945Sweongyo		bwn_restart(mac, "ucode panic");
8939203945Sweongyo}
8940203945Sweongyo
8941203945Sweongyostatic void
8942203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
8943203945Sweongyo{
8944203945Sweongyo
8945203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8946203945Sweongyo}
8947203945Sweongyo
8948203945Sweongyostatic void
8949203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
8950203945Sweongyo{
8951203945Sweongyo
8952203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8953203945Sweongyo}
8954203945Sweongyo
8955203945Sweongyostatic uint32_t
8956203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
8957203945Sweongyo{
8958203945Sweongyo	uint32_t val = 0;
8959203945Sweongyo
8960203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
8961203945Sweongyo	val <<= 16;
8962203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
8963203945Sweongyo
8964203945Sweongyo	return (val);
8965203945Sweongyo}
8966203945Sweongyo
8967203945Sweongyostatic void
8968203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
8969203945Sweongyo{
8970203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
8971203945Sweongyo
8972203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
8973203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
8974203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
8975203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
8976203945Sweongyo}
8977203945Sweongyo
8978203945Sweongyostatic int
8979203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
8980203945Sweongyo{
8981204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8982203945Sweongyo
8983203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
8984203945Sweongyo}
8985203945Sweongyo
8986203945Sweongyostatic int
8987203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
8988203945Sweongyo{
8989204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8990203945Sweongyo
8991203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
8992203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8993203945Sweongyo	if (slot == dr->dr_numslots - 1)
8994203945Sweongyo		return (0);
8995203945Sweongyo	return (slot + 1);
8996203945Sweongyo}
8997203945Sweongyo
8998203945Sweongyostatic void
8999203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
9000203945Sweongyo{
9001203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
9002203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9003203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9004203945Sweongyo	struct bwn_dmadesc_generic *desc;
9005203945Sweongyo	struct bwn_dmadesc_meta *meta;
9006203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
9007203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9008203945Sweongyo	struct mbuf *m;
9009203945Sweongyo	uint32_t macstat;
9010203945Sweongyo	int32_t tmp;
9011203945Sweongyo	int cnt = 0;
9012203945Sweongyo	uint16_t len;
9013203945Sweongyo
9014203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
9015203945Sweongyo
9016203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
9017203945Sweongyo	m = meta->mt_m;
9018203945Sweongyo
9019203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
9020203945Sweongyo		ifp->if_ierrors++;
9021203945Sweongyo		return;
9022203945Sweongyo	}
9023203945Sweongyo
9024203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
9025203945Sweongyo	len = le16toh(rxhdr->frame_len);
9026203945Sweongyo	if (len <= 0) {
9027203945Sweongyo		ifp->if_ierrors++;
9028203945Sweongyo		return;
9029203945Sweongyo	}
9030203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
9031203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
9032203945Sweongyo		bwn_dma_set_redzone(dr, m);
9033203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9034203945Sweongyo		    BUS_DMASYNC_PREWRITE);
9035203945Sweongyo		return;
9036203945Sweongyo	}
9037203945Sweongyo	if (len > dr->dr_rx_bufsize) {
9038203945Sweongyo		tmp = len;
9039203945Sweongyo		while (1) {
9040203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
9041203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
9042203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9043203945Sweongyo			    BUS_DMASYNC_PREWRITE);
9044203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
9045203945Sweongyo			cnt++;
9046203945Sweongyo			tmp -= dr->dr_rx_bufsize;
9047203945Sweongyo			if (tmp <= 0)
9048203945Sweongyo				break;
9049203945Sweongyo		}
9050203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
9051203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
9052203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
9053203945Sweongyo		return;
9054203945Sweongyo	}
9055203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9056203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9057203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9058203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
9059203945Sweongyo			return;
9060203945Sweongyo		}
9061203945Sweongyo	}
9062203945Sweongyo
9063203945Sweongyo	m->m_pkthdr.rcvif = ifp;
9064203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
9065203945Sweongyo	m_adj(m, dr->dr_frameoffset);
9066203945Sweongyo
9067203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
9068203945Sweongyo}
9069203945Sweongyo
9070203945Sweongyostatic void
9071203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
9072203945Sweongyo{
9073203945Sweongyo	struct bwn_dma_ring *dr;
9074203945Sweongyo	struct bwn_dmadesc_generic *desc;
9075203945Sweongyo	struct bwn_dmadesc_meta *meta;
9076203945Sweongyo	struct bwn_node *bn;
9077203945Sweongyo	struct bwn_pio_txqueue *tq;
9078203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9079203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9080203945Sweongyo	struct ieee80211_node *ni;
9081203945Sweongyo	int slot;
9082203945Sweongyo
9083203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
9084203945Sweongyo
9085203945Sweongyo	if (status->im)
9086203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
9087203945Sweongyo	if (status->ampdu)
9088203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
9089203945Sweongyo	if (status->rtscnt) {
9090203945Sweongyo		if (status->rtscnt == 0xf)
9091203945Sweongyo			device_printf(sc->sc_dev, "TODO: RTS fail\n");
9092203945Sweongyo		else
9093203945Sweongyo			device_printf(sc->sc_dev, "TODO: RTS ok\n");
9094203945Sweongyo	}
9095203945Sweongyo
9096203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
9097203945Sweongyo		if (status->ack) {
9098203945Sweongyo			dr = bwn_dma_parse_cookie(mac, status,
9099203945Sweongyo			    status->cookie, &slot);
9100203945Sweongyo			if (dr == NULL) {
9101203945Sweongyo				device_printf(sc->sc_dev,
9102203945Sweongyo				    "failed to parse cookie\n");
9103203945Sweongyo				return;
9104203945Sweongyo			}
9105203945Sweongyo			while (1) {
9106203945Sweongyo				dr->getdesc(dr, slot, &desc, &meta);
9107203945Sweongyo				if (meta->mt_islast) {
9108203945Sweongyo					ni = meta->mt_ni;
9109203945Sweongyo					bn = (struct bwn_node *)ni;
9110203945Sweongyo					ieee80211_amrr_tx_complete(&bn->bn_amn,
9111203945Sweongyo					    status->ack, 0);
9112203945Sweongyo					break;
9113203945Sweongyo				}
9114203945Sweongyo				slot = bwn_dma_nextslot(dr, slot);
9115203945Sweongyo			}
9116203945Sweongyo		}
9117203945Sweongyo		bwn_dma_handle_txeof(mac, status);
9118203945Sweongyo	} else {
9119203945Sweongyo		if (status->ack) {
9120203945Sweongyo			tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9121203945Sweongyo			if (tq == NULL) {
9122203945Sweongyo				device_printf(sc->sc_dev,
9123203945Sweongyo				    "failed to parse cookie\n");
9124203945Sweongyo				return;
9125203945Sweongyo			}
9126203945Sweongyo			ni = tp->tp_ni;
9127203945Sweongyo			bn = (struct bwn_node *)ni;
9128203945Sweongyo			ieee80211_amrr_tx_complete(&bn->bn_amn, status->ack, 0);
9129203945Sweongyo		}
9130203945Sweongyo		bwn_pio_handle_txeof(mac, status);
9131203945Sweongyo	}
9132203945Sweongyo
9133203945Sweongyo	bwn_phy_txpower_check(mac, 0);
9134203945Sweongyo}
9135203945Sweongyo
9136203945Sweongyostatic uint8_t
9137203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
9138203945Sweongyo{
9139203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
9140203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9141203945Sweongyo	struct bwn_rxhdr4 rxhdr;
9142203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9143203945Sweongyo	struct mbuf *m;
9144203945Sweongyo	uint32_t ctl32, macstat, v32;
9145203945Sweongyo	unsigned int i, padding;
9146203945Sweongyo	uint16_t ctl16, len, v16;
9147203945Sweongyo	unsigned char *mp;
9148203945Sweongyo	char *data;
9149203945Sweongyo
9150203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
9151203945Sweongyo
9152203945Sweongyo	if (prq->prq_rev >= 8) {
9153203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9154203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
9155203945Sweongyo			return (0);
9156203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9157203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
9158203945Sweongyo		for (i = 0; i < 10; i++) {
9159203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9160203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
9161203945Sweongyo				goto ready;
9162203945Sweongyo			DELAY(10);
9163203945Sweongyo		}
9164203945Sweongyo	} else {
9165203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9166203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
9167203945Sweongyo			return (0);
9168203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
9169203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
9170203945Sweongyo		for (i = 0; i < 10; i++) {
9171203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9172203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
9173203945Sweongyo				goto ready;
9174203945Sweongyo			DELAY(10);
9175203945Sweongyo		}
9176203945Sweongyo	}
9177203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
9178203945Sweongyo	return (1);
9179203945Sweongyoready:
9180203945Sweongyo	if (prq->prq_rev >= 8)
9181203945Sweongyo		siba_read_multi_4(mac->mac_sd, &rxhdr, sizeof(rxhdr),
9182203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9183203945Sweongyo	else
9184203945Sweongyo		siba_read_multi_2(mac->mac_sd, &rxhdr, sizeof(rxhdr),
9185203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9186203945Sweongyo	len = le16toh(rxhdr.frame_len);
9187203945Sweongyo	if (len > 0x700) {
9188203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
9189203945Sweongyo		goto error;
9190203945Sweongyo	}
9191203945Sweongyo	if (len == 0) {
9192203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
9193203945Sweongyo		goto error;
9194203945Sweongyo	}
9195203945Sweongyo
9196203945Sweongyo	macstat = le32toh(rxhdr.mac_status);
9197203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9198203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9199203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
9200203945Sweongyo			goto error;
9201203945Sweongyo		}
9202203945Sweongyo	}
9203203945Sweongyo
9204203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9205203945Sweongyo	KASSERT(len + padding <= MCLBYTES, ("too big..\n"));
9206203945Sweongyo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
9207203945Sweongyo	if (m == NULL) {
9208203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
9209203945Sweongyo		goto error;
9210203945Sweongyo	}
9211203945Sweongyo	mp = mtod(m, unsigned char *);
9212203945Sweongyo	if (prq->prq_rev >= 8) {
9213203945Sweongyo		siba_read_multi_4(mac->mac_sd, mp + padding, (len & ~3),
9214203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9215203945Sweongyo		if (len & 3) {
9216203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
9217203945Sweongyo			data = &(mp[len + padding - 1]);
9218203945Sweongyo			switch (len & 3) {
9219203945Sweongyo			case 3:
9220203945Sweongyo				*data = (v32 >> 16);
9221203945Sweongyo				data--;
9222203945Sweongyo			case 2:
9223203945Sweongyo				*data = (v32 >> 8);
9224203945Sweongyo				data--;
9225203945Sweongyo			case 1:
9226203945Sweongyo				*data = v32;
9227203945Sweongyo			}
9228203945Sweongyo		}
9229203945Sweongyo	} else {
9230203945Sweongyo		siba_read_multi_2(mac->mac_sd, mp + padding, (len & ~1),
9231203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9232203945Sweongyo		if (len & 1) {
9233203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
9234203945Sweongyo			mp[len + padding - 1] = v16;
9235203945Sweongyo		}
9236203945Sweongyo	}
9237203945Sweongyo
9238203945Sweongyo	m->m_pkthdr.rcvif = ifp;
9239203945Sweongyo	m->m_len = m->m_pkthdr.len = len + padding;
9240203945Sweongyo
9241203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
9242203945Sweongyo
9243203945Sweongyo	return (1);
9244203945Sweongyoerror:
9245203945Sweongyo	if (prq->prq_rev >= 8)
9246203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9247203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
9248203945Sweongyo	else
9249203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
9250203945Sweongyo	return (1);
9251203945Sweongyo}
9252203945Sweongyo
9253203945Sweongyostatic int
9254203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
9255203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
9256203945Sweongyo{
9257203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
9258203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9259203945Sweongyo	struct bwn_rxhdr4 *hdr;
9260203945Sweongyo	bus_dmamap_t map;
9261203945Sweongyo	bus_addr_t paddr;
9262203945Sweongyo	struct mbuf *m;
9263203945Sweongyo	int error;
9264203945Sweongyo
9265203945Sweongyo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
9266203945Sweongyo	if (m == NULL) {
9267203945Sweongyo		error = ENOBUFS;
9268203945Sweongyo
9269203945Sweongyo		/*
9270203945Sweongyo		 * If the NIC is up and running, we need to:
9271203945Sweongyo		 * - Clear RX buffer's header.
9272203945Sweongyo		 * - Restore RX descriptor settings.
9273203945Sweongyo		 */
9274203945Sweongyo		if (init)
9275203945Sweongyo			return (error);
9276203945Sweongyo		else
9277203945Sweongyo			goto back;
9278203945Sweongyo	}
9279203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
9280203945Sweongyo
9281203945Sweongyo	bwn_dma_set_redzone(dr, m);
9282203945Sweongyo
9283203945Sweongyo	/*
9284203945Sweongyo	 * Try to load RX buf into temporary DMA map
9285203945Sweongyo	 */
9286203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
9287203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
9288203945Sweongyo	if (error) {
9289203945Sweongyo		m_freem(m);
9290203945Sweongyo
9291203945Sweongyo		/*
9292203945Sweongyo		 * See the comment above
9293203945Sweongyo		 */
9294203945Sweongyo		if (init)
9295203945Sweongyo			return (error);
9296203945Sweongyo		else
9297203945Sweongyo			goto back;
9298203945Sweongyo	}
9299203945Sweongyo
9300203945Sweongyo	if (!init)
9301203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
9302203945Sweongyo	meta->mt_m = m;
9303203945Sweongyo	meta->mt_paddr = paddr;
9304203945Sweongyo
9305203945Sweongyo	/*
9306203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
9307203945Sweongyo	 */
9308203945Sweongyo	map = meta->mt_dmap;
9309203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
9310203945Sweongyo	dr->dr_spare_dmap = map;
9311203945Sweongyo
9312203945Sweongyoback:
9313203945Sweongyo	/*
9314203945Sweongyo	 * Clear RX buf header
9315203945Sweongyo	 */
9316203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
9317203945Sweongyo	bzero(hdr, sizeof(*hdr));
9318203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9319203945Sweongyo	    BUS_DMASYNC_PREWRITE);
9320203945Sweongyo
9321203945Sweongyo	/*
9322203945Sweongyo	 * Setup RX buf descriptor
9323203945Sweongyo	 */
9324203945Sweongyo	dr->setdesc(dr, desc, paddr, meta->mt_m->m_len -
9325203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
9326203945Sweongyo	return (error);
9327203945Sweongyo}
9328203945Sweongyo
9329203945Sweongyostatic void
9330203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
9331203945Sweongyo		 bus_size_t mapsz __unused, int error)
9332203945Sweongyo{
9333203945Sweongyo
9334203945Sweongyo	if (!error) {
9335203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
9336203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
9337203945Sweongyo	}
9338203945Sweongyo}
9339203945Sweongyo
9340203945Sweongyostatic int
9341203945Sweongyobwn_hwrate2ieeerate(int rate)
9342203945Sweongyo{
9343203945Sweongyo
9344203945Sweongyo	switch (rate) {
9345203945Sweongyo	case BWN_CCK_RATE_1MB:
9346203945Sweongyo		return (2);
9347203945Sweongyo	case BWN_CCK_RATE_2MB:
9348203945Sweongyo		return (4);
9349203945Sweongyo	case BWN_CCK_RATE_5MB:
9350203945Sweongyo		return (11);
9351203945Sweongyo	case BWN_CCK_RATE_11MB:
9352203945Sweongyo		return (22);
9353203945Sweongyo	case BWN_OFDM_RATE_6MB:
9354203945Sweongyo		return (12);
9355203945Sweongyo	case BWN_OFDM_RATE_9MB:
9356203945Sweongyo		return (18);
9357203945Sweongyo	case BWN_OFDM_RATE_12MB:
9358203945Sweongyo		return (24);
9359203945Sweongyo	case BWN_OFDM_RATE_18MB:
9360203945Sweongyo		return (36);
9361203945Sweongyo	case BWN_OFDM_RATE_24MB:
9362203945Sweongyo		return (48);
9363203945Sweongyo	case BWN_OFDM_RATE_36MB:
9364203945Sweongyo		return (72);
9365203945Sweongyo	case BWN_OFDM_RATE_48MB:
9366203945Sweongyo		return (96);
9367203945Sweongyo	case BWN_OFDM_RATE_54MB:
9368203945Sweongyo		return (108);
9369203945Sweongyo	default:
9370203945Sweongyo		printf("Ooops\n");
9371203945Sweongyo		return (0);
9372203945Sweongyo	}
9373203945Sweongyo}
9374203945Sweongyo
9375203945Sweongyostatic void
9376203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
9377203945Sweongyo{
9378203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
9379203945Sweongyo	struct bwn_plcp6 *plcp;
9380203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9381203945Sweongyo	struct ieee80211_frame_min *wh;
9382203945Sweongyo	struct ieee80211_node *ni;
9383203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9384203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9385203945Sweongyo	uint32_t macstat;
9386204242Simp	int padding, rate, rssi = 0, noise = 0, type;
9387203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
9388203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
9389204242Simp	static int rx_mac_dec_rpt = 0;
9390203945Sweongyo
9391203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9392203945Sweongyo
9393203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
9394203945Sweongyo	phystat3 = le16toh(rxhdr->phy_status3);
9395203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9396203945Sweongyo	chanstat = le16toh(rxhdr->channel);
9397203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
9398203945Sweongyo
9399203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
9400203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
9401203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
9402203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
9403203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_SHORTPRMBL)
9404203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_SHORTPRE\n");
9405203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
9406203945Sweongyo		goto drop;
9407203945Sweongyo
9408203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9409203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
9410204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9411204081Sweongyo		    m->m_pkthdr.len);
9412203945Sweongyo		goto drop;
9413203945Sweongyo	}
9414203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
9415203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
9416203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
9417204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9418204081Sweongyo		    m->m_pkthdr.len);
9419203945Sweongyo		goto drop;
9420203945Sweongyo	}
9421203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
9422203945Sweongyo
9423204242Simp	if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
9424204081Sweongyo		device_printf(sc->sc_dev,
9425204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
9426204081Sweongyo		    BWN_ISOLDFMT(mac),
9427204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
9428203945Sweongyo
9429203945Sweongyo	/* XXX calculating RSSI & noise & antenna */
9430203945Sweongyo
9431203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
9432203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
9433203945Sweongyo		    phytype == BWN_PHYTYPE_A);
9434203945Sweongyo	else
9435203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
9436203945Sweongyo	if (rate == -1) {
9437203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
9438203945Sweongyo			goto drop;
9439203945Sweongyo	}
9440203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
9441203945Sweongyo
9442203945Sweongyo	/* RX radio tap */
9443203945Sweongyo	if (ieee80211_radiotap_active(ic))
9444203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
9445203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
9446203945Sweongyo
9447203945Sweongyo	rssi = rxhdr->phy.abg.rssi;	/* XXX incorrect RSSI calculation? */
9448203945Sweongyo	noise = mac->mac_stats.link_noise;
9449203945Sweongyo
9450203945Sweongyo	BWN_UNLOCK(sc);
9451203945Sweongyo
9452203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
9453203945Sweongyo	if (ni != NULL) {
9454203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
9455203945Sweongyo		ieee80211_free_node(ni);
9456203945Sweongyo	} else
9457203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
9458203945Sweongyo
9459203945Sweongyo	BWN_LOCK(sc);
9460203945Sweongyo	return;
9461203945Sweongyodrop:
9462203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
9463203945Sweongyo}
9464203945Sweongyo
9465203945Sweongyostatic void
9466203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
9467203945Sweongyo    const struct bwn_txstatus *status)
9468203945Sweongyo{
9469203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9470203945Sweongyo	struct bwn_dma_ring *dr;
9471203945Sweongyo	struct bwn_dmadesc_generic *desc;
9472203945Sweongyo	struct bwn_dmadesc_meta *meta;
9473203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9474203945Sweongyo	struct ieee80211_node *ni;
9475203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9476203945Sweongyo	struct mbuf *m;
9477203945Sweongyo	int slot;
9478203945Sweongyo
9479203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9480203945Sweongyo
9481203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
9482203945Sweongyo	if (dr == NULL) {
9483203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
9484203945Sweongyo		return;
9485203945Sweongyo	}
9486203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
9487203945Sweongyo
9488203945Sweongyo	while (1) {
9489203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
9490203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9491203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
9492203945Sweongyo
9493203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
9494203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
9495203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
9496203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
9497203945Sweongyo
9498203945Sweongyo		if (meta->mt_islast) {
9499203945Sweongyo			KASSERT(meta->mt_m != NULL,
9500203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9501203945Sweongyo
9502203945Sweongyo			ni = meta->mt_ni;
9503203945Sweongyo			m = meta->mt_m;
9504203945Sweongyo			if (ni != NULL) {
9505203945Sweongyo				/*
9506203945Sweongyo				 * Do any tx complete callback. Note this must
9507203945Sweongyo				 * be done before releasing the node reference.
9508203945Sweongyo				 */
9509203945Sweongyo				if (m->m_flags & M_TXCB)
9510203945Sweongyo					ieee80211_process_callback(ni, m, 0);
9511203945Sweongyo				ieee80211_free_node(ni);
9512203945Sweongyo				meta->mt_ni = NULL;
9513203945Sweongyo			}
9514203945Sweongyo			m_freem(m);
9515203945Sweongyo			meta->mt_m = NULL;
9516203945Sweongyo		} else {
9517203945Sweongyo			KASSERT(meta->mt_m == NULL,
9518203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9519203945Sweongyo		}
9520203945Sweongyo
9521203945Sweongyo		dr->dr_usedslot--;
9522203945Sweongyo		if (meta->mt_islast) {
9523203945Sweongyo			ifp->if_opackets++;
9524203945Sweongyo			break;
9525203945Sweongyo		}
9526203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
9527203945Sweongyo	}
9528203945Sweongyo	sc->sc_watchdog_timer = 0;
9529203945Sweongyo	if (dr->dr_stop) {
9530203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
9531203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9532203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9533203945Sweongyo		dr->dr_stop = 0;
9534203945Sweongyo	}
9535203945Sweongyo}
9536203945Sweongyo
9537203945Sweongyostatic void
9538203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
9539203945Sweongyo    const struct bwn_txstatus *status)
9540203945Sweongyo{
9541203945Sweongyo	struct bwn_pio_txqueue *tq;
9542203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9543203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9544203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9545203945Sweongyo
9546203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9547203945Sweongyo
9548203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9549203945Sweongyo	if (tq == NULL)
9550203945Sweongyo		return;
9551203945Sweongyo
9552203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
9553203945Sweongyo	tq->tq_free++;
9554203945Sweongyo
9555203945Sweongyo	if (tp->tp_ni != NULL) {
9556203945Sweongyo		/*
9557203945Sweongyo		 * Do any tx complete callback.  Note this must
9558203945Sweongyo		 * be done before releasing the node reference.
9559203945Sweongyo		 */
9560203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
9561203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
9562203945Sweongyo		ieee80211_free_node(tp->tp_ni);
9563203945Sweongyo		tp->tp_ni = NULL;
9564203945Sweongyo	}
9565203945Sweongyo	m_freem(tp->tp_m);
9566203945Sweongyo	tp->tp_m = NULL;
9567203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
9568203945Sweongyo
9569203945Sweongyo	ifp->if_opackets++;
9570203945Sweongyo
9571203945Sweongyo	sc->sc_watchdog_timer = 0;
9572203945Sweongyo	if (tq->tq_stop) {
9573203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9574203945Sweongyo		tq->tq_stop = 0;
9575203945Sweongyo	}
9576203945Sweongyo}
9577203945Sweongyo
9578203945Sweongyostatic void
9579203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
9580203945Sweongyo{
9581203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9582203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
9583203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9584203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9585203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
9586203945Sweongyo	unsigned long now;
9587203945Sweongyo	int result;
9588203945Sweongyo
9589203945Sweongyo	BWN_GETTIME(now);
9590203945Sweongyo
9591203945Sweongyo	if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
9592203945Sweongyo		return;
9593203945Sweongyo	phy->nexttime = now + 2 * 1000;
9594203945Sweongyo
9595203945Sweongyo	if (siba->siba_board_vendor == SIBA_BOARDVENDOR_BCM &&
9596203945Sweongyo	    siba->siba_board_type == SIBA_BOARD_BU4306)
9597203945Sweongyo		return;
9598203945Sweongyo
9599203945Sweongyo	if (phy->recalc_txpwr != NULL) {
9600203945Sweongyo		result = phy->recalc_txpwr(mac,
9601203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
9602203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
9603203945Sweongyo			return;
9604203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
9605203945Sweongyo		    ("%s: fail", __func__));
9606203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
9607203945Sweongyo
9608203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
9609203945Sweongyo	}
9610203945Sweongyo}
9611203945Sweongyo
9612203945Sweongyostatic uint16_t
9613203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
9614203945Sweongyo{
9615203945Sweongyo
9616203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
9617203945Sweongyo}
9618203945Sweongyo
9619203945Sweongyostatic uint32_t
9620203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
9621203945Sweongyo{
9622203945Sweongyo
9623203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
9624203945Sweongyo}
9625203945Sweongyo
9626203945Sweongyostatic void
9627203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
9628203945Sweongyo{
9629203945Sweongyo
9630203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
9631203945Sweongyo}
9632203945Sweongyo
9633203945Sweongyostatic void
9634203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
9635203945Sweongyo{
9636203945Sweongyo
9637203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
9638203945Sweongyo}
9639203945Sweongyo
9640203945Sweongyostatic int
9641203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
9642203945Sweongyo{
9643203945Sweongyo
9644203945Sweongyo	switch (rate) {
9645203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
9646203945Sweongyo	case 12:
9647203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9648203945Sweongyo	case 18:
9649203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9650203945Sweongyo	case 24:
9651203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9652203945Sweongyo	case 36:
9653203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9654203945Sweongyo	case 48:
9655203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9656203945Sweongyo	case 72:
9657203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9658203945Sweongyo	case 96:
9659203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9660203945Sweongyo	case 108:
9661203945Sweongyo		return (BWN_OFDM_RATE_54MB);
9662203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
9663203945Sweongyo	case 2:
9664203945Sweongyo		return (BWN_CCK_RATE_1MB);
9665203945Sweongyo	case 4:
9666203945Sweongyo		return (BWN_CCK_RATE_2MB);
9667203945Sweongyo	case 11:
9668203945Sweongyo		return (BWN_CCK_RATE_5MB);
9669203945Sweongyo	case 22:
9670203945Sweongyo		return (BWN_CCK_RATE_11MB);
9671203945Sweongyo	}
9672203945Sweongyo
9673203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
9674203945Sweongyo	return (BWN_CCK_RATE_1MB);
9675203945Sweongyo}
9676203945Sweongyo
9677203945Sweongyostatic int
9678203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
9679203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
9680203945Sweongyo{
9681203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
9682203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9683203945Sweongyo	struct ieee80211_frame *wh;
9684203945Sweongyo	struct ieee80211_frame *protwh;
9685203945Sweongyo	struct ieee80211_frame_cts *cts;
9686203945Sweongyo	struct ieee80211_frame_rts *rts;
9687203945Sweongyo	const struct ieee80211_txparam *tp;
9688203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
9689203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9690203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9691203945Sweongyo	struct mbuf *mprot;
9692203945Sweongyo	unsigned int len;
9693203945Sweongyo	uint32_t macctl = 0;
9694203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
9695203945Sweongyo	uint16_t phyctl = 0;
9696203945Sweongyo	uint8_t rate, rate_fb;
9697203945Sweongyo
9698203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
9699203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
9700203945Sweongyo
9701203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
9702203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
9703203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
9704203945Sweongyo
9705203945Sweongyo	/*
9706203945Sweongyo	 * Find TX rate
9707203945Sweongyo	 */
9708203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
9709203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
9710203945Sweongyo		rate = rate_fb = tp->mgmtrate;
9711203945Sweongyo	else if (ismcast)
9712203945Sweongyo		rate = rate_fb = tp->mcastrate;
9713203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
9714203945Sweongyo		rate = rate_fb = tp->ucastrate;
9715203945Sweongyo	else {
9716203945Sweongyo		rix = ieee80211_amrr_choose(ni, &BWN_NODE(ni)->bn_amn);
9717203945Sweongyo		rate = ni->ni_txrate;
9718203945Sweongyo
9719203945Sweongyo		if (rix > 0)
9720203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
9721203945Sweongyo			    IEEE80211_RATE_VAL;
9722203945Sweongyo		else
9723203945Sweongyo			rate_fb = rate;
9724203945Sweongyo	}
9725203945Sweongyo
9726203945Sweongyo	sc->sc_tx_rate = rate;
9727203945Sweongyo
9728203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
9729203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
9730203945Sweongyo
9731203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
9732203945Sweongyo	    bwn_plcp_getcck(rate);
9733203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
9734203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
9735203945Sweongyo
9736203945Sweongyo	if ((rate_fb == rate) ||
9737203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
9738203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
9739203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
9740203945Sweongyo	else
9741203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
9742203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
9743203945Sweongyo
9744203945Sweongyo	/* XXX TX encryption */
9745203945Sweongyo	bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
9746203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
9747203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
9748203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
9749203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
9750203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
9751203945Sweongyo
9752203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
9753203945Sweongyo	    BWN_TX_EFT_FB_CCK;
9754203945Sweongyo	txhdr->chan = phy->chan;
9755203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
9756203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
9757203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9758203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
9759203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
9760203945Sweongyo
9761203945Sweongyo	/* XXX TX antenna selection */
9762203945Sweongyo
9763203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
9764203945Sweongyo	case 0:
9765203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
9766203945Sweongyo		break;
9767203945Sweongyo	case 1:
9768203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
9769203945Sweongyo		break;
9770203945Sweongyo	case 2:
9771203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
9772203945Sweongyo		break;
9773203945Sweongyo	case 3:
9774203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
9775203945Sweongyo		break;
9776203945Sweongyo	case 4:
9777203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
9778203945Sweongyo		break;
9779203945Sweongyo	default:
9780203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9781203945Sweongyo	}
9782203945Sweongyo
9783203945Sweongyo	if (!ismcast)
9784203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
9785203945Sweongyo
9786203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
9787203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
9788203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
9789203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
9790203945Sweongyo
9791203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
9792203945Sweongyo		/* XXX RTS rate is always 1MB??? */
9793203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
9794203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
9795203945Sweongyo
9796203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
9797203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
9798203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
9799203945Sweongyo
9800203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
9801203945Sweongyo			cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
9802203945Sweongyo			    (txhdr->body.old.rts_frame) :
9803203945Sweongyo			    (txhdr->body.new.rts_frame));
9804203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
9805203945Sweongyo			    protdur);
9806203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9807203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
9808203945Sweongyo			    mprot->m_pkthdr.len);
9809203945Sweongyo			m_freem(mprot);
9810203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
9811203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
9812203945Sweongyo		} else {
9813203945Sweongyo			rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
9814203945Sweongyo			    (txhdr->body.old.rts_frame) :
9815203945Sweongyo			    (txhdr->body.new.rts_frame));
9816203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
9817203945Sweongyo			    isshort);
9818203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
9819203945Sweongyo			    wh->i_addr2, protdur);
9820203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9821203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
9822203945Sweongyo			    mprot->m_pkthdr.len);
9823203945Sweongyo			m_freem(mprot);
9824203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
9825203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
9826203945Sweongyo		}
9827203945Sweongyo		len += IEEE80211_CRC_LEN;
9828203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
9829203945Sweongyo		    &txhdr->body.old.rts_plcp :
9830203945Sweongyo		    &txhdr->body.new.rts_plcp), len, rts_rate);
9831203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
9832203945Sweongyo		    rts_rate_fb);
9833203945Sweongyo
9834203945Sweongyo		protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
9835203945Sweongyo		    (&txhdr->body.old.rts_frame) :
9836203945Sweongyo		    (&txhdr->body.new.rts_frame));
9837203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
9838203945Sweongyo
9839203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
9840203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
9841203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
9842203945Sweongyo		} else {
9843203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
9844203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
9845203945Sweongyo		}
9846203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
9847203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
9848203945Sweongyo	}
9849203945Sweongyo
9850203945Sweongyo	if (BWN_ISOLDFMT(mac))
9851203945Sweongyo		txhdr->body.old.cookie = htole16(cookie);
9852203945Sweongyo	else
9853203945Sweongyo		txhdr->body.new.cookie = htole16(cookie);
9854203945Sweongyo
9855203945Sweongyo	txhdr->macctl = htole32(macctl);
9856203945Sweongyo	txhdr->phyctl = htole16(phyctl);
9857203945Sweongyo
9858203945Sweongyo	/*
9859203945Sweongyo	 * TX radio tap
9860203945Sweongyo	 */
9861203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
9862203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
9863203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
9864203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
9865203945Sweongyo		if (isshort &&
9866203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9867203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
9868203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
9869203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
9870203945Sweongyo
9871203945Sweongyo		ieee80211_radiotap_tx(vap, m);
9872203945Sweongyo	}
9873203945Sweongyo
9874203945Sweongyo	return (0);
9875203945Sweongyo}
9876203945Sweongyo
9877203945Sweongyostatic void
9878203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
9879203945Sweongyo    const uint8_t rate)
9880203945Sweongyo{
9881203945Sweongyo	uint32_t d, plen;
9882203945Sweongyo	uint8_t *raw = plcp->o.raw;
9883203945Sweongyo
9884203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
9885203945Sweongyo		d = bwn_plcp_getofdm(rate);
9886203945Sweongyo		KASSERT(!(octets & 0xf000),
9887203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9888203945Sweongyo		d |= (octets << 5);
9889203945Sweongyo		plcp->o.data = htole32(d);
9890203945Sweongyo	} else {
9891203945Sweongyo		plen = octets * 16 / rate;
9892203945Sweongyo		if ((octets * 16 % rate) > 0) {
9893203945Sweongyo			plen++;
9894203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
9895203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
9896203945Sweongyo				raw[1] = 0x84;
9897203945Sweongyo			} else
9898203945Sweongyo				raw[1] = 0x04;
9899203945Sweongyo		} else
9900203945Sweongyo			raw[1] = 0x04;
9901203945Sweongyo		plcp->o.data |= htole32(plen << 16);
9902203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
9903203945Sweongyo	}
9904203945Sweongyo}
9905203945Sweongyo
9906203945Sweongyostatic uint8_t
9907203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
9908203945Sweongyo{
9909203945Sweongyo	uint8_t mask;
9910203945Sweongyo
9911203945Sweongyo	if (n == 0)
9912203945Sweongyo		return (0);
9913203945Sweongyo	if (mac->mac_phy.gmode)
9914203945Sweongyo		mask = mac->mac_sd->sd_bus->siba_sprom.ant_bg;
9915203945Sweongyo	else
9916203945Sweongyo		mask = mac->mac_sd->sd_bus->siba_sprom.ant_a;
9917203945Sweongyo	if (!(mask & (1 << (n - 1))))
9918203945Sweongyo		return (0);
9919203945Sweongyo	return (n);
9920203945Sweongyo}
9921203945Sweongyo
9922203945Sweongyostatic uint8_t
9923203945Sweongyobwn_get_fbrate(uint8_t bitrate)
9924203945Sweongyo{
9925203945Sweongyo	switch (bitrate) {
9926203945Sweongyo	case BWN_CCK_RATE_1MB:
9927203945Sweongyo		return (BWN_CCK_RATE_1MB);
9928203945Sweongyo	case BWN_CCK_RATE_2MB:
9929203945Sweongyo		return (BWN_CCK_RATE_1MB);
9930203945Sweongyo	case BWN_CCK_RATE_5MB:
9931203945Sweongyo		return (BWN_CCK_RATE_2MB);
9932203945Sweongyo	case BWN_CCK_RATE_11MB:
9933203945Sweongyo		return (BWN_CCK_RATE_5MB);
9934203945Sweongyo	case BWN_OFDM_RATE_6MB:
9935203945Sweongyo		return (BWN_CCK_RATE_5MB);
9936203945Sweongyo	case BWN_OFDM_RATE_9MB:
9937203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9938203945Sweongyo	case BWN_OFDM_RATE_12MB:
9939203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9940203945Sweongyo	case BWN_OFDM_RATE_18MB:
9941203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9942203945Sweongyo	case BWN_OFDM_RATE_24MB:
9943203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9944203945Sweongyo	case BWN_OFDM_RATE_36MB:
9945203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9946203945Sweongyo	case BWN_OFDM_RATE_48MB:
9947203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9948203945Sweongyo	case BWN_OFDM_RATE_54MB:
9949203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9950203945Sweongyo	}
9951203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9952203945Sweongyo	return (0);
9953203945Sweongyo}
9954203945Sweongyo
9955203945Sweongyostatic uint32_t
9956203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9957203945Sweongyo    uint32_t ctl, const void *_data, int len)
9958203945Sweongyo{
9959203945Sweongyo	uint32_t value = 0;
9960203945Sweongyo	const uint8_t *data = _data;
9961203945Sweongyo
9962203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
9963203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
9964203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9965203945Sweongyo
9966203945Sweongyo	siba_write_multi_4(mac->mac_sd, data, (len & ~3),
9967203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
9968203945Sweongyo	if (len & 3) {
9969203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
9970203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
9971203945Sweongyo		data = &(data[len - 1]);
9972203945Sweongyo		switch (len & 3) {
9973203945Sweongyo		case 3:
9974203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
9975203945Sweongyo			value |= (uint32_t)(*data) << 16;
9976203945Sweongyo			data--;
9977203945Sweongyo		case 2:
9978203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
9979203945Sweongyo			value |= (uint32_t)(*data) << 8;
9980203945Sweongyo			data--;
9981203945Sweongyo		case 1:
9982203945Sweongyo			value |= (uint32_t)(*data);
9983203945Sweongyo		}
9984203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9985203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
9986203945Sweongyo	}
9987203945Sweongyo
9988203945Sweongyo	return (ctl);
9989203945Sweongyo}
9990203945Sweongyo
9991203945Sweongyostatic void
9992203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9993203945Sweongyo    uint16_t offset, uint32_t value)
9994203945Sweongyo{
9995203945Sweongyo
9996203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
9997203945Sweongyo}
9998203945Sweongyo
9999203945Sweongyostatic uint16_t
10000203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
10001203945Sweongyo    uint16_t ctl, const void *_data, int len)
10002203945Sweongyo{
10003203945Sweongyo	const uint8_t *data = _data;
10004203945Sweongyo
10005203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
10006203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10007203945Sweongyo
10008203945Sweongyo	siba_write_multi_2(mac->mac_sd, data, (len & ~1),
10009203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
10010203945Sweongyo	if (len & 1) {
10011203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
10012203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10013203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
10014203945Sweongyo	}
10015203945Sweongyo
10016203945Sweongyo	return (ctl);
10017203945Sweongyo}
10018203945Sweongyo
10019203945Sweongyostatic uint16_t
10020203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
10021203945Sweongyo    uint16_t ctl, struct mbuf *m0)
10022203945Sweongyo{
10023203945Sweongyo	int i, j = 0;
10024203945Sweongyo	uint16_t data = 0;
10025203945Sweongyo	const uint8_t *buf;
10026203945Sweongyo	struct mbuf *m = m0;
10027203945Sweongyo
10028203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
10029203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10030203945Sweongyo
10031203945Sweongyo	for (; m != NULL; m = m->m_next) {
10032203945Sweongyo		buf = mtod(m, const uint8_t *);
10033203945Sweongyo		for (i = 0; i < m->m_len; i++) {
10034203945Sweongyo			if (!((j++) % 2))
10035203945Sweongyo				data |= buf[i];
10036203945Sweongyo			else {
10037203945Sweongyo				data |= (buf[i] << 8);
10038203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
10039203945Sweongyo				data = 0;
10040203945Sweongyo			}
10041203945Sweongyo		}
10042203945Sweongyo	}
10043203945Sweongyo	if (m0->m_pkthdr.len % 2) {
10044203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
10045203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10046203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
10047203945Sweongyo	}
10048203945Sweongyo
10049203945Sweongyo	return (ctl);
10050203945Sweongyo}
10051203945Sweongyo
10052203945Sweongyostatic void
10053203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
10054203945Sweongyo{
10055203945Sweongyo
10056203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
10057203945Sweongyo		return;
10058203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
10059203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
10060203945Sweongyo}
10061203945Sweongyo
10062203945Sweongyostatic struct bwn_dma_ring *
10063203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
10064203945Sweongyo{
10065203945Sweongyo
10066203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
10067203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
10068203945Sweongyo
10069203945Sweongyo	switch (prio) {
10070203945Sweongyo	case 3:
10071203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
10072203945Sweongyo	case 2:
10073203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
10074203945Sweongyo	case 0:
10075203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
10076203945Sweongyo	case 1:
10077203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
10078203945Sweongyo	}
10079203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
10080204242Simp	return (NULL);
10081203945Sweongyo}
10082203945Sweongyo
10083203945Sweongyostatic int
10084203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
10085203945Sweongyo{
10086203945Sweongyo	int slot;
10087203945Sweongyo
10088204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
10089203945Sweongyo
10090203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
10091203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
10092203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
10093203945Sweongyo
10094203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
10095203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
10096203945Sweongyo	dr->dr_curslot = slot;
10097203945Sweongyo	dr->dr_usedslot++;
10098203945Sweongyo
10099203945Sweongyo	return (slot);
10100203945Sweongyo}
10101203945Sweongyo
10102203945Sweongyostatic int
10103203945Sweongyobwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
10104203945Sweongyo{
10105203945Sweongyo	const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
10106203945Sweongyo	unsigned int a, b, c, d;
10107203945Sweongyo	unsigned int avg;
10108203945Sweongyo	uint32_t tmp;
10109203945Sweongyo
10110203945Sweongyo	tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
10111203945Sweongyo	a = tmp & 0xff;
10112203945Sweongyo	b = (tmp >> 8) & 0xff;
10113203945Sweongyo	c = (tmp >> 16) & 0xff;
10114203945Sweongyo	d = (tmp >> 24) & 0xff;
10115203945Sweongyo	if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
10116203945Sweongyo	    c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
10117203945Sweongyo		return (ENOENT);
10118203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
10119203945Sweongyo	    BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
10120203945Sweongyo	    (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
10121203945Sweongyo
10122203945Sweongyo	if (ofdm) {
10123203945Sweongyo		a = (a + 32) & 0x3f;
10124203945Sweongyo		b = (b + 32) & 0x3f;
10125203945Sweongyo		c = (c + 32) & 0x3f;
10126203945Sweongyo		d = (d + 32) & 0x3f;
10127203945Sweongyo	}
10128203945Sweongyo
10129203945Sweongyo	avg = (a + b + c + d + 2) / 4;
10130203945Sweongyo	if (ofdm) {
10131203945Sweongyo		if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
10132203945Sweongyo		    & BWN_HF_4DB_CCK_POWERBOOST)
10133203945Sweongyo			avg = (avg >= 13) ? (avg - 13) : 0;
10134203945Sweongyo	}
10135203945Sweongyo	return (avg);
10136203945Sweongyo}
10137203945Sweongyo
10138203945Sweongyostatic void
10139203945Sweongyobwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
10140203945Sweongyo{
10141203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
10142203945Sweongyo	int rfatt = *rfattp;
10143203945Sweongyo	int bbatt = *bbattp;
10144203945Sweongyo
10145203945Sweongyo	while (1) {
10146203945Sweongyo		if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
10147203945Sweongyo			break;
10148203945Sweongyo		if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
10149203945Sweongyo			break;
10150203945Sweongyo		if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
10151203945Sweongyo			break;
10152203945Sweongyo		if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
10153203945Sweongyo			break;
10154203945Sweongyo		if (bbatt > lo->bbatt.max) {
10155203945Sweongyo			bbatt -= 4;
10156203945Sweongyo			rfatt += 1;
10157203945Sweongyo			continue;
10158203945Sweongyo		}
10159203945Sweongyo		if (bbatt < lo->bbatt.min) {
10160203945Sweongyo			bbatt += 4;
10161203945Sweongyo			rfatt -= 1;
10162203945Sweongyo			continue;
10163203945Sweongyo		}
10164203945Sweongyo		if (rfatt > lo->rfatt.max) {
10165203945Sweongyo			rfatt -= 1;
10166203945Sweongyo			bbatt += 4;
10167203945Sweongyo			continue;
10168203945Sweongyo		}
10169203945Sweongyo		if (rfatt < lo->rfatt.min) {
10170203945Sweongyo			rfatt += 1;
10171203945Sweongyo			bbatt -= 4;
10172203945Sweongyo			continue;
10173203945Sweongyo		}
10174203945Sweongyo		break;
10175203945Sweongyo	}
10176203945Sweongyo
10177203945Sweongyo	*rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
10178203945Sweongyo	*bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
10179203945Sweongyo}
10180203945Sweongyo
10181203945Sweongyostatic void
10182203945Sweongyobwn_phy_lock(struct bwn_mac *mac)
10183203945Sweongyo{
10184203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10185203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10186203945Sweongyo
10187203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
10188203945Sweongyo	    ("%s: unsupported rev %d", __func__, mac->mac_sd->sd_id.sd_rev));
10189203945Sweongyo
10190203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10191203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
10192203945Sweongyo}
10193203945Sweongyo
10194203945Sweongyostatic void
10195203945Sweongyobwn_phy_unlock(struct bwn_mac *mac)
10196203945Sweongyo{
10197203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10198203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10199203945Sweongyo
10200203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
10201203945Sweongyo	    ("%s: unsupported rev %d", __func__, mac->mac_sd->sd_id.sd_rev));
10202203945Sweongyo
10203203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10204203945Sweongyo		bwn_psctl(mac, 0);
10205203945Sweongyo}
10206203945Sweongyo
10207203945Sweongyostatic void
10208203945Sweongyobwn_rf_lock(struct bwn_mac *mac)
10209203945Sweongyo{
10210203945Sweongyo
10211203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10212203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
10213203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
10214203945Sweongyo	DELAY(10);
10215203945Sweongyo}
10216203945Sweongyo
10217203945Sweongyostatic void
10218203945Sweongyobwn_rf_unlock(struct bwn_mac *mac)
10219203945Sweongyo{
10220203945Sweongyo
10221203945Sweongyo	BWN_READ_2(mac, BWN_PHYVER);
10222203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10223203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
10224203945Sweongyo}
10225203945Sweongyo
10226203945Sweongyostatic struct bwn_pio_txqueue *
10227203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
10228203945Sweongyo    struct bwn_pio_txpkt **pack)
10229203945Sweongyo{
10230203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
10231203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
10232203945Sweongyo	unsigned int index;
10233203945Sweongyo
10234203945Sweongyo	switch (cookie & 0xf000) {
10235203945Sweongyo	case 0x1000:
10236203945Sweongyo		tq = &pio->wme[WME_AC_BK];
10237203945Sweongyo		break;
10238203945Sweongyo	case 0x2000:
10239203945Sweongyo		tq = &pio->wme[WME_AC_BE];
10240203945Sweongyo		break;
10241203945Sweongyo	case 0x3000:
10242203945Sweongyo		tq = &pio->wme[WME_AC_VI];
10243203945Sweongyo		break;
10244203945Sweongyo	case 0x4000:
10245203945Sweongyo		tq = &pio->wme[WME_AC_VO];
10246203945Sweongyo		break;
10247203945Sweongyo	case 0x5000:
10248203945Sweongyo		tq = &pio->mcast;
10249203945Sweongyo		break;
10250203945Sweongyo	}
10251203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
10252203945Sweongyo	if (tq == NULL)
10253203945Sweongyo		return (NULL);
10254203945Sweongyo	index = (cookie & 0x0fff);
10255203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
10256203945Sweongyo	if (index >= N(tq->tq_pkts))
10257203945Sweongyo		return (NULL);
10258203945Sweongyo	*pack = &tq->tq_pkts[index];
10259203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
10260203945Sweongyo	return (tq);
10261203945Sweongyo}
10262203945Sweongyo
10263203945Sweongyostatic void
10264203945Sweongyobwn_txpwr(void *arg, int npending)
10265203945Sweongyo{
10266203945Sweongyo	struct bwn_mac *mac = arg;
10267203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10268203945Sweongyo
10269203945Sweongyo	BWN_LOCK(sc);
10270203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
10271203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
10272203945Sweongyo		mac->mac_phy.set_txpwr(mac);
10273203945Sweongyo	BWN_UNLOCK(sc);
10274203945Sweongyo}
10275203945Sweongyo
10276203945Sweongyostatic void
10277203945Sweongyobwn_task_15s(struct bwn_mac *mac)
10278203945Sweongyo{
10279203945Sweongyo	uint16_t reg;
10280203945Sweongyo
10281203945Sweongyo	if (mac->mac_fw.opensource) {
10282203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
10283203945Sweongyo		if (reg) {
10284203945Sweongyo			bwn_restart(mac, "fw watchdog");
10285203945Sweongyo			return;
10286203945Sweongyo		}
10287203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
10288203945Sweongyo	}
10289203945Sweongyo	if (mac->mac_phy.task_15s)
10290203945Sweongyo		mac->mac_phy.task_15s(mac);
10291203945Sweongyo
10292203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
10293203945Sweongyo}
10294203945Sweongyo
10295203945Sweongyostatic void
10296203945Sweongyobwn_task_30s(struct bwn_mac *mac)
10297203945Sweongyo{
10298203945Sweongyo
10299203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
10300203945Sweongyo		return;
10301203945Sweongyo	mac->mac_noise.noi_running = 1;
10302203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
10303203945Sweongyo
10304203945Sweongyo	bwn_noise_gensample(mac);
10305203945Sweongyo}
10306203945Sweongyo
10307203945Sweongyostatic void
10308203945Sweongyobwn_task_60s(struct bwn_mac *mac)
10309203945Sweongyo{
10310203945Sweongyo
10311203945Sweongyo	if (mac->mac_phy.task_60s)
10312203945Sweongyo		mac->mac_phy.task_60s(mac);
10313203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
10314203945Sweongyo}
10315203945Sweongyo
10316203945Sweongyostatic void
10317203945Sweongyobwn_tasks(void *arg)
10318203945Sweongyo{
10319203945Sweongyo	struct bwn_mac *mac = arg;
10320203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10321203945Sweongyo
10322203945Sweongyo	BWN_ASSERT_LOCKED(sc);
10323203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
10324203945Sweongyo		return;
10325203945Sweongyo
10326203945Sweongyo	if (mac->mac_task_state % 4 == 0)
10327203945Sweongyo		bwn_task_60s(mac);
10328203945Sweongyo	if (mac->mac_task_state % 2 == 0)
10329203945Sweongyo		bwn_task_30s(mac);
10330203945Sweongyo	bwn_task_15s(mac);
10331203945Sweongyo
10332203945Sweongyo	mac->mac_task_state++;
10333203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
10334203945Sweongyo}
10335203945Sweongyo
10336203945Sweongyostatic int
10337203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
10338203945Sweongyo{
10339203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10340203945Sweongyo
10341203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
10342203945Sweongyo
10343203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
10344203945Sweongyo	case 0xb:
10345203945Sweongyo		return (BWN_OFDM_RATE_6MB);
10346203945Sweongyo	case 0xf:
10347203945Sweongyo		return (BWN_OFDM_RATE_9MB);
10348203945Sweongyo	case 0xa:
10349203945Sweongyo		return (BWN_OFDM_RATE_12MB);
10350203945Sweongyo	case 0xe:
10351203945Sweongyo		return (BWN_OFDM_RATE_18MB);
10352203945Sweongyo	case 0x9:
10353203945Sweongyo		return (BWN_OFDM_RATE_24MB);
10354203945Sweongyo	case 0xd:
10355203945Sweongyo		return (BWN_OFDM_RATE_36MB);
10356203945Sweongyo	case 0x8:
10357203945Sweongyo		return (BWN_OFDM_RATE_48MB);
10358203945Sweongyo	case 0xc:
10359203945Sweongyo		return (BWN_OFDM_RATE_54MB);
10360203945Sweongyo	}
10361203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
10362203945Sweongyo	    plcp->o.raw[0] & 0xf);
10363203945Sweongyo	return (-1);
10364203945Sweongyo}
10365203945Sweongyo
10366203945Sweongyostatic int
10367203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
10368203945Sweongyo{
10369203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10370203945Sweongyo
10371203945Sweongyo	switch (plcp->o.raw[0]) {
10372203945Sweongyo	case 0x0a:
10373203945Sweongyo		return (BWN_CCK_RATE_1MB);
10374203945Sweongyo	case 0x14:
10375203945Sweongyo		return (BWN_CCK_RATE_2MB);
10376203945Sweongyo	case 0x37:
10377203945Sweongyo		return (BWN_CCK_RATE_5MB);
10378203945Sweongyo	case 0x6e:
10379203945Sweongyo		return (BWN_CCK_RATE_11MB);
10380203945Sweongyo	}
10381203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
10382203945Sweongyo	return (-1);
10383203945Sweongyo}
10384203945Sweongyo
10385203945Sweongyostatic void
10386203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
10387203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
10388203945Sweongyo    int rssi, int noise)
10389203945Sweongyo{
10390203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10391203945Sweongyo	const struct ieee80211_frame_min *wh;
10392203945Sweongyo	uint64_t tsf;
10393203945Sweongyo	uint16_t low_mactime_now;
10394203945Sweongyo
10395203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
10396203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
10397203945Sweongyo
10398203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
10399203945Sweongyo	if (wh->i_fc[1] & IEEE80211_FC1_WEP)
10400203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
10401203945Sweongyo
10402203945Sweongyo	bwn_tsf_read(mac, &tsf);
10403203945Sweongyo	low_mactime_now = tsf;
10404203945Sweongyo	tsf = tsf & ~0xffffULL;
10405203945Sweongyo	tsf += le16toh(rxhdr->mac_time);
10406203945Sweongyo	if (low_mactime_now < le16toh(rxhdr->mac_time))
10407203945Sweongyo		tsf -= 0x10000;
10408203945Sweongyo
10409203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
10410203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
10411203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
10412203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
10413203945Sweongyo}
10414203945Sweongyo
10415203945Sweongyostatic void
10416203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
10417203945Sweongyo{
10418203945Sweongyo	uint32_t low, high;
10419203945Sweongyo
10420203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
10421203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
10422203945Sweongyo
10423203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
10424203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
10425203945Sweongyo	*tsf = high;
10426203945Sweongyo	*tsf <<= 32;
10427203945Sweongyo	*tsf |= low;
10428203945Sweongyo}
10429203945Sweongyo
10430203945Sweongyostatic int
10431203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
10432203945Sweongyo{
10433203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10434203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10435203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
10436203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
10437203945Sweongyo	bus_addr_t lowaddr = 0;
10438203945Sweongyo	int error;
10439203945Sweongyo
10440203945Sweongyo	if (siba->siba_type == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
10441203945Sweongyo		return (0);
10442203945Sweongyo
10443203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 5, ("%s: fail", __func__));
10444203945Sweongyo
10445203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
10446203945Sweongyo
10447203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
10448203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
10449203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
10450203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
10451203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
10452203945Sweongyo	else
10453203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
10454203945Sweongyo
10455203945Sweongyo	/*
10456203945Sweongyo	 * Create top level DMA tag
10457203945Sweongyo	 */
10458203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
10459203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
10460203945Sweongyo			       lowaddr,			/* lowaddr */
10461203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
10462203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
10463203945Sweongyo			       MAXBSIZE,		/* maxsize */
10464203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
10465203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
10466203945Sweongyo			       0,			/* flags */
10467203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
10468203945Sweongyo			       &dma->parent_dtag);
10469203945Sweongyo	if (error) {
10470203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
10471203945Sweongyo		return (error);
10472203945Sweongyo	}
10473203945Sweongyo
10474203945Sweongyo	/*
10475203945Sweongyo	 * Create TX/RX mbuf DMA tag
10476203945Sweongyo	 */
10477203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10478203945Sweongyo				1,
10479203945Sweongyo				0,
10480203945Sweongyo				BUS_SPACE_MAXADDR,
10481203945Sweongyo				BUS_SPACE_MAXADDR,
10482203945Sweongyo				NULL, NULL,
10483203945Sweongyo				MCLBYTES,
10484203945Sweongyo				1,
10485203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10486203945Sweongyo				0,
10487203945Sweongyo				NULL, NULL,
10488203945Sweongyo				&dma->rxbuf_dtag);
10489203945Sweongyo	if (error) {
10490203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10491203945Sweongyo		goto fail0;
10492203945Sweongyo	}
10493203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10494203945Sweongyo				1,
10495203945Sweongyo				0,
10496203945Sweongyo				BUS_SPACE_MAXADDR,
10497203945Sweongyo				BUS_SPACE_MAXADDR,
10498203945Sweongyo				NULL, NULL,
10499203945Sweongyo				MCLBYTES,
10500203945Sweongyo				1,
10501203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10502203945Sweongyo				0,
10503203945Sweongyo				NULL, NULL,
10504203945Sweongyo				&dma->txbuf_dtag);
10505203945Sweongyo	if (error) {
10506203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10507203945Sweongyo		goto fail1;
10508203945Sweongyo	}
10509203945Sweongyo
10510203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
10511203945Sweongyo	if (!dma->wme[WME_AC_BK])
10512203945Sweongyo		goto fail2;
10513203945Sweongyo
10514203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
10515203945Sweongyo	if (!dma->wme[WME_AC_BE])
10516203945Sweongyo		goto fail3;
10517203945Sweongyo
10518203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
10519203945Sweongyo	if (!dma->wme[WME_AC_VI])
10520203945Sweongyo		goto fail4;
10521203945Sweongyo
10522203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
10523203945Sweongyo	if (!dma->wme[WME_AC_VO])
10524203945Sweongyo		goto fail5;
10525203945Sweongyo
10526203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
10527203945Sweongyo	if (!dma->mcast)
10528203945Sweongyo		goto fail6;
10529203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
10530203945Sweongyo	if (!dma->rx)
10531203945Sweongyo		goto fail7;
10532203945Sweongyo
10533203945Sweongyo	return (error);
10534203945Sweongyo
10535203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
10536203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
10537203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
10538203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
10539203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
10540203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
10541203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
10542203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
10543203945Sweongyo	return (error);
10544203945Sweongyo}
10545203945Sweongyo
10546203945Sweongyostatic struct bwn_dma_ring *
10547203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
10548203945Sweongyo    uint16_t cookie, int *slot)
10549203945Sweongyo{
10550203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10551203945Sweongyo	struct bwn_dma_ring *dr;
10552203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10553203945Sweongyo
10554203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
10555203945Sweongyo
10556203945Sweongyo	switch (cookie & 0xf000) {
10557203945Sweongyo	case 0x1000:
10558203945Sweongyo		dr = dma->wme[WME_AC_BK];
10559203945Sweongyo		break;
10560203945Sweongyo	case 0x2000:
10561203945Sweongyo		dr = dma->wme[WME_AC_BE];
10562203945Sweongyo		break;
10563203945Sweongyo	case 0x3000:
10564203945Sweongyo		dr = dma->wme[WME_AC_VI];
10565203945Sweongyo		break;
10566203945Sweongyo	case 0x4000:
10567203945Sweongyo		dr = dma->wme[WME_AC_VO];
10568203945Sweongyo		break;
10569203945Sweongyo	case 0x5000:
10570203945Sweongyo		dr = dma->mcast;
10571203945Sweongyo		break;
10572203945Sweongyo	default:
10573204242Simp		dr = NULL;
10574203945Sweongyo		KASSERT(0 == 1,
10575203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
10576203945Sweongyo	}
10577203945Sweongyo	*slot = (cookie & 0x0fff);
10578203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
10579203945Sweongyo		/*
10580203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
10581203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
10582203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
10583203945Sweongyo		 */
10584203945Sweongyo		KASSERT(status->seq == dma->lastseq,
10585203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
10586203945Sweongyo		device_printf(sc->sc_dev,
10587203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
10588203945Sweongyo		    dr->dr_numslots);
10589203945Sweongyo		return (NULL);
10590203945Sweongyo	}
10591203945Sweongyo	dma->lastseq = status->seq;
10592203945Sweongyo	return (dr);
10593203945Sweongyo}
10594203945Sweongyo
10595203945Sweongyostatic void
10596203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
10597203945Sweongyo{
10598203945Sweongyo	struct bwn_dma *dma;
10599203945Sweongyo
10600203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
10601203945Sweongyo		return;
10602203945Sweongyo	dma = &mac->mac_method.dma;
10603203945Sweongyo
10604203945Sweongyo	bwn_dma_ringstop(&dma->rx);
10605203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
10606203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
10607203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
10608203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
10609203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
10610203945Sweongyo}
10611203945Sweongyo
10612203945Sweongyostatic void
10613203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
10614203945Sweongyo{
10615203945Sweongyo
10616203945Sweongyo	if (dr == NULL)
10617203945Sweongyo		return;
10618203945Sweongyo
10619203945Sweongyo	bwn_dma_cleanup(*dr);
10620203945Sweongyo}
10621203945Sweongyo
10622203945Sweongyostatic void
10623203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
10624203945Sweongyo{
10625203945Sweongyo	struct bwn_pio *pio;
10626203945Sweongyo
10627203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
10628203945Sweongyo		return;
10629203945Sweongyo	pio = &mac->mac_method.pio;
10630203945Sweongyo
10631203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
10632203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
10633203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
10634203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
10635203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
10636203945Sweongyo}
10637203945Sweongyo
10638203945Sweongyostatic void
10639203945Sweongyobwn_led_attach(struct bwn_mac *mac)
10640203945Sweongyo{
10641203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10642203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
10643203945Sweongyo	const uint8_t *led_act = NULL;
10644203945Sweongyo	uint16_t val[BWN_LED_MAX];
10645203945Sweongyo	int i;
10646203945Sweongyo
10647203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
10648203945Sweongyo	sc->sc_led_blink = 1;
10649203945Sweongyo
10650203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
10651203945Sweongyo		if (siba->siba_pci_subvid == bwn_vendor_led_act[i].vid) {
10652203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
10653203945Sweongyo			break;
10654203945Sweongyo		}
10655203945Sweongyo	}
10656203945Sweongyo	if (led_act == NULL)
10657203945Sweongyo		led_act = bwn_default_led_act;
10658203945Sweongyo
10659203945Sweongyo	val[0] = siba->siba_sprom.gpio0;
10660203945Sweongyo	val[1] = siba->siba_sprom.gpio1;
10661203945Sweongyo	val[2] = siba->siba_sprom.gpio2;
10662203945Sweongyo	val[3] = siba->siba_sprom.gpio3;
10663203945Sweongyo
10664203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10665203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10666203945Sweongyo
10667203945Sweongyo		if (val[i] == 0xff) {
10668203945Sweongyo			led->led_act = led_act[i];
10669203945Sweongyo		} else {
10670203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
10671203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
10672203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
10673203945Sweongyo		}
10674203945Sweongyo		led->led_mask = (1 << i);
10675203945Sweongyo
10676203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
10677203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
10678203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
10679203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
10680203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
10681203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
10682203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
10683203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
10684203945Sweongyo
10685203945Sweongyo			if (sc->sc_blink_led == NULL) {
10686203945Sweongyo				sc->sc_blink_led = led;
10687203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
10688203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
10689203945Sweongyo			}
10690203945Sweongyo		}
10691203945Sweongyo
10692203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
10693203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
10694203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
10695203945Sweongyo	}
10696203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
10697203945Sweongyo}
10698203945Sweongyo
10699203945Sweongyostatic __inline uint16_t
10700203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
10701203945Sweongyo{
10702203945Sweongyo
10703203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
10704203945Sweongyo		on = !on;
10705203945Sweongyo	if (on)
10706203945Sweongyo		val |= led->led_mask;
10707203945Sweongyo	else
10708203945Sweongyo		val &= ~led->led_mask;
10709203945Sweongyo	return val;
10710203945Sweongyo}
10711203945Sweongyo
10712203945Sweongyostatic void
10713203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
10714203945Sweongyo{
10715203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10716203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10717203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10718203945Sweongyo	uint16_t val;
10719203945Sweongyo	int i;
10720203945Sweongyo
10721203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
10722203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
10723203945Sweongyo		sc->sc_led_blinking = 0;
10724203945Sweongyo	}
10725203945Sweongyo
10726203945Sweongyo	if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
10727203945Sweongyo		return;
10728203945Sweongyo
10729203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10730203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10731203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10732203945Sweongyo		int on;
10733203945Sweongyo
10734203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
10735203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
10736203945Sweongyo			continue;
10737203945Sweongyo
10738203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
10739203945Sweongyo		    nstate != IEEE80211_S_INIT)
10740203945Sweongyo			continue;
10741203945Sweongyo
10742203945Sweongyo		switch (led->led_act) {
10743203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
10744203945Sweongyo			on = 1;
10745203945Sweongyo			break;
10746203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
10747203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
10748203945Sweongyo			on = 0;
10749203945Sweongyo			break;
10750203945Sweongyo		default:
10751203945Sweongyo			on = 1;
10752203945Sweongyo			switch (nstate) {
10753203945Sweongyo			case IEEE80211_S_INIT:
10754203945Sweongyo				on = 0;
10755203945Sweongyo				break;
10756203945Sweongyo			case IEEE80211_S_RUN:
10757203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
10758203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
10759203945Sweongyo					on = 0;
10760203945Sweongyo				break;
10761203945Sweongyo			default:
10762203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
10763203945Sweongyo					on = 0;
10764203945Sweongyo				break;
10765203945Sweongyo			}
10766203945Sweongyo			break;
10767203945Sweongyo		}
10768203945Sweongyo
10769203945Sweongyo		val = bwn_led_onoff(led, val, on);
10770203945Sweongyo	}
10771203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10772203945Sweongyo}
10773203945Sweongyo
10774203945Sweongyostatic void
10775203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
10776203945Sweongyo{
10777203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10778203945Sweongyo        struct bwn_led *led = sc->sc_blink_led;
10779203945Sweongyo        int rate;
10780203945Sweongyo
10781203945Sweongyo        if (event == BWN_LED_EVENT_POLL) {
10782203945Sweongyo                if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
10783203945Sweongyo                        return;
10784203945Sweongyo                if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
10785203945Sweongyo                        return;
10786203945Sweongyo        }
10787203945Sweongyo
10788203945Sweongyo        sc->sc_led_ticks = ticks;
10789203945Sweongyo        if (sc->sc_led_blinking)
10790203945Sweongyo                return;
10791203945Sweongyo
10792203945Sweongyo        switch (event) {
10793203945Sweongyo        case BWN_LED_EVENT_RX:
10794203945Sweongyo                rate = sc->sc_rx_rate;
10795203945Sweongyo                break;
10796203945Sweongyo        case BWN_LED_EVENT_TX:
10797203945Sweongyo                rate = sc->sc_tx_rate;
10798203945Sweongyo                break;
10799203945Sweongyo        case BWN_LED_EVENT_POLL:
10800203945Sweongyo                rate = 0;
10801203945Sweongyo                break;
10802203945Sweongyo        default:
10803203945Sweongyo                panic("unknown LED event %d\n", event);
10804203945Sweongyo                break;
10805203945Sweongyo        }
10806203945Sweongyo        bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
10807203945Sweongyo            bwn_led_duration[rate].off_dur);
10808203945Sweongyo}
10809203945Sweongyo
10810203945Sweongyostatic void
10811203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
10812203945Sweongyo{
10813203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10814203945Sweongyo        struct bwn_led *led = sc->sc_blink_led;
10815203945Sweongyo        uint16_t val;
10816203945Sweongyo
10817203945Sweongyo        val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10818203945Sweongyo        val = bwn_led_onoff(led, val, 1);
10819203945Sweongyo        BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10820203945Sweongyo
10821203945Sweongyo        if (led->led_flags & BWN_LED_F_SLOW) {
10822203945Sweongyo                BWN_LED_SLOWDOWN(on_dur);
10823203945Sweongyo                BWN_LED_SLOWDOWN(off_dur);
10824203945Sweongyo        }
10825203945Sweongyo
10826203945Sweongyo        sc->sc_led_blinking = 1;
10827203945Sweongyo        sc->sc_led_blink_offdur = off_dur;
10828203945Sweongyo
10829203945Sweongyo        callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
10830203945Sweongyo}
10831203945Sweongyo
10832203945Sweongyostatic void
10833203945Sweongyobwn_led_blink_next(void *arg)
10834203945Sweongyo{
10835203945Sweongyo	struct bwn_mac *mac = arg;
10836203945Sweongyo        struct bwn_softc *sc = mac->mac_sc;
10837203945Sweongyo        uint16_t val;
10838203945Sweongyo
10839203945Sweongyo        val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10840203945Sweongyo        val = bwn_led_onoff(sc->sc_blink_led, val, 0);
10841203945Sweongyo        BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10842203945Sweongyo
10843203945Sweongyo        callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
10844203945Sweongyo            bwn_led_blink_end, mac);
10845203945Sweongyo}
10846203945Sweongyo
10847203945Sweongyostatic void
10848203945Sweongyobwn_led_blink_end(void *arg)
10849203945Sweongyo{
10850203945Sweongyo	struct bwn_mac *mac = arg;
10851203945Sweongyo        struct bwn_softc *sc = mac->mac_sc;
10852203945Sweongyo
10853203945Sweongyo        sc->sc_led_blinking = 0;
10854203945Sweongyo}
10855203945Sweongyo
10856203945Sweongyostatic int
10857203945Sweongyobwn_suspend(device_t dev)
10858203945Sweongyo{
10859203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10860203945Sweongyo
10861203945Sweongyo	bwn_stop(sc, 1);
10862203945Sweongyo	return (0);
10863203945Sweongyo}
10864203945Sweongyo
10865203945Sweongyostatic int
10866203945Sweongyobwn_resume(device_t dev)
10867203945Sweongyo{
10868203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10869203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10870203945Sweongyo
10871203945Sweongyo	if (ifp->if_flags & IFF_UP)
10872203945Sweongyo		bwn_init(sc);
10873203945Sweongyo	return (0);
10874203945Sweongyo}
10875203945Sweongyo
10876203945Sweongyostatic void
10877203945Sweongyobwn_rfswitch(void *arg)
10878203945Sweongyo{
10879203945Sweongyo	struct bwn_softc *sc = arg;
10880203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
10881203945Sweongyo	int cur = 0, prev = 0;
10882203945Sweongyo
10883203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
10884203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
10885203945Sweongyo
10886203945Sweongyo	if (mac->mac_phy.rf_rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
10887203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
10888203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
10889203945Sweongyo			cur = 1;
10890203945Sweongyo	} else {
10891203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
10892203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
10893203945Sweongyo			cur = 1;
10894203945Sweongyo	}
10895203945Sweongyo
10896203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
10897203945Sweongyo		prev = 1;
10898203945Sweongyo
10899203945Sweongyo	if (cur != prev) {
10900203945Sweongyo		if (cur)
10901203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
10902203945Sweongyo		else
10903203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
10904203945Sweongyo
10905203945Sweongyo		device_printf(sc->sc_dev,
10906203945Sweongyo		    "status of RF switch is changed to %s\n",
10907203945Sweongyo		    cur ? "ON" : "OFF");
10908203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
10909203945Sweongyo			if (cur)
10910203945Sweongyo				bwn_rf_turnon(mac);
10911203945Sweongyo			else
10912203945Sweongyo				bwn_rf_turnoff(mac);
10913203945Sweongyo		}
10914203945Sweongyo	}
10915203945Sweongyo
10916203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
10917203945Sweongyo}
10918203945Sweongyo
10919203945Sweongyostatic void
10920203945Sweongyobwn_phy_lp_init_pre(struct bwn_mac *mac)
10921203945Sweongyo{
10922203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
10923203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
10924203945Sweongyo
10925203945Sweongyo	plp->plp_antenna = BWN_ANT_DEFAULT;
10926203945Sweongyo}
10927203945Sweongyo
10928203945Sweongyostatic int
10929203945Sweongyobwn_phy_lp_init(struct bwn_mac *mac)
10930203945Sweongyo{
10931203945Sweongyo	static const struct bwn_stxtable tables[] = {
10932203945Sweongyo		{ 2,  6, 0x3d, 3, 0x01 }, { 1, 12, 0x4c, 1, 0x01 },
10933203945Sweongyo		{ 1,  8, 0x50, 0, 0x7f }, { 0,  8, 0x44, 0, 0xff },
10934203945Sweongyo		{ 1,  0, 0x4a, 0, 0xff }, { 0,  4, 0x4d, 0, 0xff },
10935203945Sweongyo		{ 1,  4, 0x4e, 0, 0xff }, { 0, 12, 0x4f, 0, 0x0f },
10936203945Sweongyo		{ 1,  0, 0x4f, 4, 0x0f }, { 3,  0, 0x49, 0, 0x0f },
10937203945Sweongyo		{ 4,  3, 0x46, 4, 0x07 }, { 3, 15, 0x46, 0, 0x01 },
10938203945Sweongyo		{ 4,  0, 0x46, 1, 0x07 }, { 3,  8, 0x48, 4, 0x07 },
10939203945Sweongyo		{ 3, 11, 0x48, 0, 0x0f }, { 3,  4, 0x49, 4, 0x0f },
10940203945Sweongyo		{ 2, 15, 0x45, 0, 0x01 }, { 5, 13, 0x52, 4, 0x07 },
10941203945Sweongyo		{ 6,  0, 0x52, 7, 0x01 }, { 5,  3, 0x41, 5, 0x07 },
10942203945Sweongyo		{ 5,  6, 0x41, 0, 0x0f }, { 5, 10, 0x42, 5, 0x07 },
10943203945Sweongyo		{ 4, 15, 0x42, 0, 0x01 }, { 5,  0, 0x42, 1, 0x07 },
10944203945Sweongyo		{ 4, 11, 0x43, 4, 0x0f }, { 4,  7, 0x43, 0, 0x0f },
10945203945Sweongyo		{ 4,  6, 0x45, 1, 0x01 }, { 2,  7, 0x40, 4, 0x0f },
10946203945Sweongyo		{ 2, 11, 0x40, 0, 0x0f }
10947203945Sweongyo	};
10948203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
10949203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10950203945Sweongyo	const struct bwn_stxtable *st;
10951203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10952203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10953203945Sweongyo	int i, error;
10954203945Sweongyo	uint16_t tmp;
10955203945Sweongyo
10956203945Sweongyo	bwn_phy_lp_readsprom(mac);	/* XXX bad place */
10957203945Sweongyo	bwn_phy_lp_bbinit(mac);
10958203945Sweongyo
10959203945Sweongyo	/* initialize RF */
10960203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_4WIRECTL, 0x2);
10961203945Sweongyo	DELAY(1);
10962203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_4WIRECTL, 0xfffd);
10963203945Sweongyo	DELAY(1);
10964203945Sweongyo
10965203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2062)
10966203945Sweongyo		bwn_phy_lp_b2062_init(mac);
10967203945Sweongyo	else {
10968203945Sweongyo		bwn_phy_lp_b2063_init(mac);
10969203945Sweongyo
10970203945Sweongyo		/* synchronize stx table. */
10971203945Sweongyo		for (i = 0; i < N(tables); i++) {
10972203945Sweongyo			st = &tables[i];
10973203945Sweongyo			tmp = BWN_RF_READ(mac, st->st_rfaddr);
10974203945Sweongyo			tmp >>= st->st_rfshift;
10975203945Sweongyo			tmp <<= st->st_physhift;
10976203945Sweongyo			BWN_PHY_SETMASK(mac,
10977203945Sweongyo			    BWN_PHY_OFDM(0xf2 + st->st_phyoffset),
10978203945Sweongyo			    ~(st->st_mask << st->st_physhift), tmp);
10979203945Sweongyo		}
10980203945Sweongyo
10981203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf0), 0x5f80);
10982203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf1), 0);
10983203945Sweongyo	}
10984203945Sweongyo
10985203945Sweongyo	/* calibrate RC */
10986203945Sweongyo	if (mac->mac_phy.rev >= 2)
10987203945Sweongyo		bwn_phy_lp_rxcal_r2(mac);
10988203945Sweongyo	else if (!plp->plp_rccap) {
10989203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
10990203945Sweongyo			bwn_phy_lp_rccal_r12(mac);
10991203945Sweongyo	} else
10992203945Sweongyo		bwn_phy_lp_set_rccap(mac);
10993203945Sweongyo
10994203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
10995203945Sweongyo	if (error)
10996203945Sweongyo		device_printf(sc->sc_dev,
10997203945Sweongyo		    "failed to change channel 7 (%d)\n", error);
10998203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
10999203945Sweongyo	bwn_phy_lp_calib(mac);
11000203945Sweongyo	return (0);
11001203945Sweongyo}
11002203945Sweongyo
11003203945Sweongyostatic uint16_t
11004203945Sweongyobwn_phy_lp_read(struct bwn_mac *mac, uint16_t reg)
11005203945Sweongyo{
11006203945Sweongyo
11007203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
11008203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
11009203945Sweongyo}
11010203945Sweongyo
11011203945Sweongyostatic void
11012203945Sweongyobwn_phy_lp_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
11013203945Sweongyo{
11014203945Sweongyo
11015203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
11016203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
11017203945Sweongyo}
11018203945Sweongyo
11019203945Sweongyostatic void
11020203945Sweongyobwn_phy_lp_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
11021203945Sweongyo    uint16_t set)
11022203945Sweongyo{
11023203945Sweongyo
11024203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
11025203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA,
11026203945Sweongyo	    (BWN_READ_2(mac, BWN_PHYDATA) & mask) | set);
11027203945Sweongyo}
11028203945Sweongyo
11029203945Sweongyostatic uint16_t
11030203945Sweongyobwn_phy_lp_rf_read(struct bwn_mac *mac, uint16_t reg)
11031203945Sweongyo{
11032203945Sweongyo
11033203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
11034203945Sweongyo	if (mac->mac_phy.rev < 2 && reg != 0x4001)
11035203945Sweongyo		reg |= 0x100;
11036203945Sweongyo	if (mac->mac_phy.rev >= 2)
11037203945Sweongyo		reg |= 0x200;
11038203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
11039203945Sweongyo	return BWN_READ_2(mac, BWN_RFDATALO);
11040203945Sweongyo}
11041203945Sweongyo
11042203945Sweongyostatic void
11043203945Sweongyobwn_phy_lp_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
11044203945Sweongyo{
11045203945Sweongyo
11046203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
11047203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
11048203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
11049203945Sweongyo}
11050203945Sweongyo
11051203945Sweongyostatic void
11052203945Sweongyobwn_phy_lp_rf_onoff(struct bwn_mac *mac, int on)
11053203945Sweongyo{
11054203945Sweongyo
11055203945Sweongyo	if (on) {
11056203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xe0ff);
11057203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2,
11058203945Sweongyo		    (mac->mac_phy.rev >= 2) ? 0xf7f7 : 0xffe7);
11059203945Sweongyo		return;
11060203945Sweongyo	}
11061203945Sweongyo
11062203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11063203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x83ff);
11064203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
11065203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0x80ff);
11066203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xdfff);
11067203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0808);
11068203945Sweongyo		return;
11069203945Sweongyo	}
11070203945Sweongyo
11071203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xe0ff);
11072203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
11073203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfcff);
11074203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0018);
11075203945Sweongyo}
11076203945Sweongyo
11077203945Sweongyostatic int
11078203945Sweongyobwn_phy_lp_switch_channel(struct bwn_mac *mac, uint32_t chan)
11079203945Sweongyo{
11080203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11081203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11082203945Sweongyo	int error;
11083203945Sweongyo
11084203945Sweongyo	if (phy->rf_ver == 0x2063) {
11085203945Sweongyo		error = bwn_phy_lp_b2063_switch_channel(mac, chan);
11086203945Sweongyo		if (error)
11087203945Sweongyo			return (error);
11088203945Sweongyo	} else {
11089203945Sweongyo		error = bwn_phy_lp_b2062_switch_channel(mac, chan);
11090203945Sweongyo		if (error)
11091203945Sweongyo			return (error);
11092203945Sweongyo		bwn_phy_lp_set_anafilter(mac, chan);
11093203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, ieee80211_ieee2mhz(chan, 0));
11094203945Sweongyo	}
11095203945Sweongyo
11096203945Sweongyo	plp->plp_chan = chan;
11097203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, chan);
11098203945Sweongyo	return (0);
11099203945Sweongyo}
11100203945Sweongyo
11101203945Sweongyostatic uint32_t
11102203945Sweongyobwn_phy_lp_get_default_chan(struct bwn_mac *mac)
11103203945Sweongyo{
11104203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11105203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11106203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11107203945Sweongyo
11108203945Sweongyo	device_printf(sc->sc_dev, "correct?\n");
11109203945Sweongyo
11110203945Sweongyo	return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36);
11111203945Sweongyo}
11112203945Sweongyo
11113203945Sweongyostatic void
11114203945Sweongyobwn_phy_lp_set_antenna(struct bwn_mac *mac, int antenna)
11115203945Sweongyo{
11116203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11117203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11118203945Sweongyo
11119203945Sweongyo	if (phy->rev >= 2 || antenna > BWN_ANTAUTO1)
11120203945Sweongyo		return;
11121203945Sweongyo
11122203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER);
11123203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffd, antenna & 0x2);
11124203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffe, antenna & 0x1);
11125203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_UCODE_ANTDIV_HELPER);
11126203945Sweongyo	plp->plp_antenna = antenna;
11127203945Sweongyo}
11128203945Sweongyo
11129203945Sweongyostatic void
11130203945Sweongyobwn_phy_lp_task_60s(struct bwn_mac *mac)
11131203945Sweongyo{
11132203945Sweongyo
11133203945Sweongyo	bwn_phy_lp_calib(mac);
11134203945Sweongyo}
11135203945Sweongyo
11136203945Sweongyostatic void
11137203945Sweongyobwn_phy_lp_readsprom(struct bwn_mac *mac)
11138203945Sweongyo{
11139203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11140203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11141203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11142203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11143203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11144203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11145203945Sweongyo	struct siba_sprom *sprom = &siba->siba_sprom;
11146203945Sweongyo
11147203945Sweongyo	device_printf(sc->sc_dev, "XXX using %dghz\n",
11148203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2 : 5);
11149203945Sweongyo
11150203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11151203945Sweongyo		plp->plp_txisoband_m = sprom->tri2g;
11152203945Sweongyo		plp->plp_bxarch = sprom->bxa2g;
11153203945Sweongyo		plp->plp_rxpwroffset = sprom->rxpo2g;
11154203945Sweongyo		plp->plp_rssivf = sprom->rssismf2g;
11155203945Sweongyo		plp->plp_rssivc = sprom->rssismc2g;
11156203945Sweongyo		plp->plp_rssigs = sprom->rssisav2g;
11157203945Sweongyo		return;
11158203945Sweongyo	}
11159203945Sweongyo
11160203945Sweongyo	plp->plp_txisoband_l = sprom->tri5gl;
11161203945Sweongyo	plp->plp_txisoband_m = sprom->tri5g;
11162203945Sweongyo	plp->plp_txisoband_h = sprom->tri5gh;
11163203945Sweongyo	plp->plp_bxarch = sprom->bxa5g;
11164203945Sweongyo	plp->plp_rxpwroffset = sprom->rxpo5g;
11165203945Sweongyo	plp->plp_rssivf = sprom->rssismf5g;
11166203945Sweongyo	plp->plp_rssivc = sprom->rssismc5g;
11167203945Sweongyo	plp->plp_rssigs = sprom->rssisav5g;
11168203945Sweongyo}
11169203945Sweongyo
11170203945Sweongyostatic void
11171203945Sweongyobwn_phy_lp_bbinit(struct bwn_mac *mac)
11172203945Sweongyo{
11173203945Sweongyo
11174203945Sweongyo	bwn_phy_lp_tblinit(mac);
11175203945Sweongyo	if (mac->mac_phy.rev >= 2)
11176203945Sweongyo		bwn_phy_lp_bbinit_r2(mac);
11177203945Sweongyo	else
11178203945Sweongyo		bwn_phy_lp_bbinit_r01(mac);
11179203945Sweongyo}
11180203945Sweongyo
11181203945Sweongyostatic void
11182203945Sweongyobwn_phy_lp_txpctl_init(struct bwn_mac *mac)
11183203945Sweongyo{
11184203945Sweongyo	struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 };
11185203945Sweongyo	struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 };
11186203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11187203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11188203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11189203945Sweongyo
11190203945Sweongyo	bwn_phy_lp_set_txgain(mac,
11191203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz);
11192203945Sweongyo	bwn_phy_lp_set_bbmult(mac, 150);
11193203945Sweongyo}
11194203945Sweongyo
11195203945Sweongyostatic void
11196203945Sweongyobwn_phy_lp_calib(struct bwn_mac *mac)
11197203945Sweongyo{
11198203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11199203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11200203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11201203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11202203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11203203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11204203945Sweongyo	const struct bwn_rxcompco *rc = NULL;
11205203945Sweongyo	struct bwn_txgain ogain;
11206203945Sweongyo	int i, omode, oafeovr, orf, obbmult;
11207203945Sweongyo	uint8_t mode, fc = 0;
11208203945Sweongyo
11209203945Sweongyo	if (plp->plp_chanfullcal != plp->plp_chan) {
11210203945Sweongyo		plp->plp_chanfullcal = plp->plp_chan;
11211203945Sweongyo		fc = 1;
11212203945Sweongyo	}
11213203945Sweongyo
11214203945Sweongyo	bwn_mac_suspend(mac);
11215203945Sweongyo
11216203945Sweongyo	/* BlueTooth Coexistance Override */
11217203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_CTL, 0x3);
11218203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_TXCTL, 0xff);
11219203945Sweongyo
11220203945Sweongyo	if (mac->mac_phy.rev >= 2)
11221203945Sweongyo		bwn_phy_lp_digflt_save(mac);
11222203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11223203945Sweongyo	mode = plp->plp_txpctlmode;
11224203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11225203945Sweongyo	if (mac->mac_phy.rev == 0 && mode != BWN_PHYLP_TXPCTL_OFF)
11226203945Sweongyo		bwn_phy_lp_bugfix(mac);
11227203945Sweongyo	if (mac->mac_phy.rev >= 2 && fc == 1) {
11228203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11229203945Sweongyo		omode = plp->plp_txpctlmode;
11230203945Sweongyo		oafeovr = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40;
11231203945Sweongyo		if (oafeovr)
11232203945Sweongyo			ogain = bwn_phy_lp_get_txgain(mac);
11233203945Sweongyo		orf = BWN_PHY_READ(mac, BWN_PHY_RF_PWR_OVERRIDE) & 0xff;
11234203945Sweongyo		obbmult = bwn_phy_lp_get_bbmult(mac);
11235203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11236203945Sweongyo		if (oafeovr)
11237203945Sweongyo			bwn_phy_lp_set_txgain(mac, &ogain);
11238203945Sweongyo		bwn_phy_lp_set_bbmult(mac, obbmult);
11239203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, omode);
11240203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00, orf);
11241203945Sweongyo	}
11242203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11243203945Sweongyo	if (mac->mac_phy.rev >= 2)
11244203945Sweongyo		bwn_phy_lp_digflt_restore(mac);
11245203945Sweongyo
11246203945Sweongyo	/* do RX IQ Calculation; assumes that noise is true. */
11247203945Sweongyo	if (siba->siba_chipid == 0x5354) {
11248203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_5354); i++) {
11249203945Sweongyo			if (bwn_rxcompco_5354[i].rc_chan == plp->plp_chan)
11250203945Sweongyo				rc = &bwn_rxcompco_5354[i];
11251203945Sweongyo		}
11252203945Sweongyo	} else if (mac->mac_phy.rev >= 2)
11253203945Sweongyo		rc = &bwn_rxcompco_r2;
11254203945Sweongyo	else {
11255203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_r12); i++) {
11256203945Sweongyo			if (bwn_rxcompco_r12[i].rc_chan == plp->plp_chan)
11257203945Sweongyo				rc = &bwn_rxcompco_r12[i];
11258203945Sweongyo		}
11259203945Sweongyo	}
11260203945Sweongyo	if (rc == NULL)
11261203945Sweongyo		goto fail;
11262203945Sweongyo
11263203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, rc->rc_c1);
11264203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, rc->rc_c0 << 8);
11265203945Sweongyo
11266203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1 /* TX */, 0 /* RX */);
11267203945Sweongyo
11268203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11269203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
11270203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7, 0);
11271203945Sweongyo	} else {
11272203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
11273203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf, 0);
11274203945Sweongyo	}
11275203945Sweongyo
11276203945Sweongyo	bwn_phy_lp_set_rxgain(mac, 0x2d5d);
11277203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11278203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
11279203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
11280203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
11281203945Sweongyo	bwn_phy_lp_set_deaf(mac, 0);
11282203945Sweongyo	/* XXX no checking return value? */
11283203945Sweongyo	(void)bwn_phy_lp_calc_rx_iq_comp(mac, 0xfff0);
11284203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 0);
11285203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffc);
11286203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfff7);
11287203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffdf);
11288203945Sweongyo
11289203945Sweongyo	/* disable RX GAIN override. */
11290203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffe);
11291203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffef);
11292203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffbf);
11293203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11294203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11295203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11296203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfbff);
11297203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xe5), 0xfff7);
11298203945Sweongyo		}
11299203945Sweongyo	} else {
11300203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfdff);
11301203945Sweongyo	}
11302203945Sweongyo
11303203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11304203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xf7ff);
11305203945Sweongyofail:
11306203945Sweongyo	bwn_mac_enable(mac);
11307203945Sweongyo}
11308203945Sweongyo
11309203945Sweongyostatic void
11310203945Sweongyobwn_phy_lp_switch_analog(struct bwn_mac *mac, int on)
11311203945Sweongyo{
11312203945Sweongyo
11313203945Sweongyo       if (on) {
11314203945Sweongyo               BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfff8);
11315203945Sweongyo	       return;
11316203945Sweongyo       }
11317203945Sweongyo
11318203945Sweongyo       BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVRVAL, 0x0007);
11319203945Sweongyo       BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x0007);
11320203945Sweongyo}
11321203945Sweongyo
11322203945Sweongyostatic int
11323203945Sweongyobwn_phy_lp_b2063_switch_channel(struct bwn_mac *mac, uint8_t chan)
11324203945Sweongyo{
11325203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11326203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11327203945Sweongyo	static const struct bwn_b206x_chan *bc = NULL;
11328203945Sweongyo	uint32_t count, freqref, freqvco, freqxtal, val[3], timeout, timeoutref,
11329203945Sweongyo	    tmp[6];
11330203945Sweongyo	uint16_t old, scale, tmp16;
11331203945Sweongyo	int i, div;
11332203945Sweongyo
11333203945Sweongyo	for (i = 0; i < N(bwn_b2063_chantable); i++) {
11334203945Sweongyo		if (bwn_b2063_chantable[i].bc_chan == chan) {
11335203945Sweongyo			bc = &bwn_b2063_chantable[i];
11336203945Sweongyo			break;
11337203945Sweongyo		}
11338203945Sweongyo	}
11339203945Sweongyo	if (bc == NULL)
11340203945Sweongyo		return (EINVAL);
11341203945Sweongyo
11342203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_VCOBUF1, bc->bc_data[0]);
11343203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_MIXER2, bc->bc_data[1]);
11344203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_BUF2, bc->bc_data[2]);
11345203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_RCCR1, bc->bc_data[3]);
11346203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_1ST3, bc->bc_data[4]);
11347203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND1, bc->bc_data[5]);
11348203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND4, bc->bc_data[6]);
11349203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND7, bc->bc_data[7]);
11350203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_PS6, bc->bc_data[8]);
11351203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL2, bc->bc_data[9]);
11352203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL5, bc->bc_data[10]);
11353203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_CTL11, bc->bc_data[11]);
11354203945Sweongyo
11355203945Sweongyo	old = BWN_RF_READ(mac, BWN_B2063_COM15);
11356203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM15, 0x1e);
11357203945Sweongyo
11358203945Sweongyo	freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
11359203945Sweongyo	freqvco = bc->bc_freq << ((bc->bc_freq > 4000) ? 1 : 2);
11360203945Sweongyo	freqref = freqxtal * 3;
11361203945Sweongyo	div = (freqxtal <= 26000000 ? 1 : 2);
11362203945Sweongyo	timeout = ((((8 * freqxtal) / (div * 5000000)) + 1) >> 1) - 1;
11363203945Sweongyo	timeoutref = ((((8 * freqxtal) / (div * (timeout + 1))) +
11364203945Sweongyo		999999) / 1000000) + 1;
11365203945Sweongyo
11366203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB3, 0x2);
11367203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB6,
11368203945Sweongyo	    0xfff8, timeout >> 2);
11369203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11370203945Sweongyo	    0xff9f,timeout << 5);
11371203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB5, timeoutref);
11372203945Sweongyo
11373203945Sweongyo	val[0] = bwn_phy_lp_roundup(freqxtal, 1000000, 16);
11374203945Sweongyo	val[1] = bwn_phy_lp_roundup(freqxtal, 1000000 * div, 16);
11375203945Sweongyo	val[2] = bwn_phy_lp_roundup(freqvco, 3, 16);
11376203945Sweongyo
11377203945Sweongyo	count = (bwn_phy_lp_roundup(val[2], val[1] + 16, 16) * (timeout + 1) *
11378203945Sweongyo	    (timeoutref + 1)) - 1;
11379203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11380203945Sweongyo	    0xf0, count >> 8);
11381203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB8, count & 0xff);
11382203945Sweongyo
11383203945Sweongyo	tmp[0] = ((val[2] * 62500) / freqref) << 4;
11384203945Sweongyo	tmp[1] = ((val[2] * 62500) % freqref) << 4;
11385203945Sweongyo	while (tmp[1] >= freqref) {
11386203945Sweongyo		tmp[0]++;
11387203945Sweongyo		tmp[1] -= freqref;
11388203945Sweongyo	}
11389203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG1, 0xffe0, tmp[0] >> 4);
11390203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfe0f, tmp[0] << 4);
11391203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfff0, tmp[0] >> 16);
11392203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG3, (tmp[1] >> 8) & 0xff);
11393203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG4, tmp[1] & 0xff);
11394203945Sweongyo
11395203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF1, 0xb9);
11396203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF2, 0x88);
11397203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF3, 0x28);
11398203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF4, 0x63);
11399203945Sweongyo
11400203945Sweongyo	tmp[2] = ((41 * (val[2] - 3000)) /1200) + 27;
11401203945Sweongyo	tmp[3] = bwn_phy_lp_roundup(132000 * tmp[0], 8451, 16);
11402203945Sweongyo
11403203945Sweongyo	if ((tmp[3] + tmp[2] - 1) / tmp[2] > 60) {
11404203945Sweongyo		scale = 1;
11405203945Sweongyo		tmp[4] = ((tmp[3] + tmp[2]) / (tmp[2] << 1)) - 8;
11406203945Sweongyo	} else {
11407203945Sweongyo		scale = 0;
11408203945Sweongyo		tmp[4] = ((tmp[3] + (tmp[2] >> 1)) / tmp[2]) - 8;
11409203945Sweongyo	}
11410203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffc0, tmp[4]);
11411203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffbf, scale << 6);
11412203945Sweongyo
11413203945Sweongyo	tmp[5] = bwn_phy_lp_roundup(100 * val[0], val[2], 16) * (tmp[4] * 8) *
11414203945Sweongyo	    (scale + 1);
11415203945Sweongyo	if (tmp[5] > 150)
11416203945Sweongyo		tmp[5] = 0;
11417203945Sweongyo
11418203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffe0, tmp[5]);
11419203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffdf, scale << 5);
11420203945Sweongyo
11421203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfffb, 0x4);
11422203945Sweongyo	if (freqxtal > 26000000)
11423203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_XTAL_12, 0x2);
11424203945Sweongyo	else
11425203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfd);
11426203945Sweongyo
11427203945Sweongyo	if (val[0] == 45)
11428203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_VCO1, 0x2);
11429203945Sweongyo	else
11430203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_VCO1, 0xfd);
11431203945Sweongyo
11432203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP2, 0x3);
11433203945Sweongyo	DELAY(1);
11434203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP2, 0xfffc);
11435203945Sweongyo
11436203945Sweongyo	/* VCO Calibration */
11437203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, ~0x40);
11438203945Sweongyo	tmp16 = BWN_RF_READ(mac, BWN_B2063_JTAG_CALNRST) & 0xf8;
11439203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16);
11440203945Sweongyo	DELAY(1);
11441203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x4);
11442203945Sweongyo	DELAY(1);
11443203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x6);
11444203945Sweongyo	DELAY(1);
11445203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x7);
11446203945Sweongyo	DELAY(300);
11447203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP1, 0x40);
11448203945Sweongyo
11449203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_COM15, old);
11450203945Sweongyo	return (0);
11451203945Sweongyo}
11452203945Sweongyo
11453203945Sweongyostatic int
11454203945Sweongyobwn_phy_lp_b2062_switch_channel(struct bwn_mac *mac, uint8_t chan)
11455203945Sweongyo{
11456203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11457203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11458203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11459203945Sweongyo	const struct bwn_b206x_chan *bc = NULL;
11460203945Sweongyo	uint32_t freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
11461203945Sweongyo	uint32_t tmp[9];
11462203945Sweongyo	int i;
11463203945Sweongyo
11464203945Sweongyo	for (i = 0; i < N(bwn_b2062_chantable); i++) {
11465203945Sweongyo		if (bwn_b2062_chantable[i].bc_chan == chan) {
11466203945Sweongyo			bc = &bwn_b2062_chantable[i];
11467203945Sweongyo			break;
11468203945Sweongyo		}
11469203945Sweongyo	}
11470203945Sweongyo
11471203945Sweongyo	if (bc == NULL)
11472203945Sweongyo		return (EINVAL);
11473203945Sweongyo
11474203945Sweongyo	BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL14, 0x04);
11475203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE0, bc->bc_data[0]);
11476203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE2, bc->bc_data[1]);
11477203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE3, bc->bc_data[2]);
11478203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_TUNE, bc->bc_data[3]);
11479203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_LGENG_CTL1, bc->bc_data[4]);
11480203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL5, bc->bc_data[5]);
11481203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL6, bc->bc_data[6]);
11482203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PGA, bc->bc_data[7]);
11483203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PAD, bc->bc_data[8]);
11484203945Sweongyo
11485203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xcc);
11486203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0x07);
11487203945Sweongyo	bwn_phy_lp_b2062_reset_pllbias(mac);
11488203945Sweongyo	tmp[0] = freqxtal / 1000;
11489203945Sweongyo	tmp[1] = plp->plp_div * 1000;
11490203945Sweongyo	tmp[2] = tmp[1] * ieee80211_ieee2mhz(chan, 0);
11491203945Sweongyo	if (ieee80211_ieee2mhz(chan, 0) < 4000)
11492203945Sweongyo		tmp[2] *= 2;
11493203945Sweongyo	tmp[3] = 48 * tmp[0];
11494203945Sweongyo	tmp[5] = tmp[2] / tmp[3];
11495203945Sweongyo	tmp[6] = tmp[2] % tmp[3];
11496203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL26, tmp[5]);
11497203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11498203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11499203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11500203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL27, tmp[5]);
11501203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11502203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11503203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11504203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL28, tmp[5]);
11505203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11506203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11507203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11508203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL29,
11509203945Sweongyo	    tmp[5] + ((2 * tmp[6]) / tmp[3]));
11510203945Sweongyo	tmp[7] = BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL19);
11511203945Sweongyo	tmp[8] = ((2 * tmp[2] * (tmp[7] + 1)) + (3 * tmp[0])) / (6 * tmp[0]);
11512203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL23, (tmp[8] >> 8) + 16);
11513203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL24, tmp[8] & 0xff);
11514203945Sweongyo
11515203945Sweongyo	bwn_phy_lp_b2062_vco_calib(mac);
11516203945Sweongyo	if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11517203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xfc);
11518203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0);
11519203945Sweongyo		bwn_phy_lp_b2062_reset_pllbias(mac);
11520203945Sweongyo		bwn_phy_lp_b2062_vco_calib(mac);
11521203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11522203945Sweongyo			BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11523203945Sweongyo			return (EIO);
11524203945Sweongyo		}
11525203945Sweongyo	}
11526203945Sweongyo	BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11527203945Sweongyo	return (0);
11528203945Sweongyo}
11529203945Sweongyo
11530203945Sweongyostatic void
11531203945Sweongyobwn_phy_lp_set_anafilter(struct bwn_mac *mac, uint8_t channel)
11532203945Sweongyo{
11533203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11534203945Sweongyo	uint16_t tmp = (channel == 14);
11535203945Sweongyo
11536203945Sweongyo	if (mac->mac_phy.rev < 2) {
11537203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xfcff, tmp << 9);
11538203945Sweongyo		if ((mac->mac_phy.rev == 1) && (plp->plp_rccap))
11539203945Sweongyo			bwn_phy_lp_set_rccap(mac);
11540203945Sweongyo		return;
11541203945Sweongyo	}
11542203945Sweongyo
11543203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, 0x3f);
11544203945Sweongyo}
11545203945Sweongyo
11546203945Sweongyostatic void
11547203945Sweongyobwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq)
11548203945Sweongyo{
11549203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11550203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11551203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11552203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11553203945Sweongyo	uint16_t iso, tmp[3];
11554203945Sweongyo
11555203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
11556203945Sweongyo
11557203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
11558203945Sweongyo		iso = plp->plp_txisoband_m;
11559203945Sweongyo	else if (freq <= 5320)
11560203945Sweongyo		iso = plp->plp_txisoband_l;
11561203945Sweongyo	else if (freq <= 5700)
11562203945Sweongyo		iso = plp->plp_txisoband_m;
11563203945Sweongyo	else
11564203945Sweongyo		iso = plp->plp_txisoband_h;
11565203945Sweongyo
11566203945Sweongyo	tmp[0] = ((iso - 26) / 12) << 12;
11567203945Sweongyo	tmp[1] = tmp[0] + 0x1000;
11568203945Sweongyo	tmp[2] = tmp[0] + 0x2000;
11569203945Sweongyo
11570203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), 3, tmp);
11571203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), 3, tmp);
11572203945Sweongyo}
11573203945Sweongyo
11574203945Sweongyostatic void
11575203945Sweongyobwn_phy_lp_digflt_save(struct bwn_mac *mac)
11576203945Sweongyo{
11577203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11578203945Sweongyo	int i;
11579203945Sweongyo	static const uint16_t addr[] = {
11580203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11581203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11582203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11583203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11584203945Sweongyo		BWN_PHY_OFDM(0xcf),
11585203945Sweongyo	};
11586203945Sweongyo	static const uint16_t val[] = {
11587203945Sweongyo		0xde5e, 0xe832, 0xe331, 0x4d26,
11588203945Sweongyo		0x0026, 0x1420, 0x0020, 0xfe08,
11589203945Sweongyo		0x0008,
11590203945Sweongyo	};
11591203945Sweongyo
11592203945Sweongyo	for (i = 0; i < N(addr); i++) {
11593203945Sweongyo		plp->plp_digfilt[i] = BWN_PHY_READ(mac, addr[i]);
11594203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], val[i]);
11595203945Sweongyo	}
11596203945Sweongyo}
11597203945Sweongyo
11598203945Sweongyostatic void
11599203945Sweongyobwn_phy_lp_get_txpctlmode(struct bwn_mac *mac)
11600203945Sweongyo{
11601203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11602203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11603203945Sweongyo	uint16_t ctl;
11604203945Sweongyo
11605203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_TX_PWR_CTL_CMD);
11606203945Sweongyo	switch (ctl & BWN_PHY_TX_PWR_CTL_CMD_MODE) {
11607203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF:
11608203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_OFF;
11609203945Sweongyo		break;
11610203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_SW:
11611203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_SW;
11612203945Sweongyo		break;
11613203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_HW:
11614203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_HW;
11615203945Sweongyo		break;
11616203945Sweongyo	default:
11617203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_UNKNOWN;
11618203945Sweongyo		device_printf(sc->sc_dev, "unknown command mode\n");
11619203945Sweongyo		break;
11620203945Sweongyo	}
11621203945Sweongyo}
11622203945Sweongyo
11623203945Sweongyostatic void
11624203945Sweongyobwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
11625203945Sweongyo{
11626203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11627203945Sweongyo	uint16_t ctl;
11628203945Sweongyo	uint8_t old;
11629203945Sweongyo
11630203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11631203945Sweongyo	old = plp->plp_txpctlmode;
11632203945Sweongyo	if (old == mode)
11633203945Sweongyo		return;
11634203945Sweongyo	plp->plp_txpctlmode = mode;
11635203945Sweongyo
11636203945Sweongyo	if (old != BWN_PHYLP_TXPCTL_ON_HW && mode == BWN_PHYLP_TXPCTL_ON_HW) {
11637203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD, 0xff80,
11638203945Sweongyo		    plp->plp_tssiidx);
11639203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_NNUM,
11640203945Sweongyo		    0x8fff, ((uint16_t)plp->plp_tssinpt << 16));
11641203945Sweongyo
11642203945Sweongyo		/* disable TX GAIN override */
11643203945Sweongyo		if (mac->mac_phy.rev < 2)
11644203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11645203945Sweongyo		else {
11646203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xff7f);
11647203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xbfff);
11648203945Sweongyo		}
11649203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xffbf);
11650203945Sweongyo
11651203945Sweongyo		plp->plp_txpwridx = -1;
11652203945Sweongyo	}
11653203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11654203945Sweongyo		if (mode == BWN_PHYLP_TXPCTL_ON_HW)
11655203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xd0), 0x2);
11656203945Sweongyo		else
11657203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xd0), 0xfffd);
11658203945Sweongyo	}
11659203945Sweongyo
11660203945Sweongyo	/* writes TX Power Control mode */
11661203945Sweongyo	switch (plp->plp_txpctlmode) {
11662203945Sweongyo	case BWN_PHYLP_TXPCTL_OFF:
11663203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF;
11664203945Sweongyo		break;
11665203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_HW:
11666203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_HW;
11667203945Sweongyo		break;
11668203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_SW:
11669203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
11670203945Sweongyo		break;
11671203945Sweongyo	default:
11672204242Simp		ctl = 0;
11673203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
11674203945Sweongyo	}
11675203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
11676203945Sweongyo	    (uint16_t)~BWN_PHY_TX_PWR_CTL_CMD_MODE, ctl);
11677203945Sweongyo}
11678203945Sweongyo
11679203945Sweongyostatic void
11680203945Sweongyobwn_phy_lp_bugfix(struct bwn_mac *mac)
11681203945Sweongyo{
11682203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11683203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11684203945Sweongyo	const unsigned int size = 256;
11685203945Sweongyo	struct bwn_txgain tg;
11686203945Sweongyo	uint32_t rxcomp, txgain, coeff, rfpwr, *tabs;
11687203945Sweongyo	uint16_t tssinpt, tssiidx, value[2];
11688203945Sweongyo	uint8_t mode;
11689203945Sweongyo	int8_t txpwridx;
11690203945Sweongyo
11691203945Sweongyo	tabs = (uint32_t *)malloc(sizeof(uint32_t) * size, M_DEVBUF,
11692203945Sweongyo	    M_NOWAIT | M_ZERO);
11693203945Sweongyo	if (tabs == NULL) {
11694203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer.\n");
11695203945Sweongyo		return;
11696203945Sweongyo	}
11697203945Sweongyo
11698203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11699203945Sweongyo	mode = plp->plp_txpctlmode;
11700203945Sweongyo	txpwridx = plp->plp_txpwridx;
11701203945Sweongyo	tssinpt = plp->plp_tssinpt;
11702203945Sweongyo	tssiidx = plp->plp_tssiidx;
11703203945Sweongyo
11704203945Sweongyo	bwn_tab_read_multi(mac,
11705203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11706203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11707203945Sweongyo
11708203945Sweongyo	bwn_phy_lp_tblinit(mac);
11709203945Sweongyo	bwn_phy_lp_bbinit(mac);
11710203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
11711203945Sweongyo	bwn_phy_lp_rf_onoff(mac, 1);
11712203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11713203945Sweongyo
11714203945Sweongyo	bwn_tab_write_multi(mac,
11715203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11716203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11717203945Sweongyo
11718203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, plp->plp_chan);
11719203945Sweongyo	plp->plp_tssinpt = tssinpt;
11720203945Sweongyo	plp->plp_tssiidx = tssiidx;
11721203945Sweongyo	bwn_phy_lp_set_anafilter(mac, plp->plp_chan);
11722203945Sweongyo	if (txpwridx != -1) {
11723203945Sweongyo		/* set TX power by index */
11724203945Sweongyo		plp->plp_txpwridx = txpwridx;
11725203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11726203945Sweongyo		if (plp->plp_txpctlmode != BWN_PHYLP_TXPCTL_OFF)
11727203945Sweongyo			bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_ON_SW);
11728203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11729203945Sweongyo			rxcomp = bwn_tab_read(mac,
11730203945Sweongyo			    BWN_TAB_4(7, txpwridx + 320));
11731203945Sweongyo			txgain = bwn_tab_read(mac,
11732203945Sweongyo			    BWN_TAB_4(7, txpwridx + 192));
11733203945Sweongyo			tg.tg_pad = (txgain >> 16) & 0xff;
11734203945Sweongyo			tg.tg_gm = txgain & 0xff;
11735203945Sweongyo			tg.tg_pga = (txgain >> 8) & 0xff;
11736203945Sweongyo			tg.tg_dac = (rxcomp >> 28) & 0xff;
11737203945Sweongyo			bwn_phy_lp_set_txgain(mac, &tg);
11738203945Sweongyo		} else {
11739203945Sweongyo			rxcomp = bwn_tab_read(mac,
11740203945Sweongyo			    BWN_TAB_4(10, txpwridx + 320));
11741203945Sweongyo			txgain = bwn_tab_read(mac,
11742203945Sweongyo			    BWN_TAB_4(10, txpwridx + 192));
11743203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
11744203945Sweongyo			    0xf800, (txgain >> 4) & 0x7fff);
11745203945Sweongyo			bwn_phy_lp_set_txgain_dac(mac, txgain & 0x7);
11746203945Sweongyo			bwn_phy_lp_set_txgain_pa(mac, (txgain >> 24) & 0x7f);
11747203945Sweongyo		}
11748203945Sweongyo		bwn_phy_lp_set_bbmult(mac, (rxcomp >> 20) & 0xff);
11749203945Sweongyo
11750203945Sweongyo		/* set TX IQCC */
11751203945Sweongyo		value[0] = (rxcomp >> 10) & 0x3ff;
11752203945Sweongyo		value[1] = rxcomp & 0x3ff;
11753203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(0, 80), 2, value);
11754203945Sweongyo
11755203945Sweongyo		coeff = bwn_tab_read(mac,
11756203945Sweongyo		    (mac->mac_phy.rev >= 2) ? BWN_TAB_4(7, txpwridx + 448) :
11757203945Sweongyo		    BWN_TAB_4(10, txpwridx + 448));
11758203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0, 85), coeff & 0xffff);
11759203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11760203945Sweongyo			rfpwr = bwn_tab_read(mac,
11761203945Sweongyo			    BWN_TAB_4(7, txpwridx + 576));
11762203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00,
11763203945Sweongyo			    rfpwr & 0xffff);
11764203945Sweongyo		}
11765203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
11766203945Sweongyo	}
11767203945Sweongyo	if (plp->plp_rccap)
11768203945Sweongyo		bwn_phy_lp_set_rccap(mac);
11769203945Sweongyo	bwn_phy_lp_set_antenna(mac, plp->plp_antenna);
11770203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11771203945Sweongyo	free(tabs, M_DEVBUF);
11772203945Sweongyo}
11773203945Sweongyo
11774203945Sweongyostatic void
11775203945Sweongyobwn_phy_lp_digflt_restore(struct bwn_mac *mac)
11776203945Sweongyo{
11777203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11778203945Sweongyo	int i;
11779203945Sweongyo	static const uint16_t addr[] = {
11780203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11781203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11782203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11783203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11784203945Sweongyo		BWN_PHY_OFDM(0xcf),
11785203945Sweongyo	};
11786203945Sweongyo
11787203945Sweongyo	for (i = 0; i < N(addr); i++)
11788203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], plp->plp_digfilt[i]);
11789203945Sweongyo}
11790203945Sweongyo
11791203945Sweongyostatic void
11792203945Sweongyobwn_phy_lp_tblinit(struct bwn_mac *mac)
11793203945Sweongyo{
11794203945Sweongyo	uint32_t freq = ieee80211_ieee2mhz(bwn_phy_lp_get_default_chan(mac), 0);
11795203945Sweongyo
11796203945Sweongyo	if (mac->mac_phy.rev < 2) {
11797203945Sweongyo		bwn_phy_lp_tblinit_r01(mac);
11798203945Sweongyo		bwn_phy_lp_tblinit_txgain(mac);
11799203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, freq);
11800203945Sweongyo		return;
11801203945Sweongyo	}
11802203945Sweongyo
11803203945Sweongyo	bwn_phy_lp_tblinit_r2(mac);
11804203945Sweongyo	bwn_phy_lp_tblinit_txgain(mac);
11805203945Sweongyo}
11806203945Sweongyo
11807203945Sweongyostruct bwn_wpair {
11808203945Sweongyo	uint16_t		reg;
11809203945Sweongyo	uint16_t		value;
11810203945Sweongyo};
11811203945Sweongyo
11812203945Sweongyostruct bwn_smpair {
11813203945Sweongyo	uint16_t		offset;
11814203945Sweongyo	uint16_t		mask;
11815203945Sweongyo	uint16_t		set;
11816203945Sweongyo};
11817203945Sweongyo
11818203945Sweongyostatic void
11819203945Sweongyobwn_phy_lp_bbinit_r2(struct bwn_mac *mac)
11820203945Sweongyo{
11821203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11822203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11823203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11824203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11825203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11826203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11827203945Sweongyo	static const struct bwn_wpair v1[] = {
11828203945Sweongyo		{ BWN_PHY_AFE_DAC_CTL, 0x50 },
11829203945Sweongyo		{ BWN_PHY_AFE_CTL, 0x8800 },
11830203945Sweongyo		{ BWN_PHY_AFE_CTL_OVR, 0 },
11831203945Sweongyo		{ BWN_PHY_AFE_CTL_OVRVAL, 0 },
11832203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_0, 0 },
11833203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_2, 0 },
11834203945Sweongyo		{ BWN_PHY_OFDM(0xf9), 0 },
11835203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0 }
11836203945Sweongyo	};
11837203945Sweongyo	static const struct bwn_smpair v2[] = {
11838203945Sweongyo		{ BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0xb4 },
11839203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xf8ff, 0x200 },
11840203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xff00, 0x7f },
11841203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xff0f, 0x40 },
11842203945Sweongyo		{ BWN_PHY_PREAMBLECONFIRMTO, 0xff00, 0x2 }
11843203945Sweongyo	};
11844203945Sweongyo	static const struct bwn_smpair v3[] = {
11845203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xffe0, 0x1f },
11846203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11847203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0xff00, 0x19 },
11848203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0x03ff, 0x3c00 },
11849203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xfc1f, 0x3e0 },
11850203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11851203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0x00ff, 0x1900 },
11852203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800 },
11853203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x12 },
11854203945Sweongyo		{ BWN_PHY_GAINMISMATCH, 0x0fff, 0x9000 },
11855203945Sweongyo
11856203945Sweongyo	};
11857203945Sweongyo	int i;
11858203945Sweongyo
11859203945Sweongyo	for (i = 0; i < N(v1); i++)
11860203945Sweongyo		BWN_PHY_WRITE(mac, v1[i].reg, v1[i].value);
11861203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x10);
11862203945Sweongyo	for (i = 0; i < N(v2); i++)
11863203945Sweongyo		BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask, v2[i].set);
11864203945Sweongyo
11865203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x4000);
11866203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x2000);
11867203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_OFDM(0x10a), 0x1);
11868203945Sweongyo	if (siba->siba_board_rev >= 0x18) {
11869203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(17, 65), 0xec);
11870203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x14);
11871203945Sweongyo	} else {
11872203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x10);
11873203945Sweongyo	}
11874203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0xff00, 0xf4);
11875203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0x00ff, 0xf100);
11876203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CLIPTHRESH, 0x48);
11877203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0xff00, 0x46);
11878203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe4), 0xff00, 0x10);
11879203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_PWR_THRESH1, 0xfff0, 0x9);
11880203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_GAINDIRECTMISMATCH, ~0xf);
11881203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5500);
11882203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0xa0);
11883203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_GAINDIRECTMISMATCH, 0xe0ff, 0x300);
11884203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2a00);
11885203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
11886203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11887203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xa);
11888203945Sweongyo	} else {
11889203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x1e00);
11890203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xd);
11891203945Sweongyo	}
11892203945Sweongyo	for (i = 0; i < N(v3); i++)
11893203945Sweongyo		BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask, v3[i].set);
11894203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
11895203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x14), 0);
11896203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x12), 0x40);
11897203945Sweongyo	}
11898203945Sweongyo
11899203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11900203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x40);
11901203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0xb00);
11902203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x6);
11903203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0x9d00);
11904203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0xff00, 0xa1);
11905203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11906203945Sweongyo	} else
11907203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x40);
11908203945Sweongyo
11909203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0xff00, 0xb3);
11910203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00);
11911203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB, 0xff00, plp->plp_rxpwroffset);
11912203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RESET_CTL, 0x44);
11913203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RESET_CTL, 0x80);
11914203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, 0xa954);
11915203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_1,
11916203945Sweongyo	    0x2000 | ((uint16_t)plp->plp_rssigs << 10) |
11917203945Sweongyo	    ((uint16_t)plp->plp_rssivc << 4) | plp->plp_rssivf);
11918203945Sweongyo
11919203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
11920203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_AFE_ADC_CTL_0, 0x1c);
11921203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_CTL, 0x00ff, 0x8800);
11922203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_1, 0xfc3c, 0x0400);
11923203945Sweongyo	}
11924203945Sweongyo
11925203945Sweongyo	bwn_phy_lp_digflt_save(mac);
11926203945Sweongyo}
11927203945Sweongyo
11928203945Sweongyostatic void
11929203945Sweongyobwn_phy_lp_bbinit_r01(struct bwn_mac *mac)
11930203945Sweongyo{
11931203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11932203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11933203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11934203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11935203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11936203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11937203945Sweongyo	static const struct bwn_smpair v1[] = {
11938203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 },
11939203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 },
11940203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x3c00 },
11941203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xfff0, 0x0005 },
11942203945Sweongyo		{ BWN_PHY_GAIN_MISMATCH_LIMIT, 0xffc0, 0x001a },
11943203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0xff00, 0x00b3 },
11944203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00 }
11945203945Sweongyo	};
11946203945Sweongyo	static const struct bwn_smpair v2[] = {
11947203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11948203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0x3f00, 0x0900 },
11949203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11950203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11951203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x000a },
11952203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0400 },
11953203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x000a },
11954203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0b00 },
11955203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xffc0, 0x000a },
11956203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xc0ff, 0x0900 },
11957203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xffc0, 0x000a },
11958203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xc0ff, 0x0b00 },
11959203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xffc0, 0x000a },
11960203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xc0ff, 0x0900 },
11961203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xffc0, 0x000a },
11962203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xc0ff, 0x0b00 }
11963203945Sweongyo	};
11964203945Sweongyo	static const struct bwn_smpair v3[] = {
11965203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0001 },
11966203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0400 },
11967203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0001 },
11968203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0500 },
11969203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11970203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0800 },
11971203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11972203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0a00 }
11973203945Sweongyo	};
11974203945Sweongyo	static const struct bwn_smpair v4[] = {
11975203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0004 },
11976203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0800 },
11977203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0004 },
11978203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0c00 },
11979203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11980203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0100 },
11981203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11982203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0300 }
11983203945Sweongyo	};
11984203945Sweongyo	static const struct bwn_smpair v5[] = {
11985203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11986203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0900 },
11987203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11988203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11989203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0006 },
11990203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0500 },
11991203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0006 },
11992203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0700 }
11993203945Sweongyo	};
11994203945Sweongyo	int i;
11995203945Sweongyo	uint16_t tmp, tmp2;
11996203945Sweongyo
11997203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf7ff);
11998203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL, 0);
11999203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, 0);
12000203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, 0);
12001203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0);
12002203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DAC_CTL, 0x0004);
12003203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0x0078);
12004203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800);
12005203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x0016);
12006203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_0, 0xfff8, 0x0004);
12007203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5400);
12008203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2400);
12009203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
12010203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0x0006);
12011203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_RADIO_CTL, 0xfffe);
12012203945Sweongyo	for (i = 0; i < N(v1); i++)
12013203945Sweongyo		BWN_PHY_SETMASK(mac, v1[i].offset, v1[i].mask, v1[i].set);
12014203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB,
12015203945Sweongyo	    0xff00, plp->plp_rxpwroffset);
12016203945Sweongyo	if ((siba->siba_sprom.bf_lo & BWN_BFL_FEM) &&
12017203945Sweongyo	    ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
12018203945Sweongyo	   (siba->siba_sprom.bf_hi & BWN_BFH_LDO_PAREF))) {
12019203945Sweongyo		siba_cc_pmu_set_ldovolt(&siba->siba_cc, SIBA_LDO_PAREF, 0x28);
12020203945Sweongyo		siba_cc_pmu_set_ldoparef(&siba->siba_cc, 1);
12021203945Sweongyo		if (mac->mac_phy.rev == 0)
12022203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT,
12023203945Sweongyo			    0xffcf, 0x0010);
12024203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 60);
12025203945Sweongyo	} else {
12026203945Sweongyo		siba_cc_pmu_set_ldoparef(&siba->siba_cc, 0);
12027203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT, 0xffcf, 0x0020);
12028203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 100);
12029203945Sweongyo	}
12030203945Sweongyo	tmp = plp->plp_rssivf | plp->plp_rssivc << 4 | 0xa000;
12031203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, tmp);
12032203945Sweongyo	if (siba->siba_sprom.bf_hi & BWN_BFH_RSSIINV)
12033203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x0aaa);
12034203945Sweongyo	else
12035203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x02aa);
12036203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(11, 1), 24);
12037203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_RADIO_CTL,
12038203945Sweongyo	    0xfff9, (plp->plp_bxarch << 1));
12039203945Sweongyo	if (mac->mac_phy.rev == 1 &&
12040203945Sweongyo	    (siba->siba_sprom.bf_hi & BWN_BFH_FEM_BT)) {
12041203945Sweongyo		for (i = 0; i < N(v2); i++)
12042203945Sweongyo			BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask,
12043203945Sweongyo			    v2[i].set);
12044203945Sweongyo	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ||
12045203945Sweongyo	    (siba->siba_board_type == 0x048a) || ((mac->mac_phy.rev == 0) &&
12046203945Sweongyo	    (siba->siba_sprom.bf_lo & BWN_BFL_FEM))) {
12047203945Sweongyo		for (i = 0; i < N(v3); i++)
12048203945Sweongyo			BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask,
12049203945Sweongyo			    v3[i].set);
12050203945Sweongyo	} else if (mac->mac_phy.rev == 1 ||
12051203945Sweongyo		  (siba->siba_sprom.bf_lo & BWN_BFL_FEM)) {
12052203945Sweongyo		for (i = 0; i < N(v4); i++)
12053203945Sweongyo			BWN_PHY_SETMASK(mac, v4[i].offset, v4[i].mask,
12054203945Sweongyo			    v4[i].set);
12055203945Sweongyo	} else {
12056203945Sweongyo		for (i = 0; i < N(v5); i++)
12057203945Sweongyo			BWN_PHY_SETMASK(mac, v5[i].offset, v5[i].mask,
12058203945Sweongyo			    v5[i].set);
12059203945Sweongyo	}
12060203945Sweongyo	if (mac->mac_phy.rev == 1 &&
12061203945Sweongyo	    (siba->siba_sprom.bf_hi & BWN_BFH_LDO_PAREF)) {
12062203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_5, BWN_PHY_TR_LOOKUP_1);
12063203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_6, BWN_PHY_TR_LOOKUP_2);
12064203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_7, BWN_PHY_TR_LOOKUP_3);
12065203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_8, BWN_PHY_TR_LOOKUP_4);
12066203945Sweongyo	}
12067203945Sweongyo	if ((siba->siba_sprom.bf_hi & BWN_BFH_FEM_BT) &&
12068203945Sweongyo	    (siba->siba_chipid == 0x5354) &&
12069203945Sweongyo	    (siba->siba_chippkg == SIBA_CHIPPACK_BCM4712S)) {
12070203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0006);
12071203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_SELECT, 0x0005);
12072203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_OUTEN, 0xffff);
12073203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_PR45960W);
12074203945Sweongyo	}
12075203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12076203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x8000);
12077203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0040);
12078203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0xa400);
12079203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0x0b00);
12080203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x0007);
12081203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xfff8, 0x0003);
12082203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xffc7, 0x0020);
12083203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
12084203945Sweongyo	} else {
12085203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0x7fff);
12086203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xffbf);
12087203945Sweongyo	}
12088203945Sweongyo	if (mac->mac_phy.rev == 1) {
12089203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_CLIPCTRTHRESH);
12090203945Sweongyo		tmp2 = (tmp & 0x03e0) >> 5;
12091203945Sweongyo		tmp2 |= tmp2 << 5;
12092203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C3, tmp2);
12093203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_GAINDIRECTMISMATCH);
12094203945Sweongyo		tmp2 = (tmp & 0x1f00) >> 8;
12095203945Sweongyo		tmp2 |= tmp2 << 5;
12096203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C4, tmp2);
12097203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERYLOWGAINDB);
12098203945Sweongyo		tmp2 = tmp & 0x00ff;
12099203945Sweongyo		tmp2 |= tmp << 8;
12100203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C5, tmp2);
12101203945Sweongyo	}
12102203945Sweongyo}
12103203945Sweongyo
12104203945Sweongyostruct bwn_b2062_freq {
12105203945Sweongyo	uint16_t		freq;
12106203945Sweongyo	uint8_t			value[6];
12107203945Sweongyo};
12108203945Sweongyo
12109203945Sweongyostatic void
12110203945Sweongyobwn_phy_lp_b2062_init(struct bwn_mac *mac)
12111203945Sweongyo{
12112203945Sweongyo#define	CALC_CTL7(freq, div)						\
12113203945Sweongyo	(((800000000 * (div) + (freq)) / (2 * (freq)) - 8) & 0xff)
12114203945Sweongyo#define	CALC_CTL18(freq, div)						\
12115203945Sweongyo	((((100 * (freq) + 16000000 * (div)) / (32000000 * (div))) - 1) & 0xff)
12116203945Sweongyo#define	CALC_CTL19(freq, div)						\
12117203945Sweongyo	((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff)
12118203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12119203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
12120203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
12121203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12122203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12123203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12124203945Sweongyo	static const struct bwn_b2062_freq freqdata_tab[] = {
12125203945Sweongyo		{ 12000, { 6, 6, 6, 6, 10, 6 } },
12126203945Sweongyo		{ 13000, { 4, 4, 4, 4, 11, 7 } },
12127203945Sweongyo		{ 14400, { 3, 3, 3, 3, 12, 7 } },
12128203945Sweongyo		{ 16200, { 3, 3, 3, 3, 13, 8 } },
12129203945Sweongyo		{ 18000, { 2, 2, 2, 2, 14, 8 } },
12130203945Sweongyo		{ 19200, { 1, 1, 1, 1, 14, 9 } }
12131203945Sweongyo	};
12132203945Sweongyo	static const struct bwn_wpair v1[] = {
12133203945Sweongyo		{ BWN_B2062_N_TXCTL3, 0 },
12134203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0 },
12135203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0 },
12136203945Sweongyo		{ BWN_B2062_N_TXCTL6, 0 },
12137203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0x40 },
12138203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0 },
12139203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0x10 },
12140203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0 }
12141203945Sweongyo	};
12142203945Sweongyo	const struct bwn_b2062_freq *f = NULL;
12143203945Sweongyo	uint32_t xtalfreq, ref;
12144203945Sweongyo	unsigned int i;
12145203945Sweongyo
12146203945Sweongyo	bwn_phy_lp_b2062_tblinit(mac);
12147203945Sweongyo
12148203945Sweongyo	for (i = 0; i < N(v1); i++)
12149203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12150203945Sweongyo	if (mac->mac_phy.rev > 0)
12151203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_BG_CTL1,
12152203945Sweongyo		    (BWN_RF_READ(mac, BWN_B2062_N_COM2) >> 1) | 0x80);
12153203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12154203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_N_TSSI_CTL0, 0x1);
12155203945Sweongyo	else
12156203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_N_TSSI_CTL0, ~0x1);
12157203945Sweongyo
12158203945Sweongyo	KASSERT(siba->siba_cc.scc_caps & SIBA_CC_CAPS_PMU,
12159203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
12160203945Sweongyo	xtalfreq = siba->siba_cc.scc_pmu.freq * 1000;
12161203945Sweongyo	KASSERT(xtalfreq != 0, ("%s:%d: fail", __func__, __LINE__));
12162203945Sweongyo
12163203945Sweongyo	if (xtalfreq <= 30000000) {
12164203945Sweongyo		plp->plp_div = 1;
12165203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL1, 0xfffb);
12166203945Sweongyo	} else {
12167203945Sweongyo		plp->plp_div = 2;
12168203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL1, 0x4);
12169203945Sweongyo	}
12170203945Sweongyo
12171203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL7,
12172203945Sweongyo	    CALC_CTL7(xtalfreq, plp->plp_div));
12173203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL18,
12174203945Sweongyo	    CALC_CTL18(xtalfreq, plp->plp_div));
12175203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL19,
12176203945Sweongyo	    CALC_CTL19(xtalfreq, plp->plp_div));
12177203945Sweongyo
12178203945Sweongyo	ref = (1000 * plp->plp_div + 2 * xtalfreq) / (2000 * plp->plp_div);
12179203945Sweongyo	ref &= 0xffff;
12180203945Sweongyo	for (i = 0; i < N(freqdata_tab); i++) {
12181203945Sweongyo		if (ref < freqdata_tab[i].freq) {
12182203945Sweongyo			f = &freqdata_tab[i];
12183203945Sweongyo			break;
12184203945Sweongyo		}
12185203945Sweongyo	}
12186203945Sweongyo	if (f == NULL)
12187203945Sweongyo		f = &freqdata_tab[N(freqdata_tab) - 1];
12188203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL8,
12189203945Sweongyo	    ((uint16_t)(f->value[1]) << 4) | f->value[0]);
12190203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL9,
12191203945Sweongyo	    ((uint16_t)(f->value[3]) << 4) | f->value[2]);
12192203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL10, f->value[4]);
12193203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL11, f->value[5]);
12194203945Sweongyo#undef CALC_CTL7
12195203945Sweongyo#undef CALC_CTL18
12196203945Sweongyo#undef CALC_CTL19
12197203945Sweongyo}
12198203945Sweongyo
12199203945Sweongyostatic void
12200203945Sweongyobwn_phy_lp_b2063_init(struct bwn_mac *mac)
12201203945Sweongyo{
12202203945Sweongyo
12203203945Sweongyo	bwn_phy_lp_b2063_tblinit(mac);
12204203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_SP5, 0);
12205203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM8, 0x38);
12206203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_REG_SP1, 0x56);
12207203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_RX_BB_CTL2, ~0x2);
12208203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0);
12209203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP6, 0x20);
12210203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP9, 0x40);
12211203945Sweongyo	if (mac->mac_phy.rev == 2) {
12212203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0xa0);
12213203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP4, 0xa0);
12214203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x18);
12215203945Sweongyo	} else {
12216203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0x20);
12217203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x20);
12218203945Sweongyo	}
12219203945Sweongyo}
12220203945Sweongyo
12221203945Sweongyostatic void
12222203945Sweongyobwn_phy_lp_rxcal_r2(struct bwn_mac *mac)
12223203945Sweongyo{
12224203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
12225203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
12226203945Sweongyo	static const struct bwn_wpair v1[] = {
12227203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x0 },
12228203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12229203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12230203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x15 },
12231203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x70 },
12232203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL4, 0x52 },
12233203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL5, 0x1 },
12234203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7d }
12235203945Sweongyo	};
12236203945Sweongyo	static const struct bwn_wpair v2[] = {
12237203945Sweongyo		{ BWN_B2063_TX_BB_SP3, 0x0 },
12238203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12239203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12240203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x55 },
12241203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x76 }
12242203945Sweongyo	};
12243203945Sweongyo	uint32_t freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
12244203945Sweongyo	int i;
12245203945Sweongyo	uint8_t tmp;
12246203945Sweongyo
12247203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_RX_BB_SP8) & 0xff;
12248203945Sweongyo
12249203945Sweongyo	for (i = 0; i < 2; i++)
12250203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12251203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, 0xf7);
12252203945Sweongyo	for (i = 2; i < N(v1); i++)
12253203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12254203945Sweongyo	for (i = 0; i < 10000; i++) {
12255203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12256203945Sweongyo			break;
12257203945Sweongyo		DELAY(1000);
12258203945Sweongyo	}
12259203945Sweongyo
12260203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12261203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RX_BB_SP8, tmp);
12262203945Sweongyo
12263203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_TX_BB_SP3) & 0xff;
12264203945Sweongyo
12265203945Sweongyo	for (i = 0; i < N(v2); i++)
12266203945Sweongyo		BWN_RF_WRITE(mac, v2[i].reg, v2[i].value);
12267203945Sweongyo	if (freqxtal == 24000000) {
12268203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0xfc);
12269203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x0);
12270203945Sweongyo	} else {
12271203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0x13);
12272203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x1);
12273203945Sweongyo	}
12274203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0x7d);
12275203945Sweongyo	for (i = 0; i < 10000; i++) {
12276203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12277203945Sweongyo			break;
12278203945Sweongyo		DELAY(1000);
12279203945Sweongyo	}
12280203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12281203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, tmp);
12282203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL1, 0x7e);
12283203945Sweongyo}
12284203945Sweongyo
12285203945Sweongyostatic void
12286203945Sweongyobwn_phy_lp_rccal_r12(struct bwn_mac *mac)
12287203945Sweongyo{
12288203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12289203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12290203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12291203945Sweongyo	struct bwn_txgain tx_gains;
12292203945Sweongyo	static const uint32_t pwrtbl[21] = {
12293203945Sweongyo		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
12294203945Sweongyo		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
12295203945Sweongyo		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
12296203945Sweongyo		0x0004c, 0x0002c, 0x0001a,
12297203945Sweongyo	};
12298203945Sweongyo	uint32_t npwr, ipwr, sqpwr, tmp;
12299203945Sweongyo	int loopback, i, j, sum, error;
12300203945Sweongyo	uint16_t save[7];
12301203945Sweongyo	uint8_t txo, bbmult, txpctlmode;
12302203945Sweongyo
12303203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
12304203945Sweongyo	if (error)
12305203945Sweongyo		device_printf(sc->sc_dev,
12306203945Sweongyo		    "failed to change channel to 7 (%d)\n", error);
12307203945Sweongyo	txo = (BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40) ? 1 : 0;
12308203945Sweongyo	bbmult = bwn_phy_lp_get_bbmult(mac);
12309203945Sweongyo	if (txo)
12310203945Sweongyo		tx_gains = bwn_phy_lp_get_txgain(mac);
12311203945Sweongyo
12312203945Sweongyo	save[0] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_0);
12313203945Sweongyo	save[1] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_VAL_0);
12314203945Sweongyo	save[2] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR);
12315203945Sweongyo	save[3] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVRVAL);
12316203945Sweongyo	save[4] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2);
12317203945Sweongyo	save[5] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2_VAL);
12318203945Sweongyo	save[6] = BWN_PHY_READ(mac, BWN_PHY_LP_PHY_CTL);
12319203945Sweongyo
12320203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
12321203945Sweongyo	txpctlmode = plp->plp_txpctlmode;
12322203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
12323203945Sweongyo
12324203945Sweongyo	/* disable CRS */
12325203945Sweongyo	bwn_phy_lp_set_deaf(mac, 1);
12326203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 0, 1);
12327203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffb);
12328203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x4);
12329203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7);
12330203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
12331203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x10);
12332203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12333203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf);
12334203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
12335203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffbf);
12336203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12337203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x7);
12338203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x38);
12339203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f);
12340203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x100);
12341203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfdff);
12342203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL0, 0);
12343203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL1, 1);
12344203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL2, 0x20);
12345203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfbff);
12346203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xf7ff);
12347203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
12348203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45af);
12349203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0x3ff);
12350203945Sweongyo
12351203945Sweongyo	loopback = bwn_phy_lp_loopback(mac);
12352203945Sweongyo	if (loopback == -1)
12353203945Sweongyo		goto done;
12354203945Sweongyo	bwn_phy_lp_set_rxgain_idx(mac, loopback);
12355203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xffbf, 0x40);
12356203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfff8, 0x1);
12357203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xffc7, 0x8);
12358203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f, 0xc0);
12359203945Sweongyo
12360203945Sweongyo	tmp = 0;
12361203945Sweongyo	memset(&ie, 0, sizeof(ie));
12362203945Sweongyo	for (i = 128; i <= 159; i++) {
12363203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2, i);
12364203945Sweongyo		sum = 0;
12365203945Sweongyo		for (j = 5; j <= 25; j++) {
12366203945Sweongyo			bwn_phy_lp_ddfs_turnon(mac, 1, 1, j, j, 0);
12367203945Sweongyo			if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
12368203945Sweongyo				goto done;
12369203945Sweongyo			sqpwr = ie.ie_ipwr + ie.ie_qpwr;
12370203945Sweongyo			ipwr = ((pwrtbl[j - 5] >> 3) + 1) >> 1;
12371203945Sweongyo			npwr = bwn_phy_lp_roundup(sqpwr, (j == 5) ? sqpwr : 0,
12372203945Sweongyo			    12);
12373203945Sweongyo			sum += ((ipwr - npwr) * (ipwr - npwr));
12374203945Sweongyo			if ((i == 128) || (sum < tmp)) {
12375203945Sweongyo				plp->plp_rccap = i;
12376203945Sweongyo				tmp = sum;
12377203945Sweongyo			}
12378203945Sweongyo		}
12379203945Sweongyo	}
12380203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
12381203945Sweongyodone:
12382203945Sweongyo	/* restore CRS */
12383203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 1);
12384203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xff80);
12385203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfc00);
12386203945Sweongyo
12387203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_VAL_0, save[1]);
12388203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, save[0]);
12389203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVRVAL, save[3]);
12390203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, save[2]);
12391203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2_VAL, save[5]);
12392203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, save[4]);
12393203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LP_PHY_CTL, save[6]);
12394203945Sweongyo
12395203945Sweongyo	bwn_phy_lp_set_bbmult(mac, bbmult);
12396203945Sweongyo	if (txo)
12397203945Sweongyo		bwn_phy_lp_set_txgain(mac, &tx_gains);
12398203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, txpctlmode);
12399203945Sweongyo	if (plp->plp_rccap)
12400203945Sweongyo		bwn_phy_lp_set_rccap(mac);
12401203945Sweongyo}
12402203945Sweongyo
12403203945Sweongyostatic void
12404203945Sweongyobwn_phy_lp_set_rccap(struct bwn_mac *mac)
12405203945Sweongyo{
12406203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12407203945Sweongyo	uint8_t rc_cap = (plp->plp_rccap & 0x1f) >> 1;
12408203945Sweongyo
12409203945Sweongyo	if (mac->mac_phy.rev == 1)
12410203945Sweongyo		rc_cap = MIN(rc_cap + 5, 15);
12411203945Sweongyo
12412203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2,
12413203945Sweongyo	    MAX(plp->plp_rccap - 4, 0x80));
12414203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, rc_cap | 0x80);
12415203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RXG_CNT16,
12416203945Sweongyo	    ((plp->plp_rccap & 0x1f) >> 2) | 0x80);
12417203945Sweongyo}
12418203945Sweongyo
12419203945Sweongyostatic uint32_t
12420203945Sweongyobwn_phy_lp_roundup(uint32_t value, uint32_t div, uint8_t pre)
12421203945Sweongyo{
12422203945Sweongyo	uint32_t i, q, r;
12423203945Sweongyo
12424203945Sweongyo	if (div == 0)
12425203945Sweongyo		return (0);
12426203945Sweongyo
12427203945Sweongyo	for (i = 0, q = value / div, r = value % div; i < pre; i++) {
12428203945Sweongyo		q <<= 1;
12429203945Sweongyo		if (r << 1 >= div) {
12430203945Sweongyo			q++;
12431203945Sweongyo			r = (r << 1) - div;
12432203945Sweongyo		}
12433203945Sweongyo	}
12434203945Sweongyo	if (r << 1 >= div)
12435203945Sweongyo		q++;
12436203945Sweongyo	return (q);
12437203945Sweongyo}
12438203945Sweongyo
12439203945Sweongyostatic void
12440203945Sweongyobwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *mac)
12441203945Sweongyo{
12442203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
12443203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
12444203945Sweongyo
12445203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0xff);
12446203945Sweongyo	DELAY(20);
12447203945Sweongyo	if (siba->siba_chipid == 0x5354) {
12448203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_COM1, 4);
12449203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 4);
12450203945Sweongyo	} else {
12451203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0);
12452203945Sweongyo	}
12453203945Sweongyo	DELAY(5);
12454203945Sweongyo}
12455203945Sweongyo
12456203945Sweongyostatic void
12457203945Sweongyobwn_phy_lp_b2062_vco_calib(struct bwn_mac *mac)
12458203945Sweongyo{
12459203945Sweongyo
12460203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x42);
12461203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x62);
12462203945Sweongyo	DELAY(200);
12463203945Sweongyo}
12464203945Sweongyo
12465203945Sweongyostatic void
12466203945Sweongyobwn_phy_lp_b2062_tblinit(struct bwn_mac *mac)
12467203945Sweongyo{
12468203945Sweongyo#define	FLAG_A	0x01
12469203945Sweongyo#define	FLAG_G	0x02
12470203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12471203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12472203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12473203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = {
12474203945Sweongyo		{ BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12475203945Sweongyo		{ BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, },
12476203945Sweongyo		{ BWN_B2062_N_PDNCTL3, 0x0, 0x0, FLAG_A | FLAG_G, },
12477203945Sweongyo		{ BWN_B2062_N_PDNCTL4, 0x15, 0x2a, FLAG_A | FLAG_G, },
12478203945Sweongyo		{ BWN_B2062_N_LGENC, 0xDB, 0xff, FLAG_A, },
12479203945Sweongyo		{ BWN_B2062_N_LGENATUNE0, 0xdd, 0x0, FLAG_A | FLAG_G, },
12480203945Sweongyo		{ BWN_B2062_N_LGENATUNE2, 0xdd, 0x0, FLAG_A | FLAG_G, },
12481203945Sweongyo		{ BWN_B2062_N_LGENATUNE3, 0x77, 0xB5, FLAG_A | FLAG_G, },
12482203945Sweongyo		{ BWN_B2062_N_LGENACTL3, 0x0, 0xff, FLAG_A | FLAG_G, },
12483203945Sweongyo		{ BWN_B2062_N_LGENACTL7, 0x33, 0x33, FLAG_A | FLAG_G, },
12484203945Sweongyo		{ BWN_B2062_N_RXA_CTL1, 0x0, 0x0, FLAG_G, },
12485203945Sweongyo		{ BWN_B2062_N_RXBB_CTL0, 0x82, 0x80, FLAG_A | FLAG_G, },
12486203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN1, 0x4, 0x4, FLAG_A | FLAG_G, },
12487203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN2, 0x0, 0x0, FLAG_A | FLAG_G, },
12488203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0x3, 0x3, FLAG_A | FLAG_G, },
12489203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0x2, 0x2, FLAG_A | FLAG_G, },
12490203945Sweongyo		{ BWN_B2062_N_TX_TUNE, 0x88, 0x1b, FLAG_A | FLAG_G, },
12491203945Sweongyo		{ BWN_B2062_S_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12492203945Sweongyo		{ BWN_B2062_S_PDS_CTL0, 0xff, 0xff, FLAG_A | FLAG_G, },
12493203945Sweongyo		{ BWN_B2062_S_LGENG_CTL0, 0xf8, 0xd8, FLAG_A | FLAG_G, },
12494203945Sweongyo		{ BWN_B2062_S_LGENG_CTL1, 0x3c, 0x24, FLAG_A | FLAG_G, },
12495203945Sweongyo		{ BWN_B2062_S_LGENG_CTL8, 0x88, 0x80, FLAG_A | FLAG_G, },
12496203945Sweongyo		{ BWN_B2062_S_LGENG_CTL10, 0x88, 0x80, FLAG_A | FLAG_G, },
12497203945Sweongyo		{ BWN_B2062_S_RFPLLCTL0, 0x98, 0x98, FLAG_A | FLAG_G, },
12498203945Sweongyo		{ BWN_B2062_S_RFPLLCTL1, 0x10, 0x10, FLAG_A | FLAG_G, },
12499203945Sweongyo		{ BWN_B2062_S_RFPLLCTL5, 0x43, 0x43, FLAG_A | FLAG_G, },
12500203945Sweongyo		{ BWN_B2062_S_RFPLLCTL6, 0x47, 0x47, FLAG_A | FLAG_G, },
12501203945Sweongyo		{ BWN_B2062_S_RFPLLCTL7, 0xc, 0xc, FLAG_A | FLAG_G, },
12502203945Sweongyo		{ BWN_B2062_S_RFPLLCTL8, 0x11, 0x11, FLAG_A | FLAG_G, },
12503203945Sweongyo		{ BWN_B2062_S_RFPLLCTL9, 0x11, 0x11, FLAG_A | FLAG_G, },
12504203945Sweongyo		{ BWN_B2062_S_RFPLLCTL10, 0xe, 0xe, FLAG_A | FLAG_G, },
12505203945Sweongyo		{ BWN_B2062_S_RFPLLCTL11, 0x8, 0x8, FLAG_A | FLAG_G, },
12506203945Sweongyo		{ BWN_B2062_S_RFPLLCTL12, 0x33, 0x33, FLAG_A | FLAG_G, },
12507203945Sweongyo		{ BWN_B2062_S_RFPLLCTL13, 0xa, 0xa, FLAG_A | FLAG_G, },
12508203945Sweongyo		{ BWN_B2062_S_RFPLLCTL14, 0x6, 0x6, FLAG_A | FLAG_G, },
12509203945Sweongyo		{ BWN_B2062_S_RFPLLCTL18, 0x3e, 0x3e, FLAG_A | FLAG_G, },
12510203945Sweongyo		{ BWN_B2062_S_RFPLLCTL19, 0x13, 0x13, FLAG_A | FLAG_G, },
12511203945Sweongyo		{ BWN_B2062_S_RFPLLCTL21, 0x62, 0x62, FLAG_A | FLAG_G, },
12512203945Sweongyo		{ BWN_B2062_S_RFPLLCTL22, 0x7, 0x7, FLAG_A | FLAG_G, },
12513203945Sweongyo		{ BWN_B2062_S_RFPLLCTL23, 0x16, 0x16, FLAG_A | FLAG_G, },
12514203945Sweongyo		{ BWN_B2062_S_RFPLLCTL24, 0x5c, 0x5c, FLAG_A | FLAG_G, },
12515203945Sweongyo		{ BWN_B2062_S_RFPLLCTL25, 0x95, 0x95, FLAG_A | FLAG_G, },
12516203945Sweongyo		{ BWN_B2062_S_RFPLLCTL30, 0xa0, 0xa0, FLAG_A | FLAG_G, },
12517203945Sweongyo		{ BWN_B2062_S_RFPLLCTL31, 0x4, 0x4, FLAG_A | FLAG_G, },
12518203945Sweongyo		{ BWN_B2062_S_RFPLLCTL33, 0xcc, 0xcc, FLAG_A | FLAG_G, },
12519203945Sweongyo		{ BWN_B2062_S_RFPLLCTL34, 0x7, 0x7, FLAG_A | FLAG_G, },
12520203945Sweongyo		{ BWN_B2062_S_RXG_CNT8, 0xf, 0xf, FLAG_A, },
12521203945Sweongyo	};
12522203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12523203945Sweongyo	unsigned int i;
12524203945Sweongyo
12525203945Sweongyo	for (i = 0; i < N(bwn_b2062_init_tab); i++) {
12526203945Sweongyo		br = &bwn_b2062_init_tab[i];
12527203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12528203945Sweongyo			if (br->br_flags & FLAG_G)
12529203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12530203945Sweongyo		} else {
12531203945Sweongyo			if (br->br_flags & FLAG_A)
12532203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12533203945Sweongyo		}
12534203945Sweongyo	}
12535203945Sweongyo#undef FLAG_A
12536203945Sweongyo#undef FLAG_B
12537203945Sweongyo}
12538203945Sweongyo
12539203945Sweongyostatic void
12540203945Sweongyobwn_phy_lp_b2063_tblinit(struct bwn_mac *mac)
12541203945Sweongyo{
12542203945Sweongyo#define	FLAG_A	0x01
12543203945Sweongyo#define	FLAG_G	0x02
12544203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12545203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12546203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12547203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = {
12548203945Sweongyo		{ BWN_B2063_COM1, 0x0, 0x0, FLAG_G, },
12549203945Sweongyo		{ BWN_B2063_COM10, 0x1, 0x0, FLAG_A, },
12550203945Sweongyo		{ BWN_B2063_COM16, 0x0, 0x0, FLAG_G, },
12551203945Sweongyo		{ BWN_B2063_COM17, 0x0, 0x0, FLAG_G, },
12552203945Sweongyo		{ BWN_B2063_COM18, 0x0, 0x0, FLAG_G, },
12553203945Sweongyo		{ BWN_B2063_COM19, 0x0, 0x0, FLAG_G, },
12554203945Sweongyo		{ BWN_B2063_COM20, 0x0, 0x0, FLAG_G, },
12555203945Sweongyo		{ BWN_B2063_COM21, 0x0, 0x0, FLAG_G, },
12556203945Sweongyo		{ BWN_B2063_COM22, 0x0, 0x0, FLAG_G, },
12557203945Sweongyo		{ BWN_B2063_COM23, 0x0, 0x0, FLAG_G, },
12558203945Sweongyo		{ BWN_B2063_COM24, 0x0, 0x0, FLAG_G, },
12559203945Sweongyo		{ BWN_B2063_LOGEN_SP1, 0xe8, 0xd4, FLAG_A | FLAG_G, },
12560203945Sweongyo		{ BWN_B2063_LOGEN_SP2, 0xa7, 0x53, FLAG_A | FLAG_G, },
12561203945Sweongyo		{ BWN_B2063_LOGEN_SP4, 0xf0, 0xf, FLAG_A | FLAG_G, },
12562203945Sweongyo		{ BWN_B2063_G_RX_SP1, 0x1f, 0x5e, FLAG_G, },
12563203945Sweongyo		{ BWN_B2063_G_RX_SP2, 0x7f, 0x7e, FLAG_G, },
12564203945Sweongyo		{ BWN_B2063_G_RX_SP3, 0x30, 0xf0, FLAG_G, },
12565203945Sweongyo		{ BWN_B2063_G_RX_SP7, 0x7f, 0x7f, FLAG_A | FLAG_G, },
12566203945Sweongyo		{ BWN_B2063_G_RX_SP10, 0xc, 0xc, FLAG_A | FLAG_G, },
12567203945Sweongyo		{ BWN_B2063_A_RX_SP1, 0x3c, 0x3f, FLAG_A, },
12568203945Sweongyo		{ BWN_B2063_A_RX_SP2, 0xfc, 0xfe, FLAG_A, },
12569203945Sweongyo		{ BWN_B2063_A_RX_SP7, 0x8, 0x8, FLAG_A | FLAG_G, },
12570203945Sweongyo		{ BWN_B2063_RX_BB_SP4, 0x60, 0x60, FLAG_A | FLAG_G, },
12571203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x30, 0x30, FLAG_A | FLAG_G, },
12572203945Sweongyo		{ BWN_B2063_TX_RF_SP3, 0xc, 0xb, FLAG_A | FLAG_G, },
12573203945Sweongyo		{ BWN_B2063_TX_RF_SP4, 0x10, 0xf, FLAG_A | FLAG_G, },
12574203945Sweongyo		{ BWN_B2063_PA_SP1, 0x3d, 0xfd, FLAG_A | FLAG_G, },
12575203945Sweongyo		{ BWN_B2063_TX_BB_SP1, 0x2, 0x2, FLAG_A | FLAG_G, },
12576203945Sweongyo		{ BWN_B2063_BANDGAP_CTL1, 0x56, 0x56, FLAG_A | FLAG_G, },
12577203945Sweongyo		{ BWN_B2063_JTAG_VCO2, 0xF7, 0xF7, FLAG_A | FLAG_G, },
12578203945Sweongyo		{ BWN_B2063_G_RX_MIX3, 0x71, 0x71, FLAG_A | FLAG_G, },
12579203945Sweongyo		{ BWN_B2063_G_RX_MIX4, 0x71, 0x71, FLAG_A | FLAG_G, },
12580203945Sweongyo		{ BWN_B2063_A_RX_1ST2, 0xf0, 0x30, FLAG_A, },
12581203945Sweongyo		{ BWN_B2063_A_RX_PS6, 0x77, 0x77, FLAG_A | FLAG_G, },
12582203945Sweongyo		{ BWN_B2063_A_RX_MIX4, 0x3, 0x3, FLAG_A | FLAG_G, },
12583203945Sweongyo		{ BWN_B2063_A_RX_MIX5, 0xf, 0xf, FLAG_A | FLAG_G, },
12584203945Sweongyo		{ BWN_B2063_A_RX_MIX6, 0xf, 0xf, FLAG_A | FLAG_G, },
12585203945Sweongyo		{ BWN_B2063_RX_TIA_CTL1, 0x77, 0x77, FLAG_A | FLAG_G, },
12586203945Sweongyo		{ BWN_B2063_RX_TIA_CTL3, 0x77, 0x77, FLAG_A | FLAG_G, },
12587203945Sweongyo		{ BWN_B2063_RX_BB_CTL2, 0x4, 0x4, FLAG_A | FLAG_G, },
12588203945Sweongyo		{ BWN_B2063_PA_CTL1, 0x0, 0x4, FLAG_A, },
12589203945Sweongyo		{ BWN_B2063_VREG_CTL1, 0x3, 0x3, FLAG_A | FLAG_G, },
12590203945Sweongyo	};
12591203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12592203945Sweongyo	unsigned int i;
12593203945Sweongyo
12594203945Sweongyo	for (i = 0; i < N(bwn_b2063_init_tab); i++) {
12595203945Sweongyo		br = &bwn_b2063_init_tab[i];
12596203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12597203945Sweongyo			if (br->br_flags & FLAG_G)
12598203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12599203945Sweongyo		} else {
12600203945Sweongyo			if (br->br_flags & FLAG_A)
12601203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12602203945Sweongyo		}
12603203945Sweongyo	}
12604203945Sweongyo#undef FLAG_A
12605203945Sweongyo#undef FLAG_B
12606203945Sweongyo}
12607203945Sweongyo
12608203945Sweongyostatic void
12609203945Sweongyobwn_tab_read_multi(struct bwn_mac *mac, uint32_t typenoffset,
12610203945Sweongyo    int count, void *_data)
12611203945Sweongyo{
12612203945Sweongyo	unsigned int i;
12613203945Sweongyo	uint32_t offset, type;
12614203945Sweongyo	uint8_t *data = _data;
12615203945Sweongyo
12616203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12617203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12618203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12619203945Sweongyo
12620203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12621203945Sweongyo
12622203945Sweongyo	for (i = 0; i < count; i++) {
12623203945Sweongyo		switch (type) {
12624203945Sweongyo		case BWN_TAB_8BIT:
12625203945Sweongyo			*data = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
12626203945Sweongyo			data++;
12627203945Sweongyo			break;
12628203945Sweongyo		case BWN_TAB_16BIT:
12629203945Sweongyo			*((uint16_t *)data) = BWN_PHY_READ(mac,
12630203945Sweongyo			    BWN_PHY_TABLEDATALO);
12631203945Sweongyo			data += 2;
12632203945Sweongyo			break;
12633203945Sweongyo		case BWN_TAB_32BIT:
12634203945Sweongyo			*((uint32_t *)data) = BWN_PHY_READ(mac,
12635203945Sweongyo			    BWN_PHY_TABLEDATAHI);
12636203945Sweongyo			*((uint32_t *)data) <<= 16;
12637203945Sweongyo			*((uint32_t *)data) |= BWN_PHY_READ(mac,
12638203945Sweongyo			    BWN_PHY_TABLEDATALO);
12639203945Sweongyo			data += 4;
12640203945Sweongyo			break;
12641203945Sweongyo		default:
12642203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12643203945Sweongyo		}
12644203945Sweongyo	}
12645203945Sweongyo}
12646203945Sweongyo
12647203945Sweongyostatic void
12648203945Sweongyobwn_tab_write_multi(struct bwn_mac *mac, uint32_t typenoffset,
12649203945Sweongyo    int count, const void *_data)
12650203945Sweongyo{
12651203945Sweongyo	uint32_t offset, type, value;
12652203945Sweongyo	const uint8_t *data = _data;
12653203945Sweongyo	unsigned int i;
12654203945Sweongyo
12655203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12656203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12657203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12658203945Sweongyo
12659203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12660203945Sweongyo
12661203945Sweongyo	for (i = 0; i < count; i++) {
12662203945Sweongyo		switch (type) {
12663203945Sweongyo		case BWN_TAB_8BIT:
12664203945Sweongyo			value = *data;
12665203945Sweongyo			data++;
12666203945Sweongyo			KASSERT(!(value & ~0xff),
12667203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12668203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12669203945Sweongyo			break;
12670203945Sweongyo		case BWN_TAB_16BIT:
12671203945Sweongyo			value = *((const uint16_t *)data);
12672203945Sweongyo			data += 2;
12673203945Sweongyo			KASSERT(!(value & ~0xffff),
12674203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12675203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12676203945Sweongyo			break;
12677203945Sweongyo		case BWN_TAB_32BIT:
12678203945Sweongyo			value = *((const uint32_t *)data);
12679203945Sweongyo			data += 4;
12680203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
12681203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12682203945Sweongyo			break;
12683203945Sweongyo		default:
12684203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12685203945Sweongyo		}
12686203945Sweongyo	}
12687203945Sweongyo}
12688203945Sweongyo
12689203945Sweongyostatic struct bwn_txgain
12690203945Sweongyobwn_phy_lp_get_txgain(struct bwn_mac *mac)
12691203945Sweongyo{
12692203945Sweongyo	struct bwn_txgain tg;
12693203945Sweongyo	uint16_t tmp;
12694203945Sweongyo
12695203945Sweongyo	tg.tg_dac = (BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0x380) >> 7;
12696203945Sweongyo	if (mac->mac_phy.rev < 2) {
12697203945Sweongyo		tmp = BWN_PHY_READ(mac,
12698203945Sweongyo		    BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7ff;
12699203945Sweongyo		tg.tg_gm = tmp & 0x0007;
12700203945Sweongyo		tg.tg_pga = (tmp & 0x0078) >> 3;
12701203945Sweongyo		tg.tg_pad = (tmp & 0x780) >> 7;
12702203945Sweongyo		return (tg);
12703203945Sweongyo	}
12704203945Sweongyo
12705203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL);
12706203945Sweongyo	tg.tg_pad = BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0xff;
12707203945Sweongyo	tg.tg_gm = tmp & 0xff;
12708203945Sweongyo	tg.tg_pga = (tmp >> 8) & 0xff;
12709203945Sweongyo	return (tg);
12710203945Sweongyo}
12711203945Sweongyo
12712203945Sweongyostatic uint8_t
12713203945Sweongyobwn_phy_lp_get_bbmult(struct bwn_mac *mac)
12714203945Sweongyo{
12715203945Sweongyo
12716203945Sweongyo	return (bwn_tab_read(mac, BWN_TAB_2(0, 87)) & 0xff00) >> 8;
12717203945Sweongyo}
12718203945Sweongyo
12719203945Sweongyostatic void
12720203945Sweongyobwn_phy_lp_set_txgain(struct bwn_mac *mac, struct bwn_txgain *tg)
12721203945Sweongyo{
12722203945Sweongyo	uint16_t pa;
12723203945Sweongyo
12724203945Sweongyo	if (mac->mac_phy.rev < 2) {
12725203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xf800,
12726203945Sweongyo		    (tg->tg_pad << 7) | (tg->tg_pga << 3) | tg->tg_gm);
12727203945Sweongyo		bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12728203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
12729203945Sweongyo		return;
12730203945Sweongyo	}
12731203945Sweongyo
12732203945Sweongyo	pa = bwn_phy_lp_get_pa_gain(mac);
12733203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
12734203945Sweongyo	    (tg->tg_pga << 8) | tg->tg_gm);
12735203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0x8000,
12736203945Sweongyo	    tg->tg_pad | (pa << 6));
12737203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xfc), (tg->tg_pga << 8) | tg->tg_gm);
12738203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x8000,
12739203945Sweongyo	    tg->tg_pad | (pa << 8));
12740203945Sweongyo	bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12741203945Sweongyo	bwn_phy_lp_set_txgain_override(mac);
12742203945Sweongyo}
12743203945Sweongyo
12744203945Sweongyostatic void
12745203945Sweongyobwn_phy_lp_set_bbmult(struct bwn_mac *mac, uint8_t bbmult)
12746203945Sweongyo{
12747203945Sweongyo
12748203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(0, 87), (uint16_t)bbmult << 8);
12749203945Sweongyo}
12750203945Sweongyo
12751203945Sweongyostatic void
12752203945Sweongyobwn_phy_lp_set_trsw_over(struct bwn_mac *mac, uint8_t tx, uint8_t rx)
12753203945Sweongyo{
12754203945Sweongyo	uint16_t trsw = (tx << 1) | rx;
12755203945Sweongyo
12756203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffc, trsw);
12757203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x3);
12758203945Sweongyo}
12759203945Sweongyo
12760203945Sweongyostatic void
12761203945Sweongyobwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain)
12762203945Sweongyo{
12763203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12764203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12765203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12766203945Sweongyo	uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp;
12767203945Sweongyo
12768203945Sweongyo	if (mac->mac_phy.rev < 2) {
12769203945Sweongyo		trsw = gain & 0x1;
12770203945Sweongyo		lna = (gain & 0xfffc) | ((gain & 0xc) >> 2);
12771203945Sweongyo		ext_lna = (gain & 2) >> 1;
12772203945Sweongyo
12773203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12774203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12775203945Sweongyo		    0xfbff, ext_lna << 10);
12776203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12777203945Sweongyo		    0xf7ff, ext_lna << 11);
12778203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
12779203945Sweongyo	} else {
12780203945Sweongyo		low_gain = gain & 0xffff;
12781203945Sweongyo		high_gain = (gain >> 16) & 0xf;
12782203945Sweongyo		ext_lna = (gain >> 21) & 0x1;
12783203945Sweongyo		trsw = ~(gain >> 20) & 0x1;
12784203945Sweongyo
12785203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12786203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12787203945Sweongyo		    0xfdff, ext_lna << 9);
12788203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12789203945Sweongyo		    0xfbff, ext_lna << 10);
12790203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
12791203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff0, high_gain);
12792203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12793203945Sweongyo			tmp = (gain >> 2) & 0x3;
12794203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12795203945Sweongyo			    0xe7ff, tmp<<11);
12796203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe6), 0xffe7,
12797203945Sweongyo			    tmp << 3);
12798203945Sweongyo		}
12799203945Sweongyo	}
12800203945Sweongyo
12801203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1);
12802203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12803203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12804203945Sweongyo	if (mac->mac_phy.rev >= 2) {
12805203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
12806203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12807203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x400);
12808203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xe5), 0x8);
12809203945Sweongyo		}
12810203945Sweongyo		return;
12811203945Sweongyo	}
12812203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x200);
12813203945Sweongyo}
12814203945Sweongyo
12815203945Sweongyostatic void
12816203945Sweongyobwn_phy_lp_set_deaf(struct bwn_mac *mac, uint8_t user)
12817203945Sweongyo{
12818203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12819203945Sweongyo
12820203945Sweongyo	if (user)
12821203945Sweongyo		plp->plp_crsusr_off = 1;
12822203945Sweongyo	else
12823203945Sweongyo		plp->plp_crssys_off = 1;
12824203945Sweongyo
12825203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x80);
12826203945Sweongyo}
12827203945Sweongyo
12828203945Sweongyostatic void
12829203945Sweongyobwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
12830203945Sweongyo{
12831203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12832203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12833203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12834203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12835203945Sweongyo
12836203945Sweongyo	if (user)
12837203945Sweongyo		plp->plp_crsusr_off = 0;
12838203945Sweongyo	else
12839203945Sweongyo		plp->plp_crssys_off = 0;
12840203945Sweongyo
12841203945Sweongyo	if (plp->plp_crsusr_off || plp->plp_crssys_off)
12842203945Sweongyo		return;
12843203945Sweongyo
12844203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12845203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x60);
12846203945Sweongyo	else
12847203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x20);
12848203945Sweongyo}
12849203945Sweongyo
12850203945Sweongyostatic unsigned int
12851203945Sweongyobwn_sqrt(struct bwn_mac *mac, unsigned int x)
12852203945Sweongyo{
12853203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12854203945Sweongyo	/* Table holding (10 * sqrt(x)) for x between 1 and 256. */
12855203945Sweongyo	static uint8_t sqrt_table[256] = {
12856203945Sweongyo		10, 14, 17, 20, 22, 24, 26, 28,
12857203945Sweongyo		30, 31, 33, 34, 36, 37, 38, 40,
12858203945Sweongyo		41, 42, 43, 44, 45, 46, 47, 48,
12859203945Sweongyo		50, 50, 51, 52, 53, 54, 55, 56,
12860203945Sweongyo		57, 58, 59, 60, 60, 61, 62, 63,
12861203945Sweongyo		64, 64, 65, 66, 67, 67, 68, 69,
12862203945Sweongyo		70, 70, 71, 72, 72, 73, 74, 74,
12863203945Sweongyo		75, 76, 76, 77, 78, 78, 79, 80,
12864203945Sweongyo		80, 81, 81, 82, 83, 83, 84, 84,
12865203945Sweongyo		85, 86, 86, 87, 87, 88, 88, 89,
12866203945Sweongyo		90, 90, 91, 91, 92, 92, 93, 93,
12867203945Sweongyo		94, 94, 95, 95, 96, 96, 97, 97,
12868203945Sweongyo		98, 98, 99, 100, 100, 100, 101, 101,
12869203945Sweongyo		102, 102, 103, 103, 104, 104, 105, 105,
12870203945Sweongyo		106, 106, 107, 107, 108, 108, 109, 109,
12871203945Sweongyo		110, 110, 110, 111, 111, 112, 112, 113,
12872203945Sweongyo		113, 114, 114, 114, 115, 115, 116, 116,
12873203945Sweongyo		117, 117, 117, 118, 118, 119, 119, 120,
12874203945Sweongyo		120, 120, 121, 121, 122, 122, 122, 123,
12875203945Sweongyo		123, 124, 124, 124, 125, 125, 126, 126,
12876203945Sweongyo		126, 127, 127, 128, 128, 128, 129, 129,
12877203945Sweongyo		130, 130, 130, 131, 131, 131, 132, 132,
12878203945Sweongyo		133, 133, 133, 134, 134, 134, 135, 135,
12879203945Sweongyo		136, 136, 136, 137, 137, 137, 138, 138,
12880203945Sweongyo		138, 139, 139, 140, 140, 140, 141, 141,
12881203945Sweongyo		141, 142, 142, 142, 143, 143, 143, 144,
12882203945Sweongyo		144, 144, 145, 145, 145, 146, 146, 146,
12883203945Sweongyo		147, 147, 147, 148, 148, 148, 149, 149,
12884203945Sweongyo		150, 150, 150, 150, 151, 151, 151, 152,
12885203945Sweongyo		152, 152, 153, 153, 153, 154, 154, 154,
12886203945Sweongyo		155, 155, 155, 156, 156, 156, 157, 157,
12887203945Sweongyo		157, 158, 158, 158, 159, 159, 159, 160
12888203945Sweongyo	};
12889203945Sweongyo
12890203945Sweongyo	if (x == 0)
12891203945Sweongyo		return (0);
12892203945Sweongyo	if (x >= 256) {
12893203945Sweongyo		device_printf(sc->sc_dev,
12894203945Sweongyo		    "out of bounds of the square-root table (%d)\n", x);
12895203945Sweongyo		return (16);
12896203945Sweongyo	}
12897203945Sweongyo	return (sqrt_table[x - 1] / 10);
12898203945Sweongyo}
12899203945Sweongyo
12900203945Sweongyostatic int
12901203945Sweongyobwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *mac, uint16_t sample)
12902203945Sweongyo{
12903203945Sweongyo#define	CALC_COEFF(_v, _x, _y, _z)	do {				\
12904203945Sweongyo	int _t;								\
12905203945Sweongyo	_t = _x - 20;							\
12906203945Sweongyo	if (_t >= 0) {							\
12907203945Sweongyo		_v = ((_y << (30 - _x)) + (_z >> (1 + _t))) / (_z >> _t); \
12908203945Sweongyo	} else {							\
12909203945Sweongyo		_v = ((_y << (30 - _x)) + (_z << (-1 - _t))) / (_z << -_t); \
12910203945Sweongyo	}								\
12911203945Sweongyo} while (0)
12912203945Sweongyo#define	CALC_COEFF2(_v, _x, _y, _z)	do {				\
12913203945Sweongyo	int _t;								\
12914203945Sweongyo	_t = _x - 11;							\
12915203945Sweongyo	if (_t >= 0)							\
12916203945Sweongyo		tmp[3] = (_y << (31 - _x)) / (_z >> _t);		\
12917203945Sweongyo	else								\
12918203945Sweongyo		tmp[3] = (_y << (31 - _x)) / (_z << -_t);		\
12919203945Sweongyo} while (0)
12920203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12921203945Sweongyo	uint16_t v0, v1;
12922203945Sweongyo	int tmp[2], ret;
12923203945Sweongyo
12924203945Sweongyo	v1 = BWN_PHY_READ(mac, BWN_PHY_RX_COMP_COEFF_S);
12925203945Sweongyo	v0 = v1 >> 8;
12926203945Sweongyo	v1 |= 0xff;
12927203945Sweongyo
12928203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, 0x00c0);
12929203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff);
12930203945Sweongyo
12931203945Sweongyo	ret = bwn_phy_lp_rx_iq_est(mac, sample, 32, &ie);
12932203945Sweongyo	if (ret == 0)
12933203945Sweongyo		goto done;
12934203945Sweongyo
12935203945Sweongyo	if (ie.ie_ipwr + ie.ie_qpwr < 2) {
12936203945Sweongyo		ret = 0;
12937203945Sweongyo		goto done;
12938203945Sweongyo	}
12939203945Sweongyo
12940203945Sweongyo	CALC_COEFF(tmp[0], bwn_nbits(ie.ie_iqprod), ie.ie_iqprod, ie.ie_ipwr);
12941203945Sweongyo	CALC_COEFF2(tmp[1], bwn_nbits(ie.ie_qpwr), ie.ie_qpwr, ie.ie_ipwr);
12942203945Sweongyo
12943203945Sweongyo	tmp[1] = -bwn_sqrt(mac, tmp[1] - (tmp[0] * tmp[0]));
12944203945Sweongyo	v0 = tmp[0] >> 3;
12945203945Sweongyo	v1 = tmp[1] >> 4;
12946203945Sweongyodone:
12947203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, v1);
12948203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, v0 << 8);
12949203945Sweongyo	return ret;
12950203945Sweongyo#undef CALC_COEFF
12951203945Sweongyo#undef CALC_COEFF2
12952203945Sweongyo}
12953203945Sweongyo
12954203945Sweongyostatic void
12955203945Sweongyobwn_phy_lp_tblinit_r01(struct bwn_mac *mac)
12956203945Sweongyo{
12957203945Sweongyo	static const uint16_t noisescale[] = {
12958203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12959203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4,
12960203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12961203945Sweongyo		0xa4a4, 0xa4a4, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12962203945Sweongyo		0x0000, 0x0000, 0x4c00, 0x2d36, 0x0000, 0x0000, 0x4c00, 0x2d36,
12963203945Sweongyo	};
12964203945Sweongyo	static const uint16_t crsgainnft[] = {
12965203945Sweongyo		0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f,
12966203945Sweongyo		0x036f, 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381,
12967203945Sweongyo		0x0374, 0x0381, 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f,
12968203945Sweongyo		0x0040, 0x005e, 0x007f, 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d,
12969203945Sweongyo		0x013d,
12970203945Sweongyo	};
12971203945Sweongyo	static const uint16_t filterctl[] = {
12972203945Sweongyo		0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077,
12973203945Sweongyo		0xff53, 0x0127,
12974203945Sweongyo	};
12975203945Sweongyo	static const uint32_t psctl[] = {
12976203945Sweongyo		0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101,
12977203945Sweongyo		0x00000080, 0x08080101, 0x00000040, 0x08080101, 0x000000c0,
12978203945Sweongyo		0x08a81501, 0x000000c0, 0x0fe8fd01, 0x000000c0, 0x08300105,
12979203945Sweongyo		0x000000c0, 0x08080201, 0x000000c0, 0x08280205, 0x000000c0,
12980203945Sweongyo		0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, 0x08080202,
12981203945Sweongyo		0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
12982203945Sweongyo		0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106,
12983203945Sweongyo		0x000000c0, 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
12984203945Sweongyo	};
12985203945Sweongyo	static const uint16_t ofdmcckgain_r0[] = {
12986203945Sweongyo		0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12987203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12988203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12989203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12990203945Sweongyo		0x755d,
12991203945Sweongyo	};
12992203945Sweongyo	static const uint16_t ofdmcckgain_r1[] = {
12993203945Sweongyo		0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12994203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12995203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12996203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12997203945Sweongyo		0x755d,
12998203945Sweongyo	};
12999203945Sweongyo	static const uint16_t gaindelta[] = {
13000203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13001203945Sweongyo		0x0000,
13002203945Sweongyo	};
13003203945Sweongyo	static const uint32_t txpwrctl[] = {
13004203945Sweongyo		0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c,
13005203945Sweongyo		0x0000004b, 0x0000004a, 0x00000049, 0x00000048, 0x00000047,
13006203945Sweongyo		0x00000046, 0x00000045, 0x00000044, 0x00000043, 0x00000042,
13007203945Sweongyo		0x00000041, 0x00000040, 0x0000003f, 0x0000003e, 0x0000003d,
13008203945Sweongyo		0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, 0x00000038,
13009203945Sweongyo		0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
13010203945Sweongyo		0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e,
13011203945Sweongyo		0x0000002d, 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029,
13012203945Sweongyo		0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
13013203945Sweongyo		0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001f,
13014203945Sweongyo		0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001a,
13015203945Sweongyo		0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
13016203945Sweongyo		0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000,
13017203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13018203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13019203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13020203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13021203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13022203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13023203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13024203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13025203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13026203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13027203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13028203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13029203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13030203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13031203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13032203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13033203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13034203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13035203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13036203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13037203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13038203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13039203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13040203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13041203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13042203945Sweongyo		0x00000000, 0x00000000, 0x000075a0, 0x000075a0, 0x000075a1,
13043203945Sweongyo		0x000075a1, 0x000075a2, 0x000075a2, 0x000075a3, 0x000075a3,
13044203945Sweongyo		0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, 0x000074b2,
13045203945Sweongyo		0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
13046203945Sweongyo		0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23,
13047203945Sweongyo		0x00006d23, 0x00004660, 0x00004660, 0x00004661, 0x00004661,
13048203945Sweongyo		0x00004662, 0x00004662, 0x00004663, 0x00004663, 0x00003e60,
13049203945Sweongyo		0x00003e60, 0x00003e61, 0x00003e61, 0x00003e62, 0x00003e62,
13050203945Sweongyo		0x00003e63, 0x00003e63, 0x00003660, 0x00003660, 0x00003661,
13051203945Sweongyo		0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
13052203945Sweongyo		0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62,
13053203945Sweongyo		0x00002e62, 0x00002e63, 0x00002e63, 0x00002660, 0x00002660,
13054203945Sweongyo		0x00002661, 0x00002661, 0x00002662, 0x00002662, 0x00002663,
13055203945Sweongyo		0x00002663, 0x000025e0, 0x000025e0, 0x000025e1, 0x000025e1,
13056203945Sweongyo		0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, 0x00001de0,
13057203945Sweongyo		0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
13058203945Sweongyo		0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61,
13059203945Sweongyo		0x00001d61, 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63,
13060203945Sweongyo		0x00001560, 0x00001560, 0x00001561, 0x00001561, 0x00001562,
13061203945Sweongyo		0x00001562, 0x00001563, 0x00001563, 0x00000d60, 0x00000d60,
13062203945Sweongyo		0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, 0x00000d63,
13063203945Sweongyo		0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
13064203945Sweongyo		0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10,
13065203945Sweongyo		0x00000e10, 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12,
13066203945Sweongyo		0x00000e13, 0x00000e13, 0x00000bf0, 0x00000bf0, 0x00000bf1,
13067203945Sweongyo		0x00000bf1, 0x00000bf2, 0x00000bf2, 0x00000bf3, 0x00000bf3,
13068203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13069203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13070203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13071203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13072203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13073203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13074203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13075203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13076203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13077203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13078203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13079203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13080203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13081203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13082203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13083203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13084203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13085203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13086203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13087203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13088203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13089203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13090203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13091203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13092203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13093203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc,
13094203945Sweongyo		0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04,
13095203945Sweongyo		0x0000fcff, 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006,
13096203945Sweongyo		0x0000ff03, 0x000007fc, 0x0000fc08, 0x00000203, 0x0000fffb,
13097203945Sweongyo		0x00000600, 0x0000fa01, 0x0000fc03, 0x0000fe06, 0x0000fe00,
13098203945Sweongyo		0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, 0x000004fd,
13099203945Sweongyo		0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
13100203945Sweongyo		0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa,
13101203945Sweongyo		0x00000700, 0x00000305, 0x000004ff, 0x00000801, 0x00000503,
13102203945Sweongyo		0x000005f9, 0x00000404, 0x0000fb08, 0x000005fd, 0x00000501,
13103203945Sweongyo		0x00000405, 0x0000fb03, 0x000007fc, 0x00000403, 0x00000303,
13104203945Sweongyo		0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, 0x0000fe01,
13105203945Sweongyo		0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
13106203945Sweongyo		0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa,
13107203945Sweongyo		0x000003fe, 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06,
13108203945Sweongyo		0x000008fc, 0x00000701, 0x00000504, 0x0000fdfe, 0x0000fdfc,
13109203945Sweongyo		0x000003fe, 0x00000704, 0x000002fc, 0x000004f9, 0x0000fdfd,
13110203945Sweongyo		0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, 0x000004f9,
13111203945Sweongyo		0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
13112203945Sweongyo		0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa,
13113203945Sweongyo		0x00000305, 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc,
13114203945Sweongyo		0x0000fe03, 0x00000701, 0x000001fb, 0x000001f9, 0x00000206,
13115203945Sweongyo		0x000006fd, 0x00000508, 0x00000700, 0x00000304, 0x000005fe,
13116203945Sweongyo		0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, 0x000007f9,
13117203945Sweongyo		0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
13118203945Sweongyo		0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb,
13119203945Sweongyo		0x00000702,
13120203945Sweongyo	};
13121203945Sweongyo
13122203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13123203945Sweongyo
13124203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13125203945Sweongyo	    bwn_tab_sigsq_tbl);
13126203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13127203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(crsgainnft), crsgainnft);
13128203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(8, 0), N(filterctl), filterctl);
13129203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(psctl), psctl);
13130203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13131203945Sweongyo	    bwn_tab_pllfrac_tbl);
13132203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13133203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13134203945Sweongyo	if (mac->mac_phy.rev == 0) {
13135203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r0),
13136203945Sweongyo		    ofdmcckgain_r0);
13137203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r0),
13138203945Sweongyo		    ofdmcckgain_r0);
13139203945Sweongyo	} else {
13140203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r1),
13141203945Sweongyo		    ofdmcckgain_r1);
13142203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r1),
13143203945Sweongyo		    ofdmcckgain_r1);
13144203945Sweongyo	}
13145203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(gaindelta), gaindelta);
13146203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(txpwrctl), txpwrctl);
13147203945Sweongyo}
13148203945Sweongyo
13149203945Sweongyostatic void
13150203945Sweongyobwn_phy_lp_tblinit_r2(struct bwn_mac *mac)
13151203945Sweongyo{
13152203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
13153203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
13154203945Sweongyo	int i;
13155203945Sweongyo	static const uint16_t noisescale[] = {
13156203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13157203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13158203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13159203945Sweongyo		0x00a4, 0x00a4, 0x0000, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13160203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13161203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13162203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4
13163203945Sweongyo	};
13164203945Sweongyo	static const uint32_t filterctl[] = {
13165203945Sweongyo		0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27,
13166203945Sweongyo		0x0000217f, 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f
13167203945Sweongyo	};
13168203945Sweongyo	static const uint32_t psctl[] = {
13169203945Sweongyo		0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000,
13170203945Sweongyo		0x00002080, 0x00006180, 0x00003002, 0x00000040, 0x00002042,
13171203945Sweongyo		0x00180047, 0x00080043, 0x00000041, 0x000020c1, 0x00046006,
13172203945Sweongyo		0x00042002, 0x00040000, 0x00002003, 0x00180006, 0x00080002
13173203945Sweongyo	};
13174203945Sweongyo	static const uint32_t gainidx[] = {
13175203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13176203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13177203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13178203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x10000001, 0x00000000,
13179203945Sweongyo		0x20000082, 0x00000000, 0x40000104, 0x00000000, 0x60004207,
13180203945Sweongyo		0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
13181203945Sweongyo		0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288,
13182203945Sweongyo		0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
13183203945Sweongyo		0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794,
13184203945Sweongyo		0x00000010, 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011,
13185203945Sweongyo		0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21,
13186203945Sweongyo		0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
13187203945Sweongyo		0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329,
13188203945Sweongyo		0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
13189203945Sweongyo		0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, 0x00000000,
13190203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13191203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13192203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13193203945Sweongyo		0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082,
13194203945Sweongyo		0x00000000, 0x40000104, 0x00000000, 0x60004207, 0x00000001,
13195203945Sweongyo		0x7000838a, 0x00000001, 0xd021050d, 0x00000001, 0xe041c683,
13196203945Sweongyo		0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
13197203945Sweongyo		0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711,
13198203945Sweongyo		0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
13199203945Sweongyo		0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c,
13200203945Sweongyo		0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019,
13201203945Sweongyo		0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, 0xb36811a6,
13202203945Sweongyo		0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
13203203945Sweongyo		0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c,
13204203945Sweongyo		0x0000001a, 0x64ca55ad, 0x0000001a
13205203945Sweongyo	};
13206203945Sweongyo	static const uint16_t auxgainidx[] = {
13207203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13208203945Sweongyo		0x0000, 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000,
13209203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002,
13210203945Sweongyo		0x0004, 0x0016
13211203945Sweongyo	};
13212203945Sweongyo	static const uint16_t swctl[] = {
13213203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13214203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13215203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13216203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
13217203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13218203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13219203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13220203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018
13221203945Sweongyo	};
13222203945Sweongyo	static const uint8_t hf[] = {
13223203945Sweongyo		0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
13224203945Sweongyo		0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17
13225203945Sweongyo	};
13226203945Sweongyo	static const uint32_t gainval[] = {
13227203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13228203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13229203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13230203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13231203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13232203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13233203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13234203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13235203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13236203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13237203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13238203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13239203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009,
13240203945Sweongyo		0x000000f1, 0x00000000, 0x00000000
13241203945Sweongyo	};
13242203945Sweongyo	static const uint16_t gain[] = {
13243203945Sweongyo		0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808,
13244203945Sweongyo		0x080a, 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813,
13245203945Sweongyo		0x0814, 0x0816, 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824,
13246203945Sweongyo		0x0830, 0x0834, 0x0837, 0x083b, 0x083f, 0x0840, 0x0844, 0x0857,
13247203945Sweongyo		0x085b, 0x085f, 0x08d7, 0x08db, 0x08df, 0x0957, 0x095b, 0x095f,
13248203945Sweongyo		0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, 0x175f, 0x0000, 0x0000,
13249203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13250203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13251203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13252203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13253203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13254203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13255203945Sweongyo	};
13256203945Sweongyo	static const uint32_t papdeps[] = {
13257203945Sweongyo		0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9,
13258203945Sweongyo		0x00021fdf, 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7,
13259203945Sweongyo		0x0004efc2, 0x00055fb5, 0x0005cfb0, 0x00063fa8, 0x00068fa3,
13260203945Sweongyo		0x00071f98, 0x0007ef92, 0x00084f8b, 0x0008df82, 0x00097f77,
13261203945Sweongyo		0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, 0x000bff41,
13262203945Sweongyo		0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
13263203945Sweongyo		0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15,
13264203945Sweongyo		0x00143f1c, 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f,
13265203945Sweongyo		0x001e6f7e, 0x0021cfa4, 0x0025bfd2, 0x002a2008, 0x002fb047,
13266203945Sweongyo		0x00360090, 0x003d40e0, 0x0045c135, 0x004fb189, 0x005ae1d7,
13267203945Sweongyo		0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, 0x007ff2e3,
13268203945Sweongyo		0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
13269203945Sweongyo		0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506
13270203945Sweongyo	};
13271203945Sweongyo	static const uint32_t papdmult[] = {
13272203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13273203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13274203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13275203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13276203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13277203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13278203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13279203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13280203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13281203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13282203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13283203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13284203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13285203945Sweongyo	};
13286203945Sweongyo	static const uint32_t gainidx_a0[] = {
13287203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13288203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13289203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13290203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13291203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13292203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13293203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13294203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13295203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13296203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13297203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13298203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13299203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13300203945Sweongyo	};
13301203945Sweongyo	static const uint16_t auxgainidx_a0[] = {
13302203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13303203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000,
13304203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13305203945Sweongyo		0x0002, 0x0014
13306203945Sweongyo	};
13307203945Sweongyo	static const uint32_t gainval_a0[] = {
13308203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13309203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13310203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13311203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13312203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13313203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13314203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13315203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13316203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13317203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13318203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13319203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13320203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f,
13321203945Sweongyo		0x000000f7, 0x00000000, 0x00000000
13322203945Sweongyo	};
13323203945Sweongyo	static const uint16_t gain_a0[] = {
13324203945Sweongyo		0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b,
13325203945Sweongyo		0x000c, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016,
13326203945Sweongyo		0x0017, 0x001a, 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034,
13327203945Sweongyo		0x0037, 0x003b, 0x003f, 0x0040, 0x0044, 0x0057, 0x005b, 0x005f,
13328203945Sweongyo		0x00d7, 0x00db, 0x00df, 0x0157, 0x015b, 0x015f, 0x0357, 0x035b,
13329203945Sweongyo		0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, 0x0000, 0x0000, 0x0000,
13330203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13331203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13332203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13333203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13334203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13335203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13336203945Sweongyo	};
13337203945Sweongyo
13338203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13339203945Sweongyo
13340203945Sweongyo	for (i = 0; i < 704; i++)
13341203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(7, i), 0);
13342203945Sweongyo
13343203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13344203945Sweongyo	    bwn_tab_sigsq_tbl);
13345203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13346203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(11, 0), N(filterctl), filterctl);
13347203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(12, 0), N(psctl), psctl);
13348203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx), gainidx);
13349203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx), auxgainidx);
13350203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(swctl), swctl);
13351203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(16, 0), N(hf), hf);
13352203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval), gainval);
13353203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain), gain);
13354203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13355203945Sweongyo	    bwn_tab_pllfrac_tbl);
13356203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13357203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13358203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(papdeps), papdeps);
13359203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(papdmult), papdmult);
13360203945Sweongyo
13361203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
13362203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx_a0),
13363203945Sweongyo		    gainidx_a0);
13364203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx_a0),
13365203945Sweongyo		    auxgainidx_a0);
13366203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval_a0),
13367203945Sweongyo		    gainval_a0);
13368203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain_a0), gain_a0);
13369203945Sweongyo	}
13370203945Sweongyo}
13371203945Sweongyo
13372203945Sweongyostatic void
13373203945Sweongyobwn_phy_lp_tblinit_txgain(struct bwn_mac *mac)
13374203945Sweongyo{
13375203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
13376203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
13377203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13378203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
13379203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
13380203945Sweongyo	static struct bwn_txgain_entry txgain_r2[] = {
13381203945Sweongyo		{ 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 },
13382203945Sweongyo		{ 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 },
13383203945Sweongyo		{ 255, 255, 203, 0, 135 }, { 255, 255, 203, 0, 131 },
13384203945Sweongyo		{ 255, 255, 203, 0, 128 }, { 255, 255, 203, 0, 124 },
13385203945Sweongyo		{ 255, 255, 203, 0, 121 }, { 255, 255, 203, 0, 117 },
13386203945Sweongyo		{ 255, 255, 203, 0, 114 }, { 255, 255, 203, 0, 111 },
13387203945Sweongyo		{ 255, 255, 203, 0, 107 }, { 255, 255, 203, 0, 104 },
13388203945Sweongyo		{ 255, 255, 203, 0, 101 }, { 255, 255, 203, 0, 99 },
13389203945Sweongyo		{ 255, 255, 203, 0, 96 }, { 255, 255, 203, 0, 93 },
13390203945Sweongyo		{ 255, 255, 203, 0, 90 }, { 255, 255, 203, 0, 88 },
13391203945Sweongyo		{ 255, 255, 203, 0, 85 }, { 255, 255, 203, 0, 83 },
13392203945Sweongyo		{ 255, 255, 203, 0, 81 }, { 255, 255, 203, 0, 78 },
13393203945Sweongyo		{ 255, 255, 203, 0, 76 }, { 255, 255, 203, 0, 74 },
13394203945Sweongyo		{ 255, 255, 203, 0, 72 }, { 255, 255, 203, 0, 70 },
13395203945Sweongyo		{ 255, 255, 203, 0, 68 }, { 255, 255, 203, 0, 66 },
13396203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13397203945Sweongyo		{ 255, 255, 192, 0, 64 }, { 255, 255, 186, 0, 64 },
13398203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 176, 0, 64 },
13399203945Sweongyo		{ 255, 255, 171, 0, 64 }, { 255, 255, 166, 0, 64 },
13400203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 157, 0, 64 },
13401203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13402203945Sweongyo		{ 255, 255, 144, 0, 64 }, { 255, 255, 140, 0, 64 },
13403203945Sweongyo		{ 255, 255, 136, 0, 64 }, { 255, 255, 132, 0, 64 },
13404203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13405203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13406203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13407203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 105, 0, 64 },
13408203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13409203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13410203945Sweongyo		{ 255, 255, 91, 0, 64 }, { 255, 255, 88, 0, 64 },
13411203945Sweongyo		{ 255, 255, 86, 0, 64 }, { 255, 255, 83, 0, 64 },
13412203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 79, 0, 64 },
13413203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13414203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13415203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13416203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 248, 64, 0, 64 },
13417203945Sweongyo		{ 255, 248, 62, 0, 64 }, { 255, 241, 62, 0, 64 },
13418203945Sweongyo		{ 255, 241, 60, 0, 64 }, { 255, 234, 60, 0, 64 },
13419203945Sweongyo		{ 255, 234, 59, 0, 64 }, { 255, 227, 59, 0, 64 },
13420203945Sweongyo		{ 255, 227, 57, 0, 64 }, { 255, 221, 57, 0, 64 },
13421203945Sweongyo		{ 255, 221, 55, 0, 64 }, { 255, 215, 55, 0, 64 },
13422203945Sweongyo		{ 255, 215, 54, 0, 64 }, { 255, 208, 54, 0, 64 },
13423203945Sweongyo		{ 255, 208, 52, 0, 64 }, { 255, 203, 52, 0, 64 },
13424203945Sweongyo		{ 255, 203, 51, 0, 64 }, { 255, 197, 51, 0, 64 },
13425203945Sweongyo		{ 255, 197, 49, 0, 64 }, { 255, 191, 49, 0, 64 },
13426203945Sweongyo		{ 255, 191, 48, 0, 64 }, { 255, 186, 48, 0, 64 },
13427203945Sweongyo		{ 255, 186, 47, 0, 64 }, { 255, 181, 47, 0, 64 },
13428203945Sweongyo		{ 255, 181, 45, 0, 64 }, { 255, 175, 45, 0, 64 },
13429203945Sweongyo		{ 255, 175, 44, 0, 64 }, { 255, 170, 44, 0, 64 },
13430203945Sweongyo		{ 255, 170, 43, 0, 64 }, { 255, 166, 43, 0, 64 },
13431203945Sweongyo		{ 255, 166, 42, 0, 64 }, { 255, 161, 42, 0, 64 },
13432203945Sweongyo		{ 255, 161, 40, 0, 64 }, { 255, 156, 40, 0, 64 },
13433203945Sweongyo		{ 255, 156, 39, 0, 64 }, { 255, 152, 39, 0, 64 },
13434203945Sweongyo		{ 255, 152, 38, 0, 64 }, { 255, 148, 38, 0, 64 },
13435203945Sweongyo		{ 255, 148, 37, 0, 64 }, { 255, 143, 37, 0, 64 },
13436203945Sweongyo		{ 255, 143, 36, 0, 64 }, { 255, 139, 36, 0, 64 },
13437203945Sweongyo		{ 255, 139, 35, 0, 64 }, { 255, 135, 35, 0, 64 },
13438203945Sweongyo		{ 255, 135, 34, 0, 64 }, { 255, 132, 34, 0, 64 },
13439203945Sweongyo		{ 255, 132, 33, 0, 64 }, { 255, 128, 33, 0, 64 },
13440203945Sweongyo		{ 255, 128, 32, 0, 64 }, { 255, 124, 32, 0, 64 },
13441203945Sweongyo		{ 255, 124, 31, 0, 64 }, { 255, 121, 31, 0, 64 },
13442203945Sweongyo		{ 255, 121, 30, 0, 64 }, { 255, 117, 30, 0, 64 },
13443203945Sweongyo		{ 255, 117, 29, 0, 64 }, { 255, 114, 29, 0, 64 },
13444203945Sweongyo		{ 255, 114, 29, 0, 64 }, { 255, 111, 29, 0, 64 },
13445203945Sweongyo	};
13446203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r2[] = {
13447203945Sweongyo		{ 7, 99, 255, 0, 64 }, { 7, 96, 255, 0, 64 },
13448203945Sweongyo		{ 7, 93, 255, 0, 64 }, { 7, 90, 255, 0, 64 },
13449203945Sweongyo		{ 7, 88, 255, 0, 64 }, { 7, 85, 255, 0, 64 },
13450203945Sweongyo		{ 7, 83, 255, 0, 64 }, { 7, 81, 255, 0, 64 },
13451203945Sweongyo		{ 7, 78, 255, 0, 64 }, { 7, 76, 255, 0, 64 },
13452203945Sweongyo		{ 7, 74, 255, 0, 64 }, { 7, 72, 255, 0, 64 },
13453203945Sweongyo		{ 7, 70, 255, 0, 64 }, { 7, 68, 255, 0, 64 },
13454203945Sweongyo		{ 7, 66, 255, 0, 64 }, { 7, 64, 255, 0, 64 },
13455203945Sweongyo		{ 7, 64, 255, 0, 64 }, { 7, 62, 255, 0, 64 },
13456203945Sweongyo		{ 7, 62, 248, 0, 64 }, { 7, 60, 248, 0, 64 },
13457203945Sweongyo		{ 7, 60, 241, 0, 64 }, { 7, 59, 241, 0, 64 },
13458203945Sweongyo		{ 7, 59, 234, 0, 64 }, { 7, 57, 234, 0, 64 },
13459203945Sweongyo		{ 7, 57, 227, 0, 64 }, { 7, 55, 227, 0, 64 },
13460203945Sweongyo		{ 7, 55, 221, 0, 64 }, { 7, 54, 221, 0, 64 },
13461203945Sweongyo		{ 7, 54, 215, 0, 64 }, { 7, 52, 215, 0, 64 },
13462203945Sweongyo		{ 7, 52, 208, 0, 64 }, { 7, 51, 208, 0, 64 },
13463203945Sweongyo		{ 7, 51, 203, 0, 64 }, { 7, 49, 203, 0, 64 },
13464203945Sweongyo		{ 7, 49, 197, 0, 64 }, { 7, 48, 197, 0, 64 },
13465203945Sweongyo		{ 7, 48, 191, 0, 64 }, { 7, 47, 191, 0, 64 },
13466203945Sweongyo		{ 7, 47, 186, 0, 64 }, { 7, 45, 186, 0, 64 },
13467203945Sweongyo		{ 7, 45, 181, 0, 64 }, { 7, 44, 181, 0, 64 },
13468203945Sweongyo		{ 7, 44, 175, 0, 64 }, { 7, 43, 175, 0, 64 },
13469203945Sweongyo		{ 7, 43, 170, 0, 64 }, { 7, 42, 170, 0, 64 },
13470203945Sweongyo		{ 7, 42, 166, 0, 64 }, { 7, 40, 166, 0, 64 },
13471203945Sweongyo		{ 7, 40, 161, 0, 64 }, { 7, 39, 161, 0, 64 },
13472203945Sweongyo		{ 7, 39, 156, 0, 64 }, { 7, 38, 156, 0, 64 },
13473203945Sweongyo		{ 7, 38, 152, 0, 64 }, { 7, 37, 152, 0, 64 },
13474203945Sweongyo		{ 7, 37, 148, 0, 64 }, { 7, 36, 148, 0, 64 },
13475203945Sweongyo		{ 7, 36, 143, 0, 64 }, { 7, 35, 143, 0, 64 },
13476203945Sweongyo		{ 7, 35, 139, 0, 64 }, { 7, 34, 139, 0, 64 },
13477203945Sweongyo		{ 7, 34, 135, 0, 64 }, { 7, 33, 135, 0, 64 },
13478203945Sweongyo		{ 7, 33, 132, 0, 64 }, { 7, 32, 132, 0, 64 },
13479203945Sweongyo		{ 7, 32, 128, 0, 64 }, { 7, 31, 128, 0, 64 },
13480203945Sweongyo		{ 7, 31, 124, 0, 64 }, { 7, 30, 124, 0, 64 },
13481203945Sweongyo		{ 7, 30, 121, 0, 64 }, { 7, 29, 121, 0, 64 },
13482203945Sweongyo		{ 7, 29, 117, 0, 64 }, { 7, 29, 117, 0, 64 },
13483203945Sweongyo		{ 7, 29, 114, 0, 64 }, { 7, 28, 114, 0, 64 },
13484203945Sweongyo		{ 7, 28, 111, 0, 64 }, { 7, 27, 111, 0, 64 },
13485203945Sweongyo		{ 7, 27, 108, 0, 64 }, { 7, 26, 108, 0, 64 },
13486203945Sweongyo		{ 7, 26, 104, 0, 64 }, { 7, 25, 104, 0, 64 },
13487203945Sweongyo		{ 7, 25, 102, 0, 64 }, { 7, 25, 102, 0, 64 },
13488203945Sweongyo		{ 7, 25, 99, 0, 64 }, { 7, 24, 99, 0, 64 },
13489203945Sweongyo		{ 7, 24, 96, 0, 64 }, { 7, 23, 96, 0, 64 },
13490203945Sweongyo		{ 7, 23, 93, 0, 64 }, { 7, 23, 93, 0, 64 },
13491203945Sweongyo		{ 7, 23, 90, 0, 64 }, { 7, 22, 90, 0, 64 },
13492203945Sweongyo		{ 7, 22, 88, 0, 64 }, { 7, 21, 88, 0, 64 },
13493203945Sweongyo		{ 7, 21, 85, 0, 64 }, { 7, 21, 85, 0, 64 },
13494203945Sweongyo		{ 7, 21, 83, 0, 64 }, { 7, 20, 83, 0, 64 },
13495203945Sweongyo		{ 7, 20, 81, 0, 64 }, { 7, 20, 81, 0, 64 },
13496203945Sweongyo		{ 7, 20, 78, 0, 64 }, { 7, 19, 78, 0, 64 },
13497203945Sweongyo		{ 7, 19, 76, 0, 64 }, { 7, 19, 76, 0, 64 },
13498203945Sweongyo		{ 7, 19, 74, 0, 64 }, { 7, 18, 74, 0, 64 },
13499203945Sweongyo		{ 7, 18, 72, 0, 64 }, { 7, 18, 72, 0, 64 },
13500203945Sweongyo		{ 7, 18, 70, 0, 64 }, { 7, 17, 70, 0, 64 },
13501203945Sweongyo		{ 7, 17, 68, 0, 64 }, { 7, 17, 68, 0, 64 },
13502203945Sweongyo		{ 7, 17, 66, 0, 64 }, { 7, 16, 66, 0, 64 },
13503203945Sweongyo		{ 7, 16, 64, 0, 64 }, { 7, 16, 64, 0, 64 },
13504203945Sweongyo		{ 7, 16, 62, 0, 64 }, { 7, 15, 62, 0, 64 },
13505203945Sweongyo		{ 7, 15, 60, 0, 64 }, { 7, 15, 60, 0, 64 },
13506203945Sweongyo		{ 7, 15, 59, 0, 64 }, { 7, 14, 59, 0, 64 },
13507203945Sweongyo		{ 7, 14, 57, 0, 64 }, { 7, 14, 57, 0, 64 },
13508203945Sweongyo		{ 7, 14, 55, 0, 64 }, { 7, 14, 55, 0, 64 },
13509203945Sweongyo		{ 7, 14, 54, 0, 64 }, { 7, 13, 54, 0, 64 },
13510203945Sweongyo		{ 7, 13, 52, 0, 64 }, { 7, 13, 52, 0, 64 },
13511203945Sweongyo	};
13512203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r2[] = {
13513203945Sweongyo		{ 255, 255, 255, 0, 152 }, { 255, 255, 255, 0, 147 },
13514203945Sweongyo		{ 255, 255, 255, 0, 143 }, { 255, 255, 255, 0, 139 },
13515203945Sweongyo		{ 255, 255, 255, 0, 135 }, { 255, 255, 255, 0, 131 },
13516203945Sweongyo		{ 255, 255, 255, 0, 128 }, { 255, 255, 255, 0, 124 },
13517203945Sweongyo		{ 255, 255, 255, 0, 121 }, { 255, 255, 255, 0, 117 },
13518203945Sweongyo		{ 255, 255, 255, 0, 114 }, { 255, 255, 255, 0, 111 },
13519203945Sweongyo		{ 255, 255, 255, 0, 107 }, { 255, 255, 255, 0, 104 },
13520203945Sweongyo		{ 255, 255, 255, 0, 101 }, { 255, 255, 255, 0, 99 },
13521203945Sweongyo		{ 255, 255, 255, 0, 96 }, { 255, 255, 255, 0, 93 },
13522203945Sweongyo		{ 255, 255, 255, 0, 90 }, { 255, 255, 255, 0, 88 },
13523203945Sweongyo		{ 255, 255, 255, 0, 85 }, { 255, 255, 255, 0, 83 },
13524203945Sweongyo		{ 255, 255, 255, 0, 81 }, { 255, 255, 255, 0, 78 },
13525203945Sweongyo		{ 255, 255, 255, 0, 76 }, { 255, 255, 255, 0, 74 },
13526203945Sweongyo		{ 255, 255, 255, 0, 72 }, { 255, 255, 255, 0, 70 },
13527203945Sweongyo		{ 255, 255, 255, 0, 68 }, { 255, 255, 255, 0, 66 },
13528203945Sweongyo		{ 255, 255, 255, 0, 64 }, { 255, 255, 248, 0, 64 },
13529203945Sweongyo		{ 255, 255, 241, 0, 64 }, { 255, 255, 234, 0, 64 },
13530203945Sweongyo		{ 255, 255, 227, 0, 64 }, { 255, 255, 221, 0, 64 },
13531203945Sweongyo		{ 255, 255, 215, 0, 64 }, { 255, 255, 208, 0, 64 },
13532203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13533203945Sweongyo		{ 255, 255, 191, 0, 64 }, { 255, 255, 186, 0, 64 },
13534203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 175, 0, 64 },
13535203945Sweongyo		{ 255, 255, 170, 0, 64 }, { 255, 255, 166, 0, 64 },
13536203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 156, 0, 64 },
13537203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13538203945Sweongyo		{ 255, 255, 143, 0, 64 }, { 255, 255, 139, 0, 64 },
13539203945Sweongyo		{ 255, 255, 135, 0, 64 }, { 255, 255, 132, 0, 64 },
13540203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13541203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13542203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13543203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 104, 0, 64 },
13544203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13545203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13546203945Sweongyo		{ 255, 255, 90, 0, 64 }, { 255, 255, 88, 0, 64 },
13547203945Sweongyo		{ 255, 255, 85, 0, 64 }, { 255, 255, 83, 0, 64 },
13548203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 78, 0, 64 },
13549203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13550203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13551203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13552203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 255, 64, 0, 64 },
13553203945Sweongyo		{ 255, 255, 62, 0, 64 }, { 255, 248, 62, 0, 64 },
13554203945Sweongyo		{ 255, 248, 60, 0, 64 }, { 255, 241, 60, 0, 64 },
13555203945Sweongyo		{ 255, 241, 59, 0, 64 }, { 255, 234, 59, 0, 64 },
13556203945Sweongyo		{ 255, 234, 57, 0, 64 }, { 255, 227, 57, 0, 64 },
13557203945Sweongyo		{ 255, 227, 55, 0, 64 }, { 255, 221, 55, 0, 64 },
13558203945Sweongyo		{ 255, 221, 54, 0, 64 }, { 255, 215, 54, 0, 64 },
13559203945Sweongyo		{ 255, 215, 52, 0, 64 }, { 255, 208, 52, 0, 64 },
13560203945Sweongyo		{ 255, 208, 51, 0, 64 }, { 255, 203, 51, 0, 64 },
13561203945Sweongyo		{ 255, 203, 49, 0, 64 }, { 255, 197, 49, 0, 64 },
13562203945Sweongyo		{ 255, 197, 48, 0, 64 }, { 255, 191, 48, 0, 64 },
13563203945Sweongyo		{ 255, 191, 47, 0, 64 }, { 255, 186, 47, 0, 64 },
13564203945Sweongyo		{ 255, 186, 45, 0, 64 }, { 255, 181, 45, 0, 64 },
13565203945Sweongyo		{ 255, 181, 44, 0, 64 }, { 255, 175, 44, 0, 64 },
13566203945Sweongyo		{ 255, 175, 43, 0, 64 }, { 255, 170, 43, 0, 64 },
13567203945Sweongyo		{ 255, 170, 42, 0, 64 }, { 255, 166, 42, 0, 64 },
13568203945Sweongyo		{ 255, 166, 40, 0, 64 }, { 255, 161, 40, 0, 64 },
13569203945Sweongyo		{ 255, 161, 39, 0, 64 }, { 255, 156, 39, 0, 64 },
13570203945Sweongyo		{ 255, 156, 38, 0, 64 }, { 255, 152, 38, 0, 64 },
13571203945Sweongyo		{ 255, 152, 37, 0, 64 }, { 255, 148, 37, 0, 64 },
13572203945Sweongyo		{ 255, 148, 36, 0, 64 }, { 255, 143, 36, 0, 64 },
13573203945Sweongyo		{ 255, 143, 35, 0, 64 }, { 255, 139, 35, 0, 64 },
13574203945Sweongyo		{ 255, 139, 34, 0, 64 }, { 255, 135, 34, 0, 64 },
13575203945Sweongyo		{ 255, 135, 33, 0, 64 }, { 255, 132, 33, 0, 64 },
13576203945Sweongyo		{ 255, 132, 32, 0, 64 }, { 255, 128, 32, 0, 64 }
13577203945Sweongyo	};
13578203945Sweongyo	static struct bwn_txgain_entry txgain_r0[] = {
13579203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13580203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13581203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13582203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13583203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13584203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13585203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13586203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13587203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13588203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13589203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13590203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13591203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13592203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13593203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13594203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13595203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13596203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13597203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 13, 0, 68 },
13598203945Sweongyo		{ 7, 15, 13, 0, 66 }, { 7, 15, 13, 0, 64 },
13599203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13600203945Sweongyo		{ 7, 15, 13, 0, 59 }, { 7, 15, 13, 0, 57 },
13601203945Sweongyo		{ 7, 15, 12, 0, 71 }, { 7, 15, 12, 0, 69 },
13602203945Sweongyo		{ 7, 15, 12, 0, 67 }, { 7, 15, 12, 0, 65 },
13603203945Sweongyo		{ 7, 15, 12, 0, 63 }, { 7, 15, 12, 0, 62 },
13604203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 58 },
13605203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 70 },
13606203945Sweongyo		{ 7, 15, 11, 0, 68 }, { 7, 15, 11, 0, 66 },
13607203945Sweongyo		{ 7, 15, 11, 0, 65 }, { 7, 15, 11, 0, 63 },
13608203945Sweongyo		{ 7, 15, 11, 0, 61 }, { 7, 15, 11, 0, 59 },
13609203945Sweongyo		{ 7, 15, 11, 0, 58 }, { 7, 15, 10, 0, 71 },
13610203945Sweongyo		{ 7, 15, 10, 0, 69 }, { 7, 15, 10, 0, 67 },
13611203945Sweongyo		{ 7, 15, 10, 0, 65 }, { 7, 15, 10, 0, 63 },
13612203945Sweongyo		{ 7, 15, 10, 0, 61 }, { 7, 15, 10, 0, 60 },
13613203945Sweongyo		{ 7, 15, 10, 0, 58 }, { 7, 15, 10, 0, 56 },
13614203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13615203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13616203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 60 },
13617203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 14, 9, 0, 72 },
13618203945Sweongyo		{ 7, 14, 9, 0, 70 }, { 7, 14, 9, 0, 68 },
13619203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 64 },
13620203945Sweongyo		{ 7, 14, 9, 0, 62 }, { 7, 14, 9, 0, 60 },
13621203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 13, 9, 0, 72 },
13622203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13623203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13624203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13625203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13626203945Sweongyo		{ 7, 13, 8, 0, 72 }, { 7, 13, 8, 0, 70 },
13627203945Sweongyo		{ 7, 13, 8, 0, 68 }, { 7, 13, 8, 0, 66 },
13628203945Sweongyo		{ 7, 13, 8, 0, 64 }, { 7, 13, 8, 0, 62 },
13629203945Sweongyo		{ 7, 13, 8, 0, 60 }, { 7, 13, 8, 0, 59 },
13630203945Sweongyo		{ 7, 12, 8, 0, 72 }, { 7, 12, 8, 0, 70 },
13631203945Sweongyo		{ 7, 12, 8, 0, 68 }, { 7, 12, 8, 0, 66 },
13632203945Sweongyo		{ 7, 12, 8, 0, 64 }, { 7, 12, 8, 0, 62 },
13633203945Sweongyo		{ 7, 12, 8, 0, 61 }, { 7, 12, 8, 0, 59 },
13634203945Sweongyo		{ 7, 12, 7, 0, 73 }, { 7, 12, 7, 0, 71 },
13635203945Sweongyo		{ 7, 12, 7, 0, 69 }, { 7, 12, 7, 0, 67 },
13636203945Sweongyo		{ 7, 12, 7, 0, 65 }, { 7, 12, 7, 0, 63 },
13637203945Sweongyo		{ 7, 12, 7, 0, 61 }, { 7, 12, 7, 0, 59 },
13638203945Sweongyo		{ 7, 11, 7, 0, 72 }, { 7, 11, 7, 0, 70 },
13639203945Sweongyo		{ 7, 11, 7, 0, 68 }, { 7, 11, 7, 0, 66 },
13640203945Sweongyo		{ 7, 11, 7, 0, 65 }, { 7, 11, 7, 0, 63 },
13641203945Sweongyo		{ 7, 11, 7, 0, 61 }, { 7, 11, 7, 0, 59 },
13642203945Sweongyo		{ 7, 11, 6, 0, 73 }, { 7, 11, 6, 0, 71 }
13643203945Sweongyo	};
13644203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r0[] = {
13645203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13646203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13647203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13648203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13649203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13650203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13651203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13652203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13653203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13654203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13655203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13656203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13657203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13658203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13659203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13660203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13661203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13662203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13663203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13664203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13665203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13666203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13667203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13668203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13669203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13670203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13671203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13672203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13673203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13674203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13675203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13676203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13677203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13678203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 },
13679203945Sweongyo		{ 4, 10, 6, 0, 59 }, { 4, 10, 5, 0, 72 },
13680203945Sweongyo		{ 4, 10, 5, 0, 70 }, { 4, 10, 5, 0, 68 },
13681203945Sweongyo		{ 4, 10, 5, 0, 66 }, { 4, 10, 5, 0, 64 },
13682203945Sweongyo		{ 4, 10, 5, 0, 62 }, { 4, 10, 5, 0, 60 },
13683203945Sweongyo		{ 4, 10, 5, 0, 59 }, { 4, 9, 5, 0, 70 },
13684203945Sweongyo		{ 4, 9, 5, 0, 68 }, { 4, 9, 5, 0, 66 },
13685203945Sweongyo		{ 4, 9, 5, 0, 64 }, { 4, 9, 5, 0, 63 },
13686203945Sweongyo		{ 4, 9, 5, 0, 61 }, { 4, 9, 5, 0, 59 },
13687203945Sweongyo		{ 4, 9, 4, 0, 71 }, { 4, 9, 4, 0, 69 },
13688203945Sweongyo		{ 4, 9, 4, 0, 67 }, { 4, 9, 4, 0, 65 },
13689203945Sweongyo		{ 4, 9, 4, 0, 63 }, { 4, 9, 4, 0, 62 },
13690203945Sweongyo		{ 4, 9, 4, 0, 60 }, { 4, 9, 4, 0, 58 },
13691203945Sweongyo		{ 4, 8, 4, 0, 70 }, { 4, 8, 4, 0, 68 },
13692203945Sweongyo		{ 4, 8, 4, 0, 66 }, { 4, 8, 4, 0, 65 },
13693203945Sweongyo		{ 4, 8, 4, 0, 63 }, { 4, 8, 4, 0, 61 },
13694203945Sweongyo		{ 4, 8, 4, 0, 59 }, { 4, 7, 4, 0, 68 },
13695203945Sweongyo		{ 4, 7, 4, 0, 66 }, { 4, 7, 4, 0, 64 },
13696203945Sweongyo		{ 4, 7, 4, 0, 62 }, { 4, 7, 4, 0, 61 },
13697203945Sweongyo		{ 4, 7, 4, 0, 59 }, { 4, 7, 3, 0, 67 },
13698203945Sweongyo		{ 4, 7, 3, 0, 65 }, { 4, 7, 3, 0, 63 },
13699203945Sweongyo		{ 4, 7, 3, 0, 62 }, { 4, 7, 3, 0, 60 },
13700203945Sweongyo		{ 4, 6, 3, 0, 65 }, { 4, 6, 3, 0, 63 },
13701203945Sweongyo		{ 4, 6, 3, 0, 61 }, { 4, 6, 3, 0, 60 },
13702203945Sweongyo		{ 4, 6, 3, 0, 58 }, { 4, 5, 3, 0, 68 },
13703203945Sweongyo		{ 4, 5, 3, 0, 66 }, { 4, 5, 3, 0, 64 },
13704203945Sweongyo		{ 4, 5, 3, 0, 62 }, { 4, 5, 3, 0, 60 },
13705203945Sweongyo		{ 4, 5, 3, 0, 59 }, { 4, 5, 3, 0, 57 },
13706203945Sweongyo		{ 4, 4, 2, 0, 83 }, { 4, 4, 2, 0, 81 },
13707203945Sweongyo		{ 4, 4, 2, 0, 78 }, { 4, 4, 2, 0, 76 },
13708203945Sweongyo		{ 4, 4, 2, 0, 74 }, { 4, 4, 2, 0, 72 }
13709203945Sweongyo	};
13710203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r0[] = {
13711203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13712203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13713203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13714203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13715203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13716203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13717203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13718203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13719203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13720203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13721203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13722203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13723203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13724203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13725203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13726203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13727203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13728203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13729203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13730203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13731203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13732203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13733203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13734203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13735203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13736203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13737203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13738203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13739203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13740203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13741203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13742203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13743203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13744203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13745203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13746203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13747203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13748203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13749203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13750203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13751203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13752203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13753203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13754203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13755203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13756203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13757203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13758203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13759203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13760203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13761203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13762203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13763203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13764203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13765203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13766203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13767203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13768203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13769203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13770203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13771203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13772203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13773203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13774203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13775203945Sweongyo	};
13776203945Sweongyo	static struct bwn_txgain_entry txgain_r1[] = {
13777203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13778203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13779203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13780203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13781203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13782203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13783203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13784203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13785203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13786203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13787203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13788203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13789203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13790203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13791203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13792203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13793203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13794203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13795203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 14, 0, 68 },
13796203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13797203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13798203945Sweongyo		{ 7, 15, 14, 0, 59 }, { 7, 15, 14, 0, 57 },
13799203945Sweongyo		{ 7, 15, 13, 0, 72 }, { 7, 15, 13, 0, 70 },
13800203945Sweongyo		{ 7, 15, 13, 0, 68 }, { 7, 15, 13, 0, 66 },
13801203945Sweongyo		{ 7, 15, 13, 0, 64 }, { 7, 15, 13, 0, 62 },
13802203945Sweongyo		{ 7, 15, 13, 0, 60 }, { 7, 15, 13, 0, 59 },
13803203945Sweongyo		{ 7, 15, 13, 0, 57 }, { 7, 15, 12, 0, 71 },
13804203945Sweongyo		{ 7, 15, 12, 0, 69 }, { 7, 15, 12, 0, 67 },
13805203945Sweongyo		{ 7, 15, 12, 0, 65 }, { 7, 15, 12, 0, 63 },
13806203945Sweongyo		{ 7, 15, 12, 0, 62 }, { 7, 15, 12, 0, 60 },
13807203945Sweongyo		{ 7, 15, 12, 0, 58 }, { 7, 15, 12, 0, 57 },
13808203945Sweongyo		{ 7, 15, 11, 0, 70 }, { 7, 15, 11, 0, 68 },
13809203945Sweongyo		{ 7, 15, 11, 0, 66 }, { 7, 15, 11, 0, 65 },
13810203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13811203945Sweongyo		{ 7, 15, 11, 0, 59 }, { 7, 15, 11, 0, 58 },
13812203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13813203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13814203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13815203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13816203945Sweongyo		{ 7, 15, 10, 0, 56 }, { 7, 15, 9, 0, 70 },
13817203945Sweongyo		{ 7, 15, 9, 0, 68 }, { 7, 15, 9, 0, 66 },
13818203945Sweongyo		{ 7, 15, 9, 0, 64 }, { 7, 15, 9, 0, 62 },
13819203945Sweongyo		{ 7, 15, 9, 0, 60 }, { 7, 15, 9, 0, 59 },
13820203945Sweongyo		{ 7, 14, 9, 0, 72 }, { 7, 14, 9, 0, 70 },
13821203945Sweongyo		{ 7, 14, 9, 0, 68 }, { 7, 14, 9, 0, 66 },
13822203945Sweongyo		{ 7, 14, 9, 0, 64 }, { 7, 14, 9, 0, 62 },
13823203945Sweongyo		{ 7, 14, 9, 0, 60 }, { 7, 14, 9, 0, 59 },
13824203945Sweongyo		{ 7, 13, 9, 0, 72 }, { 7, 13, 9, 0, 70 },
13825203945Sweongyo		{ 7, 13, 9, 0, 68 }, { 7, 13, 9, 0, 66 },
13826203945Sweongyo		{ 7, 13, 9, 0, 64 }, { 7, 13, 9, 0, 63 },
13827203945Sweongyo		{ 7, 13, 9, 0, 61 }, { 7, 13, 9, 0, 59 },
13828203945Sweongyo		{ 7, 13, 9, 0, 57 }, { 7, 13, 8, 0, 72 },
13829203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13830203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13831203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13832203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 12, 8, 0, 72 },
13833203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13834203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13835203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13836203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 7, 0, 73 },
13837203945Sweongyo		{ 7, 12, 7, 0, 71 }, { 7, 12, 7, 0, 69 },
13838203945Sweongyo		{ 7, 12, 7, 0, 67 }, { 7, 12, 7, 0, 65 },
13839203945Sweongyo		{ 7, 12, 7, 0, 63 }, { 7, 12, 7, 0, 61 },
13840203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 11, 7, 0, 72 },
13841203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13842203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 65 },
13843203945Sweongyo		{ 7, 11, 7, 0, 63 }, { 7, 11, 7, 0, 61 },
13844203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 6, 0, 73 },
13845203945Sweongyo		{ 7, 11, 6, 0, 71 }
13846203945Sweongyo	};
13847203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r1[] = {
13848203945Sweongyo		{ 4, 15, 15, 0, 90 }, { 4, 15, 15, 0, 88 },
13849203945Sweongyo		{ 4, 15, 15, 0, 85 }, { 4, 15, 15, 0, 83 },
13850203945Sweongyo		{ 4, 15, 15, 0, 81 }, { 4, 15, 15, 0, 78 },
13851203945Sweongyo		{ 4, 15, 15, 0, 76 }, { 4, 15, 15, 0, 74 },
13852203945Sweongyo		{ 4, 15, 15, 0, 72 }, { 4, 15, 15, 0, 70 },
13853203945Sweongyo		{ 4, 15, 15, 0, 68 }, { 4, 15, 15, 0, 66 },
13854203945Sweongyo		{ 4, 15, 15, 0, 64 }, { 4, 15, 15, 0, 62 },
13855203945Sweongyo		{ 4, 15, 15, 0, 60 }, { 4, 15, 15, 0, 59 },
13856203945Sweongyo		{ 4, 15, 14, 0, 72 }, { 4, 15, 14, 0, 70 },
13857203945Sweongyo		{ 4, 15, 14, 0, 68 }, { 4, 15, 14, 0, 66 },
13858203945Sweongyo		{ 4, 15, 14, 0, 64 }, { 4, 15, 14, 0, 62 },
13859203945Sweongyo		{ 4, 15, 14, 0, 60 }, { 4, 15, 14, 0, 59 },
13860203945Sweongyo		{ 4, 15, 13, 0, 72 }, { 4, 15, 13, 0, 70 },
13861203945Sweongyo		{ 4, 15, 13, 0, 68 }, { 4, 15, 13, 0, 66 },
13862203945Sweongyo		{ 4, 15, 13, 0, 64 }, { 4, 15, 13, 0, 62 },
13863203945Sweongyo		{ 4, 15, 13, 0, 60 }, { 4, 15, 13, 0, 59 },
13864203945Sweongyo		{ 4, 15, 12, 0, 72 }, { 4, 15, 12, 0, 70 },
13865203945Sweongyo		{ 4, 15, 12, 0, 68 }, { 4, 15, 12, 0, 66 },
13866203945Sweongyo		{ 4, 15, 12, 0, 64 }, { 4, 15, 12, 0, 62 },
13867203945Sweongyo		{ 4, 15, 12, 0, 60 }, { 4, 15, 12, 0, 59 },
13868203945Sweongyo		{ 4, 15, 11, 0, 72 }, { 4, 15, 11, 0, 70 },
13869203945Sweongyo		{ 4, 15, 11, 0, 68 }, { 4, 15, 11, 0, 66 },
13870203945Sweongyo		{ 4, 15, 11, 0, 64 }, { 4, 15, 11, 0, 62 },
13871203945Sweongyo		{ 4, 15, 11, 0, 60 }, { 4, 15, 11, 0, 59 },
13872203945Sweongyo		{ 4, 15, 10, 0, 72 }, { 4, 15, 10, 0, 70 },
13873203945Sweongyo		{ 4, 15, 10, 0, 68 }, { 4, 15, 10, 0, 66 },
13874203945Sweongyo		{ 4, 15, 10, 0, 64 }, { 4, 15, 10, 0, 62 },
13875203945Sweongyo		{ 4, 15, 10, 0, 60 }, { 4, 15, 10, 0, 59 },
13876203945Sweongyo		{ 4, 15, 9, 0, 72 }, { 4, 15, 9, 0, 70 },
13877203945Sweongyo		{ 4, 15, 9, 0, 68 }, { 4, 15, 9, 0, 66 },
13878203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13879203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13880203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13881203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13882203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13883203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13884203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13885203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13886203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13887203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13888203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13889203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13890203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13891203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13892203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13893203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13894203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13895203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13896203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13897203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13898203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13899203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13900203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13901203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13902203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13903203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13904203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13905203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13906203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13907203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13908203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13909203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13910203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13911203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 }
13912203945Sweongyo	};
13913203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r1[] = {
13914203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13915203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13916203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13917203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13918203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13919203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13920203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13921203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13922203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13923203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13924203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13925203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13926203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13927203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13928203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13929203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13930203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13931203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13932203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13933203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13934203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13935203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13936203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13937203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13938203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13939203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13940203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13941203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13942203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13943203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13944203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13945203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13946203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13947203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13948203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13949203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13950203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13951203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13952203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13953203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13954203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13955203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13956203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13957203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13958203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13959203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13960203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13961203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13962203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13963203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13964203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13965203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13966203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13967203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13968203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13969203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13970203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13971203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13972203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13973203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13974203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13975203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13976203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13977203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13978203945Sweongyo	};
13979203945Sweongyo
13980203945Sweongyo	if (mac->mac_phy.rev != 0 && mac->mac_phy.rev != 1) {
13981203945Sweongyo		if (siba->siba_sprom.bf_hi & BWN_BFH_NOPA)
13982203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r2);
13983203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13984203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13985203945Sweongyo			    txgain_2ghz_r2);
13986203945Sweongyo		else
13987203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13988203945Sweongyo			    txgain_5ghz_r2);
13989203945Sweongyo		return;
13990203945Sweongyo	}
13991203945Sweongyo
13992203945Sweongyo	if (mac->mac_phy.rev == 0) {
13993203945Sweongyo		if ((siba->siba_sprom.bf_hi & BWN_BFH_NOPA) ||
13994203945Sweongyo		    (siba->siba_sprom.bf_lo & BWN_BFL_HGPA))
13995203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r0);
13996203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13997203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13998203945Sweongyo			    txgain_2ghz_r0);
13999203945Sweongyo		else
14000203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
14001203945Sweongyo			    txgain_5ghz_r0);
14002203945Sweongyo		return;
14003203945Sweongyo	}
14004203945Sweongyo
14005203945Sweongyo	if ((siba->siba_sprom.bf_hi & BWN_BFH_NOPA) ||
14006203945Sweongyo	    (siba->siba_sprom.bf_lo & BWN_BFL_HGPA))
14007203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r1);
14008203945Sweongyo	else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
14009203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_2ghz_r1);
14010203945Sweongyo	else
14011203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_5ghz_r1);
14012203945Sweongyo}
14013203945Sweongyo
14014203945Sweongyostatic void
14015203945Sweongyobwn_tab_write(struct bwn_mac *mac, uint32_t typeoffset, uint32_t value)
14016203945Sweongyo{
14017203945Sweongyo	uint32_t offset, type;
14018203945Sweongyo
14019203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
14020203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
14021203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
14022203945Sweongyo
14023203945Sweongyo	switch (type) {
14024203945Sweongyo	case BWN_TAB_8BIT:
14025203945Sweongyo		KASSERT(!(value & ~0xff), ("%s:%d: fail", __func__, __LINE__));
14026203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14027203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
14028203945Sweongyo		break;
14029203945Sweongyo	case BWN_TAB_16BIT:
14030203945Sweongyo		KASSERT(!(value & ~0xffff),
14031203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
14032203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14033203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
14034203945Sweongyo		break;
14035203945Sweongyo	case BWN_TAB_32BIT:
14036203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14037203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
14038203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
14039203945Sweongyo		break;
14040203945Sweongyo	default:
14041203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
14042203945Sweongyo	}
14043203945Sweongyo}
14044203945Sweongyo
14045203945Sweongyostatic int
14046203945Sweongyobwn_phy_lp_loopback(struct bwn_mac *mac)
14047203945Sweongyo{
14048203945Sweongyo	struct bwn_phy_lp_iq_est ie;
14049203945Sweongyo	int i, index = -1;
14050203945Sweongyo	uint32_t tmp;
14051203945Sweongyo
14052203945Sweongyo	memset(&ie, 0, sizeof(ie));
14053203945Sweongyo
14054203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1, 1);
14055203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 1);
14056203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
14057203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
14058203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
14059203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
14060203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x8);
14061203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, 0x80);
14062203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x80);
14063203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x80);
14064203945Sweongyo	for (i = 0; i < 32; i++) {
14065203945Sweongyo		bwn_phy_lp_set_rxgain_idx(mac, i);
14066203945Sweongyo		bwn_phy_lp_ddfs_turnon(mac, 1, 1, 5, 5, 0);
14067203945Sweongyo		if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
14068203945Sweongyo			continue;
14069203945Sweongyo		tmp = (ie.ie_ipwr + ie.ie_qpwr) / 1000;
14070203945Sweongyo		if ((tmp > 4000) && (tmp < 10000)) {
14071203945Sweongyo			index = i;
14072203945Sweongyo			break;
14073203945Sweongyo		}
14074203945Sweongyo	}
14075203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
14076203945Sweongyo	return (index);
14077203945Sweongyo}
14078203945Sweongyo
14079203945Sweongyostatic void
14080203945Sweongyobwn_phy_lp_set_rxgain_idx(struct bwn_mac *mac, uint16_t idx)
14081203945Sweongyo{
14082203945Sweongyo
14083203945Sweongyo	bwn_phy_lp_set_rxgain(mac, bwn_tab_read(mac, BWN_TAB_2(12, idx)));
14084203945Sweongyo}
14085203945Sweongyo
14086203945Sweongyostatic void
14087203945Sweongyobwn_phy_lp_ddfs_turnon(struct bwn_mac *mac, int i_on, int q_on,
14088203945Sweongyo    int incr1, int incr2, int scale_idx)
14089203945Sweongyo{
14090203945Sweongyo
14091203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
14092203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0xff80);
14093203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0x80ff);
14094203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0xff80, incr1);
14095203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0x80ff, incr2 << 8);
14096203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff7, i_on << 3);
14097203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xffef, q_on << 4);
14098203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xff9f, scale_idx << 5);
14099203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffb);
14100203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DDFS, 0x2);
14101203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x20);
14102203945Sweongyo}
14103203945Sweongyo
14104203945Sweongyostatic uint8_t
14105203945Sweongyobwn_phy_lp_rx_iq_est(struct bwn_mac *mac, uint16_t sample, uint8_t time,
14106203945Sweongyo    struct bwn_phy_lp_iq_est *ie)
14107203945Sweongyo{
14108203945Sweongyo	int i;
14109203945Sweongyo
14110203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfff7);
14111203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_IQ_NUM_SMPLS_ADDR, sample);
14112203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xff00, time);
14113203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xfeff);
14114203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
14115203945Sweongyo
14116203945Sweongyo	for (i = 0; i < 500; i++) {
14117203945Sweongyo		if (!(BWN_PHY_READ(mac,
14118203945Sweongyo		    BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
14119203945Sweongyo			break;
14120203945Sweongyo		DELAY(1000);
14121203945Sweongyo	}
14122203945Sweongyo	if ((BWN_PHY_READ(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
14123203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14124203945Sweongyo		return 0;
14125203945Sweongyo	}
14126203945Sweongyo
14127203945Sweongyo	ie->ie_iqprod = BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_HI_ADDR);
14128203945Sweongyo	ie->ie_iqprod <<= 16;
14129203945Sweongyo	ie->ie_iqprod |= BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_LO_ADDR);
14130203945Sweongyo	ie->ie_ipwr = BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_HI_ADDR);
14131203945Sweongyo	ie->ie_ipwr <<= 16;
14132203945Sweongyo	ie->ie_ipwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_LO_ADDR);
14133203945Sweongyo	ie->ie_qpwr = BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR);
14134203945Sweongyo	ie->ie_qpwr <<= 16;
14135203945Sweongyo	ie->ie_qpwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR);
14136203945Sweongyo
14137203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14138203945Sweongyo	return 1;
14139203945Sweongyo}
14140203945Sweongyo
14141203945Sweongyostatic uint32_t
14142203945Sweongyobwn_tab_read(struct bwn_mac *mac, uint32_t typeoffset)
14143203945Sweongyo{
14144203945Sweongyo	uint32_t offset, type, value;
14145203945Sweongyo
14146203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
14147203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
14148203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
14149203945Sweongyo
14150203945Sweongyo	switch (type) {
14151203945Sweongyo	case BWN_TAB_8BIT:
14152203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14153203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
14154203945Sweongyo		break;
14155203945Sweongyo	case BWN_TAB_16BIT:
14156203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14157203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14158203945Sweongyo		break;
14159203945Sweongyo	case BWN_TAB_32BIT:
14160203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14161203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATAHI);
14162203945Sweongyo		value <<= 16;
14163203945Sweongyo		value |= BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14164203945Sweongyo		break;
14165203945Sweongyo	default:
14166203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
14167203945Sweongyo		value = 0;
14168203945Sweongyo	}
14169203945Sweongyo
14170203945Sweongyo	return (value);
14171203945Sweongyo}
14172203945Sweongyo
14173203945Sweongyostatic void
14174203945Sweongyobwn_phy_lp_ddfs_turnoff(struct bwn_mac *mac)
14175203945Sweongyo{
14176203945Sweongyo
14177203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffd);
14178203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0xffdf);
14179203945Sweongyo}
14180203945Sweongyo
14181203945Sweongyostatic void
14182203945Sweongyobwn_phy_lp_set_txgain_dac(struct bwn_mac *mac, uint16_t dac)
14183203945Sweongyo{
14184203945Sweongyo	uint16_t ctl;
14185203945Sweongyo
14186203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0xc7f;
14187203945Sweongyo	ctl |= dac << 7;
14188203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf000, ctl);
14189203945Sweongyo}
14190203945Sweongyo
14191203945Sweongyostatic void
14192203945Sweongyobwn_phy_lp_set_txgain_pa(struct bwn_mac *mac, uint16_t gain)
14193203945Sweongyo{
14194203945Sweongyo
14195203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0xe03f, gain << 6);
14196203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x80ff, gain << 8);
14197203945Sweongyo}
14198203945Sweongyo
14199203945Sweongyostatic void
14200203945Sweongyobwn_phy_lp_set_txgain_override(struct bwn_mac *mac)
14201203945Sweongyo{
14202203945Sweongyo
14203203945Sweongyo	if (mac->mac_phy.rev < 2)
14204203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
14205203945Sweongyo	else {
14206203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x80);
14207203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x4000);
14208203945Sweongyo	}
14209203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x40);
14210203945Sweongyo}
14211203945Sweongyo
14212203945Sweongyostatic uint16_t
14213203945Sweongyobwn_phy_lp_get_pa_gain(struct bwn_mac *mac)
14214203945Sweongyo{
14215203945Sweongyo
14216203945Sweongyo	return BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0x7f;
14217203945Sweongyo}
14218203945Sweongyo
14219203945Sweongyostatic uint8_t
14220203945Sweongyobwn_nbits(int32_t val)
14221203945Sweongyo{
14222203945Sweongyo	uint32_t tmp;
14223203945Sweongyo	uint8_t nbits = 0;
14224203945Sweongyo
14225203945Sweongyo	for (tmp = abs(val); tmp != 0; tmp >>= 1)
14226203945Sweongyo		nbits++;
14227203945Sweongyo	return (nbits);
14228203945Sweongyo}
14229203945Sweongyo
14230203945Sweongyostatic void
14231203945Sweongyobwn_phy_lp_gaintbl_write_multi(struct bwn_mac *mac, int offset, int count,
14232203945Sweongyo    struct bwn_txgain_entry *table)
14233203945Sweongyo{
14234203945Sweongyo	int i;
14235203945Sweongyo
14236203945Sweongyo	for (i = offset; i < count; i++)
14237203945Sweongyo		bwn_phy_lp_gaintbl_write(mac, i, table[i]);
14238203945Sweongyo}
14239203945Sweongyo
14240203945Sweongyostatic void
14241203945Sweongyobwn_phy_lp_gaintbl_write(struct bwn_mac *mac, int offset,
14242203945Sweongyo    struct bwn_txgain_entry data)
14243203945Sweongyo{
14244203945Sweongyo
14245203945Sweongyo	if (mac->mac_phy.rev >= 2)
14246203945Sweongyo		bwn_phy_lp_gaintbl_write_r2(mac, offset, data);
14247203945Sweongyo	else
14248203945Sweongyo		bwn_phy_lp_gaintbl_write_r01(mac, offset, data);
14249203945Sweongyo}
14250203945Sweongyo
14251203945Sweongyostatic void
14252203945Sweongyobwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset,
14253203945Sweongyo    struct bwn_txgain_entry te)
14254203945Sweongyo{
14255203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
14256203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
14257203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
14258203945Sweongyo	uint32_t tmp;
14259203945Sweongyo
14260203945Sweongyo	KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__));
14261203945Sweongyo
14262203945Sweongyo	tmp = (te.te_pad << 16) | (te.te_pga << 8) | te.te_gm;
14263203945Sweongyo	if (mac->mac_phy.rev >= 3) {
14264203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14265203945Sweongyo		    (0x10 << 24) : (0x70 << 24));
14266203945Sweongyo	} else {
14267203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14268203945Sweongyo		    (0x14 << 24) : (0x7f << 24));
14269203945Sweongyo	}
14270203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0xc0 + offset), tmp);
14271203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0x140 + offset),
14272203945Sweongyo	    te.te_bbmult << 20 | te.te_dac << 28);
14273203945Sweongyo}
14274203945Sweongyo
14275203945Sweongyostatic void
14276203945Sweongyobwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
14277203945Sweongyo    struct bwn_txgain_entry te)
14278203945Sweongyo{
14279203945Sweongyo
14280203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
14281203945Sweongyo
14282203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0xc0 + offset),
14283203945Sweongyo	    (te.te_pad << 11) | (te.te_pga << 7) | (te.te_gm  << 4) |
14284203945Sweongyo	    te.te_dac);
14285203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0x140 + offset), te.te_bbmult << 20);
14286203945Sweongyo}
14287203945Sweongyo
14288203945Sweongyostatic void
14289203945Sweongyobwn_identify(driver_t *driver, device_t parent)
14290203945Sweongyo{
14291203945Sweongyo
14292203945Sweongyo	BUS_ADD_CHILD(parent, 0, "bwn", -1);
14293203945Sweongyo}
14294203945Sweongyo
14295203945Sweongyostatic device_method_t bwn_methods[] = {
14296203945Sweongyo	/* Device interface */
14297203945Sweongyo	DEVMETHOD(device_identify,	bwn_identify),
14298203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
14299203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
14300203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
14301203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
14302203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
14303203945Sweongyo	{ 0,0 }
14304203945Sweongyo};
14305203945Sweongyostatic driver_t bwn_driver = {
14306203945Sweongyo	"bwn",
14307203945Sweongyo	bwn_methods,
14308203945Sweongyo	sizeof(struct bwn_softc)
14309203945Sweongyo};
14310203945Sweongyostatic devclass_t bwn_devclass;
14311203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
14312203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
14313203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
14314203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
14315203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
14316