if_bwn.c revision 204081
1203945Sweongyo/*-
2203945Sweongyo * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
3203945Sweongyo * All rights reserved.
4203945Sweongyo *
5203945Sweongyo * Redistribution and use in source and binary forms, with or without
6203945Sweongyo * modification, are permitted provided that the following conditions
7203945Sweongyo * are met:
8203945Sweongyo * 1. Redistributions of source code must retain the above copyright
9203945Sweongyo *    notice, this list of conditions and the following disclaimer,
10203945Sweongyo *    without modification.
11203945Sweongyo * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12203945Sweongyo *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13203945Sweongyo *    redistribution must be conditioned upon including a substantially
14203945Sweongyo *    similar Disclaimer requirement for further binary redistribution.
15203945Sweongyo *
16203945Sweongyo * NO WARRANTY
17203945Sweongyo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18203945Sweongyo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19203945Sweongyo * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20203945Sweongyo * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21203945Sweongyo * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22203945Sweongyo * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23203945Sweongyo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24203945Sweongyo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25203945Sweongyo * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26203945Sweongyo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27203945Sweongyo * THE POSSIBILITY OF SUCH DAMAGES.
28203945Sweongyo */
29203945Sweongyo
30203945Sweongyo#include <sys/cdefs.h>
31203945Sweongyo__FBSDID("$FreeBSD: head/sys/dev/bwn/if_bwn.c 204081 2010-02-19 03:36:02Z weongyo $");
32203945Sweongyo
33203945Sweongyo/*
34203945Sweongyo * The Broadcom Wireless LAN controller driver.
35203945Sweongyo */
36203945Sweongyo
37203945Sweongyo#include <sys/param.h>
38203945Sweongyo#include <sys/systm.h>
39203945Sweongyo#include <sys/module.h>
40203945Sweongyo#include <sys/kernel.h>
41203945Sweongyo#include <sys/endian.h>
42203945Sweongyo#include <sys/errno.h>
43203945Sweongyo#include <sys/firmware.h>
44203945Sweongyo#include <sys/lock.h>
45203945Sweongyo#include <sys/mutex.h>
46203945Sweongyo#include <machine/bus.h>
47203945Sweongyo#include <machine/resource.h>
48203945Sweongyo#include <sys/bus.h>
49203945Sweongyo#include <sys/rman.h>
50203945Sweongyo#include <sys/socket.h>
51203945Sweongyo#include <sys/sockio.h>
52203945Sweongyo
53203945Sweongyo#include <net/ethernet.h>
54203945Sweongyo#include <net/if.h>
55203945Sweongyo#include <net/if_arp.h>
56203945Sweongyo#include <net/if_dl.h>
57203945Sweongyo#include <net/if_llc.h>
58203945Sweongyo#include <net/if_media.h>
59203945Sweongyo#include <net/if_types.h>
60203945Sweongyo
61203945Sweongyo#include <dev/pci/pcivar.h>
62203945Sweongyo#include <dev/pci/pcireg.h>
63203945Sweongyo#include <dev/siba/siba_ids.h>
64203945Sweongyo#include <dev/siba/sibareg.h>
65203945Sweongyo#include <dev/siba/sibavar.h>
66203945Sweongyo
67203945Sweongyo#include <net80211/ieee80211_var.h>
68203945Sweongyo#include <net80211/ieee80211_radiotap.h>
69203945Sweongyo#include <net80211/ieee80211_regdomain.h>
70203945Sweongyo#include <net80211/ieee80211_amrr.h>
71203945Sweongyo#include <net80211/ieee80211_phy.h>
72203945Sweongyo
73203945Sweongyo#include <dev/bwn/if_bwnreg.h>
74203945Sweongyo#include <dev/bwn/if_bwnvar.h>
75203945Sweongyo
76203945SweongyoSYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0, "Broadcom driver parameters");
77203945Sweongyo
78203945Sweongyo/*
79203945Sweongyo * Tunable & sysctl variables.
80203945Sweongyo */
81203945Sweongyo
82203945Sweongyo#ifdef BWN_DEBUG
83203945Sweongyostatic	int bwn_debug = 0;
84203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RW, &bwn_debug, 0,
85203945Sweongyo    "Broadcom debugging printfs");
86203945SweongyoTUNABLE_INT("hw.bwn.debug", &bwn_debug);
87203945Sweongyoenum {
88203945Sweongyo	BWN_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
89203945Sweongyo	BWN_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
90203945Sweongyo	BWN_DEBUG_STATE		= 0x00000004,	/* 802.11 state transitions */
91203945Sweongyo	BWN_DEBUG_TXPOW		= 0x00000008,	/* tx power processing */
92203945Sweongyo	BWN_DEBUG_RESET		= 0x00000010,	/* reset processing */
93203945Sweongyo	BWN_DEBUG_OPS		= 0x00000020,	/* bwn_ops processing */
94203945Sweongyo	BWN_DEBUG_BEACON	= 0x00000040,	/* beacon handling */
95203945Sweongyo	BWN_DEBUG_WATCHDOG	= 0x00000080,	/* watchdog timeout */
96203945Sweongyo	BWN_DEBUG_INTR		= 0x00000100,	/* ISR */
97203945Sweongyo	BWN_DEBUG_CALIBRATE	= 0x00000200,	/* periodic calibration */
98203945Sweongyo	BWN_DEBUG_NODE		= 0x00000400,	/* node management */
99203945Sweongyo	BWN_DEBUG_LED		= 0x00000800,	/* led management */
100203945Sweongyo	BWN_DEBUG_CMD		= 0x00001000,	/* cmd submission */
101203945Sweongyo	BWN_DEBUG_LO		= 0x00002000,	/* LO */
102203945Sweongyo	BWN_DEBUG_FW		= 0x00004000,	/* firmware */
103203945Sweongyo	BWN_DEBUG_WME		= 0x00008000,	/* WME */
104203945Sweongyo	BWN_DEBUG_RF		= 0x00010000,	/* RF */
105203945Sweongyo	BWN_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
106203945Sweongyo	BWN_DEBUG_ANY		= 0xffffffff
107203945Sweongyo};
108203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do {			\
109203945Sweongyo	if (sc->sc_debug & (m))				\
110203945Sweongyo		printf(fmt, __VA_ARGS__);		\
111203945Sweongyo} while (0)
112203945Sweongyo#else
113203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
114203945Sweongyo#endif
115203945Sweongyo
116203945Sweongyostatic int	bwn_bfp = 0;		/* use "Bad Frames Preemption" */
117203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
118203945Sweongyo    "uses Bad Frames Preemption");
119203945Sweongyostatic int	bwn_bluetooth = 1;
120203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
121203945Sweongyo    "turns on Bluetooth Coexistence");
122203945Sweongyostatic int	bwn_hwpctl = 0;
123203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
124203945Sweongyo    "uses H/W power control");
125203945Sweongyostatic int	bwn_msi_disable = 0;		/* MSI disabled  */
126203945SweongyoTUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable);
127203945Sweongyostatic int	bwn_usedma = 1;
128203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
129203945Sweongyo    "uses DMA");
130203945SweongyoTUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
131203945Sweongyostatic int	bwn_wme = 1;
132203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
133203945Sweongyo    "uses WME support");
134203945Sweongyo
135203945Sweongyostatic int	bwn_attach_pre(struct bwn_softc *);
136203945Sweongyostatic int	bwn_attach_post(struct bwn_softc *);
137203945Sweongyostatic void	bwn_sprom_bugfixes(struct siba_softc *);
138203945Sweongyostatic void	bwn_init(void *);
139203945Sweongyostatic int	bwn_init_locked(struct bwn_softc *);
140203945Sweongyostatic int	bwn_ioctl(struct ifnet *, u_long, caddr_t);
141203945Sweongyostatic void	bwn_start(struct ifnet *);
142203945Sweongyostatic int	bwn_attach_core(struct bwn_mac *);
143203945Sweongyostatic void	bwn_reset_core(struct bwn_mac *, uint32_t);
144203945Sweongyostatic int	bwn_phy_getinfo(struct bwn_mac *, int);
145203945Sweongyostatic int	bwn_chiptest(struct bwn_mac *);
146203945Sweongyostatic int	bwn_setup_channels(struct bwn_mac *, int, int);
147203945Sweongyostatic int	bwn_phy_g_attach(struct bwn_mac *);
148203945Sweongyostatic void	bwn_phy_g_detach(struct bwn_mac *);
149203945Sweongyostatic void	bwn_phy_g_init_pre(struct bwn_mac *);
150203945Sweongyostatic int	bwn_phy_g_prepare_hw(struct bwn_mac *);
151203945Sweongyostatic int	bwn_phy_g_init(struct bwn_mac *);
152203945Sweongyostatic void	bwn_phy_g_exit(struct bwn_mac *);
153203945Sweongyostatic uint16_t	bwn_phy_g_read(struct bwn_mac *, uint16_t);
154203945Sweongyostatic void	bwn_phy_g_write(struct bwn_mac *, uint16_t,
155203945Sweongyo		    uint16_t);
156203945Sweongyostatic uint16_t	bwn_phy_g_rf_read(struct bwn_mac *, uint16_t);
157203945Sweongyostatic void	bwn_phy_g_rf_write(struct bwn_mac *, uint16_t,
158203945Sweongyo		    uint16_t);
159203945Sweongyostatic int	bwn_phy_g_hwpctl(struct bwn_mac *);
160203945Sweongyostatic void	bwn_phy_g_rf_onoff(struct bwn_mac *, int);
161203945Sweongyostatic int	bwn_phy_g_switch_channel(struct bwn_mac *, uint32_t);
162203945Sweongyostatic uint32_t	bwn_phy_g_get_default_chan(struct bwn_mac *);
163203945Sweongyostatic void	bwn_phy_g_set_antenna(struct bwn_mac *, int);
164203945Sweongyostatic int	bwn_phy_g_im(struct bwn_mac *, int);
165203945Sweongyostatic int	bwn_phy_g_recalc_txpwr(struct bwn_mac *, int);
166203945Sweongyostatic void	bwn_phy_g_set_txpwr(struct bwn_mac *);
167203945Sweongyostatic void	bwn_phy_g_task_15s(struct bwn_mac *);
168203945Sweongyostatic void	bwn_phy_g_task_60s(struct bwn_mac *);
169203945Sweongyostatic uint16_t	bwn_phy_g_txctl(struct bwn_mac *);
170203945Sweongyostatic void	bwn_phy_switch_analog(struct bwn_mac *, int);
171203945Sweongyostatic uint16_t	bwn_shm_read_2(struct bwn_mac *, uint16_t, uint16_t);
172203945Sweongyostatic void	bwn_shm_write_2(struct bwn_mac *, uint16_t, uint16_t,
173203945Sweongyo		    uint16_t);
174203945Sweongyostatic uint32_t	bwn_shm_read_4(struct bwn_mac *, uint16_t, uint16_t);
175203945Sweongyostatic void	bwn_shm_write_4(struct bwn_mac *, uint16_t, uint16_t,
176203945Sweongyo		    uint32_t);
177203945Sweongyostatic void	bwn_shm_ctlword(struct bwn_mac *, uint16_t,
178203945Sweongyo		    uint16_t);
179203945Sweongyostatic void	bwn_addchannels(struct ieee80211_channel [], int, int *,
180203945Sweongyo		    const struct bwn_channelinfo *, int);
181203945Sweongyostatic int	bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
182203945Sweongyo		    const struct ieee80211_bpf_params *);
183203945Sweongyostatic void	bwn_newassoc(struct ieee80211_node *, int);
184203945Sweongyostatic void	bwn_updateslot(struct ifnet *);
185203945Sweongyostatic void	bwn_update_promisc(struct ifnet *);
186203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
187203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
188203945Sweongyostatic struct ieee80211_node *bwn_node_alloc(struct ieee80211vap *,
189203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
190203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
191203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
192203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
193203945Sweongyo		    const struct wmeParams *, uint16_t);
194203945Sweongyostatic void	bwn_node_cleanup(struct ieee80211_node *);
195203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
196203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
197203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
198203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
199203945Sweongyo		    const char [IFNAMSIZ], int, int,
200203945Sweongyo		    int, const uint8_t [IEEE80211_ADDR_LEN],
201203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
202203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
203203945Sweongyostatic void	bwn_stop(struct bwn_softc *, int);
204203945Sweongyostatic void	bwn_stop_locked(struct bwn_softc *, int);
205203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
206203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
207203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
208203945Sweongyostatic void	bwn_fix_imcfglobug(struct bwn_mac *);
209203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
210203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
211203945Sweongyostatic uint64_t	bwn_hf_read(struct bwn_mac *);
212203945Sweongyostatic void	bwn_hf_write(struct bwn_mac *, uint64_t);
213203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
214203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
215203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
216203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
217203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
218203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
219203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
220203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
221203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
222203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
223203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
224203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
225203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
226203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
227203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
228203945Sweongyostatic void	bwn_gpio_cleanup(struct bwn_mac *);
229203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
230203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
231203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
232203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
233203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
234203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
235203945Sweongyo		    int);
236203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
237203945Sweongyo		    struct bwn_pio_rxqueue *, int);
238203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
239203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
240203945Sweongyo		    uint16_t);
241203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
242203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
243203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
244203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
245203945Sweongyo		    const struct bwn_txstatus *);
246203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
247203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
248203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
249203945Sweongyo		    uint16_t);
250203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
251203945Sweongyo		    uint32_t);
252203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
253203945Sweongyo		    struct mbuf *);
254203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
255203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
256203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
257203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
258203945Sweongyo		    uint16_t, uint32_t);
259203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
260203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
261203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
262203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
263203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
264203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
265203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
266203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
267203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
268203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
269203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
270203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
271203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
272203945Sweongyo		    int, struct bwn_dmadesc_generic **,
273203945Sweongyo		    struct bwn_dmadesc_meta **);
274203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
275203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
276203945Sweongyo		    int, int);
277203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
278203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
279203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
280203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
281203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
282203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
283203945Sweongyo		    int, struct bwn_dmadesc_generic **,
284203945Sweongyo		    struct bwn_dmadesc_meta **);
285203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
286203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
287203945Sweongyo		    int, int);
288203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
289203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
290203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
291203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
292203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
293203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
294203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
295203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
296203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
297203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
298203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
299203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
300203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
301203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
302203945Sweongyo		    struct bwn_dmadesc_meta *);
303203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
304203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
305203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
306203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
307203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
308203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
309203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
310203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
311203945Sweongyo		    int);
312203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
313203945Sweongyo		    bus_size_t, int);
314203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
315203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
316203945Sweongyo		    const struct bwn_txstatus *);
317203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
318203945Sweongyo		    struct mbuf *);
319203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
320203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
321203945Sweongyo		    uint8_t);
322203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
323203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
324203945Sweongyo		    int, int, int);
325203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
326203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
327203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
328203945Sweongyostatic void	bwn_phy_g_init_sub(struct bwn_mac *);
329203945Sweongyostatic uint8_t	bwn_has_hwpctl(struct bwn_mac *);
330203945Sweongyostatic void	bwn_phy_init_b5(struct bwn_mac *);
331203945Sweongyostatic void	bwn_phy_init_b6(struct bwn_mac *);
332203945Sweongyostatic void	bwn_phy_init_a(struct bwn_mac *);
333203945Sweongyostatic void	bwn_loopback_calcgain(struct bwn_mac *);
334203945Sweongyostatic uint16_t	bwn_rf_init_bcm2050(struct bwn_mac *);
335203945Sweongyostatic void	bwn_lo_g_init(struct bwn_mac *);
336203945Sweongyostatic void	bwn_lo_g_adjust(struct bwn_mac *);
337203945Sweongyostatic void	bwn_lo_get_powervector(struct bwn_mac *);
338203945Sweongyostatic struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
339203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *);
340203945Sweongyostatic void	bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
341203945Sweongyostatic void	bwn_phy_hwpctl_init(struct bwn_mac *);
342203945Sweongyostatic void	bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
343203945Sweongyostatic void	bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
344203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *,
345203945Sweongyo		    uint8_t);
346203945Sweongyostatic void	bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
347203945Sweongyostatic uint16_t	bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
348203945Sweongyostatic void	bwn_spu_workaround(struct bwn_mac *, uint8_t);
349203945Sweongyostatic void	bwn_wa_init(struct bwn_mac *);
350203945Sweongyostatic void	bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
351203945Sweongyo		    uint16_t);
352203945Sweongyostatic void	bwn_dummy_transmission(struct bwn_mac *, int, int);
353203945Sweongyostatic void	bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
354203945Sweongyo		    uint32_t);
355203945Sweongyostatic void	bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
356203945Sweongyo		    uint16_t);
357203945Sweongyostatic void	bwn_ram_write(struct bwn_mac *, uint16_t, uint32_t);
358203945Sweongyostatic void	bwn_mac_suspend(struct bwn_mac *);
359203945Sweongyostatic void	bwn_mac_enable(struct bwn_mac *);
360203945Sweongyostatic void	bwn_psctl(struct bwn_mac *, uint32_t);
361203945Sweongyostatic int16_t	bwn_nrssi_read(struct bwn_mac *, uint16_t);
362203945Sweongyostatic void	bwn_nrssi_offset(struct bwn_mac *);
363203945Sweongyostatic void	bwn_nrssi_threshold(struct bwn_mac *);
364203945Sweongyostatic void	bwn_nrssi_slope_11g(struct bwn_mac *);
365203945Sweongyostatic void	bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
366203945Sweongyo		    int16_t);
367203945Sweongyostatic void	bwn_set_original_gains(struct bwn_mac *);
368203945Sweongyostatic void	bwn_hwpctl_early_init(struct bwn_mac *);
369203945Sweongyostatic void	bwn_hwpctl_init_gphy(struct bwn_mac *);
370203945Sweongyostatic uint16_t	bwn_phy_g_chan2freq(uint8_t);
371203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
372203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
373203945Sweongyo		    const char *, struct bwn_fwfile *);
374203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
375203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
376203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
377203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
378203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
379203945Sweongyostatic int	bwn_switch_channel(struct bwn_mac *, int);
380203945Sweongyostatic uint16_t	bwn_ant2phy(int);
381203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
382203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
383203945Sweongyo		    const uint8_t *);
384203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
385203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
386203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
387203945Sweongyo		    const uint8_t *);
388203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
389203945Sweongyo		    const uint8_t *);
390203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
391203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
392203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
393203945Sweongyo		    struct ieee80211_channel *);
394203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
395203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
396203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
397203945Sweongyostatic int	bwn_intr(void *);
398203945Sweongyostatic void	bwn_intrtask(void *, int);
399203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
400203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
401203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
402203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
403203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
404203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
405203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
406203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
407203945Sweongyostatic void	bwn_hwreset(void *, int);
408203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
409203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
410203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
411203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
412203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
413203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
414203945Sweongyo		    const struct bwn_txstatus *);
415203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
416203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
417203945Sweongyostatic void	bwn_start_locked(struct ifnet *);
418203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
419203945Sweongyo		    struct mbuf *);
420203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
421203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
422203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
423203945Sweongyo		    uint16_t);
424203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
425203945Sweongyo		    const uint8_t);
426203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
427203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
428203945Sweongyostatic int	bwn_phy_shm_tssi_read(struct bwn_mac *, uint16_t);
429203945Sweongyostatic void	bwn_phy_g_setatt(struct bwn_mac *, int *, int *);
430203945Sweongyostatic void	bwn_phy_lock(struct bwn_mac *);
431203945Sweongyostatic void	bwn_phy_unlock(struct bwn_mac *);
432203945Sweongyostatic void	bwn_rf_lock(struct bwn_mac *);
433203945Sweongyostatic void	bwn_rf_unlock(struct bwn_mac *);
434203945Sweongyostatic void	bwn_txpwr(void *, int);
435203945Sweongyostatic void	bwn_tasks(void *);
436203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
437203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
438203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
439203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
440203945Sweongyo		    uint8_t);
441203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
442203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
443203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
444203945Sweongyo		    int, int);
445203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
446203945Sweongyostatic void	bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
447203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
448203945Sweongyostatic void	bwn_watchdog(void *);
449203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
450203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
451203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
452203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
453203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
454203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
455203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
456203945Sweongyostatic void	bwn_led_blink_next(void *);
457203945Sweongyostatic void	bwn_led_blink_end(void *);
458203945Sweongyostatic void	bwn_rfswitch(void *);
459203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
460203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
461203945Sweongyostatic void	bwn_phy_lp_init_pre(struct bwn_mac *);
462203945Sweongyostatic int	bwn_phy_lp_init(struct bwn_mac *);
463203945Sweongyostatic uint16_t	bwn_phy_lp_read(struct bwn_mac *, uint16_t);
464203945Sweongyostatic void	bwn_phy_lp_write(struct bwn_mac *, uint16_t, uint16_t);
465203945Sweongyostatic void	bwn_phy_lp_maskset(struct bwn_mac *, uint16_t, uint16_t,
466203945Sweongyo		    uint16_t);
467203945Sweongyostatic uint16_t	bwn_phy_lp_rf_read(struct bwn_mac *, uint16_t);
468203945Sweongyostatic void	bwn_phy_lp_rf_write(struct bwn_mac *, uint16_t, uint16_t);
469203945Sweongyostatic void	bwn_phy_lp_rf_onoff(struct bwn_mac *, int);
470203945Sweongyostatic int	bwn_phy_lp_switch_channel(struct bwn_mac *, uint32_t);
471203945Sweongyostatic uint32_t	bwn_phy_lp_get_default_chan(struct bwn_mac *);
472203945Sweongyostatic void	bwn_phy_lp_set_antenna(struct bwn_mac *, int);
473203945Sweongyostatic void	bwn_phy_lp_task_60s(struct bwn_mac *);
474203945Sweongyostatic void	bwn_phy_lp_readsprom(struct bwn_mac *);
475203945Sweongyostatic void	bwn_phy_lp_bbinit(struct bwn_mac *);
476203945Sweongyostatic void	bwn_phy_lp_txpctl_init(struct bwn_mac *);
477203945Sweongyostatic void	bwn_phy_lp_calib(struct bwn_mac *);
478203945Sweongyostatic void	bwn_phy_lp_switch_analog(struct bwn_mac *, int);
479203945Sweongyostatic int	bwn_phy_lp_b2062_switch_channel(struct bwn_mac *, uint8_t);
480203945Sweongyostatic int	bwn_phy_lp_b2063_switch_channel(struct bwn_mac *, uint8_t);
481203945Sweongyostatic void	bwn_phy_lp_set_anafilter(struct bwn_mac *, uint8_t);
482203945Sweongyostatic void	bwn_phy_lp_set_gaintbl(struct bwn_mac *, uint32_t);
483203945Sweongyostatic void	bwn_phy_lp_digflt_save(struct bwn_mac *);
484203945Sweongyostatic void	bwn_phy_lp_get_txpctlmode(struct bwn_mac *);
485203945Sweongyostatic void	bwn_phy_lp_set_txpctlmode(struct bwn_mac *, uint8_t);
486203945Sweongyostatic void	bwn_phy_lp_bugfix(struct bwn_mac *);
487203945Sweongyostatic void	bwn_phy_lp_digflt_restore(struct bwn_mac *);
488203945Sweongyostatic void	bwn_phy_lp_tblinit(struct bwn_mac *);
489203945Sweongyostatic void	bwn_phy_lp_bbinit_r2(struct bwn_mac *);
490203945Sweongyostatic void	bwn_phy_lp_bbinit_r01(struct bwn_mac *);
491203945Sweongyostatic void	bwn_phy_lp_b2062_init(struct bwn_mac *);
492203945Sweongyostatic void	bwn_phy_lp_b2063_init(struct bwn_mac *);
493203945Sweongyostatic void	bwn_phy_lp_rxcal_r2(struct bwn_mac *);
494203945Sweongyostatic void	bwn_phy_lp_rccal_r12(struct bwn_mac *);
495203945Sweongyostatic void	bwn_phy_lp_set_rccap(struct bwn_mac *);
496203945Sweongyostatic uint32_t	bwn_phy_lp_roundup(uint32_t, uint32_t, uint8_t);
497203945Sweongyostatic void	bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *);
498203945Sweongyostatic void	bwn_phy_lp_b2062_vco_calib(struct bwn_mac *);
499203945Sweongyostatic void	bwn_tab_write_multi(struct bwn_mac *, uint32_t, int,
500203945Sweongyo		    const void *);
501203945Sweongyostatic void	bwn_tab_read_multi(struct bwn_mac *, uint32_t, int, void *);
502203945Sweongyostatic struct bwn_txgain
503203945Sweongyo		bwn_phy_lp_get_txgain(struct bwn_mac *);
504203945Sweongyostatic uint8_t	bwn_phy_lp_get_bbmult(struct bwn_mac *);
505203945Sweongyostatic void	bwn_phy_lp_set_txgain(struct bwn_mac *, struct bwn_txgain *);
506203945Sweongyostatic void	bwn_phy_lp_set_bbmult(struct bwn_mac *, uint8_t);
507203945Sweongyostatic void	bwn_phy_lp_set_trsw_over(struct bwn_mac *, uint8_t, uint8_t);
508203945Sweongyostatic void	bwn_phy_lp_set_rxgain(struct bwn_mac *, uint32_t);
509203945Sweongyostatic void	bwn_phy_lp_set_deaf(struct bwn_mac *, uint8_t);
510203945Sweongyostatic int	bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *, uint16_t);
511203945Sweongyostatic void	bwn_phy_lp_clear_deaf(struct bwn_mac *, uint8_t);
512203945Sweongyostatic void	bwn_phy_lp_tblinit_r01(struct bwn_mac *);
513203945Sweongyostatic void	bwn_phy_lp_tblinit_r2(struct bwn_mac *);
514203945Sweongyostatic void	bwn_phy_lp_tblinit_txgain(struct bwn_mac *);
515203945Sweongyostatic void	bwn_tab_write(struct bwn_mac *, uint32_t, uint32_t);
516203945Sweongyostatic void	bwn_phy_lp_b2062_tblinit(struct bwn_mac *);
517203945Sweongyostatic void	bwn_phy_lp_b2063_tblinit(struct bwn_mac *);
518203945Sweongyostatic int	bwn_phy_lp_loopback(struct bwn_mac *);
519203945Sweongyostatic void	bwn_phy_lp_set_rxgain_idx(struct bwn_mac *, uint16_t);
520203945Sweongyostatic void	bwn_phy_lp_ddfs_turnon(struct bwn_mac *, int, int, int, int,
521203945Sweongyo		    int);
522203945Sweongyostatic uint8_t	bwn_phy_lp_rx_iq_est(struct bwn_mac *, uint16_t, uint8_t,
523203945Sweongyo		    struct bwn_phy_lp_iq_est *);
524203945Sweongyostatic void	bwn_phy_lp_ddfs_turnoff(struct bwn_mac *);
525203945Sweongyostatic uint32_t	bwn_tab_read(struct bwn_mac *, uint32_t);
526203945Sweongyostatic void	bwn_phy_lp_set_txgain_dac(struct bwn_mac *, uint16_t);
527203945Sweongyostatic void	bwn_phy_lp_set_txgain_pa(struct bwn_mac *, uint16_t);
528203945Sweongyostatic void	bwn_phy_lp_set_txgain_override(struct bwn_mac *);
529203945Sweongyostatic uint16_t	bwn_phy_lp_get_pa_gain(struct bwn_mac *);
530203945Sweongyostatic uint8_t	bwn_nbits(int32_t);
531203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *, int, int,
532203945Sweongyo		    struct bwn_txgain_entry *);
533203945Sweongyostatic void	bwn_phy_lp_gaintbl_write(struct bwn_mac *, int,
534203945Sweongyo		    struct bwn_txgain_entry);
535203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
536203945Sweongyo		    struct bwn_txgain_entry);
537203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
538203945Sweongyo		    struct bwn_txgain_entry);
539203945Sweongyo
540203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
541203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
542203945Sweongyo	{ -1,			0,		0 }
543203945Sweongyo};
544203945Sweongyo
545203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
546203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
547203945Sweongyo	{ -1,			0,		0 }
548203945Sweongyo};
549203945Sweongyo
550203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
551203945Sweongyo	.channels = {
552203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
553203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
554203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
555203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
556203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
557203945Sweongyo	.nchannels = 14
558203945Sweongyo};
559203945Sweongyo
560203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
561203945Sweongyo	.channels = {
562203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
563203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
564203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
565203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
566203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
567203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
568203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
569203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
570203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
571203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
572203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
573203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
574203945Sweongyo		{ 6080, 216, 30 } },
575203945Sweongyo	.nchannels = 37
576203945Sweongyo};
577203945Sweongyo
578203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
579203945Sweongyo	.channels = {
580203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
581203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
582203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
583203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
584203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
585203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
586203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
587203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
588203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
589203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
590203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
591203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
592203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
593203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
594203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
595203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
596203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
597203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
598203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
599203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
600203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
601203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
602203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
603203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
604203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
605203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
606203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
607203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
608203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
609203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
610203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
611203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
612203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
613203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
614203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
615203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
616203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
617203945Sweongyo	.nchannels = 110
618203945Sweongyo};
619203945Sweongyo
620203945Sweongyostatic const uint8_t bwn_b2063_chantable_data[33][12] = {
621203945Sweongyo	{ 0x6f, 0x3c, 0x3c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
622203945Sweongyo	{ 0x6f, 0x2c, 0x2c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
623203945Sweongyo	{ 0x6f, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
624203945Sweongyo	{ 0x6e, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
625203945Sweongyo	{ 0x6e, 0xc, 0xc, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
626203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x2, 0x5, 0xd, 0xd, 0x77, 0x80, 0x20, 0 },
627203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x5, 0xd, 0xc, 0x77, 0x80, 0x20, 0 },
628203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x80, 0x20, 0 },
629203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x70, 0x20, 0 },
630203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xb, 0xc, 0x77, 0x70, 0x20, 0 },
631203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x4, 0xb, 0xb, 0x77, 0x60, 0x20, 0 },
632203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xb, 0x77, 0x60, 0x20, 0 },
633203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xa, 0x77, 0x60, 0x20, 0 },
634203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x2, 0x9, 0x9, 0x77, 0x60, 0x20, 0 },
635203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x1, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
636203945Sweongyo	{ 0x67, 0xc, 0xc, 0, 0, 0, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
637203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x2, 0x1, 0x77, 0x20, 0, 0 },
638203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x1, 0x1, 0x77, 0x20, 0, 0 },
639203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0x1, 0, 0x77, 0x10, 0, 0 },
640203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
641203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
642203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
643203945Sweongyo	{ 0x61, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
644203945Sweongyo	{ 0x60, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
645203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xe, 0xf, 0xf, 0x77, 0xc0, 0x50, 0 },
646203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xd, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
647203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
648203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
649203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xb, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
650203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xa, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
651203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x7, 0x9, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
652203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x6, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
653203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x5, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 }
654203945Sweongyo};
655203945Sweongyo
656203945Sweongyostatic const struct bwn_b206x_chan bwn_b2063_chantable[] = {
657203945Sweongyo	{ 1, 2412, bwn_b2063_chantable_data[0] },
658203945Sweongyo	{ 2, 2417, bwn_b2063_chantable_data[0] },
659203945Sweongyo	{ 3, 2422, bwn_b2063_chantable_data[0] },
660203945Sweongyo	{ 4, 2427, bwn_b2063_chantable_data[1] },
661203945Sweongyo	{ 5, 2432, bwn_b2063_chantable_data[1] },
662203945Sweongyo	{ 6, 2437, bwn_b2063_chantable_data[1] },
663203945Sweongyo	{ 7, 2442, bwn_b2063_chantable_data[1] },
664203945Sweongyo	{ 8, 2447, bwn_b2063_chantable_data[1] },
665203945Sweongyo	{ 9, 2452, bwn_b2063_chantable_data[2] },
666203945Sweongyo	{ 10, 2457, bwn_b2063_chantable_data[2] },
667203945Sweongyo	{ 11, 2462, bwn_b2063_chantable_data[3] },
668203945Sweongyo	{ 12, 2467, bwn_b2063_chantable_data[3] },
669203945Sweongyo	{ 13, 2472, bwn_b2063_chantable_data[3] },
670203945Sweongyo	{ 14, 2484, bwn_b2063_chantable_data[4] },
671203945Sweongyo	{ 34, 5170, bwn_b2063_chantable_data[5] },
672203945Sweongyo	{ 36, 5180, bwn_b2063_chantable_data[6] },
673203945Sweongyo	{ 38, 5190, bwn_b2063_chantable_data[7] },
674203945Sweongyo	{ 40, 5200, bwn_b2063_chantable_data[8] },
675203945Sweongyo	{ 42, 5210, bwn_b2063_chantable_data[9] },
676203945Sweongyo	{ 44, 5220, bwn_b2063_chantable_data[10] },
677203945Sweongyo	{ 46, 5230, bwn_b2063_chantable_data[11] },
678203945Sweongyo	{ 48, 5240, bwn_b2063_chantable_data[12] },
679203945Sweongyo	{ 52, 5260, bwn_b2063_chantable_data[13] },
680203945Sweongyo	{ 56, 5280, bwn_b2063_chantable_data[14] },
681203945Sweongyo	{ 60, 5300, bwn_b2063_chantable_data[14] },
682203945Sweongyo	{ 64, 5320, bwn_b2063_chantable_data[15] },
683203945Sweongyo	{ 100, 5500, bwn_b2063_chantable_data[16] },
684203945Sweongyo	{ 104, 5520, bwn_b2063_chantable_data[17] },
685203945Sweongyo	{ 108, 5540, bwn_b2063_chantable_data[18] },
686203945Sweongyo	{ 112, 5560, bwn_b2063_chantable_data[19] },
687203945Sweongyo	{ 116, 5580, bwn_b2063_chantable_data[20] },
688203945Sweongyo	{ 120, 5600, bwn_b2063_chantable_data[21] },
689203945Sweongyo	{ 124, 5620, bwn_b2063_chantable_data[21] },
690203945Sweongyo	{ 128, 5640, bwn_b2063_chantable_data[22] },
691203945Sweongyo	{ 132, 5660, bwn_b2063_chantable_data[22] },
692203945Sweongyo	{ 136, 5680, bwn_b2063_chantable_data[22] },
693203945Sweongyo	{ 140, 5700, bwn_b2063_chantable_data[23] },
694203945Sweongyo	{ 149, 5745, bwn_b2063_chantable_data[23] },
695203945Sweongyo	{ 153, 5765, bwn_b2063_chantable_data[23] },
696203945Sweongyo	{ 157, 5785, bwn_b2063_chantable_data[23] },
697203945Sweongyo	{ 161, 5805, bwn_b2063_chantable_data[23] },
698203945Sweongyo	{ 165, 5825, bwn_b2063_chantable_data[23] },
699203945Sweongyo	{ 184, 4920, bwn_b2063_chantable_data[24] },
700203945Sweongyo	{ 188, 4940, bwn_b2063_chantable_data[25] },
701203945Sweongyo	{ 192, 4960, bwn_b2063_chantable_data[26] },
702203945Sweongyo	{ 196, 4980, bwn_b2063_chantable_data[27] },
703203945Sweongyo	{ 200, 5000, bwn_b2063_chantable_data[28] },
704203945Sweongyo	{ 204, 5020, bwn_b2063_chantable_data[29] },
705203945Sweongyo	{ 208, 5040, bwn_b2063_chantable_data[30] },
706203945Sweongyo	{ 212, 5060, bwn_b2063_chantable_data[31] },
707203945Sweongyo	{ 216, 5080, bwn_b2063_chantable_data[32] }
708203945Sweongyo};
709203945Sweongyo
710203945Sweongyostatic const uint8_t bwn_b2062_chantable_data[22][12] = {
711203945Sweongyo	{ 0xff, 0xff, 0xb5, 0x1b, 0x24, 0x32, 0x32, 0x88, 0x88, 0, 0, 0 },
712203945Sweongyo	{ 0, 0x22, 0x20, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
713203945Sweongyo	{ 0, 0x11, 0x10, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
714203945Sweongyo	{ 0, 0, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
715203945Sweongyo	{ 0, 0x11, 0x20, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
716203945Sweongyo	{ 0, 0x11, 0x10, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
717203945Sweongyo	{ 0, 0x11, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
718203945Sweongyo	{ 0, 0, 0, 0x63, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
719203945Sweongyo	{ 0, 0, 0, 0x62, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
720203945Sweongyo	{ 0, 0, 0, 0x30, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
721203945Sweongyo	{ 0, 0, 0, 0x20, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
722203945Sweongyo	{ 0, 0, 0, 0x10, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
723203945Sweongyo	{ 0, 0, 0, 0, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
724203945Sweongyo	{ 0x55, 0x77, 0x90, 0xf7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
725203945Sweongyo	{ 0x44, 0x77, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
726203945Sweongyo	{ 0x44, 0x66, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
727203945Sweongyo	{ 0x33, 0x66, 0x70, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
728203945Sweongyo	{ 0x22, 0x55, 0x60, 0xd7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
729203945Sweongyo	{ 0x22, 0x55, 0x60, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
730203945Sweongyo	{ 0x22, 0x44, 0x50, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
731203945Sweongyo	{ 0x11, 0x44, 0x50, 0xa5, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
732203945Sweongyo	{ 0, 0x44, 0x40, 0xb6, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 }
733203945Sweongyo};
734203945Sweongyo
735203945Sweongyostatic const struct bwn_b206x_chan bwn_b2062_chantable[] = {
736203945Sweongyo	{ 1, 2412, bwn_b2062_chantable_data[0] },
737203945Sweongyo	{ 2, 2417, bwn_b2062_chantable_data[0] },
738203945Sweongyo	{ 3, 2422, bwn_b2062_chantable_data[0] },
739203945Sweongyo	{ 4, 2427, bwn_b2062_chantable_data[0] },
740203945Sweongyo	{ 5, 2432, bwn_b2062_chantable_data[0] },
741203945Sweongyo	{ 6, 2437, bwn_b2062_chantable_data[0] },
742203945Sweongyo	{ 7, 2442, bwn_b2062_chantable_data[0] },
743203945Sweongyo	{ 8, 2447, bwn_b2062_chantable_data[0] },
744203945Sweongyo	{ 9, 2452, bwn_b2062_chantable_data[0] },
745203945Sweongyo	{ 10, 2457, bwn_b2062_chantable_data[0] },
746203945Sweongyo	{ 11, 2462, bwn_b2062_chantable_data[0] },
747203945Sweongyo	{ 12, 2467, bwn_b2062_chantable_data[0] },
748203945Sweongyo	{ 13, 2472, bwn_b2062_chantable_data[0] },
749203945Sweongyo	{ 14, 2484, bwn_b2062_chantable_data[0] },
750203945Sweongyo	{ 34, 5170, bwn_b2062_chantable_data[1] },
751203945Sweongyo	{ 38, 5190, bwn_b2062_chantable_data[2] },
752203945Sweongyo	{ 42, 5210, bwn_b2062_chantable_data[2] },
753203945Sweongyo	{ 46, 5230, bwn_b2062_chantable_data[3] },
754203945Sweongyo	{ 36, 5180, bwn_b2062_chantable_data[4] },
755203945Sweongyo	{ 40, 5200, bwn_b2062_chantable_data[5] },
756203945Sweongyo	{ 44, 5220, bwn_b2062_chantable_data[6] },
757203945Sweongyo	{ 48, 5240, bwn_b2062_chantable_data[3] },
758203945Sweongyo	{ 52, 5260, bwn_b2062_chantable_data[3] },
759203945Sweongyo	{ 56, 5280, bwn_b2062_chantable_data[3] },
760203945Sweongyo	{ 60, 5300, bwn_b2062_chantable_data[7] },
761203945Sweongyo	{ 64, 5320, bwn_b2062_chantable_data[8] },
762203945Sweongyo	{ 100, 5500, bwn_b2062_chantable_data[9] },
763203945Sweongyo	{ 104, 5520, bwn_b2062_chantable_data[10] },
764203945Sweongyo	{ 108, 5540, bwn_b2062_chantable_data[10] },
765203945Sweongyo	{ 112, 5560, bwn_b2062_chantable_data[10] },
766203945Sweongyo	{ 116, 5580, bwn_b2062_chantable_data[11] },
767203945Sweongyo	{ 120, 5600, bwn_b2062_chantable_data[12] },
768203945Sweongyo	{ 124, 5620, bwn_b2062_chantable_data[12] },
769203945Sweongyo	{ 128, 5640, bwn_b2062_chantable_data[12] },
770203945Sweongyo	{ 132, 5660, bwn_b2062_chantable_data[12] },
771203945Sweongyo	{ 136, 5680, bwn_b2062_chantable_data[12] },
772203945Sweongyo	{ 140, 5700, bwn_b2062_chantable_data[12] },
773203945Sweongyo	{ 149, 5745, bwn_b2062_chantable_data[12] },
774203945Sweongyo	{ 153, 5765, bwn_b2062_chantable_data[12] },
775203945Sweongyo	{ 157, 5785, bwn_b2062_chantable_data[12] },
776203945Sweongyo	{ 161, 5805, bwn_b2062_chantable_data[12] },
777203945Sweongyo	{ 165, 5825, bwn_b2062_chantable_data[12] },
778203945Sweongyo	{ 184, 4920, bwn_b2062_chantable_data[13] },
779203945Sweongyo	{ 188, 4940, bwn_b2062_chantable_data[14] },
780203945Sweongyo	{ 192, 4960, bwn_b2062_chantable_data[15] },
781203945Sweongyo	{ 196, 4980, bwn_b2062_chantable_data[16] },
782203945Sweongyo	{ 200, 5000, bwn_b2062_chantable_data[17] },
783203945Sweongyo	{ 204, 5020, bwn_b2062_chantable_data[18] },
784203945Sweongyo	{ 208, 5040, bwn_b2062_chantable_data[19] },
785203945Sweongyo	{ 212, 5060, bwn_b2062_chantable_data[20] },
786203945Sweongyo	{ 216, 5080, bwn_b2062_chantable_data[21] }
787203945Sweongyo};
788203945Sweongyo
789203945Sweongyo/* for LP PHY */
790203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_5354[] = {
791203945Sweongyo	{  1, -66, 15 }, {  2, -66, 15 }, {  3, -66, 15 }, {  4, -66, 15 },
792203945Sweongyo	{  5, -66, 15 }, {  6, -66, 15 }, {  7, -66, 14 }, {  8, -66, 14 },
793203945Sweongyo	{  9, -66, 14 }, { 10, -66, 14 }, { 11, -66, 14 }, { 12, -66, 13 },
794203945Sweongyo	{ 13, -66, 13 }, { 14, -66, 13 },
795203945Sweongyo};
796203945Sweongyo
797203945Sweongyo/* for LP PHY */
798203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r12[] = {
799203945Sweongyo	{   1, -64, 13 }, {   2, -64, 13 }, {   3, -64, 13 }, {   4, -64, 13 },
800203945Sweongyo	{   5, -64, 12 }, {   6, -64, 12 }, {   7, -64, 12 }, {   8, -64, 12 },
801203945Sweongyo	{   9, -64, 12 }, {  10, -64, 11 }, {  11, -64, 11 }, {  12, -64, 11 },
802203945Sweongyo	{  13, -64, 11 }, {  14, -64, 10 }, {  34, -62, 24 }, {  38, -62, 24 },
803203945Sweongyo	{  42, -62, 24 }, {  46, -62, 23 }, {  36, -62, 24 }, {  40, -62, 24 },
804203945Sweongyo	{  44, -62, 23 }, {  48, -62, 23 }, {  52, -62, 23 }, {  56, -62, 22 },
805203945Sweongyo	{  60, -62, 22 }, {  64, -62, 22 }, { 100, -62, 16 }, { 104, -62, 16 },
806203945Sweongyo	{ 108, -62, 15 }, { 112, -62, 14 }, { 116, -62, 14 }, { 120, -62, 13 },
807203945Sweongyo	{ 124, -62, 12 }, { 128, -62, 12 }, { 132, -62, 12 }, { 136, -62, 11 },
808203945Sweongyo	{ 140, -62, 10 }, { 149, -61,  9 }, { 153, -61,  9 }, { 157, -61,  9 },
809203945Sweongyo	{ 161, -61,  8 }, { 165, -61,  8 }, { 184, -62, 25 }, { 188, -62, 25 },
810203945Sweongyo	{ 192, -62, 25 }, { 196, -62, 25 }, { 200, -62, 25 }, { 204, -62, 25 },
811203945Sweongyo	{ 208, -62, 25 }, { 212, -62, 25 }, { 216, -62, 26 },
812203945Sweongyo};
813203945Sweongyo
814203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r2 = { 0, -64, 0 };
815203945Sweongyo
816203945Sweongyostatic const uint8_t bwn_tab_sigsq_tbl[] = {
817203945Sweongyo	0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
818203945Sweongyo	0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
819203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
820203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
821203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
822203945Sweongyo	0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
823203945Sweongyo};
824203945Sweongyo
825203945Sweongyostatic const uint8_t bwn_tab_pllfrac_tbl[] = {
826203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
827203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
828203945Sweongyo};
829203945Sweongyo
830203945Sweongyostatic const uint16_t bwn_tabl_iqlocal_tbl[] = {
831203945Sweongyo	0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
832203945Sweongyo	0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
833203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
834203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
835203945Sweongyo	0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
836203945Sweongyo	0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
837203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
838203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
839203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
840203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
841203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
842203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
843203945Sweongyo};
844203945Sweongyo
845203945Sweongyostatic const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
846203945Sweongyostatic const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
847203945Sweongyostatic const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
848203945Sweongyostatic const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
849203945Sweongyostatic const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
850203945Sweongyoconst uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
851203945Sweongyo
852203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
853203945Sweongyo{							\
854203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
855203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
856203945Sweongyo}
857203945Sweongyo
858203945Sweongyostatic const struct {
859203945Sweongyo	uint16_t	vid;
860203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
861203945Sweongyo} bwn_vendor_led_act[] = {
862203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
863203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
864203945Sweongyo};
865203945Sweongyo
866203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
867203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
868203945Sweongyo
869203945Sweongyo#undef VENDOR_LED_ACT
870203945Sweongyo
871203945Sweongyostatic const struct {
872203945Sweongyo	int		on_dur;
873203945Sweongyo	int		off_dur;
874203945Sweongyo} bwn_led_duration[109] = {
875203945Sweongyo	[0]	= { 400, 100 },
876203945Sweongyo	[2]	= { 150, 75 },
877203945Sweongyo	[4]	= { 90, 45 },
878203945Sweongyo	[11]	= { 66, 34 },
879203945Sweongyo	[12]	= { 53, 26 },
880203945Sweongyo	[18]	= { 42, 21 },
881203945Sweongyo	[22]	= { 35, 17 },
882203945Sweongyo	[24]	= { 32, 16 },
883203945Sweongyo	[36]	= { 21, 10 },
884203945Sweongyo	[48]	= { 16, 8 },
885203945Sweongyo	[72]	= { 11, 5 },
886203945Sweongyo	[96]	= { 9, 4 },
887203945Sweongyo	[108]	= { 7, 3 }
888203945Sweongyo};
889203945Sweongyo
890203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
891203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
892203945Sweongyo	[1] = BWN_WME_BACKGROUND,
893203945Sweongyo	[2] = BWN_WME_VOICE,
894203945Sweongyo	[3] = BWN_WME_VIDEO,
895203945Sweongyo};
896203945Sweongyo
897203945Sweongyostatic const struct siba_devid bwn_devs[] = {
898203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
899203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
900203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
901203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
902203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
903203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
904203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
905203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
906203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
907203945Sweongyo};
908203945Sweongyo
909203945Sweongyostatic int
910203945Sweongyobwn_probe(device_t dev)
911203945Sweongyo{
912203945Sweongyo	struct siba_dev_softc *sd = device_get_ivars(dev);
913203945Sweongyo	int i;
914203945Sweongyo
915203945Sweongyo	for (i = 0; i < sizeof(bwn_devs) / sizeof(bwn_devs[0]); i++) {
916203945Sweongyo		if (sd->sd_id.sd_vendor == bwn_devs[i].sd_vendor &&
917203945Sweongyo		    sd->sd_id.sd_device == bwn_devs[i].sd_device &&
918203945Sweongyo		    sd->sd_id.sd_rev == bwn_devs[i].sd_rev)
919203945Sweongyo			return (BUS_PROBE_DEFAULT);
920203945Sweongyo	}
921203945Sweongyo
922203945Sweongyo	return (ENXIO);
923203945Sweongyo}
924203945Sweongyo
925203945Sweongyostatic int
926203945Sweongyobwn_attach(device_t dev)
927203945Sweongyo{
928203945Sweongyo	struct bwn_mac *mac;
929203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
930203945Sweongyo	struct siba_dev_softc *sd = device_get_ivars(dev);
931203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
932203945Sweongyo	int error, i, msic, reg;
933203945Sweongyo
934203945Sweongyo	sc->sc_dev = dev;
935203945Sweongyo	sc->sc_sd = sd;
936203945Sweongyo#ifdef BWN_DEBUG
937203945Sweongyo	sc->sc_debug = bwn_debug;
938203945Sweongyo#endif
939203945Sweongyo
940203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
941203945Sweongyo		error = bwn_attach_pre(sc);
942203945Sweongyo		if (error != 0)
943203945Sweongyo			return (error);
944203945Sweongyo		bwn_sprom_bugfixes(sd->sd_bus);
945203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
946203945Sweongyo	}
947203945Sweongyo
948203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
949203945Sweongyo		if (siba->siba_pci_did != 0x4313 &&
950203945Sweongyo		    siba->siba_pci_did != 0x431a &&
951203945Sweongyo		    siba->siba_pci_did != 0x4321) {
952203945Sweongyo			device_printf(sc->sc_dev,
953203945Sweongyo			    "skip 802.11 cores\n");
954203945Sweongyo			return (ENODEV);
955203945Sweongyo		}
956203945Sweongyo	}
957203945Sweongyo
958203945Sweongyo	mac = (struct bwn_mac *)malloc(sizeof(*mac), M_DEVBUF,
959203945Sweongyo	    M_NOWAIT | M_ZERO);
960203945Sweongyo	if (mac == NULL)
961203945Sweongyo		return (ENOMEM);
962203945Sweongyo	mac->mac_sc = sc;
963203945Sweongyo	mac->mac_sd = sd;
964203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
965203945Sweongyo	if (bwn_bfp != 0)
966203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
967203945Sweongyo
968203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
969203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
970203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
971203945Sweongyo
972203945Sweongyo	error = bwn_attach_core(mac);
973203945Sweongyo	if (error)
974203945Sweongyo		goto fail0;
975203945Sweongyo	bwn_led_attach(mac);
976203945Sweongyo
977203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
978203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
979203945Sweongyo	    sd->sd_bus->siba_chipid, sd->sd_id.sd_rev,
980203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
981203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
982203945Sweongyo	    mac->mac_phy.rf_rev);
983203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
984203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
985203945Sweongyo		    mac->mac_method.dma.dmatype);
986203945Sweongyo	else
987203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
988203945Sweongyo
989203945Sweongyo	/*
990203945Sweongyo	 * setup PCI resources and interrupt.
991203945Sweongyo	 */
992203945Sweongyo	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
993203945Sweongyo		msic = pci_msi_count(dev);
994203945Sweongyo		if (bootverbose)
995203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
996203945Sweongyo	} else
997203945Sweongyo		msic = 0;
998203945Sweongyo
999203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
1000203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
1001203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
1002203945Sweongyo			device_printf(sc->sc_dev,
1003203945Sweongyo			    "Using %d MSI messages\n", msic);
1004203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
1005203945Sweongyo			mac->mac_msi = 1;
1006203945Sweongyo		}
1007203945Sweongyo	}
1008203945Sweongyo
1009203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
1010203945Sweongyo	    mac->mac_res_irq);
1011203945Sweongyo	if (error) {
1012203945Sweongyo		device_printf(sc->sc_dev,
1013203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
1014203945Sweongyo		goto fail1;
1015203945Sweongyo	}
1016203945Sweongyo
1017203945Sweongyo	if (mac->mac_msi == 0)
1018203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
1019203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1020203945Sweongyo		    &mac->mac_intrhand[0]);
1021203945Sweongyo	else {
1022203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1023203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
1024203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1025203945Sweongyo			    &mac->mac_intrhand[i]);
1026203945Sweongyo			if (error != 0) {
1027203945Sweongyo				device_printf(sc->sc_dev,
1028203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
1029203945Sweongyo				break;
1030203945Sweongyo			}
1031203945Sweongyo		}
1032203945Sweongyo	}
1033203945Sweongyo
1034203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
1035203945Sweongyo
1036203945Sweongyo	/*
1037203945Sweongyo	 * calls attach-post routine
1038203945Sweongyo	 */
1039203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
1040203945Sweongyo		bwn_attach_post(sc);
1041203945Sweongyo
1042203945Sweongyo	return (0);
1043203945Sweongyofail1:
1044203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
1045203945Sweongyo		pci_release_msi(dev);
1046203945Sweongyofail0:
1047203945Sweongyo	free(mac, M_DEVBUF);
1048203945Sweongyo	return (error);
1049203945Sweongyo}
1050203945Sweongyo
1051203945Sweongyostatic int
1052203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
1053203945Sweongyo{
1054203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
1055203945Sweongyo
1056203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
1057203945Sweongyo		return (FALSE);
1058203945Sweongyo
1059203945Sweongyo	return (TRUE);
1060203945Sweongyo}
1061203945Sweongyo
1062203945Sweongyostatic int
1063203945Sweongyobwn_attach_post(struct bwn_softc *sc)
1064203945Sweongyo{
1065203945Sweongyo	struct ieee80211com *ic;
1066203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1067203945Sweongyo	struct siba_dev_softc *sd = sc->sc_sd;
1068203945Sweongyo	struct siba_sprom *sprom = &sd->sd_bus->siba_sprom;
1069203945Sweongyo#ifdef BWN_DEBUG
1070203945Sweongyo	device_t dev = sc->sc_dev;
1071203945Sweongyo#endif
1072203945Sweongyo
1073203945Sweongyo	ic = ifp->if_l2com;
1074203945Sweongyo	ic->ic_ifp = ifp;
1075203945Sweongyo	/* XXX not right but it's not used anywhere important */
1076203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
1077203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
1078203945Sweongyo	ic->ic_caps =
1079203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
1080203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
1081203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
1082203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
1083203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
1084203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
1085203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
1086203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
1087203945Sweongyo		;
1088203945Sweongyo
1089203945Sweongyo	/* call MI attach routine. */
1090203945Sweongyo	ieee80211_ifattach(ic,
1091203945Sweongyo	    bwn_is_valid_ether_addr(sprom->mac_80211a) ? sprom->mac_80211a :
1092203945Sweongyo	    sprom->mac_80211bg);
1093203945Sweongyo
1094203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
1095203945Sweongyo
1096203945Sweongyo	/* override default methods */
1097203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
1098203945Sweongyo	ic->ic_newassoc = bwn_newassoc;
1099203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
1100203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
1101203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
1102203945Sweongyo
1103203945Sweongyo	ic->ic_node_alloc = bwn_node_alloc;
1104203945Sweongyo	sc->sc_node_cleanup = ic->ic_node_cleanup;
1105203945Sweongyo	ic->ic_node_cleanup = bwn_node_cleanup;
1106203945Sweongyo
1107203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
1108203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
1109203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
1110203945Sweongyo
1111203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
1112203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
1113203945Sweongyo
1114203945Sweongyo	ieee80211_radiotap_attach(ic,
1115203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
1116203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
1117203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
1118203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
1119203945Sweongyo
1120203945Sweongyo#ifdef BWN_DEBUG
1121203945Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1122203945Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1123203945Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
1124203945Sweongyo#endif
1125203945Sweongyo
1126203945Sweongyo	if (bootverbose)
1127203945Sweongyo		ieee80211_announce(ic);
1128203945Sweongyo	return (0);
1129203945Sweongyo}
1130203945Sweongyo
1131203945Sweongyostatic void
1132203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
1133203945Sweongyo{
1134203945Sweongyo
1135203945Sweongyo	if (mac->mac_phy.detach != NULL)
1136203945Sweongyo		mac->mac_phy.detach(mac);
1137203945Sweongyo}
1138203945Sweongyo
1139203945Sweongyostatic int
1140203945Sweongyobwn_detach(device_t dev)
1141203945Sweongyo{
1142203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
1143203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1144203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1145203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1146203945Sweongyo	int i;
1147203945Sweongyo
1148203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
1149203945Sweongyo
1150203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
1151203945Sweongyo		bwn_stop(sc, 1);
1152203945Sweongyo		bwn_dma_free(mac);
1153203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
1154203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
1155203945Sweongyo		callout_drain(&sc->sc_task_ch);
1156203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
1157203945Sweongyo		bwn_phy_detach(mac);
1158203945Sweongyo		if (ifp != NULL) {
1159203945Sweongyo			ieee80211_draintask(ic, &mac->mac_hwreset);
1160203945Sweongyo			ieee80211_draintask(ic, &mac->mac_txpower);
1161203945Sweongyo			ieee80211_ifdetach(ic);
1162203945Sweongyo			if_free(ifp);
1163203945Sweongyo		}
1164203945Sweongyo	}
1165203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
1166203945Sweongyo	taskqueue_free(sc->sc_tq);
1167203945Sweongyo
1168203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1169203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
1170203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
1171203945Sweongyo			    mac->mac_intrhand[i]);
1172203945Sweongyo			mac->mac_intrhand[i] = NULL;
1173203945Sweongyo		}
1174203945Sweongyo	}
1175203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
1176203945Sweongyo	if (mac->mac_msi != 0)
1177203945Sweongyo		pci_release_msi(dev);
1178203945Sweongyo
1179203945Sweongyo	BWN_LOCK_DESTROY(sc);
1180203945Sweongyo	return (0);
1181203945Sweongyo}
1182203945Sweongyo
1183203945Sweongyostatic int
1184203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
1185203945Sweongyo{
1186203945Sweongyo	struct ifnet *ifp;
1187203945Sweongyo	int error = 0;
1188203945Sweongyo
1189203945Sweongyo	BWN_LOCK_INIT(sc);
1190203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
1191203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
1192203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
1193203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
1194203945Sweongyo
1195203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
1196203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
1197203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
1198203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
1199203945Sweongyo
1200203945Sweongyo	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
1201203945Sweongyo	if (ifp == NULL) {
1202203945Sweongyo		device_printf(sc->sc_dev, "can not if_alloc()\n");
1203203945Sweongyo		error = ENOSPC;
1204203945Sweongyo		goto fail;
1205203945Sweongyo	}
1206203945Sweongyo
1207203945Sweongyo	/* set these up early for if_printf use */
1208203945Sweongyo	if_initname(ifp, device_get_name(sc->sc_dev),
1209203945Sweongyo	    device_get_unit(sc->sc_dev));
1210203945Sweongyo
1211203945Sweongyo	ifp->if_softc = sc;
1212203945Sweongyo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1213203945Sweongyo	ifp->if_init = bwn_init;
1214203945Sweongyo	ifp->if_ioctl = bwn_ioctl;
1215203945Sweongyo	ifp->if_start = bwn_start;
1216203945Sweongyo	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
1217203945Sweongyo	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
1218203945Sweongyo	IFQ_SET_READY(&ifp->if_snd);
1219203945Sweongyo
1220203945Sweongyo	return (0);
1221203945Sweongyo
1222203945Sweongyofail:	BWN_LOCK_DESTROY(sc);
1223203945Sweongyo	return (error);
1224203945Sweongyo}
1225203945Sweongyo
1226203945Sweongyostatic void
1227203945Sweongyobwn_sprom_bugfixes(struct siba_softc *siba)
1228203945Sweongyo{
1229203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
1230203945Sweongyo	((siba->siba_pci_vid == PCI_VENDOR_##_vendor) &&		\
1231203945Sweongyo	 (siba->siba_pci_did == _device) &&				\
1232203945Sweongyo	 (siba->siba_pci_subvid == PCI_VENDOR_##_subvendor) &&		\
1233203945Sweongyo	 (siba->siba_pci_subdid == _subdevice))
1234203945Sweongyo
1235203945Sweongyo	if (siba->siba_board_vendor == PCI_VENDOR_APPLE &&
1236203945Sweongyo	    siba->siba_board_type == 0x4e && siba->siba_board_rev > 0x40)
1237203945Sweongyo		siba->siba_sprom.bf_lo |= BWN_BFL_PACTRL;
1238203945Sweongyo	if (siba->siba_board_vendor == SIBA_BOARDVENDOR_DELL &&
1239203945Sweongyo	    siba->siba_chipid == 0x4301 && siba->siba_board_rev == 0x74)
1240203945Sweongyo		siba->siba_sprom.bf_lo |= BWN_BFL_BTCOEXIST;
1241203945Sweongyo	if (siba->siba_type == SIBA_TYPE_PCI) {
1242203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
1243203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
1244203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
1245203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
1246203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
1247203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
1248203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
1249203945Sweongyo			siba->siba_sprom.bf_lo &= ~BWN_BFL_BTCOEXIST;
1250203945Sweongyo	}
1251203945Sweongyo#undef	BWN_ISDEV
1252203945Sweongyo}
1253203945Sweongyo
1254203945Sweongyostatic int
1255203945Sweongyobwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1256203945Sweongyo{
1257203945Sweongyo#define	IS_RUNNING(ifp) \
1258203945Sweongyo	((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
1259203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1260203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1261203945Sweongyo	struct ifreq *ifr = (struct ifreq *)data;
1262203945Sweongyo	int error = 0, startall;
1263203945Sweongyo
1264203945Sweongyo	switch (cmd) {
1265203945Sweongyo	case SIOCSIFFLAGS:
1266203945Sweongyo		startall = 0;
1267203945Sweongyo		if (IS_RUNNING(ifp)) {
1268203945Sweongyo			bwn_update_promisc(ifp);
1269203945Sweongyo		} else if (ifp->if_flags & IFF_UP) {
1270203945Sweongyo			if ((sc->sc_flags & BWN_FLAG_INVALID) == 0) {
1271203945Sweongyo				bwn_init(sc);
1272203945Sweongyo				startall = 1;
1273203945Sweongyo			}
1274203945Sweongyo		} else
1275203945Sweongyo			bwn_stop(sc, 1);
1276203945Sweongyo		if (startall)
1277203945Sweongyo			ieee80211_start_all(ic);
1278203945Sweongyo		break;
1279203945Sweongyo	case SIOCGIFMEDIA:
1280203945Sweongyo		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1281203945Sweongyo		break;
1282203945Sweongyo	case SIOCGIFADDR:
1283203945Sweongyo		error = ether_ioctl(ifp, cmd, data);
1284203945Sweongyo		break;
1285203945Sweongyo	default:
1286203945Sweongyo		error = EINVAL;
1287203945Sweongyo		break;
1288203945Sweongyo	}
1289203945Sweongyo	return (error);
1290203945Sweongyo}
1291203945Sweongyo
1292203945Sweongyostatic void
1293203945Sweongyobwn_start(struct ifnet *ifp)
1294203945Sweongyo{
1295203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1296203945Sweongyo
1297203945Sweongyo	BWN_LOCK(sc);
1298203945Sweongyo	bwn_start_locked(ifp);
1299203945Sweongyo	BWN_UNLOCK(sc);
1300203945Sweongyo}
1301203945Sweongyo
1302203945Sweongyostatic void
1303203945Sweongyobwn_start_locked(struct ifnet *ifp)
1304203945Sweongyo{
1305203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
1306203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1307203945Sweongyo	struct ieee80211_frame *wh;
1308203945Sweongyo	struct ieee80211_node *ni;
1309203945Sweongyo	struct ieee80211_key *k;
1310203945Sweongyo	struct mbuf *m;
1311203945Sweongyo
1312203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1313203945Sweongyo
1314203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || mac == NULL ||
1315203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
1316203945Sweongyo		return;
1317203945Sweongyo
1318203945Sweongyo	for (;;) {
1319203945Sweongyo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);	/* XXX: LOCK */
1320203945Sweongyo		if (m == NULL)
1321203945Sweongyo			break;
1322203945Sweongyo
1323203945Sweongyo		if (bwn_tx_isfull(sc, m))
1324203945Sweongyo			break;
1325203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
1326203945Sweongyo		if (ni == NULL) {
1327203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
1328203945Sweongyo			m_freem(m);
1329203945Sweongyo			ifp->if_oerrors++;
1330203945Sweongyo			continue;
1331203945Sweongyo		}
1332203945Sweongyo		KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__));
1333203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
1334203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1335203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
1336203945Sweongyo			if (k == NULL) {
1337203945Sweongyo				ieee80211_free_node(ni);
1338203945Sweongyo				m_freem(m);
1339203945Sweongyo				ifp->if_oerrors++;
1340203945Sweongyo				continue;
1341203945Sweongyo			}
1342203945Sweongyo		}
1343203945Sweongyo		wh = NULL;	/* Catch any invalid use */
1344203945Sweongyo
1345203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
1346203945Sweongyo			if (ni != NULL)
1347203945Sweongyo				ieee80211_free_node(ni);
1348203945Sweongyo			ifp->if_oerrors++;
1349203945Sweongyo			continue;
1350203945Sweongyo		}
1351203945Sweongyo
1352203945Sweongyo		sc->sc_watchdog_timer = 5;
1353203945Sweongyo	}
1354203945Sweongyo}
1355203945Sweongyo
1356203945Sweongyostatic int
1357203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
1358203945Sweongyo{
1359203945Sweongyo	struct bwn_dma_ring *dr;
1360203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1361203945Sweongyo	struct bwn_pio_txqueue *tq;
1362203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1363203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1364203945Sweongyo
1365203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1366203945Sweongyo
1367203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
1368203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
1369203945Sweongyo		if (dr->dr_stop == 1 ||
1370203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
1371203945Sweongyo			dr->dr_stop = 1;
1372203945Sweongyo			goto full;
1373203945Sweongyo		}
1374203945Sweongyo	} else {
1375203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
1376203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
1377203945Sweongyo		    pktlen > (tq->tq_size - tq->tq_used)) {
1378203945Sweongyo			tq->tq_stop = 1;
1379203945Sweongyo			goto full;
1380203945Sweongyo		}
1381203945Sweongyo	}
1382203945Sweongyo	return (0);
1383203945Sweongyofull:
1384203945Sweongyo	IFQ_DRV_PREPEND(&ifp->if_snd, m);
1385203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1386203945Sweongyo	return (1);
1387203945Sweongyo}
1388203945Sweongyo
1389203945Sweongyostatic int
1390203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
1391203945Sweongyo{
1392203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1393203945Sweongyo	int error;
1394203945Sweongyo
1395203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1396203945Sweongyo
1397203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
1398203945Sweongyo		m_freem(m);
1399203945Sweongyo		return (ENXIO);
1400203945Sweongyo	}
1401203945Sweongyo
1402203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
1403203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
1404203945Sweongyo	if (error) {
1405203945Sweongyo		m_freem(m);
1406203945Sweongyo		return (error);
1407203945Sweongyo	}
1408203945Sweongyo	return (0);
1409203945Sweongyo}
1410203945Sweongyo
1411203945Sweongyostatic int
1412203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1413203945Sweongyo{
1414203945Sweongyo	struct bwn_pio_txpkt *tp;
1415203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
1416203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1417203945Sweongyo	struct bwn_txhdr txhdr;
1418203945Sweongyo	struct mbuf *m_new;
1419203945Sweongyo	uint32_t ctl32;
1420203945Sweongyo	int error;
1421203945Sweongyo	uint16_t ctl16;
1422203945Sweongyo
1423203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1424203945Sweongyo
1425203945Sweongyo	/* XXX TODO send packets after DTIM */
1426203945Sweongyo
1427203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
1428203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
1429203945Sweongyo	tp->tp_ni = ni;
1430203945Sweongyo	tp->tp_m = m;
1431203945Sweongyo
1432203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
1433203945Sweongyo	if (error) {
1434203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
1435203945Sweongyo		return (error);
1436203945Sweongyo	}
1437203945Sweongyo
1438203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
1439203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1440203945Sweongyo	tq->tq_free--;
1441203945Sweongyo
1442203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 8) {
1443203945Sweongyo		/*
1444203945Sweongyo		 * XXX please removes m_defrag(9)
1445203945Sweongyo		 */
1446203945Sweongyo		m_new = m_defrag(m, M_DONTWAIT);
1447203945Sweongyo		if (m_new == NULL) {
1448203945Sweongyo			device_printf(sc->sc_dev,
1449203945Sweongyo			    "%s: can't defrag TX buffer\n",
1450203945Sweongyo			    __func__);
1451203945Sweongyo			return (ENOBUFS);
1452203945Sweongyo		}
1453203945Sweongyo		if (m_new->m_next != NULL)
1454203945Sweongyo			device_printf(sc->sc_dev,
1455203945Sweongyo			    "TODO: fragmented packets for PIO\n");
1456203945Sweongyo		tp->tp_m = m_new;
1457203945Sweongyo
1458203945Sweongyo		/* send HEADER */
1459203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
1460203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
1461203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
1462203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1463203945Sweongyo		/* send BODY */
1464203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
1465203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
1466203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
1467203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
1468203945Sweongyo	} else {
1469203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
1470203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
1471203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
1472203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1473203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
1474203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
1475203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
1476203945Sweongyo	}
1477203945Sweongyo
1478203945Sweongyo	return (0);
1479203945Sweongyo}
1480203945Sweongyo
1481203945Sweongyostatic struct bwn_pio_txqueue *
1482203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1483203945Sweongyo{
1484203945Sweongyo
1485203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1486203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1487203945Sweongyo
1488203945Sweongyo	switch (prio) {
1489203945Sweongyo	case 0:
1490203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1491203945Sweongyo	case 1:
1492203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1493203945Sweongyo	case 2:
1494203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1495203945Sweongyo	case 3:
1496203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1497203945Sweongyo	}
1498203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1499203945Sweongyo}
1500203945Sweongyo
1501203945Sweongyostatic int
1502203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1503203945Sweongyo{
1504203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1505203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1506203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1507203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1508203945Sweongyo	struct bwn_dmadesc_generic *desc;
1509203945Sweongyo	struct bwn_dmadesc_meta *mt;
1510203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1511203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1512203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1513203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1514203945Sweongyo
1515203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1516203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1517203945Sweongyo
1518203945Sweongyo	/* XXX send after DTIM */
1519203945Sweongyo
1520203945Sweongyo	slot = bwn_dma_getslot(dr);
1521203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1522203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1523203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1524203945Sweongyo
1525203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1526203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1527203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1528203945Sweongyo	if (error)
1529203945Sweongyo		goto fail;
1530203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1531203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1532203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1533203945Sweongyo	if (error) {
1534203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1535203945Sweongyo		    __func__, error);
1536203945Sweongyo		goto fail;
1537203945Sweongyo	}
1538203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1539203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1540203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1541203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1542203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1543203945Sweongyo
1544203945Sweongyo	slot = bwn_dma_getslot(dr);
1545203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1546203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1547203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1548203945Sweongyo	mt->mt_m = m;
1549203945Sweongyo	mt->mt_ni = ni;
1550203945Sweongyo
1551203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1552203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1553203945Sweongyo	if (error && error != EFBIG) {
1554203945Sweongyo		if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
1555203945Sweongyo		    __func__, error);
1556203945Sweongyo		goto fail;
1557203945Sweongyo	}
1558203945Sweongyo	if (error) {    /* error == EFBIG */
1559203945Sweongyo		struct mbuf *m_new;
1560203945Sweongyo
1561203945Sweongyo		m_new = m_defrag(m, M_DONTWAIT);
1562203945Sweongyo		if (m_new == NULL) {
1563203945Sweongyo			if_printf(ifp, "%s: can't defrag TX buffer\n",
1564203945Sweongyo			    __func__);
1565203945Sweongyo			error = ENOBUFS;
1566203945Sweongyo			goto fail;
1567203945Sweongyo		} else {
1568203945Sweongyo			m = m_new;
1569203945Sweongyo		}
1570203945Sweongyo
1571203945Sweongyo		mt->mt_m = m;
1572203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1573203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1574203945Sweongyo		if (error) {
1575203945Sweongyo			if_printf(ifp, "%s: can't load TX buffer (2) %d\n",
1576203945Sweongyo			    __func__, error);
1577203945Sweongyo			goto fail;
1578203945Sweongyo		}
1579203945Sweongyo	}
1580203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1581203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1582203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1583203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1584203945Sweongyo
1585203945Sweongyo	/* XXX send after DTIM */
1586203945Sweongyo
1587203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1588203945Sweongyo	return (0);
1589203945Sweongyofail:
1590203945Sweongyo	dr->dr_curslot = backup[0];
1591203945Sweongyo	dr->dr_usedslot = backup[1];
1592203945Sweongyo	return (error);
1593203945Sweongyo#undef BWN_GET_TXHDRCACHE
1594203945Sweongyo}
1595203945Sweongyo
1596203945Sweongyostatic void
1597203945Sweongyobwn_watchdog(void *arg)
1598203945Sweongyo{
1599203945Sweongyo	struct bwn_softc *sc = arg;
1600203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1601203945Sweongyo
1602203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1603203945Sweongyo		if_printf(ifp, "device timeout\n");
1604203945Sweongyo		ifp->if_oerrors++;
1605203945Sweongyo	}
1606203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1607203945Sweongyo}
1608203945Sweongyo
1609203945Sweongyostatic int
1610203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1611203945Sweongyo{
1612203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1613203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1614203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
1615203945Sweongyo	int error, have_bg = 0, have_a = 0;
1616203945Sweongyo	uint32_t high;
1617203945Sweongyo
1618203945Sweongyo	KASSERT(sd->sd_id.sd_rev >= 5,
1619203945Sweongyo	    ("unsupported revision %d", sd->sd_id.sd_rev));
1620203945Sweongyo
1621203945Sweongyo	siba_powerup(siba, 0);
1622203945Sweongyo
1623203945Sweongyo	high = siba_read_4(sd, SIBA_TGSHIGH);
1624203945Sweongyo	bwn_reset_core(mac,
1625203945Sweongyo	    (high & BWN_TGSHIGH_HAVE_2GHZ) ? BWN_TGSLOW_SUPPORT_G : 0);
1626203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1627203945Sweongyo	if (error)
1628203945Sweongyo		goto fail;
1629203945Sweongyo
1630203945Sweongyo	have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1631203945Sweongyo	have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1632203945Sweongyo	if (siba->siba_pci_did != 0x4312 && siba->siba_pci_did != 0x4319 &&
1633203945Sweongyo	    siba->siba_pci_did != 0x4324) {
1634203945Sweongyo		have_a = have_bg = 0;
1635203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1636203945Sweongyo			have_a = 1;
1637203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1638203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1639203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1640203945Sweongyo			have_bg = 1;
1641203945Sweongyo		else
1642203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1643203945Sweongyo			    mac->mac_phy.type));
1644203945Sweongyo	}
1645203945Sweongyo	/* XXX turns off PHY A because it's not supported */
1646203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1647203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1648203945Sweongyo		have_a = 0;
1649203945Sweongyo		have_bg = 1;
1650203945Sweongyo	}
1651203945Sweongyo
1652203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1653203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1654203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1655203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1656203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1657203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1658203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1659203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1660203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1661203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1662203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1663203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1664203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1665203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1666203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1667203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1668203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1669203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1670203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1671203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1672203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1673203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1674203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1675203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1676203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1677203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1678203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1679203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1680203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1681203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1682203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1683203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1684203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1685203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1686203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1687203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1688203945Sweongyo	} else {
1689203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1690203945Sweongyo		    mac->mac_phy.type);
1691203945Sweongyo		error = ENXIO;
1692203945Sweongyo		goto fail;
1693203945Sweongyo	}
1694203945Sweongyo
1695203945Sweongyo	mac->mac_phy.gmode = have_bg;
1696203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1697203945Sweongyo		error = mac->mac_phy.attach(mac);
1698203945Sweongyo		if (error) {
1699203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1700203945Sweongyo			goto fail;
1701203945Sweongyo		}
1702203945Sweongyo	}
1703203945Sweongyo
1704203945Sweongyo	bwn_reset_core(mac, have_bg ? BWN_TGSLOW_SUPPORT_G : 0);
1705203945Sweongyo
1706203945Sweongyo	error = bwn_chiptest(mac);
1707203945Sweongyo	if (error)
1708203945Sweongyo		goto fail;
1709203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1710203945Sweongyo	if (error) {
1711203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1712203945Sweongyo		goto fail;
1713203945Sweongyo	}
1714203945Sweongyo
1715203945Sweongyo	if (sc->sc_curmac == NULL)
1716203945Sweongyo		sc->sc_curmac = mac;
1717203945Sweongyo
1718203945Sweongyo	error = bwn_dma_attach(mac);
1719203945Sweongyo	if (error != 0) {
1720203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1721203945Sweongyo		goto fail;
1722203945Sweongyo	}
1723203945Sweongyo
1724203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1725203945Sweongyo
1726203945Sweongyo	siba_dev_down(sd, 0);
1727203945Sweongyofail:
1728203945Sweongyo	siba_powerdown(siba);
1729203945Sweongyo	return (error);
1730203945Sweongyo}
1731203945Sweongyo
1732203945Sweongyostatic void
1733203945Sweongyobwn_reset_core(struct bwn_mac *mac, uint32_t flags)
1734203945Sweongyo{
1735203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1736203945Sweongyo	uint32_t low, ctl;
1737203945Sweongyo
1738203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1739203945Sweongyo
1740203945Sweongyo	siba_dev_up(sd, flags);
1741203945Sweongyo	DELAY(2000);
1742203945Sweongyo
1743203945Sweongyo	low = (siba_read_4(sd, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1744203945Sweongyo	    ~BWN_TGSLOW_PHYRESET;
1745203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW, low);
1746203945Sweongyo	siba_read_4(sd, SIBA_TGSLOW);
1747203945Sweongyo	DELAY(1000);
1748203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
1749203945Sweongyo	siba_read_4(sd, SIBA_TGSLOW);
1750203945Sweongyo	DELAY(1000);
1751203945Sweongyo
1752203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1753203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1754203945Sweongyo
1755203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1756203945Sweongyo	if (flags & BWN_TGSLOW_SUPPORT_G)
1757203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1758203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1759203945Sweongyo}
1760203945Sweongyo
1761203945Sweongyostatic int
1762203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1763203945Sweongyo{
1764203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1765203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1766203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1767203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
1768203945Sweongyo	uint32_t tmp;
1769203945Sweongyo
1770203945Sweongyo	/* PHY */
1771203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1772203945Sweongyo	phy->gmode = (tgshigh & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1773203945Sweongyo	phy->rf_on = 1;
1774203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1775203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1776203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1777203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1778203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1779203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1780203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1781203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1782203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1783203945Sweongyo		goto unsupphy;
1784203945Sweongyo
1785203945Sweongyo	/* RADIO */
1786203945Sweongyo	if (siba->siba_chipid == 0x4317) {
1787203945Sweongyo		if (siba->siba_chiprev == 0)
1788203945Sweongyo			tmp = 0x3205017f;
1789203945Sweongyo		else if (siba->siba_chiprev == 1)
1790203945Sweongyo			tmp = 0x4205017f;
1791203945Sweongyo		else
1792203945Sweongyo			tmp = 0x5205017f;
1793203945Sweongyo	} else {
1794203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1795203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1796203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1797203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1798203945Sweongyo	}
1799203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1800203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1801203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1802203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1803203945Sweongyo		goto unsupradio;
1804203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1805203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1806203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1807203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1808203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1809203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1810203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1811203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1812203945Sweongyo		goto unsupradio;
1813203945Sweongyo
1814203945Sweongyo	return (0);
1815203945Sweongyounsupphy:
1816203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1817203945Sweongyo	    "analog %#x)\n",
1818203945Sweongyo	    phy->type, phy->rev, phy->analog);
1819203945Sweongyo	return (ENXIO);
1820203945Sweongyounsupradio:
1821203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1822203945Sweongyo	    "rev %#x)\n",
1823203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1824203945Sweongyo	return (ENXIO);
1825203945Sweongyo}
1826203945Sweongyo
1827203945Sweongyostatic int
1828203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1829203945Sweongyo{
1830203945Sweongyo#define	TESTVAL0	0x55aaaa55
1831203945Sweongyo#define	TESTVAL1	0xaa5555aa
1832203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1833203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
1834203945Sweongyo	uint32_t v, backup;
1835203945Sweongyo
1836203945Sweongyo	BWN_LOCK(sc);
1837203945Sweongyo
1838203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1839203945Sweongyo
1840203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1841203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1842203945Sweongyo		goto error;
1843203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1844203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1845203945Sweongyo		goto error;
1846203945Sweongyo
1847203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1848203945Sweongyo
1849203945Sweongyo	if ((sd->sd_id.sd_rev >= 3) && (sd->sd_id.sd_rev <= 10)) {
1850203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1851203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1852203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1853203945Sweongyo			goto error;
1854203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1855203945Sweongyo			goto error;
1856203945Sweongyo	}
1857203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1858203945Sweongyo
1859203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1860203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1861203945Sweongyo		goto error;
1862203945Sweongyo
1863203945Sweongyo	BWN_UNLOCK(sc);
1864203945Sweongyo	return (0);
1865203945Sweongyoerror:
1866203945Sweongyo	BWN_UNLOCK(sc);
1867203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1868203945Sweongyo	return (ENODEV);
1869203945Sweongyo}
1870203945Sweongyo
1871203945Sweongyo#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
1872203945Sweongyo#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
1873203945Sweongyo
1874203945Sweongyostatic int
1875203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1876203945Sweongyo{
1877203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1878203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
1879203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
1880203945Sweongyo
1881203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1882203945Sweongyo	ic->ic_nchans = 0;
1883203945Sweongyo
1884203945Sweongyo	if (have_bg)
1885203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1886203945Sweongyo		    &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
1887203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1888203945Sweongyo		if (have_a)
1889203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1890203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_n,
1891203945Sweongyo			    IEEE80211_CHAN_HTA);
1892203945Sweongyo	} else {
1893203945Sweongyo		if (have_a)
1894203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1895203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_a,
1896203945Sweongyo			    IEEE80211_CHAN_A);
1897203945Sweongyo	}
1898203945Sweongyo
1899203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1900203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1901203945Sweongyo
1902203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1903203945Sweongyo}
1904203945Sweongyo
1905203945Sweongyostatic uint32_t
1906203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1907203945Sweongyo{
1908203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1909203945Sweongyo	uint32_t ret;
1910203945Sweongyo
1911203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1912203945Sweongyo
1913203945Sweongyo	if (way == BWN_SHARED) {
1914203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1915203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1916203945Sweongyo		if (offset & 0x0003) {
1917203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1918203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1919203945Sweongyo			ret <<= 16;
1920203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1921203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1922203945Sweongyo			goto out;
1923203945Sweongyo		}
1924203945Sweongyo		offset >>= 2;
1925203945Sweongyo	}
1926203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1927203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1928203945Sweongyoout:
1929203945Sweongyo	return (ret);
1930203945Sweongyo}
1931203945Sweongyo
1932203945Sweongyostatic uint16_t
1933203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1934203945Sweongyo{
1935203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1936203945Sweongyo	uint16_t ret;
1937203945Sweongyo
1938203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1939203945Sweongyo
1940203945Sweongyo	if (way == BWN_SHARED) {
1941203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1942203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1943203945Sweongyo		if (offset & 0x0003) {
1944203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1945203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1946203945Sweongyo			goto out;
1947203945Sweongyo		}
1948203945Sweongyo		offset >>= 2;
1949203945Sweongyo	}
1950203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1951203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1952203945Sweongyoout:
1953203945Sweongyo
1954203945Sweongyo	return (ret);
1955203945Sweongyo}
1956203945Sweongyo
1957203945Sweongyostatic void
1958203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1959203945Sweongyo    uint16_t offset)
1960203945Sweongyo{
1961203945Sweongyo	uint32_t control;
1962203945Sweongyo
1963203945Sweongyo	control = way;
1964203945Sweongyo	control <<= 16;
1965203945Sweongyo	control |= offset;
1966203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1967203945Sweongyo}
1968203945Sweongyo
1969203945Sweongyostatic void
1970203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1971203945Sweongyo    uint32_t value)
1972203945Sweongyo{
1973203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1974203945Sweongyo
1975203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1976203945Sweongyo
1977203945Sweongyo	if (way == BWN_SHARED) {
1978203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1979203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1980203945Sweongyo		if (offset & 0x0003) {
1981203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1982203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1983203945Sweongyo				    (value >> 16) & 0xffff);
1984203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1985203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1986203945Sweongyo			return;
1987203945Sweongyo		}
1988203945Sweongyo		offset >>= 2;
1989203945Sweongyo	}
1990203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1991203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1992203945Sweongyo}
1993203945Sweongyo
1994203945Sweongyostatic void
1995203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1996203945Sweongyo    uint16_t value)
1997203945Sweongyo{
1998203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1999203945Sweongyo
2000203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2001203945Sweongyo
2002203945Sweongyo	if (way == BWN_SHARED) {
2003203945Sweongyo		KASSERT((offset & 0x0001) == 0,
2004203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
2005203945Sweongyo		if (offset & 0x0003) {
2006203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
2007203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
2008203945Sweongyo			return;
2009203945Sweongyo		}
2010203945Sweongyo		offset >>= 2;
2011203945Sweongyo	}
2012203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
2013203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
2014203945Sweongyo}
2015203945Sweongyo
2016203945Sweongyostatic void
2017203945Sweongyobwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
2018203945Sweongyo    int txpow)
2019203945Sweongyo{
2020203945Sweongyo
2021203945Sweongyo	c->ic_freq = freq;
2022203945Sweongyo	c->ic_flags = flags;
2023203945Sweongyo	c->ic_ieee = ieee;
2024203945Sweongyo	c->ic_minpower = 0;
2025203945Sweongyo	c->ic_maxpower = 2 * txpow;
2026203945Sweongyo	c->ic_maxregpower = txpow;
2027203945Sweongyo}
2028203945Sweongyo
2029203945Sweongyostatic void
2030203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
2031203945Sweongyo    const struct bwn_channelinfo *ci, int flags)
2032203945Sweongyo{
2033203945Sweongyo	struct ieee80211_channel *c;
2034203945Sweongyo	int i;
2035203945Sweongyo
2036203945Sweongyo	c = &chans[*nchans];
2037203945Sweongyo
2038203945Sweongyo	for (i = 0; i < ci->nchannels; i++) {
2039203945Sweongyo		const struct bwn_channel *hc;
2040203945Sweongyo
2041203945Sweongyo		hc = &ci->channels[i];
2042203945Sweongyo		if (*nchans >= maxchans)
2043203945Sweongyo			break;
2044203945Sweongyo		bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
2045203945Sweongyo		c++, (*nchans)++;
2046203945Sweongyo		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
2047203945Sweongyo			/* g channel have a separate b-only entry */
2048203945Sweongyo			if (*nchans >= maxchans)
2049203945Sweongyo				break;
2050203945Sweongyo			c[0] = c[-1];
2051203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_B;
2052203945Sweongyo			c++, (*nchans)++;
2053203945Sweongyo		}
2054203945Sweongyo		if (flags == IEEE80211_CHAN_HTG) {
2055203945Sweongyo			/* HT g channel have a separate g-only entry */
2056203945Sweongyo			if (*nchans >= maxchans)
2057203945Sweongyo				break;
2058203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_G;
2059203945Sweongyo			c[0] = c[-1];
2060203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2061203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2062203945Sweongyo			c++, (*nchans)++;
2063203945Sweongyo		}
2064203945Sweongyo		if (flags == IEEE80211_CHAN_HTA) {
2065203945Sweongyo			/* HT a channel have a separate a-only entry */
2066203945Sweongyo			if (*nchans >= maxchans)
2067203945Sweongyo				break;
2068203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_A;
2069203945Sweongyo			c[0] = c[-1];
2070203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
2071203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
2072203945Sweongyo			c++, (*nchans)++;
2073203945Sweongyo		}
2074203945Sweongyo	}
2075203945Sweongyo}
2076203945Sweongyo
2077203945Sweongyostatic int
2078203945Sweongyobwn_phy_g_attach(struct bwn_mac *mac)
2079203945Sweongyo{
2080203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2081203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2082203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2083203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
2084203945Sweongyo	struct siba_sprom *sprom = &sd->sd_bus->siba_sprom;
2085203945Sweongyo	unsigned int i;
2086203945Sweongyo	int16_t pab0 = (int16_t)(sprom->pa0b0), pab1 = (int16_t)(sprom->pa0b1),
2087203945Sweongyo	    pab2 = (int16_t)(sprom->pa0b2);
2088203945Sweongyo	static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
2089203945Sweongyo	int8_t bg = (int8_t)sprom->tssi_bg;
2090203945Sweongyo
2091203945Sweongyo	if ((sd->sd_bus->siba_chipid == 0x4301) && (phy->rf_ver != 0x2050))
2092203945Sweongyo		device_printf(sc->sc_dev, "not supported anymore\n");
2093203945Sweongyo
2094203945Sweongyo	pg->pg_flags = 0;
2095203945Sweongyo	if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
2096203945Sweongyo	    pab2 == -1) {
2097203945Sweongyo		pg->pg_idletssi = 52;
2098203945Sweongyo		pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
2099203945Sweongyo		return (0);
2100203945Sweongyo	}
2101203945Sweongyo
2102203945Sweongyo	pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
2103203945Sweongyo	pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
2104203945Sweongyo	if (pg->pg_tssi2dbm == NULL) {
2105203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer\n");
2106203945Sweongyo		return (ENOMEM);
2107203945Sweongyo	}
2108203945Sweongyo	for (i = 0; i < 64; i++) {
2109203945Sweongyo		int32_t m1, m2, f, q, delta;
2110203945Sweongyo		int8_t j = 0;
2111203945Sweongyo
2112203945Sweongyo		m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
2113203945Sweongyo		m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
2114203945Sweongyo		f = 256;
2115203945Sweongyo
2116203945Sweongyo		do {
2117203945Sweongyo			if (j > 15) {
2118203945Sweongyo				device_printf(sc->sc_dev,
2119203945Sweongyo				    "failed to generate tssi2dBm\n");
2120203945Sweongyo				free(pg->pg_tssi2dbm, M_DEVBUF);
2121203945Sweongyo				return (ENOMEM);
2122203945Sweongyo			}
2123203945Sweongyo			q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
2124203945Sweongyo			    f, 2048);
2125203945Sweongyo			delta = abs(q - f);
2126203945Sweongyo			f = q;
2127203945Sweongyo			j++;
2128203945Sweongyo		} while (delta >= 2);
2129203945Sweongyo
2130203945Sweongyo		pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
2131203945Sweongyo		    128);
2132203945Sweongyo	}
2133203945Sweongyo
2134203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
2135203945Sweongyo	return (0);
2136203945Sweongyo}
2137203945Sweongyo
2138203945Sweongyostatic void
2139203945Sweongyobwn_phy_g_detach(struct bwn_mac *mac)
2140203945Sweongyo{
2141203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
2142203945Sweongyo
2143203945Sweongyo	if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
2144203945Sweongyo		free(pg->pg_tssi2dbm, M_DEVBUF);
2145203945Sweongyo		pg->pg_tssi2dbm = NULL;
2146203945Sweongyo	}
2147203945Sweongyo	pg->pg_flags = 0;
2148203945Sweongyo}
2149203945Sweongyo
2150203945Sweongyostatic void
2151203945Sweongyobwn_phy_g_init_pre(struct bwn_mac *mac)
2152203945Sweongyo{
2153203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2154203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2155203945Sweongyo	void *tssi2dbm;
2156203945Sweongyo	int idletssi;
2157203945Sweongyo	unsigned int i;
2158203945Sweongyo
2159203945Sweongyo	tssi2dbm = pg->pg_tssi2dbm;
2160203945Sweongyo	idletssi = pg->pg_idletssi;
2161203945Sweongyo
2162203945Sweongyo	memset(pg, 0, sizeof(*pg));
2163203945Sweongyo
2164203945Sweongyo	pg->pg_tssi2dbm = tssi2dbm;
2165203945Sweongyo	pg->pg_idletssi = idletssi;
2166203945Sweongyo
2167203945Sweongyo	memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
2168203945Sweongyo
2169203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi); i++)
2170203945Sweongyo		pg->pg_nrssi[i] = -1000;
2171203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi_lt); i++)
2172203945Sweongyo		pg->pg_nrssi_lt[i] = i;
2173203945Sweongyo	pg->pg_lofcal = 0xffff;
2174203945Sweongyo	pg->pg_initval = 0xffff;
2175203945Sweongyo	pg->pg_immode = BWN_IMMODE_NONE;
2176203945Sweongyo	pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
2177203945Sweongyo	pg->pg_avgtssi = 0xff;
2178203945Sweongyo
2179203945Sweongyo	pg->pg_loctl.tx_bias = 0xff;
2180203945Sweongyo	TAILQ_INIT(&pg->pg_loctl.calib_list);
2181203945Sweongyo}
2182203945Sweongyo
2183203945Sweongyostatic int
2184203945Sweongyobwn_phy_g_prepare_hw(struct bwn_mac *mac)
2185203945Sweongyo{
2186203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2187203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2188203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2189203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
2190203945Sweongyo	static const struct bwn_rfatt rfatt0[] = {
2191203945Sweongyo		{ 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 },	{ 9, 0 }, { 2, 0 },
2192203945Sweongyo		{ 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
2193203945Sweongyo		{ 3, 1 }, { 4, 1 }
2194203945Sweongyo	};
2195203945Sweongyo	static const struct bwn_rfatt rfatt1[] = {
2196203945Sweongyo		{ 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
2197203945Sweongyo		{ 14, 1 }
2198203945Sweongyo	};
2199203945Sweongyo	static const struct bwn_rfatt rfatt2[] = {
2200203945Sweongyo		{ 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
2201203945Sweongyo		{ 9, 1 }
2202203945Sweongyo	};
2203203945Sweongyo	static const struct bwn_bbatt bbatt_0[] = {
2204203945Sweongyo		{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
2205203945Sweongyo	};
2206203945Sweongyo
2207203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
2208203945Sweongyo
2209203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
2210203945Sweongyo		pg->pg_bbatt.att = 0;
2211203945Sweongyo	else
2212203945Sweongyo		pg->pg_bbatt.att = 2;
2213203945Sweongyo
2214203945Sweongyo	/* prepare Radio Attenuation */
2215203945Sweongyo	pg->pg_rfatt.padmix = 0;
2216203945Sweongyo
2217203945Sweongyo	if (bus->siba_board_vendor == SIBA_BOARDVENDOR_BCM &&
2218203945Sweongyo	    bus->siba_board_type == SIBA_BOARD_BCM4309G) {
2219203945Sweongyo		if (bus->siba_board_rev < 0x43) {
2220203945Sweongyo			pg->pg_rfatt.att = 2;
2221203945Sweongyo			goto done;
2222203945Sweongyo		} else if (bus->siba_board_rev < 0x51) {
2223203945Sweongyo			pg->pg_rfatt.att = 3;
2224203945Sweongyo			goto done;
2225203945Sweongyo		}
2226203945Sweongyo	}
2227203945Sweongyo
2228203945Sweongyo	if (phy->type == BWN_PHYTYPE_A) {
2229203945Sweongyo		pg->pg_rfatt.att = 0x60;
2230203945Sweongyo		goto done;
2231203945Sweongyo	}
2232203945Sweongyo
2233203945Sweongyo	switch (phy->rf_ver) {
2234203945Sweongyo	case 0x2050:
2235203945Sweongyo		switch (phy->rf_rev) {
2236203945Sweongyo		case 0:
2237203945Sweongyo			pg->pg_rfatt.att = 5;
2238203945Sweongyo			goto done;
2239203945Sweongyo		case 1:
2240203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2241203945Sweongyo				if (bus->siba_board_vendor ==
2242203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2243203945Sweongyo				    bus->siba_board_type ==
2244203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2245203945Sweongyo				    bus->siba_board_rev >= 30)
2246203945Sweongyo					pg->pg_rfatt.att = 3;
2247203945Sweongyo				else if (bus->siba_board_vendor ==
2248203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2249203945Sweongyo				    bus->siba_board_type == SIBA_BOARD_BU4306)
2250203945Sweongyo					pg->pg_rfatt.att = 3;
2251203945Sweongyo				else
2252203945Sweongyo					pg->pg_rfatt.att = 1;
2253203945Sweongyo			} else {
2254203945Sweongyo				if (bus->siba_board_vendor ==
2255203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2256203945Sweongyo				    bus->siba_board_type ==
2257203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2258203945Sweongyo				    bus->siba_board_rev >= 30)
2259203945Sweongyo					pg->pg_rfatt.att = 7;
2260203945Sweongyo				else
2261203945Sweongyo					pg->pg_rfatt.att = 6;
2262203945Sweongyo			}
2263203945Sweongyo			goto done;
2264203945Sweongyo		case 2:
2265203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2266203945Sweongyo				if (bus->siba_board_vendor ==
2267203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2268203945Sweongyo				    bus->siba_board_type ==
2269203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2270203945Sweongyo				    bus->siba_board_rev >= 30)
2271203945Sweongyo					pg->pg_rfatt.att = 3;
2272203945Sweongyo				else if (bus->siba_board_vendor ==
2273203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2274203945Sweongyo				    bus->siba_board_type == SIBA_BOARD_BU4306)
2275203945Sweongyo					pg->pg_rfatt.att = 5;
2276203945Sweongyo				else if (bus->siba_chipid == 0x4320)
2277203945Sweongyo					pg->pg_rfatt.att = 4;
2278203945Sweongyo				else
2279203945Sweongyo					pg->pg_rfatt.att = 3;
2280203945Sweongyo			} else
2281203945Sweongyo				pg->pg_rfatt.att = 6;
2282203945Sweongyo			goto done;
2283203945Sweongyo		case 3:
2284203945Sweongyo			pg->pg_rfatt.att = 5;
2285203945Sweongyo			goto done;
2286203945Sweongyo		case 4:
2287203945Sweongyo		case 5:
2288203945Sweongyo			pg->pg_rfatt.att = 1;
2289203945Sweongyo			goto done;
2290203945Sweongyo		case 6:
2291203945Sweongyo		case 7:
2292203945Sweongyo			pg->pg_rfatt.att = 5;
2293203945Sweongyo			goto done;
2294203945Sweongyo		case 8:
2295203945Sweongyo			pg->pg_rfatt.att = 0xa;
2296203945Sweongyo			pg->pg_rfatt.padmix = 1;
2297203945Sweongyo			goto done;
2298203945Sweongyo		case 9:
2299203945Sweongyo		default:
2300203945Sweongyo			pg->pg_rfatt.att = 5;
2301203945Sweongyo			goto done;
2302203945Sweongyo		}
2303203945Sweongyo		break;
2304203945Sweongyo	case 0x2053:
2305203945Sweongyo		switch (phy->rf_rev) {
2306203945Sweongyo		case 1:
2307203945Sweongyo			pg->pg_rfatt.att = 6;
2308203945Sweongyo			goto done;
2309203945Sweongyo		}
2310203945Sweongyo		break;
2311203945Sweongyo	}
2312203945Sweongyo	pg->pg_rfatt.att = 5;
2313203945Sweongyodone:
2314203945Sweongyo	pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
2315203945Sweongyo
2316203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
2317203945Sweongyo		lo->rfatt.array = rfatt0;
2318203945Sweongyo		lo->rfatt.len = N(rfatt0);
2319203945Sweongyo		lo->rfatt.min = 0;
2320203945Sweongyo		lo->rfatt.max = 9;
2321203945Sweongyo		goto genbbatt;
2322203945Sweongyo	}
2323203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
2324203945Sweongyo		lo->rfatt.array = rfatt1;
2325203945Sweongyo		lo->rfatt.len = N(rfatt1);
2326203945Sweongyo		lo->rfatt.min = 0;
2327203945Sweongyo		lo->rfatt.max = 14;
2328203945Sweongyo		goto genbbatt;
2329203945Sweongyo	}
2330203945Sweongyo	lo->rfatt.array = rfatt2;
2331203945Sweongyo	lo->rfatt.len = N(rfatt2);
2332203945Sweongyo	lo->rfatt.min = 0;
2333203945Sweongyo	lo->rfatt.max = 9;
2334203945Sweongyogenbbatt:
2335203945Sweongyo	lo->bbatt.array = bbatt_0;
2336203945Sweongyo	lo->bbatt.len = N(bbatt_0);
2337203945Sweongyo	lo->bbatt.min = 0;
2338203945Sweongyo	lo->bbatt.max = 8;
2339203945Sweongyo
2340203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
2341203945Sweongyo	if (phy->rev == 1) {
2342203945Sweongyo		phy->gmode = 0;
2343203945Sweongyo		bwn_reset_core(mac, 0);
2344203945Sweongyo		bwn_phy_g_init_sub(mac);
2345203945Sweongyo		phy->gmode = 1;
2346203945Sweongyo		bwn_reset_core(mac, BWN_TGSLOW_SUPPORT_G);
2347203945Sweongyo	}
2348203945Sweongyo	return (0);
2349203945Sweongyo}
2350203945Sweongyo
2351203945Sweongyostatic uint16_t
2352203945Sweongyobwn_phy_g_txctl(struct bwn_mac *mac)
2353203945Sweongyo{
2354203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2355203945Sweongyo
2356203945Sweongyo	if (phy->rf_ver != 0x2050)
2357203945Sweongyo		return (0);
2358203945Sweongyo	if (phy->rf_rev == 1)
2359203945Sweongyo		return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
2360203945Sweongyo	if (phy->rf_rev < 6)
2361203945Sweongyo		return (BWN_TXCTL_PA2DB);
2362203945Sweongyo	if (phy->rf_rev == 8)
2363203945Sweongyo		return (BWN_TXCTL_TXMIX);
2364203945Sweongyo	return (0);
2365203945Sweongyo}
2366203945Sweongyo
2367203945Sweongyostatic int
2368203945Sweongyobwn_phy_g_init(struct bwn_mac *mac)
2369203945Sweongyo{
2370203945Sweongyo
2371203945Sweongyo	bwn_phy_g_init_sub(mac);
2372203945Sweongyo	return (0);
2373203945Sweongyo}
2374203945Sweongyo
2375203945Sweongyostatic void
2376203945Sweongyobwn_phy_g_exit(struct bwn_mac *mac)
2377203945Sweongyo{
2378203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
2379203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2380203945Sweongyo
2381203945Sweongyo	if (lo == NULL)
2382203945Sweongyo		return;
2383203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2384203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2385203945Sweongyo		free(cal, M_DEVBUF);
2386203945Sweongyo	}
2387203945Sweongyo}
2388203945Sweongyo
2389203945Sweongyostatic uint16_t
2390203945Sweongyobwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
2391203945Sweongyo{
2392203945Sweongyo
2393203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2394203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
2395203945Sweongyo}
2396203945Sweongyo
2397203945Sweongyostatic void
2398203945Sweongyobwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2399203945Sweongyo{
2400203945Sweongyo
2401203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2402203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
2403203945Sweongyo}
2404203945Sweongyo
2405203945Sweongyostatic uint16_t
2406203945Sweongyobwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
2407203945Sweongyo{
2408203945Sweongyo
2409203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2410203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
2411203945Sweongyo	return (BWN_READ_2(mac, BWN_RFDATALO));
2412203945Sweongyo}
2413203945Sweongyo
2414203945Sweongyostatic void
2415203945Sweongyobwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2416203945Sweongyo{
2417203945Sweongyo
2418203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2419203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
2420203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
2421203945Sweongyo}
2422203945Sweongyo
2423203945Sweongyostatic int
2424203945Sweongyobwn_phy_g_hwpctl(struct bwn_mac *mac)
2425203945Sweongyo{
2426203945Sweongyo
2427203945Sweongyo	return (mac->mac_phy.rev >= 6);
2428203945Sweongyo}
2429203945Sweongyo
2430203945Sweongyostatic void
2431203945Sweongyobwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
2432203945Sweongyo{
2433203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2434203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2435203945Sweongyo	unsigned int channel;
2436203945Sweongyo	uint16_t rfover, rfoverval;
2437203945Sweongyo
2438203945Sweongyo	if (on) {
2439203945Sweongyo		if (phy->rf_on)
2440203945Sweongyo			return;
2441203945Sweongyo
2442203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0x8000);
2443203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0xcc00);
2444203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
2445203945Sweongyo		if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
2446203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
2447203945Sweongyo			    pg->pg_radioctx_over);
2448203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
2449203945Sweongyo			    pg->pg_radioctx_overval);
2450203945Sweongyo			pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
2451203945Sweongyo		}
2452203945Sweongyo		channel = phy->chan;
2453203945Sweongyo		bwn_phy_g_switch_chan(mac, 6, 1);
2454203945Sweongyo		bwn_phy_g_switch_chan(mac, channel, 0);
2455203945Sweongyo		return;
2456203945Sweongyo	}
2457203945Sweongyo
2458203945Sweongyo	rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
2459203945Sweongyo	rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
2460203945Sweongyo	pg->pg_radioctx_over = rfover;
2461203945Sweongyo	pg->pg_radioctx_overval = rfoverval;
2462203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
2463203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
2464203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
2465203945Sweongyo}
2466203945Sweongyo
2467203945Sweongyostatic int
2468203945Sweongyobwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
2469203945Sweongyo{
2470203945Sweongyo
2471203945Sweongyo	if ((newchan < 1) || (newchan > 14))
2472203945Sweongyo		return (EINVAL);
2473203945Sweongyo	bwn_phy_g_switch_chan(mac, newchan, 0);
2474203945Sweongyo
2475203945Sweongyo	return (0);
2476203945Sweongyo}
2477203945Sweongyo
2478203945Sweongyostatic uint32_t
2479203945Sweongyobwn_phy_g_get_default_chan(struct bwn_mac *mac)
2480203945Sweongyo{
2481203945Sweongyo
2482203945Sweongyo	return (1);
2483203945Sweongyo}
2484203945Sweongyo
2485203945Sweongyostatic void
2486203945Sweongyobwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
2487203945Sweongyo{
2488203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2489203945Sweongyo	uint64_t hf;
2490203945Sweongyo	int autodiv = 0;
2491203945Sweongyo	uint16_t tmp;
2492203945Sweongyo
2493203945Sweongyo	if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
2494203945Sweongyo		autodiv = 1;
2495203945Sweongyo
2496203945Sweongyo	hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
2497203945Sweongyo	bwn_hf_write(mac, hf);
2498203945Sweongyo
2499203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
2500203945Sweongyo	    (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
2501203945Sweongyo	    ((autodiv ? BWN_ANTAUTO1 : antenna)
2502203945Sweongyo		<< BWN_PHY_BBANDCFG_RXANT_SHIFT));
2503203945Sweongyo
2504203945Sweongyo	if (autodiv) {
2505203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
2506203945Sweongyo		if (antenna == BWN_ANTAUTO1)
2507203945Sweongyo			tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
2508203945Sweongyo		else
2509203945Sweongyo			tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
2510203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
2511203945Sweongyo	}
2512203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
2513203945Sweongyo	if (autodiv)
2514203945Sweongyo		tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
2515203945Sweongyo	else
2516203945Sweongyo		tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
2517203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
2518203945Sweongyo	if (phy->rev >= 2) {
2519203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
2520203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
2521203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
2522203945Sweongyo		    (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
2523203945Sweongyo		    0x15);
2524203945Sweongyo		if (phy->rev == 2)
2525203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
2526203945Sweongyo		else
2527203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
2528203945Sweongyo			    (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
2529203945Sweongyo			    8);
2530203945Sweongyo	}
2531203945Sweongyo	if (phy->rev >= 6)
2532203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
2533203945Sweongyo
2534203945Sweongyo	hf |= BWN_HF_UCODE_ANTDIV_HELPER;
2535203945Sweongyo	bwn_hf_write(mac, hf);
2536203945Sweongyo}
2537203945Sweongyo
2538203945Sweongyostatic int
2539203945Sweongyobwn_phy_g_im(struct bwn_mac *mac, int mode)
2540203945Sweongyo{
2541203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2542203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2543203945Sweongyo
2544203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2545203945Sweongyo	KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
2546203945Sweongyo
2547203945Sweongyo	if (phy->rev == 0 || !phy->gmode)
2548203945Sweongyo		return (ENODEV);
2549203945Sweongyo
2550203945Sweongyo	pg->pg_aci_wlan_automatic = 0;
2551203945Sweongyo	return (0);
2552203945Sweongyo}
2553203945Sweongyo
2554203945Sweongyostatic int
2555203945Sweongyobwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
2556203945Sweongyo{
2557203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2558203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2559203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2560203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
2561203945Sweongyo	unsigned int tssi;
2562203945Sweongyo	int cck, ofdm;
2563203945Sweongyo	int power;
2564203945Sweongyo	int rfatt, bbatt;
2565203945Sweongyo	unsigned int max;
2566203945Sweongyo
2567203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2568203945Sweongyo
2569203945Sweongyo	cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
2570203945Sweongyo	ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
2571203945Sweongyo	if (cck < 0 && ofdm < 0) {
2572203945Sweongyo		if (ignore_tssi == 0)
2573203945Sweongyo			return (BWN_TXPWR_RES_DONE);
2574203945Sweongyo		cck = 0;
2575203945Sweongyo		ofdm = 0;
2576203945Sweongyo	}
2577203945Sweongyo	tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
2578203945Sweongyo	if (pg->pg_avgtssi != 0xff)
2579203945Sweongyo		tssi = (tssi + pg->pg_avgtssi) / 2;
2580203945Sweongyo	pg->pg_avgtssi = tssi;
2581203945Sweongyo	KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
2582203945Sweongyo
2583203945Sweongyo	max = siba->siba_sprom.maxpwr_bg;
2584203945Sweongyo	if (siba->siba_sprom.bf_lo & BWN_BFL_PACTRL)
2585203945Sweongyo		max -= 3;
2586203945Sweongyo	if (max >= 120) {
2587203945Sweongyo		device_printf(sc->sc_dev, "invalid max TX-power value\n");
2588203945Sweongyo		siba->siba_sprom.maxpwr_bg = max = 80;
2589203945Sweongyo	}
2590203945Sweongyo
2591203945Sweongyo	power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
2592203945Sweongyo	    (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
2593203945Sweongyo	     tssi, 0x00), 0x3f)]);
2594203945Sweongyo	if (power == 0)
2595203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2596203945Sweongyo
2597203945Sweongyo	rfatt = -((power + 7) / 8);
2598203945Sweongyo	bbatt = (-(power / 2)) - (4 * rfatt);
2599203945Sweongyo	if ((rfatt == 0) && (bbatt == 0))
2600203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2601203945Sweongyo	pg->pg_bbatt_delta = bbatt;
2602203945Sweongyo	pg->pg_rfatt_delta = rfatt;
2603203945Sweongyo	return (BWN_TXPWR_RES_NEED_ADJUST);
2604203945Sweongyo}
2605203945Sweongyo
2606203945Sweongyostatic void
2607203945Sweongyobwn_phy_g_set_txpwr(struct bwn_mac *mac)
2608203945Sweongyo{
2609203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2610203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2611203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2612203945Sweongyo	int rfatt, bbatt;
2613203945Sweongyo	uint8_t txctl;
2614203945Sweongyo
2615203945Sweongyo	bwn_mac_suspend(mac);
2616203945Sweongyo
2617203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2618203945Sweongyo
2619203945Sweongyo	bbatt = pg->pg_bbatt.att;
2620203945Sweongyo	bbatt += pg->pg_bbatt_delta;
2621203945Sweongyo	rfatt = pg->pg_rfatt.att;
2622203945Sweongyo	rfatt += pg->pg_rfatt_delta;
2623203945Sweongyo
2624203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2625203945Sweongyo	txctl = pg->pg_txctl;
2626203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
2627203945Sweongyo		if (rfatt <= 1) {
2628203945Sweongyo			if (txctl == 0) {
2629203945Sweongyo				txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
2630203945Sweongyo				rfatt += 2;
2631203945Sweongyo				bbatt += 2;
2632203945Sweongyo			} else if (mac->mac_sd->sd_bus->siba_sprom.
2633203945Sweongyo				   bf_lo &
2634203945Sweongyo				   BWN_BFL_PACTRL) {
2635203945Sweongyo				bbatt += 4 * (rfatt - 2);
2636203945Sweongyo				rfatt = 2;
2637203945Sweongyo			}
2638203945Sweongyo		} else if (rfatt > 4 && txctl) {
2639203945Sweongyo			txctl = 0;
2640203945Sweongyo			if (bbatt < 3) {
2641203945Sweongyo				rfatt -= 3;
2642203945Sweongyo				bbatt += 2;
2643203945Sweongyo			} else {
2644203945Sweongyo				rfatt -= 2;
2645203945Sweongyo				bbatt -= 2;
2646203945Sweongyo			}
2647203945Sweongyo		}
2648203945Sweongyo	}
2649203945Sweongyo	pg->pg_txctl = txctl;
2650203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2651203945Sweongyo	pg->pg_rfatt.att = rfatt;
2652203945Sweongyo	pg->pg_bbatt.att = bbatt;
2653203945Sweongyo
2654203945Sweongyo	DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
2655203945Sweongyo
2656203945Sweongyo	bwn_phy_lock(mac);
2657203945Sweongyo	bwn_rf_lock(mac);
2658203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
2659203945Sweongyo	    pg->pg_txctl);
2660203945Sweongyo	bwn_rf_unlock(mac);
2661203945Sweongyo	bwn_phy_unlock(mac);
2662203945Sweongyo
2663203945Sweongyo	bwn_mac_enable(mac);
2664203945Sweongyo}
2665203945Sweongyo
2666203945Sweongyostatic void
2667203945Sweongyobwn_phy_g_task_15s(struct bwn_mac *mac)
2668203945Sweongyo{
2669203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2670203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2671203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2672203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2673203945Sweongyo	unsigned long expire, now;
2674203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2675203945Sweongyo	uint8_t expired = 0;
2676203945Sweongyo
2677203945Sweongyo	bwn_mac_suspend(mac);
2678203945Sweongyo
2679203945Sweongyo	if (lo == NULL)
2680203945Sweongyo		goto fail;
2681203945Sweongyo
2682203945Sweongyo	BWN_GETTIME(now);
2683203945Sweongyo	if (bwn_has_hwpctl(mac)) {
2684203945Sweongyo		expire = now - BWN_LO_PWRVEC_EXPIRE;
2685203945Sweongyo		if (time_before(lo->pwr_vec_read_time, expire)) {
2686203945Sweongyo			bwn_lo_get_powervector(mac);
2687203945Sweongyo			bwn_phy_g_dc_lookup_init(mac, 0);
2688203945Sweongyo		}
2689203945Sweongyo		goto fail;
2690203945Sweongyo	}
2691203945Sweongyo
2692203945Sweongyo	expire = now - BWN_LO_CALIB_EXPIRE;
2693203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2694203945Sweongyo		if (!time_before(cal->calib_time, expire))
2695203945Sweongyo			continue;
2696203945Sweongyo		if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
2697203945Sweongyo		    BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
2698203945Sweongyo			KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
2699203945Sweongyo			expired = 1;
2700203945Sweongyo		}
2701203945Sweongyo
2702203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
2703203945Sweongyo		    cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
2704203945Sweongyo		    cal->ctl.i, cal->ctl.q);
2705203945Sweongyo
2706203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2707203945Sweongyo		free(cal, M_DEVBUF);
2708203945Sweongyo	}
2709203945Sweongyo	if (expired || TAILQ_EMPTY(&lo->calib_list)) {
2710203945Sweongyo		cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
2711203945Sweongyo		    &pg->pg_rfatt);
2712203945Sweongyo		if (cal == NULL) {
2713203945Sweongyo			device_printf(sc->sc_dev,
2714203945Sweongyo			    "failed to recalibrate LO\n");
2715203945Sweongyo			goto fail;
2716203945Sweongyo		}
2717203945Sweongyo		TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
2718203945Sweongyo		bwn_lo_write(mac, &cal->ctl);
2719203945Sweongyo	}
2720203945Sweongyo
2721203945Sweongyofail:
2722203945Sweongyo	bwn_mac_enable(mac);
2723203945Sweongyo}
2724203945Sweongyo
2725203945Sweongyostatic void
2726203945Sweongyobwn_phy_g_task_60s(struct bwn_mac *mac)
2727203945Sweongyo{
2728203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2729203945Sweongyo	uint8_t old = phy->chan;
2730203945Sweongyo
2731203945Sweongyo	if (!(mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_RSSI))
2732203945Sweongyo		return;
2733203945Sweongyo
2734203945Sweongyo	bwn_mac_suspend(mac);
2735203945Sweongyo	bwn_nrssi_slope_11g(mac);
2736203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
2737203945Sweongyo		bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
2738203945Sweongyo		bwn_switch_channel(mac, old);
2739203945Sweongyo	}
2740203945Sweongyo	bwn_mac_enable(mac);
2741203945Sweongyo}
2742203945Sweongyo
2743203945Sweongyostatic void
2744203945Sweongyobwn_phy_switch_analog(struct bwn_mac *mac, int on)
2745203945Sweongyo{
2746203945Sweongyo
2747203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
2748203945Sweongyo}
2749203945Sweongyo
2750203945Sweongyostatic int
2751203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
2752203945Sweongyo	const struct ieee80211_bpf_params *params)
2753203945Sweongyo{
2754203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2755203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2756203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2757203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2758203945Sweongyo
2759203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
2760203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
2761203945Sweongyo		ieee80211_free_node(ni);
2762203945Sweongyo		m_freem(m);
2763203945Sweongyo		return (ENETDOWN);
2764203945Sweongyo	}
2765203945Sweongyo
2766203945Sweongyo	BWN_LOCK(sc);
2767203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
2768203945Sweongyo		ieee80211_free_node(ni);
2769203945Sweongyo		m_freem(m);
2770203945Sweongyo		ifp->if_oerrors++;
2771203945Sweongyo		BWN_UNLOCK(sc);
2772203945Sweongyo		return (ENOBUFS);
2773203945Sweongyo	}
2774203945Sweongyo
2775203945Sweongyo	if (bwn_tx_start(sc, ni, m) != 0) {
2776203945Sweongyo		if (ni != NULL)
2777203945Sweongyo			ieee80211_free_node(ni);
2778203945Sweongyo		ifp->if_oerrors++;
2779203945Sweongyo	}
2780203945Sweongyo	sc->sc_watchdog_timer = 5;
2781203945Sweongyo	BWN_UNLOCK(sc);
2782203945Sweongyo	return (0);
2783203945Sweongyo}
2784203945Sweongyo
2785203945Sweongyo/*
2786203945Sweongyo * Setup driver-specific state for a newly associated node.
2787203945Sweongyo * Note that we're called also on a re-associate, the isnew
2788203945Sweongyo * param tells us if this is the first time or not.
2789203945Sweongyo */
2790203945Sweongyostatic void
2791203945Sweongyobwn_newassoc(struct ieee80211_node *ni, int isnew)
2792203945Sweongyo{
2793203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
2794203945Sweongyo
2795203945Sweongyo	ieee80211_amrr_node_init(&BWN_VAP(vap)->bv_amrr,
2796203945Sweongyo	    &BWN_NODE(ni)->bn_amn, ni);
2797203945Sweongyo}
2798203945Sweongyo
2799203945Sweongyo/*
2800203945Sweongyo * Callback from the 802.11 layer to update the slot time
2801203945Sweongyo * based on the current setting.  We use it to notify the
2802203945Sweongyo * firmware of ERP changes and the f/w takes care of things
2803203945Sweongyo * like slot time and preamble.
2804203945Sweongyo */
2805203945Sweongyostatic void
2806203945Sweongyobwn_updateslot(struct ifnet *ifp)
2807203945Sweongyo{
2808203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2809203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
2810203945Sweongyo	struct bwn_mac *mac;
2811203945Sweongyo
2812203945Sweongyo	BWN_LOCK(sc);
2813203945Sweongyo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2814203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
2815203945Sweongyo		bwn_set_slot_time(mac,
2816203945Sweongyo		    (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20);
2817203945Sweongyo	}
2818203945Sweongyo	BWN_UNLOCK(sc);
2819203945Sweongyo}
2820203945Sweongyo
2821203945Sweongyo/*
2822203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
2823203945Sweongyo * Note this interface does not check the operating mode as this
2824203945Sweongyo * is an internal callback and we are expected to honor the current
2825203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
2826203945Sweongyo * mode when operating in hostap mode to do ACS).
2827203945Sweongyo */
2828203945Sweongyostatic void
2829203945Sweongyobwn_update_promisc(struct ifnet *ifp)
2830203945Sweongyo{
2831203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2832203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2833203945Sweongyo
2834203945Sweongyo	BWN_LOCK(sc);
2835203945Sweongyo	mac = sc->sc_curmac;
2836203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2837203945Sweongyo		if (ifp->if_flags & IFF_PROMISC)
2838203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
2839203945Sweongyo		else
2840203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
2841203945Sweongyo		bwn_set_opmode(mac);
2842203945Sweongyo	}
2843203945Sweongyo	BWN_UNLOCK(sc);
2844203945Sweongyo}
2845203945Sweongyo
2846203945Sweongyo/*
2847203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
2848203945Sweongyo */
2849203945Sweongyostatic int
2850203945Sweongyobwn_wme_update(struct ieee80211com *ic)
2851203945Sweongyo{
2852203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2853203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2854203945Sweongyo	struct wmeParams *wmep;
2855203945Sweongyo	int i;
2856203945Sweongyo
2857203945Sweongyo	BWN_LOCK(sc);
2858203945Sweongyo	mac = sc->sc_curmac;
2859203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2860203945Sweongyo		bwn_mac_suspend(mac);
2861203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
2862203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
2863203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
2864203945Sweongyo		}
2865203945Sweongyo		bwn_mac_enable(mac);
2866203945Sweongyo	}
2867203945Sweongyo	BWN_UNLOCK(sc);
2868203945Sweongyo	return (0);
2869203945Sweongyo}
2870203945Sweongyo
2871203945Sweongyostatic struct ieee80211_node *
2872203945Sweongyobwn_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
2873203945Sweongyo{
2874203945Sweongyo	struct ieee80211com *ic = vap->iv_ic;
2875203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2876203945Sweongyo	const size_t space = sizeof(struct bwn_node);
2877203945Sweongyo	struct bwn_node *bn;
2878203945Sweongyo
2879203945Sweongyo	bn = malloc(space, M_80211_NODE, M_NOWAIT|M_ZERO);
2880203945Sweongyo	if (bn == NULL) {
2881203945Sweongyo		/* XXX stat+msg */
2882203945Sweongyo		return (NULL);
2883203945Sweongyo	}
2884203945Sweongyo	DPRINTF(sc, BWN_DEBUG_NODE, "%s: bn %p\n", __func__, bn);
2885203945Sweongyo	return (&bn->bn_node);
2886203945Sweongyo}
2887203945Sweongyo
2888203945Sweongyostatic void
2889203945Sweongyobwn_node_cleanup(struct ieee80211_node *ni)
2890203945Sweongyo{
2891203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2892203945Sweongyo	struct bwn_softc *sc = ic->ic_ifp->if_softc;
2893203945Sweongyo
2894203945Sweongyo	sc->sc_node_cleanup(ni);
2895203945Sweongyo}
2896203945Sweongyo
2897203945Sweongyostatic void
2898203945Sweongyobwn_scan_start(struct ieee80211com *ic)
2899203945Sweongyo{
2900203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2901203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2902203945Sweongyo	struct bwn_mac *mac;
2903203945Sweongyo
2904203945Sweongyo	BWN_LOCK(sc);
2905203945Sweongyo	mac = sc->sc_curmac;
2906203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2907203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
2908203945Sweongyo		bwn_set_opmode(mac);
2909203945Sweongyo		/* disable CFP update during scan */
2910203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
2911203945Sweongyo	}
2912203945Sweongyo	BWN_UNLOCK(sc);
2913203945Sweongyo}
2914203945Sweongyo
2915203945Sweongyostatic void
2916203945Sweongyobwn_scan_end(struct ieee80211com *ic)
2917203945Sweongyo{
2918203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2919203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2920203945Sweongyo	struct bwn_mac *mac;
2921203945Sweongyo
2922203945Sweongyo	BWN_LOCK(sc);
2923203945Sweongyo	mac = sc->sc_curmac;
2924203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2925203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
2926203945Sweongyo		bwn_set_opmode(mac);
2927203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
2928203945Sweongyo	}
2929203945Sweongyo	BWN_UNLOCK(sc);
2930203945Sweongyo}
2931203945Sweongyo
2932203945Sweongyostatic void
2933203945Sweongyobwn_set_channel(struct ieee80211com *ic)
2934203945Sweongyo{
2935203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2936203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2937203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2938203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2939203945Sweongyo	int chan, error;
2940203945Sweongyo
2941203945Sweongyo	BWN_LOCK(sc);
2942203945Sweongyo
2943203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
2944203945Sweongyo	if (error)
2945203945Sweongyo		goto fail;;
2946203945Sweongyo	bwn_mac_suspend(mac);
2947203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2948203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
2949203945Sweongyo	if (chan != phy->chan)
2950203945Sweongyo		bwn_switch_channel(mac, chan);
2951203945Sweongyo
2952203945Sweongyo	/* TX power level */
2953203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
2954203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
2955203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
2956203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
2957203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
2958203945Sweongyo	}
2959203945Sweongyo
2960203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2961203945Sweongyo	if (phy->set_antenna)
2962203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2963203945Sweongyo
2964203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
2965203945Sweongyo		if (sc->sc_rf_enabled) {
2966203945Sweongyo			bwn_rf_turnon(mac);
2967203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
2968203945Sweongyo				device_printf(sc->sc_dev,
2969203945Sweongyo				    "please turns on the RF switch\n");
2970203945Sweongyo		} else
2971203945Sweongyo			bwn_rf_turnoff(mac);
2972203945Sweongyo	}
2973203945Sweongyo
2974203945Sweongyo	bwn_mac_enable(mac);
2975203945Sweongyo
2976203945Sweongyofail:
2977203945Sweongyo	/*
2978203945Sweongyo	 * Setup radio tap channel freq and flags
2979203945Sweongyo	 */
2980203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
2981203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
2982203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
2983203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
2984203945Sweongyo
2985203945Sweongyo	BWN_UNLOCK(sc);
2986203945Sweongyo}
2987203945Sweongyo
2988203945Sweongyostatic struct ieee80211vap *
2989203945Sweongyobwn_vap_create(struct ieee80211com *ic,
2990203945Sweongyo	const char name[IFNAMSIZ], int unit, int opmode, int flags,
2991203945Sweongyo	const uint8_t bssid[IEEE80211_ADDR_LEN],
2992203945Sweongyo	const uint8_t mac0[IEEE80211_ADDR_LEN])
2993203945Sweongyo{
2994203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
2995203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
2996203945Sweongyo	struct ieee80211vap *vap;
2997203945Sweongyo	struct bwn_vap *bvp;
2998203945Sweongyo	uint8_t mac[IEEE80211_ADDR_LEN];
2999203945Sweongyo
3000203945Sweongyo	IEEE80211_ADDR_COPY(mac, mac0);
3001203945Sweongyo	switch (opmode) {
3002203945Sweongyo	case IEEE80211_M_HOSTAP:
3003203945Sweongyo	case IEEE80211_M_MBSS:
3004203945Sweongyo	case IEEE80211_M_STA:
3005203945Sweongyo	case IEEE80211_M_WDS:
3006203945Sweongyo	case IEEE80211_M_MONITOR:
3007203945Sweongyo	case IEEE80211_M_IBSS:
3008203945Sweongyo	case IEEE80211_M_AHDEMO:
3009203945Sweongyo		break;
3010203945Sweongyo	default:
3011203945Sweongyo		return (NULL);
3012203945Sweongyo	}
3013203945Sweongyo
3014203945Sweongyo	IEEE80211_ADDR_COPY(sc->sc_macaddr, mac0);
3015203945Sweongyo
3016203945Sweongyo	bvp = (struct bwn_vap *) malloc(sizeof(struct bwn_vap),
3017203945Sweongyo	    M_80211_VAP, M_NOWAIT | M_ZERO);
3018203945Sweongyo	if (bvp == NULL) {
3019203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate a buffer\n");
3020203945Sweongyo		return (NULL);
3021203945Sweongyo	}
3022203945Sweongyo	vap = &bvp->bv_vap;
3023203945Sweongyo	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
3024203945Sweongyo	IEEE80211_ADDR_COPY(vap->iv_myaddr, mac);
3025203945Sweongyo	/* override with driver methods */
3026203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
3027203945Sweongyo	vap->iv_newstate = bwn_newstate;
3028203945Sweongyo
3029203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
3030203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
3031203945Sweongyo
3032203945Sweongyo	ieee80211_amrr_init(&bvp->bv_amrr, vap,
3033203945Sweongyo	    IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
3034203945Sweongyo	    IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
3035203945Sweongyo	    500 /*ms*/);
3036203945Sweongyo
3037203945Sweongyo	/* complete setup */
3038203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
3039203945Sweongyo	    ieee80211_media_status);
3040203945Sweongyo	return (vap);
3041203945Sweongyo}
3042203945Sweongyo
3043203945Sweongyostatic void
3044203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
3045203945Sweongyo{
3046203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
3047203945Sweongyo
3048203945Sweongyo	ieee80211_amrr_cleanup(&bvp->bv_amrr);
3049203945Sweongyo	ieee80211_vap_detach(vap);
3050203945Sweongyo	free(bvp, M_80211_VAP);
3051203945Sweongyo}
3052203945Sweongyo
3053203945Sweongyostatic void
3054203945Sweongyobwn_init(void *arg)
3055203945Sweongyo{
3056203945Sweongyo	struct bwn_softc *sc = arg;
3057203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3058203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
3059203945Sweongyo	int error = 0;
3060203945Sweongyo
3061203945Sweongyo	DPRINTF(sc, BWN_DEBUG_ANY, "%s: if_flags 0x%x\n",
3062203945Sweongyo		__func__, ifp->if_flags);
3063203945Sweongyo
3064203945Sweongyo	BWN_LOCK(sc);
3065203945Sweongyo	error = bwn_init_locked(sc);
3066203945Sweongyo	BWN_UNLOCK(sc);
3067203945Sweongyo
3068203945Sweongyo	if (error == 0)
3069203945Sweongyo		ieee80211_start_all(ic);	/* start all vap's */
3070203945Sweongyo}
3071203945Sweongyo
3072203945Sweongyostatic int
3073203945Sweongyobwn_init_locked(struct bwn_softc *sc)
3074203945Sweongyo{
3075203945Sweongyo	struct bwn_mac *mac;
3076203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3077203945Sweongyo	int error;
3078203945Sweongyo
3079203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3080203945Sweongyo
3081203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
3082203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
3083203945Sweongyo	sc->sc_filters = 0;
3084203945Sweongyo	bwn_wme_clear(sc);
3085203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
3086203945Sweongyo	sc->sc_rf_enabled = 1;
3087203945Sweongyo
3088203945Sweongyo	mac = sc->sc_curmac;
3089203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
3090203945Sweongyo		error = bwn_core_init(mac);
3091203945Sweongyo		if (error != 0)
3092203945Sweongyo			return (error);
3093203945Sweongyo	}
3094203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
3095203945Sweongyo		bwn_core_start(mac);
3096203945Sweongyo
3097203945Sweongyo	bwn_set_opmode(mac);
3098203945Sweongyo	bwn_set_pretbtt(mac);
3099203945Sweongyo	bwn_spu_setdelay(mac, 0);
3100203945Sweongyo	bwn_set_macaddr(mac);
3101203945Sweongyo
3102203945Sweongyo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3103203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
3104203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
3105203945Sweongyo
3106203945Sweongyo	return (0);
3107203945Sweongyo}
3108203945Sweongyo
3109203945Sweongyostatic void
3110203945Sweongyobwn_stop(struct bwn_softc *sc, int statechg)
3111203945Sweongyo{
3112203945Sweongyo
3113203945Sweongyo	BWN_LOCK(sc);
3114203945Sweongyo	bwn_stop_locked(sc, statechg);
3115203945Sweongyo	BWN_UNLOCK(sc);
3116203945Sweongyo}
3117203945Sweongyo
3118203945Sweongyostatic void
3119203945Sweongyobwn_stop_locked(struct bwn_softc *sc, int statechg)
3120203945Sweongyo{
3121203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
3122203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
3123203945Sweongyo
3124203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3125203945Sweongyo
3126203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
3127203945Sweongyo		/* XXX FIXME opmode not based on VAP */
3128203945Sweongyo		bwn_set_opmode(mac);
3129203945Sweongyo		bwn_set_macaddr(mac);
3130203945Sweongyo	}
3131203945Sweongyo
3132203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
3133203945Sweongyo		bwn_core_stop(mac);
3134203945Sweongyo
3135203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
3136203945Sweongyo	sc->sc_led_blinking = 0;
3137203945Sweongyo
3138203945Sweongyo	bwn_core_exit(mac);
3139203945Sweongyo	sc->sc_rf_enabled = 0;
3140203945Sweongyo
3141203945Sweongyo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3142203945Sweongyo}
3143203945Sweongyo
3144203945Sweongyostatic void
3145203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
3146203945Sweongyo{
3147203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
3148203945Sweongyo	struct wmeParams *p;
3149203945Sweongyo	unsigned int i;
3150203945Sweongyo
3151203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
3152203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3153203945Sweongyo
3154203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
3155203945Sweongyo		p = &(sc->sc_wmeParams[i]);
3156203945Sweongyo
3157203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
3158203945Sweongyo		case BWN_WME_VOICE:
3159203945Sweongyo			p->wmep_txopLimit = 0;
3160203945Sweongyo			p->wmep_aifsn = 2;
3161203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3162203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3163203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3164203945Sweongyo			break;
3165203945Sweongyo		case BWN_WME_VIDEO:
3166203945Sweongyo			p->wmep_txopLimit = 0;
3167203945Sweongyo			p->wmep_aifsn = 2;
3168203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3169203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3170203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3171203945Sweongyo			break;
3172203945Sweongyo		case BWN_WME_BESTEFFORT:
3173203945Sweongyo			p->wmep_txopLimit = 0;
3174203945Sweongyo			p->wmep_aifsn = 3;
3175203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3176203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3177203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3178203945Sweongyo			break;
3179203945Sweongyo		case BWN_WME_BACKGROUND:
3180203945Sweongyo			p->wmep_txopLimit = 0;
3181203945Sweongyo			p->wmep_aifsn = 7;
3182203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3183203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3184203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3185203945Sweongyo			break;
3186203945Sweongyo		default:
3187203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3188203945Sweongyo		}
3189203945Sweongyo	}
3190203945Sweongyo}
3191203945Sweongyo
3192203945Sweongyostatic int
3193203945Sweongyobwn_core_init(struct bwn_mac *mac)
3194203945Sweongyo{
3195203945Sweongyo#ifdef BWN_DEBUG
3196203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3197203945Sweongyo#endif
3198203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
3199203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
3200203945Sweongyo	struct siba_sprom *sprom = &siba->siba_sprom;
3201203945Sweongyo	uint64_t hf;
3202203945Sweongyo	int error;
3203203945Sweongyo
3204203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3205203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3206203945Sweongyo
3207203945Sweongyo	siba_powerup(siba, 0);
3208203945Sweongyo	if (!siba_dev_isup(sd))
3209203945Sweongyo		bwn_reset_core(mac,
3210203945Sweongyo		    mac->mac_phy.gmode ? BWN_TGSLOW_SUPPORT_G : 0);
3211203945Sweongyo
3212203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
3213203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
3214203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
3215203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
3216203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
3217203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
3218203945Sweongyo	mac->mac_stats.link_noise = -95;
3219203945Sweongyo	mac->mac_reason_intr = 0;
3220203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
3221203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
3222203945Sweongyo#ifdef BWN_DEBUG
3223203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
3224203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
3225203945Sweongyo#endif
3226203945Sweongyo	mac->mac_suspended = 1;
3227203945Sweongyo	mac->mac_task_state = 0;
3228203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
3229203945Sweongyo
3230203945Sweongyo	mac->mac_phy.init_pre(mac);
3231203945Sweongyo
3232203945Sweongyo	siba_pcicore_intr(&siba->siba_pci, sd);
3233203945Sweongyo
3234203945Sweongyo	bwn_fix_imcfglobug(mac);
3235203945Sweongyo	bwn_bt_disable(mac);
3236203945Sweongyo	if (mac->mac_phy.prepare_hw) {
3237203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
3238203945Sweongyo		if (error)
3239203945Sweongyo			goto fail0;
3240203945Sweongyo	}
3241203945Sweongyo	error = bwn_chip_init(mac);
3242203945Sweongyo	if (error)
3243203945Sweongyo		goto fail0;
3244203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
3245203945Sweongyo	    mac->mac_sd->sd_id.sd_rev);
3246203945Sweongyo	hf = bwn_hf_read(mac);
3247203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
3248203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
3249203945Sweongyo		if (sprom->bf_lo & BWN_BFL_PACTRL)
3250203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
3251203945Sweongyo		if (mac->mac_phy.rev == 1)
3252203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
3253203945Sweongyo	}
3254203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
3255203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
3256203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
3257203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
3258203945Sweongyo			hf |= BWN_HF_4318_TSSI;
3259203945Sweongyo	}
3260203945Sweongyo	if (sprom->bf_lo & BWN_BFL_CRYSTAL_NOSLOW)
3261203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
3262203945Sweongyo	if ((siba->siba_type == SIBA_TYPE_PCI) &&
3263203945Sweongyo	    (siba->siba_pci.spc_dev->sd_id.sd_rev <= 10))
3264203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
3265203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
3266203945Sweongyo	bwn_hf_write(mac, hf);
3267203945Sweongyo
3268203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
3269203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
3270203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
3271203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
3272203945Sweongyo
3273203945Sweongyo	bwn_rate_init(mac);
3274203945Sweongyo	bwn_set_phytxctl(mac);
3275203945Sweongyo
3276203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
3277203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
3278203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
3279203945Sweongyo
3280203945Sweongyo	if (siba->siba_type == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
3281203945Sweongyo		bwn_pio_init(mac);
3282203945Sweongyo	else
3283203945Sweongyo		bwn_dma_init(mac);
3284203945Sweongyo	if (error)
3285203945Sweongyo		goto fail1;
3286203945Sweongyo	bwn_wme_init(mac);
3287203945Sweongyo	bwn_spu_setdelay(mac, 1);
3288203945Sweongyo	bwn_bt_enable(mac);
3289203945Sweongyo
3290203945Sweongyo	siba_powerup(siba, !(sprom->bf_lo & BWN_BFL_CRYSTAL_NOSLOW));
3291203945Sweongyo	bwn_set_macaddr(mac);
3292203945Sweongyo	bwn_crypt_init(mac);
3293203945Sweongyo
3294203945Sweongyo	/* XXX LED initializatin */
3295203945Sweongyo
3296203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
3297203945Sweongyo
3298203945Sweongyo	return (error);
3299203945Sweongyo
3300203945Sweongyofail1:
3301203945Sweongyo	bwn_chip_exit(mac);
3302203945Sweongyofail0:
3303203945Sweongyo	siba_powerdown(siba);
3304203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3305203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3306203945Sweongyo	return (error);
3307203945Sweongyo}
3308203945Sweongyo
3309203945Sweongyostatic void
3310203945Sweongyobwn_core_start(struct bwn_mac *mac)
3311203945Sweongyo{
3312203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3313203945Sweongyo	uint32_t tmp;
3314203945Sweongyo
3315203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
3316203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3317203945Sweongyo
3318203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev < 5)
3319203945Sweongyo		return;
3320203945Sweongyo
3321203945Sweongyo	while (1) {
3322203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
3323203945Sweongyo		if (!(tmp & 0x00000001))
3324203945Sweongyo			break;
3325203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
3326203945Sweongyo	}
3327203945Sweongyo
3328203945Sweongyo	bwn_mac_enable(mac);
3329203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
3330203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
3331203945Sweongyo
3332203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
3333203945Sweongyo}
3334203945Sweongyo
3335203945Sweongyostatic void
3336203945Sweongyobwn_core_exit(struct bwn_mac *mac)
3337203945Sweongyo{
3338203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3339203945Sweongyo	uint32_t macctl;
3340203945Sweongyo
3341203945Sweongyo	BWN_ASSERT_LOCKED(sc);
3342203945Sweongyo
3343203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
3344203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3345203945Sweongyo
3346203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
3347203945Sweongyo		return;
3348203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
3349203945Sweongyo
3350203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3351203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
3352203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
3353203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3354203945Sweongyo
3355203945Sweongyo	bwn_dma_stop(mac);
3356203945Sweongyo	bwn_pio_stop(mac);
3357203945Sweongyo	bwn_chip_exit(mac);
3358203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
3359203945Sweongyo	siba_dev_down(mac->mac_sd, 0);
3360203945Sweongyo	siba_powerdown(mac->mac_sd->sd_bus);
3361203945Sweongyo}
3362203945Sweongyo
3363203945Sweongyostatic void
3364203945Sweongyobwn_fix_imcfglobug(struct bwn_mac *mac)
3365203945Sweongyo{
3366203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
3367203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
3368203945Sweongyo	uint32_t tmp;
3369203945Sweongyo
3370203945Sweongyo	if (siba->siba_pci.spc_dev == NULL)
3371203945Sweongyo		return;
3372203945Sweongyo	if (siba->siba_pci.spc_dev->sd_id.sd_device != SIBA_DEVID_PCI ||
3373203945Sweongyo	    siba->siba_pci.spc_dev->sd_id.sd_rev > 5)
3374203945Sweongyo		return;
3375203945Sweongyo
3376203945Sweongyo	tmp = siba_read_4(sd, SIBA_IMCFGLO) &
3377203945Sweongyo	    ~(SIBA_IMCFGLO_REQTO | SIBA_IMCFGLO_SERTO);
3378203945Sweongyo	switch (siba->siba_type) {
3379203945Sweongyo	case SIBA_TYPE_PCI:
3380203945Sweongyo	case SIBA_TYPE_PCMCIA:
3381203945Sweongyo		tmp |= 0x32;
3382203945Sweongyo		break;
3383203945Sweongyo	case SIBA_TYPE_SSB:
3384203945Sweongyo		tmp |= 0x53;
3385203945Sweongyo		break;
3386203945Sweongyo	}
3387203945Sweongyo	siba_write_4(sd, SIBA_IMCFGLO, tmp);
3388203945Sweongyo}
3389203945Sweongyo
3390203945Sweongyostatic void
3391203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
3392203945Sweongyo{
3393203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3394203945Sweongyo
3395203945Sweongyo	(void)sc;
3396203945Sweongyo	/* XXX do nothing yet */
3397203945Sweongyo}
3398203945Sweongyo
3399203945Sweongyostatic int
3400203945Sweongyobwn_chip_init(struct bwn_mac *mac)
3401203945Sweongyo{
3402203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
3403203945Sweongyo	uint32_t macctl;
3404203945Sweongyo	int error;
3405203945Sweongyo
3406203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
3407203945Sweongyo	if (phy->gmode)
3408203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
3409203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3410203945Sweongyo
3411203945Sweongyo	error = bwn_fw_fillinfo(mac);
3412203945Sweongyo	if (error)
3413203945Sweongyo		return (error);
3414203945Sweongyo	error = bwn_fw_loaducode(mac);
3415203945Sweongyo	if (error)
3416203945Sweongyo		return (error);
3417203945Sweongyo
3418203945Sweongyo	error = bwn_gpio_init(mac);
3419203945Sweongyo	if (error)
3420203945Sweongyo		return (error);
3421203945Sweongyo
3422203945Sweongyo	error = bwn_fw_loadinitvals(mac);
3423203945Sweongyo	if (error) {
3424203945Sweongyo		bwn_gpio_cleanup(mac);
3425203945Sweongyo		return (error);
3426203945Sweongyo	}
3427203945Sweongyo	phy->switch_analog(mac, 1);
3428203945Sweongyo	error = bwn_phy_init(mac);
3429203945Sweongyo	if (error) {
3430203945Sweongyo		bwn_gpio_cleanup(mac);
3431203945Sweongyo		return (error);
3432203945Sweongyo	}
3433203945Sweongyo	if (phy->set_im)
3434203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
3435203945Sweongyo	if (phy->set_antenna)
3436203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
3437203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
3438203945Sweongyo
3439203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
3440203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
3441203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
3442203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev < 5)
3443203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
3444203945Sweongyo
3445203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3446203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
3447203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3448203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
3449203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
3450203945Sweongyo
3451203945Sweongyo	bwn_set_opmode(mac);
3452203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev < 3) {
3453203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
3454203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
3455203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
3456203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
3457203945Sweongyo	} else {
3458203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
3459203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
3460203945Sweongyo	}
3461203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
3462203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
3463203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
3464203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
3465203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
3466203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
3467203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
3468203945Sweongyo	siba_write_4(mac->mac_sd, SIBA_TGSLOW,
3469203945Sweongyo	    siba_read_4(mac->mac_sd, SIBA_TGSLOW) | 0x00100000);
3470203945Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY,
3471203945Sweongyo	    mac->mac_sd->sd_bus->siba_cc.scc_powerup_delay);
3472203945Sweongyo	return (error);
3473203945Sweongyo}
3474203945Sweongyo
3475203945Sweongyo/* read hostflags */
3476203945Sweongyostatic uint64_t
3477203945Sweongyobwn_hf_read(struct bwn_mac *mac)
3478203945Sweongyo{
3479203945Sweongyo	uint64_t ret;
3480203945Sweongyo
3481203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
3482203945Sweongyo	ret <<= 16;
3483203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
3484203945Sweongyo	ret <<= 16;
3485203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
3486203945Sweongyo	return (ret);
3487203945Sweongyo}
3488203945Sweongyo
3489203945Sweongyostatic void
3490203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
3491203945Sweongyo{
3492203945Sweongyo
3493203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
3494203945Sweongyo	    (value & 0x00000000ffffull));
3495203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
3496203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
3497203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
3498203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
3499203945Sweongyo}
3500203945Sweongyo
3501203945Sweongyostatic void
3502203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
3503203945Sweongyo{
3504203945Sweongyo
3505203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
3506203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
3507203945Sweongyo}
3508203945Sweongyo
3509203945Sweongyostatic void
3510203945Sweongyobwn_rate_init(struct bwn_mac *mac)
3511203945Sweongyo{
3512203945Sweongyo
3513203945Sweongyo	switch (mac->mac_phy.type) {
3514203945Sweongyo	case BWN_PHYTYPE_A:
3515203945Sweongyo	case BWN_PHYTYPE_G:
3516203945Sweongyo	case BWN_PHYTYPE_LP:
3517203945Sweongyo	case BWN_PHYTYPE_N:
3518203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
3519203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
3520203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
3521203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
3522203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
3523203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
3524203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
3525203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
3526203945Sweongyo			break;
3527203945Sweongyo		/* FALLTHROUGH */
3528203945Sweongyo	case BWN_PHYTYPE_B:
3529203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
3530203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
3531203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
3532203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
3533203945Sweongyo		break;
3534203945Sweongyo	default:
3535203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3536203945Sweongyo	}
3537203945Sweongyo}
3538203945Sweongyo
3539203945Sweongyostatic void
3540203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
3541203945Sweongyo{
3542203945Sweongyo	uint16_t offset;
3543203945Sweongyo
3544203945Sweongyo	if (ofdm) {
3545203945Sweongyo		offset = 0x480;
3546203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
3547203945Sweongyo	} else {
3548203945Sweongyo		offset = 0x4c0;
3549203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
3550203945Sweongyo	}
3551203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
3552203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
3553203945Sweongyo}
3554203945Sweongyo
3555203945Sweongyostatic uint8_t
3556203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
3557203945Sweongyo{
3558203945Sweongyo
3559203945Sweongyo	switch (bitrate) {
3560203945Sweongyo	case BWN_CCK_RATE_1MB:
3561203945Sweongyo		return (0x0a);
3562203945Sweongyo	case BWN_CCK_RATE_2MB:
3563203945Sweongyo		return (0x14);
3564203945Sweongyo	case BWN_CCK_RATE_5MB:
3565203945Sweongyo		return (0x37);
3566203945Sweongyo	case BWN_CCK_RATE_11MB:
3567203945Sweongyo		return (0x6e);
3568203945Sweongyo	}
3569203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3570203945Sweongyo	return (0);
3571203945Sweongyo}
3572203945Sweongyo
3573203945Sweongyostatic uint8_t
3574203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
3575203945Sweongyo{
3576203945Sweongyo
3577203945Sweongyo	switch (bitrate) {
3578203945Sweongyo	case BWN_OFDM_RATE_6MB:
3579203945Sweongyo		return (0xb);
3580203945Sweongyo	case BWN_OFDM_RATE_9MB:
3581203945Sweongyo		return (0xf);
3582203945Sweongyo	case BWN_OFDM_RATE_12MB:
3583203945Sweongyo		return (0xa);
3584203945Sweongyo	case BWN_OFDM_RATE_18MB:
3585203945Sweongyo		return (0xe);
3586203945Sweongyo	case BWN_OFDM_RATE_24MB:
3587203945Sweongyo		return (0x9);
3588203945Sweongyo	case BWN_OFDM_RATE_36MB:
3589203945Sweongyo		return (0xd);
3590203945Sweongyo	case BWN_OFDM_RATE_48MB:
3591203945Sweongyo		return (0x8);
3592203945Sweongyo	case BWN_OFDM_RATE_54MB:
3593203945Sweongyo		return (0xc);
3594203945Sweongyo	}
3595203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3596203945Sweongyo	return (0);
3597203945Sweongyo}
3598203945Sweongyo
3599203945Sweongyostatic void
3600203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
3601203945Sweongyo{
3602203945Sweongyo	uint16_t ctl;
3603203945Sweongyo
3604203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
3605203945Sweongyo	    BWN_TX_PHY_TXPWR);
3606203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
3607203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
3608203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
3609203945Sweongyo}
3610203945Sweongyo
3611203945Sweongyostatic void
3612203945Sweongyobwn_pio_init(struct bwn_mac *mac)
3613203945Sweongyo{
3614203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
3615203945Sweongyo
3616203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
3617203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
3618203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
3619203945Sweongyo
3620203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
3621203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
3622203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
3623203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
3624203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
3625203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
3626203945Sweongyo}
3627203945Sweongyo
3628203945Sweongyostatic void
3629203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3630203945Sweongyo    int index)
3631203945Sweongyo{
3632203945Sweongyo	struct bwn_pio_txpkt *tp;
3633203945Sweongyo	unsigned int i;
3634203945Sweongyo
3635203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
3636203945Sweongyo	tq->tq_index = index;
3637203945Sweongyo
3638203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
3639203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 8)
3640203945Sweongyo		tq->tq_size = 1920;
3641203945Sweongyo	else {
3642203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
3643203945Sweongyo		tq->tq_size -= 80;
3644203945Sweongyo	}
3645203945Sweongyo
3646203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
3647203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3648203945Sweongyo		tp = &(tq->tq_pkts[i]);
3649203945Sweongyo		tp->tp_index = i;
3650203945Sweongyo		tp->tp_queue = tq;
3651203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
3652203945Sweongyo	}
3653203945Sweongyo}
3654203945Sweongyo
3655203945Sweongyostatic uint16_t
3656203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
3657203945Sweongyo{
3658203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3659203945Sweongyo	static const uint16_t bases[] = {
3660203945Sweongyo		BWN_PIO_BASE0,
3661203945Sweongyo		BWN_PIO_BASE1,
3662203945Sweongyo		BWN_PIO_BASE2,
3663203945Sweongyo		BWN_PIO_BASE3,
3664203945Sweongyo		BWN_PIO_BASE4,
3665203945Sweongyo		BWN_PIO_BASE5,
3666203945Sweongyo		BWN_PIO_BASE6,
3667203945Sweongyo		BWN_PIO_BASE7,
3668203945Sweongyo	};
3669203945Sweongyo	static const uint16_t bases_rev11[] = {
3670203945Sweongyo		BWN_PIO11_BASE0,
3671203945Sweongyo		BWN_PIO11_BASE1,
3672203945Sweongyo		BWN_PIO11_BASE2,
3673203945Sweongyo		BWN_PIO11_BASE3,
3674203945Sweongyo		BWN_PIO11_BASE4,
3675203945Sweongyo		BWN_PIO11_BASE5,
3676203945Sweongyo	};
3677203945Sweongyo
3678203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 11) {
3679203945Sweongyo		if (index >= N(bases_rev11))
3680203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
3681203945Sweongyo		return (bases_rev11[index]);
3682203945Sweongyo	}
3683203945Sweongyo	if (index >= N(bases))
3684203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
3685203945Sweongyo	return (bases[index]);
3686203945Sweongyo}
3687203945Sweongyo
3688203945Sweongyostatic void
3689203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
3690203945Sweongyo    int index)
3691203945Sweongyo{
3692203945Sweongyo
3693203945Sweongyo	prq->prq_mac = mac;
3694203945Sweongyo	prq->prq_rev = mac->mac_sd->sd_id.sd_rev;
3695203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
3696203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
3697203945Sweongyo}
3698203945Sweongyo
3699203945Sweongyostatic void
3700203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
3701203945Sweongyo{
3702203945Sweongyo	if (tq == NULL)
3703203945Sweongyo		return;
3704203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
3705203945Sweongyo}
3706203945Sweongyo
3707203945Sweongyostatic void
3708203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
3709203945Sweongyo{
3710203945Sweongyo
3711203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
3712203945Sweongyo}
3713203945Sweongyo
3714203945Sweongyostatic uint16_t
3715203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3716203945Sweongyo    uint16_t offset)
3717203945Sweongyo{
3718203945Sweongyo
3719203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
3720203945Sweongyo}
3721203945Sweongyo
3722203945Sweongyostatic void
3723203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
3724203945Sweongyo{
3725203945Sweongyo	uint32_t ctl;
3726203945Sweongyo	int type;
3727203945Sweongyo	uint16_t base;
3728203945Sweongyo
3729203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
3730203945Sweongyo	base = bwn_dma_base(type, idx);
3731203945Sweongyo	if (type == BWN_DMA_64BIT) {
3732203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
3733203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
3734203945Sweongyo		if (enable)
3735203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
3736203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
3737203945Sweongyo	} else {
3738203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
3739203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
3740203945Sweongyo		if (enable)
3741203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
3742203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
3743203945Sweongyo	}
3744203945Sweongyo}
3745203945Sweongyo
3746203945Sweongyostatic uint64_t
3747203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
3748203945Sweongyo{
3749203945Sweongyo	uint32_t tmp;
3750203945Sweongyo	uint16_t base;
3751203945Sweongyo
3752203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3753203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3754203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
3755203945Sweongyo	base = bwn_dma_base(0, 0);
3756203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3757203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3758203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3759203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
3760203945Sweongyo
3761203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
3762203945Sweongyo}
3763203945Sweongyo
3764203945Sweongyostatic int
3765203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
3766203945Sweongyo{
3767203945Sweongyo
3768203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
3769203945Sweongyo		return (BWN_DMA_30BIT);
3770203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
3771203945Sweongyo		return (BWN_DMA_32BIT);
3772203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
3773203945Sweongyo		return (BWN_DMA_64BIT);
3774203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3775203945Sweongyo	return (BWN_DMA_30BIT);
3776203945Sweongyo}
3777203945Sweongyo
3778203945Sweongyostatic void
3779203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
3780203945Sweongyo{
3781203945Sweongyo	struct bwn_pio_txpkt *tp;
3782203945Sweongyo	unsigned int i;
3783203945Sweongyo
3784203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3785203945Sweongyo		tp = &(tq->tq_pkts[i]);
3786203945Sweongyo		if (tp->tp_m) {
3787203945Sweongyo			m_freem(tp->tp_m);
3788203945Sweongyo			tp->tp_m = NULL;
3789203945Sweongyo		}
3790203945Sweongyo	}
3791203945Sweongyo}
3792203945Sweongyo
3793203945Sweongyostatic uint16_t
3794203945Sweongyobwn_dma_base(int type, int controller_idx)
3795203945Sweongyo{
3796203945Sweongyo	static const uint16_t map64[] = {
3797203945Sweongyo		BWN_DMA64_BASE0,
3798203945Sweongyo		BWN_DMA64_BASE1,
3799203945Sweongyo		BWN_DMA64_BASE2,
3800203945Sweongyo		BWN_DMA64_BASE3,
3801203945Sweongyo		BWN_DMA64_BASE4,
3802203945Sweongyo		BWN_DMA64_BASE5,
3803203945Sweongyo	};
3804203945Sweongyo	static const uint16_t map32[] = {
3805203945Sweongyo		BWN_DMA32_BASE0,
3806203945Sweongyo		BWN_DMA32_BASE1,
3807203945Sweongyo		BWN_DMA32_BASE2,
3808203945Sweongyo		BWN_DMA32_BASE3,
3809203945Sweongyo		BWN_DMA32_BASE4,
3810203945Sweongyo		BWN_DMA32_BASE5,
3811203945Sweongyo	};
3812203945Sweongyo
3813203945Sweongyo	if (type == BWN_DMA_64BIT) {
3814203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
3815203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3816203945Sweongyo		return (map64[controller_idx]);
3817203945Sweongyo	}
3818203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
3819203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3820203945Sweongyo	return (map32[controller_idx]);
3821203945Sweongyo}
3822203945Sweongyo
3823203945Sweongyostatic void
3824203945Sweongyobwn_dma_init(struct bwn_mac *mac)
3825203945Sweongyo{
3826203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3827203945Sweongyo
3828203945Sweongyo	/* setup TX DMA channels. */
3829203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
3830203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
3831203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
3832203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
3833203945Sweongyo	bwn_dma_setup(dma->mcast);
3834203945Sweongyo	/* setup RX DMA channel. */
3835203945Sweongyo	bwn_dma_setup(dma->rx);
3836203945Sweongyo}
3837203945Sweongyo
3838203945Sweongyostatic struct bwn_dma_ring *
3839203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
3840203945Sweongyo    int for_tx, int type)
3841203945Sweongyo{
3842203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3843203945Sweongyo	struct bwn_dma_ring *dr;
3844203945Sweongyo	struct bwn_dmadesc_generic *desc;
3845203945Sweongyo	struct bwn_dmadesc_meta *mt;
3846203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3847203945Sweongyo	int error, i;
3848203945Sweongyo
3849203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
3850203945Sweongyo	if (dr == NULL)
3851203945Sweongyo		goto out;
3852203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
3853203945Sweongyo	if (for_tx)
3854203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
3855203945Sweongyo
3856203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
3857203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
3858203945Sweongyo	if (dr->dr_meta == NULL)
3859203945Sweongyo		goto fail0;
3860203945Sweongyo
3861203945Sweongyo	dr->dr_type = type;
3862203945Sweongyo	dr->dr_mac = mac;
3863203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
3864203945Sweongyo	dr->dr_index = controller_index;
3865203945Sweongyo	if (type == BWN_DMA_64BIT) {
3866203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
3867203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
3868203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
3869203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
3870203945Sweongyo		dr->resume = bwn_dma_64_resume;
3871203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
3872203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
3873203945Sweongyo	} else {
3874203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
3875203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
3876203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
3877203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
3878203945Sweongyo		dr->resume = bwn_dma_32_resume;
3879203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
3880203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
3881203945Sweongyo	}
3882203945Sweongyo	if (for_tx) {
3883203945Sweongyo		dr->dr_tx = 1;
3884203945Sweongyo		dr->dr_curslot = -1;
3885203945Sweongyo	} else {
3886203945Sweongyo		if (dr->dr_index == 0) {
3887203945Sweongyo			dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
3888203945Sweongyo			dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
3889203945Sweongyo		} else
3890203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3891203945Sweongyo	}
3892203945Sweongyo
3893203945Sweongyo	error = bwn_dma_allocringmemory(dr);
3894203945Sweongyo	if (error)
3895203945Sweongyo		goto fail2;
3896203945Sweongyo
3897203945Sweongyo	if (for_tx) {
3898203945Sweongyo		/*
3899203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
3900203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
3901203945Sweongyo		 */
3902203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
3903203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3904203945Sweongyo
3905203945Sweongyo		dr->dr_txhdr_cache =
3906203945Sweongyo		    malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
3907203945Sweongyo			BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
3908203945Sweongyo		KASSERT(dr->dr_txhdr_cache != NULL,
3909203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3910203945Sweongyo
3911203945Sweongyo		/*
3912203945Sweongyo		 * Create TX ring DMA stuffs
3913203945Sweongyo		 */
3914203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
3915203945Sweongyo				    BWN_ALIGN, 0,
3916203945Sweongyo				    BUS_SPACE_MAXADDR,
3917203945Sweongyo				    BUS_SPACE_MAXADDR,
3918203945Sweongyo				    NULL, NULL,
3919203945Sweongyo				    BWN_HDRSIZE(mac),
3920203945Sweongyo				    1,
3921203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
3922203945Sweongyo				    0,
3923203945Sweongyo				    NULL, NULL,
3924203945Sweongyo				    &dr->dr_txring_dtag);
3925203945Sweongyo		if (error) {
3926203945Sweongyo			device_printf(sc->sc_dev,
3927203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
3928203945Sweongyo			goto fail1;
3929203945Sweongyo		}
3930203945Sweongyo
3931203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
3932203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3933203945Sweongyo
3934203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
3935203945Sweongyo			mt->mt_m = NULL;
3936203945Sweongyo			mt->mt_ni = NULL;
3937203945Sweongyo			mt->mt_islast = 0;
3938203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
3939203945Sweongyo			    &mt->mt_dmap);
3940203945Sweongyo			if (error) {
3941203945Sweongyo				device_printf(sc->sc_dev,
3942203945Sweongyo				     "can't create RX buf DMA map\n");
3943203945Sweongyo				goto fail1;
3944203945Sweongyo			}
3945203945Sweongyo
3946203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
3947203945Sweongyo
3948203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
3949203945Sweongyo			mt->mt_m = NULL;
3950203945Sweongyo			mt->mt_ni = NULL;
3951203945Sweongyo			mt->mt_islast = 1;
3952203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
3953203945Sweongyo			    &mt->mt_dmap);
3954203945Sweongyo			if (error) {
3955203945Sweongyo				device_printf(sc->sc_dev,
3956203945Sweongyo				     "can't create RX buf DMA map\n");
3957203945Sweongyo				goto fail1;
3958203945Sweongyo			}
3959203945Sweongyo		}
3960203945Sweongyo	} else {
3961203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3962203945Sweongyo		    &dr->dr_spare_dmap);
3963203945Sweongyo		if (error) {
3964203945Sweongyo			device_printf(sc->sc_dev,
3965203945Sweongyo			    "can't create RX buf DMA map\n");
3966203945Sweongyo			goto out;		/* XXX wrong! */
3967203945Sweongyo		}
3968203945Sweongyo
3969203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
3970203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3971203945Sweongyo
3972203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3973203945Sweongyo			    &mt->mt_dmap);
3974203945Sweongyo			if (error) {
3975203945Sweongyo				device_printf(sc->sc_dev,
3976203945Sweongyo				    "can't create RX buf DMA map\n");
3977203945Sweongyo				goto out;	/* XXX wrong! */
3978203945Sweongyo			}
3979203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
3980203945Sweongyo			if (error) {
3981203945Sweongyo				device_printf(sc->sc_dev,
3982203945Sweongyo				    "failed to allocate RX buf\n");
3983203945Sweongyo				goto out;	/* XXX wrong! */
3984203945Sweongyo			}
3985203945Sweongyo		}
3986203945Sweongyo
3987203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
3988203945Sweongyo		    BUS_DMASYNC_PREWRITE);
3989203945Sweongyo
3990203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
3991203945Sweongyo	}
3992203945Sweongyo
3993203945Sweongyo      out:
3994203945Sweongyo	return (dr);
3995203945Sweongyo
3996203945Sweongyofail2:
3997203945Sweongyo	free(dr->dr_txhdr_cache, M_DEVBUF);
3998203945Sweongyofail1:
3999203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
4000203945Sweongyofail0:
4001203945Sweongyo	free(dr, M_DEVBUF);
4002203945Sweongyo	return (NULL);
4003203945Sweongyo}
4004203945Sweongyo
4005203945Sweongyostatic void
4006203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
4007203945Sweongyo{
4008203945Sweongyo
4009203945Sweongyo	if (dr == NULL)
4010203945Sweongyo		return;
4011203945Sweongyo
4012203945Sweongyo	bwn_dma_free_descbufs(*dr);
4013203945Sweongyo	bwn_dma_free_ringmemory(*dr);
4014203945Sweongyo
4015203945Sweongyo	free((*dr)->dr_txhdr_cache, M_DEVBUF);
4016203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
4017203945Sweongyo	free(*dr, M_DEVBUF);
4018203945Sweongyo
4019203945Sweongyo	*dr = NULL;
4020203945Sweongyo}
4021203945Sweongyo
4022203945Sweongyostatic void
4023203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
4024203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
4025203945Sweongyo{
4026203945Sweongyo	struct bwn_dmadesc32 *desc;
4027203945Sweongyo
4028203945Sweongyo	*meta = &(dr->dr_meta[slot]);
4029203945Sweongyo	desc = dr->dr_ring_descbase;
4030203945Sweongyo	desc = &(desc[slot]);
4031203945Sweongyo
4032203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
4033203945Sweongyo}
4034203945Sweongyo
4035203945Sweongyostatic void
4036203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
4037203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
4038203945Sweongyo    int start, int end, int irq)
4039203945Sweongyo{
4040203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
4041203945Sweongyo	uint32_t addr, addrext, ctl;
4042203945Sweongyo	int slot;
4043203945Sweongyo
4044203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
4045203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
4046203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4047203945Sweongyo
4048203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
4049203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
4050203945Sweongyo	addr |= siba_dma_translation(dr->dr_mac->mac_sd);
4051203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
4052203945Sweongyo	if (slot == dr->dr_numslots - 1)
4053203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
4054203945Sweongyo	if (start)
4055203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
4056203945Sweongyo	if (end)
4057203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
4058203945Sweongyo	if (irq)
4059203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
4060203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
4061203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
4062203945Sweongyo
4063203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
4064203945Sweongyo	desc->dma.dma32.address = htole32(addr);
4065203945Sweongyo}
4066203945Sweongyo
4067203945Sweongyostatic void
4068203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
4069203945Sweongyo{
4070203945Sweongyo
4071203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
4072203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
4073203945Sweongyo}
4074203945Sweongyo
4075203945Sweongyostatic void
4076203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
4077203945Sweongyo{
4078203945Sweongyo
4079203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
4080203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
4081203945Sweongyo}
4082203945Sweongyo
4083203945Sweongyostatic void
4084203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
4085203945Sweongyo{
4086203945Sweongyo
4087203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
4088203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
4089203945Sweongyo}
4090203945Sweongyo
4091203945Sweongyostatic int
4092203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
4093203945Sweongyo{
4094203945Sweongyo	uint32_t val;
4095203945Sweongyo
4096203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
4097203945Sweongyo	val &= BWN_DMA32_RXDPTR;
4098203945Sweongyo
4099203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
4100203945Sweongyo}
4101203945Sweongyo
4102203945Sweongyostatic void
4103203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
4104203945Sweongyo{
4105203945Sweongyo
4106203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
4107203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
4108203945Sweongyo}
4109203945Sweongyo
4110203945Sweongyostatic void
4111203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
4112203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
4113203945Sweongyo{
4114203945Sweongyo	struct bwn_dmadesc64 *desc;
4115203945Sweongyo
4116203945Sweongyo	*meta = &(dr->dr_meta[slot]);
4117203945Sweongyo	desc = dr->dr_ring_descbase;
4118203945Sweongyo	desc = &(desc[slot]);
4119203945Sweongyo
4120203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
4121203945Sweongyo}
4122203945Sweongyo
4123203945Sweongyostatic void
4124203945Sweongyobwn_dma_64_setdesc(struct bwn_dma_ring *dr,
4125203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
4126203945Sweongyo    int start, int end, int irq)
4127203945Sweongyo{
4128203945Sweongyo	struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
4129203945Sweongyo	int slot;
4130203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
4131203945Sweongyo	uint32_t addrlo, addrhi;
4132203945Sweongyo	uint32_t addrext;
4133203945Sweongyo
4134203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
4135203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
4136203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4137203945Sweongyo
4138203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
4139203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
4140203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
4141203945Sweongyo	    30;
4142203945Sweongyo	addrhi |= (siba_dma_translation(dr->dr_mac->mac_sd) << 1);
4143203945Sweongyo	if (slot == dr->dr_numslots - 1)
4144203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
4145203945Sweongyo	if (start)
4146203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
4147203945Sweongyo	if (end)
4148203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
4149203945Sweongyo	if (irq)
4150203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
4151203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
4152203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
4153203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
4154203945Sweongyo
4155203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
4156203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
4157203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
4158203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
4159203945Sweongyo}
4160203945Sweongyo
4161203945Sweongyostatic void
4162203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
4163203945Sweongyo{
4164203945Sweongyo
4165203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
4166203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4167203945Sweongyo}
4168203945Sweongyo
4169203945Sweongyostatic void
4170203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
4171203945Sweongyo{
4172203945Sweongyo
4173203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4174203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
4175203945Sweongyo}
4176203945Sweongyo
4177203945Sweongyostatic void
4178203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
4179203945Sweongyo{
4180203945Sweongyo
4181203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
4182203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
4183203945Sweongyo}
4184203945Sweongyo
4185203945Sweongyostatic int
4186203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
4187203945Sweongyo{
4188203945Sweongyo	uint32_t val;
4189203945Sweongyo
4190203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
4191203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
4192203945Sweongyo
4193203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
4194203945Sweongyo}
4195203945Sweongyo
4196203945Sweongyostatic void
4197203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
4198203945Sweongyo{
4199203945Sweongyo
4200203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
4201203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4202203945Sweongyo}
4203203945Sweongyo
4204203945Sweongyostatic int
4205203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
4206203945Sweongyo{
4207203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4208203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4209203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4210203945Sweongyo	int error;
4211203945Sweongyo
4212203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
4213203945Sweongyo			    BWN_ALIGN, 0,
4214203945Sweongyo			    BUS_SPACE_MAXADDR,
4215203945Sweongyo			    BUS_SPACE_MAXADDR,
4216203945Sweongyo			    NULL, NULL,
4217203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
4218203945Sweongyo			    1,
4219203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
4220203945Sweongyo			    0,
4221203945Sweongyo			    NULL, NULL,
4222203945Sweongyo			    &dr->dr_ring_dtag);
4223203945Sweongyo	if (error) {
4224203945Sweongyo		device_printf(sc->sc_dev,
4225203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
4226203945Sweongyo		return (-1);
4227203945Sweongyo	}
4228203945Sweongyo
4229203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
4230203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
4231203945Sweongyo	    &dr->dr_ring_dmap);
4232203945Sweongyo	if (error) {
4233203945Sweongyo		device_printf(sc->sc_dev,
4234203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
4235203945Sweongyo		return (-1);
4236203945Sweongyo	}
4237203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
4238203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
4239203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
4240203945Sweongyo	if (error) {
4241203945Sweongyo		device_printf(sc->sc_dev,
4242203945Sweongyo		    "can't load DMA mem: TODO free\n");
4243203945Sweongyo		return (-1);
4244203945Sweongyo	}
4245203945Sweongyo
4246203945Sweongyo	return (0);
4247203945Sweongyo}
4248203945Sweongyo
4249203945Sweongyostatic void
4250203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
4251203945Sweongyo{
4252203945Sweongyo	uint64_t ring64;
4253203945Sweongyo	uint32_t addrext, ring32, value;
4254203945Sweongyo	uint32_t trans = siba_dma_translation(dr->dr_mac->mac_sd);
4255203945Sweongyo
4256203945Sweongyo	if (dr->dr_tx) {
4257203945Sweongyo		dr->dr_curslot = -1;
4258203945Sweongyo
4259203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4260203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
4261203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
4262203945Sweongyo			    >> 30;
4263203945Sweongyo			value = BWN_DMA64_TXENABLE;
4264203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
4265203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
4266203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
4267203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
4268203945Sweongyo			    (ring64 & 0xffffffff));
4269203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
4270203945Sweongyo			    ((ring64 >> 32) &
4271203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
4272203945Sweongyo		} else {
4273203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
4274203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4275203945Sweongyo			value = BWN_DMA32_TXENABLE;
4276203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
4277203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
4278203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
4279203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
4280203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4281203945Sweongyo		}
4282203945Sweongyo		return;
4283203945Sweongyo	}
4284203945Sweongyo
4285203945Sweongyo	/*
4286203945Sweongyo	 * set for RX
4287203945Sweongyo	 */
4288203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
4289203945Sweongyo
4290203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
4291203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
4292203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
4293203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
4294203945Sweongyo		value |= BWN_DMA64_RXENABLE;
4295203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
4296203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
4297203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
4298203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
4299203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
4300203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
4301203945Sweongyo		    | (trans << 1));
4302203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
4303203945Sweongyo		    sizeof(struct bwn_dmadesc64));
4304203945Sweongyo	} else {
4305203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
4306203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4307203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
4308203945Sweongyo		value |= BWN_DMA32_RXENABLE;
4309203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
4310203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
4311203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
4312203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
4313203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4314203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
4315203945Sweongyo		    sizeof(struct bwn_dmadesc32));
4316203945Sweongyo	}
4317203945Sweongyo}
4318203945Sweongyo
4319203945Sweongyostatic void
4320203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
4321203945Sweongyo{
4322203945Sweongyo
4323203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
4324203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
4325203945Sweongyo	    dr->dr_ring_dmap);
4326203945Sweongyo}
4327203945Sweongyo
4328203945Sweongyostatic void
4329203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
4330203945Sweongyo{
4331203945Sweongyo
4332203945Sweongyo	if (dr->dr_tx) {
4333203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4334203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4335203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
4336203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
4337203945Sweongyo		} else
4338203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
4339203945Sweongyo	} else {
4340203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4341203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4342203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
4343203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
4344203945Sweongyo		} else
4345203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
4346203945Sweongyo	}
4347203945Sweongyo}
4348203945Sweongyo
4349203945Sweongyostatic void
4350203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
4351203945Sweongyo{
4352203945Sweongyo	struct bwn_dmadesc_generic *desc;
4353203945Sweongyo	struct bwn_dmadesc_meta *meta;
4354203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4355203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4356203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4357203945Sweongyo	int i;
4358203945Sweongyo
4359203945Sweongyo	if (!dr->dr_usedslot)
4360203945Sweongyo		return;
4361203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
4362203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
4363203945Sweongyo
4364203945Sweongyo		if (meta->mt_m == NULL) {
4365203945Sweongyo			if (!dr->dr_tx)
4366203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
4367203945Sweongyo				    __func__);
4368203945Sweongyo			continue;
4369203945Sweongyo		}
4370203945Sweongyo		if (dr->dr_tx) {
4371203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
4372203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
4373203945Sweongyo				    meta->mt_dmap);
4374203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
4375203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
4376203945Sweongyo				    meta->mt_dmap);
4377203945Sweongyo		} else
4378203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
4379203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
4380203945Sweongyo	}
4381203945Sweongyo}
4382203945Sweongyo
4383203945Sweongyostatic int
4384203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
4385203945Sweongyo    int type)
4386203945Sweongyo{
4387203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4388203945Sweongyo	uint32_t value;
4389203945Sweongyo	int i;
4390203945Sweongyo	uint16_t offset;
4391203945Sweongyo
4392203945Sweongyo	for (i = 0; i < 10; i++) {
4393203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4394203945Sweongyo		    BWN_DMA32_TXSTATUS;
4395203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4396203945Sweongyo		if (type == BWN_DMA_64BIT) {
4397203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4398203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
4399203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
4400203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
4401203945Sweongyo				break;
4402203945Sweongyo		} else {
4403203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4404203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
4405203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
4406203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
4407203945Sweongyo				break;
4408203945Sweongyo		}
4409203945Sweongyo		DELAY(1000);
4410203945Sweongyo	}
4411203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
4412203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4413203945Sweongyo	for (i = 0; i < 10; i++) {
4414203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4415203945Sweongyo						   BWN_DMA32_TXSTATUS;
4416203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4417203945Sweongyo		if (type == BWN_DMA_64BIT) {
4418203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4419203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
4420203945Sweongyo				i = -1;
4421203945Sweongyo				break;
4422203945Sweongyo			}
4423203945Sweongyo		} else {
4424203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4425203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
4426203945Sweongyo				i = -1;
4427203945Sweongyo				break;
4428203945Sweongyo			}
4429203945Sweongyo		}
4430203945Sweongyo		DELAY(1000);
4431203945Sweongyo	}
4432203945Sweongyo	if (i != -1) {
4433203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4434203945Sweongyo		return (ENODEV);
4435203945Sweongyo	}
4436203945Sweongyo	DELAY(1000);
4437203945Sweongyo
4438203945Sweongyo	return (0);
4439203945Sweongyo}
4440203945Sweongyo
4441203945Sweongyostatic int
4442203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
4443203945Sweongyo    int type)
4444203945Sweongyo{
4445203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4446203945Sweongyo	uint32_t value;
4447203945Sweongyo	int i;
4448203945Sweongyo	uint16_t offset;
4449203945Sweongyo
4450203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
4451203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4452203945Sweongyo	for (i = 0; i < 10; i++) {
4453203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
4454203945Sweongyo		    BWN_DMA32_RXSTATUS;
4455203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4456203945Sweongyo		if (type == BWN_DMA_64BIT) {
4457203945Sweongyo			value &= BWN_DMA64_RXSTAT;
4458203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
4459203945Sweongyo				i = -1;
4460203945Sweongyo				break;
4461203945Sweongyo			}
4462203945Sweongyo		} else {
4463203945Sweongyo			value &= BWN_DMA32_RXSTATE;
4464203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
4465203945Sweongyo				i = -1;
4466203945Sweongyo				break;
4467203945Sweongyo			}
4468203945Sweongyo		}
4469203945Sweongyo		DELAY(1000);
4470203945Sweongyo	}
4471203945Sweongyo	if (i != -1) {
4472203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4473203945Sweongyo		return (ENODEV);
4474203945Sweongyo	}
4475203945Sweongyo
4476203945Sweongyo	return (0);
4477203945Sweongyo}
4478203945Sweongyo
4479203945Sweongyostatic void
4480203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
4481203945Sweongyo    struct bwn_dmadesc_meta *meta)
4482203945Sweongyo{
4483203945Sweongyo
4484203945Sweongyo	if (meta->mt_m != NULL) {
4485203945Sweongyo		m_freem(meta->mt_m);
4486203945Sweongyo		meta->mt_m = NULL;
4487203945Sweongyo	}
4488203945Sweongyo	if (meta->mt_ni != NULL) {
4489203945Sweongyo		ieee80211_free_node(meta->mt_ni);
4490203945Sweongyo		meta->mt_ni = NULL;
4491203945Sweongyo	}
4492203945Sweongyo}
4493203945Sweongyo
4494203945Sweongyostatic void
4495203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4496203945Sweongyo{
4497203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
4498203945Sweongyo	unsigned char *frame;
4499203945Sweongyo
4500203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
4501203945Sweongyo	rxhdr->frame_len = 0;
4502203945Sweongyo
4503203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
4504203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
4505203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4506203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
4507203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
4508203945Sweongyo}
4509203945Sweongyo
4510203945Sweongyostatic uint8_t
4511203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4512203945Sweongyo{
4513203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
4514203945Sweongyo
4515203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
4516203945Sweongyo	    == 0xff);
4517203945Sweongyo}
4518203945Sweongyo
4519203945Sweongyostatic void
4520203945Sweongyobwn_wme_init(struct bwn_mac *mac)
4521203945Sweongyo{
4522203945Sweongyo
4523203945Sweongyo	bwn_wme_load(mac);
4524203945Sweongyo
4525203945Sweongyo	/* enable WME support. */
4526203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
4527203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
4528203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
4529203945Sweongyo}
4530203945Sweongyo
4531203945Sweongyostatic void
4532203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
4533203945Sweongyo{
4534203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4535203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4536203945Sweongyo	uint16_t delay;	/* microsec */
4537203945Sweongyo
4538203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
4539203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
4540203945Sweongyo		delay = 500;
4541203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
4542203945Sweongyo		delay = max(delay, (uint16_t)2400);
4543203945Sweongyo
4544203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
4545203945Sweongyo}
4546203945Sweongyo
4547203945Sweongyostatic void
4548203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
4549203945Sweongyo{
4550203945Sweongyo	struct siba_sprom *sprom = &mac->mac_sd->sd_bus->siba_sprom;
4551203945Sweongyo	uint64_t hf;
4552203945Sweongyo
4553203945Sweongyo	if (bwn_bluetooth == 0)
4554203945Sweongyo		return;
4555203945Sweongyo	if ((sprom->bf_lo & BWN_BFL_BTCOEXIST) == 0)
4556203945Sweongyo		return;
4557203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
4558203945Sweongyo		return;
4559203945Sweongyo
4560203945Sweongyo	hf = bwn_hf_read(mac);
4561203945Sweongyo	if (sprom->bf_lo & BWN_BFL_BTCMOD)
4562203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
4563203945Sweongyo	else
4564203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
4565203945Sweongyo	bwn_hf_write(mac, hf);
4566203945Sweongyo}
4567203945Sweongyo
4568203945Sweongyostatic void
4569203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
4570203945Sweongyo{
4571203945Sweongyo
4572203945Sweongyo	bwn_mac_write_bssid(mac);
4573203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF, mac->mac_sc->sc_macaddr);
4574203945Sweongyo}
4575203945Sweongyo
4576203945Sweongyostatic void
4577203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
4578203945Sweongyo{
4579203945Sweongyo	int i;
4580203945Sweongyo
4581203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
4582203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
4583203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
4584203945Sweongyo
4585203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
4586203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
4587203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
4588203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
4589203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
4590203945Sweongyo		}
4591203945Sweongyo		mac->mac_key[i].keyconf = NULL;
4592203945Sweongyo	}
4593203945Sweongyo}
4594203945Sweongyo
4595203945Sweongyostatic void
4596203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
4597203945Sweongyo{
4598203945Sweongyo
4599203945Sweongyo	mac->mac_max_nr_keys = (mac->mac_sd->sd_id.sd_rev >= 5) ? 58 : 20;
4600203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
4601203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4602203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
4603203945Sweongyo	mac->mac_ktp *= 2;
4604203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 5) {
4605203945Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT,
4606203945Sweongyo		    mac->mac_max_nr_keys - 8);
4607203945Sweongyo	}
4608203945Sweongyo	bwn_clear_keys(mac);
4609203945Sweongyo}
4610203945Sweongyo
4611203945Sweongyostatic void
4612203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
4613203945Sweongyo{
4614203945Sweongyo
4615203945Sweongyo	bwn_phy_exit(mac);
4616203945Sweongyo	bwn_gpio_cleanup(mac);
4617203945Sweongyo}
4618203945Sweongyo
4619203945Sweongyostatic int
4620203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
4621203945Sweongyo{
4622203945Sweongyo	int error;
4623203945Sweongyo
4624203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
4625203945Sweongyo	if (error == 0)
4626203945Sweongyo		return (0);
4627203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
4628203945Sweongyo	if (error == 0)
4629203945Sweongyo		return (0);
4630203945Sweongyo	return (error);
4631203945Sweongyo}
4632203945Sweongyo
4633203945Sweongyostatic int
4634203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
4635203945Sweongyo{
4636203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
4637203945Sweongyo	struct siba_dev_softc *sd;
4638203945Sweongyo	uint32_t mask = 0x0000001f, set = 0x0000000f;
4639203945Sweongyo
4640203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4641203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
4642203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
4643203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
4644203945Sweongyo
4645203945Sweongyo	if (bus->siba_chipid == 0x4301) {
4646203945Sweongyo		mask |= 0x0060;
4647203945Sweongyo		set |= 0x0060;
4648203945Sweongyo	}
4649203945Sweongyo	if (bus->siba_sprom.bf_lo & BWN_BFL_PACTRL) {
4650203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
4651203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
4652203945Sweongyo		mask |= 0x0200;
4653203945Sweongyo		set |= 0x0200;
4654203945Sweongyo	}
4655203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 2)
4656203945Sweongyo		mask |= 0x0010;
4657203945Sweongyo	sd = (bus->siba_cc.scc_dev != NULL) ? bus->siba_cc.scc_dev :
4658203945Sweongyo	    bus->siba_pci.spc_dev;
4659203945Sweongyo	if (sd == NULL)
4660203945Sweongyo		return (0);
4661203945Sweongyo	siba_write_4(sd, BWN_GPIOCTL,
4662203945Sweongyo	    (siba_read_4(sd, BWN_GPIOCTL) & mask) | set);
4663203945Sweongyo
4664203945Sweongyo	return (0);
4665203945Sweongyo}
4666203945Sweongyo
4667203945Sweongyostatic int
4668203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
4669203945Sweongyo{
4670203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
4671203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
4672203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
4673203945Sweongyo	const struct bwn_fwhdr *hdr;
4674203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
4675203945Sweongyo	int error;
4676203945Sweongyo
4677203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
4678203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
4679203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
4680203945Sweongyo	if (error)
4681203945Sweongyo		return (error);
4682203945Sweongyo	if (fw->initvals_band.fw) {
4683203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
4684203945Sweongyo		error = bwn_fwinitvals_write(mac,
4685203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
4686203945Sweongyo		    be32toh(hdr->size),
4687203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
4688203945Sweongyo	}
4689203945Sweongyo	return (error);
4690203945Sweongyo#undef GETFWOFFSET
4691203945Sweongyo}
4692203945Sweongyo
4693203945Sweongyostatic int
4694203945Sweongyobwn_phy_init(struct bwn_mac *mac)
4695203945Sweongyo{
4696203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4697203945Sweongyo	int error;
4698203945Sweongyo
4699203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
4700203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4701203945Sweongyo	error = mac->mac_phy.init(mac);
4702203945Sweongyo	if (error) {
4703203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
4704203945Sweongyo		goto fail0;
4705203945Sweongyo	}
4706203945Sweongyo	error = bwn_switch_channel(mac,
4707203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
4708203945Sweongyo	if (error) {
4709203945Sweongyo		device_printf(sc->sc_dev,
4710203945Sweongyo		    "failed to switch default channel\n");
4711203945Sweongyo		goto fail1;
4712203945Sweongyo	}
4713203945Sweongyo	return (0);
4714203945Sweongyofail1:
4715203945Sweongyo	if (mac->mac_phy.exit)
4716203945Sweongyo		mac->mac_phy.exit(mac);
4717203945Sweongyofail0:
4718203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4719203945Sweongyo
4720203945Sweongyo	return (error);
4721203945Sweongyo}
4722203945Sweongyo
4723203945Sweongyostatic void
4724203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
4725203945Sweongyo{
4726203945Sweongyo	uint16_t ant;
4727203945Sweongyo	uint16_t tmp;
4728203945Sweongyo
4729203945Sweongyo	ant = bwn_ant2phy(antenna);
4730203945Sweongyo
4731203945Sweongyo	/* For ACK/CTS */
4732203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
4733203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4734203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
4735203945Sweongyo	/* For Probe Resposes */
4736203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
4737203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4738203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
4739203945Sweongyo}
4740203945Sweongyo
4741203945Sweongyostatic void
4742203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
4743203945Sweongyo{
4744203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4745203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
4746203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
4747203945Sweongyo	uint32_t ctl;
4748203945Sweongyo	uint16_t cfp_pretbtt;
4749203945Sweongyo
4750203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
4751203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
4752203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
4753203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
4754203945Sweongyo	ctl |= BWN_MACCTL_STA;
4755203945Sweongyo
4756203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4757203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
4758203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
4759203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
4760203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
4761203945Sweongyo	ctl |= sc->sc_filters;
4762203945Sweongyo
4763203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev <= 4)
4764203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
4765203945Sweongyo
4766203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
4767203945Sweongyo
4768203945Sweongyo	cfp_pretbtt = 2;
4769203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
4770203945Sweongyo		if (mac->mac_sd->sd_bus->siba_chipid == 0x4306 &&
4771203945Sweongyo		    mac->mac_sd->sd_bus->siba_chiprev == 3)
4772203945Sweongyo			cfp_pretbtt = 100;
4773203945Sweongyo		else
4774203945Sweongyo			cfp_pretbtt = 50;
4775203945Sweongyo	}
4776203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
4777203945Sweongyo}
4778203945Sweongyo
4779203945Sweongyostatic void
4780203945Sweongyobwn_gpio_cleanup(struct bwn_mac *mac)
4781203945Sweongyo{
4782203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
4783203945Sweongyo	struct siba_dev_softc *gpiodev, *pcidev = NULL;
4784203945Sweongyo
4785203945Sweongyo	pcidev = bus->siba_pci.spc_dev;
4786203945Sweongyo	gpiodev = bus->siba_cc.scc_dev ? bus->siba_cc.scc_dev : pcidev;
4787203945Sweongyo	if (!gpiodev)
4788203945Sweongyo		return;
4789203945Sweongyo	siba_write_4(gpiodev, BWN_GPIOCTL, 0);
4790203945Sweongyo}
4791203945Sweongyo
4792203945Sweongyostatic int
4793203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
4794203945Sweongyo{
4795203945Sweongyo	uint32_t tmp;
4796203945Sweongyo	uint16_t base;
4797203945Sweongyo
4798203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
4799203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
4800203945Sweongyo		return (BWN_DMA_64BIT);
4801203945Sweongyo	base = bwn_dma_base(0, 0);
4802203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
4803203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
4804203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
4805203945Sweongyo		return (BWN_DMA_32BIT);
4806203945Sweongyo
4807203945Sweongyo	return (BWN_DMA_30BIT);
4808203945Sweongyo}
4809203945Sweongyo
4810203945Sweongyostatic void
4811203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
4812203945Sweongyo{
4813203945Sweongyo	if (!error) {
4814203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
4815203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
4816203945Sweongyo	}
4817203945Sweongyo}
4818203945Sweongyo
4819203945Sweongyostatic void
4820203945Sweongyobwn_phy_g_init_sub(struct bwn_mac *mac)
4821203945Sweongyo{
4822203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4823203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4824203945Sweongyo	uint16_t i, tmp;
4825203945Sweongyo
4826203945Sweongyo	if (phy->rev == 1)
4827203945Sweongyo		bwn_phy_init_b5(mac);
4828203945Sweongyo	else
4829203945Sweongyo		bwn_phy_init_b6(mac);
4830203945Sweongyo
4831203945Sweongyo	if (phy->rev >= 2 || phy->gmode)
4832203945Sweongyo		bwn_phy_init_a(mac);
4833203945Sweongyo
4834203945Sweongyo	if (phy->rev >= 2) {
4835203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
4836203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
4837203945Sweongyo	}
4838203945Sweongyo	if (phy->rev == 2) {
4839203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
4840203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4841203945Sweongyo	}
4842203945Sweongyo	if (phy->rev > 5) {
4843203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
4844203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4845203945Sweongyo	}
4846203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4847203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
4848203945Sweongyo		tmp &= BWN_PHYVER_VERSION;
4849203945Sweongyo		if (tmp == 3 || tmp == 5) {
4850203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
4851203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
4852203945Sweongyo		}
4853203945Sweongyo		if (tmp == 5) {
4854203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
4855203945Sweongyo			    0x1f00);
4856203945Sweongyo		}
4857203945Sweongyo	}
4858203945Sweongyo	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
4859203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
4860203945Sweongyo	if (phy->rf_rev == 8) {
4861203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
4862203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
4863203945Sweongyo	}
4864203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
4865203945Sweongyo		bwn_loopback_calcgain(mac);
4866203945Sweongyo
4867203945Sweongyo	if (phy->rf_rev != 8) {
4868203945Sweongyo		if (pg->pg_initval == 0xffff)
4869203945Sweongyo			pg->pg_initval = bwn_rf_init_bcm2050(mac);
4870203945Sweongyo		else
4871203945Sweongyo			BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
4872203945Sweongyo	}
4873203945Sweongyo	bwn_lo_g_init(mac);
4874203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
4875203945Sweongyo		BWN_RF_WRITE(mac, 0x52,
4876203945Sweongyo		    (BWN_RF_READ(mac, 0x52) & 0xff00)
4877203945Sweongyo		    | pg->pg_loctl.tx_bias |
4878203945Sweongyo		    pg->pg_loctl.tx_magn);
4879203945Sweongyo	} else {
4880203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
4881203945Sweongyo	}
4882203945Sweongyo	if (phy->rev >= 6) {
4883203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
4884203945Sweongyo		    (pg->pg_loctl.tx_bias << 12));
4885203945Sweongyo	}
4886203945Sweongyo	if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_PACTRL)
4887203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
4888203945Sweongyo	else
4889203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
4890203945Sweongyo	if (phy->rev < 2)
4891203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
4892203945Sweongyo	else
4893203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
4894203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4895203945Sweongyo		bwn_lo_g_adjust(mac);
4896203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
4897203945Sweongyo	}
4898203945Sweongyo
4899203945Sweongyo	if (!(mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_RSSI)) {
4900203945Sweongyo		for (i = 0; i < 64; i++) {
4901203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
4902203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
4903203945Sweongyo			    (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
4904203945Sweongyo			    -32), 31));
4905203945Sweongyo		}
4906203945Sweongyo		bwn_nrssi_threshold(mac);
4907203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
4908203945Sweongyo		if (pg->pg_nrssi[0] == -1000) {
4909203945Sweongyo			KASSERT(pg->pg_nrssi[1] == -1000,
4910203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
4911203945Sweongyo			bwn_nrssi_slope_11g(mac);
4912203945Sweongyo		} else
4913203945Sweongyo			bwn_nrssi_threshold(mac);
4914203945Sweongyo	}
4915203945Sweongyo	if (phy->rf_rev == 8)
4916203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
4917203945Sweongyo	bwn_phy_hwpctl_init(mac);
4918203945Sweongyo	if ((mac->mac_sd->sd_bus->siba_chipid == 0x4306
4919203945Sweongyo	     && mac->mac_sd->sd_bus->siba_chippkg == 2) || 0) {
4920203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
4921203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
4922203945Sweongyo	}
4923203945Sweongyo}
4924203945Sweongyo
4925203945Sweongyostatic uint8_t
4926203945Sweongyobwn_has_hwpctl(struct bwn_mac *mac)
4927203945Sweongyo{
4928203945Sweongyo
4929203945Sweongyo	if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
4930203945Sweongyo		return (0);
4931203945Sweongyo	return (mac->mac_phy.use_hwpctl(mac));
4932203945Sweongyo}
4933203945Sweongyo
4934203945Sweongyostatic void
4935203945Sweongyobwn_phy_init_b5(struct bwn_mac *mac)
4936203945Sweongyo{
4937203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
4938203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4939203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4940203945Sweongyo	uint16_t offset, value;
4941203945Sweongyo	uint8_t old_channel;
4942203945Sweongyo
4943203945Sweongyo	if (phy->analog == 1)
4944203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0050);
4945203945Sweongyo	if ((bus->siba_board_vendor != SIBA_BOARDVENDOR_BCM) &&
4946203945Sweongyo	    (bus->siba_board_type != SIBA_BOARD_BU4306)) {
4947203945Sweongyo		value = 0x2120;
4948203945Sweongyo		for (offset = 0x00a8; offset < 0x00c7; offset++) {
4949203945Sweongyo			BWN_PHY_WRITE(mac, offset, value);
4950203945Sweongyo			value += 0x202;
4951203945Sweongyo		}
4952203945Sweongyo	}
4953203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
4954203945Sweongyo	if (phy->rf_ver == 0x2050)
4955203945Sweongyo		BWN_PHY_WRITE(mac, 0x0038, 0x0667);
4956203945Sweongyo
4957203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4958203945Sweongyo		if (phy->rf_ver == 0x2050) {
4959203945Sweongyo			BWN_RF_SET(mac, 0x007a, 0x0020);
4960203945Sweongyo			BWN_RF_SET(mac, 0x0051, 0x0004);
4961203945Sweongyo		}
4962203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
4963203945Sweongyo
4964203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
4965203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
4966203945Sweongyo
4967203945Sweongyo		BWN_PHY_WRITE(mac, 0x001c, 0x186a);
4968203945Sweongyo
4969203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
4970203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
4971203945Sweongyo		BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
4972203945Sweongyo	}
4973203945Sweongyo
4974203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
4975203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
4976203945Sweongyo
4977203945Sweongyo	if (phy->analog == 1) {
4978203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xce00);
4979203945Sweongyo		BWN_PHY_WRITE(mac, 0x0021, 0x3763);
4980203945Sweongyo		BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
4981203945Sweongyo		BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
4982203945Sweongyo		BWN_PHY_WRITE(mac, 0x0024, 0x037e);
4983203945Sweongyo	} else
4984203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
4985203945Sweongyo	BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
4986203945Sweongyo	BWN_WRITE_2(mac, 0x03ec, 0x3f22);
4987203945Sweongyo
4988203945Sweongyo	if (phy->analog == 1)
4989203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
4990203945Sweongyo	else
4991203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x301c);
4992203945Sweongyo
4993203945Sweongyo	if (phy->analog == 0)
4994203945Sweongyo		BWN_WRITE_2(mac, 0x03e4, 0x3000);
4995203945Sweongyo
4996203945Sweongyo	old_channel = phy->chan;
4997203945Sweongyo	bwn_phy_g_switch_chan(mac, 7, 0);
4998203945Sweongyo
4999203945Sweongyo	if (phy->rf_ver != 0x2050) {
5000203945Sweongyo		BWN_RF_WRITE(mac, 0x0075, 0x0080);
5001203945Sweongyo		BWN_RF_WRITE(mac, 0x0079, 0x0081);
5002203945Sweongyo	}
5003203945Sweongyo
5004203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
5005203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
5006203945Sweongyo
5007203945Sweongyo	if (phy->rf_ver == 0x2050) {
5008203945Sweongyo		BWN_RF_WRITE(mac, 0x0050, 0x0020);
5009203945Sweongyo		BWN_RF_WRITE(mac, 0x005a, 0x0070);
5010203945Sweongyo	}
5011203945Sweongyo
5012203945Sweongyo	BWN_RF_WRITE(mac, 0x005b, 0x007b);
5013203945Sweongyo	BWN_RF_WRITE(mac, 0x005c, 0x00b0);
5014203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0007);
5015203945Sweongyo
5016203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5017203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0080);
5018203945Sweongyo	BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
5019203945Sweongyo	BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
5020203945Sweongyo
5021203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5022203945Sweongyo	    pg->pg_txctl);
5023203945Sweongyo
5024203945Sweongyo	if (phy->rf_ver == 0x2050)
5025203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5026203945Sweongyo
5027203945Sweongyo	BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
5028203945Sweongyo}
5029203945Sweongyo
5030203945Sweongyostatic void
5031203945Sweongyobwn_loopback_calcgain(struct bwn_mac *mac)
5032203945Sweongyo{
5033203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5034203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5035203945Sweongyo	uint16_t backup_phy[16] = { 0 };
5036203945Sweongyo	uint16_t backup_radio[3];
5037203945Sweongyo	uint16_t backup_bband;
5038203945Sweongyo	uint16_t i, j, loop_i_max;
5039203945Sweongyo	uint16_t trsw_rx;
5040203945Sweongyo	uint16_t loop1_outer_done, loop1_inner_done;
5041203945Sweongyo
5042203945Sweongyo	backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5043203945Sweongyo	backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
5044203945Sweongyo	backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5045203945Sweongyo	backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5046203945Sweongyo	if (phy->rev != 1) {
5047203945Sweongyo		backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5048203945Sweongyo		backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5049203945Sweongyo	}
5050203945Sweongyo	backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5051203945Sweongyo	backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5052203945Sweongyo	backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5053203945Sweongyo	backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
5054203945Sweongyo	backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
5055203945Sweongyo	backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5056203945Sweongyo	backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5057203945Sweongyo	backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
5058203945Sweongyo	backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5059203945Sweongyo	backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5060203945Sweongyo	backup_bband = pg->pg_bbatt.att;
5061203945Sweongyo	backup_radio[0] = BWN_RF_READ(mac, 0x52);
5062203945Sweongyo	backup_radio[1] = BWN_RF_READ(mac, 0x43);
5063203945Sweongyo	backup_radio[2] = BWN_RF_READ(mac, 0x7a);
5064203945Sweongyo
5065203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
5066203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
5067203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
5068203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
5069203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
5070203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
5071203945Sweongyo	if (phy->rev != 1) {
5072203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
5073203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
5074203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
5075203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
5076203945Sweongyo	}
5077203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
5078203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
5079203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
5080203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
5081203945Sweongyo
5082203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
5083203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5084203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5085203945Sweongyo
5086203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
5087203945Sweongyo	if (phy->rev != 1) {
5088203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
5089203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
5090203945Sweongyo	}
5091203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
5092203945Sweongyo
5093203945Sweongyo	if (phy->rf_rev == 8)
5094203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x000f);
5095203945Sweongyo	else {
5096203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5097203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
5098203945Sweongyo	}
5099203945Sweongyo	bwn_phy_g_set_bbatt(mac, 11);
5100203945Sweongyo
5101203945Sweongyo	if (phy->rev >= 3)
5102203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5103203945Sweongyo	else
5104203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5105203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5106203945Sweongyo
5107203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
5108203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
5109203945Sweongyo
5110203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
5111203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
5112203945Sweongyo
5113203945Sweongyo	if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA) {
5114203945Sweongyo		if (phy->rev >= 7) {
5115203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
5116203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
5117203945Sweongyo		}
5118203945Sweongyo	}
5119203945Sweongyo	BWN_RF_MASK(mac, 0x7a, 0x00f7);
5120203945Sweongyo
5121203945Sweongyo	j = 0;
5122203945Sweongyo	loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
5123203945Sweongyo	for (i = 0; i < loop_i_max; i++) {
5124203945Sweongyo		for (j = 0; j < 16; j++) {
5125203945Sweongyo			BWN_RF_WRITE(mac, 0x43, i);
5126203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
5127203945Sweongyo			    (j << 8));
5128203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5129203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5130203945Sweongyo			DELAY(20);
5131203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5132203945Sweongyo				goto done0;
5133203945Sweongyo		}
5134203945Sweongyo	}
5135203945Sweongyodone0:
5136203945Sweongyo	loop1_outer_done = i;
5137203945Sweongyo	loop1_inner_done = j;
5138203945Sweongyo	if (j >= 8) {
5139203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
5140203945Sweongyo		trsw_rx = 0x1b;
5141203945Sweongyo		for (j = j - 8; j < 16; j++) {
5142203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
5143203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
5144203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
5145203945Sweongyo			DELAY(20);
5146203945Sweongyo			trsw_rx -= 3;
5147203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
5148203945Sweongyo				goto done1;
5149203945Sweongyo		}
5150203945Sweongyo	} else
5151203945Sweongyo		trsw_rx = 0x18;
5152203945Sweongyodone1:
5153203945Sweongyo
5154203945Sweongyo	if (phy->rev != 1) {
5155203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
5156203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
5157203945Sweongyo	}
5158203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
5159203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
5160203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
5161203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
5162203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
5163203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
5164203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
5165203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
5166203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
5167203945Sweongyo
5168203945Sweongyo	bwn_phy_g_set_bbatt(mac, backup_bband);
5169203945Sweongyo
5170203945Sweongyo	BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
5171203945Sweongyo	BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
5172203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
5173203945Sweongyo
5174203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
5175203945Sweongyo	DELAY(10);
5176203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
5177203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
5178203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
5179203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
5180203945Sweongyo
5181203945Sweongyo	pg->pg_max_lb_gain =
5182203945Sweongyo	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
5183203945Sweongyo	pg->pg_trsw_rx_gain = trsw_rx * 2;
5184203945Sweongyo}
5185203945Sweongyo
5186203945Sweongyostatic uint16_t
5187203945Sweongyobwn_rf_init_bcm2050(struct bwn_mac *mac)
5188203945Sweongyo{
5189203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5190203945Sweongyo	uint32_t tmp1 = 0, tmp2 = 0;
5191203945Sweongyo	uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
5192203945Sweongyo	    analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
5193203945Sweongyo	    radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
5194203945Sweongyo	static const uint8_t rcc_table[] = {
5195203945Sweongyo		0x02, 0x03, 0x01, 0x0f,
5196203945Sweongyo		0x06, 0x07, 0x05, 0x0f,
5197203945Sweongyo		0x0a, 0x0b, 0x09, 0x0f,
5198203945Sweongyo		0x0e, 0x0f, 0x0d, 0x0f,
5199203945Sweongyo	};
5200203945Sweongyo
5201203945Sweongyo	radio0 = BWN_RF_READ(mac, 0x43);
5202203945Sweongyo	radio1 = BWN_RF_READ(mac, 0x51);
5203203945Sweongyo	radio2 = BWN_RF_READ(mac, 0x52);
5204203945Sweongyo	pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5205203945Sweongyo	cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5206203945Sweongyo	cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5207203945Sweongyo	cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5208203945Sweongyo
5209203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5210203945Sweongyo		cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
5211203945Sweongyo		reg0 = BWN_READ_2(mac, 0x3ec);
5212203945Sweongyo
5213203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
5214203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
5215203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
5216203945Sweongyo		rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5217203945Sweongyo		rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5218203945Sweongyo		analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5219203945Sweongyo		analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5220203945Sweongyo		crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5221203945Sweongyo		classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
5222203945Sweongyo
5223203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
5224203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
5225203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
5226203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
5227203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5228203945Sweongyo			lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5229203945Sweongyo			loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5230203945Sweongyo			if (phy->rev >= 3)
5231203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5232203945Sweongyo			else
5233203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5234203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5235203945Sweongyo		}
5236203945Sweongyo
5237203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5238203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5239203945Sweongyo			BWN_LPD(0, 1, 1)));
5240203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
5241203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
5242203945Sweongyo	}
5243203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
5244203945Sweongyo
5245203945Sweongyo	syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
5246203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
5247203945Sweongyo	reg1 = BWN_READ_2(mac, 0x3e6);
5248203945Sweongyo	reg2 = BWN_READ_2(mac, 0x3f4);
5249203945Sweongyo
5250203945Sweongyo	if (phy->analog == 0)
5251203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0122);
5252203945Sweongyo	else {
5253203945Sweongyo		if (phy->analog >= 2)
5254203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
5255203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
5256203945Sweongyo		    (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
5257203945Sweongyo	}
5258203945Sweongyo
5259203945Sweongyo	reg = BWN_RF_READ(mac, 0x60);
5260203945Sweongyo	index = (reg & 0x001e) >> 1;
5261203945Sweongyo	rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
5262203945Sweongyo
5263203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5264203945Sweongyo		BWN_RF_WRITE(mac, 0x78, 0x26);
5265203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5266203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5267203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5268203945Sweongyo			BWN_LPD(0, 1, 1)));
5269203945Sweongyo	}
5270203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
5271203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
5272203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5273203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5274203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5275203945Sweongyo			BWN_LPD(0, 0, 1)));
5276203945Sweongyo	}
5277203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
5278203945Sweongyo	BWN_RF_SET(mac, 0x51, 0x0004);
5279203945Sweongyo	if (phy->rf_rev == 8)
5280203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x1f);
5281203945Sweongyo	else {
5282203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5283203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
5284203945Sweongyo	}
5285203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5286203945Sweongyo
5287203945Sweongyo	for (i = 0; i < 16; i++) {
5288203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
5289203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5290203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5291203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5292203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5293203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5294203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5295203945Sweongyo		}
5296203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5297203945Sweongyo		DELAY(10);
5298203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5299203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5300203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5301203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5302203945Sweongyo		}
5303203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5304203945Sweongyo		DELAY(10);
5305203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5306203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5307203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5308203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5309203945Sweongyo		}
5310203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5311203945Sweongyo		DELAY(20);
5312203945Sweongyo		tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5313203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5314203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5315203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5316203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5317203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5318203945Sweongyo		}
5319203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5320203945Sweongyo	}
5321203945Sweongyo	DELAY(10);
5322203945Sweongyo
5323203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5324203945Sweongyo	tmp1++;
5325203945Sweongyo	tmp1 >>= 9;
5326203945Sweongyo
5327203945Sweongyo	for (i = 0; i < 16; i++) {
5328203945Sweongyo		radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
5329203945Sweongyo		BWN_RF_WRITE(mac, 0x78, radio78);
5330203945Sweongyo		DELAY(10);
5331203945Sweongyo		for (j = 0; j < 16; j++) {
5332203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
5333203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5334203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5335203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5336203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5337203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5338203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5339203945Sweongyo			}
5340203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5341203945Sweongyo			DELAY(10);
5342203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5343203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5344203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5345203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5346203945Sweongyo			}
5347203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5348203945Sweongyo			DELAY(10);
5349203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5350203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5351203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5352203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5353203945Sweongyo			}
5354203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5355203945Sweongyo			DELAY(10);
5356203945Sweongyo			tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5357203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5358203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5359203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5360203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5361203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5362203945Sweongyo			}
5363203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5364203945Sweongyo		}
5365203945Sweongyo		tmp2++;
5366203945Sweongyo		tmp2 >>= 8;
5367203945Sweongyo		if (tmp1 < tmp2)
5368203945Sweongyo			break;
5369203945Sweongyo	}
5370203945Sweongyo
5371203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
5372203945Sweongyo	BWN_RF_WRITE(mac, 0x51, radio1);
5373203945Sweongyo	BWN_RF_WRITE(mac, 0x52, radio2);
5374203945Sweongyo	BWN_RF_WRITE(mac, 0x43, radio0);
5375203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
5376203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
5377203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
5378203945Sweongyo	BWN_WRITE_2(mac, 0x3e6, reg1);
5379203945Sweongyo	if (phy->analog != 0)
5380203945Sweongyo		BWN_WRITE_2(mac, 0x3f4, reg2);
5381203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
5382203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
5383203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5384203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
5385203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, reg0);
5386203945Sweongyo	} else if (phy->gmode) {
5387203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO,
5388203945Sweongyo			    BWN_READ_2(mac, BWN_PHY_RADIO)
5389203945Sweongyo			    & 0x7fff);
5390203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
5391203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
5392203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
5393203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
5394203945Sweongyo			      analogoverval);
5395203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
5396203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
5397203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5398203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
5399203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
5400203945Sweongyo		}
5401203945Sweongyo	}
5402203945Sweongyo
5403203945Sweongyo	return ((i > 15) ? radio78 : rcc);
5404203945Sweongyo}
5405203945Sweongyo
5406203945Sweongyostatic void
5407203945Sweongyobwn_phy_init_b6(struct bwn_mac *mac)
5408203945Sweongyo{
5409203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5410203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5411203945Sweongyo	uint16_t offset, val;
5412203945Sweongyo	uint8_t old_channel;
5413203945Sweongyo
5414203945Sweongyo	KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
5415203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5416203945Sweongyo
5417203945Sweongyo	BWN_PHY_WRITE(mac, 0x003e, 0x817a);
5418203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
5419203945Sweongyo	if (phy->rf_rev == 4 || phy->rf_rev == 5) {
5420203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0x37);
5421203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x70);
5422203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb3);
5423203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x9b);
5424203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5425203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x88);
5426203945Sweongyo		BWN_RF_WRITE(mac, 0x5d, 0x88);
5427203945Sweongyo		BWN_RF_WRITE(mac, 0x5e, 0x88);
5428203945Sweongyo		BWN_RF_WRITE(mac, 0x7d, 0x88);
5429203945Sweongyo		bwn_hf_write(mac,
5430203945Sweongyo		    bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
5431203945Sweongyo	}
5432203945Sweongyo	if (phy->rf_rev == 8) {
5433203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0);
5434203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x40);
5435203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb7);
5436203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x98);
5437203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5438203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x6b);
5439203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0x0f);
5440203945Sweongyo		if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_ALTIQ) {
5441203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xfa);
5442203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xd8);
5443203945Sweongyo		} else {
5444203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xf5);
5445203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xb8);
5446203945Sweongyo		}
5447203945Sweongyo		BWN_RF_WRITE(mac, 0x0073, 0x0003);
5448203945Sweongyo		BWN_RF_WRITE(mac, 0x007d, 0x00a8);
5449203945Sweongyo		BWN_RF_WRITE(mac, 0x007c, 0x0001);
5450203945Sweongyo		BWN_RF_WRITE(mac, 0x007e, 0x0008);
5451203945Sweongyo	}
5452203945Sweongyo	for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
5453203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5454203945Sweongyo		val -= 0x0202;
5455203945Sweongyo	}
5456203945Sweongyo	for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
5457203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5458203945Sweongyo		val -= 0x0202;
5459203945Sweongyo	}
5460203945Sweongyo	for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
5461203945Sweongyo		BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
5462203945Sweongyo		val += 0x0202;
5463203945Sweongyo	}
5464203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
5465203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0020);
5466203945Sweongyo		BWN_RF_SET(mac, 0x0051, 0x0004);
5467203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
5468203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
5469203945Sweongyo		BWN_PHY_WRITE(mac, 0x5b, 0);
5470203945Sweongyo		BWN_PHY_WRITE(mac, 0x5c, 0);
5471203945Sweongyo	}
5472203945Sweongyo
5473203945Sweongyo	old_channel = phy->chan;
5474203945Sweongyo	bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
5475203945Sweongyo
5476203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
5477203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
5478203945Sweongyo	DELAY(40);
5479203945Sweongyo	if (phy->rf_rev < 6 || phy->rf_rev == 8) {
5480203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
5481203945Sweongyo		BWN_RF_WRITE(mac, 0x50, 0x20);
5482203945Sweongyo	}
5483203945Sweongyo	if (phy->rf_rev <= 2) {
5484203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, 0x20);
5485203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x70);
5486203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x7b);
5487203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0xb0);
5488203945Sweongyo	}
5489203945Sweongyo	BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
5490203945Sweongyo
5491203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5492203945Sweongyo
5493203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0200);
5494203945Sweongyo	if (phy->rf_rev >= 6)
5495203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
5496203945Sweongyo	else
5497203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
5498203945Sweongyo	BWN_PHY_WRITE(mac, 0x0038, 0x0668);
5499203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5500203945Sweongyo	    pg->pg_txctl);
5501203945Sweongyo	if (phy->rf_rev <= 5)
5502203945Sweongyo		BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
5503203945Sweongyo	if (phy->rf_rev <= 2)
5504203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5505203945Sweongyo
5506203945Sweongyo	if (phy->analog == 4) {
5507203945Sweongyo		BWN_WRITE_2(mac, 0x3e4, 9);
5508203945Sweongyo		BWN_PHY_MASK(mac, 0x61, 0x0fff);
5509203945Sweongyo	} else
5510203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
5511203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5512203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5513203945Sweongyo	else if (phy->type == BWN_PHYTYPE_G)
5514203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0);
5515203945Sweongyo}
5516203945Sweongyo
5517203945Sweongyostatic void
5518203945Sweongyobwn_phy_init_a(struct bwn_mac *mac)
5519203945Sweongyo{
5520203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5521203945Sweongyo
5522203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
5523203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5524203945Sweongyo
5525203945Sweongyo	if (phy->rev >= 6) {
5526203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5527203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
5528203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
5529203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
5530203945Sweongyo		else
5531203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
5532203945Sweongyo	}
5533203945Sweongyo
5534203945Sweongyo	bwn_wa_init(mac);
5535203945Sweongyo
5536203945Sweongyo	if (phy->type == BWN_PHYTYPE_G &&
5537203945Sweongyo	    (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_PACTRL))
5538203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
5539203945Sweongyo}
5540203945Sweongyo
5541203945Sweongyostatic void
5542203945Sweongyobwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
5543203945Sweongyo{
5544203945Sweongyo	int i;
5545203945Sweongyo
5546203945Sweongyo	for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
5547203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
5548203945Sweongyo}
5549203945Sweongyo
5550203945Sweongyostatic void
5551203945Sweongyobwn_wa_agc(struct bwn_mac *mac)
5552203945Sweongyo{
5553203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5554203945Sweongyo
5555203945Sweongyo	if (phy->rev == 1) {
5556203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
5557203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
5558203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
5559203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
5560203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
5561203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
5562203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
5563203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
5564203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
5565203945Sweongyo	} else {
5566203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
5567203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
5568203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
5569203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
5570203945Sweongyo	}
5571203945Sweongyo
5572203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
5573203945Sweongyo	    0x5700);
5574203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
5575203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
5576203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
5577203945Sweongyo	BWN_RF_SET(mac, 0x7a, 0x0008);
5578203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
5579203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
5580203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
5581203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
5582203945Sweongyo	if (phy->rev == 1)
5583203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
5584203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
5585203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
5586203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
5587203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
5588203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
5589203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
5590203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
5591203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
5592203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
5593203945Sweongyo	if (phy->rev == 1) {
5594203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
5595203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
5596203945Sweongyo	} else {
5597203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
5598203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
5599203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
5600203945Sweongyo		if (phy->rev >= 6) {
5601203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
5602203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
5603203945Sweongyo			    (uint16_t)~0xf000, 0x3000);
5604203945Sweongyo		}
5605203945Sweongyo	}
5606203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
5607203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
5608203945Sweongyo	if (phy->rev == 1) {
5609203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
5610203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
5611203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
5612203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
5613203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
5614203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
5615203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
5616203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
5617203945Sweongyo	} else {
5618203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
5619203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
5620203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
5621203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
5622203945Sweongyo	}
5623203945Sweongyo	if (phy->rev >= 6) {
5624203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
5625203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
5626203945Sweongyo	}
5627203945Sweongyo	BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
5628203945Sweongyo}
5629203945Sweongyo
5630203945Sweongyostatic void
5631203945Sweongyobwn_wa_grev1(struct bwn_mac *mac)
5632203945Sweongyo{
5633203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5634203945Sweongyo	int i;
5635203945Sweongyo	static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
5636203945Sweongyo	static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
5637203945Sweongyo	static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
5638203945Sweongyo
5639203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5640203945Sweongyo
5641203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5642203945Sweongyo	if (phy->rev == 1) {
5643203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5644203945Sweongyo	} else if (phy->rev == 2) {
5645203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5646203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5647203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5648203945Sweongyo	} else {
5649203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5650203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5651203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5652203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5653203945Sweongyo	}
5654203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
5655203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
5656203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
5657203945Sweongyo
5658203945Sweongyo	/* XXX support PHY-A??? */
5659203945Sweongyo	for (i = 0; i < N(bwn_tab_finefreqg); i++)
5660203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
5661203945Sweongyo		    bwn_tab_finefreqg[i]);
5662203945Sweongyo
5663203945Sweongyo	/* XXX support PHY-A??? */
5664203945Sweongyo	if (phy->rev == 1)
5665203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5666203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5667203945Sweongyo			    bwn_tab_noise_g1[i]);
5668203945Sweongyo	else
5669203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5670203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5671203945Sweongyo			    bwn_tab_noise_g2[i]);
5672203945Sweongyo
5673203945Sweongyo
5674203945Sweongyo	for (i = 0; i < N(bwn_tab_rotor); i++)
5675203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
5676203945Sweongyo		    bwn_tab_rotor[i]);
5677203945Sweongyo
5678203945Sweongyo	/* XXX support PHY-A??? */
5679203945Sweongyo	if (phy->rev >= 6) {
5680203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5681203945Sweongyo		    BWN_PHY_ENCORE_EN)
5682203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5683203945Sweongyo		else
5684203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5685203945Sweongyo	} else
5686203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5687203945Sweongyo
5688203945Sweongyo	for (i = 0; i < N(bwn_tab_retard); i++)
5689203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
5690203945Sweongyo		    bwn_tab_retard[i]);
5691203945Sweongyo
5692203945Sweongyo	if (phy->rev == 1) {
5693203945Sweongyo		for (i = 0; i < 16; i++)
5694203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
5695203945Sweongyo			    i, 0x0020);
5696203945Sweongyo	} else {
5697203945Sweongyo		for (i = 0; i < 32; i++)
5698203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5699203945Sweongyo	}
5700203945Sweongyo
5701203945Sweongyo	bwn_wa_agc(mac);
5702203945Sweongyo}
5703203945Sweongyo
5704203945Sweongyostatic void
5705203945Sweongyobwn_wa_grev26789(struct bwn_mac *mac)
5706203945Sweongyo{
5707203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5708203945Sweongyo	int i;
5709203945Sweongyo	static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
5710203945Sweongyo	uint16_t ofdmrev;
5711203945Sweongyo
5712203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5713203945Sweongyo
5714203945Sweongyo	bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
5715203945Sweongyo
5716203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5717203945Sweongyo	if (phy->rev == 1)
5718203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5719203945Sweongyo	else if (phy->rev == 2) {
5720203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5721203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5722203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5723203945Sweongyo	} else {
5724203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5725203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5726203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5727203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5728203945Sweongyo	}
5729203945Sweongyo
5730203945Sweongyo	for (i = 0; i < 64; i++)
5731203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
5732203945Sweongyo
5733203945Sweongyo	/* XXX support PHY-A??? */
5734203945Sweongyo	if (phy->rev == 1)
5735203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5736203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5737203945Sweongyo			    bwn_tab_noise_g1[i]);
5738203945Sweongyo	else
5739203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5740203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5741203945Sweongyo			    bwn_tab_noise_g2[i]);
5742203945Sweongyo
5743203945Sweongyo	/* XXX support PHY-A??? */
5744203945Sweongyo	if (phy->rev >= 6) {
5745203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5746203945Sweongyo		    BWN_PHY_ENCORE_EN)
5747203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5748203945Sweongyo		else
5749203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5750203945Sweongyo	} else
5751203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5752203945Sweongyo
5753203945Sweongyo	for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
5754203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
5755203945Sweongyo		    bwn_tab_sigmasqr2[i]);
5756203945Sweongyo
5757203945Sweongyo	if (phy->rev == 1) {
5758203945Sweongyo		for (i = 0; i < 16; i++)
5759203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
5760203945Sweongyo			    0x0020);
5761203945Sweongyo	} else {
5762203945Sweongyo		for (i = 0; i < 32; i++)
5763203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5764203945Sweongyo	}
5765203945Sweongyo
5766203945Sweongyo	bwn_wa_agc(mac);
5767203945Sweongyo
5768203945Sweongyo	ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
5769203945Sweongyo	if (ofdmrev > 2) {
5770203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5771203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
5772203945Sweongyo		else
5773203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
5774203945Sweongyo	} else {
5775203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
5776203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
5777203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
5778203945Sweongyo	}
5779203945Sweongyo
5780203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
5781203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
5782203945Sweongyo}
5783203945Sweongyo
5784203945Sweongyostatic void
5785203945Sweongyobwn_wa_init(struct bwn_mac *mac)
5786203945Sweongyo{
5787203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5788203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
5789203945Sweongyo
5790203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5791203945Sweongyo
5792203945Sweongyo	switch (phy->rev) {
5793203945Sweongyo	case 1:
5794203945Sweongyo		bwn_wa_grev1(mac);
5795203945Sweongyo		break;
5796203945Sweongyo	case 2:
5797203945Sweongyo	case 6:
5798203945Sweongyo	case 7:
5799203945Sweongyo	case 8:
5800203945Sweongyo	case 9:
5801203945Sweongyo		bwn_wa_grev26789(mac);
5802203945Sweongyo		break;
5803203945Sweongyo	default:
5804203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5805203945Sweongyo	}
5806203945Sweongyo
5807203945Sweongyo	if (bus->siba_board_vendor != SIBA_BOARDVENDOR_BCM ||
5808203945Sweongyo	    bus->siba_board_type != SIBA_BOARD_BU4306 ||
5809203945Sweongyo	    bus->siba_board_rev != 0x17) {
5810203945Sweongyo		if (phy->rev < 2) {
5811203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
5812203945Sweongyo			    0x0002);
5813203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
5814203945Sweongyo			    0x0001);
5815203945Sweongyo		} else {
5816203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
5817203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
5818203945Sweongyo			if ((bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA) &&
5819203945Sweongyo			    (phy->rev >= 7)) {
5820203945Sweongyo				BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
5821203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5822203945Sweongyo				    0x0020, 0x0001);
5823203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5824203945Sweongyo				    0x0021, 0x0001);
5825203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5826203945Sweongyo				    0x0022, 0x0001);
5827203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5828203945Sweongyo				    0x0023, 0x0000);
5829203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5830203945Sweongyo				    0x0000, 0x0000);
5831203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5832203945Sweongyo				    0x0003, 0x0002);
5833203945Sweongyo			}
5834203945Sweongyo		}
5835203945Sweongyo	}
5836203945Sweongyo	if (bus->siba_sprom.bf_lo & BWN_BFL_FEM) {
5837203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
5838203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
5839203945Sweongyo	}
5840203945Sweongyo
5841203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
5842203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
5843203945Sweongyo}
5844203945Sweongyo
5845203945Sweongyostatic void
5846203945Sweongyobwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5847203945Sweongyo    uint16_t value)
5848203945Sweongyo{
5849203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5850203945Sweongyo	uint16_t addr;
5851203945Sweongyo
5852203945Sweongyo	addr = table + offset;
5853203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5854203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5855203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5856203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5857203945Sweongyo	}
5858203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5859203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5860203945Sweongyo}
5861203945Sweongyo
5862203945Sweongyostatic void
5863203945Sweongyobwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5864203945Sweongyo    uint32_t value)
5865203945Sweongyo{
5866203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5867203945Sweongyo	uint16_t addr;
5868203945Sweongyo
5869203945Sweongyo	addr = table + offset;
5870203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5871203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5872203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5873203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5874203945Sweongyo	}
5875203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5876203945Sweongyo
5877203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5878203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
5879203945Sweongyo}
5880203945Sweongyo
5881203945Sweongyostatic void
5882203945Sweongyobwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5883203945Sweongyo    uint16_t value)
5884203945Sweongyo{
5885203945Sweongyo
5886203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
5887203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
5888203945Sweongyo}
5889203945Sweongyo
5890203945Sweongyostatic void
5891203945Sweongyobwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
5892203945Sweongyo{
5893203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5894203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5895203945Sweongyo	unsigned int i, max_loop;
5896203945Sweongyo	uint16_t value;
5897203945Sweongyo	uint32_t buffer[5] = {
5898203945Sweongyo		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
5899203945Sweongyo	};
5900203945Sweongyo
5901203945Sweongyo	if (ofdm) {
5902203945Sweongyo		max_loop = 0x1e;
5903203945Sweongyo		buffer[0] = 0x000201cc;
5904203945Sweongyo	} else {
5905203945Sweongyo		max_loop = 0xfa;
5906203945Sweongyo		buffer[0] = 0x000b846e;
5907203945Sweongyo	}
5908203945Sweongyo
5909203945Sweongyo	BWN_ASSERT_LOCKED(sc);
5910203945Sweongyo
5911203945Sweongyo	for (i = 0; i < 5; i++)
5912203945Sweongyo		bwn_ram_write(mac, i * 4, buffer[i]);
5913203945Sweongyo
5914203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0000);
5915203945Sweongyo	BWN_WRITE_2(mac, 0x07c0,
5916203945Sweongyo	    (mac->mac_sd->sd_id.sd_rev < 11) ? 0x0000 : 0x0100);
5917203945Sweongyo	value = ((phy->type == BWN_PHYTYPE_A) ? 0x41 : 0x40);
5918203945Sweongyo	BWN_WRITE_2(mac, 0x050c, value);
5919203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5920203945Sweongyo		BWN_WRITE_2(mac, 0x0514, 0x1a02);
5921203945Sweongyo	BWN_WRITE_2(mac, 0x0508, 0x0000);
5922203945Sweongyo	BWN_WRITE_2(mac, 0x050a, 0x0000);
5923203945Sweongyo	BWN_WRITE_2(mac, 0x054c, 0x0000);
5924203945Sweongyo	BWN_WRITE_2(mac, 0x056a, 0x0014);
5925203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0826);
5926203945Sweongyo	BWN_WRITE_2(mac, 0x0500, 0x0000);
5927203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5928203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0050);
5929203945Sweongyo	else
5930203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0030);
5931203945Sweongyo
5932203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5933203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0017);
5934203945Sweongyo	for (i = 0x00; i < max_loop; i++) {
5935203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5936203945Sweongyo		if (value & 0x0080)
5937203945Sweongyo			break;
5938203945Sweongyo		DELAY(10);
5939203945Sweongyo	}
5940203945Sweongyo	for (i = 0x00; i < 0x0a; i++) {
5941203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5942203945Sweongyo		if (value & 0x0400)
5943203945Sweongyo			break;
5944203945Sweongyo		DELAY(10);
5945203945Sweongyo	}
5946203945Sweongyo	for (i = 0x00; i < 0x19; i++) {
5947203945Sweongyo		value = BWN_READ_2(mac, 0x0690);
5948203945Sweongyo		if (!(value & 0x0100))
5949203945Sweongyo			break;
5950203945Sweongyo		DELAY(10);
5951203945Sweongyo	}
5952203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5953203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0037);
5954203945Sweongyo}
5955203945Sweongyo
5956203945Sweongyostatic void
5957203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
5958203945Sweongyo{
5959203945Sweongyo	uint32_t macctl;
5960203945Sweongyo
5961203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
5962203945Sweongyo
5963203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
5964203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
5965203945Sweongyo		printf("TODO: need swap\n");
5966203945Sweongyo
5967203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
5968203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
5969203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
5970203945Sweongyo}
5971203945Sweongyo
5972203945Sweongyostatic void
5973203945Sweongyobwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
5974203945Sweongyo{
5975203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5976203945Sweongyo	uint16_t value;
5977203945Sweongyo
5978203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
5979203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5980203945Sweongyo
5981203945Sweongyo	value = (uint8_t) (ctl->q);
5982203945Sweongyo	value |= ((uint8_t) (ctl->i)) << 8;
5983203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
5984203945Sweongyo}
5985203945Sweongyo
5986203945Sweongyostatic uint16_t
5987203945Sweongyobwn_lo_calcfeed(struct bwn_mac *mac,
5988203945Sweongyo    uint16_t lna, uint16_t pga, uint16_t trsw_rx)
5989203945Sweongyo{
5990203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5991203945Sweongyo	uint16_t rfover;
5992203945Sweongyo	uint16_t feedthrough;
5993203945Sweongyo
5994203945Sweongyo	if (phy->gmode) {
5995203945Sweongyo		lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
5996203945Sweongyo		pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
5997203945Sweongyo
5998203945Sweongyo		KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
5999203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
6000203945Sweongyo		KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
6001203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
6002203945Sweongyo
6003203945Sweongyo		trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
6004203945Sweongyo
6005203945Sweongyo		rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
6006203945Sweongyo		if ((mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA)
6007203945Sweongyo		    && phy->rev > 6)
6008203945Sweongyo			rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
6009203945Sweongyo
6010203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6011203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
6012203945Sweongyo		DELAY(10);
6013203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
6014203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
6015203945Sweongyo		DELAY(10);
6016203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
6017203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
6018203945Sweongyo		DELAY(10);
6019203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
6020203945Sweongyo	} else {
6021203945Sweongyo		pga |= BWN_PHY_PGACTL_UNKNOWN;
6022203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
6023203945Sweongyo		DELAY(10);
6024203945Sweongyo		pga |= BWN_PHY_PGACTL_LOWBANDW;
6025203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
6026203945Sweongyo		DELAY(10);
6027203945Sweongyo		pga |= BWN_PHY_PGACTL_LPF;
6028203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
6029203945Sweongyo	}
6030203945Sweongyo	DELAY(21);
6031203945Sweongyo	feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
6032203945Sweongyo
6033203945Sweongyo	return (feedthrough);
6034203945Sweongyo}
6035203945Sweongyo
6036203945Sweongyostatic uint16_t
6037203945Sweongyobwn_lo_txctl_regtable(struct bwn_mac *mac,
6038203945Sweongyo    uint16_t *value, uint16_t *pad_mix_gain)
6039203945Sweongyo{
6040203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6041203945Sweongyo	uint16_t reg, v, padmix;
6042203945Sweongyo
6043203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6044203945Sweongyo		v = 0x30;
6045203945Sweongyo		if (phy->rf_rev <= 5) {
6046203945Sweongyo			reg = 0x43;
6047203945Sweongyo			padmix = 0;
6048203945Sweongyo		} else {
6049203945Sweongyo			reg = 0x52;
6050203945Sweongyo			padmix = 5;
6051203945Sweongyo		}
6052203945Sweongyo	} else {
6053203945Sweongyo		if (phy->rev >= 2 && phy->rf_rev == 8) {
6054203945Sweongyo			reg = 0x43;
6055203945Sweongyo			v = 0x10;
6056203945Sweongyo			padmix = 2;
6057203945Sweongyo		} else {
6058203945Sweongyo			reg = 0x52;
6059203945Sweongyo			v = 0x30;
6060203945Sweongyo			padmix = 5;
6061203945Sweongyo		}
6062203945Sweongyo	}
6063203945Sweongyo	if (value)
6064203945Sweongyo		*value = v;
6065203945Sweongyo	if (pad_mix_gain)
6066203945Sweongyo		*pad_mix_gain = padmix;
6067203945Sweongyo
6068203945Sweongyo	return (reg);
6069203945Sweongyo}
6070203945Sweongyo
6071203945Sweongyostatic void
6072203945Sweongyobwn_lo_measure_txctl_values(struct bwn_mac *mac)
6073203945Sweongyo{
6074203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6075203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6076203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6077203945Sweongyo	uint16_t reg, mask;
6078203945Sweongyo	uint16_t trsw_rx, pga;
6079203945Sweongyo	uint16_t rf_pctl_reg;
6080203945Sweongyo
6081203945Sweongyo	static const uint8_t tx_bias_values[] = {
6082203945Sweongyo		0x09, 0x08, 0x0a, 0x01, 0x00,
6083203945Sweongyo		0x02, 0x05, 0x04, 0x06,
6084203945Sweongyo	};
6085203945Sweongyo	static const uint8_t tx_magn_values[] = {
6086203945Sweongyo		0x70, 0x40,
6087203945Sweongyo	};
6088203945Sweongyo
6089203945Sweongyo	if (!BWN_HAS_LOOPBACK(phy)) {
6090203945Sweongyo		rf_pctl_reg = 6;
6091203945Sweongyo		trsw_rx = 2;
6092203945Sweongyo		pga = 0;
6093203945Sweongyo	} else {
6094203945Sweongyo		int lb_gain;
6095203945Sweongyo
6096203945Sweongyo		trsw_rx = 0;
6097203945Sweongyo		lb_gain = pg->pg_max_lb_gain / 2;
6098203945Sweongyo		if (lb_gain > 10) {
6099203945Sweongyo			rf_pctl_reg = 0;
6100203945Sweongyo			pga = abs(10 - lb_gain) / 6;
6101203945Sweongyo			pga = MIN(MAX(pga, 0), 15);
6102203945Sweongyo		} else {
6103203945Sweongyo			int cmp_val;
6104203945Sweongyo			int tmp;
6105203945Sweongyo
6106203945Sweongyo			pga = 0;
6107203945Sweongyo			cmp_val = 0x24;
6108203945Sweongyo			if ((phy->rev >= 2) &&
6109203945Sweongyo			    (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
6110203945Sweongyo				cmp_val = 0x3c;
6111203945Sweongyo			tmp = lb_gain;
6112203945Sweongyo			if ((10 - lb_gain) < cmp_val)
6113203945Sweongyo				tmp = (10 - lb_gain);
6114203945Sweongyo			if (tmp < 0)
6115203945Sweongyo				tmp += 6;
6116203945Sweongyo			else
6117203945Sweongyo				tmp += 3;
6118203945Sweongyo			cmp_val /= 4;
6119203945Sweongyo			tmp /= 4;
6120203945Sweongyo			if (tmp >= cmp_val)
6121203945Sweongyo				rf_pctl_reg = cmp_val;
6122203945Sweongyo			else
6123203945Sweongyo				rf_pctl_reg = tmp;
6124203945Sweongyo		}
6125203945Sweongyo	}
6126203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
6127203945Sweongyo	bwn_phy_g_set_bbatt(mac, 2);
6128203945Sweongyo
6129203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
6130203945Sweongyo	mask = ~mask;
6131203945Sweongyo	BWN_RF_MASK(mac, reg, mask);
6132203945Sweongyo
6133203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
6134203945Sweongyo		int i, j;
6135203945Sweongyo		int feedthrough;
6136203945Sweongyo		int min_feedth = 0xffff;
6137203945Sweongyo		uint8_t tx_magn, tx_bias;
6138203945Sweongyo
6139203945Sweongyo		for (i = 0; i < N(tx_magn_values); i++) {
6140203945Sweongyo			tx_magn = tx_magn_values[i];
6141203945Sweongyo			BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
6142203945Sweongyo			for (j = 0; j < N(tx_bias_values); j++) {
6143203945Sweongyo				tx_bias = tx_bias_values[j];
6144203945Sweongyo				BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
6145203945Sweongyo				feedthrough = bwn_lo_calcfeed(mac, 0, pga,
6146203945Sweongyo				    trsw_rx);
6147203945Sweongyo				if (feedthrough < min_feedth) {
6148203945Sweongyo					lo->tx_bias = tx_bias;
6149203945Sweongyo					lo->tx_magn = tx_magn;
6150203945Sweongyo					min_feedth = feedthrough;
6151203945Sweongyo				}
6152203945Sweongyo				if (lo->tx_bias == 0)
6153203945Sweongyo					break;
6154203945Sweongyo			}
6155203945Sweongyo			BWN_RF_WRITE(mac, 0x52,
6156203945Sweongyo					  (BWN_RF_READ(mac, 0x52)
6157203945Sweongyo					   & 0xff00) | lo->tx_bias | lo->
6158203945Sweongyo					  tx_magn);
6159203945Sweongyo		}
6160203945Sweongyo	} else {
6161203945Sweongyo		lo->tx_magn = 0;
6162203945Sweongyo		lo->tx_bias = 0;
6163203945Sweongyo		BWN_RF_MASK(mac, 0x52, 0xfff0);
6164203945Sweongyo	}
6165203945Sweongyo
6166203945Sweongyo	BWN_GETTIME(lo->txctl_measured_time);
6167203945Sweongyo}
6168203945Sweongyo
6169203945Sweongyostatic void
6170203945Sweongyobwn_lo_get_powervector(struct bwn_mac *mac)
6171203945Sweongyo{
6172203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6173203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6174203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6175203945Sweongyo	int i;
6176203945Sweongyo	uint64_t tmp;
6177203945Sweongyo	uint64_t power_vector = 0;
6178203945Sweongyo
6179203945Sweongyo	for (i = 0; i < 8; i += 2) {
6180203945Sweongyo		tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
6181203945Sweongyo		power_vector |= (tmp << (i * 8));
6182203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
6183203945Sweongyo	}
6184203945Sweongyo	if (power_vector)
6185203945Sweongyo		lo->power_vector = power_vector;
6186203945Sweongyo
6187203945Sweongyo	BWN_GETTIME(lo->pwr_vec_read_time);
6188203945Sweongyo}
6189203945Sweongyo
6190203945Sweongyostatic void
6191203945Sweongyobwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
6192203945Sweongyo    int use_trsw_rx)
6193203945Sweongyo{
6194203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6195203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6196203945Sweongyo	uint16_t tmp;
6197203945Sweongyo
6198203945Sweongyo	if (max_rx_gain < 0)
6199203945Sweongyo		max_rx_gain = 0;
6200203945Sweongyo
6201203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
6202203945Sweongyo		int trsw_rx = 0;
6203203945Sweongyo		int trsw_rx_gain;
6204203945Sweongyo
6205203945Sweongyo		if (use_trsw_rx) {
6206203945Sweongyo			trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
6207203945Sweongyo			if (max_rx_gain >= trsw_rx_gain) {
6208203945Sweongyo				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
6209203945Sweongyo				trsw_rx = 0x20;
6210203945Sweongyo			}
6211203945Sweongyo		} else
6212203945Sweongyo			trsw_rx_gain = max_rx_gain;
6213203945Sweongyo		if (trsw_rx_gain < 9) {
6214203945Sweongyo			pg->pg_lna_lod_gain = 0;
6215203945Sweongyo		} else {
6216203945Sweongyo			pg->pg_lna_lod_gain = 1;
6217203945Sweongyo			trsw_rx_gain -= 8;
6218203945Sweongyo		}
6219203945Sweongyo		trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
6220203945Sweongyo		pg->pg_pga_gain = trsw_rx_gain / 3;
6221203945Sweongyo		if (pg->pg_pga_gain >= 5) {
6222203945Sweongyo			pg->pg_pga_gain -= 5;
6223203945Sweongyo			pg->pg_lna_gain = 2;
6224203945Sweongyo		} else
6225203945Sweongyo			pg->pg_lna_gain = 0;
6226203945Sweongyo	} else {
6227203945Sweongyo		pg->pg_lna_gain = 0;
6228203945Sweongyo		pg->pg_trsw_rx_gain = 0x20;
6229203945Sweongyo		if (max_rx_gain >= 0x14) {
6230203945Sweongyo			pg->pg_lna_lod_gain = 1;
6231203945Sweongyo			pg->pg_pga_gain = 2;
6232203945Sweongyo		} else if (max_rx_gain >= 0x12) {
6233203945Sweongyo			pg->pg_lna_lod_gain = 1;
6234203945Sweongyo			pg->pg_pga_gain = 1;
6235203945Sweongyo		} else if (max_rx_gain >= 0xf) {
6236203945Sweongyo			pg->pg_lna_lod_gain = 1;
6237203945Sweongyo			pg->pg_pga_gain = 0;
6238203945Sweongyo		} else {
6239203945Sweongyo			pg->pg_lna_lod_gain = 0;
6240203945Sweongyo			pg->pg_pga_gain = 0;
6241203945Sweongyo		}
6242203945Sweongyo	}
6243203945Sweongyo
6244203945Sweongyo	tmp = BWN_RF_READ(mac, 0x7a);
6245203945Sweongyo	if (pg->pg_lna_lod_gain == 0)
6246203945Sweongyo		tmp &= ~0x0008;
6247203945Sweongyo	else
6248203945Sweongyo		tmp |= 0x0008;
6249203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, tmp);
6250203945Sweongyo}
6251203945Sweongyo
6252203945Sweongyostatic void
6253203945Sweongyobwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6254203945Sweongyo{
6255203945Sweongyo	struct siba_sprom *sprom = &mac->mac_sd->sd_bus->siba_sprom;
6256203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6257203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6258203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6259203945Sweongyo	struct timespec ts;
6260203945Sweongyo	uint16_t tmp;
6261203945Sweongyo
6262203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6263203945Sweongyo		sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
6264203945Sweongyo		sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
6265203945Sweongyo		sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6266203945Sweongyo		sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
6267203945Sweongyo		sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
6268203945Sweongyo
6269203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
6270203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
6271203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
6272203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
6273203945Sweongyo	}
6274203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6275203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
6276203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
6277203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
6278203945Sweongyo	}
6279203945Sweongyo	if (phy->rev >= 2) {
6280203945Sweongyo		sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
6281203945Sweongyo		sav->phy_analogoverval =
6282203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
6283203945Sweongyo		sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
6284203945Sweongyo		sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
6285203945Sweongyo		sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
6286203945Sweongyo		sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
6287203945Sweongyo		sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
6288203945Sweongyo
6289203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
6290203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
6291203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
6292203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
6293203945Sweongyo		if (phy->type == BWN_PHYTYPE_G) {
6294203945Sweongyo			if ((phy->rev >= 7) &&
6295203945Sweongyo			    (sprom->bf_lo & BWN_BFL_EXTLNA)) {
6296203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
6297203945Sweongyo			} else {
6298203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
6299203945Sweongyo			}
6300203945Sweongyo		} else {
6301203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
6302203945Sweongyo		}
6303203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
6304203945Sweongyo	}
6305203945Sweongyo	sav->reg0 = BWN_READ_2(mac, 0x3f4);
6306203945Sweongyo	sav->reg1 = BWN_READ_2(mac, 0x3e2);
6307203945Sweongyo	sav->rf0 = BWN_RF_READ(mac, 0x43);
6308203945Sweongyo	sav->rf1 = BWN_RF_READ(mac, 0x7a);
6309203945Sweongyo	sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
6310203945Sweongyo	sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
6311203945Sweongyo	sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
6312203945Sweongyo	sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6313203945Sweongyo
6314203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6315203945Sweongyo		sav->rf2 = BWN_RF_READ(mac, 0x52);
6316203945Sweongyo		sav->rf2 &= 0x00f0;
6317203945Sweongyo	}
6318203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6319203945Sweongyo		sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
6320203945Sweongyo		sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
6321203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
6322203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
6323203945Sweongyo	} else {
6324203945Sweongyo		BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
6325203945Sweongyo			    | 0x8000);
6326203945Sweongyo	}
6327203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
6328203945Sweongyo		    & 0xf000);
6329203945Sweongyo
6330203945Sweongyo	tmp =
6331203945Sweongyo	    (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
6332203945Sweongyo	BWN_PHY_WRITE(mac, tmp, 0x007f);
6333203945Sweongyo
6334203945Sweongyo	tmp = sav->phy_syncctl;
6335203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
6336203945Sweongyo	tmp = sav->rf1;
6337203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
6338203945Sweongyo
6339203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
6340203945Sweongyo	if (phy->type == BWN_PHYTYPE_G ||
6341203945Sweongyo	    (phy->type == BWN_PHYTYPE_B &&
6342203945Sweongyo	     phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
6343203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
6344203945Sweongyo	} else
6345203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
6346203945Sweongyo	if (phy->rev >= 2)
6347203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
6348203945Sweongyo	bwn_phy_g_switch_chan(mac, 6, 0);
6349203945Sweongyo	BWN_RF_READ(mac, 0x51);
6350203945Sweongyo	if (phy->type == BWN_PHYTYPE_G)
6351203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
6352203945Sweongyo
6353203945Sweongyo	nanouptime(&ts);
6354203945Sweongyo	if (time_before(lo->txctl_measured_time,
6355203945Sweongyo	    (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
6356203945Sweongyo		bwn_lo_measure_txctl_values(mac);
6357203945Sweongyo
6358203945Sweongyo	if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
6359203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
6360203945Sweongyo	else {
6361203945Sweongyo		if (phy->type == BWN_PHYTYPE_B)
6362203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6363203945Sweongyo		else
6364203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
6365203945Sweongyo	}
6366203945Sweongyo}
6367203945Sweongyo
6368203945Sweongyostatic void
6369203945Sweongyobwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6370203945Sweongyo{
6371203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6372203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6373203945Sweongyo	uint16_t tmp;
6374203945Sweongyo
6375203945Sweongyo	if (phy->rev >= 2) {
6376203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6377203945Sweongyo		tmp = (pg->pg_pga_gain << 8);
6378203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
6379203945Sweongyo		DELAY(5);
6380203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
6381203945Sweongyo		DELAY(2);
6382203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
6383203945Sweongyo	} else {
6384203945Sweongyo		tmp = (pg->pg_pga_gain | 0xefa0);
6385203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
6386203945Sweongyo	}
6387203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
6388203945Sweongyo		if (phy->rev >= 3)
6389203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
6390203945Sweongyo		else
6391203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6392203945Sweongyo		if (phy->rev >= 2)
6393203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
6394203945Sweongyo		else
6395203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
6396203945Sweongyo	}
6397203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, sav->reg0);
6398203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
6399203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
6400203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
6401203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
6402203945Sweongyo	BWN_RF_WRITE(mac, 0x43, sav->rf0);
6403203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, sav->rf1);
6404203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6405203945Sweongyo		tmp = sav->rf2;
6406203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
6407203945Sweongyo	}
6408203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, sav->reg1);
6409203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6410203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
6411203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
6412203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
6413203945Sweongyo	}
6414203945Sweongyo	if (phy->rev >= 2) {
6415203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
6416203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
6417203945Sweongyo			      sav->phy_analogoverval);
6418203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
6419203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
6420203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
6421203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
6422203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
6423203945Sweongyo	}
6424203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6425203945Sweongyo		tmp = (sav->phy_lomask & 0xbfff);
6426203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
6427203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
6428203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
6429203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
6430203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
6431203945Sweongyo	}
6432203945Sweongyo	bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
6433203945Sweongyo}
6434203945Sweongyo
6435203945Sweongyostatic int
6436203945Sweongyobwn_lo_probe_loctl(struct bwn_mac *mac,
6437203945Sweongyo    struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
6438203945Sweongyo{
6439203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6440203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6441203945Sweongyo	struct bwn_loctl orig, test;
6442203945Sweongyo	struct bwn_loctl prev = { -100, -100 };
6443203945Sweongyo	static const struct bwn_loctl modifiers[] = {
6444203945Sweongyo		{  1,  1,}, {  1,  0,}, {  1, -1,}, {  0, -1,},
6445203945Sweongyo		{ -1, -1,}, { -1,  0,}, { -1,  1,}, {  0,  1,}
6446203945Sweongyo	};
6447203945Sweongyo	int begin, end, lower = 0, i;
6448203945Sweongyo	uint16_t feedth;
6449203945Sweongyo
6450203945Sweongyo	if (d->curstate == 0) {
6451203945Sweongyo		begin = 1;
6452203945Sweongyo		end = 8;
6453203945Sweongyo	} else if (d->curstate % 2 == 0) {
6454203945Sweongyo		begin = d->curstate - 1;
6455203945Sweongyo		end = d->curstate + 1;
6456203945Sweongyo	} else {
6457203945Sweongyo		begin = d->curstate - 2;
6458203945Sweongyo		end = d->curstate + 2;
6459203945Sweongyo	}
6460203945Sweongyo	if (begin < 1)
6461203945Sweongyo		begin += 8;
6462203945Sweongyo	if (end > 8)
6463203945Sweongyo		end -= 8;
6464203945Sweongyo
6465203945Sweongyo	memcpy(&orig, probe, sizeof(struct bwn_loctl));
6466203945Sweongyo	i = begin;
6467203945Sweongyo	d->curstate = i;
6468203945Sweongyo	while (1) {
6469203945Sweongyo		KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
6470203945Sweongyo		memcpy(&test, &orig, sizeof(struct bwn_loctl));
6471203945Sweongyo		test.i += modifiers[i - 1].i * d->multipler;
6472203945Sweongyo		test.q += modifiers[i - 1].q * d->multipler;
6473203945Sweongyo		if ((test.i != prev.i || test.q != prev.q) &&
6474203945Sweongyo		    (abs(test.i) <= 16 && abs(test.q) <= 16)) {
6475203945Sweongyo			bwn_lo_write(mac, &test);
6476203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6477203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6478203945Sweongyo			if (feedth < d->feedth) {
6479203945Sweongyo				memcpy(probe, &test,
6480203945Sweongyo				    sizeof(struct bwn_loctl));
6481203945Sweongyo				lower = 1;
6482203945Sweongyo				d->feedth = feedth;
6483203945Sweongyo				if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
6484203945Sweongyo					break;
6485203945Sweongyo			}
6486203945Sweongyo		}
6487203945Sweongyo		memcpy(&prev, &test, sizeof(prev));
6488203945Sweongyo		if (i == end)
6489203945Sweongyo			break;
6490203945Sweongyo		if (i == 8)
6491203945Sweongyo			i = 1;
6492203945Sweongyo		else
6493203945Sweongyo			i++;
6494203945Sweongyo		d->curstate = i;
6495203945Sweongyo	}
6496203945Sweongyo
6497203945Sweongyo	return (lower);
6498203945Sweongyo}
6499203945Sweongyo
6500203945Sweongyostatic void
6501203945Sweongyobwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
6502203945Sweongyo{
6503203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6504203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6505203945Sweongyo	struct bwn_lo_g_sm d;
6506203945Sweongyo	struct bwn_loctl probe;
6507203945Sweongyo	int lower, repeat, cnt = 0;
6508203945Sweongyo	uint16_t feedth;
6509203945Sweongyo
6510203945Sweongyo	d.nmeasure = 0;
6511203945Sweongyo	d.multipler = 1;
6512203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6513203945Sweongyo		d.multipler = 3;
6514203945Sweongyo
6515203945Sweongyo	memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
6516203945Sweongyo	repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
6517203945Sweongyo
6518203945Sweongyo	do {
6519203945Sweongyo		bwn_lo_write(mac, &d.loctl);
6520203945Sweongyo		feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6521203945Sweongyo		    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6522203945Sweongyo		if (feedth < 0x258) {
6523203945Sweongyo			if (feedth >= 0x12c)
6524203945Sweongyo				*rxgain += 6;
6525203945Sweongyo			else
6526203945Sweongyo				*rxgain += 3;
6527203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6528203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6529203945Sweongyo		}
6530203945Sweongyo		d.feedth = feedth;
6531203945Sweongyo		d.curstate = 0;
6532203945Sweongyo		do {
6533203945Sweongyo			KASSERT(d.curstate >= 0 && d.curstate <= 8,
6534203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
6535203945Sweongyo			memcpy(&probe, &d.loctl,
6536203945Sweongyo			       sizeof(struct bwn_loctl));
6537203945Sweongyo			lower = bwn_lo_probe_loctl(mac, &probe, &d);
6538203945Sweongyo			if (!lower)
6539203945Sweongyo				break;
6540203945Sweongyo			if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
6541203945Sweongyo				break;
6542203945Sweongyo			memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
6543203945Sweongyo			d.nmeasure++;
6544203945Sweongyo		} while (d.nmeasure < 24);
6545203945Sweongyo		memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
6546203945Sweongyo
6547203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
6548203945Sweongyo			if (d.feedth > 0x1194)
6549203945Sweongyo				*rxgain -= 6;
6550203945Sweongyo			else if (d.feedth < 0x5dc)
6551203945Sweongyo				*rxgain += 3;
6552203945Sweongyo			if (cnt == 0) {
6553203945Sweongyo				if (d.feedth <= 0x5dc) {
6554203945Sweongyo					d.multipler = 1;
6555203945Sweongyo					cnt++;
6556203945Sweongyo				} else
6557203945Sweongyo					d.multipler = 2;
6558203945Sweongyo			} else if (cnt == 2)
6559203945Sweongyo				d.multipler = 1;
6560203945Sweongyo		}
6561203945Sweongyo		bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
6562203945Sweongyo	} while (++cnt < repeat);
6563203945Sweongyo}
6564203945Sweongyo
6565203945Sweongyostatic struct bwn_lo_calib *
6566203945Sweongyobwn_lo_calibset(struct bwn_mac *mac,
6567203945Sweongyo    const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
6568203945Sweongyo{
6569203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6570203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6571203945Sweongyo	struct bwn_loctl loctl = { 0, 0 };
6572203945Sweongyo	struct bwn_lo_calib *cal;
6573203945Sweongyo	struct bwn_lo_g_value sval;
6574203945Sweongyo	int rxgain;
6575203945Sweongyo	uint16_t pad, reg, value;
6576203945Sweongyo
6577203945Sweongyo	sval.old_channel = phy->chan;
6578203945Sweongyo	bwn_mac_suspend(mac);
6579203945Sweongyo	bwn_lo_save(mac, &sval);
6580203945Sweongyo
6581203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &value, &pad);
6582203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
6583203945Sweongyo	BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
6584203945Sweongyo
6585203945Sweongyo	rxgain = (rfatt->att * 2) + (bbatt->att / 2);
6586203945Sweongyo	if (rfatt->padmix)
6587203945Sweongyo		rxgain -= pad;
6588203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6589203945Sweongyo		rxgain += pg->pg_max_lb_gain;
6590203945Sweongyo	bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
6591203945Sweongyo	bwn_phy_g_set_bbatt(mac, bbatt->att);
6592203945Sweongyo	bwn_lo_probe_sm(mac, &loctl, &rxgain);
6593203945Sweongyo
6594203945Sweongyo	bwn_lo_restore(mac, &sval);
6595203945Sweongyo	bwn_mac_enable(mac);
6596203945Sweongyo
6597203945Sweongyo	cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
6598203945Sweongyo	if (!cal) {
6599203945Sweongyo		device_printf(mac->mac_sc->sc_dev, "out of memory\n");
6600203945Sweongyo		return (NULL);
6601203945Sweongyo	}
6602203945Sweongyo	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
6603203945Sweongyo	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
6604203945Sweongyo	memcpy(&cal->ctl, &loctl, sizeof(loctl));
6605203945Sweongyo
6606203945Sweongyo	BWN_GETTIME(cal->calib_time);
6607203945Sweongyo
6608203945Sweongyo	return (cal);
6609203945Sweongyo}
6610203945Sweongyo
6611203945Sweongyostatic struct bwn_lo_calib *
6612203945Sweongyobwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
6613203945Sweongyo    const struct bwn_rfatt *rfatt)
6614203945Sweongyo{
6615203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
6616203945Sweongyo	struct bwn_lo_calib *c;
6617203945Sweongyo
6618203945Sweongyo	TAILQ_FOREACH(c, &lo->calib_list, list) {
6619203945Sweongyo		if (!BWN_BBATTCMP(&c->bbatt, bbatt))
6620203945Sweongyo			continue;
6621203945Sweongyo		if (!BWN_RFATTCMP(&c->rfatt, rfatt))
6622203945Sweongyo			continue;
6623203945Sweongyo		return (c);
6624203945Sweongyo	}
6625203945Sweongyo
6626203945Sweongyo	c = bwn_lo_calibset(mac, bbatt, rfatt);
6627203945Sweongyo	if (!c)
6628203945Sweongyo		return (NULL);
6629203945Sweongyo	TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
6630203945Sweongyo
6631203945Sweongyo	return (c);
6632203945Sweongyo}
6633203945Sweongyo
6634203945Sweongyostatic void
6635203945Sweongyobwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
6636203945Sweongyo{
6637203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6638203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6639203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6640203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6641203945Sweongyo	const struct bwn_rfatt *rfatt;
6642203945Sweongyo	const struct bwn_bbatt *bbatt;
6643203945Sweongyo	uint64_t pvector;
6644203945Sweongyo	int i;
6645203945Sweongyo	int rf_offset, bb_offset;
6646203945Sweongyo	uint8_t changed = 0;
6647203945Sweongyo
6648203945Sweongyo	KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
6649203945Sweongyo	KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
6650203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6651203945Sweongyo
6652203945Sweongyo	pvector = lo->power_vector;
6653203945Sweongyo	if (!update && !pvector)
6654203945Sweongyo		return;
6655203945Sweongyo
6656203945Sweongyo	bwn_mac_suspend(mac);
6657203945Sweongyo
6658203945Sweongyo	for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
6659203945Sweongyo		struct bwn_lo_calib *cal;
6660203945Sweongyo		int idx;
6661203945Sweongyo		uint16_t val;
6662203945Sweongyo
6663203945Sweongyo		if (!update && !(pvector & (((uint64_t)1ULL) << i)))
6664203945Sweongyo			continue;
6665203945Sweongyo		bb_offset = i / lo->rfatt.len;
6666203945Sweongyo		rf_offset = i % lo->rfatt.len;
6667203945Sweongyo		bbatt = &(lo->bbatt.array[bb_offset]);
6668203945Sweongyo		rfatt = &(lo->rfatt.array[rf_offset]);
6669203945Sweongyo
6670203945Sweongyo		cal = bwn_lo_calibset(mac, bbatt, rfatt);
6671203945Sweongyo		if (!cal) {
6672203945Sweongyo			device_printf(sc->sc_dev, "LO: Could not "
6673203945Sweongyo			    "calibrate DC table entry\n");
6674203945Sweongyo			continue;
6675203945Sweongyo		}
6676203945Sweongyo		val = (uint8_t)(cal->ctl.q);
6677203945Sweongyo		val |= ((uint8_t)(cal->ctl.i)) << 4;
6678203945Sweongyo		free(cal, M_DEVBUF);
6679203945Sweongyo
6680203945Sweongyo		idx = i / 2;
6681203945Sweongyo		if (i % 2)
6682203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
6683203945Sweongyo			    | ((val & 0x00ff) << 8);
6684203945Sweongyo		else
6685203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
6686203945Sweongyo			    | (val & 0x00ff);
6687203945Sweongyo		changed = 1;
6688203945Sweongyo	}
6689203945Sweongyo	if (changed) {
6690203945Sweongyo		for (i = 0; i < BWN_DC_LT_SIZE; i++)
6691203945Sweongyo			BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
6692203945Sweongyo	}
6693203945Sweongyo	bwn_mac_enable(mac);
6694203945Sweongyo}
6695203945Sweongyo
6696203945Sweongyostatic void
6697203945Sweongyobwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
6698203945Sweongyo{
6699203945Sweongyo
6700203945Sweongyo	if (!rf->padmix)
6701203945Sweongyo		return;
6702203945Sweongyo	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
6703203945Sweongyo		rf->att = 4;
6704203945Sweongyo}
6705203945Sweongyo
6706203945Sweongyostatic void
6707203945Sweongyobwn_lo_g_adjust(struct bwn_mac *mac)
6708203945Sweongyo{
6709203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
6710203945Sweongyo	struct bwn_lo_calib *cal;
6711203945Sweongyo	struct bwn_rfatt rf;
6712203945Sweongyo
6713203945Sweongyo	memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
6714203945Sweongyo	bwn_lo_fixup_rfatt(&rf);
6715203945Sweongyo
6716203945Sweongyo	cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
6717203945Sweongyo	if (!cal)
6718203945Sweongyo		return;
6719203945Sweongyo	bwn_lo_write(mac, &cal->ctl);
6720203945Sweongyo}
6721203945Sweongyo
6722203945Sweongyostatic void
6723203945Sweongyobwn_lo_g_init(struct bwn_mac *mac)
6724203945Sweongyo{
6725203945Sweongyo
6726203945Sweongyo	if (!bwn_has_hwpctl(mac))
6727203945Sweongyo		return;
6728203945Sweongyo
6729203945Sweongyo	bwn_lo_get_powervector(mac);
6730203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
6731203945Sweongyo}
6732203945Sweongyo
6733203945Sweongyostatic void
6734203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
6735203945Sweongyo{
6736203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6737203945Sweongyo	int i;
6738203945Sweongyo	uint32_t tmp;
6739203945Sweongyo
6740203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6741203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6742203945Sweongyo
6743203945Sweongyo	if (mac->mac_suspended == 0) {
6744203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
6745203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6746203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
6747203945Sweongyo			    & ~BWN_MACCTL_ON);
6748203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6749203945Sweongyo		for (i = 35; i; i--) {
6750203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6751203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6752203945Sweongyo				goto out;
6753203945Sweongyo			DELAY(10);
6754203945Sweongyo		}
6755203945Sweongyo		for (i = 40; i; i--) {
6756203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6757203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6758203945Sweongyo				goto out;
6759203945Sweongyo			DELAY(1000);
6760203945Sweongyo		}
6761203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
6762203945Sweongyo	}
6763203945Sweongyoout:
6764203945Sweongyo	mac->mac_suspended++;
6765203945Sweongyo}
6766203945Sweongyo
6767203945Sweongyostatic void
6768203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
6769203945Sweongyo{
6770203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6771203945Sweongyo	uint16_t state;
6772203945Sweongyo
6773203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
6774203945Sweongyo	    BWN_SHARED_UCODESTAT);
6775203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
6776203945Sweongyo	    state != BWN_SHARED_UCODESTAT_SLEEP)
6777203945Sweongyo		device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
6778203945Sweongyo
6779203945Sweongyo	mac->mac_suspended--;
6780203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6781203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6782203945Sweongyo	if (mac->mac_suspended == 0) {
6783203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6784203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
6785203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
6786203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6787203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
6788203945Sweongyo		bwn_psctl(mac, 0);
6789203945Sweongyo	}
6790203945Sweongyo}
6791203945Sweongyo
6792203945Sweongyostatic void
6793203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
6794203945Sweongyo{
6795203945Sweongyo	int i;
6796203945Sweongyo	uint16_t ucstat;
6797203945Sweongyo
6798203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
6799203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6800203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
6801203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6802203945Sweongyo
6803203945Sweongyo	/* XXX forcibly awake and hwps-off */
6804203945Sweongyo
6805203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
6806203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
6807203945Sweongyo	    ~BWN_MACCTL_HWPS);
6808203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
6809203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 5) {
6810203945Sweongyo		for (i = 0; i < 100; i++) {
6811203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
6812203945Sweongyo			    BWN_SHARED_UCODESTAT);
6813203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
6814203945Sweongyo				break;
6815203945Sweongyo			DELAY(10);
6816203945Sweongyo		}
6817203945Sweongyo	}
6818203945Sweongyo}
6819203945Sweongyo
6820203945Sweongyostatic int16_t
6821203945Sweongyobwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
6822203945Sweongyo{
6823203945Sweongyo
6824203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
6825203945Sweongyo	return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
6826203945Sweongyo}
6827203945Sweongyo
6828203945Sweongyostatic void
6829203945Sweongyobwn_nrssi_threshold(struct bwn_mac *mac)
6830203945Sweongyo{
6831203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6832203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6833203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
6834203945Sweongyo	int32_t a, b;
6835203945Sweongyo	int16_t tmp16;
6836203945Sweongyo	uint16_t tmpu16;
6837203945Sweongyo
6838203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
6839203945Sweongyo
6840203945Sweongyo	if (phy->gmode && (siba->siba_sprom.bf_lo & BWN_BFL_RSSI)) {
6841203945Sweongyo		if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
6842203945Sweongyo			a = 0x13;
6843203945Sweongyo			b = 0x12;
6844203945Sweongyo		} else {
6845203945Sweongyo			a = 0xe;
6846203945Sweongyo			b = 0x11;
6847203945Sweongyo		}
6848203945Sweongyo
6849203945Sweongyo		a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6850203945Sweongyo		a += (pg->pg_nrssi[0] << 6);
6851203945Sweongyo		a += (a < 32) ? 31 : 32;
6852203945Sweongyo		a = a >> 6;
6853203945Sweongyo		a = MIN(MAX(a, -31), 31);
6854203945Sweongyo
6855203945Sweongyo		b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6856203945Sweongyo		b += (pg->pg_nrssi[0] << 6);
6857203945Sweongyo		if (b < 32)
6858203945Sweongyo			b += 31;
6859203945Sweongyo		else
6860203945Sweongyo			b += 32;
6861203945Sweongyo		b = b >> 6;
6862203945Sweongyo		b = MIN(MAX(b, -31), 31);
6863203945Sweongyo
6864203945Sweongyo		tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
6865203945Sweongyo		tmpu16 |= ((uint32_t)b & 0x0000003f);
6866203945Sweongyo		tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
6867203945Sweongyo		BWN_PHY_WRITE(mac, 0x048a, tmpu16);
6868203945Sweongyo		return;
6869203945Sweongyo	}
6870203945Sweongyo
6871203945Sweongyo	tmp16 = bwn_nrssi_read(mac, 0x20);
6872203945Sweongyo	if (tmp16 >= 0x20)
6873203945Sweongyo		tmp16 -= 0x40;
6874203945Sweongyo	BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
6875203945Sweongyo}
6876203945Sweongyo
6877203945Sweongyostatic void
6878203945Sweongyobwn_nrssi_slope_11g(struct bwn_mac *mac)
6879203945Sweongyo{
6880203945Sweongyo#define	SAVE_RF_MAX		3
6881203945Sweongyo#define	SAVE_PHY_COMM_MAX	4
6882203945Sweongyo#define	SAVE_PHY3_MAX		8
6883203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6884203945Sweongyo		{ 0x7a, 0x52, 0x43 };
6885203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
6886203945Sweongyo		{ 0x15, 0x5a, 0x59, 0x58 };
6887203945Sweongyo	static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
6888203945Sweongyo		0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
6889203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6890203945Sweongyo	};
6891203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6892203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6893203945Sweongyo	int32_t i, tmp32, phy3_idx = 0;
6894203945Sweongyo	uint16_t delta, tmp;
6895203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6896203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6897203945Sweongyo	uint16_t save_phy3[SAVE_PHY3_MAX];
6898203945Sweongyo	uint16_t ant_div, phy0, chan_ex;
6899203945Sweongyo	int16_t nrssi0, nrssi1;
6900203945Sweongyo
6901203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
6902203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6903203945Sweongyo
6904203945Sweongyo	if (phy->rf_rev >= 9)
6905203945Sweongyo		return;
6906203945Sweongyo	if (phy->rf_rev == 8)
6907203945Sweongyo		bwn_nrssi_offset(mac);
6908203945Sweongyo
6909203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
6910203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, 0xfffc);
6911203945Sweongyo
6912203945Sweongyo	/*
6913203945Sweongyo	 * Save RF/PHY registers for later restoration
6914203945Sweongyo	 */
6915203945Sweongyo	ant_div = BWN_READ_2(mac, 0x03e2);
6916203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
6917203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6918203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6919203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6920203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6921203945Sweongyo
6922203945Sweongyo	phy0 = BWN_READ_2(mac, BWN_PHY0);
6923203945Sweongyo	chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
6924203945Sweongyo	if (phy->rev >= 3) {
6925203945Sweongyo		for (i = 0; i < SAVE_PHY3_MAX; ++i)
6926203945Sweongyo			save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
6927203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6928203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
6929203945Sweongyo		switch (phy->rev) {
6930203945Sweongyo		case 4:
6931203945Sweongyo		case 6:
6932203945Sweongyo		case 7:
6933203945Sweongyo			BWN_PHY_SET(mac, 0x0478, 0x0100);
6934203945Sweongyo			BWN_PHY_SET(mac, 0x0801, 0x0040);
6935203945Sweongyo			break;
6936203945Sweongyo		case 3:
6937203945Sweongyo		case 5:
6938203945Sweongyo			BWN_PHY_MASK(mac, 0x0801, 0xffbf);
6939203945Sweongyo			break;
6940203945Sweongyo		}
6941203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
6942203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
6943203945Sweongyo	}
6944203945Sweongyo	/*
6945203945Sweongyo	 * Calculate nrssi0
6946203945Sweongyo	 */
6947203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
6948203945Sweongyo	bwn_set_all_gains(mac, 0, 8, 0);
6949203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x00f7);
6950203945Sweongyo	if (phy->rev >= 2) {
6951203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
6952203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
6953203945Sweongyo	}
6954203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
6955203945Sweongyo	DELAY(20);
6956203945Sweongyo
6957203945Sweongyo	nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6958203945Sweongyo	if (nrssi0 >= 0x0020)
6959203945Sweongyo		nrssi0 -= 0x0040;
6960203945Sweongyo
6961203945Sweongyo	/*
6962203945Sweongyo	 * Calculate nrssi1
6963203945Sweongyo	 */
6964203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x007f);
6965203945Sweongyo	if (phy->rev >= 2)
6966203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
6967203945Sweongyo
6968203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
6969203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
6970203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x000f);
6971203945Sweongyo	BWN_PHY_WRITE(mac, 0x0015, 0xf330);
6972203945Sweongyo	if (phy->rev >= 2) {
6973203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
6974203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
6975203945Sweongyo	}
6976203945Sweongyo
6977203945Sweongyo	bwn_set_all_gains(mac, 3, 0, 1);
6978203945Sweongyo	if (phy->rf_rev == 8) {
6979203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, 0x001f);
6980203945Sweongyo	} else {
6981203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
6982203945Sweongyo		BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
6983203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
6984203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
6985203945Sweongyo	}
6986203945Sweongyo	BWN_PHY_WRITE(mac, 0x005a, 0x0480);
6987203945Sweongyo	BWN_PHY_WRITE(mac, 0x0059, 0x0810);
6988203945Sweongyo	BWN_PHY_WRITE(mac, 0x0058, 0x000d);
6989203945Sweongyo	DELAY(20);
6990203945Sweongyo	nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6991203945Sweongyo
6992203945Sweongyo	/*
6993203945Sweongyo	 * Install calculated narrow RSSI values
6994203945Sweongyo	 */
6995203945Sweongyo	if (nrssi1 >= 0x0020)
6996203945Sweongyo		nrssi1 -= 0x0040;
6997203945Sweongyo	if (nrssi0 == nrssi1)
6998203945Sweongyo		pg->pg_nrssi_slope = 0x00010000;
6999203945Sweongyo	else
7000203945Sweongyo		pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
7001203945Sweongyo	if (nrssi0 >= -4) {
7002203945Sweongyo		pg->pg_nrssi[0] = nrssi1;
7003203945Sweongyo		pg->pg_nrssi[1] = nrssi0;
7004203945Sweongyo	}
7005203945Sweongyo
7006203945Sweongyo	/*
7007203945Sweongyo	 * Restore saved RF/PHY registers
7008203945Sweongyo	 */
7009203945Sweongyo	if (phy->rev >= 3) {
7010203945Sweongyo		for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
7011203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
7012203945Sweongyo			    save_phy3[phy3_idx]);
7013203945Sweongyo		}
7014203945Sweongyo	}
7015203945Sweongyo	if (phy->rev >= 2) {
7016203945Sweongyo		BWN_PHY_MASK(mac, 0x0812, 0xffcf);
7017203945Sweongyo		BWN_PHY_MASK(mac, 0x0811, 0xffcf);
7018203945Sweongyo	}
7019203945Sweongyo
7020203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
7021203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
7022203945Sweongyo
7023203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, ant_div);
7024203945Sweongyo	BWN_WRITE_2(mac, 0x03e6, phy0);
7025203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
7026203945Sweongyo
7027203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
7028203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
7029203945Sweongyo
7030203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
7031203945Sweongyo	BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
7032203945Sweongyo	bwn_set_original_gains(mac);
7033203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
7034203945Sweongyo	if (phy->rev >= 3) {
7035203945Sweongyo		for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
7036203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
7037203945Sweongyo			    save_phy3[phy3_idx]);
7038203945Sweongyo		}
7039203945Sweongyo	}
7040203945Sweongyo
7041203945Sweongyo	delta = 0x1f - pg->pg_nrssi[0];
7042203945Sweongyo	for (i = 0; i < 64; i++) {
7043203945Sweongyo		tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
7044203945Sweongyo		tmp32 = MIN(MAX(tmp32, 0), 0x3f);
7045203945Sweongyo		pg->pg_nrssi_lt[i] = tmp32;
7046203945Sweongyo	}
7047203945Sweongyo
7048203945Sweongyo	bwn_nrssi_threshold(mac);
7049203945Sweongyo#undef SAVE_RF_MAX
7050203945Sweongyo#undef SAVE_PHY_COMM_MAX
7051203945Sweongyo#undef SAVE_PHY3_MAX
7052203945Sweongyo}
7053203945Sweongyo
7054203945Sweongyostatic void
7055203945Sweongyobwn_nrssi_offset(struct bwn_mac *mac)
7056203945Sweongyo{
7057203945Sweongyo#define	SAVE_RF_MAX		2
7058203945Sweongyo#define	SAVE_PHY_COMM_MAX	10
7059203945Sweongyo#define	SAVE_PHY6_MAX		8
7060203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
7061203945Sweongyo		{ 0x7a, 0x43 };
7062203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
7063203945Sweongyo		0x0001, 0x0811, 0x0812, 0x0814,
7064203945Sweongyo		0x0815, 0x005a, 0x0059, 0x0058,
7065203945Sweongyo		0x000a, 0x0003
7066203945Sweongyo	};
7067203945Sweongyo	static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
7068203945Sweongyo		0x002e, 0x002f, 0x080f, 0x0810,
7069203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
7070203945Sweongyo	};
7071203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7072203945Sweongyo	int i, phy6_idx = 0;
7073203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
7074203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
7075203945Sweongyo	uint16_t save_phy6[SAVE_PHY6_MAX];
7076203945Sweongyo	int16_t nrssi;
7077203945Sweongyo	uint16_t saved = 0xffff;
7078203945Sweongyo
7079203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
7080203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
7081203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
7082203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
7083203945Sweongyo
7084203945Sweongyo	BWN_PHY_MASK(mac, 0x0429, 0x7fff);
7085203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
7086203945Sweongyo	BWN_PHY_SET(mac, 0x0811, 0x000c);
7087203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
7088203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
7089203945Sweongyo	if (phy->rev >= 6) {
7090203945Sweongyo		for (i = 0; i < SAVE_PHY6_MAX; ++i)
7091203945Sweongyo			save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
7092203945Sweongyo
7093203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
7094203945Sweongyo		BWN_PHY_WRITE(mac, 0x002f, 0);
7095203945Sweongyo		BWN_PHY_WRITE(mac, 0x080f, 0);
7096203945Sweongyo		BWN_PHY_WRITE(mac, 0x0810, 0);
7097203945Sweongyo		BWN_PHY_SET(mac, 0x0478, 0x0100);
7098203945Sweongyo		BWN_PHY_SET(mac, 0x0801, 0x0040);
7099203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
7100203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
7101203945Sweongyo	}
7102203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
7103203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
7104203945Sweongyo	DELAY(30);
7105203945Sweongyo
7106203945Sweongyo	nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7107203945Sweongyo	if (nrssi >= 0x20)
7108203945Sweongyo		nrssi -= 0x40;
7109203945Sweongyo	if (nrssi == 31) {
7110203945Sweongyo		for (i = 7; i >= 4; i--) {
7111203945Sweongyo			BWN_RF_WRITE(mac, 0x007b, i);
7112203945Sweongyo			DELAY(20);
7113203945Sweongyo			nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
7114203945Sweongyo			    0x003f);
7115203945Sweongyo			if (nrssi >= 0x20)
7116203945Sweongyo				nrssi -= 0x40;
7117203945Sweongyo			if (nrssi < 31 && saved == 0xffff)
7118203945Sweongyo				saved = i;
7119203945Sweongyo		}
7120203945Sweongyo		if (saved == 0xffff)
7121203945Sweongyo			saved = 4;
7122203945Sweongyo	} else {
7123203945Sweongyo		BWN_RF_MASK(mac, 0x007a, 0x007f);
7124203945Sweongyo		if (phy->rev != 1) {
7125203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0001);
7126203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffe);
7127203945Sweongyo		}
7128203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x000c);
7129203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x000c);
7130203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x0030);
7131203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x0030);
7132203945Sweongyo		BWN_PHY_WRITE(mac, 0x005a, 0x0480);
7133203945Sweongyo		BWN_PHY_WRITE(mac, 0x0059, 0x0810);
7134203945Sweongyo		BWN_PHY_WRITE(mac, 0x0058, 0x000d);
7135203945Sweongyo		if (phy->rev == 0)
7136203945Sweongyo			BWN_PHY_WRITE(mac, 0x0003, 0x0122);
7137203945Sweongyo		else
7138203945Sweongyo			BWN_PHY_SET(mac, 0x000a, 0x2000);
7139203945Sweongyo		if (phy->rev != 1) {
7140203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0004);
7141203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffb);
7142203945Sweongyo		}
7143203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
7144203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x000f);
7145203945Sweongyo		bwn_set_all_gains(mac, 3, 0, 1);
7146203945Sweongyo		BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
7147203945Sweongyo		DELAY(30);
7148203945Sweongyo		nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
7149203945Sweongyo		if (nrssi >= 0x20)
7150203945Sweongyo			nrssi -= 0x40;
7151203945Sweongyo		if (nrssi == -32) {
7152203945Sweongyo			for (i = 0; i < 4; i++) {
7153203945Sweongyo				BWN_RF_WRITE(mac, 0x007b, i);
7154203945Sweongyo				DELAY(20);
7155203945Sweongyo				nrssi = (int16_t)((BWN_PHY_READ(mac,
7156203945Sweongyo				    0x047f) >> 8) & 0x003f);
7157203945Sweongyo				if (nrssi >= 0x20)
7158203945Sweongyo					nrssi -= 0x40;
7159203945Sweongyo				if (nrssi > -31 && saved == 0xffff)
7160203945Sweongyo					saved = i;
7161203945Sweongyo			}
7162203945Sweongyo			if (saved == 0xffff)
7163203945Sweongyo				saved = 3;
7164203945Sweongyo		} else
7165203945Sweongyo			saved = 0;
7166203945Sweongyo	}
7167203945Sweongyo	BWN_RF_WRITE(mac, 0x007b, saved);
7168203945Sweongyo
7169203945Sweongyo	/*
7170203945Sweongyo	 * Restore saved RF/PHY registers
7171203945Sweongyo	 */
7172203945Sweongyo	if (phy->rev >= 6) {
7173203945Sweongyo		for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
7174203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7175203945Sweongyo			    save_phy6[phy6_idx]);
7176203945Sweongyo		}
7177203945Sweongyo	}
7178203945Sweongyo	if (phy->rev != 1) {
7179203945Sweongyo		for (i = 3; i < 5; i++)
7180203945Sweongyo			BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
7181203945Sweongyo			    save_phy_comm[i]);
7182203945Sweongyo	}
7183203945Sweongyo	for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
7184203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
7185203945Sweongyo
7186203945Sweongyo	for (i = SAVE_RF_MAX - 1; i >= 0; --i)
7187203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
7188203945Sweongyo
7189203945Sweongyo	BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
7190203945Sweongyo	BWN_PHY_SET(mac, 0x0429, 0x8000);
7191203945Sweongyo	bwn_set_original_gains(mac);
7192203945Sweongyo	if (phy->rev >= 6) {
7193203945Sweongyo		for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
7194203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
7195203945Sweongyo			    save_phy6[phy6_idx]);
7196203945Sweongyo		}
7197203945Sweongyo	}
7198203945Sweongyo
7199203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
7200203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
7201203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
7202203945Sweongyo}
7203203945Sweongyo
7204203945Sweongyostatic void
7205203945Sweongyobwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
7206203945Sweongyo    int16_t third)
7207203945Sweongyo{
7208203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7209203945Sweongyo	uint16_t i;
7210203945Sweongyo	uint16_t start = 0x08, end = 0x18;
7211203945Sweongyo	uint16_t tmp;
7212203945Sweongyo	uint16_t table;
7213203945Sweongyo
7214203945Sweongyo	if (phy->rev <= 1) {
7215203945Sweongyo		start = 0x10;
7216203945Sweongyo		end = 0x20;
7217203945Sweongyo	}
7218203945Sweongyo
7219203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7220203945Sweongyo	if (phy->rev <= 1)
7221203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7222203945Sweongyo	for (i = 0; i < 4; i++)
7223203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, first);
7224203945Sweongyo
7225203945Sweongyo	for (i = start; i < end; i++)
7226203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, second);
7227203945Sweongyo
7228203945Sweongyo	if (third != -1) {
7229203945Sweongyo		tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
7230203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
7231203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
7232203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
7233203945Sweongyo	}
7234203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7235203945Sweongyo}
7236203945Sweongyo
7237203945Sweongyostatic void
7238203945Sweongyobwn_set_original_gains(struct bwn_mac *mac)
7239203945Sweongyo{
7240203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7241203945Sweongyo	uint16_t i, tmp;
7242203945Sweongyo	uint16_t table;
7243203945Sweongyo	uint16_t start = 0x0008, end = 0x0018;
7244203945Sweongyo
7245203945Sweongyo	if (phy->rev <= 1) {
7246203945Sweongyo		start = 0x0010;
7247203945Sweongyo		end = 0x0020;
7248203945Sweongyo	}
7249203945Sweongyo
7250203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7251203945Sweongyo	if (phy->rev <= 1)
7252203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7253203945Sweongyo	for (i = 0; i < 4; i++) {
7254203945Sweongyo		tmp = (i & 0xfffc);
7255203945Sweongyo		tmp |= (i & 0x0001) << 1;
7256203945Sweongyo		tmp |= (i & 0x0002) >> 1;
7257203945Sweongyo
7258203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, tmp);
7259203945Sweongyo	}
7260203945Sweongyo
7261203945Sweongyo	for (i = start; i < end; i++)
7262203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, i - start);
7263203945Sweongyo
7264203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
7265203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
7266203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
7267203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7268203945Sweongyo}
7269203945Sweongyo
7270203945Sweongyostatic void
7271203945Sweongyobwn_phy_hwpctl_init(struct bwn_mac *mac)
7272203945Sweongyo{
7273203945Sweongyo	struct siba_softc *bus = mac->mac_sd->sd_bus;
7274203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7275203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7276203945Sweongyo	struct bwn_rfatt old_rfatt, rfatt;
7277203945Sweongyo	struct bwn_bbatt old_bbatt, bbatt;
7278203945Sweongyo	uint8_t old_txctl = 0;
7279203945Sweongyo
7280203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
7281203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7282203945Sweongyo
7283203945Sweongyo	if ((bus->siba_board_vendor == SIBA_BOARDVENDOR_BCM) &&
7284203945Sweongyo	    (bus->siba_board_type == SIBA_BOARD_BU4306))
7285203945Sweongyo		return;
7286203945Sweongyo
7287203945Sweongyo	BWN_PHY_WRITE(mac, 0x0028, 0x8018);
7288203945Sweongyo
7289203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
7290203945Sweongyo
7291203945Sweongyo	if (!phy->gmode)
7292203945Sweongyo		return;
7293203945Sweongyo	bwn_hwpctl_early_init(mac);
7294203945Sweongyo	if (pg->pg_curtssi == 0) {
7295203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0) {
7296203945Sweongyo			BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
7297203945Sweongyo		} else {
7298203945Sweongyo			memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
7299203945Sweongyo			memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
7300203945Sweongyo			old_txctl = pg->pg_txctl;
7301203945Sweongyo
7302203945Sweongyo			bbatt.att = 11;
7303203945Sweongyo			if (phy->rf_rev == 8) {
7304203945Sweongyo				rfatt.att = 15;
7305203945Sweongyo				rfatt.padmix = 1;
7306203945Sweongyo			} else {
7307203945Sweongyo				rfatt.att = 9;
7308203945Sweongyo				rfatt.padmix = 0;
7309203945Sweongyo			}
7310203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
7311203945Sweongyo		}
7312203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
7313203945Sweongyo		pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
7314203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0)
7315203945Sweongyo			BWN_RF_MASK(mac, 0x0076, 0xff7b);
7316203945Sweongyo		else
7317203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
7318203945Sweongyo			    &old_rfatt, old_txctl);
7319203945Sweongyo	}
7320203945Sweongyo	bwn_hwpctl_init_gphy(mac);
7321203945Sweongyo
7322203945Sweongyo	/* clear TSSI */
7323203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
7324203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
7325203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
7326203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
7327203945Sweongyo}
7328203945Sweongyo
7329203945Sweongyostatic void
7330203945Sweongyobwn_hwpctl_early_init(struct bwn_mac *mac)
7331203945Sweongyo{
7332203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7333203945Sweongyo
7334203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7335203945Sweongyo		BWN_PHY_WRITE(mac, 0x047a, 0xc111);
7336203945Sweongyo		return;
7337203945Sweongyo	}
7338203945Sweongyo
7339203945Sweongyo	BWN_PHY_MASK(mac, 0x0036, 0xfeff);
7340203945Sweongyo	BWN_PHY_WRITE(mac, 0x002f, 0x0202);
7341203945Sweongyo	BWN_PHY_SET(mac, 0x047c, 0x0002);
7342203945Sweongyo	BWN_PHY_SET(mac, 0x047a, 0xf000);
7343203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
7344203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7345203945Sweongyo		BWN_PHY_SET(mac, 0x005d, 0x8000);
7346203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7347203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7348203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7349203945Sweongyo	} else {
7350203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0200);
7351203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7352203945Sweongyo		BWN_PHY_MASK(mac, 0x005d, 0x7fff);
7353203945Sweongyo		BWN_PHY_MASK(mac, 0x004f, 0xfffe);
7354203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7355203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7356203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7357203945Sweongyo	}
7358203945Sweongyo}
7359203945Sweongyo
7360203945Sweongyostatic void
7361203945Sweongyobwn_hwpctl_init_gphy(struct bwn_mac *mac)
7362203945Sweongyo{
7363203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7364203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7365203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7366203945Sweongyo	int i;
7367203945Sweongyo	uint16_t nr_written = 0, tmp, value;
7368203945Sweongyo	uint8_t rf, bb;
7369203945Sweongyo
7370203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7371203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
7372203945Sweongyo		return;
7373203945Sweongyo	}
7374203945Sweongyo
7375203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
7376203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7377203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
7378203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7379203945Sweongyo
7380203945Sweongyo	for (i = 0; i < 32; i++)
7381203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
7382203945Sweongyo	for (i = 32; i < 64; i++)
7383203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
7384203945Sweongyo	for (i = 0; i < 64; i += 2) {
7385203945Sweongyo		value = (uint16_t) pg->pg_tssi2dbm[i];
7386203945Sweongyo		value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
7387203945Sweongyo		BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
7388203945Sweongyo	}
7389203945Sweongyo
7390203945Sweongyo	for (rf = 0; rf < lo->rfatt.len; rf++) {
7391203945Sweongyo		for (bb = 0; bb < lo->bbatt.len; bb++) {
7392203945Sweongyo			if (nr_written >= 0x40)
7393203945Sweongyo				return;
7394203945Sweongyo			tmp = lo->bbatt.array[bb].att;
7395203945Sweongyo			tmp <<= 8;
7396203945Sweongyo			if (phy->rf_rev == 8)
7397203945Sweongyo				tmp |= 0x50;
7398203945Sweongyo			else
7399203945Sweongyo				tmp |= 0x40;
7400203945Sweongyo			tmp |= lo->rfatt.array[rf].att;
7401203945Sweongyo			BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
7402203945Sweongyo			nr_written++;
7403203945Sweongyo		}
7404203945Sweongyo	}
7405203945Sweongyo
7406203945Sweongyo	BWN_PHY_MASK(mac, 0x0060, 0xffbf);
7407203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0000);
7408203945Sweongyo
7409203945Sweongyo	KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
7410203945Sweongyo	BWN_PHY_SET(mac, 0x0478, 0x0800);
7411203945Sweongyo	BWN_PHY_MASK(mac, 0x0478, 0xfeff);
7412203945Sweongyo	BWN_PHY_MASK(mac, 0x0801, 0xffbf);
7413203945Sweongyo
7414203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
7415203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
7416203945Sweongyo}
7417203945Sweongyo
7418203945Sweongyostatic void
7419203945Sweongyobwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
7420203945Sweongyo{
7421203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
7422203945Sweongyo
7423203945Sweongyo	if (spu != 0)
7424203945Sweongyo		bwn_spu_workaround(mac, channel);
7425203945Sweongyo
7426203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7427203945Sweongyo
7428203945Sweongyo	if (channel == 14) {
7429203945Sweongyo		if (siba->siba_sprom.ccode == SIBA_CCODE_JAPAN)
7430203945Sweongyo			bwn_hf_write(mac,
7431203945Sweongyo			    bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
7432203945Sweongyo		else
7433203945Sweongyo			bwn_hf_write(mac,
7434203945Sweongyo			    bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
7435203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7436203945Sweongyo		    BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
7437203945Sweongyo		return;
7438203945Sweongyo	}
7439203945Sweongyo
7440203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7441203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
7442203945Sweongyo}
7443203945Sweongyo
7444203945Sweongyostatic uint16_t
7445203945Sweongyobwn_phy_g_chan2freq(uint8_t channel)
7446203945Sweongyo{
7447203945Sweongyo	static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
7448203945Sweongyo
7449203945Sweongyo	KASSERT(channel >= 1 && channel <= 14,
7450203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7451203945Sweongyo
7452203945Sweongyo	return (bwn_phy_g_rf_channels[channel - 1]);
7453203945Sweongyo}
7454203945Sweongyo
7455203945Sweongyostatic void
7456203945Sweongyobwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
7457203945Sweongyo    const struct bwn_rfatt *rfatt, uint8_t txctl)
7458203945Sweongyo{
7459203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7460203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7461203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7462203945Sweongyo	uint16_t bb, rf;
7463203945Sweongyo	uint16_t tx_bias, tx_magn;
7464203945Sweongyo
7465203945Sweongyo	bb = bbatt->att;
7466203945Sweongyo	rf = rfatt->att;
7467203945Sweongyo	tx_bias = lo->tx_bias;
7468203945Sweongyo	tx_magn = lo->tx_magn;
7469203945Sweongyo	if (tx_bias == 0xff)
7470203945Sweongyo		tx_bias = 0;
7471203945Sweongyo
7472203945Sweongyo	pg->pg_txctl = txctl;
7473203945Sweongyo	memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
7474203945Sweongyo	pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
7475203945Sweongyo	memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
7476203945Sweongyo	bwn_phy_g_set_bbatt(mac, bb);
7477203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
7478203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
7479203945Sweongyo		BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
7480203945Sweongyo	else {
7481203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
7482203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
7483203945Sweongyo	}
7484203945Sweongyo	if (BWN_HAS_TXMAG(phy))
7485203945Sweongyo		BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
7486203945Sweongyo	else
7487203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
7488203945Sweongyo	bwn_lo_g_adjust(mac);
7489203945Sweongyo}
7490203945Sweongyo
7491203945Sweongyostatic void
7492203945Sweongyobwn_phy_g_set_bbatt(struct bwn_mac *mac,
7493203945Sweongyo    uint16_t bbatt)
7494203945Sweongyo{
7495203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7496203945Sweongyo
7497203945Sweongyo	if (phy->analog == 0) {
7498203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY0,
7499203945Sweongyo		    (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
7500203945Sweongyo		return;
7501203945Sweongyo	}
7502203945Sweongyo	if (phy->analog > 1) {
7503203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
7504203945Sweongyo		return;
7505203945Sweongyo	}
7506203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
7507203945Sweongyo}
7508203945Sweongyo
7509203945Sweongyostatic uint16_t
7510203945Sweongyobwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
7511203945Sweongyo{
7512203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7513203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7514203945Sweongyo	struct siba_sprom *sprom = &(mac->mac_sd->sd_bus->siba_sprom);
7515203945Sweongyo	int max_lb_gain;
7516203945Sweongyo	uint16_t extlna;
7517203945Sweongyo	uint16_t i;
7518203945Sweongyo
7519203945Sweongyo	if (phy->gmode == 0)
7520203945Sweongyo		return (0);
7521203945Sweongyo
7522203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
7523203945Sweongyo		max_lb_gain = pg->pg_max_lb_gain;
7524203945Sweongyo		max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
7525203945Sweongyo		if (max_lb_gain >= 0x46) {
7526203945Sweongyo			extlna = 0x3000;
7527203945Sweongyo			max_lb_gain -= 0x46;
7528203945Sweongyo		} else if (max_lb_gain >= 0x3a) {
7529203945Sweongyo			extlna = 0x1000;
7530203945Sweongyo			max_lb_gain -= 0x3a;
7531203945Sweongyo		} else if (max_lb_gain >= 0x2e) {
7532203945Sweongyo			extlna = 0x2000;
7533203945Sweongyo			max_lb_gain -= 0x2e;
7534203945Sweongyo		} else {
7535203945Sweongyo			extlna = 0;
7536203945Sweongyo			max_lb_gain -= 0x10;
7537203945Sweongyo		}
7538203945Sweongyo
7539203945Sweongyo		for (i = 0; i < 16; i++) {
7540203945Sweongyo			max_lb_gain -= (i * 6);
7541203945Sweongyo			if (max_lb_gain < 6)
7542203945Sweongyo				break;
7543203945Sweongyo		}
7544203945Sweongyo
7545203945Sweongyo		if ((phy->rev < 7) || !(sprom->bf_lo & BWN_BFL_EXTLNA)) {
7546203945Sweongyo			if (reg == BWN_PHY_RFOVER) {
7547203945Sweongyo				return (0x1b3);
7548203945Sweongyo			} else if (reg == BWN_PHY_RFOVERVAL) {
7549203945Sweongyo				extlna |= (i << 8);
7550203945Sweongyo				switch (lpd) {
7551203945Sweongyo				case BWN_LPD(0, 1, 1):
7552203945Sweongyo					return (0x0f92);
7553203945Sweongyo				case BWN_LPD(0, 0, 1):
7554203945Sweongyo				case BWN_LPD(1, 0, 1):
7555203945Sweongyo					return (0x0092 | extlna);
7556203945Sweongyo				case BWN_LPD(1, 0, 0):
7557203945Sweongyo					return (0x0093 | extlna);
7558203945Sweongyo				}
7559203945Sweongyo				KASSERT(0 == 1,
7560203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7561203945Sweongyo			}
7562203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7563203945Sweongyo		} else {
7564203945Sweongyo			if (reg == BWN_PHY_RFOVER)
7565203945Sweongyo				return (0x9b3);
7566203945Sweongyo			if (reg == BWN_PHY_RFOVERVAL) {
7567203945Sweongyo				if (extlna)
7568203945Sweongyo					extlna |= 0x8000;
7569203945Sweongyo				extlna |= (i << 8);
7570203945Sweongyo				switch (lpd) {
7571203945Sweongyo				case BWN_LPD(0, 1, 1):
7572203945Sweongyo					return (0x8f92);
7573203945Sweongyo				case BWN_LPD(0, 0, 1):
7574203945Sweongyo					return (0x8092 | extlna);
7575203945Sweongyo				case BWN_LPD(1, 0, 1):
7576203945Sweongyo					return (0x2092 | extlna);
7577203945Sweongyo				case BWN_LPD(1, 0, 0):
7578203945Sweongyo					return (0x2093 | extlna);
7579203945Sweongyo				}
7580203945Sweongyo				KASSERT(0 == 1,
7581203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7582203945Sweongyo			}
7583203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7584203945Sweongyo		}
7585203945Sweongyo		return (0);
7586203945Sweongyo	}
7587203945Sweongyo
7588203945Sweongyo	if ((phy->rev < 7) ||
7589203945Sweongyo	    !(sprom->bf_lo & BWN_BFL_EXTLNA)) {
7590203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7591203945Sweongyo			return (0x1b3);
7592203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7593203945Sweongyo			switch (lpd) {
7594203945Sweongyo			case BWN_LPD(0, 1, 1):
7595203945Sweongyo				return (0x0fb2);
7596203945Sweongyo			case BWN_LPD(0, 0, 1):
7597203945Sweongyo				return (0x00b2);
7598203945Sweongyo			case BWN_LPD(1, 0, 1):
7599203945Sweongyo				return (0x30b2);
7600203945Sweongyo			case BWN_LPD(1, 0, 0):
7601203945Sweongyo				return (0x30b3);
7602203945Sweongyo			}
7603203945Sweongyo			KASSERT(0 == 1,
7604203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7605203945Sweongyo		}
7606203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7607203945Sweongyo	} else {
7608203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7609203945Sweongyo			return (0x9b3);
7610203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7611203945Sweongyo			switch (lpd) {
7612203945Sweongyo			case BWN_LPD(0, 1, 1):
7613203945Sweongyo				return (0x8fb2);
7614203945Sweongyo			case BWN_LPD(0, 0, 1):
7615203945Sweongyo				return (0x80b2);
7616203945Sweongyo			case BWN_LPD(1, 0, 1):
7617203945Sweongyo				return (0x20b2);
7618203945Sweongyo			case BWN_LPD(1, 0, 0):
7619203945Sweongyo				return (0x20b3);
7620203945Sweongyo			}
7621203945Sweongyo			KASSERT(0 == 1,
7622203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7623203945Sweongyo		}
7624203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7625203945Sweongyo	}
7626203945Sweongyo	return (0);
7627203945Sweongyo}
7628203945Sweongyo
7629203945Sweongyostatic void
7630203945Sweongyobwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
7631203945Sweongyo{
7632203945Sweongyo
7633203945Sweongyo	if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
7634203945Sweongyo		return;
7635203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
7636203945Sweongyo	    bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
7637203945Sweongyo	DELAY(1000);
7638203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7639203945Sweongyo}
7640203945Sweongyo
7641203945Sweongyostatic int
7642203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
7643203945Sweongyo{
7644203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7645203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
7646203945Sweongyo	const uint8_t rev = mac->mac_sd->sd_id.sd_rev;
7647203945Sweongyo	const char *filename;
7648203945Sweongyo	uint32_t high;
7649203945Sweongyo	int error;
7650203945Sweongyo
7651203945Sweongyo	/* microcode */
7652203945Sweongyo	if (rev >= 5 && rev <= 10)
7653203945Sweongyo		filename = "ucode5";
7654203945Sweongyo	else if (rev >= 11 && rev <= 12)
7655203945Sweongyo		filename = "ucode11";
7656203945Sweongyo	else if (rev == 13)
7657203945Sweongyo		filename = "ucode13";
7658203945Sweongyo	else if (rev == 14)
7659203945Sweongyo		filename = "ucode14";
7660203945Sweongyo	else if (rev >= 15)
7661203945Sweongyo		filename = "ucode15";
7662203945Sweongyo	else {
7663203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
7664203945Sweongyo		bwn_release_firmware(mac);
7665203945Sweongyo		return (EOPNOTSUPP);
7666203945Sweongyo	}
7667203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
7668203945Sweongyo	if (error) {
7669203945Sweongyo		bwn_release_firmware(mac);
7670203945Sweongyo		return (error);
7671203945Sweongyo	}
7672203945Sweongyo
7673203945Sweongyo	/* PCM */
7674203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
7675203945Sweongyo	if (rev >= 5 && rev <= 10) {
7676203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
7677203945Sweongyo		if (error == ENOENT)
7678203945Sweongyo			fw->no_pcmfile = 1;
7679203945Sweongyo		else if (error) {
7680203945Sweongyo			bwn_release_firmware(mac);
7681203945Sweongyo			return (error);
7682203945Sweongyo		}
7683203945Sweongyo	} else if (rev < 11) {
7684203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
7685203945Sweongyo		return (EOPNOTSUPP);
7686203945Sweongyo	}
7687203945Sweongyo
7688203945Sweongyo	/* initvals */
7689203945Sweongyo	high = siba_read_4(mac->mac_sd, SIBA_TGSHIGH);
7690203945Sweongyo	switch (mac->mac_phy.type) {
7691203945Sweongyo	case BWN_PHYTYPE_A:
7692203945Sweongyo		if (rev < 5 || rev > 10)
7693203945Sweongyo			goto fail1;
7694203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
7695203945Sweongyo			filename = "a0g1initvals5";
7696203945Sweongyo		else
7697203945Sweongyo			filename = "a0g0initvals5";
7698203945Sweongyo		break;
7699203945Sweongyo	case BWN_PHYTYPE_G:
7700203945Sweongyo		if (rev >= 5 && rev <= 10)
7701203945Sweongyo			filename = "b0g0initvals5";
7702203945Sweongyo		else if (rev >= 13)
7703203945Sweongyo			filename = "b0g0initvals13";
7704203945Sweongyo		else
7705203945Sweongyo			goto fail1;
7706203945Sweongyo		break;
7707203945Sweongyo	case BWN_PHYTYPE_LP:
7708203945Sweongyo		if (rev == 13)
7709203945Sweongyo			filename = "lp0initvals13";
7710203945Sweongyo		else if (rev == 14)
7711203945Sweongyo			filename = "lp0initvals14";
7712203945Sweongyo		else if (rev >= 15)
7713203945Sweongyo			filename = "lp0initvals15";
7714203945Sweongyo		else
7715203945Sweongyo			goto fail1;
7716203945Sweongyo		break;
7717203945Sweongyo	case BWN_PHYTYPE_N:
7718203945Sweongyo		if (rev >= 11 && rev <= 12)
7719203945Sweongyo			filename = "n0initvals11";
7720203945Sweongyo		else
7721203945Sweongyo			goto fail1;
7722203945Sweongyo		break;
7723203945Sweongyo	default:
7724203945Sweongyo		goto fail1;
7725203945Sweongyo	}
7726203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
7727203945Sweongyo	if (error) {
7728203945Sweongyo		bwn_release_firmware(mac);
7729203945Sweongyo		return (error);
7730203945Sweongyo	}
7731203945Sweongyo
7732203945Sweongyo	/* bandswitch initvals */
7733203945Sweongyo	switch (mac->mac_phy.type) {
7734203945Sweongyo	case BWN_PHYTYPE_A:
7735203945Sweongyo		if (rev >= 5 && rev <= 10) {
7736203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
7737203945Sweongyo				filename = "a0g1bsinitvals5";
7738203945Sweongyo			else
7739203945Sweongyo				filename = "a0g0bsinitvals5";
7740203945Sweongyo		} else if (rev >= 11)
7741203945Sweongyo			filename = NULL;
7742203945Sweongyo		else
7743203945Sweongyo			goto fail1;
7744203945Sweongyo		break;
7745203945Sweongyo	case BWN_PHYTYPE_G:
7746203945Sweongyo		if (rev >= 5 && rev <= 10)
7747203945Sweongyo			filename = "b0g0bsinitvals5";
7748203945Sweongyo		else if (rev >= 11)
7749203945Sweongyo			filename = NULL;
7750203945Sweongyo		else
7751203945Sweongyo			goto fail1;
7752203945Sweongyo		break;
7753203945Sweongyo	case BWN_PHYTYPE_LP:
7754203945Sweongyo		if (rev == 13)
7755203945Sweongyo			filename = "lp0bsinitvals13";
7756203945Sweongyo		else if (rev == 14)
7757203945Sweongyo			filename = "lp0bsinitvals14";
7758203945Sweongyo		else if (rev >= 15)
7759203945Sweongyo			filename = "lp0bsinitvals15";
7760203945Sweongyo		else
7761203945Sweongyo			goto fail1;
7762203945Sweongyo		break;
7763203945Sweongyo	case BWN_PHYTYPE_N:
7764203945Sweongyo		if (rev >= 11 && rev <= 12)
7765203945Sweongyo			filename = "n0bsinitvals11";
7766203945Sweongyo		else
7767203945Sweongyo			goto fail1;
7768203945Sweongyo		break;
7769203945Sweongyo	default:
7770203945Sweongyo		goto fail1;
7771203945Sweongyo	}
7772203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
7773203945Sweongyo	if (error) {
7774203945Sweongyo		bwn_release_firmware(mac);
7775203945Sweongyo		return (error);
7776203945Sweongyo	}
7777203945Sweongyo	return (0);
7778203945Sweongyofail1:
7779203945Sweongyo	device_printf(sc->sc_dev, "no INITVALS for rev %d\n", rev);
7780203945Sweongyo	bwn_release_firmware(mac);
7781203945Sweongyo	return (EOPNOTSUPP);
7782203945Sweongyo}
7783203945Sweongyo
7784203945Sweongyostatic int
7785203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
7786203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
7787203945Sweongyo{
7788203945Sweongyo	const struct bwn_fwhdr *hdr;
7789203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7790203945Sweongyo	const struct firmware *fw;
7791203945Sweongyo	char namebuf[64];
7792203945Sweongyo
7793203945Sweongyo	if (name == NULL) {
7794203945Sweongyo		bwn_do_release_fw(bfw);
7795203945Sweongyo		return (0);
7796203945Sweongyo	}
7797203945Sweongyo	if (bfw->filename != NULL) {
7798203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
7799203945Sweongyo			return (0);
7800203945Sweongyo		bwn_do_release_fw(bfw);
7801203945Sweongyo	}
7802203945Sweongyo
7803203945Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s",
7804203945Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "", name);
7805203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
7806203945Sweongyo	fw = firmware_get(namebuf);
7807203945Sweongyo	if (fw == NULL) {
7808203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
7809203945Sweongyo		    namebuf);
7810203945Sweongyo		return (ENOENT);
7811203945Sweongyo	}
7812203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
7813203945Sweongyo		goto fail;
7814203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
7815203945Sweongyo	switch (hdr->type) {
7816203945Sweongyo	case BWN_FWTYPE_UCODE:
7817203945Sweongyo	case BWN_FWTYPE_PCM:
7818203945Sweongyo		if (be32toh(hdr->size) !=
7819203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
7820203945Sweongyo			goto fail;
7821203945Sweongyo		/* FALLTHROUGH */
7822203945Sweongyo	case BWN_FWTYPE_IV:
7823203945Sweongyo		if (hdr->ver != 1)
7824203945Sweongyo			goto fail;
7825203945Sweongyo		break;
7826203945Sweongyo	default:
7827203945Sweongyo		goto fail;
7828203945Sweongyo	}
7829203945Sweongyo	bfw->filename = name;
7830203945Sweongyo	bfw->fw = fw;
7831203945Sweongyo	bfw->type = type;
7832203945Sweongyo	return (0);
7833203945Sweongyofail:
7834203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
7835203945Sweongyo	if (fw != NULL)
7836203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
7837203945Sweongyo	return (EPROTO);
7838203945Sweongyo}
7839203945Sweongyo
7840203945Sweongyostatic void
7841203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
7842203945Sweongyo{
7843203945Sweongyo
7844203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
7845203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
7846203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
7847203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
7848203945Sweongyo}
7849203945Sweongyo
7850203945Sweongyostatic void
7851203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
7852203945Sweongyo{
7853203945Sweongyo
7854203945Sweongyo	if (bfw->fw != NULL)
7855203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
7856203945Sweongyo	bfw->fw = NULL;
7857203945Sweongyo	bfw->filename = NULL;
7858203945Sweongyo}
7859203945Sweongyo
7860203945Sweongyostatic int
7861203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
7862203945Sweongyo{
7863203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
7864203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
7865203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
7866203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
7867203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7868203945Sweongyo	const uint32_t *data;
7869203945Sweongyo	unsigned int i;
7870203945Sweongyo	uint32_t ctl;
7871203945Sweongyo	uint16_t date, fwcaps, time;
7872203945Sweongyo	int error = 0;
7873203945Sweongyo
7874203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
7875203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
7876203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
7877203945Sweongyo	    __LINE__));
7878203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
7879203945Sweongyo	for (i = 0; i < 64; i++)
7880203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
7881203945Sweongyo	for (i = 0; i < 4096; i += 2)
7882203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
7883203945Sweongyo
7884203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7885203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
7886203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7887203945Sweongyo	     i++) {
7888203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7889203945Sweongyo		DELAY(10);
7890203945Sweongyo	}
7891203945Sweongyo
7892203945Sweongyo	if (mac->mac_fw.pcm.fw) {
7893203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
7894203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
7895203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
7896203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
7897203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
7898203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
7899203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7900203945Sweongyo			DELAY(10);
7901203945Sweongyo		}
7902203945Sweongyo	}
7903203945Sweongyo
7904203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
7905203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7906203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
7907203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
7908203945Sweongyo
7909203945Sweongyo	for (i = 0; i < 21; i++) {
7910203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
7911203945Sweongyo			break;
7912203945Sweongyo		if (i >= 20) {
7913203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
7914203945Sweongyo			error = ENXIO;
7915203945Sweongyo			goto error;
7916203945Sweongyo		}
7917203945Sweongyo		DELAY(50000);
7918203945Sweongyo	}
7919203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
7920203945Sweongyo
7921203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
7922203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
7923203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
7924203945Sweongyo		error = EOPNOTSUPP;
7925203945Sweongyo		goto error;
7926203945Sweongyo	}
7927203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
7928203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
7929203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
7930203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
7931203945Sweongyo	if (bwn_wme != 0)
7932203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
7933203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
7934203945Sweongyo
7935203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
7936203945Sweongyo	if (mac->mac_fw.opensource == 0) {
7937203945Sweongyo		device_printf(sc->sc_dev,
7938203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
7939203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
7940203945Sweongyo		if (mac->mac_fw.no_pcmfile)
7941203945Sweongyo			device_printf(sc->sc_dev,
7942203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
7943203945Sweongyo	} else {
7944203945Sweongyo		mac->mac_fw.patch = time;
7945203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
7946203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
7947203945Sweongyo			device_printf(sc->sc_dev,
7948203945Sweongyo			    "disabling HW crypto acceleration\n");
7949203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
7950203945Sweongyo		}
7951203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
7952203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
7953203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
7954203945Sweongyo		}
7955203945Sweongyo	}
7956203945Sweongyo
7957203945Sweongyo	if (BWN_ISOLDFMT(mac))
7958203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
7959203945Sweongyo
7960203945Sweongyo	return (0);
7961203945Sweongyo
7962203945Sweongyoerror:
7963203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7964203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
7965203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
7966203945Sweongyo
7967203945Sweongyo	return (error);
7968203945Sweongyo#undef GETFWSIZE
7969203945Sweongyo#undef GETFWOFFSET
7970203945Sweongyo}
7971203945Sweongyo
7972203945Sweongyo/* OpenFirmware only */
7973203945Sweongyostatic uint16_t
7974203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
7975203945Sweongyo{
7976203945Sweongyo
7977203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
7978203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7979203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
7980203945Sweongyo}
7981203945Sweongyo
7982203945Sweongyostatic int
7983203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
7984203945Sweongyo    size_t count, size_t array_size)
7985203945Sweongyo{
7986203945Sweongyo#define	GET_NEXTIV16(iv)						\
7987203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7988203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
7989203945Sweongyo#define	GET_NEXTIV32(iv)						\
7990203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7991203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
7992203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7993203945Sweongyo	const struct bwn_fwinitvals *iv;
7994203945Sweongyo	uint16_t offset;
7995203945Sweongyo	size_t i;
7996203945Sweongyo	uint8_t bit32;
7997203945Sweongyo
7998203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
7999203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8000203945Sweongyo	iv = ivals;
8001203945Sweongyo	for (i = 0; i < count; i++) {
8002203945Sweongyo		if (array_size < sizeof(iv->offset_size))
8003203945Sweongyo			goto fail;
8004203945Sweongyo		array_size -= sizeof(iv->offset_size);
8005203945Sweongyo		offset = be16toh(iv->offset_size);
8006203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
8007203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
8008203945Sweongyo		if (offset >= 0x1000)
8009203945Sweongyo			goto fail;
8010203945Sweongyo		if (bit32) {
8011203945Sweongyo			if (array_size < sizeof(iv->data.d32))
8012203945Sweongyo				goto fail;
8013203945Sweongyo			array_size -= sizeof(iv->data.d32);
8014203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
8015203945Sweongyo			iv = GET_NEXTIV32(iv);
8016203945Sweongyo		} else {
8017203945Sweongyo
8018203945Sweongyo			if (array_size < sizeof(iv->data.d16))
8019203945Sweongyo				goto fail;
8020203945Sweongyo			array_size -= sizeof(iv->data.d16);
8021203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
8022203945Sweongyo
8023203945Sweongyo			iv = GET_NEXTIV16(iv);
8024203945Sweongyo		}
8025203945Sweongyo	}
8026203945Sweongyo	if (array_size != 0)
8027203945Sweongyo		goto fail;
8028203945Sweongyo	return (0);
8029203945Sweongyofail:
8030203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
8031203945Sweongyo	return (EPROTO);
8032203945Sweongyo#undef GET_NEXTIV16
8033203945Sweongyo#undef GET_NEXTIV32
8034203945Sweongyo}
8035203945Sweongyo
8036203945Sweongyostatic int
8037203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
8038203945Sweongyo{
8039203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
8040203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8041203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8042203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
8043203945Sweongyo	uint16_t channelcookie, savedcookie;
8044203945Sweongyo	int error;
8045203945Sweongyo
8046203945Sweongyo	if (chan == 0xffff)
8047203945Sweongyo		chan = phy->get_default_chan(mac);
8048203945Sweongyo
8049203945Sweongyo	channelcookie = chan;
8050203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
8051203945Sweongyo		channelcookie |= 0x100;
8052203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
8053203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
8054203945Sweongyo	error = phy->switch_channel(mac, chan);
8055203945Sweongyo	if (error)
8056203945Sweongyo		goto fail;
8057203945Sweongyo
8058203945Sweongyo	mac->mac_phy.chan = chan;
8059203945Sweongyo	DELAY(8000);
8060203945Sweongyo	return (0);
8061203945Sweongyofail:
8062203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
8063203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
8064203945Sweongyo	return (error);
8065203945Sweongyo}
8066203945Sweongyo
8067203945Sweongyostatic uint16_t
8068203945Sweongyobwn_ant2phy(int antenna)
8069203945Sweongyo{
8070203945Sweongyo
8071203945Sweongyo	switch (antenna) {
8072203945Sweongyo	case BWN_ANT0:
8073203945Sweongyo		return (BWN_TX_PHY_ANT0);
8074203945Sweongyo	case BWN_ANT1:
8075203945Sweongyo		return (BWN_TX_PHY_ANT1);
8076203945Sweongyo	case BWN_ANT2:
8077203945Sweongyo		return (BWN_TX_PHY_ANT2);
8078203945Sweongyo	case BWN_ANT3:
8079203945Sweongyo		return (BWN_TX_PHY_ANT3);
8080203945Sweongyo	case BWN_ANTAUTO:
8081203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
8082203945Sweongyo	}
8083203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8084203945Sweongyo	return (0);
8085203945Sweongyo}
8086203945Sweongyo
8087203945Sweongyostatic void
8088203945Sweongyobwn_wme_load(struct bwn_mac *mac)
8089203945Sweongyo{
8090203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8091203945Sweongyo	int i;
8092203945Sweongyo
8093203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
8094203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8095203945Sweongyo
8096203945Sweongyo	bwn_mac_suspend(mac);
8097203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
8098203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
8099203945Sweongyo		    bwn_wme_shm_offsets[i]);
8100203945Sweongyo	bwn_mac_enable(mac);
8101203945Sweongyo}
8102203945Sweongyo
8103203945Sweongyostatic void
8104203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
8105203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
8106203945Sweongyo{
8107203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
8108203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8109203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
8110203945Sweongyo	int slot, tmp;
8111203945Sweongyo	unsigned int i;
8112203945Sweongyo
8113203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
8114203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8115203945Sweongyo
8116203945Sweongyo	memset(&params, 0, sizeof(params));
8117203945Sweongyo
8118203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
8119203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
8120203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
8121203945Sweongyo
8122203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
8123203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8124203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
8125203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
8126203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
8127203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
8128203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
8129203945Sweongyo
8130203945Sweongyo	for (i = 0; i < N(params); i++) {
8131203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
8132203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
8133203945Sweongyo			    shm_offset + (i * 2));
8134203945Sweongyo			tmp |= 0x100;
8135203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8136203945Sweongyo			    tmp);
8137203945Sweongyo		} else {
8138203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
8139203945Sweongyo			    params[i]);
8140203945Sweongyo		}
8141203945Sweongyo	}
8142203945Sweongyo}
8143203945Sweongyo
8144203945Sweongyostatic void
8145203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
8146203945Sweongyo{
8147203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8148203945Sweongyo	uint32_t tmp;
8149203945Sweongyo	int i;
8150203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
8151203945Sweongyo
8152203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
8153203945Sweongyo	memcpy(mac_bssid, sc->sc_macaddr, IEEE80211_ADDR_LEN);
8154203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
8155203945Sweongyo	    IEEE80211_ADDR_LEN);
8156203945Sweongyo
8157203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
8158203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
8159203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
8160203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
8161203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
8162203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
8163203945Sweongyo	}
8164203945Sweongyo}
8165203945Sweongyo
8166203945Sweongyostatic void
8167203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
8168203945Sweongyo    const uint8_t *macaddr)
8169203945Sweongyo{
8170203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
8171203945Sweongyo	uint16_t data;
8172203945Sweongyo
8173203945Sweongyo	if (!mac)
8174203945Sweongyo		macaddr = zero;
8175203945Sweongyo
8176203945Sweongyo	offset |= 0x0020;
8177203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
8178203945Sweongyo
8179203945Sweongyo	data = macaddr[0];
8180203945Sweongyo	data |= macaddr[1] << 8;
8181203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8182203945Sweongyo	data = macaddr[2];
8183203945Sweongyo	data |= macaddr[3] << 8;
8184203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8185203945Sweongyo	data = macaddr[4];
8186203945Sweongyo	data |= macaddr[5] << 8;
8187203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
8188203945Sweongyo}
8189203945Sweongyo
8190203945Sweongyostatic void
8191203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8192203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
8193203945Sweongyo{
8194203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
8195203945Sweongyo	uint8_t per_sta_keys_start = 8;
8196203945Sweongyo
8197203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8198203945Sweongyo		per_sta_keys_start = 4;
8199203945Sweongyo
8200203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
8201203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8202203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
8203203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8204203945Sweongyo
8205203945Sweongyo	if (index >= per_sta_keys_start)
8206203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
8207203945Sweongyo	if (key)
8208203945Sweongyo		memcpy(buf, key, key_len);
8209203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
8210203945Sweongyo	if (index >= per_sta_keys_start)
8211203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
8212203945Sweongyo
8213203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
8214203945Sweongyo}
8215203945Sweongyo
8216203945Sweongyostatic void
8217203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
8218203945Sweongyo{
8219203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
8220203945Sweongyo	uint8_t start = 8;
8221203945Sweongyo
8222203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8223203945Sweongyo		start = 4;
8224203945Sweongyo
8225203945Sweongyo	KASSERT(index >= start,
8226203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8227203945Sweongyo	index -= start;
8228203945Sweongyo
8229203945Sweongyo	if (addr) {
8230203945Sweongyo		addrtmp[0] = addr[0];
8231203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
8232203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
8233203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
8234203945Sweongyo		addrtmp[1] = addr[4];
8235203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
8236203945Sweongyo	}
8237203945Sweongyo
8238203945Sweongyo	if (mac->mac_sd->sd_id.sd_rev >= 5) {
8239203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
8240203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
8241203945Sweongyo	} else {
8242203945Sweongyo		if (index >= 8) {
8243203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
8244203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
8245203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
8246203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
8247203945Sweongyo		}
8248203945Sweongyo	}
8249203945Sweongyo}
8250203945Sweongyo
8251203945Sweongyostatic void
8252203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8253203945Sweongyo    const uint8_t *key)
8254203945Sweongyo{
8255203945Sweongyo	unsigned int i;
8256203945Sweongyo	uint32_t offset;
8257203945Sweongyo	uint16_t kidx, value;
8258203945Sweongyo
8259203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
8260203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
8261203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
8262203945Sweongyo
8263203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
8264203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
8265203945Sweongyo		value = key[i];
8266203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
8267203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
8268203945Sweongyo	}
8269203945Sweongyo}
8270203945Sweongyo
8271203945Sweongyostatic void
8272203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
8273203945Sweongyo{
8274203945Sweongyo
8275203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8276203945Sweongyo	if (mac->mac_phy.exit != NULL)
8277203945Sweongyo		mac->mac_phy.exit(mac);
8278203945Sweongyo}
8279203945Sweongyo
8280203945Sweongyostatic void
8281203945Sweongyobwn_dma_free(struct bwn_mac *mac)
8282203945Sweongyo{
8283203945Sweongyo	struct bwn_dma *dma;
8284203945Sweongyo
8285203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
8286203945Sweongyo		return;
8287203945Sweongyo	dma = &mac->mac_method.dma;
8288203945Sweongyo
8289203945Sweongyo	bwn_dma_ringfree(&dma->rx);
8290203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
8291203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
8292203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
8293203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
8294203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
8295203945Sweongyo}
8296203945Sweongyo
8297203945Sweongyostatic void
8298203945Sweongyobwn_core_stop(struct bwn_mac *mac)
8299203945Sweongyo{
8300203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8301203945Sweongyo
8302203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8303203945Sweongyo
8304203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8305203945Sweongyo		return;
8306203945Sweongyo
8307203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
8308203945Sweongyo	callout_stop(&sc->sc_task_ch);
8309203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
8310203945Sweongyo	sc->sc_watchdog_timer = 0;
8311203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8312203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
8313203945Sweongyo	bwn_mac_suspend(mac);
8314203945Sweongyo
8315203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
8316203945Sweongyo}
8317203945Sweongyo
8318203945Sweongyostatic int
8319203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
8320203945Sweongyo{
8321203945Sweongyo	struct bwn_mac *up_dev = NULL;
8322203945Sweongyo	struct bwn_mac *down_dev;
8323203945Sweongyo	struct bwn_mac *mac;
8324203945Sweongyo	int err, status;
8325203945Sweongyo	uint8_t gmode;
8326203945Sweongyo
8327203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8328203945Sweongyo
8329203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
8330203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
8331203945Sweongyo		    mac->mac_phy.supports_2ghz) {
8332203945Sweongyo			up_dev = mac;
8333203945Sweongyo			gmode = 1;
8334203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
8335203945Sweongyo		    mac->mac_phy.supports_5ghz) {
8336203945Sweongyo			up_dev = mac;
8337203945Sweongyo			gmode = 0;
8338203945Sweongyo		} else {
8339203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8340203945Sweongyo			return (EINVAL);
8341203945Sweongyo		}
8342203945Sweongyo		if (up_dev != NULL)
8343203945Sweongyo			break;
8344203945Sweongyo	}
8345203945Sweongyo	if (up_dev == NULL) {
8346203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
8347203945Sweongyo		return (ENODEV);
8348203945Sweongyo	}
8349203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
8350203945Sweongyo		return (0);
8351203945Sweongyo
8352203945Sweongyo	device_printf(sc->sc_dev, "switching to %s-GHz band\n",
8353203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8354203945Sweongyo
8355203945Sweongyo	down_dev = sc->sc_curmac;;
8356203945Sweongyo	status = down_dev->mac_status;
8357203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8358203945Sweongyo		bwn_core_stop(down_dev);
8359203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
8360203945Sweongyo		bwn_core_exit(down_dev);
8361203945Sweongyo
8362203945Sweongyo	if (down_dev != up_dev)
8363203945Sweongyo		bwn_phy_reset(down_dev);
8364203945Sweongyo
8365203945Sweongyo	up_dev->mac_phy.gmode = gmode;
8366203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
8367203945Sweongyo		err = bwn_core_init(up_dev);
8368203945Sweongyo		if (err) {
8369203945Sweongyo			device_printf(sc->sc_dev,
8370203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
8371203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8372203945Sweongyo			goto fail;
8373203945Sweongyo		}
8374203945Sweongyo	}
8375203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8376203945Sweongyo		bwn_core_start(up_dev);
8377203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
8378203945Sweongyo	sc->sc_curmac = up_dev;
8379203945Sweongyo
8380203945Sweongyo	return (0);
8381203945Sweongyofail:
8382203945Sweongyo	sc->sc_curmac = NULL;
8383203945Sweongyo	return (err);
8384203945Sweongyo}
8385203945Sweongyo
8386203945Sweongyostatic void
8387203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
8388203945Sweongyo{
8389203945Sweongyo
8390203945Sweongyo	bwn_mac_suspend(mac);
8391203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
8392203945Sweongyo	mac->mac_phy.rf_on = 1;
8393203945Sweongyo	bwn_mac_enable(mac);
8394203945Sweongyo}
8395203945Sweongyo
8396203945Sweongyostatic void
8397203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
8398203945Sweongyo{
8399203945Sweongyo
8400203945Sweongyo	bwn_mac_suspend(mac);
8401203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8402203945Sweongyo	mac->mac_phy.rf_on = 0;
8403203945Sweongyo	bwn_mac_enable(mac);
8404203945Sweongyo}
8405203945Sweongyo
8406203945Sweongyostatic void
8407203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
8408203945Sweongyo{
8409203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
8410203945Sweongyo
8411203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW,
8412203945Sweongyo	    ((siba_read_4(sd, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
8413203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
8414203945Sweongyo	DELAY(1000);
8415203945Sweongyo	siba_write_4(sd, SIBA_TGSLOW,
8416203945Sweongyo	    (siba_read_4(sd, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC) |
8417203945Sweongyo	    BWN_TGSLOW_PHYRESET);
8418203945Sweongyo	DELAY(1000);
8419203945Sweongyo}
8420203945Sweongyo
8421203945Sweongyostatic int
8422203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
8423203945Sweongyo{
8424203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
8425203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
8426203945Sweongyo	struct ifnet *ifp = ic->ic_ifp;
8427203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
8428203945Sweongyo	struct bwn_softc *sc = ifp->if_softc;
8429203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
8430203945Sweongyo	int error;
8431203945Sweongyo
8432203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
8433203945Sweongyo	    ieee80211_state_name[vap->iv_state],
8434203945Sweongyo	    ieee80211_state_name[nstate]);
8435203945Sweongyo
8436203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
8437203945Sweongyo	if (error != 0)
8438203945Sweongyo		return (error);
8439203945Sweongyo
8440203945Sweongyo	BWN_LOCK(sc);
8441203945Sweongyo
8442203945Sweongyo	bwn_led_newstate(mac, nstate);
8443203945Sweongyo
8444203945Sweongyo	/*
8445203945Sweongyo	 * Clear the BSSID when we stop a STA
8446203945Sweongyo	 */
8447203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
8448203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
8449203945Sweongyo			/*
8450203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
8451203945Sweongyo			 * the same AP, this will reinialize things
8452203945Sweongyo			 * correctly...
8453203945Sweongyo			 */
8454203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
8455203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
8456203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
8457203945Sweongyo				bwn_set_macaddr(mac);
8458203945Sweongyo			}
8459203945Sweongyo		}
8460203945Sweongyo	}
8461203945Sweongyo
8462203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR) {
8463203945Sweongyo		/* XXX nothing to do? */
8464203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
8465203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
8466203945Sweongyo		memcpy(sc->sc_macaddr, IF_LLADDR(ifp), IEEE80211_ADDR_LEN);
8467203945Sweongyo		bwn_set_opmode(mac);
8468203945Sweongyo		bwn_set_pretbtt(mac);
8469203945Sweongyo		bwn_spu_setdelay(mac, 0);
8470203945Sweongyo		bwn_set_macaddr(mac);
8471203945Sweongyo	}
8472203945Sweongyo
8473203945Sweongyo	BWN_UNLOCK(sc);
8474203945Sweongyo
8475203945Sweongyo	return (error);
8476203945Sweongyo}
8477203945Sweongyo
8478203945Sweongyostatic void
8479203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
8480203945Sweongyo{
8481203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8482203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8483203945Sweongyo	uint16_t pretbtt;
8484203945Sweongyo
8485203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8486203945Sweongyo		pretbtt = 2;
8487203945Sweongyo	else
8488203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
8489203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
8490203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
8491203945Sweongyo}
8492203945Sweongyo
8493203945Sweongyostatic int
8494203945Sweongyobwn_intr(void *arg)
8495203945Sweongyo{
8496203945Sweongyo	struct bwn_mac *mac = arg;
8497203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8498203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
8499203945Sweongyo	uint32_t reason;
8500203945Sweongyo
8501203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED || siba->siba_invalid)
8502203945Sweongyo		return (FILTER_STRAY);
8503203945Sweongyo
8504203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
8505203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
8506203945Sweongyo		return (FILTER_STRAY);
8507203945Sweongyo	reason &= mac->mac_intr_mask;
8508203945Sweongyo	if (reason == 0)
8509203945Sweongyo		return (FILTER_HANDLED);
8510203945Sweongyo
8511203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
8512203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
8513203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
8514203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
8515203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
8516203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
8517203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
8518203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
8519203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
8520203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
8521203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
8522203945Sweongyo
8523203945Sweongyo	/* Disable interrupts. */
8524203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8525203945Sweongyo
8526203945Sweongyo	mac->mac_reason_intr = reason;
8527203945Sweongyo
8528203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8529203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8530203945Sweongyo
8531203945Sweongyo	taskqueue_enqueue_fast(sc->sc_tq, &mac->mac_intrtask);
8532203945Sweongyo	return (FILTER_HANDLED);
8533203945Sweongyo}
8534203945Sweongyo
8535203945Sweongyostatic void
8536203945Sweongyobwn_intrtask(void *arg, int npending)
8537203945Sweongyo{
8538203945Sweongyo	struct bwn_mac *mac = arg;
8539203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8540203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8541203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
8542203945Sweongyo	uint32_t merged = 0;
8543203945Sweongyo	int i, tx = 0, rx = 0;
8544203945Sweongyo
8545203945Sweongyo	BWN_LOCK(sc);
8546203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED || siba->siba_invalid) {
8547203945Sweongyo		BWN_UNLOCK(sc);
8548203945Sweongyo		return;
8549203945Sweongyo	}
8550203945Sweongyo
8551203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
8552203945Sweongyo		merged |= mac->mac_reason[i];
8553203945Sweongyo
8554203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
8555203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
8556203945Sweongyo
8557203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
8558203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
8559203945Sweongyo		mac->mac_phy.txerrors--;
8560203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
8561203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
8562203945Sweongyo			bwn_restart(mac, "PHY TX errors");
8563203945Sweongyo		}
8564203945Sweongyo	}
8565203945Sweongyo
8566203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
8567203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
8568203945Sweongyo			device_printf(sc->sc_dev,
8569203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
8570203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8571203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8572203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8573203945Sweongyo			bwn_restart(mac, "DMA error");
8574203945Sweongyo			BWN_UNLOCK(sc);
8575203945Sweongyo			return;
8576203945Sweongyo		}
8577203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
8578203945Sweongyo			device_printf(sc->sc_dev,
8579203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
8580203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8581203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8582203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8583203945Sweongyo		}
8584203945Sweongyo	}
8585203945Sweongyo
8586203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
8587203945Sweongyo		bwn_intr_ucode_debug(mac);
8588203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
8589203945Sweongyo		bwn_intr_tbtt_indication(mac);
8590203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
8591203945Sweongyo		bwn_intr_atim_end(mac);
8592203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
8593203945Sweongyo		bwn_intr_beacon(mac);
8594203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
8595203945Sweongyo		bwn_intr_pmq(mac);
8596203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
8597203945Sweongyo		bwn_intr_noise(mac);
8598203945Sweongyo
8599203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
8600203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
8601203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
8602203945Sweongyo			rx = 1;
8603203945Sweongyo		}
8604203945Sweongyo	} else
8605203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
8606203945Sweongyo
8607203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8608203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8609203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8610203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8611203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8612203945Sweongyo
8613203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
8614203945Sweongyo		bwn_intr_txeof(mac);
8615203945Sweongyo		tx = 1;
8616203945Sweongyo	}
8617203945Sweongyo
8618203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
8619203945Sweongyo
8620203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
8621203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
8622203945Sweongyo
8623203945Sweongyo		if (tx && rx) {
8624203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
8625203945Sweongyo				evt = BWN_LED_EVENT_RX;
8626203945Sweongyo			else
8627203945Sweongyo				evt = BWN_LED_EVENT_TX;
8628203945Sweongyo		} else if (tx) {
8629203945Sweongyo			evt = BWN_LED_EVENT_TX;
8630203945Sweongyo		} else if (rx) {
8631203945Sweongyo			evt = BWN_LED_EVENT_RX;
8632203945Sweongyo		} else if (rx == 0) {
8633203945Sweongyo			evt = BWN_LED_EVENT_POLL;
8634203945Sweongyo		}
8635203945Sweongyo
8636203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
8637203945Sweongyo			bwn_led_event(mac, evt);
8638203945Sweongyo       }
8639203945Sweongyo
8640203945Sweongyo	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
8641203945Sweongyo		if (!IFQ_IS_EMPTY(&ifp->if_snd))
8642203945Sweongyo			bwn_start_locked(ifp);
8643203945Sweongyo	}
8644203945Sweongyo
8645203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8646203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8647203945Sweongyo
8648203945Sweongyo	BWN_UNLOCK(sc);
8649203945Sweongyo}
8650203945Sweongyo
8651203945Sweongyostatic void
8652203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
8653203945Sweongyo{
8654203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8655203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
8656203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
8657203945Sweongyo
8658203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
8659203945Sweongyo		return;
8660203945Sweongyo
8661203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
8662203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
8663203945Sweongyo}
8664203945Sweongyo
8665203945Sweongyostatic void
8666203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
8667203945Sweongyo{
8668203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8669203945Sweongyo	uint16_t reason;
8670203945Sweongyo
8671203945Sweongyo	if (mac->mac_fw.opensource == 0)
8672203945Sweongyo		return;
8673203945Sweongyo
8674203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
8675203945Sweongyo	switch (reason) {
8676203945Sweongyo	case BWN_DEBUGINTR_PANIC:
8677203945Sweongyo		bwn_handle_fwpanic(mac);
8678203945Sweongyo		break;
8679203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
8680203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
8681203945Sweongyo		break;
8682203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
8683203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
8684203945Sweongyo		break;
8685203945Sweongyo	case BWN_DEBUGINTR_MARKER:
8686203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
8687203945Sweongyo		break;
8688203945Sweongyo	default:
8689203945Sweongyo		device_printf(sc->sc_dev,
8690203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
8691203945Sweongyo	}
8692203945Sweongyo
8693203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
8694203945Sweongyo	    BWN_DEBUGINTR_ACK);
8695203945Sweongyo}
8696203945Sweongyo
8697203945Sweongyostatic void
8698203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
8699203945Sweongyo{
8700203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8701203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8702203945Sweongyo
8703203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
8704203945Sweongyo		bwn_psctl(mac, 0);
8705203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8706203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
8707203945Sweongyo}
8708203945Sweongyo
8709203945Sweongyostatic void
8710203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
8711203945Sweongyo{
8712203945Sweongyo
8713203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
8714203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
8715203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
8716203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
8717203945Sweongyo	}
8718203945Sweongyo}
8719203945Sweongyo
8720203945Sweongyostatic void
8721203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
8722203945Sweongyo{
8723203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8724203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
8725203945Sweongyo	uint32_t cmd, beacon0, beacon1;
8726203945Sweongyo
8727203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
8728203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
8729203945Sweongyo		return;
8730203945Sweongyo
8731203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
8732203945Sweongyo
8733203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
8734203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
8735203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
8736203945Sweongyo
8737203945Sweongyo	if (beacon0 && beacon1) {
8738203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
8739203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
8740203945Sweongyo		return;
8741203945Sweongyo	}
8742203945Sweongyo
8743203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
8744203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
8745203945Sweongyo		bwn_load_beacon0(mac);
8746203945Sweongyo		bwn_load_beacon1(mac);
8747203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
8748203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
8749203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8750203945Sweongyo	} else {
8751203945Sweongyo		if (!beacon0) {
8752203945Sweongyo			bwn_load_beacon0(mac);
8753203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8754203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
8755203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8756203945Sweongyo		} else if (!beacon1) {
8757203945Sweongyo			bwn_load_beacon1(mac);
8758203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8759203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
8760203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8761203945Sweongyo		}
8762203945Sweongyo	}
8763203945Sweongyo}
8764203945Sweongyo
8765203945Sweongyostatic void
8766203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
8767203945Sweongyo{
8768203945Sweongyo	uint32_t tmp;
8769203945Sweongyo
8770203945Sweongyo	while (1) {
8771203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
8772203945Sweongyo		if (!(tmp & 0x00000008))
8773203945Sweongyo			break;
8774203945Sweongyo	}
8775203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
8776203945Sweongyo}
8777203945Sweongyo
8778203945Sweongyostatic void
8779203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
8780203945Sweongyo{
8781203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
8782203945Sweongyo	uint16_t tmp;
8783203945Sweongyo	uint8_t noise[4];
8784203945Sweongyo	uint8_t i, j;
8785203945Sweongyo	int32_t average;
8786203945Sweongyo
8787203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
8788203945Sweongyo		return;
8789203945Sweongyo
8790203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
8791203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
8792203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
8793203945Sweongyo	    noise[3] == 0x7f)
8794203945Sweongyo		goto new;
8795203945Sweongyo
8796203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
8797203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8798203945Sweongyo	i = mac->mac_noise.noi_nsamples;
8799203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
8800203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
8801203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
8802203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
8803203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
8804203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
8805203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
8806203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
8807203945Sweongyo	mac->mac_noise.noi_nsamples++;
8808203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
8809203945Sweongyo		average = 0;
8810203945Sweongyo		for (i = 0; i < 8; i++) {
8811203945Sweongyo			for (j = 0; j < 4; j++)
8812203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
8813203945Sweongyo		}
8814203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
8815203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
8816203945Sweongyo		if (tmp >= 8)
8817203945Sweongyo			average += 2;
8818203945Sweongyo		else
8819203945Sweongyo			average -= 25;
8820203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
8821203945Sweongyo
8822203945Sweongyo		mac->mac_stats.link_noise = average;
8823203945Sweongyo		mac->mac_noise.noi_running = 0;
8824203945Sweongyo		return;
8825203945Sweongyo	}
8826203945Sweongyonew:
8827203945Sweongyo	bwn_noise_gensample(mac);
8828203945Sweongyo}
8829203945Sweongyo
8830203945Sweongyostatic int
8831203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
8832203945Sweongyo{
8833203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
8834203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8835203945Sweongyo	unsigned int i;
8836203945Sweongyo
8837203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8838203945Sweongyo
8839203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8840203945Sweongyo		return (0);
8841203945Sweongyo
8842203945Sweongyo	for (i = 0; i < 5000; i++) {
8843203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
8844203945Sweongyo			break;
8845203945Sweongyo	}
8846203945Sweongyo	if (i >= 5000)
8847203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
8848203945Sweongyo	return ((i > 0) ? 1 : 0);
8849203945Sweongyo}
8850203945Sweongyo
8851203945Sweongyostatic void
8852203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
8853203945Sweongyo{
8854203945Sweongyo	int slot, curslot;
8855203945Sweongyo
8856203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
8857203945Sweongyo	curslot = dr->get_curslot(dr);
8858203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
8859203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8860203945Sweongyo
8861203945Sweongyo	slot = dr->dr_curslot;
8862203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
8863203945Sweongyo		bwn_dma_rxeof(dr, &slot);
8864203945Sweongyo
8865203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
8866203945Sweongyo	    BUS_DMASYNC_PREWRITE);
8867203945Sweongyo
8868203945Sweongyo	dr->set_curslot(dr, slot);
8869203945Sweongyo	dr->dr_curslot = slot;
8870203945Sweongyo}
8871203945Sweongyo
8872203945Sweongyostatic void
8873203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
8874203945Sweongyo{
8875203945Sweongyo	struct bwn_txstatus stat;
8876203945Sweongyo	uint32_t stat0, stat1;
8877203945Sweongyo	uint16_t tmp;
8878203945Sweongyo
8879203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8880203945Sweongyo
8881203945Sweongyo	while (1) {
8882203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
8883203945Sweongyo		if (!(stat0 & 0x00000001))
8884203945Sweongyo			break;
8885203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
8886203945Sweongyo
8887203945Sweongyo		stat.cookie = (stat0 >> 16);
8888203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
8889203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
8890203945Sweongyo		tmp = (stat0 & 0x0000ffff);
8891203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
8892203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
8893203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
8894203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
8895203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
8896203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
8897203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
8898203945Sweongyo
8899203945Sweongyo		bwn_handle_txeof(mac, &stat);
8900203945Sweongyo	}
8901203945Sweongyo}
8902203945Sweongyo
8903203945Sweongyostatic void
8904203945Sweongyobwn_hwreset(void *arg, int npending)
8905203945Sweongyo{
8906203945Sweongyo	struct bwn_mac *mac = arg;
8907203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8908203945Sweongyo	int error = 0;
8909203945Sweongyo	int prev_status;
8910203945Sweongyo
8911203945Sweongyo	BWN_LOCK(sc);
8912203945Sweongyo
8913203945Sweongyo	prev_status = mac->mac_status;
8914203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8915203945Sweongyo		bwn_core_stop(mac);
8916203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
8917203945Sweongyo		bwn_core_exit(mac);
8918203945Sweongyo
8919203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
8920203945Sweongyo		error = bwn_core_init(mac);
8921203945Sweongyo		if (error)
8922203945Sweongyo			goto out;
8923203945Sweongyo	}
8924203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8925203945Sweongyo		bwn_core_start(mac);
8926203945Sweongyoout:
8927203945Sweongyo	if (error) {
8928203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
8929203945Sweongyo		sc->sc_curmac = NULL;
8930203945Sweongyo	}
8931203945Sweongyo	BWN_UNLOCK(sc);
8932203945Sweongyo}
8933203945Sweongyo
8934203945Sweongyostatic void
8935203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
8936203945Sweongyo{
8937203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8938203945Sweongyo	uint16_t reason;
8939203945Sweongyo
8940203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
8941203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
8942203945Sweongyo
8943203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
8944203945Sweongyo		bwn_restart(mac, "ucode panic");
8945203945Sweongyo}
8946203945Sweongyo
8947203945Sweongyostatic void
8948203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
8949203945Sweongyo{
8950203945Sweongyo
8951203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8952203945Sweongyo}
8953203945Sweongyo
8954203945Sweongyostatic void
8955203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
8956203945Sweongyo{
8957203945Sweongyo
8958203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8959203945Sweongyo}
8960203945Sweongyo
8961203945Sweongyostatic uint32_t
8962203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
8963203945Sweongyo{
8964203945Sweongyo	uint32_t val = 0;
8965203945Sweongyo
8966203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
8967203945Sweongyo	val <<= 16;
8968203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
8969203945Sweongyo
8970203945Sweongyo	return (val);
8971203945Sweongyo}
8972203945Sweongyo
8973203945Sweongyostatic void
8974203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
8975203945Sweongyo{
8976203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
8977203945Sweongyo
8978203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
8979203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
8980203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
8981203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
8982203945Sweongyo}
8983203945Sweongyo
8984203945Sweongyostatic int
8985203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
8986203945Sweongyo{
8987203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
8988203945Sweongyo
8989203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8990203945Sweongyo
8991203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
8992203945Sweongyo}
8993203945Sweongyo
8994203945Sweongyostatic int
8995203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
8996203945Sweongyo{
8997203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
8998203945Sweongyo
8999203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
9000203945Sweongyo
9001203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
9002203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
9003203945Sweongyo	if (slot == dr->dr_numslots - 1)
9004203945Sweongyo		return (0);
9005203945Sweongyo	return (slot + 1);
9006203945Sweongyo}
9007203945Sweongyo
9008203945Sweongyostatic void
9009203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
9010203945Sweongyo{
9011203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
9012203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9013203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9014203945Sweongyo	struct bwn_dmadesc_generic *desc;
9015203945Sweongyo	struct bwn_dmadesc_meta *meta;
9016203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
9017203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9018203945Sweongyo	struct mbuf *m;
9019203945Sweongyo	uint32_t macstat;
9020203945Sweongyo	int32_t tmp;
9021203945Sweongyo	int cnt = 0;
9022203945Sweongyo	uint16_t len;
9023203945Sweongyo
9024203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
9025203945Sweongyo
9026203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
9027203945Sweongyo	m = meta->mt_m;
9028203945Sweongyo
9029203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
9030203945Sweongyo		ifp->if_ierrors++;
9031203945Sweongyo		return;
9032203945Sweongyo	}
9033203945Sweongyo
9034203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
9035203945Sweongyo	len = le16toh(rxhdr->frame_len);
9036203945Sweongyo	if (len <= 0) {
9037203945Sweongyo		ifp->if_ierrors++;
9038203945Sweongyo		return;
9039203945Sweongyo	}
9040203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
9041203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
9042203945Sweongyo		bwn_dma_set_redzone(dr, m);
9043203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9044203945Sweongyo		    BUS_DMASYNC_PREWRITE);
9045203945Sweongyo		return;
9046203945Sweongyo	}
9047203945Sweongyo	if (len > dr->dr_rx_bufsize) {
9048203945Sweongyo		tmp = len;
9049203945Sweongyo		while (1) {
9050203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
9051203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
9052203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9053203945Sweongyo			    BUS_DMASYNC_PREWRITE);
9054203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
9055203945Sweongyo			cnt++;
9056203945Sweongyo			tmp -= dr->dr_rx_bufsize;
9057203945Sweongyo			if (tmp <= 0)
9058203945Sweongyo				break;
9059203945Sweongyo		}
9060203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
9061203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
9062203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
9063203945Sweongyo		return;
9064203945Sweongyo	}
9065203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9066203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9067203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9068203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
9069203945Sweongyo			return;
9070203945Sweongyo		}
9071203945Sweongyo	}
9072203945Sweongyo
9073203945Sweongyo	m->m_pkthdr.rcvif = ifp;
9074203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
9075203945Sweongyo	m_adj(m, dr->dr_frameoffset);
9076203945Sweongyo
9077203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
9078203945Sweongyo}
9079203945Sweongyo
9080203945Sweongyostatic void
9081203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
9082203945Sweongyo{
9083203945Sweongyo	struct bwn_dma_ring *dr;
9084203945Sweongyo	struct bwn_dmadesc_generic *desc;
9085203945Sweongyo	struct bwn_dmadesc_meta *meta;
9086203945Sweongyo	struct bwn_node *bn;
9087203945Sweongyo	struct bwn_pio_txqueue *tq;
9088203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9089203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9090203945Sweongyo	struct ieee80211_node *ni;
9091203945Sweongyo	int slot;
9092203945Sweongyo
9093203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
9094203945Sweongyo
9095203945Sweongyo	if (status->im)
9096203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
9097203945Sweongyo	if (status->ampdu)
9098203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
9099203945Sweongyo	if (status->rtscnt) {
9100203945Sweongyo		if (status->rtscnt == 0xf)
9101203945Sweongyo			device_printf(sc->sc_dev, "TODO: RTS fail\n");
9102203945Sweongyo		else
9103203945Sweongyo			device_printf(sc->sc_dev, "TODO: RTS ok\n");
9104203945Sweongyo	}
9105203945Sweongyo
9106203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
9107203945Sweongyo		if (status->ack) {
9108203945Sweongyo			dr = bwn_dma_parse_cookie(mac, status,
9109203945Sweongyo			    status->cookie, &slot);
9110203945Sweongyo			if (dr == NULL) {
9111203945Sweongyo				device_printf(sc->sc_dev,
9112203945Sweongyo				    "failed to parse cookie\n");
9113203945Sweongyo				return;
9114203945Sweongyo			}
9115203945Sweongyo			while (1) {
9116203945Sweongyo				dr->getdesc(dr, slot, &desc, &meta);
9117203945Sweongyo				if (meta->mt_islast) {
9118203945Sweongyo					ni = meta->mt_ni;
9119203945Sweongyo					bn = (struct bwn_node *)ni;
9120203945Sweongyo					ieee80211_amrr_tx_complete(&bn->bn_amn,
9121203945Sweongyo					    status->ack, 0);
9122203945Sweongyo					break;
9123203945Sweongyo				}
9124203945Sweongyo				slot = bwn_dma_nextslot(dr, slot);
9125203945Sweongyo			}
9126203945Sweongyo		}
9127203945Sweongyo		bwn_dma_handle_txeof(mac, status);
9128203945Sweongyo	} else {
9129203945Sweongyo		if (status->ack) {
9130203945Sweongyo			tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9131203945Sweongyo			if (tq == NULL) {
9132203945Sweongyo				device_printf(sc->sc_dev,
9133203945Sweongyo				    "failed to parse cookie\n");
9134203945Sweongyo				return;
9135203945Sweongyo			}
9136203945Sweongyo			ni = tp->tp_ni;
9137203945Sweongyo			bn = (struct bwn_node *)ni;
9138203945Sweongyo			ieee80211_amrr_tx_complete(&bn->bn_amn, status->ack, 0);
9139203945Sweongyo		}
9140203945Sweongyo		bwn_pio_handle_txeof(mac, status);
9141203945Sweongyo	}
9142203945Sweongyo
9143203945Sweongyo	bwn_phy_txpower_check(mac, 0);
9144203945Sweongyo}
9145203945Sweongyo
9146203945Sweongyostatic uint8_t
9147203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
9148203945Sweongyo{
9149203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
9150203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9151203945Sweongyo	struct bwn_rxhdr4 rxhdr;
9152203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9153203945Sweongyo	struct mbuf *m;
9154203945Sweongyo	uint32_t ctl32, macstat, v32;
9155203945Sweongyo	unsigned int i, padding;
9156203945Sweongyo	uint16_t ctl16, len, v16;
9157203945Sweongyo	unsigned char *mp;
9158203945Sweongyo	char *data;
9159203945Sweongyo
9160203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
9161203945Sweongyo
9162203945Sweongyo	if (prq->prq_rev >= 8) {
9163203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9164203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
9165203945Sweongyo			return (0);
9166203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9167203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
9168203945Sweongyo		for (i = 0; i < 10; i++) {
9169203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
9170203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
9171203945Sweongyo				goto ready;
9172203945Sweongyo			DELAY(10);
9173203945Sweongyo		}
9174203945Sweongyo	} else {
9175203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9176203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
9177203945Sweongyo			return (0);
9178203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
9179203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
9180203945Sweongyo		for (i = 0; i < 10; i++) {
9181203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
9182203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
9183203945Sweongyo				goto ready;
9184203945Sweongyo			DELAY(10);
9185203945Sweongyo		}
9186203945Sweongyo	}
9187203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
9188203945Sweongyo	return (1);
9189203945Sweongyoready:
9190203945Sweongyo	if (prq->prq_rev >= 8)
9191203945Sweongyo		siba_read_multi_4(mac->mac_sd, &rxhdr, sizeof(rxhdr),
9192203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9193203945Sweongyo	else
9194203945Sweongyo		siba_read_multi_2(mac->mac_sd, &rxhdr, sizeof(rxhdr),
9195203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9196203945Sweongyo	len = le16toh(rxhdr.frame_len);
9197203945Sweongyo	if (len > 0x700) {
9198203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
9199203945Sweongyo		goto error;
9200203945Sweongyo	}
9201203945Sweongyo	if (len == 0) {
9202203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
9203203945Sweongyo		goto error;
9204203945Sweongyo	}
9205203945Sweongyo
9206203945Sweongyo	macstat = le32toh(rxhdr.mac_status);
9207203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9208203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9209203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
9210203945Sweongyo			goto error;
9211203945Sweongyo		}
9212203945Sweongyo	}
9213203945Sweongyo
9214203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9215203945Sweongyo	KASSERT(len + padding <= MCLBYTES, ("too big..\n"));
9216203945Sweongyo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
9217203945Sweongyo	if (m == NULL) {
9218203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
9219203945Sweongyo		goto error;
9220203945Sweongyo	}
9221203945Sweongyo	mp = mtod(m, unsigned char *);
9222203945Sweongyo	if (prq->prq_rev >= 8) {
9223203945Sweongyo		siba_read_multi_4(mac->mac_sd, mp + padding, (len & ~3),
9224203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9225203945Sweongyo		if (len & 3) {
9226203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
9227203945Sweongyo			data = &(mp[len + padding - 1]);
9228203945Sweongyo			switch (len & 3) {
9229203945Sweongyo			case 3:
9230203945Sweongyo				*data = (v32 >> 16);
9231203945Sweongyo				data--;
9232203945Sweongyo			case 2:
9233203945Sweongyo				*data = (v32 >> 8);
9234203945Sweongyo				data--;
9235203945Sweongyo			case 1:
9236203945Sweongyo				*data = v32;
9237203945Sweongyo			}
9238203945Sweongyo		}
9239203945Sweongyo	} else {
9240203945Sweongyo		siba_read_multi_2(mac->mac_sd, mp + padding, (len & ~1),
9241203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9242203945Sweongyo		if (len & 1) {
9243203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
9244203945Sweongyo			mp[len + padding - 1] = v16;
9245203945Sweongyo		}
9246203945Sweongyo	}
9247203945Sweongyo
9248203945Sweongyo	m->m_pkthdr.rcvif = ifp;
9249203945Sweongyo	m->m_len = m->m_pkthdr.len = len + padding;
9250203945Sweongyo
9251203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
9252203945Sweongyo
9253203945Sweongyo	return (1);
9254203945Sweongyoerror:
9255203945Sweongyo	if (prq->prq_rev >= 8)
9256203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9257203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
9258203945Sweongyo	else
9259203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
9260203945Sweongyo	return (1);
9261203945Sweongyo}
9262203945Sweongyo
9263203945Sweongyostatic int
9264203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
9265203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
9266203945Sweongyo{
9267203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
9268203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9269203945Sweongyo	struct bwn_rxhdr4 *hdr;
9270203945Sweongyo	bus_dmamap_t map;
9271203945Sweongyo	bus_addr_t paddr;
9272203945Sweongyo	struct mbuf *m;
9273203945Sweongyo	int error;
9274203945Sweongyo
9275203945Sweongyo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
9276203945Sweongyo	if (m == NULL) {
9277203945Sweongyo		error = ENOBUFS;
9278203945Sweongyo
9279203945Sweongyo		/*
9280203945Sweongyo		 * If the NIC is up and running, we need to:
9281203945Sweongyo		 * - Clear RX buffer's header.
9282203945Sweongyo		 * - Restore RX descriptor settings.
9283203945Sweongyo		 */
9284203945Sweongyo		if (init)
9285203945Sweongyo			return (error);
9286203945Sweongyo		else
9287203945Sweongyo			goto back;
9288203945Sweongyo	}
9289203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
9290203945Sweongyo
9291203945Sweongyo	bwn_dma_set_redzone(dr, m);
9292203945Sweongyo
9293203945Sweongyo	/*
9294203945Sweongyo	 * Try to load RX buf into temporary DMA map
9295203945Sweongyo	 */
9296203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
9297203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
9298203945Sweongyo	if (error) {
9299203945Sweongyo		m_freem(m);
9300203945Sweongyo
9301203945Sweongyo		/*
9302203945Sweongyo		 * See the comment above
9303203945Sweongyo		 */
9304203945Sweongyo		if (init)
9305203945Sweongyo			return (error);
9306203945Sweongyo		else
9307203945Sweongyo			goto back;
9308203945Sweongyo	}
9309203945Sweongyo
9310203945Sweongyo	if (!init)
9311203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
9312203945Sweongyo	meta->mt_m = m;
9313203945Sweongyo	meta->mt_paddr = paddr;
9314203945Sweongyo
9315203945Sweongyo	/*
9316203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
9317203945Sweongyo	 */
9318203945Sweongyo	map = meta->mt_dmap;
9319203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
9320203945Sweongyo	dr->dr_spare_dmap = map;
9321203945Sweongyo
9322203945Sweongyoback:
9323203945Sweongyo	/*
9324203945Sweongyo	 * Clear RX buf header
9325203945Sweongyo	 */
9326203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
9327203945Sweongyo	bzero(hdr, sizeof(*hdr));
9328203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9329203945Sweongyo	    BUS_DMASYNC_PREWRITE);
9330203945Sweongyo
9331203945Sweongyo	/*
9332203945Sweongyo	 * Setup RX buf descriptor
9333203945Sweongyo	 */
9334203945Sweongyo	dr->setdesc(dr, desc, paddr, meta->mt_m->m_len -
9335203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
9336203945Sweongyo	return (error);
9337203945Sweongyo}
9338203945Sweongyo
9339203945Sweongyostatic void
9340203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
9341203945Sweongyo		 bus_size_t mapsz __unused, int error)
9342203945Sweongyo{
9343203945Sweongyo
9344203945Sweongyo	if (!error) {
9345203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
9346203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
9347203945Sweongyo	}
9348203945Sweongyo}
9349203945Sweongyo
9350203945Sweongyostatic int
9351203945Sweongyobwn_hwrate2ieeerate(int rate)
9352203945Sweongyo{
9353203945Sweongyo
9354203945Sweongyo	switch (rate) {
9355203945Sweongyo	case BWN_CCK_RATE_1MB:
9356203945Sweongyo		return (2);
9357203945Sweongyo	case BWN_CCK_RATE_2MB:
9358203945Sweongyo		return (4);
9359203945Sweongyo	case BWN_CCK_RATE_5MB:
9360203945Sweongyo		return (11);
9361203945Sweongyo	case BWN_CCK_RATE_11MB:
9362203945Sweongyo		return (22);
9363203945Sweongyo	case BWN_OFDM_RATE_6MB:
9364203945Sweongyo		return (12);
9365203945Sweongyo	case BWN_OFDM_RATE_9MB:
9366203945Sweongyo		return (18);
9367203945Sweongyo	case BWN_OFDM_RATE_12MB:
9368203945Sweongyo		return (24);
9369203945Sweongyo	case BWN_OFDM_RATE_18MB:
9370203945Sweongyo		return (36);
9371203945Sweongyo	case BWN_OFDM_RATE_24MB:
9372203945Sweongyo		return (48);
9373203945Sweongyo	case BWN_OFDM_RATE_36MB:
9374203945Sweongyo		return (72);
9375203945Sweongyo	case BWN_OFDM_RATE_48MB:
9376203945Sweongyo		return (96);
9377203945Sweongyo	case BWN_OFDM_RATE_54MB:
9378203945Sweongyo		return (108);
9379203945Sweongyo	default:
9380203945Sweongyo		printf("Ooops\n");
9381203945Sweongyo		return (0);
9382203945Sweongyo	}
9383203945Sweongyo}
9384203945Sweongyo
9385203945Sweongyostatic void
9386203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
9387203945Sweongyo{
9388203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
9389203945Sweongyo	struct bwn_plcp6 *plcp;
9390203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9391203945Sweongyo	struct ieee80211_frame_min *wh;
9392203945Sweongyo	struct ieee80211_node *ni;
9393203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9394203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9395203945Sweongyo	uint32_t macstat;
9396203945Sweongyo	int padding, rate, rssi, noise, type;
9397203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
9398203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
9399203945Sweongyo
9400203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9401203945Sweongyo
9402203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
9403203945Sweongyo	phystat3 = le16toh(rxhdr->phy_status3);
9404203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9405203945Sweongyo	chanstat = le16toh(rxhdr->channel);
9406203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
9407203945Sweongyo
9408203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
9409203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
9410203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
9411203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
9412203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_SHORTPRMBL)
9413203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_SHORTPRE\n");
9414203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
9415203945Sweongyo		goto drop;
9416203945Sweongyo
9417203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9418203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
9419204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9420204081Sweongyo		    m->m_pkthdr.len);
9421203945Sweongyo		goto drop;
9422203945Sweongyo	}
9423203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
9424203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
9425203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
9426204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9427204081Sweongyo		    m->m_pkthdr.len);
9428203945Sweongyo		goto drop;
9429203945Sweongyo	}
9430203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
9431203945Sweongyo
9432203945Sweongyo	if (macstat & BWN_RX_MAC_DEC)
9433204081Sweongyo		device_printf(sc->sc_dev,
9434204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
9435204081Sweongyo		    BWN_ISOLDFMT(mac),
9436204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
9437203945Sweongyo
9438203945Sweongyo	/* XXX calculating RSSI & noise & antenna */
9439203945Sweongyo
9440203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
9441203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
9442203945Sweongyo		    phytype == BWN_PHYTYPE_A);
9443203945Sweongyo	else
9444203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
9445203945Sweongyo	if (rate == -1) {
9446203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
9447203945Sweongyo			goto drop;
9448203945Sweongyo	}
9449203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
9450203945Sweongyo
9451203945Sweongyo	/* RX radio tap */
9452203945Sweongyo	if (ieee80211_radiotap_active(ic))
9453203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
9454203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
9455203945Sweongyo
9456203945Sweongyo	rssi = rxhdr->phy.abg.rssi;	/* XXX incorrect RSSI calculation? */
9457203945Sweongyo	noise = mac->mac_stats.link_noise;
9458203945Sweongyo
9459203945Sweongyo	BWN_UNLOCK(sc);
9460203945Sweongyo
9461203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
9462203945Sweongyo	if (ni != NULL) {
9463203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
9464203945Sweongyo		ieee80211_free_node(ni);
9465203945Sweongyo	} else
9466203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
9467203945Sweongyo
9468203945Sweongyo	BWN_LOCK(sc);
9469203945Sweongyo	return;
9470203945Sweongyodrop:
9471203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
9472203945Sweongyo}
9473203945Sweongyo
9474203945Sweongyostatic void
9475203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
9476203945Sweongyo    const struct bwn_txstatus *status)
9477203945Sweongyo{
9478203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9479203945Sweongyo	struct bwn_dma_ring *dr;
9480203945Sweongyo	struct bwn_dmadesc_generic *desc;
9481203945Sweongyo	struct bwn_dmadesc_meta *meta;
9482203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9483203945Sweongyo	struct ieee80211_node *ni;
9484203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9485203945Sweongyo	struct mbuf *m;
9486203945Sweongyo	int slot;
9487203945Sweongyo
9488203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9489203945Sweongyo
9490203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
9491203945Sweongyo	if (dr == NULL) {
9492203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
9493203945Sweongyo		return;
9494203945Sweongyo	}
9495203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
9496203945Sweongyo
9497203945Sweongyo	while (1) {
9498203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
9499203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9500203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
9501203945Sweongyo
9502203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
9503203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
9504203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
9505203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
9506203945Sweongyo
9507203945Sweongyo		if (meta->mt_islast) {
9508203945Sweongyo			KASSERT(meta->mt_m != NULL,
9509203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9510203945Sweongyo
9511203945Sweongyo			ni = meta->mt_ni;
9512203945Sweongyo			m = meta->mt_m;
9513203945Sweongyo			if (ni != NULL) {
9514203945Sweongyo				/*
9515203945Sweongyo				 * Do any tx complete callback. Note this must
9516203945Sweongyo				 * be done before releasing the node reference.
9517203945Sweongyo				 */
9518203945Sweongyo				if (m->m_flags & M_TXCB)
9519203945Sweongyo					ieee80211_process_callback(ni, m, 0);
9520203945Sweongyo				ieee80211_free_node(ni);
9521203945Sweongyo				meta->mt_ni = NULL;
9522203945Sweongyo			}
9523203945Sweongyo			m_freem(m);
9524203945Sweongyo			meta->mt_m = NULL;
9525203945Sweongyo		} else {
9526203945Sweongyo			KASSERT(meta->mt_m == NULL,
9527203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9528203945Sweongyo		}
9529203945Sweongyo
9530203945Sweongyo		dr->dr_usedslot--;
9531203945Sweongyo		if (meta->mt_islast) {
9532203945Sweongyo			ifp->if_opackets++;
9533203945Sweongyo			break;
9534203945Sweongyo		}
9535203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
9536203945Sweongyo	}
9537203945Sweongyo	sc->sc_watchdog_timer = 0;
9538203945Sweongyo	if (dr->dr_stop) {
9539203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
9540203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9541203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9542203945Sweongyo		dr->dr_stop = 0;
9543203945Sweongyo	}
9544203945Sweongyo}
9545203945Sweongyo
9546203945Sweongyostatic void
9547203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
9548203945Sweongyo    const struct bwn_txstatus *status)
9549203945Sweongyo{
9550203945Sweongyo	struct bwn_pio_txqueue *tq;
9551203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9552203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9553203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9554203945Sweongyo
9555203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9556203945Sweongyo
9557203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9558203945Sweongyo	if (tq == NULL)
9559203945Sweongyo		return;
9560203945Sweongyo
9561203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
9562203945Sweongyo	tq->tq_free++;
9563203945Sweongyo
9564203945Sweongyo	if (tp->tp_ni != NULL) {
9565203945Sweongyo		/*
9566203945Sweongyo		 * Do any tx complete callback.  Note this must
9567203945Sweongyo		 * be done before releasing the node reference.
9568203945Sweongyo		 */
9569203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
9570203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
9571203945Sweongyo		ieee80211_free_node(tp->tp_ni);
9572203945Sweongyo		tp->tp_ni = NULL;
9573203945Sweongyo	}
9574203945Sweongyo	m_freem(tp->tp_m);
9575203945Sweongyo	tp->tp_m = NULL;
9576203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
9577203945Sweongyo
9578203945Sweongyo	ifp->if_opackets++;
9579203945Sweongyo
9580203945Sweongyo	sc->sc_watchdog_timer = 0;
9581203945Sweongyo	if (tq->tq_stop) {
9582203945Sweongyo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
9583203945Sweongyo		tq->tq_stop = 0;
9584203945Sweongyo	}
9585203945Sweongyo}
9586203945Sweongyo
9587203945Sweongyostatic void
9588203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
9589203945Sweongyo{
9590203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9591203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
9592203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9593203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9594203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
9595203945Sweongyo	unsigned long now;
9596203945Sweongyo	int result;
9597203945Sweongyo
9598203945Sweongyo	BWN_GETTIME(now);
9599203945Sweongyo
9600203945Sweongyo	if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
9601203945Sweongyo		return;
9602203945Sweongyo	phy->nexttime = now + 2 * 1000;
9603203945Sweongyo
9604203945Sweongyo	if (siba->siba_board_vendor == SIBA_BOARDVENDOR_BCM &&
9605203945Sweongyo	    siba->siba_board_type == SIBA_BOARD_BU4306)
9606203945Sweongyo		return;
9607203945Sweongyo
9608203945Sweongyo	if (phy->recalc_txpwr != NULL) {
9609203945Sweongyo		result = phy->recalc_txpwr(mac,
9610203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
9611203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
9612203945Sweongyo			return;
9613203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
9614203945Sweongyo		    ("%s: fail", __func__));
9615203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
9616203945Sweongyo
9617203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
9618203945Sweongyo	}
9619203945Sweongyo}
9620203945Sweongyo
9621203945Sweongyostatic uint16_t
9622203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
9623203945Sweongyo{
9624203945Sweongyo
9625203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
9626203945Sweongyo}
9627203945Sweongyo
9628203945Sweongyostatic uint32_t
9629203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
9630203945Sweongyo{
9631203945Sweongyo
9632203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
9633203945Sweongyo}
9634203945Sweongyo
9635203945Sweongyostatic void
9636203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
9637203945Sweongyo{
9638203945Sweongyo
9639203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
9640203945Sweongyo}
9641203945Sweongyo
9642203945Sweongyostatic void
9643203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
9644203945Sweongyo{
9645203945Sweongyo
9646203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
9647203945Sweongyo}
9648203945Sweongyo
9649203945Sweongyostatic int
9650203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
9651203945Sweongyo{
9652203945Sweongyo
9653203945Sweongyo	switch (rate) {
9654203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
9655203945Sweongyo	case 12:
9656203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9657203945Sweongyo	case 18:
9658203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9659203945Sweongyo	case 24:
9660203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9661203945Sweongyo	case 36:
9662203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9663203945Sweongyo	case 48:
9664203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9665203945Sweongyo	case 72:
9666203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9667203945Sweongyo	case 96:
9668203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9669203945Sweongyo	case 108:
9670203945Sweongyo		return (BWN_OFDM_RATE_54MB);
9671203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
9672203945Sweongyo	case 2:
9673203945Sweongyo		return (BWN_CCK_RATE_1MB);
9674203945Sweongyo	case 4:
9675203945Sweongyo		return (BWN_CCK_RATE_2MB);
9676203945Sweongyo	case 11:
9677203945Sweongyo		return (BWN_CCK_RATE_5MB);
9678203945Sweongyo	case 22:
9679203945Sweongyo		return (BWN_CCK_RATE_11MB);
9680203945Sweongyo	}
9681203945Sweongyo
9682203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
9683203945Sweongyo	return (BWN_CCK_RATE_1MB);
9684203945Sweongyo}
9685203945Sweongyo
9686203945Sweongyostatic int
9687203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
9688203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
9689203945Sweongyo{
9690203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
9691203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9692203945Sweongyo	struct ieee80211_frame *wh;
9693203945Sweongyo	struct ieee80211_frame *protwh;
9694203945Sweongyo	struct ieee80211_frame_cts *cts;
9695203945Sweongyo	struct ieee80211_frame_rts *rts;
9696203945Sweongyo	const struct ieee80211_txparam *tp;
9697203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
9698203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
9699203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
9700203945Sweongyo	struct mbuf *mprot;
9701203945Sweongyo	unsigned int len;
9702203945Sweongyo	uint32_t macctl = 0;
9703203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
9704203945Sweongyo	uint16_t phyctl = 0;
9705203945Sweongyo	uint8_t rate, rate_fb;
9706203945Sweongyo
9707203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
9708203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
9709203945Sweongyo
9710203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
9711203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
9712203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
9713203945Sweongyo
9714203945Sweongyo	/*
9715203945Sweongyo	 * Find TX rate
9716203945Sweongyo	 */
9717203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
9718203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
9719203945Sweongyo		rate = rate_fb = tp->mgmtrate;
9720203945Sweongyo	else if (ismcast)
9721203945Sweongyo		rate = rate_fb = tp->mcastrate;
9722203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
9723203945Sweongyo		rate = rate_fb = tp->ucastrate;
9724203945Sweongyo	else {
9725203945Sweongyo		rix = ieee80211_amrr_choose(ni, &BWN_NODE(ni)->bn_amn);
9726203945Sweongyo		rate = ni->ni_txrate;
9727203945Sweongyo
9728203945Sweongyo		if (rix > 0)
9729203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
9730203945Sweongyo			    IEEE80211_RATE_VAL;
9731203945Sweongyo		else
9732203945Sweongyo			rate_fb = rate;
9733203945Sweongyo	}
9734203945Sweongyo
9735203945Sweongyo	sc->sc_tx_rate = rate;
9736203945Sweongyo
9737203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
9738203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
9739203945Sweongyo
9740203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
9741203945Sweongyo	    bwn_plcp_getcck(rate);
9742203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
9743203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
9744203945Sweongyo
9745203945Sweongyo	if ((rate_fb == rate) ||
9746203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
9747203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
9748203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
9749203945Sweongyo	else
9750203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
9751203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
9752203945Sweongyo
9753203945Sweongyo	/* XXX TX encryption */
9754203945Sweongyo	bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
9755203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
9756203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
9757203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
9758203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
9759203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
9760203945Sweongyo
9761203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
9762203945Sweongyo	    BWN_TX_EFT_FB_CCK;
9763203945Sweongyo	txhdr->chan = phy->chan;
9764203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
9765203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
9766203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9767203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
9768203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
9769203945Sweongyo
9770203945Sweongyo	/* XXX TX antenna selection */
9771203945Sweongyo
9772203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
9773203945Sweongyo	case 0:
9774203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
9775203945Sweongyo		break;
9776203945Sweongyo	case 1:
9777203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
9778203945Sweongyo		break;
9779203945Sweongyo	case 2:
9780203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
9781203945Sweongyo		break;
9782203945Sweongyo	case 3:
9783203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
9784203945Sweongyo		break;
9785203945Sweongyo	case 4:
9786203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
9787203945Sweongyo		break;
9788203945Sweongyo	default:
9789203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9790203945Sweongyo	}
9791203945Sweongyo
9792203945Sweongyo	if (!ismcast)
9793203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
9794203945Sweongyo
9795203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
9796203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
9797203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
9798203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
9799203945Sweongyo
9800203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
9801203945Sweongyo		/* XXX RTS rate is always 1MB??? */
9802203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
9803203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
9804203945Sweongyo
9805203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
9806203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
9807203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
9808203945Sweongyo
9809203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
9810203945Sweongyo			cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
9811203945Sweongyo			    (txhdr->body.old.rts_frame) :
9812203945Sweongyo			    (txhdr->body.new.rts_frame));
9813203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
9814203945Sweongyo			    protdur);
9815203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9816203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
9817203945Sweongyo			    mprot->m_pkthdr.len);
9818203945Sweongyo			m_freem(mprot);
9819203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
9820203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
9821203945Sweongyo		} else {
9822203945Sweongyo			rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
9823203945Sweongyo			    (txhdr->body.old.rts_frame) :
9824203945Sweongyo			    (txhdr->body.new.rts_frame));
9825203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
9826203945Sweongyo			    isshort);
9827203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
9828203945Sweongyo			    wh->i_addr2, protdur);
9829203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9830203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
9831203945Sweongyo			    mprot->m_pkthdr.len);
9832203945Sweongyo			m_freem(mprot);
9833203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
9834203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
9835203945Sweongyo		}
9836203945Sweongyo		len += IEEE80211_CRC_LEN;
9837203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
9838203945Sweongyo		    &txhdr->body.old.rts_plcp :
9839203945Sweongyo		    &txhdr->body.new.rts_plcp), len, rts_rate);
9840203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
9841203945Sweongyo		    rts_rate_fb);
9842203945Sweongyo
9843203945Sweongyo		protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
9844203945Sweongyo		    (&txhdr->body.old.rts_frame) :
9845203945Sweongyo		    (&txhdr->body.new.rts_frame));
9846203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
9847203945Sweongyo
9848203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
9849203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
9850203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
9851203945Sweongyo		} else {
9852203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
9853203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
9854203945Sweongyo		}
9855203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
9856203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
9857203945Sweongyo	}
9858203945Sweongyo
9859203945Sweongyo	if (BWN_ISOLDFMT(mac))
9860203945Sweongyo		txhdr->body.old.cookie = htole16(cookie);
9861203945Sweongyo	else
9862203945Sweongyo		txhdr->body.new.cookie = htole16(cookie);
9863203945Sweongyo
9864203945Sweongyo	txhdr->macctl = htole32(macctl);
9865203945Sweongyo	txhdr->phyctl = htole16(phyctl);
9866203945Sweongyo
9867203945Sweongyo	/*
9868203945Sweongyo	 * TX radio tap
9869203945Sweongyo	 */
9870203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
9871203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
9872203945Sweongyo		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
9873203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
9874203945Sweongyo		if (isshort &&
9875203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9876203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
9877203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
9878203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
9879203945Sweongyo
9880203945Sweongyo		ieee80211_radiotap_tx(vap, m);
9881203945Sweongyo	}
9882203945Sweongyo
9883203945Sweongyo	return (0);
9884203945Sweongyo}
9885203945Sweongyo
9886203945Sweongyostatic void
9887203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
9888203945Sweongyo    const uint8_t rate)
9889203945Sweongyo{
9890203945Sweongyo	uint32_t d, plen;
9891203945Sweongyo	uint8_t *raw = plcp->o.raw;
9892203945Sweongyo
9893203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
9894203945Sweongyo		d = bwn_plcp_getofdm(rate);
9895203945Sweongyo		KASSERT(!(octets & 0xf000),
9896203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9897203945Sweongyo		d |= (octets << 5);
9898203945Sweongyo		plcp->o.data = htole32(d);
9899203945Sweongyo	} else {
9900203945Sweongyo		plen = octets * 16 / rate;
9901203945Sweongyo		if ((octets * 16 % rate) > 0) {
9902203945Sweongyo			plen++;
9903203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
9904203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
9905203945Sweongyo				raw[1] = 0x84;
9906203945Sweongyo			} else
9907203945Sweongyo				raw[1] = 0x04;
9908203945Sweongyo		} else
9909203945Sweongyo			raw[1] = 0x04;
9910203945Sweongyo		plcp->o.data |= htole32(plen << 16);
9911203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
9912203945Sweongyo	}
9913203945Sweongyo}
9914203945Sweongyo
9915203945Sweongyostatic uint8_t
9916203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
9917203945Sweongyo{
9918203945Sweongyo	uint8_t mask;
9919203945Sweongyo
9920203945Sweongyo	if (n == 0)
9921203945Sweongyo		return (0);
9922203945Sweongyo	if (mac->mac_phy.gmode)
9923203945Sweongyo		mask = mac->mac_sd->sd_bus->siba_sprom.ant_bg;
9924203945Sweongyo	else
9925203945Sweongyo		mask = mac->mac_sd->sd_bus->siba_sprom.ant_a;
9926203945Sweongyo	if (!(mask & (1 << (n - 1))))
9927203945Sweongyo		return (0);
9928203945Sweongyo	return (n);
9929203945Sweongyo}
9930203945Sweongyo
9931203945Sweongyostatic uint8_t
9932203945Sweongyobwn_get_fbrate(uint8_t bitrate)
9933203945Sweongyo{
9934203945Sweongyo	switch (bitrate) {
9935203945Sweongyo	case BWN_CCK_RATE_1MB:
9936203945Sweongyo		return (BWN_CCK_RATE_1MB);
9937203945Sweongyo	case BWN_CCK_RATE_2MB:
9938203945Sweongyo		return (BWN_CCK_RATE_1MB);
9939203945Sweongyo	case BWN_CCK_RATE_5MB:
9940203945Sweongyo		return (BWN_CCK_RATE_2MB);
9941203945Sweongyo	case BWN_CCK_RATE_11MB:
9942203945Sweongyo		return (BWN_CCK_RATE_5MB);
9943203945Sweongyo	case BWN_OFDM_RATE_6MB:
9944203945Sweongyo		return (BWN_CCK_RATE_5MB);
9945203945Sweongyo	case BWN_OFDM_RATE_9MB:
9946203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9947203945Sweongyo	case BWN_OFDM_RATE_12MB:
9948203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9949203945Sweongyo	case BWN_OFDM_RATE_18MB:
9950203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9951203945Sweongyo	case BWN_OFDM_RATE_24MB:
9952203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9953203945Sweongyo	case BWN_OFDM_RATE_36MB:
9954203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9955203945Sweongyo	case BWN_OFDM_RATE_48MB:
9956203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9957203945Sweongyo	case BWN_OFDM_RATE_54MB:
9958203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9959203945Sweongyo	}
9960203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9961203945Sweongyo	return (0);
9962203945Sweongyo}
9963203945Sweongyo
9964203945Sweongyostatic uint32_t
9965203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9966203945Sweongyo    uint32_t ctl, const void *_data, int len)
9967203945Sweongyo{
9968203945Sweongyo	uint32_t value = 0;
9969203945Sweongyo	const uint8_t *data = _data;
9970203945Sweongyo
9971203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
9972203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
9973203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9974203945Sweongyo
9975203945Sweongyo	siba_write_multi_4(mac->mac_sd, data, (len & ~3),
9976203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
9977203945Sweongyo	if (len & 3) {
9978203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
9979203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
9980203945Sweongyo		data = &(data[len - 1]);
9981203945Sweongyo		switch (len & 3) {
9982203945Sweongyo		case 3:
9983203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
9984203945Sweongyo			value |= (uint32_t)(*data) << 16;
9985203945Sweongyo			data--;
9986203945Sweongyo		case 2:
9987203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
9988203945Sweongyo			value |= (uint32_t)(*data) << 8;
9989203945Sweongyo			data--;
9990203945Sweongyo		case 1:
9991203945Sweongyo			value |= (uint32_t)(*data);
9992203945Sweongyo		}
9993203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9994203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
9995203945Sweongyo	}
9996203945Sweongyo
9997203945Sweongyo	return (ctl);
9998203945Sweongyo}
9999203945Sweongyo
10000203945Sweongyostatic void
10001203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
10002203945Sweongyo    uint16_t offset, uint32_t value)
10003203945Sweongyo{
10004203945Sweongyo
10005203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
10006203945Sweongyo}
10007203945Sweongyo
10008203945Sweongyostatic uint16_t
10009203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
10010203945Sweongyo    uint16_t ctl, const void *_data, int len)
10011203945Sweongyo{
10012203945Sweongyo	const uint8_t *data = _data;
10013203945Sweongyo
10014203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
10015203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10016203945Sweongyo
10017203945Sweongyo	siba_write_multi_2(mac->mac_sd, data, (len & ~1),
10018203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
10019203945Sweongyo	if (len & 1) {
10020203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
10021203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10022203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
10023203945Sweongyo	}
10024203945Sweongyo
10025203945Sweongyo	return (ctl);
10026203945Sweongyo}
10027203945Sweongyo
10028203945Sweongyostatic uint16_t
10029203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
10030203945Sweongyo    uint16_t ctl, struct mbuf *m0)
10031203945Sweongyo{
10032203945Sweongyo	int i, j = 0;
10033203945Sweongyo	uint16_t data = 0;
10034203945Sweongyo	const uint8_t *buf;
10035203945Sweongyo	struct mbuf *m = m0;
10036203945Sweongyo
10037203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
10038203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10039203945Sweongyo
10040203945Sweongyo	for (; m != NULL; m = m->m_next) {
10041203945Sweongyo		buf = mtod(m, const uint8_t *);
10042203945Sweongyo		for (i = 0; i < m->m_len; i++) {
10043203945Sweongyo			if (!((j++) % 2))
10044203945Sweongyo				data |= buf[i];
10045203945Sweongyo			else {
10046203945Sweongyo				data |= (buf[i] << 8);
10047203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
10048203945Sweongyo				data = 0;
10049203945Sweongyo			}
10050203945Sweongyo		}
10051203945Sweongyo	}
10052203945Sweongyo	if (m0->m_pkthdr.len % 2) {
10053203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
10054203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
10055203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
10056203945Sweongyo	}
10057203945Sweongyo
10058203945Sweongyo	return (ctl);
10059203945Sweongyo}
10060203945Sweongyo
10061203945Sweongyostatic void
10062203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
10063203945Sweongyo{
10064203945Sweongyo
10065203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
10066203945Sweongyo		return;
10067203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
10068203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
10069203945Sweongyo}
10070203945Sweongyo
10071203945Sweongyostatic struct bwn_dma_ring *
10072203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
10073203945Sweongyo{
10074203945Sweongyo
10075203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
10076203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
10077203945Sweongyo
10078203945Sweongyo	switch (prio) {
10079203945Sweongyo	case 3:
10080203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
10081203945Sweongyo	case 2:
10082203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
10083203945Sweongyo	case 0:
10084203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
10085203945Sweongyo	case 1:
10086203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
10087203945Sweongyo	}
10088203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
10089203945Sweongyo}
10090203945Sweongyo
10091203945Sweongyostatic int
10092203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
10093203945Sweongyo{
10094203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
10095203945Sweongyo	int slot;
10096203945Sweongyo
10097203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
10098203945Sweongyo
10099203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
10100203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
10101203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
10102203945Sweongyo
10103203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
10104203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
10105203945Sweongyo	dr->dr_curslot = slot;
10106203945Sweongyo	dr->dr_usedslot++;
10107203945Sweongyo
10108203945Sweongyo	return (slot);
10109203945Sweongyo}
10110203945Sweongyo
10111203945Sweongyostatic int
10112203945Sweongyobwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
10113203945Sweongyo{
10114203945Sweongyo	const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
10115203945Sweongyo	unsigned int a, b, c, d;
10116203945Sweongyo	unsigned int avg;
10117203945Sweongyo	uint32_t tmp;
10118203945Sweongyo
10119203945Sweongyo	tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
10120203945Sweongyo	a = tmp & 0xff;
10121203945Sweongyo	b = (tmp >> 8) & 0xff;
10122203945Sweongyo	c = (tmp >> 16) & 0xff;
10123203945Sweongyo	d = (tmp >> 24) & 0xff;
10124203945Sweongyo	if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
10125203945Sweongyo	    c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
10126203945Sweongyo		return (ENOENT);
10127203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
10128203945Sweongyo	    BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
10129203945Sweongyo	    (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
10130203945Sweongyo
10131203945Sweongyo	if (ofdm) {
10132203945Sweongyo		a = (a + 32) & 0x3f;
10133203945Sweongyo		b = (b + 32) & 0x3f;
10134203945Sweongyo		c = (c + 32) & 0x3f;
10135203945Sweongyo		d = (d + 32) & 0x3f;
10136203945Sweongyo	}
10137203945Sweongyo
10138203945Sweongyo	avg = (a + b + c + d + 2) / 4;
10139203945Sweongyo	if (ofdm) {
10140203945Sweongyo		if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
10141203945Sweongyo		    & BWN_HF_4DB_CCK_POWERBOOST)
10142203945Sweongyo			avg = (avg >= 13) ? (avg - 13) : 0;
10143203945Sweongyo	}
10144203945Sweongyo	return (avg);
10145203945Sweongyo}
10146203945Sweongyo
10147203945Sweongyostatic void
10148203945Sweongyobwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
10149203945Sweongyo{
10150203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
10151203945Sweongyo	int rfatt = *rfattp;
10152203945Sweongyo	int bbatt = *bbattp;
10153203945Sweongyo
10154203945Sweongyo	while (1) {
10155203945Sweongyo		if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
10156203945Sweongyo			break;
10157203945Sweongyo		if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
10158203945Sweongyo			break;
10159203945Sweongyo		if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
10160203945Sweongyo			break;
10161203945Sweongyo		if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
10162203945Sweongyo			break;
10163203945Sweongyo		if (bbatt > lo->bbatt.max) {
10164203945Sweongyo			bbatt -= 4;
10165203945Sweongyo			rfatt += 1;
10166203945Sweongyo			continue;
10167203945Sweongyo		}
10168203945Sweongyo		if (bbatt < lo->bbatt.min) {
10169203945Sweongyo			bbatt += 4;
10170203945Sweongyo			rfatt -= 1;
10171203945Sweongyo			continue;
10172203945Sweongyo		}
10173203945Sweongyo		if (rfatt > lo->rfatt.max) {
10174203945Sweongyo			rfatt -= 1;
10175203945Sweongyo			bbatt += 4;
10176203945Sweongyo			continue;
10177203945Sweongyo		}
10178203945Sweongyo		if (rfatt < lo->rfatt.min) {
10179203945Sweongyo			rfatt += 1;
10180203945Sweongyo			bbatt -= 4;
10181203945Sweongyo			continue;
10182203945Sweongyo		}
10183203945Sweongyo		break;
10184203945Sweongyo	}
10185203945Sweongyo
10186203945Sweongyo	*rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
10187203945Sweongyo	*bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
10188203945Sweongyo}
10189203945Sweongyo
10190203945Sweongyostatic void
10191203945Sweongyobwn_phy_lock(struct bwn_mac *mac)
10192203945Sweongyo{
10193203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10194203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10195203945Sweongyo
10196203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
10197203945Sweongyo	    ("%s: unsupported rev %d", __func__, mac->mac_sd->sd_id.sd_rev));
10198203945Sweongyo
10199203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10200203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
10201203945Sweongyo}
10202203945Sweongyo
10203203945Sweongyostatic void
10204203945Sweongyobwn_phy_unlock(struct bwn_mac *mac)
10205203945Sweongyo{
10206203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10207203945Sweongyo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
10208203945Sweongyo
10209203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
10210203945Sweongyo	    ("%s: unsupported rev %d", __func__, mac->mac_sd->sd_id.sd_rev));
10211203945Sweongyo
10212203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
10213203945Sweongyo		bwn_psctl(mac, 0);
10214203945Sweongyo}
10215203945Sweongyo
10216203945Sweongyostatic void
10217203945Sweongyobwn_rf_lock(struct bwn_mac *mac)
10218203945Sweongyo{
10219203945Sweongyo
10220203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10221203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
10222203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
10223203945Sweongyo	DELAY(10);
10224203945Sweongyo}
10225203945Sweongyo
10226203945Sweongyostatic void
10227203945Sweongyobwn_rf_unlock(struct bwn_mac *mac)
10228203945Sweongyo{
10229203945Sweongyo
10230203945Sweongyo	BWN_READ_2(mac, BWN_PHYVER);
10231203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10232203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
10233203945Sweongyo}
10234203945Sweongyo
10235203945Sweongyostatic struct bwn_pio_txqueue *
10236203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
10237203945Sweongyo    struct bwn_pio_txpkt **pack)
10238203945Sweongyo{
10239203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
10240203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
10241203945Sweongyo	unsigned int index;
10242203945Sweongyo
10243203945Sweongyo	switch (cookie & 0xf000) {
10244203945Sweongyo	case 0x1000:
10245203945Sweongyo		tq = &pio->wme[WME_AC_BK];
10246203945Sweongyo		break;
10247203945Sweongyo	case 0x2000:
10248203945Sweongyo		tq = &pio->wme[WME_AC_BE];
10249203945Sweongyo		break;
10250203945Sweongyo	case 0x3000:
10251203945Sweongyo		tq = &pio->wme[WME_AC_VI];
10252203945Sweongyo		break;
10253203945Sweongyo	case 0x4000:
10254203945Sweongyo		tq = &pio->wme[WME_AC_VO];
10255203945Sweongyo		break;
10256203945Sweongyo	case 0x5000:
10257203945Sweongyo		tq = &pio->mcast;
10258203945Sweongyo		break;
10259203945Sweongyo	}
10260203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
10261203945Sweongyo	if (tq == NULL)
10262203945Sweongyo		return (NULL);
10263203945Sweongyo	index = (cookie & 0x0fff);
10264203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
10265203945Sweongyo	if (index >= N(tq->tq_pkts))
10266203945Sweongyo		return (NULL);
10267203945Sweongyo	*pack = &tq->tq_pkts[index];
10268203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
10269203945Sweongyo	return (tq);
10270203945Sweongyo}
10271203945Sweongyo
10272203945Sweongyostatic void
10273203945Sweongyobwn_txpwr(void *arg, int npending)
10274203945Sweongyo{
10275203945Sweongyo	struct bwn_mac *mac = arg;
10276203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10277203945Sweongyo
10278203945Sweongyo	BWN_LOCK(sc);
10279203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
10280203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
10281203945Sweongyo		mac->mac_phy.set_txpwr(mac);
10282203945Sweongyo	BWN_UNLOCK(sc);
10283203945Sweongyo}
10284203945Sweongyo
10285203945Sweongyostatic void
10286203945Sweongyobwn_task_15s(struct bwn_mac *mac)
10287203945Sweongyo{
10288203945Sweongyo	uint16_t reg;
10289203945Sweongyo
10290203945Sweongyo	if (mac->mac_fw.opensource) {
10291203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
10292203945Sweongyo		if (reg) {
10293203945Sweongyo			bwn_restart(mac, "fw watchdog");
10294203945Sweongyo			return;
10295203945Sweongyo		}
10296203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
10297203945Sweongyo	}
10298203945Sweongyo	if (mac->mac_phy.task_15s)
10299203945Sweongyo		mac->mac_phy.task_15s(mac);
10300203945Sweongyo
10301203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
10302203945Sweongyo}
10303203945Sweongyo
10304203945Sweongyostatic void
10305203945Sweongyobwn_task_30s(struct bwn_mac *mac)
10306203945Sweongyo{
10307203945Sweongyo
10308203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
10309203945Sweongyo		return;
10310203945Sweongyo	mac->mac_noise.noi_running = 1;
10311203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
10312203945Sweongyo
10313203945Sweongyo	bwn_noise_gensample(mac);
10314203945Sweongyo}
10315203945Sweongyo
10316203945Sweongyostatic void
10317203945Sweongyobwn_task_60s(struct bwn_mac *mac)
10318203945Sweongyo{
10319203945Sweongyo
10320203945Sweongyo	if (mac->mac_phy.task_60s)
10321203945Sweongyo		mac->mac_phy.task_60s(mac);
10322203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
10323203945Sweongyo}
10324203945Sweongyo
10325203945Sweongyostatic void
10326203945Sweongyobwn_tasks(void *arg)
10327203945Sweongyo{
10328203945Sweongyo	struct bwn_mac *mac = arg;
10329203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10330203945Sweongyo
10331203945Sweongyo	BWN_ASSERT_LOCKED(sc);
10332203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
10333203945Sweongyo		return;
10334203945Sweongyo
10335203945Sweongyo	if (mac->mac_task_state % 4 == 0)
10336203945Sweongyo		bwn_task_60s(mac);
10337203945Sweongyo	if (mac->mac_task_state % 2 == 0)
10338203945Sweongyo		bwn_task_30s(mac);
10339203945Sweongyo	bwn_task_15s(mac);
10340203945Sweongyo
10341203945Sweongyo	mac->mac_task_state++;
10342203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
10343203945Sweongyo}
10344203945Sweongyo
10345203945Sweongyostatic int
10346203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
10347203945Sweongyo{
10348203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10349203945Sweongyo
10350203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
10351203945Sweongyo
10352203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
10353203945Sweongyo	case 0xb:
10354203945Sweongyo		return (BWN_OFDM_RATE_6MB);
10355203945Sweongyo	case 0xf:
10356203945Sweongyo		return (BWN_OFDM_RATE_9MB);
10357203945Sweongyo	case 0xa:
10358203945Sweongyo		return (BWN_OFDM_RATE_12MB);
10359203945Sweongyo	case 0xe:
10360203945Sweongyo		return (BWN_OFDM_RATE_18MB);
10361203945Sweongyo	case 0x9:
10362203945Sweongyo		return (BWN_OFDM_RATE_24MB);
10363203945Sweongyo	case 0xd:
10364203945Sweongyo		return (BWN_OFDM_RATE_36MB);
10365203945Sweongyo	case 0x8:
10366203945Sweongyo		return (BWN_OFDM_RATE_48MB);
10367203945Sweongyo	case 0xc:
10368203945Sweongyo		return (BWN_OFDM_RATE_54MB);
10369203945Sweongyo	}
10370203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
10371203945Sweongyo	    plcp->o.raw[0] & 0xf);
10372203945Sweongyo	return (-1);
10373203945Sweongyo}
10374203945Sweongyo
10375203945Sweongyostatic int
10376203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
10377203945Sweongyo{
10378203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10379203945Sweongyo
10380203945Sweongyo	switch (plcp->o.raw[0]) {
10381203945Sweongyo	case 0x0a:
10382203945Sweongyo		return (BWN_CCK_RATE_1MB);
10383203945Sweongyo	case 0x14:
10384203945Sweongyo		return (BWN_CCK_RATE_2MB);
10385203945Sweongyo	case 0x37:
10386203945Sweongyo		return (BWN_CCK_RATE_5MB);
10387203945Sweongyo	case 0x6e:
10388203945Sweongyo		return (BWN_CCK_RATE_11MB);
10389203945Sweongyo	}
10390203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
10391203945Sweongyo	return (-1);
10392203945Sweongyo}
10393203945Sweongyo
10394203945Sweongyostatic void
10395203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
10396203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
10397203945Sweongyo    int rssi, int noise)
10398203945Sweongyo{
10399203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10400203945Sweongyo	const struct ieee80211_frame_min *wh;
10401203945Sweongyo	uint64_t tsf;
10402203945Sweongyo	uint16_t low_mactime_now;
10403203945Sweongyo
10404203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
10405203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
10406203945Sweongyo
10407203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
10408203945Sweongyo	if (wh->i_fc[1] & IEEE80211_FC1_WEP)
10409203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
10410203945Sweongyo
10411203945Sweongyo	bwn_tsf_read(mac, &tsf);
10412203945Sweongyo	low_mactime_now = tsf;
10413203945Sweongyo	tsf = tsf & ~0xffffULL;
10414203945Sweongyo	tsf += le16toh(rxhdr->mac_time);
10415203945Sweongyo	if (low_mactime_now < le16toh(rxhdr->mac_time))
10416203945Sweongyo		tsf -= 0x10000;
10417203945Sweongyo
10418203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
10419203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
10420203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
10421203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
10422203945Sweongyo}
10423203945Sweongyo
10424203945Sweongyostatic void
10425203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
10426203945Sweongyo{
10427203945Sweongyo	uint32_t low, high;
10428203945Sweongyo
10429203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
10430203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
10431203945Sweongyo
10432203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
10433203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
10434203945Sweongyo	*tsf = high;
10435203945Sweongyo	*tsf <<= 32;
10436203945Sweongyo	*tsf |= low;
10437203945Sweongyo}
10438203945Sweongyo
10439203945Sweongyostatic int
10440203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
10441203945Sweongyo{
10442203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10443203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10444203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
10445203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
10446203945Sweongyo	bus_addr_t lowaddr = 0;
10447203945Sweongyo	int error;
10448203945Sweongyo
10449203945Sweongyo	if (siba->siba_type == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
10450203945Sweongyo		return (0);
10451203945Sweongyo
10452203945Sweongyo	KASSERT(mac->mac_sd->sd_id.sd_rev >= 5, ("%s: fail", __func__));
10453203945Sweongyo
10454203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
10455203945Sweongyo
10456203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
10457203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
10458203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
10459203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
10460203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
10461203945Sweongyo	else
10462203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
10463203945Sweongyo
10464203945Sweongyo	/*
10465203945Sweongyo	 * Create top level DMA tag
10466203945Sweongyo	 */
10467203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
10468203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
10469203945Sweongyo			       lowaddr,			/* lowaddr */
10470203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
10471203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
10472203945Sweongyo			       MAXBSIZE,		/* maxsize */
10473203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
10474203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
10475203945Sweongyo			       0,			/* flags */
10476203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
10477203945Sweongyo			       &dma->parent_dtag);
10478203945Sweongyo	if (error) {
10479203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
10480203945Sweongyo		return (error);
10481203945Sweongyo	}
10482203945Sweongyo
10483203945Sweongyo	/*
10484203945Sweongyo	 * Create TX/RX mbuf DMA tag
10485203945Sweongyo	 */
10486203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10487203945Sweongyo				1,
10488203945Sweongyo				0,
10489203945Sweongyo				BUS_SPACE_MAXADDR,
10490203945Sweongyo				BUS_SPACE_MAXADDR,
10491203945Sweongyo				NULL, NULL,
10492203945Sweongyo				MCLBYTES,
10493203945Sweongyo				1,
10494203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10495203945Sweongyo				0,
10496203945Sweongyo				NULL, NULL,
10497203945Sweongyo				&dma->rxbuf_dtag);
10498203945Sweongyo	if (error) {
10499203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10500203945Sweongyo		goto fail0;
10501203945Sweongyo	}
10502203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10503203945Sweongyo				1,
10504203945Sweongyo				0,
10505203945Sweongyo				BUS_SPACE_MAXADDR,
10506203945Sweongyo				BUS_SPACE_MAXADDR,
10507203945Sweongyo				NULL, NULL,
10508203945Sweongyo				MCLBYTES,
10509203945Sweongyo				1,
10510203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10511203945Sweongyo				0,
10512203945Sweongyo				NULL, NULL,
10513203945Sweongyo				&dma->txbuf_dtag);
10514203945Sweongyo	if (error) {
10515203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10516203945Sweongyo		goto fail1;
10517203945Sweongyo	}
10518203945Sweongyo
10519203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
10520203945Sweongyo	if (!dma->wme[WME_AC_BK])
10521203945Sweongyo		goto fail2;
10522203945Sweongyo
10523203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
10524203945Sweongyo	if (!dma->wme[WME_AC_BE])
10525203945Sweongyo		goto fail3;
10526203945Sweongyo
10527203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
10528203945Sweongyo	if (!dma->wme[WME_AC_VI])
10529203945Sweongyo		goto fail4;
10530203945Sweongyo
10531203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
10532203945Sweongyo	if (!dma->wme[WME_AC_VO])
10533203945Sweongyo		goto fail5;
10534203945Sweongyo
10535203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
10536203945Sweongyo	if (!dma->mcast)
10537203945Sweongyo		goto fail6;
10538203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
10539203945Sweongyo	if (!dma->rx)
10540203945Sweongyo		goto fail7;
10541203945Sweongyo
10542203945Sweongyo	return (error);
10543203945Sweongyo
10544203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
10545203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
10546203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
10547203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
10548203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
10549203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
10550203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
10551203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
10552203945Sweongyo	return (error);
10553203945Sweongyo}
10554203945Sweongyo
10555203945Sweongyostatic struct bwn_dma_ring *
10556203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
10557203945Sweongyo    uint16_t cookie, int *slot)
10558203945Sweongyo{
10559203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10560203945Sweongyo	struct bwn_dma_ring *dr;
10561203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10562203945Sweongyo
10563203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
10564203945Sweongyo
10565203945Sweongyo	switch (cookie & 0xf000) {
10566203945Sweongyo	case 0x1000:
10567203945Sweongyo		dr = dma->wme[WME_AC_BK];
10568203945Sweongyo		break;
10569203945Sweongyo	case 0x2000:
10570203945Sweongyo		dr = dma->wme[WME_AC_BE];
10571203945Sweongyo		break;
10572203945Sweongyo	case 0x3000:
10573203945Sweongyo		dr = dma->wme[WME_AC_VI];
10574203945Sweongyo		break;
10575203945Sweongyo	case 0x4000:
10576203945Sweongyo		dr = dma->wme[WME_AC_VO];
10577203945Sweongyo		break;
10578203945Sweongyo	case 0x5000:
10579203945Sweongyo		dr = dma->mcast;
10580203945Sweongyo		break;
10581203945Sweongyo	default:
10582203945Sweongyo		KASSERT(0 == 1,
10583203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
10584203945Sweongyo	}
10585203945Sweongyo	*slot = (cookie & 0x0fff);
10586203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
10587203945Sweongyo		/*
10588203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
10589203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
10590203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
10591203945Sweongyo		 */
10592203945Sweongyo		KASSERT(status->seq == dma->lastseq,
10593203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
10594203945Sweongyo		device_printf(sc->sc_dev,
10595203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
10596203945Sweongyo		    dr->dr_numslots);
10597203945Sweongyo		return (NULL);
10598203945Sweongyo	}
10599203945Sweongyo	dma->lastseq = status->seq;
10600203945Sweongyo	return (dr);
10601203945Sweongyo}
10602203945Sweongyo
10603203945Sweongyostatic void
10604203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
10605203945Sweongyo{
10606203945Sweongyo	struct bwn_dma *dma;
10607203945Sweongyo
10608203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
10609203945Sweongyo		return;
10610203945Sweongyo	dma = &mac->mac_method.dma;
10611203945Sweongyo
10612203945Sweongyo	bwn_dma_ringstop(&dma->rx);
10613203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
10614203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
10615203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
10616203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
10617203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
10618203945Sweongyo}
10619203945Sweongyo
10620203945Sweongyostatic void
10621203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
10622203945Sweongyo{
10623203945Sweongyo
10624203945Sweongyo	if (dr == NULL)
10625203945Sweongyo		return;
10626203945Sweongyo
10627203945Sweongyo	bwn_dma_cleanup(*dr);
10628203945Sweongyo}
10629203945Sweongyo
10630203945Sweongyostatic void
10631203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
10632203945Sweongyo{
10633203945Sweongyo	struct bwn_pio *pio;
10634203945Sweongyo
10635203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
10636203945Sweongyo		return;
10637203945Sweongyo	pio = &mac->mac_method.pio;
10638203945Sweongyo
10639203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
10640203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
10641203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
10642203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
10643203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
10644203945Sweongyo}
10645203945Sweongyo
10646203945Sweongyostatic void
10647203945Sweongyobwn_led_attach(struct bwn_mac *mac)
10648203945Sweongyo{
10649203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10650203945Sweongyo	struct siba_softc *siba = mac->mac_sd->sd_bus;
10651203945Sweongyo	const uint8_t *led_act = NULL;
10652203945Sweongyo	uint16_t val[BWN_LED_MAX];
10653203945Sweongyo	int i;
10654203945Sweongyo
10655203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
10656203945Sweongyo	sc->sc_led_blink = 1;
10657203945Sweongyo
10658203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
10659203945Sweongyo		if (siba->siba_pci_subvid == bwn_vendor_led_act[i].vid) {
10660203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
10661203945Sweongyo			break;
10662203945Sweongyo		}
10663203945Sweongyo	}
10664203945Sweongyo	if (led_act == NULL)
10665203945Sweongyo		led_act = bwn_default_led_act;
10666203945Sweongyo
10667203945Sweongyo	val[0] = siba->siba_sprom.gpio0;
10668203945Sweongyo	val[1] = siba->siba_sprom.gpio1;
10669203945Sweongyo	val[2] = siba->siba_sprom.gpio2;
10670203945Sweongyo	val[3] = siba->siba_sprom.gpio3;
10671203945Sweongyo
10672203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10673203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10674203945Sweongyo
10675203945Sweongyo		if (val[i] == 0xff) {
10676203945Sweongyo			led->led_act = led_act[i];
10677203945Sweongyo		} else {
10678203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
10679203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
10680203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
10681203945Sweongyo		}
10682203945Sweongyo		led->led_mask = (1 << i);
10683203945Sweongyo
10684203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
10685203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
10686203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
10687203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
10688203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
10689203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
10690203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
10691203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
10692203945Sweongyo
10693203945Sweongyo			if (sc->sc_blink_led == NULL) {
10694203945Sweongyo				sc->sc_blink_led = led;
10695203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
10696203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
10697203945Sweongyo			}
10698203945Sweongyo		}
10699203945Sweongyo
10700203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
10701203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
10702203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
10703203945Sweongyo	}
10704203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
10705203945Sweongyo}
10706203945Sweongyo
10707203945Sweongyostatic __inline uint16_t
10708203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
10709203945Sweongyo{
10710203945Sweongyo
10711203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
10712203945Sweongyo		on = !on;
10713203945Sweongyo	if (on)
10714203945Sweongyo		val |= led->led_mask;
10715203945Sweongyo	else
10716203945Sweongyo		val &= ~led->led_mask;
10717203945Sweongyo	return val;
10718203945Sweongyo}
10719203945Sweongyo
10720203945Sweongyostatic void
10721203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
10722203945Sweongyo{
10723203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10724203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10725203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10726203945Sweongyo	uint16_t val;
10727203945Sweongyo	int i;
10728203945Sweongyo
10729203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
10730203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
10731203945Sweongyo		sc->sc_led_blinking = 0;
10732203945Sweongyo	}
10733203945Sweongyo
10734203945Sweongyo	if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
10735203945Sweongyo		return;
10736203945Sweongyo
10737203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10738203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10739203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10740203945Sweongyo		int on;
10741203945Sweongyo
10742203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
10743203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
10744203945Sweongyo			continue;
10745203945Sweongyo
10746203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
10747203945Sweongyo		    nstate != IEEE80211_S_INIT)
10748203945Sweongyo			continue;
10749203945Sweongyo
10750203945Sweongyo		switch (led->led_act) {
10751203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
10752203945Sweongyo			on = 1;
10753203945Sweongyo			break;
10754203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
10755203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
10756203945Sweongyo			on = 0;
10757203945Sweongyo			break;
10758203945Sweongyo		default:
10759203945Sweongyo			on = 1;
10760203945Sweongyo			switch (nstate) {
10761203945Sweongyo			case IEEE80211_S_INIT:
10762203945Sweongyo				on = 0;
10763203945Sweongyo				break;
10764203945Sweongyo			case IEEE80211_S_RUN:
10765203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
10766203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
10767203945Sweongyo					on = 0;
10768203945Sweongyo				break;
10769203945Sweongyo			default:
10770203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
10771203945Sweongyo					on = 0;
10772203945Sweongyo				break;
10773203945Sweongyo			}
10774203945Sweongyo			break;
10775203945Sweongyo		}
10776203945Sweongyo
10777203945Sweongyo		val = bwn_led_onoff(led, val, on);
10778203945Sweongyo	}
10779203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10780203945Sweongyo}
10781203945Sweongyo
10782203945Sweongyostatic void
10783203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
10784203945Sweongyo{
10785203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10786203945Sweongyo        struct bwn_led *led = sc->sc_blink_led;
10787203945Sweongyo        int rate;
10788203945Sweongyo
10789203945Sweongyo        if (event == BWN_LED_EVENT_POLL) {
10790203945Sweongyo                if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
10791203945Sweongyo                        return;
10792203945Sweongyo                if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
10793203945Sweongyo                        return;
10794203945Sweongyo        }
10795203945Sweongyo
10796203945Sweongyo        sc->sc_led_ticks = ticks;
10797203945Sweongyo        if (sc->sc_led_blinking)
10798203945Sweongyo                return;
10799203945Sweongyo
10800203945Sweongyo        switch (event) {
10801203945Sweongyo        case BWN_LED_EVENT_RX:
10802203945Sweongyo                rate = sc->sc_rx_rate;
10803203945Sweongyo                break;
10804203945Sweongyo        case BWN_LED_EVENT_TX:
10805203945Sweongyo                rate = sc->sc_tx_rate;
10806203945Sweongyo                break;
10807203945Sweongyo        case BWN_LED_EVENT_POLL:
10808203945Sweongyo                rate = 0;
10809203945Sweongyo                break;
10810203945Sweongyo        default:
10811203945Sweongyo                panic("unknown LED event %d\n", event);
10812203945Sweongyo                break;
10813203945Sweongyo        }
10814203945Sweongyo        bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
10815203945Sweongyo            bwn_led_duration[rate].off_dur);
10816203945Sweongyo}
10817203945Sweongyo
10818203945Sweongyostatic void
10819203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
10820203945Sweongyo{
10821203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10822203945Sweongyo        struct bwn_led *led = sc->sc_blink_led;
10823203945Sweongyo        uint16_t val;
10824203945Sweongyo
10825203945Sweongyo        val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10826203945Sweongyo        val = bwn_led_onoff(led, val, 1);
10827203945Sweongyo        BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10828203945Sweongyo
10829203945Sweongyo        if (led->led_flags & BWN_LED_F_SLOW) {
10830203945Sweongyo                BWN_LED_SLOWDOWN(on_dur);
10831203945Sweongyo                BWN_LED_SLOWDOWN(off_dur);
10832203945Sweongyo        }
10833203945Sweongyo
10834203945Sweongyo        sc->sc_led_blinking = 1;
10835203945Sweongyo        sc->sc_led_blink_offdur = off_dur;
10836203945Sweongyo
10837203945Sweongyo        callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
10838203945Sweongyo}
10839203945Sweongyo
10840203945Sweongyostatic void
10841203945Sweongyobwn_led_blink_next(void *arg)
10842203945Sweongyo{
10843203945Sweongyo	struct bwn_mac *mac = arg;
10844203945Sweongyo        struct bwn_softc *sc = mac->mac_sc;
10845203945Sweongyo        uint16_t val;
10846203945Sweongyo
10847203945Sweongyo        val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10848203945Sweongyo        val = bwn_led_onoff(sc->sc_blink_led, val, 0);
10849203945Sweongyo        BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10850203945Sweongyo
10851203945Sweongyo        callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
10852203945Sweongyo            bwn_led_blink_end, mac);
10853203945Sweongyo}
10854203945Sweongyo
10855203945Sweongyostatic void
10856203945Sweongyobwn_led_blink_end(void *arg)
10857203945Sweongyo{
10858203945Sweongyo	struct bwn_mac *mac = arg;
10859203945Sweongyo        struct bwn_softc *sc = mac->mac_sc;
10860203945Sweongyo
10861203945Sweongyo        sc->sc_led_blinking = 0;
10862203945Sweongyo}
10863203945Sweongyo
10864203945Sweongyostatic int
10865203945Sweongyobwn_suspend(device_t dev)
10866203945Sweongyo{
10867203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10868203945Sweongyo
10869203945Sweongyo	bwn_stop(sc, 1);
10870203945Sweongyo	return (0);
10871203945Sweongyo}
10872203945Sweongyo
10873203945Sweongyostatic int
10874203945Sweongyobwn_resume(device_t dev)
10875203945Sweongyo{
10876203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10877203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10878203945Sweongyo
10879203945Sweongyo	if (ifp->if_flags & IFF_UP)
10880203945Sweongyo		bwn_init(sc);
10881203945Sweongyo	return (0);
10882203945Sweongyo}
10883203945Sweongyo
10884203945Sweongyostatic void
10885203945Sweongyobwn_rfswitch(void *arg)
10886203945Sweongyo{
10887203945Sweongyo	struct bwn_softc *sc = arg;
10888203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
10889203945Sweongyo	int cur = 0, prev = 0;
10890203945Sweongyo
10891203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
10892203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
10893203945Sweongyo
10894203945Sweongyo	if (mac->mac_phy.rf_rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
10895203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
10896203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
10897203945Sweongyo			cur = 1;
10898203945Sweongyo	} else {
10899203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
10900203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
10901203945Sweongyo			cur = 1;
10902203945Sweongyo	}
10903203945Sweongyo
10904203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
10905203945Sweongyo		prev = 1;
10906203945Sweongyo
10907203945Sweongyo	if (cur != prev) {
10908203945Sweongyo		if (cur)
10909203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
10910203945Sweongyo		else
10911203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
10912203945Sweongyo
10913203945Sweongyo		device_printf(sc->sc_dev,
10914203945Sweongyo		    "status of RF switch is changed to %s\n",
10915203945Sweongyo		    cur ? "ON" : "OFF");
10916203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
10917203945Sweongyo			if (cur)
10918203945Sweongyo				bwn_rf_turnon(mac);
10919203945Sweongyo			else
10920203945Sweongyo				bwn_rf_turnoff(mac);
10921203945Sweongyo		}
10922203945Sweongyo	}
10923203945Sweongyo
10924203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
10925203945Sweongyo}
10926203945Sweongyo
10927203945Sweongyostatic void
10928203945Sweongyobwn_phy_lp_init_pre(struct bwn_mac *mac)
10929203945Sweongyo{
10930203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
10931203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
10932203945Sweongyo
10933203945Sweongyo	plp->plp_antenna = BWN_ANT_DEFAULT;
10934203945Sweongyo}
10935203945Sweongyo
10936203945Sweongyostatic int
10937203945Sweongyobwn_phy_lp_init(struct bwn_mac *mac)
10938203945Sweongyo{
10939203945Sweongyo	static const struct bwn_stxtable tables[] = {
10940203945Sweongyo		{ 2,  6, 0x3d, 3, 0x01 }, { 1, 12, 0x4c, 1, 0x01 },
10941203945Sweongyo		{ 1,  8, 0x50, 0, 0x7f }, { 0,  8, 0x44, 0, 0xff },
10942203945Sweongyo		{ 1,  0, 0x4a, 0, 0xff }, { 0,  4, 0x4d, 0, 0xff },
10943203945Sweongyo		{ 1,  4, 0x4e, 0, 0xff }, { 0, 12, 0x4f, 0, 0x0f },
10944203945Sweongyo		{ 1,  0, 0x4f, 4, 0x0f }, { 3,  0, 0x49, 0, 0x0f },
10945203945Sweongyo		{ 4,  3, 0x46, 4, 0x07 }, { 3, 15, 0x46, 0, 0x01 },
10946203945Sweongyo		{ 4,  0, 0x46, 1, 0x07 }, { 3,  8, 0x48, 4, 0x07 },
10947203945Sweongyo		{ 3, 11, 0x48, 0, 0x0f }, { 3,  4, 0x49, 4, 0x0f },
10948203945Sweongyo		{ 2, 15, 0x45, 0, 0x01 }, { 5, 13, 0x52, 4, 0x07 },
10949203945Sweongyo		{ 6,  0, 0x52, 7, 0x01 }, { 5,  3, 0x41, 5, 0x07 },
10950203945Sweongyo		{ 5,  6, 0x41, 0, 0x0f }, { 5, 10, 0x42, 5, 0x07 },
10951203945Sweongyo		{ 4, 15, 0x42, 0, 0x01 }, { 5,  0, 0x42, 1, 0x07 },
10952203945Sweongyo		{ 4, 11, 0x43, 4, 0x0f }, { 4,  7, 0x43, 0, 0x0f },
10953203945Sweongyo		{ 4,  6, 0x45, 1, 0x01 }, { 2,  7, 0x40, 4, 0x0f },
10954203945Sweongyo		{ 2, 11, 0x40, 0, 0x0f }
10955203945Sweongyo	};
10956203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
10957203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10958203945Sweongyo	const struct bwn_stxtable *st;
10959203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
10960203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
10961203945Sweongyo	int i, error;
10962203945Sweongyo	uint16_t tmp;
10963203945Sweongyo
10964203945Sweongyo	bwn_phy_lp_readsprom(mac);	/* XXX bad place */
10965203945Sweongyo	bwn_phy_lp_bbinit(mac);
10966203945Sweongyo
10967203945Sweongyo	/* initialize RF */
10968203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_4WIRECTL, 0x2);
10969203945Sweongyo	DELAY(1);
10970203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_4WIRECTL, 0xfffd);
10971203945Sweongyo	DELAY(1);
10972203945Sweongyo
10973203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2062)
10974203945Sweongyo		bwn_phy_lp_b2062_init(mac);
10975203945Sweongyo	else {
10976203945Sweongyo		bwn_phy_lp_b2063_init(mac);
10977203945Sweongyo
10978203945Sweongyo		/* synchronize stx table. */
10979203945Sweongyo		for (i = 0; i < N(tables); i++) {
10980203945Sweongyo			st = &tables[i];
10981203945Sweongyo			tmp = BWN_RF_READ(mac, st->st_rfaddr);
10982203945Sweongyo			tmp >>= st->st_rfshift;
10983203945Sweongyo			tmp <<= st->st_physhift;
10984203945Sweongyo			BWN_PHY_SETMASK(mac,
10985203945Sweongyo			    BWN_PHY_OFDM(0xf2 + st->st_phyoffset),
10986203945Sweongyo			    ~(st->st_mask << st->st_physhift), tmp);
10987203945Sweongyo		}
10988203945Sweongyo
10989203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf0), 0x5f80);
10990203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf1), 0);
10991203945Sweongyo	}
10992203945Sweongyo
10993203945Sweongyo	/* calibrate RC */
10994203945Sweongyo	if (mac->mac_phy.rev >= 2)
10995203945Sweongyo		bwn_phy_lp_rxcal_r2(mac);
10996203945Sweongyo	else if (!plp->plp_rccap) {
10997203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
10998203945Sweongyo			bwn_phy_lp_rccal_r12(mac);
10999203945Sweongyo	} else
11000203945Sweongyo		bwn_phy_lp_set_rccap(mac);
11001203945Sweongyo
11002203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
11003203945Sweongyo	if (error)
11004203945Sweongyo		device_printf(sc->sc_dev,
11005203945Sweongyo		    "failed to change channel 7 (%d)\n", error);
11006203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
11007203945Sweongyo	bwn_phy_lp_calib(mac);
11008203945Sweongyo	return (0);
11009203945Sweongyo}
11010203945Sweongyo
11011203945Sweongyostatic uint16_t
11012203945Sweongyobwn_phy_lp_read(struct bwn_mac *mac, uint16_t reg)
11013203945Sweongyo{
11014203945Sweongyo
11015203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
11016203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
11017203945Sweongyo}
11018203945Sweongyo
11019203945Sweongyostatic void
11020203945Sweongyobwn_phy_lp_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
11021203945Sweongyo{
11022203945Sweongyo
11023203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
11024203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
11025203945Sweongyo}
11026203945Sweongyo
11027203945Sweongyostatic void
11028203945Sweongyobwn_phy_lp_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
11029203945Sweongyo    uint16_t set)
11030203945Sweongyo{
11031203945Sweongyo
11032203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
11033203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA,
11034203945Sweongyo	    (BWN_READ_2(mac, BWN_PHYDATA) & mask) | set);
11035203945Sweongyo}
11036203945Sweongyo
11037203945Sweongyostatic uint16_t
11038203945Sweongyobwn_phy_lp_rf_read(struct bwn_mac *mac, uint16_t reg)
11039203945Sweongyo{
11040203945Sweongyo
11041203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
11042203945Sweongyo	if (mac->mac_phy.rev < 2 && reg != 0x4001)
11043203945Sweongyo		reg |= 0x100;
11044203945Sweongyo	if (mac->mac_phy.rev >= 2)
11045203945Sweongyo		reg |= 0x200;
11046203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
11047203945Sweongyo	return BWN_READ_2(mac, BWN_RFDATALO);
11048203945Sweongyo}
11049203945Sweongyo
11050203945Sweongyostatic void
11051203945Sweongyobwn_phy_lp_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
11052203945Sweongyo{
11053203945Sweongyo
11054203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
11055203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
11056203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
11057203945Sweongyo}
11058203945Sweongyo
11059203945Sweongyostatic void
11060203945Sweongyobwn_phy_lp_rf_onoff(struct bwn_mac *mac, int on)
11061203945Sweongyo{
11062203945Sweongyo
11063203945Sweongyo	if (on) {
11064203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xe0ff);
11065203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2,
11066203945Sweongyo		    (mac->mac_phy.rev >= 2) ? 0xf7f7 : 0xffe7);
11067203945Sweongyo		return;
11068203945Sweongyo	}
11069203945Sweongyo
11070203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11071203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x83ff);
11072203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
11073203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0x80ff);
11074203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xdfff);
11075203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0808);
11076203945Sweongyo		return;
11077203945Sweongyo	}
11078203945Sweongyo
11079203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xe0ff);
11080203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
11081203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfcff);
11082203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0018);
11083203945Sweongyo}
11084203945Sweongyo
11085203945Sweongyostatic int
11086203945Sweongyobwn_phy_lp_switch_channel(struct bwn_mac *mac, uint32_t chan)
11087203945Sweongyo{
11088203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11089203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11090203945Sweongyo	int error;
11091203945Sweongyo
11092203945Sweongyo	if (phy->rf_ver == 0x2063) {
11093203945Sweongyo		error = bwn_phy_lp_b2063_switch_channel(mac, chan);
11094203945Sweongyo		if (error)
11095203945Sweongyo			return (error);
11096203945Sweongyo	} else {
11097203945Sweongyo		error = bwn_phy_lp_b2062_switch_channel(mac, chan);
11098203945Sweongyo		if (error)
11099203945Sweongyo			return (error);
11100203945Sweongyo		bwn_phy_lp_set_anafilter(mac, chan);
11101203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, ieee80211_ieee2mhz(chan, 0));
11102203945Sweongyo	}
11103203945Sweongyo
11104203945Sweongyo	plp->plp_chan = chan;
11105203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, chan);
11106203945Sweongyo	return (0);
11107203945Sweongyo}
11108203945Sweongyo
11109203945Sweongyostatic uint32_t
11110203945Sweongyobwn_phy_lp_get_default_chan(struct bwn_mac *mac)
11111203945Sweongyo{
11112203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11113203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11114203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11115203945Sweongyo
11116203945Sweongyo	device_printf(sc->sc_dev, "correct?\n");
11117203945Sweongyo
11118203945Sweongyo	return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36);
11119203945Sweongyo}
11120203945Sweongyo
11121203945Sweongyostatic void
11122203945Sweongyobwn_phy_lp_set_antenna(struct bwn_mac *mac, int antenna)
11123203945Sweongyo{
11124203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
11125203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
11126203945Sweongyo
11127203945Sweongyo	if (phy->rev >= 2 || antenna > BWN_ANTAUTO1)
11128203945Sweongyo		return;
11129203945Sweongyo
11130203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER);
11131203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffd, antenna & 0x2);
11132203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffe, antenna & 0x1);
11133203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_UCODE_ANTDIV_HELPER);
11134203945Sweongyo	plp->plp_antenna = antenna;
11135203945Sweongyo}
11136203945Sweongyo
11137203945Sweongyostatic void
11138203945Sweongyobwn_phy_lp_task_60s(struct bwn_mac *mac)
11139203945Sweongyo{
11140203945Sweongyo
11141203945Sweongyo	bwn_phy_lp_calib(mac);
11142203945Sweongyo}
11143203945Sweongyo
11144203945Sweongyostatic void
11145203945Sweongyobwn_phy_lp_readsprom(struct bwn_mac *mac)
11146203945Sweongyo{
11147203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11148203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11149203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11150203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11151203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11152203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11153203945Sweongyo	struct siba_sprom *sprom = &siba->siba_sprom;
11154203945Sweongyo
11155203945Sweongyo	device_printf(sc->sc_dev, "XXX using %dghz\n",
11156203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2 : 5);
11157203945Sweongyo
11158203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11159203945Sweongyo		plp->plp_txisoband_m = sprom->tri2g;
11160203945Sweongyo		plp->plp_bxarch = sprom->bxa2g;
11161203945Sweongyo		plp->plp_rxpwroffset = sprom->rxpo2g;
11162203945Sweongyo		plp->plp_rssivf = sprom->rssismf2g;
11163203945Sweongyo		plp->plp_rssivc = sprom->rssismc2g;
11164203945Sweongyo		plp->plp_rssigs = sprom->rssisav2g;
11165203945Sweongyo		return;
11166203945Sweongyo	}
11167203945Sweongyo
11168203945Sweongyo	plp->plp_txisoband_l = sprom->tri5gl;
11169203945Sweongyo	plp->plp_txisoband_m = sprom->tri5g;
11170203945Sweongyo	plp->plp_txisoband_h = sprom->tri5gh;
11171203945Sweongyo	plp->plp_bxarch = sprom->bxa5g;
11172203945Sweongyo	plp->plp_rxpwroffset = sprom->rxpo5g;
11173203945Sweongyo	plp->plp_rssivf = sprom->rssismf5g;
11174203945Sweongyo	plp->plp_rssivc = sprom->rssismc5g;
11175203945Sweongyo	plp->plp_rssigs = sprom->rssisav5g;
11176203945Sweongyo}
11177203945Sweongyo
11178203945Sweongyostatic void
11179203945Sweongyobwn_phy_lp_bbinit(struct bwn_mac *mac)
11180203945Sweongyo{
11181203945Sweongyo
11182203945Sweongyo	bwn_phy_lp_tblinit(mac);
11183203945Sweongyo	if (mac->mac_phy.rev >= 2)
11184203945Sweongyo		bwn_phy_lp_bbinit_r2(mac);
11185203945Sweongyo	else
11186203945Sweongyo		bwn_phy_lp_bbinit_r01(mac);
11187203945Sweongyo}
11188203945Sweongyo
11189203945Sweongyostatic void
11190203945Sweongyobwn_phy_lp_txpctl_init(struct bwn_mac *mac)
11191203945Sweongyo{
11192203945Sweongyo	struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 };
11193203945Sweongyo	struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 };
11194203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11195203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11196203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11197203945Sweongyo
11198203945Sweongyo	bwn_phy_lp_set_txgain(mac,
11199203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz);
11200203945Sweongyo	bwn_phy_lp_set_bbmult(mac, 150);
11201203945Sweongyo}
11202203945Sweongyo
11203203945Sweongyostatic void
11204203945Sweongyobwn_phy_lp_calib(struct bwn_mac *mac)
11205203945Sweongyo{
11206203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11207203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11208203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11209203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11210203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11211203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11212203945Sweongyo	const struct bwn_rxcompco *rc = NULL;
11213203945Sweongyo	struct bwn_txgain ogain;
11214203945Sweongyo	int i, omode, oafeovr, orf, obbmult;
11215203945Sweongyo	uint8_t mode, fc = 0;
11216203945Sweongyo
11217203945Sweongyo	if (plp->plp_chanfullcal != plp->plp_chan) {
11218203945Sweongyo		plp->plp_chanfullcal = plp->plp_chan;
11219203945Sweongyo		fc = 1;
11220203945Sweongyo	}
11221203945Sweongyo
11222203945Sweongyo	bwn_mac_suspend(mac);
11223203945Sweongyo
11224203945Sweongyo	/* BlueTooth Coexistance Override */
11225203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_CTL, 0x3);
11226203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_TXCTL, 0xff);
11227203945Sweongyo
11228203945Sweongyo	if (mac->mac_phy.rev >= 2)
11229203945Sweongyo		bwn_phy_lp_digflt_save(mac);
11230203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11231203945Sweongyo	mode = plp->plp_txpctlmode;
11232203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11233203945Sweongyo	if (mac->mac_phy.rev == 0 && mode != BWN_PHYLP_TXPCTL_OFF)
11234203945Sweongyo		bwn_phy_lp_bugfix(mac);
11235203945Sweongyo	if (mac->mac_phy.rev >= 2 && fc == 1) {
11236203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11237203945Sweongyo		omode = plp->plp_txpctlmode;
11238203945Sweongyo		oafeovr = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40;
11239203945Sweongyo		if (oafeovr)
11240203945Sweongyo			ogain = bwn_phy_lp_get_txgain(mac);
11241203945Sweongyo		orf = BWN_PHY_READ(mac, BWN_PHY_RF_PWR_OVERRIDE) & 0xff;
11242203945Sweongyo		obbmult = bwn_phy_lp_get_bbmult(mac);
11243203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11244203945Sweongyo		if (oafeovr)
11245203945Sweongyo			bwn_phy_lp_set_txgain(mac, &ogain);
11246203945Sweongyo		bwn_phy_lp_set_bbmult(mac, obbmult);
11247203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, omode);
11248203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00, orf);
11249203945Sweongyo	}
11250203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11251203945Sweongyo	if (mac->mac_phy.rev >= 2)
11252203945Sweongyo		bwn_phy_lp_digflt_restore(mac);
11253203945Sweongyo
11254203945Sweongyo	/* do RX IQ Calculation; assumes that noise is true. */
11255203945Sweongyo	if (siba->siba_chipid == 0x5354) {
11256203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_5354); i++) {
11257203945Sweongyo			if (bwn_rxcompco_5354[i].rc_chan == plp->plp_chan)
11258203945Sweongyo				rc = &bwn_rxcompco_5354[i];
11259203945Sweongyo		}
11260203945Sweongyo	} else if (mac->mac_phy.rev >= 2)
11261203945Sweongyo		rc = &bwn_rxcompco_r2;
11262203945Sweongyo	else {
11263203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_r12); i++) {
11264203945Sweongyo			if (bwn_rxcompco_r12[i].rc_chan == plp->plp_chan)
11265203945Sweongyo				rc = &bwn_rxcompco_r12[i];
11266203945Sweongyo		}
11267203945Sweongyo	}
11268203945Sweongyo	if (rc == NULL)
11269203945Sweongyo		goto fail;
11270203945Sweongyo
11271203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, rc->rc_c1);
11272203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, rc->rc_c0 << 8);
11273203945Sweongyo
11274203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1 /* TX */, 0 /* RX */);
11275203945Sweongyo
11276203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11277203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
11278203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7, 0);
11279203945Sweongyo	} else {
11280203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
11281203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf, 0);
11282203945Sweongyo	}
11283203945Sweongyo
11284203945Sweongyo	bwn_phy_lp_set_rxgain(mac, 0x2d5d);
11285203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11286203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
11287203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
11288203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
11289203945Sweongyo	bwn_phy_lp_set_deaf(mac, 0);
11290203945Sweongyo	/* XXX no checking return value? */
11291203945Sweongyo	(void)bwn_phy_lp_calc_rx_iq_comp(mac, 0xfff0);
11292203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 0);
11293203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffc);
11294203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfff7);
11295203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffdf);
11296203945Sweongyo
11297203945Sweongyo	/* disable RX GAIN override. */
11298203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffe);
11299203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffef);
11300203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffbf);
11301203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11302203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11303203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11304203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfbff);
11305203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xe5), 0xfff7);
11306203945Sweongyo		}
11307203945Sweongyo	} else {
11308203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfdff);
11309203945Sweongyo	}
11310203945Sweongyo
11311203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11312203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xf7ff);
11313203945Sweongyofail:
11314203945Sweongyo	bwn_mac_enable(mac);
11315203945Sweongyo}
11316203945Sweongyo
11317203945Sweongyostatic void
11318203945Sweongyobwn_phy_lp_switch_analog(struct bwn_mac *mac, int on)
11319203945Sweongyo{
11320203945Sweongyo
11321203945Sweongyo       if (on) {
11322203945Sweongyo               BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfff8);
11323203945Sweongyo	       return;
11324203945Sweongyo       }
11325203945Sweongyo
11326203945Sweongyo       BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVRVAL, 0x0007);
11327203945Sweongyo       BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x0007);
11328203945Sweongyo}
11329203945Sweongyo
11330203945Sweongyostatic int
11331203945Sweongyobwn_phy_lp_b2063_switch_channel(struct bwn_mac *mac, uint8_t chan)
11332203945Sweongyo{
11333203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11334203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11335203945Sweongyo	static const struct bwn_b206x_chan *bc = NULL;
11336203945Sweongyo	uint32_t count, freqref, freqvco, freqxtal, val[3], timeout, timeoutref,
11337203945Sweongyo	    tmp[6];
11338203945Sweongyo	uint16_t old, scale, tmp16;
11339203945Sweongyo	int i, div;
11340203945Sweongyo
11341203945Sweongyo	for (i = 0; i < N(bwn_b2063_chantable); i++) {
11342203945Sweongyo		if (bwn_b2063_chantable[i].bc_chan == chan) {
11343203945Sweongyo			bc = &bwn_b2063_chantable[i];
11344203945Sweongyo			break;
11345203945Sweongyo		}
11346203945Sweongyo	}
11347203945Sweongyo	if (bc == NULL)
11348203945Sweongyo		return (EINVAL);
11349203945Sweongyo
11350203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_VCOBUF1, bc->bc_data[0]);
11351203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_MIXER2, bc->bc_data[1]);
11352203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_BUF2, bc->bc_data[2]);
11353203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_RCCR1, bc->bc_data[3]);
11354203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_1ST3, bc->bc_data[4]);
11355203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND1, bc->bc_data[5]);
11356203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND4, bc->bc_data[6]);
11357203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND7, bc->bc_data[7]);
11358203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_PS6, bc->bc_data[8]);
11359203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL2, bc->bc_data[9]);
11360203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL5, bc->bc_data[10]);
11361203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_CTL11, bc->bc_data[11]);
11362203945Sweongyo
11363203945Sweongyo	old = BWN_RF_READ(mac, BWN_B2063_COM15);
11364203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM15, 0x1e);
11365203945Sweongyo
11366203945Sweongyo	freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
11367203945Sweongyo	freqvco = bc->bc_freq << ((bc->bc_freq > 4000) ? 1 : 2);
11368203945Sweongyo	freqref = freqxtal * 3;
11369203945Sweongyo	div = (freqxtal <= 26000000 ? 1 : 2);
11370203945Sweongyo	timeout = ((((8 * freqxtal) / (div * 5000000)) + 1) >> 1) - 1;
11371203945Sweongyo	timeoutref = ((((8 * freqxtal) / (div * (timeout + 1))) +
11372203945Sweongyo		999999) / 1000000) + 1;
11373203945Sweongyo
11374203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB3, 0x2);
11375203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB6,
11376203945Sweongyo	    0xfff8, timeout >> 2);
11377203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11378203945Sweongyo	    0xff9f,timeout << 5);
11379203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB5, timeoutref);
11380203945Sweongyo
11381203945Sweongyo	val[0] = bwn_phy_lp_roundup(freqxtal, 1000000, 16);
11382203945Sweongyo	val[1] = bwn_phy_lp_roundup(freqxtal, 1000000 * div, 16);
11383203945Sweongyo	val[2] = bwn_phy_lp_roundup(freqvco, 3, 16);
11384203945Sweongyo
11385203945Sweongyo	count = (bwn_phy_lp_roundup(val[2], val[1] + 16, 16) * (timeout + 1) *
11386203945Sweongyo	    (timeoutref + 1)) - 1;
11387203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11388203945Sweongyo	    0xf0, count >> 8);
11389203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB8, count & 0xff);
11390203945Sweongyo
11391203945Sweongyo	tmp[0] = ((val[2] * 62500) / freqref) << 4;
11392203945Sweongyo	tmp[1] = ((val[2] * 62500) % freqref) << 4;
11393203945Sweongyo	while (tmp[1] >= freqref) {
11394203945Sweongyo		tmp[0]++;
11395203945Sweongyo		tmp[1] -= freqref;
11396203945Sweongyo	}
11397203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG1, 0xffe0, tmp[0] >> 4);
11398203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfe0f, tmp[0] << 4);
11399203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfff0, tmp[0] >> 16);
11400203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG3, (tmp[1] >> 8) & 0xff);
11401203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG4, tmp[1] & 0xff);
11402203945Sweongyo
11403203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF1, 0xb9);
11404203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF2, 0x88);
11405203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF3, 0x28);
11406203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF4, 0x63);
11407203945Sweongyo
11408203945Sweongyo	tmp[2] = ((41 * (val[2] - 3000)) /1200) + 27;
11409203945Sweongyo	tmp[3] = bwn_phy_lp_roundup(132000 * tmp[0], 8451, 16);
11410203945Sweongyo
11411203945Sweongyo	if ((tmp[3] + tmp[2] - 1) / tmp[2] > 60) {
11412203945Sweongyo		scale = 1;
11413203945Sweongyo		tmp[4] = ((tmp[3] + tmp[2]) / (tmp[2] << 1)) - 8;
11414203945Sweongyo	} else {
11415203945Sweongyo		scale = 0;
11416203945Sweongyo		tmp[4] = ((tmp[3] + (tmp[2] >> 1)) / tmp[2]) - 8;
11417203945Sweongyo	}
11418203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffc0, tmp[4]);
11419203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffbf, scale << 6);
11420203945Sweongyo
11421203945Sweongyo	tmp[5] = bwn_phy_lp_roundup(100 * val[0], val[2], 16) * (tmp[4] * 8) *
11422203945Sweongyo	    (scale + 1);
11423203945Sweongyo	if (tmp[5] > 150)
11424203945Sweongyo		tmp[5] = 0;
11425203945Sweongyo
11426203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffe0, tmp[5]);
11427203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffdf, scale << 5);
11428203945Sweongyo
11429203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfffb, 0x4);
11430203945Sweongyo	if (freqxtal > 26000000)
11431203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_XTAL_12, 0x2);
11432203945Sweongyo	else
11433203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfd);
11434203945Sweongyo
11435203945Sweongyo	if (val[0] == 45)
11436203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_VCO1, 0x2);
11437203945Sweongyo	else
11438203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_VCO1, 0xfd);
11439203945Sweongyo
11440203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP2, 0x3);
11441203945Sweongyo	DELAY(1);
11442203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP2, 0xfffc);
11443203945Sweongyo
11444203945Sweongyo	/* VCO Calibration */
11445203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, ~0x40);
11446203945Sweongyo	tmp16 = BWN_RF_READ(mac, BWN_B2063_JTAG_CALNRST) & 0xf8;
11447203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16);
11448203945Sweongyo	DELAY(1);
11449203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x4);
11450203945Sweongyo	DELAY(1);
11451203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x6);
11452203945Sweongyo	DELAY(1);
11453203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x7);
11454203945Sweongyo	DELAY(300);
11455203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP1, 0x40);
11456203945Sweongyo
11457203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_COM15, old);
11458203945Sweongyo	return (0);
11459203945Sweongyo}
11460203945Sweongyo
11461203945Sweongyostatic int
11462203945Sweongyobwn_phy_lp_b2062_switch_channel(struct bwn_mac *mac, uint8_t chan)
11463203945Sweongyo{
11464203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11465203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11466203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11467203945Sweongyo	const struct bwn_b206x_chan *bc = NULL;
11468203945Sweongyo	uint32_t freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
11469203945Sweongyo	uint32_t tmp[9];
11470203945Sweongyo	int i;
11471203945Sweongyo
11472203945Sweongyo	for (i = 0; i < N(bwn_b2062_chantable); i++) {
11473203945Sweongyo		if (bwn_b2062_chantable[i].bc_chan == chan) {
11474203945Sweongyo			bc = &bwn_b2062_chantable[i];
11475203945Sweongyo			break;
11476203945Sweongyo		}
11477203945Sweongyo	}
11478203945Sweongyo
11479203945Sweongyo	if (bc == NULL)
11480203945Sweongyo		return (EINVAL);
11481203945Sweongyo
11482203945Sweongyo	BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL14, 0x04);
11483203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE0, bc->bc_data[0]);
11484203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE2, bc->bc_data[1]);
11485203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE3, bc->bc_data[2]);
11486203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_TUNE, bc->bc_data[3]);
11487203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_LGENG_CTL1, bc->bc_data[4]);
11488203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL5, bc->bc_data[5]);
11489203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL6, bc->bc_data[6]);
11490203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PGA, bc->bc_data[7]);
11491203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PAD, bc->bc_data[8]);
11492203945Sweongyo
11493203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xcc);
11494203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0x07);
11495203945Sweongyo	bwn_phy_lp_b2062_reset_pllbias(mac);
11496203945Sweongyo	tmp[0] = freqxtal / 1000;
11497203945Sweongyo	tmp[1] = plp->plp_div * 1000;
11498203945Sweongyo	tmp[2] = tmp[1] * ieee80211_ieee2mhz(chan, 0);
11499203945Sweongyo	if (ieee80211_ieee2mhz(chan, 0) < 4000)
11500203945Sweongyo		tmp[2] *= 2;
11501203945Sweongyo	tmp[3] = 48 * tmp[0];
11502203945Sweongyo	tmp[5] = tmp[2] / tmp[3];
11503203945Sweongyo	tmp[6] = tmp[2] % tmp[3];
11504203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL26, tmp[5]);
11505203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11506203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11507203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11508203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL27, tmp[5]);
11509203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11510203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11511203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11512203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL28, tmp[5]);
11513203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11514203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11515203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11516203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL29,
11517203945Sweongyo	    tmp[5] + ((2 * tmp[6]) / tmp[3]));
11518203945Sweongyo	tmp[7] = BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL19);
11519203945Sweongyo	tmp[8] = ((2 * tmp[2] * (tmp[7] + 1)) + (3 * tmp[0])) / (6 * tmp[0]);
11520203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL23, (tmp[8] >> 8) + 16);
11521203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL24, tmp[8] & 0xff);
11522203945Sweongyo
11523203945Sweongyo	bwn_phy_lp_b2062_vco_calib(mac);
11524203945Sweongyo	if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11525203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xfc);
11526203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0);
11527203945Sweongyo		bwn_phy_lp_b2062_reset_pllbias(mac);
11528203945Sweongyo		bwn_phy_lp_b2062_vco_calib(mac);
11529203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11530203945Sweongyo			BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11531203945Sweongyo			return (EIO);
11532203945Sweongyo		}
11533203945Sweongyo	}
11534203945Sweongyo	BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11535203945Sweongyo	return (0);
11536203945Sweongyo}
11537203945Sweongyo
11538203945Sweongyostatic void
11539203945Sweongyobwn_phy_lp_set_anafilter(struct bwn_mac *mac, uint8_t channel)
11540203945Sweongyo{
11541203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11542203945Sweongyo	uint16_t tmp = (channel == 14);
11543203945Sweongyo
11544203945Sweongyo	if (mac->mac_phy.rev < 2) {
11545203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xfcff, tmp << 9);
11546203945Sweongyo		if ((mac->mac_phy.rev == 1) && (plp->plp_rccap))
11547203945Sweongyo			bwn_phy_lp_set_rccap(mac);
11548203945Sweongyo		return;
11549203945Sweongyo	}
11550203945Sweongyo
11551203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, 0x3f);
11552203945Sweongyo}
11553203945Sweongyo
11554203945Sweongyostatic void
11555203945Sweongyobwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq)
11556203945Sweongyo{
11557203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11558203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11559203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11560203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11561203945Sweongyo	uint16_t iso, tmp[3];
11562203945Sweongyo
11563203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
11564203945Sweongyo
11565203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
11566203945Sweongyo		iso = plp->plp_txisoband_m;
11567203945Sweongyo	else if (freq <= 5320)
11568203945Sweongyo		iso = plp->plp_txisoband_l;
11569203945Sweongyo	else if (freq <= 5700)
11570203945Sweongyo		iso = plp->plp_txisoband_m;
11571203945Sweongyo	else
11572203945Sweongyo		iso = plp->plp_txisoband_h;
11573203945Sweongyo
11574203945Sweongyo	tmp[0] = ((iso - 26) / 12) << 12;
11575203945Sweongyo	tmp[1] = tmp[0] + 0x1000;
11576203945Sweongyo	tmp[2] = tmp[0] + 0x2000;
11577203945Sweongyo
11578203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), 3, tmp);
11579203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), 3, tmp);
11580203945Sweongyo}
11581203945Sweongyo
11582203945Sweongyostatic void
11583203945Sweongyobwn_phy_lp_digflt_save(struct bwn_mac *mac)
11584203945Sweongyo{
11585203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11586203945Sweongyo	int i;
11587203945Sweongyo	static const uint16_t addr[] = {
11588203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11589203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11590203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11591203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11592203945Sweongyo		BWN_PHY_OFDM(0xcf),
11593203945Sweongyo	};
11594203945Sweongyo	static const uint16_t val[] = {
11595203945Sweongyo		0xde5e, 0xe832, 0xe331, 0x4d26,
11596203945Sweongyo		0x0026, 0x1420, 0x0020, 0xfe08,
11597203945Sweongyo		0x0008,
11598203945Sweongyo	};
11599203945Sweongyo
11600203945Sweongyo	for (i = 0; i < N(addr); i++) {
11601203945Sweongyo		plp->plp_digfilt[i] = BWN_PHY_READ(mac, addr[i]);
11602203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], val[i]);
11603203945Sweongyo	}
11604203945Sweongyo}
11605203945Sweongyo
11606203945Sweongyostatic void
11607203945Sweongyobwn_phy_lp_get_txpctlmode(struct bwn_mac *mac)
11608203945Sweongyo{
11609203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11610203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11611203945Sweongyo	uint16_t ctl;
11612203945Sweongyo
11613203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_TX_PWR_CTL_CMD);
11614203945Sweongyo	switch (ctl & BWN_PHY_TX_PWR_CTL_CMD_MODE) {
11615203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF:
11616203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_OFF;
11617203945Sweongyo		break;
11618203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_SW:
11619203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_SW;
11620203945Sweongyo		break;
11621203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_HW:
11622203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_HW;
11623203945Sweongyo		break;
11624203945Sweongyo	default:
11625203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_UNKNOWN;
11626203945Sweongyo		device_printf(sc->sc_dev, "unknown command mode\n");
11627203945Sweongyo		break;
11628203945Sweongyo	}
11629203945Sweongyo}
11630203945Sweongyo
11631203945Sweongyostatic void
11632203945Sweongyobwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
11633203945Sweongyo{
11634203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11635203945Sweongyo	uint16_t ctl;
11636203945Sweongyo	uint8_t old;
11637203945Sweongyo
11638203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11639203945Sweongyo	old = plp->plp_txpctlmode;
11640203945Sweongyo	if (old == mode)
11641203945Sweongyo		return;
11642203945Sweongyo	plp->plp_txpctlmode = mode;
11643203945Sweongyo
11644203945Sweongyo	if (old != BWN_PHYLP_TXPCTL_ON_HW && mode == BWN_PHYLP_TXPCTL_ON_HW) {
11645203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD, 0xff80,
11646203945Sweongyo		    plp->plp_tssiidx);
11647203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_NNUM,
11648203945Sweongyo		    0x8fff, ((uint16_t)plp->plp_tssinpt << 16));
11649203945Sweongyo
11650203945Sweongyo		/* disable TX GAIN override */
11651203945Sweongyo		if (mac->mac_phy.rev < 2)
11652203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11653203945Sweongyo		else {
11654203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xff7f);
11655203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xbfff);
11656203945Sweongyo		}
11657203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xffbf);
11658203945Sweongyo
11659203945Sweongyo		plp->plp_txpwridx = -1;
11660203945Sweongyo	}
11661203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11662203945Sweongyo		if (mode == BWN_PHYLP_TXPCTL_ON_HW)
11663203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xd0), 0x2);
11664203945Sweongyo		else
11665203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xd0), 0xfffd);
11666203945Sweongyo	}
11667203945Sweongyo
11668203945Sweongyo	/* writes TX Power Control mode */
11669203945Sweongyo	switch (plp->plp_txpctlmode) {
11670203945Sweongyo	case BWN_PHYLP_TXPCTL_OFF:
11671203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF;
11672203945Sweongyo		break;
11673203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_HW:
11674203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_HW;
11675203945Sweongyo		break;
11676203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_SW:
11677203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
11678203945Sweongyo		break;
11679203945Sweongyo	default:
11680203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
11681203945Sweongyo	}
11682203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
11683203945Sweongyo	    (uint16_t)~BWN_PHY_TX_PWR_CTL_CMD_MODE, ctl);
11684203945Sweongyo}
11685203945Sweongyo
11686203945Sweongyostatic void
11687203945Sweongyobwn_phy_lp_bugfix(struct bwn_mac *mac)
11688203945Sweongyo{
11689203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11690203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11691203945Sweongyo	const unsigned int size = 256;
11692203945Sweongyo	struct bwn_txgain tg;
11693203945Sweongyo	uint32_t rxcomp, txgain, coeff, rfpwr, *tabs;
11694203945Sweongyo	uint16_t tssinpt, tssiidx, value[2];
11695203945Sweongyo	uint8_t mode;
11696203945Sweongyo	int8_t txpwridx;
11697203945Sweongyo
11698203945Sweongyo	tabs = (uint32_t *)malloc(sizeof(uint32_t) * size, M_DEVBUF,
11699203945Sweongyo	    M_NOWAIT | M_ZERO);
11700203945Sweongyo	if (tabs == NULL) {
11701203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer.\n");
11702203945Sweongyo		return;
11703203945Sweongyo	}
11704203945Sweongyo
11705203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11706203945Sweongyo	mode = plp->plp_txpctlmode;
11707203945Sweongyo	txpwridx = plp->plp_txpwridx;
11708203945Sweongyo	tssinpt = plp->plp_tssinpt;
11709203945Sweongyo	tssiidx = plp->plp_tssiidx;
11710203945Sweongyo
11711203945Sweongyo	bwn_tab_read_multi(mac,
11712203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11713203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11714203945Sweongyo
11715203945Sweongyo	bwn_phy_lp_tblinit(mac);
11716203945Sweongyo	bwn_phy_lp_bbinit(mac);
11717203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
11718203945Sweongyo	bwn_phy_lp_rf_onoff(mac, 1);
11719203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11720203945Sweongyo
11721203945Sweongyo	bwn_tab_write_multi(mac,
11722203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11723203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11724203945Sweongyo
11725203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, plp->plp_chan);
11726203945Sweongyo	plp->plp_tssinpt = tssinpt;
11727203945Sweongyo	plp->plp_tssiidx = tssiidx;
11728203945Sweongyo	bwn_phy_lp_set_anafilter(mac, plp->plp_chan);
11729203945Sweongyo	if (txpwridx != -1) {
11730203945Sweongyo		/* set TX power by index */
11731203945Sweongyo		plp->plp_txpwridx = txpwridx;
11732203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11733203945Sweongyo		if (plp->plp_txpctlmode != BWN_PHYLP_TXPCTL_OFF)
11734203945Sweongyo			bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_ON_SW);
11735203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11736203945Sweongyo			rxcomp = bwn_tab_read(mac,
11737203945Sweongyo			    BWN_TAB_4(7, txpwridx + 320));
11738203945Sweongyo			txgain = bwn_tab_read(mac,
11739203945Sweongyo			    BWN_TAB_4(7, txpwridx + 192));
11740203945Sweongyo			tg.tg_pad = (txgain >> 16) & 0xff;
11741203945Sweongyo			tg.tg_gm = txgain & 0xff;
11742203945Sweongyo			tg.tg_pga = (txgain >> 8) & 0xff;
11743203945Sweongyo			tg.tg_dac = (rxcomp >> 28) & 0xff;
11744203945Sweongyo			bwn_phy_lp_set_txgain(mac, &tg);
11745203945Sweongyo		} else {
11746203945Sweongyo			rxcomp = bwn_tab_read(mac,
11747203945Sweongyo			    BWN_TAB_4(10, txpwridx + 320));
11748203945Sweongyo			txgain = bwn_tab_read(mac,
11749203945Sweongyo			    BWN_TAB_4(10, txpwridx + 192));
11750203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
11751203945Sweongyo			    0xf800, (txgain >> 4) & 0x7fff);
11752203945Sweongyo			bwn_phy_lp_set_txgain_dac(mac, txgain & 0x7);
11753203945Sweongyo			bwn_phy_lp_set_txgain_pa(mac, (txgain >> 24) & 0x7f);
11754203945Sweongyo		}
11755203945Sweongyo		bwn_phy_lp_set_bbmult(mac, (rxcomp >> 20) & 0xff);
11756203945Sweongyo
11757203945Sweongyo		/* set TX IQCC */
11758203945Sweongyo		value[0] = (rxcomp >> 10) & 0x3ff;
11759203945Sweongyo		value[1] = rxcomp & 0x3ff;
11760203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(0, 80), 2, value);
11761203945Sweongyo
11762203945Sweongyo		coeff = bwn_tab_read(mac,
11763203945Sweongyo		    (mac->mac_phy.rev >= 2) ? BWN_TAB_4(7, txpwridx + 448) :
11764203945Sweongyo		    BWN_TAB_4(10, txpwridx + 448));
11765203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0, 85), coeff & 0xffff);
11766203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11767203945Sweongyo			rfpwr = bwn_tab_read(mac,
11768203945Sweongyo			    BWN_TAB_4(7, txpwridx + 576));
11769203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00,
11770203945Sweongyo			    rfpwr & 0xffff);
11771203945Sweongyo		}
11772203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
11773203945Sweongyo	}
11774203945Sweongyo	if (plp->plp_rccap)
11775203945Sweongyo		bwn_phy_lp_set_rccap(mac);
11776203945Sweongyo	bwn_phy_lp_set_antenna(mac, plp->plp_antenna);
11777203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11778203945Sweongyo	free(tabs, M_DEVBUF);
11779203945Sweongyo}
11780203945Sweongyo
11781203945Sweongyostatic void
11782203945Sweongyobwn_phy_lp_digflt_restore(struct bwn_mac *mac)
11783203945Sweongyo{
11784203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11785203945Sweongyo	int i;
11786203945Sweongyo	static const uint16_t addr[] = {
11787203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11788203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11789203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11790203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11791203945Sweongyo		BWN_PHY_OFDM(0xcf),
11792203945Sweongyo	};
11793203945Sweongyo
11794203945Sweongyo	for (i = 0; i < N(addr); i++)
11795203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], plp->plp_digfilt[i]);
11796203945Sweongyo}
11797203945Sweongyo
11798203945Sweongyostatic void
11799203945Sweongyobwn_phy_lp_tblinit(struct bwn_mac *mac)
11800203945Sweongyo{
11801203945Sweongyo	uint32_t freq = ieee80211_ieee2mhz(bwn_phy_lp_get_default_chan(mac), 0);
11802203945Sweongyo
11803203945Sweongyo	if (mac->mac_phy.rev < 2) {
11804203945Sweongyo		bwn_phy_lp_tblinit_r01(mac);
11805203945Sweongyo		bwn_phy_lp_tblinit_txgain(mac);
11806203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, freq);
11807203945Sweongyo		return;
11808203945Sweongyo	}
11809203945Sweongyo
11810203945Sweongyo	bwn_phy_lp_tblinit_r2(mac);
11811203945Sweongyo	bwn_phy_lp_tblinit_txgain(mac);
11812203945Sweongyo}
11813203945Sweongyo
11814203945Sweongyostruct bwn_wpair {
11815203945Sweongyo	uint16_t		reg;
11816203945Sweongyo	uint16_t		value;
11817203945Sweongyo};
11818203945Sweongyo
11819203945Sweongyostruct bwn_smpair {
11820203945Sweongyo	uint16_t		offset;
11821203945Sweongyo	uint16_t		mask;
11822203945Sweongyo	uint16_t		set;
11823203945Sweongyo};
11824203945Sweongyo
11825203945Sweongyostatic void
11826203945Sweongyobwn_phy_lp_bbinit_r2(struct bwn_mac *mac)
11827203945Sweongyo{
11828203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11829203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11830203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11831203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11832203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11833203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11834203945Sweongyo	static const struct bwn_wpair v1[] = {
11835203945Sweongyo		{ BWN_PHY_AFE_DAC_CTL, 0x50 },
11836203945Sweongyo		{ BWN_PHY_AFE_CTL, 0x8800 },
11837203945Sweongyo		{ BWN_PHY_AFE_CTL_OVR, 0 },
11838203945Sweongyo		{ BWN_PHY_AFE_CTL_OVRVAL, 0 },
11839203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_0, 0 },
11840203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_2, 0 },
11841203945Sweongyo		{ BWN_PHY_OFDM(0xf9), 0 },
11842203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0 }
11843203945Sweongyo	};
11844203945Sweongyo	static const struct bwn_smpair v2[] = {
11845203945Sweongyo		{ BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0xb4 },
11846203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xf8ff, 0x200 },
11847203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xff00, 0x7f },
11848203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xff0f, 0x40 },
11849203945Sweongyo		{ BWN_PHY_PREAMBLECONFIRMTO, 0xff00, 0x2 }
11850203945Sweongyo	};
11851203945Sweongyo	static const struct bwn_smpair v3[] = {
11852203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xffe0, 0x1f },
11853203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11854203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0xff00, 0x19 },
11855203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0x03ff, 0x3c00 },
11856203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xfc1f, 0x3e0 },
11857203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11858203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0x00ff, 0x1900 },
11859203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800 },
11860203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x12 },
11861203945Sweongyo		{ BWN_PHY_GAINMISMATCH, 0x0fff, 0x9000 },
11862203945Sweongyo
11863203945Sweongyo	};
11864203945Sweongyo	int i;
11865203945Sweongyo
11866203945Sweongyo	for (i = 0; i < N(v1); i++)
11867203945Sweongyo		BWN_PHY_WRITE(mac, v1[i].reg, v1[i].value);
11868203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x10);
11869203945Sweongyo	for (i = 0; i < N(v2); i++)
11870203945Sweongyo		BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask, v2[i].set);
11871203945Sweongyo
11872203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x4000);
11873203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x2000);
11874203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_OFDM(0x10a), 0x1);
11875203945Sweongyo	if (siba->siba_board_rev >= 0x18) {
11876203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(17, 65), 0xec);
11877203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x14);
11878203945Sweongyo	} else {
11879203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x10);
11880203945Sweongyo	}
11881203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0xff00, 0xf4);
11882203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0x00ff, 0xf100);
11883203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CLIPTHRESH, 0x48);
11884203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0xff00, 0x46);
11885203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe4), 0xff00, 0x10);
11886203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_PWR_THRESH1, 0xfff0, 0x9);
11887203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_GAINDIRECTMISMATCH, ~0xf);
11888203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5500);
11889203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0xa0);
11890203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_GAINDIRECTMISMATCH, 0xe0ff, 0x300);
11891203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2a00);
11892203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
11893203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11894203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xa);
11895203945Sweongyo	} else {
11896203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x1e00);
11897203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xd);
11898203945Sweongyo	}
11899203945Sweongyo	for (i = 0; i < N(v3); i++)
11900203945Sweongyo		BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask, v3[i].set);
11901203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
11902203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x14), 0);
11903203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x12), 0x40);
11904203945Sweongyo	}
11905203945Sweongyo
11906203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11907203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x40);
11908203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0xb00);
11909203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x6);
11910203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0x9d00);
11911203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0xff00, 0xa1);
11912203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11913203945Sweongyo	} else
11914203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x40);
11915203945Sweongyo
11916203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0xff00, 0xb3);
11917203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00);
11918203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB, 0xff00, plp->plp_rxpwroffset);
11919203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RESET_CTL, 0x44);
11920203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RESET_CTL, 0x80);
11921203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, 0xa954);
11922203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_1,
11923203945Sweongyo	    0x2000 | ((uint16_t)plp->plp_rssigs << 10) |
11924203945Sweongyo	    ((uint16_t)plp->plp_rssivc << 4) | plp->plp_rssivf);
11925203945Sweongyo
11926203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
11927203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_AFE_ADC_CTL_0, 0x1c);
11928203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_CTL, 0x00ff, 0x8800);
11929203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_1, 0xfc3c, 0x0400);
11930203945Sweongyo	}
11931203945Sweongyo
11932203945Sweongyo	bwn_phy_lp_digflt_save(mac);
11933203945Sweongyo}
11934203945Sweongyo
11935203945Sweongyostatic void
11936203945Sweongyobwn_phy_lp_bbinit_r01(struct bwn_mac *mac)
11937203945Sweongyo{
11938203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11939203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
11940203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
11941203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11942203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
11943203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
11944203945Sweongyo	static const struct bwn_smpair v1[] = {
11945203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 },
11946203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 },
11947203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x3c00 },
11948203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xfff0, 0x0005 },
11949203945Sweongyo		{ BWN_PHY_GAIN_MISMATCH_LIMIT, 0xffc0, 0x001a },
11950203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0xff00, 0x00b3 },
11951203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00 }
11952203945Sweongyo	};
11953203945Sweongyo	static const struct bwn_smpair v2[] = {
11954203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11955203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0x3f00, 0x0900 },
11956203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11957203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11958203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x000a },
11959203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0400 },
11960203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x000a },
11961203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0b00 },
11962203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xffc0, 0x000a },
11963203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xc0ff, 0x0900 },
11964203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xffc0, 0x000a },
11965203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xc0ff, 0x0b00 },
11966203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xffc0, 0x000a },
11967203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xc0ff, 0x0900 },
11968203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xffc0, 0x000a },
11969203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xc0ff, 0x0b00 }
11970203945Sweongyo	};
11971203945Sweongyo	static const struct bwn_smpair v3[] = {
11972203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0001 },
11973203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0400 },
11974203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0001 },
11975203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0500 },
11976203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11977203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0800 },
11978203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11979203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0a00 }
11980203945Sweongyo	};
11981203945Sweongyo	static const struct bwn_smpair v4[] = {
11982203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0004 },
11983203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0800 },
11984203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0004 },
11985203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0c00 },
11986203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11987203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0100 },
11988203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11989203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0300 }
11990203945Sweongyo	};
11991203945Sweongyo	static const struct bwn_smpair v5[] = {
11992203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11993203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0900 },
11994203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11995203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11996203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0006 },
11997203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0500 },
11998203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0006 },
11999203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0700 }
12000203945Sweongyo	};
12001203945Sweongyo	int i;
12002203945Sweongyo	uint16_t tmp, tmp2;
12003203945Sweongyo
12004203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf7ff);
12005203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL, 0);
12006203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, 0);
12007203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, 0);
12008203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0);
12009203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DAC_CTL, 0x0004);
12010203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0x0078);
12011203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800);
12012203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x0016);
12013203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_0, 0xfff8, 0x0004);
12014203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5400);
12015203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2400);
12016203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
12017203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0x0006);
12018203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_RADIO_CTL, 0xfffe);
12019203945Sweongyo	for (i = 0; i < N(v1); i++)
12020203945Sweongyo		BWN_PHY_SETMASK(mac, v1[i].offset, v1[i].mask, v1[i].set);
12021203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB,
12022203945Sweongyo	    0xff00, plp->plp_rxpwroffset);
12023203945Sweongyo	if ((siba->siba_sprom.bf_lo & BWN_BFL_FEM) &&
12024203945Sweongyo	    ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
12025203945Sweongyo	   (siba->siba_sprom.bf_hi & BWN_BFH_LDO_PAREF))) {
12026203945Sweongyo		siba_cc_pmu_set_ldovolt(&siba->siba_cc, SIBA_LDO_PAREF, 0x28);
12027203945Sweongyo		siba_cc_pmu_set_ldoparef(&siba->siba_cc, 1);
12028203945Sweongyo		if (mac->mac_phy.rev == 0)
12029203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT,
12030203945Sweongyo			    0xffcf, 0x0010);
12031203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 60);
12032203945Sweongyo	} else {
12033203945Sweongyo		siba_cc_pmu_set_ldoparef(&siba->siba_cc, 0);
12034203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT, 0xffcf, 0x0020);
12035203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 100);
12036203945Sweongyo	}
12037203945Sweongyo	tmp = plp->plp_rssivf | plp->plp_rssivc << 4 | 0xa000;
12038203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, tmp);
12039203945Sweongyo	if (siba->siba_sprom.bf_hi & BWN_BFH_RSSIINV)
12040203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x0aaa);
12041203945Sweongyo	else
12042203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x02aa);
12043203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(11, 1), 24);
12044203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_RADIO_CTL,
12045203945Sweongyo	    0xfff9, (plp->plp_bxarch << 1));
12046203945Sweongyo	if (mac->mac_phy.rev == 1 &&
12047203945Sweongyo	    (siba->siba_sprom.bf_hi & BWN_BFH_FEM_BT)) {
12048203945Sweongyo		for (i = 0; i < N(v2); i++)
12049203945Sweongyo			BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask,
12050203945Sweongyo			    v2[i].set);
12051203945Sweongyo	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ||
12052203945Sweongyo	    (siba->siba_board_type == 0x048a) || ((mac->mac_phy.rev == 0) &&
12053203945Sweongyo	    (siba->siba_sprom.bf_lo & BWN_BFL_FEM))) {
12054203945Sweongyo		for (i = 0; i < N(v3); i++)
12055203945Sweongyo			BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask,
12056203945Sweongyo			    v3[i].set);
12057203945Sweongyo	} else if (mac->mac_phy.rev == 1 ||
12058203945Sweongyo		  (siba->siba_sprom.bf_lo & BWN_BFL_FEM)) {
12059203945Sweongyo		for (i = 0; i < N(v4); i++)
12060203945Sweongyo			BWN_PHY_SETMASK(mac, v4[i].offset, v4[i].mask,
12061203945Sweongyo			    v4[i].set);
12062203945Sweongyo	} else {
12063203945Sweongyo		for (i = 0; i < N(v5); i++)
12064203945Sweongyo			BWN_PHY_SETMASK(mac, v5[i].offset, v5[i].mask,
12065203945Sweongyo			    v5[i].set);
12066203945Sweongyo	}
12067203945Sweongyo	if (mac->mac_phy.rev == 1 &&
12068203945Sweongyo	    (siba->siba_sprom.bf_hi & BWN_BFH_LDO_PAREF)) {
12069203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_5, BWN_PHY_TR_LOOKUP_1);
12070203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_6, BWN_PHY_TR_LOOKUP_2);
12071203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_7, BWN_PHY_TR_LOOKUP_3);
12072203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_8, BWN_PHY_TR_LOOKUP_4);
12073203945Sweongyo	}
12074203945Sweongyo	if ((siba->siba_sprom.bf_hi & BWN_BFH_FEM_BT) &&
12075203945Sweongyo	    (siba->siba_chipid == 0x5354) &&
12076203945Sweongyo	    (siba->siba_chippkg == SIBA_CHIPPACK_BCM4712S)) {
12077203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0006);
12078203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_SELECT, 0x0005);
12079203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_OUTEN, 0xffff);
12080203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_PR45960W);
12081203945Sweongyo	}
12082203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12083203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x8000);
12084203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0040);
12085203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0xa400);
12086203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0x0b00);
12087203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x0007);
12088203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xfff8, 0x0003);
12089203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xffc7, 0x0020);
12090203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
12091203945Sweongyo	} else {
12092203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0x7fff);
12093203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xffbf);
12094203945Sweongyo	}
12095203945Sweongyo	if (mac->mac_phy.rev == 1) {
12096203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_CLIPCTRTHRESH);
12097203945Sweongyo		tmp2 = (tmp & 0x03e0) >> 5;
12098203945Sweongyo		tmp2 |= tmp2 << 5;
12099203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C3, tmp2);
12100203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_GAINDIRECTMISMATCH);
12101203945Sweongyo		tmp2 = (tmp & 0x1f00) >> 8;
12102203945Sweongyo		tmp2 |= tmp2 << 5;
12103203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C4, tmp2);
12104203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERYLOWGAINDB);
12105203945Sweongyo		tmp2 = tmp & 0x00ff;
12106203945Sweongyo		tmp2 |= tmp << 8;
12107203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C5, tmp2);
12108203945Sweongyo	}
12109203945Sweongyo}
12110203945Sweongyo
12111203945Sweongyostruct bwn_b2062_freq {
12112203945Sweongyo	uint16_t		freq;
12113203945Sweongyo	uint8_t			value[6];
12114203945Sweongyo};
12115203945Sweongyo
12116203945Sweongyostatic void
12117203945Sweongyobwn_phy_lp_b2062_init(struct bwn_mac *mac)
12118203945Sweongyo{
12119203945Sweongyo#define	CALC_CTL7(freq, div)						\
12120203945Sweongyo	(((800000000 * (div) + (freq)) / (2 * (freq)) - 8) & 0xff)
12121203945Sweongyo#define	CALC_CTL18(freq, div)						\
12122203945Sweongyo	((((100 * (freq) + 16000000 * (div)) / (32000000 * (div))) - 1) & 0xff)
12123203945Sweongyo#define	CALC_CTL19(freq, div)						\
12124203945Sweongyo	((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff)
12125203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12126203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
12127203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
12128203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12129203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12130203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12131203945Sweongyo	static const struct bwn_b2062_freq freqdata_tab[] = {
12132203945Sweongyo		{ 12000, { 6, 6, 6, 6, 10, 6 } },
12133203945Sweongyo		{ 13000, { 4, 4, 4, 4, 11, 7 } },
12134203945Sweongyo		{ 14400, { 3, 3, 3, 3, 12, 7 } },
12135203945Sweongyo		{ 16200, { 3, 3, 3, 3, 13, 8 } },
12136203945Sweongyo		{ 18000, { 2, 2, 2, 2, 14, 8 } },
12137203945Sweongyo		{ 19200, { 1, 1, 1, 1, 14, 9 } }
12138203945Sweongyo	};
12139203945Sweongyo	static const struct bwn_wpair v1[] = {
12140203945Sweongyo		{ BWN_B2062_N_TXCTL3, 0 },
12141203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0 },
12142203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0 },
12143203945Sweongyo		{ BWN_B2062_N_TXCTL6, 0 },
12144203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0x40 },
12145203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0 },
12146203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0x10 },
12147203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0 }
12148203945Sweongyo	};
12149203945Sweongyo	const struct bwn_b2062_freq *f = NULL;
12150203945Sweongyo	uint32_t xtalfreq, ref;
12151203945Sweongyo	unsigned int i;
12152203945Sweongyo
12153203945Sweongyo	bwn_phy_lp_b2062_tblinit(mac);
12154203945Sweongyo
12155203945Sweongyo	for (i = 0; i < N(v1); i++)
12156203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12157203945Sweongyo	if (mac->mac_phy.rev > 0)
12158203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_BG_CTL1,
12159203945Sweongyo		    (BWN_RF_READ(mac, BWN_B2062_N_COM2) >> 1) | 0x80);
12160203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12161203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_N_TSSI_CTL0, 0x1);
12162203945Sweongyo	else
12163203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_N_TSSI_CTL0, ~0x1);
12164203945Sweongyo
12165203945Sweongyo	KASSERT(siba->siba_cc.scc_caps & SIBA_CC_CAPS_PMU,
12166203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
12167203945Sweongyo	xtalfreq = siba->siba_cc.scc_pmu.freq * 1000;
12168203945Sweongyo	KASSERT(xtalfreq != 0, ("%s:%d: fail", __func__, __LINE__));
12169203945Sweongyo
12170203945Sweongyo	if (xtalfreq <= 30000000) {
12171203945Sweongyo		plp->plp_div = 1;
12172203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL1, 0xfffb);
12173203945Sweongyo	} else {
12174203945Sweongyo		plp->plp_div = 2;
12175203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL1, 0x4);
12176203945Sweongyo	}
12177203945Sweongyo
12178203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL7,
12179203945Sweongyo	    CALC_CTL7(xtalfreq, plp->plp_div));
12180203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL18,
12181203945Sweongyo	    CALC_CTL18(xtalfreq, plp->plp_div));
12182203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL19,
12183203945Sweongyo	    CALC_CTL19(xtalfreq, plp->plp_div));
12184203945Sweongyo
12185203945Sweongyo	ref = (1000 * plp->plp_div + 2 * xtalfreq) / (2000 * plp->plp_div);
12186203945Sweongyo	ref &= 0xffff;
12187203945Sweongyo	for (i = 0; i < N(freqdata_tab); i++) {
12188203945Sweongyo		if (ref < freqdata_tab[i].freq) {
12189203945Sweongyo			f = &freqdata_tab[i];
12190203945Sweongyo			break;
12191203945Sweongyo		}
12192203945Sweongyo	}
12193203945Sweongyo	if (f == NULL)
12194203945Sweongyo		f = &freqdata_tab[N(freqdata_tab) - 1];
12195203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL8,
12196203945Sweongyo	    ((uint16_t)(f->value[1]) << 4) | f->value[0]);
12197203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL9,
12198203945Sweongyo	    ((uint16_t)(f->value[3]) << 4) | f->value[2]);
12199203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL10, f->value[4]);
12200203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL11, f->value[5]);
12201203945Sweongyo#undef CALC_CTL7
12202203945Sweongyo#undef CALC_CTL18
12203203945Sweongyo#undef CALC_CTL19
12204203945Sweongyo}
12205203945Sweongyo
12206203945Sweongyostatic void
12207203945Sweongyobwn_phy_lp_b2063_init(struct bwn_mac *mac)
12208203945Sweongyo{
12209203945Sweongyo
12210203945Sweongyo	bwn_phy_lp_b2063_tblinit(mac);
12211203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_SP5, 0);
12212203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM8, 0x38);
12213203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_REG_SP1, 0x56);
12214203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_RX_BB_CTL2, ~0x2);
12215203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0);
12216203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP6, 0x20);
12217203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP9, 0x40);
12218203945Sweongyo	if (mac->mac_phy.rev == 2) {
12219203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0xa0);
12220203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP4, 0xa0);
12221203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x18);
12222203945Sweongyo	} else {
12223203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0x20);
12224203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x20);
12225203945Sweongyo	}
12226203945Sweongyo}
12227203945Sweongyo
12228203945Sweongyostatic void
12229203945Sweongyobwn_phy_lp_rxcal_r2(struct bwn_mac *mac)
12230203945Sweongyo{
12231203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
12232203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
12233203945Sweongyo	static const struct bwn_wpair v1[] = {
12234203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x0 },
12235203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12236203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12237203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x15 },
12238203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x70 },
12239203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL4, 0x52 },
12240203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL5, 0x1 },
12241203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7d }
12242203945Sweongyo	};
12243203945Sweongyo	static const struct bwn_wpair v2[] = {
12244203945Sweongyo		{ BWN_B2063_TX_BB_SP3, 0x0 },
12245203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12246203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12247203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x55 },
12248203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x76 }
12249203945Sweongyo	};
12250203945Sweongyo	uint32_t freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
12251203945Sweongyo	int i;
12252203945Sweongyo	uint8_t tmp;
12253203945Sweongyo
12254203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_RX_BB_SP8) & 0xff;
12255203945Sweongyo
12256203945Sweongyo	for (i = 0; i < 2; i++)
12257203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12258203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, 0xf7);
12259203945Sweongyo	for (i = 2; i < N(v1); i++)
12260203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12261203945Sweongyo	for (i = 0; i < 10000; i++) {
12262203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12263203945Sweongyo			break;
12264203945Sweongyo		DELAY(1000);
12265203945Sweongyo	}
12266203945Sweongyo
12267203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12268203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RX_BB_SP8, tmp);
12269203945Sweongyo
12270203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_TX_BB_SP3) & 0xff;
12271203945Sweongyo
12272203945Sweongyo	for (i = 0; i < N(v2); i++)
12273203945Sweongyo		BWN_RF_WRITE(mac, v2[i].reg, v2[i].value);
12274203945Sweongyo	if (freqxtal == 24000000) {
12275203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0xfc);
12276203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x0);
12277203945Sweongyo	} else {
12278203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0x13);
12279203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x1);
12280203945Sweongyo	}
12281203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0x7d);
12282203945Sweongyo	for (i = 0; i < 10000; i++) {
12283203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12284203945Sweongyo			break;
12285203945Sweongyo		DELAY(1000);
12286203945Sweongyo	}
12287203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12288203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, tmp);
12289203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL1, 0x7e);
12290203945Sweongyo}
12291203945Sweongyo
12292203945Sweongyostatic void
12293203945Sweongyobwn_phy_lp_rccal_r12(struct bwn_mac *mac)
12294203945Sweongyo{
12295203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12296203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12297203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12298203945Sweongyo	struct bwn_txgain tx_gains;
12299203945Sweongyo	static const uint32_t pwrtbl[21] = {
12300203945Sweongyo		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
12301203945Sweongyo		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
12302203945Sweongyo		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
12303203945Sweongyo		0x0004c, 0x0002c, 0x0001a,
12304203945Sweongyo	};
12305203945Sweongyo	uint32_t npwr, ipwr, sqpwr, tmp;
12306203945Sweongyo	int loopback, i, j, sum, error;
12307203945Sweongyo	uint16_t save[7];
12308203945Sweongyo	uint8_t txo, bbmult, txpctlmode;
12309203945Sweongyo
12310203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
12311203945Sweongyo	if (error)
12312203945Sweongyo		device_printf(sc->sc_dev,
12313203945Sweongyo		    "failed to change channel to 7 (%d)\n", error);
12314203945Sweongyo	txo = (BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40) ? 1 : 0;
12315203945Sweongyo	bbmult = bwn_phy_lp_get_bbmult(mac);
12316203945Sweongyo	if (txo)
12317203945Sweongyo		tx_gains = bwn_phy_lp_get_txgain(mac);
12318203945Sweongyo
12319203945Sweongyo	save[0] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_0);
12320203945Sweongyo	save[1] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_VAL_0);
12321203945Sweongyo	save[2] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR);
12322203945Sweongyo	save[3] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVRVAL);
12323203945Sweongyo	save[4] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2);
12324203945Sweongyo	save[5] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2_VAL);
12325203945Sweongyo	save[6] = BWN_PHY_READ(mac, BWN_PHY_LP_PHY_CTL);
12326203945Sweongyo
12327203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
12328203945Sweongyo	txpctlmode = plp->plp_txpctlmode;
12329203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
12330203945Sweongyo
12331203945Sweongyo	/* disable CRS */
12332203945Sweongyo	bwn_phy_lp_set_deaf(mac, 1);
12333203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 0, 1);
12334203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffb);
12335203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x4);
12336203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7);
12337203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
12338203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x10);
12339203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12340203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf);
12341203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
12342203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffbf);
12343203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12344203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x7);
12345203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x38);
12346203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f);
12347203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x100);
12348203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfdff);
12349203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL0, 0);
12350203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL1, 1);
12351203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL2, 0x20);
12352203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfbff);
12353203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xf7ff);
12354203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
12355203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45af);
12356203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0x3ff);
12357203945Sweongyo
12358203945Sweongyo	loopback = bwn_phy_lp_loopback(mac);
12359203945Sweongyo	if (loopback == -1)
12360203945Sweongyo		goto done;
12361203945Sweongyo	bwn_phy_lp_set_rxgain_idx(mac, loopback);
12362203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xffbf, 0x40);
12363203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfff8, 0x1);
12364203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xffc7, 0x8);
12365203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f, 0xc0);
12366203945Sweongyo
12367203945Sweongyo	tmp = 0;
12368203945Sweongyo	memset(&ie, 0, sizeof(ie));
12369203945Sweongyo	for (i = 128; i <= 159; i++) {
12370203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2, i);
12371203945Sweongyo		sum = 0;
12372203945Sweongyo		for (j = 5; j <= 25; j++) {
12373203945Sweongyo			bwn_phy_lp_ddfs_turnon(mac, 1, 1, j, j, 0);
12374203945Sweongyo			if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
12375203945Sweongyo				goto done;
12376203945Sweongyo			sqpwr = ie.ie_ipwr + ie.ie_qpwr;
12377203945Sweongyo			ipwr = ((pwrtbl[j - 5] >> 3) + 1) >> 1;
12378203945Sweongyo			npwr = bwn_phy_lp_roundup(sqpwr, (j == 5) ? sqpwr : 0,
12379203945Sweongyo			    12);
12380203945Sweongyo			sum += ((ipwr - npwr) * (ipwr - npwr));
12381203945Sweongyo			if ((i == 128) || (sum < tmp)) {
12382203945Sweongyo				plp->plp_rccap = i;
12383203945Sweongyo				tmp = sum;
12384203945Sweongyo			}
12385203945Sweongyo		}
12386203945Sweongyo	}
12387203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
12388203945Sweongyodone:
12389203945Sweongyo	/* restore CRS */
12390203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 1);
12391203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xff80);
12392203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfc00);
12393203945Sweongyo
12394203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_VAL_0, save[1]);
12395203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, save[0]);
12396203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVRVAL, save[3]);
12397203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, save[2]);
12398203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2_VAL, save[5]);
12399203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, save[4]);
12400203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LP_PHY_CTL, save[6]);
12401203945Sweongyo
12402203945Sweongyo	bwn_phy_lp_set_bbmult(mac, bbmult);
12403203945Sweongyo	if (txo)
12404203945Sweongyo		bwn_phy_lp_set_txgain(mac, &tx_gains);
12405203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, txpctlmode);
12406203945Sweongyo	if (plp->plp_rccap)
12407203945Sweongyo		bwn_phy_lp_set_rccap(mac);
12408203945Sweongyo}
12409203945Sweongyo
12410203945Sweongyostatic void
12411203945Sweongyobwn_phy_lp_set_rccap(struct bwn_mac *mac)
12412203945Sweongyo{
12413203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12414203945Sweongyo	uint8_t rc_cap = (plp->plp_rccap & 0x1f) >> 1;
12415203945Sweongyo
12416203945Sweongyo	if (mac->mac_phy.rev == 1)
12417203945Sweongyo		rc_cap = MIN(rc_cap + 5, 15);
12418203945Sweongyo
12419203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2,
12420203945Sweongyo	    MAX(plp->plp_rccap - 4, 0x80));
12421203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, rc_cap | 0x80);
12422203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RXG_CNT16,
12423203945Sweongyo	    ((plp->plp_rccap & 0x1f) >> 2) | 0x80);
12424203945Sweongyo}
12425203945Sweongyo
12426203945Sweongyostatic uint32_t
12427203945Sweongyobwn_phy_lp_roundup(uint32_t value, uint32_t div, uint8_t pre)
12428203945Sweongyo{
12429203945Sweongyo	uint32_t i, q, r;
12430203945Sweongyo
12431203945Sweongyo	if (div == 0)
12432203945Sweongyo		return (0);
12433203945Sweongyo
12434203945Sweongyo	for (i = 0, q = value / div, r = value % div; i < pre; i++) {
12435203945Sweongyo		q <<= 1;
12436203945Sweongyo		if (r << 1 >= div) {
12437203945Sweongyo			q++;
12438203945Sweongyo			r = (r << 1) - div;
12439203945Sweongyo		}
12440203945Sweongyo	}
12441203945Sweongyo	if (r << 1 >= div)
12442203945Sweongyo		q++;
12443203945Sweongyo	return (q);
12444203945Sweongyo}
12445203945Sweongyo
12446203945Sweongyostatic void
12447203945Sweongyobwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *mac)
12448203945Sweongyo{
12449203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
12450203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
12451203945Sweongyo
12452203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0xff);
12453203945Sweongyo	DELAY(20);
12454203945Sweongyo	if (siba->siba_chipid == 0x5354) {
12455203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_COM1, 4);
12456203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 4);
12457203945Sweongyo	} else {
12458203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0);
12459203945Sweongyo	}
12460203945Sweongyo	DELAY(5);
12461203945Sweongyo}
12462203945Sweongyo
12463203945Sweongyostatic void
12464203945Sweongyobwn_phy_lp_b2062_vco_calib(struct bwn_mac *mac)
12465203945Sweongyo{
12466203945Sweongyo
12467203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x42);
12468203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x62);
12469203945Sweongyo	DELAY(200);
12470203945Sweongyo}
12471203945Sweongyo
12472203945Sweongyostatic void
12473203945Sweongyobwn_phy_lp_b2062_tblinit(struct bwn_mac *mac)
12474203945Sweongyo{
12475203945Sweongyo#define	FLAG_A	0x01
12476203945Sweongyo#define	FLAG_G	0x02
12477203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12478203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12479203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12480203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = {
12481203945Sweongyo		{ BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12482203945Sweongyo		{ BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, },
12483203945Sweongyo		{ BWN_B2062_N_PDNCTL3, 0x0, 0x0, FLAG_A | FLAG_G, },
12484203945Sweongyo		{ BWN_B2062_N_PDNCTL4, 0x15, 0x2a, FLAG_A | FLAG_G, },
12485203945Sweongyo		{ BWN_B2062_N_LGENC, 0xDB, 0xff, FLAG_A, },
12486203945Sweongyo		{ BWN_B2062_N_LGENATUNE0, 0xdd, 0x0, FLAG_A | FLAG_G, },
12487203945Sweongyo		{ BWN_B2062_N_LGENATUNE2, 0xdd, 0x0, FLAG_A | FLAG_G, },
12488203945Sweongyo		{ BWN_B2062_N_LGENATUNE3, 0x77, 0xB5, FLAG_A | FLAG_G, },
12489203945Sweongyo		{ BWN_B2062_N_LGENACTL3, 0x0, 0xff, FLAG_A | FLAG_G, },
12490203945Sweongyo		{ BWN_B2062_N_LGENACTL7, 0x33, 0x33, FLAG_A | FLAG_G, },
12491203945Sweongyo		{ BWN_B2062_N_RXA_CTL1, 0x0, 0x0, FLAG_G, },
12492203945Sweongyo		{ BWN_B2062_N_RXBB_CTL0, 0x82, 0x80, FLAG_A | FLAG_G, },
12493203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN1, 0x4, 0x4, FLAG_A | FLAG_G, },
12494203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN2, 0x0, 0x0, FLAG_A | FLAG_G, },
12495203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0x3, 0x3, FLAG_A | FLAG_G, },
12496203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0x2, 0x2, FLAG_A | FLAG_G, },
12497203945Sweongyo		{ BWN_B2062_N_TX_TUNE, 0x88, 0x1b, FLAG_A | FLAG_G, },
12498203945Sweongyo		{ BWN_B2062_S_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12499203945Sweongyo		{ BWN_B2062_S_PDS_CTL0, 0xff, 0xff, FLAG_A | FLAG_G, },
12500203945Sweongyo		{ BWN_B2062_S_LGENG_CTL0, 0xf8, 0xd8, FLAG_A | FLAG_G, },
12501203945Sweongyo		{ BWN_B2062_S_LGENG_CTL1, 0x3c, 0x24, FLAG_A | FLAG_G, },
12502203945Sweongyo		{ BWN_B2062_S_LGENG_CTL8, 0x88, 0x80, FLAG_A | FLAG_G, },
12503203945Sweongyo		{ BWN_B2062_S_LGENG_CTL10, 0x88, 0x80, FLAG_A | FLAG_G, },
12504203945Sweongyo		{ BWN_B2062_S_RFPLLCTL0, 0x98, 0x98, FLAG_A | FLAG_G, },
12505203945Sweongyo		{ BWN_B2062_S_RFPLLCTL1, 0x10, 0x10, FLAG_A | FLAG_G, },
12506203945Sweongyo		{ BWN_B2062_S_RFPLLCTL5, 0x43, 0x43, FLAG_A | FLAG_G, },
12507203945Sweongyo		{ BWN_B2062_S_RFPLLCTL6, 0x47, 0x47, FLAG_A | FLAG_G, },
12508203945Sweongyo		{ BWN_B2062_S_RFPLLCTL7, 0xc, 0xc, FLAG_A | FLAG_G, },
12509203945Sweongyo		{ BWN_B2062_S_RFPLLCTL8, 0x11, 0x11, FLAG_A | FLAG_G, },
12510203945Sweongyo		{ BWN_B2062_S_RFPLLCTL9, 0x11, 0x11, FLAG_A | FLAG_G, },
12511203945Sweongyo		{ BWN_B2062_S_RFPLLCTL10, 0xe, 0xe, FLAG_A | FLAG_G, },
12512203945Sweongyo		{ BWN_B2062_S_RFPLLCTL11, 0x8, 0x8, FLAG_A | FLAG_G, },
12513203945Sweongyo		{ BWN_B2062_S_RFPLLCTL12, 0x33, 0x33, FLAG_A | FLAG_G, },
12514203945Sweongyo		{ BWN_B2062_S_RFPLLCTL13, 0xa, 0xa, FLAG_A | FLAG_G, },
12515203945Sweongyo		{ BWN_B2062_S_RFPLLCTL14, 0x6, 0x6, FLAG_A | FLAG_G, },
12516203945Sweongyo		{ BWN_B2062_S_RFPLLCTL18, 0x3e, 0x3e, FLAG_A | FLAG_G, },
12517203945Sweongyo		{ BWN_B2062_S_RFPLLCTL19, 0x13, 0x13, FLAG_A | FLAG_G, },
12518203945Sweongyo		{ BWN_B2062_S_RFPLLCTL21, 0x62, 0x62, FLAG_A | FLAG_G, },
12519203945Sweongyo		{ BWN_B2062_S_RFPLLCTL22, 0x7, 0x7, FLAG_A | FLAG_G, },
12520203945Sweongyo		{ BWN_B2062_S_RFPLLCTL23, 0x16, 0x16, FLAG_A | FLAG_G, },
12521203945Sweongyo		{ BWN_B2062_S_RFPLLCTL24, 0x5c, 0x5c, FLAG_A | FLAG_G, },
12522203945Sweongyo		{ BWN_B2062_S_RFPLLCTL25, 0x95, 0x95, FLAG_A | FLAG_G, },
12523203945Sweongyo		{ BWN_B2062_S_RFPLLCTL30, 0xa0, 0xa0, FLAG_A | FLAG_G, },
12524203945Sweongyo		{ BWN_B2062_S_RFPLLCTL31, 0x4, 0x4, FLAG_A | FLAG_G, },
12525203945Sweongyo		{ BWN_B2062_S_RFPLLCTL33, 0xcc, 0xcc, FLAG_A | FLAG_G, },
12526203945Sweongyo		{ BWN_B2062_S_RFPLLCTL34, 0x7, 0x7, FLAG_A | FLAG_G, },
12527203945Sweongyo		{ BWN_B2062_S_RXG_CNT8, 0xf, 0xf, FLAG_A, },
12528203945Sweongyo	};
12529203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12530203945Sweongyo	unsigned int i;
12531203945Sweongyo
12532203945Sweongyo	for (i = 0; i < N(bwn_b2062_init_tab); i++) {
12533203945Sweongyo		br = &bwn_b2062_init_tab[i];
12534203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12535203945Sweongyo			if (br->br_flags & FLAG_G)
12536203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12537203945Sweongyo		} else {
12538203945Sweongyo			if (br->br_flags & FLAG_A)
12539203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12540203945Sweongyo		}
12541203945Sweongyo	}
12542203945Sweongyo#undef FLAG_A
12543203945Sweongyo#undef FLAG_B
12544203945Sweongyo}
12545203945Sweongyo
12546203945Sweongyostatic void
12547203945Sweongyobwn_phy_lp_b2063_tblinit(struct bwn_mac *mac)
12548203945Sweongyo{
12549203945Sweongyo#define	FLAG_A	0x01
12550203945Sweongyo#define	FLAG_G	0x02
12551203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12552203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12553203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12554203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = {
12555203945Sweongyo		{ BWN_B2063_COM1, 0x0, 0x0, FLAG_G, },
12556203945Sweongyo		{ BWN_B2063_COM10, 0x1, 0x0, FLAG_A, },
12557203945Sweongyo		{ BWN_B2063_COM16, 0x0, 0x0, FLAG_G, },
12558203945Sweongyo		{ BWN_B2063_COM17, 0x0, 0x0, FLAG_G, },
12559203945Sweongyo		{ BWN_B2063_COM18, 0x0, 0x0, FLAG_G, },
12560203945Sweongyo		{ BWN_B2063_COM19, 0x0, 0x0, FLAG_G, },
12561203945Sweongyo		{ BWN_B2063_COM20, 0x0, 0x0, FLAG_G, },
12562203945Sweongyo		{ BWN_B2063_COM21, 0x0, 0x0, FLAG_G, },
12563203945Sweongyo		{ BWN_B2063_COM22, 0x0, 0x0, FLAG_G, },
12564203945Sweongyo		{ BWN_B2063_COM23, 0x0, 0x0, FLAG_G, },
12565203945Sweongyo		{ BWN_B2063_COM24, 0x0, 0x0, FLAG_G, },
12566203945Sweongyo		{ BWN_B2063_LOGEN_SP1, 0xe8, 0xd4, FLAG_A | FLAG_G, },
12567203945Sweongyo		{ BWN_B2063_LOGEN_SP2, 0xa7, 0x53, FLAG_A | FLAG_G, },
12568203945Sweongyo		{ BWN_B2063_LOGEN_SP4, 0xf0, 0xf, FLAG_A | FLAG_G, },
12569203945Sweongyo		{ BWN_B2063_G_RX_SP1, 0x1f, 0x5e, FLAG_G, },
12570203945Sweongyo		{ BWN_B2063_G_RX_SP2, 0x7f, 0x7e, FLAG_G, },
12571203945Sweongyo		{ BWN_B2063_G_RX_SP3, 0x30, 0xf0, FLAG_G, },
12572203945Sweongyo		{ BWN_B2063_G_RX_SP7, 0x7f, 0x7f, FLAG_A | FLAG_G, },
12573203945Sweongyo		{ BWN_B2063_G_RX_SP10, 0xc, 0xc, FLAG_A | FLAG_G, },
12574203945Sweongyo		{ BWN_B2063_A_RX_SP1, 0x3c, 0x3f, FLAG_A, },
12575203945Sweongyo		{ BWN_B2063_A_RX_SP2, 0xfc, 0xfe, FLAG_A, },
12576203945Sweongyo		{ BWN_B2063_A_RX_SP7, 0x8, 0x8, FLAG_A | FLAG_G, },
12577203945Sweongyo		{ BWN_B2063_RX_BB_SP4, 0x60, 0x60, FLAG_A | FLAG_G, },
12578203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x30, 0x30, FLAG_A | FLAG_G, },
12579203945Sweongyo		{ BWN_B2063_TX_RF_SP3, 0xc, 0xb, FLAG_A | FLAG_G, },
12580203945Sweongyo		{ BWN_B2063_TX_RF_SP4, 0x10, 0xf, FLAG_A | FLAG_G, },
12581203945Sweongyo		{ BWN_B2063_PA_SP1, 0x3d, 0xfd, FLAG_A | FLAG_G, },
12582203945Sweongyo		{ BWN_B2063_TX_BB_SP1, 0x2, 0x2, FLAG_A | FLAG_G, },
12583203945Sweongyo		{ BWN_B2063_BANDGAP_CTL1, 0x56, 0x56, FLAG_A | FLAG_G, },
12584203945Sweongyo		{ BWN_B2063_JTAG_VCO2, 0xF7, 0xF7, FLAG_A | FLAG_G, },
12585203945Sweongyo		{ BWN_B2063_G_RX_MIX3, 0x71, 0x71, FLAG_A | FLAG_G, },
12586203945Sweongyo		{ BWN_B2063_G_RX_MIX4, 0x71, 0x71, FLAG_A | FLAG_G, },
12587203945Sweongyo		{ BWN_B2063_A_RX_1ST2, 0xf0, 0x30, FLAG_A, },
12588203945Sweongyo		{ BWN_B2063_A_RX_PS6, 0x77, 0x77, FLAG_A | FLAG_G, },
12589203945Sweongyo		{ BWN_B2063_A_RX_MIX4, 0x3, 0x3, FLAG_A | FLAG_G, },
12590203945Sweongyo		{ BWN_B2063_A_RX_MIX5, 0xf, 0xf, FLAG_A | FLAG_G, },
12591203945Sweongyo		{ BWN_B2063_A_RX_MIX6, 0xf, 0xf, FLAG_A | FLAG_G, },
12592203945Sweongyo		{ BWN_B2063_RX_TIA_CTL1, 0x77, 0x77, FLAG_A | FLAG_G, },
12593203945Sweongyo		{ BWN_B2063_RX_TIA_CTL3, 0x77, 0x77, FLAG_A | FLAG_G, },
12594203945Sweongyo		{ BWN_B2063_RX_BB_CTL2, 0x4, 0x4, FLAG_A | FLAG_G, },
12595203945Sweongyo		{ BWN_B2063_PA_CTL1, 0x0, 0x4, FLAG_A, },
12596203945Sweongyo		{ BWN_B2063_VREG_CTL1, 0x3, 0x3, FLAG_A | FLAG_G, },
12597203945Sweongyo	};
12598203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12599203945Sweongyo	unsigned int i;
12600203945Sweongyo
12601203945Sweongyo	for (i = 0; i < N(bwn_b2063_init_tab); i++) {
12602203945Sweongyo		br = &bwn_b2063_init_tab[i];
12603203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12604203945Sweongyo			if (br->br_flags & FLAG_G)
12605203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12606203945Sweongyo		} else {
12607203945Sweongyo			if (br->br_flags & FLAG_A)
12608203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12609203945Sweongyo		}
12610203945Sweongyo	}
12611203945Sweongyo#undef FLAG_A
12612203945Sweongyo#undef FLAG_B
12613203945Sweongyo}
12614203945Sweongyo
12615203945Sweongyostatic void
12616203945Sweongyobwn_tab_read_multi(struct bwn_mac *mac, uint32_t typenoffset,
12617203945Sweongyo    int count, void *_data)
12618203945Sweongyo{
12619203945Sweongyo	unsigned int i;
12620203945Sweongyo	uint32_t offset, type;
12621203945Sweongyo	uint8_t *data = _data;
12622203945Sweongyo
12623203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12624203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12625203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12626203945Sweongyo
12627203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12628203945Sweongyo
12629203945Sweongyo	for (i = 0; i < count; i++) {
12630203945Sweongyo		switch (type) {
12631203945Sweongyo		case BWN_TAB_8BIT:
12632203945Sweongyo			*data = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
12633203945Sweongyo			data++;
12634203945Sweongyo			break;
12635203945Sweongyo		case BWN_TAB_16BIT:
12636203945Sweongyo			*((uint16_t *)data) = BWN_PHY_READ(mac,
12637203945Sweongyo			    BWN_PHY_TABLEDATALO);
12638203945Sweongyo			data += 2;
12639203945Sweongyo			break;
12640203945Sweongyo		case BWN_TAB_32BIT:
12641203945Sweongyo			*((uint32_t *)data) = BWN_PHY_READ(mac,
12642203945Sweongyo			    BWN_PHY_TABLEDATAHI);
12643203945Sweongyo			*((uint32_t *)data) <<= 16;
12644203945Sweongyo			*((uint32_t *)data) |= BWN_PHY_READ(mac,
12645203945Sweongyo			    BWN_PHY_TABLEDATALO);
12646203945Sweongyo			data += 4;
12647203945Sweongyo			break;
12648203945Sweongyo		default:
12649203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12650203945Sweongyo		}
12651203945Sweongyo	}
12652203945Sweongyo}
12653203945Sweongyo
12654203945Sweongyostatic void
12655203945Sweongyobwn_tab_write_multi(struct bwn_mac *mac, uint32_t typenoffset,
12656203945Sweongyo    int count, const void *_data)
12657203945Sweongyo{
12658203945Sweongyo	uint32_t offset, type, value;
12659203945Sweongyo	const uint8_t *data = _data;
12660203945Sweongyo	unsigned int i;
12661203945Sweongyo
12662203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12663203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12664203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12665203945Sweongyo
12666203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12667203945Sweongyo
12668203945Sweongyo	for (i = 0; i < count; i++) {
12669203945Sweongyo		switch (type) {
12670203945Sweongyo		case BWN_TAB_8BIT:
12671203945Sweongyo			value = *data;
12672203945Sweongyo			data++;
12673203945Sweongyo			KASSERT(!(value & ~0xff),
12674203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12675203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12676203945Sweongyo			break;
12677203945Sweongyo		case BWN_TAB_16BIT:
12678203945Sweongyo			value = *((const uint16_t *)data);
12679203945Sweongyo			data += 2;
12680203945Sweongyo			KASSERT(!(value & ~0xffff),
12681203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12682203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12683203945Sweongyo			break;
12684203945Sweongyo		case BWN_TAB_32BIT:
12685203945Sweongyo			value = *((const uint32_t *)data);
12686203945Sweongyo			data += 4;
12687203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
12688203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12689203945Sweongyo			break;
12690203945Sweongyo		default:
12691203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12692203945Sweongyo		}
12693203945Sweongyo	}
12694203945Sweongyo}
12695203945Sweongyo
12696203945Sweongyostatic struct bwn_txgain
12697203945Sweongyobwn_phy_lp_get_txgain(struct bwn_mac *mac)
12698203945Sweongyo{
12699203945Sweongyo	struct bwn_txgain tg;
12700203945Sweongyo	uint16_t tmp;
12701203945Sweongyo
12702203945Sweongyo	tg.tg_dac = (BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0x380) >> 7;
12703203945Sweongyo	if (mac->mac_phy.rev < 2) {
12704203945Sweongyo		tmp = BWN_PHY_READ(mac,
12705203945Sweongyo		    BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7ff;
12706203945Sweongyo		tg.tg_gm = tmp & 0x0007;
12707203945Sweongyo		tg.tg_pga = (tmp & 0x0078) >> 3;
12708203945Sweongyo		tg.tg_pad = (tmp & 0x780) >> 7;
12709203945Sweongyo		return (tg);
12710203945Sweongyo	}
12711203945Sweongyo
12712203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL);
12713203945Sweongyo	tg.tg_pad = BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0xff;
12714203945Sweongyo	tg.tg_gm = tmp & 0xff;
12715203945Sweongyo	tg.tg_pga = (tmp >> 8) & 0xff;
12716203945Sweongyo	return (tg);
12717203945Sweongyo}
12718203945Sweongyo
12719203945Sweongyostatic uint8_t
12720203945Sweongyobwn_phy_lp_get_bbmult(struct bwn_mac *mac)
12721203945Sweongyo{
12722203945Sweongyo
12723203945Sweongyo	return (bwn_tab_read(mac, BWN_TAB_2(0, 87)) & 0xff00) >> 8;
12724203945Sweongyo}
12725203945Sweongyo
12726203945Sweongyostatic void
12727203945Sweongyobwn_phy_lp_set_txgain(struct bwn_mac *mac, struct bwn_txgain *tg)
12728203945Sweongyo{
12729203945Sweongyo	uint16_t pa;
12730203945Sweongyo
12731203945Sweongyo	if (mac->mac_phy.rev < 2) {
12732203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xf800,
12733203945Sweongyo		    (tg->tg_pad << 7) | (tg->tg_pga << 3) | tg->tg_gm);
12734203945Sweongyo		bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12735203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
12736203945Sweongyo		return;
12737203945Sweongyo	}
12738203945Sweongyo
12739203945Sweongyo	pa = bwn_phy_lp_get_pa_gain(mac);
12740203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
12741203945Sweongyo	    (tg->tg_pga << 8) | tg->tg_gm);
12742203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0x8000,
12743203945Sweongyo	    tg->tg_pad | (pa << 6));
12744203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xfc), (tg->tg_pga << 8) | tg->tg_gm);
12745203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x8000,
12746203945Sweongyo	    tg->tg_pad | (pa << 8));
12747203945Sweongyo	bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12748203945Sweongyo	bwn_phy_lp_set_txgain_override(mac);
12749203945Sweongyo}
12750203945Sweongyo
12751203945Sweongyostatic void
12752203945Sweongyobwn_phy_lp_set_bbmult(struct bwn_mac *mac, uint8_t bbmult)
12753203945Sweongyo{
12754203945Sweongyo
12755203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(0, 87), (uint16_t)bbmult << 8);
12756203945Sweongyo}
12757203945Sweongyo
12758203945Sweongyostatic void
12759203945Sweongyobwn_phy_lp_set_trsw_over(struct bwn_mac *mac, uint8_t tx, uint8_t rx)
12760203945Sweongyo{
12761203945Sweongyo	uint16_t trsw = (tx << 1) | rx;
12762203945Sweongyo
12763203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffc, trsw);
12764203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x3);
12765203945Sweongyo}
12766203945Sweongyo
12767203945Sweongyostatic void
12768203945Sweongyobwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain)
12769203945Sweongyo{
12770203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12771203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12772203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12773203945Sweongyo	uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp;
12774203945Sweongyo
12775203945Sweongyo	if (mac->mac_phy.rev < 2) {
12776203945Sweongyo		trsw = gain & 0x1;
12777203945Sweongyo		lna = (gain & 0xfffc) | ((gain & 0xc) >> 2);
12778203945Sweongyo		ext_lna = (gain & 2) >> 1;
12779203945Sweongyo
12780203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12781203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12782203945Sweongyo		    0xfbff, ext_lna << 10);
12783203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12784203945Sweongyo		    0xf7ff, ext_lna << 11);
12785203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
12786203945Sweongyo	} else {
12787203945Sweongyo		low_gain = gain & 0xffff;
12788203945Sweongyo		high_gain = (gain >> 16) & 0xf;
12789203945Sweongyo		ext_lna = (gain >> 21) & 0x1;
12790203945Sweongyo		trsw = ~(gain >> 20) & 0x1;
12791203945Sweongyo
12792203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12793203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12794203945Sweongyo		    0xfdff, ext_lna << 9);
12795203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12796203945Sweongyo		    0xfbff, ext_lna << 10);
12797203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
12798203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff0, high_gain);
12799203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12800203945Sweongyo			tmp = (gain >> 2) & 0x3;
12801203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12802203945Sweongyo			    0xe7ff, tmp<<11);
12803203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe6), 0xffe7,
12804203945Sweongyo			    tmp << 3);
12805203945Sweongyo		}
12806203945Sweongyo	}
12807203945Sweongyo
12808203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1);
12809203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12810203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12811203945Sweongyo	if (mac->mac_phy.rev >= 2) {
12812203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
12813203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12814203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x400);
12815203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xe5), 0x8);
12816203945Sweongyo		}
12817203945Sweongyo		return;
12818203945Sweongyo	}
12819203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x200);
12820203945Sweongyo}
12821203945Sweongyo
12822203945Sweongyostatic void
12823203945Sweongyobwn_phy_lp_set_deaf(struct bwn_mac *mac, uint8_t user)
12824203945Sweongyo{
12825203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12826203945Sweongyo
12827203945Sweongyo	if (user)
12828203945Sweongyo		plp->plp_crsusr_off = 1;
12829203945Sweongyo	else
12830203945Sweongyo		plp->plp_crssys_off = 1;
12831203945Sweongyo
12832203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x80);
12833203945Sweongyo}
12834203945Sweongyo
12835203945Sweongyostatic void
12836203945Sweongyobwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
12837203945Sweongyo{
12838203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12839203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12840203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
12841203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
12842203945Sweongyo
12843203945Sweongyo	if (user)
12844203945Sweongyo		plp->plp_crsusr_off = 0;
12845203945Sweongyo	else
12846203945Sweongyo		plp->plp_crssys_off = 0;
12847203945Sweongyo
12848203945Sweongyo	if (plp->plp_crsusr_off || plp->plp_crssys_off)
12849203945Sweongyo		return;
12850203945Sweongyo
12851203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12852203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x60);
12853203945Sweongyo	else
12854203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x20);
12855203945Sweongyo}
12856203945Sweongyo
12857203945Sweongyostatic unsigned int
12858203945Sweongyobwn_sqrt(struct bwn_mac *mac, unsigned int x)
12859203945Sweongyo{
12860203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12861203945Sweongyo	/* Table holding (10 * sqrt(x)) for x between 1 and 256. */
12862203945Sweongyo	static uint8_t sqrt_table[256] = {
12863203945Sweongyo		10, 14, 17, 20, 22, 24, 26, 28,
12864203945Sweongyo		30, 31, 33, 34, 36, 37, 38, 40,
12865203945Sweongyo		41, 42, 43, 44, 45, 46, 47, 48,
12866203945Sweongyo		50, 50, 51, 52, 53, 54, 55, 56,
12867203945Sweongyo		57, 58, 59, 60, 60, 61, 62, 63,
12868203945Sweongyo		64, 64, 65, 66, 67, 67, 68, 69,
12869203945Sweongyo		70, 70, 71, 72, 72, 73, 74, 74,
12870203945Sweongyo		75, 76, 76, 77, 78, 78, 79, 80,
12871203945Sweongyo		80, 81, 81, 82, 83, 83, 84, 84,
12872203945Sweongyo		85, 86, 86, 87, 87, 88, 88, 89,
12873203945Sweongyo		90, 90, 91, 91, 92, 92, 93, 93,
12874203945Sweongyo		94, 94, 95, 95, 96, 96, 97, 97,
12875203945Sweongyo		98, 98, 99, 100, 100, 100, 101, 101,
12876203945Sweongyo		102, 102, 103, 103, 104, 104, 105, 105,
12877203945Sweongyo		106, 106, 107, 107, 108, 108, 109, 109,
12878203945Sweongyo		110, 110, 110, 111, 111, 112, 112, 113,
12879203945Sweongyo		113, 114, 114, 114, 115, 115, 116, 116,
12880203945Sweongyo		117, 117, 117, 118, 118, 119, 119, 120,
12881203945Sweongyo		120, 120, 121, 121, 122, 122, 122, 123,
12882203945Sweongyo		123, 124, 124, 124, 125, 125, 126, 126,
12883203945Sweongyo		126, 127, 127, 128, 128, 128, 129, 129,
12884203945Sweongyo		130, 130, 130, 131, 131, 131, 132, 132,
12885203945Sweongyo		133, 133, 133, 134, 134, 134, 135, 135,
12886203945Sweongyo		136, 136, 136, 137, 137, 137, 138, 138,
12887203945Sweongyo		138, 139, 139, 140, 140, 140, 141, 141,
12888203945Sweongyo		141, 142, 142, 142, 143, 143, 143, 144,
12889203945Sweongyo		144, 144, 145, 145, 145, 146, 146, 146,
12890203945Sweongyo		147, 147, 147, 148, 148, 148, 149, 149,
12891203945Sweongyo		150, 150, 150, 150, 151, 151, 151, 152,
12892203945Sweongyo		152, 152, 153, 153, 153, 154, 154, 154,
12893203945Sweongyo		155, 155, 155, 156, 156, 156, 157, 157,
12894203945Sweongyo		157, 158, 158, 158, 159, 159, 159, 160
12895203945Sweongyo	};
12896203945Sweongyo
12897203945Sweongyo	if (x == 0)
12898203945Sweongyo		return (0);
12899203945Sweongyo	if (x >= 256) {
12900203945Sweongyo		device_printf(sc->sc_dev,
12901203945Sweongyo		    "out of bounds of the square-root table (%d)\n", x);
12902203945Sweongyo		return (16);
12903203945Sweongyo	}
12904203945Sweongyo	return (sqrt_table[x - 1] / 10);
12905203945Sweongyo}
12906203945Sweongyo
12907203945Sweongyostatic int
12908203945Sweongyobwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *mac, uint16_t sample)
12909203945Sweongyo{
12910203945Sweongyo#define	CALC_COEFF(_v, _x, _y, _z)	do {				\
12911203945Sweongyo	int _t;								\
12912203945Sweongyo	_t = _x - 20;							\
12913203945Sweongyo	if (_t >= 0) {							\
12914203945Sweongyo		_v = ((_y << (30 - _x)) + (_z >> (1 + _t))) / (_z >> _t); \
12915203945Sweongyo	} else {							\
12916203945Sweongyo		_v = ((_y << (30 - _x)) + (_z << (-1 - _t))) / (_z << -_t); \
12917203945Sweongyo	}								\
12918203945Sweongyo} while (0)
12919203945Sweongyo#define	CALC_COEFF2(_v, _x, _y, _z)	do {				\
12920203945Sweongyo	int _t;								\
12921203945Sweongyo	_t = _x - 11;							\
12922203945Sweongyo	if (_t >= 0)							\
12923203945Sweongyo		tmp[3] = (_y << (31 - _x)) / (_z >> _t);		\
12924203945Sweongyo	else								\
12925203945Sweongyo		tmp[3] = (_y << (31 - _x)) / (_z << -_t);		\
12926203945Sweongyo} while (0)
12927203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12928203945Sweongyo	uint16_t v0, v1;
12929203945Sweongyo	int tmp[2], ret;
12930203945Sweongyo
12931203945Sweongyo	v1 = BWN_PHY_READ(mac, BWN_PHY_RX_COMP_COEFF_S);
12932203945Sweongyo	v0 = v1 >> 8;
12933203945Sweongyo	v1 |= 0xff;
12934203945Sweongyo
12935203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, 0x00c0);
12936203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff);
12937203945Sweongyo
12938203945Sweongyo	ret = bwn_phy_lp_rx_iq_est(mac, sample, 32, &ie);
12939203945Sweongyo	if (ret == 0)
12940203945Sweongyo		goto done;
12941203945Sweongyo
12942203945Sweongyo	if (ie.ie_ipwr + ie.ie_qpwr < 2) {
12943203945Sweongyo		ret = 0;
12944203945Sweongyo		goto done;
12945203945Sweongyo	}
12946203945Sweongyo
12947203945Sweongyo	CALC_COEFF(tmp[0], bwn_nbits(ie.ie_iqprod), ie.ie_iqprod, ie.ie_ipwr);
12948203945Sweongyo	CALC_COEFF2(tmp[1], bwn_nbits(ie.ie_qpwr), ie.ie_qpwr, ie.ie_ipwr);
12949203945Sweongyo
12950203945Sweongyo	tmp[1] = -bwn_sqrt(mac, tmp[1] - (tmp[0] * tmp[0]));
12951203945Sweongyo	v0 = tmp[0] >> 3;
12952203945Sweongyo	v1 = tmp[1] >> 4;
12953203945Sweongyodone:
12954203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, v1);
12955203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, v0 << 8);
12956203945Sweongyo	return ret;
12957203945Sweongyo#undef CALC_COEFF
12958203945Sweongyo#undef CALC_COEFF2
12959203945Sweongyo}
12960203945Sweongyo
12961203945Sweongyostatic void
12962203945Sweongyobwn_phy_lp_tblinit_r01(struct bwn_mac *mac)
12963203945Sweongyo{
12964203945Sweongyo	static const uint16_t noisescale[] = {
12965203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12966203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4,
12967203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12968203945Sweongyo		0xa4a4, 0xa4a4, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12969203945Sweongyo		0x0000, 0x0000, 0x4c00, 0x2d36, 0x0000, 0x0000, 0x4c00, 0x2d36,
12970203945Sweongyo	};
12971203945Sweongyo	static const uint16_t crsgainnft[] = {
12972203945Sweongyo		0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f,
12973203945Sweongyo		0x036f, 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381,
12974203945Sweongyo		0x0374, 0x0381, 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f,
12975203945Sweongyo		0x0040, 0x005e, 0x007f, 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d,
12976203945Sweongyo		0x013d,
12977203945Sweongyo	};
12978203945Sweongyo	static const uint16_t filterctl[] = {
12979203945Sweongyo		0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077,
12980203945Sweongyo		0xff53, 0x0127,
12981203945Sweongyo	};
12982203945Sweongyo	static const uint32_t psctl[] = {
12983203945Sweongyo		0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101,
12984203945Sweongyo		0x00000080, 0x08080101, 0x00000040, 0x08080101, 0x000000c0,
12985203945Sweongyo		0x08a81501, 0x000000c0, 0x0fe8fd01, 0x000000c0, 0x08300105,
12986203945Sweongyo		0x000000c0, 0x08080201, 0x000000c0, 0x08280205, 0x000000c0,
12987203945Sweongyo		0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, 0x08080202,
12988203945Sweongyo		0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
12989203945Sweongyo		0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106,
12990203945Sweongyo		0x000000c0, 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
12991203945Sweongyo	};
12992203945Sweongyo	static const uint16_t ofdmcckgain_r0[] = {
12993203945Sweongyo		0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12994203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12995203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12996203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12997203945Sweongyo		0x755d,
12998203945Sweongyo	};
12999203945Sweongyo	static const uint16_t ofdmcckgain_r1[] = {
13000203945Sweongyo		0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
13001203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
13002203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
13003203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
13004203945Sweongyo		0x755d,
13005203945Sweongyo	};
13006203945Sweongyo	static const uint16_t gaindelta[] = {
13007203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13008203945Sweongyo		0x0000,
13009203945Sweongyo	};
13010203945Sweongyo	static const uint32_t txpwrctl[] = {
13011203945Sweongyo		0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c,
13012203945Sweongyo		0x0000004b, 0x0000004a, 0x00000049, 0x00000048, 0x00000047,
13013203945Sweongyo		0x00000046, 0x00000045, 0x00000044, 0x00000043, 0x00000042,
13014203945Sweongyo		0x00000041, 0x00000040, 0x0000003f, 0x0000003e, 0x0000003d,
13015203945Sweongyo		0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, 0x00000038,
13016203945Sweongyo		0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
13017203945Sweongyo		0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e,
13018203945Sweongyo		0x0000002d, 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029,
13019203945Sweongyo		0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
13020203945Sweongyo		0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001f,
13021203945Sweongyo		0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001a,
13022203945Sweongyo		0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
13023203945Sweongyo		0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000,
13024203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13025203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13026203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13027203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13028203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13029203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13030203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13031203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13032203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13033203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13034203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13035203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13036203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13037203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13038203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13039203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13040203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13041203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13042203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13043203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13044203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13045203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13046203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13047203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13048203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13049203945Sweongyo		0x00000000, 0x00000000, 0x000075a0, 0x000075a0, 0x000075a1,
13050203945Sweongyo		0x000075a1, 0x000075a2, 0x000075a2, 0x000075a3, 0x000075a3,
13051203945Sweongyo		0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, 0x000074b2,
13052203945Sweongyo		0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
13053203945Sweongyo		0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23,
13054203945Sweongyo		0x00006d23, 0x00004660, 0x00004660, 0x00004661, 0x00004661,
13055203945Sweongyo		0x00004662, 0x00004662, 0x00004663, 0x00004663, 0x00003e60,
13056203945Sweongyo		0x00003e60, 0x00003e61, 0x00003e61, 0x00003e62, 0x00003e62,
13057203945Sweongyo		0x00003e63, 0x00003e63, 0x00003660, 0x00003660, 0x00003661,
13058203945Sweongyo		0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
13059203945Sweongyo		0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62,
13060203945Sweongyo		0x00002e62, 0x00002e63, 0x00002e63, 0x00002660, 0x00002660,
13061203945Sweongyo		0x00002661, 0x00002661, 0x00002662, 0x00002662, 0x00002663,
13062203945Sweongyo		0x00002663, 0x000025e0, 0x000025e0, 0x000025e1, 0x000025e1,
13063203945Sweongyo		0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, 0x00001de0,
13064203945Sweongyo		0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
13065203945Sweongyo		0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61,
13066203945Sweongyo		0x00001d61, 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63,
13067203945Sweongyo		0x00001560, 0x00001560, 0x00001561, 0x00001561, 0x00001562,
13068203945Sweongyo		0x00001562, 0x00001563, 0x00001563, 0x00000d60, 0x00000d60,
13069203945Sweongyo		0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, 0x00000d63,
13070203945Sweongyo		0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
13071203945Sweongyo		0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10,
13072203945Sweongyo		0x00000e10, 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12,
13073203945Sweongyo		0x00000e13, 0x00000e13, 0x00000bf0, 0x00000bf0, 0x00000bf1,
13074203945Sweongyo		0x00000bf1, 0x00000bf2, 0x00000bf2, 0x00000bf3, 0x00000bf3,
13075203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13076203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13077203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13078203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13079203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13080203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13081203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13082203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13083203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13084203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13085203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13086203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13087203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13088203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13089203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13090203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13091203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13092203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13093203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13094203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13095203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13096203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13097203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13098203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
13099203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
13100203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc,
13101203945Sweongyo		0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04,
13102203945Sweongyo		0x0000fcff, 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006,
13103203945Sweongyo		0x0000ff03, 0x000007fc, 0x0000fc08, 0x00000203, 0x0000fffb,
13104203945Sweongyo		0x00000600, 0x0000fa01, 0x0000fc03, 0x0000fe06, 0x0000fe00,
13105203945Sweongyo		0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, 0x000004fd,
13106203945Sweongyo		0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
13107203945Sweongyo		0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa,
13108203945Sweongyo		0x00000700, 0x00000305, 0x000004ff, 0x00000801, 0x00000503,
13109203945Sweongyo		0x000005f9, 0x00000404, 0x0000fb08, 0x000005fd, 0x00000501,
13110203945Sweongyo		0x00000405, 0x0000fb03, 0x000007fc, 0x00000403, 0x00000303,
13111203945Sweongyo		0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, 0x0000fe01,
13112203945Sweongyo		0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
13113203945Sweongyo		0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa,
13114203945Sweongyo		0x000003fe, 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06,
13115203945Sweongyo		0x000008fc, 0x00000701, 0x00000504, 0x0000fdfe, 0x0000fdfc,
13116203945Sweongyo		0x000003fe, 0x00000704, 0x000002fc, 0x000004f9, 0x0000fdfd,
13117203945Sweongyo		0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, 0x000004f9,
13118203945Sweongyo		0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
13119203945Sweongyo		0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa,
13120203945Sweongyo		0x00000305, 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc,
13121203945Sweongyo		0x0000fe03, 0x00000701, 0x000001fb, 0x000001f9, 0x00000206,
13122203945Sweongyo		0x000006fd, 0x00000508, 0x00000700, 0x00000304, 0x000005fe,
13123203945Sweongyo		0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, 0x000007f9,
13124203945Sweongyo		0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
13125203945Sweongyo		0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb,
13126203945Sweongyo		0x00000702,
13127203945Sweongyo	};
13128203945Sweongyo
13129203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13130203945Sweongyo
13131203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13132203945Sweongyo	    bwn_tab_sigsq_tbl);
13133203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13134203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(crsgainnft), crsgainnft);
13135203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(8, 0), N(filterctl), filterctl);
13136203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(psctl), psctl);
13137203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13138203945Sweongyo	    bwn_tab_pllfrac_tbl);
13139203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13140203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13141203945Sweongyo	if (mac->mac_phy.rev == 0) {
13142203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r0),
13143203945Sweongyo		    ofdmcckgain_r0);
13144203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r0),
13145203945Sweongyo		    ofdmcckgain_r0);
13146203945Sweongyo	} else {
13147203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r1),
13148203945Sweongyo		    ofdmcckgain_r1);
13149203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r1),
13150203945Sweongyo		    ofdmcckgain_r1);
13151203945Sweongyo	}
13152203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(gaindelta), gaindelta);
13153203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(txpwrctl), txpwrctl);
13154203945Sweongyo}
13155203945Sweongyo
13156203945Sweongyostatic void
13157203945Sweongyobwn_phy_lp_tblinit_r2(struct bwn_mac *mac)
13158203945Sweongyo{
13159203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
13160203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
13161203945Sweongyo	int i;
13162203945Sweongyo	static const uint16_t noisescale[] = {
13163203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13164203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13165203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13166203945Sweongyo		0x00a4, 0x00a4, 0x0000, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13167203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13168203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
13169203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4
13170203945Sweongyo	};
13171203945Sweongyo	static const uint32_t filterctl[] = {
13172203945Sweongyo		0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27,
13173203945Sweongyo		0x0000217f, 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f
13174203945Sweongyo	};
13175203945Sweongyo	static const uint32_t psctl[] = {
13176203945Sweongyo		0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000,
13177203945Sweongyo		0x00002080, 0x00006180, 0x00003002, 0x00000040, 0x00002042,
13178203945Sweongyo		0x00180047, 0x00080043, 0x00000041, 0x000020c1, 0x00046006,
13179203945Sweongyo		0x00042002, 0x00040000, 0x00002003, 0x00180006, 0x00080002
13180203945Sweongyo	};
13181203945Sweongyo	static const uint32_t gainidx[] = {
13182203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13183203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13184203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13185203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x10000001, 0x00000000,
13186203945Sweongyo		0x20000082, 0x00000000, 0x40000104, 0x00000000, 0x60004207,
13187203945Sweongyo		0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
13188203945Sweongyo		0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288,
13189203945Sweongyo		0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
13190203945Sweongyo		0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794,
13191203945Sweongyo		0x00000010, 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011,
13192203945Sweongyo		0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21,
13193203945Sweongyo		0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
13194203945Sweongyo		0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329,
13195203945Sweongyo		0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
13196203945Sweongyo		0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, 0x00000000,
13197203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13198203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13199203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13200203945Sweongyo		0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082,
13201203945Sweongyo		0x00000000, 0x40000104, 0x00000000, 0x60004207, 0x00000001,
13202203945Sweongyo		0x7000838a, 0x00000001, 0xd021050d, 0x00000001, 0xe041c683,
13203203945Sweongyo		0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
13204203945Sweongyo		0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711,
13205203945Sweongyo		0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
13206203945Sweongyo		0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c,
13207203945Sweongyo		0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019,
13208203945Sweongyo		0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, 0xb36811a6,
13209203945Sweongyo		0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
13210203945Sweongyo		0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c,
13211203945Sweongyo		0x0000001a, 0x64ca55ad, 0x0000001a
13212203945Sweongyo	};
13213203945Sweongyo	static const uint16_t auxgainidx[] = {
13214203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13215203945Sweongyo		0x0000, 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000,
13216203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002,
13217203945Sweongyo		0x0004, 0x0016
13218203945Sweongyo	};
13219203945Sweongyo	static const uint16_t swctl[] = {
13220203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13221203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13222203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13223203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
13224203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13225203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
13226203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
13227203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018
13228203945Sweongyo	};
13229203945Sweongyo	static const uint8_t hf[] = {
13230203945Sweongyo		0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
13231203945Sweongyo		0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17
13232203945Sweongyo	};
13233203945Sweongyo	static const uint32_t gainval[] = {
13234203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13235203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13236203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13237203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13238203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13239203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13240203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13241203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13242203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13243203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13244203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13245203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13246203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009,
13247203945Sweongyo		0x000000f1, 0x00000000, 0x00000000
13248203945Sweongyo	};
13249203945Sweongyo	static const uint16_t gain[] = {
13250203945Sweongyo		0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808,
13251203945Sweongyo		0x080a, 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813,
13252203945Sweongyo		0x0814, 0x0816, 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824,
13253203945Sweongyo		0x0830, 0x0834, 0x0837, 0x083b, 0x083f, 0x0840, 0x0844, 0x0857,
13254203945Sweongyo		0x085b, 0x085f, 0x08d7, 0x08db, 0x08df, 0x0957, 0x095b, 0x095f,
13255203945Sweongyo		0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, 0x175f, 0x0000, 0x0000,
13256203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13257203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13258203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13259203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13260203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13261203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13262203945Sweongyo	};
13263203945Sweongyo	static const uint32_t papdeps[] = {
13264203945Sweongyo		0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9,
13265203945Sweongyo		0x00021fdf, 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7,
13266203945Sweongyo		0x0004efc2, 0x00055fb5, 0x0005cfb0, 0x00063fa8, 0x00068fa3,
13267203945Sweongyo		0x00071f98, 0x0007ef92, 0x00084f8b, 0x0008df82, 0x00097f77,
13268203945Sweongyo		0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, 0x000bff41,
13269203945Sweongyo		0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
13270203945Sweongyo		0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15,
13271203945Sweongyo		0x00143f1c, 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f,
13272203945Sweongyo		0x001e6f7e, 0x0021cfa4, 0x0025bfd2, 0x002a2008, 0x002fb047,
13273203945Sweongyo		0x00360090, 0x003d40e0, 0x0045c135, 0x004fb189, 0x005ae1d7,
13274203945Sweongyo		0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, 0x007ff2e3,
13275203945Sweongyo		0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
13276203945Sweongyo		0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506
13277203945Sweongyo	};
13278203945Sweongyo	static const uint32_t papdmult[] = {
13279203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13280203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13281203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13282203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13283203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13284203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13285203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13286203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13287203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13288203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13289203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13290203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13291203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13292203945Sweongyo	};
13293203945Sweongyo	static const uint32_t gainidx_a0[] = {
13294203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13295203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13296203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13297203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13298203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13299203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13300203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13301203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13302203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13303203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13304203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13305203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13306203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13307203945Sweongyo	};
13308203945Sweongyo	static const uint16_t auxgainidx_a0[] = {
13309203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13310203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000,
13311203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13312203945Sweongyo		0x0002, 0x0014
13313203945Sweongyo	};
13314203945Sweongyo	static const uint32_t gainval_a0[] = {
13315203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13316203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13317203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13318203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13319203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13320203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13321203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13322203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13323203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13324203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13325203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13326203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13327203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f,
13328203945Sweongyo		0x000000f7, 0x00000000, 0x00000000
13329203945Sweongyo	};
13330203945Sweongyo	static const uint16_t gain_a0[] = {
13331203945Sweongyo		0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b,
13332203945Sweongyo		0x000c, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016,
13333203945Sweongyo		0x0017, 0x001a, 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034,
13334203945Sweongyo		0x0037, 0x003b, 0x003f, 0x0040, 0x0044, 0x0057, 0x005b, 0x005f,
13335203945Sweongyo		0x00d7, 0x00db, 0x00df, 0x0157, 0x015b, 0x015f, 0x0357, 0x035b,
13336203945Sweongyo		0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, 0x0000, 0x0000, 0x0000,
13337203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13338203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13339203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13340203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13341203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13342203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13343203945Sweongyo	};
13344203945Sweongyo
13345203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13346203945Sweongyo
13347203945Sweongyo	for (i = 0; i < 704; i++)
13348203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(7, i), 0);
13349203945Sweongyo
13350203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13351203945Sweongyo	    bwn_tab_sigsq_tbl);
13352203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13353203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(11, 0), N(filterctl), filterctl);
13354203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(12, 0), N(psctl), psctl);
13355203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx), gainidx);
13356203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx), auxgainidx);
13357203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(swctl), swctl);
13358203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(16, 0), N(hf), hf);
13359203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval), gainval);
13360203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain), gain);
13361203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13362203945Sweongyo	    bwn_tab_pllfrac_tbl);
13363203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13364203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13365203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(papdeps), papdeps);
13366203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(papdmult), papdmult);
13367203945Sweongyo
13368203945Sweongyo	if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
13369203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx_a0),
13370203945Sweongyo		    gainidx_a0);
13371203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx_a0),
13372203945Sweongyo		    auxgainidx_a0);
13373203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval_a0),
13374203945Sweongyo		    gainval_a0);
13375203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain_a0), gain_a0);
13376203945Sweongyo	}
13377203945Sweongyo}
13378203945Sweongyo
13379203945Sweongyostatic void
13380203945Sweongyobwn_phy_lp_tblinit_txgain(struct bwn_mac *mac)
13381203945Sweongyo{
13382203945Sweongyo	struct siba_dev_softc *sd = mac->mac_sd;
13383203945Sweongyo	struct siba_softc *siba = sd->sd_bus;
13384203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13385203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
13386203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
13387203945Sweongyo	static struct bwn_txgain_entry txgain_r2[] = {
13388203945Sweongyo		{ 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 },
13389203945Sweongyo		{ 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 },
13390203945Sweongyo		{ 255, 255, 203, 0, 135 }, { 255, 255, 203, 0, 131 },
13391203945Sweongyo		{ 255, 255, 203, 0, 128 }, { 255, 255, 203, 0, 124 },
13392203945Sweongyo		{ 255, 255, 203, 0, 121 }, { 255, 255, 203, 0, 117 },
13393203945Sweongyo		{ 255, 255, 203, 0, 114 }, { 255, 255, 203, 0, 111 },
13394203945Sweongyo		{ 255, 255, 203, 0, 107 }, { 255, 255, 203, 0, 104 },
13395203945Sweongyo		{ 255, 255, 203, 0, 101 }, { 255, 255, 203, 0, 99 },
13396203945Sweongyo		{ 255, 255, 203, 0, 96 }, { 255, 255, 203, 0, 93 },
13397203945Sweongyo		{ 255, 255, 203, 0, 90 }, { 255, 255, 203, 0, 88 },
13398203945Sweongyo		{ 255, 255, 203, 0, 85 }, { 255, 255, 203, 0, 83 },
13399203945Sweongyo		{ 255, 255, 203, 0, 81 }, { 255, 255, 203, 0, 78 },
13400203945Sweongyo		{ 255, 255, 203, 0, 76 }, { 255, 255, 203, 0, 74 },
13401203945Sweongyo		{ 255, 255, 203, 0, 72 }, { 255, 255, 203, 0, 70 },
13402203945Sweongyo		{ 255, 255, 203, 0, 68 }, { 255, 255, 203, 0, 66 },
13403203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13404203945Sweongyo		{ 255, 255, 192, 0, 64 }, { 255, 255, 186, 0, 64 },
13405203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 176, 0, 64 },
13406203945Sweongyo		{ 255, 255, 171, 0, 64 }, { 255, 255, 166, 0, 64 },
13407203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 157, 0, 64 },
13408203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13409203945Sweongyo		{ 255, 255, 144, 0, 64 }, { 255, 255, 140, 0, 64 },
13410203945Sweongyo		{ 255, 255, 136, 0, 64 }, { 255, 255, 132, 0, 64 },
13411203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13412203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13413203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13414203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 105, 0, 64 },
13415203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13416203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13417203945Sweongyo		{ 255, 255, 91, 0, 64 }, { 255, 255, 88, 0, 64 },
13418203945Sweongyo		{ 255, 255, 86, 0, 64 }, { 255, 255, 83, 0, 64 },
13419203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 79, 0, 64 },
13420203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13421203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13422203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13423203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 248, 64, 0, 64 },
13424203945Sweongyo		{ 255, 248, 62, 0, 64 }, { 255, 241, 62, 0, 64 },
13425203945Sweongyo		{ 255, 241, 60, 0, 64 }, { 255, 234, 60, 0, 64 },
13426203945Sweongyo		{ 255, 234, 59, 0, 64 }, { 255, 227, 59, 0, 64 },
13427203945Sweongyo		{ 255, 227, 57, 0, 64 }, { 255, 221, 57, 0, 64 },
13428203945Sweongyo		{ 255, 221, 55, 0, 64 }, { 255, 215, 55, 0, 64 },
13429203945Sweongyo		{ 255, 215, 54, 0, 64 }, { 255, 208, 54, 0, 64 },
13430203945Sweongyo		{ 255, 208, 52, 0, 64 }, { 255, 203, 52, 0, 64 },
13431203945Sweongyo		{ 255, 203, 51, 0, 64 }, { 255, 197, 51, 0, 64 },
13432203945Sweongyo		{ 255, 197, 49, 0, 64 }, { 255, 191, 49, 0, 64 },
13433203945Sweongyo		{ 255, 191, 48, 0, 64 }, { 255, 186, 48, 0, 64 },
13434203945Sweongyo		{ 255, 186, 47, 0, 64 }, { 255, 181, 47, 0, 64 },
13435203945Sweongyo		{ 255, 181, 45, 0, 64 }, { 255, 175, 45, 0, 64 },
13436203945Sweongyo		{ 255, 175, 44, 0, 64 }, { 255, 170, 44, 0, 64 },
13437203945Sweongyo		{ 255, 170, 43, 0, 64 }, { 255, 166, 43, 0, 64 },
13438203945Sweongyo		{ 255, 166, 42, 0, 64 }, { 255, 161, 42, 0, 64 },
13439203945Sweongyo		{ 255, 161, 40, 0, 64 }, { 255, 156, 40, 0, 64 },
13440203945Sweongyo		{ 255, 156, 39, 0, 64 }, { 255, 152, 39, 0, 64 },
13441203945Sweongyo		{ 255, 152, 38, 0, 64 }, { 255, 148, 38, 0, 64 },
13442203945Sweongyo		{ 255, 148, 37, 0, 64 }, { 255, 143, 37, 0, 64 },
13443203945Sweongyo		{ 255, 143, 36, 0, 64 }, { 255, 139, 36, 0, 64 },
13444203945Sweongyo		{ 255, 139, 35, 0, 64 }, { 255, 135, 35, 0, 64 },
13445203945Sweongyo		{ 255, 135, 34, 0, 64 }, { 255, 132, 34, 0, 64 },
13446203945Sweongyo		{ 255, 132, 33, 0, 64 }, { 255, 128, 33, 0, 64 },
13447203945Sweongyo		{ 255, 128, 32, 0, 64 }, { 255, 124, 32, 0, 64 },
13448203945Sweongyo		{ 255, 124, 31, 0, 64 }, { 255, 121, 31, 0, 64 },
13449203945Sweongyo		{ 255, 121, 30, 0, 64 }, { 255, 117, 30, 0, 64 },
13450203945Sweongyo		{ 255, 117, 29, 0, 64 }, { 255, 114, 29, 0, 64 },
13451203945Sweongyo		{ 255, 114, 29, 0, 64 }, { 255, 111, 29, 0, 64 },
13452203945Sweongyo	};
13453203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r2[] = {
13454203945Sweongyo		{ 7, 99, 255, 0, 64 }, { 7, 96, 255, 0, 64 },
13455203945Sweongyo		{ 7, 93, 255, 0, 64 }, { 7, 90, 255, 0, 64 },
13456203945Sweongyo		{ 7, 88, 255, 0, 64 }, { 7, 85, 255, 0, 64 },
13457203945Sweongyo		{ 7, 83, 255, 0, 64 }, { 7, 81, 255, 0, 64 },
13458203945Sweongyo		{ 7, 78, 255, 0, 64 }, { 7, 76, 255, 0, 64 },
13459203945Sweongyo		{ 7, 74, 255, 0, 64 }, { 7, 72, 255, 0, 64 },
13460203945Sweongyo		{ 7, 70, 255, 0, 64 }, { 7, 68, 255, 0, 64 },
13461203945Sweongyo		{ 7, 66, 255, 0, 64 }, { 7, 64, 255, 0, 64 },
13462203945Sweongyo		{ 7, 64, 255, 0, 64 }, { 7, 62, 255, 0, 64 },
13463203945Sweongyo		{ 7, 62, 248, 0, 64 }, { 7, 60, 248, 0, 64 },
13464203945Sweongyo		{ 7, 60, 241, 0, 64 }, { 7, 59, 241, 0, 64 },
13465203945Sweongyo		{ 7, 59, 234, 0, 64 }, { 7, 57, 234, 0, 64 },
13466203945Sweongyo		{ 7, 57, 227, 0, 64 }, { 7, 55, 227, 0, 64 },
13467203945Sweongyo		{ 7, 55, 221, 0, 64 }, { 7, 54, 221, 0, 64 },
13468203945Sweongyo		{ 7, 54, 215, 0, 64 }, { 7, 52, 215, 0, 64 },
13469203945Sweongyo		{ 7, 52, 208, 0, 64 }, { 7, 51, 208, 0, 64 },
13470203945Sweongyo		{ 7, 51, 203, 0, 64 }, { 7, 49, 203, 0, 64 },
13471203945Sweongyo		{ 7, 49, 197, 0, 64 }, { 7, 48, 197, 0, 64 },
13472203945Sweongyo		{ 7, 48, 191, 0, 64 }, { 7, 47, 191, 0, 64 },
13473203945Sweongyo		{ 7, 47, 186, 0, 64 }, { 7, 45, 186, 0, 64 },
13474203945Sweongyo		{ 7, 45, 181, 0, 64 }, { 7, 44, 181, 0, 64 },
13475203945Sweongyo		{ 7, 44, 175, 0, 64 }, { 7, 43, 175, 0, 64 },
13476203945Sweongyo		{ 7, 43, 170, 0, 64 }, { 7, 42, 170, 0, 64 },
13477203945Sweongyo		{ 7, 42, 166, 0, 64 }, { 7, 40, 166, 0, 64 },
13478203945Sweongyo		{ 7, 40, 161, 0, 64 }, { 7, 39, 161, 0, 64 },
13479203945Sweongyo		{ 7, 39, 156, 0, 64 }, { 7, 38, 156, 0, 64 },
13480203945Sweongyo		{ 7, 38, 152, 0, 64 }, { 7, 37, 152, 0, 64 },
13481203945Sweongyo		{ 7, 37, 148, 0, 64 }, { 7, 36, 148, 0, 64 },
13482203945Sweongyo		{ 7, 36, 143, 0, 64 }, { 7, 35, 143, 0, 64 },
13483203945Sweongyo		{ 7, 35, 139, 0, 64 }, { 7, 34, 139, 0, 64 },
13484203945Sweongyo		{ 7, 34, 135, 0, 64 }, { 7, 33, 135, 0, 64 },
13485203945Sweongyo		{ 7, 33, 132, 0, 64 }, { 7, 32, 132, 0, 64 },
13486203945Sweongyo		{ 7, 32, 128, 0, 64 }, { 7, 31, 128, 0, 64 },
13487203945Sweongyo		{ 7, 31, 124, 0, 64 }, { 7, 30, 124, 0, 64 },
13488203945Sweongyo		{ 7, 30, 121, 0, 64 }, { 7, 29, 121, 0, 64 },
13489203945Sweongyo		{ 7, 29, 117, 0, 64 }, { 7, 29, 117, 0, 64 },
13490203945Sweongyo		{ 7, 29, 114, 0, 64 }, { 7, 28, 114, 0, 64 },
13491203945Sweongyo		{ 7, 28, 111, 0, 64 }, { 7, 27, 111, 0, 64 },
13492203945Sweongyo		{ 7, 27, 108, 0, 64 }, { 7, 26, 108, 0, 64 },
13493203945Sweongyo		{ 7, 26, 104, 0, 64 }, { 7, 25, 104, 0, 64 },
13494203945Sweongyo		{ 7, 25, 102, 0, 64 }, { 7, 25, 102, 0, 64 },
13495203945Sweongyo		{ 7, 25, 99, 0, 64 }, { 7, 24, 99, 0, 64 },
13496203945Sweongyo		{ 7, 24, 96, 0, 64 }, { 7, 23, 96, 0, 64 },
13497203945Sweongyo		{ 7, 23, 93, 0, 64 }, { 7, 23, 93, 0, 64 },
13498203945Sweongyo		{ 7, 23, 90, 0, 64 }, { 7, 22, 90, 0, 64 },
13499203945Sweongyo		{ 7, 22, 88, 0, 64 }, { 7, 21, 88, 0, 64 },
13500203945Sweongyo		{ 7, 21, 85, 0, 64 }, { 7, 21, 85, 0, 64 },
13501203945Sweongyo		{ 7, 21, 83, 0, 64 }, { 7, 20, 83, 0, 64 },
13502203945Sweongyo		{ 7, 20, 81, 0, 64 }, { 7, 20, 81, 0, 64 },
13503203945Sweongyo		{ 7, 20, 78, 0, 64 }, { 7, 19, 78, 0, 64 },
13504203945Sweongyo		{ 7, 19, 76, 0, 64 }, { 7, 19, 76, 0, 64 },
13505203945Sweongyo		{ 7, 19, 74, 0, 64 }, { 7, 18, 74, 0, 64 },
13506203945Sweongyo		{ 7, 18, 72, 0, 64 }, { 7, 18, 72, 0, 64 },
13507203945Sweongyo		{ 7, 18, 70, 0, 64 }, { 7, 17, 70, 0, 64 },
13508203945Sweongyo		{ 7, 17, 68, 0, 64 }, { 7, 17, 68, 0, 64 },
13509203945Sweongyo		{ 7, 17, 66, 0, 64 }, { 7, 16, 66, 0, 64 },
13510203945Sweongyo		{ 7, 16, 64, 0, 64 }, { 7, 16, 64, 0, 64 },
13511203945Sweongyo		{ 7, 16, 62, 0, 64 }, { 7, 15, 62, 0, 64 },
13512203945Sweongyo		{ 7, 15, 60, 0, 64 }, { 7, 15, 60, 0, 64 },
13513203945Sweongyo		{ 7, 15, 59, 0, 64 }, { 7, 14, 59, 0, 64 },
13514203945Sweongyo		{ 7, 14, 57, 0, 64 }, { 7, 14, 57, 0, 64 },
13515203945Sweongyo		{ 7, 14, 55, 0, 64 }, { 7, 14, 55, 0, 64 },
13516203945Sweongyo		{ 7, 14, 54, 0, 64 }, { 7, 13, 54, 0, 64 },
13517203945Sweongyo		{ 7, 13, 52, 0, 64 }, { 7, 13, 52, 0, 64 },
13518203945Sweongyo	};
13519203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r2[] = {
13520203945Sweongyo		{ 255, 255, 255, 0, 152 }, { 255, 255, 255, 0, 147 },
13521203945Sweongyo		{ 255, 255, 255, 0, 143 }, { 255, 255, 255, 0, 139 },
13522203945Sweongyo		{ 255, 255, 255, 0, 135 }, { 255, 255, 255, 0, 131 },
13523203945Sweongyo		{ 255, 255, 255, 0, 128 }, { 255, 255, 255, 0, 124 },
13524203945Sweongyo		{ 255, 255, 255, 0, 121 }, { 255, 255, 255, 0, 117 },
13525203945Sweongyo		{ 255, 255, 255, 0, 114 }, { 255, 255, 255, 0, 111 },
13526203945Sweongyo		{ 255, 255, 255, 0, 107 }, { 255, 255, 255, 0, 104 },
13527203945Sweongyo		{ 255, 255, 255, 0, 101 }, { 255, 255, 255, 0, 99 },
13528203945Sweongyo		{ 255, 255, 255, 0, 96 }, { 255, 255, 255, 0, 93 },
13529203945Sweongyo		{ 255, 255, 255, 0, 90 }, { 255, 255, 255, 0, 88 },
13530203945Sweongyo		{ 255, 255, 255, 0, 85 }, { 255, 255, 255, 0, 83 },
13531203945Sweongyo		{ 255, 255, 255, 0, 81 }, { 255, 255, 255, 0, 78 },
13532203945Sweongyo		{ 255, 255, 255, 0, 76 }, { 255, 255, 255, 0, 74 },
13533203945Sweongyo		{ 255, 255, 255, 0, 72 }, { 255, 255, 255, 0, 70 },
13534203945Sweongyo		{ 255, 255, 255, 0, 68 }, { 255, 255, 255, 0, 66 },
13535203945Sweongyo		{ 255, 255, 255, 0, 64 }, { 255, 255, 248, 0, 64 },
13536203945Sweongyo		{ 255, 255, 241, 0, 64 }, { 255, 255, 234, 0, 64 },
13537203945Sweongyo		{ 255, 255, 227, 0, 64 }, { 255, 255, 221, 0, 64 },
13538203945Sweongyo		{ 255, 255, 215, 0, 64 }, { 255, 255, 208, 0, 64 },
13539203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13540203945Sweongyo		{ 255, 255, 191, 0, 64 }, { 255, 255, 186, 0, 64 },
13541203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 175, 0, 64 },
13542203945Sweongyo		{ 255, 255, 170, 0, 64 }, { 255, 255, 166, 0, 64 },
13543203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 156, 0, 64 },
13544203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13545203945Sweongyo		{ 255, 255, 143, 0, 64 }, { 255, 255, 139, 0, 64 },
13546203945Sweongyo		{ 255, 255, 135, 0, 64 }, { 255, 255, 132, 0, 64 },
13547203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13548203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13549203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13550203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 104, 0, 64 },
13551203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13552203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13553203945Sweongyo		{ 255, 255, 90, 0, 64 }, { 255, 255, 88, 0, 64 },
13554203945Sweongyo		{ 255, 255, 85, 0, 64 }, { 255, 255, 83, 0, 64 },
13555203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 78, 0, 64 },
13556203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13557203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13558203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13559203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 255, 64, 0, 64 },
13560203945Sweongyo		{ 255, 255, 62, 0, 64 }, { 255, 248, 62, 0, 64 },
13561203945Sweongyo		{ 255, 248, 60, 0, 64 }, { 255, 241, 60, 0, 64 },
13562203945Sweongyo		{ 255, 241, 59, 0, 64 }, { 255, 234, 59, 0, 64 },
13563203945Sweongyo		{ 255, 234, 57, 0, 64 }, { 255, 227, 57, 0, 64 },
13564203945Sweongyo		{ 255, 227, 55, 0, 64 }, { 255, 221, 55, 0, 64 },
13565203945Sweongyo		{ 255, 221, 54, 0, 64 }, { 255, 215, 54, 0, 64 },
13566203945Sweongyo		{ 255, 215, 52, 0, 64 }, { 255, 208, 52, 0, 64 },
13567203945Sweongyo		{ 255, 208, 51, 0, 64 }, { 255, 203, 51, 0, 64 },
13568203945Sweongyo		{ 255, 203, 49, 0, 64 }, { 255, 197, 49, 0, 64 },
13569203945Sweongyo		{ 255, 197, 48, 0, 64 }, { 255, 191, 48, 0, 64 },
13570203945Sweongyo		{ 255, 191, 47, 0, 64 }, { 255, 186, 47, 0, 64 },
13571203945Sweongyo		{ 255, 186, 45, 0, 64 }, { 255, 181, 45, 0, 64 },
13572203945Sweongyo		{ 255, 181, 44, 0, 64 }, { 255, 175, 44, 0, 64 },
13573203945Sweongyo		{ 255, 175, 43, 0, 64 }, { 255, 170, 43, 0, 64 },
13574203945Sweongyo		{ 255, 170, 42, 0, 64 }, { 255, 166, 42, 0, 64 },
13575203945Sweongyo		{ 255, 166, 40, 0, 64 }, { 255, 161, 40, 0, 64 },
13576203945Sweongyo		{ 255, 161, 39, 0, 64 }, { 255, 156, 39, 0, 64 },
13577203945Sweongyo		{ 255, 156, 38, 0, 64 }, { 255, 152, 38, 0, 64 },
13578203945Sweongyo		{ 255, 152, 37, 0, 64 }, { 255, 148, 37, 0, 64 },
13579203945Sweongyo		{ 255, 148, 36, 0, 64 }, { 255, 143, 36, 0, 64 },
13580203945Sweongyo		{ 255, 143, 35, 0, 64 }, { 255, 139, 35, 0, 64 },
13581203945Sweongyo		{ 255, 139, 34, 0, 64 }, { 255, 135, 34, 0, 64 },
13582203945Sweongyo		{ 255, 135, 33, 0, 64 }, { 255, 132, 33, 0, 64 },
13583203945Sweongyo		{ 255, 132, 32, 0, 64 }, { 255, 128, 32, 0, 64 }
13584203945Sweongyo	};
13585203945Sweongyo	static struct bwn_txgain_entry txgain_r0[] = {
13586203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13587203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13588203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13589203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13590203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13591203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13592203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13593203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13594203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13595203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13596203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13597203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13598203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13599203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13600203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13601203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13602203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13603203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13604203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 13, 0, 68 },
13605203945Sweongyo		{ 7, 15, 13, 0, 66 }, { 7, 15, 13, 0, 64 },
13606203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13607203945Sweongyo		{ 7, 15, 13, 0, 59 }, { 7, 15, 13, 0, 57 },
13608203945Sweongyo		{ 7, 15, 12, 0, 71 }, { 7, 15, 12, 0, 69 },
13609203945Sweongyo		{ 7, 15, 12, 0, 67 }, { 7, 15, 12, 0, 65 },
13610203945Sweongyo		{ 7, 15, 12, 0, 63 }, { 7, 15, 12, 0, 62 },
13611203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 58 },
13612203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 70 },
13613203945Sweongyo		{ 7, 15, 11, 0, 68 }, { 7, 15, 11, 0, 66 },
13614203945Sweongyo		{ 7, 15, 11, 0, 65 }, { 7, 15, 11, 0, 63 },
13615203945Sweongyo		{ 7, 15, 11, 0, 61 }, { 7, 15, 11, 0, 59 },
13616203945Sweongyo		{ 7, 15, 11, 0, 58 }, { 7, 15, 10, 0, 71 },
13617203945Sweongyo		{ 7, 15, 10, 0, 69 }, { 7, 15, 10, 0, 67 },
13618203945Sweongyo		{ 7, 15, 10, 0, 65 }, { 7, 15, 10, 0, 63 },
13619203945Sweongyo		{ 7, 15, 10, 0, 61 }, { 7, 15, 10, 0, 60 },
13620203945Sweongyo		{ 7, 15, 10, 0, 58 }, { 7, 15, 10, 0, 56 },
13621203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13622203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13623203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 60 },
13624203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 14, 9, 0, 72 },
13625203945Sweongyo		{ 7, 14, 9, 0, 70 }, { 7, 14, 9, 0, 68 },
13626203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 64 },
13627203945Sweongyo		{ 7, 14, 9, 0, 62 }, { 7, 14, 9, 0, 60 },
13628203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 13, 9, 0, 72 },
13629203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13630203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13631203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13632203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13633203945Sweongyo		{ 7, 13, 8, 0, 72 }, { 7, 13, 8, 0, 70 },
13634203945Sweongyo		{ 7, 13, 8, 0, 68 }, { 7, 13, 8, 0, 66 },
13635203945Sweongyo		{ 7, 13, 8, 0, 64 }, { 7, 13, 8, 0, 62 },
13636203945Sweongyo		{ 7, 13, 8, 0, 60 }, { 7, 13, 8, 0, 59 },
13637203945Sweongyo		{ 7, 12, 8, 0, 72 }, { 7, 12, 8, 0, 70 },
13638203945Sweongyo		{ 7, 12, 8, 0, 68 }, { 7, 12, 8, 0, 66 },
13639203945Sweongyo		{ 7, 12, 8, 0, 64 }, { 7, 12, 8, 0, 62 },
13640203945Sweongyo		{ 7, 12, 8, 0, 61 }, { 7, 12, 8, 0, 59 },
13641203945Sweongyo		{ 7, 12, 7, 0, 73 }, { 7, 12, 7, 0, 71 },
13642203945Sweongyo		{ 7, 12, 7, 0, 69 }, { 7, 12, 7, 0, 67 },
13643203945Sweongyo		{ 7, 12, 7, 0, 65 }, { 7, 12, 7, 0, 63 },
13644203945Sweongyo		{ 7, 12, 7, 0, 61 }, { 7, 12, 7, 0, 59 },
13645203945Sweongyo		{ 7, 11, 7, 0, 72 }, { 7, 11, 7, 0, 70 },
13646203945Sweongyo		{ 7, 11, 7, 0, 68 }, { 7, 11, 7, 0, 66 },
13647203945Sweongyo		{ 7, 11, 7, 0, 65 }, { 7, 11, 7, 0, 63 },
13648203945Sweongyo		{ 7, 11, 7, 0, 61 }, { 7, 11, 7, 0, 59 },
13649203945Sweongyo		{ 7, 11, 6, 0, 73 }, { 7, 11, 6, 0, 71 }
13650203945Sweongyo	};
13651203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r0[] = {
13652203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13653203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13654203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13655203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13656203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13657203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13658203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13659203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13660203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13661203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13662203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13663203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13664203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13665203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13666203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13667203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13668203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13669203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13670203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13671203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13672203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13673203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13674203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13675203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13676203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13677203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13678203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13679203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13680203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13681203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13682203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13683203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13684203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13685203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 },
13686203945Sweongyo		{ 4, 10, 6, 0, 59 }, { 4, 10, 5, 0, 72 },
13687203945Sweongyo		{ 4, 10, 5, 0, 70 }, { 4, 10, 5, 0, 68 },
13688203945Sweongyo		{ 4, 10, 5, 0, 66 }, { 4, 10, 5, 0, 64 },
13689203945Sweongyo		{ 4, 10, 5, 0, 62 }, { 4, 10, 5, 0, 60 },
13690203945Sweongyo		{ 4, 10, 5, 0, 59 }, { 4, 9, 5, 0, 70 },
13691203945Sweongyo		{ 4, 9, 5, 0, 68 }, { 4, 9, 5, 0, 66 },
13692203945Sweongyo		{ 4, 9, 5, 0, 64 }, { 4, 9, 5, 0, 63 },
13693203945Sweongyo		{ 4, 9, 5, 0, 61 }, { 4, 9, 5, 0, 59 },
13694203945Sweongyo		{ 4, 9, 4, 0, 71 }, { 4, 9, 4, 0, 69 },
13695203945Sweongyo		{ 4, 9, 4, 0, 67 }, { 4, 9, 4, 0, 65 },
13696203945Sweongyo		{ 4, 9, 4, 0, 63 }, { 4, 9, 4, 0, 62 },
13697203945Sweongyo		{ 4, 9, 4, 0, 60 }, { 4, 9, 4, 0, 58 },
13698203945Sweongyo		{ 4, 8, 4, 0, 70 }, { 4, 8, 4, 0, 68 },
13699203945Sweongyo		{ 4, 8, 4, 0, 66 }, { 4, 8, 4, 0, 65 },
13700203945Sweongyo		{ 4, 8, 4, 0, 63 }, { 4, 8, 4, 0, 61 },
13701203945Sweongyo		{ 4, 8, 4, 0, 59 }, { 4, 7, 4, 0, 68 },
13702203945Sweongyo		{ 4, 7, 4, 0, 66 }, { 4, 7, 4, 0, 64 },
13703203945Sweongyo		{ 4, 7, 4, 0, 62 }, { 4, 7, 4, 0, 61 },
13704203945Sweongyo		{ 4, 7, 4, 0, 59 }, { 4, 7, 3, 0, 67 },
13705203945Sweongyo		{ 4, 7, 3, 0, 65 }, { 4, 7, 3, 0, 63 },
13706203945Sweongyo		{ 4, 7, 3, 0, 62 }, { 4, 7, 3, 0, 60 },
13707203945Sweongyo		{ 4, 6, 3, 0, 65 }, { 4, 6, 3, 0, 63 },
13708203945Sweongyo		{ 4, 6, 3, 0, 61 }, { 4, 6, 3, 0, 60 },
13709203945Sweongyo		{ 4, 6, 3, 0, 58 }, { 4, 5, 3, 0, 68 },
13710203945Sweongyo		{ 4, 5, 3, 0, 66 }, { 4, 5, 3, 0, 64 },
13711203945Sweongyo		{ 4, 5, 3, 0, 62 }, { 4, 5, 3, 0, 60 },
13712203945Sweongyo		{ 4, 5, 3, 0, 59 }, { 4, 5, 3, 0, 57 },
13713203945Sweongyo		{ 4, 4, 2, 0, 83 }, { 4, 4, 2, 0, 81 },
13714203945Sweongyo		{ 4, 4, 2, 0, 78 }, { 4, 4, 2, 0, 76 },
13715203945Sweongyo		{ 4, 4, 2, 0, 74 }, { 4, 4, 2, 0, 72 }
13716203945Sweongyo	};
13717203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r0[] = {
13718203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13719203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13720203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13721203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13722203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13723203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13724203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13725203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13726203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13727203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13728203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13729203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13730203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13731203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13732203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13733203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13734203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13735203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13736203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13737203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13738203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13739203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13740203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13741203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13742203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13743203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13744203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13745203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13746203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13747203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13748203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13749203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13750203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13751203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13752203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13753203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13754203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13755203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13756203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13757203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13758203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13759203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13760203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13761203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13762203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13763203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13764203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13765203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13766203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13767203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13768203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13769203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13770203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13771203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13772203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13773203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13774203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13775203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13776203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13777203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13778203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13779203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13780203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13781203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13782203945Sweongyo	};
13783203945Sweongyo	static struct bwn_txgain_entry txgain_r1[] = {
13784203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13785203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13786203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13787203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13788203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13789203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13790203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13791203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13792203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13793203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13794203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13795203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13796203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13797203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13798203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13799203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13800203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13801203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13802203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 14, 0, 68 },
13803203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13804203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13805203945Sweongyo		{ 7, 15, 14, 0, 59 }, { 7, 15, 14, 0, 57 },
13806203945Sweongyo		{ 7, 15, 13, 0, 72 }, { 7, 15, 13, 0, 70 },
13807203945Sweongyo		{ 7, 15, 13, 0, 68 }, { 7, 15, 13, 0, 66 },
13808203945Sweongyo		{ 7, 15, 13, 0, 64 }, { 7, 15, 13, 0, 62 },
13809203945Sweongyo		{ 7, 15, 13, 0, 60 }, { 7, 15, 13, 0, 59 },
13810203945Sweongyo		{ 7, 15, 13, 0, 57 }, { 7, 15, 12, 0, 71 },
13811203945Sweongyo		{ 7, 15, 12, 0, 69 }, { 7, 15, 12, 0, 67 },
13812203945Sweongyo		{ 7, 15, 12, 0, 65 }, { 7, 15, 12, 0, 63 },
13813203945Sweongyo		{ 7, 15, 12, 0, 62 }, { 7, 15, 12, 0, 60 },
13814203945Sweongyo		{ 7, 15, 12, 0, 58 }, { 7, 15, 12, 0, 57 },
13815203945Sweongyo		{ 7, 15, 11, 0, 70 }, { 7, 15, 11, 0, 68 },
13816203945Sweongyo		{ 7, 15, 11, 0, 66 }, { 7, 15, 11, 0, 65 },
13817203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13818203945Sweongyo		{ 7, 15, 11, 0, 59 }, { 7, 15, 11, 0, 58 },
13819203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13820203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13821203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13822203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13823203945Sweongyo		{ 7, 15, 10, 0, 56 }, { 7, 15, 9, 0, 70 },
13824203945Sweongyo		{ 7, 15, 9, 0, 68 }, { 7, 15, 9, 0, 66 },
13825203945Sweongyo		{ 7, 15, 9, 0, 64 }, { 7, 15, 9, 0, 62 },
13826203945Sweongyo		{ 7, 15, 9, 0, 60 }, { 7, 15, 9, 0, 59 },
13827203945Sweongyo		{ 7, 14, 9, 0, 72 }, { 7, 14, 9, 0, 70 },
13828203945Sweongyo		{ 7, 14, 9, 0, 68 }, { 7, 14, 9, 0, 66 },
13829203945Sweongyo		{ 7, 14, 9, 0, 64 }, { 7, 14, 9, 0, 62 },
13830203945Sweongyo		{ 7, 14, 9, 0, 60 }, { 7, 14, 9, 0, 59 },
13831203945Sweongyo		{ 7, 13, 9, 0, 72 }, { 7, 13, 9, 0, 70 },
13832203945Sweongyo		{ 7, 13, 9, 0, 68 }, { 7, 13, 9, 0, 66 },
13833203945Sweongyo		{ 7, 13, 9, 0, 64 }, { 7, 13, 9, 0, 63 },
13834203945Sweongyo		{ 7, 13, 9, 0, 61 }, { 7, 13, 9, 0, 59 },
13835203945Sweongyo		{ 7, 13, 9, 0, 57 }, { 7, 13, 8, 0, 72 },
13836203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13837203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13838203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13839203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 12, 8, 0, 72 },
13840203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13841203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13842203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13843203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 7, 0, 73 },
13844203945Sweongyo		{ 7, 12, 7, 0, 71 }, { 7, 12, 7, 0, 69 },
13845203945Sweongyo		{ 7, 12, 7, 0, 67 }, { 7, 12, 7, 0, 65 },
13846203945Sweongyo		{ 7, 12, 7, 0, 63 }, { 7, 12, 7, 0, 61 },
13847203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 11, 7, 0, 72 },
13848203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13849203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 65 },
13850203945Sweongyo		{ 7, 11, 7, 0, 63 }, { 7, 11, 7, 0, 61 },
13851203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 6, 0, 73 },
13852203945Sweongyo		{ 7, 11, 6, 0, 71 }
13853203945Sweongyo	};
13854203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r1[] = {
13855203945Sweongyo		{ 4, 15, 15, 0, 90 }, { 4, 15, 15, 0, 88 },
13856203945Sweongyo		{ 4, 15, 15, 0, 85 }, { 4, 15, 15, 0, 83 },
13857203945Sweongyo		{ 4, 15, 15, 0, 81 }, { 4, 15, 15, 0, 78 },
13858203945Sweongyo		{ 4, 15, 15, 0, 76 }, { 4, 15, 15, 0, 74 },
13859203945Sweongyo		{ 4, 15, 15, 0, 72 }, { 4, 15, 15, 0, 70 },
13860203945Sweongyo		{ 4, 15, 15, 0, 68 }, { 4, 15, 15, 0, 66 },
13861203945Sweongyo		{ 4, 15, 15, 0, 64 }, { 4, 15, 15, 0, 62 },
13862203945Sweongyo		{ 4, 15, 15, 0, 60 }, { 4, 15, 15, 0, 59 },
13863203945Sweongyo		{ 4, 15, 14, 0, 72 }, { 4, 15, 14, 0, 70 },
13864203945Sweongyo		{ 4, 15, 14, 0, 68 }, { 4, 15, 14, 0, 66 },
13865203945Sweongyo		{ 4, 15, 14, 0, 64 }, { 4, 15, 14, 0, 62 },
13866203945Sweongyo		{ 4, 15, 14, 0, 60 }, { 4, 15, 14, 0, 59 },
13867203945Sweongyo		{ 4, 15, 13, 0, 72 }, { 4, 15, 13, 0, 70 },
13868203945Sweongyo		{ 4, 15, 13, 0, 68 }, { 4, 15, 13, 0, 66 },
13869203945Sweongyo		{ 4, 15, 13, 0, 64 }, { 4, 15, 13, 0, 62 },
13870203945Sweongyo		{ 4, 15, 13, 0, 60 }, { 4, 15, 13, 0, 59 },
13871203945Sweongyo		{ 4, 15, 12, 0, 72 }, { 4, 15, 12, 0, 70 },
13872203945Sweongyo		{ 4, 15, 12, 0, 68 }, { 4, 15, 12, 0, 66 },
13873203945Sweongyo		{ 4, 15, 12, 0, 64 }, { 4, 15, 12, 0, 62 },
13874203945Sweongyo		{ 4, 15, 12, 0, 60 }, { 4, 15, 12, 0, 59 },
13875203945Sweongyo		{ 4, 15, 11, 0, 72 }, { 4, 15, 11, 0, 70 },
13876203945Sweongyo		{ 4, 15, 11, 0, 68 }, { 4, 15, 11, 0, 66 },
13877203945Sweongyo		{ 4, 15, 11, 0, 64 }, { 4, 15, 11, 0, 62 },
13878203945Sweongyo		{ 4, 15, 11, 0, 60 }, { 4, 15, 11, 0, 59 },
13879203945Sweongyo		{ 4, 15, 10, 0, 72 }, { 4, 15, 10, 0, 70 },
13880203945Sweongyo		{ 4, 15, 10, 0, 68 }, { 4, 15, 10, 0, 66 },
13881203945Sweongyo		{ 4, 15, 10, 0, 64 }, { 4, 15, 10, 0, 62 },
13882203945Sweongyo		{ 4, 15, 10, 0, 60 }, { 4, 15, 10, 0, 59 },
13883203945Sweongyo		{ 4, 15, 9, 0, 72 }, { 4, 15, 9, 0, 70 },
13884203945Sweongyo		{ 4, 15, 9, 0, 68 }, { 4, 15, 9, 0, 66 },
13885203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13886203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13887203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13888203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13889203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13890203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13891203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13892203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13893203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13894203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13895203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13896203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13897203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13898203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13899203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13900203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13901203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13902203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13903203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13904203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13905203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13906203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13907203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13908203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13909203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13910203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13911203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13912203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13913203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13914203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13915203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13916203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13917203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13918203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 }
13919203945Sweongyo	};
13920203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r1[] = {
13921203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13922203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13923203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13924203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13925203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13926203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13927203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13928203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13929203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13930203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13931203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13932203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13933203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13934203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13935203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13936203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13937203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13938203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13939203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13940203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13941203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13942203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13943203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13944203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13945203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13946203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13947203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13948203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13949203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13950203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13951203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13952203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13953203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13954203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13955203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13956203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13957203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13958203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13959203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13960203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13961203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13962203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13963203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13964203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13965203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13966203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13967203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13968203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13969203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13970203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13971203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13972203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13973203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13974203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13975203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13976203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13977203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13978203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13979203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13980203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13981203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13982203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13983203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13984203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13985203945Sweongyo	};
13986203945Sweongyo
13987203945Sweongyo	if (mac->mac_phy.rev != 0 && mac->mac_phy.rev != 1) {
13988203945Sweongyo		if (siba->siba_sprom.bf_hi & BWN_BFH_NOPA)
13989203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r2);
13990203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13991203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13992203945Sweongyo			    txgain_2ghz_r2);
13993203945Sweongyo		else
13994203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13995203945Sweongyo			    txgain_5ghz_r2);
13996203945Sweongyo		return;
13997203945Sweongyo	}
13998203945Sweongyo
13999203945Sweongyo	if (mac->mac_phy.rev == 0) {
14000203945Sweongyo		if ((siba->siba_sprom.bf_hi & BWN_BFH_NOPA) ||
14001203945Sweongyo		    (siba->siba_sprom.bf_lo & BWN_BFL_HGPA))
14002203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r0);
14003203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
14004203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
14005203945Sweongyo			    txgain_2ghz_r0);
14006203945Sweongyo		else
14007203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
14008203945Sweongyo			    txgain_5ghz_r0);
14009203945Sweongyo		return;
14010203945Sweongyo	}
14011203945Sweongyo
14012203945Sweongyo	if ((siba->siba_sprom.bf_hi & BWN_BFH_NOPA) ||
14013203945Sweongyo	    (siba->siba_sprom.bf_lo & BWN_BFL_HGPA))
14014203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r1);
14015203945Sweongyo	else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
14016203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_2ghz_r1);
14017203945Sweongyo	else
14018203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_5ghz_r1);
14019203945Sweongyo}
14020203945Sweongyo
14021203945Sweongyostatic void
14022203945Sweongyobwn_tab_write(struct bwn_mac *mac, uint32_t typeoffset, uint32_t value)
14023203945Sweongyo{
14024203945Sweongyo	uint32_t offset, type;
14025203945Sweongyo
14026203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
14027203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
14028203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
14029203945Sweongyo
14030203945Sweongyo	switch (type) {
14031203945Sweongyo	case BWN_TAB_8BIT:
14032203945Sweongyo		KASSERT(!(value & ~0xff), ("%s:%d: fail", __func__, __LINE__));
14033203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14034203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
14035203945Sweongyo		break;
14036203945Sweongyo	case BWN_TAB_16BIT:
14037203945Sweongyo		KASSERT(!(value & ~0xffff),
14038203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
14039203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14040203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
14041203945Sweongyo		break;
14042203945Sweongyo	case BWN_TAB_32BIT:
14043203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14044203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
14045203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
14046203945Sweongyo		break;
14047203945Sweongyo	default:
14048203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
14049203945Sweongyo	}
14050203945Sweongyo}
14051203945Sweongyo
14052203945Sweongyostatic int
14053203945Sweongyobwn_phy_lp_loopback(struct bwn_mac *mac)
14054203945Sweongyo{
14055203945Sweongyo	struct bwn_phy_lp_iq_est ie;
14056203945Sweongyo	int i, index = -1;
14057203945Sweongyo	uint32_t tmp;
14058203945Sweongyo
14059203945Sweongyo	memset(&ie, 0, sizeof(ie));
14060203945Sweongyo
14061203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1, 1);
14062203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 1);
14063203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
14064203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
14065203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
14066203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
14067203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x8);
14068203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, 0x80);
14069203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x80);
14070203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x80);
14071203945Sweongyo	for (i = 0; i < 32; i++) {
14072203945Sweongyo		bwn_phy_lp_set_rxgain_idx(mac, i);
14073203945Sweongyo		bwn_phy_lp_ddfs_turnon(mac, 1, 1, 5, 5, 0);
14074203945Sweongyo		if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
14075203945Sweongyo			continue;
14076203945Sweongyo		tmp = (ie.ie_ipwr + ie.ie_qpwr) / 1000;
14077203945Sweongyo		if ((tmp > 4000) && (tmp < 10000)) {
14078203945Sweongyo			index = i;
14079203945Sweongyo			break;
14080203945Sweongyo		}
14081203945Sweongyo	}
14082203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
14083203945Sweongyo	return (index);
14084203945Sweongyo}
14085203945Sweongyo
14086203945Sweongyostatic void
14087203945Sweongyobwn_phy_lp_set_rxgain_idx(struct bwn_mac *mac, uint16_t idx)
14088203945Sweongyo{
14089203945Sweongyo
14090203945Sweongyo	bwn_phy_lp_set_rxgain(mac, bwn_tab_read(mac, BWN_TAB_2(12, idx)));
14091203945Sweongyo}
14092203945Sweongyo
14093203945Sweongyostatic void
14094203945Sweongyobwn_phy_lp_ddfs_turnon(struct bwn_mac *mac, int i_on, int q_on,
14095203945Sweongyo    int incr1, int incr2, int scale_idx)
14096203945Sweongyo{
14097203945Sweongyo
14098203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
14099203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0xff80);
14100203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0x80ff);
14101203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0xff80, incr1);
14102203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0x80ff, incr2 << 8);
14103203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff7, i_on << 3);
14104203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xffef, q_on << 4);
14105203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xff9f, scale_idx << 5);
14106203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffb);
14107203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DDFS, 0x2);
14108203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x20);
14109203945Sweongyo}
14110203945Sweongyo
14111203945Sweongyostatic uint8_t
14112203945Sweongyobwn_phy_lp_rx_iq_est(struct bwn_mac *mac, uint16_t sample, uint8_t time,
14113203945Sweongyo    struct bwn_phy_lp_iq_est *ie)
14114203945Sweongyo{
14115203945Sweongyo	int i;
14116203945Sweongyo
14117203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfff7);
14118203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_IQ_NUM_SMPLS_ADDR, sample);
14119203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xff00, time);
14120203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xfeff);
14121203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
14122203945Sweongyo
14123203945Sweongyo	for (i = 0; i < 500; i++) {
14124203945Sweongyo		if (!(BWN_PHY_READ(mac,
14125203945Sweongyo		    BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
14126203945Sweongyo			break;
14127203945Sweongyo		DELAY(1000);
14128203945Sweongyo	}
14129203945Sweongyo	if ((BWN_PHY_READ(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
14130203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14131203945Sweongyo		return 0;
14132203945Sweongyo	}
14133203945Sweongyo
14134203945Sweongyo	ie->ie_iqprod = BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_HI_ADDR);
14135203945Sweongyo	ie->ie_iqprod <<= 16;
14136203945Sweongyo	ie->ie_iqprod |= BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_LO_ADDR);
14137203945Sweongyo	ie->ie_ipwr = BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_HI_ADDR);
14138203945Sweongyo	ie->ie_ipwr <<= 16;
14139203945Sweongyo	ie->ie_ipwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_LO_ADDR);
14140203945Sweongyo	ie->ie_qpwr = BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR);
14141203945Sweongyo	ie->ie_qpwr <<= 16;
14142203945Sweongyo	ie->ie_qpwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR);
14143203945Sweongyo
14144203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
14145203945Sweongyo	return 1;
14146203945Sweongyo}
14147203945Sweongyo
14148203945Sweongyostatic uint32_t
14149203945Sweongyobwn_tab_read(struct bwn_mac *mac, uint32_t typeoffset)
14150203945Sweongyo{
14151203945Sweongyo	uint32_t offset, type, value;
14152203945Sweongyo
14153203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
14154203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
14155203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
14156203945Sweongyo
14157203945Sweongyo	switch (type) {
14158203945Sweongyo	case BWN_TAB_8BIT:
14159203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14160203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
14161203945Sweongyo		break;
14162203945Sweongyo	case BWN_TAB_16BIT:
14163203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14164203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14165203945Sweongyo		break;
14166203945Sweongyo	case BWN_TAB_32BIT:
14167203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
14168203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATAHI);
14169203945Sweongyo		value <<= 16;
14170203945Sweongyo		value |= BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
14171203945Sweongyo		break;
14172203945Sweongyo	default:
14173203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
14174203945Sweongyo		value = 0;
14175203945Sweongyo	}
14176203945Sweongyo
14177203945Sweongyo	return (value);
14178203945Sweongyo}
14179203945Sweongyo
14180203945Sweongyostatic void
14181203945Sweongyobwn_phy_lp_ddfs_turnoff(struct bwn_mac *mac)
14182203945Sweongyo{
14183203945Sweongyo
14184203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffd);
14185203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0xffdf);
14186203945Sweongyo}
14187203945Sweongyo
14188203945Sweongyostatic void
14189203945Sweongyobwn_phy_lp_set_txgain_dac(struct bwn_mac *mac, uint16_t dac)
14190203945Sweongyo{
14191203945Sweongyo	uint16_t ctl;
14192203945Sweongyo
14193203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0xc7f;
14194203945Sweongyo	ctl |= dac << 7;
14195203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf000, ctl);
14196203945Sweongyo}
14197203945Sweongyo
14198203945Sweongyostatic void
14199203945Sweongyobwn_phy_lp_set_txgain_pa(struct bwn_mac *mac, uint16_t gain)
14200203945Sweongyo{
14201203945Sweongyo
14202203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0xe03f, gain << 6);
14203203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x80ff, gain << 8);
14204203945Sweongyo}
14205203945Sweongyo
14206203945Sweongyostatic void
14207203945Sweongyobwn_phy_lp_set_txgain_override(struct bwn_mac *mac)
14208203945Sweongyo{
14209203945Sweongyo
14210203945Sweongyo	if (mac->mac_phy.rev < 2)
14211203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
14212203945Sweongyo	else {
14213203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x80);
14214203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x4000);
14215203945Sweongyo	}
14216203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x40);
14217203945Sweongyo}
14218203945Sweongyo
14219203945Sweongyostatic uint16_t
14220203945Sweongyobwn_phy_lp_get_pa_gain(struct bwn_mac *mac)
14221203945Sweongyo{
14222203945Sweongyo
14223203945Sweongyo	return BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0x7f;
14224203945Sweongyo}
14225203945Sweongyo
14226203945Sweongyostatic uint8_t
14227203945Sweongyobwn_nbits(int32_t val)
14228203945Sweongyo{
14229203945Sweongyo	uint32_t tmp;
14230203945Sweongyo	uint8_t nbits = 0;
14231203945Sweongyo
14232203945Sweongyo	for (tmp = abs(val); tmp != 0; tmp >>= 1)
14233203945Sweongyo		nbits++;
14234203945Sweongyo	return (nbits);
14235203945Sweongyo}
14236203945Sweongyo
14237203945Sweongyostatic void
14238203945Sweongyobwn_phy_lp_gaintbl_write_multi(struct bwn_mac *mac, int offset, int count,
14239203945Sweongyo    struct bwn_txgain_entry *table)
14240203945Sweongyo{
14241203945Sweongyo	int i;
14242203945Sweongyo
14243203945Sweongyo	for (i = offset; i < count; i++)
14244203945Sweongyo		bwn_phy_lp_gaintbl_write(mac, i, table[i]);
14245203945Sweongyo}
14246203945Sweongyo
14247203945Sweongyostatic void
14248203945Sweongyobwn_phy_lp_gaintbl_write(struct bwn_mac *mac, int offset,
14249203945Sweongyo    struct bwn_txgain_entry data)
14250203945Sweongyo{
14251203945Sweongyo
14252203945Sweongyo	if (mac->mac_phy.rev >= 2)
14253203945Sweongyo		bwn_phy_lp_gaintbl_write_r2(mac, offset, data);
14254203945Sweongyo	else
14255203945Sweongyo		bwn_phy_lp_gaintbl_write_r01(mac, offset, data);
14256203945Sweongyo}
14257203945Sweongyo
14258203945Sweongyostatic void
14259203945Sweongyobwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset,
14260203945Sweongyo    struct bwn_txgain_entry te)
14261203945Sweongyo{
14262203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
14263203945Sweongyo	struct ifnet *ifp = sc->sc_ifp;
14264203945Sweongyo	struct ieee80211com *ic = ifp->if_l2com;
14265203945Sweongyo	uint32_t tmp;
14266203945Sweongyo
14267203945Sweongyo	KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__));
14268203945Sweongyo
14269203945Sweongyo	tmp = (te.te_pad << 16) | (te.te_pga << 8) | te.te_gm;
14270203945Sweongyo	if (mac->mac_phy.rev >= 3) {
14271203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14272203945Sweongyo		    (0x10 << 24) : (0x70 << 24));
14273203945Sweongyo	} else {
14274203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14275203945Sweongyo		    (0x14 << 24) : (0x7f << 24));
14276203945Sweongyo	}
14277203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0xc0 + offset), tmp);
14278203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0x140 + offset),
14279203945Sweongyo	    te.te_bbmult << 20 | te.te_dac << 28);
14280203945Sweongyo}
14281203945Sweongyo
14282203945Sweongyostatic void
14283203945Sweongyobwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
14284203945Sweongyo    struct bwn_txgain_entry te)
14285203945Sweongyo{
14286203945Sweongyo
14287203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
14288203945Sweongyo
14289203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0xc0 + offset),
14290203945Sweongyo	    (te.te_pad << 11) | (te.te_pga << 7) | (te.te_gm  << 4) |
14291203945Sweongyo	    te.te_dac);
14292203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0x140 + offset), te.te_bbmult << 20);
14293203945Sweongyo}
14294203945Sweongyo
14295203945Sweongyostatic void
14296203945Sweongyobwn_identify(driver_t *driver, device_t parent)
14297203945Sweongyo{
14298203945Sweongyo
14299203945Sweongyo	BUS_ADD_CHILD(parent, 0, "bwn", -1);
14300203945Sweongyo}
14301203945Sweongyo
14302203945Sweongyostatic device_method_t bwn_methods[] = {
14303203945Sweongyo	/* Device interface */
14304203945Sweongyo	DEVMETHOD(device_identify,	bwn_identify),
14305203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
14306203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
14307203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
14308203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
14309203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
14310203945Sweongyo	{ 0,0 }
14311203945Sweongyo};
14312203945Sweongyostatic driver_t bwn_driver = {
14313203945Sweongyo	"bwn",
14314203945Sweongyo	bwn_methods,
14315203945Sweongyo	sizeof(struct bwn_softc)
14316203945Sweongyo};
14317203945Sweongyostatic devclass_t bwn_devclass;
14318203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
14319203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
14320203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
14321203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
14322203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
14323