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$");
32203945Sweongyo
33203945Sweongyo/*
34203945Sweongyo * The Broadcom Wireless LAN controller driver.
35203945Sweongyo */
36203945Sweongyo
37203945Sweongyo#include <sys/param.h>
38203945Sweongyo#include <sys/systm.h>
39203945Sweongyo#include <sys/module.h>
40203945Sweongyo#include <sys/kernel.h>
41203945Sweongyo#include <sys/endian.h>
42203945Sweongyo#include <sys/errno.h>
43203945Sweongyo#include <sys/firmware.h>
44203945Sweongyo#include <sys/lock.h>
45203945Sweongyo#include <sys/mutex.h>
46203945Sweongyo#include <machine/bus.h>
47203945Sweongyo#include <machine/resource.h>
48203945Sweongyo#include <sys/bus.h>
49203945Sweongyo#include <sys/rman.h>
50203945Sweongyo#include <sys/socket.h>
51203945Sweongyo#include <sys/sockio.h>
52203945Sweongyo
53203945Sweongyo#include <net/ethernet.h>
54203945Sweongyo#include <net/if.h>
55203945Sweongyo#include <net/if_arp.h>
56203945Sweongyo#include <net/if_dl.h>
57203945Sweongyo#include <net/if_llc.h>
58203945Sweongyo#include <net/if_media.h>
59203945Sweongyo#include <net/if_types.h>
60203945Sweongyo
61203945Sweongyo#include <dev/pci/pcivar.h>
62203945Sweongyo#include <dev/pci/pcireg.h>
63203945Sweongyo#include <dev/siba/siba_ids.h>
64203945Sweongyo#include <dev/siba/sibareg.h>
65203945Sweongyo#include <dev/siba/sibavar.h>
66203945Sweongyo
67203945Sweongyo#include <net80211/ieee80211_var.h>
68203945Sweongyo#include <net80211/ieee80211_radiotap.h>
69203945Sweongyo#include <net80211/ieee80211_regdomain.h>
70203945Sweongyo#include <net80211/ieee80211_phy.h>
71206358Srpaulo#include <net80211/ieee80211_ratectl.h>
72203945Sweongyo
73203945Sweongyo#include <dev/bwn/if_bwnreg.h>
74203945Sweongyo#include <dev/bwn/if_bwnvar.h>
75203945Sweongyo
76227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0,
77227309Sed    "Broadcom driver parameters");
78203945Sweongyo
79203945Sweongyo/*
80203945Sweongyo * Tunable & sysctl variables.
81203945Sweongyo */
82203945Sweongyo
83203945Sweongyo#ifdef BWN_DEBUG
84203945Sweongyostatic	int bwn_debug = 0;
85203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RW, &bwn_debug, 0,
86203945Sweongyo    "Broadcom debugging printfs");
87203945SweongyoTUNABLE_INT("hw.bwn.debug", &bwn_debug);
88203945Sweongyoenum {
89203945Sweongyo	BWN_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
90203945Sweongyo	BWN_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
91203945Sweongyo	BWN_DEBUG_STATE		= 0x00000004,	/* 802.11 state transitions */
92203945Sweongyo	BWN_DEBUG_TXPOW		= 0x00000008,	/* tx power processing */
93203945Sweongyo	BWN_DEBUG_RESET		= 0x00000010,	/* reset processing */
94203945Sweongyo	BWN_DEBUG_OPS		= 0x00000020,	/* bwn_ops processing */
95203945Sweongyo	BWN_DEBUG_BEACON	= 0x00000040,	/* beacon handling */
96203945Sweongyo	BWN_DEBUG_WATCHDOG	= 0x00000080,	/* watchdog timeout */
97203945Sweongyo	BWN_DEBUG_INTR		= 0x00000100,	/* ISR */
98203945Sweongyo	BWN_DEBUG_CALIBRATE	= 0x00000200,	/* periodic calibration */
99203945Sweongyo	BWN_DEBUG_NODE		= 0x00000400,	/* node management */
100203945Sweongyo	BWN_DEBUG_LED		= 0x00000800,	/* led management */
101203945Sweongyo	BWN_DEBUG_CMD		= 0x00001000,	/* cmd submission */
102203945Sweongyo	BWN_DEBUG_LO		= 0x00002000,	/* LO */
103203945Sweongyo	BWN_DEBUG_FW		= 0x00004000,	/* firmware */
104203945Sweongyo	BWN_DEBUG_WME		= 0x00008000,	/* WME */
105203945Sweongyo	BWN_DEBUG_RF		= 0x00010000,	/* RF */
106203945Sweongyo	BWN_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
107203945Sweongyo	BWN_DEBUG_ANY		= 0xffffffff
108203945Sweongyo};
109203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do {			\
110203945Sweongyo	if (sc->sc_debug & (m))				\
111203945Sweongyo		printf(fmt, __VA_ARGS__);		\
112203945Sweongyo} while (0)
113203945Sweongyo#else
114203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
115203945Sweongyo#endif
116203945Sweongyo
117203945Sweongyostatic int	bwn_bfp = 0;		/* use "Bad Frames Preemption" */
118203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
119203945Sweongyo    "uses Bad Frames Preemption");
120203945Sweongyostatic int	bwn_bluetooth = 1;
121203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
122203945Sweongyo    "turns on Bluetooth Coexistence");
123203945Sweongyostatic int	bwn_hwpctl = 0;
124203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
125203945Sweongyo    "uses H/W power control");
126203945Sweongyostatic int	bwn_msi_disable = 0;		/* MSI disabled  */
127203945SweongyoTUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable);
128203945Sweongyostatic int	bwn_usedma = 1;
129203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
130203945Sweongyo    "uses DMA");
131203945SweongyoTUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
132203945Sweongyostatic int	bwn_wme = 1;
133203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
134203945Sweongyo    "uses WME support");
135203945Sweongyo
136203945Sweongyostatic int	bwn_attach_pre(struct bwn_softc *);
137203945Sweongyostatic int	bwn_attach_post(struct bwn_softc *);
138204922Sweongyostatic void	bwn_sprom_bugfixes(device_t);
139203945Sweongyostatic void	bwn_init(void *);
140203945Sweongyostatic int	bwn_init_locked(struct bwn_softc *);
141203945Sweongyostatic int	bwn_ioctl(struct ifnet *, u_long, caddr_t);
142203945Sweongyostatic void	bwn_start(struct ifnet *);
143203945Sweongyostatic int	bwn_attach_core(struct bwn_mac *);
144203945Sweongyostatic void	bwn_reset_core(struct bwn_mac *, uint32_t);
145203945Sweongyostatic int	bwn_phy_getinfo(struct bwn_mac *, int);
146203945Sweongyostatic int	bwn_chiptest(struct bwn_mac *);
147203945Sweongyostatic int	bwn_setup_channels(struct bwn_mac *, int, int);
148203945Sweongyostatic int	bwn_phy_g_attach(struct bwn_mac *);
149203945Sweongyostatic void	bwn_phy_g_detach(struct bwn_mac *);
150203945Sweongyostatic void	bwn_phy_g_init_pre(struct bwn_mac *);
151203945Sweongyostatic int	bwn_phy_g_prepare_hw(struct bwn_mac *);
152203945Sweongyostatic int	bwn_phy_g_init(struct bwn_mac *);
153203945Sweongyostatic void	bwn_phy_g_exit(struct bwn_mac *);
154203945Sweongyostatic uint16_t	bwn_phy_g_read(struct bwn_mac *, uint16_t);
155203945Sweongyostatic void	bwn_phy_g_write(struct bwn_mac *, uint16_t,
156203945Sweongyo		    uint16_t);
157203945Sweongyostatic uint16_t	bwn_phy_g_rf_read(struct bwn_mac *, uint16_t);
158203945Sweongyostatic void	bwn_phy_g_rf_write(struct bwn_mac *, uint16_t,
159203945Sweongyo		    uint16_t);
160203945Sweongyostatic int	bwn_phy_g_hwpctl(struct bwn_mac *);
161203945Sweongyostatic void	bwn_phy_g_rf_onoff(struct bwn_mac *, int);
162203945Sweongyostatic int	bwn_phy_g_switch_channel(struct bwn_mac *, uint32_t);
163203945Sweongyostatic uint32_t	bwn_phy_g_get_default_chan(struct bwn_mac *);
164203945Sweongyostatic void	bwn_phy_g_set_antenna(struct bwn_mac *, int);
165203945Sweongyostatic int	bwn_phy_g_im(struct bwn_mac *, int);
166203945Sweongyostatic int	bwn_phy_g_recalc_txpwr(struct bwn_mac *, int);
167203945Sweongyostatic void	bwn_phy_g_set_txpwr(struct bwn_mac *);
168203945Sweongyostatic void	bwn_phy_g_task_15s(struct bwn_mac *);
169203945Sweongyostatic void	bwn_phy_g_task_60s(struct bwn_mac *);
170203945Sweongyostatic uint16_t	bwn_phy_g_txctl(struct bwn_mac *);
171203945Sweongyostatic void	bwn_phy_switch_analog(struct bwn_mac *, int);
172203945Sweongyostatic uint16_t	bwn_shm_read_2(struct bwn_mac *, uint16_t, uint16_t);
173203945Sweongyostatic void	bwn_shm_write_2(struct bwn_mac *, uint16_t, uint16_t,
174203945Sweongyo		    uint16_t);
175203945Sweongyostatic uint32_t	bwn_shm_read_4(struct bwn_mac *, uint16_t, uint16_t);
176203945Sweongyostatic void	bwn_shm_write_4(struct bwn_mac *, uint16_t, uint16_t,
177203945Sweongyo		    uint32_t);
178203945Sweongyostatic void	bwn_shm_ctlword(struct bwn_mac *, uint16_t,
179203945Sweongyo		    uint16_t);
180203945Sweongyostatic void	bwn_addchannels(struct ieee80211_channel [], int, int *,
181203945Sweongyo		    const struct bwn_channelinfo *, int);
182203945Sweongyostatic int	bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
183203945Sweongyo		    const struct ieee80211_bpf_params *);
184203945Sweongyostatic void	bwn_updateslot(struct ifnet *);
185203945Sweongyostatic void	bwn_update_promisc(struct ifnet *);
186203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
187203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
188203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
189203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
190203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
191203945Sweongyo		    const struct wmeParams *, uint16_t);
192203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
193203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
194203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
195203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
196228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
197228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
198203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
199203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
200203945Sweongyostatic void	bwn_stop(struct bwn_softc *, int);
201203945Sweongyostatic void	bwn_stop_locked(struct bwn_softc *, int);
202203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
203203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
204203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
205203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
206203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
207203945Sweongyostatic uint64_t	bwn_hf_read(struct bwn_mac *);
208203945Sweongyostatic void	bwn_hf_write(struct bwn_mac *, uint64_t);
209203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
210203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
211203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
212203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
213203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
214203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
215203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
216203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
217203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
218203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
219203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
220203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
221203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
222203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
223203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
224203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
225203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
226203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
227203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
228203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
229203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
230203945Sweongyo		    int);
231203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
232203945Sweongyo		    struct bwn_pio_rxqueue *, int);
233203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
234203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
235203945Sweongyo		    uint16_t);
236203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
237203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
238203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
239203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
240203945Sweongyo		    const struct bwn_txstatus *);
241203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
242203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
243203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
244203945Sweongyo		    uint16_t);
245203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
246203945Sweongyo		    uint32_t);
247203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
248203945Sweongyo		    struct mbuf *);
249203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
250203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
251203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
252203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
253203945Sweongyo		    uint16_t, uint32_t);
254203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
255203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
256203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
257203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
258203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
259203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
260203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
261203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
262203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
263203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
264203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
265203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
266203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
267203945Sweongyo		    int, struct bwn_dmadesc_generic **,
268203945Sweongyo		    struct bwn_dmadesc_meta **);
269203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
270203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
271203945Sweongyo		    int, int);
272203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
273203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
274203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
275203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
276203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
277203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
278203945Sweongyo		    int, struct bwn_dmadesc_generic **,
279203945Sweongyo		    struct bwn_dmadesc_meta **);
280203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
281203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
282203945Sweongyo		    int, int);
283203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
284203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
285203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
286203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
287203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
288203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
289203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
290203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
291203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
292203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
293203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
294203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
295203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
296203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
297203945Sweongyo		    struct bwn_dmadesc_meta *);
298203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
299203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
300203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
301203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
302203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
303203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
304203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
305203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
306203945Sweongyo		    int);
307203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
308203945Sweongyo		    bus_size_t, int);
309203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
310203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
311203945Sweongyo		    const struct bwn_txstatus *);
312203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
313203945Sweongyo		    struct mbuf *);
314203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
315203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
316203945Sweongyo		    uint8_t);
317203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
318203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
319203945Sweongyo		    int, int, int);
320203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
321203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
322203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
323203945Sweongyostatic void	bwn_phy_g_init_sub(struct bwn_mac *);
324203945Sweongyostatic uint8_t	bwn_has_hwpctl(struct bwn_mac *);
325203945Sweongyostatic void	bwn_phy_init_b5(struct bwn_mac *);
326203945Sweongyostatic void	bwn_phy_init_b6(struct bwn_mac *);
327203945Sweongyostatic void	bwn_phy_init_a(struct bwn_mac *);
328203945Sweongyostatic void	bwn_loopback_calcgain(struct bwn_mac *);
329203945Sweongyostatic uint16_t	bwn_rf_init_bcm2050(struct bwn_mac *);
330203945Sweongyostatic void	bwn_lo_g_init(struct bwn_mac *);
331203945Sweongyostatic void	bwn_lo_g_adjust(struct bwn_mac *);
332203945Sweongyostatic void	bwn_lo_get_powervector(struct bwn_mac *);
333203945Sweongyostatic struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
334203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *);
335203945Sweongyostatic void	bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
336203945Sweongyostatic void	bwn_phy_hwpctl_init(struct bwn_mac *);
337203945Sweongyostatic void	bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
338203945Sweongyostatic void	bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
339203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *,
340203945Sweongyo		    uint8_t);
341203945Sweongyostatic void	bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
342203945Sweongyostatic uint16_t	bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
343203945Sweongyostatic void	bwn_spu_workaround(struct bwn_mac *, uint8_t);
344203945Sweongyostatic void	bwn_wa_init(struct bwn_mac *);
345203945Sweongyostatic void	bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
346203945Sweongyo		    uint16_t);
347203945Sweongyostatic void	bwn_dummy_transmission(struct bwn_mac *, int, int);
348203945Sweongyostatic void	bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
349203945Sweongyo		    uint32_t);
350203945Sweongyostatic void	bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
351203945Sweongyo		    uint16_t);
352203945Sweongyostatic void	bwn_ram_write(struct bwn_mac *, uint16_t, uint32_t);
353203945Sweongyostatic void	bwn_mac_suspend(struct bwn_mac *);
354203945Sweongyostatic void	bwn_mac_enable(struct bwn_mac *);
355203945Sweongyostatic void	bwn_psctl(struct bwn_mac *, uint32_t);
356203945Sweongyostatic int16_t	bwn_nrssi_read(struct bwn_mac *, uint16_t);
357203945Sweongyostatic void	bwn_nrssi_offset(struct bwn_mac *);
358203945Sweongyostatic void	bwn_nrssi_threshold(struct bwn_mac *);
359203945Sweongyostatic void	bwn_nrssi_slope_11g(struct bwn_mac *);
360203945Sweongyostatic void	bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
361203945Sweongyo		    int16_t);
362203945Sweongyostatic void	bwn_set_original_gains(struct bwn_mac *);
363203945Sweongyostatic void	bwn_hwpctl_early_init(struct bwn_mac *);
364203945Sweongyostatic void	bwn_hwpctl_init_gphy(struct bwn_mac *);
365203945Sweongyostatic uint16_t	bwn_phy_g_chan2freq(uint8_t);
366203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
367203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
368203945Sweongyo		    const char *, struct bwn_fwfile *);
369203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
370203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
371203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
372203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
373203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
374203945Sweongyostatic int	bwn_switch_channel(struct bwn_mac *, int);
375203945Sweongyostatic uint16_t	bwn_ant2phy(int);
376203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
377203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
378203945Sweongyo		    const uint8_t *);
379203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
380203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
381203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
382203945Sweongyo		    const uint8_t *);
383203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
384203945Sweongyo		    const uint8_t *);
385203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
386203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
387203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
388203945Sweongyo		    struct ieee80211_channel *);
389203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
390203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
391203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
392203945Sweongyostatic int	bwn_intr(void *);
393203945Sweongyostatic void	bwn_intrtask(void *, int);
394203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
395203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
396203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
397203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
398203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
399203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
400203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
401203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
402203945Sweongyostatic void	bwn_hwreset(void *, int);
403203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
404203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
405203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
406203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
407203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
408203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
409203945Sweongyo		    const struct bwn_txstatus *);
410203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
411203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
412203945Sweongyostatic void	bwn_start_locked(struct ifnet *);
413203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
414203945Sweongyo		    struct mbuf *);
415203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
416203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
417203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
418203945Sweongyo		    uint16_t);
419203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
420203945Sweongyo		    const uint8_t);
421203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
422203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
423203945Sweongyostatic int	bwn_phy_shm_tssi_read(struct bwn_mac *, uint16_t);
424203945Sweongyostatic void	bwn_phy_g_setatt(struct bwn_mac *, int *, int *);
425203945Sweongyostatic void	bwn_phy_lock(struct bwn_mac *);
426203945Sweongyostatic void	bwn_phy_unlock(struct bwn_mac *);
427203945Sweongyostatic void	bwn_rf_lock(struct bwn_mac *);
428203945Sweongyostatic void	bwn_rf_unlock(struct bwn_mac *);
429203945Sweongyostatic void	bwn_txpwr(void *, int);
430203945Sweongyostatic void	bwn_tasks(void *);
431203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
432203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
433203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
434203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
435203945Sweongyo		    uint8_t);
436203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
437203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
438203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
439203945Sweongyo		    int, int);
440203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
441203945Sweongyostatic void	bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
442203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
443203945Sweongyostatic void	bwn_watchdog(void *);
444203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
445203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
446203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
447203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
448203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
449203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
450203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
451203945Sweongyostatic void	bwn_led_blink_next(void *);
452203945Sweongyostatic void	bwn_led_blink_end(void *);
453203945Sweongyostatic void	bwn_rfswitch(void *);
454203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
455203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
456203945Sweongyostatic void	bwn_phy_lp_init_pre(struct bwn_mac *);
457203945Sweongyostatic int	bwn_phy_lp_init(struct bwn_mac *);
458203945Sweongyostatic uint16_t	bwn_phy_lp_read(struct bwn_mac *, uint16_t);
459203945Sweongyostatic void	bwn_phy_lp_write(struct bwn_mac *, uint16_t, uint16_t);
460203945Sweongyostatic void	bwn_phy_lp_maskset(struct bwn_mac *, uint16_t, uint16_t,
461203945Sweongyo		    uint16_t);
462203945Sweongyostatic uint16_t	bwn_phy_lp_rf_read(struct bwn_mac *, uint16_t);
463203945Sweongyostatic void	bwn_phy_lp_rf_write(struct bwn_mac *, uint16_t, uint16_t);
464203945Sweongyostatic void	bwn_phy_lp_rf_onoff(struct bwn_mac *, int);
465203945Sweongyostatic int	bwn_phy_lp_switch_channel(struct bwn_mac *, uint32_t);
466203945Sweongyostatic uint32_t	bwn_phy_lp_get_default_chan(struct bwn_mac *);
467203945Sweongyostatic void	bwn_phy_lp_set_antenna(struct bwn_mac *, int);
468203945Sweongyostatic void	bwn_phy_lp_task_60s(struct bwn_mac *);
469203945Sweongyostatic void	bwn_phy_lp_readsprom(struct bwn_mac *);
470203945Sweongyostatic void	bwn_phy_lp_bbinit(struct bwn_mac *);
471203945Sweongyostatic void	bwn_phy_lp_txpctl_init(struct bwn_mac *);
472203945Sweongyostatic void	bwn_phy_lp_calib(struct bwn_mac *);
473203945Sweongyostatic void	bwn_phy_lp_switch_analog(struct bwn_mac *, int);
474203945Sweongyostatic int	bwn_phy_lp_b2062_switch_channel(struct bwn_mac *, uint8_t);
475203945Sweongyostatic int	bwn_phy_lp_b2063_switch_channel(struct bwn_mac *, uint8_t);
476203945Sweongyostatic void	bwn_phy_lp_set_anafilter(struct bwn_mac *, uint8_t);
477203945Sweongyostatic void	bwn_phy_lp_set_gaintbl(struct bwn_mac *, uint32_t);
478203945Sweongyostatic void	bwn_phy_lp_digflt_save(struct bwn_mac *);
479203945Sweongyostatic void	bwn_phy_lp_get_txpctlmode(struct bwn_mac *);
480203945Sweongyostatic void	bwn_phy_lp_set_txpctlmode(struct bwn_mac *, uint8_t);
481203945Sweongyostatic void	bwn_phy_lp_bugfix(struct bwn_mac *);
482203945Sweongyostatic void	bwn_phy_lp_digflt_restore(struct bwn_mac *);
483203945Sweongyostatic void	bwn_phy_lp_tblinit(struct bwn_mac *);
484203945Sweongyostatic void	bwn_phy_lp_bbinit_r2(struct bwn_mac *);
485203945Sweongyostatic void	bwn_phy_lp_bbinit_r01(struct bwn_mac *);
486203945Sweongyostatic void	bwn_phy_lp_b2062_init(struct bwn_mac *);
487203945Sweongyostatic void	bwn_phy_lp_b2063_init(struct bwn_mac *);
488203945Sweongyostatic void	bwn_phy_lp_rxcal_r2(struct bwn_mac *);
489203945Sweongyostatic void	bwn_phy_lp_rccal_r12(struct bwn_mac *);
490203945Sweongyostatic void	bwn_phy_lp_set_rccap(struct bwn_mac *);
491203945Sweongyostatic uint32_t	bwn_phy_lp_roundup(uint32_t, uint32_t, uint8_t);
492203945Sweongyostatic void	bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *);
493203945Sweongyostatic void	bwn_phy_lp_b2062_vco_calib(struct bwn_mac *);
494203945Sweongyostatic void	bwn_tab_write_multi(struct bwn_mac *, uint32_t, int,
495203945Sweongyo		    const void *);
496203945Sweongyostatic void	bwn_tab_read_multi(struct bwn_mac *, uint32_t, int, void *);
497203945Sweongyostatic struct bwn_txgain
498203945Sweongyo		bwn_phy_lp_get_txgain(struct bwn_mac *);
499203945Sweongyostatic uint8_t	bwn_phy_lp_get_bbmult(struct bwn_mac *);
500203945Sweongyostatic void	bwn_phy_lp_set_txgain(struct bwn_mac *, struct bwn_txgain *);
501203945Sweongyostatic void	bwn_phy_lp_set_bbmult(struct bwn_mac *, uint8_t);
502203945Sweongyostatic void	bwn_phy_lp_set_trsw_over(struct bwn_mac *, uint8_t, uint8_t);
503203945Sweongyostatic void	bwn_phy_lp_set_rxgain(struct bwn_mac *, uint32_t);
504203945Sweongyostatic void	bwn_phy_lp_set_deaf(struct bwn_mac *, uint8_t);
505203945Sweongyostatic int	bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *, uint16_t);
506203945Sweongyostatic void	bwn_phy_lp_clear_deaf(struct bwn_mac *, uint8_t);
507203945Sweongyostatic void	bwn_phy_lp_tblinit_r01(struct bwn_mac *);
508203945Sweongyostatic void	bwn_phy_lp_tblinit_r2(struct bwn_mac *);
509203945Sweongyostatic void	bwn_phy_lp_tblinit_txgain(struct bwn_mac *);
510203945Sweongyostatic void	bwn_tab_write(struct bwn_mac *, uint32_t, uint32_t);
511203945Sweongyostatic void	bwn_phy_lp_b2062_tblinit(struct bwn_mac *);
512203945Sweongyostatic void	bwn_phy_lp_b2063_tblinit(struct bwn_mac *);
513203945Sweongyostatic int	bwn_phy_lp_loopback(struct bwn_mac *);
514203945Sweongyostatic void	bwn_phy_lp_set_rxgain_idx(struct bwn_mac *, uint16_t);
515203945Sweongyostatic void	bwn_phy_lp_ddfs_turnon(struct bwn_mac *, int, int, int, int,
516203945Sweongyo		    int);
517203945Sweongyostatic uint8_t	bwn_phy_lp_rx_iq_est(struct bwn_mac *, uint16_t, uint8_t,
518203945Sweongyo		    struct bwn_phy_lp_iq_est *);
519203945Sweongyostatic void	bwn_phy_lp_ddfs_turnoff(struct bwn_mac *);
520203945Sweongyostatic uint32_t	bwn_tab_read(struct bwn_mac *, uint32_t);
521203945Sweongyostatic void	bwn_phy_lp_set_txgain_dac(struct bwn_mac *, uint16_t);
522203945Sweongyostatic void	bwn_phy_lp_set_txgain_pa(struct bwn_mac *, uint16_t);
523203945Sweongyostatic void	bwn_phy_lp_set_txgain_override(struct bwn_mac *);
524203945Sweongyostatic uint16_t	bwn_phy_lp_get_pa_gain(struct bwn_mac *);
525203945Sweongyostatic uint8_t	bwn_nbits(int32_t);
526203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *, int, int,
527203945Sweongyo		    struct bwn_txgain_entry *);
528203945Sweongyostatic void	bwn_phy_lp_gaintbl_write(struct bwn_mac *, int,
529203945Sweongyo		    struct bwn_txgain_entry);
530203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
531203945Sweongyo		    struct bwn_txgain_entry);
532203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
533203945Sweongyo		    struct bwn_txgain_entry);
534204257Sweongyostatic void	bwn_sysctl_node(struct bwn_softc *);
535203945Sweongyo
536203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
537203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
538203945Sweongyo	{ -1,			0,		0 }
539203945Sweongyo};
540203945Sweongyo
541203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
542203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
543203945Sweongyo	{ -1,			0,		0 }
544203945Sweongyo};
545203945Sweongyo
546203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
547203945Sweongyo	.channels = {
548203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
549203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
550203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
551203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
552203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
553203945Sweongyo	.nchannels = 14
554203945Sweongyo};
555203945Sweongyo
556203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
557203945Sweongyo	.channels = {
558203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
559203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
560203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
561203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
562203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
563203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
564203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
565203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
566203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
567203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
568203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
569203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
570203945Sweongyo		{ 6080, 216, 30 } },
571203945Sweongyo	.nchannels = 37
572203945Sweongyo};
573203945Sweongyo
574203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
575203945Sweongyo	.channels = {
576203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
577203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
578203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
579203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
580203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
581203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
582203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
583203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
584203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
585203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
586203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
587203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
588203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
589203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
590203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
591203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
592203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
593203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
594203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
595203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
596203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
597203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
598203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
599203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
600203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
601203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
602203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
603203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
604203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
605203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
606203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
607203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
608203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
609203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
610203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
611203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
612203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
613203945Sweongyo	.nchannels = 110
614203945Sweongyo};
615203945Sweongyo
616203945Sweongyostatic const uint8_t bwn_b2063_chantable_data[33][12] = {
617203945Sweongyo	{ 0x6f, 0x3c, 0x3c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
618203945Sweongyo	{ 0x6f, 0x2c, 0x2c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
619203945Sweongyo	{ 0x6f, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
620203945Sweongyo	{ 0x6e, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
621203945Sweongyo	{ 0x6e, 0xc, 0xc, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
622203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x2, 0x5, 0xd, 0xd, 0x77, 0x80, 0x20, 0 },
623203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x5, 0xd, 0xc, 0x77, 0x80, 0x20, 0 },
624203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x80, 0x20, 0 },
625203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x70, 0x20, 0 },
626203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xb, 0xc, 0x77, 0x70, 0x20, 0 },
627203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x4, 0xb, 0xb, 0x77, 0x60, 0x20, 0 },
628203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xb, 0x77, 0x60, 0x20, 0 },
629203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xa, 0x77, 0x60, 0x20, 0 },
630203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x2, 0x9, 0x9, 0x77, 0x60, 0x20, 0 },
631203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x1, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
632203945Sweongyo	{ 0x67, 0xc, 0xc, 0, 0, 0, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
633203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x2, 0x1, 0x77, 0x20, 0, 0 },
634203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x1, 0x1, 0x77, 0x20, 0, 0 },
635203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0x1, 0, 0x77, 0x10, 0, 0 },
636203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
637203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
638203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
639203945Sweongyo	{ 0x61, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
640203945Sweongyo	{ 0x60, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
641203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xe, 0xf, 0xf, 0x77, 0xc0, 0x50, 0 },
642203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xd, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
643203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
644203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
645203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xb, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
646203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xa, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
647203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x7, 0x9, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
648203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x6, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
649203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x5, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 }
650203945Sweongyo};
651203945Sweongyo
652203945Sweongyostatic const struct bwn_b206x_chan bwn_b2063_chantable[] = {
653203945Sweongyo	{ 1, 2412, bwn_b2063_chantable_data[0] },
654203945Sweongyo	{ 2, 2417, bwn_b2063_chantable_data[0] },
655203945Sweongyo	{ 3, 2422, bwn_b2063_chantable_data[0] },
656203945Sweongyo	{ 4, 2427, bwn_b2063_chantable_data[1] },
657203945Sweongyo	{ 5, 2432, bwn_b2063_chantable_data[1] },
658203945Sweongyo	{ 6, 2437, bwn_b2063_chantable_data[1] },
659203945Sweongyo	{ 7, 2442, bwn_b2063_chantable_data[1] },
660203945Sweongyo	{ 8, 2447, bwn_b2063_chantable_data[1] },
661203945Sweongyo	{ 9, 2452, bwn_b2063_chantable_data[2] },
662203945Sweongyo	{ 10, 2457, bwn_b2063_chantable_data[2] },
663203945Sweongyo	{ 11, 2462, bwn_b2063_chantable_data[3] },
664203945Sweongyo	{ 12, 2467, bwn_b2063_chantable_data[3] },
665203945Sweongyo	{ 13, 2472, bwn_b2063_chantable_data[3] },
666203945Sweongyo	{ 14, 2484, bwn_b2063_chantable_data[4] },
667203945Sweongyo	{ 34, 5170, bwn_b2063_chantable_data[5] },
668203945Sweongyo	{ 36, 5180, bwn_b2063_chantable_data[6] },
669203945Sweongyo	{ 38, 5190, bwn_b2063_chantable_data[7] },
670203945Sweongyo	{ 40, 5200, bwn_b2063_chantable_data[8] },
671203945Sweongyo	{ 42, 5210, bwn_b2063_chantable_data[9] },
672203945Sweongyo	{ 44, 5220, bwn_b2063_chantable_data[10] },
673203945Sweongyo	{ 46, 5230, bwn_b2063_chantable_data[11] },
674203945Sweongyo	{ 48, 5240, bwn_b2063_chantable_data[12] },
675203945Sweongyo	{ 52, 5260, bwn_b2063_chantable_data[13] },
676203945Sweongyo	{ 56, 5280, bwn_b2063_chantable_data[14] },
677203945Sweongyo	{ 60, 5300, bwn_b2063_chantable_data[14] },
678203945Sweongyo	{ 64, 5320, bwn_b2063_chantable_data[15] },
679203945Sweongyo	{ 100, 5500, bwn_b2063_chantable_data[16] },
680203945Sweongyo	{ 104, 5520, bwn_b2063_chantable_data[17] },
681203945Sweongyo	{ 108, 5540, bwn_b2063_chantable_data[18] },
682203945Sweongyo	{ 112, 5560, bwn_b2063_chantable_data[19] },
683203945Sweongyo	{ 116, 5580, bwn_b2063_chantable_data[20] },
684203945Sweongyo	{ 120, 5600, bwn_b2063_chantable_data[21] },
685203945Sweongyo	{ 124, 5620, bwn_b2063_chantable_data[21] },
686203945Sweongyo	{ 128, 5640, bwn_b2063_chantable_data[22] },
687203945Sweongyo	{ 132, 5660, bwn_b2063_chantable_data[22] },
688203945Sweongyo	{ 136, 5680, bwn_b2063_chantable_data[22] },
689203945Sweongyo	{ 140, 5700, bwn_b2063_chantable_data[23] },
690203945Sweongyo	{ 149, 5745, bwn_b2063_chantable_data[23] },
691203945Sweongyo	{ 153, 5765, bwn_b2063_chantable_data[23] },
692203945Sweongyo	{ 157, 5785, bwn_b2063_chantable_data[23] },
693203945Sweongyo	{ 161, 5805, bwn_b2063_chantable_data[23] },
694203945Sweongyo	{ 165, 5825, bwn_b2063_chantable_data[23] },
695203945Sweongyo	{ 184, 4920, bwn_b2063_chantable_data[24] },
696203945Sweongyo	{ 188, 4940, bwn_b2063_chantable_data[25] },
697203945Sweongyo	{ 192, 4960, bwn_b2063_chantable_data[26] },
698203945Sweongyo	{ 196, 4980, bwn_b2063_chantable_data[27] },
699203945Sweongyo	{ 200, 5000, bwn_b2063_chantable_data[28] },
700203945Sweongyo	{ 204, 5020, bwn_b2063_chantable_data[29] },
701203945Sweongyo	{ 208, 5040, bwn_b2063_chantable_data[30] },
702203945Sweongyo	{ 212, 5060, bwn_b2063_chantable_data[31] },
703203945Sweongyo	{ 216, 5080, bwn_b2063_chantable_data[32] }
704203945Sweongyo};
705203945Sweongyo
706203945Sweongyostatic const uint8_t bwn_b2062_chantable_data[22][12] = {
707203945Sweongyo	{ 0xff, 0xff, 0xb5, 0x1b, 0x24, 0x32, 0x32, 0x88, 0x88, 0, 0, 0 },
708203945Sweongyo	{ 0, 0x22, 0x20, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
709203945Sweongyo	{ 0, 0x11, 0x10, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
710203945Sweongyo	{ 0, 0, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
711203945Sweongyo	{ 0, 0x11, 0x20, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
712203945Sweongyo	{ 0, 0x11, 0x10, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
713203945Sweongyo	{ 0, 0x11, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
714203945Sweongyo	{ 0, 0, 0, 0x63, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
715203945Sweongyo	{ 0, 0, 0, 0x62, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
716203945Sweongyo	{ 0, 0, 0, 0x30, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
717203945Sweongyo	{ 0, 0, 0, 0x20, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
718203945Sweongyo	{ 0, 0, 0, 0x10, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
719203945Sweongyo	{ 0, 0, 0, 0, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
720203945Sweongyo	{ 0x55, 0x77, 0x90, 0xf7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
721203945Sweongyo	{ 0x44, 0x77, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
722203945Sweongyo	{ 0x44, 0x66, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
723203945Sweongyo	{ 0x33, 0x66, 0x70, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
724203945Sweongyo	{ 0x22, 0x55, 0x60, 0xd7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
725203945Sweongyo	{ 0x22, 0x55, 0x60, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
726203945Sweongyo	{ 0x22, 0x44, 0x50, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
727203945Sweongyo	{ 0x11, 0x44, 0x50, 0xa5, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
728203945Sweongyo	{ 0, 0x44, 0x40, 0xb6, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 }
729203945Sweongyo};
730203945Sweongyo
731203945Sweongyostatic const struct bwn_b206x_chan bwn_b2062_chantable[] = {
732203945Sweongyo	{ 1, 2412, bwn_b2062_chantable_data[0] },
733203945Sweongyo	{ 2, 2417, bwn_b2062_chantable_data[0] },
734203945Sweongyo	{ 3, 2422, bwn_b2062_chantable_data[0] },
735203945Sweongyo	{ 4, 2427, bwn_b2062_chantable_data[0] },
736203945Sweongyo	{ 5, 2432, bwn_b2062_chantable_data[0] },
737203945Sweongyo	{ 6, 2437, bwn_b2062_chantable_data[0] },
738203945Sweongyo	{ 7, 2442, bwn_b2062_chantable_data[0] },
739203945Sweongyo	{ 8, 2447, bwn_b2062_chantable_data[0] },
740203945Sweongyo	{ 9, 2452, bwn_b2062_chantable_data[0] },
741203945Sweongyo	{ 10, 2457, bwn_b2062_chantable_data[0] },
742203945Sweongyo	{ 11, 2462, bwn_b2062_chantable_data[0] },
743203945Sweongyo	{ 12, 2467, bwn_b2062_chantable_data[0] },
744203945Sweongyo	{ 13, 2472, bwn_b2062_chantable_data[0] },
745203945Sweongyo	{ 14, 2484, bwn_b2062_chantable_data[0] },
746203945Sweongyo	{ 34, 5170, bwn_b2062_chantable_data[1] },
747203945Sweongyo	{ 38, 5190, bwn_b2062_chantable_data[2] },
748203945Sweongyo	{ 42, 5210, bwn_b2062_chantable_data[2] },
749203945Sweongyo	{ 46, 5230, bwn_b2062_chantable_data[3] },
750203945Sweongyo	{ 36, 5180, bwn_b2062_chantable_data[4] },
751203945Sweongyo	{ 40, 5200, bwn_b2062_chantable_data[5] },
752203945Sweongyo	{ 44, 5220, bwn_b2062_chantable_data[6] },
753203945Sweongyo	{ 48, 5240, bwn_b2062_chantable_data[3] },
754203945Sweongyo	{ 52, 5260, bwn_b2062_chantable_data[3] },
755203945Sweongyo	{ 56, 5280, bwn_b2062_chantable_data[3] },
756203945Sweongyo	{ 60, 5300, bwn_b2062_chantable_data[7] },
757203945Sweongyo	{ 64, 5320, bwn_b2062_chantable_data[8] },
758203945Sweongyo	{ 100, 5500, bwn_b2062_chantable_data[9] },
759203945Sweongyo	{ 104, 5520, bwn_b2062_chantable_data[10] },
760203945Sweongyo	{ 108, 5540, bwn_b2062_chantable_data[10] },
761203945Sweongyo	{ 112, 5560, bwn_b2062_chantable_data[10] },
762203945Sweongyo	{ 116, 5580, bwn_b2062_chantable_data[11] },
763203945Sweongyo	{ 120, 5600, bwn_b2062_chantable_data[12] },
764203945Sweongyo	{ 124, 5620, bwn_b2062_chantable_data[12] },
765203945Sweongyo	{ 128, 5640, bwn_b2062_chantable_data[12] },
766203945Sweongyo	{ 132, 5660, bwn_b2062_chantable_data[12] },
767203945Sweongyo	{ 136, 5680, bwn_b2062_chantable_data[12] },
768203945Sweongyo	{ 140, 5700, bwn_b2062_chantable_data[12] },
769203945Sweongyo	{ 149, 5745, bwn_b2062_chantable_data[12] },
770203945Sweongyo	{ 153, 5765, bwn_b2062_chantable_data[12] },
771203945Sweongyo	{ 157, 5785, bwn_b2062_chantable_data[12] },
772203945Sweongyo	{ 161, 5805, bwn_b2062_chantable_data[12] },
773203945Sweongyo	{ 165, 5825, bwn_b2062_chantable_data[12] },
774203945Sweongyo	{ 184, 4920, bwn_b2062_chantable_data[13] },
775203945Sweongyo	{ 188, 4940, bwn_b2062_chantable_data[14] },
776203945Sweongyo	{ 192, 4960, bwn_b2062_chantable_data[15] },
777203945Sweongyo	{ 196, 4980, bwn_b2062_chantable_data[16] },
778203945Sweongyo	{ 200, 5000, bwn_b2062_chantable_data[17] },
779203945Sweongyo	{ 204, 5020, bwn_b2062_chantable_data[18] },
780203945Sweongyo	{ 208, 5040, bwn_b2062_chantable_data[19] },
781203945Sweongyo	{ 212, 5060, bwn_b2062_chantable_data[20] },
782203945Sweongyo	{ 216, 5080, bwn_b2062_chantable_data[21] }
783203945Sweongyo};
784203945Sweongyo
785203945Sweongyo/* for LP PHY */
786203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_5354[] = {
787203945Sweongyo	{  1, -66, 15 }, {  2, -66, 15 }, {  3, -66, 15 }, {  4, -66, 15 },
788203945Sweongyo	{  5, -66, 15 }, {  6, -66, 15 }, {  7, -66, 14 }, {  8, -66, 14 },
789203945Sweongyo	{  9, -66, 14 }, { 10, -66, 14 }, { 11, -66, 14 }, { 12, -66, 13 },
790203945Sweongyo	{ 13, -66, 13 }, { 14, -66, 13 },
791203945Sweongyo};
792203945Sweongyo
793203945Sweongyo/* for LP PHY */
794203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r12[] = {
795203945Sweongyo	{   1, -64, 13 }, {   2, -64, 13 }, {   3, -64, 13 }, {   4, -64, 13 },
796203945Sweongyo	{   5, -64, 12 }, {   6, -64, 12 }, {   7, -64, 12 }, {   8, -64, 12 },
797203945Sweongyo	{   9, -64, 12 }, {  10, -64, 11 }, {  11, -64, 11 }, {  12, -64, 11 },
798203945Sweongyo	{  13, -64, 11 }, {  14, -64, 10 }, {  34, -62, 24 }, {  38, -62, 24 },
799203945Sweongyo	{  42, -62, 24 }, {  46, -62, 23 }, {  36, -62, 24 }, {  40, -62, 24 },
800203945Sweongyo	{  44, -62, 23 }, {  48, -62, 23 }, {  52, -62, 23 }, {  56, -62, 22 },
801203945Sweongyo	{  60, -62, 22 }, {  64, -62, 22 }, { 100, -62, 16 }, { 104, -62, 16 },
802203945Sweongyo	{ 108, -62, 15 }, { 112, -62, 14 }, { 116, -62, 14 }, { 120, -62, 13 },
803203945Sweongyo	{ 124, -62, 12 }, { 128, -62, 12 }, { 132, -62, 12 }, { 136, -62, 11 },
804203945Sweongyo	{ 140, -62, 10 }, { 149, -61,  9 }, { 153, -61,  9 }, { 157, -61,  9 },
805203945Sweongyo	{ 161, -61,  8 }, { 165, -61,  8 }, { 184, -62, 25 }, { 188, -62, 25 },
806203945Sweongyo	{ 192, -62, 25 }, { 196, -62, 25 }, { 200, -62, 25 }, { 204, -62, 25 },
807203945Sweongyo	{ 208, -62, 25 }, { 212, -62, 25 }, { 216, -62, 26 },
808203945Sweongyo};
809203945Sweongyo
810203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r2 = { 0, -64, 0 };
811203945Sweongyo
812203945Sweongyostatic const uint8_t bwn_tab_sigsq_tbl[] = {
813203945Sweongyo	0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
814203945Sweongyo	0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
815203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
816203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
817203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
818203945Sweongyo	0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
819203945Sweongyo};
820203945Sweongyo
821203945Sweongyostatic const uint8_t bwn_tab_pllfrac_tbl[] = {
822203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
823203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
824203945Sweongyo};
825203945Sweongyo
826203945Sweongyostatic const uint16_t bwn_tabl_iqlocal_tbl[] = {
827203945Sweongyo	0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
828203945Sweongyo	0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
829203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
830203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
831203945Sweongyo	0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
832203945Sweongyo	0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
833203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
834203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
835203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
836203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
837203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
838203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
839203945Sweongyo};
840203945Sweongyo
841203945Sweongyostatic const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
842203945Sweongyostatic const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
843203945Sweongyostatic const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
844203945Sweongyostatic const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
845203945Sweongyostatic const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
846203945Sweongyoconst uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
847203945Sweongyo
848203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
849203945Sweongyo{							\
850203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
851203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
852203945Sweongyo}
853203945Sweongyo
854203945Sweongyostatic const struct {
855203945Sweongyo	uint16_t	vid;
856203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
857203945Sweongyo} bwn_vendor_led_act[] = {
858203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
859203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
860203945Sweongyo};
861203945Sweongyo
862203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
863203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
864203945Sweongyo
865203945Sweongyo#undef VENDOR_LED_ACT
866203945Sweongyo
867203945Sweongyostatic const struct {
868203945Sweongyo	int		on_dur;
869203945Sweongyo	int		off_dur;
870203945Sweongyo} bwn_led_duration[109] = {
871203945Sweongyo	[0]	= { 400, 100 },
872203945Sweongyo	[2]	= { 150, 75 },
873203945Sweongyo	[4]	= { 90, 45 },
874203945Sweongyo	[11]	= { 66, 34 },
875203945Sweongyo	[12]	= { 53, 26 },
876203945Sweongyo	[18]	= { 42, 21 },
877203945Sweongyo	[22]	= { 35, 17 },
878203945Sweongyo	[24]	= { 32, 16 },
879203945Sweongyo	[36]	= { 21, 10 },
880203945Sweongyo	[48]	= { 16, 8 },
881203945Sweongyo	[72]	= { 11, 5 },
882203945Sweongyo	[96]	= { 9, 4 },
883203945Sweongyo	[108]	= { 7, 3 }
884203945Sweongyo};
885203945Sweongyo
886203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
887203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
888203945Sweongyo	[1] = BWN_WME_BACKGROUND,
889203945Sweongyo	[2] = BWN_WME_VOICE,
890203945Sweongyo	[3] = BWN_WME_VIDEO,
891203945Sweongyo};
892203945Sweongyo
893203945Sweongyostatic const struct siba_devid bwn_devs[] = {
894203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
895203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
896203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
897203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
898203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
899203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
900203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
901203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
902203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
903203945Sweongyo};
904203945Sweongyo
905203945Sweongyostatic int
906203945Sweongyobwn_probe(device_t dev)
907203945Sweongyo{
908203945Sweongyo	int i;
909203945Sweongyo
910203945Sweongyo	for (i = 0; i < sizeof(bwn_devs) / sizeof(bwn_devs[0]); i++) {
911204922Sweongyo		if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor &&
912204922Sweongyo		    siba_get_device(dev) == bwn_devs[i].sd_device &&
913204922Sweongyo		    siba_get_revid(dev) == bwn_devs[i].sd_rev)
914203945Sweongyo			return (BUS_PROBE_DEFAULT);
915203945Sweongyo	}
916203945Sweongyo
917203945Sweongyo	return (ENXIO);
918203945Sweongyo}
919203945Sweongyo
920203945Sweongyostatic int
921203945Sweongyobwn_attach(device_t dev)
922203945Sweongyo{
923203945Sweongyo	struct bwn_mac *mac;
924203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
925203945Sweongyo	int error, i, msic, reg;
926203945Sweongyo
927203945Sweongyo	sc->sc_dev = dev;
928203945Sweongyo#ifdef BWN_DEBUG
929203945Sweongyo	sc->sc_debug = bwn_debug;
930203945Sweongyo#endif
931203945Sweongyo
932203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
933203945Sweongyo		error = bwn_attach_pre(sc);
934203945Sweongyo		if (error != 0)
935203945Sweongyo			return (error);
936204922Sweongyo		bwn_sprom_bugfixes(dev);
937203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
938203945Sweongyo	}
939203945Sweongyo
940203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
941204922Sweongyo		if (siba_get_pci_device(dev) != 0x4313 &&
942204922Sweongyo		    siba_get_pci_device(dev) != 0x431a &&
943204922Sweongyo		    siba_get_pci_device(dev) != 0x4321) {
944203945Sweongyo			device_printf(sc->sc_dev,
945203945Sweongyo			    "skip 802.11 cores\n");
946203945Sweongyo			return (ENODEV);
947203945Sweongyo		}
948203945Sweongyo	}
949203945Sweongyo
950203945Sweongyo	mac = (struct bwn_mac *)malloc(sizeof(*mac), M_DEVBUF,
951203945Sweongyo	    M_NOWAIT | M_ZERO);
952203945Sweongyo	if (mac == NULL)
953203945Sweongyo		return (ENOMEM);
954203945Sweongyo	mac->mac_sc = sc;
955203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
956203945Sweongyo	if (bwn_bfp != 0)
957203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
958203945Sweongyo
959203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
960203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
961203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
962203945Sweongyo
963203945Sweongyo	error = bwn_attach_core(mac);
964203945Sweongyo	if (error)
965203945Sweongyo		goto fail0;
966203945Sweongyo	bwn_led_attach(mac);
967203945Sweongyo
968203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
969203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
970204922Sweongyo	    siba_get_chipid(sc->sc_dev), siba_get_revid(sc->sc_dev),
971203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
972203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
973203945Sweongyo	    mac->mac_phy.rf_rev);
974203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
975203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
976203945Sweongyo		    mac->mac_method.dma.dmatype);
977203945Sweongyo	else
978203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
979203945Sweongyo
980203945Sweongyo	/*
981203945Sweongyo	 * setup PCI resources and interrupt.
982203945Sweongyo	 */
983219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
984203945Sweongyo		msic = pci_msi_count(dev);
985203945Sweongyo		if (bootverbose)
986203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
987203945Sweongyo	} else
988203945Sweongyo		msic = 0;
989203945Sweongyo
990203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
991203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
992203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
993203945Sweongyo			device_printf(sc->sc_dev,
994203945Sweongyo			    "Using %d MSI messages\n", msic);
995203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
996203945Sweongyo			mac->mac_msi = 1;
997203945Sweongyo		}
998203945Sweongyo	}
999203945Sweongyo
1000203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
1001203945Sweongyo	    mac->mac_res_irq);
1002203945Sweongyo	if (error) {
1003203945Sweongyo		device_printf(sc->sc_dev,
1004203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
1005203945Sweongyo		goto fail1;
1006203945Sweongyo	}
1007203945Sweongyo
1008203945Sweongyo	if (mac->mac_msi == 0)
1009203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
1010203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1011203945Sweongyo		    &mac->mac_intrhand[0]);
1012203945Sweongyo	else {
1013203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1014203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
1015203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1016203945Sweongyo			    &mac->mac_intrhand[i]);
1017203945Sweongyo			if (error != 0) {
1018203945Sweongyo				device_printf(sc->sc_dev,
1019203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
1020203945Sweongyo				break;
1021203945Sweongyo			}
1022203945Sweongyo		}
1023203945Sweongyo	}
1024203945Sweongyo
1025203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
1026203945Sweongyo
1027203945Sweongyo	/*
1028203945Sweongyo	 * calls attach-post routine
1029203945Sweongyo	 */
1030203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
1031203945Sweongyo		bwn_attach_post(sc);
1032203945Sweongyo
1033203945Sweongyo	return (0);
1034203945Sweongyofail1:
1035203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
1036203945Sweongyo		pci_release_msi(dev);
1037203945Sweongyofail0:
1038203945Sweongyo	free(mac, M_DEVBUF);
1039203945Sweongyo	return (error);
1040203945Sweongyo}
1041203945Sweongyo
1042203945Sweongyostatic int
1043203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
1044203945Sweongyo{
1045203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
1046203945Sweongyo
1047203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
1048203945Sweongyo		return (FALSE);
1049203945Sweongyo
1050203945Sweongyo	return (TRUE);
1051203945Sweongyo}
1052203945Sweongyo
1053203945Sweongyostatic int
1054203945Sweongyobwn_attach_post(struct bwn_softc *sc)
1055203945Sweongyo{
1056203945Sweongyo	struct ieee80211com *ic;
1057203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1058203945Sweongyo
1059203945Sweongyo	ic = ifp->if_l2com;
1060203945Sweongyo	ic->ic_ifp = ifp;
1061203945Sweongyo	/* XXX not right but it's not used anywhere important */
1062203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
1063203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
1064203945Sweongyo	ic->ic_caps =
1065203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
1066203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
1067204436Sweongyo		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
1068203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
1069203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
1070203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
1071203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
1072203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
1073203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
1074203945Sweongyo		;
1075203945Sweongyo
1076205141Sweongyo	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;	/* s/w bmiss */
1077205141Sweongyo
1078203945Sweongyo	/* call MI attach routine. */
1079203945Sweongyo	ieee80211_ifattach(ic,
1080204922Sweongyo	    bwn_is_valid_ether_addr(siba_sprom_get_mac_80211a(sc->sc_dev)) ?
1081204922Sweongyo	    siba_sprom_get_mac_80211a(sc->sc_dev) :
1082204922Sweongyo	    siba_sprom_get_mac_80211bg(sc->sc_dev));
1083203945Sweongyo
1084203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
1085203945Sweongyo
1086203945Sweongyo	/* override default methods */
1087203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
1088203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
1089203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
1090203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
1091203945Sweongyo
1092203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
1093203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
1094203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
1095203945Sweongyo
1096203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
1097203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
1098203945Sweongyo
1099203945Sweongyo	ieee80211_radiotap_attach(ic,
1100203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
1101203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
1102203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
1103203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
1104203945Sweongyo
1105204257Sweongyo	bwn_sysctl_node(sc);
1106203945Sweongyo
1107203945Sweongyo	if (bootverbose)
1108203945Sweongyo		ieee80211_announce(ic);
1109203945Sweongyo	return (0);
1110203945Sweongyo}
1111203945Sweongyo
1112203945Sweongyostatic void
1113203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
1114203945Sweongyo{
1115203945Sweongyo
1116203945Sweongyo	if (mac->mac_phy.detach != NULL)
1117203945Sweongyo		mac->mac_phy.detach(mac);
1118203945Sweongyo}
1119203945Sweongyo
1120203945Sweongyostatic int
1121203945Sweongyobwn_detach(device_t dev)
1122203945Sweongyo{
1123203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
1124203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1125203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1126203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1127203945Sweongyo	int i;
1128203945Sweongyo
1129203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
1130203945Sweongyo
1131203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
1132203945Sweongyo		bwn_stop(sc, 1);
1133203945Sweongyo		bwn_dma_free(mac);
1134203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
1135203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
1136203945Sweongyo		callout_drain(&sc->sc_task_ch);
1137203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
1138203945Sweongyo		bwn_phy_detach(mac);
1139203945Sweongyo		if (ifp != NULL) {
1140203945Sweongyo			ieee80211_draintask(ic, &mac->mac_hwreset);
1141203945Sweongyo			ieee80211_draintask(ic, &mac->mac_txpower);
1142203945Sweongyo			ieee80211_ifdetach(ic);
1143203945Sweongyo			if_free(ifp);
1144203945Sweongyo		}
1145203945Sweongyo	}
1146203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
1147203945Sweongyo	taskqueue_free(sc->sc_tq);
1148203945Sweongyo
1149203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1150203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
1151203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
1152203945Sweongyo			    mac->mac_intrhand[i]);
1153203945Sweongyo			mac->mac_intrhand[i] = NULL;
1154203945Sweongyo		}
1155203945Sweongyo	}
1156203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
1157203945Sweongyo	if (mac->mac_msi != 0)
1158203945Sweongyo		pci_release_msi(dev);
1159203945Sweongyo
1160203945Sweongyo	BWN_LOCK_DESTROY(sc);
1161203945Sweongyo	return (0);
1162203945Sweongyo}
1163203945Sweongyo
1164203945Sweongyostatic int
1165203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
1166203945Sweongyo{
1167203945Sweongyo	struct ifnet *ifp;
1168203945Sweongyo	int error = 0;
1169203945Sweongyo
1170203945Sweongyo	BWN_LOCK_INIT(sc);
1171203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
1172203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
1173203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
1174203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
1175203945Sweongyo
1176203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
1177203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
1178203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
1179203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
1180203945Sweongyo
1181203945Sweongyo	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
1182203945Sweongyo	if (ifp == NULL) {
1183203945Sweongyo		device_printf(sc->sc_dev, "can not if_alloc()\n");
1184203945Sweongyo		error = ENOSPC;
1185203945Sweongyo		goto fail;
1186203945Sweongyo	}
1187203945Sweongyo
1188203945Sweongyo	/* set these up early for if_printf use */
1189203945Sweongyo	if_initname(ifp, device_get_name(sc->sc_dev),
1190203945Sweongyo	    device_get_unit(sc->sc_dev));
1191203945Sweongyo
1192203945Sweongyo	ifp->if_softc = sc;
1193203945Sweongyo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1194203945Sweongyo	ifp->if_init = bwn_init;
1195203945Sweongyo	ifp->if_ioctl = bwn_ioctl;
1196203945Sweongyo	ifp->if_start = bwn_start;
1197207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
1198207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
1199203945Sweongyo	IFQ_SET_READY(&ifp->if_snd);
1200203945Sweongyo
1201203945Sweongyo	return (0);
1202203945Sweongyo
1203203945Sweongyofail:	BWN_LOCK_DESTROY(sc);
1204203945Sweongyo	return (error);
1205203945Sweongyo}
1206203945Sweongyo
1207203945Sweongyostatic void
1208204922Sweongyobwn_sprom_bugfixes(device_t dev)
1209203945Sweongyo{
1210203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
1211204922Sweongyo	((siba_get_pci_vendor(dev) == PCI_VENDOR_##_vendor) &&		\
1212204922Sweongyo	 (siba_get_pci_device(dev) == _device) &&			\
1213204922Sweongyo	 (siba_get_pci_subvendor(dev) == PCI_VENDOR_##_subvendor) &&	\
1214204922Sweongyo	 (siba_get_pci_subdevice(dev) == _subdevice))
1215203945Sweongyo
1216204922Sweongyo	if (siba_get_pci_subvendor(dev) == PCI_VENDOR_APPLE &&
1217204922Sweongyo	    siba_get_pci_subdevice(dev) == 0x4e &&
1218204922Sweongyo	    siba_get_pci_revid(dev) > 0x40)
1219204922Sweongyo		siba_sprom_set_bf_lo(dev,
1220204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_PACTRL);
1221204922Sweongyo	if (siba_get_pci_subvendor(dev) == SIBA_BOARDVENDOR_DELL &&
1222204922Sweongyo	    siba_get_chipid(dev) == 0x4301 && siba_get_pci_revid(dev) == 0x74)
1223204922Sweongyo		siba_sprom_set_bf_lo(dev,
1224204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_BTCOEXIST);
1225204922Sweongyo	if (siba_get_type(dev) == SIBA_TYPE_PCI) {
1226203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
1227203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
1228203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
1229203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
1230203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
1231203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
1232203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
1233204922Sweongyo			siba_sprom_set_bf_lo(dev,
1234204922Sweongyo			    siba_sprom_get_bf_lo(dev) & ~BWN_BFL_BTCOEXIST);
1235203945Sweongyo	}
1236203945Sweongyo#undef	BWN_ISDEV
1237203945Sweongyo}
1238203945Sweongyo
1239203945Sweongyostatic int
1240203945Sweongyobwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1241203945Sweongyo{
1242203945Sweongyo#define	IS_RUNNING(ifp) \
1243203945Sweongyo	((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
1244203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1245203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1246203945Sweongyo	struct ifreq *ifr = (struct ifreq *)data;
1247203945Sweongyo	int error = 0, startall;
1248203945Sweongyo
1249203945Sweongyo	switch (cmd) {
1250203945Sweongyo	case SIOCSIFFLAGS:
1251203945Sweongyo		startall = 0;
1252203945Sweongyo		if (IS_RUNNING(ifp)) {
1253203945Sweongyo			bwn_update_promisc(ifp);
1254203945Sweongyo		} else if (ifp->if_flags & IFF_UP) {
1255203945Sweongyo			if ((sc->sc_flags & BWN_FLAG_INVALID) == 0) {
1256203945Sweongyo				bwn_init(sc);
1257203945Sweongyo				startall = 1;
1258203945Sweongyo			}
1259203945Sweongyo		} else
1260203945Sweongyo			bwn_stop(sc, 1);
1261203945Sweongyo		if (startall)
1262203945Sweongyo			ieee80211_start_all(ic);
1263203945Sweongyo		break;
1264203945Sweongyo	case SIOCGIFMEDIA:
1265203945Sweongyo		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1266203945Sweongyo		break;
1267203945Sweongyo	case SIOCGIFADDR:
1268203945Sweongyo		error = ether_ioctl(ifp, cmd, data);
1269203945Sweongyo		break;
1270203945Sweongyo	default:
1271203945Sweongyo		error = EINVAL;
1272203945Sweongyo		break;
1273203945Sweongyo	}
1274203945Sweongyo	return (error);
1275203945Sweongyo}
1276203945Sweongyo
1277203945Sweongyostatic void
1278203945Sweongyobwn_start(struct ifnet *ifp)
1279203945Sweongyo{
1280203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1281203945Sweongyo
1282203945Sweongyo	BWN_LOCK(sc);
1283203945Sweongyo	bwn_start_locked(ifp);
1284203945Sweongyo	BWN_UNLOCK(sc);
1285203945Sweongyo}
1286203945Sweongyo
1287203945Sweongyostatic void
1288203945Sweongyobwn_start_locked(struct ifnet *ifp)
1289203945Sweongyo{
1290203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1291203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1292203945Sweongyo	struct ieee80211_frame *wh;
1293203945Sweongyo	struct ieee80211_node *ni;
1294203945Sweongyo	struct ieee80211_key *k;
1295203945Sweongyo	struct mbuf *m;
1296203945Sweongyo
1297203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1298203945Sweongyo
1299203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || mac == NULL ||
1300203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
1301203945Sweongyo		return;
1302203945Sweongyo
1303203945Sweongyo	for (;;) {
1304203945Sweongyo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);	/* XXX: LOCK */
1305203945Sweongyo		if (m == NULL)
1306203945Sweongyo			break;
1307203945Sweongyo
1308203945Sweongyo		if (bwn_tx_isfull(sc, m))
1309203945Sweongyo			break;
1310203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
1311203945Sweongyo		if (ni == NULL) {
1312203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
1313203945Sweongyo			m_freem(m);
1314203945Sweongyo			ifp->if_oerrors++;
1315203945Sweongyo			continue;
1316203945Sweongyo		}
1317203945Sweongyo		KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__));
1318203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
1319203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1320203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
1321203945Sweongyo			if (k == NULL) {
1322203945Sweongyo				ieee80211_free_node(ni);
1323203945Sweongyo				m_freem(m);
1324203945Sweongyo				ifp->if_oerrors++;
1325203945Sweongyo				continue;
1326203945Sweongyo			}
1327203945Sweongyo		}
1328203945Sweongyo		wh = NULL;	/* Catch any invalid use */
1329203945Sweongyo
1330203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
1331203945Sweongyo			if (ni != NULL)
1332203945Sweongyo				ieee80211_free_node(ni);
1333203945Sweongyo			ifp->if_oerrors++;
1334203945Sweongyo			continue;
1335203945Sweongyo		}
1336203945Sweongyo
1337203945Sweongyo		sc->sc_watchdog_timer = 5;
1338203945Sweongyo	}
1339203945Sweongyo}
1340203945Sweongyo
1341203945Sweongyostatic int
1342203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
1343203945Sweongyo{
1344203945Sweongyo	struct bwn_dma_ring *dr;
1345203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1346203945Sweongyo	struct bwn_pio_txqueue *tq;
1347203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1348203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1349203945Sweongyo
1350203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1351203945Sweongyo
1352203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
1353203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
1354203945Sweongyo		if (dr->dr_stop == 1 ||
1355203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
1356203945Sweongyo			dr->dr_stop = 1;
1357203945Sweongyo			goto full;
1358203945Sweongyo		}
1359203945Sweongyo	} else {
1360203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
1361203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
1362203945Sweongyo		    pktlen > (tq->tq_size - tq->tq_used)) {
1363203945Sweongyo			tq->tq_stop = 1;
1364203945Sweongyo			goto full;
1365203945Sweongyo		}
1366203945Sweongyo	}
1367203945Sweongyo	return (0);
1368203945Sweongyofull:
1369203945Sweongyo	IFQ_DRV_PREPEND(&ifp->if_snd, m);
1370203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1371203945Sweongyo	return (1);
1372203945Sweongyo}
1373203945Sweongyo
1374203945Sweongyostatic int
1375203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
1376203945Sweongyo{
1377203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1378203945Sweongyo	int error;
1379203945Sweongyo
1380203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1381203945Sweongyo
1382203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
1383203945Sweongyo		m_freem(m);
1384203945Sweongyo		return (ENXIO);
1385203945Sweongyo	}
1386203945Sweongyo
1387203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
1388203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
1389203945Sweongyo	if (error) {
1390203945Sweongyo		m_freem(m);
1391203945Sweongyo		return (error);
1392203945Sweongyo	}
1393203945Sweongyo	return (0);
1394203945Sweongyo}
1395203945Sweongyo
1396203945Sweongyostatic int
1397203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1398203945Sweongyo{
1399203945Sweongyo	struct bwn_pio_txpkt *tp;
1400203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
1401203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1402203945Sweongyo	struct bwn_txhdr txhdr;
1403203945Sweongyo	struct mbuf *m_new;
1404203945Sweongyo	uint32_t ctl32;
1405203945Sweongyo	int error;
1406203945Sweongyo	uint16_t ctl16;
1407203945Sweongyo
1408203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1409203945Sweongyo
1410203945Sweongyo	/* XXX TODO send packets after DTIM */
1411203945Sweongyo
1412203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
1413203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
1414203945Sweongyo	tp->tp_ni = ni;
1415203945Sweongyo	tp->tp_m = m;
1416203945Sweongyo
1417203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
1418203945Sweongyo	if (error) {
1419203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
1420203945Sweongyo		return (error);
1421203945Sweongyo	}
1422203945Sweongyo
1423203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
1424203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1425203945Sweongyo	tq->tq_free--;
1426203945Sweongyo
1427204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8) {
1428203945Sweongyo		/*
1429203945Sweongyo		 * XXX please removes m_defrag(9)
1430203945Sweongyo		 */
1431243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
1432203945Sweongyo		if (m_new == NULL) {
1433203945Sweongyo			device_printf(sc->sc_dev,
1434203945Sweongyo			    "%s: can't defrag TX buffer\n",
1435203945Sweongyo			    __func__);
1436203945Sweongyo			return (ENOBUFS);
1437203945Sweongyo		}
1438203945Sweongyo		if (m_new->m_next != NULL)
1439203945Sweongyo			device_printf(sc->sc_dev,
1440203945Sweongyo			    "TODO: fragmented packets for PIO\n");
1441203945Sweongyo		tp->tp_m = m_new;
1442203945Sweongyo
1443203945Sweongyo		/* send HEADER */
1444203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
1445203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
1446203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
1447203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1448203945Sweongyo		/* send BODY */
1449203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
1450203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
1451203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
1452203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
1453203945Sweongyo	} else {
1454203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
1455203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
1456203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
1457203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1458203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
1459203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
1460203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
1461203945Sweongyo	}
1462203945Sweongyo
1463203945Sweongyo	return (0);
1464203945Sweongyo}
1465203945Sweongyo
1466203945Sweongyostatic struct bwn_pio_txqueue *
1467203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1468203945Sweongyo{
1469203945Sweongyo
1470203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1471203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1472203945Sweongyo
1473203945Sweongyo	switch (prio) {
1474203945Sweongyo	case 0:
1475203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1476203945Sweongyo	case 1:
1477203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1478203945Sweongyo	case 2:
1479203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1480203945Sweongyo	case 3:
1481203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1482203945Sweongyo	}
1483203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1484204242Simp	return (NULL);
1485203945Sweongyo}
1486203945Sweongyo
1487203945Sweongyostatic int
1488203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1489203945Sweongyo{
1490203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1491203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1492203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1493203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1494203945Sweongyo	struct bwn_dmadesc_generic *desc;
1495203945Sweongyo	struct bwn_dmadesc_meta *mt;
1496203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1497203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1498203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1499203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1500203945Sweongyo
1501203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1502203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1503203945Sweongyo
1504203945Sweongyo	/* XXX send after DTIM */
1505203945Sweongyo
1506203945Sweongyo	slot = bwn_dma_getslot(dr);
1507203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1508203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1509203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1510203945Sweongyo
1511203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1512203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1513203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1514203945Sweongyo	if (error)
1515203945Sweongyo		goto fail;
1516203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1517203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1518203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1519203945Sweongyo	if (error) {
1520203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1521203945Sweongyo		    __func__, error);
1522203945Sweongyo		goto fail;
1523203945Sweongyo	}
1524203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1525203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1526203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1527203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1528203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1529203945Sweongyo
1530203945Sweongyo	slot = bwn_dma_getslot(dr);
1531203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1532203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1533203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1534203945Sweongyo	mt->mt_m = m;
1535203945Sweongyo	mt->mt_ni = ni;
1536203945Sweongyo
1537203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1538203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1539203945Sweongyo	if (error && error != EFBIG) {
1540203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1541203945Sweongyo		    __func__, error);
1542203945Sweongyo		goto fail;
1543203945Sweongyo	}
1544203945Sweongyo	if (error) {    /* error == EFBIG */
1545203945Sweongyo		struct mbuf *m_new;
1546203945Sweongyo
1547243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
1548203945Sweongyo		if (m_new == NULL) {
1549203945Sweongyo			if_printf(ifp, "%s: can't defrag TX buffer\n",
1550203945Sweongyo			    __func__);
1551203945Sweongyo			error = ENOBUFS;
1552203945Sweongyo			goto fail;
1553203945Sweongyo		} else {
1554203945Sweongyo			m = m_new;
1555203945Sweongyo		}
1556203945Sweongyo
1557203945Sweongyo		mt->mt_m = m;
1558203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1559203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1560203945Sweongyo		if (error) {
1561203945Sweongyo			if_printf(ifp, "%s: can't load TX buffer (2) %d\n",
1562203945Sweongyo			    __func__, error);
1563203945Sweongyo			goto fail;
1564203945Sweongyo		}
1565203945Sweongyo	}
1566203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1567203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1568203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1569203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1570203945Sweongyo
1571203945Sweongyo	/* XXX send after DTIM */
1572203945Sweongyo
1573203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1574203945Sweongyo	return (0);
1575203945Sweongyofail:
1576203945Sweongyo	dr->dr_curslot = backup[0];
1577203945Sweongyo	dr->dr_usedslot = backup[1];
1578203945Sweongyo	return (error);
1579203945Sweongyo#undef BWN_GET_TXHDRCACHE
1580203945Sweongyo}
1581203945Sweongyo
1582203945Sweongyostatic void
1583203945Sweongyobwn_watchdog(void *arg)
1584203945Sweongyo{
1585203945Sweongyo	struct bwn_softc *sc = arg;
1586203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1587203945Sweongyo
1588203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1589203945Sweongyo		if_printf(ifp, "device timeout\n");
1590203945Sweongyo		ifp->if_oerrors++;
1591203945Sweongyo	}
1592203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1593203945Sweongyo}
1594203945Sweongyo
1595203945Sweongyostatic int
1596203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1597203945Sweongyo{
1598203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1599203945Sweongyo	int error, have_bg = 0, have_a = 0;
1600203945Sweongyo	uint32_t high;
1601203945Sweongyo
1602204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5,
1603204922Sweongyo	    ("unsupported revision %d", siba_get_revid(sc->sc_dev)));
1604203945Sweongyo
1605204922Sweongyo	siba_powerup(sc->sc_dev, 0);
1606203945Sweongyo
1607204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
1608203945Sweongyo	bwn_reset_core(mac,
1609203945Sweongyo	    (high & BWN_TGSHIGH_HAVE_2GHZ) ? BWN_TGSLOW_SUPPORT_G : 0);
1610203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1611203945Sweongyo	if (error)
1612203945Sweongyo		goto fail;
1613203945Sweongyo
1614203945Sweongyo	have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1615203945Sweongyo	have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1616204922Sweongyo	if (siba_get_pci_device(sc->sc_dev) != 0x4312 &&
1617204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4319 &&
1618204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4324) {
1619203945Sweongyo		have_a = have_bg = 0;
1620203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1621203945Sweongyo			have_a = 1;
1622203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1623203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1624203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1625203945Sweongyo			have_bg = 1;
1626203945Sweongyo		else
1627203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1628203945Sweongyo			    mac->mac_phy.type));
1629203945Sweongyo	}
1630203945Sweongyo	/* XXX turns off PHY A because it's not supported */
1631203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1632203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1633203945Sweongyo		have_a = 0;
1634203945Sweongyo		have_bg = 1;
1635203945Sweongyo	}
1636203945Sweongyo
1637203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1638203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1639203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1640203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1641203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1642203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1643203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1644203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1645203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1646203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1647203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1648203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1649203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1650203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1651203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1652203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1653203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1654203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1655203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1656203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1657203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1658203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1659203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1660203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1661203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1662203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1663203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1664203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1665203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1666203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1667203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1668203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1669203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1670203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1671203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1672203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1673203945Sweongyo	} else {
1674203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1675203945Sweongyo		    mac->mac_phy.type);
1676203945Sweongyo		error = ENXIO;
1677203945Sweongyo		goto fail;
1678203945Sweongyo	}
1679203945Sweongyo
1680203945Sweongyo	mac->mac_phy.gmode = have_bg;
1681203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1682203945Sweongyo		error = mac->mac_phy.attach(mac);
1683203945Sweongyo		if (error) {
1684203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1685203945Sweongyo			goto fail;
1686203945Sweongyo		}
1687203945Sweongyo	}
1688203945Sweongyo
1689203945Sweongyo	bwn_reset_core(mac, have_bg ? BWN_TGSLOW_SUPPORT_G : 0);
1690203945Sweongyo
1691203945Sweongyo	error = bwn_chiptest(mac);
1692203945Sweongyo	if (error)
1693203945Sweongyo		goto fail;
1694203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1695203945Sweongyo	if (error) {
1696203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1697203945Sweongyo		goto fail;
1698203945Sweongyo	}
1699203945Sweongyo
1700203945Sweongyo	if (sc->sc_curmac == NULL)
1701203945Sweongyo		sc->sc_curmac = mac;
1702203945Sweongyo
1703203945Sweongyo	error = bwn_dma_attach(mac);
1704203945Sweongyo	if (error != 0) {
1705203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1706203945Sweongyo		goto fail;
1707203945Sweongyo	}
1708203945Sweongyo
1709203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1710203945Sweongyo
1711204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
1712203945Sweongyofail:
1713204922Sweongyo	siba_powerdown(sc->sc_dev);
1714203945Sweongyo	return (error);
1715203945Sweongyo}
1716203945Sweongyo
1717203945Sweongyostatic void
1718203945Sweongyobwn_reset_core(struct bwn_mac *mac, uint32_t flags)
1719203945Sweongyo{
1720204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1721203945Sweongyo	uint32_t low, ctl;
1722203945Sweongyo
1723203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1724203945Sweongyo
1725204922Sweongyo	siba_dev_up(sc->sc_dev, flags);
1726203945Sweongyo	DELAY(2000);
1727203945Sweongyo
1728204922Sweongyo	low = (siba_read_4(sc->sc_dev, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1729203945Sweongyo	    ~BWN_TGSLOW_PHYRESET;
1730204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low);
1731204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1732203945Sweongyo	DELAY(1000);
1733204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
1734204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1735203945Sweongyo	DELAY(1000);
1736203945Sweongyo
1737203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1738203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1739203945Sweongyo
1740203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1741203945Sweongyo	if (flags & BWN_TGSLOW_SUPPORT_G)
1742203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1743203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1744203945Sweongyo}
1745203945Sweongyo
1746203945Sweongyostatic int
1747203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1748203945Sweongyo{
1749203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1750203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1751203945Sweongyo	uint32_t tmp;
1752203945Sweongyo
1753203945Sweongyo	/* PHY */
1754203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1755203945Sweongyo	phy->gmode = (tgshigh & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1756203945Sweongyo	phy->rf_on = 1;
1757203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1758203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1759203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1760203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1761203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1762203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1763203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1764203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1765203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1766203945Sweongyo		goto unsupphy;
1767203945Sweongyo
1768203945Sweongyo	/* RADIO */
1769204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4317) {
1770204922Sweongyo		if (siba_get_chiprev(sc->sc_dev) == 0)
1771203945Sweongyo			tmp = 0x3205017f;
1772204922Sweongyo		else if (siba_get_chiprev(sc->sc_dev) == 1)
1773203945Sweongyo			tmp = 0x4205017f;
1774203945Sweongyo		else
1775203945Sweongyo			tmp = 0x5205017f;
1776203945Sweongyo	} else {
1777203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1778203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1779203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1780203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1781203945Sweongyo	}
1782203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1783203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1784203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1785203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1786203945Sweongyo		goto unsupradio;
1787203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1788203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1789203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1790203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1791203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1792203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1793203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1794203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1795203945Sweongyo		goto unsupradio;
1796203945Sweongyo
1797203945Sweongyo	return (0);
1798203945Sweongyounsupphy:
1799203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1800203945Sweongyo	    "analog %#x)\n",
1801203945Sweongyo	    phy->type, phy->rev, phy->analog);
1802203945Sweongyo	return (ENXIO);
1803203945Sweongyounsupradio:
1804203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1805203945Sweongyo	    "rev %#x)\n",
1806203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1807203945Sweongyo	return (ENXIO);
1808203945Sweongyo}
1809203945Sweongyo
1810203945Sweongyostatic int
1811203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1812203945Sweongyo{
1813203945Sweongyo#define	TESTVAL0	0x55aaaa55
1814203945Sweongyo#define	TESTVAL1	0xaa5555aa
1815203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1816203945Sweongyo	uint32_t v, backup;
1817203945Sweongyo
1818203945Sweongyo	BWN_LOCK(sc);
1819203945Sweongyo
1820203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1821203945Sweongyo
1822203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1823203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1824203945Sweongyo		goto error;
1825203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1826203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1827203945Sweongyo		goto error;
1828203945Sweongyo
1829203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1830203945Sweongyo
1831204922Sweongyo	if ((siba_get_revid(sc->sc_dev) >= 3) &&
1832204922Sweongyo	    (siba_get_revid(sc->sc_dev) <= 10)) {
1833203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1834203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1835203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1836203945Sweongyo			goto error;
1837203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1838203945Sweongyo			goto error;
1839203945Sweongyo	}
1840203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1841203945Sweongyo
1842203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1843203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1844203945Sweongyo		goto error;
1845203945Sweongyo
1846203945Sweongyo	BWN_UNLOCK(sc);
1847203945Sweongyo	return (0);
1848203945Sweongyoerror:
1849203945Sweongyo	BWN_UNLOCK(sc);
1850203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1851203945Sweongyo	return (ENODEV);
1852203945Sweongyo}
1853203945Sweongyo
1854203945Sweongyo#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
1855203945Sweongyo#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
1856203945Sweongyo
1857203945Sweongyostatic int
1858203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1859203945Sweongyo{
1860203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1861203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1862203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1863203945Sweongyo
1864203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1865203945Sweongyo	ic->ic_nchans = 0;
1866203945Sweongyo
1867203945Sweongyo	if (have_bg)
1868203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1869203945Sweongyo		    &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
1870203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1871203945Sweongyo		if (have_a)
1872203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1873203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_n,
1874203945Sweongyo			    IEEE80211_CHAN_HTA);
1875203945Sweongyo	} else {
1876203945Sweongyo		if (have_a)
1877203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1878203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_a,
1879203945Sweongyo			    IEEE80211_CHAN_A);
1880203945Sweongyo	}
1881203945Sweongyo
1882203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1883203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1884203945Sweongyo
1885203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1886203945Sweongyo}
1887203945Sweongyo
1888203945Sweongyostatic uint32_t
1889203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1890203945Sweongyo{
1891203945Sweongyo	uint32_t ret;
1892203945Sweongyo
1893204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1894203945Sweongyo
1895203945Sweongyo	if (way == BWN_SHARED) {
1896203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1897203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1898203945Sweongyo		if (offset & 0x0003) {
1899203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1900203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1901203945Sweongyo			ret <<= 16;
1902203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1903203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1904203945Sweongyo			goto out;
1905203945Sweongyo		}
1906203945Sweongyo		offset >>= 2;
1907203945Sweongyo	}
1908203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1909203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1910203945Sweongyoout:
1911203945Sweongyo	return (ret);
1912203945Sweongyo}
1913203945Sweongyo
1914203945Sweongyostatic uint16_t
1915203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1916203945Sweongyo{
1917203945Sweongyo	uint16_t ret;
1918203945Sweongyo
1919204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1920203945Sweongyo
1921203945Sweongyo	if (way == BWN_SHARED) {
1922203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1923203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1924203945Sweongyo		if (offset & 0x0003) {
1925203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1926203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1927203945Sweongyo			goto out;
1928203945Sweongyo		}
1929203945Sweongyo		offset >>= 2;
1930203945Sweongyo	}
1931203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1932203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1933203945Sweongyoout:
1934203945Sweongyo
1935203945Sweongyo	return (ret);
1936203945Sweongyo}
1937203945Sweongyo
1938203945Sweongyostatic void
1939203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1940203945Sweongyo    uint16_t offset)
1941203945Sweongyo{
1942203945Sweongyo	uint32_t control;
1943203945Sweongyo
1944203945Sweongyo	control = way;
1945203945Sweongyo	control <<= 16;
1946203945Sweongyo	control |= offset;
1947203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1948203945Sweongyo}
1949203945Sweongyo
1950203945Sweongyostatic void
1951203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1952203945Sweongyo    uint32_t value)
1953203945Sweongyo{
1954204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1955203945Sweongyo
1956203945Sweongyo	if (way == BWN_SHARED) {
1957203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1958203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1959203945Sweongyo		if (offset & 0x0003) {
1960203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1961203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1962203945Sweongyo				    (value >> 16) & 0xffff);
1963203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1964203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1965203945Sweongyo			return;
1966203945Sweongyo		}
1967203945Sweongyo		offset >>= 2;
1968203945Sweongyo	}
1969203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1970203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1971203945Sweongyo}
1972203945Sweongyo
1973203945Sweongyostatic void
1974203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1975203945Sweongyo    uint16_t value)
1976203945Sweongyo{
1977204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1978203945Sweongyo
1979203945Sweongyo	if (way == BWN_SHARED) {
1980203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1981203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1982203945Sweongyo		if (offset & 0x0003) {
1983203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1984203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
1985203945Sweongyo			return;
1986203945Sweongyo		}
1987203945Sweongyo		offset >>= 2;
1988203945Sweongyo	}
1989203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1990203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
1991203945Sweongyo}
1992203945Sweongyo
1993203945Sweongyostatic void
1994203945Sweongyobwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
1995203945Sweongyo    int txpow)
1996203945Sweongyo{
1997203945Sweongyo
1998203945Sweongyo	c->ic_freq = freq;
1999203945Sweongyo	c->ic_flags = flags;
2000203945Sweongyo	c->ic_ieee = ieee;
2001203945Sweongyo	c->ic_minpower = 0;
2002203945Sweongyo	c->ic_maxpower = 2 * txpow;
2003203945Sweongyo	c->ic_maxregpower = txpow;
2004203945Sweongyo}
2005203945Sweongyo
2006203945Sweongyostatic void
2007203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
2008203945Sweongyo    const struct bwn_channelinfo *ci, int flags)
2009203945Sweongyo{
2010203945Sweongyo	struct ieee80211_channel *c;
2011203945Sweongyo	int i;
2012203945Sweongyo
2013203945Sweongyo	c = &chans[*nchans];
2014203945Sweongyo
2015203945Sweongyo	for (i = 0; i < ci->nchannels; i++) {
2016203945Sweongyo		const struct bwn_channel *hc;
2017203945Sweongyo
2018203945Sweongyo		hc = &ci->channels[i];
2019203945Sweongyo		if (*nchans >= maxchans)
2020203945Sweongyo			break;
2021203945Sweongyo		bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
2022203945Sweongyo		c++, (*nchans)++;
2023203945Sweongyo		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
2024203945Sweongyo			/* g channel have a separate b-only entry */
2025203945Sweongyo			if (*nchans >= maxchans)
2026203945Sweongyo				break;
2027203945Sweongyo			c[0] = c[-1];
2028203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_B;
2029203945Sweongyo			c++, (*nchans)++;
2030203945Sweongyo		}
2031203945Sweongyo		if (flags == IEEE80211_CHAN_HTG) {
2032203945Sweongyo			/* HT g channel have a separate g-only entry */
2033203945Sweongyo			if (*nchans >= maxchans)
2034203945Sweongyo				break;
2035203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_G;
2036203945Sweongyo			c[0] = c[-1];
2037203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2038203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2039203945Sweongyo			c++, (*nchans)++;
2040203945Sweongyo		}
2041203945Sweongyo		if (flags == IEEE80211_CHAN_HTA) {
2042203945Sweongyo			/* HT a channel have a separate a-only entry */
2043203945Sweongyo			if (*nchans >= maxchans)
2044203945Sweongyo				break;
2045203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_A;
2046203945Sweongyo			c[0] = c[-1];
2047203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2048203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2049203945Sweongyo			c++, (*nchans)++;
2050203945Sweongyo		}
2051203945Sweongyo	}
2052203945Sweongyo}
2053203945Sweongyo
2054203945Sweongyostatic int
2055203945Sweongyobwn_phy_g_attach(struct bwn_mac *mac)
2056203945Sweongyo{
2057203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2058203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2059203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2060203945Sweongyo	unsigned int i;
2061204922Sweongyo	int16_t pab0, pab1, pab2;
2062203945Sweongyo	static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
2063204922Sweongyo	int8_t bg;
2064203945Sweongyo
2065204922Sweongyo	bg = (int8_t)siba_sprom_get_tssi_bg(sc->sc_dev);
2066204922Sweongyo	pab0 = (int16_t)siba_sprom_get_pa0b0(sc->sc_dev);
2067204922Sweongyo	pab1 = (int16_t)siba_sprom_get_pa0b1(sc->sc_dev);
2068204922Sweongyo	pab2 = (int16_t)siba_sprom_get_pa0b2(sc->sc_dev);
2069204922Sweongyo
2070204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4301) && (phy->rf_ver != 0x2050))
2071203945Sweongyo		device_printf(sc->sc_dev, "not supported anymore\n");
2072203945Sweongyo
2073203945Sweongyo	pg->pg_flags = 0;
2074203945Sweongyo	if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
2075203945Sweongyo	    pab2 == -1) {
2076203945Sweongyo		pg->pg_idletssi = 52;
2077203945Sweongyo		pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
2078203945Sweongyo		return (0);
2079203945Sweongyo	}
2080203945Sweongyo
2081203945Sweongyo	pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
2082203945Sweongyo	pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
2083203945Sweongyo	if (pg->pg_tssi2dbm == NULL) {
2084203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer\n");
2085203945Sweongyo		return (ENOMEM);
2086203945Sweongyo	}
2087203945Sweongyo	for (i = 0; i < 64; i++) {
2088203945Sweongyo		int32_t m1, m2, f, q, delta;
2089203945Sweongyo		int8_t j = 0;
2090203945Sweongyo
2091203945Sweongyo		m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
2092203945Sweongyo		m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
2093203945Sweongyo		f = 256;
2094203945Sweongyo
2095203945Sweongyo		do {
2096203945Sweongyo			if (j > 15) {
2097203945Sweongyo				device_printf(sc->sc_dev,
2098203945Sweongyo				    "failed to generate tssi2dBm\n");
2099203945Sweongyo				free(pg->pg_tssi2dbm, M_DEVBUF);
2100203945Sweongyo				return (ENOMEM);
2101203945Sweongyo			}
2102203945Sweongyo			q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
2103203945Sweongyo			    f, 2048);
2104203945Sweongyo			delta = abs(q - f);
2105203945Sweongyo			f = q;
2106203945Sweongyo			j++;
2107203945Sweongyo		} while (delta >= 2);
2108203945Sweongyo
2109203945Sweongyo		pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
2110203945Sweongyo		    128);
2111203945Sweongyo	}
2112203945Sweongyo
2113203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
2114203945Sweongyo	return (0);
2115203945Sweongyo}
2116203945Sweongyo
2117203945Sweongyostatic void
2118203945Sweongyobwn_phy_g_detach(struct bwn_mac *mac)
2119203945Sweongyo{
2120203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
2121203945Sweongyo
2122203945Sweongyo	if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
2123203945Sweongyo		free(pg->pg_tssi2dbm, M_DEVBUF);
2124203945Sweongyo		pg->pg_tssi2dbm = NULL;
2125203945Sweongyo	}
2126203945Sweongyo	pg->pg_flags = 0;
2127203945Sweongyo}
2128203945Sweongyo
2129203945Sweongyostatic void
2130203945Sweongyobwn_phy_g_init_pre(struct bwn_mac *mac)
2131203945Sweongyo{
2132203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2133203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2134203945Sweongyo	void *tssi2dbm;
2135203945Sweongyo	int idletssi;
2136203945Sweongyo	unsigned int i;
2137203945Sweongyo
2138203945Sweongyo	tssi2dbm = pg->pg_tssi2dbm;
2139203945Sweongyo	idletssi = pg->pg_idletssi;
2140203945Sweongyo
2141203945Sweongyo	memset(pg, 0, sizeof(*pg));
2142203945Sweongyo
2143203945Sweongyo	pg->pg_tssi2dbm = tssi2dbm;
2144203945Sweongyo	pg->pg_idletssi = idletssi;
2145203945Sweongyo
2146203945Sweongyo	memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
2147203945Sweongyo
2148203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi); i++)
2149203945Sweongyo		pg->pg_nrssi[i] = -1000;
2150203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi_lt); i++)
2151203945Sweongyo		pg->pg_nrssi_lt[i] = i;
2152203945Sweongyo	pg->pg_lofcal = 0xffff;
2153203945Sweongyo	pg->pg_initval = 0xffff;
2154203945Sweongyo	pg->pg_immode = BWN_IMMODE_NONE;
2155203945Sweongyo	pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
2156203945Sweongyo	pg->pg_avgtssi = 0xff;
2157203945Sweongyo
2158203945Sweongyo	pg->pg_loctl.tx_bias = 0xff;
2159203945Sweongyo	TAILQ_INIT(&pg->pg_loctl.calib_list);
2160203945Sweongyo}
2161203945Sweongyo
2162203945Sweongyostatic int
2163203945Sweongyobwn_phy_g_prepare_hw(struct bwn_mac *mac)
2164203945Sweongyo{
2165203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2166203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2167204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2168203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2169203945Sweongyo	static const struct bwn_rfatt rfatt0[] = {
2170203945Sweongyo		{ 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 },	{ 9, 0 }, { 2, 0 },
2171203945Sweongyo		{ 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
2172203945Sweongyo		{ 3, 1 }, { 4, 1 }
2173203945Sweongyo	};
2174203945Sweongyo	static const struct bwn_rfatt rfatt1[] = {
2175203945Sweongyo		{ 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
2176203945Sweongyo		{ 14, 1 }
2177203945Sweongyo	};
2178203945Sweongyo	static const struct bwn_rfatt rfatt2[] = {
2179203945Sweongyo		{ 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
2180203945Sweongyo		{ 9, 1 }
2181203945Sweongyo	};
2182203945Sweongyo	static const struct bwn_bbatt bbatt_0[] = {
2183203945Sweongyo		{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
2184203945Sweongyo	};
2185203945Sweongyo
2186203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
2187203945Sweongyo
2188203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
2189203945Sweongyo		pg->pg_bbatt.att = 0;
2190203945Sweongyo	else
2191203945Sweongyo		pg->pg_bbatt.att = 2;
2192203945Sweongyo
2193203945Sweongyo	/* prepare Radio Attenuation */
2194203945Sweongyo	pg->pg_rfatt.padmix = 0;
2195203945Sweongyo
2196204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
2197204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BCM4309G) {
2198204922Sweongyo		if (siba_get_pci_revid(sc->sc_dev) < 0x43) {
2199203945Sweongyo			pg->pg_rfatt.att = 2;
2200203945Sweongyo			goto done;
2201204922Sweongyo		} else if (siba_get_pci_revid(sc->sc_dev) < 0x51) {
2202203945Sweongyo			pg->pg_rfatt.att = 3;
2203203945Sweongyo			goto done;
2204203945Sweongyo		}
2205203945Sweongyo	}
2206203945Sweongyo
2207203945Sweongyo	if (phy->type == BWN_PHYTYPE_A) {
2208203945Sweongyo		pg->pg_rfatt.att = 0x60;
2209203945Sweongyo		goto done;
2210203945Sweongyo	}
2211203945Sweongyo
2212203945Sweongyo	switch (phy->rf_ver) {
2213203945Sweongyo	case 0x2050:
2214203945Sweongyo		switch (phy->rf_rev) {
2215203945Sweongyo		case 0:
2216203945Sweongyo			pg->pg_rfatt.att = 5;
2217203945Sweongyo			goto done;
2218203945Sweongyo		case 1:
2219203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2220204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2221203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2222204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2223203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2224204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2225203945Sweongyo					pg->pg_rfatt.att = 3;
2226204922Sweongyo				else if (siba_get_pci_subvendor(sc->sc_dev) ==
2227203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2228204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2229204922Sweongyo				    SIBA_BOARD_BU4306)
2230203945Sweongyo					pg->pg_rfatt.att = 3;
2231203945Sweongyo				else
2232203945Sweongyo					pg->pg_rfatt.att = 1;
2233203945Sweongyo			} else {
2234204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2235203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2236204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2237203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2238204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2239203945Sweongyo					pg->pg_rfatt.att = 7;
2240203945Sweongyo				else
2241203945Sweongyo					pg->pg_rfatt.att = 6;
2242203945Sweongyo			}
2243203945Sweongyo			goto done;
2244203945Sweongyo		case 2:
2245203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2246204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2247203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2248204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2249203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2250204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2251203945Sweongyo					pg->pg_rfatt.att = 3;
2252204922Sweongyo				else if (siba_get_pci_subvendor(sc->sc_dev) ==
2253203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2254204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2255204922Sweongyo				    SIBA_BOARD_BU4306)
2256203945Sweongyo					pg->pg_rfatt.att = 5;
2257204922Sweongyo				else if (siba_get_chipid(sc->sc_dev) == 0x4320)
2258203945Sweongyo					pg->pg_rfatt.att = 4;
2259203945Sweongyo				else
2260203945Sweongyo					pg->pg_rfatt.att = 3;
2261203945Sweongyo			} else
2262203945Sweongyo				pg->pg_rfatt.att = 6;
2263203945Sweongyo			goto done;
2264203945Sweongyo		case 3:
2265203945Sweongyo			pg->pg_rfatt.att = 5;
2266203945Sweongyo			goto done;
2267203945Sweongyo		case 4:
2268203945Sweongyo		case 5:
2269203945Sweongyo			pg->pg_rfatt.att = 1;
2270203945Sweongyo			goto done;
2271203945Sweongyo		case 6:
2272203945Sweongyo		case 7:
2273203945Sweongyo			pg->pg_rfatt.att = 5;
2274203945Sweongyo			goto done;
2275203945Sweongyo		case 8:
2276203945Sweongyo			pg->pg_rfatt.att = 0xa;
2277203945Sweongyo			pg->pg_rfatt.padmix = 1;
2278203945Sweongyo			goto done;
2279203945Sweongyo		case 9:
2280203945Sweongyo		default:
2281203945Sweongyo			pg->pg_rfatt.att = 5;
2282203945Sweongyo			goto done;
2283203945Sweongyo		}
2284203945Sweongyo		break;
2285203945Sweongyo	case 0x2053:
2286203945Sweongyo		switch (phy->rf_rev) {
2287203945Sweongyo		case 1:
2288203945Sweongyo			pg->pg_rfatt.att = 6;
2289203945Sweongyo			goto done;
2290203945Sweongyo		}
2291203945Sweongyo		break;
2292203945Sweongyo	}
2293203945Sweongyo	pg->pg_rfatt.att = 5;
2294203945Sweongyodone:
2295203945Sweongyo	pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
2296203945Sweongyo
2297203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
2298203945Sweongyo		lo->rfatt.array = rfatt0;
2299203945Sweongyo		lo->rfatt.len = N(rfatt0);
2300203945Sweongyo		lo->rfatt.min = 0;
2301203945Sweongyo		lo->rfatt.max = 9;
2302203945Sweongyo		goto genbbatt;
2303203945Sweongyo	}
2304203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
2305203945Sweongyo		lo->rfatt.array = rfatt1;
2306203945Sweongyo		lo->rfatt.len = N(rfatt1);
2307203945Sweongyo		lo->rfatt.min = 0;
2308203945Sweongyo		lo->rfatt.max = 14;
2309203945Sweongyo		goto genbbatt;
2310203945Sweongyo	}
2311203945Sweongyo	lo->rfatt.array = rfatt2;
2312203945Sweongyo	lo->rfatt.len = N(rfatt2);
2313203945Sweongyo	lo->rfatt.min = 0;
2314203945Sweongyo	lo->rfatt.max = 9;
2315203945Sweongyogenbbatt:
2316203945Sweongyo	lo->bbatt.array = bbatt_0;
2317203945Sweongyo	lo->bbatt.len = N(bbatt_0);
2318203945Sweongyo	lo->bbatt.min = 0;
2319203945Sweongyo	lo->bbatt.max = 8;
2320203945Sweongyo
2321203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
2322203945Sweongyo	if (phy->rev == 1) {
2323203945Sweongyo		phy->gmode = 0;
2324203945Sweongyo		bwn_reset_core(mac, 0);
2325203945Sweongyo		bwn_phy_g_init_sub(mac);
2326203945Sweongyo		phy->gmode = 1;
2327203945Sweongyo		bwn_reset_core(mac, BWN_TGSLOW_SUPPORT_G);
2328203945Sweongyo	}
2329203945Sweongyo	return (0);
2330203945Sweongyo}
2331203945Sweongyo
2332203945Sweongyostatic uint16_t
2333203945Sweongyobwn_phy_g_txctl(struct bwn_mac *mac)
2334203945Sweongyo{
2335203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2336203945Sweongyo
2337203945Sweongyo	if (phy->rf_ver != 0x2050)
2338203945Sweongyo		return (0);
2339203945Sweongyo	if (phy->rf_rev == 1)
2340203945Sweongyo		return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
2341203945Sweongyo	if (phy->rf_rev < 6)
2342203945Sweongyo		return (BWN_TXCTL_PA2DB);
2343203945Sweongyo	if (phy->rf_rev == 8)
2344203945Sweongyo		return (BWN_TXCTL_TXMIX);
2345203945Sweongyo	return (0);
2346203945Sweongyo}
2347203945Sweongyo
2348203945Sweongyostatic int
2349203945Sweongyobwn_phy_g_init(struct bwn_mac *mac)
2350203945Sweongyo{
2351203945Sweongyo
2352203945Sweongyo	bwn_phy_g_init_sub(mac);
2353203945Sweongyo	return (0);
2354203945Sweongyo}
2355203945Sweongyo
2356203945Sweongyostatic void
2357203945Sweongyobwn_phy_g_exit(struct bwn_mac *mac)
2358203945Sweongyo{
2359203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
2360203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2361203945Sweongyo
2362203945Sweongyo	if (lo == NULL)
2363203945Sweongyo		return;
2364203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2365203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2366203945Sweongyo		free(cal, M_DEVBUF);
2367203945Sweongyo	}
2368203945Sweongyo}
2369203945Sweongyo
2370203945Sweongyostatic uint16_t
2371203945Sweongyobwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
2372203945Sweongyo{
2373203945Sweongyo
2374203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2375203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
2376203945Sweongyo}
2377203945Sweongyo
2378203945Sweongyostatic void
2379203945Sweongyobwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2380203945Sweongyo{
2381203945Sweongyo
2382203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2383203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
2384203945Sweongyo}
2385203945Sweongyo
2386203945Sweongyostatic uint16_t
2387203945Sweongyobwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
2388203945Sweongyo{
2389203945Sweongyo
2390203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2391203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
2392203945Sweongyo	return (BWN_READ_2(mac, BWN_RFDATALO));
2393203945Sweongyo}
2394203945Sweongyo
2395203945Sweongyostatic void
2396203945Sweongyobwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2397203945Sweongyo{
2398203945Sweongyo
2399203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2400203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
2401203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
2402203945Sweongyo}
2403203945Sweongyo
2404203945Sweongyostatic int
2405203945Sweongyobwn_phy_g_hwpctl(struct bwn_mac *mac)
2406203945Sweongyo{
2407203945Sweongyo
2408203945Sweongyo	return (mac->mac_phy.rev >= 6);
2409203945Sweongyo}
2410203945Sweongyo
2411203945Sweongyostatic void
2412203945Sweongyobwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
2413203945Sweongyo{
2414203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2415203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2416203945Sweongyo	unsigned int channel;
2417203945Sweongyo	uint16_t rfover, rfoverval;
2418203945Sweongyo
2419203945Sweongyo	if (on) {
2420203945Sweongyo		if (phy->rf_on)
2421203945Sweongyo			return;
2422203945Sweongyo
2423203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0x8000);
2424203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0xcc00);
2425203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
2426203945Sweongyo		if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
2427203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
2428203945Sweongyo			    pg->pg_radioctx_over);
2429203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
2430203945Sweongyo			    pg->pg_radioctx_overval);
2431203945Sweongyo			pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
2432203945Sweongyo		}
2433203945Sweongyo		channel = phy->chan;
2434203945Sweongyo		bwn_phy_g_switch_chan(mac, 6, 1);
2435203945Sweongyo		bwn_phy_g_switch_chan(mac, channel, 0);
2436203945Sweongyo		return;
2437203945Sweongyo	}
2438203945Sweongyo
2439203945Sweongyo	rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
2440203945Sweongyo	rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
2441203945Sweongyo	pg->pg_radioctx_over = rfover;
2442203945Sweongyo	pg->pg_radioctx_overval = rfoverval;
2443203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
2444203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
2445203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
2446203945Sweongyo}
2447203945Sweongyo
2448203945Sweongyostatic int
2449203945Sweongyobwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
2450203945Sweongyo{
2451203945Sweongyo
2452203945Sweongyo	if ((newchan < 1) || (newchan > 14))
2453203945Sweongyo		return (EINVAL);
2454203945Sweongyo	bwn_phy_g_switch_chan(mac, newchan, 0);
2455203945Sweongyo
2456203945Sweongyo	return (0);
2457203945Sweongyo}
2458203945Sweongyo
2459203945Sweongyostatic uint32_t
2460203945Sweongyobwn_phy_g_get_default_chan(struct bwn_mac *mac)
2461203945Sweongyo{
2462203945Sweongyo
2463203945Sweongyo	return (1);
2464203945Sweongyo}
2465203945Sweongyo
2466203945Sweongyostatic void
2467203945Sweongyobwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
2468203945Sweongyo{
2469203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2470203945Sweongyo	uint64_t hf;
2471203945Sweongyo	int autodiv = 0;
2472203945Sweongyo	uint16_t tmp;
2473203945Sweongyo
2474203945Sweongyo	if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
2475203945Sweongyo		autodiv = 1;
2476203945Sweongyo
2477203945Sweongyo	hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
2478203945Sweongyo	bwn_hf_write(mac, hf);
2479203945Sweongyo
2480203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
2481203945Sweongyo	    (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
2482203945Sweongyo	    ((autodiv ? BWN_ANTAUTO1 : antenna)
2483203945Sweongyo		<< BWN_PHY_BBANDCFG_RXANT_SHIFT));
2484203945Sweongyo
2485203945Sweongyo	if (autodiv) {
2486203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
2487203945Sweongyo		if (antenna == BWN_ANTAUTO1)
2488203945Sweongyo			tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
2489203945Sweongyo		else
2490203945Sweongyo			tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
2491203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
2492203945Sweongyo	}
2493203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
2494203945Sweongyo	if (autodiv)
2495203945Sweongyo		tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
2496203945Sweongyo	else
2497203945Sweongyo		tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
2498203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
2499203945Sweongyo	if (phy->rev >= 2) {
2500203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
2501203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
2502203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
2503203945Sweongyo		    (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
2504203945Sweongyo		    0x15);
2505203945Sweongyo		if (phy->rev == 2)
2506203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
2507203945Sweongyo		else
2508203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
2509203945Sweongyo			    (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
2510203945Sweongyo			    8);
2511203945Sweongyo	}
2512203945Sweongyo	if (phy->rev >= 6)
2513203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
2514203945Sweongyo
2515203945Sweongyo	hf |= BWN_HF_UCODE_ANTDIV_HELPER;
2516203945Sweongyo	bwn_hf_write(mac, hf);
2517203945Sweongyo}
2518203945Sweongyo
2519203945Sweongyostatic int
2520203945Sweongyobwn_phy_g_im(struct bwn_mac *mac, int mode)
2521203945Sweongyo{
2522203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2523203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2524203945Sweongyo
2525203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2526203945Sweongyo	KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
2527203945Sweongyo
2528203945Sweongyo	if (phy->rev == 0 || !phy->gmode)
2529203945Sweongyo		return (ENODEV);
2530203945Sweongyo
2531203945Sweongyo	pg->pg_aci_wlan_automatic = 0;
2532203945Sweongyo	return (0);
2533203945Sweongyo}
2534203945Sweongyo
2535203945Sweongyostatic int
2536203945Sweongyobwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
2537203945Sweongyo{
2538203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2539203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2540203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2541203945Sweongyo	unsigned int tssi;
2542203945Sweongyo	int cck, ofdm;
2543203945Sweongyo	int power;
2544203945Sweongyo	int rfatt, bbatt;
2545203945Sweongyo	unsigned int max;
2546203945Sweongyo
2547203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2548203945Sweongyo
2549203945Sweongyo	cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
2550203945Sweongyo	ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
2551203945Sweongyo	if (cck < 0 && ofdm < 0) {
2552203945Sweongyo		if (ignore_tssi == 0)
2553203945Sweongyo			return (BWN_TXPWR_RES_DONE);
2554203945Sweongyo		cck = 0;
2555203945Sweongyo		ofdm = 0;
2556203945Sweongyo	}
2557203945Sweongyo	tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
2558203945Sweongyo	if (pg->pg_avgtssi != 0xff)
2559203945Sweongyo		tssi = (tssi + pg->pg_avgtssi) / 2;
2560203945Sweongyo	pg->pg_avgtssi = tssi;
2561203945Sweongyo	KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
2562203945Sweongyo
2563204922Sweongyo	max = siba_sprom_get_maxpwr_bg(sc->sc_dev);
2564204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
2565203945Sweongyo		max -= 3;
2566203945Sweongyo	if (max >= 120) {
2567203945Sweongyo		device_printf(sc->sc_dev, "invalid max TX-power value\n");
2568204922Sweongyo		max = 80;
2569204922Sweongyo		siba_sprom_set_maxpwr_bg(sc->sc_dev, max);
2570203945Sweongyo	}
2571203945Sweongyo
2572203945Sweongyo	power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
2573203945Sweongyo	    (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
2574203945Sweongyo	     tssi, 0x00), 0x3f)]);
2575203945Sweongyo	if (power == 0)
2576203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2577203945Sweongyo
2578203945Sweongyo	rfatt = -((power + 7) / 8);
2579203945Sweongyo	bbatt = (-(power / 2)) - (4 * rfatt);
2580203945Sweongyo	if ((rfatt == 0) && (bbatt == 0))
2581203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2582203945Sweongyo	pg->pg_bbatt_delta = bbatt;
2583203945Sweongyo	pg->pg_rfatt_delta = rfatt;
2584203945Sweongyo	return (BWN_TXPWR_RES_NEED_ADJUST);
2585203945Sweongyo}
2586203945Sweongyo
2587203945Sweongyostatic void
2588203945Sweongyobwn_phy_g_set_txpwr(struct bwn_mac *mac)
2589203945Sweongyo{
2590203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2591203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2592203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2593203945Sweongyo	int rfatt, bbatt;
2594203945Sweongyo	uint8_t txctl;
2595203945Sweongyo
2596203945Sweongyo	bwn_mac_suspend(mac);
2597203945Sweongyo
2598203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2599203945Sweongyo
2600203945Sweongyo	bbatt = pg->pg_bbatt.att;
2601203945Sweongyo	bbatt += pg->pg_bbatt_delta;
2602203945Sweongyo	rfatt = pg->pg_rfatt.att;
2603203945Sweongyo	rfatt += pg->pg_rfatt_delta;
2604203945Sweongyo
2605203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2606203945Sweongyo	txctl = pg->pg_txctl;
2607203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
2608203945Sweongyo		if (rfatt <= 1) {
2609203945Sweongyo			if (txctl == 0) {
2610203945Sweongyo				txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
2611203945Sweongyo				rfatt += 2;
2612203945Sweongyo				bbatt += 2;
2613204922Sweongyo			} else if (siba_sprom_get_bf_lo(sc->sc_dev) &
2614204922Sweongyo			    BWN_BFL_PACTRL) {
2615203945Sweongyo				bbatt += 4 * (rfatt - 2);
2616203945Sweongyo				rfatt = 2;
2617203945Sweongyo			}
2618203945Sweongyo		} else if (rfatt > 4 && txctl) {
2619203945Sweongyo			txctl = 0;
2620203945Sweongyo			if (bbatt < 3) {
2621203945Sweongyo				rfatt -= 3;
2622203945Sweongyo				bbatt += 2;
2623203945Sweongyo			} else {
2624203945Sweongyo				rfatt -= 2;
2625203945Sweongyo				bbatt -= 2;
2626203945Sweongyo			}
2627203945Sweongyo		}
2628203945Sweongyo	}
2629203945Sweongyo	pg->pg_txctl = txctl;
2630203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2631203945Sweongyo	pg->pg_rfatt.att = rfatt;
2632203945Sweongyo	pg->pg_bbatt.att = bbatt;
2633203945Sweongyo
2634203945Sweongyo	DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
2635203945Sweongyo
2636203945Sweongyo	bwn_phy_lock(mac);
2637203945Sweongyo	bwn_rf_lock(mac);
2638203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
2639203945Sweongyo	    pg->pg_txctl);
2640203945Sweongyo	bwn_rf_unlock(mac);
2641203945Sweongyo	bwn_phy_unlock(mac);
2642203945Sweongyo
2643203945Sweongyo	bwn_mac_enable(mac);
2644203945Sweongyo}
2645203945Sweongyo
2646203945Sweongyostatic void
2647203945Sweongyobwn_phy_g_task_15s(struct bwn_mac *mac)
2648203945Sweongyo{
2649203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2650203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2651203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2652203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2653203945Sweongyo	unsigned long expire, now;
2654203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2655203945Sweongyo	uint8_t expired = 0;
2656203945Sweongyo
2657203945Sweongyo	bwn_mac_suspend(mac);
2658203945Sweongyo
2659203945Sweongyo	if (lo == NULL)
2660203945Sweongyo		goto fail;
2661203945Sweongyo
2662203945Sweongyo	BWN_GETTIME(now);
2663203945Sweongyo	if (bwn_has_hwpctl(mac)) {
2664203945Sweongyo		expire = now - BWN_LO_PWRVEC_EXPIRE;
2665203945Sweongyo		if (time_before(lo->pwr_vec_read_time, expire)) {
2666203945Sweongyo			bwn_lo_get_powervector(mac);
2667203945Sweongyo			bwn_phy_g_dc_lookup_init(mac, 0);
2668203945Sweongyo		}
2669203945Sweongyo		goto fail;
2670203945Sweongyo	}
2671203945Sweongyo
2672203945Sweongyo	expire = now - BWN_LO_CALIB_EXPIRE;
2673203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2674203945Sweongyo		if (!time_before(cal->calib_time, expire))
2675203945Sweongyo			continue;
2676203945Sweongyo		if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
2677203945Sweongyo		    BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
2678203945Sweongyo			KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
2679203945Sweongyo			expired = 1;
2680203945Sweongyo		}
2681203945Sweongyo
2682203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
2683203945Sweongyo		    cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
2684203945Sweongyo		    cal->ctl.i, cal->ctl.q);
2685203945Sweongyo
2686203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2687203945Sweongyo		free(cal, M_DEVBUF);
2688203945Sweongyo	}
2689203945Sweongyo	if (expired || TAILQ_EMPTY(&lo->calib_list)) {
2690203945Sweongyo		cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
2691203945Sweongyo		    &pg->pg_rfatt);
2692203945Sweongyo		if (cal == NULL) {
2693203945Sweongyo			device_printf(sc->sc_dev,
2694203945Sweongyo			    "failed to recalibrate LO\n");
2695203945Sweongyo			goto fail;
2696203945Sweongyo		}
2697203945Sweongyo		TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
2698203945Sweongyo		bwn_lo_write(mac, &cal->ctl);
2699203945Sweongyo	}
2700203945Sweongyo
2701203945Sweongyofail:
2702203945Sweongyo	bwn_mac_enable(mac);
2703203945Sweongyo}
2704203945Sweongyo
2705203945Sweongyostatic void
2706203945Sweongyobwn_phy_g_task_60s(struct bwn_mac *mac)
2707203945Sweongyo{
2708203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2709204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2710203945Sweongyo	uint8_t old = phy->chan;
2711203945Sweongyo
2712204922Sweongyo	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI))
2713203945Sweongyo		return;
2714203945Sweongyo
2715203945Sweongyo	bwn_mac_suspend(mac);
2716203945Sweongyo	bwn_nrssi_slope_11g(mac);
2717203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
2718203945Sweongyo		bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
2719203945Sweongyo		bwn_switch_channel(mac, old);
2720203945Sweongyo	}
2721203945Sweongyo	bwn_mac_enable(mac);
2722203945Sweongyo}
2723203945Sweongyo
2724203945Sweongyostatic void
2725203945Sweongyobwn_phy_switch_analog(struct bwn_mac *mac, int on)
2726203945Sweongyo{
2727203945Sweongyo
2728203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
2729203945Sweongyo}
2730203945Sweongyo
2731203945Sweongyostatic int
2732203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
2733203945Sweongyo	const struct ieee80211_bpf_params *params)
2734203945Sweongyo{
2735203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2736203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2737203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2738203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2739203945Sweongyo
2740203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
2741203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
2742203945Sweongyo		ieee80211_free_node(ni);
2743203945Sweongyo		m_freem(m);
2744203945Sweongyo		return (ENETDOWN);
2745203945Sweongyo	}
2746203945Sweongyo
2747203945Sweongyo	BWN_LOCK(sc);
2748203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
2749203945Sweongyo		ieee80211_free_node(ni);
2750203945Sweongyo		m_freem(m);
2751203945Sweongyo		ifp->if_oerrors++;
2752203945Sweongyo		BWN_UNLOCK(sc);
2753203945Sweongyo		return (ENOBUFS);
2754203945Sweongyo	}
2755203945Sweongyo
2756203945Sweongyo	if (bwn_tx_start(sc, ni, m) != 0) {
2757203945Sweongyo		if (ni != NULL)
2758203945Sweongyo			ieee80211_free_node(ni);
2759203945Sweongyo		ifp->if_oerrors++;
2760203945Sweongyo	}
2761203945Sweongyo	sc->sc_watchdog_timer = 5;
2762203945Sweongyo	BWN_UNLOCK(sc);
2763203945Sweongyo	return (0);
2764203945Sweongyo}
2765203945Sweongyo
2766203945Sweongyo/*
2767203945Sweongyo * Callback from the 802.11 layer to update the slot time
2768203945Sweongyo * based on the current setting.  We use it to notify the
2769203945Sweongyo * firmware of ERP changes and the f/w takes care of things
2770203945Sweongyo * like slot time and preamble.
2771203945Sweongyo */
2772203945Sweongyostatic void
2773203945Sweongyobwn_updateslot(struct ifnet *ifp)
2774203945Sweongyo{
2775203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2776203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
2777203945Sweongyo	struct bwn_mac *mac;
2778203945Sweongyo
2779203945Sweongyo	BWN_LOCK(sc);
2780203945Sweongyo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2781203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
2782203945Sweongyo		bwn_set_slot_time(mac,
2783203945Sweongyo		    (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20);
2784203945Sweongyo	}
2785203945Sweongyo	BWN_UNLOCK(sc);
2786203945Sweongyo}
2787203945Sweongyo
2788203945Sweongyo/*
2789203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
2790203945Sweongyo * Note this interface does not check the operating mode as this
2791203945Sweongyo * is an internal callback and we are expected to honor the current
2792203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
2793203945Sweongyo * mode when operating in hostap mode to do ACS).
2794203945Sweongyo */
2795203945Sweongyostatic void
2796203945Sweongyobwn_update_promisc(struct ifnet *ifp)
2797203945Sweongyo{
2798203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2799203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2800203945Sweongyo
2801203945Sweongyo	BWN_LOCK(sc);
2802203945Sweongyo	mac = sc->sc_curmac;
2803203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2804203945Sweongyo		if (ifp->if_flags & IFF_PROMISC)
2805203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
2806203945Sweongyo		else
2807203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
2808203945Sweongyo		bwn_set_opmode(mac);
2809203945Sweongyo	}
2810203945Sweongyo	BWN_UNLOCK(sc);
2811203945Sweongyo}
2812203945Sweongyo
2813203945Sweongyo/*
2814203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
2815203945Sweongyo */
2816203945Sweongyostatic int
2817203945Sweongyobwn_wme_update(struct ieee80211com *ic)
2818203945Sweongyo{
2819203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2820203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2821203945Sweongyo	struct wmeParams *wmep;
2822203945Sweongyo	int i;
2823203945Sweongyo
2824203945Sweongyo	BWN_LOCK(sc);
2825203945Sweongyo	mac = sc->sc_curmac;
2826203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2827203945Sweongyo		bwn_mac_suspend(mac);
2828203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
2829203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
2830203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
2831203945Sweongyo		}
2832203945Sweongyo		bwn_mac_enable(mac);
2833203945Sweongyo	}
2834203945Sweongyo	BWN_UNLOCK(sc);
2835203945Sweongyo	return (0);
2836203945Sweongyo}
2837203945Sweongyo
2838203945Sweongyostatic void
2839203945Sweongyobwn_scan_start(struct ieee80211com *ic)
2840203945Sweongyo{
2841203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2842203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2843203945Sweongyo	struct bwn_mac *mac;
2844203945Sweongyo
2845203945Sweongyo	BWN_LOCK(sc);
2846203945Sweongyo	mac = sc->sc_curmac;
2847203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2848203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
2849203945Sweongyo		bwn_set_opmode(mac);
2850203945Sweongyo		/* disable CFP update during scan */
2851203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
2852203945Sweongyo	}
2853203945Sweongyo	BWN_UNLOCK(sc);
2854203945Sweongyo}
2855203945Sweongyo
2856203945Sweongyostatic void
2857203945Sweongyobwn_scan_end(struct ieee80211com *ic)
2858203945Sweongyo{
2859203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2860203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2861203945Sweongyo	struct bwn_mac *mac;
2862203945Sweongyo
2863203945Sweongyo	BWN_LOCK(sc);
2864203945Sweongyo	mac = sc->sc_curmac;
2865203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2866203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
2867203945Sweongyo		bwn_set_opmode(mac);
2868203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
2869203945Sweongyo	}
2870203945Sweongyo	BWN_UNLOCK(sc);
2871203945Sweongyo}
2872203945Sweongyo
2873203945Sweongyostatic void
2874203945Sweongyobwn_set_channel(struct ieee80211com *ic)
2875203945Sweongyo{
2876203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2877203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2878203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2879203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2880203945Sweongyo	int chan, error;
2881203945Sweongyo
2882203945Sweongyo	BWN_LOCK(sc);
2883203945Sweongyo
2884203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
2885203945Sweongyo	if (error)
2886216227Skevlo		goto fail;
2887203945Sweongyo	bwn_mac_suspend(mac);
2888203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2889203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
2890203945Sweongyo	if (chan != phy->chan)
2891203945Sweongyo		bwn_switch_channel(mac, chan);
2892203945Sweongyo
2893203945Sweongyo	/* TX power level */
2894203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
2895203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
2896203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
2897203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
2898203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
2899203945Sweongyo	}
2900203945Sweongyo
2901203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2902203945Sweongyo	if (phy->set_antenna)
2903203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2904203945Sweongyo
2905203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
2906203945Sweongyo		if (sc->sc_rf_enabled) {
2907203945Sweongyo			bwn_rf_turnon(mac);
2908203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
2909203945Sweongyo				device_printf(sc->sc_dev,
2910213719Sjoel				    "please turn on the RF switch\n");
2911203945Sweongyo		} else
2912203945Sweongyo			bwn_rf_turnoff(mac);
2913203945Sweongyo	}
2914203945Sweongyo
2915203945Sweongyo	bwn_mac_enable(mac);
2916203945Sweongyo
2917203945Sweongyofail:
2918203945Sweongyo	/*
2919203945Sweongyo	 * Setup radio tap channel freq and flags
2920203945Sweongyo	 */
2921203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
2922203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
2923203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
2924203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
2925203945Sweongyo
2926203945Sweongyo	BWN_UNLOCK(sc);
2927203945Sweongyo}
2928203945Sweongyo
2929203945Sweongyostatic struct ieee80211vap *
2930228621Sbschmidtbwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
2931228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
2932228621Sbschmidt    const uint8_t bssid[IEEE80211_ADDR_LEN],
2933228621Sbschmidt    const uint8_t mac0[IEEE80211_ADDR_LEN])
2934203945Sweongyo{
2935203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2936203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2937203945Sweongyo	struct ieee80211vap *vap;
2938203945Sweongyo	struct bwn_vap *bvp;
2939203945Sweongyo	uint8_t mac[IEEE80211_ADDR_LEN];
2940203945Sweongyo
2941203945Sweongyo	IEEE80211_ADDR_COPY(mac, mac0);
2942203945Sweongyo	switch (opmode) {
2943203945Sweongyo	case IEEE80211_M_HOSTAP:
2944203945Sweongyo	case IEEE80211_M_MBSS:
2945203945Sweongyo	case IEEE80211_M_STA:
2946203945Sweongyo	case IEEE80211_M_WDS:
2947203945Sweongyo	case IEEE80211_M_MONITOR:
2948203945Sweongyo	case IEEE80211_M_IBSS:
2949203945Sweongyo	case IEEE80211_M_AHDEMO:
2950203945Sweongyo		break;
2951203945Sweongyo	default:
2952203945Sweongyo		return (NULL);
2953203945Sweongyo	}
2954203945Sweongyo
2955203945Sweongyo	IEEE80211_ADDR_COPY(sc->sc_macaddr, mac0);
2956203945Sweongyo
2957203945Sweongyo	bvp = (struct bwn_vap *) malloc(sizeof(struct bwn_vap),
2958203945Sweongyo	    M_80211_VAP, M_NOWAIT | M_ZERO);
2959203945Sweongyo	if (bvp == NULL) {
2960203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate a buffer\n");
2961203945Sweongyo		return (NULL);
2962203945Sweongyo	}
2963203945Sweongyo	vap = &bvp->bv_vap;
2964203945Sweongyo	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
2965203945Sweongyo	IEEE80211_ADDR_COPY(vap->iv_myaddr, mac);
2966203945Sweongyo	/* override with driver methods */
2967203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
2968203945Sweongyo	vap->iv_newstate = bwn_newstate;
2969203945Sweongyo
2970203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
2971203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
2972203945Sweongyo
2973206358Srpaulo	ieee80211_ratectl_init(vap);
2974203945Sweongyo
2975203945Sweongyo	/* complete setup */
2976203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
2977203945Sweongyo	    ieee80211_media_status);
2978203945Sweongyo	return (vap);
2979203945Sweongyo}
2980203945Sweongyo
2981203945Sweongyostatic void
2982203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
2983203945Sweongyo{
2984203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
2985203945Sweongyo
2986206358Srpaulo	ieee80211_ratectl_deinit(vap);
2987203945Sweongyo	ieee80211_vap_detach(vap);
2988203945Sweongyo	free(bvp, M_80211_VAP);
2989203945Sweongyo}
2990203945Sweongyo
2991203945Sweongyostatic void
2992203945Sweongyobwn_init(void *arg)
2993203945Sweongyo{
2994203945Sweongyo	struct bwn_softc *sc = arg;
2995203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
2996203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
2997203945Sweongyo	int error = 0;
2998203945Sweongyo
2999203945Sweongyo	DPRINTF(sc, BWN_DEBUG_ANY, "%s: if_flags 0x%x\n",
3000203945Sweongyo		__func__, ifp->if_flags);
3001203945Sweongyo
3002203945Sweongyo	BWN_LOCK(sc);
3003203945Sweongyo	error = bwn_init_locked(sc);
3004203945Sweongyo	BWN_UNLOCK(sc);
3005203945Sweongyo
3006203945Sweongyo	if (error == 0)
3007203945Sweongyo		ieee80211_start_all(ic);	/* start all vap's */
3008203945Sweongyo}
3009203945Sweongyo
3010203945Sweongyostatic int
3011203945Sweongyobwn_init_locked(struct bwn_softc *sc)
3012203945Sweongyo{
3013203945Sweongyo	struct bwn_mac *mac;
3014203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3015203945Sweongyo	int error;
3016203945Sweongyo
3017203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3018203945Sweongyo
3019203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
3020203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
3021203945Sweongyo	sc->sc_filters = 0;
3022203945Sweongyo	bwn_wme_clear(sc);
3023203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
3024203945Sweongyo	sc->sc_rf_enabled = 1;
3025203945Sweongyo
3026203945Sweongyo	mac = sc->sc_curmac;
3027203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
3028203945Sweongyo		error = bwn_core_init(mac);
3029203945Sweongyo		if (error != 0)
3030203945Sweongyo			return (error);
3031203945Sweongyo	}
3032203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
3033203945Sweongyo		bwn_core_start(mac);
3034203945Sweongyo
3035203945Sweongyo	bwn_set_opmode(mac);
3036203945Sweongyo	bwn_set_pretbtt(mac);
3037203945Sweongyo	bwn_spu_setdelay(mac, 0);
3038203945Sweongyo	bwn_set_macaddr(mac);
3039203945Sweongyo
3040203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3041203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
3042203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
3043203945Sweongyo
3044203945Sweongyo	return (0);
3045203945Sweongyo}
3046203945Sweongyo
3047203945Sweongyostatic void
3048203945Sweongyobwn_stop(struct bwn_softc *sc, int statechg)
3049203945Sweongyo{
3050203945Sweongyo
3051203945Sweongyo	BWN_LOCK(sc);
3052203945Sweongyo	bwn_stop_locked(sc, statechg);
3053203945Sweongyo	BWN_UNLOCK(sc);
3054203945Sweongyo}
3055203945Sweongyo
3056203945Sweongyostatic void
3057203945Sweongyobwn_stop_locked(struct bwn_softc *sc, int statechg)
3058203945Sweongyo{
3059203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
3060203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3061203945Sweongyo
3062203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3063203945Sweongyo
3064203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
3065203945Sweongyo		/* XXX FIXME opmode not based on VAP */
3066203945Sweongyo		bwn_set_opmode(mac);
3067203945Sweongyo		bwn_set_macaddr(mac);
3068203945Sweongyo	}
3069203945Sweongyo
3070203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
3071203945Sweongyo		bwn_core_stop(mac);
3072203945Sweongyo
3073203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
3074203945Sweongyo	sc->sc_led_blinking = 0;
3075203945Sweongyo
3076203945Sweongyo	bwn_core_exit(mac);
3077203945Sweongyo	sc->sc_rf_enabled = 0;
3078203945Sweongyo
3079203945Sweongyo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3080203945Sweongyo}
3081203945Sweongyo
3082203945Sweongyostatic void
3083203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
3084203945Sweongyo{
3085203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
3086203945Sweongyo	struct wmeParams *p;
3087203945Sweongyo	unsigned int i;
3088203945Sweongyo
3089203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
3090203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3091203945Sweongyo
3092203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
3093203945Sweongyo		p = &(sc->sc_wmeParams[i]);
3094203945Sweongyo
3095203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
3096203945Sweongyo		case BWN_WME_VOICE:
3097203945Sweongyo			p->wmep_txopLimit = 0;
3098203945Sweongyo			p->wmep_aifsn = 2;
3099203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3100203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3101203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3102203945Sweongyo			break;
3103203945Sweongyo		case BWN_WME_VIDEO:
3104203945Sweongyo			p->wmep_txopLimit = 0;
3105203945Sweongyo			p->wmep_aifsn = 2;
3106203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3107203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3108203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3109203945Sweongyo			break;
3110203945Sweongyo		case BWN_WME_BESTEFFORT:
3111203945Sweongyo			p->wmep_txopLimit = 0;
3112203945Sweongyo			p->wmep_aifsn = 3;
3113203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3114203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3115203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3116203945Sweongyo			break;
3117203945Sweongyo		case BWN_WME_BACKGROUND:
3118203945Sweongyo			p->wmep_txopLimit = 0;
3119203945Sweongyo			p->wmep_aifsn = 7;
3120203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3121203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3122203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3123203945Sweongyo			break;
3124203945Sweongyo		default:
3125203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3126203945Sweongyo		}
3127203945Sweongyo	}
3128203945Sweongyo}
3129203945Sweongyo
3130203945Sweongyostatic int
3131203945Sweongyobwn_core_init(struct bwn_mac *mac)
3132203945Sweongyo{
3133203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3134203945Sweongyo	uint64_t hf;
3135203945Sweongyo	int error;
3136203945Sweongyo
3137203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3138203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3139203945Sweongyo
3140204922Sweongyo	siba_powerup(sc->sc_dev, 0);
3141204922Sweongyo	if (!siba_dev_isup(sc->sc_dev))
3142203945Sweongyo		bwn_reset_core(mac,
3143203945Sweongyo		    mac->mac_phy.gmode ? BWN_TGSLOW_SUPPORT_G : 0);
3144203945Sweongyo
3145203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
3146203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
3147203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
3148203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
3149203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
3150203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
3151203945Sweongyo	mac->mac_stats.link_noise = -95;
3152203945Sweongyo	mac->mac_reason_intr = 0;
3153203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
3154203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
3155203945Sweongyo#ifdef BWN_DEBUG
3156203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
3157203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
3158203945Sweongyo#endif
3159203945Sweongyo	mac->mac_suspended = 1;
3160203945Sweongyo	mac->mac_task_state = 0;
3161203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
3162203945Sweongyo
3163203945Sweongyo	mac->mac_phy.init_pre(mac);
3164203945Sweongyo
3165204922Sweongyo	siba_pcicore_intr(sc->sc_dev);
3166203945Sweongyo
3167204922Sweongyo	siba_fix_imcfglobug(sc->sc_dev);
3168203945Sweongyo	bwn_bt_disable(mac);
3169203945Sweongyo	if (mac->mac_phy.prepare_hw) {
3170203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
3171203945Sweongyo		if (error)
3172203945Sweongyo			goto fail0;
3173203945Sweongyo	}
3174203945Sweongyo	error = bwn_chip_init(mac);
3175203945Sweongyo	if (error)
3176203945Sweongyo		goto fail0;
3177203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
3178204922Sweongyo	    siba_get_revid(sc->sc_dev));
3179203945Sweongyo	hf = bwn_hf_read(mac);
3180203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
3181203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
3182204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
3183203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
3184203945Sweongyo		if (mac->mac_phy.rev == 1)
3185203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
3186203945Sweongyo	}
3187203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
3188203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
3189203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
3190203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
3191203945Sweongyo			hf |= BWN_HF_4318_TSSI;
3192203945Sweongyo	}
3193204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW)
3194203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
3195204922Sweongyo	if ((siba_get_type(sc->sc_dev) == SIBA_TYPE_PCI) &&
3196204922Sweongyo	    (siba_get_pcicore_revid(sc->sc_dev) <= 10))
3197203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
3198203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
3199203945Sweongyo	bwn_hf_write(mac, hf);
3200203945Sweongyo
3201203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
3202203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
3203203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
3204203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
3205203945Sweongyo
3206203945Sweongyo	bwn_rate_init(mac);
3207203945Sweongyo	bwn_set_phytxctl(mac);
3208203945Sweongyo
3209203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
3210203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
3211203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
3212203945Sweongyo
3213204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
3214203945Sweongyo		bwn_pio_init(mac);
3215203945Sweongyo	else
3216203945Sweongyo		bwn_dma_init(mac);
3217203945Sweongyo	bwn_wme_init(mac);
3218203945Sweongyo	bwn_spu_setdelay(mac, 1);
3219203945Sweongyo	bwn_bt_enable(mac);
3220203945Sweongyo
3221204922Sweongyo	siba_powerup(sc->sc_dev,
3222204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW));
3223203945Sweongyo	bwn_set_macaddr(mac);
3224203945Sweongyo	bwn_crypt_init(mac);
3225203945Sweongyo
3226203945Sweongyo	/* XXX LED initializatin */
3227203945Sweongyo
3228203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
3229203945Sweongyo
3230203945Sweongyo	return (error);
3231203945Sweongyo
3232203945Sweongyofail0:
3233204922Sweongyo	siba_powerdown(sc->sc_dev);
3234203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3235203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3236203945Sweongyo	return (error);
3237203945Sweongyo}
3238203945Sweongyo
3239203945Sweongyostatic void
3240203945Sweongyobwn_core_start(struct bwn_mac *mac)
3241203945Sweongyo{
3242203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3243203945Sweongyo	uint32_t tmp;
3244203945Sweongyo
3245203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
3246203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3247203945Sweongyo
3248204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
3249203945Sweongyo		return;
3250203945Sweongyo
3251203945Sweongyo	while (1) {
3252203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
3253203945Sweongyo		if (!(tmp & 0x00000001))
3254203945Sweongyo			break;
3255203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
3256203945Sweongyo	}
3257203945Sweongyo
3258203945Sweongyo	bwn_mac_enable(mac);
3259203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
3260203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
3261203945Sweongyo
3262203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
3263203945Sweongyo}
3264203945Sweongyo
3265203945Sweongyostatic void
3266203945Sweongyobwn_core_exit(struct bwn_mac *mac)
3267203945Sweongyo{
3268204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3269203945Sweongyo	uint32_t macctl;
3270203945Sweongyo
3271204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
3272203945Sweongyo
3273203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
3274203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3275203945Sweongyo
3276203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
3277203945Sweongyo		return;
3278203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
3279203945Sweongyo
3280203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3281203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
3282203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
3283203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3284203945Sweongyo
3285203945Sweongyo	bwn_dma_stop(mac);
3286203945Sweongyo	bwn_pio_stop(mac);
3287203945Sweongyo	bwn_chip_exit(mac);
3288203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
3289204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
3290204922Sweongyo	siba_powerdown(sc->sc_dev);
3291203945Sweongyo}
3292203945Sweongyo
3293203945Sweongyostatic void
3294203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
3295203945Sweongyo{
3296203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3297203945Sweongyo
3298203945Sweongyo	(void)sc;
3299203945Sweongyo	/* XXX do nothing yet */
3300203945Sweongyo}
3301203945Sweongyo
3302203945Sweongyostatic int
3303203945Sweongyobwn_chip_init(struct bwn_mac *mac)
3304203945Sweongyo{
3305204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3306203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
3307203945Sweongyo	uint32_t macctl;
3308203945Sweongyo	int error;
3309203945Sweongyo
3310203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
3311203945Sweongyo	if (phy->gmode)
3312203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
3313203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3314203945Sweongyo
3315203945Sweongyo	error = bwn_fw_fillinfo(mac);
3316203945Sweongyo	if (error)
3317203945Sweongyo		return (error);
3318203945Sweongyo	error = bwn_fw_loaducode(mac);
3319203945Sweongyo	if (error)
3320203945Sweongyo		return (error);
3321203945Sweongyo
3322203945Sweongyo	error = bwn_gpio_init(mac);
3323203945Sweongyo	if (error)
3324203945Sweongyo		return (error);
3325203945Sweongyo
3326203945Sweongyo	error = bwn_fw_loadinitvals(mac);
3327203945Sweongyo	if (error) {
3328204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
3329203945Sweongyo		return (error);
3330203945Sweongyo	}
3331203945Sweongyo	phy->switch_analog(mac, 1);
3332203945Sweongyo	error = bwn_phy_init(mac);
3333203945Sweongyo	if (error) {
3334204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
3335203945Sweongyo		return (error);
3336203945Sweongyo	}
3337203945Sweongyo	if (phy->set_im)
3338203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
3339203945Sweongyo	if (phy->set_antenna)
3340203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
3341203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
3342203945Sweongyo
3343203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
3344203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
3345203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
3346204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
3347203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
3348203945Sweongyo
3349203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3350203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
3351203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3352203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
3353203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
3354203945Sweongyo
3355203945Sweongyo	bwn_set_opmode(mac);
3356204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 3) {
3357203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
3358203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
3359203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
3360203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
3361203945Sweongyo	} else {
3362203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
3363203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
3364203945Sweongyo	}
3365203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
3366203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
3367203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
3368203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
3369203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
3370203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
3371203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
3372204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
3373204922Sweongyo	    siba_read_4(sc->sc_dev, SIBA_TGSLOW) | 0x00100000);
3374204922Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev));
3375203945Sweongyo	return (error);
3376203945Sweongyo}
3377203945Sweongyo
3378203945Sweongyo/* read hostflags */
3379203945Sweongyostatic uint64_t
3380203945Sweongyobwn_hf_read(struct bwn_mac *mac)
3381203945Sweongyo{
3382203945Sweongyo	uint64_t ret;
3383203945Sweongyo
3384203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
3385203945Sweongyo	ret <<= 16;
3386203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
3387203945Sweongyo	ret <<= 16;
3388203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
3389203945Sweongyo	return (ret);
3390203945Sweongyo}
3391203945Sweongyo
3392203945Sweongyostatic void
3393203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
3394203945Sweongyo{
3395203945Sweongyo
3396203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
3397203945Sweongyo	    (value & 0x00000000ffffull));
3398203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
3399203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
3400203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
3401203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
3402203945Sweongyo}
3403203945Sweongyo
3404203945Sweongyostatic void
3405203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
3406203945Sweongyo{
3407203945Sweongyo
3408203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
3409203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
3410203945Sweongyo}
3411203945Sweongyo
3412203945Sweongyostatic void
3413203945Sweongyobwn_rate_init(struct bwn_mac *mac)
3414203945Sweongyo{
3415203945Sweongyo
3416203945Sweongyo	switch (mac->mac_phy.type) {
3417203945Sweongyo	case BWN_PHYTYPE_A:
3418203945Sweongyo	case BWN_PHYTYPE_G:
3419203945Sweongyo	case BWN_PHYTYPE_LP:
3420203945Sweongyo	case BWN_PHYTYPE_N:
3421203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
3422203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
3423203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
3424203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
3425203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
3426203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
3427203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
3428203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
3429203945Sweongyo			break;
3430203945Sweongyo		/* FALLTHROUGH */
3431203945Sweongyo	case BWN_PHYTYPE_B:
3432203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
3433203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
3434203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
3435203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
3436203945Sweongyo		break;
3437203945Sweongyo	default:
3438203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3439203945Sweongyo	}
3440203945Sweongyo}
3441203945Sweongyo
3442203945Sweongyostatic void
3443203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
3444203945Sweongyo{
3445203945Sweongyo	uint16_t offset;
3446203945Sweongyo
3447203945Sweongyo	if (ofdm) {
3448203945Sweongyo		offset = 0x480;
3449203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
3450203945Sweongyo	} else {
3451203945Sweongyo		offset = 0x4c0;
3452203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
3453203945Sweongyo	}
3454203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
3455203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
3456203945Sweongyo}
3457203945Sweongyo
3458203945Sweongyostatic uint8_t
3459203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
3460203945Sweongyo{
3461203945Sweongyo
3462203945Sweongyo	switch (bitrate) {
3463203945Sweongyo	case BWN_CCK_RATE_1MB:
3464203945Sweongyo		return (0x0a);
3465203945Sweongyo	case BWN_CCK_RATE_2MB:
3466203945Sweongyo		return (0x14);
3467203945Sweongyo	case BWN_CCK_RATE_5MB:
3468203945Sweongyo		return (0x37);
3469203945Sweongyo	case BWN_CCK_RATE_11MB:
3470203945Sweongyo		return (0x6e);
3471203945Sweongyo	}
3472203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3473203945Sweongyo	return (0);
3474203945Sweongyo}
3475203945Sweongyo
3476203945Sweongyostatic uint8_t
3477203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
3478203945Sweongyo{
3479203945Sweongyo
3480203945Sweongyo	switch (bitrate) {
3481203945Sweongyo	case BWN_OFDM_RATE_6MB:
3482203945Sweongyo		return (0xb);
3483203945Sweongyo	case BWN_OFDM_RATE_9MB:
3484203945Sweongyo		return (0xf);
3485203945Sweongyo	case BWN_OFDM_RATE_12MB:
3486203945Sweongyo		return (0xa);
3487203945Sweongyo	case BWN_OFDM_RATE_18MB:
3488203945Sweongyo		return (0xe);
3489203945Sweongyo	case BWN_OFDM_RATE_24MB:
3490203945Sweongyo		return (0x9);
3491203945Sweongyo	case BWN_OFDM_RATE_36MB:
3492203945Sweongyo		return (0xd);
3493203945Sweongyo	case BWN_OFDM_RATE_48MB:
3494203945Sweongyo		return (0x8);
3495203945Sweongyo	case BWN_OFDM_RATE_54MB:
3496203945Sweongyo		return (0xc);
3497203945Sweongyo	}
3498203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3499203945Sweongyo	return (0);
3500203945Sweongyo}
3501203945Sweongyo
3502203945Sweongyostatic void
3503203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
3504203945Sweongyo{
3505203945Sweongyo	uint16_t ctl;
3506203945Sweongyo
3507203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
3508203945Sweongyo	    BWN_TX_PHY_TXPWR);
3509203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
3510203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
3511203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
3512203945Sweongyo}
3513203945Sweongyo
3514203945Sweongyostatic void
3515203945Sweongyobwn_pio_init(struct bwn_mac *mac)
3516203945Sweongyo{
3517203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
3518203945Sweongyo
3519203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
3520203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
3521203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
3522203945Sweongyo
3523203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
3524203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
3525203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
3526203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
3527203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
3528203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
3529203945Sweongyo}
3530203945Sweongyo
3531203945Sweongyostatic void
3532203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3533203945Sweongyo    int index)
3534203945Sweongyo{
3535203945Sweongyo	struct bwn_pio_txpkt *tp;
3536204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3537203945Sweongyo	unsigned int i;
3538203945Sweongyo
3539203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
3540203945Sweongyo	tq->tq_index = index;
3541203945Sweongyo
3542203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
3543204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8)
3544203945Sweongyo		tq->tq_size = 1920;
3545203945Sweongyo	else {
3546203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
3547203945Sweongyo		tq->tq_size -= 80;
3548203945Sweongyo	}
3549203945Sweongyo
3550203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
3551203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3552203945Sweongyo		tp = &(tq->tq_pkts[i]);
3553203945Sweongyo		tp->tp_index = i;
3554203945Sweongyo		tp->tp_queue = tq;
3555203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
3556203945Sweongyo	}
3557203945Sweongyo}
3558203945Sweongyo
3559203945Sweongyostatic uint16_t
3560203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
3561203945Sweongyo{
3562203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3563203945Sweongyo	static const uint16_t bases[] = {
3564203945Sweongyo		BWN_PIO_BASE0,
3565203945Sweongyo		BWN_PIO_BASE1,
3566203945Sweongyo		BWN_PIO_BASE2,
3567203945Sweongyo		BWN_PIO_BASE3,
3568203945Sweongyo		BWN_PIO_BASE4,
3569203945Sweongyo		BWN_PIO_BASE5,
3570203945Sweongyo		BWN_PIO_BASE6,
3571203945Sweongyo		BWN_PIO_BASE7,
3572203945Sweongyo	};
3573203945Sweongyo	static const uint16_t bases_rev11[] = {
3574203945Sweongyo		BWN_PIO11_BASE0,
3575203945Sweongyo		BWN_PIO11_BASE1,
3576203945Sweongyo		BWN_PIO11_BASE2,
3577203945Sweongyo		BWN_PIO11_BASE3,
3578203945Sweongyo		BWN_PIO11_BASE4,
3579203945Sweongyo		BWN_PIO11_BASE5,
3580203945Sweongyo	};
3581203945Sweongyo
3582204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 11) {
3583203945Sweongyo		if (index >= N(bases_rev11))
3584203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
3585203945Sweongyo		return (bases_rev11[index]);
3586203945Sweongyo	}
3587203945Sweongyo	if (index >= N(bases))
3588203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
3589203945Sweongyo	return (bases[index]);
3590203945Sweongyo}
3591203945Sweongyo
3592203945Sweongyostatic void
3593203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
3594203945Sweongyo    int index)
3595203945Sweongyo{
3596204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3597203945Sweongyo
3598203945Sweongyo	prq->prq_mac = mac;
3599204922Sweongyo	prq->prq_rev = siba_get_revid(sc->sc_dev);
3600203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
3601203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
3602203945Sweongyo}
3603203945Sweongyo
3604203945Sweongyostatic void
3605203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
3606203945Sweongyo{
3607203945Sweongyo	if (tq == NULL)
3608203945Sweongyo		return;
3609203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
3610203945Sweongyo}
3611203945Sweongyo
3612203945Sweongyostatic void
3613203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
3614203945Sweongyo{
3615203945Sweongyo
3616203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
3617203945Sweongyo}
3618203945Sweongyo
3619203945Sweongyostatic uint16_t
3620203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3621203945Sweongyo    uint16_t offset)
3622203945Sweongyo{
3623203945Sweongyo
3624203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
3625203945Sweongyo}
3626203945Sweongyo
3627203945Sweongyostatic void
3628203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
3629203945Sweongyo{
3630203945Sweongyo	uint32_t ctl;
3631203945Sweongyo	int type;
3632203945Sweongyo	uint16_t base;
3633203945Sweongyo
3634203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
3635203945Sweongyo	base = bwn_dma_base(type, idx);
3636203945Sweongyo	if (type == BWN_DMA_64BIT) {
3637203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
3638203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
3639203945Sweongyo		if (enable)
3640203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
3641203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
3642203945Sweongyo	} else {
3643203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
3644203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
3645203945Sweongyo		if (enable)
3646203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
3647203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
3648203945Sweongyo	}
3649203945Sweongyo}
3650203945Sweongyo
3651203945Sweongyostatic uint64_t
3652203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
3653203945Sweongyo{
3654203945Sweongyo	uint32_t tmp;
3655203945Sweongyo	uint16_t base;
3656203945Sweongyo
3657203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3658203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3659203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
3660203945Sweongyo	base = bwn_dma_base(0, 0);
3661203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3662203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3663203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3664203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
3665203945Sweongyo
3666203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
3667203945Sweongyo}
3668203945Sweongyo
3669203945Sweongyostatic int
3670203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
3671203945Sweongyo{
3672203945Sweongyo
3673203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
3674203945Sweongyo		return (BWN_DMA_30BIT);
3675203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
3676203945Sweongyo		return (BWN_DMA_32BIT);
3677203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
3678203945Sweongyo		return (BWN_DMA_64BIT);
3679203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3680203945Sweongyo	return (BWN_DMA_30BIT);
3681203945Sweongyo}
3682203945Sweongyo
3683203945Sweongyostatic void
3684203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
3685203945Sweongyo{
3686203945Sweongyo	struct bwn_pio_txpkt *tp;
3687203945Sweongyo	unsigned int i;
3688203945Sweongyo
3689203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3690203945Sweongyo		tp = &(tq->tq_pkts[i]);
3691203945Sweongyo		if (tp->tp_m) {
3692203945Sweongyo			m_freem(tp->tp_m);
3693203945Sweongyo			tp->tp_m = NULL;
3694203945Sweongyo		}
3695203945Sweongyo	}
3696203945Sweongyo}
3697203945Sweongyo
3698203945Sweongyostatic uint16_t
3699203945Sweongyobwn_dma_base(int type, int controller_idx)
3700203945Sweongyo{
3701203945Sweongyo	static const uint16_t map64[] = {
3702203945Sweongyo		BWN_DMA64_BASE0,
3703203945Sweongyo		BWN_DMA64_BASE1,
3704203945Sweongyo		BWN_DMA64_BASE2,
3705203945Sweongyo		BWN_DMA64_BASE3,
3706203945Sweongyo		BWN_DMA64_BASE4,
3707203945Sweongyo		BWN_DMA64_BASE5,
3708203945Sweongyo	};
3709203945Sweongyo	static const uint16_t map32[] = {
3710203945Sweongyo		BWN_DMA32_BASE0,
3711203945Sweongyo		BWN_DMA32_BASE1,
3712203945Sweongyo		BWN_DMA32_BASE2,
3713203945Sweongyo		BWN_DMA32_BASE3,
3714203945Sweongyo		BWN_DMA32_BASE4,
3715203945Sweongyo		BWN_DMA32_BASE5,
3716203945Sweongyo	};
3717203945Sweongyo
3718203945Sweongyo	if (type == BWN_DMA_64BIT) {
3719203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
3720203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3721203945Sweongyo		return (map64[controller_idx]);
3722203945Sweongyo	}
3723203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
3724203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3725203945Sweongyo	return (map32[controller_idx]);
3726203945Sweongyo}
3727203945Sweongyo
3728203945Sweongyostatic void
3729203945Sweongyobwn_dma_init(struct bwn_mac *mac)
3730203945Sweongyo{
3731203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3732203945Sweongyo
3733203945Sweongyo	/* setup TX DMA channels. */
3734203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
3735203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
3736203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
3737203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
3738203945Sweongyo	bwn_dma_setup(dma->mcast);
3739203945Sweongyo	/* setup RX DMA channel. */
3740203945Sweongyo	bwn_dma_setup(dma->rx);
3741203945Sweongyo}
3742203945Sweongyo
3743203945Sweongyostatic struct bwn_dma_ring *
3744203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
3745203945Sweongyo    int for_tx, int type)
3746203945Sweongyo{
3747203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3748203945Sweongyo	struct bwn_dma_ring *dr;
3749203945Sweongyo	struct bwn_dmadesc_generic *desc;
3750203945Sweongyo	struct bwn_dmadesc_meta *mt;
3751203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3752203945Sweongyo	int error, i;
3753203945Sweongyo
3754203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
3755203945Sweongyo	if (dr == NULL)
3756203945Sweongyo		goto out;
3757203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
3758203945Sweongyo	if (for_tx)
3759203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
3760203945Sweongyo
3761203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
3762203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
3763203945Sweongyo	if (dr->dr_meta == NULL)
3764203945Sweongyo		goto fail0;
3765203945Sweongyo
3766203945Sweongyo	dr->dr_type = type;
3767203945Sweongyo	dr->dr_mac = mac;
3768203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
3769203945Sweongyo	dr->dr_index = controller_index;
3770203945Sweongyo	if (type == BWN_DMA_64BIT) {
3771203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
3772203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
3773203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
3774203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
3775203945Sweongyo		dr->resume = bwn_dma_64_resume;
3776203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
3777203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
3778203945Sweongyo	} else {
3779203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
3780203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
3781203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
3782203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
3783203945Sweongyo		dr->resume = bwn_dma_32_resume;
3784203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
3785203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
3786203945Sweongyo	}
3787203945Sweongyo	if (for_tx) {
3788203945Sweongyo		dr->dr_tx = 1;
3789203945Sweongyo		dr->dr_curslot = -1;
3790203945Sweongyo	} else {
3791203945Sweongyo		if (dr->dr_index == 0) {
3792203945Sweongyo			dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
3793203945Sweongyo			dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
3794203945Sweongyo		} else
3795203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3796203945Sweongyo	}
3797203945Sweongyo
3798203945Sweongyo	error = bwn_dma_allocringmemory(dr);
3799203945Sweongyo	if (error)
3800203945Sweongyo		goto fail2;
3801203945Sweongyo
3802203945Sweongyo	if (for_tx) {
3803203945Sweongyo		/*
3804203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
3805203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
3806203945Sweongyo		 */
3807203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
3808203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3809203945Sweongyo
3810203945Sweongyo		dr->dr_txhdr_cache =
3811203945Sweongyo		    malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
3812203945Sweongyo			BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
3813203945Sweongyo		KASSERT(dr->dr_txhdr_cache != NULL,
3814203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3815203945Sweongyo
3816203945Sweongyo		/*
3817203945Sweongyo		 * Create TX ring DMA stuffs
3818203945Sweongyo		 */
3819203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
3820203945Sweongyo				    BWN_ALIGN, 0,
3821203945Sweongyo				    BUS_SPACE_MAXADDR,
3822203945Sweongyo				    BUS_SPACE_MAXADDR,
3823203945Sweongyo				    NULL, NULL,
3824203945Sweongyo				    BWN_HDRSIZE(mac),
3825203945Sweongyo				    1,
3826203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
3827203945Sweongyo				    0,
3828203945Sweongyo				    NULL, NULL,
3829203945Sweongyo				    &dr->dr_txring_dtag);
3830203945Sweongyo		if (error) {
3831203945Sweongyo			device_printf(sc->sc_dev,
3832203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
3833203945Sweongyo			goto fail1;
3834203945Sweongyo		}
3835203945Sweongyo
3836203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
3837203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3838203945Sweongyo
3839203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
3840203945Sweongyo			mt->mt_m = NULL;
3841203945Sweongyo			mt->mt_ni = NULL;
3842203945Sweongyo			mt->mt_islast = 0;
3843203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
3844203945Sweongyo			    &mt->mt_dmap);
3845203945Sweongyo			if (error) {
3846203945Sweongyo				device_printf(sc->sc_dev,
3847203945Sweongyo				     "can't create RX buf DMA map\n");
3848203945Sweongyo				goto fail1;
3849203945Sweongyo			}
3850203945Sweongyo
3851203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
3852203945Sweongyo
3853203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
3854203945Sweongyo			mt->mt_m = NULL;
3855203945Sweongyo			mt->mt_ni = NULL;
3856203945Sweongyo			mt->mt_islast = 1;
3857203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
3858203945Sweongyo			    &mt->mt_dmap);
3859203945Sweongyo			if (error) {
3860203945Sweongyo				device_printf(sc->sc_dev,
3861203945Sweongyo				     "can't create RX buf DMA map\n");
3862203945Sweongyo				goto fail1;
3863203945Sweongyo			}
3864203945Sweongyo		}
3865203945Sweongyo	} else {
3866203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3867203945Sweongyo		    &dr->dr_spare_dmap);
3868203945Sweongyo		if (error) {
3869203945Sweongyo			device_printf(sc->sc_dev,
3870203945Sweongyo			    "can't create RX buf DMA map\n");
3871203945Sweongyo			goto out;		/* XXX wrong! */
3872203945Sweongyo		}
3873203945Sweongyo
3874203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
3875203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3876203945Sweongyo
3877203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3878203945Sweongyo			    &mt->mt_dmap);
3879203945Sweongyo			if (error) {
3880203945Sweongyo				device_printf(sc->sc_dev,
3881203945Sweongyo				    "can't create RX buf DMA map\n");
3882203945Sweongyo				goto out;	/* XXX wrong! */
3883203945Sweongyo			}
3884203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
3885203945Sweongyo			if (error) {
3886203945Sweongyo				device_printf(sc->sc_dev,
3887203945Sweongyo				    "failed to allocate RX buf\n");
3888203945Sweongyo				goto out;	/* XXX wrong! */
3889203945Sweongyo			}
3890203945Sweongyo		}
3891203945Sweongyo
3892203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
3893203945Sweongyo		    BUS_DMASYNC_PREWRITE);
3894203945Sweongyo
3895203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
3896203945Sweongyo	}
3897203945Sweongyo
3898203945Sweongyo      out:
3899203945Sweongyo	return (dr);
3900203945Sweongyo
3901203945Sweongyofail2:
3902203945Sweongyo	free(dr->dr_txhdr_cache, M_DEVBUF);
3903203945Sweongyofail1:
3904203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
3905203945Sweongyofail0:
3906203945Sweongyo	free(dr, M_DEVBUF);
3907203945Sweongyo	return (NULL);
3908203945Sweongyo}
3909203945Sweongyo
3910203945Sweongyostatic void
3911203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
3912203945Sweongyo{
3913203945Sweongyo
3914203945Sweongyo	if (dr == NULL)
3915203945Sweongyo		return;
3916203945Sweongyo
3917203945Sweongyo	bwn_dma_free_descbufs(*dr);
3918203945Sweongyo	bwn_dma_free_ringmemory(*dr);
3919203945Sweongyo
3920203945Sweongyo	free((*dr)->dr_txhdr_cache, M_DEVBUF);
3921203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
3922203945Sweongyo	free(*dr, M_DEVBUF);
3923203945Sweongyo
3924203945Sweongyo	*dr = NULL;
3925203945Sweongyo}
3926203945Sweongyo
3927203945Sweongyostatic void
3928203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
3929203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
3930203945Sweongyo{
3931203945Sweongyo	struct bwn_dmadesc32 *desc;
3932203945Sweongyo
3933203945Sweongyo	*meta = &(dr->dr_meta[slot]);
3934203945Sweongyo	desc = dr->dr_ring_descbase;
3935203945Sweongyo	desc = &(desc[slot]);
3936203945Sweongyo
3937203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
3938203945Sweongyo}
3939203945Sweongyo
3940203945Sweongyostatic void
3941203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
3942203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
3943203945Sweongyo    int start, int end, int irq)
3944203945Sweongyo{
3945203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
3946204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
3947203945Sweongyo	uint32_t addr, addrext, ctl;
3948203945Sweongyo	int slot;
3949203945Sweongyo
3950203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
3951203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
3952203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3953203945Sweongyo
3954203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
3955203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
3956204922Sweongyo	addr |= siba_dma_translation(sc->sc_dev);
3957203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
3958203945Sweongyo	if (slot == dr->dr_numslots - 1)
3959203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
3960203945Sweongyo	if (start)
3961203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
3962203945Sweongyo	if (end)
3963203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
3964203945Sweongyo	if (irq)
3965203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
3966203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
3967203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
3968203945Sweongyo
3969203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
3970203945Sweongyo	desc->dma.dma32.address = htole32(addr);
3971203945Sweongyo}
3972203945Sweongyo
3973203945Sweongyostatic void
3974203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
3975203945Sweongyo{
3976203945Sweongyo
3977203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
3978203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
3979203945Sweongyo}
3980203945Sweongyo
3981203945Sweongyostatic void
3982203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
3983203945Sweongyo{
3984203945Sweongyo
3985203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
3986203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
3987203945Sweongyo}
3988203945Sweongyo
3989203945Sweongyostatic void
3990203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
3991203945Sweongyo{
3992203945Sweongyo
3993203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
3994203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
3995203945Sweongyo}
3996203945Sweongyo
3997203945Sweongyostatic int
3998203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
3999203945Sweongyo{
4000203945Sweongyo	uint32_t val;
4001203945Sweongyo
4002203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
4003203945Sweongyo	val &= BWN_DMA32_RXDPTR;
4004203945Sweongyo
4005203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
4006203945Sweongyo}
4007203945Sweongyo
4008203945Sweongyostatic void
4009203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
4010203945Sweongyo{
4011203945Sweongyo
4012203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
4013203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
4014203945Sweongyo}
4015203945Sweongyo
4016203945Sweongyostatic void
4017203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
4018203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
4019203945Sweongyo{
4020203945Sweongyo	struct bwn_dmadesc64 *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_64_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_dmadesc64 *descbase = dr->dr_ring_descbase;
4035204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
4036203945Sweongyo	int slot;
4037203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
4038203945Sweongyo	uint32_t addrlo, addrhi;
4039203945Sweongyo	uint32_t addrext;
4040203945Sweongyo
4041203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
4042203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
4043203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4044203945Sweongyo
4045203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
4046203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
4047203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
4048203945Sweongyo	    30;
4049204922Sweongyo	addrhi |= (siba_dma_translation(sc->sc_dev) << 1);
4050203945Sweongyo	if (slot == dr->dr_numslots - 1)
4051203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
4052203945Sweongyo	if (start)
4053203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
4054203945Sweongyo	if (end)
4055203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
4056203945Sweongyo	if (irq)
4057203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
4058203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
4059203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
4060203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
4061203945Sweongyo
4062203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
4063203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
4064203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
4065203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
4066203945Sweongyo}
4067203945Sweongyo
4068203945Sweongyostatic void
4069203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
4070203945Sweongyo{
4071203945Sweongyo
4072203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
4073203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4074203945Sweongyo}
4075203945Sweongyo
4076203945Sweongyostatic void
4077203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
4078203945Sweongyo{
4079203945Sweongyo
4080203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4081203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
4082203945Sweongyo}
4083203945Sweongyo
4084203945Sweongyostatic void
4085203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
4086203945Sweongyo{
4087203945Sweongyo
4088203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4089203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
4090203945Sweongyo}
4091203945Sweongyo
4092203945Sweongyostatic int
4093203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
4094203945Sweongyo{
4095203945Sweongyo	uint32_t val;
4096203945Sweongyo
4097203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
4098203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
4099203945Sweongyo
4100203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
4101203945Sweongyo}
4102203945Sweongyo
4103203945Sweongyostatic void
4104203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
4105203945Sweongyo{
4106203945Sweongyo
4107203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
4108203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4109203945Sweongyo}
4110203945Sweongyo
4111203945Sweongyostatic int
4112203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
4113203945Sweongyo{
4114203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4115203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4116203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4117203945Sweongyo	int error;
4118203945Sweongyo
4119203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
4120203945Sweongyo			    BWN_ALIGN, 0,
4121203945Sweongyo			    BUS_SPACE_MAXADDR,
4122203945Sweongyo			    BUS_SPACE_MAXADDR,
4123203945Sweongyo			    NULL, NULL,
4124203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
4125203945Sweongyo			    1,
4126203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
4127203945Sweongyo			    0,
4128203945Sweongyo			    NULL, NULL,
4129203945Sweongyo			    &dr->dr_ring_dtag);
4130203945Sweongyo	if (error) {
4131203945Sweongyo		device_printf(sc->sc_dev,
4132203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
4133203945Sweongyo		return (-1);
4134203945Sweongyo	}
4135203945Sweongyo
4136203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
4137203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
4138203945Sweongyo	    &dr->dr_ring_dmap);
4139203945Sweongyo	if (error) {
4140203945Sweongyo		device_printf(sc->sc_dev,
4141203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
4142203945Sweongyo		return (-1);
4143203945Sweongyo	}
4144203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
4145203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
4146203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
4147203945Sweongyo	if (error) {
4148203945Sweongyo		device_printf(sc->sc_dev,
4149203945Sweongyo		    "can't load DMA mem: TODO free\n");
4150203945Sweongyo		return (-1);
4151203945Sweongyo	}
4152203945Sweongyo
4153203945Sweongyo	return (0);
4154203945Sweongyo}
4155203945Sweongyo
4156203945Sweongyostatic void
4157203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
4158203945Sweongyo{
4159204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
4160203945Sweongyo	uint64_t ring64;
4161203945Sweongyo	uint32_t addrext, ring32, value;
4162204922Sweongyo	uint32_t trans = siba_dma_translation(sc->sc_dev);
4163203945Sweongyo
4164203945Sweongyo	if (dr->dr_tx) {
4165203945Sweongyo		dr->dr_curslot = -1;
4166203945Sweongyo
4167203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4168203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
4169203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
4170203945Sweongyo			    >> 30;
4171203945Sweongyo			value = BWN_DMA64_TXENABLE;
4172203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
4173203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
4174203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
4175203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
4176203945Sweongyo			    (ring64 & 0xffffffff));
4177203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
4178203945Sweongyo			    ((ring64 >> 32) &
4179203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
4180203945Sweongyo		} else {
4181203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
4182203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4183203945Sweongyo			value = BWN_DMA32_TXENABLE;
4184203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
4185203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
4186203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
4187203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
4188203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4189203945Sweongyo		}
4190203945Sweongyo		return;
4191203945Sweongyo	}
4192203945Sweongyo
4193203945Sweongyo	/*
4194203945Sweongyo	 * set for RX
4195203945Sweongyo	 */
4196203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
4197203945Sweongyo
4198203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
4199203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
4200203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
4201203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
4202203945Sweongyo		value |= BWN_DMA64_RXENABLE;
4203203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
4204203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
4205203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
4206203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
4207203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
4208203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
4209203945Sweongyo		    | (trans << 1));
4210203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
4211203945Sweongyo		    sizeof(struct bwn_dmadesc64));
4212203945Sweongyo	} else {
4213203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
4214203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4215203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
4216203945Sweongyo		value |= BWN_DMA32_RXENABLE;
4217203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
4218203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
4219203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
4220203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
4221203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4222203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
4223203945Sweongyo		    sizeof(struct bwn_dmadesc32));
4224203945Sweongyo	}
4225203945Sweongyo}
4226203945Sweongyo
4227203945Sweongyostatic void
4228203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
4229203945Sweongyo{
4230203945Sweongyo
4231203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
4232203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
4233203945Sweongyo	    dr->dr_ring_dmap);
4234203945Sweongyo}
4235203945Sweongyo
4236203945Sweongyostatic void
4237203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
4238203945Sweongyo{
4239203945Sweongyo
4240203945Sweongyo	if (dr->dr_tx) {
4241203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4242203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4243203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
4244203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
4245203945Sweongyo		} else
4246203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
4247203945Sweongyo	} else {
4248203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4249203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4250203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
4251203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
4252203945Sweongyo		} else
4253203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
4254203945Sweongyo	}
4255203945Sweongyo}
4256203945Sweongyo
4257203945Sweongyostatic void
4258203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
4259203945Sweongyo{
4260203945Sweongyo	struct bwn_dmadesc_generic *desc;
4261203945Sweongyo	struct bwn_dmadesc_meta *meta;
4262203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4263203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4264203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4265203945Sweongyo	int i;
4266203945Sweongyo
4267203945Sweongyo	if (!dr->dr_usedslot)
4268203945Sweongyo		return;
4269203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
4270203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
4271203945Sweongyo
4272203945Sweongyo		if (meta->mt_m == NULL) {
4273203945Sweongyo			if (!dr->dr_tx)
4274203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
4275203945Sweongyo				    __func__);
4276203945Sweongyo			continue;
4277203945Sweongyo		}
4278203945Sweongyo		if (dr->dr_tx) {
4279203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
4280203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
4281203945Sweongyo				    meta->mt_dmap);
4282203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
4283203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
4284203945Sweongyo				    meta->mt_dmap);
4285203945Sweongyo		} else
4286203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
4287203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
4288203945Sweongyo	}
4289203945Sweongyo}
4290203945Sweongyo
4291203945Sweongyostatic int
4292203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
4293203945Sweongyo    int type)
4294203945Sweongyo{
4295203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4296203945Sweongyo	uint32_t value;
4297203945Sweongyo	int i;
4298203945Sweongyo	uint16_t offset;
4299203945Sweongyo
4300203945Sweongyo	for (i = 0; i < 10; i++) {
4301203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4302203945Sweongyo		    BWN_DMA32_TXSTATUS;
4303203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4304203945Sweongyo		if (type == BWN_DMA_64BIT) {
4305203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4306203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
4307203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
4308203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
4309203945Sweongyo				break;
4310203945Sweongyo		} else {
4311203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4312203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
4313203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
4314203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
4315203945Sweongyo				break;
4316203945Sweongyo		}
4317203945Sweongyo		DELAY(1000);
4318203945Sweongyo	}
4319203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
4320203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4321203945Sweongyo	for (i = 0; i < 10; i++) {
4322203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4323203945Sweongyo						   BWN_DMA32_TXSTATUS;
4324203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4325203945Sweongyo		if (type == BWN_DMA_64BIT) {
4326203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4327203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
4328203945Sweongyo				i = -1;
4329203945Sweongyo				break;
4330203945Sweongyo			}
4331203945Sweongyo		} else {
4332203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4333203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
4334203945Sweongyo				i = -1;
4335203945Sweongyo				break;
4336203945Sweongyo			}
4337203945Sweongyo		}
4338203945Sweongyo		DELAY(1000);
4339203945Sweongyo	}
4340203945Sweongyo	if (i != -1) {
4341203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4342203945Sweongyo		return (ENODEV);
4343203945Sweongyo	}
4344203945Sweongyo	DELAY(1000);
4345203945Sweongyo
4346203945Sweongyo	return (0);
4347203945Sweongyo}
4348203945Sweongyo
4349203945Sweongyostatic int
4350203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
4351203945Sweongyo    int type)
4352203945Sweongyo{
4353203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4354203945Sweongyo	uint32_t value;
4355203945Sweongyo	int i;
4356203945Sweongyo	uint16_t offset;
4357203945Sweongyo
4358203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
4359203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4360203945Sweongyo	for (i = 0; i < 10; i++) {
4361203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
4362203945Sweongyo		    BWN_DMA32_RXSTATUS;
4363203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4364203945Sweongyo		if (type == BWN_DMA_64BIT) {
4365203945Sweongyo			value &= BWN_DMA64_RXSTAT;
4366203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
4367203945Sweongyo				i = -1;
4368203945Sweongyo				break;
4369203945Sweongyo			}
4370203945Sweongyo		} else {
4371203945Sweongyo			value &= BWN_DMA32_RXSTATE;
4372203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
4373203945Sweongyo				i = -1;
4374203945Sweongyo				break;
4375203945Sweongyo			}
4376203945Sweongyo		}
4377203945Sweongyo		DELAY(1000);
4378203945Sweongyo	}
4379203945Sweongyo	if (i != -1) {
4380203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4381203945Sweongyo		return (ENODEV);
4382203945Sweongyo	}
4383203945Sweongyo
4384203945Sweongyo	return (0);
4385203945Sweongyo}
4386203945Sweongyo
4387203945Sweongyostatic void
4388203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
4389203945Sweongyo    struct bwn_dmadesc_meta *meta)
4390203945Sweongyo{
4391203945Sweongyo
4392203945Sweongyo	if (meta->mt_m != NULL) {
4393203945Sweongyo		m_freem(meta->mt_m);
4394203945Sweongyo		meta->mt_m = NULL;
4395203945Sweongyo	}
4396203945Sweongyo	if (meta->mt_ni != NULL) {
4397203945Sweongyo		ieee80211_free_node(meta->mt_ni);
4398203945Sweongyo		meta->mt_ni = NULL;
4399203945Sweongyo	}
4400203945Sweongyo}
4401203945Sweongyo
4402203945Sweongyostatic void
4403203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4404203945Sweongyo{
4405203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
4406203945Sweongyo	unsigned char *frame;
4407203945Sweongyo
4408203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
4409203945Sweongyo	rxhdr->frame_len = 0;
4410203945Sweongyo
4411203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
4412203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
4413203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4414203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
4415203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
4416203945Sweongyo}
4417203945Sweongyo
4418203945Sweongyostatic uint8_t
4419203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4420203945Sweongyo{
4421203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
4422203945Sweongyo
4423203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
4424203945Sweongyo	    == 0xff);
4425203945Sweongyo}
4426203945Sweongyo
4427203945Sweongyostatic void
4428203945Sweongyobwn_wme_init(struct bwn_mac *mac)
4429203945Sweongyo{
4430203945Sweongyo
4431203945Sweongyo	bwn_wme_load(mac);
4432203945Sweongyo
4433203945Sweongyo	/* enable WME support. */
4434203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
4435203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
4436203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
4437203945Sweongyo}
4438203945Sweongyo
4439203945Sweongyostatic void
4440203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
4441203945Sweongyo{
4442203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4443203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4444203945Sweongyo	uint16_t delay;	/* microsec */
4445203945Sweongyo
4446203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
4447203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
4448203945Sweongyo		delay = 500;
4449203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
4450203945Sweongyo		delay = max(delay, (uint16_t)2400);
4451203945Sweongyo
4452203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
4453203945Sweongyo}
4454203945Sweongyo
4455203945Sweongyostatic void
4456203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
4457203945Sweongyo{
4458204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4459203945Sweongyo	uint64_t hf;
4460203945Sweongyo
4461203945Sweongyo	if (bwn_bluetooth == 0)
4462203945Sweongyo		return;
4463204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCOEXIST) == 0)
4464203945Sweongyo		return;
4465203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
4466203945Sweongyo		return;
4467203945Sweongyo
4468203945Sweongyo	hf = bwn_hf_read(mac);
4469204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCMOD)
4470203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
4471203945Sweongyo	else
4472203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
4473203945Sweongyo	bwn_hf_write(mac, hf);
4474203945Sweongyo}
4475203945Sweongyo
4476203945Sweongyostatic void
4477203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
4478203945Sweongyo{
4479203945Sweongyo
4480203945Sweongyo	bwn_mac_write_bssid(mac);
4481203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF, mac->mac_sc->sc_macaddr);
4482203945Sweongyo}
4483203945Sweongyo
4484203945Sweongyostatic void
4485203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
4486203945Sweongyo{
4487203945Sweongyo	int i;
4488203945Sweongyo
4489203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
4490203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
4491203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
4492203945Sweongyo
4493203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
4494203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
4495203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
4496203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
4497203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
4498203945Sweongyo		}
4499203945Sweongyo		mac->mac_key[i].keyconf = NULL;
4500203945Sweongyo	}
4501203945Sweongyo}
4502203945Sweongyo
4503203945Sweongyostatic void
4504203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
4505203945Sweongyo{
4506204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4507203945Sweongyo
4508204922Sweongyo	mac->mac_max_nr_keys = (siba_get_revid(sc->sc_dev) >= 5) ? 58 : 20;
4509203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
4510203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4511203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
4512203945Sweongyo	mac->mac_ktp *= 2;
4513204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5)
4514204922Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT, mac->mac_max_nr_keys - 8);
4515203945Sweongyo	bwn_clear_keys(mac);
4516203945Sweongyo}
4517203945Sweongyo
4518203945Sweongyostatic void
4519203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
4520203945Sweongyo{
4521204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4522203945Sweongyo
4523203945Sweongyo	bwn_phy_exit(mac);
4524204922Sweongyo	siba_gpio_set(sc->sc_dev, 0);
4525203945Sweongyo}
4526203945Sweongyo
4527203945Sweongyostatic int
4528203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
4529203945Sweongyo{
4530203945Sweongyo	int error;
4531203945Sweongyo
4532203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
4533203945Sweongyo	if (error == 0)
4534203945Sweongyo		return (0);
4535203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
4536203945Sweongyo	if (error == 0)
4537203945Sweongyo		return (0);
4538203945Sweongyo	return (error);
4539203945Sweongyo}
4540203945Sweongyo
4541203945Sweongyostatic int
4542203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
4543203945Sweongyo{
4544204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4545204922Sweongyo	uint32_t mask = 0x1f, set = 0xf, value;
4546203945Sweongyo
4547203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4548203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
4549203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
4550203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
4551203945Sweongyo
4552204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4301) {
4553203945Sweongyo		mask |= 0x0060;
4554203945Sweongyo		set |= 0x0060;
4555203945Sweongyo	}
4556204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL) {
4557203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
4558203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
4559203945Sweongyo		mask |= 0x0200;
4560203945Sweongyo		set |= 0x0200;
4561203945Sweongyo	}
4562204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 2)
4563203945Sweongyo		mask |= 0x0010;
4564204922Sweongyo
4565204922Sweongyo	value = siba_gpio_get(sc->sc_dev);
4566204922Sweongyo	if (value == -1)
4567203945Sweongyo		return (0);
4568204922Sweongyo	siba_gpio_set(sc->sc_dev, (value & mask) | set);
4569203945Sweongyo
4570203945Sweongyo	return (0);
4571203945Sweongyo}
4572203945Sweongyo
4573203945Sweongyostatic int
4574203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
4575203945Sweongyo{
4576203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
4577203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
4578203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
4579203945Sweongyo	const struct bwn_fwhdr *hdr;
4580203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
4581203945Sweongyo	int error;
4582203945Sweongyo
4583203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
4584203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
4585203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
4586203945Sweongyo	if (error)
4587203945Sweongyo		return (error);
4588203945Sweongyo	if (fw->initvals_band.fw) {
4589203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
4590203945Sweongyo		error = bwn_fwinitvals_write(mac,
4591203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
4592203945Sweongyo		    be32toh(hdr->size),
4593203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
4594203945Sweongyo	}
4595203945Sweongyo	return (error);
4596203945Sweongyo#undef GETFWOFFSET
4597203945Sweongyo}
4598203945Sweongyo
4599203945Sweongyostatic int
4600203945Sweongyobwn_phy_init(struct bwn_mac *mac)
4601203945Sweongyo{
4602203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4603203945Sweongyo	int error;
4604203945Sweongyo
4605203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
4606203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4607203945Sweongyo	error = mac->mac_phy.init(mac);
4608203945Sweongyo	if (error) {
4609203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
4610203945Sweongyo		goto fail0;
4611203945Sweongyo	}
4612203945Sweongyo	error = bwn_switch_channel(mac,
4613203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
4614203945Sweongyo	if (error) {
4615203945Sweongyo		device_printf(sc->sc_dev,
4616203945Sweongyo		    "failed to switch default channel\n");
4617203945Sweongyo		goto fail1;
4618203945Sweongyo	}
4619203945Sweongyo	return (0);
4620203945Sweongyofail1:
4621203945Sweongyo	if (mac->mac_phy.exit)
4622203945Sweongyo		mac->mac_phy.exit(mac);
4623203945Sweongyofail0:
4624203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4625203945Sweongyo
4626203945Sweongyo	return (error);
4627203945Sweongyo}
4628203945Sweongyo
4629203945Sweongyostatic void
4630203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
4631203945Sweongyo{
4632203945Sweongyo	uint16_t ant;
4633203945Sweongyo	uint16_t tmp;
4634203945Sweongyo
4635203945Sweongyo	ant = bwn_ant2phy(antenna);
4636203945Sweongyo
4637203945Sweongyo	/* For ACK/CTS */
4638203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
4639203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4640203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
4641203945Sweongyo	/* For Probe Resposes */
4642203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
4643203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4644203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
4645203945Sweongyo}
4646203945Sweongyo
4647203945Sweongyostatic void
4648203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
4649203945Sweongyo{
4650203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4651203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4652203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
4653203945Sweongyo	uint32_t ctl;
4654203945Sweongyo	uint16_t cfp_pretbtt;
4655203945Sweongyo
4656203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
4657203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
4658203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
4659203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
4660203945Sweongyo	ctl |= BWN_MACCTL_STA;
4661203945Sweongyo
4662203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4663203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
4664203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
4665203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
4666203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
4667203945Sweongyo	ctl |= sc->sc_filters;
4668203945Sweongyo
4669204922Sweongyo	if (siba_get_revid(sc->sc_dev) <= 4)
4670203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
4671203945Sweongyo
4672203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
4673203945Sweongyo
4674203945Sweongyo	cfp_pretbtt = 2;
4675203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
4676204922Sweongyo		if (siba_get_chipid(sc->sc_dev) == 0x4306 &&
4677204922Sweongyo		    siba_get_chiprev(sc->sc_dev) == 3)
4678203945Sweongyo			cfp_pretbtt = 100;
4679203945Sweongyo		else
4680203945Sweongyo			cfp_pretbtt = 50;
4681203945Sweongyo	}
4682203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
4683203945Sweongyo}
4684203945Sweongyo
4685203945Sweongyostatic int
4686203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
4687203945Sweongyo{
4688203945Sweongyo	uint32_t tmp;
4689203945Sweongyo	uint16_t base;
4690203945Sweongyo
4691203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
4692203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
4693203945Sweongyo		return (BWN_DMA_64BIT);
4694203945Sweongyo	base = bwn_dma_base(0, 0);
4695203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
4696203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
4697203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
4698203945Sweongyo		return (BWN_DMA_32BIT);
4699203945Sweongyo
4700203945Sweongyo	return (BWN_DMA_30BIT);
4701203945Sweongyo}
4702203945Sweongyo
4703203945Sweongyostatic void
4704203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
4705203945Sweongyo{
4706203945Sweongyo	if (!error) {
4707203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
4708203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
4709203945Sweongyo	}
4710203945Sweongyo}
4711203945Sweongyo
4712203945Sweongyostatic void
4713203945Sweongyobwn_phy_g_init_sub(struct bwn_mac *mac)
4714203945Sweongyo{
4715203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4716203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4717204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4718203945Sweongyo	uint16_t i, tmp;
4719203945Sweongyo
4720203945Sweongyo	if (phy->rev == 1)
4721203945Sweongyo		bwn_phy_init_b5(mac);
4722203945Sweongyo	else
4723203945Sweongyo		bwn_phy_init_b6(mac);
4724203945Sweongyo
4725203945Sweongyo	if (phy->rev >= 2 || phy->gmode)
4726203945Sweongyo		bwn_phy_init_a(mac);
4727203945Sweongyo
4728203945Sweongyo	if (phy->rev >= 2) {
4729203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
4730203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
4731203945Sweongyo	}
4732203945Sweongyo	if (phy->rev == 2) {
4733203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
4734203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4735203945Sweongyo	}
4736203945Sweongyo	if (phy->rev > 5) {
4737203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
4738203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4739203945Sweongyo	}
4740203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4741203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
4742203945Sweongyo		tmp &= BWN_PHYVER_VERSION;
4743203945Sweongyo		if (tmp == 3 || tmp == 5) {
4744203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
4745203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
4746203945Sweongyo		}
4747203945Sweongyo		if (tmp == 5) {
4748203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
4749203945Sweongyo			    0x1f00);
4750203945Sweongyo		}
4751203945Sweongyo	}
4752203945Sweongyo	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
4753203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
4754203945Sweongyo	if (phy->rf_rev == 8) {
4755203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
4756203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
4757203945Sweongyo	}
4758203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
4759203945Sweongyo		bwn_loopback_calcgain(mac);
4760203945Sweongyo
4761203945Sweongyo	if (phy->rf_rev != 8) {
4762203945Sweongyo		if (pg->pg_initval == 0xffff)
4763203945Sweongyo			pg->pg_initval = bwn_rf_init_bcm2050(mac);
4764203945Sweongyo		else
4765203945Sweongyo			BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
4766203945Sweongyo	}
4767203945Sweongyo	bwn_lo_g_init(mac);
4768203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
4769203945Sweongyo		BWN_RF_WRITE(mac, 0x52,
4770203945Sweongyo		    (BWN_RF_READ(mac, 0x52) & 0xff00)
4771203945Sweongyo		    | pg->pg_loctl.tx_bias |
4772203945Sweongyo		    pg->pg_loctl.tx_magn);
4773203945Sweongyo	} else {
4774203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
4775203945Sweongyo	}
4776203945Sweongyo	if (phy->rev >= 6) {
4777203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
4778203945Sweongyo		    (pg->pg_loctl.tx_bias << 12));
4779203945Sweongyo	}
4780204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
4781203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
4782203945Sweongyo	else
4783203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
4784203945Sweongyo	if (phy->rev < 2)
4785203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
4786203945Sweongyo	else
4787203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
4788203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4789203945Sweongyo		bwn_lo_g_adjust(mac);
4790203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
4791203945Sweongyo	}
4792203945Sweongyo
4793204922Sweongyo	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
4794203945Sweongyo		for (i = 0; i < 64; i++) {
4795203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
4796203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
4797203945Sweongyo			    (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
4798203945Sweongyo			    -32), 31));
4799203945Sweongyo		}
4800203945Sweongyo		bwn_nrssi_threshold(mac);
4801203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
4802203945Sweongyo		if (pg->pg_nrssi[0] == -1000) {
4803203945Sweongyo			KASSERT(pg->pg_nrssi[1] == -1000,
4804203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
4805203945Sweongyo			bwn_nrssi_slope_11g(mac);
4806203945Sweongyo		} else
4807203945Sweongyo			bwn_nrssi_threshold(mac);
4808203945Sweongyo	}
4809203945Sweongyo	if (phy->rf_rev == 8)
4810203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
4811203945Sweongyo	bwn_phy_hwpctl_init(mac);
4812204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4306
4813204922Sweongyo	     && siba_get_chippkg(sc->sc_dev) == 2) || 0) {
4814203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
4815203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
4816203945Sweongyo	}
4817203945Sweongyo}
4818203945Sweongyo
4819203945Sweongyostatic uint8_t
4820203945Sweongyobwn_has_hwpctl(struct bwn_mac *mac)
4821203945Sweongyo{
4822203945Sweongyo
4823203945Sweongyo	if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
4824203945Sweongyo		return (0);
4825203945Sweongyo	return (mac->mac_phy.use_hwpctl(mac));
4826203945Sweongyo}
4827203945Sweongyo
4828203945Sweongyostatic void
4829203945Sweongyobwn_phy_init_b5(struct bwn_mac *mac)
4830203945Sweongyo{
4831203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4832203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4833204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4834203945Sweongyo	uint16_t offset, value;
4835203945Sweongyo	uint8_t old_channel;
4836203945Sweongyo
4837203945Sweongyo	if (phy->analog == 1)
4838203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0050);
4839204922Sweongyo	if ((siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM) &&
4840204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306)) {
4841203945Sweongyo		value = 0x2120;
4842203945Sweongyo		for (offset = 0x00a8; offset < 0x00c7; offset++) {
4843203945Sweongyo			BWN_PHY_WRITE(mac, offset, value);
4844203945Sweongyo			value += 0x202;
4845203945Sweongyo		}
4846203945Sweongyo	}
4847203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
4848203945Sweongyo	if (phy->rf_ver == 0x2050)
4849203945Sweongyo		BWN_PHY_WRITE(mac, 0x0038, 0x0667);
4850203945Sweongyo
4851203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4852203945Sweongyo		if (phy->rf_ver == 0x2050) {
4853203945Sweongyo			BWN_RF_SET(mac, 0x007a, 0x0020);
4854203945Sweongyo			BWN_RF_SET(mac, 0x0051, 0x0004);
4855203945Sweongyo		}
4856203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
4857203945Sweongyo
4858203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
4859203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
4860203945Sweongyo
4861203945Sweongyo		BWN_PHY_WRITE(mac, 0x001c, 0x186a);
4862203945Sweongyo
4863203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
4864203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
4865203945Sweongyo		BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
4866203945Sweongyo	}
4867203945Sweongyo
4868203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
4869203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
4870203945Sweongyo
4871203945Sweongyo	if (phy->analog == 1) {
4872203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xce00);
4873203945Sweongyo		BWN_PHY_WRITE(mac, 0x0021, 0x3763);
4874203945Sweongyo		BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
4875203945Sweongyo		BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
4876203945Sweongyo		BWN_PHY_WRITE(mac, 0x0024, 0x037e);
4877203945Sweongyo	} else
4878203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
4879203945Sweongyo	BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
4880203945Sweongyo	BWN_WRITE_2(mac, 0x03ec, 0x3f22);
4881203945Sweongyo
4882203945Sweongyo	if (phy->analog == 1)
4883203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
4884203945Sweongyo	else
4885203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x301c);
4886203945Sweongyo
4887203945Sweongyo	if (phy->analog == 0)
4888203945Sweongyo		BWN_WRITE_2(mac, 0x03e4, 0x3000);
4889203945Sweongyo
4890203945Sweongyo	old_channel = phy->chan;
4891203945Sweongyo	bwn_phy_g_switch_chan(mac, 7, 0);
4892203945Sweongyo
4893203945Sweongyo	if (phy->rf_ver != 0x2050) {
4894203945Sweongyo		BWN_RF_WRITE(mac, 0x0075, 0x0080);
4895203945Sweongyo		BWN_RF_WRITE(mac, 0x0079, 0x0081);
4896203945Sweongyo	}
4897203945Sweongyo
4898203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
4899203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
4900203945Sweongyo
4901203945Sweongyo	if (phy->rf_ver == 0x2050) {
4902203945Sweongyo		BWN_RF_WRITE(mac, 0x0050, 0x0020);
4903203945Sweongyo		BWN_RF_WRITE(mac, 0x005a, 0x0070);
4904203945Sweongyo	}
4905203945Sweongyo
4906203945Sweongyo	BWN_RF_WRITE(mac, 0x005b, 0x007b);
4907203945Sweongyo	BWN_RF_WRITE(mac, 0x005c, 0x00b0);
4908203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0007);
4909203945Sweongyo
4910203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
4911203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0080);
4912203945Sweongyo	BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
4913203945Sweongyo	BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
4914203945Sweongyo
4915203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
4916203945Sweongyo	    pg->pg_txctl);
4917203945Sweongyo
4918203945Sweongyo	if (phy->rf_ver == 0x2050)
4919203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
4920203945Sweongyo
4921203945Sweongyo	BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
4922203945Sweongyo}
4923203945Sweongyo
4924203945Sweongyostatic void
4925203945Sweongyobwn_loopback_calcgain(struct bwn_mac *mac)
4926203945Sweongyo{
4927203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4928203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4929204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4930203945Sweongyo	uint16_t backup_phy[16] = { 0 };
4931203945Sweongyo	uint16_t backup_radio[3];
4932203945Sweongyo	uint16_t backup_bband;
4933203945Sweongyo	uint16_t i, j, loop_i_max;
4934203945Sweongyo	uint16_t trsw_rx;
4935203945Sweongyo	uint16_t loop1_outer_done, loop1_inner_done;
4936203945Sweongyo
4937203945Sweongyo	backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
4938203945Sweongyo	backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
4939203945Sweongyo	backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
4940203945Sweongyo	backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
4941203945Sweongyo	if (phy->rev != 1) {
4942203945Sweongyo		backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
4943203945Sweongyo		backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
4944203945Sweongyo	}
4945203945Sweongyo	backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
4946203945Sweongyo	backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
4947203945Sweongyo	backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
4948203945Sweongyo	backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
4949203945Sweongyo	backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
4950203945Sweongyo	backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
4951203945Sweongyo	backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
4952203945Sweongyo	backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
4953203945Sweongyo	backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
4954203945Sweongyo	backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
4955203945Sweongyo	backup_bband = pg->pg_bbatt.att;
4956203945Sweongyo	backup_radio[0] = BWN_RF_READ(mac, 0x52);
4957203945Sweongyo	backup_radio[1] = BWN_RF_READ(mac, 0x43);
4958203945Sweongyo	backup_radio[2] = BWN_RF_READ(mac, 0x7a);
4959203945Sweongyo
4960203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
4961203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
4962203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
4963203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
4964203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
4965203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
4966203945Sweongyo	if (phy->rev != 1) {
4967203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
4968203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
4969203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
4970203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
4971203945Sweongyo	}
4972203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
4973203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
4974203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
4975203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
4976203945Sweongyo
4977203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
4978203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
4979203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
4980203945Sweongyo
4981203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
4982203945Sweongyo	if (phy->rev != 1) {
4983203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
4984203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
4985203945Sweongyo	}
4986203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
4987203945Sweongyo
4988203945Sweongyo	if (phy->rf_rev == 8)
4989203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x000f);
4990203945Sweongyo	else {
4991203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
4992203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
4993203945Sweongyo	}
4994203945Sweongyo	bwn_phy_g_set_bbatt(mac, 11);
4995203945Sweongyo
4996203945Sweongyo	if (phy->rev >= 3)
4997203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
4998203945Sweongyo	else
4999203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5000203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5001203945Sweongyo
5002203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
5003203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
5004203945Sweongyo
5005203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
5006203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
5007203945Sweongyo
5008204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) {
5009203945Sweongyo		if (phy->rev >= 7) {
5010203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
5011203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
5012203945Sweongyo		}
5013203945Sweongyo	}
5014203945Sweongyo	BWN_RF_MASK(mac, 0x7a, 0x00f7);
5015203945Sweongyo
5016203945Sweongyo	j = 0;
5017203945Sweongyo	loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
5018203945Sweongyo	for (i = 0; i < loop_i_max; i++) {
5019203945Sweongyo		for (j = 0; j < 16; j++) {
5020203945Sweongyo			BWN_RF_WRITE(mac, 0x43, i);
5021203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
5022203945Sweongyo			    (j << 8));
5023203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5024203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5025203945Sweongyo			DELAY(20);
5026203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5027203945Sweongyo				goto done0;
5028203945Sweongyo		}
5029203945Sweongyo	}
5030203945Sweongyodone0:
5031203945Sweongyo	loop1_outer_done = i;
5032203945Sweongyo	loop1_inner_done = j;
5033203945Sweongyo	if (j >= 8) {
5034203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
5035203945Sweongyo		trsw_rx = 0x1b;
5036203945Sweongyo		for (j = j - 8; j < 16; j++) {
5037203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
5038203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5039203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5040203945Sweongyo			DELAY(20);
5041203945Sweongyo			trsw_rx -= 3;
5042203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5043203945Sweongyo				goto done1;
5044203945Sweongyo		}
5045203945Sweongyo	} else
5046203945Sweongyo		trsw_rx = 0x18;
5047203945Sweongyodone1:
5048203945Sweongyo
5049203945Sweongyo	if (phy->rev != 1) {
5050203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
5051203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
5052203945Sweongyo	}
5053203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
5054203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
5055203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
5056203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
5057203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
5058203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
5059203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
5060203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
5061203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
5062203945Sweongyo
5063203945Sweongyo	bwn_phy_g_set_bbatt(mac, backup_bband);
5064203945Sweongyo
5065203945Sweongyo	BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
5066203945Sweongyo	BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
5067203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
5068203945Sweongyo
5069203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
5070203945Sweongyo	DELAY(10);
5071203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
5072203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
5073203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
5074203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
5075203945Sweongyo
5076203945Sweongyo	pg->pg_max_lb_gain =
5077203945Sweongyo	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
5078203945Sweongyo	pg->pg_trsw_rx_gain = trsw_rx * 2;
5079203945Sweongyo}
5080203945Sweongyo
5081203945Sweongyostatic uint16_t
5082203945Sweongyobwn_rf_init_bcm2050(struct bwn_mac *mac)
5083203945Sweongyo{
5084203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5085203945Sweongyo	uint32_t tmp1 = 0, tmp2 = 0;
5086203945Sweongyo	uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
5087203945Sweongyo	    analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
5088203945Sweongyo	    radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
5089203945Sweongyo	static const uint8_t rcc_table[] = {
5090203945Sweongyo		0x02, 0x03, 0x01, 0x0f,
5091203945Sweongyo		0x06, 0x07, 0x05, 0x0f,
5092203945Sweongyo		0x0a, 0x0b, 0x09, 0x0f,
5093203945Sweongyo		0x0e, 0x0f, 0x0d, 0x0f,
5094203945Sweongyo	};
5095203945Sweongyo
5096204242Simp	loctl = lomask = reg0 = classctl = crs0 = analogoverval = analogover =
5097204242Simp	    rfoverval = rfover = cck3 = 0;
5098203945Sweongyo	radio0 = BWN_RF_READ(mac, 0x43);
5099203945Sweongyo	radio1 = BWN_RF_READ(mac, 0x51);
5100203945Sweongyo	radio2 = BWN_RF_READ(mac, 0x52);
5101203945Sweongyo	pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5102203945Sweongyo	cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5103203945Sweongyo	cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5104203945Sweongyo	cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5105203945Sweongyo
5106203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5107203945Sweongyo		cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
5108203945Sweongyo		reg0 = BWN_READ_2(mac, 0x3ec);
5109203945Sweongyo
5110203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
5111203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
5112203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
5113203945Sweongyo		rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5114203945Sweongyo		rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5115203945Sweongyo		analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5116203945Sweongyo		analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5117203945Sweongyo		crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5118203945Sweongyo		classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
5119203945Sweongyo
5120203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
5121203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
5122203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
5123203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
5124203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5125203945Sweongyo			lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5126203945Sweongyo			loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5127203945Sweongyo			if (phy->rev >= 3)
5128203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5129203945Sweongyo			else
5130203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5131203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5132203945Sweongyo		}
5133203945Sweongyo
5134203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5135203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5136203945Sweongyo			BWN_LPD(0, 1, 1)));
5137203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
5138203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
5139203945Sweongyo	}
5140203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
5141203945Sweongyo
5142203945Sweongyo	syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
5143203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
5144203945Sweongyo	reg1 = BWN_READ_2(mac, 0x3e6);
5145203945Sweongyo	reg2 = BWN_READ_2(mac, 0x3f4);
5146203945Sweongyo
5147203945Sweongyo	if (phy->analog == 0)
5148203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0122);
5149203945Sweongyo	else {
5150203945Sweongyo		if (phy->analog >= 2)
5151203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
5152203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
5153203945Sweongyo		    (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
5154203945Sweongyo	}
5155203945Sweongyo
5156203945Sweongyo	reg = BWN_RF_READ(mac, 0x60);
5157203945Sweongyo	index = (reg & 0x001e) >> 1;
5158203945Sweongyo	rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
5159203945Sweongyo
5160203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5161203945Sweongyo		BWN_RF_WRITE(mac, 0x78, 0x26);
5162203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5163203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5164203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5165203945Sweongyo			BWN_LPD(0, 1, 1)));
5166203945Sweongyo	}
5167203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
5168203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
5169203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5170203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5171203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5172203945Sweongyo			BWN_LPD(0, 0, 1)));
5173203945Sweongyo	}
5174203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
5175203945Sweongyo	BWN_RF_SET(mac, 0x51, 0x0004);
5176203945Sweongyo	if (phy->rf_rev == 8)
5177203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x1f);
5178203945Sweongyo	else {
5179203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5180203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
5181203945Sweongyo	}
5182203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5183203945Sweongyo
5184203945Sweongyo	for (i = 0; i < 16; i++) {
5185203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
5186203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5187203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5188203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5189203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5190203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5191203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5192203945Sweongyo		}
5193203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5194203945Sweongyo		DELAY(10);
5195203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5196203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5197203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5198203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5199203945Sweongyo		}
5200203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5201203945Sweongyo		DELAY(10);
5202203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5203203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5204203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5205203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5206203945Sweongyo		}
5207203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5208203945Sweongyo		DELAY(20);
5209203945Sweongyo		tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5210203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5211203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5212203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5213203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5214203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5215203945Sweongyo		}
5216203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5217203945Sweongyo	}
5218203945Sweongyo	DELAY(10);
5219203945Sweongyo
5220203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5221203945Sweongyo	tmp1++;
5222203945Sweongyo	tmp1 >>= 9;
5223203945Sweongyo
5224203945Sweongyo	for (i = 0; i < 16; i++) {
5225203945Sweongyo		radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
5226203945Sweongyo		BWN_RF_WRITE(mac, 0x78, radio78);
5227203945Sweongyo		DELAY(10);
5228203945Sweongyo		for (j = 0; j < 16; j++) {
5229203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
5230203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5231203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5232203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5233203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5234203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5235203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5236203945Sweongyo			}
5237203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5238203945Sweongyo			DELAY(10);
5239203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5240203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5241203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5242203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5243203945Sweongyo			}
5244203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5245203945Sweongyo			DELAY(10);
5246203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5247203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5248203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5249203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5250203945Sweongyo			}
5251203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5252203945Sweongyo			DELAY(10);
5253203945Sweongyo			tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5254203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5255203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5256203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5257203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5258203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5259203945Sweongyo			}
5260203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5261203945Sweongyo		}
5262203945Sweongyo		tmp2++;
5263203945Sweongyo		tmp2 >>= 8;
5264203945Sweongyo		if (tmp1 < tmp2)
5265203945Sweongyo			break;
5266203945Sweongyo	}
5267203945Sweongyo
5268203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
5269203945Sweongyo	BWN_RF_WRITE(mac, 0x51, radio1);
5270203945Sweongyo	BWN_RF_WRITE(mac, 0x52, radio2);
5271203945Sweongyo	BWN_RF_WRITE(mac, 0x43, radio0);
5272203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
5273203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
5274203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
5275203945Sweongyo	BWN_WRITE_2(mac, 0x3e6, reg1);
5276203945Sweongyo	if (phy->analog != 0)
5277203945Sweongyo		BWN_WRITE_2(mac, 0x3f4, reg2);
5278203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
5279203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
5280203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5281203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
5282203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, reg0);
5283203945Sweongyo	} else if (phy->gmode) {
5284203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO,
5285203945Sweongyo			    BWN_READ_2(mac, BWN_PHY_RADIO)
5286203945Sweongyo			    & 0x7fff);
5287203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
5288203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
5289203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
5290203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
5291203945Sweongyo			      analogoverval);
5292203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
5293203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
5294203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5295203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
5296203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
5297203945Sweongyo		}
5298203945Sweongyo	}
5299203945Sweongyo
5300203945Sweongyo	return ((i > 15) ? radio78 : rcc);
5301203945Sweongyo}
5302203945Sweongyo
5303203945Sweongyostatic void
5304203945Sweongyobwn_phy_init_b6(struct bwn_mac *mac)
5305203945Sweongyo{
5306203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5307203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5308204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5309203945Sweongyo	uint16_t offset, val;
5310203945Sweongyo	uint8_t old_channel;
5311203945Sweongyo
5312203945Sweongyo	KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
5313203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5314203945Sweongyo
5315203945Sweongyo	BWN_PHY_WRITE(mac, 0x003e, 0x817a);
5316203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
5317203945Sweongyo	if (phy->rf_rev == 4 || phy->rf_rev == 5) {
5318203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0x37);
5319203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x70);
5320203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb3);
5321203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x9b);
5322203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5323203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x88);
5324203945Sweongyo		BWN_RF_WRITE(mac, 0x5d, 0x88);
5325203945Sweongyo		BWN_RF_WRITE(mac, 0x5e, 0x88);
5326203945Sweongyo		BWN_RF_WRITE(mac, 0x7d, 0x88);
5327203945Sweongyo		bwn_hf_write(mac,
5328203945Sweongyo		    bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
5329203945Sweongyo	}
5330203945Sweongyo	if (phy->rf_rev == 8) {
5331203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0);
5332203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x40);
5333203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb7);
5334203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x98);
5335203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5336203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x6b);
5337203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0x0f);
5338204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_ALTIQ) {
5339203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xfa);
5340203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xd8);
5341203945Sweongyo		} else {
5342203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xf5);
5343203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xb8);
5344203945Sweongyo		}
5345203945Sweongyo		BWN_RF_WRITE(mac, 0x0073, 0x0003);
5346203945Sweongyo		BWN_RF_WRITE(mac, 0x007d, 0x00a8);
5347203945Sweongyo		BWN_RF_WRITE(mac, 0x007c, 0x0001);
5348203945Sweongyo		BWN_RF_WRITE(mac, 0x007e, 0x0008);
5349203945Sweongyo	}
5350203945Sweongyo	for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
5351203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5352203945Sweongyo		val -= 0x0202;
5353203945Sweongyo	}
5354203945Sweongyo	for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
5355203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5356203945Sweongyo		val -= 0x0202;
5357203945Sweongyo	}
5358203945Sweongyo	for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
5359203945Sweongyo		BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
5360203945Sweongyo		val += 0x0202;
5361203945Sweongyo	}
5362203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
5363203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0020);
5364203945Sweongyo		BWN_RF_SET(mac, 0x0051, 0x0004);
5365203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
5366203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
5367203945Sweongyo		BWN_PHY_WRITE(mac, 0x5b, 0);
5368203945Sweongyo		BWN_PHY_WRITE(mac, 0x5c, 0);
5369203945Sweongyo	}
5370203945Sweongyo
5371203945Sweongyo	old_channel = phy->chan;
5372203945Sweongyo	bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
5373203945Sweongyo
5374203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
5375203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
5376203945Sweongyo	DELAY(40);
5377203945Sweongyo	if (phy->rf_rev < 6 || phy->rf_rev == 8) {
5378203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
5379203945Sweongyo		BWN_RF_WRITE(mac, 0x50, 0x20);
5380203945Sweongyo	}
5381203945Sweongyo	if (phy->rf_rev <= 2) {
5382203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, 0x20);
5383203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x70);
5384203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x7b);
5385203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0xb0);
5386203945Sweongyo	}
5387203945Sweongyo	BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
5388203945Sweongyo
5389203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5390203945Sweongyo
5391203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0200);
5392203945Sweongyo	if (phy->rf_rev >= 6)
5393203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
5394203945Sweongyo	else
5395203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
5396203945Sweongyo	BWN_PHY_WRITE(mac, 0x0038, 0x0668);
5397203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5398203945Sweongyo	    pg->pg_txctl);
5399203945Sweongyo	if (phy->rf_rev <= 5)
5400203945Sweongyo		BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
5401203945Sweongyo	if (phy->rf_rev <= 2)
5402203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5403203945Sweongyo
5404203945Sweongyo	if (phy->analog == 4) {
5405203945Sweongyo		BWN_WRITE_2(mac, 0x3e4, 9);
5406203945Sweongyo		BWN_PHY_MASK(mac, 0x61, 0x0fff);
5407203945Sweongyo	} else
5408203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
5409203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5410203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5411203945Sweongyo	else if (phy->type == BWN_PHYTYPE_G)
5412203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0);
5413203945Sweongyo}
5414203945Sweongyo
5415203945Sweongyostatic void
5416203945Sweongyobwn_phy_init_a(struct bwn_mac *mac)
5417203945Sweongyo{
5418203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5419204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5420203945Sweongyo
5421203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
5422203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5423203945Sweongyo
5424203945Sweongyo	if (phy->rev >= 6) {
5425203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5426203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
5427203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
5428203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
5429203945Sweongyo		else
5430203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
5431203945Sweongyo	}
5432203945Sweongyo
5433203945Sweongyo	bwn_wa_init(mac);
5434203945Sweongyo
5435203945Sweongyo	if (phy->type == BWN_PHYTYPE_G &&
5436204922Sweongyo	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL))
5437203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
5438203945Sweongyo}
5439203945Sweongyo
5440203945Sweongyostatic void
5441203945Sweongyobwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
5442203945Sweongyo{
5443203945Sweongyo	int i;
5444203945Sweongyo
5445203945Sweongyo	for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
5446203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
5447203945Sweongyo}
5448203945Sweongyo
5449203945Sweongyostatic void
5450203945Sweongyobwn_wa_agc(struct bwn_mac *mac)
5451203945Sweongyo{
5452203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5453203945Sweongyo
5454203945Sweongyo	if (phy->rev == 1) {
5455203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
5456203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
5457203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
5458203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
5459203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
5460203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
5461203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
5462203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
5463203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
5464203945Sweongyo	} else {
5465203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
5466203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
5467203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
5468203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
5469203945Sweongyo	}
5470203945Sweongyo
5471203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
5472203945Sweongyo	    0x5700);
5473203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
5474203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
5475203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
5476203945Sweongyo	BWN_RF_SET(mac, 0x7a, 0x0008);
5477203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
5478203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
5479203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
5480203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
5481203945Sweongyo	if (phy->rev == 1)
5482203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
5483203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
5484203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
5485203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
5486203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
5487203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
5488203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
5489203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
5490203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
5491203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
5492203945Sweongyo	if (phy->rev == 1) {
5493203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
5494203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
5495203945Sweongyo	} else {
5496203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
5497203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
5498203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
5499203945Sweongyo		if (phy->rev >= 6) {
5500203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
5501203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
5502203945Sweongyo			    (uint16_t)~0xf000, 0x3000);
5503203945Sweongyo		}
5504203945Sweongyo	}
5505203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
5506203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
5507203945Sweongyo	if (phy->rev == 1) {
5508203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
5509203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
5510203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
5511203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
5512203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
5513203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
5514203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
5515203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
5516203945Sweongyo	} else {
5517203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
5518203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
5519203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
5520203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
5521203945Sweongyo	}
5522203945Sweongyo	if (phy->rev >= 6) {
5523203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
5524203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
5525203945Sweongyo	}
5526203945Sweongyo	BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
5527203945Sweongyo}
5528203945Sweongyo
5529203945Sweongyostatic void
5530203945Sweongyobwn_wa_grev1(struct bwn_mac *mac)
5531203945Sweongyo{
5532203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5533203945Sweongyo	int i;
5534203945Sweongyo	static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
5535203945Sweongyo	static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
5536203945Sweongyo	static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
5537203945Sweongyo
5538203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5539203945Sweongyo
5540203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5541203945Sweongyo	if (phy->rev == 1) {
5542203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5543203945Sweongyo	} else if (phy->rev == 2) {
5544203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5545203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5546203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5547203945Sweongyo	} else {
5548203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5549203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5550203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5551203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5552203945Sweongyo	}
5553203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
5554203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
5555203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
5556203945Sweongyo
5557203945Sweongyo	/* XXX support PHY-A??? */
5558203945Sweongyo	for (i = 0; i < N(bwn_tab_finefreqg); i++)
5559203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
5560203945Sweongyo		    bwn_tab_finefreqg[i]);
5561203945Sweongyo
5562203945Sweongyo	/* XXX support PHY-A??? */
5563203945Sweongyo	if (phy->rev == 1)
5564203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5565203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5566203945Sweongyo			    bwn_tab_noise_g1[i]);
5567203945Sweongyo	else
5568203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5569203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5570203945Sweongyo			    bwn_tab_noise_g2[i]);
5571203945Sweongyo
5572203945Sweongyo
5573203945Sweongyo	for (i = 0; i < N(bwn_tab_rotor); i++)
5574203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
5575203945Sweongyo		    bwn_tab_rotor[i]);
5576203945Sweongyo
5577203945Sweongyo	/* XXX support PHY-A??? */
5578203945Sweongyo	if (phy->rev >= 6) {
5579203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5580203945Sweongyo		    BWN_PHY_ENCORE_EN)
5581203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5582203945Sweongyo		else
5583203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5584203945Sweongyo	} else
5585203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5586203945Sweongyo
5587203945Sweongyo	for (i = 0; i < N(bwn_tab_retard); i++)
5588203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
5589203945Sweongyo		    bwn_tab_retard[i]);
5590203945Sweongyo
5591203945Sweongyo	if (phy->rev == 1) {
5592203945Sweongyo		for (i = 0; i < 16; i++)
5593203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
5594203945Sweongyo			    i, 0x0020);
5595203945Sweongyo	} else {
5596203945Sweongyo		for (i = 0; i < 32; i++)
5597203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5598203945Sweongyo	}
5599203945Sweongyo
5600203945Sweongyo	bwn_wa_agc(mac);
5601203945Sweongyo}
5602203945Sweongyo
5603203945Sweongyostatic void
5604203945Sweongyobwn_wa_grev26789(struct bwn_mac *mac)
5605203945Sweongyo{
5606203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5607203945Sweongyo	int i;
5608203945Sweongyo	static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
5609203945Sweongyo	uint16_t ofdmrev;
5610203945Sweongyo
5611203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5612203945Sweongyo
5613203945Sweongyo	bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
5614203945Sweongyo
5615203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5616203945Sweongyo	if (phy->rev == 1)
5617203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5618203945Sweongyo	else if (phy->rev == 2) {
5619203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5620203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5621203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5622203945Sweongyo	} else {
5623203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5624203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5625203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5626203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5627203945Sweongyo	}
5628203945Sweongyo
5629203945Sweongyo	for (i = 0; i < 64; i++)
5630203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
5631203945Sweongyo
5632203945Sweongyo	/* XXX support PHY-A??? */
5633203945Sweongyo	if (phy->rev == 1)
5634203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5635203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5636203945Sweongyo			    bwn_tab_noise_g1[i]);
5637203945Sweongyo	else
5638203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5639203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5640203945Sweongyo			    bwn_tab_noise_g2[i]);
5641203945Sweongyo
5642203945Sweongyo	/* XXX support PHY-A??? */
5643203945Sweongyo	if (phy->rev >= 6) {
5644203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5645203945Sweongyo		    BWN_PHY_ENCORE_EN)
5646203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5647203945Sweongyo		else
5648203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5649203945Sweongyo	} else
5650203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5651203945Sweongyo
5652203945Sweongyo	for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
5653203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
5654203945Sweongyo		    bwn_tab_sigmasqr2[i]);
5655203945Sweongyo
5656203945Sweongyo	if (phy->rev == 1) {
5657203945Sweongyo		for (i = 0; i < 16; i++)
5658203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
5659203945Sweongyo			    0x0020);
5660203945Sweongyo	} else {
5661203945Sweongyo		for (i = 0; i < 32; i++)
5662203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5663203945Sweongyo	}
5664203945Sweongyo
5665203945Sweongyo	bwn_wa_agc(mac);
5666203945Sweongyo
5667203945Sweongyo	ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
5668203945Sweongyo	if (ofdmrev > 2) {
5669203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5670203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
5671203945Sweongyo		else
5672203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
5673203945Sweongyo	} else {
5674203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
5675203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
5676203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
5677203945Sweongyo	}
5678203945Sweongyo
5679203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
5680203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
5681203945Sweongyo}
5682203945Sweongyo
5683203945Sweongyostatic void
5684203945Sweongyobwn_wa_init(struct bwn_mac *mac)
5685203945Sweongyo{
5686203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5687204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5688203945Sweongyo
5689203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5690203945Sweongyo
5691203945Sweongyo	switch (phy->rev) {
5692203945Sweongyo	case 1:
5693203945Sweongyo		bwn_wa_grev1(mac);
5694203945Sweongyo		break;
5695203945Sweongyo	case 2:
5696203945Sweongyo	case 6:
5697203945Sweongyo	case 7:
5698203945Sweongyo	case 8:
5699203945Sweongyo	case 9:
5700203945Sweongyo		bwn_wa_grev26789(mac);
5701203945Sweongyo		break;
5702203945Sweongyo	default:
5703203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5704203945Sweongyo	}
5705203945Sweongyo
5706204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM ||
5707204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306 ||
5708204922Sweongyo	    siba_get_pci_revid(sc->sc_dev) != 0x17) {
5709203945Sweongyo		if (phy->rev < 2) {
5710203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
5711203945Sweongyo			    0x0002);
5712203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
5713203945Sweongyo			    0x0001);
5714203945Sweongyo		} else {
5715203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
5716203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
5717204922Sweongyo			if ((siba_sprom_get_bf_lo(sc->sc_dev) &
5718204922Sweongyo			     BWN_BFL_EXTLNA) &&
5719203945Sweongyo			    (phy->rev >= 7)) {
5720203945Sweongyo				BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
5721203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5722203945Sweongyo				    0x0020, 0x0001);
5723203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5724203945Sweongyo				    0x0021, 0x0001);
5725203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5726203945Sweongyo				    0x0022, 0x0001);
5727203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5728203945Sweongyo				    0x0023, 0x0000);
5729203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5730203945Sweongyo				    0x0000, 0x0000);
5731203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5732203945Sweongyo				    0x0003, 0x0002);
5733203945Sweongyo			}
5734203945Sweongyo		}
5735203945Sweongyo	}
5736204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) {
5737203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
5738203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
5739203945Sweongyo	}
5740203945Sweongyo
5741203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
5742203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
5743203945Sweongyo}
5744203945Sweongyo
5745203945Sweongyostatic void
5746203945Sweongyobwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5747203945Sweongyo    uint16_t value)
5748203945Sweongyo{
5749203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5750203945Sweongyo	uint16_t addr;
5751203945Sweongyo
5752203945Sweongyo	addr = table + offset;
5753203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5754203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5755203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5756203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5757203945Sweongyo	}
5758203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5759203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5760203945Sweongyo}
5761203945Sweongyo
5762203945Sweongyostatic void
5763203945Sweongyobwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5764203945Sweongyo    uint32_t value)
5765203945Sweongyo{
5766203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5767203945Sweongyo	uint16_t addr;
5768203945Sweongyo
5769203945Sweongyo	addr = table + offset;
5770203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5771203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5772203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5773203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5774203945Sweongyo	}
5775203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5776203945Sweongyo
5777203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5778203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
5779203945Sweongyo}
5780203945Sweongyo
5781203945Sweongyostatic void
5782203945Sweongyobwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5783203945Sweongyo    uint16_t value)
5784203945Sweongyo{
5785203945Sweongyo
5786203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
5787203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
5788203945Sweongyo}
5789203945Sweongyo
5790203945Sweongyostatic void
5791203945Sweongyobwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
5792203945Sweongyo{
5793203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5794204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5795203945Sweongyo	unsigned int i, max_loop;
5796203945Sweongyo	uint16_t value;
5797203945Sweongyo	uint32_t buffer[5] = {
5798203945Sweongyo		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
5799203945Sweongyo	};
5800203945Sweongyo
5801203945Sweongyo	if (ofdm) {
5802203945Sweongyo		max_loop = 0x1e;
5803203945Sweongyo		buffer[0] = 0x000201cc;
5804203945Sweongyo	} else {
5805203945Sweongyo		max_loop = 0xfa;
5806203945Sweongyo		buffer[0] = 0x000b846e;
5807203945Sweongyo	}
5808203945Sweongyo
5809204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
5810203945Sweongyo
5811203945Sweongyo	for (i = 0; i < 5; i++)
5812203945Sweongyo		bwn_ram_write(mac, i * 4, buffer[i]);
5813203945Sweongyo
5814203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0000);
5815203945Sweongyo	BWN_WRITE_2(mac, 0x07c0,
5816204922Sweongyo	    (siba_get_revid(sc->sc_dev) < 11) ? 0x0000 : 0x0100);
5817203945Sweongyo	value = ((phy->type == BWN_PHYTYPE_A) ? 0x41 : 0x40);
5818203945Sweongyo	BWN_WRITE_2(mac, 0x050c, value);
5819203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5820203945Sweongyo		BWN_WRITE_2(mac, 0x0514, 0x1a02);
5821203945Sweongyo	BWN_WRITE_2(mac, 0x0508, 0x0000);
5822203945Sweongyo	BWN_WRITE_2(mac, 0x050a, 0x0000);
5823203945Sweongyo	BWN_WRITE_2(mac, 0x054c, 0x0000);
5824203945Sweongyo	BWN_WRITE_2(mac, 0x056a, 0x0014);
5825203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0826);
5826203945Sweongyo	BWN_WRITE_2(mac, 0x0500, 0x0000);
5827203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5828203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0050);
5829203945Sweongyo	else
5830203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0030);
5831203945Sweongyo
5832203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5833203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0017);
5834203945Sweongyo	for (i = 0x00; i < max_loop; i++) {
5835203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5836203945Sweongyo		if (value & 0x0080)
5837203945Sweongyo			break;
5838203945Sweongyo		DELAY(10);
5839203945Sweongyo	}
5840203945Sweongyo	for (i = 0x00; i < 0x0a; i++) {
5841203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5842203945Sweongyo		if (value & 0x0400)
5843203945Sweongyo			break;
5844203945Sweongyo		DELAY(10);
5845203945Sweongyo	}
5846203945Sweongyo	for (i = 0x00; i < 0x19; i++) {
5847203945Sweongyo		value = BWN_READ_2(mac, 0x0690);
5848203945Sweongyo		if (!(value & 0x0100))
5849203945Sweongyo			break;
5850203945Sweongyo		DELAY(10);
5851203945Sweongyo	}
5852203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5853203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0037);
5854203945Sweongyo}
5855203945Sweongyo
5856203945Sweongyostatic void
5857203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
5858203945Sweongyo{
5859203945Sweongyo	uint32_t macctl;
5860203945Sweongyo
5861203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
5862203945Sweongyo
5863203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
5864203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
5865203945Sweongyo		printf("TODO: need swap\n");
5866203945Sweongyo
5867203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
5868203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
5869203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
5870203945Sweongyo}
5871203945Sweongyo
5872203945Sweongyostatic void
5873203945Sweongyobwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
5874203945Sweongyo{
5875203945Sweongyo	uint16_t value;
5876203945Sweongyo
5877204256Sweongyo	KASSERT(mac->mac_phy.type == BWN_PHYTYPE_G,
5878203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5879203945Sweongyo
5880203945Sweongyo	value = (uint8_t) (ctl->q);
5881203945Sweongyo	value |= ((uint8_t) (ctl->i)) << 8;
5882203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
5883203945Sweongyo}
5884203945Sweongyo
5885203945Sweongyostatic uint16_t
5886203945Sweongyobwn_lo_calcfeed(struct bwn_mac *mac,
5887203945Sweongyo    uint16_t lna, uint16_t pga, uint16_t trsw_rx)
5888203945Sweongyo{
5889203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5890204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5891203945Sweongyo	uint16_t rfover;
5892203945Sweongyo	uint16_t feedthrough;
5893203945Sweongyo
5894203945Sweongyo	if (phy->gmode) {
5895203945Sweongyo		lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
5896203945Sweongyo		pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
5897203945Sweongyo
5898203945Sweongyo		KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
5899203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5900203945Sweongyo		KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
5901203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5902203945Sweongyo
5903203945Sweongyo		trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
5904203945Sweongyo
5905203945Sweongyo		rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
5906204922Sweongyo		if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) &&
5907204922Sweongyo		    phy->rev > 6)
5908203945Sweongyo			rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
5909203945Sweongyo
5910203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
5911203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5912203945Sweongyo		DELAY(10);
5913203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
5914203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5915203945Sweongyo		DELAY(10);
5916203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
5917203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5918203945Sweongyo		DELAY(10);
5919203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
5920203945Sweongyo	} else {
5921203945Sweongyo		pga |= BWN_PHY_PGACTL_UNKNOWN;
5922203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5923203945Sweongyo		DELAY(10);
5924203945Sweongyo		pga |= BWN_PHY_PGACTL_LOWBANDW;
5925203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5926203945Sweongyo		DELAY(10);
5927203945Sweongyo		pga |= BWN_PHY_PGACTL_LPF;
5928203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5929203945Sweongyo	}
5930203945Sweongyo	DELAY(21);
5931203945Sweongyo	feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5932203945Sweongyo
5933203945Sweongyo	return (feedthrough);
5934203945Sweongyo}
5935203945Sweongyo
5936203945Sweongyostatic uint16_t
5937203945Sweongyobwn_lo_txctl_regtable(struct bwn_mac *mac,
5938203945Sweongyo    uint16_t *value, uint16_t *pad_mix_gain)
5939203945Sweongyo{
5940203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5941203945Sweongyo	uint16_t reg, v, padmix;
5942203945Sweongyo
5943203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5944203945Sweongyo		v = 0x30;
5945203945Sweongyo		if (phy->rf_rev <= 5) {
5946203945Sweongyo			reg = 0x43;
5947203945Sweongyo			padmix = 0;
5948203945Sweongyo		} else {
5949203945Sweongyo			reg = 0x52;
5950203945Sweongyo			padmix = 5;
5951203945Sweongyo		}
5952203945Sweongyo	} else {
5953203945Sweongyo		if (phy->rev >= 2 && phy->rf_rev == 8) {
5954203945Sweongyo			reg = 0x43;
5955203945Sweongyo			v = 0x10;
5956203945Sweongyo			padmix = 2;
5957203945Sweongyo		} else {
5958203945Sweongyo			reg = 0x52;
5959203945Sweongyo			v = 0x30;
5960203945Sweongyo			padmix = 5;
5961203945Sweongyo		}
5962203945Sweongyo	}
5963203945Sweongyo	if (value)
5964203945Sweongyo		*value = v;
5965203945Sweongyo	if (pad_mix_gain)
5966203945Sweongyo		*pad_mix_gain = padmix;
5967203945Sweongyo
5968203945Sweongyo	return (reg);
5969203945Sweongyo}
5970203945Sweongyo
5971203945Sweongyostatic void
5972203945Sweongyobwn_lo_measure_txctl_values(struct bwn_mac *mac)
5973203945Sweongyo{
5974203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5975203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5976203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
5977203945Sweongyo	uint16_t reg, mask;
5978203945Sweongyo	uint16_t trsw_rx, pga;
5979203945Sweongyo	uint16_t rf_pctl_reg;
5980203945Sweongyo
5981203945Sweongyo	static const uint8_t tx_bias_values[] = {
5982203945Sweongyo		0x09, 0x08, 0x0a, 0x01, 0x00,
5983203945Sweongyo		0x02, 0x05, 0x04, 0x06,
5984203945Sweongyo	};
5985203945Sweongyo	static const uint8_t tx_magn_values[] = {
5986203945Sweongyo		0x70, 0x40,
5987203945Sweongyo	};
5988203945Sweongyo
5989203945Sweongyo	if (!BWN_HAS_LOOPBACK(phy)) {
5990203945Sweongyo		rf_pctl_reg = 6;
5991203945Sweongyo		trsw_rx = 2;
5992203945Sweongyo		pga = 0;
5993203945Sweongyo	} else {
5994203945Sweongyo		int lb_gain;
5995203945Sweongyo
5996203945Sweongyo		trsw_rx = 0;
5997203945Sweongyo		lb_gain = pg->pg_max_lb_gain / 2;
5998203945Sweongyo		if (lb_gain > 10) {
5999203945Sweongyo			rf_pctl_reg = 0;
6000203945Sweongyo			pga = abs(10 - lb_gain) / 6;
6001203945Sweongyo			pga = MIN(MAX(pga, 0), 15);
6002203945Sweongyo		} else {
6003203945Sweongyo			int cmp_val;
6004203945Sweongyo			int tmp;
6005203945Sweongyo
6006203945Sweongyo			pga = 0;
6007203945Sweongyo			cmp_val = 0x24;
6008203945Sweongyo			if ((phy->rev >= 2) &&
6009203945Sweongyo			    (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
6010203945Sweongyo				cmp_val = 0x3c;
6011203945Sweongyo			tmp = lb_gain;
6012203945Sweongyo			if ((10 - lb_gain) < cmp_val)
6013203945Sweongyo				tmp = (10 - lb_gain);
6014203945Sweongyo			if (tmp < 0)
6015203945Sweongyo				tmp += 6;
6016203945Sweongyo			else
6017203945Sweongyo				tmp += 3;
6018203945Sweongyo			cmp_val /= 4;
6019203945Sweongyo			tmp /= 4;
6020203945Sweongyo			if (tmp >= cmp_val)
6021203945Sweongyo				rf_pctl_reg = cmp_val;
6022203945Sweongyo			else
6023203945Sweongyo				rf_pctl_reg = tmp;
6024203945Sweongyo		}
6025203945Sweongyo	}
6026203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
6027203945Sweongyo	bwn_phy_g_set_bbatt(mac, 2);
6028203945Sweongyo
6029203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
6030203945Sweongyo	mask = ~mask;
6031203945Sweongyo	BWN_RF_MASK(mac, reg, mask);
6032203945Sweongyo
6033203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
6034203945Sweongyo		int i, j;
6035203945Sweongyo		int feedthrough;
6036203945Sweongyo		int min_feedth = 0xffff;
6037203945Sweongyo		uint8_t tx_magn, tx_bias;
6038203945Sweongyo
6039203945Sweongyo		for (i = 0; i < N(tx_magn_values); i++) {
6040203945Sweongyo			tx_magn = tx_magn_values[i];
6041203945Sweongyo			BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
6042203945Sweongyo			for (j = 0; j < N(tx_bias_values); j++) {
6043203945Sweongyo				tx_bias = tx_bias_values[j];
6044203945Sweongyo				BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
6045203945Sweongyo				feedthrough = bwn_lo_calcfeed(mac, 0, pga,
6046203945Sweongyo				    trsw_rx);
6047203945Sweongyo				if (feedthrough < min_feedth) {
6048203945Sweongyo					lo->tx_bias = tx_bias;
6049203945Sweongyo					lo->tx_magn = tx_magn;
6050203945Sweongyo					min_feedth = feedthrough;
6051203945Sweongyo				}
6052203945Sweongyo				if (lo->tx_bias == 0)
6053203945Sweongyo					break;
6054203945Sweongyo			}
6055203945Sweongyo			BWN_RF_WRITE(mac, 0x52,
6056203945Sweongyo					  (BWN_RF_READ(mac, 0x52)
6057203945Sweongyo					   & 0xff00) | lo->tx_bias | lo->
6058203945Sweongyo					  tx_magn);
6059203945Sweongyo		}
6060203945Sweongyo	} else {
6061203945Sweongyo		lo->tx_magn = 0;
6062203945Sweongyo		lo->tx_bias = 0;
6063203945Sweongyo		BWN_RF_MASK(mac, 0x52, 0xfff0);
6064203945Sweongyo	}
6065203945Sweongyo
6066203945Sweongyo	BWN_GETTIME(lo->txctl_measured_time);
6067203945Sweongyo}
6068203945Sweongyo
6069203945Sweongyostatic void
6070203945Sweongyobwn_lo_get_powervector(struct bwn_mac *mac)
6071203945Sweongyo{
6072203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6073203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6074203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6075203945Sweongyo	int i;
6076203945Sweongyo	uint64_t tmp;
6077203945Sweongyo	uint64_t power_vector = 0;
6078203945Sweongyo
6079203945Sweongyo	for (i = 0; i < 8; i += 2) {
6080203945Sweongyo		tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
6081203945Sweongyo		power_vector |= (tmp << (i * 8));
6082203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
6083203945Sweongyo	}
6084203945Sweongyo	if (power_vector)
6085203945Sweongyo		lo->power_vector = power_vector;
6086203945Sweongyo
6087203945Sweongyo	BWN_GETTIME(lo->pwr_vec_read_time);
6088203945Sweongyo}
6089203945Sweongyo
6090203945Sweongyostatic void
6091203945Sweongyobwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
6092203945Sweongyo    int use_trsw_rx)
6093203945Sweongyo{
6094203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6095203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6096203945Sweongyo	uint16_t tmp;
6097203945Sweongyo
6098203945Sweongyo	if (max_rx_gain < 0)
6099203945Sweongyo		max_rx_gain = 0;
6100203945Sweongyo
6101203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
6102203945Sweongyo		int trsw_rx = 0;
6103203945Sweongyo		int trsw_rx_gain;
6104203945Sweongyo
6105203945Sweongyo		if (use_trsw_rx) {
6106203945Sweongyo			trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
6107203945Sweongyo			if (max_rx_gain >= trsw_rx_gain) {
6108203945Sweongyo				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
6109203945Sweongyo				trsw_rx = 0x20;
6110203945Sweongyo			}
6111203945Sweongyo		} else
6112203945Sweongyo			trsw_rx_gain = max_rx_gain;
6113203945Sweongyo		if (trsw_rx_gain < 9) {
6114203945Sweongyo			pg->pg_lna_lod_gain = 0;
6115203945Sweongyo		} else {
6116203945Sweongyo			pg->pg_lna_lod_gain = 1;
6117203945Sweongyo			trsw_rx_gain -= 8;
6118203945Sweongyo		}
6119203945Sweongyo		trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
6120203945Sweongyo		pg->pg_pga_gain = trsw_rx_gain / 3;
6121203945Sweongyo		if (pg->pg_pga_gain >= 5) {
6122203945Sweongyo			pg->pg_pga_gain -= 5;
6123203945Sweongyo			pg->pg_lna_gain = 2;
6124203945Sweongyo		} else
6125203945Sweongyo			pg->pg_lna_gain = 0;
6126203945Sweongyo	} else {
6127203945Sweongyo		pg->pg_lna_gain = 0;
6128203945Sweongyo		pg->pg_trsw_rx_gain = 0x20;
6129203945Sweongyo		if (max_rx_gain >= 0x14) {
6130203945Sweongyo			pg->pg_lna_lod_gain = 1;
6131203945Sweongyo			pg->pg_pga_gain = 2;
6132203945Sweongyo		} else if (max_rx_gain >= 0x12) {
6133203945Sweongyo			pg->pg_lna_lod_gain = 1;
6134203945Sweongyo			pg->pg_pga_gain = 1;
6135203945Sweongyo		} else if (max_rx_gain >= 0xf) {
6136203945Sweongyo			pg->pg_lna_lod_gain = 1;
6137203945Sweongyo			pg->pg_pga_gain = 0;
6138203945Sweongyo		} else {
6139203945Sweongyo			pg->pg_lna_lod_gain = 0;
6140203945Sweongyo			pg->pg_pga_gain = 0;
6141203945Sweongyo		}
6142203945Sweongyo	}
6143203945Sweongyo
6144203945Sweongyo	tmp = BWN_RF_READ(mac, 0x7a);
6145203945Sweongyo	if (pg->pg_lna_lod_gain == 0)
6146203945Sweongyo		tmp &= ~0x0008;
6147203945Sweongyo	else
6148203945Sweongyo		tmp |= 0x0008;
6149203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, tmp);
6150203945Sweongyo}
6151203945Sweongyo
6152203945Sweongyostatic void
6153203945Sweongyobwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6154203945Sweongyo{
6155203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6156203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6157204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6158203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6159203945Sweongyo	struct timespec ts;
6160203945Sweongyo	uint16_t tmp;
6161203945Sweongyo
6162203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6163203945Sweongyo		sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
6164203945Sweongyo		sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
6165203945Sweongyo		sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6166203945Sweongyo		sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
6167203945Sweongyo		sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
6168203945Sweongyo
6169203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
6170203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
6171203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
6172203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
6173203945Sweongyo	}
6174203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6175203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
6176203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
6177203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
6178203945Sweongyo	}
6179203945Sweongyo	if (phy->rev >= 2) {
6180203945Sweongyo		sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
6181203945Sweongyo		sav->phy_analogoverval =
6182203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
6183203945Sweongyo		sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
6184203945Sweongyo		sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
6185203945Sweongyo		sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
6186203945Sweongyo		sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
6187203945Sweongyo		sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
6188203945Sweongyo
6189203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
6190203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
6191203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
6192203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
6193203945Sweongyo		if (phy->type == BWN_PHYTYPE_G) {
6194203945Sweongyo			if ((phy->rev >= 7) &&
6195204922Sweongyo			    (siba_sprom_get_bf_lo(sc->sc_dev) &
6196204922Sweongyo			     BWN_BFL_EXTLNA)) {
6197203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
6198203945Sweongyo			} else {
6199203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
6200203945Sweongyo			}
6201203945Sweongyo		} else {
6202203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
6203203945Sweongyo		}
6204203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
6205203945Sweongyo	}
6206203945Sweongyo	sav->reg0 = BWN_READ_2(mac, 0x3f4);
6207203945Sweongyo	sav->reg1 = BWN_READ_2(mac, 0x3e2);
6208203945Sweongyo	sav->rf0 = BWN_RF_READ(mac, 0x43);
6209203945Sweongyo	sav->rf1 = BWN_RF_READ(mac, 0x7a);
6210203945Sweongyo	sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
6211203945Sweongyo	sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
6212203945Sweongyo	sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
6213203945Sweongyo	sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6214203945Sweongyo
6215203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6216203945Sweongyo		sav->rf2 = BWN_RF_READ(mac, 0x52);
6217203945Sweongyo		sav->rf2 &= 0x00f0;
6218203945Sweongyo	}
6219203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6220203945Sweongyo		sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
6221203945Sweongyo		sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
6222203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
6223203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
6224203945Sweongyo	} else {
6225203945Sweongyo		BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
6226203945Sweongyo			    | 0x8000);
6227203945Sweongyo	}
6228203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
6229203945Sweongyo		    & 0xf000);
6230203945Sweongyo
6231203945Sweongyo	tmp =
6232203945Sweongyo	    (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
6233203945Sweongyo	BWN_PHY_WRITE(mac, tmp, 0x007f);
6234203945Sweongyo
6235203945Sweongyo	tmp = sav->phy_syncctl;
6236203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
6237203945Sweongyo	tmp = sav->rf1;
6238203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
6239203945Sweongyo
6240203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
6241203945Sweongyo	if (phy->type == BWN_PHYTYPE_G ||
6242203945Sweongyo	    (phy->type == BWN_PHYTYPE_B &&
6243203945Sweongyo	     phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
6244203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
6245203945Sweongyo	} else
6246203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
6247203945Sweongyo	if (phy->rev >= 2)
6248203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
6249203945Sweongyo	bwn_phy_g_switch_chan(mac, 6, 0);
6250203945Sweongyo	BWN_RF_READ(mac, 0x51);
6251203945Sweongyo	if (phy->type == BWN_PHYTYPE_G)
6252203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
6253203945Sweongyo
6254203945Sweongyo	nanouptime(&ts);
6255203945Sweongyo	if (time_before(lo->txctl_measured_time,
6256203945Sweongyo	    (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
6257203945Sweongyo		bwn_lo_measure_txctl_values(mac);
6258203945Sweongyo
6259203945Sweongyo	if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
6260203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
6261203945Sweongyo	else {
6262203945Sweongyo		if (phy->type == BWN_PHYTYPE_B)
6263203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6264203945Sweongyo		else
6265203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
6266203945Sweongyo	}
6267203945Sweongyo}
6268203945Sweongyo
6269203945Sweongyostatic void
6270203945Sweongyobwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6271203945Sweongyo{
6272203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6273203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6274203945Sweongyo	uint16_t tmp;
6275203945Sweongyo
6276203945Sweongyo	if (phy->rev >= 2) {
6277203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6278203945Sweongyo		tmp = (pg->pg_pga_gain << 8);
6279203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
6280203945Sweongyo		DELAY(5);
6281203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
6282203945Sweongyo		DELAY(2);
6283203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
6284203945Sweongyo	} else {
6285203945Sweongyo		tmp = (pg->pg_pga_gain | 0xefa0);
6286203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
6287203945Sweongyo	}
6288203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
6289203945Sweongyo		if (phy->rev >= 3)
6290203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
6291203945Sweongyo		else
6292203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6293203945Sweongyo		if (phy->rev >= 2)
6294203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
6295203945Sweongyo		else
6296203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
6297203945Sweongyo	}
6298203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, sav->reg0);
6299203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
6300203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
6301203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
6302203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
6303203945Sweongyo	BWN_RF_WRITE(mac, 0x43, sav->rf0);
6304203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, sav->rf1);
6305203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6306203945Sweongyo		tmp = sav->rf2;
6307203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
6308203945Sweongyo	}
6309203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, sav->reg1);
6310203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6311203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
6312203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
6313203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
6314203945Sweongyo	}
6315203945Sweongyo	if (phy->rev >= 2) {
6316203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
6317203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
6318203945Sweongyo			      sav->phy_analogoverval);
6319203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
6320203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
6321203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
6322203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
6323203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
6324203945Sweongyo	}
6325203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6326203945Sweongyo		tmp = (sav->phy_lomask & 0xbfff);
6327203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
6328203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
6329203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
6330203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
6331203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
6332203945Sweongyo	}
6333203945Sweongyo	bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
6334203945Sweongyo}
6335203945Sweongyo
6336203945Sweongyostatic int
6337203945Sweongyobwn_lo_probe_loctl(struct bwn_mac *mac,
6338203945Sweongyo    struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
6339203945Sweongyo{
6340203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6341203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6342203945Sweongyo	struct bwn_loctl orig, test;
6343203945Sweongyo	struct bwn_loctl prev = { -100, -100 };
6344203945Sweongyo	static const struct bwn_loctl modifiers[] = {
6345203945Sweongyo		{  1,  1,}, {  1,  0,}, {  1, -1,}, {  0, -1,},
6346203945Sweongyo		{ -1, -1,}, { -1,  0,}, { -1,  1,}, {  0,  1,}
6347203945Sweongyo	};
6348203945Sweongyo	int begin, end, lower = 0, i;
6349203945Sweongyo	uint16_t feedth;
6350203945Sweongyo
6351203945Sweongyo	if (d->curstate == 0) {
6352203945Sweongyo		begin = 1;
6353203945Sweongyo		end = 8;
6354203945Sweongyo	} else if (d->curstate % 2 == 0) {
6355203945Sweongyo		begin = d->curstate - 1;
6356203945Sweongyo		end = d->curstate + 1;
6357203945Sweongyo	} else {
6358203945Sweongyo		begin = d->curstate - 2;
6359203945Sweongyo		end = d->curstate + 2;
6360203945Sweongyo	}
6361203945Sweongyo	if (begin < 1)
6362203945Sweongyo		begin += 8;
6363203945Sweongyo	if (end > 8)
6364203945Sweongyo		end -= 8;
6365203945Sweongyo
6366203945Sweongyo	memcpy(&orig, probe, sizeof(struct bwn_loctl));
6367203945Sweongyo	i = begin;
6368203945Sweongyo	d->curstate = i;
6369203945Sweongyo	while (1) {
6370203945Sweongyo		KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
6371203945Sweongyo		memcpy(&test, &orig, sizeof(struct bwn_loctl));
6372203945Sweongyo		test.i += modifiers[i - 1].i * d->multipler;
6373203945Sweongyo		test.q += modifiers[i - 1].q * d->multipler;
6374203945Sweongyo		if ((test.i != prev.i || test.q != prev.q) &&
6375203945Sweongyo		    (abs(test.i) <= 16 && abs(test.q) <= 16)) {
6376203945Sweongyo			bwn_lo_write(mac, &test);
6377203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6378203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6379203945Sweongyo			if (feedth < d->feedth) {
6380203945Sweongyo				memcpy(probe, &test,
6381203945Sweongyo				    sizeof(struct bwn_loctl));
6382203945Sweongyo				lower = 1;
6383203945Sweongyo				d->feedth = feedth;
6384203945Sweongyo				if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
6385203945Sweongyo					break;
6386203945Sweongyo			}
6387203945Sweongyo		}
6388203945Sweongyo		memcpy(&prev, &test, sizeof(prev));
6389203945Sweongyo		if (i == end)
6390203945Sweongyo			break;
6391203945Sweongyo		if (i == 8)
6392203945Sweongyo			i = 1;
6393203945Sweongyo		else
6394203945Sweongyo			i++;
6395203945Sweongyo		d->curstate = i;
6396203945Sweongyo	}
6397203945Sweongyo
6398203945Sweongyo	return (lower);
6399203945Sweongyo}
6400203945Sweongyo
6401203945Sweongyostatic void
6402203945Sweongyobwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
6403203945Sweongyo{
6404203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6405203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6406203945Sweongyo	struct bwn_lo_g_sm d;
6407203945Sweongyo	struct bwn_loctl probe;
6408203945Sweongyo	int lower, repeat, cnt = 0;
6409203945Sweongyo	uint16_t feedth;
6410203945Sweongyo
6411203945Sweongyo	d.nmeasure = 0;
6412203945Sweongyo	d.multipler = 1;
6413203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6414203945Sweongyo		d.multipler = 3;
6415203945Sweongyo
6416203945Sweongyo	memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
6417203945Sweongyo	repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
6418203945Sweongyo
6419203945Sweongyo	do {
6420203945Sweongyo		bwn_lo_write(mac, &d.loctl);
6421203945Sweongyo		feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6422203945Sweongyo		    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6423203945Sweongyo		if (feedth < 0x258) {
6424203945Sweongyo			if (feedth >= 0x12c)
6425203945Sweongyo				*rxgain += 6;
6426203945Sweongyo			else
6427203945Sweongyo				*rxgain += 3;
6428203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6429203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6430203945Sweongyo		}
6431203945Sweongyo		d.feedth = feedth;
6432203945Sweongyo		d.curstate = 0;
6433203945Sweongyo		do {
6434203945Sweongyo			KASSERT(d.curstate >= 0 && d.curstate <= 8,
6435203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
6436203945Sweongyo			memcpy(&probe, &d.loctl,
6437203945Sweongyo			       sizeof(struct bwn_loctl));
6438203945Sweongyo			lower = bwn_lo_probe_loctl(mac, &probe, &d);
6439203945Sweongyo			if (!lower)
6440203945Sweongyo				break;
6441203945Sweongyo			if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
6442203945Sweongyo				break;
6443203945Sweongyo			memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
6444203945Sweongyo			d.nmeasure++;
6445203945Sweongyo		} while (d.nmeasure < 24);
6446203945Sweongyo		memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
6447203945Sweongyo
6448203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
6449203945Sweongyo			if (d.feedth > 0x1194)
6450203945Sweongyo				*rxgain -= 6;
6451203945Sweongyo			else if (d.feedth < 0x5dc)
6452203945Sweongyo				*rxgain += 3;
6453203945Sweongyo			if (cnt == 0) {
6454203945Sweongyo				if (d.feedth <= 0x5dc) {
6455203945Sweongyo					d.multipler = 1;
6456203945Sweongyo					cnt++;
6457203945Sweongyo				} else
6458203945Sweongyo					d.multipler = 2;
6459203945Sweongyo			} else if (cnt == 2)
6460203945Sweongyo				d.multipler = 1;
6461203945Sweongyo		}
6462203945Sweongyo		bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
6463203945Sweongyo	} while (++cnt < repeat);
6464203945Sweongyo}
6465203945Sweongyo
6466203945Sweongyostatic struct bwn_lo_calib *
6467203945Sweongyobwn_lo_calibset(struct bwn_mac *mac,
6468203945Sweongyo    const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
6469203945Sweongyo{
6470203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6471203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6472203945Sweongyo	struct bwn_loctl loctl = { 0, 0 };
6473203945Sweongyo	struct bwn_lo_calib *cal;
6474204242Simp	struct bwn_lo_g_value sval = { 0 };
6475203945Sweongyo	int rxgain;
6476203945Sweongyo	uint16_t pad, reg, value;
6477203945Sweongyo
6478203945Sweongyo	sval.old_channel = phy->chan;
6479203945Sweongyo	bwn_mac_suspend(mac);
6480203945Sweongyo	bwn_lo_save(mac, &sval);
6481203945Sweongyo
6482203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &value, &pad);
6483203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
6484203945Sweongyo	BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
6485203945Sweongyo
6486203945Sweongyo	rxgain = (rfatt->att * 2) + (bbatt->att / 2);
6487203945Sweongyo	if (rfatt->padmix)
6488203945Sweongyo		rxgain -= pad;
6489203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6490203945Sweongyo		rxgain += pg->pg_max_lb_gain;
6491203945Sweongyo	bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
6492203945Sweongyo	bwn_phy_g_set_bbatt(mac, bbatt->att);
6493203945Sweongyo	bwn_lo_probe_sm(mac, &loctl, &rxgain);
6494203945Sweongyo
6495203945Sweongyo	bwn_lo_restore(mac, &sval);
6496203945Sweongyo	bwn_mac_enable(mac);
6497203945Sweongyo
6498203945Sweongyo	cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
6499203945Sweongyo	if (!cal) {
6500203945Sweongyo		device_printf(mac->mac_sc->sc_dev, "out of memory\n");
6501203945Sweongyo		return (NULL);
6502203945Sweongyo	}
6503203945Sweongyo	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
6504203945Sweongyo	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
6505203945Sweongyo	memcpy(&cal->ctl, &loctl, sizeof(loctl));
6506203945Sweongyo
6507203945Sweongyo	BWN_GETTIME(cal->calib_time);
6508203945Sweongyo
6509203945Sweongyo	return (cal);
6510203945Sweongyo}
6511203945Sweongyo
6512203945Sweongyostatic struct bwn_lo_calib *
6513203945Sweongyobwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
6514203945Sweongyo    const struct bwn_rfatt *rfatt)
6515203945Sweongyo{
6516203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
6517203945Sweongyo	struct bwn_lo_calib *c;
6518203945Sweongyo
6519203945Sweongyo	TAILQ_FOREACH(c, &lo->calib_list, list) {
6520203945Sweongyo		if (!BWN_BBATTCMP(&c->bbatt, bbatt))
6521203945Sweongyo			continue;
6522203945Sweongyo		if (!BWN_RFATTCMP(&c->rfatt, rfatt))
6523203945Sweongyo			continue;
6524203945Sweongyo		return (c);
6525203945Sweongyo	}
6526203945Sweongyo
6527203945Sweongyo	c = bwn_lo_calibset(mac, bbatt, rfatt);
6528203945Sweongyo	if (!c)
6529203945Sweongyo		return (NULL);
6530203945Sweongyo	TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
6531203945Sweongyo
6532203945Sweongyo	return (c);
6533203945Sweongyo}
6534203945Sweongyo
6535203945Sweongyostatic void
6536203945Sweongyobwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
6537203945Sweongyo{
6538203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6539203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6540203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6541203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6542203945Sweongyo	const struct bwn_rfatt *rfatt;
6543203945Sweongyo	const struct bwn_bbatt *bbatt;
6544203945Sweongyo	uint64_t pvector;
6545203945Sweongyo	int i;
6546203945Sweongyo	int rf_offset, bb_offset;
6547203945Sweongyo	uint8_t changed = 0;
6548203945Sweongyo
6549203945Sweongyo	KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
6550203945Sweongyo	KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
6551203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6552203945Sweongyo
6553203945Sweongyo	pvector = lo->power_vector;
6554203945Sweongyo	if (!update && !pvector)
6555203945Sweongyo		return;
6556203945Sweongyo
6557203945Sweongyo	bwn_mac_suspend(mac);
6558203945Sweongyo
6559203945Sweongyo	for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
6560203945Sweongyo		struct bwn_lo_calib *cal;
6561203945Sweongyo		int idx;
6562203945Sweongyo		uint16_t val;
6563203945Sweongyo
6564203945Sweongyo		if (!update && !(pvector & (((uint64_t)1ULL) << i)))
6565203945Sweongyo			continue;
6566203945Sweongyo		bb_offset = i / lo->rfatt.len;
6567203945Sweongyo		rf_offset = i % lo->rfatt.len;
6568203945Sweongyo		bbatt = &(lo->bbatt.array[bb_offset]);
6569203945Sweongyo		rfatt = &(lo->rfatt.array[rf_offset]);
6570203945Sweongyo
6571203945Sweongyo		cal = bwn_lo_calibset(mac, bbatt, rfatt);
6572203945Sweongyo		if (!cal) {
6573203945Sweongyo			device_printf(sc->sc_dev, "LO: Could not "
6574203945Sweongyo			    "calibrate DC table entry\n");
6575203945Sweongyo			continue;
6576203945Sweongyo		}
6577203945Sweongyo		val = (uint8_t)(cal->ctl.q);
6578203945Sweongyo		val |= ((uint8_t)(cal->ctl.i)) << 4;
6579203945Sweongyo		free(cal, M_DEVBUF);
6580203945Sweongyo
6581203945Sweongyo		idx = i / 2;
6582203945Sweongyo		if (i % 2)
6583203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
6584203945Sweongyo			    | ((val & 0x00ff) << 8);
6585203945Sweongyo		else
6586203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
6587203945Sweongyo			    | (val & 0x00ff);
6588203945Sweongyo		changed = 1;
6589203945Sweongyo	}
6590203945Sweongyo	if (changed) {
6591203945Sweongyo		for (i = 0; i < BWN_DC_LT_SIZE; i++)
6592203945Sweongyo			BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
6593203945Sweongyo	}
6594203945Sweongyo	bwn_mac_enable(mac);
6595203945Sweongyo}
6596203945Sweongyo
6597203945Sweongyostatic void
6598203945Sweongyobwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
6599203945Sweongyo{
6600203945Sweongyo
6601203945Sweongyo	if (!rf->padmix)
6602203945Sweongyo		return;
6603203945Sweongyo	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
6604203945Sweongyo		rf->att = 4;
6605203945Sweongyo}
6606203945Sweongyo
6607203945Sweongyostatic void
6608203945Sweongyobwn_lo_g_adjust(struct bwn_mac *mac)
6609203945Sweongyo{
6610203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
6611203945Sweongyo	struct bwn_lo_calib *cal;
6612203945Sweongyo	struct bwn_rfatt rf;
6613203945Sweongyo
6614203945Sweongyo	memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
6615203945Sweongyo	bwn_lo_fixup_rfatt(&rf);
6616203945Sweongyo
6617203945Sweongyo	cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
6618203945Sweongyo	if (!cal)
6619203945Sweongyo		return;
6620203945Sweongyo	bwn_lo_write(mac, &cal->ctl);
6621203945Sweongyo}
6622203945Sweongyo
6623203945Sweongyostatic void
6624203945Sweongyobwn_lo_g_init(struct bwn_mac *mac)
6625203945Sweongyo{
6626203945Sweongyo
6627203945Sweongyo	if (!bwn_has_hwpctl(mac))
6628203945Sweongyo		return;
6629203945Sweongyo
6630203945Sweongyo	bwn_lo_get_powervector(mac);
6631203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
6632203945Sweongyo}
6633203945Sweongyo
6634203945Sweongyostatic void
6635203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
6636203945Sweongyo{
6637203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6638203945Sweongyo	int i;
6639203945Sweongyo	uint32_t tmp;
6640203945Sweongyo
6641203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6642203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6643203945Sweongyo
6644203945Sweongyo	if (mac->mac_suspended == 0) {
6645203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
6646203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6647203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
6648203945Sweongyo			    & ~BWN_MACCTL_ON);
6649203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6650203945Sweongyo		for (i = 35; i; i--) {
6651203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6652203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6653203945Sweongyo				goto out;
6654203945Sweongyo			DELAY(10);
6655203945Sweongyo		}
6656203945Sweongyo		for (i = 40; i; i--) {
6657203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6658203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6659203945Sweongyo				goto out;
6660203945Sweongyo			DELAY(1000);
6661203945Sweongyo		}
6662203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
6663203945Sweongyo	}
6664203945Sweongyoout:
6665203945Sweongyo	mac->mac_suspended++;
6666203945Sweongyo}
6667203945Sweongyo
6668203945Sweongyostatic void
6669203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
6670203945Sweongyo{
6671203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6672203945Sweongyo	uint16_t state;
6673203945Sweongyo
6674203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
6675203945Sweongyo	    BWN_SHARED_UCODESTAT);
6676203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
6677203945Sweongyo	    state != BWN_SHARED_UCODESTAT_SLEEP)
6678203945Sweongyo		device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
6679203945Sweongyo
6680203945Sweongyo	mac->mac_suspended--;
6681203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6682203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6683203945Sweongyo	if (mac->mac_suspended == 0) {
6684203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6685203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
6686203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
6687203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6688203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
6689203945Sweongyo		bwn_psctl(mac, 0);
6690203945Sweongyo	}
6691203945Sweongyo}
6692203945Sweongyo
6693203945Sweongyostatic void
6694203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
6695203945Sweongyo{
6696204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6697203945Sweongyo	int i;
6698203945Sweongyo	uint16_t ucstat;
6699203945Sweongyo
6700203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
6701203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6702203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
6703203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6704203945Sweongyo
6705203945Sweongyo	/* XXX forcibly awake and hwps-off */
6706203945Sweongyo
6707203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
6708203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
6709203945Sweongyo	    ~BWN_MACCTL_HWPS);
6710203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
6711204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
6712203945Sweongyo		for (i = 0; i < 100; i++) {
6713203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
6714203945Sweongyo			    BWN_SHARED_UCODESTAT);
6715203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
6716203945Sweongyo				break;
6717203945Sweongyo			DELAY(10);
6718203945Sweongyo		}
6719203945Sweongyo	}
6720203945Sweongyo}
6721203945Sweongyo
6722203945Sweongyostatic int16_t
6723203945Sweongyobwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
6724203945Sweongyo{
6725203945Sweongyo
6726203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
6727203945Sweongyo	return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
6728203945Sweongyo}
6729203945Sweongyo
6730203945Sweongyostatic void
6731203945Sweongyobwn_nrssi_threshold(struct bwn_mac *mac)
6732203945Sweongyo{
6733203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6734203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6735204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6736203945Sweongyo	int32_t a, b;
6737203945Sweongyo	int16_t tmp16;
6738203945Sweongyo	uint16_t tmpu16;
6739203945Sweongyo
6740203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
6741203945Sweongyo
6742204922Sweongyo	if (phy->gmode && (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
6743203945Sweongyo		if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
6744203945Sweongyo			a = 0x13;
6745203945Sweongyo			b = 0x12;
6746203945Sweongyo		} else {
6747203945Sweongyo			a = 0xe;
6748203945Sweongyo			b = 0x11;
6749203945Sweongyo		}
6750203945Sweongyo
6751203945Sweongyo		a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6752203945Sweongyo		a += (pg->pg_nrssi[0] << 6);
6753203945Sweongyo		a += (a < 32) ? 31 : 32;
6754203945Sweongyo		a = a >> 6;
6755203945Sweongyo		a = MIN(MAX(a, -31), 31);
6756203945Sweongyo
6757203945Sweongyo		b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6758203945Sweongyo		b += (pg->pg_nrssi[0] << 6);
6759203945Sweongyo		if (b < 32)
6760203945Sweongyo			b += 31;
6761203945Sweongyo		else
6762203945Sweongyo			b += 32;
6763203945Sweongyo		b = b >> 6;
6764203945Sweongyo		b = MIN(MAX(b, -31), 31);
6765203945Sweongyo
6766203945Sweongyo		tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
6767203945Sweongyo		tmpu16 |= ((uint32_t)b & 0x0000003f);
6768203945Sweongyo		tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
6769203945Sweongyo		BWN_PHY_WRITE(mac, 0x048a, tmpu16);
6770203945Sweongyo		return;
6771203945Sweongyo	}
6772203945Sweongyo
6773203945Sweongyo	tmp16 = bwn_nrssi_read(mac, 0x20);
6774203945Sweongyo	if (tmp16 >= 0x20)
6775203945Sweongyo		tmp16 -= 0x40;
6776203945Sweongyo	BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
6777203945Sweongyo}
6778203945Sweongyo
6779203945Sweongyostatic void
6780203945Sweongyobwn_nrssi_slope_11g(struct bwn_mac *mac)
6781203945Sweongyo{
6782203945Sweongyo#define	SAVE_RF_MAX		3
6783203945Sweongyo#define	SAVE_PHY_COMM_MAX	4
6784203945Sweongyo#define	SAVE_PHY3_MAX		8
6785203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6786203945Sweongyo		{ 0x7a, 0x52, 0x43 };
6787203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
6788203945Sweongyo		{ 0x15, 0x5a, 0x59, 0x58 };
6789203945Sweongyo	static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
6790203945Sweongyo		0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
6791203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6792203945Sweongyo	};
6793203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6794203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6795203945Sweongyo	int32_t i, tmp32, phy3_idx = 0;
6796203945Sweongyo	uint16_t delta, tmp;
6797203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6798203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6799203945Sweongyo	uint16_t save_phy3[SAVE_PHY3_MAX];
6800203945Sweongyo	uint16_t ant_div, phy0, chan_ex;
6801203945Sweongyo	int16_t nrssi0, nrssi1;
6802203945Sweongyo
6803203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
6804203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6805203945Sweongyo
6806203945Sweongyo	if (phy->rf_rev >= 9)
6807203945Sweongyo		return;
6808203945Sweongyo	if (phy->rf_rev == 8)
6809203945Sweongyo		bwn_nrssi_offset(mac);
6810203945Sweongyo
6811203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
6812203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, 0xfffc);
6813203945Sweongyo
6814203945Sweongyo	/*
6815203945Sweongyo	 * Save RF/PHY registers for later restoration
6816203945Sweongyo	 */
6817203945Sweongyo	ant_div = BWN_READ_2(mac, 0x03e2);
6818203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
6819203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6820203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6821203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6822203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6823203945Sweongyo
6824203945Sweongyo	phy0 = BWN_READ_2(mac, BWN_PHY0);
6825203945Sweongyo	chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
6826203945Sweongyo	if (phy->rev >= 3) {
6827203945Sweongyo		for (i = 0; i < SAVE_PHY3_MAX; ++i)
6828203945Sweongyo			save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
6829203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6830203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
6831203945Sweongyo		switch (phy->rev) {
6832203945Sweongyo		case 4:
6833203945Sweongyo		case 6:
6834203945Sweongyo		case 7:
6835203945Sweongyo			BWN_PHY_SET(mac, 0x0478, 0x0100);
6836203945Sweongyo			BWN_PHY_SET(mac, 0x0801, 0x0040);
6837203945Sweongyo			break;
6838203945Sweongyo		case 3:
6839203945Sweongyo		case 5:
6840203945Sweongyo			BWN_PHY_MASK(mac, 0x0801, 0xffbf);
6841203945Sweongyo			break;
6842203945Sweongyo		}
6843203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
6844203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
6845203945Sweongyo	}
6846203945Sweongyo	/*
6847203945Sweongyo	 * Calculate nrssi0
6848203945Sweongyo	 */
6849203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
6850203945Sweongyo	bwn_set_all_gains(mac, 0, 8, 0);
6851203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x00f7);
6852203945Sweongyo	if (phy->rev >= 2) {
6853203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
6854203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
6855203945Sweongyo	}
6856203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
6857203945Sweongyo	DELAY(20);
6858203945Sweongyo
6859203945Sweongyo	nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6860203945Sweongyo	if (nrssi0 >= 0x0020)
6861203945Sweongyo		nrssi0 -= 0x0040;
6862203945Sweongyo
6863203945Sweongyo	/*
6864203945Sweongyo	 * Calculate nrssi1
6865203945Sweongyo	 */
6866203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x007f);
6867203945Sweongyo	if (phy->rev >= 2)
6868203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
6869203945Sweongyo
6870203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
6871203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
6872203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x000f);
6873203945Sweongyo	BWN_PHY_WRITE(mac, 0x0015, 0xf330);
6874203945Sweongyo	if (phy->rev >= 2) {
6875203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
6876203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
6877203945Sweongyo	}
6878203945Sweongyo
6879203945Sweongyo	bwn_set_all_gains(mac, 3, 0, 1);
6880203945Sweongyo	if (phy->rf_rev == 8) {
6881203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, 0x001f);
6882203945Sweongyo	} else {
6883203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
6884203945Sweongyo		BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
6885203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
6886203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
6887203945Sweongyo	}
6888203945Sweongyo	BWN_PHY_WRITE(mac, 0x005a, 0x0480);
6889203945Sweongyo	BWN_PHY_WRITE(mac, 0x0059, 0x0810);
6890203945Sweongyo	BWN_PHY_WRITE(mac, 0x0058, 0x000d);
6891203945Sweongyo	DELAY(20);
6892203945Sweongyo	nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6893203945Sweongyo
6894203945Sweongyo	/*
6895203945Sweongyo	 * Install calculated narrow RSSI values
6896203945Sweongyo	 */
6897203945Sweongyo	if (nrssi1 >= 0x0020)
6898203945Sweongyo		nrssi1 -= 0x0040;
6899203945Sweongyo	if (nrssi0 == nrssi1)
6900203945Sweongyo		pg->pg_nrssi_slope = 0x00010000;
6901203945Sweongyo	else
6902203945Sweongyo		pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
6903203945Sweongyo	if (nrssi0 >= -4) {
6904203945Sweongyo		pg->pg_nrssi[0] = nrssi1;
6905203945Sweongyo		pg->pg_nrssi[1] = nrssi0;
6906203945Sweongyo	}
6907203945Sweongyo
6908203945Sweongyo	/*
6909203945Sweongyo	 * Restore saved RF/PHY registers
6910203945Sweongyo	 */
6911203945Sweongyo	if (phy->rev >= 3) {
6912203945Sweongyo		for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
6913203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
6914203945Sweongyo			    save_phy3[phy3_idx]);
6915203945Sweongyo		}
6916203945Sweongyo	}
6917203945Sweongyo	if (phy->rev >= 2) {
6918203945Sweongyo		BWN_PHY_MASK(mac, 0x0812, 0xffcf);
6919203945Sweongyo		BWN_PHY_MASK(mac, 0x0811, 0xffcf);
6920203945Sweongyo	}
6921203945Sweongyo
6922203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6923203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
6924203945Sweongyo
6925203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, ant_div);
6926203945Sweongyo	BWN_WRITE_2(mac, 0x03e6, phy0);
6927203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
6928203945Sweongyo
6929203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6930203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
6931203945Sweongyo
6932203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
6933203945Sweongyo	BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
6934203945Sweongyo	bwn_set_original_gains(mac);
6935203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
6936203945Sweongyo	if (phy->rev >= 3) {
6937203945Sweongyo		for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
6938203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
6939203945Sweongyo			    save_phy3[phy3_idx]);
6940203945Sweongyo		}
6941203945Sweongyo	}
6942203945Sweongyo
6943203945Sweongyo	delta = 0x1f - pg->pg_nrssi[0];
6944203945Sweongyo	for (i = 0; i < 64; i++) {
6945203945Sweongyo		tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
6946203945Sweongyo		tmp32 = MIN(MAX(tmp32, 0), 0x3f);
6947203945Sweongyo		pg->pg_nrssi_lt[i] = tmp32;
6948203945Sweongyo	}
6949203945Sweongyo
6950203945Sweongyo	bwn_nrssi_threshold(mac);
6951203945Sweongyo#undef SAVE_RF_MAX
6952203945Sweongyo#undef SAVE_PHY_COMM_MAX
6953203945Sweongyo#undef SAVE_PHY3_MAX
6954203945Sweongyo}
6955203945Sweongyo
6956203945Sweongyostatic void
6957203945Sweongyobwn_nrssi_offset(struct bwn_mac *mac)
6958203945Sweongyo{
6959203945Sweongyo#define	SAVE_RF_MAX		2
6960203945Sweongyo#define	SAVE_PHY_COMM_MAX	10
6961203945Sweongyo#define	SAVE_PHY6_MAX		8
6962203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6963203945Sweongyo		{ 0x7a, 0x43 };
6964203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
6965203945Sweongyo		0x0001, 0x0811, 0x0812, 0x0814,
6966203945Sweongyo		0x0815, 0x005a, 0x0059, 0x0058,
6967203945Sweongyo		0x000a, 0x0003
6968203945Sweongyo	};
6969203945Sweongyo	static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
6970203945Sweongyo		0x002e, 0x002f, 0x080f, 0x0810,
6971203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6972203945Sweongyo	};
6973203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6974203945Sweongyo	int i, phy6_idx = 0;
6975203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6976203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6977203945Sweongyo	uint16_t save_phy6[SAVE_PHY6_MAX];
6978203945Sweongyo	int16_t nrssi;
6979203945Sweongyo	uint16_t saved = 0xffff;
6980203945Sweongyo
6981203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6982203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6983203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6984203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6985203945Sweongyo
6986203945Sweongyo	BWN_PHY_MASK(mac, 0x0429, 0x7fff);
6987203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
6988203945Sweongyo	BWN_PHY_SET(mac, 0x0811, 0x000c);
6989203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
6990203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
6991203945Sweongyo	if (phy->rev >= 6) {
6992203945Sweongyo		for (i = 0; i < SAVE_PHY6_MAX; ++i)
6993203945Sweongyo			save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
6994203945Sweongyo
6995203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6996203945Sweongyo		BWN_PHY_WRITE(mac, 0x002f, 0);
6997203945Sweongyo		BWN_PHY_WRITE(mac, 0x080f, 0);
6998203945Sweongyo		BWN_PHY_WRITE(mac, 0x0810, 0);
6999203945Sweongyo		BWN_PHY_SET(mac, 0x0478, 0x0100);
7000203945Sweongyo		BWN_PHY_SET(mac, 0x0801, 0x0040);
7001203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
7002203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
7003203945Sweongyo	}
7004203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
7005203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
7006203945Sweongyo	DELAY(30);
7007203945Sweongyo
7008203945Sweongyo	nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7009203945Sweongyo	if (nrssi >= 0x20)
7010203945Sweongyo		nrssi -= 0x40;
7011203945Sweongyo	if (nrssi == 31) {
7012203945Sweongyo		for (i = 7; i >= 4; i--) {
7013203945Sweongyo			BWN_RF_WRITE(mac, 0x007b, i);
7014203945Sweongyo			DELAY(20);
7015203945Sweongyo			nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
7016203945Sweongyo			    0x003f);
7017203945Sweongyo			if (nrssi >= 0x20)
7018203945Sweongyo				nrssi -= 0x40;
7019203945Sweongyo			if (nrssi < 31 && saved == 0xffff)
7020203945Sweongyo				saved = i;
7021203945Sweongyo		}
7022203945Sweongyo		if (saved == 0xffff)
7023203945Sweongyo			saved = 4;
7024203945Sweongyo	} else {
7025203945Sweongyo		BWN_RF_MASK(mac, 0x007a, 0x007f);
7026203945Sweongyo		if (phy->rev != 1) {
7027203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0001);
7028203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffe);
7029203945Sweongyo		}
7030203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x000c);
7031203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x000c);
7032203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x0030);
7033203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x0030);
7034203945Sweongyo		BWN_PHY_WRITE(mac, 0x005a, 0x0480);
7035203945Sweongyo		BWN_PHY_WRITE(mac, 0x0059, 0x0810);
7036203945Sweongyo		BWN_PHY_WRITE(mac, 0x0058, 0x000d);
7037203945Sweongyo		if (phy->rev == 0)
7038203945Sweongyo			BWN_PHY_WRITE(mac, 0x0003, 0x0122);
7039203945Sweongyo		else
7040203945Sweongyo			BWN_PHY_SET(mac, 0x000a, 0x2000);
7041203945Sweongyo		if (phy->rev != 1) {
7042203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0004);
7043203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffb);
7044203945Sweongyo		}
7045203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
7046203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x000f);
7047203945Sweongyo		bwn_set_all_gains(mac, 3, 0, 1);
7048203945Sweongyo		BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
7049203945Sweongyo		DELAY(30);
7050203945Sweongyo		nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7051203945Sweongyo		if (nrssi >= 0x20)
7052203945Sweongyo			nrssi -= 0x40;
7053203945Sweongyo		if (nrssi == -32) {
7054203945Sweongyo			for (i = 0; i < 4; i++) {
7055203945Sweongyo				BWN_RF_WRITE(mac, 0x007b, i);
7056203945Sweongyo				DELAY(20);
7057203945Sweongyo				nrssi = (int16_t)((BWN_PHY_READ(mac,
7058203945Sweongyo				    0x047f) >> 8) & 0x003f);
7059203945Sweongyo				if (nrssi >= 0x20)
7060203945Sweongyo					nrssi -= 0x40;
7061203945Sweongyo				if (nrssi > -31 && saved == 0xffff)
7062203945Sweongyo					saved = i;
7063203945Sweongyo			}
7064203945Sweongyo			if (saved == 0xffff)
7065203945Sweongyo				saved = 3;
7066203945Sweongyo		} else
7067203945Sweongyo			saved = 0;
7068203945Sweongyo	}
7069203945Sweongyo	BWN_RF_WRITE(mac, 0x007b, saved);
7070203945Sweongyo
7071203945Sweongyo	/*
7072203945Sweongyo	 * Restore saved RF/PHY registers
7073203945Sweongyo	 */
7074203945Sweongyo	if (phy->rev >= 6) {
7075203945Sweongyo		for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
7076203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7077203945Sweongyo			    save_phy6[phy6_idx]);
7078203945Sweongyo		}
7079203945Sweongyo	}
7080203945Sweongyo	if (phy->rev != 1) {
7081203945Sweongyo		for (i = 3; i < 5; i++)
7082203945Sweongyo			BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
7083203945Sweongyo			    save_phy_comm[i]);
7084203945Sweongyo	}
7085203945Sweongyo	for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
7086203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
7087203945Sweongyo
7088203945Sweongyo	for (i = SAVE_RF_MAX - 1; i >= 0; --i)
7089203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
7090203945Sweongyo
7091203945Sweongyo	BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
7092203945Sweongyo	BWN_PHY_SET(mac, 0x0429, 0x8000);
7093203945Sweongyo	bwn_set_original_gains(mac);
7094203945Sweongyo	if (phy->rev >= 6) {
7095203945Sweongyo		for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
7096203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7097203945Sweongyo			    save_phy6[phy6_idx]);
7098203945Sweongyo		}
7099203945Sweongyo	}
7100203945Sweongyo
7101203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
7102203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
7103203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
7104203945Sweongyo}
7105203945Sweongyo
7106203945Sweongyostatic void
7107203945Sweongyobwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
7108203945Sweongyo    int16_t third)
7109203945Sweongyo{
7110203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7111203945Sweongyo	uint16_t i;
7112203945Sweongyo	uint16_t start = 0x08, end = 0x18;
7113203945Sweongyo	uint16_t tmp;
7114203945Sweongyo	uint16_t table;
7115203945Sweongyo
7116203945Sweongyo	if (phy->rev <= 1) {
7117203945Sweongyo		start = 0x10;
7118203945Sweongyo		end = 0x20;
7119203945Sweongyo	}
7120203945Sweongyo
7121203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7122203945Sweongyo	if (phy->rev <= 1)
7123203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7124203945Sweongyo	for (i = 0; i < 4; i++)
7125203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, first);
7126203945Sweongyo
7127203945Sweongyo	for (i = start; i < end; i++)
7128203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, second);
7129203945Sweongyo
7130203945Sweongyo	if (third != -1) {
7131203945Sweongyo		tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
7132203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
7133203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
7134203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
7135203945Sweongyo	}
7136203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7137203945Sweongyo}
7138203945Sweongyo
7139203945Sweongyostatic void
7140203945Sweongyobwn_set_original_gains(struct bwn_mac *mac)
7141203945Sweongyo{
7142203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7143203945Sweongyo	uint16_t i, tmp;
7144203945Sweongyo	uint16_t table;
7145203945Sweongyo	uint16_t start = 0x0008, end = 0x0018;
7146203945Sweongyo
7147203945Sweongyo	if (phy->rev <= 1) {
7148203945Sweongyo		start = 0x0010;
7149203945Sweongyo		end = 0x0020;
7150203945Sweongyo	}
7151203945Sweongyo
7152203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7153203945Sweongyo	if (phy->rev <= 1)
7154203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7155203945Sweongyo	for (i = 0; i < 4; i++) {
7156203945Sweongyo		tmp = (i & 0xfffc);
7157203945Sweongyo		tmp |= (i & 0x0001) << 1;
7158203945Sweongyo		tmp |= (i & 0x0002) >> 1;
7159203945Sweongyo
7160203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, tmp);
7161203945Sweongyo	}
7162203945Sweongyo
7163203945Sweongyo	for (i = start; i < end; i++)
7164203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, i - start);
7165203945Sweongyo
7166203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
7167203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
7168203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
7169203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7170203945Sweongyo}
7171203945Sweongyo
7172203945Sweongyostatic void
7173203945Sweongyobwn_phy_hwpctl_init(struct bwn_mac *mac)
7174203945Sweongyo{
7175203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7176203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7177203945Sweongyo	struct bwn_rfatt old_rfatt, rfatt;
7178203945Sweongyo	struct bwn_bbatt old_bbatt, bbatt;
7179204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7180203945Sweongyo	uint8_t old_txctl = 0;
7181203945Sweongyo
7182203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
7183203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7184203945Sweongyo
7185204922Sweongyo	if ((siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM) &&
7186204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306))
7187203945Sweongyo		return;
7188203945Sweongyo
7189203945Sweongyo	BWN_PHY_WRITE(mac, 0x0028, 0x8018);
7190203945Sweongyo
7191203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
7192203945Sweongyo
7193203945Sweongyo	if (!phy->gmode)
7194203945Sweongyo		return;
7195203945Sweongyo	bwn_hwpctl_early_init(mac);
7196203945Sweongyo	if (pg->pg_curtssi == 0) {
7197203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0) {
7198203945Sweongyo			BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
7199203945Sweongyo		} else {
7200203945Sweongyo			memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
7201203945Sweongyo			memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
7202203945Sweongyo			old_txctl = pg->pg_txctl;
7203203945Sweongyo
7204203945Sweongyo			bbatt.att = 11;
7205203945Sweongyo			if (phy->rf_rev == 8) {
7206203945Sweongyo				rfatt.att = 15;
7207203945Sweongyo				rfatt.padmix = 1;
7208203945Sweongyo			} else {
7209203945Sweongyo				rfatt.att = 9;
7210203945Sweongyo				rfatt.padmix = 0;
7211203945Sweongyo			}
7212203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
7213203945Sweongyo		}
7214203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
7215203945Sweongyo		pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
7216203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0)
7217203945Sweongyo			BWN_RF_MASK(mac, 0x0076, 0xff7b);
7218203945Sweongyo		else
7219203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
7220203945Sweongyo			    &old_rfatt, old_txctl);
7221203945Sweongyo	}
7222203945Sweongyo	bwn_hwpctl_init_gphy(mac);
7223203945Sweongyo
7224203945Sweongyo	/* clear TSSI */
7225203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
7226203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
7227203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
7228203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
7229203945Sweongyo}
7230203945Sweongyo
7231203945Sweongyostatic void
7232203945Sweongyobwn_hwpctl_early_init(struct bwn_mac *mac)
7233203945Sweongyo{
7234203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7235203945Sweongyo
7236203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7237203945Sweongyo		BWN_PHY_WRITE(mac, 0x047a, 0xc111);
7238203945Sweongyo		return;
7239203945Sweongyo	}
7240203945Sweongyo
7241203945Sweongyo	BWN_PHY_MASK(mac, 0x0036, 0xfeff);
7242203945Sweongyo	BWN_PHY_WRITE(mac, 0x002f, 0x0202);
7243203945Sweongyo	BWN_PHY_SET(mac, 0x047c, 0x0002);
7244203945Sweongyo	BWN_PHY_SET(mac, 0x047a, 0xf000);
7245203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
7246203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7247203945Sweongyo		BWN_PHY_SET(mac, 0x005d, 0x8000);
7248203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7249203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7250203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7251203945Sweongyo	} else {
7252203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0200);
7253203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7254203945Sweongyo		BWN_PHY_MASK(mac, 0x005d, 0x7fff);
7255203945Sweongyo		BWN_PHY_MASK(mac, 0x004f, 0xfffe);
7256203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7257203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7258203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7259203945Sweongyo	}
7260203945Sweongyo}
7261203945Sweongyo
7262203945Sweongyostatic void
7263203945Sweongyobwn_hwpctl_init_gphy(struct bwn_mac *mac)
7264203945Sweongyo{
7265203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7266203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7267203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7268203945Sweongyo	int i;
7269203945Sweongyo	uint16_t nr_written = 0, tmp, value;
7270203945Sweongyo	uint8_t rf, bb;
7271203945Sweongyo
7272203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7273203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
7274203945Sweongyo		return;
7275203945Sweongyo	}
7276203945Sweongyo
7277203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
7278203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7279203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
7280203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7281203945Sweongyo
7282203945Sweongyo	for (i = 0; i < 32; i++)
7283203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
7284203945Sweongyo	for (i = 32; i < 64; i++)
7285203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
7286203945Sweongyo	for (i = 0; i < 64; i += 2) {
7287203945Sweongyo		value = (uint16_t) pg->pg_tssi2dbm[i];
7288203945Sweongyo		value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
7289203945Sweongyo		BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
7290203945Sweongyo	}
7291203945Sweongyo
7292203945Sweongyo	for (rf = 0; rf < lo->rfatt.len; rf++) {
7293203945Sweongyo		for (bb = 0; bb < lo->bbatt.len; bb++) {
7294203945Sweongyo			if (nr_written >= 0x40)
7295203945Sweongyo				return;
7296203945Sweongyo			tmp = lo->bbatt.array[bb].att;
7297203945Sweongyo			tmp <<= 8;
7298203945Sweongyo			if (phy->rf_rev == 8)
7299203945Sweongyo				tmp |= 0x50;
7300203945Sweongyo			else
7301203945Sweongyo				tmp |= 0x40;
7302203945Sweongyo			tmp |= lo->rfatt.array[rf].att;
7303203945Sweongyo			BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
7304203945Sweongyo			nr_written++;
7305203945Sweongyo		}
7306203945Sweongyo	}
7307203945Sweongyo
7308203945Sweongyo	BWN_PHY_MASK(mac, 0x0060, 0xffbf);
7309203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0000);
7310203945Sweongyo
7311203945Sweongyo	KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
7312203945Sweongyo	BWN_PHY_SET(mac, 0x0478, 0x0800);
7313203945Sweongyo	BWN_PHY_MASK(mac, 0x0478, 0xfeff);
7314203945Sweongyo	BWN_PHY_MASK(mac, 0x0801, 0xffbf);
7315203945Sweongyo
7316203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
7317203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
7318203945Sweongyo}
7319203945Sweongyo
7320203945Sweongyostatic void
7321203945Sweongyobwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
7322203945Sweongyo{
7323204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7324203945Sweongyo
7325203945Sweongyo	if (spu != 0)
7326203945Sweongyo		bwn_spu_workaround(mac, channel);
7327203945Sweongyo
7328203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7329203945Sweongyo
7330203945Sweongyo	if (channel == 14) {
7331204922Sweongyo		if (siba_sprom_get_ccode(sc->sc_dev) == SIBA_CCODE_JAPAN)
7332203945Sweongyo			bwn_hf_write(mac,
7333203945Sweongyo			    bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
7334203945Sweongyo		else
7335203945Sweongyo			bwn_hf_write(mac,
7336203945Sweongyo			    bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
7337203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7338203945Sweongyo		    BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
7339203945Sweongyo		return;
7340203945Sweongyo	}
7341203945Sweongyo
7342203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7343203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
7344203945Sweongyo}
7345203945Sweongyo
7346203945Sweongyostatic uint16_t
7347203945Sweongyobwn_phy_g_chan2freq(uint8_t channel)
7348203945Sweongyo{
7349203945Sweongyo	static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
7350203945Sweongyo
7351203945Sweongyo	KASSERT(channel >= 1 && channel <= 14,
7352203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7353203945Sweongyo
7354203945Sweongyo	return (bwn_phy_g_rf_channels[channel - 1]);
7355203945Sweongyo}
7356203945Sweongyo
7357203945Sweongyostatic void
7358203945Sweongyobwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
7359203945Sweongyo    const struct bwn_rfatt *rfatt, uint8_t txctl)
7360203945Sweongyo{
7361203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7362203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7363203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7364203945Sweongyo	uint16_t bb, rf;
7365203945Sweongyo	uint16_t tx_bias, tx_magn;
7366203945Sweongyo
7367203945Sweongyo	bb = bbatt->att;
7368203945Sweongyo	rf = rfatt->att;
7369203945Sweongyo	tx_bias = lo->tx_bias;
7370203945Sweongyo	tx_magn = lo->tx_magn;
7371203945Sweongyo	if (tx_bias == 0xff)
7372203945Sweongyo		tx_bias = 0;
7373203945Sweongyo
7374203945Sweongyo	pg->pg_txctl = txctl;
7375203945Sweongyo	memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
7376203945Sweongyo	pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
7377203945Sweongyo	memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
7378203945Sweongyo	bwn_phy_g_set_bbatt(mac, bb);
7379203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
7380203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
7381203945Sweongyo		BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
7382203945Sweongyo	else {
7383203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
7384203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
7385203945Sweongyo	}
7386203945Sweongyo	if (BWN_HAS_TXMAG(phy))
7387203945Sweongyo		BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
7388203945Sweongyo	else
7389203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
7390203945Sweongyo	bwn_lo_g_adjust(mac);
7391203945Sweongyo}
7392203945Sweongyo
7393203945Sweongyostatic void
7394203945Sweongyobwn_phy_g_set_bbatt(struct bwn_mac *mac,
7395203945Sweongyo    uint16_t bbatt)
7396203945Sweongyo{
7397203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7398203945Sweongyo
7399203945Sweongyo	if (phy->analog == 0) {
7400203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY0,
7401203945Sweongyo		    (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
7402203945Sweongyo		return;
7403203945Sweongyo	}
7404203945Sweongyo	if (phy->analog > 1) {
7405203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
7406203945Sweongyo		return;
7407203945Sweongyo	}
7408203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
7409203945Sweongyo}
7410203945Sweongyo
7411203945Sweongyostatic uint16_t
7412203945Sweongyobwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
7413203945Sweongyo{
7414203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7415203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7416204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7417203945Sweongyo	int max_lb_gain;
7418203945Sweongyo	uint16_t extlna;
7419203945Sweongyo	uint16_t i;
7420203945Sweongyo
7421203945Sweongyo	if (phy->gmode == 0)
7422203945Sweongyo		return (0);
7423203945Sweongyo
7424203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
7425203945Sweongyo		max_lb_gain = pg->pg_max_lb_gain;
7426203945Sweongyo		max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
7427203945Sweongyo		if (max_lb_gain >= 0x46) {
7428203945Sweongyo			extlna = 0x3000;
7429203945Sweongyo			max_lb_gain -= 0x46;
7430203945Sweongyo		} else if (max_lb_gain >= 0x3a) {
7431203945Sweongyo			extlna = 0x1000;
7432203945Sweongyo			max_lb_gain -= 0x3a;
7433203945Sweongyo		} else if (max_lb_gain >= 0x2e) {
7434203945Sweongyo			extlna = 0x2000;
7435203945Sweongyo			max_lb_gain -= 0x2e;
7436203945Sweongyo		} else {
7437203945Sweongyo			extlna = 0;
7438203945Sweongyo			max_lb_gain -= 0x10;
7439203945Sweongyo		}
7440203945Sweongyo
7441203945Sweongyo		for (i = 0; i < 16; i++) {
7442203945Sweongyo			max_lb_gain -= (i * 6);
7443203945Sweongyo			if (max_lb_gain < 6)
7444203945Sweongyo				break;
7445203945Sweongyo		}
7446203945Sweongyo
7447204922Sweongyo		if ((phy->rev < 7) ||
7448204922Sweongyo		    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
7449203945Sweongyo			if (reg == BWN_PHY_RFOVER) {
7450203945Sweongyo				return (0x1b3);
7451203945Sweongyo			} else if (reg == BWN_PHY_RFOVERVAL) {
7452203945Sweongyo				extlna |= (i << 8);
7453203945Sweongyo				switch (lpd) {
7454203945Sweongyo				case BWN_LPD(0, 1, 1):
7455203945Sweongyo					return (0x0f92);
7456203945Sweongyo				case BWN_LPD(0, 0, 1):
7457203945Sweongyo				case BWN_LPD(1, 0, 1):
7458203945Sweongyo					return (0x0092 | extlna);
7459203945Sweongyo				case BWN_LPD(1, 0, 0):
7460203945Sweongyo					return (0x0093 | extlna);
7461203945Sweongyo				}
7462203945Sweongyo				KASSERT(0 == 1,
7463203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7464203945Sweongyo			}
7465203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7466203945Sweongyo		} else {
7467203945Sweongyo			if (reg == BWN_PHY_RFOVER)
7468203945Sweongyo				return (0x9b3);
7469203945Sweongyo			if (reg == BWN_PHY_RFOVERVAL) {
7470203945Sweongyo				if (extlna)
7471203945Sweongyo					extlna |= 0x8000;
7472203945Sweongyo				extlna |= (i << 8);
7473203945Sweongyo				switch (lpd) {
7474203945Sweongyo				case BWN_LPD(0, 1, 1):
7475203945Sweongyo					return (0x8f92);
7476203945Sweongyo				case BWN_LPD(0, 0, 1):
7477203945Sweongyo					return (0x8092 | extlna);
7478203945Sweongyo				case BWN_LPD(1, 0, 1):
7479203945Sweongyo					return (0x2092 | extlna);
7480203945Sweongyo				case BWN_LPD(1, 0, 0):
7481203945Sweongyo					return (0x2093 | extlna);
7482203945Sweongyo				}
7483203945Sweongyo				KASSERT(0 == 1,
7484203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7485203945Sweongyo			}
7486203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7487203945Sweongyo		}
7488203945Sweongyo		return (0);
7489203945Sweongyo	}
7490203945Sweongyo
7491203945Sweongyo	if ((phy->rev < 7) ||
7492204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
7493203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7494203945Sweongyo			return (0x1b3);
7495203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7496203945Sweongyo			switch (lpd) {
7497203945Sweongyo			case BWN_LPD(0, 1, 1):
7498203945Sweongyo				return (0x0fb2);
7499203945Sweongyo			case BWN_LPD(0, 0, 1):
7500203945Sweongyo				return (0x00b2);
7501203945Sweongyo			case BWN_LPD(1, 0, 1):
7502203945Sweongyo				return (0x30b2);
7503203945Sweongyo			case BWN_LPD(1, 0, 0):
7504203945Sweongyo				return (0x30b3);
7505203945Sweongyo			}
7506203945Sweongyo			KASSERT(0 == 1,
7507203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7508203945Sweongyo		}
7509203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7510203945Sweongyo	} else {
7511203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7512203945Sweongyo			return (0x9b3);
7513203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7514203945Sweongyo			switch (lpd) {
7515203945Sweongyo			case BWN_LPD(0, 1, 1):
7516203945Sweongyo				return (0x8fb2);
7517203945Sweongyo			case BWN_LPD(0, 0, 1):
7518203945Sweongyo				return (0x80b2);
7519203945Sweongyo			case BWN_LPD(1, 0, 1):
7520203945Sweongyo				return (0x20b2);
7521203945Sweongyo			case BWN_LPD(1, 0, 0):
7522203945Sweongyo				return (0x20b3);
7523203945Sweongyo			}
7524203945Sweongyo			KASSERT(0 == 1,
7525203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7526203945Sweongyo		}
7527203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7528203945Sweongyo	}
7529203945Sweongyo	return (0);
7530203945Sweongyo}
7531203945Sweongyo
7532203945Sweongyostatic void
7533203945Sweongyobwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
7534203945Sweongyo{
7535203945Sweongyo
7536203945Sweongyo	if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
7537203945Sweongyo		return;
7538203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
7539203945Sweongyo	    bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
7540203945Sweongyo	DELAY(1000);
7541203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7542203945Sweongyo}
7543203945Sweongyo
7544203945Sweongyostatic int
7545203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
7546203945Sweongyo{
7547203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7548203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
7549204922Sweongyo	const uint8_t rev = siba_get_revid(sc->sc_dev);
7550203945Sweongyo	const char *filename;
7551203945Sweongyo	uint32_t high;
7552203945Sweongyo	int error;
7553203945Sweongyo
7554203945Sweongyo	/* microcode */
7555203945Sweongyo	if (rev >= 5 && rev <= 10)
7556203945Sweongyo		filename = "ucode5";
7557203945Sweongyo	else if (rev >= 11 && rev <= 12)
7558203945Sweongyo		filename = "ucode11";
7559203945Sweongyo	else if (rev == 13)
7560203945Sweongyo		filename = "ucode13";
7561203945Sweongyo	else if (rev == 14)
7562203945Sweongyo		filename = "ucode14";
7563203945Sweongyo	else if (rev >= 15)
7564203945Sweongyo		filename = "ucode15";
7565203945Sweongyo	else {
7566203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
7567203945Sweongyo		bwn_release_firmware(mac);
7568203945Sweongyo		return (EOPNOTSUPP);
7569203945Sweongyo	}
7570203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
7571203945Sweongyo	if (error) {
7572203945Sweongyo		bwn_release_firmware(mac);
7573203945Sweongyo		return (error);
7574203945Sweongyo	}
7575203945Sweongyo
7576203945Sweongyo	/* PCM */
7577203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
7578203945Sweongyo	if (rev >= 5 && rev <= 10) {
7579203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
7580203945Sweongyo		if (error == ENOENT)
7581203945Sweongyo			fw->no_pcmfile = 1;
7582203945Sweongyo		else if (error) {
7583203945Sweongyo			bwn_release_firmware(mac);
7584203945Sweongyo			return (error);
7585203945Sweongyo		}
7586203945Sweongyo	} else if (rev < 11) {
7587203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
7588203945Sweongyo		return (EOPNOTSUPP);
7589203945Sweongyo	}
7590203945Sweongyo
7591203945Sweongyo	/* initvals */
7592204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
7593203945Sweongyo	switch (mac->mac_phy.type) {
7594203945Sweongyo	case BWN_PHYTYPE_A:
7595203945Sweongyo		if (rev < 5 || rev > 10)
7596203945Sweongyo			goto fail1;
7597203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
7598203945Sweongyo			filename = "a0g1initvals5";
7599203945Sweongyo		else
7600203945Sweongyo			filename = "a0g0initvals5";
7601203945Sweongyo		break;
7602203945Sweongyo	case BWN_PHYTYPE_G:
7603203945Sweongyo		if (rev >= 5 && rev <= 10)
7604203945Sweongyo			filename = "b0g0initvals5";
7605203945Sweongyo		else if (rev >= 13)
7606203945Sweongyo			filename = "b0g0initvals13";
7607203945Sweongyo		else
7608203945Sweongyo			goto fail1;
7609203945Sweongyo		break;
7610203945Sweongyo	case BWN_PHYTYPE_LP:
7611203945Sweongyo		if (rev == 13)
7612203945Sweongyo			filename = "lp0initvals13";
7613203945Sweongyo		else if (rev == 14)
7614203945Sweongyo			filename = "lp0initvals14";
7615203945Sweongyo		else if (rev >= 15)
7616203945Sweongyo			filename = "lp0initvals15";
7617203945Sweongyo		else
7618203945Sweongyo			goto fail1;
7619203945Sweongyo		break;
7620203945Sweongyo	case BWN_PHYTYPE_N:
7621203945Sweongyo		if (rev >= 11 && rev <= 12)
7622203945Sweongyo			filename = "n0initvals11";
7623203945Sweongyo		else
7624203945Sweongyo			goto fail1;
7625203945Sweongyo		break;
7626203945Sweongyo	default:
7627203945Sweongyo		goto fail1;
7628203945Sweongyo	}
7629203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
7630203945Sweongyo	if (error) {
7631203945Sweongyo		bwn_release_firmware(mac);
7632203945Sweongyo		return (error);
7633203945Sweongyo	}
7634203945Sweongyo
7635203945Sweongyo	/* bandswitch initvals */
7636203945Sweongyo	switch (mac->mac_phy.type) {
7637203945Sweongyo	case BWN_PHYTYPE_A:
7638203945Sweongyo		if (rev >= 5 && rev <= 10) {
7639203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
7640203945Sweongyo				filename = "a0g1bsinitvals5";
7641203945Sweongyo			else
7642203945Sweongyo				filename = "a0g0bsinitvals5";
7643203945Sweongyo		} else if (rev >= 11)
7644203945Sweongyo			filename = NULL;
7645203945Sweongyo		else
7646203945Sweongyo			goto fail1;
7647203945Sweongyo		break;
7648203945Sweongyo	case BWN_PHYTYPE_G:
7649203945Sweongyo		if (rev >= 5 && rev <= 10)
7650203945Sweongyo			filename = "b0g0bsinitvals5";
7651203945Sweongyo		else if (rev >= 11)
7652203945Sweongyo			filename = NULL;
7653203945Sweongyo		else
7654203945Sweongyo			goto fail1;
7655203945Sweongyo		break;
7656203945Sweongyo	case BWN_PHYTYPE_LP:
7657203945Sweongyo		if (rev == 13)
7658203945Sweongyo			filename = "lp0bsinitvals13";
7659203945Sweongyo		else if (rev == 14)
7660203945Sweongyo			filename = "lp0bsinitvals14";
7661203945Sweongyo		else if (rev >= 15)
7662203945Sweongyo			filename = "lp0bsinitvals15";
7663203945Sweongyo		else
7664203945Sweongyo			goto fail1;
7665203945Sweongyo		break;
7666203945Sweongyo	case BWN_PHYTYPE_N:
7667203945Sweongyo		if (rev >= 11 && rev <= 12)
7668203945Sweongyo			filename = "n0bsinitvals11";
7669203945Sweongyo		else
7670203945Sweongyo			goto fail1;
7671203945Sweongyo		break;
7672203945Sweongyo	default:
7673203945Sweongyo		goto fail1;
7674203945Sweongyo	}
7675203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
7676203945Sweongyo	if (error) {
7677203945Sweongyo		bwn_release_firmware(mac);
7678203945Sweongyo		return (error);
7679203945Sweongyo	}
7680203945Sweongyo	return (0);
7681203945Sweongyofail1:
7682203945Sweongyo	device_printf(sc->sc_dev, "no INITVALS for rev %d\n", rev);
7683203945Sweongyo	bwn_release_firmware(mac);
7684203945Sweongyo	return (EOPNOTSUPP);
7685203945Sweongyo}
7686203945Sweongyo
7687203945Sweongyostatic int
7688203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
7689203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
7690203945Sweongyo{
7691203945Sweongyo	const struct bwn_fwhdr *hdr;
7692203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7693203945Sweongyo	const struct firmware *fw;
7694203945Sweongyo	char namebuf[64];
7695203945Sweongyo
7696203945Sweongyo	if (name == NULL) {
7697203945Sweongyo		bwn_do_release_fw(bfw);
7698203945Sweongyo		return (0);
7699203945Sweongyo	}
7700203945Sweongyo	if (bfw->filename != NULL) {
7701203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
7702203945Sweongyo			return (0);
7703203945Sweongyo		bwn_do_release_fw(bfw);
7704203945Sweongyo	}
7705203945Sweongyo
7706204437Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s%s",
7707204437Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "",
7708204437Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_LP) ? "lp_" : "", name);
7709203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
7710203945Sweongyo	fw = firmware_get(namebuf);
7711203945Sweongyo	if (fw == NULL) {
7712203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
7713203945Sweongyo		    namebuf);
7714203945Sweongyo		return (ENOENT);
7715203945Sweongyo	}
7716203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
7717203945Sweongyo		goto fail;
7718203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
7719203945Sweongyo	switch (hdr->type) {
7720203945Sweongyo	case BWN_FWTYPE_UCODE:
7721203945Sweongyo	case BWN_FWTYPE_PCM:
7722203945Sweongyo		if (be32toh(hdr->size) !=
7723203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
7724203945Sweongyo			goto fail;
7725203945Sweongyo		/* FALLTHROUGH */
7726203945Sweongyo	case BWN_FWTYPE_IV:
7727203945Sweongyo		if (hdr->ver != 1)
7728203945Sweongyo			goto fail;
7729203945Sweongyo		break;
7730203945Sweongyo	default:
7731203945Sweongyo		goto fail;
7732203945Sweongyo	}
7733203945Sweongyo	bfw->filename = name;
7734203945Sweongyo	bfw->fw = fw;
7735203945Sweongyo	bfw->type = type;
7736203945Sweongyo	return (0);
7737203945Sweongyofail:
7738203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
7739203945Sweongyo	if (fw != NULL)
7740203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
7741203945Sweongyo	return (EPROTO);
7742203945Sweongyo}
7743203945Sweongyo
7744203945Sweongyostatic void
7745203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
7746203945Sweongyo{
7747203945Sweongyo
7748203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
7749203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
7750203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
7751203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
7752203945Sweongyo}
7753203945Sweongyo
7754203945Sweongyostatic void
7755203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
7756203945Sweongyo{
7757203945Sweongyo
7758203945Sweongyo	if (bfw->fw != NULL)
7759203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
7760203945Sweongyo	bfw->fw = NULL;
7761203945Sweongyo	bfw->filename = NULL;
7762203945Sweongyo}
7763203945Sweongyo
7764203945Sweongyostatic int
7765203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
7766203945Sweongyo{
7767203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
7768203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
7769203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
7770203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
7771203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7772203945Sweongyo	const uint32_t *data;
7773203945Sweongyo	unsigned int i;
7774203945Sweongyo	uint32_t ctl;
7775203945Sweongyo	uint16_t date, fwcaps, time;
7776203945Sweongyo	int error = 0;
7777203945Sweongyo
7778203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
7779203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
7780203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
7781203945Sweongyo	    __LINE__));
7782203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
7783203945Sweongyo	for (i = 0; i < 64; i++)
7784203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
7785203945Sweongyo	for (i = 0; i < 4096; i += 2)
7786203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
7787203945Sweongyo
7788203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7789203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
7790203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7791203945Sweongyo	     i++) {
7792203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7793203945Sweongyo		DELAY(10);
7794203945Sweongyo	}
7795203945Sweongyo
7796203945Sweongyo	if (mac->mac_fw.pcm.fw) {
7797203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
7798203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
7799203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
7800203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
7801203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
7802203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
7803203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7804203945Sweongyo			DELAY(10);
7805203945Sweongyo		}
7806203945Sweongyo	}
7807203945Sweongyo
7808203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
7809203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7810203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
7811203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
7812203945Sweongyo
7813203945Sweongyo	for (i = 0; i < 21; i++) {
7814203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
7815203945Sweongyo			break;
7816203945Sweongyo		if (i >= 20) {
7817203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
7818203945Sweongyo			error = ENXIO;
7819203945Sweongyo			goto error;
7820203945Sweongyo		}
7821203945Sweongyo		DELAY(50000);
7822203945Sweongyo	}
7823203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
7824203945Sweongyo
7825203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
7826203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
7827203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
7828203945Sweongyo		error = EOPNOTSUPP;
7829203945Sweongyo		goto error;
7830203945Sweongyo	}
7831203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
7832203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
7833203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
7834203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
7835203945Sweongyo	if (bwn_wme != 0)
7836203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
7837203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
7838203945Sweongyo
7839203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
7840203945Sweongyo	if (mac->mac_fw.opensource == 0) {
7841203945Sweongyo		device_printf(sc->sc_dev,
7842203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
7843203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
7844203945Sweongyo		if (mac->mac_fw.no_pcmfile)
7845203945Sweongyo			device_printf(sc->sc_dev,
7846203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
7847203945Sweongyo	} else {
7848203945Sweongyo		mac->mac_fw.patch = time;
7849203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
7850203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
7851203945Sweongyo			device_printf(sc->sc_dev,
7852203945Sweongyo			    "disabling HW crypto acceleration\n");
7853203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
7854203945Sweongyo		}
7855203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
7856203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
7857203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
7858203945Sweongyo		}
7859203945Sweongyo	}
7860203945Sweongyo
7861203945Sweongyo	if (BWN_ISOLDFMT(mac))
7862203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
7863203945Sweongyo
7864203945Sweongyo	return (0);
7865203945Sweongyo
7866203945Sweongyoerror:
7867203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7868203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
7869203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
7870203945Sweongyo
7871203945Sweongyo	return (error);
7872203945Sweongyo#undef GETFWSIZE
7873203945Sweongyo#undef GETFWOFFSET
7874203945Sweongyo}
7875203945Sweongyo
7876203945Sweongyo/* OpenFirmware only */
7877203945Sweongyostatic uint16_t
7878203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
7879203945Sweongyo{
7880203945Sweongyo
7881203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
7882203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7883203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
7884203945Sweongyo}
7885203945Sweongyo
7886203945Sweongyostatic int
7887203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
7888203945Sweongyo    size_t count, size_t array_size)
7889203945Sweongyo{
7890203945Sweongyo#define	GET_NEXTIV16(iv)						\
7891203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7892203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
7893203945Sweongyo#define	GET_NEXTIV32(iv)						\
7894203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7895203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
7896203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7897203945Sweongyo	const struct bwn_fwinitvals *iv;
7898203945Sweongyo	uint16_t offset;
7899203945Sweongyo	size_t i;
7900203945Sweongyo	uint8_t bit32;
7901203945Sweongyo
7902203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
7903203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7904203945Sweongyo	iv = ivals;
7905203945Sweongyo	for (i = 0; i < count; i++) {
7906203945Sweongyo		if (array_size < sizeof(iv->offset_size))
7907203945Sweongyo			goto fail;
7908203945Sweongyo		array_size -= sizeof(iv->offset_size);
7909203945Sweongyo		offset = be16toh(iv->offset_size);
7910203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
7911203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
7912203945Sweongyo		if (offset >= 0x1000)
7913203945Sweongyo			goto fail;
7914203945Sweongyo		if (bit32) {
7915203945Sweongyo			if (array_size < sizeof(iv->data.d32))
7916203945Sweongyo				goto fail;
7917203945Sweongyo			array_size -= sizeof(iv->data.d32);
7918203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
7919203945Sweongyo			iv = GET_NEXTIV32(iv);
7920203945Sweongyo		} else {
7921203945Sweongyo
7922203945Sweongyo			if (array_size < sizeof(iv->data.d16))
7923203945Sweongyo				goto fail;
7924203945Sweongyo			array_size -= sizeof(iv->data.d16);
7925203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
7926203945Sweongyo
7927203945Sweongyo			iv = GET_NEXTIV16(iv);
7928203945Sweongyo		}
7929203945Sweongyo	}
7930203945Sweongyo	if (array_size != 0)
7931203945Sweongyo		goto fail;
7932203945Sweongyo	return (0);
7933203945Sweongyofail:
7934203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
7935203945Sweongyo	return (EPROTO);
7936203945Sweongyo#undef GET_NEXTIV16
7937203945Sweongyo#undef GET_NEXTIV32
7938203945Sweongyo}
7939203945Sweongyo
7940203945Sweongyostatic int
7941203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
7942203945Sweongyo{
7943203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
7944203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7945203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
7946203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
7947203945Sweongyo	uint16_t channelcookie, savedcookie;
7948203945Sweongyo	int error;
7949203945Sweongyo
7950203945Sweongyo	if (chan == 0xffff)
7951203945Sweongyo		chan = phy->get_default_chan(mac);
7952203945Sweongyo
7953203945Sweongyo	channelcookie = chan;
7954203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
7955203945Sweongyo		channelcookie |= 0x100;
7956203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
7957203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
7958203945Sweongyo	error = phy->switch_channel(mac, chan);
7959203945Sweongyo	if (error)
7960203945Sweongyo		goto fail;
7961203945Sweongyo
7962203945Sweongyo	mac->mac_phy.chan = chan;
7963203945Sweongyo	DELAY(8000);
7964203945Sweongyo	return (0);
7965203945Sweongyofail:
7966203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
7967203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
7968203945Sweongyo	return (error);
7969203945Sweongyo}
7970203945Sweongyo
7971203945Sweongyostatic uint16_t
7972203945Sweongyobwn_ant2phy(int antenna)
7973203945Sweongyo{
7974203945Sweongyo
7975203945Sweongyo	switch (antenna) {
7976203945Sweongyo	case BWN_ANT0:
7977203945Sweongyo		return (BWN_TX_PHY_ANT0);
7978203945Sweongyo	case BWN_ANT1:
7979203945Sweongyo		return (BWN_TX_PHY_ANT1);
7980203945Sweongyo	case BWN_ANT2:
7981203945Sweongyo		return (BWN_TX_PHY_ANT2);
7982203945Sweongyo	case BWN_ANT3:
7983203945Sweongyo		return (BWN_TX_PHY_ANT3);
7984203945Sweongyo	case BWN_ANTAUTO:
7985203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
7986203945Sweongyo	}
7987203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7988203945Sweongyo	return (0);
7989203945Sweongyo}
7990203945Sweongyo
7991203945Sweongyostatic void
7992203945Sweongyobwn_wme_load(struct bwn_mac *mac)
7993203945Sweongyo{
7994203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7995203945Sweongyo	int i;
7996203945Sweongyo
7997203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
7998203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7999203945Sweongyo
8000203945Sweongyo	bwn_mac_suspend(mac);
8001203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
8002203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
8003203945Sweongyo		    bwn_wme_shm_offsets[i]);
8004203945Sweongyo	bwn_mac_enable(mac);
8005203945Sweongyo}
8006203945Sweongyo
8007203945Sweongyostatic void
8008203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
8009203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
8010203945Sweongyo{
8011203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
8012203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8013203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
8014203945Sweongyo	int slot, tmp;
8015203945Sweongyo	unsigned int i;
8016203945Sweongyo
8017203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
8018203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8019203945Sweongyo
8020203945Sweongyo	memset(&params, 0, sizeof(params));
8021203945Sweongyo
8022203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
8023203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
8024203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
8025203945Sweongyo
8026203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
8027203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8028203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
8029203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8030203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
8031203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
8032203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
8033203945Sweongyo
8034203945Sweongyo	for (i = 0; i < N(params); i++) {
8035203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
8036203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
8037203945Sweongyo			    shm_offset + (i * 2));
8038203945Sweongyo			tmp |= 0x100;
8039203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8040203945Sweongyo			    tmp);
8041203945Sweongyo		} else {
8042203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8043203945Sweongyo			    params[i]);
8044203945Sweongyo		}
8045203945Sweongyo	}
8046203945Sweongyo}
8047203945Sweongyo
8048203945Sweongyostatic void
8049203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
8050203945Sweongyo{
8051203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8052203945Sweongyo	uint32_t tmp;
8053203945Sweongyo	int i;
8054203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
8055203945Sweongyo
8056203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
8057203945Sweongyo	memcpy(mac_bssid, sc->sc_macaddr, IEEE80211_ADDR_LEN);
8058203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
8059203945Sweongyo	    IEEE80211_ADDR_LEN);
8060203945Sweongyo
8061203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
8062203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
8063203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
8064203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
8065203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
8066203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
8067203945Sweongyo	}
8068203945Sweongyo}
8069203945Sweongyo
8070203945Sweongyostatic void
8071203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
8072203945Sweongyo    const uint8_t *macaddr)
8073203945Sweongyo{
8074203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
8075203945Sweongyo	uint16_t data;
8076203945Sweongyo
8077203945Sweongyo	if (!mac)
8078203945Sweongyo		macaddr = zero;
8079203945Sweongyo
8080203945Sweongyo	offset |= 0x0020;
8081203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
8082203945Sweongyo
8083203945Sweongyo	data = macaddr[0];
8084203945Sweongyo	data |= macaddr[1] << 8;
8085203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8086203945Sweongyo	data = macaddr[2];
8087203945Sweongyo	data |= macaddr[3] << 8;
8088203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8089203945Sweongyo	data = macaddr[4];
8090203945Sweongyo	data |= macaddr[5] << 8;
8091203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8092203945Sweongyo}
8093203945Sweongyo
8094203945Sweongyostatic void
8095203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8096203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
8097203945Sweongyo{
8098203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
8099203945Sweongyo	uint8_t per_sta_keys_start = 8;
8100203945Sweongyo
8101203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8102203945Sweongyo		per_sta_keys_start = 4;
8103203945Sweongyo
8104203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
8105203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8106203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
8107203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8108203945Sweongyo
8109203945Sweongyo	if (index >= per_sta_keys_start)
8110203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
8111203945Sweongyo	if (key)
8112203945Sweongyo		memcpy(buf, key, key_len);
8113203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
8114203945Sweongyo	if (index >= per_sta_keys_start)
8115203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
8116203945Sweongyo
8117203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
8118203945Sweongyo}
8119203945Sweongyo
8120203945Sweongyostatic void
8121203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
8122203945Sweongyo{
8123204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8124203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
8125203945Sweongyo	uint8_t start = 8;
8126203945Sweongyo
8127203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8128203945Sweongyo		start = 4;
8129203945Sweongyo
8130203945Sweongyo	KASSERT(index >= start,
8131203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8132203945Sweongyo	index -= start;
8133203945Sweongyo
8134203945Sweongyo	if (addr) {
8135203945Sweongyo		addrtmp[0] = addr[0];
8136203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
8137203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
8138203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
8139203945Sweongyo		addrtmp[1] = addr[4];
8140203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
8141203945Sweongyo	}
8142203945Sweongyo
8143204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
8144203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
8145203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
8146203945Sweongyo	} else {
8147203945Sweongyo		if (index >= 8) {
8148203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
8149203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
8150203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
8151203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
8152203945Sweongyo		}
8153203945Sweongyo	}
8154203945Sweongyo}
8155203945Sweongyo
8156203945Sweongyostatic void
8157203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8158203945Sweongyo    const uint8_t *key)
8159203945Sweongyo{
8160203945Sweongyo	unsigned int i;
8161203945Sweongyo	uint32_t offset;
8162203945Sweongyo	uint16_t kidx, value;
8163203945Sweongyo
8164203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
8165203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
8166203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
8167203945Sweongyo
8168203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
8169203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
8170203945Sweongyo		value = key[i];
8171203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
8172203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
8173203945Sweongyo	}
8174203945Sweongyo}
8175203945Sweongyo
8176203945Sweongyostatic void
8177203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
8178203945Sweongyo{
8179203945Sweongyo
8180203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8181203945Sweongyo	if (mac->mac_phy.exit != NULL)
8182203945Sweongyo		mac->mac_phy.exit(mac);
8183203945Sweongyo}
8184203945Sweongyo
8185203945Sweongyostatic void
8186203945Sweongyobwn_dma_free(struct bwn_mac *mac)
8187203945Sweongyo{
8188203945Sweongyo	struct bwn_dma *dma;
8189203945Sweongyo
8190203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
8191203945Sweongyo		return;
8192203945Sweongyo	dma = &mac->mac_method.dma;
8193203945Sweongyo
8194203945Sweongyo	bwn_dma_ringfree(&dma->rx);
8195203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
8196203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
8197203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
8198203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
8199203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
8200203945Sweongyo}
8201203945Sweongyo
8202203945Sweongyostatic void
8203203945Sweongyobwn_core_stop(struct bwn_mac *mac)
8204203945Sweongyo{
8205203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8206203945Sweongyo
8207203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8208203945Sweongyo
8209203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8210203945Sweongyo		return;
8211203945Sweongyo
8212203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
8213203945Sweongyo	callout_stop(&sc->sc_task_ch);
8214203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
8215203945Sweongyo	sc->sc_watchdog_timer = 0;
8216203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8217203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
8218203945Sweongyo	bwn_mac_suspend(mac);
8219203945Sweongyo
8220203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
8221203945Sweongyo}
8222203945Sweongyo
8223203945Sweongyostatic int
8224203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
8225203945Sweongyo{
8226203945Sweongyo	struct bwn_mac *up_dev = NULL;
8227203945Sweongyo	struct bwn_mac *down_dev;
8228203945Sweongyo	struct bwn_mac *mac;
8229203945Sweongyo	int err, status;
8230203945Sweongyo	uint8_t gmode;
8231203945Sweongyo
8232203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8233203945Sweongyo
8234203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
8235203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
8236203945Sweongyo		    mac->mac_phy.supports_2ghz) {
8237203945Sweongyo			up_dev = mac;
8238203945Sweongyo			gmode = 1;
8239203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
8240203945Sweongyo		    mac->mac_phy.supports_5ghz) {
8241203945Sweongyo			up_dev = mac;
8242203945Sweongyo			gmode = 0;
8243203945Sweongyo		} else {
8244203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8245203945Sweongyo			return (EINVAL);
8246203945Sweongyo		}
8247203945Sweongyo		if (up_dev != NULL)
8248203945Sweongyo			break;
8249203945Sweongyo	}
8250203945Sweongyo	if (up_dev == NULL) {
8251203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
8252203945Sweongyo		return (ENODEV);
8253203945Sweongyo	}
8254203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
8255203945Sweongyo		return (0);
8256203945Sweongyo
8257203945Sweongyo	device_printf(sc->sc_dev, "switching to %s-GHz band\n",
8258203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8259203945Sweongyo
8260216227Skevlo	down_dev = sc->sc_curmac;
8261203945Sweongyo	status = down_dev->mac_status;
8262203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8263203945Sweongyo		bwn_core_stop(down_dev);
8264203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
8265203945Sweongyo		bwn_core_exit(down_dev);
8266203945Sweongyo
8267203945Sweongyo	if (down_dev != up_dev)
8268203945Sweongyo		bwn_phy_reset(down_dev);
8269203945Sweongyo
8270203945Sweongyo	up_dev->mac_phy.gmode = gmode;
8271203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
8272203945Sweongyo		err = bwn_core_init(up_dev);
8273203945Sweongyo		if (err) {
8274203945Sweongyo			device_printf(sc->sc_dev,
8275203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
8276203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8277203945Sweongyo			goto fail;
8278203945Sweongyo		}
8279203945Sweongyo	}
8280203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8281203945Sweongyo		bwn_core_start(up_dev);
8282203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
8283203945Sweongyo	sc->sc_curmac = up_dev;
8284203945Sweongyo
8285203945Sweongyo	return (0);
8286203945Sweongyofail:
8287203945Sweongyo	sc->sc_curmac = NULL;
8288203945Sweongyo	return (err);
8289203945Sweongyo}
8290203945Sweongyo
8291203945Sweongyostatic void
8292203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
8293203945Sweongyo{
8294203945Sweongyo
8295203945Sweongyo	bwn_mac_suspend(mac);
8296203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
8297203945Sweongyo	mac->mac_phy.rf_on = 1;
8298203945Sweongyo	bwn_mac_enable(mac);
8299203945Sweongyo}
8300203945Sweongyo
8301203945Sweongyostatic void
8302203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
8303203945Sweongyo{
8304203945Sweongyo
8305203945Sweongyo	bwn_mac_suspend(mac);
8306203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8307203945Sweongyo	mac->mac_phy.rf_on = 0;
8308203945Sweongyo	bwn_mac_enable(mac);
8309203945Sweongyo}
8310203945Sweongyo
8311203945Sweongyostatic void
8312203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
8313203945Sweongyo{
8314204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8315203945Sweongyo
8316204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
8317204922Sweongyo	    ((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
8318203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
8319203945Sweongyo	DELAY(1000);
8320204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
8321204922Sweongyo	    (siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC) |
8322203945Sweongyo	    BWN_TGSLOW_PHYRESET);
8323203945Sweongyo	DELAY(1000);
8324203945Sweongyo}
8325203945Sweongyo
8326203945Sweongyostatic int
8327203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
8328203945Sweongyo{
8329203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
8330203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
8331203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
8332203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
8333203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
8334203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
8335203945Sweongyo	int error;
8336203945Sweongyo
8337203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
8338203945Sweongyo	    ieee80211_state_name[vap->iv_state],
8339203945Sweongyo	    ieee80211_state_name[nstate]);
8340203945Sweongyo
8341203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
8342203945Sweongyo	if (error != 0)
8343203945Sweongyo		return (error);
8344203945Sweongyo
8345203945Sweongyo	BWN_LOCK(sc);
8346203945Sweongyo
8347203945Sweongyo	bwn_led_newstate(mac, nstate);
8348203945Sweongyo
8349203945Sweongyo	/*
8350203945Sweongyo	 * Clear the BSSID when we stop a STA
8351203945Sweongyo	 */
8352203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
8353203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
8354203945Sweongyo			/*
8355203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
8356203945Sweongyo			 * the same AP, this will reinialize things
8357203945Sweongyo			 * correctly...
8358203945Sweongyo			 */
8359203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
8360203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
8361203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
8362203945Sweongyo				bwn_set_macaddr(mac);
8363203945Sweongyo			}
8364203945Sweongyo		}
8365203945Sweongyo	}
8366203945Sweongyo
8367204436Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR ||
8368204436Sweongyo	    vap->iv_opmode == IEEE80211_M_AHDEMO) {
8369203945Sweongyo		/* XXX nothing to do? */
8370203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
8371203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
8372203945Sweongyo		memcpy(sc->sc_macaddr, IF_LLADDR(ifp), IEEE80211_ADDR_LEN);
8373203945Sweongyo		bwn_set_opmode(mac);
8374203945Sweongyo		bwn_set_pretbtt(mac);
8375203945Sweongyo		bwn_spu_setdelay(mac, 0);
8376203945Sweongyo		bwn_set_macaddr(mac);
8377203945Sweongyo	}
8378203945Sweongyo
8379203945Sweongyo	BWN_UNLOCK(sc);
8380203945Sweongyo
8381203945Sweongyo	return (error);
8382203945Sweongyo}
8383203945Sweongyo
8384203945Sweongyostatic void
8385203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
8386203945Sweongyo{
8387203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8388203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8389203945Sweongyo	uint16_t pretbtt;
8390203945Sweongyo
8391203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8392203945Sweongyo		pretbtt = 2;
8393203945Sweongyo	else
8394203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
8395203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
8396203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
8397203945Sweongyo}
8398203945Sweongyo
8399203945Sweongyostatic int
8400203945Sweongyobwn_intr(void *arg)
8401203945Sweongyo{
8402203945Sweongyo	struct bwn_mac *mac = arg;
8403203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8404203945Sweongyo	uint32_t reason;
8405203945Sweongyo
8406204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
8407204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID))
8408203945Sweongyo		return (FILTER_STRAY);
8409203945Sweongyo
8410203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
8411203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
8412203945Sweongyo		return (FILTER_STRAY);
8413203945Sweongyo	reason &= mac->mac_intr_mask;
8414203945Sweongyo	if (reason == 0)
8415203945Sweongyo		return (FILTER_HANDLED);
8416203945Sweongyo
8417203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
8418203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
8419203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
8420203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
8421203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
8422203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
8423203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
8424203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
8425203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
8426203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
8427203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
8428203945Sweongyo
8429203945Sweongyo	/* Disable interrupts. */
8430203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8431203945Sweongyo
8432203945Sweongyo	mac->mac_reason_intr = reason;
8433203945Sweongyo
8434203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8435203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8436203945Sweongyo
8437203945Sweongyo	taskqueue_enqueue_fast(sc->sc_tq, &mac->mac_intrtask);
8438203945Sweongyo	return (FILTER_HANDLED);
8439203945Sweongyo}
8440203945Sweongyo
8441203945Sweongyostatic void
8442203945Sweongyobwn_intrtask(void *arg, int npending)
8443203945Sweongyo{
8444203945Sweongyo	struct bwn_mac *mac = arg;
8445203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8446203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8447203945Sweongyo	uint32_t merged = 0;
8448203945Sweongyo	int i, tx = 0, rx = 0;
8449203945Sweongyo
8450203945Sweongyo	BWN_LOCK(sc);
8451204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
8452204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID)) {
8453203945Sweongyo		BWN_UNLOCK(sc);
8454203945Sweongyo		return;
8455203945Sweongyo	}
8456203945Sweongyo
8457203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
8458203945Sweongyo		merged |= mac->mac_reason[i];
8459203945Sweongyo
8460203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
8461203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
8462203945Sweongyo
8463203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
8464203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
8465203945Sweongyo		mac->mac_phy.txerrors--;
8466203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
8467203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
8468203945Sweongyo			bwn_restart(mac, "PHY TX errors");
8469203945Sweongyo		}
8470203945Sweongyo	}
8471203945Sweongyo
8472203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
8473203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
8474203945Sweongyo			device_printf(sc->sc_dev,
8475203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
8476203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8477203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8478203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8479203945Sweongyo			bwn_restart(mac, "DMA error");
8480203945Sweongyo			BWN_UNLOCK(sc);
8481203945Sweongyo			return;
8482203945Sweongyo		}
8483203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
8484203945Sweongyo			device_printf(sc->sc_dev,
8485203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
8486203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8487203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8488203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8489203945Sweongyo		}
8490203945Sweongyo	}
8491203945Sweongyo
8492203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
8493203945Sweongyo		bwn_intr_ucode_debug(mac);
8494203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
8495203945Sweongyo		bwn_intr_tbtt_indication(mac);
8496203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
8497203945Sweongyo		bwn_intr_atim_end(mac);
8498203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
8499203945Sweongyo		bwn_intr_beacon(mac);
8500203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
8501203945Sweongyo		bwn_intr_pmq(mac);
8502203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
8503203945Sweongyo		bwn_intr_noise(mac);
8504203945Sweongyo
8505203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
8506203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
8507203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
8508203945Sweongyo			rx = 1;
8509203945Sweongyo		}
8510203945Sweongyo	} else
8511203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
8512203945Sweongyo
8513203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8514203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8515203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8516203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8517203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8518203945Sweongyo
8519203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
8520203945Sweongyo		bwn_intr_txeof(mac);
8521203945Sweongyo		tx = 1;
8522203945Sweongyo	}
8523203945Sweongyo
8524203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
8525203945Sweongyo
8526203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
8527203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
8528203945Sweongyo
8529203945Sweongyo		if (tx && rx) {
8530203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
8531203945Sweongyo				evt = BWN_LED_EVENT_RX;
8532203945Sweongyo			else
8533203945Sweongyo				evt = BWN_LED_EVENT_TX;
8534203945Sweongyo		} else if (tx) {
8535203945Sweongyo			evt = BWN_LED_EVENT_TX;
8536203945Sweongyo		} else if (rx) {
8537203945Sweongyo			evt = BWN_LED_EVENT_RX;
8538203945Sweongyo		} else if (rx == 0) {
8539203945Sweongyo			evt = BWN_LED_EVENT_POLL;
8540203945Sweongyo		}
8541203945Sweongyo
8542203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
8543203945Sweongyo			bwn_led_event(mac, evt);
8544203945Sweongyo       }
8545203945Sweongyo
8546203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
8547203945Sweongyo		if (!IFQ_IS_EMPTY(&ifp->if_snd))
8548203945Sweongyo			bwn_start_locked(ifp);
8549203945Sweongyo	}
8550203945Sweongyo
8551203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8552203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8553203945Sweongyo
8554203945Sweongyo	BWN_UNLOCK(sc);
8555203945Sweongyo}
8556203945Sweongyo
8557203945Sweongyostatic void
8558203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
8559203945Sweongyo{
8560203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8561203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8562203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
8563203945Sweongyo
8564203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
8565203945Sweongyo		return;
8566203945Sweongyo
8567203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
8568203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
8569203945Sweongyo}
8570203945Sweongyo
8571203945Sweongyostatic void
8572203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
8573203945Sweongyo{
8574203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8575203945Sweongyo	uint16_t reason;
8576203945Sweongyo
8577203945Sweongyo	if (mac->mac_fw.opensource == 0)
8578203945Sweongyo		return;
8579203945Sweongyo
8580203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
8581203945Sweongyo	switch (reason) {
8582203945Sweongyo	case BWN_DEBUGINTR_PANIC:
8583203945Sweongyo		bwn_handle_fwpanic(mac);
8584203945Sweongyo		break;
8585203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
8586203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
8587203945Sweongyo		break;
8588203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
8589203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
8590203945Sweongyo		break;
8591203945Sweongyo	case BWN_DEBUGINTR_MARKER:
8592203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
8593203945Sweongyo		break;
8594203945Sweongyo	default:
8595203945Sweongyo		device_printf(sc->sc_dev,
8596203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
8597203945Sweongyo	}
8598203945Sweongyo
8599203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
8600203945Sweongyo	    BWN_DEBUGINTR_ACK);
8601203945Sweongyo}
8602203945Sweongyo
8603203945Sweongyostatic void
8604203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
8605203945Sweongyo{
8606203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8607203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8608203945Sweongyo
8609203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
8610203945Sweongyo		bwn_psctl(mac, 0);
8611203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8612203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
8613203945Sweongyo}
8614203945Sweongyo
8615203945Sweongyostatic void
8616203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
8617203945Sweongyo{
8618203945Sweongyo
8619203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
8620203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
8621203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
8622203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
8623203945Sweongyo	}
8624203945Sweongyo}
8625203945Sweongyo
8626203945Sweongyostatic void
8627203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
8628203945Sweongyo{
8629203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8630203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8631203945Sweongyo	uint32_t cmd, beacon0, beacon1;
8632203945Sweongyo
8633203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
8634203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
8635203945Sweongyo		return;
8636203945Sweongyo
8637203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
8638203945Sweongyo
8639203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
8640203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
8641203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
8642203945Sweongyo
8643203945Sweongyo	if (beacon0 && beacon1) {
8644203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
8645203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
8646203945Sweongyo		return;
8647203945Sweongyo	}
8648203945Sweongyo
8649203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
8650203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
8651203945Sweongyo		bwn_load_beacon0(mac);
8652203945Sweongyo		bwn_load_beacon1(mac);
8653203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
8654203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
8655203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8656203945Sweongyo	} else {
8657203945Sweongyo		if (!beacon0) {
8658203945Sweongyo			bwn_load_beacon0(mac);
8659203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8660203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
8661203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8662203945Sweongyo		} else if (!beacon1) {
8663203945Sweongyo			bwn_load_beacon1(mac);
8664203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8665203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
8666203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8667203945Sweongyo		}
8668203945Sweongyo	}
8669203945Sweongyo}
8670203945Sweongyo
8671203945Sweongyostatic void
8672203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
8673203945Sweongyo{
8674203945Sweongyo	uint32_t tmp;
8675203945Sweongyo
8676203945Sweongyo	while (1) {
8677203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
8678203945Sweongyo		if (!(tmp & 0x00000008))
8679203945Sweongyo			break;
8680203945Sweongyo	}
8681203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
8682203945Sweongyo}
8683203945Sweongyo
8684203945Sweongyostatic void
8685203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
8686203945Sweongyo{
8687203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
8688203945Sweongyo	uint16_t tmp;
8689203945Sweongyo	uint8_t noise[4];
8690203945Sweongyo	uint8_t i, j;
8691203945Sweongyo	int32_t average;
8692203945Sweongyo
8693203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
8694203945Sweongyo		return;
8695203945Sweongyo
8696203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
8697203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
8698203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
8699203945Sweongyo	    noise[3] == 0x7f)
8700203945Sweongyo		goto new;
8701203945Sweongyo
8702203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
8703203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8704203945Sweongyo	i = mac->mac_noise.noi_nsamples;
8705203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
8706203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
8707203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
8708203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
8709203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
8710203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
8711203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
8712203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
8713203945Sweongyo	mac->mac_noise.noi_nsamples++;
8714203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
8715203945Sweongyo		average = 0;
8716203945Sweongyo		for (i = 0; i < 8; i++) {
8717203945Sweongyo			for (j = 0; j < 4; j++)
8718203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
8719203945Sweongyo		}
8720203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
8721203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
8722203945Sweongyo		if (tmp >= 8)
8723203945Sweongyo			average += 2;
8724203945Sweongyo		else
8725203945Sweongyo			average -= 25;
8726203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
8727203945Sweongyo
8728203945Sweongyo		mac->mac_stats.link_noise = average;
8729203945Sweongyo		mac->mac_noise.noi_running = 0;
8730203945Sweongyo		return;
8731203945Sweongyo	}
8732203945Sweongyonew:
8733203945Sweongyo	bwn_noise_gensample(mac);
8734203945Sweongyo}
8735203945Sweongyo
8736203945Sweongyostatic int
8737203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
8738203945Sweongyo{
8739203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
8740203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8741203945Sweongyo	unsigned int i;
8742203945Sweongyo
8743203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8744203945Sweongyo
8745203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8746203945Sweongyo		return (0);
8747203945Sweongyo
8748203945Sweongyo	for (i = 0; i < 5000; i++) {
8749203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
8750203945Sweongyo			break;
8751203945Sweongyo	}
8752203945Sweongyo	if (i >= 5000)
8753203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
8754203945Sweongyo	return ((i > 0) ? 1 : 0);
8755203945Sweongyo}
8756203945Sweongyo
8757203945Sweongyostatic void
8758203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
8759203945Sweongyo{
8760203945Sweongyo	int slot, curslot;
8761203945Sweongyo
8762203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
8763203945Sweongyo	curslot = dr->get_curslot(dr);
8764203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
8765203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8766203945Sweongyo
8767203945Sweongyo	slot = dr->dr_curslot;
8768203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
8769203945Sweongyo		bwn_dma_rxeof(dr, &slot);
8770203945Sweongyo
8771203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
8772203945Sweongyo	    BUS_DMASYNC_PREWRITE);
8773203945Sweongyo
8774203945Sweongyo	dr->set_curslot(dr, slot);
8775203945Sweongyo	dr->dr_curslot = slot;
8776203945Sweongyo}
8777203945Sweongyo
8778203945Sweongyostatic void
8779203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
8780203945Sweongyo{
8781203945Sweongyo	struct bwn_txstatus stat;
8782203945Sweongyo	uint32_t stat0, stat1;
8783203945Sweongyo	uint16_t tmp;
8784203945Sweongyo
8785203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8786203945Sweongyo
8787203945Sweongyo	while (1) {
8788203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
8789203945Sweongyo		if (!(stat0 & 0x00000001))
8790203945Sweongyo			break;
8791203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
8792203945Sweongyo
8793203945Sweongyo		stat.cookie = (stat0 >> 16);
8794203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
8795203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
8796203945Sweongyo		tmp = (stat0 & 0x0000ffff);
8797203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
8798203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
8799203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
8800203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
8801203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
8802203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
8803203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
8804203945Sweongyo
8805203945Sweongyo		bwn_handle_txeof(mac, &stat);
8806203945Sweongyo	}
8807203945Sweongyo}
8808203945Sweongyo
8809203945Sweongyostatic void
8810203945Sweongyobwn_hwreset(void *arg, int npending)
8811203945Sweongyo{
8812203945Sweongyo	struct bwn_mac *mac = arg;
8813203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8814203945Sweongyo	int error = 0;
8815203945Sweongyo	int prev_status;
8816203945Sweongyo
8817203945Sweongyo	BWN_LOCK(sc);
8818203945Sweongyo
8819203945Sweongyo	prev_status = mac->mac_status;
8820203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8821203945Sweongyo		bwn_core_stop(mac);
8822203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
8823203945Sweongyo		bwn_core_exit(mac);
8824203945Sweongyo
8825203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
8826203945Sweongyo		error = bwn_core_init(mac);
8827203945Sweongyo		if (error)
8828203945Sweongyo			goto out;
8829203945Sweongyo	}
8830203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8831203945Sweongyo		bwn_core_start(mac);
8832203945Sweongyoout:
8833203945Sweongyo	if (error) {
8834203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
8835203945Sweongyo		sc->sc_curmac = NULL;
8836203945Sweongyo	}
8837203945Sweongyo	BWN_UNLOCK(sc);
8838203945Sweongyo}
8839203945Sweongyo
8840203945Sweongyostatic void
8841203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
8842203945Sweongyo{
8843203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8844203945Sweongyo	uint16_t reason;
8845203945Sweongyo
8846203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
8847203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
8848203945Sweongyo
8849203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
8850203945Sweongyo		bwn_restart(mac, "ucode panic");
8851203945Sweongyo}
8852203945Sweongyo
8853203945Sweongyostatic void
8854203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
8855203945Sweongyo{
8856203945Sweongyo
8857203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8858203945Sweongyo}
8859203945Sweongyo
8860203945Sweongyostatic void
8861203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
8862203945Sweongyo{
8863203945Sweongyo
8864203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8865203945Sweongyo}
8866203945Sweongyo
8867203945Sweongyostatic uint32_t
8868203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
8869203945Sweongyo{
8870203945Sweongyo	uint32_t val = 0;
8871203945Sweongyo
8872203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
8873203945Sweongyo	val <<= 16;
8874203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
8875203945Sweongyo
8876203945Sweongyo	return (val);
8877203945Sweongyo}
8878203945Sweongyo
8879203945Sweongyostatic void
8880203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
8881203945Sweongyo{
8882203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
8883203945Sweongyo
8884203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
8885203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
8886203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
8887203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
8888203945Sweongyo}
8889203945Sweongyo
8890203945Sweongyostatic int
8891203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
8892203945Sweongyo{
8893204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8894203945Sweongyo
8895203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
8896203945Sweongyo}
8897203945Sweongyo
8898203945Sweongyostatic int
8899203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
8900203945Sweongyo{
8901204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8902203945Sweongyo
8903203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
8904203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8905203945Sweongyo	if (slot == dr->dr_numslots - 1)
8906203945Sweongyo		return (0);
8907203945Sweongyo	return (slot + 1);
8908203945Sweongyo}
8909203945Sweongyo
8910203945Sweongyostatic void
8911203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
8912203945Sweongyo{
8913203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
8914203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8915203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
8916203945Sweongyo	struct bwn_dmadesc_generic *desc;
8917203945Sweongyo	struct bwn_dmadesc_meta *meta;
8918203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
8919203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8920203945Sweongyo	struct mbuf *m;
8921203945Sweongyo	uint32_t macstat;
8922203945Sweongyo	int32_t tmp;
8923203945Sweongyo	int cnt = 0;
8924203945Sweongyo	uint16_t len;
8925203945Sweongyo
8926203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
8927203945Sweongyo
8928203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
8929203945Sweongyo	m = meta->mt_m;
8930203945Sweongyo
8931203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
8932203945Sweongyo		ifp->if_ierrors++;
8933203945Sweongyo		return;
8934203945Sweongyo	}
8935203945Sweongyo
8936203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
8937203945Sweongyo	len = le16toh(rxhdr->frame_len);
8938203945Sweongyo	if (len <= 0) {
8939203945Sweongyo		ifp->if_ierrors++;
8940203945Sweongyo		return;
8941203945Sweongyo	}
8942203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
8943203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
8944203945Sweongyo		bwn_dma_set_redzone(dr, m);
8945203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
8946203945Sweongyo		    BUS_DMASYNC_PREWRITE);
8947203945Sweongyo		return;
8948203945Sweongyo	}
8949203945Sweongyo	if (len > dr->dr_rx_bufsize) {
8950203945Sweongyo		tmp = len;
8951203945Sweongyo		while (1) {
8952203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
8953203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
8954203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
8955203945Sweongyo			    BUS_DMASYNC_PREWRITE);
8956203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
8957203945Sweongyo			cnt++;
8958203945Sweongyo			tmp -= dr->dr_rx_bufsize;
8959203945Sweongyo			if (tmp <= 0)
8960203945Sweongyo				break;
8961203945Sweongyo		}
8962203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
8963203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
8964203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
8965203945Sweongyo		return;
8966203945Sweongyo	}
8967203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
8968203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
8969203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
8970203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
8971203945Sweongyo			return;
8972203945Sweongyo		}
8973203945Sweongyo	}
8974203945Sweongyo
8975203945Sweongyo	m->m_pkthdr.rcvif = ifp;
8976203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
8977203945Sweongyo	m_adj(m, dr->dr_frameoffset);
8978203945Sweongyo
8979203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
8980203945Sweongyo}
8981203945Sweongyo
8982203945Sweongyostatic void
8983203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
8984203945Sweongyo{
8985203945Sweongyo	struct bwn_dma_ring *dr;
8986203945Sweongyo	struct bwn_dmadesc_generic *desc;
8987203945Sweongyo	struct bwn_dmadesc_meta *meta;
8988203945Sweongyo	struct bwn_pio_txqueue *tq;
8989203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
8990203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8991204257Sweongyo	struct bwn_stats *stats = &mac->mac_stats;
8992203945Sweongyo	struct ieee80211_node *ni;
8993206358Srpaulo	struct ieee80211vap *vap;
8994208120Sweongyo	int retrycnt = 0, slot;
8995203945Sweongyo
8996203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8997203945Sweongyo
8998203945Sweongyo	if (status->im)
8999203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
9000203945Sweongyo	if (status->ampdu)
9001203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
9002203945Sweongyo	if (status->rtscnt) {
9003203945Sweongyo		if (status->rtscnt == 0xf)
9004204257Sweongyo			stats->rtsfail++;
9005203945Sweongyo		else
9006204257Sweongyo			stats->rts++;
9007203945Sweongyo	}
9008203945Sweongyo
9009203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
9010203945Sweongyo		if (status->ack) {
9011203945Sweongyo			dr = bwn_dma_parse_cookie(mac, status,
9012203945Sweongyo			    status->cookie, &slot);
9013203945Sweongyo			if (dr == NULL) {
9014203945Sweongyo				device_printf(sc->sc_dev,
9015203945Sweongyo				    "failed to parse cookie\n");
9016203945Sweongyo				return;
9017203945Sweongyo			}
9018203945Sweongyo			while (1) {
9019203945Sweongyo				dr->getdesc(dr, slot, &desc, &meta);
9020203945Sweongyo				if (meta->mt_islast) {
9021203945Sweongyo					ni = meta->mt_ni;
9022206358Srpaulo					vap = ni->ni_vap;
9023206358Srpaulo					ieee80211_ratectl_tx_complete(vap, ni,
9024206358Srpaulo					    status->ack ?
9025206358Srpaulo					      IEEE80211_RATECTL_TX_SUCCESS :
9026206358Srpaulo					      IEEE80211_RATECTL_TX_FAILURE,
9027208120Sweongyo					    &retrycnt, 0);
9028203945Sweongyo					break;
9029203945Sweongyo				}
9030203945Sweongyo				slot = bwn_dma_nextslot(dr, slot);
9031203945Sweongyo			}
9032203945Sweongyo		}
9033203945Sweongyo		bwn_dma_handle_txeof(mac, status);
9034203945Sweongyo	} else {
9035203945Sweongyo		if (status->ack) {
9036203945Sweongyo			tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9037203945Sweongyo			if (tq == NULL) {
9038203945Sweongyo				device_printf(sc->sc_dev,
9039203945Sweongyo				    "failed to parse cookie\n");
9040203945Sweongyo				return;
9041203945Sweongyo			}
9042203945Sweongyo			ni = tp->tp_ni;
9043206358Srpaulo			vap = ni->ni_vap;
9044206358Srpaulo			ieee80211_ratectl_tx_complete(vap, ni,
9045206358Srpaulo			    status->ack ?
9046206358Srpaulo			      IEEE80211_RATECTL_TX_SUCCESS :
9047206358Srpaulo			      IEEE80211_RATECTL_TX_FAILURE,
9048208120Sweongyo			    &retrycnt, 0);
9049203945Sweongyo		}
9050203945Sweongyo		bwn_pio_handle_txeof(mac, status);
9051203945Sweongyo	}
9052203945Sweongyo
9053203945Sweongyo	bwn_phy_txpower_check(mac, 0);
9054203945Sweongyo}
9055203945Sweongyo
9056203945Sweongyostatic uint8_t
9057203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
9058203945Sweongyo{
9059203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
9060203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9061203945Sweongyo	struct bwn_rxhdr4 rxhdr;
9062203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9063203945Sweongyo	struct mbuf *m;
9064203945Sweongyo	uint32_t ctl32, macstat, v32;
9065203945Sweongyo	unsigned int i, padding;
9066209888Sweongyo	uint16_t ctl16, len, totlen, v16;
9067203945Sweongyo	unsigned char *mp;
9068203945Sweongyo	char *data;
9069203945Sweongyo
9070203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
9071203945Sweongyo
9072203945Sweongyo	if (prq->prq_rev >= 8) {
9073203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9074203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
9075203945Sweongyo			return (0);
9076203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9077203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
9078203945Sweongyo		for (i = 0; i < 10; i++) {
9079203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9080203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
9081203945Sweongyo				goto ready;
9082203945Sweongyo			DELAY(10);
9083203945Sweongyo		}
9084203945Sweongyo	} else {
9085203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9086203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
9087203945Sweongyo			return (0);
9088203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
9089203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
9090203945Sweongyo		for (i = 0; i < 10; i++) {
9091203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9092203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
9093203945Sweongyo				goto ready;
9094203945Sweongyo			DELAY(10);
9095203945Sweongyo		}
9096203945Sweongyo	}
9097203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
9098203945Sweongyo	return (1);
9099203945Sweongyoready:
9100203945Sweongyo	if (prq->prq_rev >= 8)
9101204922Sweongyo		siba_read_multi_4(sc->sc_dev, &rxhdr, sizeof(rxhdr),
9102203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9103203945Sweongyo	else
9104204922Sweongyo		siba_read_multi_2(sc->sc_dev, &rxhdr, sizeof(rxhdr),
9105203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9106203945Sweongyo	len = le16toh(rxhdr.frame_len);
9107203945Sweongyo	if (len > 0x700) {
9108203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
9109203945Sweongyo		goto error;
9110203945Sweongyo	}
9111203945Sweongyo	if (len == 0) {
9112203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
9113203945Sweongyo		goto error;
9114203945Sweongyo	}
9115203945Sweongyo
9116203945Sweongyo	macstat = le32toh(rxhdr.mac_status);
9117203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9118203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9119203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
9120203945Sweongyo			goto error;
9121203945Sweongyo		}
9122203945Sweongyo	}
9123203945Sweongyo
9124203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9125209888Sweongyo	totlen = len + padding;
9126209888Sweongyo	KASSERT(totlen <= MCLBYTES, ("too big..\n"));
9127243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
9128203945Sweongyo	if (m == NULL) {
9129203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
9130203945Sweongyo		goto error;
9131203945Sweongyo	}
9132203945Sweongyo	mp = mtod(m, unsigned char *);
9133203945Sweongyo	if (prq->prq_rev >= 8) {
9134209888Sweongyo		siba_read_multi_4(sc->sc_dev, mp, (totlen & ~3),
9135203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9136209888Sweongyo		if (totlen & 3) {
9137203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
9138209888Sweongyo			data = &(mp[totlen - 1]);
9139209888Sweongyo			switch (totlen & 3) {
9140203945Sweongyo			case 3:
9141203945Sweongyo				*data = (v32 >> 16);
9142203945Sweongyo				data--;
9143203945Sweongyo			case 2:
9144203945Sweongyo				*data = (v32 >> 8);
9145203945Sweongyo				data--;
9146203945Sweongyo			case 1:
9147203945Sweongyo				*data = v32;
9148203945Sweongyo			}
9149203945Sweongyo		}
9150203945Sweongyo	} else {
9151209888Sweongyo		siba_read_multi_2(sc->sc_dev, mp, (totlen & ~1),
9152203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9153209888Sweongyo		if (totlen & 1) {
9154203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
9155209888Sweongyo			mp[totlen - 1] = v16;
9156203945Sweongyo		}
9157203945Sweongyo	}
9158203945Sweongyo
9159203945Sweongyo	m->m_pkthdr.rcvif = ifp;
9160209888Sweongyo	m->m_len = m->m_pkthdr.len = totlen;
9161203945Sweongyo
9162203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
9163203945Sweongyo
9164203945Sweongyo	return (1);
9165203945Sweongyoerror:
9166203945Sweongyo	if (prq->prq_rev >= 8)
9167203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9168203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
9169203945Sweongyo	else
9170203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
9171203945Sweongyo	return (1);
9172203945Sweongyo}
9173203945Sweongyo
9174203945Sweongyostatic int
9175203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
9176203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
9177203945Sweongyo{
9178203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
9179203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9180203945Sweongyo	struct bwn_rxhdr4 *hdr;
9181203945Sweongyo	bus_dmamap_t map;
9182203945Sweongyo	bus_addr_t paddr;
9183203945Sweongyo	struct mbuf *m;
9184203945Sweongyo	int error;
9185203945Sweongyo
9186243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
9187203945Sweongyo	if (m == NULL) {
9188203945Sweongyo		error = ENOBUFS;
9189203945Sweongyo
9190203945Sweongyo		/*
9191203945Sweongyo		 * If the NIC is up and running, we need to:
9192203945Sweongyo		 * - Clear RX buffer's header.
9193203945Sweongyo		 * - Restore RX descriptor settings.
9194203945Sweongyo		 */
9195203945Sweongyo		if (init)
9196203945Sweongyo			return (error);
9197203945Sweongyo		else
9198203945Sweongyo			goto back;
9199203945Sweongyo	}
9200203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
9201203945Sweongyo
9202203945Sweongyo	bwn_dma_set_redzone(dr, m);
9203203945Sweongyo
9204203945Sweongyo	/*
9205203945Sweongyo	 * Try to load RX buf into temporary DMA map
9206203945Sweongyo	 */
9207203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
9208203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
9209203945Sweongyo	if (error) {
9210203945Sweongyo		m_freem(m);
9211203945Sweongyo
9212203945Sweongyo		/*
9213203945Sweongyo		 * See the comment above
9214203945Sweongyo		 */
9215203945Sweongyo		if (init)
9216203945Sweongyo			return (error);
9217203945Sweongyo		else
9218203945Sweongyo			goto back;
9219203945Sweongyo	}
9220203945Sweongyo
9221203945Sweongyo	if (!init)
9222203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
9223203945Sweongyo	meta->mt_m = m;
9224203945Sweongyo	meta->mt_paddr = paddr;
9225203945Sweongyo
9226203945Sweongyo	/*
9227203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
9228203945Sweongyo	 */
9229203945Sweongyo	map = meta->mt_dmap;
9230203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
9231203945Sweongyo	dr->dr_spare_dmap = map;
9232203945Sweongyo
9233203945Sweongyoback:
9234203945Sweongyo	/*
9235203945Sweongyo	 * Clear RX buf header
9236203945Sweongyo	 */
9237203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
9238203945Sweongyo	bzero(hdr, sizeof(*hdr));
9239203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9240203945Sweongyo	    BUS_DMASYNC_PREWRITE);
9241203945Sweongyo
9242203945Sweongyo	/*
9243203945Sweongyo	 * Setup RX buf descriptor
9244203945Sweongyo	 */
9245250314Shiren	dr->setdesc(dr, desc, meta->mt_paddr, meta->mt_m->m_len -
9246203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
9247203945Sweongyo	return (error);
9248203945Sweongyo}
9249203945Sweongyo
9250203945Sweongyostatic void
9251203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
9252203945Sweongyo		 bus_size_t mapsz __unused, int error)
9253203945Sweongyo{
9254203945Sweongyo
9255203945Sweongyo	if (!error) {
9256203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
9257203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
9258203945Sweongyo	}
9259203945Sweongyo}
9260203945Sweongyo
9261203945Sweongyostatic int
9262203945Sweongyobwn_hwrate2ieeerate(int rate)
9263203945Sweongyo{
9264203945Sweongyo
9265203945Sweongyo	switch (rate) {
9266203945Sweongyo	case BWN_CCK_RATE_1MB:
9267203945Sweongyo		return (2);
9268203945Sweongyo	case BWN_CCK_RATE_2MB:
9269203945Sweongyo		return (4);
9270203945Sweongyo	case BWN_CCK_RATE_5MB:
9271203945Sweongyo		return (11);
9272203945Sweongyo	case BWN_CCK_RATE_11MB:
9273203945Sweongyo		return (22);
9274203945Sweongyo	case BWN_OFDM_RATE_6MB:
9275203945Sweongyo		return (12);
9276203945Sweongyo	case BWN_OFDM_RATE_9MB:
9277203945Sweongyo		return (18);
9278203945Sweongyo	case BWN_OFDM_RATE_12MB:
9279203945Sweongyo		return (24);
9280203945Sweongyo	case BWN_OFDM_RATE_18MB:
9281203945Sweongyo		return (36);
9282203945Sweongyo	case BWN_OFDM_RATE_24MB:
9283203945Sweongyo		return (48);
9284203945Sweongyo	case BWN_OFDM_RATE_36MB:
9285203945Sweongyo		return (72);
9286203945Sweongyo	case BWN_OFDM_RATE_48MB:
9287203945Sweongyo		return (96);
9288203945Sweongyo	case BWN_OFDM_RATE_54MB:
9289203945Sweongyo		return (108);
9290203945Sweongyo	default:
9291203945Sweongyo		printf("Ooops\n");
9292203945Sweongyo		return (0);
9293203945Sweongyo	}
9294203945Sweongyo}
9295203945Sweongyo
9296203945Sweongyostatic void
9297203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
9298203945Sweongyo{
9299203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
9300203945Sweongyo	struct bwn_plcp6 *plcp;
9301203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9302203945Sweongyo	struct ieee80211_frame_min *wh;
9303203945Sweongyo	struct ieee80211_node *ni;
9304203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9305203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9306203945Sweongyo	uint32_t macstat;
9307204242Simp	int padding, rate, rssi = 0, noise = 0, type;
9308203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
9309203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
9310204242Simp	static int rx_mac_dec_rpt = 0;
9311203945Sweongyo
9312203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9313203945Sweongyo
9314203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
9315203945Sweongyo	phystat3 = le16toh(rxhdr->phy_status3);
9316203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9317203945Sweongyo	chanstat = le16toh(rxhdr->channel);
9318203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
9319203945Sweongyo
9320203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
9321203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
9322203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
9323203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
9324203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
9325203945Sweongyo		goto drop;
9326203945Sweongyo
9327203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9328203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
9329204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9330204081Sweongyo		    m->m_pkthdr.len);
9331203945Sweongyo		goto drop;
9332203945Sweongyo	}
9333203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
9334203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
9335203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
9336204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9337204081Sweongyo		    m->m_pkthdr.len);
9338203945Sweongyo		goto drop;
9339203945Sweongyo	}
9340203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
9341203945Sweongyo
9342204242Simp	if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
9343204081Sweongyo		device_printf(sc->sc_dev,
9344204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
9345204081Sweongyo		    BWN_ISOLDFMT(mac),
9346204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
9347203945Sweongyo
9348203945Sweongyo	/* XXX calculating RSSI & noise & antenna */
9349203945Sweongyo
9350203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
9351203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
9352203945Sweongyo		    phytype == BWN_PHYTYPE_A);
9353203945Sweongyo	else
9354203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
9355203945Sweongyo	if (rate == -1) {
9356203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
9357203945Sweongyo			goto drop;
9358203945Sweongyo	}
9359203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
9360203945Sweongyo
9361203945Sweongyo	/* RX radio tap */
9362203945Sweongyo	if (ieee80211_radiotap_active(ic))
9363203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
9364203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
9365203945Sweongyo
9366203945Sweongyo	rssi = rxhdr->phy.abg.rssi;	/* XXX incorrect RSSI calculation? */
9367203945Sweongyo	noise = mac->mac_stats.link_noise;
9368203945Sweongyo
9369207176Sweongyo	ifp->if_ipackets++;
9370207176Sweongyo
9371203945Sweongyo	BWN_UNLOCK(sc);
9372203945Sweongyo
9373203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
9374203945Sweongyo	if (ni != NULL) {
9375203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
9376203945Sweongyo		ieee80211_free_node(ni);
9377203945Sweongyo	} else
9378203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
9379203945Sweongyo
9380203945Sweongyo	BWN_LOCK(sc);
9381203945Sweongyo	return;
9382203945Sweongyodrop:
9383203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
9384203945Sweongyo}
9385203945Sweongyo
9386203945Sweongyostatic void
9387203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
9388203945Sweongyo    const struct bwn_txstatus *status)
9389203945Sweongyo{
9390203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9391203945Sweongyo	struct bwn_dma_ring *dr;
9392203945Sweongyo	struct bwn_dmadesc_generic *desc;
9393203945Sweongyo	struct bwn_dmadesc_meta *meta;
9394203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9395203945Sweongyo	struct ieee80211_node *ni;
9396203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9397203945Sweongyo	struct mbuf *m;
9398203945Sweongyo	int slot;
9399203945Sweongyo
9400203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9401203945Sweongyo
9402203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
9403203945Sweongyo	if (dr == NULL) {
9404203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
9405203945Sweongyo		return;
9406203945Sweongyo	}
9407203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
9408203945Sweongyo
9409203945Sweongyo	while (1) {
9410203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
9411203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9412203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
9413203945Sweongyo
9414203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
9415203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
9416203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
9417203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
9418203945Sweongyo
9419203945Sweongyo		if (meta->mt_islast) {
9420203945Sweongyo			KASSERT(meta->mt_m != NULL,
9421203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9422203945Sweongyo
9423203945Sweongyo			ni = meta->mt_ni;
9424203945Sweongyo			m = meta->mt_m;
9425203945Sweongyo			if (ni != NULL) {
9426203945Sweongyo				/*
9427203945Sweongyo				 * Do any tx complete callback. Note this must
9428203945Sweongyo				 * be done before releasing the node reference.
9429203945Sweongyo				 */
9430203945Sweongyo				if (m->m_flags & M_TXCB)
9431203945Sweongyo					ieee80211_process_callback(ni, m, 0);
9432203945Sweongyo				ieee80211_free_node(ni);
9433203945Sweongyo				meta->mt_ni = NULL;
9434203945Sweongyo			}
9435203945Sweongyo			m_freem(m);
9436203945Sweongyo			meta->mt_m = NULL;
9437203945Sweongyo		} else {
9438203945Sweongyo			KASSERT(meta->mt_m == NULL,
9439203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9440203945Sweongyo		}
9441203945Sweongyo
9442203945Sweongyo		dr->dr_usedslot--;
9443203945Sweongyo		if (meta->mt_islast) {
9444203945Sweongyo			ifp->if_opackets++;
9445203945Sweongyo			break;
9446203945Sweongyo		}
9447203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
9448203945Sweongyo	}
9449203945Sweongyo	sc->sc_watchdog_timer = 0;
9450203945Sweongyo	if (dr->dr_stop) {
9451203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
9452203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9453203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9454203945Sweongyo		dr->dr_stop = 0;
9455203945Sweongyo	}
9456203945Sweongyo}
9457203945Sweongyo
9458203945Sweongyostatic void
9459203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
9460203945Sweongyo    const struct bwn_txstatus *status)
9461203945Sweongyo{
9462203945Sweongyo	struct bwn_pio_txqueue *tq;
9463203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9464203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9465203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9466203945Sweongyo
9467203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9468203945Sweongyo
9469203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9470203945Sweongyo	if (tq == NULL)
9471203945Sweongyo		return;
9472203945Sweongyo
9473203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
9474203945Sweongyo	tq->tq_free++;
9475203945Sweongyo
9476203945Sweongyo	if (tp->tp_ni != NULL) {
9477203945Sweongyo		/*
9478203945Sweongyo		 * Do any tx complete callback.  Note this must
9479203945Sweongyo		 * be done before releasing the node reference.
9480203945Sweongyo		 */
9481203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
9482203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
9483203945Sweongyo		ieee80211_free_node(tp->tp_ni);
9484203945Sweongyo		tp->tp_ni = NULL;
9485203945Sweongyo	}
9486203945Sweongyo	m_freem(tp->tp_m);
9487203945Sweongyo	tp->tp_m = NULL;
9488203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
9489203945Sweongyo
9490203945Sweongyo	ifp->if_opackets++;
9491203945Sweongyo
9492203945Sweongyo	sc->sc_watchdog_timer = 0;
9493203945Sweongyo	if (tq->tq_stop) {
9494203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9495203945Sweongyo		tq->tq_stop = 0;
9496203945Sweongyo	}
9497203945Sweongyo}
9498203945Sweongyo
9499203945Sweongyostatic void
9500203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
9501203945Sweongyo{
9502203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9503203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
9504203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9505203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9506203945Sweongyo	unsigned long now;
9507203945Sweongyo	int result;
9508203945Sweongyo
9509203945Sweongyo	BWN_GETTIME(now);
9510203945Sweongyo
9511203945Sweongyo	if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
9512203945Sweongyo		return;
9513203945Sweongyo	phy->nexttime = now + 2 * 1000;
9514203945Sweongyo
9515204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
9516204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306)
9517203945Sweongyo		return;
9518203945Sweongyo
9519203945Sweongyo	if (phy->recalc_txpwr != NULL) {
9520203945Sweongyo		result = phy->recalc_txpwr(mac,
9521203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
9522203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
9523203945Sweongyo			return;
9524203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
9525203945Sweongyo		    ("%s: fail", __func__));
9526203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
9527203945Sweongyo
9528203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
9529203945Sweongyo	}
9530203945Sweongyo}
9531203945Sweongyo
9532203945Sweongyostatic uint16_t
9533203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
9534203945Sweongyo{
9535203945Sweongyo
9536203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
9537203945Sweongyo}
9538203945Sweongyo
9539203945Sweongyostatic uint32_t
9540203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
9541203945Sweongyo{
9542203945Sweongyo
9543203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
9544203945Sweongyo}
9545203945Sweongyo
9546203945Sweongyostatic void
9547203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
9548203945Sweongyo{
9549203945Sweongyo
9550203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
9551203945Sweongyo}
9552203945Sweongyo
9553203945Sweongyostatic void
9554203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
9555203945Sweongyo{
9556203945Sweongyo
9557203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
9558203945Sweongyo}
9559203945Sweongyo
9560203945Sweongyostatic int
9561203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
9562203945Sweongyo{
9563203945Sweongyo
9564203945Sweongyo	switch (rate) {
9565203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
9566203945Sweongyo	case 12:
9567203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9568203945Sweongyo	case 18:
9569203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9570203945Sweongyo	case 24:
9571203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9572203945Sweongyo	case 36:
9573203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9574203945Sweongyo	case 48:
9575203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9576203945Sweongyo	case 72:
9577203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9578203945Sweongyo	case 96:
9579203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9580203945Sweongyo	case 108:
9581203945Sweongyo		return (BWN_OFDM_RATE_54MB);
9582203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
9583203945Sweongyo	case 2:
9584203945Sweongyo		return (BWN_CCK_RATE_1MB);
9585203945Sweongyo	case 4:
9586203945Sweongyo		return (BWN_CCK_RATE_2MB);
9587203945Sweongyo	case 11:
9588203945Sweongyo		return (BWN_CCK_RATE_5MB);
9589203945Sweongyo	case 22:
9590203945Sweongyo		return (BWN_CCK_RATE_11MB);
9591203945Sweongyo	}
9592203945Sweongyo
9593203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
9594203945Sweongyo	return (BWN_CCK_RATE_1MB);
9595203945Sweongyo}
9596203945Sweongyo
9597203945Sweongyostatic int
9598203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
9599203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
9600203945Sweongyo{
9601203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
9602203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9603203945Sweongyo	struct ieee80211_frame *wh;
9604203945Sweongyo	struct ieee80211_frame *protwh;
9605203945Sweongyo	struct ieee80211_frame_cts *cts;
9606203945Sweongyo	struct ieee80211_frame_rts *rts;
9607203945Sweongyo	const struct ieee80211_txparam *tp;
9608203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
9609203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9610203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9611203945Sweongyo	struct mbuf *mprot;
9612203945Sweongyo	unsigned int len;
9613203945Sweongyo	uint32_t macctl = 0;
9614203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
9615203945Sweongyo	uint16_t phyctl = 0;
9616203945Sweongyo	uint8_t rate, rate_fb;
9617203945Sweongyo
9618203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
9619203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
9620203945Sweongyo
9621203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
9622203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
9623203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
9624203945Sweongyo
9625203945Sweongyo	/*
9626203945Sweongyo	 * Find TX rate
9627203945Sweongyo	 */
9628203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
9629203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
9630203945Sweongyo		rate = rate_fb = tp->mgmtrate;
9631203945Sweongyo	else if (ismcast)
9632203945Sweongyo		rate = rate_fb = tp->mcastrate;
9633203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
9634203945Sweongyo		rate = rate_fb = tp->ucastrate;
9635203945Sweongyo	else {
9636206358Srpaulo		rix = ieee80211_ratectl_rate(ni, NULL, 0);
9637203945Sweongyo		rate = ni->ni_txrate;
9638203945Sweongyo
9639203945Sweongyo		if (rix > 0)
9640203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
9641203945Sweongyo			    IEEE80211_RATE_VAL;
9642203945Sweongyo		else
9643203945Sweongyo			rate_fb = rate;
9644203945Sweongyo	}
9645203945Sweongyo
9646203945Sweongyo	sc->sc_tx_rate = rate;
9647203945Sweongyo
9648203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
9649203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
9650203945Sweongyo
9651203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
9652203945Sweongyo	    bwn_plcp_getcck(rate);
9653203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
9654203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
9655203945Sweongyo
9656203945Sweongyo	if ((rate_fb == rate) ||
9657203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
9658203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
9659203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
9660203945Sweongyo	else
9661203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
9662203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
9663203945Sweongyo
9664203945Sweongyo	/* XXX TX encryption */
9665203945Sweongyo	bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
9666203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
9667203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
9668203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
9669203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
9670203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
9671203945Sweongyo
9672203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
9673203945Sweongyo	    BWN_TX_EFT_FB_CCK;
9674203945Sweongyo	txhdr->chan = phy->chan;
9675203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
9676203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
9677203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9678203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
9679203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
9680203945Sweongyo
9681203945Sweongyo	/* XXX TX antenna selection */
9682203945Sweongyo
9683203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
9684203945Sweongyo	case 0:
9685203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
9686203945Sweongyo		break;
9687203945Sweongyo	case 1:
9688203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
9689203945Sweongyo		break;
9690203945Sweongyo	case 2:
9691203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
9692203945Sweongyo		break;
9693203945Sweongyo	case 3:
9694203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
9695203945Sweongyo		break;
9696203945Sweongyo	case 4:
9697203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
9698203945Sweongyo		break;
9699203945Sweongyo	default:
9700203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9701203945Sweongyo	}
9702203945Sweongyo
9703203945Sweongyo	if (!ismcast)
9704203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
9705203945Sweongyo
9706203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
9707203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
9708203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
9709203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
9710203945Sweongyo
9711203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
9712203945Sweongyo		/* XXX RTS rate is always 1MB??? */
9713203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
9714203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
9715203945Sweongyo
9716203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
9717203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
9718203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
9719203945Sweongyo
9720203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
9721203945Sweongyo			cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
9722203945Sweongyo			    (txhdr->body.old.rts_frame) :
9723203945Sweongyo			    (txhdr->body.new.rts_frame));
9724203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
9725203945Sweongyo			    protdur);
9726203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9727203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
9728203945Sweongyo			    mprot->m_pkthdr.len);
9729203945Sweongyo			m_freem(mprot);
9730203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
9731203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
9732203945Sweongyo		} else {
9733203945Sweongyo			rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
9734203945Sweongyo			    (txhdr->body.old.rts_frame) :
9735203945Sweongyo			    (txhdr->body.new.rts_frame));
9736203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
9737203945Sweongyo			    isshort);
9738203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
9739203945Sweongyo			    wh->i_addr2, protdur);
9740203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9741203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
9742203945Sweongyo			    mprot->m_pkthdr.len);
9743203945Sweongyo			m_freem(mprot);
9744203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
9745203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
9746203945Sweongyo		}
9747203945Sweongyo		len += IEEE80211_CRC_LEN;
9748203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
9749203945Sweongyo		    &txhdr->body.old.rts_plcp :
9750203945Sweongyo		    &txhdr->body.new.rts_plcp), len, rts_rate);
9751203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
9752203945Sweongyo		    rts_rate_fb);
9753203945Sweongyo
9754203945Sweongyo		protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
9755203945Sweongyo		    (&txhdr->body.old.rts_frame) :
9756203945Sweongyo		    (&txhdr->body.new.rts_frame));
9757203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
9758203945Sweongyo
9759203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
9760203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
9761203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
9762203945Sweongyo		} else {
9763203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
9764203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
9765203945Sweongyo		}
9766203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
9767203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
9768203945Sweongyo	}
9769203945Sweongyo
9770203945Sweongyo	if (BWN_ISOLDFMT(mac))
9771203945Sweongyo		txhdr->body.old.cookie = htole16(cookie);
9772203945Sweongyo	else
9773203945Sweongyo		txhdr->body.new.cookie = htole16(cookie);
9774203945Sweongyo
9775203945Sweongyo	txhdr->macctl = htole32(macctl);
9776203945Sweongyo	txhdr->phyctl = htole16(phyctl);
9777203945Sweongyo
9778203945Sweongyo	/*
9779203945Sweongyo	 * TX radio tap
9780203945Sweongyo	 */
9781203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
9782203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
9783203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
9784203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
9785203945Sweongyo		if (isshort &&
9786203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9787203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
9788203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
9789203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
9790203945Sweongyo
9791203945Sweongyo		ieee80211_radiotap_tx(vap, m);
9792203945Sweongyo	}
9793203945Sweongyo
9794203945Sweongyo	return (0);
9795203945Sweongyo}
9796203945Sweongyo
9797203945Sweongyostatic void
9798203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
9799203945Sweongyo    const uint8_t rate)
9800203945Sweongyo{
9801203945Sweongyo	uint32_t d, plen;
9802203945Sweongyo	uint8_t *raw = plcp->o.raw;
9803203945Sweongyo
9804203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
9805203945Sweongyo		d = bwn_plcp_getofdm(rate);
9806203945Sweongyo		KASSERT(!(octets & 0xf000),
9807203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9808203945Sweongyo		d |= (octets << 5);
9809203945Sweongyo		plcp->o.data = htole32(d);
9810203945Sweongyo	} else {
9811203945Sweongyo		plen = octets * 16 / rate;
9812203945Sweongyo		if ((octets * 16 % rate) > 0) {
9813203945Sweongyo			plen++;
9814203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
9815203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
9816203945Sweongyo				raw[1] = 0x84;
9817203945Sweongyo			} else
9818203945Sweongyo				raw[1] = 0x04;
9819203945Sweongyo		} else
9820203945Sweongyo			raw[1] = 0x04;
9821203945Sweongyo		plcp->o.data |= htole32(plen << 16);
9822203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
9823203945Sweongyo	}
9824203945Sweongyo}
9825203945Sweongyo
9826203945Sweongyostatic uint8_t
9827203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
9828203945Sweongyo{
9829204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9830203945Sweongyo	uint8_t mask;
9831203945Sweongyo
9832203945Sweongyo	if (n == 0)
9833203945Sweongyo		return (0);
9834203945Sweongyo	if (mac->mac_phy.gmode)
9835204922Sweongyo		mask = siba_sprom_get_ant_bg(sc->sc_dev);
9836203945Sweongyo	else
9837204922Sweongyo		mask = siba_sprom_get_ant_a(sc->sc_dev);
9838203945Sweongyo	if (!(mask & (1 << (n - 1))))
9839203945Sweongyo		return (0);
9840203945Sweongyo	return (n);
9841203945Sweongyo}
9842203945Sweongyo
9843203945Sweongyostatic uint8_t
9844203945Sweongyobwn_get_fbrate(uint8_t bitrate)
9845203945Sweongyo{
9846203945Sweongyo	switch (bitrate) {
9847203945Sweongyo	case BWN_CCK_RATE_1MB:
9848203945Sweongyo		return (BWN_CCK_RATE_1MB);
9849203945Sweongyo	case BWN_CCK_RATE_2MB:
9850203945Sweongyo		return (BWN_CCK_RATE_1MB);
9851203945Sweongyo	case BWN_CCK_RATE_5MB:
9852203945Sweongyo		return (BWN_CCK_RATE_2MB);
9853203945Sweongyo	case BWN_CCK_RATE_11MB:
9854203945Sweongyo		return (BWN_CCK_RATE_5MB);
9855203945Sweongyo	case BWN_OFDM_RATE_6MB:
9856203945Sweongyo		return (BWN_CCK_RATE_5MB);
9857203945Sweongyo	case BWN_OFDM_RATE_9MB:
9858203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9859203945Sweongyo	case BWN_OFDM_RATE_12MB:
9860203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9861203945Sweongyo	case BWN_OFDM_RATE_18MB:
9862203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9863203945Sweongyo	case BWN_OFDM_RATE_24MB:
9864203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9865203945Sweongyo	case BWN_OFDM_RATE_36MB:
9866203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9867203945Sweongyo	case BWN_OFDM_RATE_48MB:
9868203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9869203945Sweongyo	case BWN_OFDM_RATE_54MB:
9870203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9871203945Sweongyo	}
9872203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9873203945Sweongyo	return (0);
9874203945Sweongyo}
9875203945Sweongyo
9876203945Sweongyostatic uint32_t
9877203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9878203945Sweongyo    uint32_t ctl, const void *_data, int len)
9879203945Sweongyo{
9880204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9881203945Sweongyo	uint32_t value = 0;
9882203945Sweongyo	const uint8_t *data = _data;
9883203945Sweongyo
9884203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
9885203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
9886203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9887203945Sweongyo
9888204922Sweongyo	siba_write_multi_4(sc->sc_dev, data, (len & ~3),
9889203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
9890203945Sweongyo	if (len & 3) {
9891203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
9892203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
9893203945Sweongyo		data = &(data[len - 1]);
9894203945Sweongyo		switch (len & 3) {
9895203945Sweongyo		case 3:
9896203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
9897203945Sweongyo			value |= (uint32_t)(*data) << 16;
9898203945Sweongyo			data--;
9899203945Sweongyo		case 2:
9900203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
9901203945Sweongyo			value |= (uint32_t)(*data) << 8;
9902203945Sweongyo			data--;
9903203945Sweongyo		case 1:
9904203945Sweongyo			value |= (uint32_t)(*data);
9905203945Sweongyo		}
9906203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9907203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
9908203945Sweongyo	}
9909203945Sweongyo
9910203945Sweongyo	return (ctl);
9911203945Sweongyo}
9912203945Sweongyo
9913203945Sweongyostatic void
9914203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9915203945Sweongyo    uint16_t offset, uint32_t value)
9916203945Sweongyo{
9917203945Sweongyo
9918203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
9919203945Sweongyo}
9920203945Sweongyo
9921203945Sweongyostatic uint16_t
9922203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9923203945Sweongyo    uint16_t ctl, const void *_data, int len)
9924203945Sweongyo{
9925204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9926203945Sweongyo	const uint8_t *data = _data;
9927203945Sweongyo
9928203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
9929203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9930203945Sweongyo
9931204922Sweongyo	siba_write_multi_2(sc->sc_dev, data, (len & ~1),
9932203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
9933203945Sweongyo	if (len & 1) {
9934203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
9935203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9936203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
9937203945Sweongyo	}
9938203945Sweongyo
9939203945Sweongyo	return (ctl);
9940203945Sweongyo}
9941203945Sweongyo
9942203945Sweongyostatic uint16_t
9943203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9944203945Sweongyo    uint16_t ctl, struct mbuf *m0)
9945203945Sweongyo{
9946203945Sweongyo	int i, j = 0;
9947203945Sweongyo	uint16_t data = 0;
9948203945Sweongyo	const uint8_t *buf;
9949203945Sweongyo	struct mbuf *m = m0;
9950203945Sweongyo
9951203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
9952203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9953203945Sweongyo
9954203945Sweongyo	for (; m != NULL; m = m->m_next) {
9955203945Sweongyo		buf = mtod(m, const uint8_t *);
9956203945Sweongyo		for (i = 0; i < m->m_len; i++) {
9957203945Sweongyo			if (!((j++) % 2))
9958203945Sweongyo				data |= buf[i];
9959203945Sweongyo			else {
9960203945Sweongyo				data |= (buf[i] << 8);
9961203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
9962203945Sweongyo				data = 0;
9963203945Sweongyo			}
9964203945Sweongyo		}
9965203945Sweongyo	}
9966203945Sweongyo	if (m0->m_pkthdr.len % 2) {
9967203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
9968203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9969203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
9970203945Sweongyo	}
9971203945Sweongyo
9972203945Sweongyo	return (ctl);
9973203945Sweongyo}
9974203945Sweongyo
9975203945Sweongyostatic void
9976203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
9977203945Sweongyo{
9978203945Sweongyo
9979203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
9980203945Sweongyo		return;
9981203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
9982203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
9983203945Sweongyo}
9984203945Sweongyo
9985203945Sweongyostatic struct bwn_dma_ring *
9986203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
9987203945Sweongyo{
9988203945Sweongyo
9989203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
9990203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
9991203945Sweongyo
9992203945Sweongyo	switch (prio) {
9993203945Sweongyo	case 3:
9994203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
9995203945Sweongyo	case 2:
9996203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
9997203945Sweongyo	case 0:
9998203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
9999203945Sweongyo	case 1:
10000203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
10001203945Sweongyo	}
10002203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
10003204242Simp	return (NULL);
10004203945Sweongyo}
10005203945Sweongyo
10006203945Sweongyostatic int
10007203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
10008203945Sweongyo{
10009203945Sweongyo	int slot;
10010203945Sweongyo
10011204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
10012203945Sweongyo
10013203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
10014203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
10015203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
10016203945Sweongyo
10017203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
10018203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
10019203945Sweongyo	dr->dr_curslot = slot;
10020203945Sweongyo	dr->dr_usedslot++;
10021203945Sweongyo
10022203945Sweongyo	return (slot);
10023203945Sweongyo}
10024203945Sweongyo
10025203945Sweongyostatic int
10026203945Sweongyobwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
10027203945Sweongyo{
10028203945Sweongyo	const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
10029203945Sweongyo	unsigned int a, b, c, d;
10030203945Sweongyo	unsigned int avg;
10031203945Sweongyo	uint32_t tmp;
10032203945Sweongyo
10033203945Sweongyo	tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
10034203945Sweongyo	a = tmp & 0xff;
10035203945Sweongyo	b = (tmp >> 8) & 0xff;
10036203945Sweongyo	c = (tmp >> 16) & 0xff;
10037203945Sweongyo	d = (tmp >> 24) & 0xff;
10038203945Sweongyo	if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
10039203945Sweongyo	    c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
10040203945Sweongyo		return (ENOENT);
10041203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
10042203945Sweongyo	    BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
10043203945Sweongyo	    (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
10044203945Sweongyo
10045203945Sweongyo	if (ofdm) {
10046203945Sweongyo		a = (a + 32) & 0x3f;
10047203945Sweongyo		b = (b + 32) & 0x3f;
10048203945Sweongyo		c = (c + 32) & 0x3f;
10049203945Sweongyo		d = (d + 32) & 0x3f;
10050203945Sweongyo	}
10051203945Sweongyo
10052203945Sweongyo	avg = (a + b + c + d + 2) / 4;
10053203945Sweongyo	if (ofdm) {
10054203945Sweongyo		if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
10055203945Sweongyo		    & BWN_HF_4DB_CCK_POWERBOOST)
10056203945Sweongyo			avg = (avg >= 13) ? (avg - 13) : 0;
10057203945Sweongyo	}
10058203945Sweongyo	return (avg);
10059203945Sweongyo}
10060203945Sweongyo
10061203945Sweongyostatic void
10062203945Sweongyobwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
10063203945Sweongyo{
10064203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
10065203945Sweongyo	int rfatt = *rfattp;
10066203945Sweongyo	int bbatt = *bbattp;
10067203945Sweongyo
10068203945Sweongyo	while (1) {
10069203945Sweongyo		if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
10070203945Sweongyo			break;
10071203945Sweongyo		if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
10072203945Sweongyo			break;
10073203945Sweongyo		if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
10074203945Sweongyo			break;
10075203945Sweongyo		if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
10076203945Sweongyo			break;
10077203945Sweongyo		if (bbatt > lo->bbatt.max) {
10078203945Sweongyo			bbatt -= 4;
10079203945Sweongyo			rfatt += 1;
10080203945Sweongyo			continue;
10081203945Sweongyo		}
10082203945Sweongyo		if (bbatt < lo->bbatt.min) {
10083203945Sweongyo			bbatt += 4;
10084203945Sweongyo			rfatt -= 1;
10085203945Sweongyo			continue;
10086203945Sweongyo		}
10087203945Sweongyo		if (rfatt > lo->rfatt.max) {
10088203945Sweongyo			rfatt -= 1;
10089203945Sweongyo			bbatt += 4;
10090203945Sweongyo			continue;
10091203945Sweongyo		}
10092203945Sweongyo		if (rfatt < lo->rfatt.min) {
10093203945Sweongyo			rfatt += 1;
10094203945Sweongyo			bbatt -= 4;
10095203945Sweongyo			continue;
10096203945Sweongyo		}
10097203945Sweongyo		break;
10098203945Sweongyo	}
10099203945Sweongyo
10100203945Sweongyo	*rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
10101203945Sweongyo	*bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
10102203945Sweongyo}
10103203945Sweongyo
10104203945Sweongyostatic void
10105203945Sweongyobwn_phy_lock(struct bwn_mac *mac)
10106203945Sweongyo{
10107203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10108203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10109203945Sweongyo
10110204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
10111204922Sweongyo	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
10112203945Sweongyo
10113203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10114203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
10115203945Sweongyo}
10116203945Sweongyo
10117203945Sweongyostatic void
10118203945Sweongyobwn_phy_unlock(struct bwn_mac *mac)
10119203945Sweongyo{
10120203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10121203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10122203945Sweongyo
10123204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
10124204922Sweongyo	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
10125203945Sweongyo
10126203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10127203945Sweongyo		bwn_psctl(mac, 0);
10128203945Sweongyo}
10129203945Sweongyo
10130203945Sweongyostatic void
10131203945Sweongyobwn_rf_lock(struct bwn_mac *mac)
10132203945Sweongyo{
10133203945Sweongyo
10134203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10135203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
10136203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
10137203945Sweongyo	DELAY(10);
10138203945Sweongyo}
10139203945Sweongyo
10140203945Sweongyostatic void
10141203945Sweongyobwn_rf_unlock(struct bwn_mac *mac)
10142203945Sweongyo{
10143203945Sweongyo
10144203945Sweongyo	BWN_READ_2(mac, BWN_PHYVER);
10145203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10146203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
10147203945Sweongyo}
10148203945Sweongyo
10149203945Sweongyostatic struct bwn_pio_txqueue *
10150203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
10151203945Sweongyo    struct bwn_pio_txpkt **pack)
10152203945Sweongyo{
10153203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
10154203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
10155203945Sweongyo	unsigned int index;
10156203945Sweongyo
10157203945Sweongyo	switch (cookie & 0xf000) {
10158203945Sweongyo	case 0x1000:
10159203945Sweongyo		tq = &pio->wme[WME_AC_BK];
10160203945Sweongyo		break;
10161203945Sweongyo	case 0x2000:
10162203945Sweongyo		tq = &pio->wme[WME_AC_BE];
10163203945Sweongyo		break;
10164203945Sweongyo	case 0x3000:
10165203945Sweongyo		tq = &pio->wme[WME_AC_VI];
10166203945Sweongyo		break;
10167203945Sweongyo	case 0x4000:
10168203945Sweongyo		tq = &pio->wme[WME_AC_VO];
10169203945Sweongyo		break;
10170203945Sweongyo	case 0x5000:
10171203945Sweongyo		tq = &pio->mcast;
10172203945Sweongyo		break;
10173203945Sweongyo	}
10174203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
10175203945Sweongyo	if (tq == NULL)
10176203945Sweongyo		return (NULL);
10177203945Sweongyo	index = (cookie & 0x0fff);
10178203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
10179203945Sweongyo	if (index >= N(tq->tq_pkts))
10180203945Sweongyo		return (NULL);
10181203945Sweongyo	*pack = &tq->tq_pkts[index];
10182203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
10183203945Sweongyo	return (tq);
10184203945Sweongyo}
10185203945Sweongyo
10186203945Sweongyostatic void
10187203945Sweongyobwn_txpwr(void *arg, int npending)
10188203945Sweongyo{
10189203945Sweongyo	struct bwn_mac *mac = arg;
10190203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10191203945Sweongyo
10192203945Sweongyo	BWN_LOCK(sc);
10193203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
10194203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
10195203945Sweongyo		mac->mac_phy.set_txpwr(mac);
10196203945Sweongyo	BWN_UNLOCK(sc);
10197203945Sweongyo}
10198203945Sweongyo
10199203945Sweongyostatic void
10200203945Sweongyobwn_task_15s(struct bwn_mac *mac)
10201203945Sweongyo{
10202203945Sweongyo	uint16_t reg;
10203203945Sweongyo
10204203945Sweongyo	if (mac->mac_fw.opensource) {
10205203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
10206203945Sweongyo		if (reg) {
10207203945Sweongyo			bwn_restart(mac, "fw watchdog");
10208203945Sweongyo			return;
10209203945Sweongyo		}
10210203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
10211203945Sweongyo	}
10212203945Sweongyo	if (mac->mac_phy.task_15s)
10213203945Sweongyo		mac->mac_phy.task_15s(mac);
10214203945Sweongyo
10215203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
10216203945Sweongyo}
10217203945Sweongyo
10218203945Sweongyostatic void
10219203945Sweongyobwn_task_30s(struct bwn_mac *mac)
10220203945Sweongyo{
10221203945Sweongyo
10222203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
10223203945Sweongyo		return;
10224203945Sweongyo	mac->mac_noise.noi_running = 1;
10225203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
10226203945Sweongyo
10227203945Sweongyo	bwn_noise_gensample(mac);
10228203945Sweongyo}
10229203945Sweongyo
10230203945Sweongyostatic void
10231203945Sweongyobwn_task_60s(struct bwn_mac *mac)
10232203945Sweongyo{
10233203945Sweongyo
10234203945Sweongyo	if (mac->mac_phy.task_60s)
10235203945Sweongyo		mac->mac_phy.task_60s(mac);
10236203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
10237203945Sweongyo}
10238203945Sweongyo
10239203945Sweongyostatic void
10240203945Sweongyobwn_tasks(void *arg)
10241203945Sweongyo{
10242203945Sweongyo	struct bwn_mac *mac = arg;
10243203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10244203945Sweongyo
10245203945Sweongyo	BWN_ASSERT_LOCKED(sc);
10246203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
10247203945Sweongyo		return;
10248203945Sweongyo
10249203945Sweongyo	if (mac->mac_task_state % 4 == 0)
10250203945Sweongyo		bwn_task_60s(mac);
10251203945Sweongyo	if (mac->mac_task_state % 2 == 0)
10252203945Sweongyo		bwn_task_30s(mac);
10253203945Sweongyo	bwn_task_15s(mac);
10254203945Sweongyo
10255203945Sweongyo	mac->mac_task_state++;
10256203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
10257203945Sweongyo}
10258203945Sweongyo
10259203945Sweongyostatic int
10260203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
10261203945Sweongyo{
10262203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10263203945Sweongyo
10264203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
10265203945Sweongyo
10266203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
10267203945Sweongyo	case 0xb:
10268203945Sweongyo		return (BWN_OFDM_RATE_6MB);
10269203945Sweongyo	case 0xf:
10270203945Sweongyo		return (BWN_OFDM_RATE_9MB);
10271203945Sweongyo	case 0xa:
10272203945Sweongyo		return (BWN_OFDM_RATE_12MB);
10273203945Sweongyo	case 0xe:
10274203945Sweongyo		return (BWN_OFDM_RATE_18MB);
10275203945Sweongyo	case 0x9:
10276203945Sweongyo		return (BWN_OFDM_RATE_24MB);
10277203945Sweongyo	case 0xd:
10278203945Sweongyo		return (BWN_OFDM_RATE_36MB);
10279203945Sweongyo	case 0x8:
10280203945Sweongyo		return (BWN_OFDM_RATE_48MB);
10281203945Sweongyo	case 0xc:
10282203945Sweongyo		return (BWN_OFDM_RATE_54MB);
10283203945Sweongyo	}
10284203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
10285203945Sweongyo	    plcp->o.raw[0] & 0xf);
10286203945Sweongyo	return (-1);
10287203945Sweongyo}
10288203945Sweongyo
10289203945Sweongyostatic int
10290203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
10291203945Sweongyo{
10292203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10293203945Sweongyo
10294203945Sweongyo	switch (plcp->o.raw[0]) {
10295203945Sweongyo	case 0x0a:
10296203945Sweongyo		return (BWN_CCK_RATE_1MB);
10297203945Sweongyo	case 0x14:
10298203945Sweongyo		return (BWN_CCK_RATE_2MB);
10299203945Sweongyo	case 0x37:
10300203945Sweongyo		return (BWN_CCK_RATE_5MB);
10301203945Sweongyo	case 0x6e:
10302203945Sweongyo		return (BWN_CCK_RATE_11MB);
10303203945Sweongyo	}
10304203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
10305203945Sweongyo	return (-1);
10306203945Sweongyo}
10307203945Sweongyo
10308203945Sweongyostatic void
10309203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
10310203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
10311203945Sweongyo    int rssi, int noise)
10312203945Sweongyo{
10313203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10314203945Sweongyo	const struct ieee80211_frame_min *wh;
10315203945Sweongyo	uint64_t tsf;
10316203945Sweongyo	uint16_t low_mactime_now;
10317203945Sweongyo
10318203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
10319203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
10320203945Sweongyo
10321203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
10322203945Sweongyo	if (wh->i_fc[1] & IEEE80211_FC1_WEP)
10323203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
10324203945Sweongyo
10325203945Sweongyo	bwn_tsf_read(mac, &tsf);
10326203945Sweongyo	low_mactime_now = tsf;
10327203945Sweongyo	tsf = tsf & ~0xffffULL;
10328203945Sweongyo	tsf += le16toh(rxhdr->mac_time);
10329203945Sweongyo	if (low_mactime_now < le16toh(rxhdr->mac_time))
10330203945Sweongyo		tsf -= 0x10000;
10331203945Sweongyo
10332203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
10333203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
10334203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
10335203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
10336203945Sweongyo}
10337203945Sweongyo
10338203945Sweongyostatic void
10339203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
10340203945Sweongyo{
10341203945Sweongyo	uint32_t low, high;
10342203945Sweongyo
10343204983Syongari	KASSERT(siba_get_revid(mac->mac_sc->sc_dev) >= 3,
10344203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
10345203945Sweongyo
10346203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
10347203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
10348203945Sweongyo	*tsf = high;
10349203945Sweongyo	*tsf <<= 32;
10350203945Sweongyo	*tsf |= low;
10351203945Sweongyo}
10352203945Sweongyo
10353203945Sweongyostatic int
10354203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
10355203945Sweongyo{
10356203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10357203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10358203945Sweongyo	bus_addr_t lowaddr = 0;
10359203945Sweongyo	int error;
10360203945Sweongyo
10361204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
10362203945Sweongyo		return (0);
10363203945Sweongyo
10364204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5, ("%s: fail", __func__));
10365203945Sweongyo
10366203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
10367203945Sweongyo
10368203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
10369203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
10370203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
10371203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
10372203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
10373203945Sweongyo	else
10374203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
10375203945Sweongyo
10376203945Sweongyo	/*
10377203945Sweongyo	 * Create top level DMA tag
10378203945Sweongyo	 */
10379203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
10380203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
10381203945Sweongyo			       lowaddr,			/* lowaddr */
10382203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
10383203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
10384203945Sweongyo			       MAXBSIZE,		/* maxsize */
10385203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
10386203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
10387203945Sweongyo			       0,			/* flags */
10388203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
10389203945Sweongyo			       &dma->parent_dtag);
10390203945Sweongyo	if (error) {
10391203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
10392203945Sweongyo		return (error);
10393203945Sweongyo	}
10394203945Sweongyo
10395203945Sweongyo	/*
10396203945Sweongyo	 * Create TX/RX mbuf DMA tag
10397203945Sweongyo	 */
10398203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10399203945Sweongyo				1,
10400203945Sweongyo				0,
10401203945Sweongyo				BUS_SPACE_MAXADDR,
10402203945Sweongyo				BUS_SPACE_MAXADDR,
10403203945Sweongyo				NULL, NULL,
10404203945Sweongyo				MCLBYTES,
10405203945Sweongyo				1,
10406203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10407203945Sweongyo				0,
10408203945Sweongyo				NULL, NULL,
10409203945Sweongyo				&dma->rxbuf_dtag);
10410203945Sweongyo	if (error) {
10411203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10412203945Sweongyo		goto fail0;
10413203945Sweongyo	}
10414203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10415203945Sweongyo				1,
10416203945Sweongyo				0,
10417203945Sweongyo				BUS_SPACE_MAXADDR,
10418203945Sweongyo				BUS_SPACE_MAXADDR,
10419203945Sweongyo				NULL, NULL,
10420203945Sweongyo				MCLBYTES,
10421203945Sweongyo				1,
10422203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10423203945Sweongyo				0,
10424203945Sweongyo				NULL, NULL,
10425203945Sweongyo				&dma->txbuf_dtag);
10426203945Sweongyo	if (error) {
10427203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10428203945Sweongyo		goto fail1;
10429203945Sweongyo	}
10430203945Sweongyo
10431203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
10432203945Sweongyo	if (!dma->wme[WME_AC_BK])
10433203945Sweongyo		goto fail2;
10434203945Sweongyo
10435203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
10436203945Sweongyo	if (!dma->wme[WME_AC_BE])
10437203945Sweongyo		goto fail3;
10438203945Sweongyo
10439203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
10440203945Sweongyo	if (!dma->wme[WME_AC_VI])
10441203945Sweongyo		goto fail4;
10442203945Sweongyo
10443203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
10444203945Sweongyo	if (!dma->wme[WME_AC_VO])
10445203945Sweongyo		goto fail5;
10446203945Sweongyo
10447203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
10448203945Sweongyo	if (!dma->mcast)
10449203945Sweongyo		goto fail6;
10450203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
10451203945Sweongyo	if (!dma->rx)
10452203945Sweongyo		goto fail7;
10453203945Sweongyo
10454203945Sweongyo	return (error);
10455203945Sweongyo
10456203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
10457203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
10458203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
10459203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
10460203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
10461203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
10462203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
10463203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
10464203945Sweongyo	return (error);
10465203945Sweongyo}
10466203945Sweongyo
10467203945Sweongyostatic struct bwn_dma_ring *
10468203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
10469203945Sweongyo    uint16_t cookie, int *slot)
10470203945Sweongyo{
10471203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10472203945Sweongyo	struct bwn_dma_ring *dr;
10473203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10474203945Sweongyo
10475203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
10476203945Sweongyo
10477203945Sweongyo	switch (cookie & 0xf000) {
10478203945Sweongyo	case 0x1000:
10479203945Sweongyo		dr = dma->wme[WME_AC_BK];
10480203945Sweongyo		break;
10481203945Sweongyo	case 0x2000:
10482203945Sweongyo		dr = dma->wme[WME_AC_BE];
10483203945Sweongyo		break;
10484203945Sweongyo	case 0x3000:
10485203945Sweongyo		dr = dma->wme[WME_AC_VI];
10486203945Sweongyo		break;
10487203945Sweongyo	case 0x4000:
10488203945Sweongyo		dr = dma->wme[WME_AC_VO];
10489203945Sweongyo		break;
10490203945Sweongyo	case 0x5000:
10491203945Sweongyo		dr = dma->mcast;
10492203945Sweongyo		break;
10493203945Sweongyo	default:
10494204242Simp		dr = NULL;
10495203945Sweongyo		KASSERT(0 == 1,
10496203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
10497203945Sweongyo	}
10498203945Sweongyo	*slot = (cookie & 0x0fff);
10499203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
10500203945Sweongyo		/*
10501203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
10502203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
10503203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
10504203945Sweongyo		 */
10505203945Sweongyo		KASSERT(status->seq == dma->lastseq,
10506203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
10507203945Sweongyo		device_printf(sc->sc_dev,
10508203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
10509203945Sweongyo		    dr->dr_numslots);
10510203945Sweongyo		return (NULL);
10511203945Sweongyo	}
10512203945Sweongyo	dma->lastseq = status->seq;
10513203945Sweongyo	return (dr);
10514203945Sweongyo}
10515203945Sweongyo
10516203945Sweongyostatic void
10517203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
10518203945Sweongyo{
10519203945Sweongyo	struct bwn_dma *dma;
10520203945Sweongyo
10521203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
10522203945Sweongyo		return;
10523203945Sweongyo	dma = &mac->mac_method.dma;
10524203945Sweongyo
10525203945Sweongyo	bwn_dma_ringstop(&dma->rx);
10526203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
10527203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
10528203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
10529203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
10530203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
10531203945Sweongyo}
10532203945Sweongyo
10533203945Sweongyostatic void
10534203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
10535203945Sweongyo{
10536203945Sweongyo
10537203945Sweongyo	if (dr == NULL)
10538203945Sweongyo		return;
10539203945Sweongyo
10540203945Sweongyo	bwn_dma_cleanup(*dr);
10541203945Sweongyo}
10542203945Sweongyo
10543203945Sweongyostatic void
10544203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
10545203945Sweongyo{
10546203945Sweongyo	struct bwn_pio *pio;
10547203945Sweongyo
10548203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
10549203945Sweongyo		return;
10550203945Sweongyo	pio = &mac->mac_method.pio;
10551203945Sweongyo
10552203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
10553203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
10554203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
10555203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
10556203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
10557203945Sweongyo}
10558203945Sweongyo
10559203945Sweongyostatic void
10560203945Sweongyobwn_led_attach(struct bwn_mac *mac)
10561203945Sweongyo{
10562203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10563203945Sweongyo	const uint8_t *led_act = NULL;
10564203945Sweongyo	uint16_t val[BWN_LED_MAX];
10565203945Sweongyo	int i;
10566203945Sweongyo
10567203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
10568203945Sweongyo	sc->sc_led_blink = 1;
10569203945Sweongyo
10570203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
10571204922Sweongyo		if (siba_get_pci_subvendor(sc->sc_dev) ==
10572204922Sweongyo		    bwn_vendor_led_act[i].vid) {
10573203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
10574203945Sweongyo			break;
10575203945Sweongyo		}
10576203945Sweongyo	}
10577203945Sweongyo	if (led_act == NULL)
10578203945Sweongyo		led_act = bwn_default_led_act;
10579203945Sweongyo
10580204922Sweongyo	val[0] = siba_sprom_get_gpio0(sc->sc_dev);
10581204922Sweongyo	val[1] = siba_sprom_get_gpio1(sc->sc_dev);
10582204922Sweongyo	val[2] = siba_sprom_get_gpio2(sc->sc_dev);
10583204922Sweongyo	val[3] = siba_sprom_get_gpio3(sc->sc_dev);
10584203945Sweongyo
10585203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10586203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10587203945Sweongyo
10588203945Sweongyo		if (val[i] == 0xff) {
10589203945Sweongyo			led->led_act = led_act[i];
10590203945Sweongyo		} else {
10591203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
10592203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
10593203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
10594203945Sweongyo		}
10595203945Sweongyo		led->led_mask = (1 << i);
10596203945Sweongyo
10597203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
10598203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
10599203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
10600203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
10601203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
10602203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
10603203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
10604203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
10605203945Sweongyo
10606203945Sweongyo			if (sc->sc_blink_led == NULL) {
10607203945Sweongyo				sc->sc_blink_led = led;
10608203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
10609203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
10610203945Sweongyo			}
10611203945Sweongyo		}
10612203945Sweongyo
10613203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
10614203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
10615203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
10616203945Sweongyo	}
10617203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
10618203945Sweongyo}
10619203945Sweongyo
10620203945Sweongyostatic __inline uint16_t
10621203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
10622203945Sweongyo{
10623203945Sweongyo
10624203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
10625203945Sweongyo		on = !on;
10626203945Sweongyo	if (on)
10627203945Sweongyo		val |= led->led_mask;
10628203945Sweongyo	else
10629203945Sweongyo		val &= ~led->led_mask;
10630203945Sweongyo	return val;
10631203945Sweongyo}
10632203945Sweongyo
10633203945Sweongyostatic void
10634203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
10635203945Sweongyo{
10636203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10637203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10638203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10639203945Sweongyo	uint16_t val;
10640203945Sweongyo	int i;
10641203945Sweongyo
10642203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
10643203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
10644203945Sweongyo		sc->sc_led_blinking = 0;
10645203945Sweongyo	}
10646203945Sweongyo
10647203945Sweongyo	if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
10648203945Sweongyo		return;
10649203945Sweongyo
10650203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10651203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10652203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10653203945Sweongyo		int on;
10654203945Sweongyo
10655203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
10656203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
10657203945Sweongyo			continue;
10658203945Sweongyo
10659203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
10660203945Sweongyo		    nstate != IEEE80211_S_INIT)
10661203945Sweongyo			continue;
10662203945Sweongyo
10663203945Sweongyo		switch (led->led_act) {
10664203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
10665203945Sweongyo			on = 1;
10666203945Sweongyo			break;
10667203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
10668203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
10669203945Sweongyo			on = 0;
10670203945Sweongyo			break;
10671203945Sweongyo		default:
10672203945Sweongyo			on = 1;
10673203945Sweongyo			switch (nstate) {
10674203945Sweongyo			case IEEE80211_S_INIT:
10675203945Sweongyo				on = 0;
10676203945Sweongyo				break;
10677203945Sweongyo			case IEEE80211_S_RUN:
10678203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
10679203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
10680203945Sweongyo					on = 0;
10681203945Sweongyo				break;
10682203945Sweongyo			default:
10683203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
10684203945Sweongyo					on = 0;
10685203945Sweongyo				break;
10686203945Sweongyo			}
10687203945Sweongyo			break;
10688203945Sweongyo		}
10689203945Sweongyo
10690203945Sweongyo		val = bwn_led_onoff(led, val, on);
10691203945Sweongyo	}
10692203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10693203945Sweongyo}
10694203945Sweongyo
10695203945Sweongyostatic void
10696203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
10697203945Sweongyo{
10698203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10699204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
10700204922Sweongyo	int rate;
10701203945Sweongyo
10702204922Sweongyo	if (event == BWN_LED_EVENT_POLL) {
10703204922Sweongyo		if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
10704204922Sweongyo			return;
10705204922Sweongyo		if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
10706204922Sweongyo			return;
10707204922Sweongyo	}
10708203945Sweongyo
10709204922Sweongyo	sc->sc_led_ticks = ticks;
10710204922Sweongyo	if (sc->sc_led_blinking)
10711204922Sweongyo		return;
10712203945Sweongyo
10713204922Sweongyo	switch (event) {
10714204922Sweongyo	case BWN_LED_EVENT_RX:
10715204922Sweongyo		rate = sc->sc_rx_rate;
10716204922Sweongyo		break;
10717204922Sweongyo	case BWN_LED_EVENT_TX:
10718204922Sweongyo		rate = sc->sc_tx_rate;
10719204922Sweongyo		break;
10720204922Sweongyo	case BWN_LED_EVENT_POLL:
10721204922Sweongyo		rate = 0;
10722204922Sweongyo		break;
10723204922Sweongyo	default:
10724204922Sweongyo		panic("unknown LED event %d\n", event);
10725204922Sweongyo		break;
10726204922Sweongyo	}
10727204922Sweongyo	bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
10728204922Sweongyo	    bwn_led_duration[rate].off_dur);
10729203945Sweongyo}
10730203945Sweongyo
10731203945Sweongyostatic void
10732203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
10733203945Sweongyo{
10734203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10735204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
10736204922Sweongyo	uint16_t val;
10737203945Sweongyo
10738204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10739204922Sweongyo	val = bwn_led_onoff(led, val, 1);
10740204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10741203945Sweongyo
10742204922Sweongyo	if (led->led_flags & BWN_LED_F_SLOW) {
10743204922Sweongyo		BWN_LED_SLOWDOWN(on_dur);
10744204922Sweongyo		BWN_LED_SLOWDOWN(off_dur);
10745204922Sweongyo	}
10746203945Sweongyo
10747204922Sweongyo	sc->sc_led_blinking = 1;
10748204922Sweongyo	sc->sc_led_blink_offdur = off_dur;
10749203945Sweongyo
10750204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
10751203945Sweongyo}
10752203945Sweongyo
10753203945Sweongyostatic void
10754203945Sweongyobwn_led_blink_next(void *arg)
10755203945Sweongyo{
10756203945Sweongyo	struct bwn_mac *mac = arg;
10757204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10758204922Sweongyo	uint16_t val;
10759203945Sweongyo
10760204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10761204922Sweongyo	val = bwn_led_onoff(sc->sc_blink_led, val, 0);
10762204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10763203945Sweongyo
10764204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
10765204922Sweongyo	    bwn_led_blink_end, mac);
10766203945Sweongyo}
10767203945Sweongyo
10768203945Sweongyostatic void
10769203945Sweongyobwn_led_blink_end(void *arg)
10770203945Sweongyo{
10771203945Sweongyo	struct bwn_mac *mac = arg;
10772204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10773203945Sweongyo
10774204922Sweongyo	sc->sc_led_blinking = 0;
10775203945Sweongyo}
10776203945Sweongyo
10777203945Sweongyostatic int
10778203945Sweongyobwn_suspend(device_t dev)
10779203945Sweongyo{
10780203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10781203945Sweongyo
10782203945Sweongyo	bwn_stop(sc, 1);
10783203945Sweongyo	return (0);
10784203945Sweongyo}
10785203945Sweongyo
10786203945Sweongyostatic int
10787203945Sweongyobwn_resume(device_t dev)
10788203945Sweongyo{
10789203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10790203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10791203945Sweongyo
10792203945Sweongyo	if (ifp->if_flags & IFF_UP)
10793203945Sweongyo		bwn_init(sc);
10794203945Sweongyo	return (0);
10795203945Sweongyo}
10796203945Sweongyo
10797203945Sweongyostatic void
10798203945Sweongyobwn_rfswitch(void *arg)
10799203945Sweongyo{
10800203945Sweongyo	struct bwn_softc *sc = arg;
10801203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
10802203945Sweongyo	int cur = 0, prev = 0;
10803203945Sweongyo
10804203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
10805203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
10806203945Sweongyo
10807203945Sweongyo	if (mac->mac_phy.rf_rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
10808203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
10809203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
10810203945Sweongyo			cur = 1;
10811203945Sweongyo	} else {
10812203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
10813203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
10814203945Sweongyo			cur = 1;
10815203945Sweongyo	}
10816203945Sweongyo
10817203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
10818203945Sweongyo		prev = 1;
10819203945Sweongyo
10820203945Sweongyo	if (cur != prev) {
10821203945Sweongyo		if (cur)
10822203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
10823203945Sweongyo		else
10824203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
10825203945Sweongyo
10826203945Sweongyo		device_printf(sc->sc_dev,
10827203945Sweongyo		    "status of RF switch is changed to %s\n",
10828203945Sweongyo		    cur ? "ON" : "OFF");
10829203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
10830203945Sweongyo			if (cur)
10831203945Sweongyo				bwn_rf_turnon(mac);
10832203945Sweongyo			else
10833203945Sweongyo				bwn_rf_turnoff(mac);
10834203945Sweongyo		}
10835203945Sweongyo	}
10836203945Sweongyo
10837203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
10838203945Sweongyo}
10839203945Sweongyo
10840203945Sweongyostatic void
10841203945Sweongyobwn_phy_lp_init_pre(struct bwn_mac *mac)
10842203945Sweongyo{
10843203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
10844203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
10845203945Sweongyo
10846203945Sweongyo	plp->plp_antenna = BWN_ANT_DEFAULT;
10847203945Sweongyo}
10848203945Sweongyo
10849203945Sweongyostatic int
10850203945Sweongyobwn_phy_lp_init(struct bwn_mac *mac)
10851203945Sweongyo{
10852203945Sweongyo	static const struct bwn_stxtable tables[] = {
10853203945Sweongyo		{ 2,  6, 0x3d, 3, 0x01 }, { 1, 12, 0x4c, 1, 0x01 },
10854203945Sweongyo		{ 1,  8, 0x50, 0, 0x7f }, { 0,  8, 0x44, 0, 0xff },
10855203945Sweongyo		{ 1,  0, 0x4a, 0, 0xff }, { 0,  4, 0x4d, 0, 0xff },
10856203945Sweongyo		{ 1,  4, 0x4e, 0, 0xff }, { 0, 12, 0x4f, 0, 0x0f },
10857203945Sweongyo		{ 1,  0, 0x4f, 4, 0x0f }, { 3,  0, 0x49, 0, 0x0f },
10858203945Sweongyo		{ 4,  3, 0x46, 4, 0x07 }, { 3, 15, 0x46, 0, 0x01 },
10859203945Sweongyo		{ 4,  0, 0x46, 1, 0x07 }, { 3,  8, 0x48, 4, 0x07 },
10860203945Sweongyo		{ 3, 11, 0x48, 0, 0x0f }, { 3,  4, 0x49, 4, 0x0f },
10861203945Sweongyo		{ 2, 15, 0x45, 0, 0x01 }, { 5, 13, 0x52, 4, 0x07 },
10862203945Sweongyo		{ 6,  0, 0x52, 7, 0x01 }, { 5,  3, 0x41, 5, 0x07 },
10863203945Sweongyo		{ 5,  6, 0x41, 0, 0x0f }, { 5, 10, 0x42, 5, 0x07 },
10864203945Sweongyo		{ 4, 15, 0x42, 0, 0x01 }, { 5,  0, 0x42, 1, 0x07 },
10865203945Sweongyo		{ 4, 11, 0x43, 4, 0x0f }, { 4,  7, 0x43, 0, 0x0f },
10866203945Sweongyo		{ 4,  6, 0x45, 1, 0x01 }, { 2,  7, 0x40, 4, 0x0f },
10867203945Sweongyo		{ 2, 11, 0x40, 0, 0x0f }
10868203945Sweongyo	};
10869203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
10870203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10871203945Sweongyo	const struct bwn_stxtable *st;
10872203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10873203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10874203945Sweongyo	int i, error;
10875203945Sweongyo	uint16_t tmp;
10876203945Sweongyo
10877203945Sweongyo	bwn_phy_lp_readsprom(mac);	/* XXX bad place */
10878203945Sweongyo	bwn_phy_lp_bbinit(mac);
10879203945Sweongyo
10880203945Sweongyo	/* initialize RF */
10881203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_4WIRECTL, 0x2);
10882203945Sweongyo	DELAY(1);
10883203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_4WIRECTL, 0xfffd);
10884203945Sweongyo	DELAY(1);
10885203945Sweongyo
10886203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2062)
10887203945Sweongyo		bwn_phy_lp_b2062_init(mac);
10888203945Sweongyo	else {
10889203945Sweongyo		bwn_phy_lp_b2063_init(mac);
10890203945Sweongyo
10891203945Sweongyo		/* synchronize stx table. */
10892203945Sweongyo		for (i = 0; i < N(tables); i++) {
10893203945Sweongyo			st = &tables[i];
10894203945Sweongyo			tmp = BWN_RF_READ(mac, st->st_rfaddr);
10895203945Sweongyo			tmp >>= st->st_rfshift;
10896203945Sweongyo			tmp <<= st->st_physhift;
10897203945Sweongyo			BWN_PHY_SETMASK(mac,
10898203945Sweongyo			    BWN_PHY_OFDM(0xf2 + st->st_phyoffset),
10899203945Sweongyo			    ~(st->st_mask << st->st_physhift), tmp);
10900203945Sweongyo		}
10901203945Sweongyo
10902203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf0), 0x5f80);
10903203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf1), 0);
10904203945Sweongyo	}
10905203945Sweongyo
10906203945Sweongyo	/* calibrate RC */
10907203945Sweongyo	if (mac->mac_phy.rev >= 2)
10908203945Sweongyo		bwn_phy_lp_rxcal_r2(mac);
10909203945Sweongyo	else if (!plp->plp_rccap) {
10910203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
10911203945Sweongyo			bwn_phy_lp_rccal_r12(mac);
10912203945Sweongyo	} else
10913203945Sweongyo		bwn_phy_lp_set_rccap(mac);
10914203945Sweongyo
10915203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
10916203945Sweongyo	if (error)
10917203945Sweongyo		device_printf(sc->sc_dev,
10918203945Sweongyo		    "failed to change channel 7 (%d)\n", error);
10919203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
10920203945Sweongyo	bwn_phy_lp_calib(mac);
10921203945Sweongyo	return (0);
10922203945Sweongyo}
10923203945Sweongyo
10924203945Sweongyostatic uint16_t
10925203945Sweongyobwn_phy_lp_read(struct bwn_mac *mac, uint16_t reg)
10926203945Sweongyo{
10927203945Sweongyo
10928203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10929203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
10930203945Sweongyo}
10931203945Sweongyo
10932203945Sweongyostatic void
10933203945Sweongyobwn_phy_lp_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
10934203945Sweongyo{
10935203945Sweongyo
10936203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10937203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
10938203945Sweongyo}
10939203945Sweongyo
10940203945Sweongyostatic void
10941203945Sweongyobwn_phy_lp_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
10942203945Sweongyo    uint16_t set)
10943203945Sweongyo{
10944203945Sweongyo
10945203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10946203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA,
10947203945Sweongyo	    (BWN_READ_2(mac, BWN_PHYDATA) & mask) | set);
10948203945Sweongyo}
10949203945Sweongyo
10950203945Sweongyostatic uint16_t
10951203945Sweongyobwn_phy_lp_rf_read(struct bwn_mac *mac, uint16_t reg)
10952203945Sweongyo{
10953203945Sweongyo
10954203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
10955203945Sweongyo	if (mac->mac_phy.rev < 2 && reg != 0x4001)
10956203945Sweongyo		reg |= 0x100;
10957203945Sweongyo	if (mac->mac_phy.rev >= 2)
10958203945Sweongyo		reg |= 0x200;
10959203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
10960203945Sweongyo	return BWN_READ_2(mac, BWN_RFDATALO);
10961203945Sweongyo}
10962203945Sweongyo
10963203945Sweongyostatic void
10964203945Sweongyobwn_phy_lp_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
10965203945Sweongyo{
10966203945Sweongyo
10967203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
10968203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
10969203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
10970203945Sweongyo}
10971203945Sweongyo
10972203945Sweongyostatic void
10973203945Sweongyobwn_phy_lp_rf_onoff(struct bwn_mac *mac, int on)
10974203945Sweongyo{
10975203945Sweongyo
10976203945Sweongyo	if (on) {
10977203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xe0ff);
10978203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2,
10979203945Sweongyo		    (mac->mac_phy.rev >= 2) ? 0xf7f7 : 0xffe7);
10980203945Sweongyo		return;
10981203945Sweongyo	}
10982203945Sweongyo
10983203945Sweongyo	if (mac->mac_phy.rev >= 2) {
10984203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x83ff);
10985203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
10986203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0x80ff);
10987203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xdfff);
10988203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0808);
10989203945Sweongyo		return;
10990203945Sweongyo	}
10991203945Sweongyo
10992203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xe0ff);
10993203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
10994203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfcff);
10995203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0018);
10996203945Sweongyo}
10997203945Sweongyo
10998203945Sweongyostatic int
10999203945Sweongyobwn_phy_lp_switch_channel(struct bwn_mac *mac, uint32_t chan)
11000203945Sweongyo{
11001203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11002203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11003203945Sweongyo	int error;
11004203945Sweongyo
11005203945Sweongyo	if (phy->rf_ver == 0x2063) {
11006203945Sweongyo		error = bwn_phy_lp_b2063_switch_channel(mac, chan);
11007203945Sweongyo		if (error)
11008203945Sweongyo			return (error);
11009203945Sweongyo	} else {
11010203945Sweongyo		error = bwn_phy_lp_b2062_switch_channel(mac, chan);
11011203945Sweongyo		if (error)
11012203945Sweongyo			return (error);
11013203945Sweongyo		bwn_phy_lp_set_anafilter(mac, chan);
11014203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, ieee80211_ieee2mhz(chan, 0));
11015203945Sweongyo	}
11016203945Sweongyo
11017203945Sweongyo	plp->plp_chan = chan;
11018203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, chan);
11019203945Sweongyo	return (0);
11020203945Sweongyo}
11021203945Sweongyo
11022203945Sweongyostatic uint32_t
11023203945Sweongyobwn_phy_lp_get_default_chan(struct bwn_mac *mac)
11024203945Sweongyo{
11025203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11026203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11027203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11028203945Sweongyo
11029203945Sweongyo	return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36);
11030203945Sweongyo}
11031203945Sweongyo
11032203945Sweongyostatic void
11033203945Sweongyobwn_phy_lp_set_antenna(struct bwn_mac *mac, int antenna)
11034203945Sweongyo{
11035203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11036203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11037203945Sweongyo
11038203945Sweongyo	if (phy->rev >= 2 || antenna > BWN_ANTAUTO1)
11039203945Sweongyo		return;
11040203945Sweongyo
11041203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER);
11042203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffd, antenna & 0x2);
11043203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffe, antenna & 0x1);
11044203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_UCODE_ANTDIV_HELPER);
11045203945Sweongyo	plp->plp_antenna = antenna;
11046203945Sweongyo}
11047203945Sweongyo
11048203945Sweongyostatic void
11049203945Sweongyobwn_phy_lp_task_60s(struct bwn_mac *mac)
11050203945Sweongyo{
11051203945Sweongyo
11052203945Sweongyo	bwn_phy_lp_calib(mac);
11053203945Sweongyo}
11054203945Sweongyo
11055203945Sweongyostatic void
11056203945Sweongyobwn_phy_lp_readsprom(struct bwn_mac *mac)
11057203945Sweongyo{
11058203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11059203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11060203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11061203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11062203945Sweongyo
11063203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11064204922Sweongyo		plp->plp_txisoband_m = siba_sprom_get_tri2g(sc->sc_dev);
11065204922Sweongyo		plp->plp_bxarch = siba_sprom_get_bxa2g(sc->sc_dev);
11066204922Sweongyo		plp->plp_rxpwroffset = siba_sprom_get_rxpo2g(sc->sc_dev);
11067204922Sweongyo		plp->plp_rssivf = siba_sprom_get_rssismf2g(sc->sc_dev);
11068204922Sweongyo		plp->plp_rssivc = siba_sprom_get_rssismc2g(sc->sc_dev);
11069204922Sweongyo		plp->plp_rssigs = siba_sprom_get_rssisav2g(sc->sc_dev);
11070203945Sweongyo		return;
11071203945Sweongyo	}
11072203945Sweongyo
11073204922Sweongyo	plp->plp_txisoband_l = siba_sprom_get_tri5gl(sc->sc_dev);
11074204922Sweongyo	plp->plp_txisoband_m = siba_sprom_get_tri5g(sc->sc_dev);
11075204922Sweongyo	plp->plp_txisoband_h = siba_sprom_get_tri5gh(sc->sc_dev);
11076204922Sweongyo	plp->plp_bxarch = siba_sprom_get_bxa5g(sc->sc_dev);
11077204922Sweongyo	plp->plp_rxpwroffset = siba_sprom_get_rxpo5g(sc->sc_dev);
11078204922Sweongyo	plp->plp_rssivf = siba_sprom_get_rssismf5g(sc->sc_dev);
11079204922Sweongyo	plp->plp_rssivc = siba_sprom_get_rssismc5g(sc->sc_dev);
11080204922Sweongyo	plp->plp_rssigs = siba_sprom_get_rssisav5g(sc->sc_dev);
11081203945Sweongyo}
11082203945Sweongyo
11083203945Sweongyostatic void
11084203945Sweongyobwn_phy_lp_bbinit(struct bwn_mac *mac)
11085203945Sweongyo{
11086203945Sweongyo
11087203945Sweongyo	bwn_phy_lp_tblinit(mac);
11088203945Sweongyo	if (mac->mac_phy.rev >= 2)
11089203945Sweongyo		bwn_phy_lp_bbinit_r2(mac);
11090203945Sweongyo	else
11091203945Sweongyo		bwn_phy_lp_bbinit_r01(mac);
11092203945Sweongyo}
11093203945Sweongyo
11094203945Sweongyostatic void
11095203945Sweongyobwn_phy_lp_txpctl_init(struct bwn_mac *mac)
11096203945Sweongyo{
11097203945Sweongyo	struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 };
11098203945Sweongyo	struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 };
11099203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11100203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11101203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11102203945Sweongyo
11103203945Sweongyo	bwn_phy_lp_set_txgain(mac,
11104203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz);
11105203945Sweongyo	bwn_phy_lp_set_bbmult(mac, 150);
11106203945Sweongyo}
11107203945Sweongyo
11108203945Sweongyostatic void
11109203945Sweongyobwn_phy_lp_calib(struct bwn_mac *mac)
11110203945Sweongyo{
11111203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11112203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11113203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11114203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11115203945Sweongyo	const struct bwn_rxcompco *rc = NULL;
11116203945Sweongyo	struct bwn_txgain ogain;
11117203945Sweongyo	int i, omode, oafeovr, orf, obbmult;
11118203945Sweongyo	uint8_t mode, fc = 0;
11119203945Sweongyo
11120203945Sweongyo	if (plp->plp_chanfullcal != plp->plp_chan) {
11121203945Sweongyo		plp->plp_chanfullcal = plp->plp_chan;
11122203945Sweongyo		fc = 1;
11123203945Sweongyo	}
11124203945Sweongyo
11125203945Sweongyo	bwn_mac_suspend(mac);
11126203945Sweongyo
11127203945Sweongyo	/* BlueTooth Coexistance Override */
11128203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_CTL, 0x3);
11129203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_TXCTL, 0xff);
11130203945Sweongyo
11131203945Sweongyo	if (mac->mac_phy.rev >= 2)
11132203945Sweongyo		bwn_phy_lp_digflt_save(mac);
11133203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11134203945Sweongyo	mode = plp->plp_txpctlmode;
11135203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11136203945Sweongyo	if (mac->mac_phy.rev == 0 && mode != BWN_PHYLP_TXPCTL_OFF)
11137203945Sweongyo		bwn_phy_lp_bugfix(mac);
11138203945Sweongyo	if (mac->mac_phy.rev >= 2 && fc == 1) {
11139203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11140203945Sweongyo		omode = plp->plp_txpctlmode;
11141203945Sweongyo		oafeovr = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40;
11142203945Sweongyo		if (oafeovr)
11143203945Sweongyo			ogain = bwn_phy_lp_get_txgain(mac);
11144203945Sweongyo		orf = BWN_PHY_READ(mac, BWN_PHY_RF_PWR_OVERRIDE) & 0xff;
11145203945Sweongyo		obbmult = bwn_phy_lp_get_bbmult(mac);
11146203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11147203945Sweongyo		if (oafeovr)
11148203945Sweongyo			bwn_phy_lp_set_txgain(mac, &ogain);
11149203945Sweongyo		bwn_phy_lp_set_bbmult(mac, obbmult);
11150203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, omode);
11151203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00, orf);
11152203945Sweongyo	}
11153203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11154203945Sweongyo	if (mac->mac_phy.rev >= 2)
11155203945Sweongyo		bwn_phy_lp_digflt_restore(mac);
11156203945Sweongyo
11157203945Sweongyo	/* do RX IQ Calculation; assumes that noise is true. */
11158204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x5354) {
11159203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_5354); i++) {
11160203945Sweongyo			if (bwn_rxcompco_5354[i].rc_chan == plp->plp_chan)
11161203945Sweongyo				rc = &bwn_rxcompco_5354[i];
11162203945Sweongyo		}
11163203945Sweongyo	} else if (mac->mac_phy.rev >= 2)
11164203945Sweongyo		rc = &bwn_rxcompco_r2;
11165203945Sweongyo	else {
11166203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_r12); i++) {
11167203945Sweongyo			if (bwn_rxcompco_r12[i].rc_chan == plp->plp_chan)
11168203945Sweongyo				rc = &bwn_rxcompco_r12[i];
11169203945Sweongyo		}
11170203945Sweongyo	}
11171203945Sweongyo	if (rc == NULL)
11172203945Sweongyo		goto fail;
11173203945Sweongyo
11174203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, rc->rc_c1);
11175203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, rc->rc_c0 << 8);
11176203945Sweongyo
11177203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1 /* TX */, 0 /* RX */);
11178203945Sweongyo
11179203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11180203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
11181203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7, 0);
11182203945Sweongyo	} else {
11183203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
11184203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf, 0);
11185203945Sweongyo	}
11186203945Sweongyo
11187203945Sweongyo	bwn_phy_lp_set_rxgain(mac, 0x2d5d);
11188203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11189203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
11190203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
11191203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
11192203945Sweongyo	bwn_phy_lp_set_deaf(mac, 0);
11193203945Sweongyo	/* XXX no checking return value? */
11194203945Sweongyo	(void)bwn_phy_lp_calc_rx_iq_comp(mac, 0xfff0);
11195203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 0);
11196203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffc);
11197203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfff7);
11198203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffdf);
11199203945Sweongyo
11200203945Sweongyo	/* disable RX GAIN override. */
11201203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffe);
11202203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffef);
11203203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffbf);
11204203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11205203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11206203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11207203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfbff);
11208203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xe5), 0xfff7);
11209203945Sweongyo		}
11210203945Sweongyo	} else {
11211203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfdff);
11212203945Sweongyo	}
11213203945Sweongyo
11214203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11215203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xf7ff);
11216203945Sweongyofail:
11217203945Sweongyo	bwn_mac_enable(mac);
11218203945Sweongyo}
11219203945Sweongyo
11220203945Sweongyostatic void
11221203945Sweongyobwn_phy_lp_switch_analog(struct bwn_mac *mac, int on)
11222203945Sweongyo{
11223203945Sweongyo
11224204922Sweongyo	if (on) {
11225204922Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfff8);
11226204922Sweongyo		return;
11227204922Sweongyo	}
11228203945Sweongyo
11229204922Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVRVAL, 0x0007);
11230204922Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x0007);
11231203945Sweongyo}
11232203945Sweongyo
11233203945Sweongyostatic int
11234203945Sweongyobwn_phy_lp_b2063_switch_channel(struct bwn_mac *mac, uint8_t chan)
11235203945Sweongyo{
11236203945Sweongyo	static const struct bwn_b206x_chan *bc = NULL;
11237204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11238203945Sweongyo	uint32_t count, freqref, freqvco, freqxtal, val[3], timeout, timeoutref,
11239203945Sweongyo	    tmp[6];
11240203945Sweongyo	uint16_t old, scale, tmp16;
11241203945Sweongyo	int i, div;
11242203945Sweongyo
11243203945Sweongyo	for (i = 0; i < N(bwn_b2063_chantable); i++) {
11244203945Sweongyo		if (bwn_b2063_chantable[i].bc_chan == chan) {
11245203945Sweongyo			bc = &bwn_b2063_chantable[i];
11246203945Sweongyo			break;
11247203945Sweongyo		}
11248203945Sweongyo	}
11249203945Sweongyo	if (bc == NULL)
11250203945Sweongyo		return (EINVAL);
11251203945Sweongyo
11252203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_VCOBUF1, bc->bc_data[0]);
11253203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_MIXER2, bc->bc_data[1]);
11254203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_BUF2, bc->bc_data[2]);
11255203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_RCCR1, bc->bc_data[3]);
11256203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_1ST3, bc->bc_data[4]);
11257203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND1, bc->bc_data[5]);
11258203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND4, bc->bc_data[6]);
11259203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND7, bc->bc_data[7]);
11260203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_PS6, bc->bc_data[8]);
11261203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL2, bc->bc_data[9]);
11262203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL5, bc->bc_data[10]);
11263203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_CTL11, bc->bc_data[11]);
11264203945Sweongyo
11265203945Sweongyo	old = BWN_RF_READ(mac, BWN_B2063_COM15);
11266203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM15, 0x1e);
11267203945Sweongyo
11268204922Sweongyo	freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
11269203945Sweongyo	freqvco = bc->bc_freq << ((bc->bc_freq > 4000) ? 1 : 2);
11270203945Sweongyo	freqref = freqxtal * 3;
11271203945Sweongyo	div = (freqxtal <= 26000000 ? 1 : 2);
11272203945Sweongyo	timeout = ((((8 * freqxtal) / (div * 5000000)) + 1) >> 1) - 1;
11273203945Sweongyo	timeoutref = ((((8 * freqxtal) / (div * (timeout + 1))) +
11274203945Sweongyo		999999) / 1000000) + 1;
11275203945Sweongyo
11276203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB3, 0x2);
11277203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB6,
11278203945Sweongyo	    0xfff8, timeout >> 2);
11279203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11280203945Sweongyo	    0xff9f,timeout << 5);
11281203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB5, timeoutref);
11282203945Sweongyo
11283203945Sweongyo	val[0] = bwn_phy_lp_roundup(freqxtal, 1000000, 16);
11284203945Sweongyo	val[1] = bwn_phy_lp_roundup(freqxtal, 1000000 * div, 16);
11285203945Sweongyo	val[2] = bwn_phy_lp_roundup(freqvco, 3, 16);
11286203945Sweongyo
11287203945Sweongyo	count = (bwn_phy_lp_roundup(val[2], val[1] + 16, 16) * (timeout + 1) *
11288203945Sweongyo	    (timeoutref + 1)) - 1;
11289203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11290203945Sweongyo	    0xf0, count >> 8);
11291203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB8, count & 0xff);
11292203945Sweongyo
11293203945Sweongyo	tmp[0] = ((val[2] * 62500) / freqref) << 4;
11294203945Sweongyo	tmp[1] = ((val[2] * 62500) % freqref) << 4;
11295203945Sweongyo	while (tmp[1] >= freqref) {
11296203945Sweongyo		tmp[0]++;
11297203945Sweongyo		tmp[1] -= freqref;
11298203945Sweongyo	}
11299203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG1, 0xffe0, tmp[0] >> 4);
11300203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfe0f, tmp[0] << 4);
11301203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfff0, tmp[0] >> 16);
11302203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG3, (tmp[1] >> 8) & 0xff);
11303203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG4, tmp[1] & 0xff);
11304203945Sweongyo
11305203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF1, 0xb9);
11306203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF2, 0x88);
11307203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF3, 0x28);
11308203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF4, 0x63);
11309203945Sweongyo
11310203945Sweongyo	tmp[2] = ((41 * (val[2] - 3000)) /1200) + 27;
11311203945Sweongyo	tmp[3] = bwn_phy_lp_roundup(132000 * tmp[0], 8451, 16);
11312203945Sweongyo
11313203945Sweongyo	if ((tmp[3] + tmp[2] - 1) / tmp[2] > 60) {
11314203945Sweongyo		scale = 1;
11315203945Sweongyo		tmp[4] = ((tmp[3] + tmp[2]) / (tmp[2] << 1)) - 8;
11316203945Sweongyo	} else {
11317203945Sweongyo		scale = 0;
11318203945Sweongyo		tmp[4] = ((tmp[3] + (tmp[2] >> 1)) / tmp[2]) - 8;
11319203945Sweongyo	}
11320203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffc0, tmp[4]);
11321203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffbf, scale << 6);
11322203945Sweongyo
11323203945Sweongyo	tmp[5] = bwn_phy_lp_roundup(100 * val[0], val[2], 16) * (tmp[4] * 8) *
11324203945Sweongyo	    (scale + 1);
11325203945Sweongyo	if (tmp[5] > 150)
11326203945Sweongyo		tmp[5] = 0;
11327203945Sweongyo
11328203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffe0, tmp[5]);
11329203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffdf, scale << 5);
11330203945Sweongyo
11331203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfffb, 0x4);
11332203945Sweongyo	if (freqxtal > 26000000)
11333203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_XTAL_12, 0x2);
11334203945Sweongyo	else
11335203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfd);
11336203945Sweongyo
11337203945Sweongyo	if (val[0] == 45)
11338203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_VCO1, 0x2);
11339203945Sweongyo	else
11340203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_VCO1, 0xfd);
11341203945Sweongyo
11342203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP2, 0x3);
11343203945Sweongyo	DELAY(1);
11344203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP2, 0xfffc);
11345203945Sweongyo
11346203945Sweongyo	/* VCO Calibration */
11347203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, ~0x40);
11348203945Sweongyo	tmp16 = BWN_RF_READ(mac, BWN_B2063_JTAG_CALNRST) & 0xf8;
11349203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16);
11350203945Sweongyo	DELAY(1);
11351203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x4);
11352203945Sweongyo	DELAY(1);
11353203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x6);
11354203945Sweongyo	DELAY(1);
11355203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x7);
11356203945Sweongyo	DELAY(300);
11357203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP1, 0x40);
11358203945Sweongyo
11359203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_COM15, old);
11360203945Sweongyo	return (0);
11361203945Sweongyo}
11362203945Sweongyo
11363203945Sweongyostatic int
11364203945Sweongyobwn_phy_lp_b2062_switch_channel(struct bwn_mac *mac, uint8_t chan)
11365203945Sweongyo{
11366204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11367203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11368203945Sweongyo	const struct bwn_b206x_chan *bc = NULL;
11369204922Sweongyo	uint32_t freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
11370203945Sweongyo	uint32_t tmp[9];
11371203945Sweongyo	int i;
11372203945Sweongyo
11373203945Sweongyo	for (i = 0; i < N(bwn_b2062_chantable); i++) {
11374203945Sweongyo		if (bwn_b2062_chantable[i].bc_chan == chan) {
11375203945Sweongyo			bc = &bwn_b2062_chantable[i];
11376203945Sweongyo			break;
11377203945Sweongyo		}
11378203945Sweongyo	}
11379203945Sweongyo
11380203945Sweongyo	if (bc == NULL)
11381203945Sweongyo		return (EINVAL);
11382203945Sweongyo
11383203945Sweongyo	BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL14, 0x04);
11384203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE0, bc->bc_data[0]);
11385203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE2, bc->bc_data[1]);
11386203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE3, bc->bc_data[2]);
11387203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_TUNE, bc->bc_data[3]);
11388203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_LGENG_CTL1, bc->bc_data[4]);
11389203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL5, bc->bc_data[5]);
11390203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL6, bc->bc_data[6]);
11391203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PGA, bc->bc_data[7]);
11392203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PAD, bc->bc_data[8]);
11393203945Sweongyo
11394203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xcc);
11395203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0x07);
11396203945Sweongyo	bwn_phy_lp_b2062_reset_pllbias(mac);
11397203945Sweongyo	tmp[0] = freqxtal / 1000;
11398203945Sweongyo	tmp[1] = plp->plp_div * 1000;
11399203945Sweongyo	tmp[2] = tmp[1] * ieee80211_ieee2mhz(chan, 0);
11400203945Sweongyo	if (ieee80211_ieee2mhz(chan, 0) < 4000)
11401203945Sweongyo		tmp[2] *= 2;
11402203945Sweongyo	tmp[3] = 48 * tmp[0];
11403203945Sweongyo	tmp[5] = tmp[2] / tmp[3];
11404203945Sweongyo	tmp[6] = tmp[2] % tmp[3];
11405203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL26, tmp[5]);
11406203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11407203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11408203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11409203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL27, tmp[5]);
11410203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11411203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11412203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11413203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL28, tmp[5]);
11414203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11415203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11416203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11417203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL29,
11418203945Sweongyo	    tmp[5] + ((2 * tmp[6]) / tmp[3]));
11419203945Sweongyo	tmp[7] = BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL19);
11420203945Sweongyo	tmp[8] = ((2 * tmp[2] * (tmp[7] + 1)) + (3 * tmp[0])) / (6 * tmp[0]);
11421203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL23, (tmp[8] >> 8) + 16);
11422203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL24, tmp[8] & 0xff);
11423203945Sweongyo
11424203945Sweongyo	bwn_phy_lp_b2062_vco_calib(mac);
11425203945Sweongyo	if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11426203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xfc);
11427203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0);
11428203945Sweongyo		bwn_phy_lp_b2062_reset_pllbias(mac);
11429203945Sweongyo		bwn_phy_lp_b2062_vco_calib(mac);
11430203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11431203945Sweongyo			BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11432203945Sweongyo			return (EIO);
11433203945Sweongyo		}
11434203945Sweongyo	}
11435203945Sweongyo	BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11436203945Sweongyo	return (0);
11437203945Sweongyo}
11438203945Sweongyo
11439203945Sweongyostatic void
11440203945Sweongyobwn_phy_lp_set_anafilter(struct bwn_mac *mac, uint8_t channel)
11441203945Sweongyo{
11442203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11443203945Sweongyo	uint16_t tmp = (channel == 14);
11444203945Sweongyo
11445203945Sweongyo	if (mac->mac_phy.rev < 2) {
11446203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xfcff, tmp << 9);
11447203945Sweongyo		if ((mac->mac_phy.rev == 1) && (plp->plp_rccap))
11448203945Sweongyo			bwn_phy_lp_set_rccap(mac);
11449203945Sweongyo		return;
11450203945Sweongyo	}
11451203945Sweongyo
11452203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, 0x3f);
11453203945Sweongyo}
11454203945Sweongyo
11455203945Sweongyostatic void
11456203945Sweongyobwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq)
11457203945Sweongyo{
11458203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11459203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11460203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11461203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11462203945Sweongyo	uint16_t iso, tmp[3];
11463203945Sweongyo
11464203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
11465203945Sweongyo
11466203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
11467203945Sweongyo		iso = plp->plp_txisoband_m;
11468203945Sweongyo	else if (freq <= 5320)
11469203945Sweongyo		iso = plp->plp_txisoband_l;
11470203945Sweongyo	else if (freq <= 5700)
11471203945Sweongyo		iso = plp->plp_txisoband_m;
11472203945Sweongyo	else
11473203945Sweongyo		iso = plp->plp_txisoband_h;
11474203945Sweongyo
11475203945Sweongyo	tmp[0] = ((iso - 26) / 12) << 12;
11476203945Sweongyo	tmp[1] = tmp[0] + 0x1000;
11477203945Sweongyo	tmp[2] = tmp[0] + 0x2000;
11478203945Sweongyo
11479203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), 3, tmp);
11480203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), 3, tmp);
11481203945Sweongyo}
11482203945Sweongyo
11483203945Sweongyostatic void
11484203945Sweongyobwn_phy_lp_digflt_save(struct bwn_mac *mac)
11485203945Sweongyo{
11486203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11487203945Sweongyo	int i;
11488203945Sweongyo	static const uint16_t addr[] = {
11489203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11490203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11491203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11492203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11493203945Sweongyo		BWN_PHY_OFDM(0xcf),
11494203945Sweongyo	};
11495203945Sweongyo	static const uint16_t val[] = {
11496203945Sweongyo		0xde5e, 0xe832, 0xe331, 0x4d26,
11497203945Sweongyo		0x0026, 0x1420, 0x0020, 0xfe08,
11498203945Sweongyo		0x0008,
11499203945Sweongyo	};
11500203945Sweongyo
11501203945Sweongyo	for (i = 0; i < N(addr); i++) {
11502203945Sweongyo		plp->plp_digfilt[i] = BWN_PHY_READ(mac, addr[i]);
11503203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], val[i]);
11504203945Sweongyo	}
11505203945Sweongyo}
11506203945Sweongyo
11507203945Sweongyostatic void
11508203945Sweongyobwn_phy_lp_get_txpctlmode(struct bwn_mac *mac)
11509203945Sweongyo{
11510203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11511203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11512203945Sweongyo	uint16_t ctl;
11513203945Sweongyo
11514203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_TX_PWR_CTL_CMD);
11515203945Sweongyo	switch (ctl & BWN_PHY_TX_PWR_CTL_CMD_MODE) {
11516203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF:
11517203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_OFF;
11518203945Sweongyo		break;
11519203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_SW:
11520203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_SW;
11521203945Sweongyo		break;
11522203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_HW:
11523203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_HW;
11524203945Sweongyo		break;
11525203945Sweongyo	default:
11526203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_UNKNOWN;
11527203945Sweongyo		device_printf(sc->sc_dev, "unknown command mode\n");
11528203945Sweongyo		break;
11529203945Sweongyo	}
11530203945Sweongyo}
11531203945Sweongyo
11532203945Sweongyostatic void
11533203945Sweongyobwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
11534203945Sweongyo{
11535203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11536203945Sweongyo	uint16_t ctl;
11537203945Sweongyo	uint8_t old;
11538203945Sweongyo
11539203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11540203945Sweongyo	old = plp->plp_txpctlmode;
11541203945Sweongyo	if (old == mode)
11542203945Sweongyo		return;
11543203945Sweongyo	plp->plp_txpctlmode = mode;
11544203945Sweongyo
11545203945Sweongyo	if (old != BWN_PHYLP_TXPCTL_ON_HW && mode == BWN_PHYLP_TXPCTL_ON_HW) {
11546203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD, 0xff80,
11547203945Sweongyo		    plp->plp_tssiidx);
11548203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_NNUM,
11549203945Sweongyo		    0x8fff, ((uint16_t)plp->plp_tssinpt << 16));
11550203945Sweongyo
11551203945Sweongyo		/* disable TX GAIN override */
11552203945Sweongyo		if (mac->mac_phy.rev < 2)
11553203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11554203945Sweongyo		else {
11555203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xff7f);
11556203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xbfff);
11557203945Sweongyo		}
11558203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xffbf);
11559203945Sweongyo
11560203945Sweongyo		plp->plp_txpwridx = -1;
11561203945Sweongyo	}
11562203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11563203945Sweongyo		if (mode == BWN_PHYLP_TXPCTL_ON_HW)
11564203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xd0), 0x2);
11565203945Sweongyo		else
11566203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xd0), 0xfffd);
11567203945Sweongyo	}
11568203945Sweongyo
11569203945Sweongyo	/* writes TX Power Control mode */
11570203945Sweongyo	switch (plp->plp_txpctlmode) {
11571203945Sweongyo	case BWN_PHYLP_TXPCTL_OFF:
11572203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF;
11573203945Sweongyo		break;
11574203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_HW:
11575203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_HW;
11576203945Sweongyo		break;
11577203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_SW:
11578203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
11579203945Sweongyo		break;
11580203945Sweongyo	default:
11581204242Simp		ctl = 0;
11582203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
11583203945Sweongyo	}
11584203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
11585203945Sweongyo	    (uint16_t)~BWN_PHY_TX_PWR_CTL_CMD_MODE, ctl);
11586203945Sweongyo}
11587203945Sweongyo
11588203945Sweongyostatic void
11589203945Sweongyobwn_phy_lp_bugfix(struct bwn_mac *mac)
11590203945Sweongyo{
11591203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11592203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11593203945Sweongyo	const unsigned int size = 256;
11594203945Sweongyo	struct bwn_txgain tg;
11595203945Sweongyo	uint32_t rxcomp, txgain, coeff, rfpwr, *tabs;
11596203945Sweongyo	uint16_t tssinpt, tssiidx, value[2];
11597203945Sweongyo	uint8_t mode;
11598203945Sweongyo	int8_t txpwridx;
11599203945Sweongyo
11600203945Sweongyo	tabs = (uint32_t *)malloc(sizeof(uint32_t) * size, M_DEVBUF,
11601203945Sweongyo	    M_NOWAIT | M_ZERO);
11602203945Sweongyo	if (tabs == NULL) {
11603203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer.\n");
11604203945Sweongyo		return;
11605203945Sweongyo	}
11606203945Sweongyo
11607203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11608203945Sweongyo	mode = plp->plp_txpctlmode;
11609203945Sweongyo	txpwridx = plp->plp_txpwridx;
11610203945Sweongyo	tssinpt = plp->plp_tssinpt;
11611203945Sweongyo	tssiidx = plp->plp_tssiidx;
11612203945Sweongyo
11613203945Sweongyo	bwn_tab_read_multi(mac,
11614203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11615203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11616203945Sweongyo
11617203945Sweongyo	bwn_phy_lp_tblinit(mac);
11618203945Sweongyo	bwn_phy_lp_bbinit(mac);
11619203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
11620203945Sweongyo	bwn_phy_lp_rf_onoff(mac, 1);
11621203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11622203945Sweongyo
11623203945Sweongyo	bwn_tab_write_multi(mac,
11624203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11625203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11626203945Sweongyo
11627203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, plp->plp_chan);
11628203945Sweongyo	plp->plp_tssinpt = tssinpt;
11629203945Sweongyo	plp->plp_tssiidx = tssiidx;
11630203945Sweongyo	bwn_phy_lp_set_anafilter(mac, plp->plp_chan);
11631203945Sweongyo	if (txpwridx != -1) {
11632203945Sweongyo		/* set TX power by index */
11633203945Sweongyo		plp->plp_txpwridx = txpwridx;
11634203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11635203945Sweongyo		if (plp->plp_txpctlmode != BWN_PHYLP_TXPCTL_OFF)
11636203945Sweongyo			bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_ON_SW);
11637203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11638203945Sweongyo			rxcomp = bwn_tab_read(mac,
11639203945Sweongyo			    BWN_TAB_4(7, txpwridx + 320));
11640203945Sweongyo			txgain = bwn_tab_read(mac,
11641203945Sweongyo			    BWN_TAB_4(7, txpwridx + 192));
11642203945Sweongyo			tg.tg_pad = (txgain >> 16) & 0xff;
11643203945Sweongyo			tg.tg_gm = txgain & 0xff;
11644203945Sweongyo			tg.tg_pga = (txgain >> 8) & 0xff;
11645203945Sweongyo			tg.tg_dac = (rxcomp >> 28) & 0xff;
11646203945Sweongyo			bwn_phy_lp_set_txgain(mac, &tg);
11647203945Sweongyo		} else {
11648203945Sweongyo			rxcomp = bwn_tab_read(mac,
11649203945Sweongyo			    BWN_TAB_4(10, txpwridx + 320));
11650203945Sweongyo			txgain = bwn_tab_read(mac,
11651203945Sweongyo			    BWN_TAB_4(10, txpwridx + 192));
11652203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
11653203945Sweongyo			    0xf800, (txgain >> 4) & 0x7fff);
11654203945Sweongyo			bwn_phy_lp_set_txgain_dac(mac, txgain & 0x7);
11655203945Sweongyo			bwn_phy_lp_set_txgain_pa(mac, (txgain >> 24) & 0x7f);
11656203945Sweongyo		}
11657203945Sweongyo		bwn_phy_lp_set_bbmult(mac, (rxcomp >> 20) & 0xff);
11658203945Sweongyo
11659203945Sweongyo		/* set TX IQCC */
11660203945Sweongyo		value[0] = (rxcomp >> 10) & 0x3ff;
11661203945Sweongyo		value[1] = rxcomp & 0x3ff;
11662203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(0, 80), 2, value);
11663203945Sweongyo
11664203945Sweongyo		coeff = bwn_tab_read(mac,
11665203945Sweongyo		    (mac->mac_phy.rev >= 2) ? BWN_TAB_4(7, txpwridx + 448) :
11666203945Sweongyo		    BWN_TAB_4(10, txpwridx + 448));
11667203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0, 85), coeff & 0xffff);
11668203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11669203945Sweongyo			rfpwr = bwn_tab_read(mac,
11670203945Sweongyo			    BWN_TAB_4(7, txpwridx + 576));
11671203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00,
11672203945Sweongyo			    rfpwr & 0xffff);
11673203945Sweongyo		}
11674203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
11675203945Sweongyo	}
11676203945Sweongyo	if (plp->plp_rccap)
11677203945Sweongyo		bwn_phy_lp_set_rccap(mac);
11678203945Sweongyo	bwn_phy_lp_set_antenna(mac, plp->plp_antenna);
11679203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11680203945Sweongyo	free(tabs, M_DEVBUF);
11681203945Sweongyo}
11682203945Sweongyo
11683203945Sweongyostatic void
11684203945Sweongyobwn_phy_lp_digflt_restore(struct bwn_mac *mac)
11685203945Sweongyo{
11686203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11687203945Sweongyo	int i;
11688203945Sweongyo	static const uint16_t addr[] = {
11689203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11690203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11691203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11692203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11693203945Sweongyo		BWN_PHY_OFDM(0xcf),
11694203945Sweongyo	};
11695203945Sweongyo
11696203945Sweongyo	for (i = 0; i < N(addr); i++)
11697203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], plp->plp_digfilt[i]);
11698203945Sweongyo}
11699203945Sweongyo
11700203945Sweongyostatic void
11701203945Sweongyobwn_phy_lp_tblinit(struct bwn_mac *mac)
11702203945Sweongyo{
11703203945Sweongyo	uint32_t freq = ieee80211_ieee2mhz(bwn_phy_lp_get_default_chan(mac), 0);
11704203945Sweongyo
11705203945Sweongyo	if (mac->mac_phy.rev < 2) {
11706203945Sweongyo		bwn_phy_lp_tblinit_r01(mac);
11707203945Sweongyo		bwn_phy_lp_tblinit_txgain(mac);
11708203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, freq);
11709203945Sweongyo		return;
11710203945Sweongyo	}
11711203945Sweongyo
11712203945Sweongyo	bwn_phy_lp_tblinit_r2(mac);
11713203945Sweongyo	bwn_phy_lp_tblinit_txgain(mac);
11714203945Sweongyo}
11715203945Sweongyo
11716203945Sweongyostruct bwn_wpair {
11717203945Sweongyo	uint16_t		reg;
11718203945Sweongyo	uint16_t		value;
11719203945Sweongyo};
11720203945Sweongyo
11721203945Sweongyostruct bwn_smpair {
11722203945Sweongyo	uint16_t		offset;
11723203945Sweongyo	uint16_t		mask;
11724203945Sweongyo	uint16_t		set;
11725203945Sweongyo};
11726203945Sweongyo
11727203945Sweongyostatic void
11728203945Sweongyobwn_phy_lp_bbinit_r2(struct bwn_mac *mac)
11729203945Sweongyo{
11730203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11731203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11732203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11733203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11734203945Sweongyo	static const struct bwn_wpair v1[] = {
11735203945Sweongyo		{ BWN_PHY_AFE_DAC_CTL, 0x50 },
11736203945Sweongyo		{ BWN_PHY_AFE_CTL, 0x8800 },
11737203945Sweongyo		{ BWN_PHY_AFE_CTL_OVR, 0 },
11738203945Sweongyo		{ BWN_PHY_AFE_CTL_OVRVAL, 0 },
11739203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_0, 0 },
11740203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_2, 0 },
11741203945Sweongyo		{ BWN_PHY_OFDM(0xf9), 0 },
11742203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0 }
11743203945Sweongyo	};
11744203945Sweongyo	static const struct bwn_smpair v2[] = {
11745203945Sweongyo		{ BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0xb4 },
11746203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xf8ff, 0x200 },
11747203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xff00, 0x7f },
11748203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xff0f, 0x40 },
11749203945Sweongyo		{ BWN_PHY_PREAMBLECONFIRMTO, 0xff00, 0x2 }
11750203945Sweongyo	};
11751203945Sweongyo	static const struct bwn_smpair v3[] = {
11752203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xffe0, 0x1f },
11753203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11754203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0xff00, 0x19 },
11755203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0x03ff, 0x3c00 },
11756203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xfc1f, 0x3e0 },
11757203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11758203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0x00ff, 0x1900 },
11759203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800 },
11760203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x12 },
11761203945Sweongyo		{ BWN_PHY_GAINMISMATCH, 0x0fff, 0x9000 },
11762204922Sweongyo
11763203945Sweongyo	};
11764203945Sweongyo	int i;
11765203945Sweongyo
11766203945Sweongyo	for (i = 0; i < N(v1); i++)
11767203945Sweongyo		BWN_PHY_WRITE(mac, v1[i].reg, v1[i].value);
11768203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x10);
11769203945Sweongyo	for (i = 0; i < N(v2); i++)
11770203945Sweongyo		BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask, v2[i].set);
11771203945Sweongyo
11772203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x4000);
11773203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x2000);
11774203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_OFDM(0x10a), 0x1);
11775204922Sweongyo	if (siba_get_pci_revid(sc->sc_dev) >= 0x18) {
11776203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(17, 65), 0xec);
11777203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x14);
11778203945Sweongyo	} else {
11779203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x10);
11780203945Sweongyo	}
11781203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0xff00, 0xf4);
11782203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0x00ff, 0xf100);
11783203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CLIPTHRESH, 0x48);
11784203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0xff00, 0x46);
11785203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe4), 0xff00, 0x10);
11786203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_PWR_THRESH1, 0xfff0, 0x9);
11787203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_GAINDIRECTMISMATCH, ~0xf);
11788203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5500);
11789203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0xa0);
11790203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_GAINDIRECTMISMATCH, 0xe0ff, 0x300);
11791203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2a00);
11792204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11793204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11794203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11795203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xa);
11796203945Sweongyo	} else {
11797203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x1e00);
11798203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xd);
11799203945Sweongyo	}
11800203945Sweongyo	for (i = 0; i < N(v3); i++)
11801203945Sweongyo		BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask, v3[i].set);
11802204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11803204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11804203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x14), 0);
11805203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x12), 0x40);
11806203945Sweongyo	}
11807203945Sweongyo
11808203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11809203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x40);
11810203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0xb00);
11811203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x6);
11812203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0x9d00);
11813203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0xff00, 0xa1);
11814203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11815203945Sweongyo	} else
11816203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x40);
11817203945Sweongyo
11818203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0xff00, 0xb3);
11819203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00);
11820203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB, 0xff00, plp->plp_rxpwroffset);
11821203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RESET_CTL, 0x44);
11822203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RESET_CTL, 0x80);
11823203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, 0xa954);
11824203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_1,
11825203945Sweongyo	    0x2000 | ((uint16_t)plp->plp_rssigs << 10) |
11826203945Sweongyo	    ((uint16_t)plp->plp_rssivc << 4) | plp->plp_rssivf);
11827203945Sweongyo
11828204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11829204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11830203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_AFE_ADC_CTL_0, 0x1c);
11831203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_CTL, 0x00ff, 0x8800);
11832203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_1, 0xfc3c, 0x0400);
11833203945Sweongyo	}
11834203945Sweongyo
11835203945Sweongyo	bwn_phy_lp_digflt_save(mac);
11836203945Sweongyo}
11837203945Sweongyo
11838203945Sweongyostatic void
11839203945Sweongyobwn_phy_lp_bbinit_r01(struct bwn_mac *mac)
11840203945Sweongyo{
11841203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11842203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11843203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11844203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11845203945Sweongyo	static const struct bwn_smpair v1[] = {
11846203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 },
11847203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 },
11848203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x3c00 },
11849203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xfff0, 0x0005 },
11850203945Sweongyo		{ BWN_PHY_GAIN_MISMATCH_LIMIT, 0xffc0, 0x001a },
11851203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0xff00, 0x00b3 },
11852203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00 }
11853203945Sweongyo	};
11854203945Sweongyo	static const struct bwn_smpair v2[] = {
11855203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11856203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0x3f00, 0x0900 },
11857203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11858203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11859203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x000a },
11860203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0400 },
11861203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x000a },
11862203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0b00 },
11863203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xffc0, 0x000a },
11864203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xc0ff, 0x0900 },
11865203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xffc0, 0x000a },
11866203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xc0ff, 0x0b00 },
11867203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xffc0, 0x000a },
11868203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xc0ff, 0x0900 },
11869203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xffc0, 0x000a },
11870203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xc0ff, 0x0b00 }
11871203945Sweongyo	};
11872203945Sweongyo	static const struct bwn_smpair v3[] = {
11873203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0001 },
11874203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0400 },
11875203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0001 },
11876203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0500 },
11877203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11878203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0800 },
11879203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11880203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0a00 }
11881203945Sweongyo	};
11882203945Sweongyo	static const struct bwn_smpair v4[] = {
11883203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0004 },
11884203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0800 },
11885203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0004 },
11886203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0c00 },
11887203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11888203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0100 },
11889203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11890203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0300 }
11891203945Sweongyo	};
11892203945Sweongyo	static const struct bwn_smpair v5[] = {
11893203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11894203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0900 },
11895203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11896203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11897203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0006 },
11898203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0500 },
11899203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0006 },
11900203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0700 }
11901203945Sweongyo	};
11902203945Sweongyo	int i;
11903203945Sweongyo	uint16_t tmp, tmp2;
11904203945Sweongyo
11905203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf7ff);
11906203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL, 0);
11907203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, 0);
11908203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, 0);
11909203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0);
11910203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DAC_CTL, 0x0004);
11911203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0x0078);
11912203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800);
11913203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x0016);
11914203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_0, 0xfff8, 0x0004);
11915203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5400);
11916203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2400);
11917203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11918203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0x0006);
11919203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_RADIO_CTL, 0xfffe);
11920203945Sweongyo	for (i = 0; i < N(v1); i++)
11921203945Sweongyo		BWN_PHY_SETMASK(mac, v1[i].offset, v1[i].mask, v1[i].set);
11922203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB,
11923203945Sweongyo	    0xff00, plp->plp_rxpwroffset);
11924204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) &&
11925203945Sweongyo	    ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
11926204922Sweongyo	   (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_PAREF))) {
11927204922Sweongyo		siba_cc_pmu_set_ldovolt(sc->sc_dev, SIBA_LDO_PAREF, 0x28);
11928204922Sweongyo		siba_cc_pmu_set_ldoparef(sc->sc_dev, 1);
11929203945Sweongyo		if (mac->mac_phy.rev == 0)
11930203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT,
11931203945Sweongyo			    0xffcf, 0x0010);
11932203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 60);
11933203945Sweongyo	} else {
11934204922Sweongyo		siba_cc_pmu_set_ldoparef(sc->sc_dev, 0);
11935203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT, 0xffcf, 0x0020);
11936203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 100);
11937203945Sweongyo	}
11938203945Sweongyo	tmp = plp->plp_rssivf | plp->plp_rssivc << 4 | 0xa000;
11939203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, tmp);
11940204922Sweongyo	if (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_RSSIINV)
11941203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x0aaa);
11942203945Sweongyo	else
11943203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x02aa);
11944203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(11, 1), 24);
11945203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_RADIO_CTL,
11946203945Sweongyo	    0xfff9, (plp->plp_bxarch << 1));
11947203945Sweongyo	if (mac->mac_phy.rev == 1 &&
11948204922Sweongyo	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_FEM_BT)) {
11949203945Sweongyo		for (i = 0; i < N(v2); i++)
11950203945Sweongyo			BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask,
11951203945Sweongyo			    v2[i].set);
11952203945Sweongyo	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ||
11953204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) == 0x048a) ||
11954204922Sweongyo	    ((mac->mac_phy.rev == 0) &&
11955204922Sweongyo	     (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM))) {
11956203945Sweongyo		for (i = 0; i < N(v3); i++)
11957203945Sweongyo			BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask,
11958203945Sweongyo			    v3[i].set);
11959203945Sweongyo	} else if (mac->mac_phy.rev == 1 ||
11960204922Sweongyo		  (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM)) {
11961203945Sweongyo		for (i = 0; i < N(v4); i++)
11962203945Sweongyo			BWN_PHY_SETMASK(mac, v4[i].offset, v4[i].mask,
11963203945Sweongyo			    v4[i].set);
11964203945Sweongyo	} else {
11965203945Sweongyo		for (i = 0; i < N(v5); i++)
11966203945Sweongyo			BWN_PHY_SETMASK(mac, v5[i].offset, v5[i].mask,
11967203945Sweongyo			    v5[i].set);
11968203945Sweongyo	}
11969203945Sweongyo	if (mac->mac_phy.rev == 1 &&
11970204922Sweongyo	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_PAREF)) {
11971203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_5, BWN_PHY_TR_LOOKUP_1);
11972203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_6, BWN_PHY_TR_LOOKUP_2);
11973203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_7, BWN_PHY_TR_LOOKUP_3);
11974203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_8, BWN_PHY_TR_LOOKUP_4);
11975203945Sweongyo	}
11976204922Sweongyo	if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_FEM_BT) &&
11977204922Sweongyo	    (siba_get_chipid(sc->sc_dev) == 0x5354) &&
11978204922Sweongyo	    (siba_get_chippkg(sc->sc_dev) == SIBA_CHIPPACK_BCM4712S)) {
11979203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0006);
11980203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_SELECT, 0x0005);
11981203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_OUTEN, 0xffff);
11982203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_PR45960W);
11983203945Sweongyo	}
11984203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11985203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x8000);
11986203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0040);
11987203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0xa400);
11988203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0x0b00);
11989203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x0007);
11990203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xfff8, 0x0003);
11991203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xffc7, 0x0020);
11992203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11993203945Sweongyo	} else {
11994203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0x7fff);
11995203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xffbf);
11996203945Sweongyo	}
11997203945Sweongyo	if (mac->mac_phy.rev == 1) {
11998203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_CLIPCTRTHRESH);
11999203945Sweongyo		tmp2 = (tmp & 0x03e0) >> 5;
12000203945Sweongyo		tmp2 |= tmp2 << 5;
12001203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C3, tmp2);
12002203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_GAINDIRECTMISMATCH);
12003203945Sweongyo		tmp2 = (tmp & 0x1f00) >> 8;
12004203945Sweongyo		tmp2 |= tmp2 << 5;
12005203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C4, tmp2);
12006203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERYLOWGAINDB);
12007203945Sweongyo		tmp2 = tmp & 0x00ff;
12008203945Sweongyo		tmp2 |= tmp << 8;
12009203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C5, tmp2);
12010203945Sweongyo	}
12011203945Sweongyo}
12012203945Sweongyo
12013203945Sweongyostruct bwn_b2062_freq {
12014203945Sweongyo	uint16_t		freq;
12015203945Sweongyo	uint8_t			value[6];
12016203945Sweongyo};
12017203945Sweongyo
12018203945Sweongyostatic void
12019203945Sweongyobwn_phy_lp_b2062_init(struct bwn_mac *mac)
12020203945Sweongyo{
12021203945Sweongyo#define	CALC_CTL7(freq, div)						\
12022203945Sweongyo	(((800000000 * (div) + (freq)) / (2 * (freq)) - 8) & 0xff)
12023203945Sweongyo#define	CALC_CTL18(freq, div)						\
12024203945Sweongyo	((((100 * (freq) + 16000000 * (div)) / (32000000 * (div))) - 1) & 0xff)
12025203945Sweongyo#define	CALC_CTL19(freq, div)						\
12026203945Sweongyo	((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff)
12027203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12028203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12029203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12030203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12031203945Sweongyo	static const struct bwn_b2062_freq freqdata_tab[] = {
12032203945Sweongyo		{ 12000, { 6, 6, 6, 6, 10, 6 } },
12033203945Sweongyo		{ 13000, { 4, 4, 4, 4, 11, 7 } },
12034203945Sweongyo		{ 14400, { 3, 3, 3, 3, 12, 7 } },
12035203945Sweongyo		{ 16200, { 3, 3, 3, 3, 13, 8 } },
12036203945Sweongyo		{ 18000, { 2, 2, 2, 2, 14, 8 } },
12037203945Sweongyo		{ 19200, { 1, 1, 1, 1, 14, 9 } }
12038203945Sweongyo	};
12039203945Sweongyo	static const struct bwn_wpair v1[] = {
12040203945Sweongyo		{ BWN_B2062_N_TXCTL3, 0 },
12041203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0 },
12042203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0 },
12043203945Sweongyo		{ BWN_B2062_N_TXCTL6, 0 },
12044203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0x40 },
12045203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0 },
12046203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0x10 },
12047203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0 }
12048203945Sweongyo	};
12049203945Sweongyo	const struct bwn_b2062_freq *f = NULL;
12050203945Sweongyo	uint32_t xtalfreq, ref;
12051203945Sweongyo	unsigned int i;
12052203945Sweongyo
12053203945Sweongyo	bwn_phy_lp_b2062_tblinit(mac);
12054203945Sweongyo
12055203945Sweongyo	for (i = 0; i < N(v1); i++)
12056203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12057203945Sweongyo	if (mac->mac_phy.rev > 0)
12058203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_BG_CTL1,
12059203945Sweongyo		    (BWN_RF_READ(mac, BWN_B2062_N_COM2) >> 1) | 0x80);
12060203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12061203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_N_TSSI_CTL0, 0x1);
12062203945Sweongyo	else
12063203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_N_TSSI_CTL0, ~0x1);
12064203945Sweongyo
12065204922Sweongyo	KASSERT(siba_get_cc_caps(sc->sc_dev) & SIBA_CC_CAPS_PMU,
12066203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
12067204922Sweongyo	xtalfreq = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
12068203945Sweongyo	KASSERT(xtalfreq != 0, ("%s:%d: fail", __func__, __LINE__));
12069203945Sweongyo
12070203945Sweongyo	if (xtalfreq <= 30000000) {
12071203945Sweongyo		plp->plp_div = 1;
12072203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL1, 0xfffb);
12073203945Sweongyo	} else {
12074203945Sweongyo		plp->plp_div = 2;
12075203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL1, 0x4);
12076203945Sweongyo	}
12077203945Sweongyo
12078203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL7,
12079203945Sweongyo	    CALC_CTL7(xtalfreq, plp->plp_div));
12080203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL18,
12081203945Sweongyo	    CALC_CTL18(xtalfreq, plp->plp_div));
12082203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL19,
12083203945Sweongyo	    CALC_CTL19(xtalfreq, plp->plp_div));
12084203945Sweongyo
12085203945Sweongyo	ref = (1000 * plp->plp_div + 2 * xtalfreq) / (2000 * plp->plp_div);
12086203945Sweongyo	ref &= 0xffff;
12087203945Sweongyo	for (i = 0; i < N(freqdata_tab); i++) {
12088203945Sweongyo		if (ref < freqdata_tab[i].freq) {
12089203945Sweongyo			f = &freqdata_tab[i];
12090203945Sweongyo			break;
12091203945Sweongyo		}
12092203945Sweongyo	}
12093203945Sweongyo	if (f == NULL)
12094203945Sweongyo		f = &freqdata_tab[N(freqdata_tab) - 1];
12095203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL8,
12096203945Sweongyo	    ((uint16_t)(f->value[1]) << 4) | f->value[0]);
12097203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL9,
12098203945Sweongyo	    ((uint16_t)(f->value[3]) << 4) | f->value[2]);
12099203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL10, f->value[4]);
12100203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL11, f->value[5]);
12101203945Sweongyo#undef CALC_CTL7
12102203945Sweongyo#undef CALC_CTL18
12103203945Sweongyo#undef CALC_CTL19
12104203945Sweongyo}
12105203945Sweongyo
12106203945Sweongyostatic void
12107203945Sweongyobwn_phy_lp_b2063_init(struct bwn_mac *mac)
12108203945Sweongyo{
12109203945Sweongyo
12110203945Sweongyo	bwn_phy_lp_b2063_tblinit(mac);
12111203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_SP5, 0);
12112203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM8, 0x38);
12113203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_REG_SP1, 0x56);
12114203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_RX_BB_CTL2, ~0x2);
12115203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0);
12116203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP6, 0x20);
12117203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP9, 0x40);
12118203945Sweongyo	if (mac->mac_phy.rev == 2) {
12119203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0xa0);
12120203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP4, 0xa0);
12121203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x18);
12122203945Sweongyo	} else {
12123203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0x20);
12124203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x20);
12125203945Sweongyo	}
12126203945Sweongyo}
12127203945Sweongyo
12128203945Sweongyostatic void
12129203945Sweongyobwn_phy_lp_rxcal_r2(struct bwn_mac *mac)
12130203945Sweongyo{
12131204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12132203945Sweongyo	static const struct bwn_wpair v1[] = {
12133203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x0 },
12134203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12135203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12136203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x15 },
12137203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x70 },
12138203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL4, 0x52 },
12139203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL5, 0x1 },
12140203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7d }
12141203945Sweongyo	};
12142203945Sweongyo	static const struct bwn_wpair v2[] = {
12143203945Sweongyo		{ BWN_B2063_TX_BB_SP3, 0x0 },
12144203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12145203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12146203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x55 },
12147203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x76 }
12148203945Sweongyo	};
12149204922Sweongyo	uint32_t freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
12150203945Sweongyo	int i;
12151203945Sweongyo	uint8_t tmp;
12152203945Sweongyo
12153203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_RX_BB_SP8) & 0xff;
12154203945Sweongyo
12155203945Sweongyo	for (i = 0; i < 2; i++)
12156203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12157203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, 0xf7);
12158203945Sweongyo	for (i = 2; i < N(v1); i++)
12159203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12160203945Sweongyo	for (i = 0; i < 10000; i++) {
12161203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12162203945Sweongyo			break;
12163203945Sweongyo		DELAY(1000);
12164203945Sweongyo	}
12165203945Sweongyo
12166203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12167203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RX_BB_SP8, tmp);
12168203945Sweongyo
12169203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_TX_BB_SP3) & 0xff;
12170203945Sweongyo
12171203945Sweongyo	for (i = 0; i < N(v2); i++)
12172203945Sweongyo		BWN_RF_WRITE(mac, v2[i].reg, v2[i].value);
12173203945Sweongyo	if (freqxtal == 24000000) {
12174203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0xfc);
12175203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x0);
12176203945Sweongyo	} else {
12177203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0x13);
12178203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x1);
12179203945Sweongyo	}
12180203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0x7d);
12181203945Sweongyo	for (i = 0; i < 10000; i++) {
12182203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12183203945Sweongyo			break;
12184203945Sweongyo		DELAY(1000);
12185203945Sweongyo	}
12186203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12187203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, tmp);
12188203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL1, 0x7e);
12189203945Sweongyo}
12190203945Sweongyo
12191203945Sweongyostatic void
12192203945Sweongyobwn_phy_lp_rccal_r12(struct bwn_mac *mac)
12193203945Sweongyo{
12194203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12195203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12196203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12197203945Sweongyo	struct bwn_txgain tx_gains;
12198203945Sweongyo	static const uint32_t pwrtbl[21] = {
12199203945Sweongyo		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
12200203945Sweongyo		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
12201203945Sweongyo		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
12202203945Sweongyo		0x0004c, 0x0002c, 0x0001a,
12203203945Sweongyo	};
12204203945Sweongyo	uint32_t npwr, ipwr, sqpwr, tmp;
12205203945Sweongyo	int loopback, i, j, sum, error;
12206203945Sweongyo	uint16_t save[7];
12207203945Sweongyo	uint8_t txo, bbmult, txpctlmode;
12208203945Sweongyo
12209203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
12210203945Sweongyo	if (error)
12211203945Sweongyo		device_printf(sc->sc_dev,
12212203945Sweongyo		    "failed to change channel to 7 (%d)\n", error);
12213203945Sweongyo	txo = (BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40) ? 1 : 0;
12214203945Sweongyo	bbmult = bwn_phy_lp_get_bbmult(mac);
12215203945Sweongyo	if (txo)
12216203945Sweongyo		tx_gains = bwn_phy_lp_get_txgain(mac);
12217203945Sweongyo
12218203945Sweongyo	save[0] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_0);
12219203945Sweongyo	save[1] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_VAL_0);
12220203945Sweongyo	save[2] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR);
12221203945Sweongyo	save[3] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVRVAL);
12222203945Sweongyo	save[4] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2);
12223203945Sweongyo	save[5] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2_VAL);
12224203945Sweongyo	save[6] = BWN_PHY_READ(mac, BWN_PHY_LP_PHY_CTL);
12225203945Sweongyo
12226203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
12227203945Sweongyo	txpctlmode = plp->plp_txpctlmode;
12228203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
12229203945Sweongyo
12230203945Sweongyo	/* disable CRS */
12231203945Sweongyo	bwn_phy_lp_set_deaf(mac, 1);
12232203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 0, 1);
12233203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffb);
12234203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x4);
12235203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7);
12236203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
12237203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x10);
12238203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12239203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf);
12240203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
12241203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffbf);
12242203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12243203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x7);
12244203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x38);
12245203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f);
12246203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x100);
12247203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfdff);
12248203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL0, 0);
12249203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL1, 1);
12250203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL2, 0x20);
12251203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfbff);
12252203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xf7ff);
12253203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
12254203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45af);
12255203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0x3ff);
12256203945Sweongyo
12257203945Sweongyo	loopback = bwn_phy_lp_loopback(mac);
12258203945Sweongyo	if (loopback == -1)
12259203945Sweongyo		goto done;
12260203945Sweongyo	bwn_phy_lp_set_rxgain_idx(mac, loopback);
12261203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xffbf, 0x40);
12262203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfff8, 0x1);
12263203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xffc7, 0x8);
12264203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f, 0xc0);
12265203945Sweongyo
12266203945Sweongyo	tmp = 0;
12267203945Sweongyo	memset(&ie, 0, sizeof(ie));
12268203945Sweongyo	for (i = 128; i <= 159; i++) {
12269203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2, i);
12270203945Sweongyo		sum = 0;
12271203945Sweongyo		for (j = 5; j <= 25; j++) {
12272203945Sweongyo			bwn_phy_lp_ddfs_turnon(mac, 1, 1, j, j, 0);
12273203945Sweongyo			if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
12274203945Sweongyo				goto done;
12275203945Sweongyo			sqpwr = ie.ie_ipwr + ie.ie_qpwr;
12276203945Sweongyo			ipwr = ((pwrtbl[j - 5] >> 3) + 1) >> 1;
12277203945Sweongyo			npwr = bwn_phy_lp_roundup(sqpwr, (j == 5) ? sqpwr : 0,
12278203945Sweongyo			    12);
12279203945Sweongyo			sum += ((ipwr - npwr) * (ipwr - npwr));
12280203945Sweongyo			if ((i == 128) || (sum < tmp)) {
12281203945Sweongyo				plp->plp_rccap = i;
12282203945Sweongyo				tmp = sum;
12283203945Sweongyo			}
12284203945Sweongyo		}
12285203945Sweongyo	}
12286203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
12287203945Sweongyodone:
12288203945Sweongyo	/* restore CRS */
12289203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 1);
12290203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xff80);
12291203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfc00);
12292203945Sweongyo
12293203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_VAL_0, save[1]);
12294203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, save[0]);
12295203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVRVAL, save[3]);
12296203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, save[2]);
12297203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2_VAL, save[5]);
12298203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, save[4]);
12299203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LP_PHY_CTL, save[6]);
12300203945Sweongyo
12301203945Sweongyo	bwn_phy_lp_set_bbmult(mac, bbmult);
12302203945Sweongyo	if (txo)
12303203945Sweongyo		bwn_phy_lp_set_txgain(mac, &tx_gains);
12304203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, txpctlmode);
12305203945Sweongyo	if (plp->plp_rccap)
12306203945Sweongyo		bwn_phy_lp_set_rccap(mac);
12307203945Sweongyo}
12308203945Sweongyo
12309203945Sweongyostatic void
12310203945Sweongyobwn_phy_lp_set_rccap(struct bwn_mac *mac)
12311203945Sweongyo{
12312203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12313203945Sweongyo	uint8_t rc_cap = (plp->plp_rccap & 0x1f) >> 1;
12314203945Sweongyo
12315203945Sweongyo	if (mac->mac_phy.rev == 1)
12316203945Sweongyo		rc_cap = MIN(rc_cap + 5, 15);
12317203945Sweongyo
12318203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2,
12319203945Sweongyo	    MAX(plp->plp_rccap - 4, 0x80));
12320203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, rc_cap | 0x80);
12321203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RXG_CNT16,
12322203945Sweongyo	    ((plp->plp_rccap & 0x1f) >> 2) | 0x80);
12323203945Sweongyo}
12324203945Sweongyo
12325203945Sweongyostatic uint32_t
12326203945Sweongyobwn_phy_lp_roundup(uint32_t value, uint32_t div, uint8_t pre)
12327203945Sweongyo{
12328203945Sweongyo	uint32_t i, q, r;
12329203945Sweongyo
12330203945Sweongyo	if (div == 0)
12331203945Sweongyo		return (0);
12332203945Sweongyo
12333203945Sweongyo	for (i = 0, q = value / div, r = value % div; i < pre; i++) {
12334203945Sweongyo		q <<= 1;
12335203945Sweongyo		if (r << 1 >= div) {
12336203945Sweongyo			q++;
12337203945Sweongyo			r = (r << 1) - div;
12338203945Sweongyo		}
12339203945Sweongyo	}
12340203945Sweongyo	if (r << 1 >= div)
12341203945Sweongyo		q++;
12342203945Sweongyo	return (q);
12343203945Sweongyo}
12344203945Sweongyo
12345203945Sweongyostatic void
12346203945Sweongyobwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *mac)
12347203945Sweongyo{
12348204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12349203945Sweongyo
12350203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0xff);
12351203945Sweongyo	DELAY(20);
12352204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x5354) {
12353203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_COM1, 4);
12354203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 4);
12355203945Sweongyo	} else {
12356203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0);
12357203945Sweongyo	}
12358203945Sweongyo	DELAY(5);
12359203945Sweongyo}
12360203945Sweongyo
12361203945Sweongyostatic void
12362203945Sweongyobwn_phy_lp_b2062_vco_calib(struct bwn_mac *mac)
12363203945Sweongyo{
12364203945Sweongyo
12365203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x42);
12366203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x62);
12367203945Sweongyo	DELAY(200);
12368203945Sweongyo}
12369203945Sweongyo
12370203945Sweongyostatic void
12371203945Sweongyobwn_phy_lp_b2062_tblinit(struct bwn_mac *mac)
12372203945Sweongyo{
12373203945Sweongyo#define	FLAG_A	0x01
12374203945Sweongyo#define	FLAG_G	0x02
12375203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12376203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12377203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12378203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = {
12379203945Sweongyo		{ BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12380203945Sweongyo		{ BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, },
12381203945Sweongyo		{ BWN_B2062_N_PDNCTL3, 0x0, 0x0, FLAG_A | FLAG_G, },
12382203945Sweongyo		{ BWN_B2062_N_PDNCTL4, 0x15, 0x2a, FLAG_A | FLAG_G, },
12383203945Sweongyo		{ BWN_B2062_N_LGENC, 0xDB, 0xff, FLAG_A, },
12384203945Sweongyo		{ BWN_B2062_N_LGENATUNE0, 0xdd, 0x0, FLAG_A | FLAG_G, },
12385203945Sweongyo		{ BWN_B2062_N_LGENATUNE2, 0xdd, 0x0, FLAG_A | FLAG_G, },
12386203945Sweongyo		{ BWN_B2062_N_LGENATUNE3, 0x77, 0xB5, FLAG_A | FLAG_G, },
12387203945Sweongyo		{ BWN_B2062_N_LGENACTL3, 0x0, 0xff, FLAG_A | FLAG_G, },
12388203945Sweongyo		{ BWN_B2062_N_LGENACTL7, 0x33, 0x33, FLAG_A | FLAG_G, },
12389203945Sweongyo		{ BWN_B2062_N_RXA_CTL1, 0x0, 0x0, FLAG_G, },
12390203945Sweongyo		{ BWN_B2062_N_RXBB_CTL0, 0x82, 0x80, FLAG_A | FLAG_G, },
12391203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN1, 0x4, 0x4, FLAG_A | FLAG_G, },
12392203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN2, 0x0, 0x0, FLAG_A | FLAG_G, },
12393203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0x3, 0x3, FLAG_A | FLAG_G, },
12394203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0x2, 0x2, FLAG_A | FLAG_G, },
12395203945Sweongyo		{ BWN_B2062_N_TX_TUNE, 0x88, 0x1b, FLAG_A | FLAG_G, },
12396203945Sweongyo		{ BWN_B2062_S_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12397203945Sweongyo		{ BWN_B2062_S_PDS_CTL0, 0xff, 0xff, FLAG_A | FLAG_G, },
12398203945Sweongyo		{ BWN_B2062_S_LGENG_CTL0, 0xf8, 0xd8, FLAG_A | FLAG_G, },
12399203945Sweongyo		{ BWN_B2062_S_LGENG_CTL1, 0x3c, 0x24, FLAG_A | FLAG_G, },
12400203945Sweongyo		{ BWN_B2062_S_LGENG_CTL8, 0x88, 0x80, FLAG_A | FLAG_G, },
12401203945Sweongyo		{ BWN_B2062_S_LGENG_CTL10, 0x88, 0x80, FLAG_A | FLAG_G, },
12402203945Sweongyo		{ BWN_B2062_S_RFPLLCTL0, 0x98, 0x98, FLAG_A | FLAG_G, },
12403203945Sweongyo		{ BWN_B2062_S_RFPLLCTL1, 0x10, 0x10, FLAG_A | FLAG_G, },
12404203945Sweongyo		{ BWN_B2062_S_RFPLLCTL5, 0x43, 0x43, FLAG_A | FLAG_G, },
12405203945Sweongyo		{ BWN_B2062_S_RFPLLCTL6, 0x47, 0x47, FLAG_A | FLAG_G, },
12406203945Sweongyo		{ BWN_B2062_S_RFPLLCTL7, 0xc, 0xc, FLAG_A | FLAG_G, },
12407203945Sweongyo		{ BWN_B2062_S_RFPLLCTL8, 0x11, 0x11, FLAG_A | FLAG_G, },
12408203945Sweongyo		{ BWN_B2062_S_RFPLLCTL9, 0x11, 0x11, FLAG_A | FLAG_G, },
12409203945Sweongyo		{ BWN_B2062_S_RFPLLCTL10, 0xe, 0xe, FLAG_A | FLAG_G, },
12410203945Sweongyo		{ BWN_B2062_S_RFPLLCTL11, 0x8, 0x8, FLAG_A | FLAG_G, },
12411203945Sweongyo		{ BWN_B2062_S_RFPLLCTL12, 0x33, 0x33, FLAG_A | FLAG_G, },
12412203945Sweongyo		{ BWN_B2062_S_RFPLLCTL13, 0xa, 0xa, FLAG_A | FLAG_G, },
12413203945Sweongyo		{ BWN_B2062_S_RFPLLCTL14, 0x6, 0x6, FLAG_A | FLAG_G, },
12414203945Sweongyo		{ BWN_B2062_S_RFPLLCTL18, 0x3e, 0x3e, FLAG_A | FLAG_G, },
12415203945Sweongyo		{ BWN_B2062_S_RFPLLCTL19, 0x13, 0x13, FLAG_A | FLAG_G, },
12416203945Sweongyo		{ BWN_B2062_S_RFPLLCTL21, 0x62, 0x62, FLAG_A | FLAG_G, },
12417203945Sweongyo		{ BWN_B2062_S_RFPLLCTL22, 0x7, 0x7, FLAG_A | FLAG_G, },
12418203945Sweongyo		{ BWN_B2062_S_RFPLLCTL23, 0x16, 0x16, FLAG_A | FLAG_G, },
12419203945Sweongyo		{ BWN_B2062_S_RFPLLCTL24, 0x5c, 0x5c, FLAG_A | FLAG_G, },
12420203945Sweongyo		{ BWN_B2062_S_RFPLLCTL25, 0x95, 0x95, FLAG_A | FLAG_G, },
12421203945Sweongyo		{ BWN_B2062_S_RFPLLCTL30, 0xa0, 0xa0, FLAG_A | FLAG_G, },
12422203945Sweongyo		{ BWN_B2062_S_RFPLLCTL31, 0x4, 0x4, FLAG_A | FLAG_G, },
12423203945Sweongyo		{ BWN_B2062_S_RFPLLCTL33, 0xcc, 0xcc, FLAG_A | FLAG_G, },
12424203945Sweongyo		{ BWN_B2062_S_RFPLLCTL34, 0x7, 0x7, FLAG_A | FLAG_G, },
12425203945Sweongyo		{ BWN_B2062_S_RXG_CNT8, 0xf, 0xf, FLAG_A, },
12426203945Sweongyo	};
12427203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12428203945Sweongyo	unsigned int i;
12429203945Sweongyo
12430203945Sweongyo	for (i = 0; i < N(bwn_b2062_init_tab); i++) {
12431203945Sweongyo		br = &bwn_b2062_init_tab[i];
12432203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12433203945Sweongyo			if (br->br_flags & FLAG_G)
12434203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12435203945Sweongyo		} else {
12436203945Sweongyo			if (br->br_flags & FLAG_A)
12437203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12438203945Sweongyo		}
12439203945Sweongyo	}
12440203945Sweongyo#undef FLAG_A
12441203945Sweongyo#undef FLAG_B
12442203945Sweongyo}
12443203945Sweongyo
12444203945Sweongyostatic void
12445203945Sweongyobwn_phy_lp_b2063_tblinit(struct bwn_mac *mac)
12446203945Sweongyo{
12447203945Sweongyo#define	FLAG_A	0x01
12448203945Sweongyo#define	FLAG_G	0x02
12449203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12450203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12451203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12452203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = {
12453203945Sweongyo		{ BWN_B2063_COM1, 0x0, 0x0, FLAG_G, },
12454203945Sweongyo		{ BWN_B2063_COM10, 0x1, 0x0, FLAG_A, },
12455203945Sweongyo		{ BWN_B2063_COM16, 0x0, 0x0, FLAG_G, },
12456203945Sweongyo		{ BWN_B2063_COM17, 0x0, 0x0, FLAG_G, },
12457203945Sweongyo		{ BWN_B2063_COM18, 0x0, 0x0, FLAG_G, },
12458203945Sweongyo		{ BWN_B2063_COM19, 0x0, 0x0, FLAG_G, },
12459203945Sweongyo		{ BWN_B2063_COM20, 0x0, 0x0, FLAG_G, },
12460203945Sweongyo		{ BWN_B2063_COM21, 0x0, 0x0, FLAG_G, },
12461203945Sweongyo		{ BWN_B2063_COM22, 0x0, 0x0, FLAG_G, },
12462203945Sweongyo		{ BWN_B2063_COM23, 0x0, 0x0, FLAG_G, },
12463203945Sweongyo		{ BWN_B2063_COM24, 0x0, 0x0, FLAG_G, },
12464203945Sweongyo		{ BWN_B2063_LOGEN_SP1, 0xe8, 0xd4, FLAG_A | FLAG_G, },
12465203945Sweongyo		{ BWN_B2063_LOGEN_SP2, 0xa7, 0x53, FLAG_A | FLAG_G, },
12466203945Sweongyo		{ BWN_B2063_LOGEN_SP4, 0xf0, 0xf, FLAG_A | FLAG_G, },
12467203945Sweongyo		{ BWN_B2063_G_RX_SP1, 0x1f, 0x5e, FLAG_G, },
12468203945Sweongyo		{ BWN_B2063_G_RX_SP2, 0x7f, 0x7e, FLAG_G, },
12469203945Sweongyo		{ BWN_B2063_G_RX_SP3, 0x30, 0xf0, FLAG_G, },
12470203945Sweongyo		{ BWN_B2063_G_RX_SP7, 0x7f, 0x7f, FLAG_A | FLAG_G, },
12471203945Sweongyo		{ BWN_B2063_G_RX_SP10, 0xc, 0xc, FLAG_A | FLAG_G, },
12472203945Sweongyo		{ BWN_B2063_A_RX_SP1, 0x3c, 0x3f, FLAG_A, },
12473203945Sweongyo		{ BWN_B2063_A_RX_SP2, 0xfc, 0xfe, FLAG_A, },
12474203945Sweongyo		{ BWN_B2063_A_RX_SP7, 0x8, 0x8, FLAG_A | FLAG_G, },
12475203945Sweongyo		{ BWN_B2063_RX_BB_SP4, 0x60, 0x60, FLAG_A | FLAG_G, },
12476203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x30, 0x30, FLAG_A | FLAG_G, },
12477203945Sweongyo		{ BWN_B2063_TX_RF_SP3, 0xc, 0xb, FLAG_A | FLAG_G, },
12478203945Sweongyo		{ BWN_B2063_TX_RF_SP4, 0x10, 0xf, FLAG_A | FLAG_G, },
12479203945Sweongyo		{ BWN_B2063_PA_SP1, 0x3d, 0xfd, FLAG_A | FLAG_G, },
12480203945Sweongyo		{ BWN_B2063_TX_BB_SP1, 0x2, 0x2, FLAG_A | FLAG_G, },
12481203945Sweongyo		{ BWN_B2063_BANDGAP_CTL1, 0x56, 0x56, FLAG_A | FLAG_G, },
12482203945Sweongyo		{ BWN_B2063_JTAG_VCO2, 0xF7, 0xF7, FLAG_A | FLAG_G, },
12483203945Sweongyo		{ BWN_B2063_G_RX_MIX3, 0x71, 0x71, FLAG_A | FLAG_G, },
12484203945Sweongyo		{ BWN_B2063_G_RX_MIX4, 0x71, 0x71, FLAG_A | FLAG_G, },
12485203945Sweongyo		{ BWN_B2063_A_RX_1ST2, 0xf0, 0x30, FLAG_A, },
12486203945Sweongyo		{ BWN_B2063_A_RX_PS6, 0x77, 0x77, FLAG_A | FLAG_G, },
12487203945Sweongyo		{ BWN_B2063_A_RX_MIX4, 0x3, 0x3, FLAG_A | FLAG_G, },
12488203945Sweongyo		{ BWN_B2063_A_RX_MIX5, 0xf, 0xf, FLAG_A | FLAG_G, },
12489203945Sweongyo		{ BWN_B2063_A_RX_MIX6, 0xf, 0xf, FLAG_A | FLAG_G, },
12490203945Sweongyo		{ BWN_B2063_RX_TIA_CTL1, 0x77, 0x77, FLAG_A | FLAG_G, },
12491203945Sweongyo		{ BWN_B2063_RX_TIA_CTL3, 0x77, 0x77, FLAG_A | FLAG_G, },
12492203945Sweongyo		{ BWN_B2063_RX_BB_CTL2, 0x4, 0x4, FLAG_A | FLAG_G, },
12493203945Sweongyo		{ BWN_B2063_PA_CTL1, 0x0, 0x4, FLAG_A, },
12494203945Sweongyo		{ BWN_B2063_VREG_CTL1, 0x3, 0x3, FLAG_A | FLAG_G, },
12495203945Sweongyo	};
12496203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12497203945Sweongyo	unsigned int i;
12498203945Sweongyo
12499203945Sweongyo	for (i = 0; i < N(bwn_b2063_init_tab); i++) {
12500203945Sweongyo		br = &bwn_b2063_init_tab[i];
12501203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12502203945Sweongyo			if (br->br_flags & FLAG_G)
12503203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12504203945Sweongyo		} else {
12505203945Sweongyo			if (br->br_flags & FLAG_A)
12506203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12507203945Sweongyo		}
12508203945Sweongyo	}
12509203945Sweongyo#undef FLAG_A
12510203945Sweongyo#undef FLAG_B
12511203945Sweongyo}
12512203945Sweongyo
12513203945Sweongyostatic void
12514203945Sweongyobwn_tab_read_multi(struct bwn_mac *mac, uint32_t typenoffset,
12515203945Sweongyo    int count, void *_data)
12516203945Sweongyo{
12517203945Sweongyo	unsigned int i;
12518203945Sweongyo	uint32_t offset, type;
12519203945Sweongyo	uint8_t *data = _data;
12520203945Sweongyo
12521203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12522203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12523203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12524203945Sweongyo
12525203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12526203945Sweongyo
12527203945Sweongyo	for (i = 0; i < count; i++) {
12528203945Sweongyo		switch (type) {
12529203945Sweongyo		case BWN_TAB_8BIT:
12530203945Sweongyo			*data = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
12531203945Sweongyo			data++;
12532203945Sweongyo			break;
12533203945Sweongyo		case BWN_TAB_16BIT:
12534203945Sweongyo			*((uint16_t *)data) = BWN_PHY_READ(mac,
12535203945Sweongyo			    BWN_PHY_TABLEDATALO);
12536203945Sweongyo			data += 2;
12537203945Sweongyo			break;
12538203945Sweongyo		case BWN_TAB_32BIT:
12539203945Sweongyo			*((uint32_t *)data) = BWN_PHY_READ(mac,
12540203945Sweongyo			    BWN_PHY_TABLEDATAHI);
12541203945Sweongyo			*((uint32_t *)data) <<= 16;
12542203945Sweongyo			*((uint32_t *)data) |= BWN_PHY_READ(mac,
12543203945Sweongyo			    BWN_PHY_TABLEDATALO);
12544203945Sweongyo			data += 4;
12545203945Sweongyo			break;
12546203945Sweongyo		default:
12547203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12548203945Sweongyo		}
12549203945Sweongyo	}
12550203945Sweongyo}
12551203945Sweongyo
12552203945Sweongyostatic void
12553203945Sweongyobwn_tab_write_multi(struct bwn_mac *mac, uint32_t typenoffset,
12554203945Sweongyo    int count, const void *_data)
12555203945Sweongyo{
12556203945Sweongyo	uint32_t offset, type, value;
12557203945Sweongyo	const uint8_t *data = _data;
12558203945Sweongyo	unsigned int i;
12559203945Sweongyo
12560203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12561203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12562203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12563203945Sweongyo
12564203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12565203945Sweongyo
12566203945Sweongyo	for (i = 0; i < count; i++) {
12567203945Sweongyo		switch (type) {
12568203945Sweongyo		case BWN_TAB_8BIT:
12569203945Sweongyo			value = *data;
12570203945Sweongyo			data++;
12571203945Sweongyo			KASSERT(!(value & ~0xff),
12572203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12573203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12574203945Sweongyo			break;
12575203945Sweongyo		case BWN_TAB_16BIT:
12576203945Sweongyo			value = *((const uint16_t *)data);
12577203945Sweongyo			data += 2;
12578203945Sweongyo			KASSERT(!(value & ~0xffff),
12579203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12580203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12581203945Sweongyo			break;
12582203945Sweongyo		case BWN_TAB_32BIT:
12583203945Sweongyo			value = *((const uint32_t *)data);
12584203945Sweongyo			data += 4;
12585203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
12586203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12587203945Sweongyo			break;
12588203945Sweongyo		default:
12589203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12590203945Sweongyo		}
12591203945Sweongyo	}
12592203945Sweongyo}
12593203945Sweongyo
12594203945Sweongyostatic struct bwn_txgain
12595203945Sweongyobwn_phy_lp_get_txgain(struct bwn_mac *mac)
12596203945Sweongyo{
12597203945Sweongyo	struct bwn_txgain tg;
12598203945Sweongyo	uint16_t tmp;
12599203945Sweongyo
12600203945Sweongyo	tg.tg_dac = (BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0x380) >> 7;
12601203945Sweongyo	if (mac->mac_phy.rev < 2) {
12602203945Sweongyo		tmp = BWN_PHY_READ(mac,
12603203945Sweongyo		    BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7ff;
12604203945Sweongyo		tg.tg_gm = tmp & 0x0007;
12605203945Sweongyo		tg.tg_pga = (tmp & 0x0078) >> 3;
12606203945Sweongyo		tg.tg_pad = (tmp & 0x780) >> 7;
12607203945Sweongyo		return (tg);
12608203945Sweongyo	}
12609203945Sweongyo
12610203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL);
12611203945Sweongyo	tg.tg_pad = BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0xff;
12612203945Sweongyo	tg.tg_gm = tmp & 0xff;
12613203945Sweongyo	tg.tg_pga = (tmp >> 8) & 0xff;
12614203945Sweongyo	return (tg);
12615203945Sweongyo}
12616203945Sweongyo
12617203945Sweongyostatic uint8_t
12618203945Sweongyobwn_phy_lp_get_bbmult(struct bwn_mac *mac)
12619203945Sweongyo{
12620203945Sweongyo
12621203945Sweongyo	return (bwn_tab_read(mac, BWN_TAB_2(0, 87)) & 0xff00) >> 8;
12622203945Sweongyo}
12623203945Sweongyo
12624203945Sweongyostatic void
12625203945Sweongyobwn_phy_lp_set_txgain(struct bwn_mac *mac, struct bwn_txgain *tg)
12626203945Sweongyo{
12627203945Sweongyo	uint16_t pa;
12628203945Sweongyo
12629203945Sweongyo	if (mac->mac_phy.rev < 2) {
12630203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xf800,
12631203945Sweongyo		    (tg->tg_pad << 7) | (tg->tg_pga << 3) | tg->tg_gm);
12632203945Sweongyo		bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12633203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
12634203945Sweongyo		return;
12635203945Sweongyo	}
12636203945Sweongyo
12637203945Sweongyo	pa = bwn_phy_lp_get_pa_gain(mac);
12638203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
12639203945Sweongyo	    (tg->tg_pga << 8) | tg->tg_gm);
12640203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0x8000,
12641203945Sweongyo	    tg->tg_pad | (pa << 6));
12642203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xfc), (tg->tg_pga << 8) | tg->tg_gm);
12643203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x8000,
12644203945Sweongyo	    tg->tg_pad | (pa << 8));
12645203945Sweongyo	bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12646203945Sweongyo	bwn_phy_lp_set_txgain_override(mac);
12647203945Sweongyo}
12648203945Sweongyo
12649203945Sweongyostatic void
12650203945Sweongyobwn_phy_lp_set_bbmult(struct bwn_mac *mac, uint8_t bbmult)
12651203945Sweongyo{
12652203945Sweongyo
12653203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(0, 87), (uint16_t)bbmult << 8);
12654203945Sweongyo}
12655203945Sweongyo
12656203945Sweongyostatic void
12657203945Sweongyobwn_phy_lp_set_trsw_over(struct bwn_mac *mac, uint8_t tx, uint8_t rx)
12658203945Sweongyo{
12659203945Sweongyo	uint16_t trsw = (tx << 1) | rx;
12660203945Sweongyo
12661203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffc, trsw);
12662203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x3);
12663203945Sweongyo}
12664203945Sweongyo
12665203945Sweongyostatic void
12666203945Sweongyobwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain)
12667203945Sweongyo{
12668203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12669203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12670203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12671203945Sweongyo	uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp;
12672203945Sweongyo
12673203945Sweongyo	if (mac->mac_phy.rev < 2) {
12674203945Sweongyo		trsw = gain & 0x1;
12675203945Sweongyo		lna = (gain & 0xfffc) | ((gain & 0xc) >> 2);
12676203945Sweongyo		ext_lna = (gain & 2) >> 1;
12677203945Sweongyo
12678203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12679203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12680203945Sweongyo		    0xfbff, ext_lna << 10);
12681203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12682203945Sweongyo		    0xf7ff, ext_lna << 11);
12683203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
12684203945Sweongyo	} else {
12685203945Sweongyo		low_gain = gain & 0xffff;
12686203945Sweongyo		high_gain = (gain >> 16) & 0xf;
12687203945Sweongyo		ext_lna = (gain >> 21) & 0x1;
12688203945Sweongyo		trsw = ~(gain >> 20) & 0x1;
12689203945Sweongyo
12690203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12691203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12692203945Sweongyo		    0xfdff, ext_lna << 9);
12693203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12694203945Sweongyo		    0xfbff, ext_lna << 10);
12695203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
12696203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff0, high_gain);
12697203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12698203945Sweongyo			tmp = (gain >> 2) & 0x3;
12699203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12700203945Sweongyo			    0xe7ff, tmp<<11);
12701203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe6), 0xffe7,
12702203945Sweongyo			    tmp << 3);
12703203945Sweongyo		}
12704203945Sweongyo	}
12705203945Sweongyo
12706203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1);
12707203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12708203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12709203945Sweongyo	if (mac->mac_phy.rev >= 2) {
12710203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
12711203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12712203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x400);
12713203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xe5), 0x8);
12714203945Sweongyo		}
12715203945Sweongyo		return;
12716203945Sweongyo	}
12717203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x200);
12718203945Sweongyo}
12719203945Sweongyo
12720203945Sweongyostatic void
12721203945Sweongyobwn_phy_lp_set_deaf(struct bwn_mac *mac, uint8_t user)
12722203945Sweongyo{
12723203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12724203945Sweongyo
12725203945Sweongyo	if (user)
12726203945Sweongyo		plp->plp_crsusr_off = 1;
12727203945Sweongyo	else
12728203945Sweongyo		plp->plp_crssys_off = 1;
12729203945Sweongyo
12730203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x80);
12731203945Sweongyo}
12732203945Sweongyo
12733203945Sweongyostatic void
12734203945Sweongyobwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
12735203945Sweongyo{
12736203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12737203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12738203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12739203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12740203945Sweongyo
12741203945Sweongyo	if (user)
12742203945Sweongyo		plp->plp_crsusr_off = 0;
12743203945Sweongyo	else
12744203945Sweongyo		plp->plp_crssys_off = 0;
12745203945Sweongyo
12746203945Sweongyo	if (plp->plp_crsusr_off || plp->plp_crssys_off)
12747203945Sweongyo		return;
12748203945Sweongyo
12749203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12750203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x60);
12751203945Sweongyo	else
12752203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x20);
12753203945Sweongyo}
12754203945Sweongyo
12755203945Sweongyostatic unsigned int
12756203945Sweongyobwn_sqrt(struct bwn_mac *mac, unsigned int x)
12757203945Sweongyo{
12758203945Sweongyo	/* Table holding (10 * sqrt(x)) for x between 1 and 256. */
12759203945Sweongyo	static uint8_t sqrt_table[256] = {
12760203945Sweongyo		10, 14, 17, 20, 22, 24, 26, 28,
12761203945Sweongyo		30, 31, 33, 34, 36, 37, 38, 40,
12762203945Sweongyo		41, 42, 43, 44, 45, 46, 47, 48,
12763203945Sweongyo		50, 50, 51, 52, 53, 54, 55, 56,
12764203945Sweongyo		57, 58, 59, 60, 60, 61, 62, 63,
12765203945Sweongyo		64, 64, 65, 66, 67, 67, 68, 69,
12766203945Sweongyo		70, 70, 71, 72, 72, 73, 74, 74,
12767203945Sweongyo		75, 76, 76, 77, 78, 78, 79, 80,
12768203945Sweongyo		80, 81, 81, 82, 83, 83, 84, 84,
12769203945Sweongyo		85, 86, 86, 87, 87, 88, 88, 89,
12770203945Sweongyo		90, 90, 91, 91, 92, 92, 93, 93,
12771203945Sweongyo		94, 94, 95, 95, 96, 96, 97, 97,
12772203945Sweongyo		98, 98, 99, 100, 100, 100, 101, 101,
12773203945Sweongyo		102, 102, 103, 103, 104, 104, 105, 105,
12774203945Sweongyo		106, 106, 107, 107, 108, 108, 109, 109,
12775203945Sweongyo		110, 110, 110, 111, 111, 112, 112, 113,
12776203945Sweongyo		113, 114, 114, 114, 115, 115, 116, 116,
12777203945Sweongyo		117, 117, 117, 118, 118, 119, 119, 120,
12778203945Sweongyo		120, 120, 121, 121, 122, 122, 122, 123,
12779203945Sweongyo		123, 124, 124, 124, 125, 125, 126, 126,
12780203945Sweongyo		126, 127, 127, 128, 128, 128, 129, 129,
12781203945Sweongyo		130, 130, 130, 131, 131, 131, 132, 132,
12782203945Sweongyo		133, 133, 133, 134, 134, 134, 135, 135,
12783203945Sweongyo		136, 136, 136, 137, 137, 137, 138, 138,
12784203945Sweongyo		138, 139, 139, 140, 140, 140, 141, 141,
12785203945Sweongyo		141, 142, 142, 142, 143, 143, 143, 144,
12786203945Sweongyo		144, 144, 145, 145, 145, 146, 146, 146,
12787203945Sweongyo		147, 147, 147, 148, 148, 148, 149, 149,
12788203945Sweongyo		150, 150, 150, 150, 151, 151, 151, 152,
12789203945Sweongyo		152, 152, 153, 153, 153, 154, 154, 154,
12790203945Sweongyo		155, 155, 155, 156, 156, 156, 157, 157,
12791203945Sweongyo		157, 158, 158, 158, 159, 159, 159, 160
12792203945Sweongyo	};
12793203945Sweongyo
12794203945Sweongyo	if (x == 0)
12795203945Sweongyo		return (0);
12796203945Sweongyo	if (x >= 256) {
12797204542Sweongyo		unsigned int tmp;
12798204542Sweongyo
12799204542Sweongyo		for (tmp = 0; x >= (2 * tmp) + 1; x -= (2 * tmp++) + 1)
12800204542Sweongyo			/* do nothing */ ;
12801204542Sweongyo		return (tmp);
12802203945Sweongyo	}
12803203945Sweongyo	return (sqrt_table[x - 1] / 10);
12804203945Sweongyo}
12805203945Sweongyo
12806203945Sweongyostatic int
12807203945Sweongyobwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *mac, uint16_t sample)
12808203945Sweongyo{
12809203945Sweongyo#define	CALC_COEFF(_v, _x, _y, _z)	do {				\
12810203945Sweongyo	int _t;								\
12811203945Sweongyo	_t = _x - 20;							\
12812203945Sweongyo	if (_t >= 0) {							\
12813203945Sweongyo		_v = ((_y << (30 - _x)) + (_z >> (1 + _t))) / (_z >> _t); \
12814203945Sweongyo	} else {							\
12815203945Sweongyo		_v = ((_y << (30 - _x)) + (_z << (-1 - _t))) / (_z << -_t); \
12816203945Sweongyo	}								\
12817203945Sweongyo} while (0)
12818203945Sweongyo#define	CALC_COEFF2(_v, _x, _y, _z)	do {				\
12819203945Sweongyo	int _t;								\
12820203945Sweongyo	_t = _x - 11;							\
12821203945Sweongyo	if (_t >= 0)							\
12822210393Sweongyo		_v = (_y << (31 - _x)) / (_z >> _t);			\
12823203945Sweongyo	else								\
12824210393Sweongyo		_v = (_y << (31 - _x)) / (_z << -_t);			\
12825203945Sweongyo} while (0)
12826203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12827203945Sweongyo	uint16_t v0, v1;
12828203945Sweongyo	int tmp[2], ret;
12829203945Sweongyo
12830203945Sweongyo	v1 = BWN_PHY_READ(mac, BWN_PHY_RX_COMP_COEFF_S);
12831203945Sweongyo	v0 = v1 >> 8;
12832203945Sweongyo	v1 |= 0xff;
12833203945Sweongyo
12834203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, 0x00c0);
12835203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff);
12836203945Sweongyo
12837203945Sweongyo	ret = bwn_phy_lp_rx_iq_est(mac, sample, 32, &ie);
12838203945Sweongyo	if (ret == 0)
12839203945Sweongyo		goto done;
12840203945Sweongyo
12841203945Sweongyo	if (ie.ie_ipwr + ie.ie_qpwr < 2) {
12842203945Sweongyo		ret = 0;
12843203945Sweongyo		goto done;
12844203945Sweongyo	}
12845203945Sweongyo
12846203945Sweongyo	CALC_COEFF(tmp[0], bwn_nbits(ie.ie_iqprod), ie.ie_iqprod, ie.ie_ipwr);
12847203945Sweongyo	CALC_COEFF2(tmp[1], bwn_nbits(ie.ie_qpwr), ie.ie_qpwr, ie.ie_ipwr);
12848203945Sweongyo
12849203945Sweongyo	tmp[1] = -bwn_sqrt(mac, tmp[1] - (tmp[0] * tmp[0]));
12850203945Sweongyo	v0 = tmp[0] >> 3;
12851203945Sweongyo	v1 = tmp[1] >> 4;
12852203945Sweongyodone:
12853203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, v1);
12854203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, v0 << 8);
12855203945Sweongyo	return ret;
12856203945Sweongyo#undef CALC_COEFF
12857203945Sweongyo#undef CALC_COEFF2
12858203945Sweongyo}
12859203945Sweongyo
12860203945Sweongyostatic void
12861203945Sweongyobwn_phy_lp_tblinit_r01(struct bwn_mac *mac)
12862203945Sweongyo{
12863203945Sweongyo	static const uint16_t noisescale[] = {
12864203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12865203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4,
12866203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12867203945Sweongyo		0xa4a4, 0xa4a4, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12868203945Sweongyo		0x0000, 0x0000, 0x4c00, 0x2d36, 0x0000, 0x0000, 0x4c00, 0x2d36,
12869203945Sweongyo	};
12870203945Sweongyo	static const uint16_t crsgainnft[] = {
12871203945Sweongyo		0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f,
12872203945Sweongyo		0x036f, 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381,
12873203945Sweongyo		0x0374, 0x0381, 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f,
12874203945Sweongyo		0x0040, 0x005e, 0x007f, 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d,
12875203945Sweongyo		0x013d,
12876203945Sweongyo	};
12877203945Sweongyo	static const uint16_t filterctl[] = {
12878203945Sweongyo		0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077,
12879203945Sweongyo		0xff53, 0x0127,
12880203945Sweongyo	};
12881203945Sweongyo	static const uint32_t psctl[] = {
12882203945Sweongyo		0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101,
12883203945Sweongyo		0x00000080, 0x08080101, 0x00000040, 0x08080101, 0x000000c0,
12884203945Sweongyo		0x08a81501, 0x000000c0, 0x0fe8fd01, 0x000000c0, 0x08300105,
12885203945Sweongyo		0x000000c0, 0x08080201, 0x000000c0, 0x08280205, 0x000000c0,
12886203945Sweongyo		0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, 0x08080202,
12887203945Sweongyo		0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
12888203945Sweongyo		0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106,
12889203945Sweongyo		0x000000c0, 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
12890203945Sweongyo	};
12891203945Sweongyo	static const uint16_t ofdmcckgain_r0[] = {
12892203945Sweongyo		0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12893203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12894203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12895203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12896203945Sweongyo		0x755d,
12897203945Sweongyo	};
12898203945Sweongyo	static const uint16_t ofdmcckgain_r1[] = {
12899203945Sweongyo		0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12900203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12901203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12902203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12903203945Sweongyo		0x755d,
12904203945Sweongyo	};
12905203945Sweongyo	static const uint16_t gaindelta[] = {
12906203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12907203945Sweongyo		0x0000,
12908203945Sweongyo	};
12909203945Sweongyo	static const uint32_t txpwrctl[] = {
12910203945Sweongyo		0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c,
12911203945Sweongyo		0x0000004b, 0x0000004a, 0x00000049, 0x00000048, 0x00000047,
12912203945Sweongyo		0x00000046, 0x00000045, 0x00000044, 0x00000043, 0x00000042,
12913203945Sweongyo		0x00000041, 0x00000040, 0x0000003f, 0x0000003e, 0x0000003d,
12914203945Sweongyo		0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, 0x00000038,
12915203945Sweongyo		0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
12916203945Sweongyo		0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e,
12917203945Sweongyo		0x0000002d, 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029,
12918203945Sweongyo		0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
12919203945Sweongyo		0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001f,
12920203945Sweongyo		0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001a,
12921203945Sweongyo		0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
12922203945Sweongyo		0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000,
12923203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12924203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12925203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12926203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12927203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12928203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12929203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12930203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12931203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12932203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12933203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12934203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12935203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12936203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12937203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12938203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12939203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12940203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12941203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12942203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12943203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12944203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12945203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12946203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12947203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12948203945Sweongyo		0x00000000, 0x00000000, 0x000075a0, 0x000075a0, 0x000075a1,
12949203945Sweongyo		0x000075a1, 0x000075a2, 0x000075a2, 0x000075a3, 0x000075a3,
12950203945Sweongyo		0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, 0x000074b2,
12951203945Sweongyo		0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
12952203945Sweongyo		0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23,
12953203945Sweongyo		0x00006d23, 0x00004660, 0x00004660, 0x00004661, 0x00004661,
12954203945Sweongyo		0x00004662, 0x00004662, 0x00004663, 0x00004663, 0x00003e60,
12955203945Sweongyo		0x00003e60, 0x00003e61, 0x00003e61, 0x00003e62, 0x00003e62,
12956203945Sweongyo		0x00003e63, 0x00003e63, 0x00003660, 0x00003660, 0x00003661,
12957203945Sweongyo		0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
12958203945Sweongyo		0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62,
12959203945Sweongyo		0x00002e62, 0x00002e63, 0x00002e63, 0x00002660, 0x00002660,
12960203945Sweongyo		0x00002661, 0x00002661, 0x00002662, 0x00002662, 0x00002663,
12961203945Sweongyo		0x00002663, 0x000025e0, 0x000025e0, 0x000025e1, 0x000025e1,
12962203945Sweongyo		0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, 0x00001de0,
12963203945Sweongyo		0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
12964203945Sweongyo		0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61,
12965203945Sweongyo		0x00001d61, 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63,
12966203945Sweongyo		0x00001560, 0x00001560, 0x00001561, 0x00001561, 0x00001562,
12967203945Sweongyo		0x00001562, 0x00001563, 0x00001563, 0x00000d60, 0x00000d60,
12968203945Sweongyo		0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, 0x00000d63,
12969203945Sweongyo		0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
12970203945Sweongyo		0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10,
12971203945Sweongyo		0x00000e10, 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12,
12972203945Sweongyo		0x00000e13, 0x00000e13, 0x00000bf0, 0x00000bf0, 0x00000bf1,
12973203945Sweongyo		0x00000bf1, 0x00000bf2, 0x00000bf2, 0x00000bf3, 0x00000bf3,
12974203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12975203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12976203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12977203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12978203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12979203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12980203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12981203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12982203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12983203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12984203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12985203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12986203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12987203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12988203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12989203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12990203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12991203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12992203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12993203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12994203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12995203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12996203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12997203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12998203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12999203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc,
13000203945Sweongyo		0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04,
13001203945Sweongyo		0x0000fcff, 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006,
13002203945Sweongyo		0x0000ff03, 0x000007fc, 0x0000fc08, 0x00000203, 0x0000fffb,
13003203945Sweongyo		0x00000600, 0x0000fa01, 0x0000fc03, 0x0000fe06, 0x0000fe00,
13004203945Sweongyo		0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, 0x000004fd,
13005203945Sweongyo		0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
13006203945Sweongyo		0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa,
13007203945Sweongyo		0x00000700, 0x00000305, 0x000004ff, 0x00000801, 0x00000503,
13008203945Sweongyo		0x000005f9, 0x00000404, 0x0000fb08, 0x000005fd, 0x00000501,
13009203945Sweongyo		0x00000405, 0x0000fb03, 0x000007fc, 0x00000403, 0x00000303,
13010203945Sweongyo		0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, 0x0000fe01,
13011203945Sweongyo		0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
13012203945Sweongyo		0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa,
13013203945Sweongyo		0x000003fe, 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06,
13014203945Sweongyo		0x000008fc, 0x00000701, 0x00000504, 0x0000fdfe, 0x0000fdfc,
13015203945Sweongyo		0x000003fe, 0x00000704, 0x000002fc, 0x000004f9, 0x0000fdfd,
13016203945Sweongyo		0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, 0x000004f9,
13017203945Sweongyo		0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
13018203945Sweongyo		0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa,
13019203945Sweongyo		0x00000305, 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc,
13020203945Sweongyo		0x0000fe03, 0x00000701, 0x000001fb, 0x000001f9, 0x00000206,
13021203945Sweongyo		0x000006fd, 0x00000508, 0x00000700, 0x00000304, 0x000005fe,
13022203945Sweongyo		0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, 0x000007f9,
13023203945Sweongyo		0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
13024203945Sweongyo		0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb,
13025203945Sweongyo		0x00000702,
13026203945Sweongyo	};
13027203945Sweongyo
13028203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13029203945Sweongyo
13030203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13031203945Sweongyo	    bwn_tab_sigsq_tbl);
13032203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13033203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(crsgainnft), crsgainnft);
13034203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(8, 0), N(filterctl), filterctl);
13035203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(psctl), psctl);
13036203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13037203945Sweongyo	    bwn_tab_pllfrac_tbl);
13038203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13039203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13040203945Sweongyo	if (mac->mac_phy.rev == 0) {
13041203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r0),
13042203945Sweongyo		    ofdmcckgain_r0);
13043203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r0),
13044203945Sweongyo		    ofdmcckgain_r0);
13045203945Sweongyo	} else {
13046203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r1),
13047203945Sweongyo		    ofdmcckgain_r1);
13048203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r1),
13049203945Sweongyo		    ofdmcckgain_r1);
13050203945Sweongyo	}
13051203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(gaindelta), gaindelta);
13052203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(txpwrctl), txpwrctl);
13053203945Sweongyo}
13054203945Sweongyo
13055203945Sweongyostatic void
13056203945Sweongyobwn_phy_lp_tblinit_r2(struct bwn_mac *mac)
13057203945Sweongyo{
13058204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13059203945Sweongyo	int i;
13060203945Sweongyo	static const uint16_t noisescale[] = {
13061203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13062203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13063203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13064203945Sweongyo		0x00a4, 0x00a4, 0x0000, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13065203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13066203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13067203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4
13068203945Sweongyo	};
13069203945Sweongyo	static const uint32_t filterctl[] = {
13070203945Sweongyo		0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27,
13071203945Sweongyo		0x0000217f, 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f
13072203945Sweongyo	};
13073203945Sweongyo	static const uint32_t psctl[] = {
13074203945Sweongyo		0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000,
13075203945Sweongyo		0x00002080, 0x00006180, 0x00003002, 0x00000040, 0x00002042,
13076203945Sweongyo		0x00180047, 0x00080043, 0x00000041, 0x000020c1, 0x00046006,
13077203945Sweongyo		0x00042002, 0x00040000, 0x00002003, 0x00180006, 0x00080002
13078203945Sweongyo	};
13079203945Sweongyo	static const uint32_t gainidx[] = {
13080203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13081203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13082203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13083203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x10000001, 0x00000000,
13084203945Sweongyo		0x20000082, 0x00000000, 0x40000104, 0x00000000, 0x60004207,
13085203945Sweongyo		0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
13086203945Sweongyo		0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288,
13087203945Sweongyo		0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
13088203945Sweongyo		0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794,
13089203945Sweongyo		0x00000010, 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011,
13090203945Sweongyo		0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21,
13091203945Sweongyo		0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
13092203945Sweongyo		0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329,
13093203945Sweongyo		0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
13094203945Sweongyo		0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, 0x00000000,
13095203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13096203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13097203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13098203945Sweongyo		0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082,
13099203945Sweongyo		0x00000000, 0x40000104, 0x00000000, 0x60004207, 0x00000001,
13100203945Sweongyo		0x7000838a, 0x00000001, 0xd021050d, 0x00000001, 0xe041c683,
13101203945Sweongyo		0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
13102203945Sweongyo		0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711,
13103203945Sweongyo		0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
13104203945Sweongyo		0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c,
13105203945Sweongyo		0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019,
13106203945Sweongyo		0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, 0xb36811a6,
13107203945Sweongyo		0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
13108203945Sweongyo		0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c,
13109203945Sweongyo		0x0000001a, 0x64ca55ad, 0x0000001a
13110203945Sweongyo	};
13111203945Sweongyo	static const uint16_t auxgainidx[] = {
13112203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13113203945Sweongyo		0x0000, 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000,
13114203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002,
13115203945Sweongyo		0x0004, 0x0016
13116203945Sweongyo	};
13117203945Sweongyo	static const uint16_t swctl[] = {
13118203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13119203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13120203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13121203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
13122203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13123203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13124203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13125203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018
13126203945Sweongyo	};
13127203945Sweongyo	static const uint8_t hf[] = {
13128203945Sweongyo		0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
13129203945Sweongyo		0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17
13130203945Sweongyo	};
13131203945Sweongyo	static const uint32_t gainval[] = {
13132203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13133203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13134203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13135203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13136203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13137203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13138203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13139203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13140203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13141203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13142203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13143203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13144203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009,
13145203945Sweongyo		0x000000f1, 0x00000000, 0x00000000
13146203945Sweongyo	};
13147203945Sweongyo	static const uint16_t gain[] = {
13148203945Sweongyo		0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808,
13149203945Sweongyo		0x080a, 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813,
13150203945Sweongyo		0x0814, 0x0816, 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824,
13151203945Sweongyo		0x0830, 0x0834, 0x0837, 0x083b, 0x083f, 0x0840, 0x0844, 0x0857,
13152203945Sweongyo		0x085b, 0x085f, 0x08d7, 0x08db, 0x08df, 0x0957, 0x095b, 0x095f,
13153203945Sweongyo		0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, 0x175f, 0x0000, 0x0000,
13154203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13155203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13156203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13157203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13158203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13159203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13160203945Sweongyo	};
13161203945Sweongyo	static const uint32_t papdeps[] = {
13162203945Sweongyo		0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9,
13163203945Sweongyo		0x00021fdf, 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7,
13164203945Sweongyo		0x0004efc2, 0x00055fb5, 0x0005cfb0, 0x00063fa8, 0x00068fa3,
13165203945Sweongyo		0x00071f98, 0x0007ef92, 0x00084f8b, 0x0008df82, 0x00097f77,
13166203945Sweongyo		0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, 0x000bff41,
13167203945Sweongyo		0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
13168203945Sweongyo		0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15,
13169203945Sweongyo		0x00143f1c, 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f,
13170203945Sweongyo		0x001e6f7e, 0x0021cfa4, 0x0025bfd2, 0x002a2008, 0x002fb047,
13171203945Sweongyo		0x00360090, 0x003d40e0, 0x0045c135, 0x004fb189, 0x005ae1d7,
13172203945Sweongyo		0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, 0x007ff2e3,
13173203945Sweongyo		0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
13174203945Sweongyo		0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506
13175203945Sweongyo	};
13176203945Sweongyo	static const uint32_t papdmult[] = {
13177203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13178203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13179203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13180203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13181203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13182203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13183203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13184203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13185203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13186203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13187203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13188203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13189203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13190203945Sweongyo	};
13191203945Sweongyo	static const uint32_t gainidx_a0[] = {
13192203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13193203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13194203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13195203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13196203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13197203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13198203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13199203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13200203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13201203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13202203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13203203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13204203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13205203945Sweongyo	};
13206203945Sweongyo	static const uint16_t auxgainidx_a0[] = {
13207203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13208203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000,
13209203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13210203945Sweongyo		0x0002, 0x0014
13211203945Sweongyo	};
13212203945Sweongyo	static const uint32_t gainval_a0[] = {
13213203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13214203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13215203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13216203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13217203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13218203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13219203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13220203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13221203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13222203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13223203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13224203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13225203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f,
13226203945Sweongyo		0x000000f7, 0x00000000, 0x00000000
13227203945Sweongyo	};
13228203945Sweongyo	static const uint16_t gain_a0[] = {
13229203945Sweongyo		0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b,
13230203945Sweongyo		0x000c, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016,
13231203945Sweongyo		0x0017, 0x001a, 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034,
13232203945Sweongyo		0x0037, 0x003b, 0x003f, 0x0040, 0x0044, 0x0057, 0x005b, 0x005f,
13233203945Sweongyo		0x00d7, 0x00db, 0x00df, 0x0157, 0x015b, 0x015f, 0x0357, 0x035b,
13234203945Sweongyo		0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, 0x0000, 0x0000, 0x0000,
13235203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13236203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13237203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13238203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13239203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13240203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13241203945Sweongyo	};
13242203945Sweongyo
13243203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13244203945Sweongyo
13245203945Sweongyo	for (i = 0; i < 704; i++)
13246203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(7, i), 0);
13247203945Sweongyo
13248203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13249203945Sweongyo	    bwn_tab_sigsq_tbl);
13250203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13251203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(11, 0), N(filterctl), filterctl);
13252203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(12, 0), N(psctl), psctl);
13253203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx), gainidx);
13254203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx), auxgainidx);
13255203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(swctl), swctl);
13256203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(16, 0), N(hf), hf);
13257203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval), gainval);
13258203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain), gain);
13259203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13260203945Sweongyo	    bwn_tab_pllfrac_tbl);
13261203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13262203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13263203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(papdeps), papdeps);
13264203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(papdmult), papdmult);
13265203945Sweongyo
13266204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
13267204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
13268203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx_a0),
13269203945Sweongyo		    gainidx_a0);
13270203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx_a0),
13271203945Sweongyo		    auxgainidx_a0);
13272203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval_a0),
13273203945Sweongyo		    gainval_a0);
13274203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain_a0), gain_a0);
13275203945Sweongyo	}
13276203945Sweongyo}
13277203945Sweongyo
13278203945Sweongyostatic void
13279203945Sweongyobwn_phy_lp_tblinit_txgain(struct bwn_mac *mac)
13280203945Sweongyo{
13281203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13282203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
13283203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
13284203945Sweongyo	static struct bwn_txgain_entry txgain_r2[] = {
13285203945Sweongyo		{ 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 },
13286203945Sweongyo		{ 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 },
13287203945Sweongyo		{ 255, 255, 203, 0, 135 }, { 255, 255, 203, 0, 131 },
13288203945Sweongyo		{ 255, 255, 203, 0, 128 }, { 255, 255, 203, 0, 124 },
13289203945Sweongyo		{ 255, 255, 203, 0, 121 }, { 255, 255, 203, 0, 117 },
13290203945Sweongyo		{ 255, 255, 203, 0, 114 }, { 255, 255, 203, 0, 111 },
13291203945Sweongyo		{ 255, 255, 203, 0, 107 }, { 255, 255, 203, 0, 104 },
13292203945Sweongyo		{ 255, 255, 203, 0, 101 }, { 255, 255, 203, 0, 99 },
13293203945Sweongyo		{ 255, 255, 203, 0, 96 }, { 255, 255, 203, 0, 93 },
13294203945Sweongyo		{ 255, 255, 203, 0, 90 }, { 255, 255, 203, 0, 88 },
13295203945Sweongyo		{ 255, 255, 203, 0, 85 }, { 255, 255, 203, 0, 83 },
13296203945Sweongyo		{ 255, 255, 203, 0, 81 }, { 255, 255, 203, 0, 78 },
13297203945Sweongyo		{ 255, 255, 203, 0, 76 }, { 255, 255, 203, 0, 74 },
13298203945Sweongyo		{ 255, 255, 203, 0, 72 }, { 255, 255, 203, 0, 70 },
13299203945Sweongyo		{ 255, 255, 203, 0, 68 }, { 255, 255, 203, 0, 66 },
13300203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13301203945Sweongyo		{ 255, 255, 192, 0, 64 }, { 255, 255, 186, 0, 64 },
13302203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 176, 0, 64 },
13303203945Sweongyo		{ 255, 255, 171, 0, 64 }, { 255, 255, 166, 0, 64 },
13304203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 157, 0, 64 },
13305203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13306203945Sweongyo		{ 255, 255, 144, 0, 64 }, { 255, 255, 140, 0, 64 },
13307203945Sweongyo		{ 255, 255, 136, 0, 64 }, { 255, 255, 132, 0, 64 },
13308203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13309203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13310203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13311203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 105, 0, 64 },
13312203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13313203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13314203945Sweongyo		{ 255, 255, 91, 0, 64 }, { 255, 255, 88, 0, 64 },
13315203945Sweongyo		{ 255, 255, 86, 0, 64 }, { 255, 255, 83, 0, 64 },
13316203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 79, 0, 64 },
13317203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13318203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13319203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13320203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 248, 64, 0, 64 },
13321203945Sweongyo		{ 255, 248, 62, 0, 64 }, { 255, 241, 62, 0, 64 },
13322203945Sweongyo		{ 255, 241, 60, 0, 64 }, { 255, 234, 60, 0, 64 },
13323203945Sweongyo		{ 255, 234, 59, 0, 64 }, { 255, 227, 59, 0, 64 },
13324203945Sweongyo		{ 255, 227, 57, 0, 64 }, { 255, 221, 57, 0, 64 },
13325203945Sweongyo		{ 255, 221, 55, 0, 64 }, { 255, 215, 55, 0, 64 },
13326203945Sweongyo		{ 255, 215, 54, 0, 64 }, { 255, 208, 54, 0, 64 },
13327203945Sweongyo		{ 255, 208, 52, 0, 64 }, { 255, 203, 52, 0, 64 },
13328203945Sweongyo		{ 255, 203, 51, 0, 64 }, { 255, 197, 51, 0, 64 },
13329203945Sweongyo		{ 255, 197, 49, 0, 64 }, { 255, 191, 49, 0, 64 },
13330203945Sweongyo		{ 255, 191, 48, 0, 64 }, { 255, 186, 48, 0, 64 },
13331203945Sweongyo		{ 255, 186, 47, 0, 64 }, { 255, 181, 47, 0, 64 },
13332203945Sweongyo		{ 255, 181, 45, 0, 64 }, { 255, 175, 45, 0, 64 },
13333203945Sweongyo		{ 255, 175, 44, 0, 64 }, { 255, 170, 44, 0, 64 },
13334203945Sweongyo		{ 255, 170, 43, 0, 64 }, { 255, 166, 43, 0, 64 },
13335203945Sweongyo		{ 255, 166, 42, 0, 64 }, { 255, 161, 42, 0, 64 },
13336203945Sweongyo		{ 255, 161, 40, 0, 64 }, { 255, 156, 40, 0, 64 },
13337203945Sweongyo		{ 255, 156, 39, 0, 64 }, { 255, 152, 39, 0, 64 },
13338203945Sweongyo		{ 255, 152, 38, 0, 64 }, { 255, 148, 38, 0, 64 },
13339203945Sweongyo		{ 255, 148, 37, 0, 64 }, { 255, 143, 37, 0, 64 },
13340203945Sweongyo		{ 255, 143, 36, 0, 64 }, { 255, 139, 36, 0, 64 },
13341203945Sweongyo		{ 255, 139, 35, 0, 64 }, { 255, 135, 35, 0, 64 },
13342203945Sweongyo		{ 255, 135, 34, 0, 64 }, { 255, 132, 34, 0, 64 },
13343203945Sweongyo		{ 255, 132, 33, 0, 64 }, { 255, 128, 33, 0, 64 },
13344203945Sweongyo		{ 255, 128, 32, 0, 64 }, { 255, 124, 32, 0, 64 },
13345203945Sweongyo		{ 255, 124, 31, 0, 64 }, { 255, 121, 31, 0, 64 },
13346203945Sweongyo		{ 255, 121, 30, 0, 64 }, { 255, 117, 30, 0, 64 },
13347203945Sweongyo		{ 255, 117, 29, 0, 64 }, { 255, 114, 29, 0, 64 },
13348203945Sweongyo		{ 255, 114, 29, 0, 64 }, { 255, 111, 29, 0, 64 },
13349203945Sweongyo	};
13350203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r2[] = {
13351203945Sweongyo		{ 7, 99, 255, 0, 64 }, { 7, 96, 255, 0, 64 },
13352203945Sweongyo		{ 7, 93, 255, 0, 64 }, { 7, 90, 255, 0, 64 },
13353203945Sweongyo		{ 7, 88, 255, 0, 64 }, { 7, 85, 255, 0, 64 },
13354203945Sweongyo		{ 7, 83, 255, 0, 64 }, { 7, 81, 255, 0, 64 },
13355203945Sweongyo		{ 7, 78, 255, 0, 64 }, { 7, 76, 255, 0, 64 },
13356203945Sweongyo		{ 7, 74, 255, 0, 64 }, { 7, 72, 255, 0, 64 },
13357203945Sweongyo		{ 7, 70, 255, 0, 64 }, { 7, 68, 255, 0, 64 },
13358203945Sweongyo		{ 7, 66, 255, 0, 64 }, { 7, 64, 255, 0, 64 },
13359203945Sweongyo		{ 7, 64, 255, 0, 64 }, { 7, 62, 255, 0, 64 },
13360203945Sweongyo		{ 7, 62, 248, 0, 64 }, { 7, 60, 248, 0, 64 },
13361203945Sweongyo		{ 7, 60, 241, 0, 64 }, { 7, 59, 241, 0, 64 },
13362203945Sweongyo		{ 7, 59, 234, 0, 64 }, { 7, 57, 234, 0, 64 },
13363203945Sweongyo		{ 7, 57, 227, 0, 64 }, { 7, 55, 227, 0, 64 },
13364203945Sweongyo		{ 7, 55, 221, 0, 64 }, { 7, 54, 221, 0, 64 },
13365203945Sweongyo		{ 7, 54, 215, 0, 64 }, { 7, 52, 215, 0, 64 },
13366203945Sweongyo		{ 7, 52, 208, 0, 64 }, { 7, 51, 208, 0, 64 },
13367203945Sweongyo		{ 7, 51, 203, 0, 64 }, { 7, 49, 203, 0, 64 },
13368203945Sweongyo		{ 7, 49, 197, 0, 64 }, { 7, 48, 197, 0, 64 },
13369203945Sweongyo		{ 7, 48, 191, 0, 64 }, { 7, 47, 191, 0, 64 },
13370203945Sweongyo		{ 7, 47, 186, 0, 64 }, { 7, 45, 186, 0, 64 },
13371203945Sweongyo		{ 7, 45, 181, 0, 64 }, { 7, 44, 181, 0, 64 },
13372203945Sweongyo		{ 7, 44, 175, 0, 64 }, { 7, 43, 175, 0, 64 },
13373203945Sweongyo		{ 7, 43, 170, 0, 64 }, { 7, 42, 170, 0, 64 },
13374203945Sweongyo		{ 7, 42, 166, 0, 64 }, { 7, 40, 166, 0, 64 },
13375203945Sweongyo		{ 7, 40, 161, 0, 64 }, { 7, 39, 161, 0, 64 },
13376203945Sweongyo		{ 7, 39, 156, 0, 64 }, { 7, 38, 156, 0, 64 },
13377203945Sweongyo		{ 7, 38, 152, 0, 64 }, { 7, 37, 152, 0, 64 },
13378203945Sweongyo		{ 7, 37, 148, 0, 64 }, { 7, 36, 148, 0, 64 },
13379203945Sweongyo		{ 7, 36, 143, 0, 64 }, { 7, 35, 143, 0, 64 },
13380203945Sweongyo		{ 7, 35, 139, 0, 64 }, { 7, 34, 139, 0, 64 },
13381203945Sweongyo		{ 7, 34, 135, 0, 64 }, { 7, 33, 135, 0, 64 },
13382203945Sweongyo		{ 7, 33, 132, 0, 64 }, { 7, 32, 132, 0, 64 },
13383203945Sweongyo		{ 7, 32, 128, 0, 64 }, { 7, 31, 128, 0, 64 },
13384203945Sweongyo		{ 7, 31, 124, 0, 64 }, { 7, 30, 124, 0, 64 },
13385203945Sweongyo		{ 7, 30, 121, 0, 64 }, { 7, 29, 121, 0, 64 },
13386203945Sweongyo		{ 7, 29, 117, 0, 64 }, { 7, 29, 117, 0, 64 },
13387203945Sweongyo		{ 7, 29, 114, 0, 64 }, { 7, 28, 114, 0, 64 },
13388203945Sweongyo		{ 7, 28, 111, 0, 64 }, { 7, 27, 111, 0, 64 },
13389203945Sweongyo		{ 7, 27, 108, 0, 64 }, { 7, 26, 108, 0, 64 },
13390203945Sweongyo		{ 7, 26, 104, 0, 64 }, { 7, 25, 104, 0, 64 },
13391203945Sweongyo		{ 7, 25, 102, 0, 64 }, { 7, 25, 102, 0, 64 },
13392203945Sweongyo		{ 7, 25, 99, 0, 64 }, { 7, 24, 99, 0, 64 },
13393203945Sweongyo		{ 7, 24, 96, 0, 64 }, { 7, 23, 96, 0, 64 },
13394203945Sweongyo		{ 7, 23, 93, 0, 64 }, { 7, 23, 93, 0, 64 },
13395203945Sweongyo		{ 7, 23, 90, 0, 64 }, { 7, 22, 90, 0, 64 },
13396203945Sweongyo		{ 7, 22, 88, 0, 64 }, { 7, 21, 88, 0, 64 },
13397203945Sweongyo		{ 7, 21, 85, 0, 64 }, { 7, 21, 85, 0, 64 },
13398203945Sweongyo		{ 7, 21, 83, 0, 64 }, { 7, 20, 83, 0, 64 },
13399203945Sweongyo		{ 7, 20, 81, 0, 64 }, { 7, 20, 81, 0, 64 },
13400203945Sweongyo		{ 7, 20, 78, 0, 64 }, { 7, 19, 78, 0, 64 },
13401203945Sweongyo		{ 7, 19, 76, 0, 64 }, { 7, 19, 76, 0, 64 },
13402203945Sweongyo		{ 7, 19, 74, 0, 64 }, { 7, 18, 74, 0, 64 },
13403203945Sweongyo		{ 7, 18, 72, 0, 64 }, { 7, 18, 72, 0, 64 },
13404203945Sweongyo		{ 7, 18, 70, 0, 64 }, { 7, 17, 70, 0, 64 },
13405203945Sweongyo		{ 7, 17, 68, 0, 64 }, { 7, 17, 68, 0, 64 },
13406203945Sweongyo		{ 7, 17, 66, 0, 64 }, { 7, 16, 66, 0, 64 },
13407203945Sweongyo		{ 7, 16, 64, 0, 64 }, { 7, 16, 64, 0, 64 },
13408203945Sweongyo		{ 7, 16, 62, 0, 64 }, { 7, 15, 62, 0, 64 },
13409203945Sweongyo		{ 7, 15, 60, 0, 64 }, { 7, 15, 60, 0, 64 },
13410203945Sweongyo		{ 7, 15, 59, 0, 64 }, { 7, 14, 59, 0, 64 },
13411203945Sweongyo		{ 7, 14, 57, 0, 64 }, { 7, 14, 57, 0, 64 },
13412203945Sweongyo		{ 7, 14, 55, 0, 64 }, { 7, 14, 55, 0, 64 },
13413203945Sweongyo		{ 7, 14, 54, 0, 64 }, { 7, 13, 54, 0, 64 },
13414203945Sweongyo		{ 7, 13, 52, 0, 64 }, { 7, 13, 52, 0, 64 },
13415203945Sweongyo	};
13416203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r2[] = {
13417203945Sweongyo		{ 255, 255, 255, 0, 152 }, { 255, 255, 255, 0, 147 },
13418203945Sweongyo		{ 255, 255, 255, 0, 143 }, { 255, 255, 255, 0, 139 },
13419203945Sweongyo		{ 255, 255, 255, 0, 135 }, { 255, 255, 255, 0, 131 },
13420203945Sweongyo		{ 255, 255, 255, 0, 128 }, { 255, 255, 255, 0, 124 },
13421203945Sweongyo		{ 255, 255, 255, 0, 121 }, { 255, 255, 255, 0, 117 },
13422203945Sweongyo		{ 255, 255, 255, 0, 114 }, { 255, 255, 255, 0, 111 },
13423203945Sweongyo		{ 255, 255, 255, 0, 107 }, { 255, 255, 255, 0, 104 },
13424203945Sweongyo		{ 255, 255, 255, 0, 101 }, { 255, 255, 255, 0, 99 },
13425203945Sweongyo		{ 255, 255, 255, 0, 96 }, { 255, 255, 255, 0, 93 },
13426203945Sweongyo		{ 255, 255, 255, 0, 90 }, { 255, 255, 255, 0, 88 },
13427203945Sweongyo		{ 255, 255, 255, 0, 85 }, { 255, 255, 255, 0, 83 },
13428203945Sweongyo		{ 255, 255, 255, 0, 81 }, { 255, 255, 255, 0, 78 },
13429203945Sweongyo		{ 255, 255, 255, 0, 76 }, { 255, 255, 255, 0, 74 },
13430203945Sweongyo		{ 255, 255, 255, 0, 72 }, { 255, 255, 255, 0, 70 },
13431203945Sweongyo		{ 255, 255, 255, 0, 68 }, { 255, 255, 255, 0, 66 },
13432203945Sweongyo		{ 255, 255, 255, 0, 64 }, { 255, 255, 248, 0, 64 },
13433203945Sweongyo		{ 255, 255, 241, 0, 64 }, { 255, 255, 234, 0, 64 },
13434203945Sweongyo		{ 255, 255, 227, 0, 64 }, { 255, 255, 221, 0, 64 },
13435203945Sweongyo		{ 255, 255, 215, 0, 64 }, { 255, 255, 208, 0, 64 },
13436203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13437203945Sweongyo		{ 255, 255, 191, 0, 64 }, { 255, 255, 186, 0, 64 },
13438203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 175, 0, 64 },
13439203945Sweongyo		{ 255, 255, 170, 0, 64 }, { 255, 255, 166, 0, 64 },
13440203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 156, 0, 64 },
13441203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13442203945Sweongyo		{ 255, 255, 143, 0, 64 }, { 255, 255, 139, 0, 64 },
13443203945Sweongyo		{ 255, 255, 135, 0, 64 }, { 255, 255, 132, 0, 64 },
13444203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13445203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13446203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13447203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 104, 0, 64 },
13448203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13449203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13450203945Sweongyo		{ 255, 255, 90, 0, 64 }, { 255, 255, 88, 0, 64 },
13451203945Sweongyo		{ 255, 255, 85, 0, 64 }, { 255, 255, 83, 0, 64 },
13452203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 78, 0, 64 },
13453203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13454203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13455203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13456203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 255, 64, 0, 64 },
13457203945Sweongyo		{ 255, 255, 62, 0, 64 }, { 255, 248, 62, 0, 64 },
13458203945Sweongyo		{ 255, 248, 60, 0, 64 }, { 255, 241, 60, 0, 64 },
13459203945Sweongyo		{ 255, 241, 59, 0, 64 }, { 255, 234, 59, 0, 64 },
13460203945Sweongyo		{ 255, 234, 57, 0, 64 }, { 255, 227, 57, 0, 64 },
13461203945Sweongyo		{ 255, 227, 55, 0, 64 }, { 255, 221, 55, 0, 64 },
13462203945Sweongyo		{ 255, 221, 54, 0, 64 }, { 255, 215, 54, 0, 64 },
13463203945Sweongyo		{ 255, 215, 52, 0, 64 }, { 255, 208, 52, 0, 64 },
13464203945Sweongyo		{ 255, 208, 51, 0, 64 }, { 255, 203, 51, 0, 64 },
13465203945Sweongyo		{ 255, 203, 49, 0, 64 }, { 255, 197, 49, 0, 64 },
13466203945Sweongyo		{ 255, 197, 48, 0, 64 }, { 255, 191, 48, 0, 64 },
13467203945Sweongyo		{ 255, 191, 47, 0, 64 }, { 255, 186, 47, 0, 64 },
13468203945Sweongyo		{ 255, 186, 45, 0, 64 }, { 255, 181, 45, 0, 64 },
13469203945Sweongyo		{ 255, 181, 44, 0, 64 }, { 255, 175, 44, 0, 64 },
13470203945Sweongyo		{ 255, 175, 43, 0, 64 }, { 255, 170, 43, 0, 64 },
13471203945Sweongyo		{ 255, 170, 42, 0, 64 }, { 255, 166, 42, 0, 64 },
13472203945Sweongyo		{ 255, 166, 40, 0, 64 }, { 255, 161, 40, 0, 64 },
13473203945Sweongyo		{ 255, 161, 39, 0, 64 }, { 255, 156, 39, 0, 64 },
13474203945Sweongyo		{ 255, 156, 38, 0, 64 }, { 255, 152, 38, 0, 64 },
13475203945Sweongyo		{ 255, 152, 37, 0, 64 }, { 255, 148, 37, 0, 64 },
13476203945Sweongyo		{ 255, 148, 36, 0, 64 }, { 255, 143, 36, 0, 64 },
13477203945Sweongyo		{ 255, 143, 35, 0, 64 }, { 255, 139, 35, 0, 64 },
13478203945Sweongyo		{ 255, 139, 34, 0, 64 }, { 255, 135, 34, 0, 64 },
13479203945Sweongyo		{ 255, 135, 33, 0, 64 }, { 255, 132, 33, 0, 64 },
13480203945Sweongyo		{ 255, 132, 32, 0, 64 }, { 255, 128, 32, 0, 64 }
13481203945Sweongyo	};
13482203945Sweongyo	static struct bwn_txgain_entry txgain_r0[] = {
13483203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13484203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13485203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13486203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13487203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13488203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13489203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13490203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13491203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13492203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13493203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13494203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13495203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13496203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13497203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13498203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13499203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13500203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13501203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 13, 0, 68 },
13502203945Sweongyo		{ 7, 15, 13, 0, 66 }, { 7, 15, 13, 0, 64 },
13503203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13504203945Sweongyo		{ 7, 15, 13, 0, 59 }, { 7, 15, 13, 0, 57 },
13505203945Sweongyo		{ 7, 15, 12, 0, 71 }, { 7, 15, 12, 0, 69 },
13506203945Sweongyo		{ 7, 15, 12, 0, 67 }, { 7, 15, 12, 0, 65 },
13507203945Sweongyo		{ 7, 15, 12, 0, 63 }, { 7, 15, 12, 0, 62 },
13508203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 58 },
13509203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 70 },
13510203945Sweongyo		{ 7, 15, 11, 0, 68 }, { 7, 15, 11, 0, 66 },
13511203945Sweongyo		{ 7, 15, 11, 0, 65 }, { 7, 15, 11, 0, 63 },
13512203945Sweongyo		{ 7, 15, 11, 0, 61 }, { 7, 15, 11, 0, 59 },
13513203945Sweongyo		{ 7, 15, 11, 0, 58 }, { 7, 15, 10, 0, 71 },
13514203945Sweongyo		{ 7, 15, 10, 0, 69 }, { 7, 15, 10, 0, 67 },
13515203945Sweongyo		{ 7, 15, 10, 0, 65 }, { 7, 15, 10, 0, 63 },
13516203945Sweongyo		{ 7, 15, 10, 0, 61 }, { 7, 15, 10, 0, 60 },
13517203945Sweongyo		{ 7, 15, 10, 0, 58 }, { 7, 15, 10, 0, 56 },
13518203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13519203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13520203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 60 },
13521203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 14, 9, 0, 72 },
13522203945Sweongyo		{ 7, 14, 9, 0, 70 }, { 7, 14, 9, 0, 68 },
13523203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 64 },
13524203945Sweongyo		{ 7, 14, 9, 0, 62 }, { 7, 14, 9, 0, 60 },
13525203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 13, 9, 0, 72 },
13526203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13527203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13528203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13529203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13530203945Sweongyo		{ 7, 13, 8, 0, 72 }, { 7, 13, 8, 0, 70 },
13531203945Sweongyo		{ 7, 13, 8, 0, 68 }, { 7, 13, 8, 0, 66 },
13532203945Sweongyo		{ 7, 13, 8, 0, 64 }, { 7, 13, 8, 0, 62 },
13533203945Sweongyo		{ 7, 13, 8, 0, 60 }, { 7, 13, 8, 0, 59 },
13534203945Sweongyo		{ 7, 12, 8, 0, 72 }, { 7, 12, 8, 0, 70 },
13535203945Sweongyo		{ 7, 12, 8, 0, 68 }, { 7, 12, 8, 0, 66 },
13536203945Sweongyo		{ 7, 12, 8, 0, 64 }, { 7, 12, 8, 0, 62 },
13537203945Sweongyo		{ 7, 12, 8, 0, 61 }, { 7, 12, 8, 0, 59 },
13538203945Sweongyo		{ 7, 12, 7, 0, 73 }, { 7, 12, 7, 0, 71 },
13539203945Sweongyo		{ 7, 12, 7, 0, 69 }, { 7, 12, 7, 0, 67 },
13540203945Sweongyo		{ 7, 12, 7, 0, 65 }, { 7, 12, 7, 0, 63 },
13541203945Sweongyo		{ 7, 12, 7, 0, 61 }, { 7, 12, 7, 0, 59 },
13542203945Sweongyo		{ 7, 11, 7, 0, 72 }, { 7, 11, 7, 0, 70 },
13543203945Sweongyo		{ 7, 11, 7, 0, 68 }, { 7, 11, 7, 0, 66 },
13544203945Sweongyo		{ 7, 11, 7, 0, 65 }, { 7, 11, 7, 0, 63 },
13545203945Sweongyo		{ 7, 11, 7, 0, 61 }, { 7, 11, 7, 0, 59 },
13546203945Sweongyo		{ 7, 11, 6, 0, 73 }, { 7, 11, 6, 0, 71 }
13547203945Sweongyo	};
13548203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r0[] = {
13549203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13550203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13551203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13552203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13553203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13554203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13555203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13556203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13557203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13558203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13559203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13560203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13561203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13562203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13563203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13564203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13565203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13566203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13567203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13568203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13569203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13570203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13571203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13572203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13573203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13574203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13575203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13576203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13577203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13578203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13579203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13580203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13581203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13582203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 },
13583203945Sweongyo		{ 4, 10, 6, 0, 59 }, { 4, 10, 5, 0, 72 },
13584203945Sweongyo		{ 4, 10, 5, 0, 70 }, { 4, 10, 5, 0, 68 },
13585203945Sweongyo		{ 4, 10, 5, 0, 66 }, { 4, 10, 5, 0, 64 },
13586203945Sweongyo		{ 4, 10, 5, 0, 62 }, { 4, 10, 5, 0, 60 },
13587203945Sweongyo		{ 4, 10, 5, 0, 59 }, { 4, 9, 5, 0, 70 },
13588203945Sweongyo		{ 4, 9, 5, 0, 68 }, { 4, 9, 5, 0, 66 },
13589203945Sweongyo		{ 4, 9, 5, 0, 64 }, { 4, 9, 5, 0, 63 },
13590203945Sweongyo		{ 4, 9, 5, 0, 61 }, { 4, 9, 5, 0, 59 },
13591203945Sweongyo		{ 4, 9, 4, 0, 71 }, { 4, 9, 4, 0, 69 },
13592203945Sweongyo		{ 4, 9, 4, 0, 67 }, { 4, 9, 4, 0, 65 },
13593203945Sweongyo		{ 4, 9, 4, 0, 63 }, { 4, 9, 4, 0, 62 },
13594203945Sweongyo		{ 4, 9, 4, 0, 60 }, { 4, 9, 4, 0, 58 },
13595203945Sweongyo		{ 4, 8, 4, 0, 70 }, { 4, 8, 4, 0, 68 },
13596203945Sweongyo		{ 4, 8, 4, 0, 66 }, { 4, 8, 4, 0, 65 },
13597203945Sweongyo		{ 4, 8, 4, 0, 63 }, { 4, 8, 4, 0, 61 },
13598203945Sweongyo		{ 4, 8, 4, 0, 59 }, { 4, 7, 4, 0, 68 },
13599203945Sweongyo		{ 4, 7, 4, 0, 66 }, { 4, 7, 4, 0, 64 },
13600203945Sweongyo		{ 4, 7, 4, 0, 62 }, { 4, 7, 4, 0, 61 },
13601203945Sweongyo		{ 4, 7, 4, 0, 59 }, { 4, 7, 3, 0, 67 },
13602203945Sweongyo		{ 4, 7, 3, 0, 65 }, { 4, 7, 3, 0, 63 },
13603203945Sweongyo		{ 4, 7, 3, 0, 62 }, { 4, 7, 3, 0, 60 },
13604203945Sweongyo		{ 4, 6, 3, 0, 65 }, { 4, 6, 3, 0, 63 },
13605203945Sweongyo		{ 4, 6, 3, 0, 61 }, { 4, 6, 3, 0, 60 },
13606203945Sweongyo		{ 4, 6, 3, 0, 58 }, { 4, 5, 3, 0, 68 },
13607203945Sweongyo		{ 4, 5, 3, 0, 66 }, { 4, 5, 3, 0, 64 },
13608203945Sweongyo		{ 4, 5, 3, 0, 62 }, { 4, 5, 3, 0, 60 },
13609203945Sweongyo		{ 4, 5, 3, 0, 59 }, { 4, 5, 3, 0, 57 },
13610203945Sweongyo		{ 4, 4, 2, 0, 83 }, { 4, 4, 2, 0, 81 },
13611203945Sweongyo		{ 4, 4, 2, 0, 78 }, { 4, 4, 2, 0, 76 },
13612203945Sweongyo		{ 4, 4, 2, 0, 74 }, { 4, 4, 2, 0, 72 }
13613203945Sweongyo	};
13614203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r0[] = {
13615203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13616203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13617203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13618203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13619203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13620203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13621203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13622203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13623203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13624203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13625203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13626203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13627203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13628203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13629203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13630203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13631203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13632203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13633203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13634203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13635203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13636203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13637203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13638203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13639203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13640203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13641203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13642203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13643203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13644203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13645203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13646203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13647203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13648203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13649203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13650203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13651203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13652203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13653203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13654203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13655203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13656203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13657203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13658203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13659203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13660203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13661203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13662203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13663203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13664203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13665203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13666203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13667203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13668203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13669203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13670203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13671203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13672203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13673203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13674203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13675203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13676203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13677203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13678203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13679203945Sweongyo	};
13680203945Sweongyo	static struct bwn_txgain_entry txgain_r1[] = {
13681203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13682203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13683203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13684203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13685203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13686203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13687203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13688203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13689203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13690203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13691203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13692203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13693203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13694203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13695203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13696203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13697203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13698203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13699203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 14, 0, 68 },
13700203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13701203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13702203945Sweongyo		{ 7, 15, 14, 0, 59 }, { 7, 15, 14, 0, 57 },
13703203945Sweongyo		{ 7, 15, 13, 0, 72 }, { 7, 15, 13, 0, 70 },
13704203945Sweongyo		{ 7, 15, 13, 0, 68 }, { 7, 15, 13, 0, 66 },
13705203945Sweongyo		{ 7, 15, 13, 0, 64 }, { 7, 15, 13, 0, 62 },
13706203945Sweongyo		{ 7, 15, 13, 0, 60 }, { 7, 15, 13, 0, 59 },
13707203945Sweongyo		{ 7, 15, 13, 0, 57 }, { 7, 15, 12, 0, 71 },
13708203945Sweongyo		{ 7, 15, 12, 0, 69 }, { 7, 15, 12, 0, 67 },
13709203945Sweongyo		{ 7, 15, 12, 0, 65 }, { 7, 15, 12, 0, 63 },
13710203945Sweongyo		{ 7, 15, 12, 0, 62 }, { 7, 15, 12, 0, 60 },
13711203945Sweongyo		{ 7, 15, 12, 0, 58 }, { 7, 15, 12, 0, 57 },
13712203945Sweongyo		{ 7, 15, 11, 0, 70 }, { 7, 15, 11, 0, 68 },
13713203945Sweongyo		{ 7, 15, 11, 0, 66 }, { 7, 15, 11, 0, 65 },
13714203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13715203945Sweongyo		{ 7, 15, 11, 0, 59 }, { 7, 15, 11, 0, 58 },
13716203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13717203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13718203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13719203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13720203945Sweongyo		{ 7, 15, 10, 0, 56 }, { 7, 15, 9, 0, 70 },
13721203945Sweongyo		{ 7, 15, 9, 0, 68 }, { 7, 15, 9, 0, 66 },
13722203945Sweongyo		{ 7, 15, 9, 0, 64 }, { 7, 15, 9, 0, 62 },
13723203945Sweongyo		{ 7, 15, 9, 0, 60 }, { 7, 15, 9, 0, 59 },
13724203945Sweongyo		{ 7, 14, 9, 0, 72 }, { 7, 14, 9, 0, 70 },
13725203945Sweongyo		{ 7, 14, 9, 0, 68 }, { 7, 14, 9, 0, 66 },
13726203945Sweongyo		{ 7, 14, 9, 0, 64 }, { 7, 14, 9, 0, 62 },
13727203945Sweongyo		{ 7, 14, 9, 0, 60 }, { 7, 14, 9, 0, 59 },
13728203945Sweongyo		{ 7, 13, 9, 0, 72 }, { 7, 13, 9, 0, 70 },
13729203945Sweongyo		{ 7, 13, 9, 0, 68 }, { 7, 13, 9, 0, 66 },
13730203945Sweongyo		{ 7, 13, 9, 0, 64 }, { 7, 13, 9, 0, 63 },
13731203945Sweongyo		{ 7, 13, 9, 0, 61 }, { 7, 13, 9, 0, 59 },
13732203945Sweongyo		{ 7, 13, 9, 0, 57 }, { 7, 13, 8, 0, 72 },
13733203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13734203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13735203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13736203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 12, 8, 0, 72 },
13737203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13738203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13739203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13740203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 7, 0, 73 },
13741203945Sweongyo		{ 7, 12, 7, 0, 71 }, { 7, 12, 7, 0, 69 },
13742203945Sweongyo		{ 7, 12, 7, 0, 67 }, { 7, 12, 7, 0, 65 },
13743203945Sweongyo		{ 7, 12, 7, 0, 63 }, { 7, 12, 7, 0, 61 },
13744203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 11, 7, 0, 72 },
13745203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13746203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 65 },
13747203945Sweongyo		{ 7, 11, 7, 0, 63 }, { 7, 11, 7, 0, 61 },
13748203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 6, 0, 73 },
13749203945Sweongyo		{ 7, 11, 6, 0, 71 }
13750203945Sweongyo	};
13751203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r1[] = {
13752203945Sweongyo		{ 4, 15, 15, 0, 90 }, { 4, 15, 15, 0, 88 },
13753203945Sweongyo		{ 4, 15, 15, 0, 85 }, { 4, 15, 15, 0, 83 },
13754203945Sweongyo		{ 4, 15, 15, 0, 81 }, { 4, 15, 15, 0, 78 },
13755203945Sweongyo		{ 4, 15, 15, 0, 76 }, { 4, 15, 15, 0, 74 },
13756203945Sweongyo		{ 4, 15, 15, 0, 72 }, { 4, 15, 15, 0, 70 },
13757203945Sweongyo		{ 4, 15, 15, 0, 68 }, { 4, 15, 15, 0, 66 },
13758203945Sweongyo		{ 4, 15, 15, 0, 64 }, { 4, 15, 15, 0, 62 },
13759203945Sweongyo		{ 4, 15, 15, 0, 60 }, { 4, 15, 15, 0, 59 },
13760203945Sweongyo		{ 4, 15, 14, 0, 72 }, { 4, 15, 14, 0, 70 },
13761203945Sweongyo		{ 4, 15, 14, 0, 68 }, { 4, 15, 14, 0, 66 },
13762203945Sweongyo		{ 4, 15, 14, 0, 64 }, { 4, 15, 14, 0, 62 },
13763203945Sweongyo		{ 4, 15, 14, 0, 60 }, { 4, 15, 14, 0, 59 },
13764203945Sweongyo		{ 4, 15, 13, 0, 72 }, { 4, 15, 13, 0, 70 },
13765203945Sweongyo		{ 4, 15, 13, 0, 68 }, { 4, 15, 13, 0, 66 },
13766203945Sweongyo		{ 4, 15, 13, 0, 64 }, { 4, 15, 13, 0, 62 },
13767203945Sweongyo		{ 4, 15, 13, 0, 60 }, { 4, 15, 13, 0, 59 },
13768203945Sweongyo		{ 4, 15, 12, 0, 72 }, { 4, 15, 12, 0, 70 },
13769203945Sweongyo		{ 4, 15, 12, 0, 68 }, { 4, 15, 12, 0, 66 },
13770203945Sweongyo		{ 4, 15, 12, 0, 64 }, { 4, 15, 12, 0, 62 },
13771203945Sweongyo		{ 4, 15, 12, 0, 60 }, { 4, 15, 12, 0, 59 },
13772203945Sweongyo		{ 4, 15, 11, 0, 72 }, { 4, 15, 11, 0, 70 },
13773203945Sweongyo		{ 4, 15, 11, 0, 68 }, { 4, 15, 11, 0, 66 },
13774203945Sweongyo		{ 4, 15, 11, 0, 64 }, { 4, 15, 11, 0, 62 },
13775203945Sweongyo		{ 4, 15, 11, 0, 60 }, { 4, 15, 11, 0, 59 },
13776203945Sweongyo		{ 4, 15, 10, 0, 72 }, { 4, 15, 10, 0, 70 },
13777203945Sweongyo		{ 4, 15, 10, 0, 68 }, { 4, 15, 10, 0, 66 },
13778203945Sweongyo		{ 4, 15, 10, 0, 64 }, { 4, 15, 10, 0, 62 },
13779203945Sweongyo		{ 4, 15, 10, 0, 60 }, { 4, 15, 10, 0, 59 },
13780203945Sweongyo		{ 4, 15, 9, 0, 72 }, { 4, 15, 9, 0, 70 },
13781203945Sweongyo		{ 4, 15, 9, 0, 68 }, { 4, 15, 9, 0, 66 },
13782203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13783203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13784203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13785203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13786203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13787203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13788203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13789203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13790203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13791203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13792203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13793203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13794203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13795203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13796203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13797203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13798203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13799203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13800203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13801203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13802203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13803203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13804203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13805203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13806203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13807203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13808203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13809203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13810203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13811203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13812203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13813203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13814203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13815203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 }
13816203945Sweongyo	};
13817203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r1[] = {
13818203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13819203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13820203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13821203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13822203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13823203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13824203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13825203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13826203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13827203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13828203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13829203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13830203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13831203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13832203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13833203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13834203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13835203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13836203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13837203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13838203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13839203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13840203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13841203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13842203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13843203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13844203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13845203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13846203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13847203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13848203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13849203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13850203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13851203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13852203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13853203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13854203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13855203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13856203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13857203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13858203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13859203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13860203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13861203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13862203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13863203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13864203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13865203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13866203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13867203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13868203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13869203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13870203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13871203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13872203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13873203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13874203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13875203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13876203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13877203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13878203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13879203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13880203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13881203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13882203945Sweongyo	};
13883203945Sweongyo
13884203945Sweongyo	if (mac->mac_phy.rev != 0 && mac->mac_phy.rev != 1) {
13885204922Sweongyo		if (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA)
13886203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r2);
13887203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13888203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13889203945Sweongyo			    txgain_2ghz_r2);
13890203945Sweongyo		else
13891203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13892203945Sweongyo			    txgain_5ghz_r2);
13893203945Sweongyo		return;
13894203945Sweongyo	}
13895203945Sweongyo
13896203945Sweongyo	if (mac->mac_phy.rev == 0) {
13897204922Sweongyo		if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
13898204922Sweongyo		    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_HGPA))
13899203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r0);
13900203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13901203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13902203945Sweongyo			    txgain_2ghz_r0);
13903203945Sweongyo		else
13904203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13905203945Sweongyo			    txgain_5ghz_r0);
13906203945Sweongyo		return;
13907203945Sweongyo	}
13908203945Sweongyo
13909204922Sweongyo	if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
13910204922Sweongyo	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_HGPA))
13911203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r1);
13912203945Sweongyo	else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13913203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_2ghz_r1);
13914203945Sweongyo	else
13915203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_5ghz_r1);
13916203945Sweongyo}
13917203945Sweongyo
13918203945Sweongyostatic void
13919203945Sweongyobwn_tab_write(struct bwn_mac *mac, uint32_t typeoffset, uint32_t value)
13920203945Sweongyo{
13921203945Sweongyo	uint32_t offset, type;
13922203945Sweongyo
13923203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
13924203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
13925203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
13926203945Sweongyo
13927203945Sweongyo	switch (type) {
13928203945Sweongyo	case BWN_TAB_8BIT:
13929203945Sweongyo		KASSERT(!(value & ~0xff), ("%s:%d: fail", __func__, __LINE__));
13930203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13931203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13932203945Sweongyo		break;
13933203945Sweongyo	case BWN_TAB_16BIT:
13934203945Sweongyo		KASSERT(!(value & ~0xffff),
13935203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
13936203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13937203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13938203945Sweongyo		break;
13939203945Sweongyo	case BWN_TAB_32BIT:
13940203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13941203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
13942203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13943203945Sweongyo		break;
13944203945Sweongyo	default:
13945203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
13946203945Sweongyo	}
13947203945Sweongyo}
13948203945Sweongyo
13949203945Sweongyostatic int
13950203945Sweongyobwn_phy_lp_loopback(struct bwn_mac *mac)
13951203945Sweongyo{
13952203945Sweongyo	struct bwn_phy_lp_iq_est ie;
13953203945Sweongyo	int i, index = -1;
13954203945Sweongyo	uint32_t tmp;
13955203945Sweongyo
13956203945Sweongyo	memset(&ie, 0, sizeof(ie));
13957203945Sweongyo
13958203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1, 1);
13959203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 1);
13960203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
13961203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
13962203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
13963203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
13964203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x8);
13965203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, 0x80);
13966203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x80);
13967203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x80);
13968203945Sweongyo	for (i = 0; i < 32; i++) {
13969203945Sweongyo		bwn_phy_lp_set_rxgain_idx(mac, i);
13970203945Sweongyo		bwn_phy_lp_ddfs_turnon(mac, 1, 1, 5, 5, 0);
13971203945Sweongyo		if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
13972203945Sweongyo			continue;
13973203945Sweongyo		tmp = (ie.ie_ipwr + ie.ie_qpwr) / 1000;
13974203945Sweongyo		if ((tmp > 4000) && (tmp < 10000)) {
13975203945Sweongyo			index = i;
13976203945Sweongyo			break;
13977203945Sweongyo		}
13978203945Sweongyo	}
13979203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
13980203945Sweongyo	return (index);
13981203945Sweongyo}
13982203945Sweongyo
13983203945Sweongyostatic void
13984203945Sweongyobwn_phy_lp_set_rxgain_idx(struct bwn_mac *mac, uint16_t idx)
13985203945Sweongyo{
13986203945Sweongyo
13987203945Sweongyo	bwn_phy_lp_set_rxgain(mac, bwn_tab_read(mac, BWN_TAB_2(12, idx)));
13988203945Sweongyo}
13989203945Sweongyo
13990203945Sweongyostatic void
13991203945Sweongyobwn_phy_lp_ddfs_turnon(struct bwn_mac *mac, int i_on, int q_on,
13992203945Sweongyo    int incr1, int incr2, int scale_idx)
13993203945Sweongyo{
13994203945Sweongyo
13995203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
13996203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0xff80);
13997203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0x80ff);
13998203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0xff80, incr1);
13999203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0x80ff, incr2 << 8);
14000203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff7, i_on << 3);
14001203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xffef, q_on << 4);
14002203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xff9f, scale_idx << 5);
14003203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffb);
14004203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DDFS, 0x2);
14005203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x20);
14006203945Sweongyo}
14007203945Sweongyo
14008203945Sweongyostatic uint8_t
14009203945Sweongyobwn_phy_lp_rx_iq_est(struct bwn_mac *mac, uint16_t sample, uint8_t time,
14010203945Sweongyo    struct bwn_phy_lp_iq_est *ie)
14011203945Sweongyo{
14012203945Sweongyo	int i;
14013203945Sweongyo
14014203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfff7);
14015203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_IQ_NUM_SMPLS_ADDR, sample);
14016203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xff00, time);
14017203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xfeff);
14018203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
14019203945Sweongyo
14020203945Sweongyo	for (i = 0; i < 500; i++) {
14021203945Sweongyo		if (!(BWN_PHY_READ(mac,
14022203945Sweongyo		    BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
14023203945Sweongyo			break;
14024203945Sweongyo		DELAY(1000);
14025203945Sweongyo	}
14026203945Sweongyo	if ((BWN_PHY_READ(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
14027203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14028203945Sweongyo		return 0;
14029203945Sweongyo	}
14030203945Sweongyo
14031203945Sweongyo	ie->ie_iqprod = BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_HI_ADDR);
14032203945Sweongyo	ie->ie_iqprod <<= 16;
14033203945Sweongyo	ie->ie_iqprod |= BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_LO_ADDR);
14034203945Sweongyo	ie->ie_ipwr = BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_HI_ADDR);
14035203945Sweongyo	ie->ie_ipwr <<= 16;
14036203945Sweongyo	ie->ie_ipwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_LO_ADDR);
14037203945Sweongyo	ie->ie_qpwr = BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR);
14038203945Sweongyo	ie->ie_qpwr <<= 16;
14039203945Sweongyo	ie->ie_qpwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR);
14040203945Sweongyo
14041203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14042203945Sweongyo	return 1;
14043203945Sweongyo}
14044203945Sweongyo
14045203945Sweongyostatic uint32_t
14046203945Sweongyobwn_tab_read(struct bwn_mac *mac, uint32_t typeoffset)
14047203945Sweongyo{
14048203945Sweongyo	uint32_t offset, type, value;
14049203945Sweongyo
14050203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
14051203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
14052203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
14053203945Sweongyo
14054203945Sweongyo	switch (type) {
14055203945Sweongyo	case BWN_TAB_8BIT:
14056203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14057203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
14058203945Sweongyo		break;
14059203945Sweongyo	case BWN_TAB_16BIT:
14060203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14061203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14062203945Sweongyo		break;
14063203945Sweongyo	case BWN_TAB_32BIT:
14064203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14065203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATAHI);
14066203945Sweongyo		value <<= 16;
14067203945Sweongyo		value |= BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14068203945Sweongyo		break;
14069203945Sweongyo	default:
14070203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
14071203945Sweongyo		value = 0;
14072203945Sweongyo	}
14073203945Sweongyo
14074203945Sweongyo	return (value);
14075203945Sweongyo}
14076203945Sweongyo
14077203945Sweongyostatic void
14078203945Sweongyobwn_phy_lp_ddfs_turnoff(struct bwn_mac *mac)
14079203945Sweongyo{
14080203945Sweongyo
14081203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffd);
14082203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0xffdf);
14083203945Sweongyo}
14084203945Sweongyo
14085203945Sweongyostatic void
14086203945Sweongyobwn_phy_lp_set_txgain_dac(struct bwn_mac *mac, uint16_t dac)
14087203945Sweongyo{
14088203945Sweongyo	uint16_t ctl;
14089203945Sweongyo
14090203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0xc7f;
14091203945Sweongyo	ctl |= dac << 7;
14092203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf000, ctl);
14093203945Sweongyo}
14094203945Sweongyo
14095203945Sweongyostatic void
14096203945Sweongyobwn_phy_lp_set_txgain_pa(struct bwn_mac *mac, uint16_t gain)
14097203945Sweongyo{
14098203945Sweongyo
14099203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0xe03f, gain << 6);
14100203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x80ff, gain << 8);
14101203945Sweongyo}
14102203945Sweongyo
14103203945Sweongyostatic void
14104203945Sweongyobwn_phy_lp_set_txgain_override(struct bwn_mac *mac)
14105203945Sweongyo{
14106203945Sweongyo
14107203945Sweongyo	if (mac->mac_phy.rev < 2)
14108203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
14109203945Sweongyo	else {
14110203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x80);
14111203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x4000);
14112203945Sweongyo	}
14113203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x40);
14114203945Sweongyo}
14115203945Sweongyo
14116203945Sweongyostatic uint16_t
14117203945Sweongyobwn_phy_lp_get_pa_gain(struct bwn_mac *mac)
14118203945Sweongyo{
14119203945Sweongyo
14120203945Sweongyo	return BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0x7f;
14121203945Sweongyo}
14122203945Sweongyo
14123203945Sweongyostatic uint8_t
14124203945Sweongyobwn_nbits(int32_t val)
14125203945Sweongyo{
14126203945Sweongyo	uint32_t tmp;
14127203945Sweongyo	uint8_t nbits = 0;
14128203945Sweongyo
14129203945Sweongyo	for (tmp = abs(val); tmp != 0; tmp >>= 1)
14130203945Sweongyo		nbits++;
14131203945Sweongyo	return (nbits);
14132203945Sweongyo}
14133203945Sweongyo
14134203945Sweongyostatic void
14135203945Sweongyobwn_phy_lp_gaintbl_write_multi(struct bwn_mac *mac, int offset, int count,
14136203945Sweongyo    struct bwn_txgain_entry *table)
14137203945Sweongyo{
14138203945Sweongyo	int i;
14139203945Sweongyo
14140203945Sweongyo	for (i = offset; i < count; i++)
14141203945Sweongyo		bwn_phy_lp_gaintbl_write(mac, i, table[i]);
14142203945Sweongyo}
14143203945Sweongyo
14144203945Sweongyostatic void
14145203945Sweongyobwn_phy_lp_gaintbl_write(struct bwn_mac *mac, int offset,
14146203945Sweongyo    struct bwn_txgain_entry data)
14147203945Sweongyo{
14148203945Sweongyo
14149203945Sweongyo	if (mac->mac_phy.rev >= 2)
14150203945Sweongyo		bwn_phy_lp_gaintbl_write_r2(mac, offset, data);
14151203945Sweongyo	else
14152203945Sweongyo		bwn_phy_lp_gaintbl_write_r01(mac, offset, data);
14153203945Sweongyo}
14154203945Sweongyo
14155203945Sweongyostatic void
14156203945Sweongyobwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset,
14157203945Sweongyo    struct bwn_txgain_entry te)
14158203945Sweongyo{
14159203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
14160203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
14161203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
14162203945Sweongyo	uint32_t tmp;
14163203945Sweongyo
14164203945Sweongyo	KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__));
14165203945Sweongyo
14166203945Sweongyo	tmp = (te.te_pad << 16) | (te.te_pga << 8) | te.te_gm;
14167203945Sweongyo	if (mac->mac_phy.rev >= 3) {
14168203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14169203945Sweongyo		    (0x10 << 24) : (0x70 << 24));
14170203945Sweongyo	} else {
14171203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14172203945Sweongyo		    (0x14 << 24) : (0x7f << 24));
14173203945Sweongyo	}
14174203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0xc0 + offset), tmp);
14175203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0x140 + offset),
14176203945Sweongyo	    te.te_bbmult << 20 | te.te_dac << 28);
14177203945Sweongyo}
14178203945Sweongyo
14179203945Sweongyostatic void
14180203945Sweongyobwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
14181203945Sweongyo    struct bwn_txgain_entry te)
14182203945Sweongyo{
14183203945Sweongyo
14184203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
14185203945Sweongyo
14186203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0xc0 + offset),
14187203945Sweongyo	    (te.te_pad << 11) | (te.te_pga << 7) | (te.te_gm  << 4) |
14188203945Sweongyo	    te.te_dac);
14189203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0x140 + offset), te.te_bbmult << 20);
14190203945Sweongyo}
14191203945Sweongyo
14192203945Sweongyostatic void
14193204257Sweongyobwn_sysctl_node(struct bwn_softc *sc)
14194204257Sweongyo{
14195204257Sweongyo	device_t dev = sc->sc_dev;
14196204257Sweongyo	struct bwn_mac *mac;
14197204257Sweongyo	struct bwn_stats *stats;
14198204257Sweongyo
14199204257Sweongyo	/* XXX assume that count of MAC is only 1. */
14200204257Sweongyo
14201204257Sweongyo	if ((mac = sc->sc_curmac) == NULL)
14202204257Sweongyo		return;
14203204257Sweongyo	stats = &mac->mac_stats;
14204204257Sweongyo
14205217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
14206204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14207204257Sweongyo	    "linknoise", CTLFLAG_RW, &stats->rts, 0, "Noise level");
14208217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
14209204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14210204257Sweongyo	    "rts", CTLFLAG_RW, &stats->rts, 0, "RTS");
14211217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
14212204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14213204257Sweongyo	    "rtsfail", CTLFLAG_RW, &stats->rtsfail, 0, "RTS failed to send");
14214204257Sweongyo
14215204257Sweongyo#ifdef BWN_DEBUG
14216204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14217204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14218204257Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
14219204257Sweongyo#endif
14220204257Sweongyo}
14221204257Sweongyo
14222203945Sweongyostatic device_method_t bwn_methods[] = {
14223203945Sweongyo	/* Device interface */
14224203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
14225203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
14226203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
14227203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
14228203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
14229227848Smarius	DEVMETHOD_END
14230203945Sweongyo};
14231203945Sweongyostatic driver_t bwn_driver = {
14232203945Sweongyo	"bwn",
14233203945Sweongyo	bwn_methods,
14234203945Sweongyo	sizeof(struct bwn_softc)
14235203945Sweongyo};
14236203945Sweongyostatic devclass_t bwn_devclass;
14237203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
14238203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
14239203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
14240203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
14241203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
14242