if_bwn.c revision 287197
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 287197 2015-08-27 08:56:39Z glebius $");
32203945Sweongyo
33203945Sweongyo/*
34203945Sweongyo * The Broadcom Wireless LAN controller driver.
35203945Sweongyo */
36203945Sweongyo
37203945Sweongyo#include <sys/param.h>
38203945Sweongyo#include <sys/systm.h>
39203945Sweongyo#include <sys/module.h>
40203945Sweongyo#include <sys/kernel.h>
41203945Sweongyo#include <sys/endian.h>
42203945Sweongyo#include <sys/errno.h>
43203945Sweongyo#include <sys/firmware.h>
44203945Sweongyo#include <sys/lock.h>
45203945Sweongyo#include <sys/mutex.h>
46203945Sweongyo#include <machine/bus.h>
47203945Sweongyo#include <machine/resource.h>
48203945Sweongyo#include <sys/bus.h>
49203945Sweongyo#include <sys/rman.h>
50203945Sweongyo#include <sys/socket.h>
51203945Sweongyo#include <sys/sockio.h>
52203945Sweongyo
53203945Sweongyo#include <net/ethernet.h>
54203945Sweongyo#include <net/if.h>
55257176Sglebius#include <net/if_var.h>
56203945Sweongyo#include <net/if_arp.h>
57203945Sweongyo#include <net/if_dl.h>
58203945Sweongyo#include <net/if_llc.h>
59203945Sweongyo#include <net/if_media.h>
60203945Sweongyo#include <net/if_types.h>
61203945Sweongyo
62203945Sweongyo#include <dev/pci/pcivar.h>
63203945Sweongyo#include <dev/pci/pcireg.h>
64203945Sweongyo#include <dev/siba/siba_ids.h>
65203945Sweongyo#include <dev/siba/sibareg.h>
66203945Sweongyo#include <dev/siba/sibavar.h>
67203945Sweongyo
68203945Sweongyo#include <net80211/ieee80211_var.h>
69203945Sweongyo#include <net80211/ieee80211_radiotap.h>
70203945Sweongyo#include <net80211/ieee80211_regdomain.h>
71203945Sweongyo#include <net80211/ieee80211_phy.h>
72206358Srpaulo#include <net80211/ieee80211_ratectl.h>
73203945Sweongyo
74203945Sweongyo#include <dev/bwn/if_bwnreg.h>
75203945Sweongyo#include <dev/bwn/if_bwnvar.h>
76203945Sweongyo
77227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0,
78227309Sed    "Broadcom driver parameters");
79203945Sweongyo
80203945Sweongyo/*
81203945Sweongyo * Tunable & sysctl variables.
82203945Sweongyo */
83203945Sweongyo
84203945Sweongyo#ifdef BWN_DEBUG
85203945Sweongyostatic	int bwn_debug = 0;
86267992ShselaskySYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RWTUN, &bwn_debug, 0,
87203945Sweongyo    "Broadcom debugging printfs");
88203945Sweongyoenum {
89203945Sweongyo	BWN_DEBUG_XMIT		= 0x00000001,	/* basic xmit operation */
90203945Sweongyo	BWN_DEBUG_RECV		= 0x00000002,	/* basic recv operation */
91203945Sweongyo	BWN_DEBUG_STATE		= 0x00000004,	/* 802.11 state transitions */
92203945Sweongyo	BWN_DEBUG_TXPOW		= 0x00000008,	/* tx power processing */
93203945Sweongyo	BWN_DEBUG_RESET		= 0x00000010,	/* reset processing */
94203945Sweongyo	BWN_DEBUG_OPS		= 0x00000020,	/* bwn_ops processing */
95203945Sweongyo	BWN_DEBUG_BEACON	= 0x00000040,	/* beacon handling */
96203945Sweongyo	BWN_DEBUG_WATCHDOG	= 0x00000080,	/* watchdog timeout */
97203945Sweongyo	BWN_DEBUG_INTR		= 0x00000100,	/* ISR */
98203945Sweongyo	BWN_DEBUG_CALIBRATE	= 0x00000200,	/* periodic calibration */
99203945Sweongyo	BWN_DEBUG_NODE		= 0x00000400,	/* node management */
100203945Sweongyo	BWN_DEBUG_LED		= 0x00000800,	/* led management */
101203945Sweongyo	BWN_DEBUG_CMD		= 0x00001000,	/* cmd submission */
102203945Sweongyo	BWN_DEBUG_LO		= 0x00002000,	/* LO */
103203945Sweongyo	BWN_DEBUG_FW		= 0x00004000,	/* firmware */
104203945Sweongyo	BWN_DEBUG_WME		= 0x00008000,	/* WME */
105203945Sweongyo	BWN_DEBUG_RF		= 0x00010000,	/* RF */
106203945Sweongyo	BWN_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
107203945Sweongyo	BWN_DEBUG_ANY		= 0xffffffff
108203945Sweongyo};
109203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do {			\
110203945Sweongyo	if (sc->sc_debug & (m))				\
111203945Sweongyo		printf(fmt, __VA_ARGS__);		\
112203945Sweongyo} while (0)
113203945Sweongyo#else
114203945Sweongyo#define	DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
115203945Sweongyo#endif
116203945Sweongyo
117203945Sweongyostatic int	bwn_bfp = 0;		/* use "Bad Frames Preemption" */
118203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
119203945Sweongyo    "uses Bad Frames Preemption");
120203945Sweongyostatic int	bwn_bluetooth = 1;
121203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
122203945Sweongyo    "turns on Bluetooth Coexistence");
123203945Sweongyostatic int	bwn_hwpctl = 0;
124203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
125203945Sweongyo    "uses H/W power control");
126203945Sweongyostatic int	bwn_msi_disable = 0;		/* MSI disabled  */
127203945SweongyoTUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable);
128203945Sweongyostatic int	bwn_usedma = 1;
129203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
130203945Sweongyo    "uses DMA");
131203945SweongyoTUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
132203945Sweongyostatic int	bwn_wme = 1;
133203945SweongyoSYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
134203945Sweongyo    "uses WME support");
135203945Sweongyo
136287197Sglebiusstatic void	bwn_attach_pre(struct bwn_softc *);
137203945Sweongyostatic int	bwn_attach_post(struct bwn_softc *);
138204922Sweongyostatic void	bwn_sprom_bugfixes(device_t);
139287197Sglebiusstatic int	bwn_init(struct bwn_softc *);
140287197Sglebiusstatic void	bwn_parent(struct ieee80211com *);
141287197Sglebiusstatic void	bwn_start(struct bwn_softc *);
142287197Sglebiusstatic int	bwn_transmit(struct ieee80211com *, struct mbuf *);
143203945Sweongyostatic int	bwn_attach_core(struct bwn_mac *);
144203945Sweongyostatic void	bwn_reset_core(struct bwn_mac *, uint32_t);
145203945Sweongyostatic int	bwn_phy_getinfo(struct bwn_mac *, int);
146203945Sweongyostatic int	bwn_chiptest(struct bwn_mac *);
147203945Sweongyostatic int	bwn_setup_channels(struct bwn_mac *, int, int);
148203945Sweongyostatic int	bwn_phy_g_attach(struct bwn_mac *);
149203945Sweongyostatic void	bwn_phy_g_detach(struct bwn_mac *);
150203945Sweongyostatic void	bwn_phy_g_init_pre(struct bwn_mac *);
151203945Sweongyostatic int	bwn_phy_g_prepare_hw(struct bwn_mac *);
152203945Sweongyostatic int	bwn_phy_g_init(struct bwn_mac *);
153203945Sweongyostatic void	bwn_phy_g_exit(struct bwn_mac *);
154203945Sweongyostatic uint16_t	bwn_phy_g_read(struct bwn_mac *, uint16_t);
155203945Sweongyostatic void	bwn_phy_g_write(struct bwn_mac *, uint16_t,
156203945Sweongyo		    uint16_t);
157203945Sweongyostatic uint16_t	bwn_phy_g_rf_read(struct bwn_mac *, uint16_t);
158203945Sweongyostatic void	bwn_phy_g_rf_write(struct bwn_mac *, uint16_t,
159203945Sweongyo		    uint16_t);
160203945Sweongyostatic int	bwn_phy_g_hwpctl(struct bwn_mac *);
161203945Sweongyostatic void	bwn_phy_g_rf_onoff(struct bwn_mac *, int);
162203945Sweongyostatic int	bwn_phy_g_switch_channel(struct bwn_mac *, uint32_t);
163203945Sweongyostatic uint32_t	bwn_phy_g_get_default_chan(struct bwn_mac *);
164203945Sweongyostatic void	bwn_phy_g_set_antenna(struct bwn_mac *, int);
165203945Sweongyostatic int	bwn_phy_g_im(struct bwn_mac *, int);
166203945Sweongyostatic int	bwn_phy_g_recalc_txpwr(struct bwn_mac *, int);
167203945Sweongyostatic void	bwn_phy_g_set_txpwr(struct bwn_mac *);
168203945Sweongyostatic void	bwn_phy_g_task_15s(struct bwn_mac *);
169203945Sweongyostatic void	bwn_phy_g_task_60s(struct bwn_mac *);
170203945Sweongyostatic uint16_t	bwn_phy_g_txctl(struct bwn_mac *);
171203945Sweongyostatic void	bwn_phy_switch_analog(struct bwn_mac *, int);
172203945Sweongyostatic uint16_t	bwn_shm_read_2(struct bwn_mac *, uint16_t, uint16_t);
173203945Sweongyostatic void	bwn_shm_write_2(struct bwn_mac *, uint16_t, uint16_t,
174203945Sweongyo		    uint16_t);
175203945Sweongyostatic uint32_t	bwn_shm_read_4(struct bwn_mac *, uint16_t, uint16_t);
176203945Sweongyostatic void	bwn_shm_write_4(struct bwn_mac *, uint16_t, uint16_t,
177203945Sweongyo		    uint32_t);
178203945Sweongyostatic void	bwn_shm_ctlword(struct bwn_mac *, uint16_t,
179203945Sweongyo		    uint16_t);
180203945Sweongyostatic void	bwn_addchannels(struct ieee80211_channel [], int, int *,
181203945Sweongyo		    const struct bwn_channelinfo *, int);
182203945Sweongyostatic int	bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
183203945Sweongyo		    const struct ieee80211_bpf_params *);
184283540Sglebiusstatic void	bwn_updateslot(struct ieee80211com *);
185283540Sglebiusstatic void	bwn_update_promisc(struct ieee80211com *);
186203945Sweongyostatic void	bwn_wme_init(struct bwn_mac *);
187203945Sweongyostatic int	bwn_wme_update(struct ieee80211com *);
188203945Sweongyostatic void	bwn_wme_clear(struct bwn_softc *);
189203945Sweongyostatic void	bwn_wme_load(struct bwn_mac *);
190203945Sweongyostatic void	bwn_wme_loadparams(struct bwn_mac *,
191203945Sweongyo		    const struct wmeParams *, uint16_t);
192203945Sweongyostatic void	bwn_scan_start(struct ieee80211com *);
193203945Sweongyostatic void	bwn_scan_end(struct ieee80211com *);
194203945Sweongyostatic void	bwn_set_channel(struct ieee80211com *);
195203945Sweongyostatic struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
196228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
197228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
198203945Sweongyo		    const uint8_t [IEEE80211_ADDR_LEN]);
199203945Sweongyostatic void	bwn_vap_delete(struct ieee80211vap *);
200287197Sglebiusstatic void	bwn_stop(struct bwn_softc *);
201203945Sweongyostatic int	bwn_core_init(struct bwn_mac *);
202203945Sweongyostatic void	bwn_core_start(struct bwn_mac *);
203203945Sweongyostatic void	bwn_core_exit(struct bwn_mac *);
204203945Sweongyostatic void	bwn_bt_disable(struct bwn_mac *);
205203945Sweongyostatic int	bwn_chip_init(struct bwn_mac *);
206203945Sweongyostatic uint64_t	bwn_hf_read(struct bwn_mac *);
207203945Sweongyostatic void	bwn_hf_write(struct bwn_mac *, uint64_t);
208203945Sweongyostatic void	bwn_set_txretry(struct bwn_mac *, int, int);
209203945Sweongyostatic void	bwn_rate_init(struct bwn_mac *);
210203945Sweongyostatic void	bwn_set_phytxctl(struct bwn_mac *);
211203945Sweongyostatic void	bwn_spu_setdelay(struct bwn_mac *, int);
212203945Sweongyostatic void	bwn_bt_enable(struct bwn_mac *);
213203945Sweongyostatic void	bwn_set_macaddr(struct bwn_mac *);
214203945Sweongyostatic void	bwn_crypt_init(struct bwn_mac *);
215203945Sweongyostatic void	bwn_chip_exit(struct bwn_mac *);
216203945Sweongyostatic int	bwn_fw_fillinfo(struct bwn_mac *);
217203945Sweongyostatic int	bwn_fw_loaducode(struct bwn_mac *);
218203945Sweongyostatic int	bwn_gpio_init(struct bwn_mac *);
219203945Sweongyostatic int	bwn_fw_loadinitvals(struct bwn_mac *);
220203945Sweongyostatic int	bwn_phy_init(struct bwn_mac *);
221203945Sweongyostatic void	bwn_set_txantenna(struct bwn_mac *, int);
222203945Sweongyostatic void	bwn_set_opmode(struct bwn_mac *);
223203945Sweongyostatic void	bwn_rate_write(struct bwn_mac *, uint16_t, int);
224203945Sweongyostatic uint8_t	bwn_plcp_getcck(const uint8_t);
225203945Sweongyostatic uint8_t	bwn_plcp_getofdm(const uint8_t);
226203945Sweongyostatic void	bwn_pio_init(struct bwn_mac *);
227203945Sweongyostatic uint16_t	bwn_pio_idx2base(struct bwn_mac *, int);
228203945Sweongyostatic void	bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
229203945Sweongyo		    int);
230203945Sweongyostatic void	bwn_pio_setupqueue_rx(struct bwn_mac *,
231203945Sweongyo		    struct bwn_pio_rxqueue *, int);
232203945Sweongyostatic void	bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
233203945Sweongyostatic uint16_t	bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
234203945Sweongyo		    uint16_t);
235203945Sweongyostatic void	bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
236203945Sweongyostatic int	bwn_pio_rx(struct bwn_pio_rxqueue *);
237203945Sweongyostatic uint8_t	bwn_pio_rxeof(struct bwn_pio_rxqueue *);
238203945Sweongyostatic void	bwn_pio_handle_txeof(struct bwn_mac *,
239203945Sweongyo		    const struct bwn_txstatus *);
240203945Sweongyostatic uint16_t	bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
241203945Sweongyostatic uint32_t	bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
242203945Sweongyostatic void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
243203945Sweongyo		    uint16_t);
244203945Sweongyostatic void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
245203945Sweongyo		    uint32_t);
246203945Sweongyostatic int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
247203945Sweongyo		    struct mbuf *);
248203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
249203945Sweongyostatic uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
250203945Sweongyo		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
251203945Sweongyostatic void	bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
252203945Sweongyo		    uint16_t, uint32_t);
253203945Sweongyostatic uint16_t	bwn_pio_write_multi_2(struct bwn_mac *,
254203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, const void *, int);
255203945Sweongyostatic uint16_t	bwn_pio_write_mbuf_2(struct bwn_mac *,
256203945Sweongyo		    struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
257203945Sweongyostatic struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
258203945Sweongyo		    uint16_t, struct bwn_pio_txpkt **);
259203945Sweongyostatic void	bwn_dma_init(struct bwn_mac *);
260203945Sweongyostatic void	bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t);
261203945Sweongyostatic int	bwn_dma_mask2type(uint64_t);
262203945Sweongyostatic uint64_t	bwn_dma_mask(struct bwn_mac *);
263203945Sweongyostatic uint16_t	bwn_dma_base(int, int);
264203945Sweongyostatic void	bwn_dma_ringfree(struct bwn_dma_ring **);
265203945Sweongyostatic void	bwn_dma_32_getdesc(struct bwn_dma_ring *,
266203945Sweongyo		    int, struct bwn_dmadesc_generic **,
267203945Sweongyo		    struct bwn_dmadesc_meta **);
268203945Sweongyostatic void	bwn_dma_32_setdesc(struct bwn_dma_ring *,
269203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
270203945Sweongyo		    int, int);
271203945Sweongyostatic void	bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
272203945Sweongyostatic void	bwn_dma_32_suspend(struct bwn_dma_ring *);
273203945Sweongyostatic void	bwn_dma_32_resume(struct bwn_dma_ring *);
274203945Sweongyostatic int	bwn_dma_32_get_curslot(struct bwn_dma_ring *);
275203945Sweongyostatic void	bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
276203945Sweongyostatic void	bwn_dma_64_getdesc(struct bwn_dma_ring *,
277203945Sweongyo		    int, struct bwn_dmadesc_generic **,
278203945Sweongyo		    struct bwn_dmadesc_meta **);
279203945Sweongyostatic void	bwn_dma_64_setdesc(struct bwn_dma_ring *,
280203945Sweongyo		    struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
281203945Sweongyo		    int, int);
282203945Sweongyostatic void	bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
283203945Sweongyostatic void	bwn_dma_64_suspend(struct bwn_dma_ring *);
284203945Sweongyostatic void	bwn_dma_64_resume(struct bwn_dma_ring *);
285203945Sweongyostatic int	bwn_dma_64_get_curslot(struct bwn_dma_ring *);
286203945Sweongyostatic void	bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
287203945Sweongyostatic int	bwn_dma_allocringmemory(struct bwn_dma_ring *);
288203945Sweongyostatic void	bwn_dma_setup(struct bwn_dma_ring *);
289203945Sweongyostatic void	bwn_dma_free_ringmemory(struct bwn_dma_ring *);
290203945Sweongyostatic void	bwn_dma_cleanup(struct bwn_dma_ring *);
291203945Sweongyostatic void	bwn_dma_free_descbufs(struct bwn_dma_ring *);
292203945Sweongyostatic int	bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int);
293203945Sweongyostatic void	bwn_dma_rx(struct bwn_dma_ring *);
294203945Sweongyostatic int	bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
295203945Sweongyostatic void	bwn_dma_free_descbuf(struct bwn_dma_ring *,
296203945Sweongyo		    struct bwn_dmadesc_meta *);
297203945Sweongyostatic void	bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *);
298203945Sweongyostatic int	bwn_dma_gettype(struct bwn_mac *);
299203945Sweongyostatic void	bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int);
300203945Sweongyostatic int	bwn_dma_freeslot(struct bwn_dma_ring *);
301203945Sweongyostatic int	bwn_dma_nextslot(struct bwn_dma_ring *, int);
302203945Sweongyostatic void	bwn_dma_rxeof(struct bwn_dma_ring *, int *);
303203945Sweongyostatic int	bwn_dma_newbuf(struct bwn_dma_ring *,
304203945Sweongyo		    struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
305203945Sweongyo		    int);
306203945Sweongyostatic void	bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
307203945Sweongyo		    bus_size_t, int);
308203945Sweongyostatic uint8_t	bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
309203945Sweongyostatic void	bwn_dma_handle_txeof(struct bwn_mac *,
310203945Sweongyo		    const struct bwn_txstatus *);
311203945Sweongyostatic int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
312203945Sweongyo		    struct mbuf *);
313203945Sweongyostatic int	bwn_dma_getslot(struct bwn_dma_ring *);
314203945Sweongyostatic struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
315203945Sweongyo		    uint8_t);
316203945Sweongyostatic int	bwn_dma_attach(struct bwn_mac *);
317203945Sweongyostatic struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
318203945Sweongyo		    int, int, int);
319203945Sweongyostatic struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
320203945Sweongyo		    const struct bwn_txstatus *, uint16_t, int *);
321203945Sweongyostatic void	bwn_dma_free(struct bwn_mac *);
322203945Sweongyostatic void	bwn_phy_g_init_sub(struct bwn_mac *);
323203945Sweongyostatic uint8_t	bwn_has_hwpctl(struct bwn_mac *);
324203945Sweongyostatic void	bwn_phy_init_b5(struct bwn_mac *);
325203945Sweongyostatic void	bwn_phy_init_b6(struct bwn_mac *);
326203945Sweongyostatic void	bwn_phy_init_a(struct bwn_mac *);
327203945Sweongyostatic void	bwn_loopback_calcgain(struct bwn_mac *);
328203945Sweongyostatic uint16_t	bwn_rf_init_bcm2050(struct bwn_mac *);
329203945Sweongyostatic void	bwn_lo_g_init(struct bwn_mac *);
330203945Sweongyostatic void	bwn_lo_g_adjust(struct bwn_mac *);
331203945Sweongyostatic void	bwn_lo_get_powervector(struct bwn_mac *);
332203945Sweongyostatic struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
333203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *);
334203945Sweongyostatic void	bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
335203945Sweongyostatic void	bwn_phy_hwpctl_init(struct bwn_mac *);
336203945Sweongyostatic void	bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
337203945Sweongyostatic void	bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
338203945Sweongyo		    const struct bwn_bbatt *, const struct bwn_rfatt *,
339203945Sweongyo		    uint8_t);
340203945Sweongyostatic void	bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
341203945Sweongyostatic uint16_t	bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
342203945Sweongyostatic void	bwn_spu_workaround(struct bwn_mac *, uint8_t);
343203945Sweongyostatic void	bwn_wa_init(struct bwn_mac *);
344203945Sweongyostatic void	bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
345203945Sweongyo		    uint16_t);
346203945Sweongyostatic void	bwn_dummy_transmission(struct bwn_mac *, int, int);
347203945Sweongyostatic void	bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
348203945Sweongyo		    uint32_t);
349203945Sweongyostatic void	bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
350203945Sweongyo		    uint16_t);
351203945Sweongyostatic void	bwn_ram_write(struct bwn_mac *, uint16_t, uint32_t);
352203945Sweongyostatic void	bwn_mac_suspend(struct bwn_mac *);
353203945Sweongyostatic void	bwn_mac_enable(struct bwn_mac *);
354203945Sweongyostatic void	bwn_psctl(struct bwn_mac *, uint32_t);
355203945Sweongyostatic int16_t	bwn_nrssi_read(struct bwn_mac *, uint16_t);
356203945Sweongyostatic void	bwn_nrssi_offset(struct bwn_mac *);
357203945Sweongyostatic void	bwn_nrssi_threshold(struct bwn_mac *);
358203945Sweongyostatic void	bwn_nrssi_slope_11g(struct bwn_mac *);
359203945Sweongyostatic void	bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
360203945Sweongyo		    int16_t);
361203945Sweongyostatic void	bwn_set_original_gains(struct bwn_mac *);
362203945Sweongyostatic void	bwn_hwpctl_early_init(struct bwn_mac *);
363203945Sweongyostatic void	bwn_hwpctl_init_gphy(struct bwn_mac *);
364203945Sweongyostatic uint16_t	bwn_phy_g_chan2freq(uint8_t);
365203945Sweongyostatic int	bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
366203945Sweongyostatic int	bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
367203945Sweongyo		    const char *, struct bwn_fwfile *);
368203945Sweongyostatic void	bwn_release_firmware(struct bwn_mac *);
369203945Sweongyostatic void	bwn_do_release_fw(struct bwn_fwfile *);
370203945Sweongyostatic uint16_t	bwn_fwcaps_read(struct bwn_mac *);
371203945Sweongyostatic int	bwn_fwinitvals_write(struct bwn_mac *,
372203945Sweongyo		    const struct bwn_fwinitvals *, size_t, size_t);
373203945Sweongyostatic int	bwn_switch_channel(struct bwn_mac *, int);
374203945Sweongyostatic uint16_t	bwn_ant2phy(int);
375203945Sweongyostatic void	bwn_mac_write_bssid(struct bwn_mac *);
376203945Sweongyostatic void	bwn_mac_setfilter(struct bwn_mac *, uint16_t,
377203945Sweongyo		    const uint8_t *);
378203945Sweongyostatic void	bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
379203945Sweongyo		    const uint8_t *, size_t, const uint8_t *);
380203945Sweongyostatic void	bwn_key_macwrite(struct bwn_mac *, uint8_t,
381203945Sweongyo		    const uint8_t *);
382203945Sweongyostatic void	bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
383203945Sweongyo		    const uint8_t *);
384203945Sweongyostatic void	bwn_phy_exit(struct bwn_mac *);
385203945Sweongyostatic void	bwn_core_stop(struct bwn_mac *);
386203945Sweongyostatic int	bwn_switch_band(struct bwn_softc *,
387203945Sweongyo		    struct ieee80211_channel *);
388203945Sweongyostatic void	bwn_phy_reset(struct bwn_mac *);
389203945Sweongyostatic int	bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
390203945Sweongyostatic void	bwn_set_pretbtt(struct bwn_mac *);
391203945Sweongyostatic int	bwn_intr(void *);
392203945Sweongyostatic void	bwn_intrtask(void *, int);
393203945Sweongyostatic void	bwn_restart(struct bwn_mac *, const char *);
394203945Sweongyostatic void	bwn_intr_ucode_debug(struct bwn_mac *);
395203945Sweongyostatic void	bwn_intr_tbtt_indication(struct bwn_mac *);
396203945Sweongyostatic void	bwn_intr_atim_end(struct bwn_mac *);
397203945Sweongyostatic void	bwn_intr_beacon(struct bwn_mac *);
398203945Sweongyostatic void	bwn_intr_pmq(struct bwn_mac *);
399203945Sweongyostatic void	bwn_intr_noise(struct bwn_mac *);
400203945Sweongyostatic void	bwn_intr_txeof(struct bwn_mac *);
401203945Sweongyostatic void	bwn_hwreset(void *, int);
402203945Sweongyostatic void	bwn_handle_fwpanic(struct bwn_mac *);
403203945Sweongyostatic void	bwn_load_beacon0(struct bwn_mac *);
404203945Sweongyostatic void	bwn_load_beacon1(struct bwn_mac *);
405203945Sweongyostatic uint32_t	bwn_jssi_read(struct bwn_mac *);
406203945Sweongyostatic void	bwn_noise_gensample(struct bwn_mac *);
407203945Sweongyostatic void	bwn_handle_txeof(struct bwn_mac *,
408203945Sweongyo		    const struct bwn_txstatus *);
409203945Sweongyostatic void	bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
410203945Sweongyostatic void	bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
411203945Sweongyostatic int	bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
412203945Sweongyo		    struct mbuf *);
413203945Sweongyostatic int	bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
414203945Sweongyostatic int	bwn_set_txhdr(struct bwn_mac *,
415203945Sweongyo		    struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
416203945Sweongyo		    uint16_t);
417203945Sweongyostatic void	bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
418203945Sweongyo		    const uint8_t);
419203945Sweongyostatic uint8_t	bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
420203945Sweongyostatic uint8_t	bwn_get_fbrate(uint8_t);
421203945Sweongyostatic int	bwn_phy_shm_tssi_read(struct bwn_mac *, uint16_t);
422203945Sweongyostatic void	bwn_phy_g_setatt(struct bwn_mac *, int *, int *);
423203945Sweongyostatic void	bwn_phy_lock(struct bwn_mac *);
424203945Sweongyostatic void	bwn_phy_unlock(struct bwn_mac *);
425203945Sweongyostatic void	bwn_rf_lock(struct bwn_mac *);
426203945Sweongyostatic void	bwn_rf_unlock(struct bwn_mac *);
427203945Sweongyostatic void	bwn_txpwr(void *, int);
428203945Sweongyostatic void	bwn_tasks(void *);
429203945Sweongyostatic void	bwn_task_15s(struct bwn_mac *);
430203945Sweongyostatic void	bwn_task_30s(struct bwn_mac *);
431203945Sweongyostatic void	bwn_task_60s(struct bwn_mac *);
432203945Sweongyostatic int	bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
433203945Sweongyo		    uint8_t);
434203945Sweongyostatic int	bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
435203945Sweongyostatic void	bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
436203945Sweongyo		    const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
437203945Sweongyo		    int, int);
438203945Sweongyostatic void	bwn_tsf_read(struct bwn_mac *, uint64_t *);
439203945Sweongyostatic void	bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
440203945Sweongyostatic void	bwn_set_slot_time(struct bwn_mac *, uint16_t);
441203945Sweongyostatic void	bwn_watchdog(void *);
442203945Sweongyostatic void	bwn_dma_stop(struct bwn_mac *);
443203945Sweongyostatic void	bwn_pio_stop(struct bwn_mac *);
444203945Sweongyostatic void	bwn_dma_ringstop(struct bwn_dma_ring **);
445203945Sweongyostatic void	bwn_led_attach(struct bwn_mac *);
446203945Sweongyostatic void	bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
447203945Sweongyostatic void	bwn_led_event(struct bwn_mac *, int);
448203945Sweongyostatic void	bwn_led_blink_start(struct bwn_mac *, int, int);
449203945Sweongyostatic void	bwn_led_blink_next(void *);
450203945Sweongyostatic void	bwn_led_blink_end(void *);
451203945Sweongyostatic void	bwn_rfswitch(void *);
452203945Sweongyostatic void	bwn_rf_turnon(struct bwn_mac *);
453203945Sweongyostatic void	bwn_rf_turnoff(struct bwn_mac *);
454203945Sweongyostatic void	bwn_phy_lp_init_pre(struct bwn_mac *);
455203945Sweongyostatic int	bwn_phy_lp_init(struct bwn_mac *);
456203945Sweongyostatic uint16_t	bwn_phy_lp_read(struct bwn_mac *, uint16_t);
457203945Sweongyostatic void	bwn_phy_lp_write(struct bwn_mac *, uint16_t, uint16_t);
458203945Sweongyostatic void	bwn_phy_lp_maskset(struct bwn_mac *, uint16_t, uint16_t,
459203945Sweongyo		    uint16_t);
460203945Sweongyostatic uint16_t	bwn_phy_lp_rf_read(struct bwn_mac *, uint16_t);
461203945Sweongyostatic void	bwn_phy_lp_rf_write(struct bwn_mac *, uint16_t, uint16_t);
462203945Sweongyostatic void	bwn_phy_lp_rf_onoff(struct bwn_mac *, int);
463203945Sweongyostatic int	bwn_phy_lp_switch_channel(struct bwn_mac *, uint32_t);
464203945Sweongyostatic uint32_t	bwn_phy_lp_get_default_chan(struct bwn_mac *);
465203945Sweongyostatic void	bwn_phy_lp_set_antenna(struct bwn_mac *, int);
466203945Sweongyostatic void	bwn_phy_lp_task_60s(struct bwn_mac *);
467203945Sweongyostatic void	bwn_phy_lp_readsprom(struct bwn_mac *);
468203945Sweongyostatic void	bwn_phy_lp_bbinit(struct bwn_mac *);
469203945Sweongyostatic void	bwn_phy_lp_txpctl_init(struct bwn_mac *);
470203945Sweongyostatic void	bwn_phy_lp_calib(struct bwn_mac *);
471203945Sweongyostatic void	bwn_phy_lp_switch_analog(struct bwn_mac *, int);
472203945Sweongyostatic int	bwn_phy_lp_b2062_switch_channel(struct bwn_mac *, uint8_t);
473203945Sweongyostatic int	bwn_phy_lp_b2063_switch_channel(struct bwn_mac *, uint8_t);
474203945Sweongyostatic void	bwn_phy_lp_set_anafilter(struct bwn_mac *, uint8_t);
475203945Sweongyostatic void	bwn_phy_lp_set_gaintbl(struct bwn_mac *, uint32_t);
476203945Sweongyostatic void	bwn_phy_lp_digflt_save(struct bwn_mac *);
477203945Sweongyostatic void	bwn_phy_lp_get_txpctlmode(struct bwn_mac *);
478203945Sweongyostatic void	bwn_phy_lp_set_txpctlmode(struct bwn_mac *, uint8_t);
479203945Sweongyostatic void	bwn_phy_lp_bugfix(struct bwn_mac *);
480203945Sweongyostatic void	bwn_phy_lp_digflt_restore(struct bwn_mac *);
481203945Sweongyostatic void	bwn_phy_lp_tblinit(struct bwn_mac *);
482203945Sweongyostatic void	bwn_phy_lp_bbinit_r2(struct bwn_mac *);
483203945Sweongyostatic void	bwn_phy_lp_bbinit_r01(struct bwn_mac *);
484203945Sweongyostatic void	bwn_phy_lp_b2062_init(struct bwn_mac *);
485203945Sweongyostatic void	bwn_phy_lp_b2063_init(struct bwn_mac *);
486203945Sweongyostatic void	bwn_phy_lp_rxcal_r2(struct bwn_mac *);
487203945Sweongyostatic void	bwn_phy_lp_rccal_r12(struct bwn_mac *);
488203945Sweongyostatic void	bwn_phy_lp_set_rccap(struct bwn_mac *);
489203945Sweongyostatic uint32_t	bwn_phy_lp_roundup(uint32_t, uint32_t, uint8_t);
490203945Sweongyostatic void	bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *);
491203945Sweongyostatic void	bwn_phy_lp_b2062_vco_calib(struct bwn_mac *);
492203945Sweongyostatic void	bwn_tab_write_multi(struct bwn_mac *, uint32_t, int,
493203945Sweongyo		    const void *);
494203945Sweongyostatic void	bwn_tab_read_multi(struct bwn_mac *, uint32_t, int, void *);
495203945Sweongyostatic struct bwn_txgain
496203945Sweongyo		bwn_phy_lp_get_txgain(struct bwn_mac *);
497203945Sweongyostatic uint8_t	bwn_phy_lp_get_bbmult(struct bwn_mac *);
498203945Sweongyostatic void	bwn_phy_lp_set_txgain(struct bwn_mac *, struct bwn_txgain *);
499203945Sweongyostatic void	bwn_phy_lp_set_bbmult(struct bwn_mac *, uint8_t);
500203945Sweongyostatic void	bwn_phy_lp_set_trsw_over(struct bwn_mac *, uint8_t, uint8_t);
501203945Sweongyostatic void	bwn_phy_lp_set_rxgain(struct bwn_mac *, uint32_t);
502203945Sweongyostatic void	bwn_phy_lp_set_deaf(struct bwn_mac *, uint8_t);
503203945Sweongyostatic int	bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *, uint16_t);
504203945Sweongyostatic void	bwn_phy_lp_clear_deaf(struct bwn_mac *, uint8_t);
505203945Sweongyostatic void	bwn_phy_lp_tblinit_r01(struct bwn_mac *);
506203945Sweongyostatic void	bwn_phy_lp_tblinit_r2(struct bwn_mac *);
507203945Sweongyostatic void	bwn_phy_lp_tblinit_txgain(struct bwn_mac *);
508203945Sweongyostatic void	bwn_tab_write(struct bwn_mac *, uint32_t, uint32_t);
509203945Sweongyostatic void	bwn_phy_lp_b2062_tblinit(struct bwn_mac *);
510203945Sweongyostatic void	bwn_phy_lp_b2063_tblinit(struct bwn_mac *);
511203945Sweongyostatic int	bwn_phy_lp_loopback(struct bwn_mac *);
512203945Sweongyostatic void	bwn_phy_lp_set_rxgain_idx(struct bwn_mac *, uint16_t);
513203945Sweongyostatic void	bwn_phy_lp_ddfs_turnon(struct bwn_mac *, int, int, int, int,
514203945Sweongyo		    int);
515203945Sweongyostatic uint8_t	bwn_phy_lp_rx_iq_est(struct bwn_mac *, uint16_t, uint8_t,
516203945Sweongyo		    struct bwn_phy_lp_iq_est *);
517203945Sweongyostatic void	bwn_phy_lp_ddfs_turnoff(struct bwn_mac *);
518203945Sweongyostatic uint32_t	bwn_tab_read(struct bwn_mac *, uint32_t);
519203945Sweongyostatic void	bwn_phy_lp_set_txgain_dac(struct bwn_mac *, uint16_t);
520203945Sweongyostatic void	bwn_phy_lp_set_txgain_pa(struct bwn_mac *, uint16_t);
521203945Sweongyostatic void	bwn_phy_lp_set_txgain_override(struct bwn_mac *);
522203945Sweongyostatic uint16_t	bwn_phy_lp_get_pa_gain(struct bwn_mac *);
523203945Sweongyostatic uint8_t	bwn_nbits(int32_t);
524203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *, int, int,
525203945Sweongyo		    struct bwn_txgain_entry *);
526203945Sweongyostatic void	bwn_phy_lp_gaintbl_write(struct bwn_mac *, int,
527203945Sweongyo		    struct bwn_txgain_entry);
528203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
529203945Sweongyo		    struct bwn_txgain_entry);
530203945Sweongyostatic void	bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
531203945Sweongyo		    struct bwn_txgain_entry);
532204257Sweongyostatic void	bwn_sysctl_node(struct bwn_softc *);
533203945Sweongyo
534203945Sweongyostatic struct resource_spec bwn_res_spec_legacy[] = {
535203945Sweongyo	{ SYS_RES_IRQ,		0,		RF_ACTIVE | RF_SHAREABLE },
536203945Sweongyo	{ -1,			0,		0 }
537203945Sweongyo};
538203945Sweongyo
539203945Sweongyostatic struct resource_spec bwn_res_spec_msi[] = {
540203945Sweongyo	{ SYS_RES_IRQ,		1,		RF_ACTIVE },
541203945Sweongyo	{ -1,			0,		0 }
542203945Sweongyo};
543203945Sweongyo
544203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_bg = {
545203945Sweongyo	.channels = {
546203945Sweongyo		{ 2412,  1, 30 }, { 2417,  2, 30 }, { 2422,  3, 30 },
547203945Sweongyo		{ 2427,  4, 30 }, { 2432,  5, 30 }, { 2437,  6, 30 },
548203945Sweongyo		{ 2442,  7, 30 }, { 2447,  8, 30 }, { 2452,  9, 30 },
549203945Sweongyo		{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
550203945Sweongyo		{ 2472, 13, 30 }, { 2484, 14, 30 } },
551203945Sweongyo	.nchannels = 14
552203945Sweongyo};
553203945Sweongyo
554203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_a = {
555203945Sweongyo	.channels = {
556203945Sweongyo		{ 5170,  34, 30 }, { 5180,  36, 30 }, { 5190,  38, 30 },
557203945Sweongyo		{ 5200,  40, 30 }, { 5210,  42, 30 }, { 5220,  44, 30 },
558203945Sweongyo		{ 5230,  46, 30 }, { 5240,  48, 30 }, { 5260,  52, 30 },
559203945Sweongyo		{ 5280,  56, 30 }, { 5300,  60, 30 }, { 5320,  64, 30 },
560203945Sweongyo		{ 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
561203945Sweongyo		{ 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
562203945Sweongyo		{ 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
563203945Sweongyo		{ 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
564203945Sweongyo		{ 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
565203945Sweongyo		{ 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
566203945Sweongyo		{ 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
567203945Sweongyo		{ 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
568203945Sweongyo		{ 6080, 216, 30 } },
569203945Sweongyo	.nchannels = 37
570203945Sweongyo};
571203945Sweongyo
572203945Sweongyostatic const struct bwn_channelinfo bwn_chantable_n = {
573203945Sweongyo	.channels = {
574203945Sweongyo		{ 5160,  32, 30 }, { 5170,  34, 30 }, { 5180,  36, 30 },
575203945Sweongyo		{ 5190,  38, 30 }, { 5200,  40, 30 }, { 5210,  42, 30 },
576203945Sweongyo		{ 5220,  44, 30 }, { 5230,  46, 30 }, { 5240,  48, 30 },
577203945Sweongyo		{ 5250,  50, 30 }, { 5260,  52, 30 }, { 5270,  54, 30 },
578203945Sweongyo		{ 5280,  56, 30 }, { 5290,  58, 30 }, { 5300,  60, 30 },
579203945Sweongyo		{ 5310,  62, 30 }, { 5320,  64, 30 }, { 5330,  66, 30 },
580203945Sweongyo		{ 5340,  68, 30 }, { 5350,  70, 30 }, { 5360,  72, 30 },
581203945Sweongyo		{ 5370,  74, 30 }, { 5380,  76, 30 }, { 5390,  78, 30 },
582203945Sweongyo		{ 5400,  80, 30 }, { 5410,  82, 30 }, { 5420,  84, 30 },
583203945Sweongyo		{ 5430,  86, 30 }, { 5440,  88, 30 }, { 5450,  90, 30 },
584203945Sweongyo		{ 5460,  92, 30 }, { 5470,  94, 30 }, { 5480,  96, 30 },
585203945Sweongyo		{ 5490,  98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
586203945Sweongyo		{ 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
587203945Sweongyo		{ 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
588203945Sweongyo		{ 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
589203945Sweongyo		{ 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
590203945Sweongyo		{ 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
591203945Sweongyo		{ 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
592203945Sweongyo		{ 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
593203945Sweongyo		{ 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
594203945Sweongyo		{ 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
595203945Sweongyo		{ 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
596203945Sweongyo		{ 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
597203945Sweongyo		{ 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
598203945Sweongyo		{ 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
599203945Sweongyo		{ 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
600203945Sweongyo		{ 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
601203945Sweongyo		{ 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
602203945Sweongyo		{ 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
603203945Sweongyo		{ 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
604203945Sweongyo		{ 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
605203945Sweongyo		{ 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
606203945Sweongyo		{ 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
607203945Sweongyo		{ 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
608203945Sweongyo		{ 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
609203945Sweongyo		{ 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
610203945Sweongyo		{ 6130, 226, 30 }, { 6140, 228, 30 } },
611203945Sweongyo	.nchannels = 110
612203945Sweongyo};
613203945Sweongyo
614203945Sweongyostatic const uint8_t bwn_b2063_chantable_data[33][12] = {
615203945Sweongyo	{ 0x6f, 0x3c, 0x3c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
616203945Sweongyo	{ 0x6f, 0x2c, 0x2c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
617203945Sweongyo	{ 0x6f, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
618203945Sweongyo	{ 0x6e, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
619203945Sweongyo	{ 0x6e, 0xc, 0xc, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
620203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x2, 0x5, 0xd, 0xd, 0x77, 0x80, 0x20, 0 },
621203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x5, 0xd, 0xc, 0x77, 0x80, 0x20, 0 },
622203945Sweongyo	{ 0x6a, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x80, 0x20, 0 },
623203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x70, 0x20, 0 },
624203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xb, 0xc, 0x77, 0x70, 0x20, 0 },
625203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x4, 0xb, 0xb, 0x77, 0x60, 0x20, 0 },
626203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xb, 0x77, 0x60, 0x20, 0 },
627203945Sweongyo	{ 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xa, 0x77, 0x60, 0x20, 0 },
628203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x2, 0x9, 0x9, 0x77, 0x60, 0x20, 0 },
629203945Sweongyo	{ 0x68, 0xc, 0xc, 0, 0, 0x1, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
630203945Sweongyo	{ 0x67, 0xc, 0xc, 0, 0, 0, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
631203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x2, 0x1, 0x77, 0x20, 0, 0 },
632203945Sweongyo	{ 0x64, 0xc, 0xc, 0, 0, 0, 0x1, 0x1, 0x77, 0x20, 0, 0 },
633203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0x1, 0, 0x77, 0x10, 0, 0 },
634203945Sweongyo	{ 0x63, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
635203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
636203945Sweongyo	{ 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
637203945Sweongyo	{ 0x61, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
638203945Sweongyo	{ 0x60, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
639203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xe, 0xf, 0xf, 0x77, 0xc0, 0x50, 0 },
640203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x9, 0xd, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
641203945Sweongyo	{ 0x6e, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
642203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
643203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xb, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
644203945Sweongyo	{ 0x6d, 0xc, 0xc, 0, 0x8, 0xa, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
645203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x7, 0x9, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
646203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x6, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
647203945Sweongyo	{ 0x6c, 0xc, 0xc, 0, 0x5, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 }
648203945Sweongyo};
649203945Sweongyo
650203945Sweongyostatic const struct bwn_b206x_chan bwn_b2063_chantable[] = {
651203945Sweongyo	{ 1, 2412, bwn_b2063_chantable_data[0] },
652203945Sweongyo	{ 2, 2417, bwn_b2063_chantable_data[0] },
653203945Sweongyo	{ 3, 2422, bwn_b2063_chantable_data[0] },
654203945Sweongyo	{ 4, 2427, bwn_b2063_chantable_data[1] },
655203945Sweongyo	{ 5, 2432, bwn_b2063_chantable_data[1] },
656203945Sweongyo	{ 6, 2437, bwn_b2063_chantable_data[1] },
657203945Sweongyo	{ 7, 2442, bwn_b2063_chantable_data[1] },
658203945Sweongyo	{ 8, 2447, bwn_b2063_chantable_data[1] },
659203945Sweongyo	{ 9, 2452, bwn_b2063_chantable_data[2] },
660203945Sweongyo	{ 10, 2457, bwn_b2063_chantable_data[2] },
661203945Sweongyo	{ 11, 2462, bwn_b2063_chantable_data[3] },
662203945Sweongyo	{ 12, 2467, bwn_b2063_chantable_data[3] },
663203945Sweongyo	{ 13, 2472, bwn_b2063_chantable_data[3] },
664203945Sweongyo	{ 14, 2484, bwn_b2063_chantable_data[4] },
665203945Sweongyo	{ 34, 5170, bwn_b2063_chantable_data[5] },
666203945Sweongyo	{ 36, 5180, bwn_b2063_chantable_data[6] },
667203945Sweongyo	{ 38, 5190, bwn_b2063_chantable_data[7] },
668203945Sweongyo	{ 40, 5200, bwn_b2063_chantable_data[8] },
669203945Sweongyo	{ 42, 5210, bwn_b2063_chantable_data[9] },
670203945Sweongyo	{ 44, 5220, bwn_b2063_chantable_data[10] },
671203945Sweongyo	{ 46, 5230, bwn_b2063_chantable_data[11] },
672203945Sweongyo	{ 48, 5240, bwn_b2063_chantable_data[12] },
673203945Sweongyo	{ 52, 5260, bwn_b2063_chantable_data[13] },
674203945Sweongyo	{ 56, 5280, bwn_b2063_chantable_data[14] },
675203945Sweongyo	{ 60, 5300, bwn_b2063_chantable_data[14] },
676203945Sweongyo	{ 64, 5320, bwn_b2063_chantable_data[15] },
677203945Sweongyo	{ 100, 5500, bwn_b2063_chantable_data[16] },
678203945Sweongyo	{ 104, 5520, bwn_b2063_chantable_data[17] },
679203945Sweongyo	{ 108, 5540, bwn_b2063_chantable_data[18] },
680203945Sweongyo	{ 112, 5560, bwn_b2063_chantable_data[19] },
681203945Sweongyo	{ 116, 5580, bwn_b2063_chantable_data[20] },
682203945Sweongyo	{ 120, 5600, bwn_b2063_chantable_data[21] },
683203945Sweongyo	{ 124, 5620, bwn_b2063_chantable_data[21] },
684203945Sweongyo	{ 128, 5640, bwn_b2063_chantable_data[22] },
685203945Sweongyo	{ 132, 5660, bwn_b2063_chantable_data[22] },
686203945Sweongyo	{ 136, 5680, bwn_b2063_chantable_data[22] },
687203945Sweongyo	{ 140, 5700, bwn_b2063_chantable_data[23] },
688203945Sweongyo	{ 149, 5745, bwn_b2063_chantable_data[23] },
689203945Sweongyo	{ 153, 5765, bwn_b2063_chantable_data[23] },
690203945Sweongyo	{ 157, 5785, bwn_b2063_chantable_data[23] },
691203945Sweongyo	{ 161, 5805, bwn_b2063_chantable_data[23] },
692203945Sweongyo	{ 165, 5825, bwn_b2063_chantable_data[23] },
693203945Sweongyo	{ 184, 4920, bwn_b2063_chantable_data[24] },
694203945Sweongyo	{ 188, 4940, bwn_b2063_chantable_data[25] },
695203945Sweongyo	{ 192, 4960, bwn_b2063_chantable_data[26] },
696203945Sweongyo	{ 196, 4980, bwn_b2063_chantable_data[27] },
697203945Sweongyo	{ 200, 5000, bwn_b2063_chantable_data[28] },
698203945Sweongyo	{ 204, 5020, bwn_b2063_chantable_data[29] },
699203945Sweongyo	{ 208, 5040, bwn_b2063_chantable_data[30] },
700203945Sweongyo	{ 212, 5060, bwn_b2063_chantable_data[31] },
701203945Sweongyo	{ 216, 5080, bwn_b2063_chantable_data[32] }
702203945Sweongyo};
703203945Sweongyo
704203945Sweongyostatic const uint8_t bwn_b2062_chantable_data[22][12] = {
705203945Sweongyo	{ 0xff, 0xff, 0xb5, 0x1b, 0x24, 0x32, 0x32, 0x88, 0x88, 0, 0, 0 },
706203945Sweongyo	{ 0, 0x22, 0x20, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
707203945Sweongyo	{ 0, 0x11, 0x10, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
708203945Sweongyo	{ 0, 0, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
709203945Sweongyo	{ 0, 0x11, 0x20, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
710203945Sweongyo	{ 0, 0x11, 0x10, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
711203945Sweongyo	{ 0, 0x11, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
712203945Sweongyo	{ 0, 0, 0, 0x63, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
713203945Sweongyo	{ 0, 0, 0, 0x62, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
714203945Sweongyo	{ 0, 0, 0, 0x30, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
715203945Sweongyo	{ 0, 0, 0, 0x20, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
716203945Sweongyo	{ 0, 0, 0, 0x10, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
717203945Sweongyo	{ 0, 0, 0, 0, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
718203945Sweongyo	{ 0x55, 0x77, 0x90, 0xf7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
719203945Sweongyo	{ 0x44, 0x77, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
720203945Sweongyo	{ 0x44, 0x66, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
721203945Sweongyo	{ 0x33, 0x66, 0x70, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
722203945Sweongyo	{ 0x22, 0x55, 0x60, 0xd7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
723203945Sweongyo	{ 0x22, 0x55, 0x60, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
724203945Sweongyo	{ 0x22, 0x44, 0x50, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
725203945Sweongyo	{ 0x11, 0x44, 0x50, 0xa5, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
726203945Sweongyo	{ 0, 0x44, 0x40, 0xb6, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 }
727203945Sweongyo};
728203945Sweongyo
729203945Sweongyostatic const struct bwn_b206x_chan bwn_b2062_chantable[] = {
730203945Sweongyo	{ 1, 2412, bwn_b2062_chantable_data[0] },
731203945Sweongyo	{ 2, 2417, bwn_b2062_chantable_data[0] },
732203945Sweongyo	{ 3, 2422, bwn_b2062_chantable_data[0] },
733203945Sweongyo	{ 4, 2427, bwn_b2062_chantable_data[0] },
734203945Sweongyo	{ 5, 2432, bwn_b2062_chantable_data[0] },
735203945Sweongyo	{ 6, 2437, bwn_b2062_chantable_data[0] },
736203945Sweongyo	{ 7, 2442, bwn_b2062_chantable_data[0] },
737203945Sweongyo	{ 8, 2447, bwn_b2062_chantable_data[0] },
738203945Sweongyo	{ 9, 2452, bwn_b2062_chantable_data[0] },
739203945Sweongyo	{ 10, 2457, bwn_b2062_chantable_data[0] },
740203945Sweongyo	{ 11, 2462, bwn_b2062_chantable_data[0] },
741203945Sweongyo	{ 12, 2467, bwn_b2062_chantable_data[0] },
742203945Sweongyo	{ 13, 2472, bwn_b2062_chantable_data[0] },
743203945Sweongyo	{ 14, 2484, bwn_b2062_chantable_data[0] },
744203945Sweongyo	{ 34, 5170, bwn_b2062_chantable_data[1] },
745203945Sweongyo	{ 38, 5190, bwn_b2062_chantable_data[2] },
746203945Sweongyo	{ 42, 5210, bwn_b2062_chantable_data[2] },
747203945Sweongyo	{ 46, 5230, bwn_b2062_chantable_data[3] },
748203945Sweongyo	{ 36, 5180, bwn_b2062_chantable_data[4] },
749203945Sweongyo	{ 40, 5200, bwn_b2062_chantable_data[5] },
750203945Sweongyo	{ 44, 5220, bwn_b2062_chantable_data[6] },
751203945Sweongyo	{ 48, 5240, bwn_b2062_chantable_data[3] },
752203945Sweongyo	{ 52, 5260, bwn_b2062_chantable_data[3] },
753203945Sweongyo	{ 56, 5280, bwn_b2062_chantable_data[3] },
754203945Sweongyo	{ 60, 5300, bwn_b2062_chantable_data[7] },
755203945Sweongyo	{ 64, 5320, bwn_b2062_chantable_data[8] },
756203945Sweongyo	{ 100, 5500, bwn_b2062_chantable_data[9] },
757203945Sweongyo	{ 104, 5520, bwn_b2062_chantable_data[10] },
758203945Sweongyo	{ 108, 5540, bwn_b2062_chantable_data[10] },
759203945Sweongyo	{ 112, 5560, bwn_b2062_chantable_data[10] },
760203945Sweongyo	{ 116, 5580, bwn_b2062_chantable_data[11] },
761203945Sweongyo	{ 120, 5600, bwn_b2062_chantable_data[12] },
762203945Sweongyo	{ 124, 5620, bwn_b2062_chantable_data[12] },
763203945Sweongyo	{ 128, 5640, bwn_b2062_chantable_data[12] },
764203945Sweongyo	{ 132, 5660, bwn_b2062_chantable_data[12] },
765203945Sweongyo	{ 136, 5680, bwn_b2062_chantable_data[12] },
766203945Sweongyo	{ 140, 5700, bwn_b2062_chantable_data[12] },
767203945Sweongyo	{ 149, 5745, bwn_b2062_chantable_data[12] },
768203945Sweongyo	{ 153, 5765, bwn_b2062_chantable_data[12] },
769203945Sweongyo	{ 157, 5785, bwn_b2062_chantable_data[12] },
770203945Sweongyo	{ 161, 5805, bwn_b2062_chantable_data[12] },
771203945Sweongyo	{ 165, 5825, bwn_b2062_chantable_data[12] },
772203945Sweongyo	{ 184, 4920, bwn_b2062_chantable_data[13] },
773203945Sweongyo	{ 188, 4940, bwn_b2062_chantable_data[14] },
774203945Sweongyo	{ 192, 4960, bwn_b2062_chantable_data[15] },
775203945Sweongyo	{ 196, 4980, bwn_b2062_chantable_data[16] },
776203945Sweongyo	{ 200, 5000, bwn_b2062_chantable_data[17] },
777203945Sweongyo	{ 204, 5020, bwn_b2062_chantable_data[18] },
778203945Sweongyo	{ 208, 5040, bwn_b2062_chantable_data[19] },
779203945Sweongyo	{ 212, 5060, bwn_b2062_chantable_data[20] },
780203945Sweongyo	{ 216, 5080, bwn_b2062_chantable_data[21] }
781203945Sweongyo};
782203945Sweongyo
783203945Sweongyo/* for LP PHY */
784203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_5354[] = {
785203945Sweongyo	{  1, -66, 15 }, {  2, -66, 15 }, {  3, -66, 15 }, {  4, -66, 15 },
786203945Sweongyo	{  5, -66, 15 }, {  6, -66, 15 }, {  7, -66, 14 }, {  8, -66, 14 },
787203945Sweongyo	{  9, -66, 14 }, { 10, -66, 14 }, { 11, -66, 14 }, { 12, -66, 13 },
788203945Sweongyo	{ 13, -66, 13 }, { 14, -66, 13 },
789203945Sweongyo};
790203945Sweongyo
791203945Sweongyo/* for LP PHY */
792203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r12[] = {
793203945Sweongyo	{   1, -64, 13 }, {   2, -64, 13 }, {   3, -64, 13 }, {   4, -64, 13 },
794203945Sweongyo	{   5, -64, 12 }, {   6, -64, 12 }, {   7, -64, 12 }, {   8, -64, 12 },
795203945Sweongyo	{   9, -64, 12 }, {  10, -64, 11 }, {  11, -64, 11 }, {  12, -64, 11 },
796203945Sweongyo	{  13, -64, 11 }, {  14, -64, 10 }, {  34, -62, 24 }, {  38, -62, 24 },
797203945Sweongyo	{  42, -62, 24 }, {  46, -62, 23 }, {  36, -62, 24 }, {  40, -62, 24 },
798203945Sweongyo	{  44, -62, 23 }, {  48, -62, 23 }, {  52, -62, 23 }, {  56, -62, 22 },
799203945Sweongyo	{  60, -62, 22 }, {  64, -62, 22 }, { 100, -62, 16 }, { 104, -62, 16 },
800203945Sweongyo	{ 108, -62, 15 }, { 112, -62, 14 }, { 116, -62, 14 }, { 120, -62, 13 },
801203945Sweongyo	{ 124, -62, 12 }, { 128, -62, 12 }, { 132, -62, 12 }, { 136, -62, 11 },
802203945Sweongyo	{ 140, -62, 10 }, { 149, -61,  9 }, { 153, -61,  9 }, { 157, -61,  9 },
803203945Sweongyo	{ 161, -61,  8 }, { 165, -61,  8 }, { 184, -62, 25 }, { 188, -62, 25 },
804203945Sweongyo	{ 192, -62, 25 }, { 196, -62, 25 }, { 200, -62, 25 }, { 204, -62, 25 },
805203945Sweongyo	{ 208, -62, 25 }, { 212, -62, 25 }, { 216, -62, 26 },
806203945Sweongyo};
807203945Sweongyo
808203945Sweongyostatic const struct bwn_rxcompco bwn_rxcompco_r2 = { 0, -64, 0 };
809203945Sweongyo
810203945Sweongyostatic const uint8_t bwn_tab_sigsq_tbl[] = {
811203945Sweongyo	0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
812203945Sweongyo	0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
813203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
814203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
815203945Sweongyo	0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
816203945Sweongyo	0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
817203945Sweongyo};
818203945Sweongyo
819203945Sweongyostatic const uint8_t bwn_tab_pllfrac_tbl[] = {
820203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
821203945Sweongyo	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
822203945Sweongyo};
823203945Sweongyo
824203945Sweongyostatic const uint16_t bwn_tabl_iqlocal_tbl[] = {
825203945Sweongyo	0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
826203945Sweongyo	0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
827203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
828203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
829203945Sweongyo	0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
830203945Sweongyo	0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
831203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
832203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
833203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
834203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
835203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
836203945Sweongyo	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
837203945Sweongyo};
838203945Sweongyo
839203945Sweongyostatic const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
840203945Sweongyostatic const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
841203945Sweongyostatic const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
842203945Sweongyostatic const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
843203945Sweongyostatic const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
844203945Sweongyoconst uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
845203945Sweongyo
846203945Sweongyo#define	VENDOR_LED_ACT(vendor)				\
847203945Sweongyo{							\
848203945Sweongyo	.vid = PCI_VENDOR_##vendor,			\
849203945Sweongyo	.led_act = { BWN_VENDOR_LED_ACT_##vendor }	\
850203945Sweongyo}
851203945Sweongyo
852203945Sweongyostatic const struct {
853203945Sweongyo	uint16_t	vid;
854203945Sweongyo	uint8_t		led_act[BWN_LED_MAX];
855203945Sweongyo} bwn_vendor_led_act[] = {
856203945Sweongyo	VENDOR_LED_ACT(COMPAQ),
857203945Sweongyo	VENDOR_LED_ACT(ASUSTEK)
858203945Sweongyo};
859203945Sweongyo
860203945Sweongyostatic const uint8_t bwn_default_led_act[BWN_LED_MAX] =
861203945Sweongyo	{ BWN_VENDOR_LED_ACT_DEFAULT };
862203945Sweongyo
863203945Sweongyo#undef VENDOR_LED_ACT
864203945Sweongyo
865203945Sweongyostatic const struct {
866203945Sweongyo	int		on_dur;
867203945Sweongyo	int		off_dur;
868203945Sweongyo} bwn_led_duration[109] = {
869203945Sweongyo	[0]	= { 400, 100 },
870203945Sweongyo	[2]	= { 150, 75 },
871203945Sweongyo	[4]	= { 90, 45 },
872203945Sweongyo	[11]	= { 66, 34 },
873203945Sweongyo	[12]	= { 53, 26 },
874203945Sweongyo	[18]	= { 42, 21 },
875203945Sweongyo	[22]	= { 35, 17 },
876203945Sweongyo	[24]	= { 32, 16 },
877203945Sweongyo	[36]	= { 21, 10 },
878203945Sweongyo	[48]	= { 16, 8 },
879203945Sweongyo	[72]	= { 11, 5 },
880203945Sweongyo	[96]	= { 9, 4 },
881203945Sweongyo	[108]	= { 7, 3 }
882203945Sweongyo};
883203945Sweongyo
884203945Sweongyostatic const uint16_t bwn_wme_shm_offsets[] = {
885203945Sweongyo	[0] = BWN_WME_BESTEFFORT,
886203945Sweongyo	[1] = BWN_WME_BACKGROUND,
887203945Sweongyo	[2] = BWN_WME_VOICE,
888203945Sweongyo	[3] = BWN_WME_VIDEO,
889203945Sweongyo};
890203945Sweongyo
891203945Sweongyostatic const struct siba_devid bwn_devs[] = {
892203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
893203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
894203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
895203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
896203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
897203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
898203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
899203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
900203945Sweongyo	SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
901203945Sweongyo};
902203945Sweongyo
903203945Sweongyostatic int
904203945Sweongyobwn_probe(device_t dev)
905203945Sweongyo{
906203945Sweongyo	int i;
907203945Sweongyo
908203945Sweongyo	for (i = 0; i < sizeof(bwn_devs) / sizeof(bwn_devs[0]); i++) {
909204922Sweongyo		if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor &&
910204922Sweongyo		    siba_get_device(dev) == bwn_devs[i].sd_device &&
911204922Sweongyo		    siba_get_revid(dev) == bwn_devs[i].sd_rev)
912203945Sweongyo			return (BUS_PROBE_DEFAULT);
913203945Sweongyo	}
914203945Sweongyo
915203945Sweongyo	return (ENXIO);
916203945Sweongyo}
917203945Sweongyo
918203945Sweongyostatic int
919203945Sweongyobwn_attach(device_t dev)
920203945Sweongyo{
921203945Sweongyo	struct bwn_mac *mac;
922203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
923203945Sweongyo	int error, i, msic, reg;
924203945Sweongyo
925203945Sweongyo	sc->sc_dev = dev;
926203945Sweongyo#ifdef BWN_DEBUG
927203945Sweongyo	sc->sc_debug = bwn_debug;
928203945Sweongyo#endif
929203945Sweongyo
930203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
931287197Sglebius		bwn_attach_pre(sc);
932204922Sweongyo		bwn_sprom_bugfixes(dev);
933203945Sweongyo		sc->sc_flags |= BWN_FLAG_ATTACHED;
934203945Sweongyo	}
935203945Sweongyo
936203945Sweongyo	if (!TAILQ_EMPTY(&sc->sc_maclist)) {
937204922Sweongyo		if (siba_get_pci_device(dev) != 0x4313 &&
938204922Sweongyo		    siba_get_pci_device(dev) != 0x431a &&
939204922Sweongyo		    siba_get_pci_device(dev) != 0x4321) {
940203945Sweongyo			device_printf(sc->sc_dev,
941203945Sweongyo			    "skip 802.11 cores\n");
942203945Sweongyo			return (ENODEV);
943203945Sweongyo		}
944203945Sweongyo	}
945203945Sweongyo
946287197Sglebius	mac = malloc(sizeof(*mac), M_DEVBUF, M_WAITOK | M_ZERO);
947203945Sweongyo	mac->mac_sc = sc;
948203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
949203945Sweongyo	if (bwn_bfp != 0)
950203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
951203945Sweongyo
952203945Sweongyo	TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
953203945Sweongyo	TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
954203945Sweongyo	TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
955203945Sweongyo
956203945Sweongyo	error = bwn_attach_core(mac);
957203945Sweongyo	if (error)
958203945Sweongyo		goto fail0;
959203945Sweongyo	bwn_led_attach(mac);
960203945Sweongyo
961203945Sweongyo	device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
962203945Sweongyo	    "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
963204922Sweongyo	    siba_get_chipid(sc->sc_dev), siba_get_revid(sc->sc_dev),
964203945Sweongyo	    mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
965203945Sweongyo	    mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
966203945Sweongyo	    mac->mac_phy.rf_rev);
967203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
968203945Sweongyo		device_printf(sc->sc_dev, "DMA (%d bits)\n",
969203945Sweongyo		    mac->mac_method.dma.dmatype);
970203945Sweongyo	else
971203945Sweongyo		device_printf(sc->sc_dev, "PIO\n");
972203945Sweongyo
973203945Sweongyo	/*
974203945Sweongyo	 * setup PCI resources and interrupt.
975203945Sweongyo	 */
976219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
977203945Sweongyo		msic = pci_msi_count(dev);
978203945Sweongyo		if (bootverbose)
979203945Sweongyo			device_printf(sc->sc_dev, "MSI count : %d\n", msic);
980203945Sweongyo	} else
981203945Sweongyo		msic = 0;
982203945Sweongyo
983203945Sweongyo	mac->mac_intr_spec = bwn_res_spec_legacy;
984203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
985203945Sweongyo		if (pci_alloc_msi(dev, &msic) == 0) {
986203945Sweongyo			device_printf(sc->sc_dev,
987203945Sweongyo			    "Using %d MSI messages\n", msic);
988203945Sweongyo			mac->mac_intr_spec = bwn_res_spec_msi;
989203945Sweongyo			mac->mac_msi = 1;
990203945Sweongyo		}
991203945Sweongyo	}
992203945Sweongyo
993203945Sweongyo	error = bus_alloc_resources(dev, mac->mac_intr_spec,
994203945Sweongyo	    mac->mac_res_irq);
995203945Sweongyo	if (error) {
996203945Sweongyo		device_printf(sc->sc_dev,
997203945Sweongyo		    "couldn't allocate IRQ resources (%d)\n", error);
998203945Sweongyo		goto fail1;
999203945Sweongyo	}
1000203945Sweongyo
1001203945Sweongyo	if (mac->mac_msi == 0)
1002203945Sweongyo		error = bus_setup_intr(dev, mac->mac_res_irq[0],
1003203945Sweongyo		    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1004203945Sweongyo		    &mac->mac_intrhand[0]);
1005203945Sweongyo	else {
1006203945Sweongyo		for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1007203945Sweongyo			error = bus_setup_intr(dev, mac->mac_res_irq[i],
1008203945Sweongyo			    INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac,
1009203945Sweongyo			    &mac->mac_intrhand[i]);
1010203945Sweongyo			if (error != 0) {
1011203945Sweongyo				device_printf(sc->sc_dev,
1012203945Sweongyo				    "couldn't setup interrupt (%d)\n", error);
1013203945Sweongyo				break;
1014203945Sweongyo			}
1015203945Sweongyo		}
1016203945Sweongyo	}
1017203945Sweongyo
1018203945Sweongyo	TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
1019203945Sweongyo
1020203945Sweongyo	/*
1021203945Sweongyo	 * calls attach-post routine
1022203945Sweongyo	 */
1023203945Sweongyo	if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
1024203945Sweongyo		bwn_attach_post(sc);
1025203945Sweongyo
1026203945Sweongyo	return (0);
1027203945Sweongyofail1:
1028203945Sweongyo	if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
1029203945Sweongyo		pci_release_msi(dev);
1030203945Sweongyofail0:
1031203945Sweongyo	free(mac, M_DEVBUF);
1032203945Sweongyo	return (error);
1033203945Sweongyo}
1034203945Sweongyo
1035203945Sweongyostatic int
1036203945Sweongyobwn_is_valid_ether_addr(uint8_t *addr)
1037203945Sweongyo{
1038203945Sweongyo	char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
1039203945Sweongyo
1040203945Sweongyo	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
1041203945Sweongyo		return (FALSE);
1042203945Sweongyo
1043203945Sweongyo	return (TRUE);
1044203945Sweongyo}
1045203945Sweongyo
1046203945Sweongyostatic int
1047203945Sweongyobwn_attach_post(struct bwn_softc *sc)
1048203945Sweongyo{
1049287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1050203945Sweongyo
1051283537Sglebius	ic->ic_softc = sc;
1052283527Sglebius	ic->ic_name = device_get_nameunit(sc->sc_dev);
1053203945Sweongyo	/* XXX not right but it's not used anywhere important */
1054203945Sweongyo	ic->ic_phytype = IEEE80211_T_OFDM;
1055203945Sweongyo	ic->ic_opmode = IEEE80211_M_STA;
1056203945Sweongyo	ic->ic_caps =
1057203945Sweongyo		  IEEE80211_C_STA		/* station mode supported */
1058203945Sweongyo		| IEEE80211_C_MONITOR		/* monitor mode */
1059204436Sweongyo		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
1060203945Sweongyo		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
1061203945Sweongyo		| IEEE80211_C_SHSLOT		/* short slot time supported */
1062203945Sweongyo		| IEEE80211_C_WME		/* WME/WMM supported */
1063203945Sweongyo		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
1064203945Sweongyo		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
1065203945Sweongyo		| IEEE80211_C_TXPMGT		/* capable of txpow mgt */
1066203945Sweongyo		;
1067203945Sweongyo
1068205141Sweongyo	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;	/* s/w bmiss */
1069205141Sweongyo
1070287197Sglebius	IEEE80211_ADDR_COPY(ic->ic_macaddr,
1071204922Sweongyo	    bwn_is_valid_ether_addr(siba_sprom_get_mac_80211a(sc->sc_dev)) ?
1072204922Sweongyo	    siba_sprom_get_mac_80211a(sc->sc_dev) :
1073204922Sweongyo	    siba_sprom_get_mac_80211bg(sc->sc_dev));
1074203945Sweongyo
1075287197Sglebius	/* call MI attach routine. */
1076287197Sglebius	ieee80211_ifattach(ic);
1077287197Sglebius
1078203945Sweongyo	ic->ic_headroom = sizeof(struct bwn_txhdr);
1079203945Sweongyo
1080203945Sweongyo	/* override default methods */
1081203945Sweongyo	ic->ic_raw_xmit = bwn_raw_xmit;
1082203945Sweongyo	ic->ic_updateslot = bwn_updateslot;
1083203945Sweongyo	ic->ic_update_promisc = bwn_update_promisc;
1084203945Sweongyo	ic->ic_wme.wme_update = bwn_wme_update;
1085203945Sweongyo	ic->ic_scan_start = bwn_scan_start;
1086203945Sweongyo	ic->ic_scan_end = bwn_scan_end;
1087203945Sweongyo	ic->ic_set_channel = bwn_set_channel;
1088203945Sweongyo	ic->ic_vap_create = bwn_vap_create;
1089203945Sweongyo	ic->ic_vap_delete = bwn_vap_delete;
1090287197Sglebius	ic->ic_transmit = bwn_transmit;
1091287197Sglebius	ic->ic_parent = bwn_parent;
1092203945Sweongyo
1093203945Sweongyo	ieee80211_radiotap_attach(ic,
1094203945Sweongyo	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
1095203945Sweongyo	    BWN_TX_RADIOTAP_PRESENT,
1096203945Sweongyo	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
1097203945Sweongyo	    BWN_RX_RADIOTAP_PRESENT);
1098203945Sweongyo
1099204257Sweongyo	bwn_sysctl_node(sc);
1100203945Sweongyo
1101203945Sweongyo	if (bootverbose)
1102203945Sweongyo		ieee80211_announce(ic);
1103203945Sweongyo	return (0);
1104203945Sweongyo}
1105203945Sweongyo
1106203945Sweongyostatic void
1107203945Sweongyobwn_phy_detach(struct bwn_mac *mac)
1108203945Sweongyo{
1109203945Sweongyo
1110203945Sweongyo	if (mac->mac_phy.detach != NULL)
1111203945Sweongyo		mac->mac_phy.detach(mac);
1112203945Sweongyo}
1113203945Sweongyo
1114203945Sweongyostatic int
1115203945Sweongyobwn_detach(device_t dev)
1116203945Sweongyo{
1117203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
1118203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1119287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1120203945Sweongyo	int i;
1121203945Sweongyo
1122203945Sweongyo	sc->sc_flags |= BWN_FLAG_INVALID;
1123203945Sweongyo
1124203945Sweongyo	if (device_is_attached(sc->sc_dev)) {
1125287197Sglebius		BWN_LOCK(sc);
1126287197Sglebius		bwn_stop(sc);
1127287197Sglebius		BWN_UNLOCK(sc);
1128203945Sweongyo		bwn_dma_free(mac);
1129203945Sweongyo		callout_drain(&sc->sc_led_blink_ch);
1130203945Sweongyo		callout_drain(&sc->sc_rfswitch_ch);
1131203945Sweongyo		callout_drain(&sc->sc_task_ch);
1132203945Sweongyo		callout_drain(&sc->sc_watchdog_ch);
1133203945Sweongyo		bwn_phy_detach(mac);
1134287197Sglebius		ieee80211_draintask(ic, &mac->mac_hwreset);
1135287197Sglebius		ieee80211_draintask(ic, &mac->mac_txpower);
1136287197Sglebius		ieee80211_ifdetach(ic);
1137203945Sweongyo	}
1138203945Sweongyo	taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
1139203945Sweongyo	taskqueue_free(sc->sc_tq);
1140203945Sweongyo
1141203945Sweongyo	for (i = 0; i < BWN_MSI_MESSAGES; i++) {
1142203945Sweongyo		if (mac->mac_intrhand[i] != NULL) {
1143203945Sweongyo			bus_teardown_intr(dev, mac->mac_res_irq[i],
1144203945Sweongyo			    mac->mac_intrhand[i]);
1145203945Sweongyo			mac->mac_intrhand[i] = NULL;
1146203945Sweongyo		}
1147203945Sweongyo	}
1148203945Sweongyo	bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
1149203945Sweongyo	if (mac->mac_msi != 0)
1150203945Sweongyo		pci_release_msi(dev);
1151287197Sglebius	mbufq_drain(&sc->sc_snd);
1152203945Sweongyo	BWN_LOCK_DESTROY(sc);
1153203945Sweongyo	return (0);
1154203945Sweongyo}
1155203945Sweongyo
1156287197Sglebiusstatic void
1157203945Sweongyobwn_attach_pre(struct bwn_softc *sc)
1158203945Sweongyo{
1159203945Sweongyo
1160203945Sweongyo	BWN_LOCK_INIT(sc);
1161203945Sweongyo	TAILQ_INIT(&sc->sc_maclist);
1162203945Sweongyo	callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0);
1163203945Sweongyo	callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0);
1164203945Sweongyo	callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0);
1165287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
1166203945Sweongyo	sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
1167203945Sweongyo		taskqueue_thread_enqueue, &sc->sc_tq);
1168203945Sweongyo	taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
1169203945Sweongyo		"%s taskq", device_get_nameunit(sc->sc_dev));
1170203945Sweongyo}
1171203945Sweongyo
1172203945Sweongyostatic void
1173204922Sweongyobwn_sprom_bugfixes(device_t dev)
1174203945Sweongyo{
1175203945Sweongyo#define	BWN_ISDEV(_vendor, _device, _subvendor, _subdevice)		\
1176204922Sweongyo	((siba_get_pci_vendor(dev) == PCI_VENDOR_##_vendor) &&		\
1177204922Sweongyo	 (siba_get_pci_device(dev) == _device) &&			\
1178204922Sweongyo	 (siba_get_pci_subvendor(dev) == PCI_VENDOR_##_subvendor) &&	\
1179204922Sweongyo	 (siba_get_pci_subdevice(dev) == _subdevice))
1180203945Sweongyo
1181204922Sweongyo	if (siba_get_pci_subvendor(dev) == PCI_VENDOR_APPLE &&
1182204922Sweongyo	    siba_get_pci_subdevice(dev) == 0x4e &&
1183204922Sweongyo	    siba_get_pci_revid(dev) > 0x40)
1184204922Sweongyo		siba_sprom_set_bf_lo(dev,
1185204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_PACTRL);
1186204922Sweongyo	if (siba_get_pci_subvendor(dev) == SIBA_BOARDVENDOR_DELL &&
1187204922Sweongyo	    siba_get_chipid(dev) == 0x4301 && siba_get_pci_revid(dev) == 0x74)
1188204922Sweongyo		siba_sprom_set_bf_lo(dev,
1189204922Sweongyo		    siba_sprom_get_bf_lo(dev) | BWN_BFL_BTCOEXIST);
1190204922Sweongyo	if (siba_get_type(dev) == SIBA_TYPE_PCI) {
1191203945Sweongyo		if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
1192203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
1193203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
1194203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
1195203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
1196203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
1197203945Sweongyo		    BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
1198204922Sweongyo			siba_sprom_set_bf_lo(dev,
1199204922Sweongyo			    siba_sprom_get_bf_lo(dev) & ~BWN_BFL_BTCOEXIST);
1200203945Sweongyo	}
1201203945Sweongyo#undef	BWN_ISDEV
1202203945Sweongyo}
1203203945Sweongyo
1204287197Sglebiusstatic void
1205287197Sglebiusbwn_parent(struct ieee80211com *ic)
1206203945Sweongyo{
1207287197Sglebius	struct bwn_softc *sc = ic->ic_softc;
1208287197Sglebius	int startall = 0;
1209203945Sweongyo
1210287197Sglebius	BWN_LOCK(sc);
1211287197Sglebius	if (ic->ic_nrunning > 0) {
1212287197Sglebius		if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) {
1213287197Sglebius			bwn_init(sc);
1214287197Sglebius			startall = 1;
1215287197Sglebius		} else
1216286437Sadrian			bwn_update_promisc(ic);
1217287197Sglebius	} else if (sc->sc_flags & BWN_FLAG_RUNNING)
1218287197Sglebius		bwn_stop(sc);
1219287197Sglebius	BWN_UNLOCK(sc);
1220287197Sglebius
1221287197Sglebius	if (startall)
1222287197Sglebius		ieee80211_start_all(ic);
1223203945Sweongyo}
1224203945Sweongyo
1225287197Sglebiusstatic int
1226287197Sglebiusbwn_transmit(struct ieee80211com *ic, struct mbuf *m)
1227203945Sweongyo{
1228287197Sglebius	struct bwn_softc *sc = ic->ic_softc;
1229287197Sglebius	int error;
1230203945Sweongyo
1231203945Sweongyo	BWN_LOCK(sc);
1232287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0) {
1233287197Sglebius		BWN_UNLOCK(sc);
1234287197Sglebius		return (ENXIO);
1235287197Sglebius	}
1236287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
1237287197Sglebius	if (error) {
1238287197Sglebius		BWN_UNLOCK(sc);
1239287197Sglebius		return (error);
1240287197Sglebius	}
1241287197Sglebius	bwn_start(sc);
1242203945Sweongyo	BWN_UNLOCK(sc);
1243287197Sglebius	return (0);
1244203945Sweongyo}
1245203945Sweongyo
1246203945Sweongyostatic void
1247287197Sglebiusbwn_start(struct bwn_softc *sc)
1248203945Sweongyo{
1249203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1250203945Sweongyo	struct ieee80211_frame *wh;
1251203945Sweongyo	struct ieee80211_node *ni;
1252203945Sweongyo	struct ieee80211_key *k;
1253203945Sweongyo	struct mbuf *m;
1254203945Sweongyo
1255203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1256203945Sweongyo
1257287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 || mac == NULL ||
1258203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED)
1259203945Sweongyo		return;
1260203945Sweongyo
1261287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
1262203945Sweongyo		if (bwn_tx_isfull(sc, m))
1263203945Sweongyo			break;
1264203945Sweongyo		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
1265203945Sweongyo		if (ni == NULL) {
1266203945Sweongyo			device_printf(sc->sc_dev, "unexpected NULL ni\n");
1267203945Sweongyo			m_freem(m);
1268287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
1269203945Sweongyo			continue;
1270203945Sweongyo		}
1271203945Sweongyo		wh = mtod(m, struct ieee80211_frame *);
1272260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
1273203945Sweongyo			k = ieee80211_crypto_encap(ni, m);
1274203945Sweongyo			if (k == NULL) {
1275287197Sglebius				if_inc_counter(ni->ni_vap->iv_ifp,
1276287197Sglebius				    IFCOUNTER_OERRORS, 1);
1277203945Sweongyo				ieee80211_free_node(ni);
1278203945Sweongyo				m_freem(m);
1279203945Sweongyo				continue;
1280203945Sweongyo			}
1281203945Sweongyo		}
1282203945Sweongyo		wh = NULL;	/* Catch any invalid use */
1283203945Sweongyo		if (bwn_tx_start(sc, ni, m) != 0) {
1284287197Sglebius			if (ni != NULL) {
1285287197Sglebius				if_inc_counter(ni->ni_vap->iv_ifp,
1286287197Sglebius				    IFCOUNTER_OERRORS, 1);
1287203945Sweongyo				ieee80211_free_node(ni);
1288287197Sglebius			}
1289203945Sweongyo			continue;
1290203945Sweongyo		}
1291203945Sweongyo		sc->sc_watchdog_timer = 5;
1292203945Sweongyo	}
1293203945Sweongyo}
1294203945Sweongyo
1295203945Sweongyostatic int
1296203945Sweongyobwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
1297203945Sweongyo{
1298203945Sweongyo	struct bwn_dma_ring *dr;
1299203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1300203945Sweongyo	struct bwn_pio_txqueue *tq;
1301203945Sweongyo	int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1302203945Sweongyo
1303203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1304203945Sweongyo
1305203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
1306203945Sweongyo		dr = bwn_dma_select(mac, M_WME_GETAC(m));
1307203945Sweongyo		if (dr->dr_stop == 1 ||
1308203945Sweongyo		    bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
1309203945Sweongyo			dr->dr_stop = 1;
1310203945Sweongyo			goto full;
1311203945Sweongyo		}
1312203945Sweongyo	} else {
1313203945Sweongyo		tq = bwn_pio_select(mac, M_WME_GETAC(m));
1314203945Sweongyo		if (tq->tq_free == 0 || pktlen > tq->tq_size ||
1315287197Sglebius		    pktlen > (tq->tq_size - tq->tq_used))
1316203945Sweongyo			goto full;
1317203945Sweongyo	}
1318203945Sweongyo	return (0);
1319203945Sweongyofull:
1320287197Sglebius	mbufq_prepend(&sc->sc_snd, m);
1321203945Sweongyo	return (1);
1322203945Sweongyo}
1323203945Sweongyo
1324203945Sweongyostatic int
1325203945Sweongyobwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
1326203945Sweongyo{
1327203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
1328203945Sweongyo	int error;
1329203945Sweongyo
1330203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1331203945Sweongyo
1332203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
1333203945Sweongyo		m_freem(m);
1334203945Sweongyo		return (ENXIO);
1335203945Sweongyo	}
1336203945Sweongyo
1337203945Sweongyo	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
1338203945Sweongyo	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
1339203945Sweongyo	if (error) {
1340203945Sweongyo		m_freem(m);
1341203945Sweongyo		return (error);
1342203945Sweongyo	}
1343203945Sweongyo	return (0);
1344203945Sweongyo}
1345203945Sweongyo
1346203945Sweongyostatic int
1347203945Sweongyobwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1348203945Sweongyo{
1349203945Sweongyo	struct bwn_pio_txpkt *tp;
1350203945Sweongyo	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
1351203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1352203945Sweongyo	struct bwn_txhdr txhdr;
1353203945Sweongyo	struct mbuf *m_new;
1354203945Sweongyo	uint32_t ctl32;
1355203945Sweongyo	int error;
1356203945Sweongyo	uint16_t ctl16;
1357203945Sweongyo
1358203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1359203945Sweongyo
1360203945Sweongyo	/* XXX TODO send packets after DTIM */
1361203945Sweongyo
1362203945Sweongyo	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
1363203945Sweongyo	tp = TAILQ_FIRST(&tq->tq_pktlist);
1364203945Sweongyo	tp->tp_ni = ni;
1365203945Sweongyo	tp->tp_m = m;
1366203945Sweongyo
1367203945Sweongyo	error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
1368203945Sweongyo	if (error) {
1369203945Sweongyo		device_printf(sc->sc_dev, "tx fail\n");
1370203945Sweongyo		return (error);
1371203945Sweongyo	}
1372203945Sweongyo
1373203945Sweongyo	TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
1374203945Sweongyo	tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
1375203945Sweongyo	tq->tq_free--;
1376203945Sweongyo
1377204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8) {
1378203945Sweongyo		/*
1379203945Sweongyo		 * XXX please removes m_defrag(9)
1380203945Sweongyo		 */
1381243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
1382203945Sweongyo		if (m_new == NULL) {
1383203945Sweongyo			device_printf(sc->sc_dev,
1384203945Sweongyo			    "%s: can't defrag TX buffer\n",
1385203945Sweongyo			    __func__);
1386203945Sweongyo			return (ENOBUFS);
1387203945Sweongyo		}
1388203945Sweongyo		if (m_new->m_next != NULL)
1389203945Sweongyo			device_printf(sc->sc_dev,
1390203945Sweongyo			    "TODO: fragmented packets for PIO\n");
1391203945Sweongyo		tp->tp_m = m_new;
1392203945Sweongyo
1393203945Sweongyo		/* send HEADER */
1394203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq,
1395203945Sweongyo		    (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
1396203945Sweongyo			BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
1397203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1398203945Sweongyo		/* send BODY */
1399203945Sweongyo		ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
1400203945Sweongyo		    mtod(m_new, const void *), m_new->m_pkthdr.len);
1401203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
1402203945Sweongyo		    ctl32 | BWN_PIO8_TXCTL_EOF);
1403203945Sweongyo	} else {
1404203945Sweongyo		ctl16 = bwn_pio_write_multi_2(mac, tq,
1405203945Sweongyo		    (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
1406203945Sweongyo			BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
1407203945Sweongyo		    (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
1408203945Sweongyo		ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
1409203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
1410203945Sweongyo		    ctl16 | BWN_PIO_TXCTL_EOF);
1411203945Sweongyo	}
1412203945Sweongyo
1413203945Sweongyo	return (0);
1414203945Sweongyo}
1415203945Sweongyo
1416203945Sweongyostatic struct bwn_pio_txqueue *
1417203945Sweongyobwn_pio_select(struct bwn_mac *mac, uint8_t prio)
1418203945Sweongyo{
1419203945Sweongyo
1420203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
1421203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1422203945Sweongyo
1423203945Sweongyo	switch (prio) {
1424203945Sweongyo	case 0:
1425203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BE]);
1426203945Sweongyo	case 1:
1427203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_BK]);
1428203945Sweongyo	case 2:
1429203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VI]);
1430203945Sweongyo	case 3:
1431203945Sweongyo		return (&mac->mac_method.pio.wme[WME_AC_VO]);
1432203945Sweongyo	}
1433203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
1434204242Simp	return (NULL);
1435203945Sweongyo}
1436203945Sweongyo
1437203945Sweongyostatic int
1438203945Sweongyobwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
1439203945Sweongyo{
1440203945Sweongyo#define	BWN_GET_TXHDRCACHE(slot)					\
1441203945Sweongyo	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
1442203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
1443203945Sweongyo	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
1444203945Sweongyo	struct bwn_dmadesc_generic *desc;
1445203945Sweongyo	struct bwn_dmadesc_meta *mt;
1446203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1447203945Sweongyo	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
1448203945Sweongyo	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
1449203945Sweongyo
1450203945Sweongyo	BWN_ASSERT_LOCKED(sc);
1451203945Sweongyo	KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
1452203945Sweongyo
1453203945Sweongyo	/* XXX send after DTIM */
1454203945Sweongyo
1455203945Sweongyo	slot = bwn_dma_getslot(dr);
1456203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1457203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
1458203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
1459203945Sweongyo
1460203945Sweongyo	error = bwn_set_txhdr(dr->dr_mac, ni, m,
1461203945Sweongyo	    (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
1462203945Sweongyo	    BWN_DMA_COOKIE(dr, slot));
1463203945Sweongyo	if (error)
1464203945Sweongyo		goto fail;
1465203945Sweongyo	error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
1466203945Sweongyo	    BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
1467203945Sweongyo	    &mt->mt_paddr, BUS_DMA_NOWAIT);
1468203945Sweongyo	if (error) {
1469287197Sglebius		device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n",
1470203945Sweongyo		    __func__, error);
1471203945Sweongyo		goto fail;
1472203945Sweongyo	}
1473203945Sweongyo	bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
1474203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1475203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
1476203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1477203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1478203945Sweongyo
1479203945Sweongyo	slot = bwn_dma_getslot(dr);
1480203945Sweongyo	dr->getdesc(dr, slot, &desc, &mt);
1481203945Sweongyo	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
1482203945Sweongyo	    mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
1483203945Sweongyo	mt->mt_m = m;
1484203945Sweongyo	mt->mt_ni = ni;
1485203945Sweongyo
1486203945Sweongyo	error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
1487203945Sweongyo	    bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1488203945Sweongyo	if (error && error != EFBIG) {
1489287197Sglebius		device_printf(sc->sc_dev, "%s: can't load TX buffer (1) %d\n",
1490203945Sweongyo		    __func__, error);
1491203945Sweongyo		goto fail;
1492203945Sweongyo	}
1493203945Sweongyo	if (error) {    /* error == EFBIG */
1494203945Sweongyo		struct mbuf *m_new;
1495203945Sweongyo
1496243857Sglebius		m_new = m_defrag(m, M_NOWAIT);
1497203945Sweongyo		if (m_new == NULL) {
1498287197Sglebius			device_printf(sc->sc_dev,
1499287197Sglebius			    "%s: can't defrag TX buffer\n",
1500203945Sweongyo			    __func__);
1501203945Sweongyo			error = ENOBUFS;
1502203945Sweongyo			goto fail;
1503203945Sweongyo		} else {
1504203945Sweongyo			m = m_new;
1505203945Sweongyo		}
1506203945Sweongyo
1507203945Sweongyo		mt->mt_m = m;
1508203945Sweongyo		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
1509203945Sweongyo		    m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
1510203945Sweongyo		if (error) {
1511287197Sglebius			device_printf(sc->sc_dev,
1512287197Sglebius			    "%s: can't load TX buffer (2) %d\n",
1513203945Sweongyo			    __func__, error);
1514203945Sweongyo			goto fail;
1515203945Sweongyo		}
1516203945Sweongyo	}
1517203945Sweongyo	bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
1518203945Sweongyo	dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
1519203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
1520203945Sweongyo	    BUS_DMASYNC_PREWRITE);
1521203945Sweongyo
1522203945Sweongyo	/* XXX send after DTIM */
1523203945Sweongyo
1524203945Sweongyo	dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
1525203945Sweongyo	return (0);
1526203945Sweongyofail:
1527203945Sweongyo	dr->dr_curslot = backup[0];
1528203945Sweongyo	dr->dr_usedslot = backup[1];
1529203945Sweongyo	return (error);
1530203945Sweongyo#undef BWN_GET_TXHDRCACHE
1531203945Sweongyo}
1532203945Sweongyo
1533203945Sweongyostatic void
1534203945Sweongyobwn_watchdog(void *arg)
1535203945Sweongyo{
1536203945Sweongyo	struct bwn_softc *sc = arg;
1537203945Sweongyo
1538203945Sweongyo	if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
1539287197Sglebius		device_printf(sc->sc_dev, "device timeout\n");
1540287197Sglebius		counter_u64_add(sc->sc_ic.ic_oerrors, 1);
1541203945Sweongyo	}
1542203945Sweongyo	callout_schedule(&sc->sc_watchdog_ch, hz);
1543203945Sweongyo}
1544203945Sweongyo
1545203945Sweongyostatic int
1546203945Sweongyobwn_attach_core(struct bwn_mac *mac)
1547203945Sweongyo{
1548203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1549203945Sweongyo	int error, have_bg = 0, have_a = 0;
1550203945Sweongyo	uint32_t high;
1551203945Sweongyo
1552204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5,
1553204922Sweongyo	    ("unsupported revision %d", siba_get_revid(sc->sc_dev)));
1554203945Sweongyo
1555204922Sweongyo	siba_powerup(sc->sc_dev, 0);
1556203945Sweongyo
1557204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
1558203945Sweongyo	bwn_reset_core(mac,
1559203945Sweongyo	    (high & BWN_TGSHIGH_HAVE_2GHZ) ? BWN_TGSLOW_SUPPORT_G : 0);
1560203945Sweongyo	error = bwn_phy_getinfo(mac, high);
1561203945Sweongyo	if (error)
1562203945Sweongyo		goto fail;
1563203945Sweongyo
1564203945Sweongyo	have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
1565203945Sweongyo	have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1566204922Sweongyo	if (siba_get_pci_device(sc->sc_dev) != 0x4312 &&
1567204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4319 &&
1568204922Sweongyo	    siba_get_pci_device(sc->sc_dev) != 0x4324) {
1569203945Sweongyo		have_a = have_bg = 0;
1570203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
1571203945Sweongyo			have_a = 1;
1572203945Sweongyo		else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
1573203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_N ||
1574203945Sweongyo		    mac->mac_phy.type == BWN_PHYTYPE_LP)
1575203945Sweongyo			have_bg = 1;
1576203945Sweongyo		else
1577203945Sweongyo			KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
1578203945Sweongyo			    mac->mac_phy.type));
1579203945Sweongyo	}
1580203945Sweongyo	/* XXX turns off PHY A because it's not supported */
1581203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
1582203945Sweongyo	    mac->mac_phy.type != BWN_PHYTYPE_N) {
1583203945Sweongyo		have_a = 0;
1584203945Sweongyo		have_bg = 1;
1585203945Sweongyo	}
1586203945Sweongyo
1587203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
1588203945Sweongyo		mac->mac_phy.attach = bwn_phy_g_attach;
1589203945Sweongyo		mac->mac_phy.detach = bwn_phy_g_detach;
1590203945Sweongyo		mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
1591203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_g_init_pre;
1592203945Sweongyo		mac->mac_phy.init = bwn_phy_g_init;
1593203945Sweongyo		mac->mac_phy.exit = bwn_phy_g_exit;
1594203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_g_read;
1595203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_g_write;
1596203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_g_rf_read;
1597203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_g_rf_write;
1598203945Sweongyo		mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
1599203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
1600203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_switch_analog;
1601203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
1602203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
1603203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
1604203945Sweongyo		mac->mac_phy.set_im = bwn_phy_g_im;
1605203945Sweongyo		mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
1606203945Sweongyo		mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
1607203945Sweongyo		mac->mac_phy.task_15s = bwn_phy_g_task_15s;
1608203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_g_task_60s;
1609203945Sweongyo	} else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
1610203945Sweongyo		mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
1611203945Sweongyo		mac->mac_phy.init = bwn_phy_lp_init;
1612203945Sweongyo		mac->mac_phy.phy_read = bwn_phy_lp_read;
1613203945Sweongyo		mac->mac_phy.phy_write = bwn_phy_lp_write;
1614203945Sweongyo		mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
1615203945Sweongyo		mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
1616203945Sweongyo		mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
1617203945Sweongyo		mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
1618203945Sweongyo		mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
1619203945Sweongyo		mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
1620203945Sweongyo		mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
1621203945Sweongyo		mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
1622203945Sweongyo		mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
1623203945Sweongyo	} else {
1624203945Sweongyo		device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
1625203945Sweongyo		    mac->mac_phy.type);
1626203945Sweongyo		error = ENXIO;
1627203945Sweongyo		goto fail;
1628203945Sweongyo	}
1629203945Sweongyo
1630203945Sweongyo	mac->mac_phy.gmode = have_bg;
1631203945Sweongyo	if (mac->mac_phy.attach != NULL) {
1632203945Sweongyo		error = mac->mac_phy.attach(mac);
1633203945Sweongyo		if (error) {
1634203945Sweongyo			device_printf(sc->sc_dev, "failed\n");
1635203945Sweongyo			goto fail;
1636203945Sweongyo		}
1637203945Sweongyo	}
1638203945Sweongyo
1639203945Sweongyo	bwn_reset_core(mac, have_bg ? BWN_TGSLOW_SUPPORT_G : 0);
1640203945Sweongyo
1641203945Sweongyo	error = bwn_chiptest(mac);
1642203945Sweongyo	if (error)
1643203945Sweongyo		goto fail;
1644203945Sweongyo	error = bwn_setup_channels(mac, have_bg, have_a);
1645203945Sweongyo	if (error) {
1646203945Sweongyo		device_printf(sc->sc_dev, "failed to setup channels\n");
1647203945Sweongyo		goto fail;
1648203945Sweongyo	}
1649203945Sweongyo
1650203945Sweongyo	if (sc->sc_curmac == NULL)
1651203945Sweongyo		sc->sc_curmac = mac;
1652203945Sweongyo
1653203945Sweongyo	error = bwn_dma_attach(mac);
1654203945Sweongyo	if (error != 0) {
1655203945Sweongyo		device_printf(sc->sc_dev, "failed to initialize DMA\n");
1656203945Sweongyo		goto fail;
1657203945Sweongyo	}
1658203945Sweongyo
1659203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
1660203945Sweongyo
1661204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
1662203945Sweongyofail:
1663204922Sweongyo	siba_powerdown(sc->sc_dev);
1664203945Sweongyo	return (error);
1665203945Sweongyo}
1666203945Sweongyo
1667203945Sweongyostatic void
1668203945Sweongyobwn_reset_core(struct bwn_mac *mac, uint32_t flags)
1669203945Sweongyo{
1670204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1671203945Sweongyo	uint32_t low, ctl;
1672203945Sweongyo
1673203945Sweongyo	flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
1674203945Sweongyo
1675204922Sweongyo	siba_dev_up(sc->sc_dev, flags);
1676203945Sweongyo	DELAY(2000);
1677203945Sweongyo
1678204922Sweongyo	low = (siba_read_4(sc->sc_dev, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
1679203945Sweongyo	    ~BWN_TGSLOW_PHYRESET;
1680204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low);
1681204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1682203945Sweongyo	DELAY(1000);
1683204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
1684204922Sweongyo	siba_read_4(sc->sc_dev, SIBA_TGSLOW);
1685203945Sweongyo	DELAY(1000);
1686203945Sweongyo
1687203945Sweongyo	if (mac->mac_phy.switch_analog != NULL)
1688203945Sweongyo		mac->mac_phy.switch_analog(mac, 1);
1689203945Sweongyo
1690203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
1691203945Sweongyo	if (flags & BWN_TGSLOW_SUPPORT_G)
1692203945Sweongyo		ctl |= BWN_MACCTL_GMODE;
1693203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
1694203945Sweongyo}
1695203945Sweongyo
1696203945Sweongyostatic int
1697203945Sweongyobwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
1698203945Sweongyo{
1699203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
1700203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1701203945Sweongyo	uint32_t tmp;
1702203945Sweongyo
1703203945Sweongyo	/* PHY */
1704203945Sweongyo	tmp = BWN_READ_2(mac, BWN_PHYVER);
1705203945Sweongyo	phy->gmode = (tgshigh & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
1706203945Sweongyo	phy->rf_on = 1;
1707203945Sweongyo	phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
1708203945Sweongyo	phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
1709203945Sweongyo	phy->rev = (tmp & BWN_PHYVER_VERSION);
1710203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
1711203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
1712203945Sweongyo		phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
1713203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
1714203945Sweongyo	    (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
1715203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
1716203945Sweongyo		goto unsupphy;
1717203945Sweongyo
1718203945Sweongyo	/* RADIO */
1719204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4317) {
1720204922Sweongyo		if (siba_get_chiprev(sc->sc_dev) == 0)
1721203945Sweongyo			tmp = 0x3205017f;
1722204922Sweongyo		else if (siba_get_chiprev(sc->sc_dev) == 1)
1723203945Sweongyo			tmp = 0x4205017f;
1724203945Sweongyo		else
1725203945Sweongyo			tmp = 0x5205017f;
1726203945Sweongyo	} else {
1727203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1728203945Sweongyo		tmp = BWN_READ_2(mac, BWN_RFDATALO);
1729203945Sweongyo		BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
1730203945Sweongyo		tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
1731203945Sweongyo	}
1732203945Sweongyo	phy->rf_rev = (tmp & 0xf0000000) >> 28;
1733203945Sweongyo	phy->rf_ver = (tmp & 0x0ffff000) >> 12;
1734203945Sweongyo	phy->rf_manuf = (tmp & 0x00000fff);
1735203945Sweongyo	if (phy->rf_manuf != 0x17f)	/* 0x17f is broadcom */
1736203945Sweongyo		goto unsupradio;
1737203945Sweongyo	if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
1738203945Sweongyo	     phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
1739203945Sweongyo	    (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
1740203945Sweongyo	    (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
1741203945Sweongyo	    (phy->type == BWN_PHYTYPE_N &&
1742203945Sweongyo	     phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
1743203945Sweongyo	    (phy->type == BWN_PHYTYPE_LP &&
1744203945Sweongyo	     phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
1745203945Sweongyo		goto unsupradio;
1746203945Sweongyo
1747203945Sweongyo	return (0);
1748203945Sweongyounsupphy:
1749203945Sweongyo	device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
1750203945Sweongyo	    "analog %#x)\n",
1751203945Sweongyo	    phy->type, phy->rev, phy->analog);
1752203945Sweongyo	return (ENXIO);
1753203945Sweongyounsupradio:
1754203945Sweongyo	device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
1755203945Sweongyo	    "rev %#x)\n",
1756203945Sweongyo	    phy->rf_manuf, phy->rf_ver, phy->rf_rev);
1757203945Sweongyo	return (ENXIO);
1758203945Sweongyo}
1759203945Sweongyo
1760203945Sweongyostatic int
1761203945Sweongyobwn_chiptest(struct bwn_mac *mac)
1762203945Sweongyo{
1763203945Sweongyo#define	TESTVAL0	0x55aaaa55
1764203945Sweongyo#define	TESTVAL1	0xaa5555aa
1765203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1766203945Sweongyo	uint32_t v, backup;
1767203945Sweongyo
1768203945Sweongyo	BWN_LOCK(sc);
1769203945Sweongyo
1770203945Sweongyo	backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
1771203945Sweongyo
1772203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
1773203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
1774203945Sweongyo		goto error;
1775203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
1776203945Sweongyo	if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
1777203945Sweongyo		goto error;
1778203945Sweongyo
1779203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
1780203945Sweongyo
1781204922Sweongyo	if ((siba_get_revid(sc->sc_dev) >= 3) &&
1782204922Sweongyo	    (siba_get_revid(sc->sc_dev) <= 10)) {
1783203945Sweongyo		BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
1784203945Sweongyo		BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
1785203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
1786203945Sweongyo			goto error;
1787203945Sweongyo		if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
1788203945Sweongyo			goto error;
1789203945Sweongyo	}
1790203945Sweongyo	BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
1791203945Sweongyo
1792203945Sweongyo	v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
1793203945Sweongyo	if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
1794203945Sweongyo		goto error;
1795203945Sweongyo
1796203945Sweongyo	BWN_UNLOCK(sc);
1797203945Sweongyo	return (0);
1798203945Sweongyoerror:
1799203945Sweongyo	BWN_UNLOCK(sc);
1800203945Sweongyo	device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
1801203945Sweongyo	return (ENODEV);
1802203945Sweongyo}
1803203945Sweongyo
1804203945Sweongyo#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
1805203945Sweongyo#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
1806203945Sweongyo
1807203945Sweongyostatic int
1808203945Sweongyobwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
1809203945Sweongyo{
1810203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
1811287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1812203945Sweongyo
1813203945Sweongyo	memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
1814203945Sweongyo	ic->ic_nchans = 0;
1815203945Sweongyo
1816203945Sweongyo	if (have_bg)
1817203945Sweongyo		bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1818203945Sweongyo		    &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
1819203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_N) {
1820203945Sweongyo		if (have_a)
1821203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1822203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_n,
1823203945Sweongyo			    IEEE80211_CHAN_HTA);
1824203945Sweongyo	} else {
1825203945Sweongyo		if (have_a)
1826203945Sweongyo			bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
1827203945Sweongyo			    &ic->ic_nchans, &bwn_chantable_a,
1828203945Sweongyo			    IEEE80211_CHAN_A);
1829203945Sweongyo	}
1830203945Sweongyo
1831203945Sweongyo	mac->mac_phy.supports_2ghz = have_bg;
1832203945Sweongyo	mac->mac_phy.supports_5ghz = have_a;
1833203945Sweongyo
1834203945Sweongyo	return (ic->ic_nchans == 0 ? ENXIO : 0);
1835203945Sweongyo}
1836203945Sweongyo
1837203945Sweongyostatic uint32_t
1838203945Sweongyobwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1839203945Sweongyo{
1840203945Sweongyo	uint32_t ret;
1841203945Sweongyo
1842204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1843203945Sweongyo
1844203945Sweongyo	if (way == BWN_SHARED) {
1845203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1846203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1847203945Sweongyo		if (offset & 0x0003) {
1848203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1849203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1850203945Sweongyo			ret <<= 16;
1851203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1852203945Sweongyo			ret |= BWN_READ_2(mac, BWN_SHM_DATA);
1853203945Sweongyo			goto out;
1854203945Sweongyo		}
1855203945Sweongyo		offset >>= 2;
1856203945Sweongyo	}
1857203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1858203945Sweongyo	ret = BWN_READ_4(mac, BWN_SHM_DATA);
1859203945Sweongyoout:
1860203945Sweongyo	return (ret);
1861203945Sweongyo}
1862203945Sweongyo
1863203945Sweongyostatic uint16_t
1864203945Sweongyobwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
1865203945Sweongyo{
1866203945Sweongyo	uint16_t ret;
1867203945Sweongyo
1868204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1869203945Sweongyo
1870203945Sweongyo	if (way == BWN_SHARED) {
1871203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1872203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1873203945Sweongyo		if (offset & 0x0003) {
1874203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1875203945Sweongyo			ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
1876203945Sweongyo			goto out;
1877203945Sweongyo		}
1878203945Sweongyo		offset >>= 2;
1879203945Sweongyo	}
1880203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1881203945Sweongyo	ret = BWN_READ_2(mac, BWN_SHM_DATA);
1882203945Sweongyoout:
1883203945Sweongyo
1884203945Sweongyo	return (ret);
1885203945Sweongyo}
1886203945Sweongyo
1887203945Sweongyostatic void
1888203945Sweongyobwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
1889203945Sweongyo    uint16_t offset)
1890203945Sweongyo{
1891203945Sweongyo	uint32_t control;
1892203945Sweongyo
1893203945Sweongyo	control = way;
1894203945Sweongyo	control <<= 16;
1895203945Sweongyo	control |= offset;
1896203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
1897203945Sweongyo}
1898203945Sweongyo
1899203945Sweongyostatic void
1900203945Sweongyobwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1901203945Sweongyo    uint32_t value)
1902203945Sweongyo{
1903204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1904203945Sweongyo
1905203945Sweongyo	if (way == BWN_SHARED) {
1906203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1907203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1908203945Sweongyo		if (offset & 0x0003) {
1909203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1910203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
1911203945Sweongyo				    (value >> 16) & 0xffff);
1912203945Sweongyo			bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
1913203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
1914203945Sweongyo			return;
1915203945Sweongyo		}
1916203945Sweongyo		offset >>= 2;
1917203945Sweongyo	}
1918203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1919203945Sweongyo	BWN_WRITE_4(mac, BWN_SHM_DATA, value);
1920203945Sweongyo}
1921203945Sweongyo
1922203945Sweongyostatic void
1923203945Sweongyobwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
1924203945Sweongyo    uint16_t value)
1925203945Sweongyo{
1926204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
1927203945Sweongyo
1928203945Sweongyo	if (way == BWN_SHARED) {
1929203945Sweongyo		KASSERT((offset & 0x0001) == 0,
1930203945Sweongyo		    ("%s:%d warn", __func__, __LINE__));
1931203945Sweongyo		if (offset & 0x0003) {
1932203945Sweongyo			bwn_shm_ctlword(mac, way, offset >> 2);
1933203945Sweongyo			BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
1934203945Sweongyo			return;
1935203945Sweongyo		}
1936203945Sweongyo		offset >>= 2;
1937203945Sweongyo	}
1938203945Sweongyo	bwn_shm_ctlword(mac, way, offset);
1939203945Sweongyo	BWN_WRITE_2(mac, BWN_SHM_DATA, value);
1940203945Sweongyo}
1941203945Sweongyo
1942203945Sweongyostatic void
1943203945Sweongyobwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
1944203945Sweongyo    int txpow)
1945203945Sweongyo{
1946203945Sweongyo
1947203945Sweongyo	c->ic_freq = freq;
1948203945Sweongyo	c->ic_flags = flags;
1949203945Sweongyo	c->ic_ieee = ieee;
1950203945Sweongyo	c->ic_minpower = 0;
1951203945Sweongyo	c->ic_maxpower = 2 * txpow;
1952203945Sweongyo	c->ic_maxregpower = txpow;
1953203945Sweongyo}
1954203945Sweongyo
1955203945Sweongyostatic void
1956203945Sweongyobwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
1957203945Sweongyo    const struct bwn_channelinfo *ci, int flags)
1958203945Sweongyo{
1959203945Sweongyo	struct ieee80211_channel *c;
1960203945Sweongyo	int i;
1961203945Sweongyo
1962203945Sweongyo	c = &chans[*nchans];
1963203945Sweongyo
1964203945Sweongyo	for (i = 0; i < ci->nchannels; i++) {
1965203945Sweongyo		const struct bwn_channel *hc;
1966203945Sweongyo
1967203945Sweongyo		hc = &ci->channels[i];
1968203945Sweongyo		if (*nchans >= maxchans)
1969203945Sweongyo			break;
1970203945Sweongyo		bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
1971203945Sweongyo		c++, (*nchans)++;
1972203945Sweongyo		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
1973203945Sweongyo			/* g channel have a separate b-only entry */
1974203945Sweongyo			if (*nchans >= maxchans)
1975203945Sweongyo				break;
1976203945Sweongyo			c[0] = c[-1];
1977203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_B;
1978203945Sweongyo			c++, (*nchans)++;
1979203945Sweongyo		}
1980203945Sweongyo		if (flags == IEEE80211_CHAN_HTG) {
1981203945Sweongyo			/* HT g channel have a separate g-only entry */
1982203945Sweongyo			if (*nchans >= maxchans)
1983203945Sweongyo				break;
1984203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_G;
1985203945Sweongyo			c[0] = c[-1];
1986203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1987203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
1988203945Sweongyo			c++, (*nchans)++;
1989203945Sweongyo		}
1990203945Sweongyo		if (flags == IEEE80211_CHAN_HTA) {
1991203945Sweongyo			/* HT a channel have a separate a-only entry */
1992203945Sweongyo			if (*nchans >= maxchans)
1993203945Sweongyo				break;
1994203945Sweongyo			c[-1].ic_flags = IEEE80211_CHAN_A;
1995203945Sweongyo			c[0] = c[-1];
1996203945Sweongyo			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1997203945Sweongyo			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
1998203945Sweongyo			c++, (*nchans)++;
1999203945Sweongyo		}
2000203945Sweongyo	}
2001203945Sweongyo}
2002203945Sweongyo
2003203945Sweongyostatic int
2004203945Sweongyobwn_phy_g_attach(struct bwn_mac *mac)
2005203945Sweongyo{
2006203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2007203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2008203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2009203945Sweongyo	unsigned int i;
2010204922Sweongyo	int16_t pab0, pab1, pab2;
2011203945Sweongyo	static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
2012204922Sweongyo	int8_t bg;
2013203945Sweongyo
2014204922Sweongyo	bg = (int8_t)siba_sprom_get_tssi_bg(sc->sc_dev);
2015204922Sweongyo	pab0 = (int16_t)siba_sprom_get_pa0b0(sc->sc_dev);
2016204922Sweongyo	pab1 = (int16_t)siba_sprom_get_pa0b1(sc->sc_dev);
2017204922Sweongyo	pab2 = (int16_t)siba_sprom_get_pa0b2(sc->sc_dev);
2018204922Sweongyo
2019204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4301) && (phy->rf_ver != 0x2050))
2020203945Sweongyo		device_printf(sc->sc_dev, "not supported anymore\n");
2021203945Sweongyo
2022203945Sweongyo	pg->pg_flags = 0;
2023203945Sweongyo	if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
2024203945Sweongyo	    pab2 == -1) {
2025203945Sweongyo		pg->pg_idletssi = 52;
2026203945Sweongyo		pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
2027203945Sweongyo		return (0);
2028203945Sweongyo	}
2029203945Sweongyo
2030203945Sweongyo	pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
2031203945Sweongyo	pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
2032203945Sweongyo	if (pg->pg_tssi2dbm == NULL) {
2033203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer\n");
2034203945Sweongyo		return (ENOMEM);
2035203945Sweongyo	}
2036203945Sweongyo	for (i = 0; i < 64; i++) {
2037203945Sweongyo		int32_t m1, m2, f, q, delta;
2038203945Sweongyo		int8_t j = 0;
2039203945Sweongyo
2040203945Sweongyo		m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
2041203945Sweongyo		m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
2042203945Sweongyo		f = 256;
2043203945Sweongyo
2044203945Sweongyo		do {
2045203945Sweongyo			if (j > 15) {
2046203945Sweongyo				device_printf(sc->sc_dev,
2047203945Sweongyo				    "failed to generate tssi2dBm\n");
2048203945Sweongyo				free(pg->pg_tssi2dbm, M_DEVBUF);
2049203945Sweongyo				return (ENOMEM);
2050203945Sweongyo			}
2051203945Sweongyo			q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
2052203945Sweongyo			    f, 2048);
2053203945Sweongyo			delta = abs(q - f);
2054203945Sweongyo			f = q;
2055203945Sweongyo			j++;
2056203945Sweongyo		} while (delta >= 2);
2057203945Sweongyo
2058203945Sweongyo		pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
2059203945Sweongyo		    128);
2060203945Sweongyo	}
2061203945Sweongyo
2062203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
2063203945Sweongyo	return (0);
2064203945Sweongyo}
2065203945Sweongyo
2066203945Sweongyostatic void
2067203945Sweongyobwn_phy_g_detach(struct bwn_mac *mac)
2068203945Sweongyo{
2069203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
2070203945Sweongyo
2071203945Sweongyo	if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
2072203945Sweongyo		free(pg->pg_tssi2dbm, M_DEVBUF);
2073203945Sweongyo		pg->pg_tssi2dbm = NULL;
2074203945Sweongyo	}
2075203945Sweongyo	pg->pg_flags = 0;
2076203945Sweongyo}
2077203945Sweongyo
2078203945Sweongyostatic void
2079203945Sweongyobwn_phy_g_init_pre(struct bwn_mac *mac)
2080203945Sweongyo{
2081203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2082203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2083203945Sweongyo	void *tssi2dbm;
2084203945Sweongyo	int idletssi;
2085203945Sweongyo	unsigned int i;
2086203945Sweongyo
2087203945Sweongyo	tssi2dbm = pg->pg_tssi2dbm;
2088203945Sweongyo	idletssi = pg->pg_idletssi;
2089203945Sweongyo
2090203945Sweongyo	memset(pg, 0, sizeof(*pg));
2091203945Sweongyo
2092203945Sweongyo	pg->pg_tssi2dbm = tssi2dbm;
2093203945Sweongyo	pg->pg_idletssi = idletssi;
2094203945Sweongyo
2095203945Sweongyo	memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
2096203945Sweongyo
2097203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi); i++)
2098203945Sweongyo		pg->pg_nrssi[i] = -1000;
2099203945Sweongyo	for (i = 0; i < N(pg->pg_nrssi_lt); i++)
2100203945Sweongyo		pg->pg_nrssi_lt[i] = i;
2101203945Sweongyo	pg->pg_lofcal = 0xffff;
2102203945Sweongyo	pg->pg_initval = 0xffff;
2103203945Sweongyo	pg->pg_immode = BWN_IMMODE_NONE;
2104203945Sweongyo	pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
2105203945Sweongyo	pg->pg_avgtssi = 0xff;
2106203945Sweongyo
2107203945Sweongyo	pg->pg_loctl.tx_bias = 0xff;
2108203945Sweongyo	TAILQ_INIT(&pg->pg_loctl.calib_list);
2109203945Sweongyo}
2110203945Sweongyo
2111203945Sweongyostatic int
2112203945Sweongyobwn_phy_g_prepare_hw(struct bwn_mac *mac)
2113203945Sweongyo{
2114203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2115203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2116204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2117203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2118203945Sweongyo	static const struct bwn_rfatt rfatt0[] = {
2119203945Sweongyo		{ 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 },	{ 9, 0 }, { 2, 0 },
2120203945Sweongyo		{ 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
2121203945Sweongyo		{ 3, 1 }, { 4, 1 }
2122203945Sweongyo	};
2123203945Sweongyo	static const struct bwn_rfatt rfatt1[] = {
2124203945Sweongyo		{ 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
2125203945Sweongyo		{ 14, 1 }
2126203945Sweongyo	};
2127203945Sweongyo	static const struct bwn_rfatt rfatt2[] = {
2128203945Sweongyo		{ 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
2129203945Sweongyo		{ 9, 1 }
2130203945Sweongyo	};
2131203945Sweongyo	static const struct bwn_bbatt bbatt_0[] = {
2132203945Sweongyo		{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
2133203945Sweongyo	};
2134203945Sweongyo
2135203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
2136203945Sweongyo
2137203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
2138203945Sweongyo		pg->pg_bbatt.att = 0;
2139203945Sweongyo	else
2140203945Sweongyo		pg->pg_bbatt.att = 2;
2141203945Sweongyo
2142203945Sweongyo	/* prepare Radio Attenuation */
2143203945Sweongyo	pg->pg_rfatt.padmix = 0;
2144203945Sweongyo
2145204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
2146204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BCM4309G) {
2147204922Sweongyo		if (siba_get_pci_revid(sc->sc_dev) < 0x43) {
2148203945Sweongyo			pg->pg_rfatt.att = 2;
2149203945Sweongyo			goto done;
2150204922Sweongyo		} else if (siba_get_pci_revid(sc->sc_dev) < 0x51) {
2151203945Sweongyo			pg->pg_rfatt.att = 3;
2152203945Sweongyo			goto done;
2153203945Sweongyo		}
2154203945Sweongyo	}
2155203945Sweongyo
2156203945Sweongyo	if (phy->type == BWN_PHYTYPE_A) {
2157203945Sweongyo		pg->pg_rfatt.att = 0x60;
2158203945Sweongyo		goto done;
2159203945Sweongyo	}
2160203945Sweongyo
2161203945Sweongyo	switch (phy->rf_ver) {
2162203945Sweongyo	case 0x2050:
2163203945Sweongyo		switch (phy->rf_rev) {
2164203945Sweongyo		case 0:
2165203945Sweongyo			pg->pg_rfatt.att = 5;
2166203945Sweongyo			goto done;
2167203945Sweongyo		case 1:
2168203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2169204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2170203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2171204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2172203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2173204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2174203945Sweongyo					pg->pg_rfatt.att = 3;
2175204922Sweongyo				else if (siba_get_pci_subvendor(sc->sc_dev) ==
2176203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2177204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2178204922Sweongyo				    SIBA_BOARD_BU4306)
2179203945Sweongyo					pg->pg_rfatt.att = 3;
2180203945Sweongyo				else
2181203945Sweongyo					pg->pg_rfatt.att = 1;
2182203945Sweongyo			} else {
2183204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2184203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2185204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2186203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2187204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2188203945Sweongyo					pg->pg_rfatt.att = 7;
2189203945Sweongyo				else
2190203945Sweongyo					pg->pg_rfatt.att = 6;
2191203945Sweongyo			}
2192203945Sweongyo			goto done;
2193203945Sweongyo		case 2:
2194203945Sweongyo			if (phy->type == BWN_PHYTYPE_G) {
2195204922Sweongyo				if (siba_get_pci_subvendor(sc->sc_dev) ==
2196203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2197204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2198203945Sweongyo				    SIBA_BOARD_BCM4309G &&
2199204922Sweongyo				    siba_get_pci_revid(sc->sc_dev) >= 30)
2200203945Sweongyo					pg->pg_rfatt.att = 3;
2201204922Sweongyo				else if (siba_get_pci_subvendor(sc->sc_dev) ==
2202203945Sweongyo				    SIBA_BOARDVENDOR_BCM &&
2203204922Sweongyo				    siba_get_pci_subdevice(sc->sc_dev) ==
2204204922Sweongyo				    SIBA_BOARD_BU4306)
2205203945Sweongyo					pg->pg_rfatt.att = 5;
2206204922Sweongyo				else if (siba_get_chipid(sc->sc_dev) == 0x4320)
2207203945Sweongyo					pg->pg_rfatt.att = 4;
2208203945Sweongyo				else
2209203945Sweongyo					pg->pg_rfatt.att = 3;
2210203945Sweongyo			} else
2211203945Sweongyo				pg->pg_rfatt.att = 6;
2212203945Sweongyo			goto done;
2213203945Sweongyo		case 3:
2214203945Sweongyo			pg->pg_rfatt.att = 5;
2215203945Sweongyo			goto done;
2216203945Sweongyo		case 4:
2217203945Sweongyo		case 5:
2218203945Sweongyo			pg->pg_rfatt.att = 1;
2219203945Sweongyo			goto done;
2220203945Sweongyo		case 6:
2221203945Sweongyo		case 7:
2222203945Sweongyo			pg->pg_rfatt.att = 5;
2223203945Sweongyo			goto done;
2224203945Sweongyo		case 8:
2225203945Sweongyo			pg->pg_rfatt.att = 0xa;
2226203945Sweongyo			pg->pg_rfatt.padmix = 1;
2227203945Sweongyo			goto done;
2228203945Sweongyo		case 9:
2229203945Sweongyo		default:
2230203945Sweongyo			pg->pg_rfatt.att = 5;
2231203945Sweongyo			goto done;
2232203945Sweongyo		}
2233203945Sweongyo		break;
2234203945Sweongyo	case 0x2053:
2235203945Sweongyo		switch (phy->rf_rev) {
2236203945Sweongyo		case 1:
2237203945Sweongyo			pg->pg_rfatt.att = 6;
2238203945Sweongyo			goto done;
2239203945Sweongyo		}
2240203945Sweongyo		break;
2241203945Sweongyo	}
2242203945Sweongyo	pg->pg_rfatt.att = 5;
2243203945Sweongyodone:
2244203945Sweongyo	pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
2245203945Sweongyo
2246203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
2247203945Sweongyo		lo->rfatt.array = rfatt0;
2248203945Sweongyo		lo->rfatt.len = N(rfatt0);
2249203945Sweongyo		lo->rfatt.min = 0;
2250203945Sweongyo		lo->rfatt.max = 9;
2251203945Sweongyo		goto genbbatt;
2252203945Sweongyo	}
2253203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
2254203945Sweongyo		lo->rfatt.array = rfatt1;
2255203945Sweongyo		lo->rfatt.len = N(rfatt1);
2256203945Sweongyo		lo->rfatt.min = 0;
2257203945Sweongyo		lo->rfatt.max = 14;
2258203945Sweongyo		goto genbbatt;
2259203945Sweongyo	}
2260203945Sweongyo	lo->rfatt.array = rfatt2;
2261203945Sweongyo	lo->rfatt.len = N(rfatt2);
2262203945Sweongyo	lo->rfatt.min = 0;
2263203945Sweongyo	lo->rfatt.max = 9;
2264203945Sweongyogenbbatt:
2265203945Sweongyo	lo->bbatt.array = bbatt_0;
2266203945Sweongyo	lo->bbatt.len = N(bbatt_0);
2267203945Sweongyo	lo->bbatt.min = 0;
2268203945Sweongyo	lo->bbatt.max = 8;
2269203945Sweongyo
2270203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
2271203945Sweongyo	if (phy->rev == 1) {
2272203945Sweongyo		phy->gmode = 0;
2273203945Sweongyo		bwn_reset_core(mac, 0);
2274203945Sweongyo		bwn_phy_g_init_sub(mac);
2275203945Sweongyo		phy->gmode = 1;
2276203945Sweongyo		bwn_reset_core(mac, BWN_TGSLOW_SUPPORT_G);
2277203945Sweongyo	}
2278203945Sweongyo	return (0);
2279203945Sweongyo}
2280203945Sweongyo
2281203945Sweongyostatic uint16_t
2282203945Sweongyobwn_phy_g_txctl(struct bwn_mac *mac)
2283203945Sweongyo{
2284203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2285203945Sweongyo
2286203945Sweongyo	if (phy->rf_ver != 0x2050)
2287203945Sweongyo		return (0);
2288203945Sweongyo	if (phy->rf_rev == 1)
2289203945Sweongyo		return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
2290203945Sweongyo	if (phy->rf_rev < 6)
2291203945Sweongyo		return (BWN_TXCTL_PA2DB);
2292203945Sweongyo	if (phy->rf_rev == 8)
2293203945Sweongyo		return (BWN_TXCTL_TXMIX);
2294203945Sweongyo	return (0);
2295203945Sweongyo}
2296203945Sweongyo
2297203945Sweongyostatic int
2298203945Sweongyobwn_phy_g_init(struct bwn_mac *mac)
2299203945Sweongyo{
2300203945Sweongyo
2301203945Sweongyo	bwn_phy_g_init_sub(mac);
2302203945Sweongyo	return (0);
2303203945Sweongyo}
2304203945Sweongyo
2305203945Sweongyostatic void
2306203945Sweongyobwn_phy_g_exit(struct bwn_mac *mac)
2307203945Sweongyo{
2308203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
2309203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2310203945Sweongyo
2311203945Sweongyo	if (lo == NULL)
2312203945Sweongyo		return;
2313203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2314203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2315203945Sweongyo		free(cal, M_DEVBUF);
2316203945Sweongyo	}
2317203945Sweongyo}
2318203945Sweongyo
2319203945Sweongyostatic uint16_t
2320203945Sweongyobwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
2321203945Sweongyo{
2322203945Sweongyo
2323203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2324203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
2325203945Sweongyo}
2326203945Sweongyo
2327203945Sweongyostatic void
2328203945Sweongyobwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2329203945Sweongyo{
2330203945Sweongyo
2331203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
2332203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
2333203945Sweongyo}
2334203945Sweongyo
2335203945Sweongyostatic uint16_t
2336203945Sweongyobwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
2337203945Sweongyo{
2338203945Sweongyo
2339203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2340203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
2341203945Sweongyo	return (BWN_READ_2(mac, BWN_RFDATALO));
2342203945Sweongyo}
2343203945Sweongyo
2344203945Sweongyostatic void
2345203945Sweongyobwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
2346203945Sweongyo{
2347203945Sweongyo
2348203945Sweongyo	KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
2349203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
2350203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
2351203945Sweongyo}
2352203945Sweongyo
2353203945Sweongyostatic int
2354203945Sweongyobwn_phy_g_hwpctl(struct bwn_mac *mac)
2355203945Sweongyo{
2356203945Sweongyo
2357203945Sweongyo	return (mac->mac_phy.rev >= 6);
2358203945Sweongyo}
2359203945Sweongyo
2360203945Sweongyostatic void
2361203945Sweongyobwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
2362203945Sweongyo{
2363203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2364203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2365203945Sweongyo	unsigned int channel;
2366203945Sweongyo	uint16_t rfover, rfoverval;
2367203945Sweongyo
2368203945Sweongyo	if (on) {
2369203945Sweongyo		if (phy->rf_on)
2370203945Sweongyo			return;
2371203945Sweongyo
2372203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0x8000);
2373203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, 0xcc00);
2374203945Sweongyo		BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
2375203945Sweongyo		if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
2376203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
2377203945Sweongyo			    pg->pg_radioctx_over);
2378203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
2379203945Sweongyo			    pg->pg_radioctx_overval);
2380203945Sweongyo			pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
2381203945Sweongyo		}
2382203945Sweongyo		channel = phy->chan;
2383203945Sweongyo		bwn_phy_g_switch_chan(mac, 6, 1);
2384203945Sweongyo		bwn_phy_g_switch_chan(mac, channel, 0);
2385203945Sweongyo		return;
2386203945Sweongyo	}
2387203945Sweongyo
2388203945Sweongyo	rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
2389203945Sweongyo	rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
2390203945Sweongyo	pg->pg_radioctx_over = rfover;
2391203945Sweongyo	pg->pg_radioctx_overval = rfoverval;
2392203945Sweongyo	pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
2393203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
2394203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
2395203945Sweongyo}
2396203945Sweongyo
2397203945Sweongyostatic int
2398203945Sweongyobwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
2399203945Sweongyo{
2400203945Sweongyo
2401203945Sweongyo	if ((newchan < 1) || (newchan > 14))
2402203945Sweongyo		return (EINVAL);
2403203945Sweongyo	bwn_phy_g_switch_chan(mac, newchan, 0);
2404203945Sweongyo
2405203945Sweongyo	return (0);
2406203945Sweongyo}
2407203945Sweongyo
2408203945Sweongyostatic uint32_t
2409203945Sweongyobwn_phy_g_get_default_chan(struct bwn_mac *mac)
2410203945Sweongyo{
2411203945Sweongyo
2412203945Sweongyo	return (1);
2413203945Sweongyo}
2414203945Sweongyo
2415203945Sweongyostatic void
2416203945Sweongyobwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
2417203945Sweongyo{
2418203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2419203945Sweongyo	uint64_t hf;
2420203945Sweongyo	int autodiv = 0;
2421203945Sweongyo	uint16_t tmp;
2422203945Sweongyo
2423203945Sweongyo	if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
2424203945Sweongyo		autodiv = 1;
2425203945Sweongyo
2426203945Sweongyo	hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
2427203945Sweongyo	bwn_hf_write(mac, hf);
2428203945Sweongyo
2429203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
2430203945Sweongyo	    (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
2431203945Sweongyo	    ((autodiv ? BWN_ANTAUTO1 : antenna)
2432203945Sweongyo		<< BWN_PHY_BBANDCFG_RXANT_SHIFT));
2433203945Sweongyo
2434203945Sweongyo	if (autodiv) {
2435203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
2436203945Sweongyo		if (antenna == BWN_ANTAUTO1)
2437203945Sweongyo			tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
2438203945Sweongyo		else
2439203945Sweongyo			tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
2440203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
2441203945Sweongyo	}
2442203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
2443203945Sweongyo	if (autodiv)
2444203945Sweongyo		tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
2445203945Sweongyo	else
2446203945Sweongyo		tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
2447203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
2448203945Sweongyo	if (phy->rev >= 2) {
2449203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
2450203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
2451203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
2452203945Sweongyo		    (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
2453203945Sweongyo		    0x15);
2454203945Sweongyo		if (phy->rev == 2)
2455203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
2456203945Sweongyo		else
2457203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
2458203945Sweongyo			    (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
2459203945Sweongyo			    8);
2460203945Sweongyo	}
2461203945Sweongyo	if (phy->rev >= 6)
2462203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
2463203945Sweongyo
2464203945Sweongyo	hf |= BWN_HF_UCODE_ANTDIV_HELPER;
2465203945Sweongyo	bwn_hf_write(mac, hf);
2466203945Sweongyo}
2467203945Sweongyo
2468203945Sweongyostatic int
2469203945Sweongyobwn_phy_g_im(struct bwn_mac *mac, int mode)
2470203945Sweongyo{
2471203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2472203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2473203945Sweongyo
2474203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2475203945Sweongyo	KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
2476203945Sweongyo
2477203945Sweongyo	if (phy->rev == 0 || !phy->gmode)
2478203945Sweongyo		return (ENODEV);
2479203945Sweongyo
2480203945Sweongyo	pg->pg_aci_wlan_automatic = 0;
2481203945Sweongyo	return (0);
2482203945Sweongyo}
2483203945Sweongyo
2484203945Sweongyostatic int
2485203945Sweongyobwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
2486203945Sweongyo{
2487203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2488203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2489203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2490203945Sweongyo	unsigned int tssi;
2491203945Sweongyo	int cck, ofdm;
2492203945Sweongyo	int power;
2493203945Sweongyo	int rfatt, bbatt;
2494203945Sweongyo	unsigned int max;
2495203945Sweongyo
2496203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
2497203945Sweongyo
2498203945Sweongyo	cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
2499203945Sweongyo	ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
2500203945Sweongyo	if (cck < 0 && ofdm < 0) {
2501203945Sweongyo		if (ignore_tssi == 0)
2502203945Sweongyo			return (BWN_TXPWR_RES_DONE);
2503203945Sweongyo		cck = 0;
2504203945Sweongyo		ofdm = 0;
2505203945Sweongyo	}
2506203945Sweongyo	tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
2507203945Sweongyo	if (pg->pg_avgtssi != 0xff)
2508203945Sweongyo		tssi = (tssi + pg->pg_avgtssi) / 2;
2509203945Sweongyo	pg->pg_avgtssi = tssi;
2510203945Sweongyo	KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
2511203945Sweongyo
2512204922Sweongyo	max = siba_sprom_get_maxpwr_bg(sc->sc_dev);
2513204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
2514203945Sweongyo		max -= 3;
2515203945Sweongyo	if (max >= 120) {
2516203945Sweongyo		device_printf(sc->sc_dev, "invalid max TX-power value\n");
2517204922Sweongyo		max = 80;
2518204922Sweongyo		siba_sprom_set_maxpwr_bg(sc->sc_dev, max);
2519203945Sweongyo	}
2520203945Sweongyo
2521203945Sweongyo	power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
2522203945Sweongyo	    (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
2523203945Sweongyo	     tssi, 0x00), 0x3f)]);
2524203945Sweongyo	if (power == 0)
2525203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2526203945Sweongyo
2527203945Sweongyo	rfatt = -((power + 7) / 8);
2528203945Sweongyo	bbatt = (-(power / 2)) - (4 * rfatt);
2529203945Sweongyo	if ((rfatt == 0) && (bbatt == 0))
2530203945Sweongyo		return (BWN_TXPWR_RES_DONE);
2531203945Sweongyo	pg->pg_bbatt_delta = bbatt;
2532203945Sweongyo	pg->pg_rfatt_delta = rfatt;
2533203945Sweongyo	return (BWN_TXPWR_RES_NEED_ADJUST);
2534203945Sweongyo}
2535203945Sweongyo
2536203945Sweongyostatic void
2537203945Sweongyobwn_phy_g_set_txpwr(struct bwn_mac *mac)
2538203945Sweongyo{
2539203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2540203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2541203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2542203945Sweongyo	int rfatt, bbatt;
2543203945Sweongyo	uint8_t txctl;
2544203945Sweongyo
2545203945Sweongyo	bwn_mac_suspend(mac);
2546203945Sweongyo
2547203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2548203945Sweongyo
2549203945Sweongyo	bbatt = pg->pg_bbatt.att;
2550203945Sweongyo	bbatt += pg->pg_bbatt_delta;
2551203945Sweongyo	rfatt = pg->pg_rfatt.att;
2552203945Sweongyo	rfatt += pg->pg_rfatt_delta;
2553203945Sweongyo
2554203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2555203945Sweongyo	txctl = pg->pg_txctl;
2556203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
2557203945Sweongyo		if (rfatt <= 1) {
2558203945Sweongyo			if (txctl == 0) {
2559203945Sweongyo				txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
2560203945Sweongyo				rfatt += 2;
2561203945Sweongyo				bbatt += 2;
2562204922Sweongyo			} else if (siba_sprom_get_bf_lo(sc->sc_dev) &
2563204922Sweongyo			    BWN_BFL_PACTRL) {
2564203945Sweongyo				bbatt += 4 * (rfatt - 2);
2565203945Sweongyo				rfatt = 2;
2566203945Sweongyo			}
2567203945Sweongyo		} else if (rfatt > 4 && txctl) {
2568203945Sweongyo			txctl = 0;
2569203945Sweongyo			if (bbatt < 3) {
2570203945Sweongyo				rfatt -= 3;
2571203945Sweongyo				bbatt += 2;
2572203945Sweongyo			} else {
2573203945Sweongyo				rfatt -= 2;
2574203945Sweongyo				bbatt -= 2;
2575203945Sweongyo			}
2576203945Sweongyo		}
2577203945Sweongyo	}
2578203945Sweongyo	pg->pg_txctl = txctl;
2579203945Sweongyo	bwn_phy_g_setatt(mac, &bbatt, &rfatt);
2580203945Sweongyo	pg->pg_rfatt.att = rfatt;
2581203945Sweongyo	pg->pg_bbatt.att = bbatt;
2582203945Sweongyo
2583203945Sweongyo	DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
2584203945Sweongyo
2585203945Sweongyo	bwn_phy_lock(mac);
2586203945Sweongyo	bwn_rf_lock(mac);
2587203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
2588203945Sweongyo	    pg->pg_txctl);
2589203945Sweongyo	bwn_rf_unlock(mac);
2590203945Sweongyo	bwn_phy_unlock(mac);
2591203945Sweongyo
2592203945Sweongyo	bwn_mac_enable(mac);
2593203945Sweongyo}
2594203945Sweongyo
2595203945Sweongyostatic void
2596203945Sweongyobwn_phy_g_task_15s(struct bwn_mac *mac)
2597203945Sweongyo{
2598203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2599203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
2600203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2601203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
2602203945Sweongyo	unsigned long expire, now;
2603203945Sweongyo	struct bwn_lo_calib *cal, *tmp;
2604203945Sweongyo	uint8_t expired = 0;
2605203945Sweongyo
2606203945Sweongyo	bwn_mac_suspend(mac);
2607203945Sweongyo
2608203945Sweongyo	if (lo == NULL)
2609203945Sweongyo		goto fail;
2610203945Sweongyo
2611203945Sweongyo	BWN_GETTIME(now);
2612203945Sweongyo	if (bwn_has_hwpctl(mac)) {
2613203945Sweongyo		expire = now - BWN_LO_PWRVEC_EXPIRE;
2614203945Sweongyo		if (time_before(lo->pwr_vec_read_time, expire)) {
2615203945Sweongyo			bwn_lo_get_powervector(mac);
2616203945Sweongyo			bwn_phy_g_dc_lookup_init(mac, 0);
2617203945Sweongyo		}
2618203945Sweongyo		goto fail;
2619203945Sweongyo	}
2620203945Sweongyo
2621203945Sweongyo	expire = now - BWN_LO_CALIB_EXPIRE;
2622203945Sweongyo	TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
2623203945Sweongyo		if (!time_before(cal->calib_time, expire))
2624203945Sweongyo			continue;
2625203945Sweongyo		if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
2626203945Sweongyo		    BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
2627203945Sweongyo			KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
2628203945Sweongyo			expired = 1;
2629203945Sweongyo		}
2630203945Sweongyo
2631203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
2632203945Sweongyo		    cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
2633203945Sweongyo		    cal->ctl.i, cal->ctl.q);
2634203945Sweongyo
2635203945Sweongyo		TAILQ_REMOVE(&lo->calib_list, cal, list);
2636203945Sweongyo		free(cal, M_DEVBUF);
2637203945Sweongyo	}
2638203945Sweongyo	if (expired || TAILQ_EMPTY(&lo->calib_list)) {
2639203945Sweongyo		cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
2640203945Sweongyo		    &pg->pg_rfatt);
2641203945Sweongyo		if (cal == NULL) {
2642203945Sweongyo			device_printf(sc->sc_dev,
2643203945Sweongyo			    "failed to recalibrate LO\n");
2644203945Sweongyo			goto fail;
2645203945Sweongyo		}
2646203945Sweongyo		TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
2647203945Sweongyo		bwn_lo_write(mac, &cal->ctl);
2648203945Sweongyo	}
2649203945Sweongyo
2650203945Sweongyofail:
2651203945Sweongyo	bwn_mac_enable(mac);
2652203945Sweongyo}
2653203945Sweongyo
2654203945Sweongyostatic void
2655203945Sweongyobwn_phy_g_task_60s(struct bwn_mac *mac)
2656203945Sweongyo{
2657203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2658204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
2659203945Sweongyo	uint8_t old = phy->chan;
2660203945Sweongyo
2661204922Sweongyo	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI))
2662203945Sweongyo		return;
2663203945Sweongyo
2664203945Sweongyo	bwn_mac_suspend(mac);
2665203945Sweongyo	bwn_nrssi_slope_11g(mac);
2666203945Sweongyo	if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
2667203945Sweongyo		bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
2668203945Sweongyo		bwn_switch_channel(mac, old);
2669203945Sweongyo	}
2670203945Sweongyo	bwn_mac_enable(mac);
2671203945Sweongyo}
2672203945Sweongyo
2673203945Sweongyostatic void
2674203945Sweongyobwn_phy_switch_analog(struct bwn_mac *mac, int on)
2675203945Sweongyo{
2676203945Sweongyo
2677203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
2678203945Sweongyo}
2679203945Sweongyo
2680203945Sweongyostatic int
2681203945Sweongyobwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
2682203945Sweongyo	const struct ieee80211_bpf_params *params)
2683203945Sweongyo{
2684203945Sweongyo	struct ieee80211com *ic = ni->ni_ic;
2685286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
2686203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2687203945Sweongyo
2688287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0 ||
2689203945Sweongyo	    mac->mac_status < BWN_MAC_STATUS_STARTED) {
2690203945Sweongyo		ieee80211_free_node(ni);
2691203945Sweongyo		m_freem(m);
2692203945Sweongyo		return (ENETDOWN);
2693203945Sweongyo	}
2694203945Sweongyo
2695203945Sweongyo	BWN_LOCK(sc);
2696203945Sweongyo	if (bwn_tx_isfull(sc, m)) {
2697203945Sweongyo		ieee80211_free_node(ni);
2698203945Sweongyo		m_freem(m);
2699203945Sweongyo		BWN_UNLOCK(sc);
2700203945Sweongyo		return (ENOBUFS);
2701203945Sweongyo	}
2702203945Sweongyo
2703203945Sweongyo	if (bwn_tx_start(sc, ni, m) != 0) {
2704203945Sweongyo		if (ni != NULL)
2705203945Sweongyo			ieee80211_free_node(ni);
2706203945Sweongyo	}
2707203945Sweongyo	sc->sc_watchdog_timer = 5;
2708203945Sweongyo	BWN_UNLOCK(sc);
2709203945Sweongyo	return (0);
2710203945Sweongyo}
2711203945Sweongyo
2712203945Sweongyo/*
2713203945Sweongyo * Callback from the 802.11 layer to update the slot time
2714203945Sweongyo * based on the current setting.  We use it to notify the
2715203945Sweongyo * firmware of ERP changes and the f/w takes care of things
2716203945Sweongyo * like slot time and preamble.
2717203945Sweongyo */
2718203945Sweongyostatic void
2719283540Sglebiusbwn_updateslot(struct ieee80211com *ic)
2720203945Sweongyo{
2721283540Sglebius	struct bwn_softc *sc = ic->ic_softc;
2722203945Sweongyo	struct bwn_mac *mac;
2723203945Sweongyo
2724203945Sweongyo	BWN_LOCK(sc);
2725287197Sglebius	if (sc->sc_flags & BWN_FLAG_RUNNING) {
2726203945Sweongyo		mac = (struct bwn_mac *)sc->sc_curmac;
2727203945Sweongyo		bwn_set_slot_time(mac,
2728203945Sweongyo		    (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20);
2729203945Sweongyo	}
2730203945Sweongyo	BWN_UNLOCK(sc);
2731203945Sweongyo}
2732203945Sweongyo
2733203945Sweongyo/*
2734203945Sweongyo * Callback from the 802.11 layer after a promiscuous mode change.
2735203945Sweongyo * Note this interface does not check the operating mode as this
2736203945Sweongyo * is an internal callback and we are expected to honor the current
2737203945Sweongyo * state (e.g. this is used for setting the interface in promiscuous
2738203945Sweongyo * mode when operating in hostap mode to do ACS).
2739203945Sweongyo */
2740203945Sweongyostatic void
2741283540Sglebiusbwn_update_promisc(struct ieee80211com *ic)
2742203945Sweongyo{
2743283540Sglebius	struct bwn_softc *sc = ic->ic_softc;
2744203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2745203945Sweongyo
2746203945Sweongyo	BWN_LOCK(sc);
2747203945Sweongyo	mac = sc->sc_curmac;
2748203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2749287197Sglebius		if (ic->ic_promisc > 0)
2750203945Sweongyo			sc->sc_filters |= BWN_MACCTL_PROMISC;
2751203945Sweongyo		else
2752203945Sweongyo			sc->sc_filters &= ~BWN_MACCTL_PROMISC;
2753203945Sweongyo		bwn_set_opmode(mac);
2754203945Sweongyo	}
2755203945Sweongyo	BWN_UNLOCK(sc);
2756203945Sweongyo}
2757203945Sweongyo
2758203945Sweongyo/*
2759203945Sweongyo * Callback from the 802.11 layer to update WME parameters.
2760203945Sweongyo */
2761203945Sweongyostatic int
2762203945Sweongyobwn_wme_update(struct ieee80211com *ic)
2763203945Sweongyo{
2764286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
2765203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2766203945Sweongyo	struct wmeParams *wmep;
2767203945Sweongyo	int i;
2768203945Sweongyo
2769203945Sweongyo	BWN_LOCK(sc);
2770203945Sweongyo	mac = sc->sc_curmac;
2771203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2772203945Sweongyo		bwn_mac_suspend(mac);
2773203945Sweongyo		for (i = 0; i < N(sc->sc_wmeParams); i++) {
2774203945Sweongyo			wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
2775203945Sweongyo			bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
2776203945Sweongyo		}
2777203945Sweongyo		bwn_mac_enable(mac);
2778203945Sweongyo	}
2779203945Sweongyo	BWN_UNLOCK(sc);
2780203945Sweongyo	return (0);
2781203945Sweongyo}
2782203945Sweongyo
2783203945Sweongyostatic void
2784203945Sweongyobwn_scan_start(struct ieee80211com *ic)
2785203945Sweongyo{
2786286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
2787203945Sweongyo	struct bwn_mac *mac;
2788203945Sweongyo
2789203945Sweongyo	BWN_LOCK(sc);
2790203945Sweongyo	mac = sc->sc_curmac;
2791203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2792203945Sweongyo		sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
2793203945Sweongyo		bwn_set_opmode(mac);
2794203945Sweongyo		/* disable CFP update during scan */
2795203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
2796203945Sweongyo	}
2797203945Sweongyo	BWN_UNLOCK(sc);
2798203945Sweongyo}
2799203945Sweongyo
2800203945Sweongyostatic void
2801203945Sweongyobwn_scan_end(struct ieee80211com *ic)
2802203945Sweongyo{
2803286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
2804203945Sweongyo	struct bwn_mac *mac;
2805203945Sweongyo
2806203945Sweongyo	BWN_LOCK(sc);
2807203945Sweongyo	mac = sc->sc_curmac;
2808203945Sweongyo	if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
2809203945Sweongyo		sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
2810203945Sweongyo		bwn_set_opmode(mac);
2811203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
2812203945Sweongyo	}
2813203945Sweongyo	BWN_UNLOCK(sc);
2814203945Sweongyo}
2815203945Sweongyo
2816203945Sweongyostatic void
2817203945Sweongyobwn_set_channel(struct ieee80211com *ic)
2818203945Sweongyo{
2819286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
2820203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2821203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
2822203945Sweongyo	int chan, error;
2823203945Sweongyo
2824203945Sweongyo	BWN_LOCK(sc);
2825203945Sweongyo
2826203945Sweongyo	error = bwn_switch_band(sc, ic->ic_curchan);
2827203945Sweongyo	if (error)
2828216227Skevlo		goto fail;
2829203945Sweongyo	bwn_mac_suspend(mac);
2830203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
2831203945Sweongyo	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
2832203945Sweongyo	if (chan != phy->chan)
2833203945Sweongyo		bwn_switch_channel(mac, chan);
2834203945Sweongyo
2835203945Sweongyo	/* TX power level */
2836203945Sweongyo	if (ic->ic_curchan->ic_maxpower != 0 &&
2837203945Sweongyo	    ic->ic_curchan->ic_maxpower != phy->txpower) {
2838203945Sweongyo		phy->txpower = ic->ic_curchan->ic_maxpower / 2;
2839203945Sweongyo		bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
2840203945Sweongyo		    BWN_TXPWR_IGNORE_TSSI);
2841203945Sweongyo	}
2842203945Sweongyo
2843203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
2844203945Sweongyo	if (phy->set_antenna)
2845203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
2846203945Sweongyo
2847203945Sweongyo	if (sc->sc_rf_enabled != phy->rf_on) {
2848203945Sweongyo		if (sc->sc_rf_enabled) {
2849203945Sweongyo			bwn_rf_turnon(mac);
2850203945Sweongyo			if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
2851203945Sweongyo				device_printf(sc->sc_dev,
2852213719Sjoel				    "please turn on the RF switch\n");
2853203945Sweongyo		} else
2854203945Sweongyo			bwn_rf_turnoff(mac);
2855203945Sweongyo	}
2856203945Sweongyo
2857203945Sweongyo	bwn_mac_enable(mac);
2858203945Sweongyo
2859203945Sweongyofail:
2860203945Sweongyo	/*
2861203945Sweongyo	 * Setup radio tap channel freq and flags
2862203945Sweongyo	 */
2863203945Sweongyo	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
2864203945Sweongyo		htole16(ic->ic_curchan->ic_freq);
2865203945Sweongyo	sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
2866203945Sweongyo		htole16(ic->ic_curchan->ic_flags & 0xffff);
2867203945Sweongyo
2868203945Sweongyo	BWN_UNLOCK(sc);
2869203945Sweongyo}
2870203945Sweongyo
2871203945Sweongyostatic struct ieee80211vap *
2872228621Sbschmidtbwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
2873228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
2874228621Sbschmidt    const uint8_t bssid[IEEE80211_ADDR_LEN],
2875287197Sglebius    const uint8_t mac[IEEE80211_ADDR_LEN])
2876203945Sweongyo{
2877203945Sweongyo	struct ieee80211vap *vap;
2878203945Sweongyo	struct bwn_vap *bvp;
2879203945Sweongyo
2880203945Sweongyo	switch (opmode) {
2881203945Sweongyo	case IEEE80211_M_HOSTAP:
2882203945Sweongyo	case IEEE80211_M_MBSS:
2883203945Sweongyo	case IEEE80211_M_STA:
2884203945Sweongyo	case IEEE80211_M_WDS:
2885203945Sweongyo	case IEEE80211_M_MONITOR:
2886203945Sweongyo	case IEEE80211_M_IBSS:
2887203945Sweongyo	case IEEE80211_M_AHDEMO:
2888203945Sweongyo		break;
2889203945Sweongyo	default:
2890203945Sweongyo		return (NULL);
2891203945Sweongyo	}
2892203945Sweongyo
2893287197Sglebius	bvp = malloc(sizeof(struct bwn_vap), M_80211_VAP, M_WAITOK | M_ZERO);
2894203945Sweongyo	vap = &bvp->bv_vap;
2895287197Sglebius	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
2896203945Sweongyo	/* override with driver methods */
2897203945Sweongyo	bvp->bv_newstate = vap->iv_newstate;
2898203945Sweongyo	vap->iv_newstate = bwn_newstate;
2899203945Sweongyo
2900203945Sweongyo	/* override max aid so sta's cannot assoc when we're out of sta id's */
2901203945Sweongyo	vap->iv_max_aid = BWN_STAID_MAX;
2902203945Sweongyo
2903206358Srpaulo	ieee80211_ratectl_init(vap);
2904203945Sweongyo
2905203945Sweongyo	/* complete setup */
2906203945Sweongyo	ieee80211_vap_attach(vap, ieee80211_media_change,
2907287197Sglebius	    ieee80211_media_status, mac);
2908203945Sweongyo	return (vap);
2909203945Sweongyo}
2910203945Sweongyo
2911203945Sweongyostatic void
2912203945Sweongyobwn_vap_delete(struct ieee80211vap *vap)
2913203945Sweongyo{
2914203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
2915203945Sweongyo
2916206358Srpaulo	ieee80211_ratectl_deinit(vap);
2917203945Sweongyo	ieee80211_vap_detach(vap);
2918203945Sweongyo	free(bvp, M_80211_VAP);
2919203945Sweongyo}
2920203945Sweongyo
2921203945Sweongyostatic int
2922287197Sglebiusbwn_init(struct bwn_softc *sc)
2923203945Sweongyo{
2924203945Sweongyo	struct bwn_mac *mac;
2925203945Sweongyo	int error;
2926203945Sweongyo
2927203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2928203945Sweongyo
2929203945Sweongyo	bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
2930203945Sweongyo	sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
2931203945Sweongyo	sc->sc_filters = 0;
2932203945Sweongyo	bwn_wme_clear(sc);
2933203945Sweongyo	sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
2934203945Sweongyo	sc->sc_rf_enabled = 1;
2935203945Sweongyo
2936203945Sweongyo	mac = sc->sc_curmac;
2937203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
2938203945Sweongyo		error = bwn_core_init(mac);
2939203945Sweongyo		if (error != 0)
2940203945Sweongyo			return (error);
2941203945Sweongyo	}
2942203945Sweongyo	if (mac->mac_status == BWN_MAC_STATUS_INITED)
2943203945Sweongyo		bwn_core_start(mac);
2944203945Sweongyo
2945203945Sweongyo	bwn_set_opmode(mac);
2946203945Sweongyo	bwn_set_pretbtt(mac);
2947203945Sweongyo	bwn_spu_setdelay(mac, 0);
2948203945Sweongyo	bwn_set_macaddr(mac);
2949203945Sweongyo
2950287197Sglebius	sc->sc_flags |= BWN_FLAG_RUNNING;
2951203945Sweongyo	callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
2952203945Sweongyo	callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
2953203945Sweongyo
2954203945Sweongyo	return (0);
2955203945Sweongyo}
2956203945Sweongyo
2957203945Sweongyostatic void
2958287197Sglebiusbwn_stop(struct bwn_softc *sc)
2959203945Sweongyo{
2960203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
2961203945Sweongyo
2962203945Sweongyo	BWN_ASSERT_LOCKED(sc);
2963203945Sweongyo
2964203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
2965203945Sweongyo		/* XXX FIXME opmode not based on VAP */
2966203945Sweongyo		bwn_set_opmode(mac);
2967203945Sweongyo		bwn_set_macaddr(mac);
2968203945Sweongyo	}
2969203945Sweongyo
2970203945Sweongyo	if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
2971203945Sweongyo		bwn_core_stop(mac);
2972203945Sweongyo
2973203945Sweongyo	callout_stop(&sc->sc_led_blink_ch);
2974203945Sweongyo	sc->sc_led_blinking = 0;
2975203945Sweongyo
2976203945Sweongyo	bwn_core_exit(mac);
2977203945Sweongyo	sc->sc_rf_enabled = 0;
2978203945Sweongyo
2979287197Sglebius	sc->sc_flags &= ~BWN_FLAG_RUNNING;
2980203945Sweongyo}
2981203945Sweongyo
2982203945Sweongyostatic void
2983203945Sweongyobwn_wme_clear(struct bwn_softc *sc)
2984203945Sweongyo{
2985203945Sweongyo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
2986203945Sweongyo	struct wmeParams *p;
2987203945Sweongyo	unsigned int i;
2988203945Sweongyo
2989203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
2990203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
2991203945Sweongyo
2992203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++) {
2993203945Sweongyo		p = &(sc->sc_wmeParams[i]);
2994203945Sweongyo
2995203945Sweongyo		switch (bwn_wme_shm_offsets[i]) {
2996203945Sweongyo		case BWN_WME_VOICE:
2997203945Sweongyo			p->wmep_txopLimit = 0;
2998203945Sweongyo			p->wmep_aifsn = 2;
2999203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3000203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3001203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3002203945Sweongyo			break;
3003203945Sweongyo		case BWN_WME_VIDEO:
3004203945Sweongyo			p->wmep_txopLimit = 0;
3005203945Sweongyo			p->wmep_aifsn = 2;
3006203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3007203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3008203945Sweongyo			p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
3009203945Sweongyo			break;
3010203945Sweongyo		case BWN_WME_BESTEFFORT:
3011203945Sweongyo			p->wmep_txopLimit = 0;
3012203945Sweongyo			p->wmep_aifsn = 3;
3013203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3014203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3015203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3016203945Sweongyo			break;
3017203945Sweongyo		case BWN_WME_BACKGROUND:
3018203945Sweongyo			p->wmep_txopLimit = 0;
3019203945Sweongyo			p->wmep_aifsn = 7;
3020203945Sweongyo			/* XXX FIXME: log2(cwmin) */
3021203945Sweongyo			p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
3022203945Sweongyo			p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
3023203945Sweongyo			break;
3024203945Sweongyo		default:
3025203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3026203945Sweongyo		}
3027203945Sweongyo	}
3028203945Sweongyo}
3029203945Sweongyo
3030203945Sweongyostatic int
3031203945Sweongyobwn_core_init(struct bwn_mac *mac)
3032203945Sweongyo{
3033203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3034203945Sweongyo	uint64_t hf;
3035203945Sweongyo	int error;
3036203945Sweongyo
3037203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3038203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3039203945Sweongyo
3040204922Sweongyo	siba_powerup(sc->sc_dev, 0);
3041204922Sweongyo	if (!siba_dev_isup(sc->sc_dev))
3042203945Sweongyo		bwn_reset_core(mac,
3043203945Sweongyo		    mac->mac_phy.gmode ? BWN_TGSLOW_SUPPORT_G : 0);
3044203945Sweongyo
3045203945Sweongyo	mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
3046203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
3047203945Sweongyo	mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
3048203945Sweongyo	BWN_GETTIME(mac->mac_phy.nexttime);
3049203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
3050203945Sweongyo	bzero(&mac->mac_stats, sizeof(mac->mac_stats));
3051203945Sweongyo	mac->mac_stats.link_noise = -95;
3052203945Sweongyo	mac->mac_reason_intr = 0;
3053203945Sweongyo	bzero(mac->mac_reason, sizeof(mac->mac_reason));
3054203945Sweongyo	mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
3055203945Sweongyo#ifdef BWN_DEBUG
3056203945Sweongyo	if (sc->sc_debug & BWN_DEBUG_XMIT)
3057203945Sweongyo		mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
3058203945Sweongyo#endif
3059203945Sweongyo	mac->mac_suspended = 1;
3060203945Sweongyo	mac->mac_task_state = 0;
3061203945Sweongyo	memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
3062203945Sweongyo
3063203945Sweongyo	mac->mac_phy.init_pre(mac);
3064203945Sweongyo
3065204922Sweongyo	siba_pcicore_intr(sc->sc_dev);
3066203945Sweongyo
3067204922Sweongyo	siba_fix_imcfglobug(sc->sc_dev);
3068203945Sweongyo	bwn_bt_disable(mac);
3069203945Sweongyo	if (mac->mac_phy.prepare_hw) {
3070203945Sweongyo		error = mac->mac_phy.prepare_hw(mac);
3071203945Sweongyo		if (error)
3072203945Sweongyo			goto fail0;
3073203945Sweongyo	}
3074203945Sweongyo	error = bwn_chip_init(mac);
3075203945Sweongyo	if (error)
3076203945Sweongyo		goto fail0;
3077203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
3078204922Sweongyo	    siba_get_revid(sc->sc_dev));
3079203945Sweongyo	hf = bwn_hf_read(mac);
3080203945Sweongyo	if (mac->mac_phy.type == BWN_PHYTYPE_G) {
3081203945Sweongyo		hf |= BWN_HF_GPHY_SYM_WORKAROUND;
3082204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
3083203945Sweongyo			hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
3084203945Sweongyo		if (mac->mac_phy.rev == 1)
3085203945Sweongyo			hf |= BWN_HF_GPHY_DC_CANCELFILTER;
3086203945Sweongyo	}
3087203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2050) {
3088203945Sweongyo		if (mac->mac_phy.rf_rev < 6)
3089203945Sweongyo			hf |= BWN_HF_FORCE_VCO_RECALC;
3090203945Sweongyo		if (mac->mac_phy.rf_rev == 6)
3091203945Sweongyo			hf |= BWN_HF_4318_TSSI;
3092203945Sweongyo	}
3093204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW)
3094203945Sweongyo		hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
3095204922Sweongyo	if ((siba_get_type(sc->sc_dev) == SIBA_TYPE_PCI) &&
3096204922Sweongyo	    (siba_get_pcicore_revid(sc->sc_dev) <= 10))
3097203945Sweongyo		hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
3098203945Sweongyo	hf &= ~BWN_HF_SKIP_CFP_UPDATE;
3099203945Sweongyo	bwn_hf_write(mac, hf);
3100203945Sweongyo
3101203945Sweongyo	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
3102203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3);
3103203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2);
3104203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
3105203945Sweongyo
3106203945Sweongyo	bwn_rate_init(mac);
3107203945Sweongyo	bwn_set_phytxctl(mac);
3108203945Sweongyo
3109203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
3110203945Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
3111203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
3112203945Sweongyo
3113204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
3114203945Sweongyo		bwn_pio_init(mac);
3115203945Sweongyo	else
3116203945Sweongyo		bwn_dma_init(mac);
3117203945Sweongyo	bwn_wme_init(mac);
3118203945Sweongyo	bwn_spu_setdelay(mac, 1);
3119203945Sweongyo	bwn_bt_enable(mac);
3120203945Sweongyo
3121204922Sweongyo	siba_powerup(sc->sc_dev,
3122204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW));
3123203945Sweongyo	bwn_set_macaddr(mac);
3124203945Sweongyo	bwn_crypt_init(mac);
3125203945Sweongyo
3126203945Sweongyo	/* XXX LED initializatin */
3127203945Sweongyo
3128203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
3129203945Sweongyo
3130203945Sweongyo	return (error);
3131203945Sweongyo
3132203945Sweongyofail0:
3133204922Sweongyo	siba_powerdown(sc->sc_dev);
3134203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
3135203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3136203945Sweongyo	return (error);
3137203945Sweongyo}
3138203945Sweongyo
3139203945Sweongyostatic void
3140203945Sweongyobwn_core_start(struct bwn_mac *mac)
3141203945Sweongyo{
3142203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3143203945Sweongyo	uint32_t tmp;
3144203945Sweongyo
3145203945Sweongyo	KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
3146203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3147203945Sweongyo
3148204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
3149203945Sweongyo		return;
3150203945Sweongyo
3151203945Sweongyo	while (1) {
3152203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
3153203945Sweongyo		if (!(tmp & 0x00000001))
3154203945Sweongyo			break;
3155203945Sweongyo		tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
3156203945Sweongyo	}
3157203945Sweongyo
3158203945Sweongyo	bwn_mac_enable(mac);
3159203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
3160203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
3161203945Sweongyo
3162203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_STARTED;
3163203945Sweongyo}
3164203945Sweongyo
3165203945Sweongyostatic void
3166203945Sweongyobwn_core_exit(struct bwn_mac *mac)
3167203945Sweongyo{
3168204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3169203945Sweongyo	uint32_t macctl;
3170203945Sweongyo
3171204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
3172203945Sweongyo
3173203945Sweongyo	KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
3174203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3175203945Sweongyo
3176203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_INITED)
3177203945Sweongyo		return;
3178203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_UNINIT;
3179203945Sweongyo
3180203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
3181203945Sweongyo	macctl &= ~BWN_MACCTL_MCODE_RUN;
3182203945Sweongyo	macctl |= BWN_MACCTL_MCODE_JMP0;
3183203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3184203945Sweongyo
3185203945Sweongyo	bwn_dma_stop(mac);
3186203945Sweongyo	bwn_pio_stop(mac);
3187203945Sweongyo	bwn_chip_exit(mac);
3188203945Sweongyo	mac->mac_phy.switch_analog(mac, 0);
3189204922Sweongyo	siba_dev_down(sc->sc_dev, 0);
3190204922Sweongyo	siba_powerdown(sc->sc_dev);
3191203945Sweongyo}
3192203945Sweongyo
3193203945Sweongyostatic void
3194203945Sweongyobwn_bt_disable(struct bwn_mac *mac)
3195203945Sweongyo{
3196203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3197203945Sweongyo
3198203945Sweongyo	(void)sc;
3199203945Sweongyo	/* XXX do nothing yet */
3200203945Sweongyo}
3201203945Sweongyo
3202203945Sweongyostatic int
3203203945Sweongyobwn_chip_init(struct bwn_mac *mac)
3204203945Sweongyo{
3205204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3206203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
3207203945Sweongyo	uint32_t macctl;
3208203945Sweongyo	int error;
3209203945Sweongyo
3210203945Sweongyo	macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
3211203945Sweongyo	if (phy->gmode)
3212203945Sweongyo		macctl |= BWN_MACCTL_GMODE;
3213203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, macctl);
3214203945Sweongyo
3215203945Sweongyo	error = bwn_fw_fillinfo(mac);
3216203945Sweongyo	if (error)
3217203945Sweongyo		return (error);
3218203945Sweongyo	error = bwn_fw_loaducode(mac);
3219203945Sweongyo	if (error)
3220203945Sweongyo		return (error);
3221203945Sweongyo
3222203945Sweongyo	error = bwn_gpio_init(mac);
3223203945Sweongyo	if (error)
3224203945Sweongyo		return (error);
3225203945Sweongyo
3226203945Sweongyo	error = bwn_fw_loadinitvals(mac);
3227203945Sweongyo	if (error) {
3228204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
3229203945Sweongyo		return (error);
3230203945Sweongyo	}
3231203945Sweongyo	phy->switch_analog(mac, 1);
3232203945Sweongyo	error = bwn_phy_init(mac);
3233203945Sweongyo	if (error) {
3234204922Sweongyo		siba_gpio_set(sc->sc_dev, 0);
3235203945Sweongyo		return (error);
3236203945Sweongyo	}
3237203945Sweongyo	if (phy->set_im)
3238203945Sweongyo		phy->set_im(mac, BWN_IMMODE_NONE);
3239203945Sweongyo	if (phy->set_antenna)
3240203945Sweongyo		phy->set_antenna(mac, BWN_ANT_DEFAULT);
3241203945Sweongyo	bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
3242203945Sweongyo
3243203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
3244203945Sweongyo		BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
3245203945Sweongyo	BWN_WRITE_4(mac, 0x0100, 0x01000000);
3246204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 5)
3247203945Sweongyo		BWN_WRITE_4(mac, 0x010c, 0x01000000);
3248203945Sweongyo
3249203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3250203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
3251203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
3252203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
3253203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
3254203945Sweongyo
3255203945Sweongyo	bwn_set_opmode(mac);
3256204922Sweongyo	if (siba_get_revid(sc->sc_dev) < 3) {
3257203945Sweongyo		BWN_WRITE_2(mac, 0x060e, 0x0000);
3258203945Sweongyo		BWN_WRITE_2(mac, 0x0610, 0x8000);
3259203945Sweongyo		BWN_WRITE_2(mac, 0x0604, 0x0000);
3260203945Sweongyo		BWN_WRITE_2(mac, 0x0606, 0x0200);
3261203945Sweongyo	} else {
3262203945Sweongyo		BWN_WRITE_4(mac, 0x0188, 0x80000000);
3263203945Sweongyo		BWN_WRITE_4(mac, 0x018c, 0x02000000);
3264203945Sweongyo	}
3265203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
3266203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
3267203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00);
3268203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00);
3269203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00);
3270203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00);
3271203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
3272204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
3273204922Sweongyo	    siba_read_4(sc->sc_dev, SIBA_TGSLOW) | 0x00100000);
3274204922Sweongyo	BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev));
3275203945Sweongyo	return (error);
3276203945Sweongyo}
3277203945Sweongyo
3278203945Sweongyo/* read hostflags */
3279203945Sweongyostatic uint64_t
3280203945Sweongyobwn_hf_read(struct bwn_mac *mac)
3281203945Sweongyo{
3282203945Sweongyo	uint64_t ret;
3283203945Sweongyo
3284203945Sweongyo	ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
3285203945Sweongyo	ret <<= 16;
3286203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
3287203945Sweongyo	ret <<= 16;
3288203945Sweongyo	ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
3289203945Sweongyo	return (ret);
3290203945Sweongyo}
3291203945Sweongyo
3292203945Sweongyostatic void
3293203945Sweongyobwn_hf_write(struct bwn_mac *mac, uint64_t value)
3294203945Sweongyo{
3295203945Sweongyo
3296203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
3297203945Sweongyo	    (value & 0x00000000ffffull));
3298203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
3299203945Sweongyo	    (value & 0x0000ffff0000ull) >> 16);
3300203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
3301203945Sweongyo	    (value & 0xffff00000000ULL) >> 32);
3302203945Sweongyo}
3303203945Sweongyo
3304203945Sweongyostatic void
3305203945Sweongyobwn_set_txretry(struct bwn_mac *mac, int s, int l)
3306203945Sweongyo{
3307203945Sweongyo
3308203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
3309203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
3310203945Sweongyo}
3311203945Sweongyo
3312203945Sweongyostatic void
3313203945Sweongyobwn_rate_init(struct bwn_mac *mac)
3314203945Sweongyo{
3315203945Sweongyo
3316203945Sweongyo	switch (mac->mac_phy.type) {
3317203945Sweongyo	case BWN_PHYTYPE_A:
3318203945Sweongyo	case BWN_PHYTYPE_G:
3319203945Sweongyo	case BWN_PHYTYPE_LP:
3320203945Sweongyo	case BWN_PHYTYPE_N:
3321203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
3322203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
3323203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
3324203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
3325203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
3326203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
3327203945Sweongyo		bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
3328203945Sweongyo		if (mac->mac_phy.type == BWN_PHYTYPE_A)
3329203945Sweongyo			break;
3330203945Sweongyo		/* FALLTHROUGH */
3331203945Sweongyo	case BWN_PHYTYPE_B:
3332203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
3333203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
3334203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
3335203945Sweongyo		bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
3336203945Sweongyo		break;
3337203945Sweongyo	default:
3338203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3339203945Sweongyo	}
3340203945Sweongyo}
3341203945Sweongyo
3342203945Sweongyostatic void
3343203945Sweongyobwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
3344203945Sweongyo{
3345203945Sweongyo	uint16_t offset;
3346203945Sweongyo
3347203945Sweongyo	if (ofdm) {
3348203945Sweongyo		offset = 0x480;
3349203945Sweongyo		offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
3350203945Sweongyo	} else {
3351203945Sweongyo		offset = 0x4c0;
3352203945Sweongyo		offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
3353203945Sweongyo	}
3354203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
3355203945Sweongyo	    bwn_shm_read_2(mac, BWN_SHARED, offset));
3356203945Sweongyo}
3357203945Sweongyo
3358203945Sweongyostatic uint8_t
3359203945Sweongyobwn_plcp_getcck(const uint8_t bitrate)
3360203945Sweongyo{
3361203945Sweongyo
3362203945Sweongyo	switch (bitrate) {
3363203945Sweongyo	case BWN_CCK_RATE_1MB:
3364203945Sweongyo		return (0x0a);
3365203945Sweongyo	case BWN_CCK_RATE_2MB:
3366203945Sweongyo		return (0x14);
3367203945Sweongyo	case BWN_CCK_RATE_5MB:
3368203945Sweongyo		return (0x37);
3369203945Sweongyo	case BWN_CCK_RATE_11MB:
3370203945Sweongyo		return (0x6e);
3371203945Sweongyo	}
3372203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3373203945Sweongyo	return (0);
3374203945Sweongyo}
3375203945Sweongyo
3376203945Sweongyostatic uint8_t
3377203945Sweongyobwn_plcp_getofdm(const uint8_t bitrate)
3378203945Sweongyo{
3379203945Sweongyo
3380203945Sweongyo	switch (bitrate) {
3381203945Sweongyo	case BWN_OFDM_RATE_6MB:
3382203945Sweongyo		return (0xb);
3383203945Sweongyo	case BWN_OFDM_RATE_9MB:
3384203945Sweongyo		return (0xf);
3385203945Sweongyo	case BWN_OFDM_RATE_12MB:
3386203945Sweongyo		return (0xa);
3387203945Sweongyo	case BWN_OFDM_RATE_18MB:
3388203945Sweongyo		return (0xe);
3389203945Sweongyo	case BWN_OFDM_RATE_24MB:
3390203945Sweongyo		return (0x9);
3391203945Sweongyo	case BWN_OFDM_RATE_36MB:
3392203945Sweongyo		return (0xd);
3393203945Sweongyo	case BWN_OFDM_RATE_48MB:
3394203945Sweongyo		return (0x8);
3395203945Sweongyo	case BWN_OFDM_RATE_54MB:
3396203945Sweongyo		return (0xc);
3397203945Sweongyo	}
3398203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3399203945Sweongyo	return (0);
3400203945Sweongyo}
3401203945Sweongyo
3402203945Sweongyostatic void
3403203945Sweongyobwn_set_phytxctl(struct bwn_mac *mac)
3404203945Sweongyo{
3405203945Sweongyo	uint16_t ctl;
3406203945Sweongyo
3407203945Sweongyo	ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
3408203945Sweongyo	    BWN_TX_PHY_TXPWR);
3409203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
3410203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
3411203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
3412203945Sweongyo}
3413203945Sweongyo
3414203945Sweongyostatic void
3415203945Sweongyobwn_pio_init(struct bwn_mac *mac)
3416203945Sweongyo{
3417203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
3418203945Sweongyo
3419203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
3420203945Sweongyo	    & ~BWN_MACCTL_BIGENDIAN);
3421203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
3422203945Sweongyo
3423203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
3424203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
3425203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
3426203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
3427203945Sweongyo	bwn_pio_set_txqueue(mac, &pio->mcast, 4);
3428203945Sweongyo	bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
3429203945Sweongyo}
3430203945Sweongyo
3431203945Sweongyostatic void
3432203945Sweongyobwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3433203945Sweongyo    int index)
3434203945Sweongyo{
3435203945Sweongyo	struct bwn_pio_txpkt *tp;
3436204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3437203945Sweongyo	unsigned int i;
3438203945Sweongyo
3439203945Sweongyo	tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
3440203945Sweongyo	tq->tq_index = index;
3441203945Sweongyo
3442203945Sweongyo	tq->tq_free = BWN_PIO_MAX_TXPACKETS;
3443204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 8)
3444203945Sweongyo		tq->tq_size = 1920;
3445203945Sweongyo	else {
3446203945Sweongyo		tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
3447203945Sweongyo		tq->tq_size -= 80;
3448203945Sweongyo	}
3449203945Sweongyo
3450203945Sweongyo	TAILQ_INIT(&tq->tq_pktlist);
3451203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3452203945Sweongyo		tp = &(tq->tq_pkts[i]);
3453203945Sweongyo		tp->tp_index = i;
3454203945Sweongyo		tp->tp_queue = tq;
3455203945Sweongyo		TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
3456203945Sweongyo	}
3457203945Sweongyo}
3458203945Sweongyo
3459203945Sweongyostatic uint16_t
3460203945Sweongyobwn_pio_idx2base(struct bwn_mac *mac, int index)
3461203945Sweongyo{
3462203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3463203945Sweongyo	static const uint16_t bases[] = {
3464203945Sweongyo		BWN_PIO_BASE0,
3465203945Sweongyo		BWN_PIO_BASE1,
3466203945Sweongyo		BWN_PIO_BASE2,
3467203945Sweongyo		BWN_PIO_BASE3,
3468203945Sweongyo		BWN_PIO_BASE4,
3469203945Sweongyo		BWN_PIO_BASE5,
3470203945Sweongyo		BWN_PIO_BASE6,
3471203945Sweongyo		BWN_PIO_BASE7,
3472203945Sweongyo	};
3473203945Sweongyo	static const uint16_t bases_rev11[] = {
3474203945Sweongyo		BWN_PIO11_BASE0,
3475203945Sweongyo		BWN_PIO11_BASE1,
3476203945Sweongyo		BWN_PIO11_BASE2,
3477203945Sweongyo		BWN_PIO11_BASE3,
3478203945Sweongyo		BWN_PIO11_BASE4,
3479203945Sweongyo		BWN_PIO11_BASE5,
3480203945Sweongyo	};
3481203945Sweongyo
3482204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 11) {
3483203945Sweongyo		if (index >= N(bases_rev11))
3484203945Sweongyo			device_printf(sc->sc_dev, "%s: warning\n", __func__);
3485203945Sweongyo		return (bases_rev11[index]);
3486203945Sweongyo	}
3487203945Sweongyo	if (index >= N(bases))
3488203945Sweongyo		device_printf(sc->sc_dev, "%s: warning\n", __func__);
3489203945Sweongyo	return (bases[index]);
3490203945Sweongyo}
3491203945Sweongyo
3492203945Sweongyostatic void
3493203945Sweongyobwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
3494203945Sweongyo    int index)
3495203945Sweongyo{
3496204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3497203945Sweongyo
3498203945Sweongyo	prq->prq_mac = mac;
3499204922Sweongyo	prq->prq_rev = siba_get_revid(sc->sc_dev);
3500203945Sweongyo	prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
3501203945Sweongyo	bwn_dma_rxdirectfifo(mac, index, 1);
3502203945Sweongyo}
3503203945Sweongyo
3504203945Sweongyostatic void
3505203945Sweongyobwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
3506203945Sweongyo{
3507203945Sweongyo	if (tq == NULL)
3508203945Sweongyo		return;
3509203945Sweongyo	bwn_pio_cancel_tx_packets(tq);
3510203945Sweongyo}
3511203945Sweongyo
3512203945Sweongyostatic void
3513203945Sweongyobwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
3514203945Sweongyo{
3515203945Sweongyo
3516203945Sweongyo	bwn_destroy_pioqueue_tx(pio);
3517203945Sweongyo}
3518203945Sweongyo
3519203945Sweongyostatic uint16_t
3520203945Sweongyobwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
3521203945Sweongyo    uint16_t offset)
3522203945Sweongyo{
3523203945Sweongyo
3524203945Sweongyo	return (BWN_READ_2(mac, tq->tq_base + offset));
3525203945Sweongyo}
3526203945Sweongyo
3527203945Sweongyostatic void
3528203945Sweongyobwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
3529203945Sweongyo{
3530203945Sweongyo	uint32_t ctl;
3531203945Sweongyo	int type;
3532203945Sweongyo	uint16_t base;
3533203945Sweongyo
3534203945Sweongyo	type = bwn_dma_mask2type(bwn_dma_mask(mac));
3535203945Sweongyo	base = bwn_dma_base(type, idx);
3536203945Sweongyo	if (type == BWN_DMA_64BIT) {
3537203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
3538203945Sweongyo		ctl &= ~BWN_DMA64_RXDIRECTFIFO;
3539203945Sweongyo		if (enable)
3540203945Sweongyo			ctl |= BWN_DMA64_RXDIRECTFIFO;
3541203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
3542203945Sweongyo	} else {
3543203945Sweongyo		ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
3544203945Sweongyo		ctl &= ~BWN_DMA32_RXDIRECTFIFO;
3545203945Sweongyo		if (enable)
3546203945Sweongyo			ctl |= BWN_DMA32_RXDIRECTFIFO;
3547203945Sweongyo		BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl);
3548203945Sweongyo	}
3549203945Sweongyo}
3550203945Sweongyo
3551203945Sweongyostatic uint64_t
3552203945Sweongyobwn_dma_mask(struct bwn_mac *mac)
3553203945Sweongyo{
3554203945Sweongyo	uint32_t tmp;
3555203945Sweongyo	uint16_t base;
3556203945Sweongyo
3557203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
3558203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
3559203945Sweongyo		return (BWN_DMA_BIT_MASK(64));
3560203945Sweongyo	base = bwn_dma_base(0, 0);
3561203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
3562203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
3563203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
3564203945Sweongyo		return (BWN_DMA_BIT_MASK(32));
3565203945Sweongyo
3566203945Sweongyo	return (BWN_DMA_BIT_MASK(30));
3567203945Sweongyo}
3568203945Sweongyo
3569203945Sweongyostatic int
3570203945Sweongyobwn_dma_mask2type(uint64_t dmamask)
3571203945Sweongyo{
3572203945Sweongyo
3573203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(30))
3574203945Sweongyo		return (BWN_DMA_30BIT);
3575203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(32))
3576203945Sweongyo		return (BWN_DMA_32BIT);
3577203945Sweongyo	if (dmamask == BWN_DMA_BIT_MASK(64))
3578203945Sweongyo		return (BWN_DMA_64BIT);
3579203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3580203945Sweongyo	return (BWN_DMA_30BIT);
3581203945Sweongyo}
3582203945Sweongyo
3583203945Sweongyostatic void
3584203945Sweongyobwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
3585203945Sweongyo{
3586203945Sweongyo	struct bwn_pio_txpkt *tp;
3587203945Sweongyo	unsigned int i;
3588203945Sweongyo
3589203945Sweongyo	for (i = 0; i < N(tq->tq_pkts); i++) {
3590203945Sweongyo		tp = &(tq->tq_pkts[i]);
3591203945Sweongyo		if (tp->tp_m) {
3592203945Sweongyo			m_freem(tp->tp_m);
3593203945Sweongyo			tp->tp_m = NULL;
3594203945Sweongyo		}
3595203945Sweongyo	}
3596203945Sweongyo}
3597203945Sweongyo
3598203945Sweongyostatic uint16_t
3599203945Sweongyobwn_dma_base(int type, int controller_idx)
3600203945Sweongyo{
3601203945Sweongyo	static const uint16_t map64[] = {
3602203945Sweongyo		BWN_DMA64_BASE0,
3603203945Sweongyo		BWN_DMA64_BASE1,
3604203945Sweongyo		BWN_DMA64_BASE2,
3605203945Sweongyo		BWN_DMA64_BASE3,
3606203945Sweongyo		BWN_DMA64_BASE4,
3607203945Sweongyo		BWN_DMA64_BASE5,
3608203945Sweongyo	};
3609203945Sweongyo	static const uint16_t map32[] = {
3610203945Sweongyo		BWN_DMA32_BASE0,
3611203945Sweongyo		BWN_DMA32_BASE1,
3612203945Sweongyo		BWN_DMA32_BASE2,
3613203945Sweongyo		BWN_DMA32_BASE3,
3614203945Sweongyo		BWN_DMA32_BASE4,
3615203945Sweongyo		BWN_DMA32_BASE5,
3616203945Sweongyo	};
3617203945Sweongyo
3618203945Sweongyo	if (type == BWN_DMA_64BIT) {
3619203945Sweongyo		KASSERT(controller_idx >= 0 && controller_idx < N(map64),
3620203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3621203945Sweongyo		return (map64[controller_idx]);
3622203945Sweongyo	}
3623203945Sweongyo	KASSERT(controller_idx >= 0 && controller_idx < N(map32),
3624203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3625203945Sweongyo	return (map32[controller_idx]);
3626203945Sweongyo}
3627203945Sweongyo
3628203945Sweongyostatic void
3629203945Sweongyobwn_dma_init(struct bwn_mac *mac)
3630203945Sweongyo{
3631203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3632203945Sweongyo
3633203945Sweongyo	/* setup TX DMA channels. */
3634203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BK]);
3635203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_BE]);
3636203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VI]);
3637203945Sweongyo	bwn_dma_setup(dma->wme[WME_AC_VO]);
3638203945Sweongyo	bwn_dma_setup(dma->mcast);
3639203945Sweongyo	/* setup RX DMA channel. */
3640203945Sweongyo	bwn_dma_setup(dma->rx);
3641203945Sweongyo}
3642203945Sweongyo
3643203945Sweongyostatic struct bwn_dma_ring *
3644203945Sweongyobwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
3645203945Sweongyo    int for_tx, int type)
3646203945Sweongyo{
3647203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
3648203945Sweongyo	struct bwn_dma_ring *dr;
3649203945Sweongyo	struct bwn_dmadesc_generic *desc;
3650203945Sweongyo	struct bwn_dmadesc_meta *mt;
3651203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
3652203945Sweongyo	int error, i;
3653203945Sweongyo
3654203945Sweongyo	dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
3655203945Sweongyo	if (dr == NULL)
3656203945Sweongyo		goto out;
3657203945Sweongyo	dr->dr_numslots = BWN_RXRING_SLOTS;
3658203945Sweongyo	if (for_tx)
3659203945Sweongyo		dr->dr_numslots = BWN_TXRING_SLOTS;
3660203945Sweongyo
3661203945Sweongyo	dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
3662203945Sweongyo	    M_DEVBUF, M_NOWAIT | M_ZERO);
3663203945Sweongyo	if (dr->dr_meta == NULL)
3664203945Sweongyo		goto fail0;
3665203945Sweongyo
3666203945Sweongyo	dr->dr_type = type;
3667203945Sweongyo	dr->dr_mac = mac;
3668203945Sweongyo	dr->dr_base = bwn_dma_base(type, controller_index);
3669203945Sweongyo	dr->dr_index = controller_index;
3670203945Sweongyo	if (type == BWN_DMA_64BIT) {
3671203945Sweongyo		dr->getdesc = bwn_dma_64_getdesc;
3672203945Sweongyo		dr->setdesc = bwn_dma_64_setdesc;
3673203945Sweongyo		dr->start_transfer = bwn_dma_64_start_transfer;
3674203945Sweongyo		dr->suspend = bwn_dma_64_suspend;
3675203945Sweongyo		dr->resume = bwn_dma_64_resume;
3676203945Sweongyo		dr->get_curslot = bwn_dma_64_get_curslot;
3677203945Sweongyo		dr->set_curslot = bwn_dma_64_set_curslot;
3678203945Sweongyo	} else {
3679203945Sweongyo		dr->getdesc = bwn_dma_32_getdesc;
3680203945Sweongyo		dr->setdesc = bwn_dma_32_setdesc;
3681203945Sweongyo		dr->start_transfer = bwn_dma_32_start_transfer;
3682203945Sweongyo		dr->suspend = bwn_dma_32_suspend;
3683203945Sweongyo		dr->resume = bwn_dma_32_resume;
3684203945Sweongyo		dr->get_curslot = bwn_dma_32_get_curslot;
3685203945Sweongyo		dr->set_curslot = bwn_dma_32_set_curslot;
3686203945Sweongyo	}
3687203945Sweongyo	if (for_tx) {
3688203945Sweongyo		dr->dr_tx = 1;
3689203945Sweongyo		dr->dr_curslot = -1;
3690203945Sweongyo	} else {
3691203945Sweongyo		if (dr->dr_index == 0) {
3692203945Sweongyo			dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
3693203945Sweongyo			dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
3694203945Sweongyo		} else
3695203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
3696203945Sweongyo	}
3697203945Sweongyo
3698203945Sweongyo	error = bwn_dma_allocringmemory(dr);
3699203945Sweongyo	if (error)
3700203945Sweongyo		goto fail2;
3701203945Sweongyo
3702203945Sweongyo	if (for_tx) {
3703203945Sweongyo		/*
3704203945Sweongyo		 * Assumption: BWN_TXRING_SLOTS can be divided by
3705203945Sweongyo		 * BWN_TX_SLOTS_PER_FRAME
3706203945Sweongyo		 */
3707203945Sweongyo		KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
3708203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3709203945Sweongyo
3710203945Sweongyo		dr->dr_txhdr_cache =
3711203945Sweongyo		    malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
3712203945Sweongyo			BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
3713203945Sweongyo		KASSERT(dr->dr_txhdr_cache != NULL,
3714203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
3715203945Sweongyo
3716203945Sweongyo		/*
3717203945Sweongyo		 * Create TX ring DMA stuffs
3718203945Sweongyo		 */
3719203945Sweongyo		error = bus_dma_tag_create(dma->parent_dtag,
3720203945Sweongyo				    BWN_ALIGN, 0,
3721203945Sweongyo				    BUS_SPACE_MAXADDR,
3722203945Sweongyo				    BUS_SPACE_MAXADDR,
3723203945Sweongyo				    NULL, NULL,
3724203945Sweongyo				    BWN_HDRSIZE(mac),
3725203945Sweongyo				    1,
3726203945Sweongyo				    BUS_SPACE_MAXSIZE_32BIT,
3727203945Sweongyo				    0,
3728203945Sweongyo				    NULL, NULL,
3729203945Sweongyo				    &dr->dr_txring_dtag);
3730203945Sweongyo		if (error) {
3731203945Sweongyo			device_printf(sc->sc_dev,
3732203945Sweongyo			    "can't create TX ring DMA tag: TODO frees\n");
3733203945Sweongyo			goto fail1;
3734203945Sweongyo		}
3735203945Sweongyo
3736203945Sweongyo		for (i = 0; i < dr->dr_numslots; i += 2) {
3737203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3738203945Sweongyo
3739203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
3740203945Sweongyo			mt->mt_m = NULL;
3741203945Sweongyo			mt->mt_ni = NULL;
3742203945Sweongyo			mt->mt_islast = 0;
3743203945Sweongyo			error = bus_dmamap_create(dr->dr_txring_dtag, 0,
3744203945Sweongyo			    &mt->mt_dmap);
3745203945Sweongyo			if (error) {
3746203945Sweongyo				device_printf(sc->sc_dev,
3747203945Sweongyo				     "can't create RX buf DMA map\n");
3748203945Sweongyo				goto fail1;
3749203945Sweongyo			}
3750203945Sweongyo
3751203945Sweongyo			dr->getdesc(dr, i + 1, &desc, &mt);
3752203945Sweongyo
3753203945Sweongyo			mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
3754203945Sweongyo			mt->mt_m = NULL;
3755203945Sweongyo			mt->mt_ni = NULL;
3756203945Sweongyo			mt->mt_islast = 1;
3757203945Sweongyo			error = bus_dmamap_create(dma->txbuf_dtag, 0,
3758203945Sweongyo			    &mt->mt_dmap);
3759203945Sweongyo			if (error) {
3760203945Sweongyo				device_printf(sc->sc_dev,
3761203945Sweongyo				     "can't create RX buf DMA map\n");
3762203945Sweongyo				goto fail1;
3763203945Sweongyo			}
3764203945Sweongyo		}
3765203945Sweongyo	} else {
3766203945Sweongyo		error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3767203945Sweongyo		    &dr->dr_spare_dmap);
3768203945Sweongyo		if (error) {
3769203945Sweongyo			device_printf(sc->sc_dev,
3770203945Sweongyo			    "can't create RX buf DMA map\n");
3771203945Sweongyo			goto out;		/* XXX wrong! */
3772203945Sweongyo		}
3773203945Sweongyo
3774203945Sweongyo		for (i = 0; i < dr->dr_numslots; i++) {
3775203945Sweongyo			dr->getdesc(dr, i, &desc, &mt);
3776203945Sweongyo
3777203945Sweongyo			error = bus_dmamap_create(dma->rxbuf_dtag, 0,
3778203945Sweongyo			    &mt->mt_dmap);
3779203945Sweongyo			if (error) {
3780203945Sweongyo				device_printf(sc->sc_dev,
3781203945Sweongyo				    "can't create RX buf DMA map\n");
3782203945Sweongyo				goto out;	/* XXX wrong! */
3783203945Sweongyo			}
3784203945Sweongyo			error = bwn_dma_newbuf(dr, desc, mt, 1);
3785203945Sweongyo			if (error) {
3786203945Sweongyo				device_printf(sc->sc_dev,
3787203945Sweongyo				    "failed to allocate RX buf\n");
3788203945Sweongyo				goto out;	/* XXX wrong! */
3789203945Sweongyo			}
3790203945Sweongyo		}
3791203945Sweongyo
3792203945Sweongyo		bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
3793203945Sweongyo		    BUS_DMASYNC_PREWRITE);
3794203945Sweongyo
3795203945Sweongyo		dr->dr_usedslot = dr->dr_numslots;
3796203945Sweongyo	}
3797203945Sweongyo
3798203945Sweongyo      out:
3799203945Sweongyo	return (dr);
3800203945Sweongyo
3801203945Sweongyofail2:
3802203945Sweongyo	free(dr->dr_txhdr_cache, M_DEVBUF);
3803203945Sweongyofail1:
3804203945Sweongyo	free(dr->dr_meta, M_DEVBUF);
3805203945Sweongyofail0:
3806203945Sweongyo	free(dr, M_DEVBUF);
3807203945Sweongyo	return (NULL);
3808203945Sweongyo}
3809203945Sweongyo
3810203945Sweongyostatic void
3811203945Sweongyobwn_dma_ringfree(struct bwn_dma_ring **dr)
3812203945Sweongyo{
3813203945Sweongyo
3814203945Sweongyo	if (dr == NULL)
3815203945Sweongyo		return;
3816203945Sweongyo
3817203945Sweongyo	bwn_dma_free_descbufs(*dr);
3818203945Sweongyo	bwn_dma_free_ringmemory(*dr);
3819203945Sweongyo
3820203945Sweongyo	free((*dr)->dr_txhdr_cache, M_DEVBUF);
3821203945Sweongyo	free((*dr)->dr_meta, M_DEVBUF);
3822203945Sweongyo	free(*dr, M_DEVBUF);
3823203945Sweongyo
3824203945Sweongyo	*dr = NULL;
3825203945Sweongyo}
3826203945Sweongyo
3827203945Sweongyostatic void
3828203945Sweongyobwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
3829203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
3830203945Sweongyo{
3831203945Sweongyo	struct bwn_dmadesc32 *desc;
3832203945Sweongyo
3833203945Sweongyo	*meta = &(dr->dr_meta[slot]);
3834203945Sweongyo	desc = dr->dr_ring_descbase;
3835203945Sweongyo	desc = &(desc[slot]);
3836203945Sweongyo
3837203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
3838203945Sweongyo}
3839203945Sweongyo
3840203945Sweongyostatic void
3841203945Sweongyobwn_dma_32_setdesc(struct bwn_dma_ring *dr,
3842203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
3843203945Sweongyo    int start, int end, int irq)
3844203945Sweongyo{
3845203945Sweongyo	struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
3846204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
3847203945Sweongyo	uint32_t addr, addrext, ctl;
3848203945Sweongyo	int slot;
3849203945Sweongyo
3850203945Sweongyo	slot = (int)(&(desc->dma.dma32) - descbase);
3851203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
3852203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3853203945Sweongyo
3854203945Sweongyo	addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
3855203945Sweongyo	addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
3856204922Sweongyo	addr |= siba_dma_translation(sc->sc_dev);
3857203945Sweongyo	ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
3858203945Sweongyo	if (slot == dr->dr_numslots - 1)
3859203945Sweongyo		ctl |= BWN_DMA32_DCTL_DTABLEEND;
3860203945Sweongyo	if (start)
3861203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMESTART;
3862203945Sweongyo	if (end)
3863203945Sweongyo		ctl |= BWN_DMA32_DCTL_FRAMEEND;
3864203945Sweongyo	if (irq)
3865203945Sweongyo		ctl |= BWN_DMA32_DCTL_IRQ;
3866203945Sweongyo	ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
3867203945Sweongyo	    & BWN_DMA32_DCTL_ADDREXT_MASK;
3868203945Sweongyo
3869203945Sweongyo	desc->dma.dma32.control = htole32(ctl);
3870203945Sweongyo	desc->dma.dma32.address = htole32(addr);
3871203945Sweongyo}
3872203945Sweongyo
3873203945Sweongyostatic void
3874203945Sweongyobwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
3875203945Sweongyo{
3876203945Sweongyo
3877203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
3878203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
3879203945Sweongyo}
3880203945Sweongyo
3881203945Sweongyostatic void
3882203945Sweongyobwn_dma_32_suspend(struct bwn_dma_ring *dr)
3883203945Sweongyo{
3884203945Sweongyo
3885203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
3886203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
3887203945Sweongyo}
3888203945Sweongyo
3889203945Sweongyostatic void
3890203945Sweongyobwn_dma_32_resume(struct bwn_dma_ring *dr)
3891203945Sweongyo{
3892203945Sweongyo
3893203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
3894203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
3895203945Sweongyo}
3896203945Sweongyo
3897203945Sweongyostatic int
3898203945Sweongyobwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
3899203945Sweongyo{
3900203945Sweongyo	uint32_t val;
3901203945Sweongyo
3902203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
3903203945Sweongyo	val &= BWN_DMA32_RXDPTR;
3904203945Sweongyo
3905203945Sweongyo	return (val / sizeof(struct bwn_dmadesc32));
3906203945Sweongyo}
3907203945Sweongyo
3908203945Sweongyostatic void
3909203945Sweongyobwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
3910203945Sweongyo{
3911203945Sweongyo
3912203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
3913203945Sweongyo	    (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
3914203945Sweongyo}
3915203945Sweongyo
3916203945Sweongyostatic void
3917203945Sweongyobwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
3918203945Sweongyo    struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
3919203945Sweongyo{
3920203945Sweongyo	struct bwn_dmadesc64 *desc;
3921203945Sweongyo
3922203945Sweongyo	*meta = &(dr->dr_meta[slot]);
3923203945Sweongyo	desc = dr->dr_ring_descbase;
3924203945Sweongyo	desc = &(desc[slot]);
3925203945Sweongyo
3926203945Sweongyo	*gdesc = (struct bwn_dmadesc_generic *)desc;
3927203945Sweongyo}
3928203945Sweongyo
3929203945Sweongyostatic void
3930203945Sweongyobwn_dma_64_setdesc(struct bwn_dma_ring *dr,
3931203945Sweongyo    struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
3932203945Sweongyo    int start, int end, int irq)
3933203945Sweongyo{
3934203945Sweongyo	struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
3935204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
3936203945Sweongyo	int slot;
3937203945Sweongyo	uint32_t ctl0 = 0, ctl1 = 0;
3938203945Sweongyo	uint32_t addrlo, addrhi;
3939203945Sweongyo	uint32_t addrext;
3940203945Sweongyo
3941203945Sweongyo	slot = (int)(&(desc->dma.dma64) - descbase);
3942203945Sweongyo	KASSERT(slot >= 0 && slot < dr->dr_numslots,
3943203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
3944203945Sweongyo
3945203945Sweongyo	addrlo = (uint32_t) (dmaaddr & 0xffffffff);
3946203945Sweongyo	addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
3947203945Sweongyo	addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
3948203945Sweongyo	    30;
3949204922Sweongyo	addrhi |= (siba_dma_translation(sc->sc_dev) << 1);
3950203945Sweongyo	if (slot == dr->dr_numslots - 1)
3951203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
3952203945Sweongyo	if (start)
3953203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
3954203945Sweongyo	if (end)
3955203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
3956203945Sweongyo	if (irq)
3957203945Sweongyo		ctl0 |= BWN_DMA64_DCTL0_IRQ;
3958203945Sweongyo	ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
3959203945Sweongyo	ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
3960203945Sweongyo	    & BWN_DMA64_DCTL1_ADDREXT_MASK;
3961203945Sweongyo
3962203945Sweongyo	desc->dma.dma64.control0 = htole32(ctl0);
3963203945Sweongyo	desc->dma.dma64.control1 = htole32(ctl1);
3964203945Sweongyo	desc->dma.dma64.address_low = htole32(addrlo);
3965203945Sweongyo	desc->dma.dma64.address_high = htole32(addrhi);
3966203945Sweongyo}
3967203945Sweongyo
3968203945Sweongyostatic void
3969203945Sweongyobwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
3970203945Sweongyo{
3971203945Sweongyo
3972203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
3973203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
3974203945Sweongyo}
3975203945Sweongyo
3976203945Sweongyostatic void
3977203945Sweongyobwn_dma_64_suspend(struct bwn_dma_ring *dr)
3978203945Sweongyo{
3979203945Sweongyo
3980203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
3981203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
3982203945Sweongyo}
3983203945Sweongyo
3984203945Sweongyostatic void
3985203945Sweongyobwn_dma_64_resume(struct bwn_dma_ring *dr)
3986203945Sweongyo{
3987203945Sweongyo
3988203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
3989203945Sweongyo	    BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
3990203945Sweongyo}
3991203945Sweongyo
3992203945Sweongyostatic int
3993203945Sweongyobwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
3994203945Sweongyo{
3995203945Sweongyo	uint32_t val;
3996203945Sweongyo
3997203945Sweongyo	val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
3998203945Sweongyo	val &= BWN_DMA64_RXSTATDPTR;
3999203945Sweongyo
4000203945Sweongyo	return (val / sizeof(struct bwn_dmadesc64));
4001203945Sweongyo}
4002203945Sweongyo
4003203945Sweongyostatic void
4004203945Sweongyobwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
4005203945Sweongyo{
4006203945Sweongyo
4007203945Sweongyo	BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
4008203945Sweongyo	    (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
4009203945Sweongyo}
4010203945Sweongyo
4011203945Sweongyostatic int
4012203945Sweongyobwn_dma_allocringmemory(struct bwn_dma_ring *dr)
4013203945Sweongyo{
4014203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4015203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4016203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4017203945Sweongyo	int error;
4018203945Sweongyo
4019203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
4020203945Sweongyo			    BWN_ALIGN, 0,
4021203945Sweongyo			    BUS_SPACE_MAXADDR,
4022203945Sweongyo			    BUS_SPACE_MAXADDR,
4023203945Sweongyo			    NULL, NULL,
4024203945Sweongyo			    BWN_DMA_RINGMEMSIZE,
4025203945Sweongyo			    1,
4026203945Sweongyo			    BUS_SPACE_MAXSIZE_32BIT,
4027203945Sweongyo			    0,
4028203945Sweongyo			    NULL, NULL,
4029203945Sweongyo			    &dr->dr_ring_dtag);
4030203945Sweongyo	if (error) {
4031203945Sweongyo		device_printf(sc->sc_dev,
4032203945Sweongyo		    "can't create TX ring DMA tag: TODO frees\n");
4033203945Sweongyo		return (-1);
4034203945Sweongyo	}
4035203945Sweongyo
4036203945Sweongyo	error = bus_dmamem_alloc(dr->dr_ring_dtag,
4037203945Sweongyo	    &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
4038203945Sweongyo	    &dr->dr_ring_dmap);
4039203945Sweongyo	if (error) {
4040203945Sweongyo		device_printf(sc->sc_dev,
4041203945Sweongyo		    "can't allocate DMA mem: TODO frees\n");
4042203945Sweongyo		return (-1);
4043203945Sweongyo	}
4044203945Sweongyo	error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
4045203945Sweongyo	    dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
4046203945Sweongyo	    bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
4047203945Sweongyo	if (error) {
4048203945Sweongyo		device_printf(sc->sc_dev,
4049203945Sweongyo		    "can't load DMA mem: TODO free\n");
4050203945Sweongyo		return (-1);
4051203945Sweongyo	}
4052203945Sweongyo
4053203945Sweongyo	return (0);
4054203945Sweongyo}
4055203945Sweongyo
4056203945Sweongyostatic void
4057203945Sweongyobwn_dma_setup(struct bwn_dma_ring *dr)
4058203945Sweongyo{
4059204922Sweongyo	struct bwn_softc *sc = dr->dr_mac->mac_sc;
4060203945Sweongyo	uint64_t ring64;
4061203945Sweongyo	uint32_t addrext, ring32, value;
4062204922Sweongyo	uint32_t trans = siba_dma_translation(sc->sc_dev);
4063203945Sweongyo
4064203945Sweongyo	if (dr->dr_tx) {
4065203945Sweongyo		dr->dr_curslot = -1;
4066203945Sweongyo
4067203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4068203945Sweongyo			ring64 = (uint64_t)(dr->dr_ring_dmabase);
4069203945Sweongyo			addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
4070203945Sweongyo			    >> 30;
4071203945Sweongyo			value = BWN_DMA64_TXENABLE;
4072203945Sweongyo			value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
4073203945Sweongyo			    & BWN_DMA64_TXADDREXT_MASK;
4074203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
4075203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
4076203945Sweongyo			    (ring64 & 0xffffffff));
4077203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
4078203945Sweongyo			    ((ring64 >> 32) &
4079203945Sweongyo			    ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
4080203945Sweongyo		} else {
4081203945Sweongyo			ring32 = (uint32_t)(dr->dr_ring_dmabase);
4082203945Sweongyo			addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4083203945Sweongyo			value = BWN_DMA32_TXENABLE;
4084203945Sweongyo			value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
4085203945Sweongyo			    & BWN_DMA32_TXADDREXT_MASK;
4086203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
4087203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
4088203945Sweongyo			    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4089203945Sweongyo		}
4090203945Sweongyo		return;
4091203945Sweongyo	}
4092203945Sweongyo
4093203945Sweongyo	/*
4094203945Sweongyo	 * set for RX
4095203945Sweongyo	 */
4096203945Sweongyo	dr->dr_usedslot = dr->dr_numslots;
4097203945Sweongyo
4098203945Sweongyo	if (dr->dr_type == BWN_DMA_64BIT) {
4099203945Sweongyo		ring64 = (uint64_t)(dr->dr_ring_dmabase);
4100203945Sweongyo		addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30;
4101203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT);
4102203945Sweongyo		value |= BWN_DMA64_RXENABLE;
4103203945Sweongyo		value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
4104203945Sweongyo		    & BWN_DMA64_RXADDREXT_MASK;
4105203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
4106203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
4107203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
4108203945Sweongyo		    ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
4109203945Sweongyo		    | (trans << 1));
4110203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
4111203945Sweongyo		    sizeof(struct bwn_dmadesc64));
4112203945Sweongyo	} else {
4113203945Sweongyo		ring32 = (uint32_t)(dr->dr_ring_dmabase);
4114203945Sweongyo		addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
4115203945Sweongyo		value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
4116203945Sweongyo		value |= BWN_DMA32_RXENABLE;
4117203945Sweongyo		value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
4118203945Sweongyo		    & BWN_DMA32_RXADDREXT_MASK;
4119203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
4120203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
4121203945Sweongyo		    (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
4122203945Sweongyo		BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
4123203945Sweongyo		    sizeof(struct bwn_dmadesc32));
4124203945Sweongyo	}
4125203945Sweongyo}
4126203945Sweongyo
4127203945Sweongyostatic void
4128203945Sweongyobwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
4129203945Sweongyo{
4130203945Sweongyo
4131203945Sweongyo	bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
4132203945Sweongyo	bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
4133203945Sweongyo	    dr->dr_ring_dmap);
4134203945Sweongyo}
4135203945Sweongyo
4136203945Sweongyostatic void
4137203945Sweongyobwn_dma_cleanup(struct bwn_dma_ring *dr)
4138203945Sweongyo{
4139203945Sweongyo
4140203945Sweongyo	if (dr->dr_tx) {
4141203945Sweongyo		bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4142203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4143203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
4144203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
4145203945Sweongyo		} else
4146203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
4147203945Sweongyo	} else {
4148203945Sweongyo		bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
4149203945Sweongyo		if (dr->dr_type == BWN_DMA_64BIT) {
4150203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
4151203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
4152203945Sweongyo		} else
4153203945Sweongyo			BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
4154203945Sweongyo	}
4155203945Sweongyo}
4156203945Sweongyo
4157203945Sweongyostatic void
4158203945Sweongyobwn_dma_free_descbufs(struct bwn_dma_ring *dr)
4159203945Sweongyo{
4160203945Sweongyo	struct bwn_dmadesc_generic *desc;
4161203945Sweongyo	struct bwn_dmadesc_meta *meta;
4162203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
4163203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
4164203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4165203945Sweongyo	int i;
4166203945Sweongyo
4167203945Sweongyo	if (!dr->dr_usedslot)
4168203945Sweongyo		return;
4169203945Sweongyo	for (i = 0; i < dr->dr_numslots; i++) {
4170203945Sweongyo		dr->getdesc(dr, i, &desc, &meta);
4171203945Sweongyo
4172203945Sweongyo		if (meta->mt_m == NULL) {
4173203945Sweongyo			if (!dr->dr_tx)
4174203945Sweongyo				device_printf(sc->sc_dev, "%s: not TX?\n",
4175203945Sweongyo				    __func__);
4176203945Sweongyo			continue;
4177203945Sweongyo		}
4178203945Sweongyo		if (dr->dr_tx) {
4179203945Sweongyo			if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
4180203945Sweongyo				bus_dmamap_unload(dr->dr_txring_dtag,
4181203945Sweongyo				    meta->mt_dmap);
4182203945Sweongyo			else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
4183203945Sweongyo				bus_dmamap_unload(dma->txbuf_dtag,
4184203945Sweongyo				    meta->mt_dmap);
4185203945Sweongyo		} else
4186203945Sweongyo			bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
4187203945Sweongyo		bwn_dma_free_descbuf(dr, meta);
4188203945Sweongyo	}
4189203945Sweongyo}
4190203945Sweongyo
4191203945Sweongyostatic int
4192203945Sweongyobwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
4193203945Sweongyo    int type)
4194203945Sweongyo{
4195203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4196203945Sweongyo	uint32_t value;
4197203945Sweongyo	int i;
4198203945Sweongyo	uint16_t offset;
4199203945Sweongyo
4200203945Sweongyo	for (i = 0; i < 10; i++) {
4201203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4202203945Sweongyo		    BWN_DMA32_TXSTATUS;
4203203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4204203945Sweongyo		if (type == BWN_DMA_64BIT) {
4205203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4206203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED ||
4207203945Sweongyo			    value == BWN_DMA64_TXSTAT_IDLEWAIT ||
4208203945Sweongyo			    value == BWN_DMA64_TXSTAT_STOPPED)
4209203945Sweongyo				break;
4210203945Sweongyo		} else {
4211203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4212203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED ||
4213203945Sweongyo			    value == BWN_DMA32_TXSTAT_IDLEWAIT ||
4214203945Sweongyo			    value == BWN_DMA32_TXSTAT_STOPPED)
4215203945Sweongyo				break;
4216203945Sweongyo		}
4217203945Sweongyo		DELAY(1000);
4218203945Sweongyo	}
4219203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
4220203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4221203945Sweongyo	for (i = 0; i < 10; i++) {
4222203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
4223203945Sweongyo						   BWN_DMA32_TXSTATUS;
4224203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4225203945Sweongyo		if (type == BWN_DMA_64BIT) {
4226203945Sweongyo			value &= BWN_DMA64_TXSTAT;
4227203945Sweongyo			if (value == BWN_DMA64_TXSTAT_DISABLED) {
4228203945Sweongyo				i = -1;
4229203945Sweongyo				break;
4230203945Sweongyo			}
4231203945Sweongyo		} else {
4232203945Sweongyo			value &= BWN_DMA32_TXSTATE;
4233203945Sweongyo			if (value == BWN_DMA32_TXSTAT_DISABLED) {
4234203945Sweongyo				i = -1;
4235203945Sweongyo				break;
4236203945Sweongyo			}
4237203945Sweongyo		}
4238203945Sweongyo		DELAY(1000);
4239203945Sweongyo	}
4240203945Sweongyo	if (i != -1) {
4241203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4242203945Sweongyo		return (ENODEV);
4243203945Sweongyo	}
4244203945Sweongyo	DELAY(1000);
4245203945Sweongyo
4246203945Sweongyo	return (0);
4247203945Sweongyo}
4248203945Sweongyo
4249203945Sweongyostatic int
4250203945Sweongyobwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
4251203945Sweongyo    int type)
4252203945Sweongyo{
4253203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4254203945Sweongyo	uint32_t value;
4255203945Sweongyo	int i;
4256203945Sweongyo	uint16_t offset;
4257203945Sweongyo
4258203945Sweongyo	offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
4259203945Sweongyo	BWN_WRITE_4(mac, base + offset, 0);
4260203945Sweongyo	for (i = 0; i < 10; i++) {
4261203945Sweongyo		offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
4262203945Sweongyo		    BWN_DMA32_RXSTATUS;
4263203945Sweongyo		value = BWN_READ_4(mac, base + offset);
4264203945Sweongyo		if (type == BWN_DMA_64BIT) {
4265203945Sweongyo			value &= BWN_DMA64_RXSTAT;
4266203945Sweongyo			if (value == BWN_DMA64_RXSTAT_DISABLED) {
4267203945Sweongyo				i = -1;
4268203945Sweongyo				break;
4269203945Sweongyo			}
4270203945Sweongyo		} else {
4271203945Sweongyo			value &= BWN_DMA32_RXSTATE;
4272203945Sweongyo			if (value == BWN_DMA32_RXSTAT_DISABLED) {
4273203945Sweongyo				i = -1;
4274203945Sweongyo				break;
4275203945Sweongyo			}
4276203945Sweongyo		}
4277203945Sweongyo		DELAY(1000);
4278203945Sweongyo	}
4279203945Sweongyo	if (i != -1) {
4280203945Sweongyo		device_printf(sc->sc_dev, "%s: timed out\n", __func__);
4281203945Sweongyo		return (ENODEV);
4282203945Sweongyo	}
4283203945Sweongyo
4284203945Sweongyo	return (0);
4285203945Sweongyo}
4286203945Sweongyo
4287203945Sweongyostatic void
4288203945Sweongyobwn_dma_free_descbuf(struct bwn_dma_ring *dr,
4289203945Sweongyo    struct bwn_dmadesc_meta *meta)
4290203945Sweongyo{
4291203945Sweongyo
4292203945Sweongyo	if (meta->mt_m != NULL) {
4293203945Sweongyo		m_freem(meta->mt_m);
4294203945Sweongyo		meta->mt_m = NULL;
4295203945Sweongyo	}
4296203945Sweongyo	if (meta->mt_ni != NULL) {
4297203945Sweongyo		ieee80211_free_node(meta->mt_ni);
4298203945Sweongyo		meta->mt_ni = NULL;
4299203945Sweongyo	}
4300203945Sweongyo}
4301203945Sweongyo
4302203945Sweongyostatic void
4303203945Sweongyobwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4304203945Sweongyo{
4305203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
4306203945Sweongyo	unsigned char *frame;
4307203945Sweongyo
4308203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
4309203945Sweongyo	rxhdr->frame_len = 0;
4310203945Sweongyo
4311203945Sweongyo	KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
4312203945Sweongyo	    sizeof(struct bwn_plcp6) + 2,
4313203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4314203945Sweongyo	frame = mtod(m, char *) + dr->dr_frameoffset;
4315203945Sweongyo	memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
4316203945Sweongyo}
4317203945Sweongyo
4318203945Sweongyostatic uint8_t
4319203945Sweongyobwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
4320203945Sweongyo{
4321203945Sweongyo	unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
4322203945Sweongyo
4323203945Sweongyo	return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
4324203945Sweongyo	    == 0xff);
4325203945Sweongyo}
4326203945Sweongyo
4327203945Sweongyostatic void
4328203945Sweongyobwn_wme_init(struct bwn_mac *mac)
4329203945Sweongyo{
4330203945Sweongyo
4331203945Sweongyo	bwn_wme_load(mac);
4332203945Sweongyo
4333203945Sweongyo	/* enable WME support. */
4334203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
4335203945Sweongyo	BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
4336203945Sweongyo	    BWN_IFSCTL_USE_EDCF);
4337203945Sweongyo}
4338203945Sweongyo
4339203945Sweongyostatic void
4340203945Sweongyobwn_spu_setdelay(struct bwn_mac *mac, int idle)
4341203945Sweongyo{
4342203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4343287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4344203945Sweongyo	uint16_t delay;	/* microsec */
4345203945Sweongyo
4346203945Sweongyo	delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
4347203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
4348203945Sweongyo		delay = 500;
4349203945Sweongyo	if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
4350203945Sweongyo		delay = max(delay, (uint16_t)2400);
4351203945Sweongyo
4352203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
4353203945Sweongyo}
4354203945Sweongyo
4355203945Sweongyostatic void
4356203945Sweongyobwn_bt_enable(struct bwn_mac *mac)
4357203945Sweongyo{
4358204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4359203945Sweongyo	uint64_t hf;
4360203945Sweongyo
4361203945Sweongyo	if (bwn_bluetooth == 0)
4362203945Sweongyo		return;
4363204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCOEXIST) == 0)
4364203945Sweongyo		return;
4365203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
4366203945Sweongyo		return;
4367203945Sweongyo
4368203945Sweongyo	hf = bwn_hf_read(mac);
4369204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCMOD)
4370203945Sweongyo		hf |= BWN_HF_BT_COEXISTALT;
4371203945Sweongyo	else
4372203945Sweongyo		hf |= BWN_HF_BT_COEXIST;
4373203945Sweongyo	bwn_hf_write(mac, hf);
4374203945Sweongyo}
4375203945Sweongyo
4376203945Sweongyostatic void
4377203945Sweongyobwn_set_macaddr(struct bwn_mac *mac)
4378203945Sweongyo{
4379203945Sweongyo
4380203945Sweongyo	bwn_mac_write_bssid(mac);
4381287197Sglebius	bwn_mac_setfilter(mac, BWN_MACFILTER_SELF,
4382287197Sglebius	    mac->mac_sc->sc_ic.ic_macaddr);
4383203945Sweongyo}
4384203945Sweongyo
4385203945Sweongyostatic void
4386203945Sweongyobwn_clear_keys(struct bwn_mac *mac)
4387203945Sweongyo{
4388203945Sweongyo	int i;
4389203945Sweongyo
4390203945Sweongyo	for (i = 0; i < mac->mac_max_nr_keys; i++) {
4391203945Sweongyo		KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
4392203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
4393203945Sweongyo
4394203945Sweongyo		bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
4395203945Sweongyo		    NULL, BWN_SEC_KEYSIZE, NULL);
4396203945Sweongyo		if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
4397203945Sweongyo			bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
4398203945Sweongyo			    NULL, BWN_SEC_KEYSIZE, NULL);
4399203945Sweongyo		}
4400203945Sweongyo		mac->mac_key[i].keyconf = NULL;
4401203945Sweongyo	}
4402203945Sweongyo}
4403203945Sweongyo
4404203945Sweongyostatic void
4405203945Sweongyobwn_crypt_init(struct bwn_mac *mac)
4406203945Sweongyo{
4407204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4408203945Sweongyo
4409204922Sweongyo	mac->mac_max_nr_keys = (siba_get_revid(sc->sc_dev) >= 5) ? 58 : 20;
4410203945Sweongyo	KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
4411203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
4412203945Sweongyo	mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
4413203945Sweongyo	mac->mac_ktp *= 2;
4414204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5)
4415204922Sweongyo		BWN_WRITE_2(mac, BWN_RCMTA_COUNT, mac->mac_max_nr_keys - 8);
4416203945Sweongyo	bwn_clear_keys(mac);
4417203945Sweongyo}
4418203945Sweongyo
4419203945Sweongyostatic void
4420203945Sweongyobwn_chip_exit(struct bwn_mac *mac)
4421203945Sweongyo{
4422204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4423203945Sweongyo
4424203945Sweongyo	bwn_phy_exit(mac);
4425204922Sweongyo	siba_gpio_set(sc->sc_dev, 0);
4426203945Sweongyo}
4427203945Sweongyo
4428203945Sweongyostatic int
4429203945Sweongyobwn_fw_fillinfo(struct bwn_mac *mac)
4430203945Sweongyo{
4431203945Sweongyo	int error;
4432203945Sweongyo
4433203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
4434203945Sweongyo	if (error == 0)
4435203945Sweongyo		return (0);
4436203945Sweongyo	error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
4437203945Sweongyo	if (error == 0)
4438203945Sweongyo		return (0);
4439203945Sweongyo	return (error);
4440203945Sweongyo}
4441203945Sweongyo
4442203945Sweongyostatic int
4443203945Sweongyobwn_gpio_init(struct bwn_mac *mac)
4444203945Sweongyo{
4445204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4446204922Sweongyo	uint32_t mask = 0x1f, set = 0xf, value;
4447203945Sweongyo
4448203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
4449203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
4450203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_MASK,
4451203945Sweongyo	    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
4452203945Sweongyo
4453204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x4301) {
4454203945Sweongyo		mask |= 0x0060;
4455203945Sweongyo		set |= 0x0060;
4456203945Sweongyo	}
4457204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL) {
4458203945Sweongyo		BWN_WRITE_2(mac, BWN_GPIO_MASK,
4459203945Sweongyo		    BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
4460203945Sweongyo		mask |= 0x0200;
4461203945Sweongyo		set |= 0x0200;
4462203945Sweongyo	}
4463204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 2)
4464203945Sweongyo		mask |= 0x0010;
4465204922Sweongyo
4466204922Sweongyo	value = siba_gpio_get(sc->sc_dev);
4467204922Sweongyo	if (value == -1)
4468203945Sweongyo		return (0);
4469204922Sweongyo	siba_gpio_set(sc->sc_dev, (value & mask) | set);
4470203945Sweongyo
4471203945Sweongyo	return (0);
4472203945Sweongyo}
4473203945Sweongyo
4474203945Sweongyostatic int
4475203945Sweongyobwn_fw_loadinitvals(struct bwn_mac *mac)
4476203945Sweongyo{
4477203945Sweongyo#define	GETFWOFFSET(fwp, offset)				\
4478203945Sweongyo	((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
4479203945Sweongyo	const size_t hdr_len = sizeof(struct bwn_fwhdr);
4480203945Sweongyo	const struct bwn_fwhdr *hdr;
4481203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
4482203945Sweongyo	int error;
4483203945Sweongyo
4484203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
4485203945Sweongyo	error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
4486203945Sweongyo	    be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
4487203945Sweongyo	if (error)
4488203945Sweongyo		return (error);
4489203945Sweongyo	if (fw->initvals_band.fw) {
4490203945Sweongyo		hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
4491203945Sweongyo		error = bwn_fwinitvals_write(mac,
4492203945Sweongyo		    GETFWOFFSET(fw->initvals_band, hdr_len),
4493203945Sweongyo		    be32toh(hdr->size),
4494203945Sweongyo		    fw->initvals_band.fw->datasize - hdr_len);
4495203945Sweongyo	}
4496203945Sweongyo	return (error);
4497203945Sweongyo#undef GETFWOFFSET
4498203945Sweongyo}
4499203945Sweongyo
4500203945Sweongyostatic int
4501203945Sweongyobwn_phy_init(struct bwn_mac *mac)
4502203945Sweongyo{
4503203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4504203945Sweongyo	int error;
4505203945Sweongyo
4506203945Sweongyo	mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
4507203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
4508203945Sweongyo	error = mac->mac_phy.init(mac);
4509203945Sweongyo	if (error) {
4510203945Sweongyo		device_printf(sc->sc_dev, "PHY init failed\n");
4511203945Sweongyo		goto fail0;
4512203945Sweongyo	}
4513203945Sweongyo	error = bwn_switch_channel(mac,
4514203945Sweongyo	    mac->mac_phy.get_default_chan(mac));
4515203945Sweongyo	if (error) {
4516203945Sweongyo		device_printf(sc->sc_dev,
4517203945Sweongyo		    "failed to switch default channel\n");
4518203945Sweongyo		goto fail1;
4519203945Sweongyo	}
4520203945Sweongyo	return (0);
4521203945Sweongyofail1:
4522203945Sweongyo	if (mac->mac_phy.exit)
4523203945Sweongyo		mac->mac_phy.exit(mac);
4524203945Sweongyofail0:
4525203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
4526203945Sweongyo
4527203945Sweongyo	return (error);
4528203945Sweongyo}
4529203945Sweongyo
4530203945Sweongyostatic void
4531203945Sweongyobwn_set_txantenna(struct bwn_mac *mac, int antenna)
4532203945Sweongyo{
4533203945Sweongyo	uint16_t ant;
4534203945Sweongyo	uint16_t tmp;
4535203945Sweongyo
4536203945Sweongyo	ant = bwn_ant2phy(antenna);
4537203945Sweongyo
4538203945Sweongyo	/* For ACK/CTS */
4539203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
4540203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4541203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
4542203945Sweongyo	/* For Probe Resposes */
4543203945Sweongyo	tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
4544203945Sweongyo	tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
4545203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
4546203945Sweongyo}
4547203945Sweongyo
4548203945Sweongyostatic void
4549203945Sweongyobwn_set_opmode(struct bwn_mac *mac)
4550203945Sweongyo{
4551203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4552287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4553203945Sweongyo	uint32_t ctl;
4554203945Sweongyo	uint16_t cfp_pretbtt;
4555203945Sweongyo
4556203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
4557203945Sweongyo	ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
4558203945Sweongyo	    BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
4559203945Sweongyo	    BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
4560203945Sweongyo	ctl |= BWN_MACCTL_STA;
4561203945Sweongyo
4562203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4563203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
4564203945Sweongyo		ctl |= BWN_MACCTL_HOSTAP;
4565203945Sweongyo	else if (ic->ic_opmode == IEEE80211_M_IBSS)
4566203945Sweongyo		ctl &= ~BWN_MACCTL_STA;
4567203945Sweongyo	ctl |= sc->sc_filters;
4568203945Sweongyo
4569204922Sweongyo	if (siba_get_revid(sc->sc_dev) <= 4)
4570203945Sweongyo		ctl |= BWN_MACCTL_PROMISC;
4571203945Sweongyo
4572203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
4573203945Sweongyo
4574203945Sweongyo	cfp_pretbtt = 2;
4575203945Sweongyo	if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
4576204922Sweongyo		if (siba_get_chipid(sc->sc_dev) == 0x4306 &&
4577204922Sweongyo		    siba_get_chiprev(sc->sc_dev) == 3)
4578203945Sweongyo			cfp_pretbtt = 100;
4579203945Sweongyo		else
4580203945Sweongyo			cfp_pretbtt = 50;
4581203945Sweongyo	}
4582203945Sweongyo	BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
4583203945Sweongyo}
4584203945Sweongyo
4585203945Sweongyostatic int
4586203945Sweongyobwn_dma_gettype(struct bwn_mac *mac)
4587203945Sweongyo{
4588203945Sweongyo	uint32_t tmp;
4589203945Sweongyo	uint16_t base;
4590203945Sweongyo
4591203945Sweongyo	tmp = BWN_READ_4(mac, SIBA_TGSHIGH);
4592203945Sweongyo	if (tmp & SIBA_TGSHIGH_DMA64)
4593203945Sweongyo		return (BWN_DMA_64BIT);
4594203945Sweongyo	base = bwn_dma_base(0, 0);
4595203945Sweongyo	BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK);
4596203945Sweongyo	tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL);
4597203945Sweongyo	if (tmp & BWN_DMA32_TXADDREXT_MASK)
4598203945Sweongyo		return (BWN_DMA_32BIT);
4599203945Sweongyo
4600203945Sweongyo	return (BWN_DMA_30BIT);
4601203945Sweongyo}
4602203945Sweongyo
4603203945Sweongyostatic void
4604203945Sweongyobwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
4605203945Sweongyo{
4606203945Sweongyo	if (!error) {
4607203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
4608203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
4609203945Sweongyo	}
4610203945Sweongyo}
4611203945Sweongyo
4612203945Sweongyostatic void
4613203945Sweongyobwn_phy_g_init_sub(struct bwn_mac *mac)
4614203945Sweongyo{
4615203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4616203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4617204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4618203945Sweongyo	uint16_t i, tmp;
4619203945Sweongyo
4620203945Sweongyo	if (phy->rev == 1)
4621203945Sweongyo		bwn_phy_init_b5(mac);
4622203945Sweongyo	else
4623203945Sweongyo		bwn_phy_init_b6(mac);
4624203945Sweongyo
4625203945Sweongyo	if (phy->rev >= 2 || phy->gmode)
4626203945Sweongyo		bwn_phy_init_a(mac);
4627203945Sweongyo
4628203945Sweongyo	if (phy->rev >= 2) {
4629203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
4630203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
4631203945Sweongyo	}
4632203945Sweongyo	if (phy->rev == 2) {
4633203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
4634203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4635203945Sweongyo	}
4636203945Sweongyo	if (phy->rev > 5) {
4637203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
4638203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
4639203945Sweongyo	}
4640203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4641203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
4642203945Sweongyo		tmp &= BWN_PHYVER_VERSION;
4643203945Sweongyo		if (tmp == 3 || tmp == 5) {
4644203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
4645203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
4646203945Sweongyo		}
4647203945Sweongyo		if (tmp == 5) {
4648203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
4649203945Sweongyo			    0x1f00);
4650203945Sweongyo		}
4651203945Sweongyo	}
4652203945Sweongyo	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
4653203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
4654203945Sweongyo	if (phy->rf_rev == 8) {
4655203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
4656203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
4657203945Sweongyo	}
4658203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
4659203945Sweongyo		bwn_loopback_calcgain(mac);
4660203945Sweongyo
4661203945Sweongyo	if (phy->rf_rev != 8) {
4662203945Sweongyo		if (pg->pg_initval == 0xffff)
4663203945Sweongyo			pg->pg_initval = bwn_rf_init_bcm2050(mac);
4664203945Sweongyo		else
4665203945Sweongyo			BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
4666203945Sweongyo	}
4667203945Sweongyo	bwn_lo_g_init(mac);
4668203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
4669203945Sweongyo		BWN_RF_WRITE(mac, 0x52,
4670203945Sweongyo		    (BWN_RF_READ(mac, 0x52) & 0xff00)
4671203945Sweongyo		    | pg->pg_loctl.tx_bias |
4672203945Sweongyo		    pg->pg_loctl.tx_magn);
4673203945Sweongyo	} else {
4674203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
4675203945Sweongyo	}
4676203945Sweongyo	if (phy->rev >= 6) {
4677203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
4678203945Sweongyo		    (pg->pg_loctl.tx_bias << 12));
4679203945Sweongyo	}
4680204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL)
4681203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
4682203945Sweongyo	else
4683203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
4684203945Sweongyo	if (phy->rev < 2)
4685203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
4686203945Sweongyo	else
4687203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
4688203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4689203945Sweongyo		bwn_lo_g_adjust(mac);
4690203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
4691203945Sweongyo	}
4692203945Sweongyo
4693204922Sweongyo	if (!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
4694203945Sweongyo		for (i = 0; i < 64; i++) {
4695203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
4696203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
4697203945Sweongyo			    (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
4698203945Sweongyo			    -32), 31));
4699203945Sweongyo		}
4700203945Sweongyo		bwn_nrssi_threshold(mac);
4701203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
4702203945Sweongyo		if (pg->pg_nrssi[0] == -1000) {
4703203945Sweongyo			KASSERT(pg->pg_nrssi[1] == -1000,
4704203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
4705203945Sweongyo			bwn_nrssi_slope_11g(mac);
4706203945Sweongyo		} else
4707203945Sweongyo			bwn_nrssi_threshold(mac);
4708203945Sweongyo	}
4709203945Sweongyo	if (phy->rf_rev == 8)
4710203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
4711203945Sweongyo	bwn_phy_hwpctl_init(mac);
4712204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4306
4713204922Sweongyo	     && siba_get_chippkg(sc->sc_dev) == 2) || 0) {
4714203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
4715203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
4716203945Sweongyo	}
4717203945Sweongyo}
4718203945Sweongyo
4719203945Sweongyostatic uint8_t
4720203945Sweongyobwn_has_hwpctl(struct bwn_mac *mac)
4721203945Sweongyo{
4722203945Sweongyo
4723203945Sweongyo	if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
4724203945Sweongyo		return (0);
4725203945Sweongyo	return (mac->mac_phy.use_hwpctl(mac));
4726203945Sweongyo}
4727203945Sweongyo
4728203945Sweongyostatic void
4729203945Sweongyobwn_phy_init_b5(struct bwn_mac *mac)
4730203945Sweongyo{
4731203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4732203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4733204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4734203945Sweongyo	uint16_t offset, value;
4735203945Sweongyo	uint8_t old_channel;
4736203945Sweongyo
4737203945Sweongyo	if (phy->analog == 1)
4738203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0050);
4739204922Sweongyo	if ((siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM) &&
4740204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306)) {
4741203945Sweongyo		value = 0x2120;
4742203945Sweongyo		for (offset = 0x00a8; offset < 0x00c7; offset++) {
4743203945Sweongyo			BWN_PHY_WRITE(mac, offset, value);
4744203945Sweongyo			value += 0x202;
4745203945Sweongyo		}
4746203945Sweongyo	}
4747203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
4748203945Sweongyo	if (phy->rf_ver == 0x2050)
4749203945Sweongyo		BWN_PHY_WRITE(mac, 0x0038, 0x0667);
4750203945Sweongyo
4751203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
4752203945Sweongyo		if (phy->rf_ver == 0x2050) {
4753203945Sweongyo			BWN_RF_SET(mac, 0x007a, 0x0020);
4754203945Sweongyo			BWN_RF_SET(mac, 0x0051, 0x0004);
4755203945Sweongyo		}
4756203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
4757203945Sweongyo
4758203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
4759203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
4760203945Sweongyo
4761203945Sweongyo		BWN_PHY_WRITE(mac, 0x001c, 0x186a);
4762203945Sweongyo
4763203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
4764203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
4765203945Sweongyo		BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
4766203945Sweongyo	}
4767203945Sweongyo
4768203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
4769203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
4770203945Sweongyo
4771203945Sweongyo	if (phy->analog == 1) {
4772203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xce00);
4773203945Sweongyo		BWN_PHY_WRITE(mac, 0x0021, 0x3763);
4774203945Sweongyo		BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
4775203945Sweongyo		BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
4776203945Sweongyo		BWN_PHY_WRITE(mac, 0x0024, 0x037e);
4777203945Sweongyo	} else
4778203945Sweongyo		BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
4779203945Sweongyo	BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
4780203945Sweongyo	BWN_WRITE_2(mac, 0x03ec, 0x3f22);
4781203945Sweongyo
4782203945Sweongyo	if (phy->analog == 1)
4783203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
4784203945Sweongyo	else
4785203945Sweongyo		BWN_PHY_WRITE(mac, 0x0020, 0x301c);
4786203945Sweongyo
4787203945Sweongyo	if (phy->analog == 0)
4788203945Sweongyo		BWN_WRITE_2(mac, 0x03e4, 0x3000);
4789203945Sweongyo
4790203945Sweongyo	old_channel = phy->chan;
4791203945Sweongyo	bwn_phy_g_switch_chan(mac, 7, 0);
4792203945Sweongyo
4793203945Sweongyo	if (phy->rf_ver != 0x2050) {
4794203945Sweongyo		BWN_RF_WRITE(mac, 0x0075, 0x0080);
4795203945Sweongyo		BWN_RF_WRITE(mac, 0x0079, 0x0081);
4796203945Sweongyo	}
4797203945Sweongyo
4798203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
4799203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
4800203945Sweongyo
4801203945Sweongyo	if (phy->rf_ver == 0x2050) {
4802203945Sweongyo		BWN_RF_WRITE(mac, 0x0050, 0x0020);
4803203945Sweongyo		BWN_RF_WRITE(mac, 0x005a, 0x0070);
4804203945Sweongyo	}
4805203945Sweongyo
4806203945Sweongyo	BWN_RF_WRITE(mac, 0x005b, 0x007b);
4807203945Sweongyo	BWN_RF_WRITE(mac, 0x005c, 0x00b0);
4808203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0007);
4809203945Sweongyo
4810203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
4811203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0080);
4812203945Sweongyo	BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
4813203945Sweongyo	BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
4814203945Sweongyo
4815203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
4816203945Sweongyo	    pg->pg_txctl);
4817203945Sweongyo
4818203945Sweongyo	if (phy->rf_ver == 0x2050)
4819203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
4820203945Sweongyo
4821203945Sweongyo	BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
4822203945Sweongyo}
4823203945Sweongyo
4824203945Sweongyostatic void
4825203945Sweongyobwn_loopback_calcgain(struct bwn_mac *mac)
4826203945Sweongyo{
4827203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4828203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
4829204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
4830203945Sweongyo	uint16_t backup_phy[16] = { 0 };
4831203945Sweongyo	uint16_t backup_radio[3];
4832203945Sweongyo	uint16_t backup_bband;
4833203945Sweongyo	uint16_t i, j, loop_i_max;
4834203945Sweongyo	uint16_t trsw_rx;
4835203945Sweongyo	uint16_t loop1_outer_done, loop1_inner_done;
4836203945Sweongyo
4837203945Sweongyo	backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
4838203945Sweongyo	backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
4839203945Sweongyo	backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
4840203945Sweongyo	backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
4841203945Sweongyo	if (phy->rev != 1) {
4842203945Sweongyo		backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
4843203945Sweongyo		backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
4844203945Sweongyo	}
4845203945Sweongyo	backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
4846203945Sweongyo	backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
4847203945Sweongyo	backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
4848203945Sweongyo	backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
4849203945Sweongyo	backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
4850203945Sweongyo	backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
4851203945Sweongyo	backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
4852203945Sweongyo	backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
4853203945Sweongyo	backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
4854203945Sweongyo	backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
4855203945Sweongyo	backup_bband = pg->pg_bbatt.att;
4856203945Sweongyo	backup_radio[0] = BWN_RF_READ(mac, 0x52);
4857203945Sweongyo	backup_radio[1] = BWN_RF_READ(mac, 0x43);
4858203945Sweongyo	backup_radio[2] = BWN_RF_READ(mac, 0x7a);
4859203945Sweongyo
4860203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
4861203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
4862203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
4863203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
4864203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
4865203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
4866203945Sweongyo	if (phy->rev != 1) {
4867203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
4868203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
4869203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
4870203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
4871203945Sweongyo	}
4872203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
4873203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
4874203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
4875203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
4876203945Sweongyo
4877203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
4878203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
4879203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
4880203945Sweongyo
4881203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
4882203945Sweongyo	if (phy->rev != 1) {
4883203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
4884203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
4885203945Sweongyo	}
4886203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
4887203945Sweongyo
4888203945Sweongyo	if (phy->rf_rev == 8)
4889203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x000f);
4890203945Sweongyo	else {
4891203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
4892203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
4893203945Sweongyo	}
4894203945Sweongyo	bwn_phy_g_set_bbatt(mac, 11);
4895203945Sweongyo
4896203945Sweongyo	if (phy->rev >= 3)
4897203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
4898203945Sweongyo	else
4899203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
4900203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
4901203945Sweongyo
4902203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
4903203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
4904203945Sweongyo
4905203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
4906203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
4907203945Sweongyo
4908204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) {
4909203945Sweongyo		if (phy->rev >= 7) {
4910203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
4911203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
4912203945Sweongyo		}
4913203945Sweongyo	}
4914203945Sweongyo	BWN_RF_MASK(mac, 0x7a, 0x00f7);
4915203945Sweongyo
4916203945Sweongyo	j = 0;
4917203945Sweongyo	loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
4918203945Sweongyo	for (i = 0; i < loop_i_max; i++) {
4919203945Sweongyo		for (j = 0; j < 16; j++) {
4920203945Sweongyo			BWN_RF_WRITE(mac, 0x43, i);
4921203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
4922203945Sweongyo			    (j << 8));
4923203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
4924203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
4925203945Sweongyo			DELAY(20);
4926203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
4927203945Sweongyo				goto done0;
4928203945Sweongyo		}
4929203945Sweongyo	}
4930203945Sweongyodone0:
4931203945Sweongyo	loop1_outer_done = i;
4932203945Sweongyo	loop1_inner_done = j;
4933203945Sweongyo	if (j >= 8) {
4934203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
4935203945Sweongyo		trsw_rx = 0x1b;
4936203945Sweongyo		for (j = j - 8; j < 16; j++) {
4937203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
4938203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
4939203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
4940203945Sweongyo			DELAY(20);
4941203945Sweongyo			trsw_rx -= 3;
4942203945Sweongyo			if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
4943203945Sweongyo				goto done1;
4944203945Sweongyo		}
4945203945Sweongyo	} else
4946203945Sweongyo		trsw_rx = 0x18;
4947203945Sweongyodone1:
4948203945Sweongyo
4949203945Sweongyo	if (phy->rev != 1) {
4950203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
4951203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
4952203945Sweongyo	}
4953203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
4954203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
4955203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
4956203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
4957203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
4958203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
4959203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
4960203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
4961203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
4962203945Sweongyo
4963203945Sweongyo	bwn_phy_g_set_bbatt(mac, backup_bband);
4964203945Sweongyo
4965203945Sweongyo	BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
4966203945Sweongyo	BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
4967203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
4968203945Sweongyo
4969203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
4970203945Sweongyo	DELAY(10);
4971203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
4972203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
4973203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
4974203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
4975203945Sweongyo
4976203945Sweongyo	pg->pg_max_lb_gain =
4977203945Sweongyo	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
4978203945Sweongyo	pg->pg_trsw_rx_gain = trsw_rx * 2;
4979203945Sweongyo}
4980203945Sweongyo
4981203945Sweongyostatic uint16_t
4982203945Sweongyobwn_rf_init_bcm2050(struct bwn_mac *mac)
4983203945Sweongyo{
4984203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
4985203945Sweongyo	uint32_t tmp1 = 0, tmp2 = 0;
4986203945Sweongyo	uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
4987203945Sweongyo	    analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
4988203945Sweongyo	    radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
4989203945Sweongyo	static const uint8_t rcc_table[] = {
4990203945Sweongyo		0x02, 0x03, 0x01, 0x0f,
4991203945Sweongyo		0x06, 0x07, 0x05, 0x0f,
4992203945Sweongyo		0x0a, 0x0b, 0x09, 0x0f,
4993203945Sweongyo		0x0e, 0x0f, 0x0d, 0x0f,
4994203945Sweongyo	};
4995203945Sweongyo
4996204242Simp	loctl = lomask = reg0 = classctl = crs0 = analogoverval = analogover =
4997204242Simp	    rfoverval = rfover = cck3 = 0;
4998203945Sweongyo	radio0 = BWN_RF_READ(mac, 0x43);
4999203945Sweongyo	radio1 = BWN_RF_READ(mac, 0x51);
5000203945Sweongyo	radio2 = BWN_RF_READ(mac, 0x52);
5001203945Sweongyo	pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
5002203945Sweongyo	cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
5003203945Sweongyo	cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
5004203945Sweongyo	cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
5005203945Sweongyo
5006203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5007203945Sweongyo		cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
5008203945Sweongyo		reg0 = BWN_READ_2(mac, 0x3ec);
5009203945Sweongyo
5010203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
5011203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
5012203945Sweongyo	} else if (phy->gmode || phy->rev >= 2) {
5013203945Sweongyo		rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
5014203945Sweongyo		rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
5015203945Sweongyo		analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
5016203945Sweongyo		analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
5017203945Sweongyo		crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
5018203945Sweongyo		classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
5019203945Sweongyo
5020203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
5021203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
5022203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
5023203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
5024203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5025203945Sweongyo			lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
5026203945Sweongyo			loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
5027203945Sweongyo			if (phy->rev >= 3)
5028203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
5029203945Sweongyo			else
5030203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
5031203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
5032203945Sweongyo		}
5033203945Sweongyo
5034203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5035203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5036203945Sweongyo			BWN_LPD(0, 1, 1)));
5037203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
5038203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
5039203945Sweongyo	}
5040203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
5041203945Sweongyo
5042203945Sweongyo	syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
5043203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
5044203945Sweongyo	reg1 = BWN_READ_2(mac, 0x3e6);
5045203945Sweongyo	reg2 = BWN_READ_2(mac, 0x3f4);
5046203945Sweongyo
5047203945Sweongyo	if (phy->analog == 0)
5048203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0122);
5049203945Sweongyo	else {
5050203945Sweongyo		if (phy->analog >= 2)
5051203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
5052203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
5053203945Sweongyo		    (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
5054203945Sweongyo	}
5055203945Sweongyo
5056203945Sweongyo	reg = BWN_RF_READ(mac, 0x60);
5057203945Sweongyo	index = (reg & 0x001e) >> 1;
5058203945Sweongyo	rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
5059203945Sweongyo
5060203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5061203945Sweongyo		BWN_RF_WRITE(mac, 0x78, 0x26);
5062203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5063203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5064203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5065203945Sweongyo			BWN_LPD(0, 1, 1)));
5066203945Sweongyo	}
5067203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
5068203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
5069203945Sweongyo	if (phy->gmode || phy->rev >= 2) {
5070203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5071203945Sweongyo		    bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
5072203945Sweongyo			BWN_LPD(0, 0, 1)));
5073203945Sweongyo	}
5074203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
5075203945Sweongyo	BWN_RF_SET(mac, 0x51, 0x0004);
5076203945Sweongyo	if (phy->rf_rev == 8)
5077203945Sweongyo		BWN_RF_WRITE(mac, 0x43, 0x1f);
5078203945Sweongyo	else {
5079203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0);
5080203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
5081203945Sweongyo	}
5082203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5083203945Sweongyo
5084203945Sweongyo	for (i = 0; i < 16; i++) {
5085203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
5086203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5087203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5088203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5089203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5090203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5091203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5092203945Sweongyo		}
5093203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5094203945Sweongyo		DELAY(10);
5095203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5096203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5097203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5098203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5099203945Sweongyo		}
5100203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5101203945Sweongyo		DELAY(10);
5102203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5103203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5104203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5105203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5106203945Sweongyo		}
5107203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5108203945Sweongyo		DELAY(20);
5109203945Sweongyo		tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5110203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5111203945Sweongyo		if (phy->gmode || phy->rev >= 2) {
5112203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5113203945Sweongyo			    bwn_rf_2050_rfoverval(mac,
5114203945Sweongyo				BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5115203945Sweongyo		}
5116203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5117203945Sweongyo	}
5118203945Sweongyo	DELAY(10);
5119203945Sweongyo
5120203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5121203945Sweongyo	tmp1++;
5122203945Sweongyo	tmp1 >>= 9;
5123203945Sweongyo
5124203945Sweongyo	for (i = 0; i < 16; i++) {
5125203945Sweongyo		radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
5126203945Sweongyo		BWN_RF_WRITE(mac, 0x78, radio78);
5127203945Sweongyo		DELAY(10);
5128203945Sweongyo		for (j = 0; j < 16; j++) {
5129203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
5130203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
5131203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
5132203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5133203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5134203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5135203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5136203945Sweongyo			}
5137203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5138203945Sweongyo			DELAY(10);
5139203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5140203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5141203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5142203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5143203945Sweongyo			}
5144203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
5145203945Sweongyo			DELAY(10);
5146203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5147203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5148203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5149203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
5150203945Sweongyo			}
5151203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
5152203945Sweongyo			DELAY(10);
5153203945Sweongyo			tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5154203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
5155203945Sweongyo			if (phy->gmode || phy->rev >= 2) {
5156203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
5157203945Sweongyo				    bwn_rf_2050_rfoverval(mac,
5158203945Sweongyo					BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
5159203945Sweongyo			}
5160203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
5161203945Sweongyo		}
5162203945Sweongyo		tmp2++;
5163203945Sweongyo		tmp2 >>= 8;
5164203945Sweongyo		if (tmp1 < tmp2)
5165203945Sweongyo			break;
5166203945Sweongyo	}
5167203945Sweongyo
5168203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
5169203945Sweongyo	BWN_RF_WRITE(mac, 0x51, radio1);
5170203945Sweongyo	BWN_RF_WRITE(mac, 0x52, radio2);
5171203945Sweongyo	BWN_RF_WRITE(mac, 0x43, radio0);
5172203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
5173203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
5174203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
5175203945Sweongyo	BWN_WRITE_2(mac, 0x3e6, reg1);
5176203945Sweongyo	if (phy->analog != 0)
5177203945Sweongyo		BWN_WRITE_2(mac, 0x3f4, reg2);
5178203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
5179203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
5180203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5181203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
5182203945Sweongyo		BWN_WRITE_2(mac, 0x3ec, reg0);
5183203945Sweongyo	} else if (phy->gmode) {
5184203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY_RADIO,
5185203945Sweongyo			    BWN_READ_2(mac, BWN_PHY_RADIO)
5186203945Sweongyo			    & 0x7fff);
5187203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
5188203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
5189203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
5190203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
5191203945Sweongyo			      analogoverval);
5192203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
5193203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
5194203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
5195203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
5196203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
5197203945Sweongyo		}
5198203945Sweongyo	}
5199203945Sweongyo
5200203945Sweongyo	return ((i > 15) ? radio78 : rcc);
5201203945Sweongyo}
5202203945Sweongyo
5203203945Sweongyostatic void
5204203945Sweongyobwn_phy_init_b6(struct bwn_mac *mac)
5205203945Sweongyo{
5206203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5207203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5208204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5209203945Sweongyo	uint16_t offset, val;
5210203945Sweongyo	uint8_t old_channel;
5211203945Sweongyo
5212203945Sweongyo	KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
5213203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5214203945Sweongyo
5215203945Sweongyo	BWN_PHY_WRITE(mac, 0x003e, 0x817a);
5216203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
5217203945Sweongyo	if (phy->rf_rev == 4 || phy->rf_rev == 5) {
5218203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0x37);
5219203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x70);
5220203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb3);
5221203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x9b);
5222203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5223203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x88);
5224203945Sweongyo		BWN_RF_WRITE(mac, 0x5d, 0x88);
5225203945Sweongyo		BWN_RF_WRITE(mac, 0x5e, 0x88);
5226203945Sweongyo		BWN_RF_WRITE(mac, 0x7d, 0x88);
5227203945Sweongyo		bwn_hf_write(mac,
5228203945Sweongyo		    bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
5229203945Sweongyo	}
5230203945Sweongyo	if (phy->rf_rev == 8) {
5231203945Sweongyo		BWN_RF_WRITE(mac, 0x51, 0);
5232203945Sweongyo		BWN_RF_WRITE(mac, 0x52, 0x40);
5233203945Sweongyo		BWN_RF_WRITE(mac, 0x53, 0xb7);
5234203945Sweongyo		BWN_RF_WRITE(mac, 0x54, 0x98);
5235203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x88);
5236203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x6b);
5237203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0x0f);
5238204922Sweongyo		if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_ALTIQ) {
5239203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xfa);
5240203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xd8);
5241203945Sweongyo		} else {
5242203945Sweongyo			BWN_RF_WRITE(mac, 0x5d, 0xf5);
5243203945Sweongyo			BWN_RF_WRITE(mac, 0x5e, 0xb8);
5244203945Sweongyo		}
5245203945Sweongyo		BWN_RF_WRITE(mac, 0x0073, 0x0003);
5246203945Sweongyo		BWN_RF_WRITE(mac, 0x007d, 0x00a8);
5247203945Sweongyo		BWN_RF_WRITE(mac, 0x007c, 0x0001);
5248203945Sweongyo		BWN_RF_WRITE(mac, 0x007e, 0x0008);
5249203945Sweongyo	}
5250203945Sweongyo	for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
5251203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5252203945Sweongyo		val -= 0x0202;
5253203945Sweongyo	}
5254203945Sweongyo	for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
5255203945Sweongyo		BWN_PHY_WRITE(mac, offset, val);
5256203945Sweongyo		val -= 0x0202;
5257203945Sweongyo	}
5258203945Sweongyo	for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
5259203945Sweongyo		BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
5260203945Sweongyo		val += 0x0202;
5261203945Sweongyo	}
5262203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
5263203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x0020);
5264203945Sweongyo		BWN_RF_SET(mac, 0x0051, 0x0004);
5265203945Sweongyo		BWN_PHY_SET(mac, 0x0802, 0x0100);
5266203945Sweongyo		BWN_PHY_SET(mac, 0x042b, 0x2000);
5267203945Sweongyo		BWN_PHY_WRITE(mac, 0x5b, 0);
5268203945Sweongyo		BWN_PHY_WRITE(mac, 0x5c, 0);
5269203945Sweongyo	}
5270203945Sweongyo
5271203945Sweongyo	old_channel = phy->chan;
5272203945Sweongyo	bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
5273203945Sweongyo
5274203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0020);
5275203945Sweongyo	BWN_RF_WRITE(mac, 0x0050, 0x0023);
5276203945Sweongyo	DELAY(40);
5277203945Sweongyo	if (phy->rf_rev < 6 || phy->rf_rev == 8) {
5278203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
5279203945Sweongyo		BWN_RF_WRITE(mac, 0x50, 0x20);
5280203945Sweongyo	}
5281203945Sweongyo	if (phy->rf_rev <= 2) {
5282203945Sweongyo		BWN_RF_WRITE(mac, 0x7c, 0x20);
5283203945Sweongyo		BWN_RF_WRITE(mac, 0x5a, 0x70);
5284203945Sweongyo		BWN_RF_WRITE(mac, 0x5b, 0x7b);
5285203945Sweongyo		BWN_RF_WRITE(mac, 0x5c, 0xb0);
5286203945Sweongyo	}
5287203945Sweongyo	BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
5288203945Sweongyo
5289203945Sweongyo	bwn_phy_g_switch_chan(mac, old_channel, 0);
5290203945Sweongyo
5291203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0200);
5292203945Sweongyo	if (phy->rf_rev >= 6)
5293203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
5294203945Sweongyo	else
5295203945Sweongyo		BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
5296203945Sweongyo	BWN_PHY_WRITE(mac, 0x0038, 0x0668);
5297203945Sweongyo	bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
5298203945Sweongyo	    pg->pg_txctl);
5299203945Sweongyo	if (phy->rf_rev <= 5)
5300203945Sweongyo		BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
5301203945Sweongyo	if (phy->rf_rev <= 2)
5302203945Sweongyo		BWN_RF_WRITE(mac, 0x005d, 0x000d);
5303203945Sweongyo
5304203945Sweongyo	if (phy->analog == 4) {
5305203945Sweongyo		BWN_WRITE_2(mac, 0x3e4, 9);
5306203945Sweongyo		BWN_PHY_MASK(mac, 0x61, 0x0fff);
5307203945Sweongyo	} else
5308203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
5309203945Sweongyo	if (phy->type == BWN_PHYTYPE_B)
5310203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5311203945Sweongyo	else if (phy->type == BWN_PHYTYPE_G)
5312203945Sweongyo		BWN_WRITE_2(mac, 0x03e6, 0x0);
5313203945Sweongyo}
5314203945Sweongyo
5315203945Sweongyostatic void
5316203945Sweongyobwn_phy_init_a(struct bwn_mac *mac)
5317203945Sweongyo{
5318203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5319204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5320203945Sweongyo
5321203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
5322203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5323203945Sweongyo
5324203945Sweongyo	if (phy->rev >= 6) {
5325203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5326203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
5327203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
5328203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
5329203945Sweongyo		else
5330203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
5331203945Sweongyo	}
5332203945Sweongyo
5333203945Sweongyo	bwn_wa_init(mac);
5334203945Sweongyo
5335203945Sweongyo	if (phy->type == BWN_PHYTYPE_G &&
5336204922Sweongyo	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL))
5337203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
5338203945Sweongyo}
5339203945Sweongyo
5340203945Sweongyostatic void
5341203945Sweongyobwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
5342203945Sweongyo{
5343203945Sweongyo	int i;
5344203945Sweongyo
5345203945Sweongyo	for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
5346203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
5347203945Sweongyo}
5348203945Sweongyo
5349203945Sweongyostatic void
5350203945Sweongyobwn_wa_agc(struct bwn_mac *mac)
5351203945Sweongyo{
5352203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5353203945Sweongyo
5354203945Sweongyo	if (phy->rev == 1) {
5355203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
5356203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
5357203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
5358203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
5359203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
5360203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
5361203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
5362203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
5363203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
5364203945Sweongyo	} else {
5365203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
5366203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
5367203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
5368203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
5369203945Sweongyo	}
5370203945Sweongyo
5371203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
5372203945Sweongyo	    0x5700);
5373203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
5374203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
5375203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
5376203945Sweongyo	BWN_RF_SET(mac, 0x7a, 0x0008);
5377203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
5378203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
5379203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
5380203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
5381203945Sweongyo	if (phy->rev == 1)
5382203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
5383203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
5384203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
5385203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
5386203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
5387203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
5388203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
5389203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
5390203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
5391203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
5392203945Sweongyo	if (phy->rev == 1) {
5393203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
5394203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
5395203945Sweongyo	} else {
5396203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
5397203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
5398203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
5399203945Sweongyo		if (phy->rev >= 6) {
5400203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
5401203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
5402203945Sweongyo			    (uint16_t)~0xf000, 0x3000);
5403203945Sweongyo		}
5404203945Sweongyo	}
5405203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
5406203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
5407203945Sweongyo	if (phy->rev == 1) {
5408203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
5409203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
5410203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
5411203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
5412203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
5413203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
5414203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
5415203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
5416203945Sweongyo	} else {
5417203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
5418203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
5419203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
5420203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
5421203945Sweongyo	}
5422203945Sweongyo	if (phy->rev >= 6) {
5423203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
5424203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
5425203945Sweongyo	}
5426203945Sweongyo	BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
5427203945Sweongyo}
5428203945Sweongyo
5429203945Sweongyostatic void
5430203945Sweongyobwn_wa_grev1(struct bwn_mac *mac)
5431203945Sweongyo{
5432203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5433203945Sweongyo	int i;
5434203945Sweongyo	static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
5435203945Sweongyo	static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
5436203945Sweongyo	static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
5437203945Sweongyo
5438203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5439203945Sweongyo
5440203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5441203945Sweongyo	if (phy->rev == 1) {
5442203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5443203945Sweongyo	} else if (phy->rev == 2) {
5444203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5445203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5446203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5447203945Sweongyo	} else {
5448203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5449203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5450203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5451203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5452203945Sweongyo	}
5453203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
5454203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
5455203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
5456203945Sweongyo
5457203945Sweongyo	/* XXX support PHY-A??? */
5458203945Sweongyo	for (i = 0; i < N(bwn_tab_finefreqg); i++)
5459203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
5460203945Sweongyo		    bwn_tab_finefreqg[i]);
5461203945Sweongyo
5462203945Sweongyo	/* XXX support PHY-A??? */
5463203945Sweongyo	if (phy->rev == 1)
5464203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5465203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5466203945Sweongyo			    bwn_tab_noise_g1[i]);
5467203945Sweongyo	else
5468203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5469203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5470203945Sweongyo			    bwn_tab_noise_g2[i]);
5471203945Sweongyo
5472203945Sweongyo
5473203945Sweongyo	for (i = 0; i < N(bwn_tab_rotor); i++)
5474203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
5475203945Sweongyo		    bwn_tab_rotor[i]);
5476203945Sweongyo
5477203945Sweongyo	/* XXX support PHY-A??? */
5478203945Sweongyo	if (phy->rev >= 6) {
5479203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5480203945Sweongyo		    BWN_PHY_ENCORE_EN)
5481203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5482203945Sweongyo		else
5483203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5484203945Sweongyo	} else
5485203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5486203945Sweongyo
5487203945Sweongyo	for (i = 0; i < N(bwn_tab_retard); i++)
5488203945Sweongyo		bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
5489203945Sweongyo		    bwn_tab_retard[i]);
5490203945Sweongyo
5491203945Sweongyo	if (phy->rev == 1) {
5492203945Sweongyo		for (i = 0; i < 16; i++)
5493203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
5494203945Sweongyo			    i, 0x0020);
5495203945Sweongyo	} else {
5496203945Sweongyo		for (i = 0; i < 32; i++)
5497203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5498203945Sweongyo	}
5499203945Sweongyo
5500203945Sweongyo	bwn_wa_agc(mac);
5501203945Sweongyo}
5502203945Sweongyo
5503203945Sweongyostatic void
5504203945Sweongyobwn_wa_grev26789(struct bwn_mac *mac)
5505203945Sweongyo{
5506203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5507203945Sweongyo	int i;
5508203945Sweongyo	static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
5509203945Sweongyo	uint16_t ofdmrev;
5510203945Sweongyo
5511203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5512203945Sweongyo
5513203945Sweongyo	bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
5514203945Sweongyo
5515203945Sweongyo	/* init CRSTHRES and ANTDWELL */
5516203945Sweongyo	if (phy->rev == 1)
5517203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
5518203945Sweongyo	else if (phy->rev == 2) {
5519203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
5520203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
5521203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5522203945Sweongyo	} else {
5523203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
5524203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
5525203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
5526203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
5527203945Sweongyo	}
5528203945Sweongyo
5529203945Sweongyo	for (i = 0; i < 64; i++)
5530203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
5531203945Sweongyo
5532203945Sweongyo	/* XXX support PHY-A??? */
5533203945Sweongyo	if (phy->rev == 1)
5534203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g1); i++)
5535203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5536203945Sweongyo			    bwn_tab_noise_g1[i]);
5537203945Sweongyo	else
5538203945Sweongyo		for (i = 0; i < N(bwn_tab_noise_g2); i++)
5539203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
5540203945Sweongyo			    bwn_tab_noise_g2[i]);
5541203945Sweongyo
5542203945Sweongyo	/* XXX support PHY-A??? */
5543203945Sweongyo	if (phy->rev >= 6) {
5544203945Sweongyo		if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
5545203945Sweongyo		    BWN_PHY_ENCORE_EN)
5546203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
5547203945Sweongyo		else
5548203945Sweongyo			bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
5549203945Sweongyo	} else
5550203945Sweongyo		bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
5551203945Sweongyo
5552203945Sweongyo	for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
5553203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
5554203945Sweongyo		    bwn_tab_sigmasqr2[i]);
5555203945Sweongyo
5556203945Sweongyo	if (phy->rev == 1) {
5557203945Sweongyo		for (i = 0; i < 16; i++)
5558203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
5559203945Sweongyo			    0x0020);
5560203945Sweongyo	} else {
5561203945Sweongyo		for (i = 0; i < 32; i++)
5562203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
5563203945Sweongyo	}
5564203945Sweongyo
5565203945Sweongyo	bwn_wa_agc(mac);
5566203945Sweongyo
5567203945Sweongyo	ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
5568203945Sweongyo	if (ofdmrev > 2) {
5569203945Sweongyo		if (phy->type == BWN_PHYTYPE_A)
5570203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
5571203945Sweongyo		else
5572203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
5573203945Sweongyo	} else {
5574203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
5575203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
5576203945Sweongyo		bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
5577203945Sweongyo	}
5578203945Sweongyo
5579203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
5580203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
5581203945Sweongyo}
5582203945Sweongyo
5583203945Sweongyostatic void
5584203945Sweongyobwn_wa_init(struct bwn_mac *mac)
5585203945Sweongyo{
5586203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5587204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5588203945Sweongyo
5589203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
5590203945Sweongyo
5591203945Sweongyo	switch (phy->rev) {
5592203945Sweongyo	case 1:
5593203945Sweongyo		bwn_wa_grev1(mac);
5594203945Sweongyo		break;
5595203945Sweongyo	case 2:
5596203945Sweongyo	case 6:
5597203945Sweongyo	case 7:
5598203945Sweongyo	case 8:
5599203945Sweongyo	case 9:
5600203945Sweongyo		bwn_wa_grev26789(mac);
5601203945Sweongyo		break;
5602203945Sweongyo	default:
5603203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
5604203945Sweongyo	}
5605203945Sweongyo
5606204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) != SIBA_BOARDVENDOR_BCM ||
5607204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) != SIBA_BOARD_BU4306 ||
5608204922Sweongyo	    siba_get_pci_revid(sc->sc_dev) != 0x17) {
5609203945Sweongyo		if (phy->rev < 2) {
5610203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
5611203945Sweongyo			    0x0002);
5612203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
5613203945Sweongyo			    0x0001);
5614203945Sweongyo		} else {
5615203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
5616203945Sweongyo			bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
5617204922Sweongyo			if ((siba_sprom_get_bf_lo(sc->sc_dev) &
5618204922Sweongyo			     BWN_BFL_EXTLNA) &&
5619203945Sweongyo			    (phy->rev >= 7)) {
5620203945Sweongyo				BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
5621203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5622203945Sweongyo				    0x0020, 0x0001);
5623203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5624203945Sweongyo				    0x0021, 0x0001);
5625203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5626203945Sweongyo				    0x0022, 0x0001);
5627203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5628203945Sweongyo				    0x0023, 0x0000);
5629203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5630203945Sweongyo				    0x0000, 0x0000);
5631203945Sweongyo				bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
5632203945Sweongyo				    0x0003, 0x0002);
5633203945Sweongyo			}
5634203945Sweongyo		}
5635203945Sweongyo	}
5636204922Sweongyo	if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) {
5637203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
5638203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
5639203945Sweongyo	}
5640203945Sweongyo
5641203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
5642203945Sweongyo	bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
5643203945Sweongyo}
5644203945Sweongyo
5645203945Sweongyostatic void
5646203945Sweongyobwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5647203945Sweongyo    uint16_t value)
5648203945Sweongyo{
5649203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5650203945Sweongyo	uint16_t addr;
5651203945Sweongyo
5652203945Sweongyo	addr = table + offset;
5653203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5654203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5655203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5656203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5657203945Sweongyo	}
5658203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5659203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5660203945Sweongyo}
5661203945Sweongyo
5662203945Sweongyostatic void
5663203945Sweongyobwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5664203945Sweongyo    uint32_t value)
5665203945Sweongyo{
5666203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
5667203945Sweongyo	uint16_t addr;
5668203945Sweongyo
5669203945Sweongyo	addr = table + offset;
5670203945Sweongyo	if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
5671203945Sweongyo	    (addr - 1 != pg->pg_ofdmtab_addr)) {
5672203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
5673203945Sweongyo		pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
5674203945Sweongyo	}
5675203945Sweongyo	pg->pg_ofdmtab_addr = addr;
5676203945Sweongyo
5677203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
5678203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
5679203945Sweongyo}
5680203945Sweongyo
5681203945Sweongyostatic void
5682203945Sweongyobwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
5683203945Sweongyo    uint16_t value)
5684203945Sweongyo{
5685203945Sweongyo
5686203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
5687203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
5688203945Sweongyo}
5689203945Sweongyo
5690203945Sweongyostatic void
5691203945Sweongyobwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
5692203945Sweongyo{
5693203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5694204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5695203945Sweongyo	unsigned int i, max_loop;
5696203945Sweongyo	uint16_t value;
5697203945Sweongyo	uint32_t buffer[5] = {
5698203945Sweongyo		0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
5699203945Sweongyo	};
5700203945Sweongyo
5701203945Sweongyo	if (ofdm) {
5702203945Sweongyo		max_loop = 0x1e;
5703203945Sweongyo		buffer[0] = 0x000201cc;
5704203945Sweongyo	} else {
5705203945Sweongyo		max_loop = 0xfa;
5706203945Sweongyo		buffer[0] = 0x000b846e;
5707203945Sweongyo	}
5708203945Sweongyo
5709204242Simp	BWN_ASSERT_LOCKED(mac->mac_sc);
5710203945Sweongyo
5711203945Sweongyo	for (i = 0; i < 5; i++)
5712203945Sweongyo		bwn_ram_write(mac, i * 4, buffer[i]);
5713203945Sweongyo
5714203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0000);
5715203945Sweongyo	BWN_WRITE_2(mac, 0x07c0,
5716204922Sweongyo	    (siba_get_revid(sc->sc_dev) < 11) ? 0x0000 : 0x0100);
5717203945Sweongyo	value = ((phy->type == BWN_PHYTYPE_A) ? 0x41 : 0x40);
5718203945Sweongyo	BWN_WRITE_2(mac, 0x050c, value);
5719203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5720203945Sweongyo		BWN_WRITE_2(mac, 0x0514, 0x1a02);
5721203945Sweongyo	BWN_WRITE_2(mac, 0x0508, 0x0000);
5722203945Sweongyo	BWN_WRITE_2(mac, 0x050a, 0x0000);
5723203945Sweongyo	BWN_WRITE_2(mac, 0x054c, 0x0000);
5724203945Sweongyo	BWN_WRITE_2(mac, 0x056a, 0x0014);
5725203945Sweongyo	BWN_WRITE_2(mac, 0x0568, 0x0826);
5726203945Sweongyo	BWN_WRITE_2(mac, 0x0500, 0x0000);
5727203945Sweongyo	if (phy->type == BWN_PHYTYPE_LP)
5728203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0050);
5729203945Sweongyo	else
5730203945Sweongyo		BWN_WRITE_2(mac, 0x0502, 0x0030);
5731203945Sweongyo
5732203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5733203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0017);
5734203945Sweongyo	for (i = 0x00; i < max_loop; i++) {
5735203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5736203945Sweongyo		if (value & 0x0080)
5737203945Sweongyo			break;
5738203945Sweongyo		DELAY(10);
5739203945Sweongyo	}
5740203945Sweongyo	for (i = 0x00; i < 0x0a; i++) {
5741203945Sweongyo		value = BWN_READ_2(mac, 0x050e);
5742203945Sweongyo		if (value & 0x0400)
5743203945Sweongyo			break;
5744203945Sweongyo		DELAY(10);
5745203945Sweongyo	}
5746203945Sweongyo	for (i = 0x00; i < 0x19; i++) {
5747203945Sweongyo		value = BWN_READ_2(mac, 0x0690);
5748203945Sweongyo		if (!(value & 0x0100))
5749203945Sweongyo			break;
5750203945Sweongyo		DELAY(10);
5751203945Sweongyo	}
5752203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
5753203945Sweongyo		BWN_RF_WRITE(mac, 0x0051, 0x0037);
5754203945Sweongyo}
5755203945Sweongyo
5756203945Sweongyostatic void
5757203945Sweongyobwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
5758203945Sweongyo{
5759203945Sweongyo	uint32_t macctl;
5760203945Sweongyo
5761203945Sweongyo	KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
5762203945Sweongyo
5763203945Sweongyo	macctl = BWN_READ_4(mac, BWN_MACCTL);
5764203945Sweongyo	if (macctl & BWN_MACCTL_BIGENDIAN)
5765203945Sweongyo		printf("TODO: need swap\n");
5766203945Sweongyo
5767203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
5768203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
5769203945Sweongyo	BWN_WRITE_4(mac, BWN_RAM_DATA, val);
5770203945Sweongyo}
5771203945Sweongyo
5772203945Sweongyostatic void
5773203945Sweongyobwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
5774203945Sweongyo{
5775203945Sweongyo	uint16_t value;
5776203945Sweongyo
5777204256Sweongyo	KASSERT(mac->mac_phy.type == BWN_PHYTYPE_G,
5778203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
5779203945Sweongyo
5780203945Sweongyo	value = (uint8_t) (ctl->q);
5781203945Sweongyo	value |= ((uint8_t) (ctl->i)) << 8;
5782203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
5783203945Sweongyo}
5784203945Sweongyo
5785203945Sweongyostatic uint16_t
5786203945Sweongyobwn_lo_calcfeed(struct bwn_mac *mac,
5787203945Sweongyo    uint16_t lna, uint16_t pga, uint16_t trsw_rx)
5788203945Sweongyo{
5789203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5790204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
5791203945Sweongyo	uint16_t rfover;
5792203945Sweongyo	uint16_t feedthrough;
5793203945Sweongyo
5794203945Sweongyo	if (phy->gmode) {
5795203945Sweongyo		lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
5796203945Sweongyo		pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
5797203945Sweongyo
5798203945Sweongyo		KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
5799203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5800203945Sweongyo		KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
5801203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
5802203945Sweongyo
5803203945Sweongyo		trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
5804203945Sweongyo
5805203945Sweongyo		rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
5806204922Sweongyo		if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA) &&
5807204922Sweongyo		    phy->rev > 6)
5808203945Sweongyo			rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
5809203945Sweongyo
5810203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
5811203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5812203945Sweongyo		DELAY(10);
5813203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
5814203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5815203945Sweongyo		DELAY(10);
5816203945Sweongyo		rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
5817203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
5818203945Sweongyo		DELAY(10);
5819203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
5820203945Sweongyo	} else {
5821203945Sweongyo		pga |= BWN_PHY_PGACTL_UNKNOWN;
5822203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5823203945Sweongyo		DELAY(10);
5824203945Sweongyo		pga |= BWN_PHY_PGACTL_LOWBANDW;
5825203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5826203945Sweongyo		DELAY(10);
5827203945Sweongyo		pga |= BWN_PHY_PGACTL_LPF;
5828203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
5829203945Sweongyo	}
5830203945Sweongyo	DELAY(21);
5831203945Sweongyo	feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
5832203945Sweongyo
5833203945Sweongyo	return (feedthrough);
5834203945Sweongyo}
5835203945Sweongyo
5836203945Sweongyostatic uint16_t
5837203945Sweongyobwn_lo_txctl_regtable(struct bwn_mac *mac,
5838203945Sweongyo    uint16_t *value, uint16_t *pad_mix_gain)
5839203945Sweongyo{
5840203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5841203945Sweongyo	uint16_t reg, v, padmix;
5842203945Sweongyo
5843203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
5844203945Sweongyo		v = 0x30;
5845203945Sweongyo		if (phy->rf_rev <= 5) {
5846203945Sweongyo			reg = 0x43;
5847203945Sweongyo			padmix = 0;
5848203945Sweongyo		} else {
5849203945Sweongyo			reg = 0x52;
5850203945Sweongyo			padmix = 5;
5851203945Sweongyo		}
5852203945Sweongyo	} else {
5853203945Sweongyo		if (phy->rev >= 2 && phy->rf_rev == 8) {
5854203945Sweongyo			reg = 0x43;
5855203945Sweongyo			v = 0x10;
5856203945Sweongyo			padmix = 2;
5857203945Sweongyo		} else {
5858203945Sweongyo			reg = 0x52;
5859203945Sweongyo			v = 0x30;
5860203945Sweongyo			padmix = 5;
5861203945Sweongyo		}
5862203945Sweongyo	}
5863203945Sweongyo	if (value)
5864203945Sweongyo		*value = v;
5865203945Sweongyo	if (pad_mix_gain)
5866203945Sweongyo		*pad_mix_gain = padmix;
5867203945Sweongyo
5868203945Sweongyo	return (reg);
5869203945Sweongyo}
5870203945Sweongyo
5871203945Sweongyostatic void
5872203945Sweongyobwn_lo_measure_txctl_values(struct bwn_mac *mac)
5873203945Sweongyo{
5874203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5875203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5876203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
5877203945Sweongyo	uint16_t reg, mask;
5878203945Sweongyo	uint16_t trsw_rx, pga;
5879203945Sweongyo	uint16_t rf_pctl_reg;
5880203945Sweongyo
5881203945Sweongyo	static const uint8_t tx_bias_values[] = {
5882203945Sweongyo		0x09, 0x08, 0x0a, 0x01, 0x00,
5883203945Sweongyo		0x02, 0x05, 0x04, 0x06,
5884203945Sweongyo	};
5885203945Sweongyo	static const uint8_t tx_magn_values[] = {
5886203945Sweongyo		0x70, 0x40,
5887203945Sweongyo	};
5888203945Sweongyo
5889203945Sweongyo	if (!BWN_HAS_LOOPBACK(phy)) {
5890203945Sweongyo		rf_pctl_reg = 6;
5891203945Sweongyo		trsw_rx = 2;
5892203945Sweongyo		pga = 0;
5893203945Sweongyo	} else {
5894203945Sweongyo		int lb_gain;
5895203945Sweongyo
5896203945Sweongyo		trsw_rx = 0;
5897203945Sweongyo		lb_gain = pg->pg_max_lb_gain / 2;
5898203945Sweongyo		if (lb_gain > 10) {
5899203945Sweongyo			rf_pctl_reg = 0;
5900203945Sweongyo			pga = abs(10 - lb_gain) / 6;
5901203945Sweongyo			pga = MIN(MAX(pga, 0), 15);
5902203945Sweongyo		} else {
5903203945Sweongyo			int cmp_val;
5904203945Sweongyo			int tmp;
5905203945Sweongyo
5906203945Sweongyo			pga = 0;
5907203945Sweongyo			cmp_val = 0x24;
5908203945Sweongyo			if ((phy->rev >= 2) &&
5909203945Sweongyo			    (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
5910203945Sweongyo				cmp_val = 0x3c;
5911203945Sweongyo			tmp = lb_gain;
5912203945Sweongyo			if ((10 - lb_gain) < cmp_val)
5913203945Sweongyo				tmp = (10 - lb_gain);
5914203945Sweongyo			if (tmp < 0)
5915203945Sweongyo				tmp += 6;
5916203945Sweongyo			else
5917203945Sweongyo				tmp += 3;
5918203945Sweongyo			cmp_val /= 4;
5919203945Sweongyo			tmp /= 4;
5920203945Sweongyo			if (tmp >= cmp_val)
5921203945Sweongyo				rf_pctl_reg = cmp_val;
5922203945Sweongyo			else
5923203945Sweongyo				rf_pctl_reg = tmp;
5924203945Sweongyo		}
5925203945Sweongyo	}
5926203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
5927203945Sweongyo	bwn_phy_g_set_bbatt(mac, 2);
5928203945Sweongyo
5929203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
5930203945Sweongyo	mask = ~mask;
5931203945Sweongyo	BWN_RF_MASK(mac, reg, mask);
5932203945Sweongyo
5933203945Sweongyo	if (BWN_HAS_TXMAG(phy)) {
5934203945Sweongyo		int i, j;
5935203945Sweongyo		int feedthrough;
5936203945Sweongyo		int min_feedth = 0xffff;
5937203945Sweongyo		uint8_t tx_magn, tx_bias;
5938203945Sweongyo
5939203945Sweongyo		for (i = 0; i < N(tx_magn_values); i++) {
5940203945Sweongyo			tx_magn = tx_magn_values[i];
5941203945Sweongyo			BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
5942203945Sweongyo			for (j = 0; j < N(tx_bias_values); j++) {
5943203945Sweongyo				tx_bias = tx_bias_values[j];
5944203945Sweongyo				BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
5945203945Sweongyo				feedthrough = bwn_lo_calcfeed(mac, 0, pga,
5946203945Sweongyo				    trsw_rx);
5947203945Sweongyo				if (feedthrough < min_feedth) {
5948203945Sweongyo					lo->tx_bias = tx_bias;
5949203945Sweongyo					lo->tx_magn = tx_magn;
5950203945Sweongyo					min_feedth = feedthrough;
5951203945Sweongyo				}
5952203945Sweongyo				if (lo->tx_bias == 0)
5953203945Sweongyo					break;
5954203945Sweongyo			}
5955203945Sweongyo			BWN_RF_WRITE(mac, 0x52,
5956203945Sweongyo					  (BWN_RF_READ(mac, 0x52)
5957203945Sweongyo					   & 0xff00) | lo->tx_bias | lo->
5958203945Sweongyo					  tx_magn);
5959203945Sweongyo		}
5960203945Sweongyo	} else {
5961203945Sweongyo		lo->tx_magn = 0;
5962203945Sweongyo		lo->tx_bias = 0;
5963203945Sweongyo		BWN_RF_MASK(mac, 0x52, 0xfff0);
5964203945Sweongyo	}
5965203945Sweongyo
5966203945Sweongyo	BWN_GETTIME(lo->txctl_measured_time);
5967203945Sweongyo}
5968203945Sweongyo
5969203945Sweongyostatic void
5970203945Sweongyobwn_lo_get_powervector(struct bwn_mac *mac)
5971203945Sweongyo{
5972203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5973203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5974203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
5975203945Sweongyo	int i;
5976203945Sweongyo	uint64_t tmp;
5977203945Sweongyo	uint64_t power_vector = 0;
5978203945Sweongyo
5979203945Sweongyo	for (i = 0; i < 8; i += 2) {
5980203945Sweongyo		tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
5981203945Sweongyo		power_vector |= (tmp << (i * 8));
5982203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
5983203945Sweongyo	}
5984203945Sweongyo	if (power_vector)
5985203945Sweongyo		lo->power_vector = power_vector;
5986203945Sweongyo
5987203945Sweongyo	BWN_GETTIME(lo->pwr_vec_read_time);
5988203945Sweongyo}
5989203945Sweongyo
5990203945Sweongyostatic void
5991203945Sweongyobwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
5992203945Sweongyo    int use_trsw_rx)
5993203945Sweongyo{
5994203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
5995203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
5996203945Sweongyo	uint16_t tmp;
5997203945Sweongyo
5998203945Sweongyo	if (max_rx_gain < 0)
5999203945Sweongyo		max_rx_gain = 0;
6000203945Sweongyo
6001203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
6002203945Sweongyo		int trsw_rx = 0;
6003203945Sweongyo		int trsw_rx_gain;
6004203945Sweongyo
6005203945Sweongyo		if (use_trsw_rx) {
6006203945Sweongyo			trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
6007203945Sweongyo			if (max_rx_gain >= trsw_rx_gain) {
6008203945Sweongyo				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
6009203945Sweongyo				trsw_rx = 0x20;
6010203945Sweongyo			}
6011203945Sweongyo		} else
6012203945Sweongyo			trsw_rx_gain = max_rx_gain;
6013203945Sweongyo		if (trsw_rx_gain < 9) {
6014203945Sweongyo			pg->pg_lna_lod_gain = 0;
6015203945Sweongyo		} else {
6016203945Sweongyo			pg->pg_lna_lod_gain = 1;
6017203945Sweongyo			trsw_rx_gain -= 8;
6018203945Sweongyo		}
6019203945Sweongyo		trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
6020203945Sweongyo		pg->pg_pga_gain = trsw_rx_gain / 3;
6021203945Sweongyo		if (pg->pg_pga_gain >= 5) {
6022203945Sweongyo			pg->pg_pga_gain -= 5;
6023203945Sweongyo			pg->pg_lna_gain = 2;
6024203945Sweongyo		} else
6025203945Sweongyo			pg->pg_lna_gain = 0;
6026203945Sweongyo	} else {
6027203945Sweongyo		pg->pg_lna_gain = 0;
6028203945Sweongyo		pg->pg_trsw_rx_gain = 0x20;
6029203945Sweongyo		if (max_rx_gain >= 0x14) {
6030203945Sweongyo			pg->pg_lna_lod_gain = 1;
6031203945Sweongyo			pg->pg_pga_gain = 2;
6032203945Sweongyo		} else if (max_rx_gain >= 0x12) {
6033203945Sweongyo			pg->pg_lna_lod_gain = 1;
6034203945Sweongyo			pg->pg_pga_gain = 1;
6035203945Sweongyo		} else if (max_rx_gain >= 0xf) {
6036203945Sweongyo			pg->pg_lna_lod_gain = 1;
6037203945Sweongyo			pg->pg_pga_gain = 0;
6038203945Sweongyo		} else {
6039203945Sweongyo			pg->pg_lna_lod_gain = 0;
6040203945Sweongyo			pg->pg_pga_gain = 0;
6041203945Sweongyo		}
6042203945Sweongyo	}
6043203945Sweongyo
6044203945Sweongyo	tmp = BWN_RF_READ(mac, 0x7a);
6045203945Sweongyo	if (pg->pg_lna_lod_gain == 0)
6046203945Sweongyo		tmp &= ~0x0008;
6047203945Sweongyo	else
6048203945Sweongyo		tmp |= 0x0008;
6049203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, tmp);
6050203945Sweongyo}
6051203945Sweongyo
6052203945Sweongyostatic void
6053203945Sweongyobwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6054203945Sweongyo{
6055203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6056203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6057204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6058203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6059203945Sweongyo	struct timespec ts;
6060203945Sweongyo	uint16_t tmp;
6061203945Sweongyo
6062203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6063203945Sweongyo		sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
6064203945Sweongyo		sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
6065203945Sweongyo		sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6066203945Sweongyo		sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
6067203945Sweongyo		sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
6068203945Sweongyo
6069203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
6070203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
6071203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
6072203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
6073203945Sweongyo	}
6074203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6075203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
6076203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
6077203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
6078203945Sweongyo	}
6079203945Sweongyo	if (phy->rev >= 2) {
6080203945Sweongyo		sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
6081203945Sweongyo		sav->phy_analogoverval =
6082203945Sweongyo		    BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
6083203945Sweongyo		sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
6084203945Sweongyo		sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
6085203945Sweongyo		sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
6086203945Sweongyo		sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
6087203945Sweongyo		sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
6088203945Sweongyo
6089203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
6090203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
6091203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
6092203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
6093203945Sweongyo		if (phy->type == BWN_PHYTYPE_G) {
6094203945Sweongyo			if ((phy->rev >= 7) &&
6095204922Sweongyo			    (siba_sprom_get_bf_lo(sc->sc_dev) &
6096204922Sweongyo			     BWN_BFL_EXTLNA)) {
6097203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
6098203945Sweongyo			} else {
6099203945Sweongyo				BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
6100203945Sweongyo			}
6101203945Sweongyo		} else {
6102203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
6103203945Sweongyo		}
6104203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
6105203945Sweongyo	}
6106203945Sweongyo	sav->reg0 = BWN_READ_2(mac, 0x3f4);
6107203945Sweongyo	sav->reg1 = BWN_READ_2(mac, 0x3e2);
6108203945Sweongyo	sav->rf0 = BWN_RF_READ(mac, 0x43);
6109203945Sweongyo	sav->rf1 = BWN_RF_READ(mac, 0x7a);
6110203945Sweongyo	sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
6111203945Sweongyo	sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
6112203945Sweongyo	sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
6113203945Sweongyo	sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
6114203945Sweongyo
6115203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6116203945Sweongyo		sav->rf2 = BWN_RF_READ(mac, 0x52);
6117203945Sweongyo		sav->rf2 &= 0x00f0;
6118203945Sweongyo	}
6119203945Sweongyo	if (phy->type == BWN_PHYTYPE_B) {
6120203945Sweongyo		sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
6121203945Sweongyo		sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
6122203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
6123203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
6124203945Sweongyo	} else {
6125203945Sweongyo		BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
6126203945Sweongyo			    | 0x8000);
6127203945Sweongyo	}
6128203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
6129203945Sweongyo		    & 0xf000);
6130203945Sweongyo
6131203945Sweongyo	tmp =
6132203945Sweongyo	    (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
6133203945Sweongyo	BWN_PHY_WRITE(mac, tmp, 0x007f);
6134203945Sweongyo
6135203945Sweongyo	tmp = sav->phy_syncctl;
6136203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
6137203945Sweongyo	tmp = sav->rf1;
6138203945Sweongyo	BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
6139203945Sweongyo
6140203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
6141203945Sweongyo	if (phy->type == BWN_PHYTYPE_G ||
6142203945Sweongyo	    (phy->type == BWN_PHYTYPE_B &&
6143203945Sweongyo	     phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
6144203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
6145203945Sweongyo	} else
6146203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
6147203945Sweongyo	if (phy->rev >= 2)
6148203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
6149203945Sweongyo	bwn_phy_g_switch_chan(mac, 6, 0);
6150203945Sweongyo	BWN_RF_READ(mac, 0x51);
6151203945Sweongyo	if (phy->type == BWN_PHYTYPE_G)
6152203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
6153203945Sweongyo
6154203945Sweongyo	nanouptime(&ts);
6155203945Sweongyo	if (time_before(lo->txctl_measured_time,
6156203945Sweongyo	    (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
6157203945Sweongyo		bwn_lo_measure_txctl_values(mac);
6158203945Sweongyo
6159203945Sweongyo	if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
6160203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
6161203945Sweongyo	else {
6162203945Sweongyo		if (phy->type == BWN_PHYTYPE_B)
6163203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6164203945Sweongyo		else
6165203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
6166203945Sweongyo	}
6167203945Sweongyo}
6168203945Sweongyo
6169203945Sweongyostatic void
6170203945Sweongyobwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
6171203945Sweongyo{
6172203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6173203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6174203945Sweongyo	uint16_t tmp;
6175203945Sweongyo
6176203945Sweongyo	if (phy->rev >= 2) {
6177203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
6178203945Sweongyo		tmp = (pg->pg_pga_gain << 8);
6179203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
6180203945Sweongyo		DELAY(5);
6181203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
6182203945Sweongyo		DELAY(2);
6183203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
6184203945Sweongyo	} else {
6185203945Sweongyo		tmp = (pg->pg_pga_gain | 0xefa0);
6186203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
6187203945Sweongyo	}
6188203945Sweongyo	if (phy->type == BWN_PHYTYPE_G) {
6189203945Sweongyo		if (phy->rev >= 3)
6190203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
6191203945Sweongyo		else
6192203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
6193203945Sweongyo		if (phy->rev >= 2)
6194203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
6195203945Sweongyo		else
6196203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
6197203945Sweongyo	}
6198203945Sweongyo	BWN_WRITE_2(mac, 0x3f4, sav->reg0);
6199203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
6200203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
6201203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
6202203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
6203203945Sweongyo	BWN_RF_WRITE(mac, 0x43, sav->rf0);
6204203945Sweongyo	BWN_RF_WRITE(mac, 0x7a, sav->rf1);
6205203945Sweongyo	if (!BWN_HAS_TXMAG(phy)) {
6206203945Sweongyo		tmp = sav->rf2;
6207203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
6208203945Sweongyo	}
6209203945Sweongyo	BWN_WRITE_2(mac, 0x3e2, sav->reg1);
6210203945Sweongyo	if (phy->type == BWN_PHYTYPE_B &&
6211203945Sweongyo	    phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
6212203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
6213203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
6214203945Sweongyo	}
6215203945Sweongyo	if (phy->rev >= 2) {
6216203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
6217203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
6218203945Sweongyo			      sav->phy_analogoverval);
6219203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
6220203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
6221203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
6222203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
6223203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
6224203945Sweongyo	}
6225203945Sweongyo	if (bwn_has_hwpctl(mac)) {
6226203945Sweongyo		tmp = (sav->phy_lomask & 0xbfff);
6227203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
6228203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
6229203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
6230203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
6231203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
6232203945Sweongyo	}
6233203945Sweongyo	bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
6234203945Sweongyo}
6235203945Sweongyo
6236203945Sweongyostatic int
6237203945Sweongyobwn_lo_probe_loctl(struct bwn_mac *mac,
6238203945Sweongyo    struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
6239203945Sweongyo{
6240203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6241203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6242203945Sweongyo	struct bwn_loctl orig, test;
6243203945Sweongyo	struct bwn_loctl prev = { -100, -100 };
6244203945Sweongyo	static const struct bwn_loctl modifiers[] = {
6245203945Sweongyo		{  1,  1,}, {  1,  0,}, {  1, -1,}, {  0, -1,},
6246203945Sweongyo		{ -1, -1,}, { -1,  0,}, { -1,  1,}, {  0,  1,}
6247203945Sweongyo	};
6248203945Sweongyo	int begin, end, lower = 0, i;
6249203945Sweongyo	uint16_t feedth;
6250203945Sweongyo
6251203945Sweongyo	if (d->curstate == 0) {
6252203945Sweongyo		begin = 1;
6253203945Sweongyo		end = 8;
6254203945Sweongyo	} else if (d->curstate % 2 == 0) {
6255203945Sweongyo		begin = d->curstate - 1;
6256203945Sweongyo		end = d->curstate + 1;
6257203945Sweongyo	} else {
6258203945Sweongyo		begin = d->curstate - 2;
6259203945Sweongyo		end = d->curstate + 2;
6260203945Sweongyo	}
6261203945Sweongyo	if (begin < 1)
6262203945Sweongyo		begin += 8;
6263203945Sweongyo	if (end > 8)
6264203945Sweongyo		end -= 8;
6265203945Sweongyo
6266203945Sweongyo	memcpy(&orig, probe, sizeof(struct bwn_loctl));
6267203945Sweongyo	i = begin;
6268203945Sweongyo	d->curstate = i;
6269203945Sweongyo	while (1) {
6270203945Sweongyo		KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
6271203945Sweongyo		memcpy(&test, &orig, sizeof(struct bwn_loctl));
6272203945Sweongyo		test.i += modifiers[i - 1].i * d->multipler;
6273203945Sweongyo		test.q += modifiers[i - 1].q * d->multipler;
6274203945Sweongyo		if ((test.i != prev.i || test.q != prev.q) &&
6275203945Sweongyo		    (abs(test.i) <= 16 && abs(test.q) <= 16)) {
6276203945Sweongyo			bwn_lo_write(mac, &test);
6277203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6278203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6279203945Sweongyo			if (feedth < d->feedth) {
6280203945Sweongyo				memcpy(probe, &test,
6281203945Sweongyo				    sizeof(struct bwn_loctl));
6282203945Sweongyo				lower = 1;
6283203945Sweongyo				d->feedth = feedth;
6284203945Sweongyo				if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
6285203945Sweongyo					break;
6286203945Sweongyo			}
6287203945Sweongyo		}
6288203945Sweongyo		memcpy(&prev, &test, sizeof(prev));
6289203945Sweongyo		if (i == end)
6290203945Sweongyo			break;
6291203945Sweongyo		if (i == 8)
6292203945Sweongyo			i = 1;
6293203945Sweongyo		else
6294203945Sweongyo			i++;
6295203945Sweongyo		d->curstate = i;
6296203945Sweongyo	}
6297203945Sweongyo
6298203945Sweongyo	return (lower);
6299203945Sweongyo}
6300203945Sweongyo
6301203945Sweongyostatic void
6302203945Sweongyobwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
6303203945Sweongyo{
6304203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6305203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6306203945Sweongyo	struct bwn_lo_g_sm d;
6307203945Sweongyo	struct bwn_loctl probe;
6308203945Sweongyo	int lower, repeat, cnt = 0;
6309203945Sweongyo	uint16_t feedth;
6310203945Sweongyo
6311203945Sweongyo	d.nmeasure = 0;
6312203945Sweongyo	d.multipler = 1;
6313203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6314203945Sweongyo		d.multipler = 3;
6315203945Sweongyo
6316203945Sweongyo	memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
6317203945Sweongyo	repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
6318203945Sweongyo
6319203945Sweongyo	do {
6320203945Sweongyo		bwn_lo_write(mac, &d.loctl);
6321203945Sweongyo		feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6322203945Sweongyo		    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6323203945Sweongyo		if (feedth < 0x258) {
6324203945Sweongyo			if (feedth >= 0x12c)
6325203945Sweongyo				*rxgain += 6;
6326203945Sweongyo			else
6327203945Sweongyo				*rxgain += 3;
6328203945Sweongyo			feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
6329203945Sweongyo			    pg->pg_pga_gain, pg->pg_trsw_rx_gain);
6330203945Sweongyo		}
6331203945Sweongyo		d.feedth = feedth;
6332203945Sweongyo		d.curstate = 0;
6333203945Sweongyo		do {
6334203945Sweongyo			KASSERT(d.curstate >= 0 && d.curstate <= 8,
6335203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
6336203945Sweongyo			memcpy(&probe, &d.loctl,
6337203945Sweongyo			       sizeof(struct bwn_loctl));
6338203945Sweongyo			lower = bwn_lo_probe_loctl(mac, &probe, &d);
6339203945Sweongyo			if (!lower)
6340203945Sweongyo				break;
6341203945Sweongyo			if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
6342203945Sweongyo				break;
6343203945Sweongyo			memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
6344203945Sweongyo			d.nmeasure++;
6345203945Sweongyo		} while (d.nmeasure < 24);
6346203945Sweongyo		memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
6347203945Sweongyo
6348203945Sweongyo		if (BWN_HAS_LOOPBACK(phy)) {
6349203945Sweongyo			if (d.feedth > 0x1194)
6350203945Sweongyo				*rxgain -= 6;
6351203945Sweongyo			else if (d.feedth < 0x5dc)
6352203945Sweongyo				*rxgain += 3;
6353203945Sweongyo			if (cnt == 0) {
6354203945Sweongyo				if (d.feedth <= 0x5dc) {
6355203945Sweongyo					d.multipler = 1;
6356203945Sweongyo					cnt++;
6357203945Sweongyo				} else
6358203945Sweongyo					d.multipler = 2;
6359203945Sweongyo			} else if (cnt == 2)
6360203945Sweongyo				d.multipler = 1;
6361203945Sweongyo		}
6362203945Sweongyo		bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
6363203945Sweongyo	} while (++cnt < repeat);
6364203945Sweongyo}
6365203945Sweongyo
6366203945Sweongyostatic struct bwn_lo_calib *
6367203945Sweongyobwn_lo_calibset(struct bwn_mac *mac,
6368203945Sweongyo    const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
6369203945Sweongyo{
6370203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6371203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6372203945Sweongyo	struct bwn_loctl loctl = { 0, 0 };
6373203945Sweongyo	struct bwn_lo_calib *cal;
6374204242Simp	struct bwn_lo_g_value sval = { 0 };
6375203945Sweongyo	int rxgain;
6376203945Sweongyo	uint16_t pad, reg, value;
6377203945Sweongyo
6378203945Sweongyo	sval.old_channel = phy->chan;
6379203945Sweongyo	bwn_mac_suspend(mac);
6380203945Sweongyo	bwn_lo_save(mac, &sval);
6381203945Sweongyo
6382203945Sweongyo	reg = bwn_lo_txctl_regtable(mac, &value, &pad);
6383203945Sweongyo	BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
6384203945Sweongyo	BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
6385203945Sweongyo
6386203945Sweongyo	rxgain = (rfatt->att * 2) + (bbatt->att / 2);
6387203945Sweongyo	if (rfatt->padmix)
6388203945Sweongyo		rxgain -= pad;
6389203945Sweongyo	if (BWN_HAS_LOOPBACK(phy))
6390203945Sweongyo		rxgain += pg->pg_max_lb_gain;
6391203945Sweongyo	bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
6392203945Sweongyo	bwn_phy_g_set_bbatt(mac, bbatt->att);
6393203945Sweongyo	bwn_lo_probe_sm(mac, &loctl, &rxgain);
6394203945Sweongyo
6395203945Sweongyo	bwn_lo_restore(mac, &sval);
6396203945Sweongyo	bwn_mac_enable(mac);
6397203945Sweongyo
6398203945Sweongyo	cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
6399203945Sweongyo	if (!cal) {
6400203945Sweongyo		device_printf(mac->mac_sc->sc_dev, "out of memory\n");
6401203945Sweongyo		return (NULL);
6402203945Sweongyo	}
6403203945Sweongyo	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
6404203945Sweongyo	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
6405203945Sweongyo	memcpy(&cal->ctl, &loctl, sizeof(loctl));
6406203945Sweongyo
6407203945Sweongyo	BWN_GETTIME(cal->calib_time);
6408203945Sweongyo
6409203945Sweongyo	return (cal);
6410203945Sweongyo}
6411203945Sweongyo
6412203945Sweongyostatic struct bwn_lo_calib *
6413203945Sweongyobwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
6414203945Sweongyo    const struct bwn_rfatt *rfatt)
6415203945Sweongyo{
6416203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
6417203945Sweongyo	struct bwn_lo_calib *c;
6418203945Sweongyo
6419203945Sweongyo	TAILQ_FOREACH(c, &lo->calib_list, list) {
6420203945Sweongyo		if (!BWN_BBATTCMP(&c->bbatt, bbatt))
6421203945Sweongyo			continue;
6422203945Sweongyo		if (!BWN_RFATTCMP(&c->rfatt, rfatt))
6423203945Sweongyo			continue;
6424203945Sweongyo		return (c);
6425203945Sweongyo	}
6426203945Sweongyo
6427203945Sweongyo	c = bwn_lo_calibset(mac, bbatt, rfatt);
6428203945Sweongyo	if (!c)
6429203945Sweongyo		return (NULL);
6430203945Sweongyo	TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
6431203945Sweongyo
6432203945Sweongyo	return (c);
6433203945Sweongyo}
6434203945Sweongyo
6435203945Sweongyostatic void
6436203945Sweongyobwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
6437203945Sweongyo{
6438203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6439203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6440203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6441203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
6442203945Sweongyo	const struct bwn_rfatt *rfatt;
6443203945Sweongyo	const struct bwn_bbatt *bbatt;
6444203945Sweongyo	uint64_t pvector;
6445203945Sweongyo	int i;
6446203945Sweongyo	int rf_offset, bb_offset;
6447203945Sweongyo	uint8_t changed = 0;
6448203945Sweongyo
6449203945Sweongyo	KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
6450203945Sweongyo	KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
6451203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6452203945Sweongyo
6453203945Sweongyo	pvector = lo->power_vector;
6454203945Sweongyo	if (!update && !pvector)
6455203945Sweongyo		return;
6456203945Sweongyo
6457203945Sweongyo	bwn_mac_suspend(mac);
6458203945Sweongyo
6459203945Sweongyo	for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
6460203945Sweongyo		struct bwn_lo_calib *cal;
6461203945Sweongyo		int idx;
6462203945Sweongyo		uint16_t val;
6463203945Sweongyo
6464203945Sweongyo		if (!update && !(pvector & (((uint64_t)1ULL) << i)))
6465203945Sweongyo			continue;
6466203945Sweongyo		bb_offset = i / lo->rfatt.len;
6467203945Sweongyo		rf_offset = i % lo->rfatt.len;
6468203945Sweongyo		bbatt = &(lo->bbatt.array[bb_offset]);
6469203945Sweongyo		rfatt = &(lo->rfatt.array[rf_offset]);
6470203945Sweongyo
6471203945Sweongyo		cal = bwn_lo_calibset(mac, bbatt, rfatt);
6472203945Sweongyo		if (!cal) {
6473203945Sweongyo			device_printf(sc->sc_dev, "LO: Could not "
6474203945Sweongyo			    "calibrate DC table entry\n");
6475203945Sweongyo			continue;
6476203945Sweongyo		}
6477203945Sweongyo		val = (uint8_t)(cal->ctl.q);
6478203945Sweongyo		val |= ((uint8_t)(cal->ctl.i)) << 4;
6479203945Sweongyo		free(cal, M_DEVBUF);
6480203945Sweongyo
6481203945Sweongyo		idx = i / 2;
6482203945Sweongyo		if (i % 2)
6483203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
6484203945Sweongyo			    | ((val & 0x00ff) << 8);
6485203945Sweongyo		else
6486203945Sweongyo			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
6487203945Sweongyo			    | (val & 0x00ff);
6488203945Sweongyo		changed = 1;
6489203945Sweongyo	}
6490203945Sweongyo	if (changed) {
6491203945Sweongyo		for (i = 0; i < BWN_DC_LT_SIZE; i++)
6492203945Sweongyo			BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
6493203945Sweongyo	}
6494203945Sweongyo	bwn_mac_enable(mac);
6495203945Sweongyo}
6496203945Sweongyo
6497203945Sweongyostatic void
6498203945Sweongyobwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
6499203945Sweongyo{
6500203945Sweongyo
6501203945Sweongyo	if (!rf->padmix)
6502203945Sweongyo		return;
6503203945Sweongyo	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
6504203945Sweongyo		rf->att = 4;
6505203945Sweongyo}
6506203945Sweongyo
6507203945Sweongyostatic void
6508203945Sweongyobwn_lo_g_adjust(struct bwn_mac *mac)
6509203945Sweongyo{
6510203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
6511203945Sweongyo	struct bwn_lo_calib *cal;
6512203945Sweongyo	struct bwn_rfatt rf;
6513203945Sweongyo
6514203945Sweongyo	memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
6515203945Sweongyo	bwn_lo_fixup_rfatt(&rf);
6516203945Sweongyo
6517203945Sweongyo	cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
6518203945Sweongyo	if (!cal)
6519203945Sweongyo		return;
6520203945Sweongyo	bwn_lo_write(mac, &cal->ctl);
6521203945Sweongyo}
6522203945Sweongyo
6523203945Sweongyostatic void
6524203945Sweongyobwn_lo_g_init(struct bwn_mac *mac)
6525203945Sweongyo{
6526203945Sweongyo
6527203945Sweongyo	if (!bwn_has_hwpctl(mac))
6528203945Sweongyo		return;
6529203945Sweongyo
6530203945Sweongyo	bwn_lo_get_powervector(mac);
6531203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
6532203945Sweongyo}
6533203945Sweongyo
6534203945Sweongyostatic void
6535203945Sweongyobwn_mac_suspend(struct bwn_mac *mac)
6536203945Sweongyo{
6537203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6538203945Sweongyo	int i;
6539203945Sweongyo	uint32_t tmp;
6540203945Sweongyo
6541203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6542203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6543203945Sweongyo
6544203945Sweongyo	if (mac->mac_suspended == 0) {
6545203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
6546203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6547203945Sweongyo			    BWN_READ_4(mac, BWN_MACCTL)
6548203945Sweongyo			    & ~BWN_MACCTL_ON);
6549203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6550203945Sweongyo		for (i = 35; i; i--) {
6551203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6552203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6553203945Sweongyo				goto out;
6554203945Sweongyo			DELAY(10);
6555203945Sweongyo		}
6556203945Sweongyo		for (i = 40; i; i--) {
6557203945Sweongyo			tmp = BWN_READ_4(mac, BWN_INTR_REASON);
6558203945Sweongyo			if (tmp & BWN_INTR_MAC_SUSPENDED)
6559203945Sweongyo				goto out;
6560203945Sweongyo			DELAY(1000);
6561203945Sweongyo		}
6562203945Sweongyo		device_printf(sc->sc_dev, "MAC suspend failed\n");
6563203945Sweongyo	}
6564203945Sweongyoout:
6565203945Sweongyo	mac->mac_suspended++;
6566203945Sweongyo}
6567203945Sweongyo
6568203945Sweongyostatic void
6569203945Sweongyobwn_mac_enable(struct bwn_mac *mac)
6570203945Sweongyo{
6571203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6572203945Sweongyo	uint16_t state;
6573203945Sweongyo
6574203945Sweongyo	state = bwn_shm_read_2(mac, BWN_SHARED,
6575203945Sweongyo	    BWN_SHARED_UCODESTAT);
6576203945Sweongyo	if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
6577203945Sweongyo	    state != BWN_SHARED_UCODESTAT_SLEEP)
6578203945Sweongyo		device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
6579203945Sweongyo
6580203945Sweongyo	mac->mac_suspended--;
6581203945Sweongyo	KASSERT(mac->mac_suspended >= 0,
6582203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6583203945Sweongyo	if (mac->mac_suspended == 0) {
6584203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCTL,
6585203945Sweongyo		    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
6586203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
6587203945Sweongyo		BWN_READ_4(mac, BWN_MACCTL);
6588203945Sweongyo		BWN_READ_4(mac, BWN_INTR_REASON);
6589203945Sweongyo		bwn_psctl(mac, 0);
6590203945Sweongyo	}
6591203945Sweongyo}
6592203945Sweongyo
6593203945Sweongyostatic void
6594203945Sweongyobwn_psctl(struct bwn_mac *mac, uint32_t flags)
6595203945Sweongyo{
6596204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6597203945Sweongyo	int i;
6598203945Sweongyo	uint16_t ucstat;
6599203945Sweongyo
6600203945Sweongyo	KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
6601203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6602203945Sweongyo	KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
6603203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6604203945Sweongyo
6605203945Sweongyo	/* XXX forcibly awake and hwps-off */
6606203945Sweongyo
6607203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
6608203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
6609203945Sweongyo	    ~BWN_MACCTL_HWPS);
6610203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
6611204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
6612203945Sweongyo		for (i = 0; i < 100; i++) {
6613203945Sweongyo			ucstat = bwn_shm_read_2(mac, BWN_SHARED,
6614203945Sweongyo			    BWN_SHARED_UCODESTAT);
6615203945Sweongyo			if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
6616203945Sweongyo				break;
6617203945Sweongyo			DELAY(10);
6618203945Sweongyo		}
6619203945Sweongyo	}
6620203945Sweongyo}
6621203945Sweongyo
6622203945Sweongyostatic int16_t
6623203945Sweongyobwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
6624203945Sweongyo{
6625203945Sweongyo
6626203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
6627203945Sweongyo	return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
6628203945Sweongyo}
6629203945Sweongyo
6630203945Sweongyostatic void
6631203945Sweongyobwn_nrssi_threshold(struct bwn_mac *mac)
6632203945Sweongyo{
6633203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6634203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6635204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
6636203945Sweongyo	int32_t a, b;
6637203945Sweongyo	int16_t tmp16;
6638203945Sweongyo	uint16_t tmpu16;
6639203945Sweongyo
6640203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
6641203945Sweongyo
6642204922Sweongyo	if (phy->gmode && (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_RSSI)) {
6643203945Sweongyo		if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
6644203945Sweongyo			a = 0x13;
6645203945Sweongyo			b = 0x12;
6646203945Sweongyo		} else {
6647203945Sweongyo			a = 0xe;
6648203945Sweongyo			b = 0x11;
6649203945Sweongyo		}
6650203945Sweongyo
6651203945Sweongyo		a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6652203945Sweongyo		a += (pg->pg_nrssi[0] << 6);
6653203945Sweongyo		a += (a < 32) ? 31 : 32;
6654203945Sweongyo		a = a >> 6;
6655203945Sweongyo		a = MIN(MAX(a, -31), 31);
6656203945Sweongyo
6657203945Sweongyo		b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
6658203945Sweongyo		b += (pg->pg_nrssi[0] << 6);
6659203945Sweongyo		if (b < 32)
6660203945Sweongyo			b += 31;
6661203945Sweongyo		else
6662203945Sweongyo			b += 32;
6663203945Sweongyo		b = b >> 6;
6664203945Sweongyo		b = MIN(MAX(b, -31), 31);
6665203945Sweongyo
6666203945Sweongyo		tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
6667203945Sweongyo		tmpu16 |= ((uint32_t)b & 0x0000003f);
6668203945Sweongyo		tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
6669203945Sweongyo		BWN_PHY_WRITE(mac, 0x048a, tmpu16);
6670203945Sweongyo		return;
6671203945Sweongyo	}
6672203945Sweongyo
6673203945Sweongyo	tmp16 = bwn_nrssi_read(mac, 0x20);
6674203945Sweongyo	if (tmp16 >= 0x20)
6675203945Sweongyo		tmp16 -= 0x40;
6676203945Sweongyo	BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
6677203945Sweongyo}
6678203945Sweongyo
6679203945Sweongyostatic void
6680203945Sweongyobwn_nrssi_slope_11g(struct bwn_mac *mac)
6681203945Sweongyo{
6682203945Sweongyo#define	SAVE_RF_MAX		3
6683203945Sweongyo#define	SAVE_PHY_COMM_MAX	4
6684203945Sweongyo#define	SAVE_PHY3_MAX		8
6685203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6686203945Sweongyo		{ 0x7a, 0x52, 0x43 };
6687203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
6688203945Sweongyo		{ 0x15, 0x5a, 0x59, 0x58 };
6689203945Sweongyo	static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
6690203945Sweongyo		0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
6691203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6692203945Sweongyo	};
6693203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6694203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
6695203945Sweongyo	int32_t i, tmp32, phy3_idx = 0;
6696203945Sweongyo	uint16_t delta, tmp;
6697203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6698203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6699203945Sweongyo	uint16_t save_phy3[SAVE_PHY3_MAX];
6700203945Sweongyo	uint16_t ant_div, phy0, chan_ex;
6701203945Sweongyo	int16_t nrssi0, nrssi1;
6702203945Sweongyo
6703203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
6704203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
6705203945Sweongyo
6706203945Sweongyo	if (phy->rf_rev >= 9)
6707203945Sweongyo		return;
6708203945Sweongyo	if (phy->rf_rev == 8)
6709203945Sweongyo		bwn_nrssi_offset(mac);
6710203945Sweongyo
6711203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
6712203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, 0xfffc);
6713203945Sweongyo
6714203945Sweongyo	/*
6715203945Sweongyo	 * Save RF/PHY registers for later restoration
6716203945Sweongyo	 */
6717203945Sweongyo	ant_div = BWN_READ_2(mac, 0x03e2);
6718203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
6719203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6720203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6721203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6722203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6723203945Sweongyo
6724203945Sweongyo	phy0 = BWN_READ_2(mac, BWN_PHY0);
6725203945Sweongyo	chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
6726203945Sweongyo	if (phy->rev >= 3) {
6727203945Sweongyo		for (i = 0; i < SAVE_PHY3_MAX; ++i)
6728203945Sweongyo			save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
6729203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6730203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
6731203945Sweongyo		switch (phy->rev) {
6732203945Sweongyo		case 4:
6733203945Sweongyo		case 6:
6734203945Sweongyo		case 7:
6735203945Sweongyo			BWN_PHY_SET(mac, 0x0478, 0x0100);
6736203945Sweongyo			BWN_PHY_SET(mac, 0x0801, 0x0040);
6737203945Sweongyo			break;
6738203945Sweongyo		case 3:
6739203945Sweongyo		case 5:
6740203945Sweongyo			BWN_PHY_MASK(mac, 0x0801, 0xffbf);
6741203945Sweongyo			break;
6742203945Sweongyo		}
6743203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
6744203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
6745203945Sweongyo	}
6746203945Sweongyo	/*
6747203945Sweongyo	 * Calculate nrssi0
6748203945Sweongyo	 */
6749203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
6750203945Sweongyo	bwn_set_all_gains(mac, 0, 8, 0);
6751203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x00f7);
6752203945Sweongyo	if (phy->rev >= 2) {
6753203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
6754203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
6755203945Sweongyo	}
6756203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
6757203945Sweongyo	DELAY(20);
6758203945Sweongyo
6759203945Sweongyo	nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6760203945Sweongyo	if (nrssi0 >= 0x0020)
6761203945Sweongyo		nrssi0 -= 0x0040;
6762203945Sweongyo
6763203945Sweongyo	/*
6764203945Sweongyo	 * Calculate nrssi1
6765203945Sweongyo	 */
6766203945Sweongyo	BWN_RF_MASK(mac, 0x007a, 0x007f);
6767203945Sweongyo	if (phy->rev >= 2)
6768203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
6769203945Sweongyo
6770203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
6771203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
6772203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x000f);
6773203945Sweongyo	BWN_PHY_WRITE(mac, 0x0015, 0xf330);
6774203945Sweongyo	if (phy->rev >= 2) {
6775203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
6776203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
6777203945Sweongyo	}
6778203945Sweongyo
6779203945Sweongyo	bwn_set_all_gains(mac, 3, 0, 1);
6780203945Sweongyo	if (phy->rf_rev == 8) {
6781203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, 0x001f);
6782203945Sweongyo	} else {
6783203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
6784203945Sweongyo		BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
6785203945Sweongyo		tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
6786203945Sweongyo		BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
6787203945Sweongyo	}
6788203945Sweongyo	BWN_PHY_WRITE(mac, 0x005a, 0x0480);
6789203945Sweongyo	BWN_PHY_WRITE(mac, 0x0059, 0x0810);
6790203945Sweongyo	BWN_PHY_WRITE(mac, 0x0058, 0x000d);
6791203945Sweongyo	DELAY(20);
6792203945Sweongyo	nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6793203945Sweongyo
6794203945Sweongyo	/*
6795203945Sweongyo	 * Install calculated narrow RSSI values
6796203945Sweongyo	 */
6797203945Sweongyo	if (nrssi1 >= 0x0020)
6798203945Sweongyo		nrssi1 -= 0x0040;
6799203945Sweongyo	if (nrssi0 == nrssi1)
6800203945Sweongyo		pg->pg_nrssi_slope = 0x00010000;
6801203945Sweongyo	else
6802203945Sweongyo		pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
6803203945Sweongyo	if (nrssi0 >= -4) {
6804203945Sweongyo		pg->pg_nrssi[0] = nrssi1;
6805203945Sweongyo		pg->pg_nrssi[1] = nrssi0;
6806203945Sweongyo	}
6807203945Sweongyo
6808203945Sweongyo	/*
6809203945Sweongyo	 * Restore saved RF/PHY registers
6810203945Sweongyo	 */
6811203945Sweongyo	if (phy->rev >= 3) {
6812203945Sweongyo		for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
6813203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
6814203945Sweongyo			    save_phy3[phy3_idx]);
6815203945Sweongyo		}
6816203945Sweongyo	}
6817203945Sweongyo	if (phy->rev >= 2) {
6818203945Sweongyo		BWN_PHY_MASK(mac, 0x0812, 0xffcf);
6819203945Sweongyo		BWN_PHY_MASK(mac, 0x0811, 0xffcf);
6820203945Sweongyo	}
6821203945Sweongyo
6822203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6823203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
6824203945Sweongyo
6825203945Sweongyo	BWN_WRITE_2(mac, 0x03e2, ant_div);
6826203945Sweongyo	BWN_WRITE_2(mac, 0x03e6, phy0);
6827203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
6828203945Sweongyo
6829203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6830203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
6831203945Sweongyo
6832203945Sweongyo	bwn_spu_workaround(mac, phy->chan);
6833203945Sweongyo	BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
6834203945Sweongyo	bwn_set_original_gains(mac);
6835203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
6836203945Sweongyo	if (phy->rev >= 3) {
6837203945Sweongyo		for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
6838203945Sweongyo			BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
6839203945Sweongyo			    save_phy3[phy3_idx]);
6840203945Sweongyo		}
6841203945Sweongyo	}
6842203945Sweongyo
6843203945Sweongyo	delta = 0x1f - pg->pg_nrssi[0];
6844203945Sweongyo	for (i = 0; i < 64; i++) {
6845203945Sweongyo		tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
6846203945Sweongyo		tmp32 = MIN(MAX(tmp32, 0), 0x3f);
6847203945Sweongyo		pg->pg_nrssi_lt[i] = tmp32;
6848203945Sweongyo	}
6849203945Sweongyo
6850203945Sweongyo	bwn_nrssi_threshold(mac);
6851203945Sweongyo#undef SAVE_RF_MAX
6852203945Sweongyo#undef SAVE_PHY_COMM_MAX
6853203945Sweongyo#undef SAVE_PHY3_MAX
6854203945Sweongyo}
6855203945Sweongyo
6856203945Sweongyostatic void
6857203945Sweongyobwn_nrssi_offset(struct bwn_mac *mac)
6858203945Sweongyo{
6859203945Sweongyo#define	SAVE_RF_MAX		2
6860203945Sweongyo#define	SAVE_PHY_COMM_MAX	10
6861203945Sweongyo#define	SAVE_PHY6_MAX		8
6862203945Sweongyo	static const uint16_t save_rf_regs[SAVE_RF_MAX] =
6863203945Sweongyo		{ 0x7a, 0x43 };
6864203945Sweongyo	static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
6865203945Sweongyo		0x0001, 0x0811, 0x0812, 0x0814,
6866203945Sweongyo		0x0815, 0x005a, 0x0059, 0x0058,
6867203945Sweongyo		0x000a, 0x0003
6868203945Sweongyo	};
6869203945Sweongyo	static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
6870203945Sweongyo		0x002e, 0x002f, 0x080f, 0x0810,
6871203945Sweongyo		0x0801, 0x0060, 0x0014, 0x0478
6872203945Sweongyo	};
6873203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
6874203945Sweongyo	int i, phy6_idx = 0;
6875203945Sweongyo	uint16_t save_rf[SAVE_RF_MAX];
6876203945Sweongyo	uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
6877203945Sweongyo	uint16_t save_phy6[SAVE_PHY6_MAX];
6878203945Sweongyo	int16_t nrssi;
6879203945Sweongyo	uint16_t saved = 0xffff;
6880203945Sweongyo
6881203945Sweongyo	for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
6882203945Sweongyo		save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
6883203945Sweongyo	for (i = 0; i < SAVE_RF_MAX; ++i)
6884203945Sweongyo		save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
6885203945Sweongyo
6886203945Sweongyo	BWN_PHY_MASK(mac, 0x0429, 0x7fff);
6887203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
6888203945Sweongyo	BWN_PHY_SET(mac, 0x0811, 0x000c);
6889203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
6890203945Sweongyo	BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
6891203945Sweongyo	if (phy->rev >= 6) {
6892203945Sweongyo		for (i = 0; i < SAVE_PHY6_MAX; ++i)
6893203945Sweongyo			save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
6894203945Sweongyo
6895203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0);
6896203945Sweongyo		BWN_PHY_WRITE(mac, 0x002f, 0);
6897203945Sweongyo		BWN_PHY_WRITE(mac, 0x080f, 0);
6898203945Sweongyo		BWN_PHY_WRITE(mac, 0x0810, 0);
6899203945Sweongyo		BWN_PHY_SET(mac, 0x0478, 0x0100);
6900203945Sweongyo		BWN_PHY_SET(mac, 0x0801, 0x0040);
6901203945Sweongyo		BWN_PHY_SET(mac, 0x0060, 0x0040);
6902203945Sweongyo		BWN_PHY_SET(mac, 0x0014, 0x0200);
6903203945Sweongyo	}
6904203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0070);
6905203945Sweongyo	BWN_RF_SET(mac, 0x007a, 0x0080);
6906203945Sweongyo	DELAY(30);
6907203945Sweongyo
6908203945Sweongyo	nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6909203945Sweongyo	if (nrssi >= 0x20)
6910203945Sweongyo		nrssi -= 0x40;
6911203945Sweongyo	if (nrssi == 31) {
6912203945Sweongyo		for (i = 7; i >= 4; i--) {
6913203945Sweongyo			BWN_RF_WRITE(mac, 0x007b, i);
6914203945Sweongyo			DELAY(20);
6915203945Sweongyo			nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
6916203945Sweongyo			    0x003f);
6917203945Sweongyo			if (nrssi >= 0x20)
6918203945Sweongyo				nrssi -= 0x40;
6919203945Sweongyo			if (nrssi < 31 && saved == 0xffff)
6920203945Sweongyo				saved = i;
6921203945Sweongyo		}
6922203945Sweongyo		if (saved == 0xffff)
6923203945Sweongyo			saved = 4;
6924203945Sweongyo	} else {
6925203945Sweongyo		BWN_RF_MASK(mac, 0x007a, 0x007f);
6926203945Sweongyo		if (phy->rev != 1) {
6927203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0001);
6928203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffe);
6929203945Sweongyo		}
6930203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x000c);
6931203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x000c);
6932203945Sweongyo		BWN_PHY_SET(mac, 0x0811, 0x0030);
6933203945Sweongyo		BWN_PHY_SET(mac, 0x0812, 0x0030);
6934203945Sweongyo		BWN_PHY_WRITE(mac, 0x005a, 0x0480);
6935203945Sweongyo		BWN_PHY_WRITE(mac, 0x0059, 0x0810);
6936203945Sweongyo		BWN_PHY_WRITE(mac, 0x0058, 0x000d);
6937203945Sweongyo		if (phy->rev == 0)
6938203945Sweongyo			BWN_PHY_WRITE(mac, 0x0003, 0x0122);
6939203945Sweongyo		else
6940203945Sweongyo			BWN_PHY_SET(mac, 0x000a, 0x2000);
6941203945Sweongyo		if (phy->rev != 1) {
6942203945Sweongyo			BWN_PHY_SET(mac, 0x0814, 0x0004);
6943203945Sweongyo			BWN_PHY_MASK(mac, 0x0815, 0xfffb);
6944203945Sweongyo		}
6945203945Sweongyo		BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
6946203945Sweongyo		BWN_RF_SET(mac, 0x007a, 0x000f);
6947203945Sweongyo		bwn_set_all_gains(mac, 3, 0, 1);
6948203945Sweongyo		BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
6949203945Sweongyo		DELAY(30);
6950203945Sweongyo		nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
6951203945Sweongyo		if (nrssi >= 0x20)
6952203945Sweongyo			nrssi -= 0x40;
6953203945Sweongyo		if (nrssi == -32) {
6954203945Sweongyo			for (i = 0; i < 4; i++) {
6955203945Sweongyo				BWN_RF_WRITE(mac, 0x007b, i);
6956203945Sweongyo				DELAY(20);
6957203945Sweongyo				nrssi = (int16_t)((BWN_PHY_READ(mac,
6958203945Sweongyo				    0x047f) >> 8) & 0x003f);
6959203945Sweongyo				if (nrssi >= 0x20)
6960203945Sweongyo					nrssi -= 0x40;
6961203945Sweongyo				if (nrssi > -31 && saved == 0xffff)
6962203945Sweongyo					saved = i;
6963203945Sweongyo			}
6964203945Sweongyo			if (saved == 0xffff)
6965203945Sweongyo				saved = 3;
6966203945Sweongyo		} else
6967203945Sweongyo			saved = 0;
6968203945Sweongyo	}
6969203945Sweongyo	BWN_RF_WRITE(mac, 0x007b, saved);
6970203945Sweongyo
6971203945Sweongyo	/*
6972203945Sweongyo	 * Restore saved RF/PHY registers
6973203945Sweongyo	 */
6974203945Sweongyo	if (phy->rev >= 6) {
6975203945Sweongyo		for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
6976203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
6977203945Sweongyo			    save_phy6[phy6_idx]);
6978203945Sweongyo		}
6979203945Sweongyo	}
6980203945Sweongyo	if (phy->rev != 1) {
6981203945Sweongyo		for (i = 3; i < 5; i++)
6982203945Sweongyo			BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
6983203945Sweongyo			    save_phy_comm[i]);
6984203945Sweongyo	}
6985203945Sweongyo	for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
6986203945Sweongyo		BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
6987203945Sweongyo
6988203945Sweongyo	for (i = SAVE_RF_MAX - 1; i >= 0; --i)
6989203945Sweongyo		BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
6990203945Sweongyo
6991203945Sweongyo	BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
6992203945Sweongyo	BWN_PHY_SET(mac, 0x0429, 0x8000);
6993203945Sweongyo	bwn_set_original_gains(mac);
6994203945Sweongyo	if (phy->rev >= 6) {
6995203945Sweongyo		for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
6996203945Sweongyo			BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
6997203945Sweongyo			    save_phy6[phy6_idx]);
6998203945Sweongyo		}
6999203945Sweongyo	}
7000203945Sweongyo
7001203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
7002203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
7003203945Sweongyo	BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
7004203945Sweongyo}
7005203945Sweongyo
7006203945Sweongyostatic void
7007203945Sweongyobwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
7008203945Sweongyo    int16_t third)
7009203945Sweongyo{
7010203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7011203945Sweongyo	uint16_t i;
7012203945Sweongyo	uint16_t start = 0x08, end = 0x18;
7013203945Sweongyo	uint16_t tmp;
7014203945Sweongyo	uint16_t table;
7015203945Sweongyo
7016203945Sweongyo	if (phy->rev <= 1) {
7017203945Sweongyo		start = 0x10;
7018203945Sweongyo		end = 0x20;
7019203945Sweongyo	}
7020203945Sweongyo
7021203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7022203945Sweongyo	if (phy->rev <= 1)
7023203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7024203945Sweongyo	for (i = 0; i < 4; i++)
7025203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, first);
7026203945Sweongyo
7027203945Sweongyo	for (i = start; i < end; i++)
7028203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, second);
7029203945Sweongyo
7030203945Sweongyo	if (third != -1) {
7031203945Sweongyo		tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
7032203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
7033203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
7034203945Sweongyo		BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
7035203945Sweongyo	}
7036203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7037203945Sweongyo}
7038203945Sweongyo
7039203945Sweongyostatic void
7040203945Sweongyobwn_set_original_gains(struct bwn_mac *mac)
7041203945Sweongyo{
7042203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7043203945Sweongyo	uint16_t i, tmp;
7044203945Sweongyo	uint16_t table;
7045203945Sweongyo	uint16_t start = 0x0008, end = 0x0018;
7046203945Sweongyo
7047203945Sweongyo	if (phy->rev <= 1) {
7048203945Sweongyo		start = 0x0010;
7049203945Sweongyo		end = 0x0020;
7050203945Sweongyo	}
7051203945Sweongyo
7052203945Sweongyo	table = BWN_OFDMTAB_GAINX;
7053203945Sweongyo	if (phy->rev <= 1)
7054203945Sweongyo		table = BWN_OFDMTAB_GAINX_R1;
7055203945Sweongyo	for (i = 0; i < 4; i++) {
7056203945Sweongyo		tmp = (i & 0xfffc);
7057203945Sweongyo		tmp |= (i & 0x0001) << 1;
7058203945Sweongyo		tmp |= (i & 0x0002) >> 1;
7059203945Sweongyo
7060203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, tmp);
7061203945Sweongyo	}
7062203945Sweongyo
7063203945Sweongyo	for (i = start; i < end; i++)
7064203945Sweongyo		bwn_ofdmtab_write_2(mac, table, i, i - start);
7065203945Sweongyo
7066203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
7067203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
7068203945Sweongyo	BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
7069203945Sweongyo	bwn_dummy_transmission(mac, 0, 1);
7070203945Sweongyo}
7071203945Sweongyo
7072203945Sweongyostatic void
7073203945Sweongyobwn_phy_hwpctl_init(struct bwn_mac *mac)
7074203945Sweongyo{
7075203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7076203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7077203945Sweongyo	struct bwn_rfatt old_rfatt, rfatt;
7078203945Sweongyo	struct bwn_bbatt old_bbatt, bbatt;
7079204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7080203945Sweongyo	uint8_t old_txctl = 0;
7081203945Sweongyo
7082203945Sweongyo	KASSERT(phy->type == BWN_PHYTYPE_G,
7083203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7084203945Sweongyo
7085204922Sweongyo	if ((siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM) &&
7086204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306))
7087203945Sweongyo		return;
7088203945Sweongyo
7089203945Sweongyo	BWN_PHY_WRITE(mac, 0x0028, 0x8018);
7090203945Sweongyo
7091203945Sweongyo	BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
7092203945Sweongyo
7093203945Sweongyo	if (!phy->gmode)
7094203945Sweongyo		return;
7095203945Sweongyo	bwn_hwpctl_early_init(mac);
7096203945Sweongyo	if (pg->pg_curtssi == 0) {
7097203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0) {
7098203945Sweongyo			BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
7099203945Sweongyo		} else {
7100203945Sweongyo			memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
7101203945Sweongyo			memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
7102203945Sweongyo			old_txctl = pg->pg_txctl;
7103203945Sweongyo
7104203945Sweongyo			bbatt.att = 11;
7105203945Sweongyo			if (phy->rf_rev == 8) {
7106203945Sweongyo				rfatt.att = 15;
7107203945Sweongyo				rfatt.padmix = 1;
7108203945Sweongyo			} else {
7109203945Sweongyo				rfatt.att = 9;
7110203945Sweongyo				rfatt.padmix = 0;
7111203945Sweongyo			}
7112203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
7113203945Sweongyo		}
7114203945Sweongyo		bwn_dummy_transmission(mac, 0, 1);
7115203945Sweongyo		pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
7116203945Sweongyo		if (phy->rf_ver == 0x2050 && phy->analog == 0)
7117203945Sweongyo			BWN_RF_MASK(mac, 0x0076, 0xff7b);
7118203945Sweongyo		else
7119203945Sweongyo			bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
7120203945Sweongyo			    &old_rfatt, old_txctl);
7121203945Sweongyo	}
7122203945Sweongyo	bwn_hwpctl_init_gphy(mac);
7123203945Sweongyo
7124203945Sweongyo	/* clear TSSI */
7125203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
7126203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
7127203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
7128203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
7129203945Sweongyo}
7130203945Sweongyo
7131203945Sweongyostatic void
7132203945Sweongyobwn_hwpctl_early_init(struct bwn_mac *mac)
7133203945Sweongyo{
7134203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7135203945Sweongyo
7136203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7137203945Sweongyo		BWN_PHY_WRITE(mac, 0x047a, 0xc111);
7138203945Sweongyo		return;
7139203945Sweongyo	}
7140203945Sweongyo
7141203945Sweongyo	BWN_PHY_MASK(mac, 0x0036, 0xfeff);
7142203945Sweongyo	BWN_PHY_WRITE(mac, 0x002f, 0x0202);
7143203945Sweongyo	BWN_PHY_SET(mac, 0x047c, 0x0002);
7144203945Sweongyo	BWN_PHY_SET(mac, 0x047a, 0xf000);
7145203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
7146203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7147203945Sweongyo		BWN_PHY_SET(mac, 0x005d, 0x8000);
7148203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7149203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7150203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7151203945Sweongyo	} else {
7152203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0200);
7153203945Sweongyo		BWN_PHY_SET(mac, 0x0036, 0x0400);
7154203945Sweongyo		BWN_PHY_MASK(mac, 0x005d, 0x7fff);
7155203945Sweongyo		BWN_PHY_MASK(mac, 0x004f, 0xfffe);
7156203945Sweongyo		BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
7157203945Sweongyo		BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
7158203945Sweongyo		BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
7159203945Sweongyo	}
7160203945Sweongyo}
7161203945Sweongyo
7162203945Sweongyostatic void
7163203945Sweongyobwn_hwpctl_init_gphy(struct bwn_mac *mac)
7164203945Sweongyo{
7165203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7166203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7167203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7168203945Sweongyo	int i;
7169203945Sweongyo	uint16_t nr_written = 0, tmp, value;
7170203945Sweongyo	uint8_t rf, bb;
7171203945Sweongyo
7172203945Sweongyo	if (!bwn_has_hwpctl(mac)) {
7173203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
7174203945Sweongyo		return;
7175203945Sweongyo	}
7176203945Sweongyo
7177203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
7178203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7179203945Sweongyo	BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
7180203945Sweongyo	    (pg->pg_idletssi - pg->pg_curtssi));
7181203945Sweongyo
7182203945Sweongyo	for (i = 0; i < 32; i++)
7183203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
7184203945Sweongyo	for (i = 32; i < 64; i++)
7185203945Sweongyo		bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
7186203945Sweongyo	for (i = 0; i < 64; i += 2) {
7187203945Sweongyo		value = (uint16_t) pg->pg_tssi2dbm[i];
7188203945Sweongyo		value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
7189203945Sweongyo		BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
7190203945Sweongyo	}
7191203945Sweongyo
7192203945Sweongyo	for (rf = 0; rf < lo->rfatt.len; rf++) {
7193203945Sweongyo		for (bb = 0; bb < lo->bbatt.len; bb++) {
7194203945Sweongyo			if (nr_written >= 0x40)
7195203945Sweongyo				return;
7196203945Sweongyo			tmp = lo->bbatt.array[bb].att;
7197203945Sweongyo			tmp <<= 8;
7198203945Sweongyo			if (phy->rf_rev == 8)
7199203945Sweongyo				tmp |= 0x50;
7200203945Sweongyo			else
7201203945Sweongyo				tmp |= 0x40;
7202203945Sweongyo			tmp |= lo->rfatt.array[rf].att;
7203203945Sweongyo			BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
7204203945Sweongyo			nr_written++;
7205203945Sweongyo		}
7206203945Sweongyo	}
7207203945Sweongyo
7208203945Sweongyo	BWN_PHY_MASK(mac, 0x0060, 0xffbf);
7209203945Sweongyo	BWN_PHY_WRITE(mac, 0x0014, 0x0000);
7210203945Sweongyo
7211203945Sweongyo	KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
7212203945Sweongyo	BWN_PHY_SET(mac, 0x0478, 0x0800);
7213203945Sweongyo	BWN_PHY_MASK(mac, 0x0478, 0xfeff);
7214203945Sweongyo	BWN_PHY_MASK(mac, 0x0801, 0xffbf);
7215203945Sweongyo
7216203945Sweongyo	bwn_phy_g_dc_lookup_init(mac, 1);
7217203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
7218203945Sweongyo}
7219203945Sweongyo
7220203945Sweongyostatic void
7221203945Sweongyobwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
7222203945Sweongyo{
7223204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7224203945Sweongyo
7225203945Sweongyo	if (spu != 0)
7226203945Sweongyo		bwn_spu_workaround(mac, channel);
7227203945Sweongyo
7228203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7229203945Sweongyo
7230203945Sweongyo	if (channel == 14) {
7231204922Sweongyo		if (siba_sprom_get_ccode(sc->sc_dev) == SIBA_CCODE_JAPAN)
7232203945Sweongyo			bwn_hf_write(mac,
7233203945Sweongyo			    bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
7234203945Sweongyo		else
7235203945Sweongyo			bwn_hf_write(mac,
7236203945Sweongyo			    bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
7237203945Sweongyo		BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7238203945Sweongyo		    BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
7239203945Sweongyo		return;
7240203945Sweongyo	}
7241203945Sweongyo
7242203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
7243203945Sweongyo	    BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
7244203945Sweongyo}
7245203945Sweongyo
7246203945Sweongyostatic uint16_t
7247203945Sweongyobwn_phy_g_chan2freq(uint8_t channel)
7248203945Sweongyo{
7249203945Sweongyo	static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
7250203945Sweongyo
7251203945Sweongyo	KASSERT(channel >= 1 && channel <= 14,
7252203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7253203945Sweongyo
7254203945Sweongyo	return (bwn_phy_g_rf_channels[channel - 1]);
7255203945Sweongyo}
7256203945Sweongyo
7257203945Sweongyostatic void
7258203945Sweongyobwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
7259203945Sweongyo    const struct bwn_rfatt *rfatt, uint8_t txctl)
7260203945Sweongyo{
7261203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7262203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7263203945Sweongyo	struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
7264203945Sweongyo	uint16_t bb, rf;
7265203945Sweongyo	uint16_t tx_bias, tx_magn;
7266203945Sweongyo
7267203945Sweongyo	bb = bbatt->att;
7268203945Sweongyo	rf = rfatt->att;
7269203945Sweongyo	tx_bias = lo->tx_bias;
7270203945Sweongyo	tx_magn = lo->tx_magn;
7271203945Sweongyo	if (tx_bias == 0xff)
7272203945Sweongyo		tx_bias = 0;
7273203945Sweongyo
7274203945Sweongyo	pg->pg_txctl = txctl;
7275203945Sweongyo	memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
7276203945Sweongyo	pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
7277203945Sweongyo	memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
7278203945Sweongyo	bwn_phy_g_set_bbatt(mac, bb);
7279203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
7280203945Sweongyo	if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
7281203945Sweongyo		BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
7282203945Sweongyo	else {
7283203945Sweongyo		BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
7284203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
7285203945Sweongyo	}
7286203945Sweongyo	if (BWN_HAS_TXMAG(phy))
7287203945Sweongyo		BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
7288203945Sweongyo	else
7289203945Sweongyo		BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
7290203945Sweongyo	bwn_lo_g_adjust(mac);
7291203945Sweongyo}
7292203945Sweongyo
7293203945Sweongyostatic void
7294203945Sweongyobwn_phy_g_set_bbatt(struct bwn_mac *mac,
7295203945Sweongyo    uint16_t bbatt)
7296203945Sweongyo{
7297203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7298203945Sweongyo
7299203945Sweongyo	if (phy->analog == 0) {
7300203945Sweongyo		BWN_WRITE_2(mac, BWN_PHY0,
7301203945Sweongyo		    (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
7302203945Sweongyo		return;
7303203945Sweongyo	}
7304203945Sweongyo	if (phy->analog > 1) {
7305203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
7306203945Sweongyo		return;
7307203945Sweongyo	}
7308203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
7309203945Sweongyo}
7310203945Sweongyo
7311203945Sweongyostatic uint16_t
7312203945Sweongyobwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
7313203945Sweongyo{
7314203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
7315203945Sweongyo	struct bwn_phy_g *pg = &phy->phy_g;
7316204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7317203945Sweongyo	int max_lb_gain;
7318203945Sweongyo	uint16_t extlna;
7319203945Sweongyo	uint16_t i;
7320203945Sweongyo
7321203945Sweongyo	if (phy->gmode == 0)
7322203945Sweongyo		return (0);
7323203945Sweongyo
7324203945Sweongyo	if (BWN_HAS_LOOPBACK(phy)) {
7325203945Sweongyo		max_lb_gain = pg->pg_max_lb_gain;
7326203945Sweongyo		max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
7327203945Sweongyo		if (max_lb_gain >= 0x46) {
7328203945Sweongyo			extlna = 0x3000;
7329203945Sweongyo			max_lb_gain -= 0x46;
7330203945Sweongyo		} else if (max_lb_gain >= 0x3a) {
7331203945Sweongyo			extlna = 0x1000;
7332203945Sweongyo			max_lb_gain -= 0x3a;
7333203945Sweongyo		} else if (max_lb_gain >= 0x2e) {
7334203945Sweongyo			extlna = 0x2000;
7335203945Sweongyo			max_lb_gain -= 0x2e;
7336203945Sweongyo		} else {
7337203945Sweongyo			extlna = 0;
7338203945Sweongyo			max_lb_gain -= 0x10;
7339203945Sweongyo		}
7340203945Sweongyo
7341203945Sweongyo		for (i = 0; i < 16; i++) {
7342203945Sweongyo			max_lb_gain -= (i * 6);
7343203945Sweongyo			if (max_lb_gain < 6)
7344203945Sweongyo				break;
7345203945Sweongyo		}
7346203945Sweongyo
7347204922Sweongyo		if ((phy->rev < 7) ||
7348204922Sweongyo		    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
7349203945Sweongyo			if (reg == BWN_PHY_RFOVER) {
7350203945Sweongyo				return (0x1b3);
7351203945Sweongyo			} else if (reg == BWN_PHY_RFOVERVAL) {
7352203945Sweongyo				extlna |= (i << 8);
7353203945Sweongyo				switch (lpd) {
7354203945Sweongyo				case BWN_LPD(0, 1, 1):
7355203945Sweongyo					return (0x0f92);
7356203945Sweongyo				case BWN_LPD(0, 0, 1):
7357203945Sweongyo				case BWN_LPD(1, 0, 1):
7358203945Sweongyo					return (0x0092 | extlna);
7359203945Sweongyo				case BWN_LPD(1, 0, 0):
7360203945Sweongyo					return (0x0093 | extlna);
7361203945Sweongyo				}
7362203945Sweongyo				KASSERT(0 == 1,
7363203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7364203945Sweongyo			}
7365203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7366203945Sweongyo		} else {
7367203945Sweongyo			if (reg == BWN_PHY_RFOVER)
7368203945Sweongyo				return (0x9b3);
7369203945Sweongyo			if (reg == BWN_PHY_RFOVERVAL) {
7370203945Sweongyo				if (extlna)
7371203945Sweongyo					extlna |= 0x8000;
7372203945Sweongyo				extlna |= (i << 8);
7373203945Sweongyo				switch (lpd) {
7374203945Sweongyo				case BWN_LPD(0, 1, 1):
7375203945Sweongyo					return (0x8f92);
7376203945Sweongyo				case BWN_LPD(0, 0, 1):
7377203945Sweongyo					return (0x8092 | extlna);
7378203945Sweongyo				case BWN_LPD(1, 0, 1):
7379203945Sweongyo					return (0x2092 | extlna);
7380203945Sweongyo				case BWN_LPD(1, 0, 0):
7381203945Sweongyo					return (0x2093 | extlna);
7382203945Sweongyo				}
7383203945Sweongyo				KASSERT(0 == 1,
7384203945Sweongyo				    ("%s:%d: fail", __func__, __LINE__));
7385203945Sweongyo			}
7386203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7387203945Sweongyo		}
7388203945Sweongyo		return (0);
7389203945Sweongyo	}
7390203945Sweongyo
7391203945Sweongyo	if ((phy->rev < 7) ||
7392204922Sweongyo	    !(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_EXTLNA)) {
7393203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7394203945Sweongyo			return (0x1b3);
7395203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7396203945Sweongyo			switch (lpd) {
7397203945Sweongyo			case BWN_LPD(0, 1, 1):
7398203945Sweongyo				return (0x0fb2);
7399203945Sweongyo			case BWN_LPD(0, 0, 1):
7400203945Sweongyo				return (0x00b2);
7401203945Sweongyo			case BWN_LPD(1, 0, 1):
7402203945Sweongyo				return (0x30b2);
7403203945Sweongyo			case BWN_LPD(1, 0, 0):
7404203945Sweongyo				return (0x30b3);
7405203945Sweongyo			}
7406203945Sweongyo			KASSERT(0 == 1,
7407203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7408203945Sweongyo		}
7409203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7410203945Sweongyo	} else {
7411203945Sweongyo		if (reg == BWN_PHY_RFOVER) {
7412203945Sweongyo			return (0x9b3);
7413203945Sweongyo		} else if (reg == BWN_PHY_RFOVERVAL) {
7414203945Sweongyo			switch (lpd) {
7415203945Sweongyo			case BWN_LPD(0, 1, 1):
7416203945Sweongyo				return (0x8fb2);
7417203945Sweongyo			case BWN_LPD(0, 0, 1):
7418203945Sweongyo				return (0x80b2);
7419203945Sweongyo			case BWN_LPD(1, 0, 1):
7420203945Sweongyo				return (0x20b2);
7421203945Sweongyo			case BWN_LPD(1, 0, 0):
7422203945Sweongyo				return (0x20b3);
7423203945Sweongyo			}
7424203945Sweongyo			KASSERT(0 == 1,
7425203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
7426203945Sweongyo		}
7427203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7428203945Sweongyo	}
7429203945Sweongyo	return (0);
7430203945Sweongyo}
7431203945Sweongyo
7432203945Sweongyostatic void
7433203945Sweongyobwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
7434203945Sweongyo{
7435203945Sweongyo
7436203945Sweongyo	if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
7437203945Sweongyo		return;
7438203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
7439203945Sweongyo	    bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
7440203945Sweongyo	DELAY(1000);
7441203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
7442203945Sweongyo}
7443203945Sweongyo
7444203945Sweongyostatic int
7445203945Sweongyobwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
7446203945Sweongyo{
7447203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7448203945Sweongyo	struct bwn_fw *fw = &mac->mac_fw;
7449204922Sweongyo	const uint8_t rev = siba_get_revid(sc->sc_dev);
7450203945Sweongyo	const char *filename;
7451203945Sweongyo	uint32_t high;
7452203945Sweongyo	int error;
7453203945Sweongyo
7454203945Sweongyo	/* microcode */
7455203945Sweongyo	if (rev >= 5 && rev <= 10)
7456203945Sweongyo		filename = "ucode5";
7457203945Sweongyo	else if (rev >= 11 && rev <= 12)
7458203945Sweongyo		filename = "ucode11";
7459203945Sweongyo	else if (rev == 13)
7460203945Sweongyo		filename = "ucode13";
7461203945Sweongyo	else if (rev == 14)
7462203945Sweongyo		filename = "ucode14";
7463203945Sweongyo	else if (rev >= 15)
7464203945Sweongyo		filename = "ucode15";
7465203945Sweongyo	else {
7466203945Sweongyo		device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
7467203945Sweongyo		bwn_release_firmware(mac);
7468203945Sweongyo		return (EOPNOTSUPP);
7469203945Sweongyo	}
7470203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->ucode);
7471203945Sweongyo	if (error) {
7472203945Sweongyo		bwn_release_firmware(mac);
7473203945Sweongyo		return (error);
7474203945Sweongyo	}
7475203945Sweongyo
7476203945Sweongyo	/* PCM */
7477203945Sweongyo	KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
7478203945Sweongyo	if (rev >= 5 && rev <= 10) {
7479203945Sweongyo		error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
7480203945Sweongyo		if (error == ENOENT)
7481203945Sweongyo			fw->no_pcmfile = 1;
7482203945Sweongyo		else if (error) {
7483203945Sweongyo			bwn_release_firmware(mac);
7484203945Sweongyo			return (error);
7485203945Sweongyo		}
7486203945Sweongyo	} else if (rev < 11) {
7487203945Sweongyo		device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
7488203945Sweongyo		return (EOPNOTSUPP);
7489203945Sweongyo	}
7490203945Sweongyo
7491203945Sweongyo	/* initvals */
7492204922Sweongyo	high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH);
7493203945Sweongyo	switch (mac->mac_phy.type) {
7494203945Sweongyo	case BWN_PHYTYPE_A:
7495203945Sweongyo		if (rev < 5 || rev > 10)
7496203945Sweongyo			goto fail1;
7497203945Sweongyo		if (high & BWN_TGSHIGH_HAVE_2GHZ)
7498203945Sweongyo			filename = "a0g1initvals5";
7499203945Sweongyo		else
7500203945Sweongyo			filename = "a0g0initvals5";
7501203945Sweongyo		break;
7502203945Sweongyo	case BWN_PHYTYPE_G:
7503203945Sweongyo		if (rev >= 5 && rev <= 10)
7504203945Sweongyo			filename = "b0g0initvals5";
7505203945Sweongyo		else if (rev >= 13)
7506203945Sweongyo			filename = "b0g0initvals13";
7507203945Sweongyo		else
7508203945Sweongyo			goto fail1;
7509203945Sweongyo		break;
7510203945Sweongyo	case BWN_PHYTYPE_LP:
7511203945Sweongyo		if (rev == 13)
7512203945Sweongyo			filename = "lp0initvals13";
7513203945Sweongyo		else if (rev == 14)
7514203945Sweongyo			filename = "lp0initvals14";
7515203945Sweongyo		else if (rev >= 15)
7516203945Sweongyo			filename = "lp0initvals15";
7517203945Sweongyo		else
7518203945Sweongyo			goto fail1;
7519203945Sweongyo		break;
7520203945Sweongyo	case BWN_PHYTYPE_N:
7521203945Sweongyo		if (rev >= 11 && rev <= 12)
7522203945Sweongyo			filename = "n0initvals11";
7523203945Sweongyo		else
7524203945Sweongyo			goto fail1;
7525203945Sweongyo		break;
7526203945Sweongyo	default:
7527203945Sweongyo		goto fail1;
7528203945Sweongyo	}
7529203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals);
7530203945Sweongyo	if (error) {
7531203945Sweongyo		bwn_release_firmware(mac);
7532203945Sweongyo		return (error);
7533203945Sweongyo	}
7534203945Sweongyo
7535203945Sweongyo	/* bandswitch initvals */
7536203945Sweongyo	switch (mac->mac_phy.type) {
7537203945Sweongyo	case BWN_PHYTYPE_A:
7538203945Sweongyo		if (rev >= 5 && rev <= 10) {
7539203945Sweongyo			if (high & BWN_TGSHIGH_HAVE_2GHZ)
7540203945Sweongyo				filename = "a0g1bsinitvals5";
7541203945Sweongyo			else
7542203945Sweongyo				filename = "a0g0bsinitvals5";
7543203945Sweongyo		} else if (rev >= 11)
7544203945Sweongyo			filename = NULL;
7545203945Sweongyo		else
7546203945Sweongyo			goto fail1;
7547203945Sweongyo		break;
7548203945Sweongyo	case BWN_PHYTYPE_G:
7549203945Sweongyo		if (rev >= 5 && rev <= 10)
7550203945Sweongyo			filename = "b0g0bsinitvals5";
7551203945Sweongyo		else if (rev >= 11)
7552203945Sweongyo			filename = NULL;
7553203945Sweongyo		else
7554203945Sweongyo			goto fail1;
7555203945Sweongyo		break;
7556203945Sweongyo	case BWN_PHYTYPE_LP:
7557203945Sweongyo		if (rev == 13)
7558203945Sweongyo			filename = "lp0bsinitvals13";
7559203945Sweongyo		else if (rev == 14)
7560203945Sweongyo			filename = "lp0bsinitvals14";
7561203945Sweongyo		else if (rev >= 15)
7562203945Sweongyo			filename = "lp0bsinitvals15";
7563203945Sweongyo		else
7564203945Sweongyo			goto fail1;
7565203945Sweongyo		break;
7566203945Sweongyo	case BWN_PHYTYPE_N:
7567203945Sweongyo		if (rev >= 11 && rev <= 12)
7568203945Sweongyo			filename = "n0bsinitvals11";
7569203945Sweongyo		else
7570203945Sweongyo			goto fail1;
7571203945Sweongyo		break;
7572203945Sweongyo	default:
7573203945Sweongyo		goto fail1;
7574203945Sweongyo	}
7575203945Sweongyo	error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
7576203945Sweongyo	if (error) {
7577203945Sweongyo		bwn_release_firmware(mac);
7578203945Sweongyo		return (error);
7579203945Sweongyo	}
7580203945Sweongyo	return (0);
7581203945Sweongyofail1:
7582203945Sweongyo	device_printf(sc->sc_dev, "no INITVALS for rev %d\n", rev);
7583203945Sweongyo	bwn_release_firmware(mac);
7584203945Sweongyo	return (EOPNOTSUPP);
7585203945Sweongyo}
7586203945Sweongyo
7587203945Sweongyostatic int
7588203945Sweongyobwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
7589203945Sweongyo    const char *name, struct bwn_fwfile *bfw)
7590203945Sweongyo{
7591203945Sweongyo	const struct bwn_fwhdr *hdr;
7592203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7593203945Sweongyo	const struct firmware *fw;
7594203945Sweongyo	char namebuf[64];
7595203945Sweongyo
7596203945Sweongyo	if (name == NULL) {
7597203945Sweongyo		bwn_do_release_fw(bfw);
7598203945Sweongyo		return (0);
7599203945Sweongyo	}
7600203945Sweongyo	if (bfw->filename != NULL) {
7601203945Sweongyo		if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
7602203945Sweongyo			return (0);
7603203945Sweongyo		bwn_do_release_fw(bfw);
7604203945Sweongyo	}
7605203945Sweongyo
7606204437Sweongyo	snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s%s",
7607204437Sweongyo	    (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "",
7608204437Sweongyo	    (mac->mac_phy.type == BWN_PHYTYPE_LP) ? "lp_" : "", name);
7609203945Sweongyo	/* XXX Sleeping on "fwload" with the non-sleepable locks held */
7610203945Sweongyo	fw = firmware_get(namebuf);
7611203945Sweongyo	if (fw == NULL) {
7612203945Sweongyo		device_printf(sc->sc_dev, "the fw file(%s) not found\n",
7613203945Sweongyo		    namebuf);
7614203945Sweongyo		return (ENOENT);
7615203945Sweongyo	}
7616203945Sweongyo	if (fw->datasize < sizeof(struct bwn_fwhdr))
7617203945Sweongyo		goto fail;
7618203945Sweongyo	hdr = (const struct bwn_fwhdr *)(fw->data);
7619203945Sweongyo	switch (hdr->type) {
7620203945Sweongyo	case BWN_FWTYPE_UCODE:
7621203945Sweongyo	case BWN_FWTYPE_PCM:
7622203945Sweongyo		if (be32toh(hdr->size) !=
7623203945Sweongyo		    (fw->datasize - sizeof(struct bwn_fwhdr)))
7624203945Sweongyo			goto fail;
7625203945Sweongyo		/* FALLTHROUGH */
7626203945Sweongyo	case BWN_FWTYPE_IV:
7627203945Sweongyo		if (hdr->ver != 1)
7628203945Sweongyo			goto fail;
7629203945Sweongyo		break;
7630203945Sweongyo	default:
7631203945Sweongyo		goto fail;
7632203945Sweongyo	}
7633203945Sweongyo	bfw->filename = name;
7634203945Sweongyo	bfw->fw = fw;
7635203945Sweongyo	bfw->type = type;
7636203945Sweongyo	return (0);
7637203945Sweongyofail:
7638203945Sweongyo	device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
7639203945Sweongyo	if (fw != NULL)
7640203945Sweongyo		firmware_put(fw, FIRMWARE_UNLOAD);
7641203945Sweongyo	return (EPROTO);
7642203945Sweongyo}
7643203945Sweongyo
7644203945Sweongyostatic void
7645203945Sweongyobwn_release_firmware(struct bwn_mac *mac)
7646203945Sweongyo{
7647203945Sweongyo
7648203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.ucode);
7649203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.pcm);
7650203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals);
7651203945Sweongyo	bwn_do_release_fw(&mac->mac_fw.initvals_band);
7652203945Sweongyo}
7653203945Sweongyo
7654203945Sweongyostatic void
7655203945Sweongyobwn_do_release_fw(struct bwn_fwfile *bfw)
7656203945Sweongyo{
7657203945Sweongyo
7658203945Sweongyo	if (bfw->fw != NULL)
7659203945Sweongyo		firmware_put(bfw->fw, FIRMWARE_UNLOAD);
7660203945Sweongyo	bfw->fw = NULL;
7661203945Sweongyo	bfw->filename = NULL;
7662203945Sweongyo}
7663203945Sweongyo
7664203945Sweongyostatic int
7665203945Sweongyobwn_fw_loaducode(struct bwn_mac *mac)
7666203945Sweongyo{
7667203945Sweongyo#define	GETFWOFFSET(fwp, offset)	\
7668203945Sweongyo	((const uint32_t *)((const char *)fwp.fw->data + offset))
7669203945Sweongyo#define	GETFWSIZE(fwp, offset)	\
7670203945Sweongyo	((fwp.fw->datasize - offset) / sizeof(uint32_t))
7671203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7672203945Sweongyo	const uint32_t *data;
7673203945Sweongyo	unsigned int i;
7674203945Sweongyo	uint32_t ctl;
7675203945Sweongyo	uint16_t date, fwcaps, time;
7676203945Sweongyo	int error = 0;
7677203945Sweongyo
7678203945Sweongyo	ctl = BWN_READ_4(mac, BWN_MACCTL);
7679203945Sweongyo	ctl |= BWN_MACCTL_MCODE_JMP0;
7680203945Sweongyo	KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
7681203945Sweongyo	    __LINE__));
7682203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL, ctl);
7683203945Sweongyo	for (i = 0; i < 64; i++)
7684203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
7685203945Sweongyo	for (i = 0; i < 4096; i += 2)
7686203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, i, 0);
7687203945Sweongyo
7688203945Sweongyo	data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7689203945Sweongyo	bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
7690203945Sweongyo	for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
7691203945Sweongyo	     i++) {
7692203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7693203945Sweongyo		DELAY(10);
7694203945Sweongyo	}
7695203945Sweongyo
7696203945Sweongyo	if (mac->mac_fw.pcm.fw) {
7697203945Sweongyo		data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
7698203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
7699203945Sweongyo		BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
7700203945Sweongyo		bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
7701203945Sweongyo		for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
7702203945Sweongyo		    sizeof(struct bwn_fwhdr)); i++) {
7703203945Sweongyo			BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
7704203945Sweongyo			DELAY(10);
7705203945Sweongyo		}
7706203945Sweongyo	}
7707203945Sweongyo
7708203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
7709203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7710203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
7711203945Sweongyo	    BWN_MACCTL_MCODE_RUN);
7712203945Sweongyo
7713203945Sweongyo	for (i = 0; i < 21; i++) {
7714203945Sweongyo		if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
7715203945Sweongyo			break;
7716203945Sweongyo		if (i >= 20) {
7717203945Sweongyo			device_printf(sc->sc_dev, "ucode timeout\n");
7718203945Sweongyo			error = ENXIO;
7719203945Sweongyo			goto error;
7720203945Sweongyo		}
7721203945Sweongyo		DELAY(50000);
7722203945Sweongyo	}
7723203945Sweongyo	BWN_READ_4(mac, BWN_INTR_REASON);
7724203945Sweongyo
7725203945Sweongyo	mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
7726203945Sweongyo	if (mac->mac_fw.rev <= 0x128) {
7727203945Sweongyo		device_printf(sc->sc_dev, "the firmware is too old\n");
7728203945Sweongyo		error = EOPNOTSUPP;
7729203945Sweongyo		goto error;
7730203945Sweongyo	}
7731203945Sweongyo	mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
7732203945Sweongyo	    BWN_SHARED_UCODE_PATCH);
7733203945Sweongyo	date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
7734203945Sweongyo	mac->mac_fw.opensource = (date == 0xffff);
7735203945Sweongyo	if (bwn_wme != 0)
7736203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_WME;
7737203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
7738203945Sweongyo
7739203945Sweongyo	time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
7740203945Sweongyo	if (mac->mac_fw.opensource == 0) {
7741203945Sweongyo		device_printf(sc->sc_dev,
7742203945Sweongyo		    "firmware version (rev %u patch %u date %#x time %#x)\n",
7743203945Sweongyo		    mac->mac_fw.rev, mac->mac_fw.patch, date, time);
7744203945Sweongyo		if (mac->mac_fw.no_pcmfile)
7745203945Sweongyo			device_printf(sc->sc_dev,
7746203945Sweongyo			    "no HW crypto acceleration due to pcm5\n");
7747203945Sweongyo	} else {
7748203945Sweongyo		mac->mac_fw.patch = time;
7749203945Sweongyo		fwcaps = bwn_fwcaps_read(mac);
7750203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
7751203945Sweongyo			device_printf(sc->sc_dev,
7752203945Sweongyo			    "disabling HW crypto acceleration\n");
7753203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
7754203945Sweongyo		}
7755203945Sweongyo		if (!(fwcaps & BWN_FWCAPS_WME)) {
7756203945Sweongyo			device_printf(sc->sc_dev, "disabling WME support\n");
7757203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_WME;
7758203945Sweongyo		}
7759203945Sweongyo	}
7760203945Sweongyo
7761203945Sweongyo	if (BWN_ISOLDFMT(mac))
7762203945Sweongyo		device_printf(sc->sc_dev, "using old firmware image\n");
7763203945Sweongyo
7764203945Sweongyo	return (0);
7765203945Sweongyo
7766203945Sweongyoerror:
7767203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
7768203945Sweongyo	    (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
7769203945Sweongyo	    BWN_MACCTL_MCODE_JMP0);
7770203945Sweongyo
7771203945Sweongyo	return (error);
7772203945Sweongyo#undef GETFWSIZE
7773203945Sweongyo#undef GETFWOFFSET
7774203945Sweongyo}
7775203945Sweongyo
7776203945Sweongyo/* OpenFirmware only */
7777203945Sweongyostatic uint16_t
7778203945Sweongyobwn_fwcaps_read(struct bwn_mac *mac)
7779203945Sweongyo{
7780203945Sweongyo
7781203945Sweongyo	KASSERT(mac->mac_fw.opensource == 1,
7782203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7783203945Sweongyo	return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
7784203945Sweongyo}
7785203945Sweongyo
7786203945Sweongyostatic int
7787203945Sweongyobwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
7788203945Sweongyo    size_t count, size_t array_size)
7789203945Sweongyo{
7790203945Sweongyo#define	GET_NEXTIV16(iv)						\
7791203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7792203945Sweongyo	    sizeof(uint16_t) + sizeof(uint16_t)))
7793203945Sweongyo#define	GET_NEXTIV32(iv)						\
7794203945Sweongyo	((const struct bwn_fwinitvals *)((const uint8_t *)(iv) +	\
7795203945Sweongyo	    sizeof(uint16_t) + sizeof(uint32_t)))
7796203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7797203945Sweongyo	const struct bwn_fwinitvals *iv;
7798203945Sweongyo	uint16_t offset;
7799203945Sweongyo	size_t i;
7800203945Sweongyo	uint8_t bit32;
7801203945Sweongyo
7802203945Sweongyo	KASSERT(sizeof(struct bwn_fwinitvals) == 6,
7803203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7804203945Sweongyo	iv = ivals;
7805203945Sweongyo	for (i = 0; i < count; i++) {
7806203945Sweongyo		if (array_size < sizeof(iv->offset_size))
7807203945Sweongyo			goto fail;
7808203945Sweongyo		array_size -= sizeof(iv->offset_size);
7809203945Sweongyo		offset = be16toh(iv->offset_size);
7810203945Sweongyo		bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
7811203945Sweongyo		offset &= BWN_FWINITVALS_OFFSET_MASK;
7812203945Sweongyo		if (offset >= 0x1000)
7813203945Sweongyo			goto fail;
7814203945Sweongyo		if (bit32) {
7815203945Sweongyo			if (array_size < sizeof(iv->data.d32))
7816203945Sweongyo				goto fail;
7817203945Sweongyo			array_size -= sizeof(iv->data.d32);
7818203945Sweongyo			BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
7819203945Sweongyo			iv = GET_NEXTIV32(iv);
7820203945Sweongyo		} else {
7821203945Sweongyo
7822203945Sweongyo			if (array_size < sizeof(iv->data.d16))
7823203945Sweongyo				goto fail;
7824203945Sweongyo			array_size -= sizeof(iv->data.d16);
7825203945Sweongyo			BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
7826203945Sweongyo
7827203945Sweongyo			iv = GET_NEXTIV16(iv);
7828203945Sweongyo		}
7829203945Sweongyo	}
7830203945Sweongyo	if (array_size != 0)
7831203945Sweongyo		goto fail;
7832203945Sweongyo	return (0);
7833203945Sweongyofail:
7834203945Sweongyo	device_printf(sc->sc_dev, "initvals: invalid format\n");
7835203945Sweongyo	return (EPROTO);
7836203945Sweongyo#undef GET_NEXTIV16
7837203945Sweongyo#undef GET_NEXTIV32
7838203945Sweongyo}
7839203945Sweongyo
7840203945Sweongyostatic int
7841203945Sweongyobwn_switch_channel(struct bwn_mac *mac, int chan)
7842203945Sweongyo{
7843203945Sweongyo	struct bwn_phy *phy = &(mac->mac_phy);
7844203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7845287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
7846203945Sweongyo	uint16_t channelcookie, savedcookie;
7847203945Sweongyo	int error;
7848203945Sweongyo
7849203945Sweongyo	if (chan == 0xffff)
7850203945Sweongyo		chan = phy->get_default_chan(mac);
7851203945Sweongyo
7852203945Sweongyo	channelcookie = chan;
7853203945Sweongyo	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
7854203945Sweongyo		channelcookie |= 0x100;
7855203945Sweongyo	savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
7856203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
7857203945Sweongyo	error = phy->switch_channel(mac, chan);
7858203945Sweongyo	if (error)
7859203945Sweongyo		goto fail;
7860203945Sweongyo
7861203945Sweongyo	mac->mac_phy.chan = chan;
7862203945Sweongyo	DELAY(8000);
7863203945Sweongyo	return (0);
7864203945Sweongyofail:
7865203945Sweongyo	device_printf(sc->sc_dev, "failed to switch channel\n");
7866203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
7867203945Sweongyo	return (error);
7868203945Sweongyo}
7869203945Sweongyo
7870203945Sweongyostatic uint16_t
7871203945Sweongyobwn_ant2phy(int antenna)
7872203945Sweongyo{
7873203945Sweongyo
7874203945Sweongyo	switch (antenna) {
7875203945Sweongyo	case BWN_ANT0:
7876203945Sweongyo		return (BWN_TX_PHY_ANT0);
7877203945Sweongyo	case BWN_ANT1:
7878203945Sweongyo		return (BWN_TX_PHY_ANT1);
7879203945Sweongyo	case BWN_ANT2:
7880203945Sweongyo		return (BWN_TX_PHY_ANT2);
7881203945Sweongyo	case BWN_ANT3:
7882203945Sweongyo		return (BWN_TX_PHY_ANT3);
7883203945Sweongyo	case BWN_ANTAUTO:
7884203945Sweongyo		return (BWN_TX_PHY_ANT01AUTO);
7885203945Sweongyo	}
7886203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
7887203945Sweongyo	return (0);
7888203945Sweongyo}
7889203945Sweongyo
7890203945Sweongyostatic void
7891203945Sweongyobwn_wme_load(struct bwn_mac *mac)
7892203945Sweongyo{
7893203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7894203945Sweongyo	int i;
7895203945Sweongyo
7896203945Sweongyo	KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
7897203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
7898203945Sweongyo
7899203945Sweongyo	bwn_mac_suspend(mac);
7900203945Sweongyo	for (i = 0; i < N(sc->sc_wmeParams); i++)
7901203945Sweongyo		bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
7902203945Sweongyo		    bwn_wme_shm_offsets[i]);
7903203945Sweongyo	bwn_mac_enable(mac);
7904203945Sweongyo}
7905203945Sweongyo
7906203945Sweongyostatic void
7907203945Sweongyobwn_wme_loadparams(struct bwn_mac *mac,
7908203945Sweongyo    const struct wmeParams *p, uint16_t shm_offset)
7909203945Sweongyo{
7910203945Sweongyo#define	SM(_v, _f)      (((_v) << _f##_S) & _f)
7911203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7912203945Sweongyo	uint16_t params[BWN_NR_WMEPARAMS];
7913203945Sweongyo	int slot, tmp;
7914203945Sweongyo	unsigned int i;
7915203945Sweongyo
7916203945Sweongyo	slot = BWN_READ_2(mac, BWN_RNG) &
7917203945Sweongyo	    SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
7918203945Sweongyo
7919203945Sweongyo	memset(&params, 0, sizeof(params));
7920203945Sweongyo
7921203945Sweongyo	DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
7922203945Sweongyo	    "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
7923203945Sweongyo	    p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
7924203945Sweongyo
7925203945Sweongyo	params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
7926203945Sweongyo	params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
7927203945Sweongyo	params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
7928203945Sweongyo	params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
7929203945Sweongyo	params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
7930203945Sweongyo	params[BWN_WMEPARAM_BSLOTS] = slot;
7931203945Sweongyo	params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
7932203945Sweongyo
7933203945Sweongyo	for (i = 0; i < N(params); i++) {
7934203945Sweongyo		if (i == BWN_WMEPARAM_STATUS) {
7935203945Sweongyo			tmp = bwn_shm_read_2(mac, BWN_SHARED,
7936203945Sweongyo			    shm_offset + (i * 2));
7937203945Sweongyo			tmp |= 0x100;
7938203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
7939203945Sweongyo			    tmp);
7940203945Sweongyo		} else {
7941203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
7942203945Sweongyo			    params[i]);
7943203945Sweongyo		}
7944203945Sweongyo	}
7945203945Sweongyo}
7946203945Sweongyo
7947203945Sweongyostatic void
7948203945Sweongyobwn_mac_write_bssid(struct bwn_mac *mac)
7949203945Sweongyo{
7950203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
7951203945Sweongyo	uint32_t tmp;
7952203945Sweongyo	int i;
7953203945Sweongyo	uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
7954203945Sweongyo
7955203945Sweongyo	bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
7956287197Sglebius	memcpy(mac_bssid, sc->sc_ic.ic_macaddr, IEEE80211_ADDR_LEN);
7957203945Sweongyo	memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
7958203945Sweongyo	    IEEE80211_ADDR_LEN);
7959203945Sweongyo
7960203945Sweongyo	for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
7961203945Sweongyo		tmp = (uint32_t) (mac_bssid[i + 0]);
7962203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
7963203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
7964203945Sweongyo		tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
7965203945Sweongyo		bwn_ram_write(mac, 0x20 + i, tmp);
7966203945Sweongyo	}
7967203945Sweongyo}
7968203945Sweongyo
7969203945Sweongyostatic void
7970203945Sweongyobwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
7971203945Sweongyo    const uint8_t *macaddr)
7972203945Sweongyo{
7973203945Sweongyo	static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
7974203945Sweongyo	uint16_t data;
7975203945Sweongyo
7976203945Sweongyo	if (!mac)
7977203945Sweongyo		macaddr = zero;
7978203945Sweongyo
7979203945Sweongyo	offset |= 0x0020;
7980203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
7981203945Sweongyo
7982203945Sweongyo	data = macaddr[0];
7983203945Sweongyo	data |= macaddr[1] << 8;
7984203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
7985203945Sweongyo	data = macaddr[2];
7986203945Sweongyo	data |= macaddr[3] << 8;
7987203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
7988203945Sweongyo	data = macaddr[4];
7989203945Sweongyo	data |= macaddr[5] << 8;
7990203945Sweongyo	BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
7991203945Sweongyo}
7992203945Sweongyo
7993203945Sweongyostatic void
7994203945Sweongyobwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
7995203945Sweongyo    const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
7996203945Sweongyo{
7997203945Sweongyo	uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
7998203945Sweongyo	uint8_t per_sta_keys_start = 8;
7999203945Sweongyo
8000203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8001203945Sweongyo		per_sta_keys_start = 4;
8002203945Sweongyo
8003203945Sweongyo	KASSERT(index < mac->mac_max_nr_keys,
8004203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8005203945Sweongyo	KASSERT(key_len <= BWN_SEC_KEYSIZE,
8006203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8007203945Sweongyo
8008203945Sweongyo	if (index >= per_sta_keys_start)
8009203945Sweongyo		bwn_key_macwrite(mac, index, NULL);
8010203945Sweongyo	if (key)
8011203945Sweongyo		memcpy(buf, key, key_len);
8012203945Sweongyo	bwn_key_write(mac, index, algorithm, buf);
8013203945Sweongyo	if (index >= per_sta_keys_start)
8014203945Sweongyo		bwn_key_macwrite(mac, index, mac_addr);
8015203945Sweongyo
8016203945Sweongyo	mac->mac_key[index].algorithm = algorithm;
8017203945Sweongyo}
8018203945Sweongyo
8019203945Sweongyostatic void
8020203945Sweongyobwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
8021203945Sweongyo{
8022204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8023203945Sweongyo	uint32_t addrtmp[2] = { 0, 0 };
8024203945Sweongyo	uint8_t start = 8;
8025203945Sweongyo
8026203945Sweongyo	if (BWN_SEC_NEWAPI(mac))
8027203945Sweongyo		start = 4;
8028203945Sweongyo
8029203945Sweongyo	KASSERT(index >= start,
8030203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8031203945Sweongyo	index -= start;
8032203945Sweongyo
8033203945Sweongyo	if (addr) {
8034203945Sweongyo		addrtmp[0] = addr[0];
8035203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
8036203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
8037203945Sweongyo		addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
8038203945Sweongyo		addrtmp[1] = addr[4];
8039203945Sweongyo		addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
8040203945Sweongyo	}
8041203945Sweongyo
8042204922Sweongyo	if (siba_get_revid(sc->sc_dev) >= 5) {
8043203945Sweongyo		bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
8044203945Sweongyo		bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
8045203945Sweongyo	} else {
8046203945Sweongyo		if (index >= 8) {
8047203945Sweongyo			bwn_shm_write_4(mac, BWN_SHARED,
8048203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
8049203945Sweongyo			bwn_shm_write_2(mac, BWN_SHARED,
8050203945Sweongyo			    BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
8051203945Sweongyo		}
8052203945Sweongyo	}
8053203945Sweongyo}
8054203945Sweongyo
8055203945Sweongyostatic void
8056203945Sweongyobwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
8057203945Sweongyo    const uint8_t *key)
8058203945Sweongyo{
8059203945Sweongyo	unsigned int i;
8060203945Sweongyo	uint32_t offset;
8061203945Sweongyo	uint16_t kidx, value;
8062203945Sweongyo
8063203945Sweongyo	kidx = BWN_SEC_KEY2FW(mac, index);
8064203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED,
8065203945Sweongyo	    BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
8066203945Sweongyo
8067203945Sweongyo	offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
8068203945Sweongyo	for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
8069203945Sweongyo		value = key[i];
8070203945Sweongyo		value |= (uint16_t)(key[i + 1]) << 8;
8071203945Sweongyo		bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
8072203945Sweongyo	}
8073203945Sweongyo}
8074203945Sweongyo
8075203945Sweongyostatic void
8076203945Sweongyobwn_phy_exit(struct bwn_mac *mac)
8077203945Sweongyo{
8078203945Sweongyo
8079203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8080203945Sweongyo	if (mac->mac_phy.exit != NULL)
8081203945Sweongyo		mac->mac_phy.exit(mac);
8082203945Sweongyo}
8083203945Sweongyo
8084203945Sweongyostatic void
8085203945Sweongyobwn_dma_free(struct bwn_mac *mac)
8086203945Sweongyo{
8087203945Sweongyo	struct bwn_dma *dma;
8088203945Sweongyo
8089203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
8090203945Sweongyo		return;
8091203945Sweongyo	dma = &mac->mac_method.dma;
8092203945Sweongyo
8093203945Sweongyo	bwn_dma_ringfree(&dma->rx);
8094203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
8095203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
8096203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
8097203945Sweongyo	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
8098203945Sweongyo	bwn_dma_ringfree(&dma->mcast);
8099203945Sweongyo}
8100203945Sweongyo
8101203945Sweongyostatic void
8102203945Sweongyobwn_core_stop(struct bwn_mac *mac)
8103203945Sweongyo{
8104203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8105203945Sweongyo
8106203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8107203945Sweongyo
8108203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8109203945Sweongyo		return;
8110203945Sweongyo
8111203945Sweongyo	callout_stop(&sc->sc_rfswitch_ch);
8112203945Sweongyo	callout_stop(&sc->sc_task_ch);
8113203945Sweongyo	callout_stop(&sc->sc_watchdog_ch);
8114203945Sweongyo	sc->sc_watchdog_timer = 0;
8115203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8116203945Sweongyo	BWN_READ_4(mac, BWN_INTR_MASK);
8117203945Sweongyo	bwn_mac_suspend(mac);
8118203945Sweongyo
8119203945Sweongyo	mac->mac_status = BWN_MAC_STATUS_INITED;
8120203945Sweongyo}
8121203945Sweongyo
8122203945Sweongyostatic int
8123203945Sweongyobwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
8124203945Sweongyo{
8125203945Sweongyo	struct bwn_mac *up_dev = NULL;
8126203945Sweongyo	struct bwn_mac *down_dev;
8127203945Sweongyo	struct bwn_mac *mac;
8128203945Sweongyo	int err, status;
8129203945Sweongyo	uint8_t gmode;
8130203945Sweongyo
8131203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8132203945Sweongyo
8133203945Sweongyo	TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
8134203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(chan) &&
8135203945Sweongyo		    mac->mac_phy.supports_2ghz) {
8136203945Sweongyo			up_dev = mac;
8137203945Sweongyo			gmode = 1;
8138203945Sweongyo		} else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
8139203945Sweongyo		    mac->mac_phy.supports_5ghz) {
8140203945Sweongyo			up_dev = mac;
8141203945Sweongyo			gmode = 0;
8142203945Sweongyo		} else {
8143203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8144203945Sweongyo			return (EINVAL);
8145203945Sweongyo		}
8146203945Sweongyo		if (up_dev != NULL)
8147203945Sweongyo			break;
8148203945Sweongyo	}
8149203945Sweongyo	if (up_dev == NULL) {
8150203945Sweongyo		device_printf(sc->sc_dev, "Could not find a device\n");
8151203945Sweongyo		return (ENODEV);
8152203945Sweongyo	}
8153203945Sweongyo	if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
8154203945Sweongyo		return (0);
8155203945Sweongyo
8156203945Sweongyo	device_printf(sc->sc_dev, "switching to %s-GHz band\n",
8157203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8158203945Sweongyo
8159216227Skevlo	down_dev = sc->sc_curmac;
8160203945Sweongyo	status = down_dev->mac_status;
8161203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8162203945Sweongyo		bwn_core_stop(down_dev);
8163203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED)
8164203945Sweongyo		bwn_core_exit(down_dev);
8165203945Sweongyo
8166203945Sweongyo	if (down_dev != up_dev)
8167203945Sweongyo		bwn_phy_reset(down_dev);
8168203945Sweongyo
8169203945Sweongyo	up_dev->mac_phy.gmode = gmode;
8170203945Sweongyo	if (status >= BWN_MAC_STATUS_INITED) {
8171203945Sweongyo		err = bwn_core_init(up_dev);
8172203945Sweongyo		if (err) {
8173203945Sweongyo			device_printf(sc->sc_dev,
8174203945Sweongyo			    "fatal: failed to initialize for %s-GHz\n",
8175203945Sweongyo			    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
8176203945Sweongyo			goto fail;
8177203945Sweongyo		}
8178203945Sweongyo	}
8179203945Sweongyo	if (status >= BWN_MAC_STATUS_STARTED)
8180203945Sweongyo		bwn_core_start(up_dev);
8181203945Sweongyo	KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
8182203945Sweongyo	sc->sc_curmac = up_dev;
8183203945Sweongyo
8184203945Sweongyo	return (0);
8185203945Sweongyofail:
8186203945Sweongyo	sc->sc_curmac = NULL;
8187203945Sweongyo	return (err);
8188203945Sweongyo}
8189203945Sweongyo
8190203945Sweongyostatic void
8191203945Sweongyobwn_rf_turnon(struct bwn_mac *mac)
8192203945Sweongyo{
8193203945Sweongyo
8194203945Sweongyo	bwn_mac_suspend(mac);
8195203945Sweongyo	mac->mac_phy.rf_onoff(mac, 1);
8196203945Sweongyo	mac->mac_phy.rf_on = 1;
8197203945Sweongyo	bwn_mac_enable(mac);
8198203945Sweongyo}
8199203945Sweongyo
8200203945Sweongyostatic void
8201203945Sweongyobwn_rf_turnoff(struct bwn_mac *mac)
8202203945Sweongyo{
8203203945Sweongyo
8204203945Sweongyo	bwn_mac_suspend(mac);
8205203945Sweongyo	mac->mac_phy.rf_onoff(mac, 0);
8206203945Sweongyo	mac->mac_phy.rf_on = 0;
8207203945Sweongyo	bwn_mac_enable(mac);
8208203945Sweongyo}
8209203945Sweongyo
8210203945Sweongyostatic void
8211203945Sweongyobwn_phy_reset(struct bwn_mac *mac)
8212203945Sweongyo{
8213204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8214203945Sweongyo
8215204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
8216204922Sweongyo	    ((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
8217203945Sweongyo	     BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
8218203945Sweongyo	DELAY(1000);
8219204922Sweongyo	siba_write_4(sc->sc_dev, SIBA_TGSLOW,
8220204922Sweongyo	    (siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC) |
8221203945Sweongyo	    BWN_TGSLOW_PHYRESET);
8222203945Sweongyo	DELAY(1000);
8223203945Sweongyo}
8224203945Sweongyo
8225203945Sweongyostatic int
8226203945Sweongyobwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
8227203945Sweongyo{
8228203945Sweongyo	struct bwn_vap *bvp = BWN_VAP(vap);
8229203945Sweongyo	struct ieee80211com *ic= vap->iv_ic;
8230203945Sweongyo	enum ieee80211_state ostate = vap->iv_state;
8231286865Sadrian	struct bwn_softc *sc = ic->ic_softc;
8232203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
8233203945Sweongyo	int error;
8234203945Sweongyo
8235203945Sweongyo	DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
8236203945Sweongyo	    ieee80211_state_name[vap->iv_state],
8237203945Sweongyo	    ieee80211_state_name[nstate]);
8238203945Sweongyo
8239203945Sweongyo	error = bvp->bv_newstate(vap, nstate, arg);
8240203945Sweongyo	if (error != 0)
8241203945Sweongyo		return (error);
8242203945Sweongyo
8243203945Sweongyo	BWN_LOCK(sc);
8244203945Sweongyo
8245203945Sweongyo	bwn_led_newstate(mac, nstate);
8246203945Sweongyo
8247203945Sweongyo	/*
8248203945Sweongyo	 * Clear the BSSID when we stop a STA
8249203945Sweongyo	 */
8250203945Sweongyo	if (vap->iv_opmode == IEEE80211_M_STA) {
8251203945Sweongyo		if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
8252203945Sweongyo			/*
8253203945Sweongyo			 * Clear out the BSSID.  If we reassociate to
8254203945Sweongyo			 * the same AP, this will reinialize things
8255203945Sweongyo			 * correctly...
8256203945Sweongyo			 */
8257203945Sweongyo			if (ic->ic_opmode == IEEE80211_M_STA &&
8258203945Sweongyo			    (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
8259203945Sweongyo				memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
8260203945Sweongyo				bwn_set_macaddr(mac);
8261203945Sweongyo			}
8262203945Sweongyo		}
8263203945Sweongyo	}
8264203945Sweongyo
8265204436Sweongyo	if (vap->iv_opmode == IEEE80211_M_MONITOR ||
8266204436Sweongyo	    vap->iv_opmode == IEEE80211_M_AHDEMO) {
8267203945Sweongyo		/* XXX nothing to do? */
8268203945Sweongyo	} else if (nstate == IEEE80211_S_RUN) {
8269203945Sweongyo		memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
8270203945Sweongyo		bwn_set_opmode(mac);
8271203945Sweongyo		bwn_set_pretbtt(mac);
8272203945Sweongyo		bwn_spu_setdelay(mac, 0);
8273203945Sweongyo		bwn_set_macaddr(mac);
8274203945Sweongyo	}
8275203945Sweongyo
8276203945Sweongyo	BWN_UNLOCK(sc);
8277203945Sweongyo
8278203945Sweongyo	return (error);
8279203945Sweongyo}
8280203945Sweongyo
8281203945Sweongyostatic void
8282203945Sweongyobwn_set_pretbtt(struct bwn_mac *mac)
8283203945Sweongyo{
8284203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8285287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
8286203945Sweongyo	uint16_t pretbtt;
8287203945Sweongyo
8288203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8289203945Sweongyo		pretbtt = 2;
8290203945Sweongyo	else
8291203945Sweongyo		pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
8292203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
8293203945Sweongyo	BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
8294203945Sweongyo}
8295203945Sweongyo
8296203945Sweongyostatic int
8297203945Sweongyobwn_intr(void *arg)
8298203945Sweongyo{
8299203945Sweongyo	struct bwn_mac *mac = arg;
8300203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8301203945Sweongyo	uint32_t reason;
8302203945Sweongyo
8303204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
8304204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID))
8305203945Sweongyo		return (FILTER_STRAY);
8306203945Sweongyo
8307203945Sweongyo	reason = BWN_READ_4(mac, BWN_INTR_REASON);
8308203945Sweongyo	if (reason == 0xffffffff)	/* shared IRQ */
8309203945Sweongyo		return (FILTER_STRAY);
8310203945Sweongyo	reason &= mac->mac_intr_mask;
8311203945Sweongyo	if (reason == 0)
8312203945Sweongyo		return (FILTER_HANDLED);
8313203945Sweongyo
8314203945Sweongyo	mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
8315203945Sweongyo	mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
8316203945Sweongyo	mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
8317203945Sweongyo	mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
8318203945Sweongyo	mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
8319203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
8320203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
8321203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
8322203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
8323203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
8324203945Sweongyo	BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
8325203945Sweongyo
8326203945Sweongyo	/* Disable interrupts. */
8327203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
8328203945Sweongyo
8329203945Sweongyo	mac->mac_reason_intr = reason;
8330203945Sweongyo
8331203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8332203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8333203945Sweongyo
8334203945Sweongyo	taskqueue_enqueue_fast(sc->sc_tq, &mac->mac_intrtask);
8335203945Sweongyo	return (FILTER_HANDLED);
8336203945Sweongyo}
8337203945Sweongyo
8338203945Sweongyostatic void
8339203945Sweongyobwn_intrtask(void *arg, int npending)
8340203945Sweongyo{
8341203945Sweongyo	struct bwn_mac *mac = arg;
8342203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8343203945Sweongyo	uint32_t merged = 0;
8344203945Sweongyo	int i, tx = 0, rx = 0;
8345203945Sweongyo
8346203945Sweongyo	BWN_LOCK(sc);
8347204922Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED ||
8348204922Sweongyo	    (sc->sc_flags & BWN_FLAG_INVALID)) {
8349203945Sweongyo		BWN_UNLOCK(sc);
8350203945Sweongyo		return;
8351203945Sweongyo	}
8352203945Sweongyo
8353203945Sweongyo	for (i = 0; i < N(mac->mac_reason); i++)
8354203945Sweongyo		merged |= mac->mac_reason[i];
8355203945Sweongyo
8356203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
8357203945Sweongyo		device_printf(sc->sc_dev, "MAC trans error\n");
8358203945Sweongyo
8359203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
8360203945Sweongyo		DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
8361203945Sweongyo		mac->mac_phy.txerrors--;
8362203945Sweongyo		if (mac->mac_phy.txerrors == 0) {
8363203945Sweongyo			mac->mac_phy.txerrors = BWN_TXERROR_MAX;
8364203945Sweongyo			bwn_restart(mac, "PHY TX errors");
8365203945Sweongyo		}
8366203945Sweongyo	}
8367203945Sweongyo
8368203945Sweongyo	if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
8369203945Sweongyo		if (merged & BWN_DMAINTR_FATALMASK) {
8370203945Sweongyo			device_printf(sc->sc_dev,
8371203945Sweongyo			    "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
8372203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8373203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8374203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8375203945Sweongyo			bwn_restart(mac, "DMA error");
8376203945Sweongyo			BWN_UNLOCK(sc);
8377203945Sweongyo			return;
8378203945Sweongyo		}
8379203945Sweongyo		if (merged & BWN_DMAINTR_NONFATALMASK) {
8380203945Sweongyo			device_printf(sc->sc_dev,
8381203945Sweongyo			    "DMA error: %#x %#x %#x %#x %#x %#x\n",
8382203945Sweongyo			    mac->mac_reason[0], mac->mac_reason[1],
8383203945Sweongyo			    mac->mac_reason[2], mac->mac_reason[3],
8384203945Sweongyo			    mac->mac_reason[4], mac->mac_reason[5]);
8385203945Sweongyo		}
8386203945Sweongyo	}
8387203945Sweongyo
8388203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
8389203945Sweongyo		bwn_intr_ucode_debug(mac);
8390203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
8391203945Sweongyo		bwn_intr_tbtt_indication(mac);
8392203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
8393203945Sweongyo		bwn_intr_atim_end(mac);
8394203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_BEACON)
8395203945Sweongyo		bwn_intr_beacon(mac);
8396203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_PMQ)
8397203945Sweongyo		bwn_intr_pmq(mac);
8398203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
8399203945Sweongyo		bwn_intr_noise(mac);
8400203945Sweongyo
8401203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
8402203945Sweongyo		if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
8403203945Sweongyo			bwn_dma_rx(mac->mac_method.dma.rx);
8404203945Sweongyo			rx = 1;
8405203945Sweongyo		}
8406203945Sweongyo	} else
8407203945Sweongyo		rx = bwn_pio_rx(&mac->mac_method.pio.rx);
8408203945Sweongyo
8409203945Sweongyo	KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8410203945Sweongyo	KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8411203945Sweongyo	KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8412203945Sweongyo	KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8413203945Sweongyo	KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
8414203945Sweongyo
8415203945Sweongyo	if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
8416203945Sweongyo		bwn_intr_txeof(mac);
8417203945Sweongyo		tx = 1;
8418203945Sweongyo	}
8419203945Sweongyo
8420203945Sweongyo	BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
8421203945Sweongyo
8422203945Sweongyo	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
8423203945Sweongyo		int evt = BWN_LED_EVENT_NONE;
8424203945Sweongyo
8425203945Sweongyo		if (tx && rx) {
8426203945Sweongyo			if (sc->sc_rx_rate > sc->sc_tx_rate)
8427203945Sweongyo				evt = BWN_LED_EVENT_RX;
8428203945Sweongyo			else
8429203945Sweongyo				evt = BWN_LED_EVENT_TX;
8430203945Sweongyo		} else if (tx) {
8431203945Sweongyo			evt = BWN_LED_EVENT_TX;
8432203945Sweongyo		} else if (rx) {
8433203945Sweongyo			evt = BWN_LED_EVENT_RX;
8434203945Sweongyo		} else if (rx == 0) {
8435203945Sweongyo			evt = BWN_LED_EVENT_POLL;
8436203945Sweongyo		}
8437203945Sweongyo
8438203945Sweongyo		if (evt != BWN_LED_EVENT_NONE)
8439203945Sweongyo			bwn_led_event(mac, evt);
8440203945Sweongyo       }
8441203945Sweongyo
8442287197Sglebius	if (mbufq_first(&sc->sc_snd) != NULL)
8443287197Sglebius		bwn_start(sc);
8444203945Sweongyo
8445203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
8446203945Sweongyo	BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
8447203945Sweongyo
8448203945Sweongyo	BWN_UNLOCK(sc);
8449203945Sweongyo}
8450203945Sweongyo
8451203945Sweongyostatic void
8452203945Sweongyobwn_restart(struct bwn_mac *mac, const char *msg)
8453203945Sweongyo{
8454203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8455287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
8456203945Sweongyo
8457203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_INITED)
8458203945Sweongyo		return;
8459203945Sweongyo
8460203945Sweongyo	device_printf(sc->sc_dev, "HW reset: %s\n", msg);
8461203945Sweongyo	ieee80211_runtask(ic, &mac->mac_hwreset);
8462203945Sweongyo}
8463203945Sweongyo
8464203945Sweongyostatic void
8465203945Sweongyobwn_intr_ucode_debug(struct bwn_mac *mac)
8466203945Sweongyo{
8467203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8468203945Sweongyo	uint16_t reason;
8469203945Sweongyo
8470203945Sweongyo	if (mac->mac_fw.opensource == 0)
8471203945Sweongyo		return;
8472203945Sweongyo
8473203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
8474203945Sweongyo	switch (reason) {
8475203945Sweongyo	case BWN_DEBUGINTR_PANIC:
8476203945Sweongyo		bwn_handle_fwpanic(mac);
8477203945Sweongyo		break;
8478203945Sweongyo	case BWN_DEBUGINTR_DUMP_SHM:
8479203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
8480203945Sweongyo		break;
8481203945Sweongyo	case BWN_DEBUGINTR_DUMP_REGS:
8482203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
8483203945Sweongyo		break;
8484203945Sweongyo	case BWN_DEBUGINTR_MARKER:
8485203945Sweongyo		device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
8486203945Sweongyo		break;
8487203945Sweongyo	default:
8488203945Sweongyo		device_printf(sc->sc_dev,
8489203945Sweongyo		    "ucode debug unknown reason: %#x\n", reason);
8490203945Sweongyo	}
8491203945Sweongyo
8492203945Sweongyo	bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
8493203945Sweongyo	    BWN_DEBUGINTR_ACK);
8494203945Sweongyo}
8495203945Sweongyo
8496203945Sweongyostatic void
8497203945Sweongyobwn_intr_tbtt_indication(struct bwn_mac *mac)
8498203945Sweongyo{
8499203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8500287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
8501203945Sweongyo
8502203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
8503203945Sweongyo		bwn_psctl(mac, 0);
8504203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_IBSS)
8505203945Sweongyo		mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
8506203945Sweongyo}
8507203945Sweongyo
8508203945Sweongyostatic void
8509203945Sweongyobwn_intr_atim_end(struct bwn_mac *mac)
8510203945Sweongyo{
8511203945Sweongyo
8512203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
8513203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD,
8514203945Sweongyo		    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
8515203945Sweongyo		mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
8516203945Sweongyo	}
8517203945Sweongyo}
8518203945Sweongyo
8519203945Sweongyostatic void
8520203945Sweongyobwn_intr_beacon(struct bwn_mac *mac)
8521203945Sweongyo{
8522203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8523287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
8524203945Sweongyo	uint32_t cmd, beacon0, beacon1;
8525203945Sweongyo
8526203945Sweongyo	if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
8527203945Sweongyo	    ic->ic_opmode == IEEE80211_M_MBSS)
8528203945Sweongyo		return;
8529203945Sweongyo
8530203945Sweongyo	mac->mac_intr_mask &= ~BWN_INTR_BEACON;
8531203945Sweongyo
8532203945Sweongyo	cmd = BWN_READ_4(mac, BWN_MACCMD);
8533203945Sweongyo	beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
8534203945Sweongyo	beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
8535203945Sweongyo
8536203945Sweongyo	if (beacon0 && beacon1) {
8537203945Sweongyo		BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
8538203945Sweongyo		mac->mac_intr_mask |= BWN_INTR_BEACON;
8539203945Sweongyo		return;
8540203945Sweongyo	}
8541203945Sweongyo
8542203945Sweongyo	if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
8543203945Sweongyo		sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
8544203945Sweongyo		bwn_load_beacon0(mac);
8545203945Sweongyo		bwn_load_beacon1(mac);
8546203945Sweongyo		cmd = BWN_READ_4(mac, BWN_MACCMD);
8547203945Sweongyo		cmd |= BWN_MACCMD_BEACON0_VALID;
8548203945Sweongyo		BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8549203945Sweongyo	} else {
8550203945Sweongyo		if (!beacon0) {
8551203945Sweongyo			bwn_load_beacon0(mac);
8552203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8553203945Sweongyo			cmd |= BWN_MACCMD_BEACON0_VALID;
8554203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8555203945Sweongyo		} else if (!beacon1) {
8556203945Sweongyo			bwn_load_beacon1(mac);
8557203945Sweongyo			cmd = BWN_READ_4(mac, BWN_MACCMD);
8558203945Sweongyo			cmd |= BWN_MACCMD_BEACON1_VALID;
8559203945Sweongyo			BWN_WRITE_4(mac, BWN_MACCMD, cmd);
8560203945Sweongyo		}
8561203945Sweongyo	}
8562203945Sweongyo}
8563203945Sweongyo
8564203945Sweongyostatic void
8565203945Sweongyobwn_intr_pmq(struct bwn_mac *mac)
8566203945Sweongyo{
8567203945Sweongyo	uint32_t tmp;
8568203945Sweongyo
8569203945Sweongyo	while (1) {
8570203945Sweongyo		tmp = BWN_READ_4(mac, BWN_PS_STATUS);
8571203945Sweongyo		if (!(tmp & 0x00000008))
8572203945Sweongyo			break;
8573203945Sweongyo	}
8574203945Sweongyo	BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
8575203945Sweongyo}
8576203945Sweongyo
8577203945Sweongyostatic void
8578203945Sweongyobwn_intr_noise(struct bwn_mac *mac)
8579203945Sweongyo{
8580203945Sweongyo	struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
8581203945Sweongyo	uint16_t tmp;
8582203945Sweongyo	uint8_t noise[4];
8583203945Sweongyo	uint8_t i, j;
8584203945Sweongyo	int32_t average;
8585203945Sweongyo
8586203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
8587203945Sweongyo		return;
8588203945Sweongyo
8589203945Sweongyo	KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
8590203945Sweongyo	*((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
8591203945Sweongyo	if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
8592203945Sweongyo	    noise[3] == 0x7f)
8593203945Sweongyo		goto new;
8594203945Sweongyo
8595203945Sweongyo	KASSERT(mac->mac_noise.noi_nsamples < 8,
8596203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8597203945Sweongyo	i = mac->mac_noise.noi_nsamples;
8598203945Sweongyo	noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
8599203945Sweongyo	noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
8600203945Sweongyo	noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
8601203945Sweongyo	noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
8602203945Sweongyo	mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
8603203945Sweongyo	mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
8604203945Sweongyo	mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
8605203945Sweongyo	mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
8606203945Sweongyo	mac->mac_noise.noi_nsamples++;
8607203945Sweongyo	if (mac->mac_noise.noi_nsamples == 8) {
8608203945Sweongyo		average = 0;
8609203945Sweongyo		for (i = 0; i < 8; i++) {
8610203945Sweongyo			for (j = 0; j < 4; j++)
8611203945Sweongyo				average += mac->mac_noise.noi_samples[i][j];
8612203945Sweongyo		}
8613203945Sweongyo		average = (((average / 32) * 125) + 64) / 128;
8614203945Sweongyo		tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
8615203945Sweongyo		if (tmp >= 8)
8616203945Sweongyo			average += 2;
8617203945Sweongyo		else
8618203945Sweongyo			average -= 25;
8619203945Sweongyo		average -= (tmp == 8) ? 72 : 48;
8620203945Sweongyo
8621203945Sweongyo		mac->mac_stats.link_noise = average;
8622203945Sweongyo		mac->mac_noise.noi_running = 0;
8623203945Sweongyo		return;
8624203945Sweongyo	}
8625203945Sweongyonew:
8626203945Sweongyo	bwn_noise_gensample(mac);
8627203945Sweongyo}
8628203945Sweongyo
8629203945Sweongyostatic int
8630203945Sweongyobwn_pio_rx(struct bwn_pio_rxqueue *prq)
8631203945Sweongyo{
8632203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
8633203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8634203945Sweongyo	unsigned int i;
8635203945Sweongyo
8636203945Sweongyo	BWN_ASSERT_LOCKED(sc);
8637203945Sweongyo
8638203945Sweongyo	if (mac->mac_status < BWN_MAC_STATUS_STARTED)
8639203945Sweongyo		return (0);
8640203945Sweongyo
8641203945Sweongyo	for (i = 0; i < 5000; i++) {
8642203945Sweongyo		if (bwn_pio_rxeof(prq) == 0)
8643203945Sweongyo			break;
8644203945Sweongyo	}
8645203945Sweongyo	if (i >= 5000)
8646203945Sweongyo		device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
8647203945Sweongyo	return ((i > 0) ? 1 : 0);
8648203945Sweongyo}
8649203945Sweongyo
8650203945Sweongyostatic void
8651203945Sweongyobwn_dma_rx(struct bwn_dma_ring *dr)
8652203945Sweongyo{
8653203945Sweongyo	int slot, curslot;
8654203945Sweongyo
8655203945Sweongyo	KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
8656203945Sweongyo	curslot = dr->get_curslot(dr);
8657203945Sweongyo	KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
8658203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8659203945Sweongyo
8660203945Sweongyo	slot = dr->dr_curslot;
8661203945Sweongyo	for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
8662203945Sweongyo		bwn_dma_rxeof(dr, &slot);
8663203945Sweongyo
8664203945Sweongyo	bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
8665203945Sweongyo	    BUS_DMASYNC_PREWRITE);
8666203945Sweongyo
8667203945Sweongyo	dr->set_curslot(dr, slot);
8668203945Sweongyo	dr->dr_curslot = slot;
8669203945Sweongyo}
8670203945Sweongyo
8671203945Sweongyostatic void
8672203945Sweongyobwn_intr_txeof(struct bwn_mac *mac)
8673203945Sweongyo{
8674203945Sweongyo	struct bwn_txstatus stat;
8675203945Sweongyo	uint32_t stat0, stat1;
8676203945Sweongyo	uint16_t tmp;
8677203945Sweongyo
8678203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8679203945Sweongyo
8680203945Sweongyo	while (1) {
8681203945Sweongyo		stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
8682203945Sweongyo		if (!(stat0 & 0x00000001))
8683203945Sweongyo			break;
8684203945Sweongyo		stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
8685203945Sweongyo
8686203945Sweongyo		stat.cookie = (stat0 >> 16);
8687203945Sweongyo		stat.seq = (stat1 & 0x0000ffff);
8688203945Sweongyo		stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
8689203945Sweongyo		tmp = (stat0 & 0x0000ffff);
8690203945Sweongyo		stat.framecnt = ((tmp & 0xf000) >> 12);
8691203945Sweongyo		stat.rtscnt = ((tmp & 0x0f00) >> 8);
8692203945Sweongyo		stat.sreason = ((tmp & 0x001c) >> 2);
8693203945Sweongyo		stat.pm = (tmp & 0x0080) ? 1 : 0;
8694203945Sweongyo		stat.im = (tmp & 0x0040) ? 1 : 0;
8695203945Sweongyo		stat.ampdu = (tmp & 0x0020) ? 1 : 0;
8696203945Sweongyo		stat.ack = (tmp & 0x0002) ? 1 : 0;
8697203945Sweongyo
8698203945Sweongyo		bwn_handle_txeof(mac, &stat);
8699203945Sweongyo	}
8700203945Sweongyo}
8701203945Sweongyo
8702203945Sweongyostatic void
8703203945Sweongyobwn_hwreset(void *arg, int npending)
8704203945Sweongyo{
8705203945Sweongyo	struct bwn_mac *mac = arg;
8706203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8707203945Sweongyo	int error = 0;
8708203945Sweongyo	int prev_status;
8709203945Sweongyo
8710203945Sweongyo	BWN_LOCK(sc);
8711203945Sweongyo
8712203945Sweongyo	prev_status = mac->mac_status;
8713203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8714203945Sweongyo		bwn_core_stop(mac);
8715203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED)
8716203945Sweongyo		bwn_core_exit(mac);
8717203945Sweongyo
8718203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_INITED) {
8719203945Sweongyo		error = bwn_core_init(mac);
8720203945Sweongyo		if (error)
8721203945Sweongyo			goto out;
8722203945Sweongyo	}
8723203945Sweongyo	if (prev_status >= BWN_MAC_STATUS_STARTED)
8724203945Sweongyo		bwn_core_start(mac);
8725203945Sweongyoout:
8726203945Sweongyo	if (error) {
8727203945Sweongyo		device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
8728203945Sweongyo		sc->sc_curmac = NULL;
8729203945Sweongyo	}
8730203945Sweongyo	BWN_UNLOCK(sc);
8731203945Sweongyo}
8732203945Sweongyo
8733203945Sweongyostatic void
8734203945Sweongyobwn_handle_fwpanic(struct bwn_mac *mac)
8735203945Sweongyo{
8736203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8737203945Sweongyo	uint16_t reason;
8738203945Sweongyo
8739203945Sweongyo	reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
8740203945Sweongyo	device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
8741203945Sweongyo
8742203945Sweongyo	if (reason == BWN_FWPANIC_RESTART)
8743203945Sweongyo		bwn_restart(mac, "ucode panic");
8744203945Sweongyo}
8745203945Sweongyo
8746203945Sweongyostatic void
8747203945Sweongyobwn_load_beacon0(struct bwn_mac *mac)
8748203945Sweongyo{
8749203945Sweongyo
8750203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8751203945Sweongyo}
8752203945Sweongyo
8753203945Sweongyostatic void
8754203945Sweongyobwn_load_beacon1(struct bwn_mac *mac)
8755203945Sweongyo{
8756203945Sweongyo
8757203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
8758203945Sweongyo}
8759203945Sweongyo
8760203945Sweongyostatic uint32_t
8761203945Sweongyobwn_jssi_read(struct bwn_mac *mac)
8762203945Sweongyo{
8763203945Sweongyo	uint32_t val = 0;
8764203945Sweongyo
8765203945Sweongyo	val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
8766203945Sweongyo	val <<= 16;
8767203945Sweongyo	val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
8768203945Sweongyo
8769203945Sweongyo	return (val);
8770203945Sweongyo}
8771203945Sweongyo
8772203945Sweongyostatic void
8773203945Sweongyobwn_noise_gensample(struct bwn_mac *mac)
8774203945Sweongyo{
8775203945Sweongyo	uint32_t jssi = 0x7f7f7f7f;
8776203945Sweongyo
8777203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
8778203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
8779203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCMD,
8780203945Sweongyo	    BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
8781203945Sweongyo}
8782203945Sweongyo
8783203945Sweongyostatic int
8784203945Sweongyobwn_dma_freeslot(struct bwn_dma_ring *dr)
8785203945Sweongyo{
8786204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8787203945Sweongyo
8788203945Sweongyo	return (dr->dr_numslots - dr->dr_usedslot);
8789203945Sweongyo}
8790203945Sweongyo
8791203945Sweongyostatic int
8792203945Sweongyobwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
8793203945Sweongyo{
8794204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
8795203945Sweongyo
8796203945Sweongyo	KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
8797203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
8798203945Sweongyo	if (slot == dr->dr_numslots - 1)
8799203945Sweongyo		return (0);
8800203945Sweongyo	return (slot + 1);
8801203945Sweongyo}
8802203945Sweongyo
8803203945Sweongyostatic void
8804203945Sweongyobwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
8805203945Sweongyo{
8806203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
8807203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8808203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
8809203945Sweongyo	struct bwn_dmadesc_generic *desc;
8810203945Sweongyo	struct bwn_dmadesc_meta *meta;
8811203945Sweongyo	struct bwn_rxhdr4 *rxhdr;
8812203945Sweongyo	struct mbuf *m;
8813203945Sweongyo	uint32_t macstat;
8814203945Sweongyo	int32_t tmp;
8815203945Sweongyo	int cnt = 0;
8816203945Sweongyo	uint16_t len;
8817203945Sweongyo
8818203945Sweongyo	dr->getdesc(dr, *slot, &desc, &meta);
8819203945Sweongyo
8820203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
8821203945Sweongyo	m = meta->mt_m;
8822203945Sweongyo
8823203945Sweongyo	if (bwn_dma_newbuf(dr, desc, meta, 0)) {
8824287197Sglebius		counter_u64_add(sc->sc_ic.ic_ierrors, 1);
8825203945Sweongyo		return;
8826203945Sweongyo	}
8827203945Sweongyo
8828203945Sweongyo	rxhdr = mtod(m, struct bwn_rxhdr4 *);
8829203945Sweongyo	len = le16toh(rxhdr->frame_len);
8830203945Sweongyo	if (len <= 0) {
8831287197Sglebius		counter_u64_add(sc->sc_ic.ic_ierrors, 1);
8832203945Sweongyo		return;
8833203945Sweongyo	}
8834203945Sweongyo	if (bwn_dma_check_redzone(dr, m)) {
8835203945Sweongyo		device_printf(sc->sc_dev, "redzone error.\n");
8836203945Sweongyo		bwn_dma_set_redzone(dr, m);
8837203945Sweongyo		bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
8838203945Sweongyo		    BUS_DMASYNC_PREWRITE);
8839203945Sweongyo		return;
8840203945Sweongyo	}
8841203945Sweongyo	if (len > dr->dr_rx_bufsize) {
8842203945Sweongyo		tmp = len;
8843203945Sweongyo		while (1) {
8844203945Sweongyo			dr->getdesc(dr, *slot, &desc, &meta);
8845203945Sweongyo			bwn_dma_set_redzone(dr, meta->mt_m);
8846203945Sweongyo			bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
8847203945Sweongyo			    BUS_DMASYNC_PREWRITE);
8848203945Sweongyo			*slot = bwn_dma_nextslot(dr, *slot);
8849203945Sweongyo			cnt++;
8850203945Sweongyo			tmp -= dr->dr_rx_bufsize;
8851203945Sweongyo			if (tmp <= 0)
8852203945Sweongyo				break;
8853203945Sweongyo		}
8854203945Sweongyo		device_printf(sc->sc_dev, "too small buffer "
8855203945Sweongyo		       "(len %u buffer %u dropped %d)\n",
8856203945Sweongyo		       len, dr->dr_rx_bufsize, cnt);
8857203945Sweongyo		return;
8858203945Sweongyo	}
8859203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
8860203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
8861203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
8862203945Sweongyo			device_printf(sc->sc_dev, "RX drop\n");
8863203945Sweongyo			return;
8864203945Sweongyo		}
8865203945Sweongyo	}
8866203945Sweongyo
8867203945Sweongyo	m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
8868203945Sweongyo	m_adj(m, dr->dr_frameoffset);
8869203945Sweongyo
8870203945Sweongyo	bwn_rxeof(dr->dr_mac, m, rxhdr);
8871203945Sweongyo}
8872203945Sweongyo
8873203945Sweongyostatic void
8874203945Sweongyobwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
8875203945Sweongyo{
8876203945Sweongyo	struct bwn_dma_ring *dr;
8877203945Sweongyo	struct bwn_dmadesc_generic *desc;
8878203945Sweongyo	struct bwn_dmadesc_meta *meta;
8879203945Sweongyo	struct bwn_pio_txqueue *tq;
8880203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
8881203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8882204257Sweongyo	struct bwn_stats *stats = &mac->mac_stats;
8883203945Sweongyo	struct ieee80211_node *ni;
8884206358Srpaulo	struct ieee80211vap *vap;
8885208120Sweongyo	int retrycnt = 0, slot;
8886203945Sweongyo
8887203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
8888203945Sweongyo
8889203945Sweongyo	if (status->im)
8890203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS IM\n");
8891203945Sweongyo	if (status->ampdu)
8892203945Sweongyo		device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
8893203945Sweongyo	if (status->rtscnt) {
8894203945Sweongyo		if (status->rtscnt == 0xf)
8895204257Sweongyo			stats->rtsfail++;
8896203945Sweongyo		else
8897204257Sweongyo			stats->rts++;
8898203945Sweongyo	}
8899203945Sweongyo
8900203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
8901203945Sweongyo		if (status->ack) {
8902203945Sweongyo			dr = bwn_dma_parse_cookie(mac, status,
8903203945Sweongyo			    status->cookie, &slot);
8904203945Sweongyo			if (dr == NULL) {
8905203945Sweongyo				device_printf(sc->sc_dev,
8906203945Sweongyo				    "failed to parse cookie\n");
8907203945Sweongyo				return;
8908203945Sweongyo			}
8909203945Sweongyo			while (1) {
8910203945Sweongyo				dr->getdesc(dr, slot, &desc, &meta);
8911203945Sweongyo				if (meta->mt_islast) {
8912203945Sweongyo					ni = meta->mt_ni;
8913206358Srpaulo					vap = ni->ni_vap;
8914206358Srpaulo					ieee80211_ratectl_tx_complete(vap, ni,
8915206358Srpaulo					    status->ack ?
8916206358Srpaulo					      IEEE80211_RATECTL_TX_SUCCESS :
8917206358Srpaulo					      IEEE80211_RATECTL_TX_FAILURE,
8918208120Sweongyo					    &retrycnt, 0);
8919203945Sweongyo					break;
8920203945Sweongyo				}
8921203945Sweongyo				slot = bwn_dma_nextslot(dr, slot);
8922203945Sweongyo			}
8923203945Sweongyo		}
8924203945Sweongyo		bwn_dma_handle_txeof(mac, status);
8925203945Sweongyo	} else {
8926203945Sweongyo		if (status->ack) {
8927203945Sweongyo			tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
8928203945Sweongyo			if (tq == NULL) {
8929203945Sweongyo				device_printf(sc->sc_dev,
8930203945Sweongyo				    "failed to parse cookie\n");
8931203945Sweongyo				return;
8932203945Sweongyo			}
8933203945Sweongyo			ni = tp->tp_ni;
8934206358Srpaulo			vap = ni->ni_vap;
8935206358Srpaulo			ieee80211_ratectl_tx_complete(vap, ni,
8936206358Srpaulo			    status->ack ?
8937206358Srpaulo			      IEEE80211_RATECTL_TX_SUCCESS :
8938206358Srpaulo			      IEEE80211_RATECTL_TX_FAILURE,
8939208120Sweongyo			    &retrycnt, 0);
8940203945Sweongyo		}
8941203945Sweongyo		bwn_pio_handle_txeof(mac, status);
8942203945Sweongyo	}
8943203945Sweongyo
8944203945Sweongyo	bwn_phy_txpower_check(mac, 0);
8945203945Sweongyo}
8946203945Sweongyo
8947203945Sweongyostatic uint8_t
8948203945Sweongyobwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
8949203945Sweongyo{
8950203945Sweongyo	struct bwn_mac *mac = prq->prq_mac;
8951203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
8952203945Sweongyo	struct bwn_rxhdr4 rxhdr;
8953203945Sweongyo	struct mbuf *m;
8954203945Sweongyo	uint32_t ctl32, macstat, v32;
8955203945Sweongyo	unsigned int i, padding;
8956209888Sweongyo	uint16_t ctl16, len, totlen, v16;
8957203945Sweongyo	unsigned char *mp;
8958203945Sweongyo	char *data;
8959203945Sweongyo
8960203945Sweongyo	memset(&rxhdr, 0, sizeof(rxhdr));
8961203945Sweongyo
8962203945Sweongyo	if (prq->prq_rev >= 8) {
8963203945Sweongyo		ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
8964203945Sweongyo		if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
8965203945Sweongyo			return (0);
8966203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
8967203945Sweongyo		    BWN_PIO8_RXCTL_FRAMEREADY);
8968203945Sweongyo		for (i = 0; i < 10; i++) {
8969203945Sweongyo			ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
8970203945Sweongyo			if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
8971203945Sweongyo				goto ready;
8972203945Sweongyo			DELAY(10);
8973203945Sweongyo		}
8974203945Sweongyo	} else {
8975203945Sweongyo		ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
8976203945Sweongyo		if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
8977203945Sweongyo			return (0);
8978203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
8979203945Sweongyo		    BWN_PIO_RXCTL_FRAMEREADY);
8980203945Sweongyo		for (i = 0; i < 10; i++) {
8981203945Sweongyo			ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
8982203945Sweongyo			if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
8983203945Sweongyo				goto ready;
8984203945Sweongyo			DELAY(10);
8985203945Sweongyo		}
8986203945Sweongyo	}
8987203945Sweongyo	device_printf(sc->sc_dev, "%s: timed out\n", __func__);
8988203945Sweongyo	return (1);
8989203945Sweongyoready:
8990203945Sweongyo	if (prq->prq_rev >= 8)
8991204922Sweongyo		siba_read_multi_4(sc->sc_dev, &rxhdr, sizeof(rxhdr),
8992203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
8993203945Sweongyo	else
8994204922Sweongyo		siba_read_multi_2(sc->sc_dev, &rxhdr, sizeof(rxhdr),
8995203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
8996203945Sweongyo	len = le16toh(rxhdr.frame_len);
8997203945Sweongyo	if (len > 0x700) {
8998203945Sweongyo		device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
8999203945Sweongyo		goto error;
9000203945Sweongyo	}
9001203945Sweongyo	if (len == 0) {
9002203945Sweongyo		device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
9003203945Sweongyo		goto error;
9004203945Sweongyo	}
9005203945Sweongyo
9006203945Sweongyo	macstat = le32toh(rxhdr.mac_status);
9007203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR) {
9008203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
9009203945Sweongyo			device_printf(sc->sc_dev, "%s: FCS error", __func__);
9010203945Sweongyo			goto error;
9011203945Sweongyo		}
9012203945Sweongyo	}
9013203945Sweongyo
9014203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9015209888Sweongyo	totlen = len + padding;
9016209888Sweongyo	KASSERT(totlen <= MCLBYTES, ("too big..\n"));
9017243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
9018203945Sweongyo	if (m == NULL) {
9019203945Sweongyo		device_printf(sc->sc_dev, "%s: out of memory", __func__);
9020203945Sweongyo		goto error;
9021203945Sweongyo	}
9022203945Sweongyo	mp = mtod(m, unsigned char *);
9023203945Sweongyo	if (prq->prq_rev >= 8) {
9024209888Sweongyo		siba_read_multi_4(sc->sc_dev, mp, (totlen & ~3),
9025203945Sweongyo		    prq->prq_base + BWN_PIO8_RXDATA);
9026209888Sweongyo		if (totlen & 3) {
9027203945Sweongyo			v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
9028209888Sweongyo			data = &(mp[totlen - 1]);
9029209888Sweongyo			switch (totlen & 3) {
9030203945Sweongyo			case 3:
9031203945Sweongyo				*data = (v32 >> 16);
9032203945Sweongyo				data--;
9033203945Sweongyo			case 2:
9034203945Sweongyo				*data = (v32 >> 8);
9035203945Sweongyo				data--;
9036203945Sweongyo			case 1:
9037203945Sweongyo				*data = v32;
9038203945Sweongyo			}
9039203945Sweongyo		}
9040203945Sweongyo	} else {
9041209888Sweongyo		siba_read_multi_2(sc->sc_dev, mp, (totlen & ~1),
9042203945Sweongyo		    prq->prq_base + BWN_PIO_RXDATA);
9043209888Sweongyo		if (totlen & 1) {
9044203945Sweongyo			v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
9045209888Sweongyo			mp[totlen - 1] = v16;
9046203945Sweongyo		}
9047203945Sweongyo	}
9048203945Sweongyo
9049209888Sweongyo	m->m_len = m->m_pkthdr.len = totlen;
9050203945Sweongyo
9051203945Sweongyo	bwn_rxeof(prq->prq_mac, m, &rxhdr);
9052203945Sweongyo
9053203945Sweongyo	return (1);
9054203945Sweongyoerror:
9055203945Sweongyo	if (prq->prq_rev >= 8)
9056203945Sweongyo		bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
9057203945Sweongyo		    BWN_PIO8_RXCTL_DATAREADY);
9058203945Sweongyo	else
9059203945Sweongyo		bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
9060203945Sweongyo	return (1);
9061203945Sweongyo}
9062203945Sweongyo
9063203945Sweongyostatic int
9064203945Sweongyobwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
9065203945Sweongyo    struct bwn_dmadesc_meta *meta, int init)
9066203945Sweongyo{
9067203945Sweongyo	struct bwn_mac *mac = dr->dr_mac;
9068203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9069203945Sweongyo	struct bwn_rxhdr4 *hdr;
9070203945Sweongyo	bus_dmamap_t map;
9071203945Sweongyo	bus_addr_t paddr;
9072203945Sweongyo	struct mbuf *m;
9073203945Sweongyo	int error;
9074203945Sweongyo
9075243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
9076203945Sweongyo	if (m == NULL) {
9077203945Sweongyo		error = ENOBUFS;
9078203945Sweongyo
9079203945Sweongyo		/*
9080203945Sweongyo		 * If the NIC is up and running, we need to:
9081203945Sweongyo		 * - Clear RX buffer's header.
9082203945Sweongyo		 * - Restore RX descriptor settings.
9083203945Sweongyo		 */
9084203945Sweongyo		if (init)
9085203945Sweongyo			return (error);
9086203945Sweongyo		else
9087203945Sweongyo			goto back;
9088203945Sweongyo	}
9089203945Sweongyo	m->m_len = m->m_pkthdr.len = MCLBYTES;
9090203945Sweongyo
9091203945Sweongyo	bwn_dma_set_redzone(dr, m);
9092203945Sweongyo
9093203945Sweongyo	/*
9094203945Sweongyo	 * Try to load RX buf into temporary DMA map
9095203945Sweongyo	 */
9096203945Sweongyo	error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
9097203945Sweongyo	    bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
9098203945Sweongyo	if (error) {
9099203945Sweongyo		m_freem(m);
9100203945Sweongyo
9101203945Sweongyo		/*
9102203945Sweongyo		 * See the comment above
9103203945Sweongyo		 */
9104203945Sweongyo		if (init)
9105203945Sweongyo			return (error);
9106203945Sweongyo		else
9107203945Sweongyo			goto back;
9108203945Sweongyo	}
9109203945Sweongyo
9110203945Sweongyo	if (!init)
9111203945Sweongyo		bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
9112203945Sweongyo	meta->mt_m = m;
9113203945Sweongyo	meta->mt_paddr = paddr;
9114203945Sweongyo
9115203945Sweongyo	/*
9116203945Sweongyo	 * Swap RX buf's DMA map with the loaded temporary one
9117203945Sweongyo	 */
9118203945Sweongyo	map = meta->mt_dmap;
9119203945Sweongyo	meta->mt_dmap = dr->dr_spare_dmap;
9120203945Sweongyo	dr->dr_spare_dmap = map;
9121203945Sweongyo
9122203945Sweongyoback:
9123203945Sweongyo	/*
9124203945Sweongyo	 * Clear RX buf header
9125203945Sweongyo	 */
9126203945Sweongyo	hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
9127203945Sweongyo	bzero(hdr, sizeof(*hdr));
9128203945Sweongyo	bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
9129203945Sweongyo	    BUS_DMASYNC_PREWRITE);
9130203945Sweongyo
9131203945Sweongyo	/*
9132203945Sweongyo	 * Setup RX buf descriptor
9133203945Sweongyo	 */
9134250314Shiren	dr->setdesc(dr, desc, meta->mt_paddr, meta->mt_m->m_len -
9135203945Sweongyo	    sizeof(*hdr), 0, 0, 0);
9136203945Sweongyo	return (error);
9137203945Sweongyo}
9138203945Sweongyo
9139203945Sweongyostatic void
9140203945Sweongyobwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
9141203945Sweongyo		 bus_size_t mapsz __unused, int error)
9142203945Sweongyo{
9143203945Sweongyo
9144203945Sweongyo	if (!error) {
9145203945Sweongyo		KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
9146203945Sweongyo		*((bus_addr_t *)arg) = seg->ds_addr;
9147203945Sweongyo	}
9148203945Sweongyo}
9149203945Sweongyo
9150203945Sweongyostatic int
9151203945Sweongyobwn_hwrate2ieeerate(int rate)
9152203945Sweongyo{
9153203945Sweongyo
9154203945Sweongyo	switch (rate) {
9155203945Sweongyo	case BWN_CCK_RATE_1MB:
9156203945Sweongyo		return (2);
9157203945Sweongyo	case BWN_CCK_RATE_2MB:
9158203945Sweongyo		return (4);
9159203945Sweongyo	case BWN_CCK_RATE_5MB:
9160203945Sweongyo		return (11);
9161203945Sweongyo	case BWN_CCK_RATE_11MB:
9162203945Sweongyo		return (22);
9163203945Sweongyo	case BWN_OFDM_RATE_6MB:
9164203945Sweongyo		return (12);
9165203945Sweongyo	case BWN_OFDM_RATE_9MB:
9166203945Sweongyo		return (18);
9167203945Sweongyo	case BWN_OFDM_RATE_12MB:
9168203945Sweongyo		return (24);
9169203945Sweongyo	case BWN_OFDM_RATE_18MB:
9170203945Sweongyo		return (36);
9171203945Sweongyo	case BWN_OFDM_RATE_24MB:
9172203945Sweongyo		return (48);
9173203945Sweongyo	case BWN_OFDM_RATE_36MB:
9174203945Sweongyo		return (72);
9175203945Sweongyo	case BWN_OFDM_RATE_48MB:
9176203945Sweongyo		return (96);
9177203945Sweongyo	case BWN_OFDM_RATE_54MB:
9178203945Sweongyo		return (108);
9179203945Sweongyo	default:
9180203945Sweongyo		printf("Ooops\n");
9181203945Sweongyo		return (0);
9182203945Sweongyo	}
9183203945Sweongyo}
9184203945Sweongyo
9185203945Sweongyostatic void
9186203945Sweongyobwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
9187203945Sweongyo{
9188203945Sweongyo	const struct bwn_rxhdr4 *rxhdr = _rxhdr;
9189203945Sweongyo	struct bwn_plcp6 *plcp;
9190203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9191203945Sweongyo	struct ieee80211_frame_min *wh;
9192203945Sweongyo	struct ieee80211_node *ni;
9193287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
9194203945Sweongyo	uint32_t macstat;
9195204242Simp	int padding, rate, rssi = 0, noise = 0, type;
9196203945Sweongyo	uint16_t phytype, phystat0, phystat3, chanstat;
9197203945Sweongyo	unsigned char *mp = mtod(m, unsigned char *);
9198204242Simp	static int rx_mac_dec_rpt = 0;
9199203945Sweongyo
9200203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9201203945Sweongyo
9202203945Sweongyo	phystat0 = le16toh(rxhdr->phy_status0);
9203203945Sweongyo	phystat3 = le16toh(rxhdr->phy_status3);
9204203945Sweongyo	macstat = le32toh(rxhdr->mac_status);
9205203945Sweongyo	chanstat = le16toh(rxhdr->channel);
9206203945Sweongyo	phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
9207203945Sweongyo
9208203945Sweongyo	if (macstat & BWN_RX_MAC_FCSERR)
9209203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
9210203945Sweongyo	if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
9211203945Sweongyo		device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
9212203945Sweongyo	if (macstat & BWN_RX_MAC_DECERR)
9213203945Sweongyo		goto drop;
9214203945Sweongyo
9215203945Sweongyo	padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
9216203945Sweongyo	if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
9217204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9218204081Sweongyo		    m->m_pkthdr.len);
9219203945Sweongyo		goto drop;
9220203945Sweongyo	}
9221203945Sweongyo	plcp = (struct bwn_plcp6 *)(mp + padding);
9222203945Sweongyo	m_adj(m, sizeof(struct bwn_plcp6) + padding);
9223203945Sweongyo	if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
9224204081Sweongyo		device_printf(sc->sc_dev, "frame too short (length=%d)\n",
9225204081Sweongyo		    m->m_pkthdr.len);
9226203945Sweongyo		goto drop;
9227203945Sweongyo	}
9228203945Sweongyo	wh = mtod(m, struct ieee80211_frame_min *);
9229203945Sweongyo
9230204242Simp	if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
9231204081Sweongyo		device_printf(sc->sc_dev,
9232204081Sweongyo		    "RX decryption attempted (old %d keyidx %#x)\n",
9233204081Sweongyo		    BWN_ISOLDFMT(mac),
9234204081Sweongyo		    (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
9235203945Sweongyo
9236203945Sweongyo	/* XXX calculating RSSI & noise & antenna */
9237203945Sweongyo
9238203945Sweongyo	if (phystat0 & BWN_RX_PHYST0_OFDM)
9239203945Sweongyo		rate = bwn_plcp_get_ofdmrate(mac, plcp,
9240203945Sweongyo		    phytype == BWN_PHYTYPE_A);
9241203945Sweongyo	else
9242203945Sweongyo		rate = bwn_plcp_get_cckrate(mac, plcp);
9243203945Sweongyo	if (rate == -1) {
9244203945Sweongyo		if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
9245203945Sweongyo			goto drop;
9246203945Sweongyo	}
9247203945Sweongyo	sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
9248203945Sweongyo
9249203945Sweongyo	/* RX radio tap */
9250203945Sweongyo	if (ieee80211_radiotap_active(ic))
9251203945Sweongyo		bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
9252203945Sweongyo	m_adj(m, -IEEE80211_CRC_LEN);
9253203945Sweongyo
9254203945Sweongyo	rssi = rxhdr->phy.abg.rssi;	/* XXX incorrect RSSI calculation? */
9255203945Sweongyo	noise = mac->mac_stats.link_noise;
9256203945Sweongyo
9257203945Sweongyo	BWN_UNLOCK(sc);
9258203945Sweongyo
9259203945Sweongyo	ni = ieee80211_find_rxnode(ic, wh);
9260203945Sweongyo	if (ni != NULL) {
9261203945Sweongyo		type = ieee80211_input(ni, m, rssi, noise);
9262203945Sweongyo		ieee80211_free_node(ni);
9263203945Sweongyo	} else
9264203945Sweongyo		type = ieee80211_input_all(ic, m, rssi, noise);
9265203945Sweongyo
9266203945Sweongyo	BWN_LOCK(sc);
9267203945Sweongyo	return;
9268203945Sweongyodrop:
9269203945Sweongyo	device_printf(sc->sc_dev, "%s: dropped\n", __func__);
9270203945Sweongyo}
9271203945Sweongyo
9272203945Sweongyostatic void
9273203945Sweongyobwn_dma_handle_txeof(struct bwn_mac *mac,
9274203945Sweongyo    const struct bwn_txstatus *status)
9275203945Sweongyo{
9276203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
9277203945Sweongyo	struct bwn_dma_ring *dr;
9278203945Sweongyo	struct bwn_dmadesc_generic *desc;
9279203945Sweongyo	struct bwn_dmadesc_meta *meta;
9280203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9281203945Sweongyo	int slot;
9282203945Sweongyo
9283203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9284203945Sweongyo
9285203945Sweongyo	dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
9286203945Sweongyo	if (dr == NULL) {
9287203945Sweongyo		device_printf(sc->sc_dev, "failed to parse cookie\n");
9288203945Sweongyo		return;
9289203945Sweongyo	}
9290203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
9291203945Sweongyo
9292203945Sweongyo	while (1) {
9293203945Sweongyo		KASSERT(slot >= 0 && slot < dr->dr_numslots,
9294203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9295203945Sweongyo		dr->getdesc(dr, slot, &desc, &meta);
9296203945Sweongyo
9297203945Sweongyo		if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
9298203945Sweongyo			bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
9299203945Sweongyo		else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
9300203945Sweongyo			bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
9301203945Sweongyo
9302203945Sweongyo		if (meta->mt_islast) {
9303203945Sweongyo			KASSERT(meta->mt_m != NULL,
9304203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9305203945Sweongyo
9306287197Sglebius			ieee80211_tx_complete(meta->mt_ni, meta->mt_m, 0);
9307287197Sglebius			meta->mt_ni = NULL;
9308203945Sweongyo			meta->mt_m = NULL;
9309287197Sglebius		} else
9310203945Sweongyo			KASSERT(meta->mt_m == NULL,
9311203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
9312203945Sweongyo
9313203945Sweongyo		dr->dr_usedslot--;
9314287197Sglebius		if (meta->mt_islast)
9315203945Sweongyo			break;
9316203945Sweongyo		slot = bwn_dma_nextslot(dr, slot);
9317203945Sweongyo	}
9318203945Sweongyo	sc->sc_watchdog_timer = 0;
9319203945Sweongyo	if (dr->dr_stop) {
9320203945Sweongyo		KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
9321203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9322203945Sweongyo		dr->dr_stop = 0;
9323203945Sweongyo	}
9324203945Sweongyo}
9325203945Sweongyo
9326203945Sweongyostatic void
9327203945Sweongyobwn_pio_handle_txeof(struct bwn_mac *mac,
9328203945Sweongyo    const struct bwn_txstatus *status)
9329203945Sweongyo{
9330203945Sweongyo	struct bwn_pio_txqueue *tq;
9331203945Sweongyo	struct bwn_pio_txpkt *tp = NULL;
9332203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9333203945Sweongyo
9334203945Sweongyo	BWN_ASSERT_LOCKED(sc);
9335203945Sweongyo
9336203945Sweongyo	tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
9337203945Sweongyo	if (tq == NULL)
9338203945Sweongyo		return;
9339203945Sweongyo
9340203945Sweongyo	tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
9341203945Sweongyo	tq->tq_free++;
9342203945Sweongyo
9343203945Sweongyo	if (tp->tp_ni != NULL) {
9344203945Sweongyo		/*
9345203945Sweongyo		 * Do any tx complete callback.  Note this must
9346203945Sweongyo		 * be done before releasing the node reference.
9347203945Sweongyo		 */
9348203945Sweongyo		if (tp->tp_m->m_flags & M_TXCB)
9349203945Sweongyo			ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
9350203945Sweongyo		ieee80211_free_node(tp->tp_ni);
9351203945Sweongyo		tp->tp_ni = NULL;
9352203945Sweongyo	}
9353203945Sweongyo	m_freem(tp->tp_m);
9354203945Sweongyo	tp->tp_m = NULL;
9355203945Sweongyo	TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
9356203945Sweongyo
9357203945Sweongyo	sc->sc_watchdog_timer = 0;
9358203945Sweongyo}
9359203945Sweongyo
9360203945Sweongyostatic void
9361203945Sweongyobwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
9362203945Sweongyo{
9363203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9364203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
9365287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
9366203945Sweongyo	unsigned long now;
9367203945Sweongyo	int result;
9368203945Sweongyo
9369203945Sweongyo	BWN_GETTIME(now);
9370203945Sweongyo
9371203945Sweongyo	if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
9372203945Sweongyo		return;
9373203945Sweongyo	phy->nexttime = now + 2 * 1000;
9374203945Sweongyo
9375204922Sweongyo	if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM &&
9376204922Sweongyo	    siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306)
9377203945Sweongyo		return;
9378203945Sweongyo
9379203945Sweongyo	if (phy->recalc_txpwr != NULL) {
9380203945Sweongyo		result = phy->recalc_txpwr(mac,
9381203945Sweongyo		    (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
9382203945Sweongyo		if (result == BWN_TXPWR_RES_DONE)
9383203945Sweongyo			return;
9384203945Sweongyo		KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
9385203945Sweongyo		    ("%s: fail", __func__));
9386203945Sweongyo		KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
9387203945Sweongyo
9388203945Sweongyo		ieee80211_runtask(ic, &mac->mac_txpower);
9389203945Sweongyo	}
9390203945Sweongyo}
9391203945Sweongyo
9392203945Sweongyostatic uint16_t
9393203945Sweongyobwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
9394203945Sweongyo{
9395203945Sweongyo
9396203945Sweongyo	return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
9397203945Sweongyo}
9398203945Sweongyo
9399203945Sweongyostatic uint32_t
9400203945Sweongyobwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
9401203945Sweongyo{
9402203945Sweongyo
9403203945Sweongyo	return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
9404203945Sweongyo}
9405203945Sweongyo
9406203945Sweongyostatic void
9407203945Sweongyobwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
9408203945Sweongyo{
9409203945Sweongyo
9410203945Sweongyo	BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
9411203945Sweongyo}
9412203945Sweongyo
9413203945Sweongyostatic void
9414203945Sweongyobwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
9415203945Sweongyo{
9416203945Sweongyo
9417203945Sweongyo	BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
9418203945Sweongyo}
9419203945Sweongyo
9420203945Sweongyostatic int
9421203945Sweongyobwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
9422203945Sweongyo{
9423203945Sweongyo
9424203945Sweongyo	switch (rate) {
9425203945Sweongyo	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
9426203945Sweongyo	case 12:
9427203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9428203945Sweongyo	case 18:
9429203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9430203945Sweongyo	case 24:
9431203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9432203945Sweongyo	case 36:
9433203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9434203945Sweongyo	case 48:
9435203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9436203945Sweongyo	case 72:
9437203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9438203945Sweongyo	case 96:
9439203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9440203945Sweongyo	case 108:
9441203945Sweongyo		return (BWN_OFDM_RATE_54MB);
9442203945Sweongyo	/* CCK rates (NB: not IEEE std, device-specific) */
9443203945Sweongyo	case 2:
9444203945Sweongyo		return (BWN_CCK_RATE_1MB);
9445203945Sweongyo	case 4:
9446203945Sweongyo		return (BWN_CCK_RATE_2MB);
9447203945Sweongyo	case 11:
9448203945Sweongyo		return (BWN_CCK_RATE_5MB);
9449203945Sweongyo	case 22:
9450203945Sweongyo		return (BWN_CCK_RATE_11MB);
9451203945Sweongyo	}
9452203945Sweongyo
9453203945Sweongyo	device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
9454203945Sweongyo	return (BWN_CCK_RATE_1MB);
9455203945Sweongyo}
9456203945Sweongyo
9457203945Sweongyostatic int
9458203945Sweongyobwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
9459203945Sweongyo    struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
9460203945Sweongyo{
9461203945Sweongyo	const struct bwn_phy *phy = &mac->mac_phy;
9462203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9463203945Sweongyo	struct ieee80211_frame *wh;
9464203945Sweongyo	struct ieee80211_frame *protwh;
9465203945Sweongyo	struct ieee80211_frame_cts *cts;
9466203945Sweongyo	struct ieee80211_frame_rts *rts;
9467203945Sweongyo	const struct ieee80211_txparam *tp;
9468203945Sweongyo	struct ieee80211vap *vap = ni->ni_vap;
9469287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
9470203945Sweongyo	struct mbuf *mprot;
9471203945Sweongyo	unsigned int len;
9472203945Sweongyo	uint32_t macctl = 0;
9473203945Sweongyo	int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
9474203945Sweongyo	uint16_t phyctl = 0;
9475203945Sweongyo	uint8_t rate, rate_fb;
9476203945Sweongyo
9477203945Sweongyo	wh = mtod(m, struct ieee80211_frame *);
9478203945Sweongyo	memset(txhdr, 0, sizeof(*txhdr));
9479203945Sweongyo
9480203945Sweongyo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
9481203945Sweongyo	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
9482203945Sweongyo	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
9483203945Sweongyo
9484203945Sweongyo	/*
9485203945Sweongyo	 * Find TX rate
9486203945Sweongyo	 */
9487203945Sweongyo	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
9488203945Sweongyo	if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
9489203945Sweongyo		rate = rate_fb = tp->mgmtrate;
9490203945Sweongyo	else if (ismcast)
9491203945Sweongyo		rate = rate_fb = tp->mcastrate;
9492203945Sweongyo	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
9493203945Sweongyo		rate = rate_fb = tp->ucastrate;
9494203945Sweongyo	else {
9495206358Srpaulo		rix = ieee80211_ratectl_rate(ni, NULL, 0);
9496203945Sweongyo		rate = ni->ni_txrate;
9497203945Sweongyo
9498203945Sweongyo		if (rix > 0)
9499203945Sweongyo			rate_fb = ni->ni_rates.rs_rates[rix - 1] &
9500203945Sweongyo			    IEEE80211_RATE_VAL;
9501203945Sweongyo		else
9502203945Sweongyo			rate_fb = rate;
9503203945Sweongyo	}
9504203945Sweongyo
9505203945Sweongyo	sc->sc_tx_rate = rate;
9506203945Sweongyo
9507203945Sweongyo	rate = bwn_ieeerate2hwrate(sc, rate);
9508203945Sweongyo	rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
9509203945Sweongyo
9510203945Sweongyo	txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
9511203945Sweongyo	    bwn_plcp_getcck(rate);
9512203945Sweongyo	bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
9513203945Sweongyo	bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
9514203945Sweongyo
9515203945Sweongyo	if ((rate_fb == rate) ||
9516203945Sweongyo	    (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
9517203945Sweongyo	    (*(u_int16_t *)wh->i_dur == htole16(0)))
9518203945Sweongyo		txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
9519203945Sweongyo	else
9520203945Sweongyo		txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
9521203945Sweongyo		    m->m_pkthdr.len, rate, isshort);
9522203945Sweongyo
9523203945Sweongyo	/* XXX TX encryption */
9524203945Sweongyo	bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
9525203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
9526203945Sweongyo	    (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
9527203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
9528203945Sweongyo	bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
9529203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
9530203945Sweongyo
9531203945Sweongyo	txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
9532203945Sweongyo	    BWN_TX_EFT_FB_CCK;
9533203945Sweongyo	txhdr->chan = phy->chan;
9534203945Sweongyo	phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
9535203945Sweongyo	    BWN_TX_PHY_ENC_CCK;
9536203945Sweongyo	if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9537203945Sweongyo	     rate == BWN_CCK_RATE_11MB))
9538203945Sweongyo		phyctl |= BWN_TX_PHY_SHORTPRMBL;
9539203945Sweongyo
9540203945Sweongyo	/* XXX TX antenna selection */
9541203945Sweongyo
9542203945Sweongyo	switch (bwn_antenna_sanitize(mac, 0)) {
9543203945Sweongyo	case 0:
9544203945Sweongyo		phyctl |= BWN_TX_PHY_ANT01AUTO;
9545203945Sweongyo		break;
9546203945Sweongyo	case 1:
9547203945Sweongyo		phyctl |= BWN_TX_PHY_ANT0;
9548203945Sweongyo		break;
9549203945Sweongyo	case 2:
9550203945Sweongyo		phyctl |= BWN_TX_PHY_ANT1;
9551203945Sweongyo		break;
9552203945Sweongyo	case 3:
9553203945Sweongyo		phyctl |= BWN_TX_PHY_ANT2;
9554203945Sweongyo		break;
9555203945Sweongyo	case 4:
9556203945Sweongyo		phyctl |= BWN_TX_PHY_ANT3;
9557203945Sweongyo		break;
9558203945Sweongyo	default:
9559203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9560203945Sweongyo	}
9561203945Sweongyo
9562203945Sweongyo	if (!ismcast)
9563203945Sweongyo		macctl |= BWN_TX_MAC_ACK;
9564203945Sweongyo
9565203945Sweongyo	macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
9566203945Sweongyo	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
9567203945Sweongyo	    m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
9568203945Sweongyo		macctl |= BWN_TX_MAC_LONGFRAME;
9569203945Sweongyo
9570203945Sweongyo	if (ic->ic_flags & IEEE80211_F_USEPROT) {
9571203945Sweongyo		/* XXX RTS rate is always 1MB??? */
9572203945Sweongyo		rts_rate = BWN_CCK_RATE_1MB;
9573203945Sweongyo		rts_rate_fb = bwn_get_fbrate(rts_rate);
9574203945Sweongyo
9575203945Sweongyo		protdur = ieee80211_compute_duration(ic->ic_rt,
9576203945Sweongyo		    m->m_pkthdr.len, rate, isshort) +
9577203945Sweongyo		    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
9578203945Sweongyo
9579203945Sweongyo		if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
9580203945Sweongyo			cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
9581203945Sweongyo			    (txhdr->body.old.rts_frame) :
9582203945Sweongyo			    (txhdr->body.new.rts_frame));
9583203945Sweongyo			mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
9584203945Sweongyo			    protdur);
9585203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9586203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
9587203945Sweongyo			    mprot->m_pkthdr.len);
9588203945Sweongyo			m_freem(mprot);
9589203945Sweongyo			macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
9590203945Sweongyo			len = sizeof(struct ieee80211_frame_cts);
9591203945Sweongyo		} else {
9592203945Sweongyo			rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
9593203945Sweongyo			    (txhdr->body.old.rts_frame) :
9594203945Sweongyo			    (txhdr->body.new.rts_frame));
9595203945Sweongyo			protdur += ieee80211_ack_duration(ic->ic_rt, rate,
9596203945Sweongyo			    isshort);
9597203945Sweongyo			mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
9598203945Sweongyo			    wh->i_addr2, protdur);
9599203945Sweongyo			KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
9600203945Sweongyo			bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
9601203945Sweongyo			    mprot->m_pkthdr.len);
9602203945Sweongyo			m_freem(mprot);
9603203945Sweongyo			macctl |= BWN_TX_MAC_SEND_RTSCTS;
9604203945Sweongyo			len = sizeof(struct ieee80211_frame_rts);
9605203945Sweongyo		}
9606203945Sweongyo		len += IEEE80211_CRC_LEN;
9607203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
9608203945Sweongyo		    &txhdr->body.old.rts_plcp :
9609203945Sweongyo		    &txhdr->body.new.rts_plcp), len, rts_rate);
9610203945Sweongyo		bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
9611203945Sweongyo		    rts_rate_fb);
9612203945Sweongyo
9613203945Sweongyo		protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
9614203945Sweongyo		    (&txhdr->body.old.rts_frame) :
9615203945Sweongyo		    (&txhdr->body.new.rts_frame));
9616203945Sweongyo		txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
9617203945Sweongyo
9618203945Sweongyo		if (BWN_ISOFDMRATE(rts_rate)) {
9619203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
9620203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
9621203945Sweongyo		} else {
9622203945Sweongyo			txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
9623203945Sweongyo			txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
9624203945Sweongyo		}
9625203945Sweongyo		txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
9626203945Sweongyo		    BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
9627203945Sweongyo	}
9628203945Sweongyo
9629203945Sweongyo	if (BWN_ISOLDFMT(mac))
9630203945Sweongyo		txhdr->body.old.cookie = htole16(cookie);
9631203945Sweongyo	else
9632203945Sweongyo		txhdr->body.new.cookie = htole16(cookie);
9633203945Sweongyo
9634203945Sweongyo	txhdr->macctl = htole32(macctl);
9635203945Sweongyo	txhdr->phyctl = htole16(phyctl);
9636203945Sweongyo
9637203945Sweongyo	/*
9638203945Sweongyo	 * TX radio tap
9639203945Sweongyo	 */
9640203945Sweongyo	if (ieee80211_radiotap_active_vap(vap)) {
9641203945Sweongyo		sc->sc_tx_th.wt_flags = 0;
9642260444Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
9643203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
9644203945Sweongyo		if (isshort &&
9645203945Sweongyo		    (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
9646203945Sweongyo		     rate == BWN_CCK_RATE_11MB))
9647203945Sweongyo			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
9648203945Sweongyo		sc->sc_tx_th.wt_rate = rate;
9649203945Sweongyo
9650203945Sweongyo		ieee80211_radiotap_tx(vap, m);
9651203945Sweongyo	}
9652203945Sweongyo
9653203945Sweongyo	return (0);
9654203945Sweongyo}
9655203945Sweongyo
9656203945Sweongyostatic void
9657203945Sweongyobwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
9658203945Sweongyo    const uint8_t rate)
9659203945Sweongyo{
9660203945Sweongyo	uint32_t d, plen;
9661203945Sweongyo	uint8_t *raw = plcp->o.raw;
9662203945Sweongyo
9663203945Sweongyo	if (BWN_ISOFDMRATE(rate)) {
9664203945Sweongyo		d = bwn_plcp_getofdm(rate);
9665203945Sweongyo		KASSERT(!(octets & 0xf000),
9666203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
9667203945Sweongyo		d |= (octets << 5);
9668203945Sweongyo		plcp->o.data = htole32(d);
9669203945Sweongyo	} else {
9670203945Sweongyo		plen = octets * 16 / rate;
9671203945Sweongyo		if ((octets * 16 % rate) > 0) {
9672203945Sweongyo			plen++;
9673203945Sweongyo			if ((rate == BWN_CCK_RATE_11MB)
9674203945Sweongyo			    && ((octets * 8 % 11) < 4)) {
9675203945Sweongyo				raw[1] = 0x84;
9676203945Sweongyo			} else
9677203945Sweongyo				raw[1] = 0x04;
9678203945Sweongyo		} else
9679203945Sweongyo			raw[1] = 0x04;
9680203945Sweongyo		plcp->o.data |= htole32(plen << 16);
9681203945Sweongyo		raw[0] = bwn_plcp_getcck(rate);
9682203945Sweongyo	}
9683203945Sweongyo}
9684203945Sweongyo
9685203945Sweongyostatic uint8_t
9686203945Sweongyobwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
9687203945Sweongyo{
9688204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9689203945Sweongyo	uint8_t mask;
9690203945Sweongyo
9691203945Sweongyo	if (n == 0)
9692203945Sweongyo		return (0);
9693203945Sweongyo	if (mac->mac_phy.gmode)
9694204922Sweongyo		mask = siba_sprom_get_ant_bg(sc->sc_dev);
9695203945Sweongyo	else
9696204922Sweongyo		mask = siba_sprom_get_ant_a(sc->sc_dev);
9697203945Sweongyo	if (!(mask & (1 << (n - 1))))
9698203945Sweongyo		return (0);
9699203945Sweongyo	return (n);
9700203945Sweongyo}
9701203945Sweongyo
9702203945Sweongyostatic uint8_t
9703203945Sweongyobwn_get_fbrate(uint8_t bitrate)
9704203945Sweongyo{
9705203945Sweongyo	switch (bitrate) {
9706203945Sweongyo	case BWN_CCK_RATE_1MB:
9707203945Sweongyo		return (BWN_CCK_RATE_1MB);
9708203945Sweongyo	case BWN_CCK_RATE_2MB:
9709203945Sweongyo		return (BWN_CCK_RATE_1MB);
9710203945Sweongyo	case BWN_CCK_RATE_5MB:
9711203945Sweongyo		return (BWN_CCK_RATE_2MB);
9712203945Sweongyo	case BWN_CCK_RATE_11MB:
9713203945Sweongyo		return (BWN_CCK_RATE_5MB);
9714203945Sweongyo	case BWN_OFDM_RATE_6MB:
9715203945Sweongyo		return (BWN_CCK_RATE_5MB);
9716203945Sweongyo	case BWN_OFDM_RATE_9MB:
9717203945Sweongyo		return (BWN_OFDM_RATE_6MB);
9718203945Sweongyo	case BWN_OFDM_RATE_12MB:
9719203945Sweongyo		return (BWN_OFDM_RATE_9MB);
9720203945Sweongyo	case BWN_OFDM_RATE_18MB:
9721203945Sweongyo		return (BWN_OFDM_RATE_12MB);
9722203945Sweongyo	case BWN_OFDM_RATE_24MB:
9723203945Sweongyo		return (BWN_OFDM_RATE_18MB);
9724203945Sweongyo	case BWN_OFDM_RATE_36MB:
9725203945Sweongyo		return (BWN_OFDM_RATE_24MB);
9726203945Sweongyo	case BWN_OFDM_RATE_48MB:
9727203945Sweongyo		return (BWN_OFDM_RATE_36MB);
9728203945Sweongyo	case BWN_OFDM_RATE_54MB:
9729203945Sweongyo		return (BWN_OFDM_RATE_48MB);
9730203945Sweongyo	}
9731203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9732203945Sweongyo	return (0);
9733203945Sweongyo}
9734203945Sweongyo
9735203945Sweongyostatic uint32_t
9736203945Sweongyobwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9737203945Sweongyo    uint32_t ctl, const void *_data, int len)
9738203945Sweongyo{
9739204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9740203945Sweongyo	uint32_t value = 0;
9741203945Sweongyo	const uint8_t *data = _data;
9742203945Sweongyo
9743203945Sweongyo	ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
9744203945Sweongyo	    BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
9745203945Sweongyo	bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9746203945Sweongyo
9747204922Sweongyo	siba_write_multi_4(sc->sc_dev, data, (len & ~3),
9748203945Sweongyo	    tq->tq_base + BWN_PIO8_TXDATA);
9749203945Sweongyo	if (len & 3) {
9750203945Sweongyo		ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
9751203945Sweongyo		    BWN_PIO8_TXCTL_24_31);
9752203945Sweongyo		data = &(data[len - 1]);
9753203945Sweongyo		switch (len & 3) {
9754203945Sweongyo		case 3:
9755203945Sweongyo			ctl |= BWN_PIO8_TXCTL_16_23;
9756203945Sweongyo			value |= (uint32_t)(*data) << 16;
9757203945Sweongyo			data--;
9758203945Sweongyo		case 2:
9759203945Sweongyo			ctl |= BWN_PIO8_TXCTL_8_15;
9760203945Sweongyo			value |= (uint32_t)(*data) << 8;
9761203945Sweongyo			data--;
9762203945Sweongyo		case 1:
9763203945Sweongyo			value |= (uint32_t)(*data);
9764203945Sweongyo		}
9765203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
9766203945Sweongyo		bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
9767203945Sweongyo	}
9768203945Sweongyo
9769203945Sweongyo	return (ctl);
9770203945Sweongyo}
9771203945Sweongyo
9772203945Sweongyostatic void
9773203945Sweongyobwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9774203945Sweongyo    uint16_t offset, uint32_t value)
9775203945Sweongyo{
9776203945Sweongyo
9777203945Sweongyo	BWN_WRITE_4(mac, tq->tq_base + offset, value);
9778203945Sweongyo}
9779203945Sweongyo
9780203945Sweongyostatic uint16_t
9781203945Sweongyobwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9782203945Sweongyo    uint16_t ctl, const void *_data, int len)
9783203945Sweongyo{
9784204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9785203945Sweongyo	const uint8_t *data = _data;
9786203945Sweongyo
9787203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
9788203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9789203945Sweongyo
9790204922Sweongyo	siba_write_multi_2(sc->sc_dev, data, (len & ~1),
9791203945Sweongyo	    tq->tq_base + BWN_PIO_TXDATA);
9792203945Sweongyo	if (len & 1) {
9793203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
9794203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9795203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
9796203945Sweongyo	}
9797203945Sweongyo
9798203945Sweongyo	return (ctl);
9799203945Sweongyo}
9800203945Sweongyo
9801203945Sweongyostatic uint16_t
9802203945Sweongyobwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
9803203945Sweongyo    uint16_t ctl, struct mbuf *m0)
9804203945Sweongyo{
9805203945Sweongyo	int i, j = 0;
9806203945Sweongyo	uint16_t data = 0;
9807203945Sweongyo	const uint8_t *buf;
9808203945Sweongyo	struct mbuf *m = m0;
9809203945Sweongyo
9810203945Sweongyo	ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
9811203945Sweongyo	BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9812203945Sweongyo
9813203945Sweongyo	for (; m != NULL; m = m->m_next) {
9814203945Sweongyo		buf = mtod(m, const uint8_t *);
9815203945Sweongyo		for (i = 0; i < m->m_len; i++) {
9816203945Sweongyo			if (!((j++) % 2))
9817203945Sweongyo				data |= buf[i];
9818203945Sweongyo			else {
9819203945Sweongyo				data |= (buf[i] << 8);
9820203945Sweongyo				BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
9821203945Sweongyo				data = 0;
9822203945Sweongyo			}
9823203945Sweongyo		}
9824203945Sweongyo	}
9825203945Sweongyo	if (m0->m_pkthdr.len % 2) {
9826203945Sweongyo		ctl &= ~BWN_PIO_TXCTL_WRITEHI;
9827203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
9828203945Sweongyo		BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
9829203945Sweongyo	}
9830203945Sweongyo
9831203945Sweongyo	return (ctl);
9832203945Sweongyo}
9833203945Sweongyo
9834203945Sweongyostatic void
9835203945Sweongyobwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
9836203945Sweongyo{
9837203945Sweongyo
9838203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G)
9839203945Sweongyo		return;
9840203945Sweongyo	BWN_WRITE_2(mac, 0x684, 510 + time);
9841203945Sweongyo	bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
9842203945Sweongyo}
9843203945Sweongyo
9844203945Sweongyostatic struct bwn_dma_ring *
9845203945Sweongyobwn_dma_select(struct bwn_mac *mac, uint8_t prio)
9846203945Sweongyo{
9847203945Sweongyo
9848203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
9849203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
9850203945Sweongyo
9851203945Sweongyo	switch (prio) {
9852203945Sweongyo	case 3:
9853203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VO]);
9854203945Sweongyo	case 2:
9855203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_VI]);
9856203945Sweongyo	case 0:
9857203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BE]);
9858203945Sweongyo	case 1:
9859203945Sweongyo		return (mac->mac_method.dma.wme[WME_AC_BK]);
9860203945Sweongyo	}
9861203945Sweongyo	KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
9862204242Simp	return (NULL);
9863203945Sweongyo}
9864203945Sweongyo
9865203945Sweongyostatic int
9866203945Sweongyobwn_dma_getslot(struct bwn_dma_ring *dr)
9867203945Sweongyo{
9868203945Sweongyo	int slot;
9869203945Sweongyo
9870204242Simp	BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
9871203945Sweongyo
9872203945Sweongyo	KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
9873203945Sweongyo	KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
9874203945Sweongyo	KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
9875203945Sweongyo
9876203945Sweongyo	slot = bwn_dma_nextslot(dr, dr->dr_curslot);
9877203945Sweongyo	KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
9878203945Sweongyo	dr->dr_curslot = slot;
9879203945Sweongyo	dr->dr_usedslot++;
9880203945Sweongyo
9881203945Sweongyo	return (slot);
9882203945Sweongyo}
9883203945Sweongyo
9884203945Sweongyostatic int
9885203945Sweongyobwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
9886203945Sweongyo{
9887203945Sweongyo	const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
9888203945Sweongyo	unsigned int a, b, c, d;
9889203945Sweongyo	unsigned int avg;
9890203945Sweongyo	uint32_t tmp;
9891203945Sweongyo
9892203945Sweongyo	tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
9893203945Sweongyo	a = tmp & 0xff;
9894203945Sweongyo	b = (tmp >> 8) & 0xff;
9895203945Sweongyo	c = (tmp >> 16) & 0xff;
9896203945Sweongyo	d = (tmp >> 24) & 0xff;
9897203945Sweongyo	if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
9898203945Sweongyo	    c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
9899203945Sweongyo		return (ENOENT);
9900203945Sweongyo	bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
9901203945Sweongyo	    BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
9902203945Sweongyo	    (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
9903203945Sweongyo
9904203945Sweongyo	if (ofdm) {
9905203945Sweongyo		a = (a + 32) & 0x3f;
9906203945Sweongyo		b = (b + 32) & 0x3f;
9907203945Sweongyo		c = (c + 32) & 0x3f;
9908203945Sweongyo		d = (d + 32) & 0x3f;
9909203945Sweongyo	}
9910203945Sweongyo
9911203945Sweongyo	avg = (a + b + c + d + 2) / 4;
9912203945Sweongyo	if (ofdm) {
9913203945Sweongyo		if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
9914203945Sweongyo		    & BWN_HF_4DB_CCK_POWERBOOST)
9915203945Sweongyo			avg = (avg >= 13) ? (avg - 13) : 0;
9916203945Sweongyo	}
9917203945Sweongyo	return (avg);
9918203945Sweongyo}
9919203945Sweongyo
9920203945Sweongyostatic void
9921203945Sweongyobwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
9922203945Sweongyo{
9923203945Sweongyo	struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
9924203945Sweongyo	int rfatt = *rfattp;
9925203945Sweongyo	int bbatt = *bbattp;
9926203945Sweongyo
9927203945Sweongyo	while (1) {
9928203945Sweongyo		if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
9929203945Sweongyo			break;
9930203945Sweongyo		if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
9931203945Sweongyo			break;
9932203945Sweongyo		if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
9933203945Sweongyo			break;
9934203945Sweongyo		if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
9935203945Sweongyo			break;
9936203945Sweongyo		if (bbatt > lo->bbatt.max) {
9937203945Sweongyo			bbatt -= 4;
9938203945Sweongyo			rfatt += 1;
9939203945Sweongyo			continue;
9940203945Sweongyo		}
9941203945Sweongyo		if (bbatt < lo->bbatt.min) {
9942203945Sweongyo			bbatt += 4;
9943203945Sweongyo			rfatt -= 1;
9944203945Sweongyo			continue;
9945203945Sweongyo		}
9946203945Sweongyo		if (rfatt > lo->rfatt.max) {
9947203945Sweongyo			rfatt -= 1;
9948203945Sweongyo			bbatt += 4;
9949203945Sweongyo			continue;
9950203945Sweongyo		}
9951203945Sweongyo		if (rfatt < lo->rfatt.min) {
9952203945Sweongyo			rfatt += 1;
9953203945Sweongyo			bbatt -= 4;
9954203945Sweongyo			continue;
9955203945Sweongyo		}
9956203945Sweongyo		break;
9957203945Sweongyo	}
9958203945Sweongyo
9959203945Sweongyo	*rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
9960203945Sweongyo	*bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
9961203945Sweongyo}
9962203945Sweongyo
9963203945Sweongyostatic void
9964203945Sweongyobwn_phy_lock(struct bwn_mac *mac)
9965203945Sweongyo{
9966203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9967287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
9968203945Sweongyo
9969204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
9970204922Sweongyo	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
9971203945Sweongyo
9972203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
9973203945Sweongyo		bwn_psctl(mac, BWN_PS_AWAKE);
9974203945Sweongyo}
9975203945Sweongyo
9976203945Sweongyostatic void
9977203945Sweongyobwn_phy_unlock(struct bwn_mac *mac)
9978203945Sweongyo{
9979203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
9980287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
9981203945Sweongyo
9982204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 3,
9983204922Sweongyo	    ("%s: unsupported rev %d", __func__, siba_get_revid(sc->sc_dev)));
9984203945Sweongyo
9985203945Sweongyo	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
9986203945Sweongyo		bwn_psctl(mac, 0);
9987203945Sweongyo}
9988203945Sweongyo
9989203945Sweongyostatic void
9990203945Sweongyobwn_rf_lock(struct bwn_mac *mac)
9991203945Sweongyo{
9992203945Sweongyo
9993203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
9994203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
9995203945Sweongyo	BWN_READ_4(mac, BWN_MACCTL);
9996203945Sweongyo	DELAY(10);
9997203945Sweongyo}
9998203945Sweongyo
9999203945Sweongyostatic void
10000203945Sweongyobwn_rf_unlock(struct bwn_mac *mac)
10001203945Sweongyo{
10002203945Sweongyo
10003203945Sweongyo	BWN_READ_2(mac, BWN_PHYVER);
10004203945Sweongyo	BWN_WRITE_4(mac, BWN_MACCTL,
10005203945Sweongyo	    BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
10006203945Sweongyo}
10007203945Sweongyo
10008203945Sweongyostatic struct bwn_pio_txqueue *
10009203945Sweongyobwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
10010203945Sweongyo    struct bwn_pio_txpkt **pack)
10011203945Sweongyo{
10012203945Sweongyo	struct bwn_pio *pio = &mac->mac_method.pio;
10013203945Sweongyo	struct bwn_pio_txqueue *tq = NULL;
10014203945Sweongyo	unsigned int index;
10015203945Sweongyo
10016203945Sweongyo	switch (cookie & 0xf000) {
10017203945Sweongyo	case 0x1000:
10018203945Sweongyo		tq = &pio->wme[WME_AC_BK];
10019203945Sweongyo		break;
10020203945Sweongyo	case 0x2000:
10021203945Sweongyo		tq = &pio->wme[WME_AC_BE];
10022203945Sweongyo		break;
10023203945Sweongyo	case 0x3000:
10024203945Sweongyo		tq = &pio->wme[WME_AC_VI];
10025203945Sweongyo		break;
10026203945Sweongyo	case 0x4000:
10027203945Sweongyo		tq = &pio->wme[WME_AC_VO];
10028203945Sweongyo		break;
10029203945Sweongyo	case 0x5000:
10030203945Sweongyo		tq = &pio->mcast;
10031203945Sweongyo		break;
10032203945Sweongyo	}
10033203945Sweongyo	KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
10034203945Sweongyo	if (tq == NULL)
10035203945Sweongyo		return (NULL);
10036203945Sweongyo	index = (cookie & 0x0fff);
10037203945Sweongyo	KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
10038203945Sweongyo	if (index >= N(tq->tq_pkts))
10039203945Sweongyo		return (NULL);
10040203945Sweongyo	*pack = &tq->tq_pkts[index];
10041203945Sweongyo	KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
10042203945Sweongyo	return (tq);
10043203945Sweongyo}
10044203945Sweongyo
10045203945Sweongyostatic void
10046203945Sweongyobwn_txpwr(void *arg, int npending)
10047203945Sweongyo{
10048203945Sweongyo	struct bwn_mac *mac = arg;
10049203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10050203945Sweongyo
10051203945Sweongyo	BWN_LOCK(sc);
10052203945Sweongyo	if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
10053203945Sweongyo	    mac->mac_phy.set_txpwr != NULL)
10054203945Sweongyo		mac->mac_phy.set_txpwr(mac);
10055203945Sweongyo	BWN_UNLOCK(sc);
10056203945Sweongyo}
10057203945Sweongyo
10058203945Sweongyostatic void
10059203945Sweongyobwn_task_15s(struct bwn_mac *mac)
10060203945Sweongyo{
10061203945Sweongyo	uint16_t reg;
10062203945Sweongyo
10063203945Sweongyo	if (mac->mac_fw.opensource) {
10064203945Sweongyo		reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
10065203945Sweongyo		if (reg) {
10066203945Sweongyo			bwn_restart(mac, "fw watchdog");
10067203945Sweongyo			return;
10068203945Sweongyo		}
10069203945Sweongyo		bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
10070203945Sweongyo	}
10071203945Sweongyo	if (mac->mac_phy.task_15s)
10072203945Sweongyo		mac->mac_phy.task_15s(mac);
10073203945Sweongyo
10074203945Sweongyo	mac->mac_phy.txerrors = BWN_TXERROR_MAX;
10075203945Sweongyo}
10076203945Sweongyo
10077203945Sweongyostatic void
10078203945Sweongyobwn_task_30s(struct bwn_mac *mac)
10079203945Sweongyo{
10080203945Sweongyo
10081203945Sweongyo	if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
10082203945Sweongyo		return;
10083203945Sweongyo	mac->mac_noise.noi_running = 1;
10084203945Sweongyo	mac->mac_noise.noi_nsamples = 0;
10085203945Sweongyo
10086203945Sweongyo	bwn_noise_gensample(mac);
10087203945Sweongyo}
10088203945Sweongyo
10089203945Sweongyostatic void
10090203945Sweongyobwn_task_60s(struct bwn_mac *mac)
10091203945Sweongyo{
10092203945Sweongyo
10093203945Sweongyo	if (mac->mac_phy.task_60s)
10094203945Sweongyo		mac->mac_phy.task_60s(mac);
10095203945Sweongyo	bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
10096203945Sweongyo}
10097203945Sweongyo
10098203945Sweongyostatic void
10099203945Sweongyobwn_tasks(void *arg)
10100203945Sweongyo{
10101203945Sweongyo	struct bwn_mac *mac = arg;
10102203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10103203945Sweongyo
10104203945Sweongyo	BWN_ASSERT_LOCKED(sc);
10105203945Sweongyo	if (mac->mac_status != BWN_MAC_STATUS_STARTED)
10106203945Sweongyo		return;
10107203945Sweongyo
10108203945Sweongyo	if (mac->mac_task_state % 4 == 0)
10109203945Sweongyo		bwn_task_60s(mac);
10110203945Sweongyo	if (mac->mac_task_state % 2 == 0)
10111203945Sweongyo		bwn_task_30s(mac);
10112203945Sweongyo	bwn_task_15s(mac);
10113203945Sweongyo
10114203945Sweongyo	mac->mac_task_state++;
10115203945Sweongyo	callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
10116203945Sweongyo}
10117203945Sweongyo
10118203945Sweongyostatic int
10119203945Sweongyobwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
10120203945Sweongyo{
10121203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10122203945Sweongyo
10123203945Sweongyo	KASSERT(a == 0, ("not support APHY\n"));
10124203945Sweongyo
10125203945Sweongyo	switch (plcp->o.raw[0] & 0xf) {
10126203945Sweongyo	case 0xb:
10127203945Sweongyo		return (BWN_OFDM_RATE_6MB);
10128203945Sweongyo	case 0xf:
10129203945Sweongyo		return (BWN_OFDM_RATE_9MB);
10130203945Sweongyo	case 0xa:
10131203945Sweongyo		return (BWN_OFDM_RATE_12MB);
10132203945Sweongyo	case 0xe:
10133203945Sweongyo		return (BWN_OFDM_RATE_18MB);
10134203945Sweongyo	case 0x9:
10135203945Sweongyo		return (BWN_OFDM_RATE_24MB);
10136203945Sweongyo	case 0xd:
10137203945Sweongyo		return (BWN_OFDM_RATE_36MB);
10138203945Sweongyo	case 0x8:
10139203945Sweongyo		return (BWN_OFDM_RATE_48MB);
10140203945Sweongyo	case 0xc:
10141203945Sweongyo		return (BWN_OFDM_RATE_54MB);
10142203945Sweongyo	}
10143203945Sweongyo	device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
10144203945Sweongyo	    plcp->o.raw[0] & 0xf);
10145203945Sweongyo	return (-1);
10146203945Sweongyo}
10147203945Sweongyo
10148203945Sweongyostatic int
10149203945Sweongyobwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
10150203945Sweongyo{
10151203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10152203945Sweongyo
10153203945Sweongyo	switch (plcp->o.raw[0]) {
10154203945Sweongyo	case 0x0a:
10155203945Sweongyo		return (BWN_CCK_RATE_1MB);
10156203945Sweongyo	case 0x14:
10157203945Sweongyo		return (BWN_CCK_RATE_2MB);
10158203945Sweongyo	case 0x37:
10159203945Sweongyo		return (BWN_CCK_RATE_5MB);
10160203945Sweongyo	case 0x6e:
10161203945Sweongyo		return (BWN_CCK_RATE_11MB);
10162203945Sweongyo	}
10163203945Sweongyo	device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
10164203945Sweongyo	return (-1);
10165203945Sweongyo}
10166203945Sweongyo
10167203945Sweongyostatic void
10168203945Sweongyobwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
10169203945Sweongyo    const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
10170203945Sweongyo    int rssi, int noise)
10171203945Sweongyo{
10172203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10173203945Sweongyo	const struct ieee80211_frame_min *wh;
10174203945Sweongyo	uint64_t tsf;
10175203945Sweongyo	uint16_t low_mactime_now;
10176203945Sweongyo
10177203945Sweongyo	if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
10178203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
10179203945Sweongyo
10180203945Sweongyo	wh = mtod(m, const struct ieee80211_frame_min *);
10181260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
10182203945Sweongyo		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
10183203945Sweongyo
10184203945Sweongyo	bwn_tsf_read(mac, &tsf);
10185203945Sweongyo	low_mactime_now = tsf;
10186203945Sweongyo	tsf = tsf & ~0xffffULL;
10187203945Sweongyo	tsf += le16toh(rxhdr->mac_time);
10188203945Sweongyo	if (low_mactime_now < le16toh(rxhdr->mac_time))
10189203945Sweongyo		tsf -= 0x10000;
10190203945Sweongyo
10191203945Sweongyo	sc->sc_rx_th.wr_tsf = tsf;
10192203945Sweongyo	sc->sc_rx_th.wr_rate = rate;
10193203945Sweongyo	sc->sc_rx_th.wr_antsignal = rssi;
10194203945Sweongyo	sc->sc_rx_th.wr_antnoise = noise;
10195203945Sweongyo}
10196203945Sweongyo
10197203945Sweongyostatic void
10198203945Sweongyobwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
10199203945Sweongyo{
10200203945Sweongyo	uint32_t low, high;
10201203945Sweongyo
10202204983Syongari	KASSERT(siba_get_revid(mac->mac_sc->sc_dev) >= 3,
10203203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
10204203945Sweongyo
10205203945Sweongyo	low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
10206203945Sweongyo	high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
10207203945Sweongyo	*tsf = high;
10208203945Sweongyo	*tsf <<= 32;
10209203945Sweongyo	*tsf |= low;
10210203945Sweongyo}
10211203945Sweongyo
10212203945Sweongyostatic int
10213203945Sweongyobwn_dma_attach(struct bwn_mac *mac)
10214203945Sweongyo{
10215203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10216203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10217203945Sweongyo	bus_addr_t lowaddr = 0;
10218203945Sweongyo	int error;
10219203945Sweongyo
10220204922Sweongyo	if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
10221203945Sweongyo		return (0);
10222203945Sweongyo
10223204922Sweongyo	KASSERT(siba_get_revid(sc->sc_dev) >= 5, ("%s: fail", __func__));
10224203945Sweongyo
10225203945Sweongyo	mac->mac_flags |= BWN_MAC_FLAG_DMA;
10226203945Sweongyo
10227203945Sweongyo	dma->dmatype = bwn_dma_gettype(mac);
10228203945Sweongyo	if (dma->dmatype == BWN_DMA_30BIT)
10229203945Sweongyo		lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
10230203945Sweongyo	else if (dma->dmatype == BWN_DMA_32BIT)
10231203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR_32BIT;
10232203945Sweongyo	else
10233203945Sweongyo		lowaddr = BUS_SPACE_MAXADDR;
10234203945Sweongyo
10235203945Sweongyo	/*
10236203945Sweongyo	 * Create top level DMA tag
10237203945Sweongyo	 */
10238203945Sweongyo	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
10239203945Sweongyo			       BWN_ALIGN, 0,		/* alignment, bounds */
10240203945Sweongyo			       lowaddr,			/* lowaddr */
10241203945Sweongyo			       BUS_SPACE_MAXADDR,	/* highaddr */
10242203945Sweongyo			       NULL, NULL,		/* filter, filterarg */
10243280347Smav			       BUS_SPACE_MAXSIZE,	/* maxsize */
10244203945Sweongyo			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
10245203945Sweongyo			       BUS_SPACE_MAXSIZE,	/* maxsegsize */
10246203945Sweongyo			       0,			/* flags */
10247203945Sweongyo			       NULL, NULL,		/* lockfunc, lockarg */
10248203945Sweongyo			       &dma->parent_dtag);
10249203945Sweongyo	if (error) {
10250203945Sweongyo		device_printf(sc->sc_dev, "can't create parent DMA tag\n");
10251203945Sweongyo		return (error);
10252203945Sweongyo	}
10253203945Sweongyo
10254203945Sweongyo	/*
10255203945Sweongyo	 * Create TX/RX mbuf DMA tag
10256203945Sweongyo	 */
10257203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10258203945Sweongyo				1,
10259203945Sweongyo				0,
10260203945Sweongyo				BUS_SPACE_MAXADDR,
10261203945Sweongyo				BUS_SPACE_MAXADDR,
10262203945Sweongyo				NULL, NULL,
10263203945Sweongyo				MCLBYTES,
10264203945Sweongyo				1,
10265203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10266203945Sweongyo				0,
10267203945Sweongyo				NULL, NULL,
10268203945Sweongyo				&dma->rxbuf_dtag);
10269203945Sweongyo	if (error) {
10270203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10271203945Sweongyo		goto fail0;
10272203945Sweongyo	}
10273203945Sweongyo	error = bus_dma_tag_create(dma->parent_dtag,
10274203945Sweongyo				1,
10275203945Sweongyo				0,
10276203945Sweongyo				BUS_SPACE_MAXADDR,
10277203945Sweongyo				BUS_SPACE_MAXADDR,
10278203945Sweongyo				NULL, NULL,
10279203945Sweongyo				MCLBYTES,
10280203945Sweongyo				1,
10281203945Sweongyo				BUS_SPACE_MAXSIZE_32BIT,
10282203945Sweongyo				0,
10283203945Sweongyo				NULL, NULL,
10284203945Sweongyo				&dma->txbuf_dtag);
10285203945Sweongyo	if (error) {
10286203945Sweongyo		device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
10287203945Sweongyo		goto fail1;
10288203945Sweongyo	}
10289203945Sweongyo
10290203945Sweongyo	dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
10291203945Sweongyo	if (!dma->wme[WME_AC_BK])
10292203945Sweongyo		goto fail2;
10293203945Sweongyo
10294203945Sweongyo	dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
10295203945Sweongyo	if (!dma->wme[WME_AC_BE])
10296203945Sweongyo		goto fail3;
10297203945Sweongyo
10298203945Sweongyo	dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
10299203945Sweongyo	if (!dma->wme[WME_AC_VI])
10300203945Sweongyo		goto fail4;
10301203945Sweongyo
10302203945Sweongyo	dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
10303203945Sweongyo	if (!dma->wme[WME_AC_VO])
10304203945Sweongyo		goto fail5;
10305203945Sweongyo
10306203945Sweongyo	dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
10307203945Sweongyo	if (!dma->mcast)
10308203945Sweongyo		goto fail6;
10309203945Sweongyo	dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
10310203945Sweongyo	if (!dma->rx)
10311203945Sweongyo		goto fail7;
10312203945Sweongyo
10313203945Sweongyo	return (error);
10314203945Sweongyo
10315203945Sweongyofail7:	bwn_dma_ringfree(&dma->mcast);
10316203945Sweongyofail6:	bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
10317203945Sweongyofail5:	bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
10318203945Sweongyofail4:	bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
10319203945Sweongyofail3:	bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
10320203945Sweongyofail2:	bus_dma_tag_destroy(dma->txbuf_dtag);
10321203945Sweongyofail1:	bus_dma_tag_destroy(dma->rxbuf_dtag);
10322203945Sweongyofail0:	bus_dma_tag_destroy(dma->parent_dtag);
10323203945Sweongyo	return (error);
10324203945Sweongyo}
10325203945Sweongyo
10326203945Sweongyostatic struct bwn_dma_ring *
10327203945Sweongyobwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
10328203945Sweongyo    uint16_t cookie, int *slot)
10329203945Sweongyo{
10330203945Sweongyo	struct bwn_dma *dma = &mac->mac_method.dma;
10331203945Sweongyo	struct bwn_dma_ring *dr;
10332203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10333203945Sweongyo
10334203945Sweongyo	BWN_ASSERT_LOCKED(mac->mac_sc);
10335203945Sweongyo
10336203945Sweongyo	switch (cookie & 0xf000) {
10337203945Sweongyo	case 0x1000:
10338203945Sweongyo		dr = dma->wme[WME_AC_BK];
10339203945Sweongyo		break;
10340203945Sweongyo	case 0x2000:
10341203945Sweongyo		dr = dma->wme[WME_AC_BE];
10342203945Sweongyo		break;
10343203945Sweongyo	case 0x3000:
10344203945Sweongyo		dr = dma->wme[WME_AC_VI];
10345203945Sweongyo		break;
10346203945Sweongyo	case 0x4000:
10347203945Sweongyo		dr = dma->wme[WME_AC_VO];
10348203945Sweongyo		break;
10349203945Sweongyo	case 0x5000:
10350203945Sweongyo		dr = dma->mcast;
10351203945Sweongyo		break;
10352203945Sweongyo	default:
10353204242Simp		dr = NULL;
10354203945Sweongyo		KASSERT(0 == 1,
10355203945Sweongyo		    ("invalid cookie value %d", cookie & 0xf000));
10356203945Sweongyo	}
10357203945Sweongyo	*slot = (cookie & 0x0fff);
10358203945Sweongyo	if (*slot < 0 || *slot >= dr->dr_numslots) {
10359203945Sweongyo		/*
10360203945Sweongyo		 * XXX FIXME: sometimes H/W returns TX DONE events duplicately
10361203945Sweongyo		 * that it occurs events which have same H/W sequence numbers.
10362203945Sweongyo		 * When it's occurred just prints a WARNING msgs and ignores.
10363203945Sweongyo		 */
10364203945Sweongyo		KASSERT(status->seq == dma->lastseq,
10365203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
10366203945Sweongyo		device_printf(sc->sc_dev,
10367203945Sweongyo		    "out of slot ranges (0 < %d < %d)\n", *slot,
10368203945Sweongyo		    dr->dr_numslots);
10369203945Sweongyo		return (NULL);
10370203945Sweongyo	}
10371203945Sweongyo	dma->lastseq = status->seq;
10372203945Sweongyo	return (dr);
10373203945Sweongyo}
10374203945Sweongyo
10375203945Sweongyostatic void
10376203945Sweongyobwn_dma_stop(struct bwn_mac *mac)
10377203945Sweongyo{
10378203945Sweongyo	struct bwn_dma *dma;
10379203945Sweongyo
10380203945Sweongyo	if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
10381203945Sweongyo		return;
10382203945Sweongyo	dma = &mac->mac_method.dma;
10383203945Sweongyo
10384203945Sweongyo	bwn_dma_ringstop(&dma->rx);
10385203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
10386203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
10387203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
10388203945Sweongyo	bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
10389203945Sweongyo	bwn_dma_ringstop(&dma->mcast);
10390203945Sweongyo}
10391203945Sweongyo
10392203945Sweongyostatic void
10393203945Sweongyobwn_dma_ringstop(struct bwn_dma_ring **dr)
10394203945Sweongyo{
10395203945Sweongyo
10396203945Sweongyo	if (dr == NULL)
10397203945Sweongyo		return;
10398203945Sweongyo
10399203945Sweongyo	bwn_dma_cleanup(*dr);
10400203945Sweongyo}
10401203945Sweongyo
10402203945Sweongyostatic void
10403203945Sweongyobwn_pio_stop(struct bwn_mac *mac)
10404203945Sweongyo{
10405203945Sweongyo	struct bwn_pio *pio;
10406203945Sweongyo
10407203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_DMA)
10408203945Sweongyo		return;
10409203945Sweongyo	pio = &mac->mac_method.pio;
10410203945Sweongyo
10411203945Sweongyo	bwn_destroy_queue_tx(&pio->mcast);
10412203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]);
10413203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]);
10414203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]);
10415203945Sweongyo	bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
10416203945Sweongyo}
10417203945Sweongyo
10418203945Sweongyostatic void
10419203945Sweongyobwn_led_attach(struct bwn_mac *mac)
10420203945Sweongyo{
10421203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10422203945Sweongyo	const uint8_t *led_act = NULL;
10423203945Sweongyo	uint16_t val[BWN_LED_MAX];
10424203945Sweongyo	int i;
10425203945Sweongyo
10426203945Sweongyo	sc->sc_led_idle = (2350 * hz) / 1000;
10427203945Sweongyo	sc->sc_led_blink = 1;
10428203945Sweongyo
10429203945Sweongyo	for (i = 0; i < N(bwn_vendor_led_act); ++i) {
10430204922Sweongyo		if (siba_get_pci_subvendor(sc->sc_dev) ==
10431204922Sweongyo		    bwn_vendor_led_act[i].vid) {
10432203945Sweongyo			led_act = bwn_vendor_led_act[i].led_act;
10433203945Sweongyo			break;
10434203945Sweongyo		}
10435203945Sweongyo	}
10436203945Sweongyo	if (led_act == NULL)
10437203945Sweongyo		led_act = bwn_default_led_act;
10438203945Sweongyo
10439204922Sweongyo	val[0] = siba_sprom_get_gpio0(sc->sc_dev);
10440204922Sweongyo	val[1] = siba_sprom_get_gpio1(sc->sc_dev);
10441204922Sweongyo	val[2] = siba_sprom_get_gpio2(sc->sc_dev);
10442204922Sweongyo	val[3] = siba_sprom_get_gpio3(sc->sc_dev);
10443203945Sweongyo
10444203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10445203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10446203945Sweongyo
10447203945Sweongyo		if (val[i] == 0xff) {
10448203945Sweongyo			led->led_act = led_act[i];
10449203945Sweongyo		} else {
10450203945Sweongyo			if (val[i] & BWN_LED_ACT_LOW)
10451203945Sweongyo				led->led_flags |= BWN_LED_F_ACTLOW;
10452203945Sweongyo			led->led_act = val[i] & BWN_LED_ACT_MASK;
10453203945Sweongyo		}
10454203945Sweongyo		led->led_mask = (1 << i);
10455203945Sweongyo
10456203945Sweongyo		if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
10457203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK_POLL ||
10458203945Sweongyo		    led->led_act == BWN_LED_ACT_BLINK) {
10459203945Sweongyo			led->led_flags |= BWN_LED_F_BLINK;
10460203945Sweongyo			if (led->led_act == BWN_LED_ACT_BLINK_POLL)
10461203945Sweongyo				led->led_flags |= BWN_LED_F_POLLABLE;
10462203945Sweongyo			else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
10463203945Sweongyo				led->led_flags |= BWN_LED_F_SLOW;
10464203945Sweongyo
10465203945Sweongyo			if (sc->sc_blink_led == NULL) {
10466203945Sweongyo				sc->sc_blink_led = led;
10467203945Sweongyo				if (led->led_flags & BWN_LED_F_SLOW)
10468203945Sweongyo					BWN_LED_SLOWDOWN(sc->sc_led_idle);
10469203945Sweongyo			}
10470203945Sweongyo		}
10471203945Sweongyo
10472203945Sweongyo		DPRINTF(sc, BWN_DEBUG_LED,
10473203945Sweongyo		    "%dth led, act %d, lowact %d\n", i,
10474203945Sweongyo		    led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
10475203945Sweongyo	}
10476203945Sweongyo	callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
10477203945Sweongyo}
10478203945Sweongyo
10479203945Sweongyostatic __inline uint16_t
10480203945Sweongyobwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
10481203945Sweongyo{
10482203945Sweongyo
10483203945Sweongyo	if (led->led_flags & BWN_LED_F_ACTLOW)
10484203945Sweongyo		on = !on;
10485203945Sweongyo	if (on)
10486203945Sweongyo		val |= led->led_mask;
10487203945Sweongyo	else
10488203945Sweongyo		val &= ~led->led_mask;
10489203945Sweongyo	return val;
10490203945Sweongyo}
10491203945Sweongyo
10492203945Sweongyostatic void
10493203945Sweongyobwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
10494203945Sweongyo{
10495203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10496287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
10497203945Sweongyo	uint16_t val;
10498203945Sweongyo	int i;
10499203945Sweongyo
10500203945Sweongyo	if (nstate == IEEE80211_S_INIT) {
10501203945Sweongyo		callout_stop(&sc->sc_led_blink_ch);
10502203945Sweongyo		sc->sc_led_blinking = 0;
10503203945Sweongyo	}
10504203945Sweongyo
10505287197Sglebius	if ((sc->sc_flags & BWN_FLAG_RUNNING) == 0)
10506203945Sweongyo		return;
10507203945Sweongyo
10508203945Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10509203945Sweongyo	for (i = 0; i < BWN_LED_MAX; ++i) {
10510203945Sweongyo		struct bwn_led *led = &sc->sc_leds[i];
10511203945Sweongyo		int on;
10512203945Sweongyo
10513203945Sweongyo		if (led->led_act == BWN_LED_ACT_UNKN ||
10514203945Sweongyo		    led->led_act == BWN_LED_ACT_NULL)
10515203945Sweongyo			continue;
10516203945Sweongyo
10517203945Sweongyo		if ((led->led_flags & BWN_LED_F_BLINK) &&
10518203945Sweongyo		    nstate != IEEE80211_S_INIT)
10519203945Sweongyo			continue;
10520203945Sweongyo
10521203945Sweongyo		switch (led->led_act) {
10522203945Sweongyo		case BWN_LED_ACT_ON:    /* Always on */
10523203945Sweongyo			on = 1;
10524203945Sweongyo			break;
10525203945Sweongyo		case BWN_LED_ACT_OFF:   /* Always off */
10526203945Sweongyo		case BWN_LED_ACT_5GHZ:  /* TODO: 11A */
10527203945Sweongyo			on = 0;
10528203945Sweongyo			break;
10529203945Sweongyo		default:
10530203945Sweongyo			on = 1;
10531203945Sweongyo			switch (nstate) {
10532203945Sweongyo			case IEEE80211_S_INIT:
10533203945Sweongyo				on = 0;
10534203945Sweongyo				break;
10535203945Sweongyo			case IEEE80211_S_RUN:
10536203945Sweongyo				if (led->led_act == BWN_LED_ACT_11G &&
10537203945Sweongyo				    ic->ic_curmode != IEEE80211_MODE_11G)
10538203945Sweongyo					on = 0;
10539203945Sweongyo				break;
10540203945Sweongyo			default:
10541203945Sweongyo				if (led->led_act == BWN_LED_ACT_ASSOC)
10542203945Sweongyo					on = 0;
10543203945Sweongyo				break;
10544203945Sweongyo			}
10545203945Sweongyo			break;
10546203945Sweongyo		}
10547203945Sweongyo
10548203945Sweongyo		val = bwn_led_onoff(led, val, on);
10549203945Sweongyo	}
10550203945Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10551203945Sweongyo}
10552203945Sweongyo
10553203945Sweongyostatic void
10554203945Sweongyobwn_led_event(struct bwn_mac *mac, int event)
10555203945Sweongyo{
10556203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10557204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
10558204922Sweongyo	int rate;
10559203945Sweongyo
10560204922Sweongyo	if (event == BWN_LED_EVENT_POLL) {
10561204922Sweongyo		if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
10562204922Sweongyo			return;
10563204922Sweongyo		if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
10564204922Sweongyo			return;
10565204922Sweongyo	}
10566203945Sweongyo
10567204922Sweongyo	sc->sc_led_ticks = ticks;
10568204922Sweongyo	if (sc->sc_led_blinking)
10569204922Sweongyo		return;
10570203945Sweongyo
10571204922Sweongyo	switch (event) {
10572204922Sweongyo	case BWN_LED_EVENT_RX:
10573204922Sweongyo		rate = sc->sc_rx_rate;
10574204922Sweongyo		break;
10575204922Sweongyo	case BWN_LED_EVENT_TX:
10576204922Sweongyo		rate = sc->sc_tx_rate;
10577204922Sweongyo		break;
10578204922Sweongyo	case BWN_LED_EVENT_POLL:
10579204922Sweongyo		rate = 0;
10580204922Sweongyo		break;
10581204922Sweongyo	default:
10582204922Sweongyo		panic("unknown LED event %d\n", event);
10583204922Sweongyo		break;
10584204922Sweongyo	}
10585204922Sweongyo	bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
10586204922Sweongyo	    bwn_led_duration[rate].off_dur);
10587203945Sweongyo}
10588203945Sweongyo
10589203945Sweongyostatic void
10590203945Sweongyobwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
10591203945Sweongyo{
10592203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10593204922Sweongyo	struct bwn_led *led = sc->sc_blink_led;
10594204922Sweongyo	uint16_t val;
10595203945Sweongyo
10596204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10597204922Sweongyo	val = bwn_led_onoff(led, val, 1);
10598204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10599203945Sweongyo
10600204922Sweongyo	if (led->led_flags & BWN_LED_F_SLOW) {
10601204922Sweongyo		BWN_LED_SLOWDOWN(on_dur);
10602204922Sweongyo		BWN_LED_SLOWDOWN(off_dur);
10603204922Sweongyo	}
10604203945Sweongyo
10605204922Sweongyo	sc->sc_led_blinking = 1;
10606204922Sweongyo	sc->sc_led_blink_offdur = off_dur;
10607203945Sweongyo
10608204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
10609203945Sweongyo}
10610203945Sweongyo
10611203945Sweongyostatic void
10612203945Sweongyobwn_led_blink_next(void *arg)
10613203945Sweongyo{
10614203945Sweongyo	struct bwn_mac *mac = arg;
10615204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10616204922Sweongyo	uint16_t val;
10617203945Sweongyo
10618204922Sweongyo	val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
10619204922Sweongyo	val = bwn_led_onoff(sc->sc_blink_led, val, 0);
10620204922Sweongyo	BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
10621203945Sweongyo
10622204922Sweongyo	callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
10623204922Sweongyo	    bwn_led_blink_end, mac);
10624203945Sweongyo}
10625203945Sweongyo
10626203945Sweongyostatic void
10627203945Sweongyobwn_led_blink_end(void *arg)
10628203945Sweongyo{
10629203945Sweongyo	struct bwn_mac *mac = arg;
10630204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10631203945Sweongyo
10632204922Sweongyo	sc->sc_led_blinking = 0;
10633203945Sweongyo}
10634203945Sweongyo
10635203945Sweongyostatic int
10636203945Sweongyobwn_suspend(device_t dev)
10637203945Sweongyo{
10638203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10639203945Sweongyo
10640287197Sglebius	BWN_LOCK(sc);
10641287197Sglebius	bwn_stop(sc);
10642287197Sglebius	BWN_UNLOCK(sc);
10643203945Sweongyo	return (0);
10644203945Sweongyo}
10645203945Sweongyo
10646203945Sweongyostatic int
10647203945Sweongyobwn_resume(device_t dev)
10648203945Sweongyo{
10649203945Sweongyo	struct bwn_softc *sc = device_get_softc(dev);
10650287197Sglebius	int error = EDOOFUS;
10651203945Sweongyo
10652287197Sglebius	BWN_LOCK(sc);
10653287197Sglebius	if (sc->sc_ic.ic_nrunning > 0)
10654287197Sglebius		error = bwn_init(sc);
10655287197Sglebius	BWN_UNLOCK(sc);
10656287197Sglebius	if (error == 0)
10657287197Sglebius		ieee80211_start_all(&sc->sc_ic);
10658203945Sweongyo	return (0);
10659203945Sweongyo}
10660203945Sweongyo
10661203945Sweongyostatic void
10662203945Sweongyobwn_rfswitch(void *arg)
10663203945Sweongyo{
10664203945Sweongyo	struct bwn_softc *sc = arg;
10665203945Sweongyo	struct bwn_mac *mac = sc->sc_curmac;
10666203945Sweongyo	int cur = 0, prev = 0;
10667203945Sweongyo
10668203945Sweongyo	KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
10669203945Sweongyo	    ("%s: invalid MAC status %d", __func__, mac->mac_status));
10670203945Sweongyo
10671285436Sadrian	if (mac->mac_phy.rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
10672203945Sweongyo		if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
10673203945Sweongyo			& BWN_RF_HWENABLED_HI_MASK))
10674203945Sweongyo			cur = 1;
10675203945Sweongyo	} else {
10676203945Sweongyo		if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
10677203945Sweongyo		    & BWN_RF_HWENABLED_LO_MASK)
10678203945Sweongyo			cur = 1;
10679203945Sweongyo	}
10680203945Sweongyo
10681203945Sweongyo	if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
10682203945Sweongyo		prev = 1;
10683203945Sweongyo
10684203945Sweongyo	if (cur != prev) {
10685203945Sweongyo		if (cur)
10686203945Sweongyo			mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
10687203945Sweongyo		else
10688203945Sweongyo			mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
10689203945Sweongyo
10690203945Sweongyo		device_printf(sc->sc_dev,
10691203945Sweongyo		    "status of RF switch is changed to %s\n",
10692203945Sweongyo		    cur ? "ON" : "OFF");
10693203945Sweongyo		if (cur != mac->mac_phy.rf_on) {
10694203945Sweongyo			if (cur)
10695203945Sweongyo				bwn_rf_turnon(mac);
10696203945Sweongyo			else
10697203945Sweongyo				bwn_rf_turnoff(mac);
10698203945Sweongyo		}
10699203945Sweongyo	}
10700203945Sweongyo
10701203945Sweongyo	callout_schedule(&sc->sc_rfswitch_ch, hz);
10702203945Sweongyo}
10703203945Sweongyo
10704203945Sweongyostatic void
10705203945Sweongyobwn_phy_lp_init_pre(struct bwn_mac *mac)
10706203945Sweongyo{
10707203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
10708203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
10709203945Sweongyo
10710203945Sweongyo	plp->plp_antenna = BWN_ANT_DEFAULT;
10711203945Sweongyo}
10712203945Sweongyo
10713203945Sweongyostatic int
10714203945Sweongyobwn_phy_lp_init(struct bwn_mac *mac)
10715203945Sweongyo{
10716203945Sweongyo	static const struct bwn_stxtable tables[] = {
10717203945Sweongyo		{ 2,  6, 0x3d, 3, 0x01 }, { 1, 12, 0x4c, 1, 0x01 },
10718203945Sweongyo		{ 1,  8, 0x50, 0, 0x7f }, { 0,  8, 0x44, 0, 0xff },
10719203945Sweongyo		{ 1,  0, 0x4a, 0, 0xff }, { 0,  4, 0x4d, 0, 0xff },
10720203945Sweongyo		{ 1,  4, 0x4e, 0, 0xff }, { 0, 12, 0x4f, 0, 0x0f },
10721203945Sweongyo		{ 1,  0, 0x4f, 4, 0x0f }, { 3,  0, 0x49, 0, 0x0f },
10722203945Sweongyo		{ 4,  3, 0x46, 4, 0x07 }, { 3, 15, 0x46, 0, 0x01 },
10723203945Sweongyo		{ 4,  0, 0x46, 1, 0x07 }, { 3,  8, 0x48, 4, 0x07 },
10724203945Sweongyo		{ 3, 11, 0x48, 0, 0x0f }, { 3,  4, 0x49, 4, 0x0f },
10725203945Sweongyo		{ 2, 15, 0x45, 0, 0x01 }, { 5, 13, 0x52, 4, 0x07 },
10726203945Sweongyo		{ 6,  0, 0x52, 7, 0x01 }, { 5,  3, 0x41, 5, 0x07 },
10727203945Sweongyo		{ 5,  6, 0x41, 0, 0x0f }, { 5, 10, 0x42, 5, 0x07 },
10728203945Sweongyo		{ 4, 15, 0x42, 0, 0x01 }, { 5,  0, 0x42, 1, 0x07 },
10729203945Sweongyo		{ 4, 11, 0x43, 4, 0x0f }, { 4,  7, 0x43, 0, 0x0f },
10730203945Sweongyo		{ 4,  6, 0x45, 1, 0x01 }, { 2,  7, 0x40, 4, 0x0f },
10731203945Sweongyo		{ 2, 11, 0x40, 0, 0x0f }
10732203945Sweongyo	};
10733203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
10734203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10735203945Sweongyo	const struct bwn_stxtable *st;
10736287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
10737203945Sweongyo	int i, error;
10738203945Sweongyo	uint16_t tmp;
10739203945Sweongyo
10740203945Sweongyo	bwn_phy_lp_readsprom(mac);	/* XXX bad place */
10741203945Sweongyo	bwn_phy_lp_bbinit(mac);
10742203945Sweongyo
10743203945Sweongyo	/* initialize RF */
10744203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_4WIRECTL, 0x2);
10745203945Sweongyo	DELAY(1);
10746203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_4WIRECTL, 0xfffd);
10747203945Sweongyo	DELAY(1);
10748203945Sweongyo
10749203945Sweongyo	if (mac->mac_phy.rf_ver == 0x2062)
10750203945Sweongyo		bwn_phy_lp_b2062_init(mac);
10751203945Sweongyo	else {
10752203945Sweongyo		bwn_phy_lp_b2063_init(mac);
10753203945Sweongyo
10754203945Sweongyo		/* synchronize stx table. */
10755203945Sweongyo		for (i = 0; i < N(tables); i++) {
10756203945Sweongyo			st = &tables[i];
10757203945Sweongyo			tmp = BWN_RF_READ(mac, st->st_rfaddr);
10758203945Sweongyo			tmp >>= st->st_rfshift;
10759203945Sweongyo			tmp <<= st->st_physhift;
10760203945Sweongyo			BWN_PHY_SETMASK(mac,
10761203945Sweongyo			    BWN_PHY_OFDM(0xf2 + st->st_phyoffset),
10762203945Sweongyo			    ~(st->st_mask << st->st_physhift), tmp);
10763203945Sweongyo		}
10764203945Sweongyo
10765203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf0), 0x5f80);
10766203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf1), 0);
10767203945Sweongyo	}
10768203945Sweongyo
10769203945Sweongyo	/* calibrate RC */
10770203945Sweongyo	if (mac->mac_phy.rev >= 2)
10771203945Sweongyo		bwn_phy_lp_rxcal_r2(mac);
10772203945Sweongyo	else if (!plp->plp_rccap) {
10773203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
10774203945Sweongyo			bwn_phy_lp_rccal_r12(mac);
10775203945Sweongyo	} else
10776203945Sweongyo		bwn_phy_lp_set_rccap(mac);
10777203945Sweongyo
10778203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
10779203945Sweongyo	if (error)
10780203945Sweongyo		device_printf(sc->sc_dev,
10781203945Sweongyo		    "failed to change channel 7 (%d)\n", error);
10782203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
10783203945Sweongyo	bwn_phy_lp_calib(mac);
10784203945Sweongyo	return (0);
10785203945Sweongyo}
10786203945Sweongyo
10787203945Sweongyostatic uint16_t
10788203945Sweongyobwn_phy_lp_read(struct bwn_mac *mac, uint16_t reg)
10789203945Sweongyo{
10790203945Sweongyo
10791203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10792203945Sweongyo	return (BWN_READ_2(mac, BWN_PHYDATA));
10793203945Sweongyo}
10794203945Sweongyo
10795203945Sweongyostatic void
10796203945Sweongyobwn_phy_lp_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
10797203945Sweongyo{
10798203945Sweongyo
10799203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10800203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA, value);
10801203945Sweongyo}
10802203945Sweongyo
10803203945Sweongyostatic void
10804203945Sweongyobwn_phy_lp_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
10805203945Sweongyo    uint16_t set)
10806203945Sweongyo{
10807203945Sweongyo
10808203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYCTL, reg);
10809203945Sweongyo	BWN_WRITE_2(mac, BWN_PHYDATA,
10810203945Sweongyo	    (BWN_READ_2(mac, BWN_PHYDATA) & mask) | set);
10811203945Sweongyo}
10812203945Sweongyo
10813203945Sweongyostatic uint16_t
10814203945Sweongyobwn_phy_lp_rf_read(struct bwn_mac *mac, uint16_t reg)
10815203945Sweongyo{
10816203945Sweongyo
10817203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
10818203945Sweongyo	if (mac->mac_phy.rev < 2 && reg != 0x4001)
10819203945Sweongyo		reg |= 0x100;
10820203945Sweongyo	if (mac->mac_phy.rev >= 2)
10821203945Sweongyo		reg |= 0x200;
10822203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
10823203945Sweongyo	return BWN_READ_2(mac, BWN_RFDATALO);
10824203945Sweongyo}
10825203945Sweongyo
10826203945Sweongyostatic void
10827203945Sweongyobwn_phy_lp_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
10828203945Sweongyo{
10829203945Sweongyo
10830203945Sweongyo	KASSERT(reg != 1, ("unaccessible register %d", reg));
10831203945Sweongyo	BWN_WRITE_2(mac, BWN_RFCTL, reg);
10832203945Sweongyo	BWN_WRITE_2(mac, BWN_RFDATALO, value);
10833203945Sweongyo}
10834203945Sweongyo
10835203945Sweongyostatic void
10836203945Sweongyobwn_phy_lp_rf_onoff(struct bwn_mac *mac, int on)
10837203945Sweongyo{
10838203945Sweongyo
10839203945Sweongyo	if (on) {
10840203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xe0ff);
10841203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2,
10842203945Sweongyo		    (mac->mac_phy.rev >= 2) ? 0xf7f7 : 0xffe7);
10843203945Sweongyo		return;
10844203945Sweongyo	}
10845203945Sweongyo
10846203945Sweongyo	if (mac->mac_phy.rev >= 2) {
10847203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x83ff);
10848203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
10849203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0x80ff);
10850203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xdfff);
10851203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0808);
10852203945Sweongyo		return;
10853203945Sweongyo	}
10854203945Sweongyo
10855203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xe0ff);
10856203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
10857203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfcff);
10858203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0018);
10859203945Sweongyo}
10860203945Sweongyo
10861203945Sweongyostatic int
10862203945Sweongyobwn_phy_lp_switch_channel(struct bwn_mac *mac, uint32_t chan)
10863203945Sweongyo{
10864203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
10865203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
10866203945Sweongyo	int error;
10867203945Sweongyo
10868203945Sweongyo	if (phy->rf_ver == 0x2063) {
10869203945Sweongyo		error = bwn_phy_lp_b2063_switch_channel(mac, chan);
10870203945Sweongyo		if (error)
10871203945Sweongyo			return (error);
10872203945Sweongyo	} else {
10873203945Sweongyo		error = bwn_phy_lp_b2062_switch_channel(mac, chan);
10874203945Sweongyo		if (error)
10875203945Sweongyo			return (error);
10876203945Sweongyo		bwn_phy_lp_set_anafilter(mac, chan);
10877203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, ieee80211_ieee2mhz(chan, 0));
10878203945Sweongyo	}
10879203945Sweongyo
10880203945Sweongyo	plp->plp_chan = chan;
10881203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, chan);
10882203945Sweongyo	return (0);
10883203945Sweongyo}
10884203945Sweongyo
10885203945Sweongyostatic uint32_t
10886203945Sweongyobwn_phy_lp_get_default_chan(struct bwn_mac *mac)
10887203945Sweongyo{
10888203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10889287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
10890203945Sweongyo
10891203945Sweongyo	return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36);
10892203945Sweongyo}
10893203945Sweongyo
10894203945Sweongyostatic void
10895203945Sweongyobwn_phy_lp_set_antenna(struct bwn_mac *mac, int antenna)
10896203945Sweongyo{
10897203945Sweongyo	struct bwn_phy *phy = &mac->mac_phy;
10898203945Sweongyo	struct bwn_phy_lp *plp = &phy->phy_lp;
10899203945Sweongyo
10900203945Sweongyo	if (phy->rev >= 2 || antenna > BWN_ANTAUTO1)
10901203945Sweongyo		return;
10902203945Sweongyo
10903203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER);
10904203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffd, antenna & 0x2);
10905203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffe, antenna & 0x1);
10906203945Sweongyo	bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_UCODE_ANTDIV_HELPER);
10907203945Sweongyo	plp->plp_antenna = antenna;
10908203945Sweongyo}
10909203945Sweongyo
10910203945Sweongyostatic void
10911203945Sweongyobwn_phy_lp_task_60s(struct bwn_mac *mac)
10912203945Sweongyo{
10913203945Sweongyo
10914203945Sweongyo	bwn_phy_lp_calib(mac);
10915203945Sweongyo}
10916203945Sweongyo
10917203945Sweongyostatic void
10918203945Sweongyobwn_phy_lp_readsprom(struct bwn_mac *mac)
10919203945Sweongyo{
10920203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
10921203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10922287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
10923203945Sweongyo
10924203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
10925204922Sweongyo		plp->plp_txisoband_m = siba_sprom_get_tri2g(sc->sc_dev);
10926204922Sweongyo		plp->plp_bxarch = siba_sprom_get_bxa2g(sc->sc_dev);
10927204922Sweongyo		plp->plp_rxpwroffset = siba_sprom_get_rxpo2g(sc->sc_dev);
10928204922Sweongyo		plp->plp_rssivf = siba_sprom_get_rssismf2g(sc->sc_dev);
10929204922Sweongyo		plp->plp_rssivc = siba_sprom_get_rssismc2g(sc->sc_dev);
10930204922Sweongyo		plp->plp_rssigs = siba_sprom_get_rssisav2g(sc->sc_dev);
10931203945Sweongyo		return;
10932203945Sweongyo	}
10933203945Sweongyo
10934204922Sweongyo	plp->plp_txisoband_l = siba_sprom_get_tri5gl(sc->sc_dev);
10935204922Sweongyo	plp->plp_txisoband_m = siba_sprom_get_tri5g(sc->sc_dev);
10936204922Sweongyo	plp->plp_txisoband_h = siba_sprom_get_tri5gh(sc->sc_dev);
10937204922Sweongyo	plp->plp_bxarch = siba_sprom_get_bxa5g(sc->sc_dev);
10938204922Sweongyo	plp->plp_rxpwroffset = siba_sprom_get_rxpo5g(sc->sc_dev);
10939204922Sweongyo	plp->plp_rssivf = siba_sprom_get_rssismf5g(sc->sc_dev);
10940204922Sweongyo	plp->plp_rssivc = siba_sprom_get_rssismc5g(sc->sc_dev);
10941204922Sweongyo	plp->plp_rssigs = siba_sprom_get_rssisav5g(sc->sc_dev);
10942203945Sweongyo}
10943203945Sweongyo
10944203945Sweongyostatic void
10945203945Sweongyobwn_phy_lp_bbinit(struct bwn_mac *mac)
10946203945Sweongyo{
10947203945Sweongyo
10948203945Sweongyo	bwn_phy_lp_tblinit(mac);
10949203945Sweongyo	if (mac->mac_phy.rev >= 2)
10950203945Sweongyo		bwn_phy_lp_bbinit_r2(mac);
10951203945Sweongyo	else
10952203945Sweongyo		bwn_phy_lp_bbinit_r01(mac);
10953203945Sweongyo}
10954203945Sweongyo
10955203945Sweongyostatic void
10956203945Sweongyobwn_phy_lp_txpctl_init(struct bwn_mac *mac)
10957203945Sweongyo{
10958203945Sweongyo	struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 };
10959203945Sweongyo	struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 };
10960203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10961287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
10962203945Sweongyo
10963203945Sweongyo	bwn_phy_lp_set_txgain(mac,
10964203945Sweongyo	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz);
10965203945Sweongyo	bwn_phy_lp_set_bbmult(mac, 150);
10966203945Sweongyo}
10967203945Sweongyo
10968203945Sweongyostatic void
10969203945Sweongyobwn_phy_lp_calib(struct bwn_mac *mac)
10970203945Sweongyo{
10971203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
10972203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
10973287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
10974203945Sweongyo	const struct bwn_rxcompco *rc = NULL;
10975203945Sweongyo	struct bwn_txgain ogain;
10976203945Sweongyo	int i, omode, oafeovr, orf, obbmult;
10977203945Sweongyo	uint8_t mode, fc = 0;
10978203945Sweongyo
10979203945Sweongyo	if (plp->plp_chanfullcal != plp->plp_chan) {
10980203945Sweongyo		plp->plp_chanfullcal = plp->plp_chan;
10981203945Sweongyo		fc = 1;
10982203945Sweongyo	}
10983203945Sweongyo
10984203945Sweongyo	bwn_mac_suspend(mac);
10985203945Sweongyo
10986203945Sweongyo	/* BlueTooth Coexistance Override */
10987203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_CTL, 0x3);
10988203945Sweongyo	BWN_WRITE_2(mac, BWN_BTCOEX_TXCTL, 0xff);
10989203945Sweongyo
10990203945Sweongyo	if (mac->mac_phy.rev >= 2)
10991203945Sweongyo		bwn_phy_lp_digflt_save(mac);
10992203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
10993203945Sweongyo	mode = plp->plp_txpctlmode;
10994203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
10995203945Sweongyo	if (mac->mac_phy.rev == 0 && mode != BWN_PHYLP_TXPCTL_OFF)
10996203945Sweongyo		bwn_phy_lp_bugfix(mac);
10997203945Sweongyo	if (mac->mac_phy.rev >= 2 && fc == 1) {
10998203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
10999203945Sweongyo		omode = plp->plp_txpctlmode;
11000203945Sweongyo		oafeovr = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40;
11001203945Sweongyo		if (oafeovr)
11002203945Sweongyo			ogain = bwn_phy_lp_get_txgain(mac);
11003203945Sweongyo		orf = BWN_PHY_READ(mac, BWN_PHY_RF_PWR_OVERRIDE) & 0xff;
11004203945Sweongyo		obbmult = bwn_phy_lp_get_bbmult(mac);
11005203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11006203945Sweongyo		if (oafeovr)
11007203945Sweongyo			bwn_phy_lp_set_txgain(mac, &ogain);
11008203945Sweongyo		bwn_phy_lp_set_bbmult(mac, obbmult);
11009203945Sweongyo		bwn_phy_lp_set_txpctlmode(mac, omode);
11010203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00, orf);
11011203945Sweongyo	}
11012203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11013203945Sweongyo	if (mac->mac_phy.rev >= 2)
11014203945Sweongyo		bwn_phy_lp_digflt_restore(mac);
11015203945Sweongyo
11016203945Sweongyo	/* do RX IQ Calculation; assumes that noise is true. */
11017204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x5354) {
11018203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_5354); i++) {
11019203945Sweongyo			if (bwn_rxcompco_5354[i].rc_chan == plp->plp_chan)
11020203945Sweongyo				rc = &bwn_rxcompco_5354[i];
11021203945Sweongyo		}
11022203945Sweongyo	} else if (mac->mac_phy.rev >= 2)
11023203945Sweongyo		rc = &bwn_rxcompco_r2;
11024203945Sweongyo	else {
11025203945Sweongyo		for (i = 0; i < N(bwn_rxcompco_r12); i++) {
11026203945Sweongyo			if (bwn_rxcompco_r12[i].rc_chan == plp->plp_chan)
11027203945Sweongyo				rc = &bwn_rxcompco_r12[i];
11028203945Sweongyo		}
11029203945Sweongyo	}
11030203945Sweongyo	if (rc == NULL)
11031203945Sweongyo		goto fail;
11032203945Sweongyo
11033203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, rc->rc_c1);
11034203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, rc->rc_c0 << 8);
11035203945Sweongyo
11036203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1 /* TX */, 0 /* RX */);
11037203945Sweongyo
11038203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11039203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
11040203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7, 0);
11041203945Sweongyo	} else {
11042203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
11043203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf, 0);
11044203945Sweongyo	}
11045203945Sweongyo
11046203945Sweongyo	bwn_phy_lp_set_rxgain(mac, 0x2d5d);
11047203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11048203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
11049203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
11050203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
11051203945Sweongyo	bwn_phy_lp_set_deaf(mac, 0);
11052203945Sweongyo	/* XXX no checking return value? */
11053203945Sweongyo	(void)bwn_phy_lp_calc_rx_iq_comp(mac, 0xfff0);
11054203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 0);
11055203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffc);
11056203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfff7);
11057203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffdf);
11058203945Sweongyo
11059203945Sweongyo	/* disable RX GAIN override. */
11060203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffe);
11061203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffef);
11062203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffbf);
11063203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11064203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11065203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11066203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfbff);
11067203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xe5), 0xfff7);
11068203945Sweongyo		}
11069203945Sweongyo	} else {
11070203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfdff);
11071203945Sweongyo	}
11072203945Sweongyo
11073203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
11074203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xf7ff);
11075203945Sweongyofail:
11076203945Sweongyo	bwn_mac_enable(mac);
11077203945Sweongyo}
11078203945Sweongyo
11079203945Sweongyostatic void
11080203945Sweongyobwn_phy_lp_switch_analog(struct bwn_mac *mac, int on)
11081203945Sweongyo{
11082203945Sweongyo
11083204922Sweongyo	if (on) {
11084204922Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfff8);
11085204922Sweongyo		return;
11086204922Sweongyo	}
11087203945Sweongyo
11088204922Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVRVAL, 0x0007);
11089204922Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x0007);
11090203945Sweongyo}
11091203945Sweongyo
11092203945Sweongyostatic int
11093203945Sweongyobwn_phy_lp_b2063_switch_channel(struct bwn_mac *mac, uint8_t chan)
11094203945Sweongyo{
11095203945Sweongyo	static const struct bwn_b206x_chan *bc = NULL;
11096204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11097203945Sweongyo	uint32_t count, freqref, freqvco, freqxtal, val[3], timeout, timeoutref,
11098203945Sweongyo	    tmp[6];
11099203945Sweongyo	uint16_t old, scale, tmp16;
11100203945Sweongyo	int i, div;
11101203945Sweongyo
11102203945Sweongyo	for (i = 0; i < N(bwn_b2063_chantable); i++) {
11103203945Sweongyo		if (bwn_b2063_chantable[i].bc_chan == chan) {
11104203945Sweongyo			bc = &bwn_b2063_chantable[i];
11105203945Sweongyo			break;
11106203945Sweongyo		}
11107203945Sweongyo	}
11108203945Sweongyo	if (bc == NULL)
11109203945Sweongyo		return (EINVAL);
11110203945Sweongyo
11111203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_VCOBUF1, bc->bc_data[0]);
11112203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_MIXER2, bc->bc_data[1]);
11113203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_BUF2, bc->bc_data[2]);
11114203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_RCCR1, bc->bc_data[3]);
11115203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_1ST3, bc->bc_data[4]);
11116203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND1, bc->bc_data[5]);
11117203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND4, bc->bc_data[6]);
11118203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND7, bc->bc_data[7]);
11119203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_A_RX_PS6, bc->bc_data[8]);
11120203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL2, bc->bc_data[9]);
11121203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL5, bc->bc_data[10]);
11122203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_CTL11, bc->bc_data[11]);
11123203945Sweongyo
11124203945Sweongyo	old = BWN_RF_READ(mac, BWN_B2063_COM15);
11125203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM15, 0x1e);
11126203945Sweongyo
11127204922Sweongyo	freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
11128203945Sweongyo	freqvco = bc->bc_freq << ((bc->bc_freq > 4000) ? 1 : 2);
11129203945Sweongyo	freqref = freqxtal * 3;
11130203945Sweongyo	div = (freqxtal <= 26000000 ? 1 : 2);
11131203945Sweongyo	timeout = ((((8 * freqxtal) / (div * 5000000)) + 1) >> 1) - 1;
11132203945Sweongyo	timeoutref = ((((8 * freqxtal) / (div * (timeout + 1))) +
11133203945Sweongyo		999999) / 1000000) + 1;
11134203945Sweongyo
11135203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB3, 0x2);
11136203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB6,
11137203945Sweongyo	    0xfff8, timeout >> 2);
11138203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11139203945Sweongyo	    0xff9f,timeout << 5);
11140203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB5, timeoutref);
11141203945Sweongyo
11142203945Sweongyo	val[0] = bwn_phy_lp_roundup(freqxtal, 1000000, 16);
11143203945Sweongyo	val[1] = bwn_phy_lp_roundup(freqxtal, 1000000 * div, 16);
11144203945Sweongyo	val[2] = bwn_phy_lp_roundup(freqvco, 3, 16);
11145203945Sweongyo
11146203945Sweongyo	count = (bwn_phy_lp_roundup(val[2], val[1] + 16, 16) * (timeout + 1) *
11147203945Sweongyo	    (timeoutref + 1)) - 1;
11148203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
11149203945Sweongyo	    0xf0, count >> 8);
11150203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB8, count & 0xff);
11151203945Sweongyo
11152203945Sweongyo	tmp[0] = ((val[2] * 62500) / freqref) << 4;
11153203945Sweongyo	tmp[1] = ((val[2] * 62500) % freqref) << 4;
11154203945Sweongyo	while (tmp[1] >= freqref) {
11155203945Sweongyo		tmp[0]++;
11156203945Sweongyo		tmp[1] -= freqref;
11157203945Sweongyo	}
11158203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG1, 0xffe0, tmp[0] >> 4);
11159203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfe0f, tmp[0] << 4);
11160203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfff0, tmp[0] >> 16);
11161203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG3, (tmp[1] >> 8) & 0xff);
11162203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG4, tmp[1] & 0xff);
11163203945Sweongyo
11164203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF1, 0xb9);
11165203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF2, 0x88);
11166203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF3, 0x28);
11167203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF4, 0x63);
11168203945Sweongyo
11169203945Sweongyo	tmp[2] = ((41 * (val[2] - 3000)) /1200) + 27;
11170203945Sweongyo	tmp[3] = bwn_phy_lp_roundup(132000 * tmp[0], 8451, 16);
11171203945Sweongyo
11172203945Sweongyo	if ((tmp[3] + tmp[2] - 1) / tmp[2] > 60) {
11173203945Sweongyo		scale = 1;
11174203945Sweongyo		tmp[4] = ((tmp[3] + tmp[2]) / (tmp[2] << 1)) - 8;
11175203945Sweongyo	} else {
11176203945Sweongyo		scale = 0;
11177203945Sweongyo		tmp[4] = ((tmp[3] + (tmp[2] >> 1)) / tmp[2]) - 8;
11178203945Sweongyo	}
11179203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffc0, tmp[4]);
11180203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffbf, scale << 6);
11181203945Sweongyo
11182203945Sweongyo	tmp[5] = bwn_phy_lp_roundup(100 * val[0], val[2], 16) * (tmp[4] * 8) *
11183203945Sweongyo	    (scale + 1);
11184203945Sweongyo	if (tmp[5] > 150)
11185203945Sweongyo		tmp[5] = 0;
11186203945Sweongyo
11187203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffe0, tmp[5]);
11188203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffdf, scale << 5);
11189203945Sweongyo
11190203945Sweongyo	BWN_RF_SETMASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfffb, 0x4);
11191203945Sweongyo	if (freqxtal > 26000000)
11192203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_XTAL_12, 0x2);
11193203945Sweongyo	else
11194203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfd);
11195203945Sweongyo
11196203945Sweongyo	if (val[0] == 45)
11197203945Sweongyo		BWN_RF_SET(mac, BWN_B2063_JTAG_VCO1, 0x2);
11198203945Sweongyo	else
11199203945Sweongyo		BWN_RF_MASK(mac, BWN_B2063_JTAG_VCO1, 0xfd);
11200203945Sweongyo
11201203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP2, 0x3);
11202203945Sweongyo	DELAY(1);
11203203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP2, 0xfffc);
11204203945Sweongyo
11205203945Sweongyo	/* VCO Calibration */
11206203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, ~0x40);
11207203945Sweongyo	tmp16 = BWN_RF_READ(mac, BWN_B2063_JTAG_CALNRST) & 0xf8;
11208203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16);
11209203945Sweongyo	DELAY(1);
11210203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x4);
11211203945Sweongyo	DELAY(1);
11212203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x6);
11213203945Sweongyo	DELAY(1);
11214203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x7);
11215203945Sweongyo	DELAY(300);
11216203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_PLL_SP1, 0x40);
11217203945Sweongyo
11218203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_COM15, old);
11219203945Sweongyo	return (0);
11220203945Sweongyo}
11221203945Sweongyo
11222203945Sweongyostatic int
11223203945Sweongyobwn_phy_lp_b2062_switch_channel(struct bwn_mac *mac, uint8_t chan)
11224203945Sweongyo{
11225204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11226203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11227203945Sweongyo	const struct bwn_b206x_chan *bc = NULL;
11228204922Sweongyo	uint32_t freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
11229203945Sweongyo	uint32_t tmp[9];
11230203945Sweongyo	int i;
11231203945Sweongyo
11232203945Sweongyo	for (i = 0; i < N(bwn_b2062_chantable); i++) {
11233203945Sweongyo		if (bwn_b2062_chantable[i].bc_chan == chan) {
11234203945Sweongyo			bc = &bwn_b2062_chantable[i];
11235203945Sweongyo			break;
11236203945Sweongyo		}
11237203945Sweongyo	}
11238203945Sweongyo
11239203945Sweongyo	if (bc == NULL)
11240203945Sweongyo		return (EINVAL);
11241203945Sweongyo
11242203945Sweongyo	BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL14, 0x04);
11243203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE0, bc->bc_data[0]);
11244203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE2, bc->bc_data[1]);
11245203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE3, bc->bc_data[2]);
11246203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_TUNE, bc->bc_data[3]);
11247203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_LGENG_CTL1, bc->bc_data[4]);
11248203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL5, bc->bc_data[5]);
11249203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL6, bc->bc_data[6]);
11250203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PGA, bc->bc_data[7]);
11251203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TX_PAD, bc->bc_data[8]);
11252203945Sweongyo
11253203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xcc);
11254203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0x07);
11255203945Sweongyo	bwn_phy_lp_b2062_reset_pllbias(mac);
11256203945Sweongyo	tmp[0] = freqxtal / 1000;
11257203945Sweongyo	tmp[1] = plp->plp_div * 1000;
11258203945Sweongyo	tmp[2] = tmp[1] * ieee80211_ieee2mhz(chan, 0);
11259203945Sweongyo	if (ieee80211_ieee2mhz(chan, 0) < 4000)
11260203945Sweongyo		tmp[2] *= 2;
11261203945Sweongyo	tmp[3] = 48 * tmp[0];
11262203945Sweongyo	tmp[5] = tmp[2] / tmp[3];
11263203945Sweongyo	tmp[6] = tmp[2] % tmp[3];
11264203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL26, tmp[5]);
11265203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11266203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11267203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11268203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL27, tmp[5]);
11269203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11270203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11271203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11272203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL28, tmp[5]);
11273203945Sweongyo	tmp[4] = tmp[6] * 0x100;
11274203945Sweongyo	tmp[5] = tmp[4] / tmp[3];
11275203945Sweongyo	tmp[6] = tmp[4] % tmp[3];
11276203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL29,
11277203945Sweongyo	    tmp[5] + ((2 * tmp[6]) / tmp[3]));
11278203945Sweongyo	tmp[7] = BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL19);
11279203945Sweongyo	tmp[8] = ((2 * tmp[2] * (tmp[7] + 1)) + (3 * tmp[0])) / (6 * tmp[0]);
11280203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL23, (tmp[8] >> 8) + 16);
11281203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL24, tmp[8] & 0xff);
11282203945Sweongyo
11283203945Sweongyo	bwn_phy_lp_b2062_vco_calib(mac);
11284203945Sweongyo	if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11285203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xfc);
11286203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0);
11287203945Sweongyo		bwn_phy_lp_b2062_reset_pllbias(mac);
11288203945Sweongyo		bwn_phy_lp_b2062_vco_calib(mac);
11289203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
11290203945Sweongyo			BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11291203945Sweongyo			return (EIO);
11292203945Sweongyo		}
11293203945Sweongyo	}
11294203945Sweongyo	BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
11295203945Sweongyo	return (0);
11296203945Sweongyo}
11297203945Sweongyo
11298203945Sweongyostatic void
11299203945Sweongyobwn_phy_lp_set_anafilter(struct bwn_mac *mac, uint8_t channel)
11300203945Sweongyo{
11301203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11302203945Sweongyo	uint16_t tmp = (channel == 14);
11303203945Sweongyo
11304203945Sweongyo	if (mac->mac_phy.rev < 2) {
11305203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xfcff, tmp << 9);
11306203945Sweongyo		if ((mac->mac_phy.rev == 1) && (plp->plp_rccap))
11307203945Sweongyo			bwn_phy_lp_set_rccap(mac);
11308203945Sweongyo		return;
11309203945Sweongyo	}
11310203945Sweongyo
11311203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, 0x3f);
11312203945Sweongyo}
11313203945Sweongyo
11314203945Sweongyostatic void
11315203945Sweongyobwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq)
11316203945Sweongyo{
11317203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11318203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11319287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
11320203945Sweongyo	uint16_t iso, tmp[3];
11321203945Sweongyo
11322203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
11323203945Sweongyo
11324203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
11325203945Sweongyo		iso = plp->plp_txisoband_m;
11326203945Sweongyo	else if (freq <= 5320)
11327203945Sweongyo		iso = plp->plp_txisoband_l;
11328203945Sweongyo	else if (freq <= 5700)
11329203945Sweongyo		iso = plp->plp_txisoband_m;
11330203945Sweongyo	else
11331203945Sweongyo		iso = plp->plp_txisoband_h;
11332203945Sweongyo
11333203945Sweongyo	tmp[0] = ((iso - 26) / 12) << 12;
11334203945Sweongyo	tmp[1] = tmp[0] + 0x1000;
11335203945Sweongyo	tmp[2] = tmp[0] + 0x2000;
11336203945Sweongyo
11337203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), 3, tmp);
11338203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), 3, tmp);
11339203945Sweongyo}
11340203945Sweongyo
11341203945Sweongyostatic void
11342203945Sweongyobwn_phy_lp_digflt_save(struct bwn_mac *mac)
11343203945Sweongyo{
11344203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11345203945Sweongyo	int i;
11346203945Sweongyo	static const uint16_t addr[] = {
11347203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11348203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11349203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11350203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11351203945Sweongyo		BWN_PHY_OFDM(0xcf),
11352203945Sweongyo	};
11353203945Sweongyo	static const uint16_t val[] = {
11354203945Sweongyo		0xde5e, 0xe832, 0xe331, 0x4d26,
11355203945Sweongyo		0x0026, 0x1420, 0x0020, 0xfe08,
11356203945Sweongyo		0x0008,
11357203945Sweongyo	};
11358203945Sweongyo
11359203945Sweongyo	for (i = 0; i < N(addr); i++) {
11360203945Sweongyo		plp->plp_digfilt[i] = BWN_PHY_READ(mac, addr[i]);
11361203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], val[i]);
11362203945Sweongyo	}
11363203945Sweongyo}
11364203945Sweongyo
11365203945Sweongyostatic void
11366203945Sweongyobwn_phy_lp_get_txpctlmode(struct bwn_mac *mac)
11367203945Sweongyo{
11368203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11369203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11370203945Sweongyo	uint16_t ctl;
11371203945Sweongyo
11372203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_TX_PWR_CTL_CMD);
11373203945Sweongyo	switch (ctl & BWN_PHY_TX_PWR_CTL_CMD_MODE) {
11374203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF:
11375203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_OFF;
11376203945Sweongyo		break;
11377203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_SW:
11378203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_SW;
11379203945Sweongyo		break;
11380203945Sweongyo	case BWN_PHY_TX_PWR_CTL_CMD_MODE_HW:
11381203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_HW;
11382203945Sweongyo		break;
11383203945Sweongyo	default:
11384203945Sweongyo		plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_UNKNOWN;
11385203945Sweongyo		device_printf(sc->sc_dev, "unknown command mode\n");
11386203945Sweongyo		break;
11387203945Sweongyo	}
11388203945Sweongyo}
11389203945Sweongyo
11390203945Sweongyostatic void
11391203945Sweongyobwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
11392203945Sweongyo{
11393203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11394203945Sweongyo	uint16_t ctl;
11395203945Sweongyo	uint8_t old;
11396203945Sweongyo
11397203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11398203945Sweongyo	old = plp->plp_txpctlmode;
11399203945Sweongyo	if (old == mode)
11400203945Sweongyo		return;
11401203945Sweongyo	plp->plp_txpctlmode = mode;
11402203945Sweongyo
11403203945Sweongyo	if (old != BWN_PHYLP_TXPCTL_ON_HW && mode == BWN_PHYLP_TXPCTL_ON_HW) {
11404203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD, 0xff80,
11405203945Sweongyo		    plp->plp_tssiidx);
11406203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_NNUM,
11407203945Sweongyo		    0x8fff, ((uint16_t)plp->plp_tssinpt << 16));
11408203945Sweongyo
11409203945Sweongyo		/* disable TX GAIN override */
11410203945Sweongyo		if (mac->mac_phy.rev < 2)
11411203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
11412203945Sweongyo		else {
11413203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xff7f);
11414203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xbfff);
11415203945Sweongyo		}
11416203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xffbf);
11417203945Sweongyo
11418203945Sweongyo		plp->plp_txpwridx = -1;
11419203945Sweongyo	}
11420203945Sweongyo	if (mac->mac_phy.rev >= 2) {
11421203945Sweongyo		if (mode == BWN_PHYLP_TXPCTL_ON_HW)
11422203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xd0), 0x2);
11423203945Sweongyo		else
11424203945Sweongyo			BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xd0), 0xfffd);
11425203945Sweongyo	}
11426203945Sweongyo
11427203945Sweongyo	/* writes TX Power Control mode */
11428203945Sweongyo	switch (plp->plp_txpctlmode) {
11429203945Sweongyo	case BWN_PHYLP_TXPCTL_OFF:
11430203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF;
11431203945Sweongyo		break;
11432203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_HW:
11433203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_HW;
11434203945Sweongyo		break;
11435203945Sweongyo	case BWN_PHYLP_TXPCTL_ON_SW:
11436203945Sweongyo		ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
11437203945Sweongyo		break;
11438203945Sweongyo	default:
11439204242Simp		ctl = 0;
11440203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
11441203945Sweongyo	}
11442203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
11443203945Sweongyo	    (uint16_t)~BWN_PHY_TX_PWR_CTL_CMD_MODE, ctl);
11444203945Sweongyo}
11445203945Sweongyo
11446203945Sweongyostatic void
11447203945Sweongyobwn_phy_lp_bugfix(struct bwn_mac *mac)
11448203945Sweongyo{
11449203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11450203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11451203945Sweongyo	const unsigned int size = 256;
11452203945Sweongyo	struct bwn_txgain tg;
11453203945Sweongyo	uint32_t rxcomp, txgain, coeff, rfpwr, *tabs;
11454203945Sweongyo	uint16_t tssinpt, tssiidx, value[2];
11455203945Sweongyo	uint8_t mode;
11456203945Sweongyo	int8_t txpwridx;
11457203945Sweongyo
11458203945Sweongyo	tabs = (uint32_t *)malloc(sizeof(uint32_t) * size, M_DEVBUF,
11459203945Sweongyo	    M_NOWAIT | M_ZERO);
11460203945Sweongyo	if (tabs == NULL) {
11461203945Sweongyo		device_printf(sc->sc_dev, "failed to allocate buffer.\n");
11462203945Sweongyo		return;
11463203945Sweongyo	}
11464203945Sweongyo
11465203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
11466203945Sweongyo	mode = plp->plp_txpctlmode;
11467203945Sweongyo	txpwridx = plp->plp_txpwridx;
11468203945Sweongyo	tssinpt = plp->plp_tssinpt;
11469203945Sweongyo	tssiidx = plp->plp_tssiidx;
11470203945Sweongyo
11471203945Sweongyo	bwn_tab_read_multi(mac,
11472203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11473203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11474203945Sweongyo
11475203945Sweongyo	bwn_phy_lp_tblinit(mac);
11476203945Sweongyo	bwn_phy_lp_bbinit(mac);
11477203945Sweongyo	bwn_phy_lp_txpctl_init(mac);
11478203945Sweongyo	bwn_phy_lp_rf_onoff(mac, 1);
11479203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
11480203945Sweongyo
11481203945Sweongyo	bwn_tab_write_multi(mac,
11482203945Sweongyo	    (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
11483203945Sweongyo	    BWN_TAB_4(7, 0x140), size, tabs);
11484203945Sweongyo
11485203945Sweongyo	BWN_WRITE_2(mac, BWN_CHANNEL, plp->plp_chan);
11486203945Sweongyo	plp->plp_tssinpt = tssinpt;
11487203945Sweongyo	plp->plp_tssiidx = tssiidx;
11488203945Sweongyo	bwn_phy_lp_set_anafilter(mac, plp->plp_chan);
11489203945Sweongyo	if (txpwridx != -1) {
11490203945Sweongyo		/* set TX power by index */
11491203945Sweongyo		plp->plp_txpwridx = txpwridx;
11492203945Sweongyo		bwn_phy_lp_get_txpctlmode(mac);
11493203945Sweongyo		if (plp->plp_txpctlmode != BWN_PHYLP_TXPCTL_OFF)
11494203945Sweongyo			bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_ON_SW);
11495203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11496203945Sweongyo			rxcomp = bwn_tab_read(mac,
11497203945Sweongyo			    BWN_TAB_4(7, txpwridx + 320));
11498203945Sweongyo			txgain = bwn_tab_read(mac,
11499203945Sweongyo			    BWN_TAB_4(7, txpwridx + 192));
11500203945Sweongyo			tg.tg_pad = (txgain >> 16) & 0xff;
11501203945Sweongyo			tg.tg_gm = txgain & 0xff;
11502203945Sweongyo			tg.tg_pga = (txgain >> 8) & 0xff;
11503203945Sweongyo			tg.tg_dac = (rxcomp >> 28) & 0xff;
11504203945Sweongyo			bwn_phy_lp_set_txgain(mac, &tg);
11505203945Sweongyo		} else {
11506203945Sweongyo			rxcomp = bwn_tab_read(mac,
11507203945Sweongyo			    BWN_TAB_4(10, txpwridx + 320));
11508203945Sweongyo			txgain = bwn_tab_read(mac,
11509203945Sweongyo			    BWN_TAB_4(10, txpwridx + 192));
11510203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
11511203945Sweongyo			    0xf800, (txgain >> 4) & 0x7fff);
11512203945Sweongyo			bwn_phy_lp_set_txgain_dac(mac, txgain & 0x7);
11513203945Sweongyo			bwn_phy_lp_set_txgain_pa(mac, (txgain >> 24) & 0x7f);
11514203945Sweongyo		}
11515203945Sweongyo		bwn_phy_lp_set_bbmult(mac, (rxcomp >> 20) & 0xff);
11516203945Sweongyo
11517203945Sweongyo		/* set TX IQCC */
11518203945Sweongyo		value[0] = (rxcomp >> 10) & 0x3ff;
11519203945Sweongyo		value[1] = rxcomp & 0x3ff;
11520203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(0, 80), 2, value);
11521203945Sweongyo
11522203945Sweongyo		coeff = bwn_tab_read(mac,
11523203945Sweongyo		    (mac->mac_phy.rev >= 2) ? BWN_TAB_4(7, txpwridx + 448) :
11524203945Sweongyo		    BWN_TAB_4(10, txpwridx + 448));
11525203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0, 85), coeff & 0xffff);
11526203945Sweongyo		if (mac->mac_phy.rev >= 2) {
11527203945Sweongyo			rfpwr = bwn_tab_read(mac,
11528203945Sweongyo			    BWN_TAB_4(7, txpwridx + 576));
11529203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00,
11530203945Sweongyo			    rfpwr & 0xffff);
11531203945Sweongyo		}
11532203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
11533203945Sweongyo	}
11534203945Sweongyo	if (plp->plp_rccap)
11535203945Sweongyo		bwn_phy_lp_set_rccap(mac);
11536203945Sweongyo	bwn_phy_lp_set_antenna(mac, plp->plp_antenna);
11537203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, mode);
11538203945Sweongyo	free(tabs, M_DEVBUF);
11539203945Sweongyo}
11540203945Sweongyo
11541203945Sweongyostatic void
11542203945Sweongyobwn_phy_lp_digflt_restore(struct bwn_mac *mac)
11543203945Sweongyo{
11544203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11545203945Sweongyo	int i;
11546203945Sweongyo	static const uint16_t addr[] = {
11547203945Sweongyo		BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
11548203945Sweongyo		BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
11549203945Sweongyo		BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
11550203945Sweongyo		BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
11551203945Sweongyo		BWN_PHY_OFDM(0xcf),
11552203945Sweongyo	};
11553203945Sweongyo
11554203945Sweongyo	for (i = 0; i < N(addr); i++)
11555203945Sweongyo		BWN_PHY_WRITE(mac, addr[i], plp->plp_digfilt[i]);
11556203945Sweongyo}
11557203945Sweongyo
11558203945Sweongyostatic void
11559203945Sweongyobwn_phy_lp_tblinit(struct bwn_mac *mac)
11560203945Sweongyo{
11561203945Sweongyo	uint32_t freq = ieee80211_ieee2mhz(bwn_phy_lp_get_default_chan(mac), 0);
11562203945Sweongyo
11563203945Sweongyo	if (mac->mac_phy.rev < 2) {
11564203945Sweongyo		bwn_phy_lp_tblinit_r01(mac);
11565203945Sweongyo		bwn_phy_lp_tblinit_txgain(mac);
11566203945Sweongyo		bwn_phy_lp_set_gaintbl(mac, freq);
11567203945Sweongyo		return;
11568203945Sweongyo	}
11569203945Sweongyo
11570203945Sweongyo	bwn_phy_lp_tblinit_r2(mac);
11571203945Sweongyo	bwn_phy_lp_tblinit_txgain(mac);
11572203945Sweongyo}
11573203945Sweongyo
11574203945Sweongyostruct bwn_wpair {
11575203945Sweongyo	uint16_t		reg;
11576203945Sweongyo	uint16_t		value;
11577203945Sweongyo};
11578203945Sweongyo
11579203945Sweongyostruct bwn_smpair {
11580203945Sweongyo	uint16_t		offset;
11581203945Sweongyo	uint16_t		mask;
11582203945Sweongyo	uint16_t		set;
11583203945Sweongyo};
11584203945Sweongyo
11585203945Sweongyostatic void
11586203945Sweongyobwn_phy_lp_bbinit_r2(struct bwn_mac *mac)
11587203945Sweongyo{
11588203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11589203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11590287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
11591203945Sweongyo	static const struct bwn_wpair v1[] = {
11592203945Sweongyo		{ BWN_PHY_AFE_DAC_CTL, 0x50 },
11593203945Sweongyo		{ BWN_PHY_AFE_CTL, 0x8800 },
11594203945Sweongyo		{ BWN_PHY_AFE_CTL_OVR, 0 },
11595203945Sweongyo		{ BWN_PHY_AFE_CTL_OVRVAL, 0 },
11596203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_0, 0 },
11597203945Sweongyo		{ BWN_PHY_RF_OVERRIDE_2, 0 },
11598203945Sweongyo		{ BWN_PHY_OFDM(0xf9), 0 },
11599203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0 }
11600203945Sweongyo	};
11601203945Sweongyo	static const struct bwn_smpair v2[] = {
11602203945Sweongyo		{ BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0xb4 },
11603203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xf8ff, 0x200 },
11604203945Sweongyo		{ BWN_PHY_DCOFFSETTRANSIENT, 0xff00, 0x7f },
11605203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xff0f, 0x40 },
11606203945Sweongyo		{ BWN_PHY_PREAMBLECONFIRMTO, 0xff00, 0x2 }
11607203945Sweongyo	};
11608203945Sweongyo	static const struct bwn_smpair v3[] = {
11609203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xffe0, 0x1f },
11610203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11611203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0xff00, 0x19 },
11612203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0x03ff, 0x3c00 },
11613203945Sweongyo		{ BWN_PHY_OFDM(0xfe), 0xfc1f, 0x3e0 },
11614203945Sweongyo		{ BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
11615203945Sweongyo		{ BWN_PHY_OFDM(0x100), 0x00ff, 0x1900 },
11616203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800 },
11617203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x12 },
11618203945Sweongyo		{ BWN_PHY_GAINMISMATCH, 0x0fff, 0x9000 },
11619204922Sweongyo
11620203945Sweongyo	};
11621203945Sweongyo	int i;
11622203945Sweongyo
11623203945Sweongyo	for (i = 0; i < N(v1); i++)
11624203945Sweongyo		BWN_PHY_WRITE(mac, v1[i].reg, v1[i].value);
11625203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x10);
11626203945Sweongyo	for (i = 0; i < N(v2); i++)
11627203945Sweongyo		BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask, v2[i].set);
11628203945Sweongyo
11629203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x4000);
11630203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x2000);
11631203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_OFDM(0x10a), 0x1);
11632204922Sweongyo	if (siba_get_pci_revid(sc->sc_dev) >= 0x18) {
11633203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(17, 65), 0xec);
11634203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x14);
11635203945Sweongyo	} else {
11636203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x10);
11637203945Sweongyo	}
11638203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0xff00, 0xf4);
11639203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0x00ff, 0xf100);
11640203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_CLIPTHRESH, 0x48);
11641203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0xff00, 0x46);
11642203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe4), 0xff00, 0x10);
11643203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_PWR_THRESH1, 0xfff0, 0x9);
11644203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_GAINDIRECTMISMATCH, ~0xf);
11645203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5500);
11646203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0xa0);
11647203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_GAINDIRECTMISMATCH, 0xe0ff, 0x300);
11648203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2a00);
11649204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11650204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11651203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11652203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xa);
11653203945Sweongyo	} else {
11654203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x1e00);
11655203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xd);
11656203945Sweongyo	}
11657203945Sweongyo	for (i = 0; i < N(v3); i++)
11658203945Sweongyo		BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask, v3[i].set);
11659204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11660204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11661203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x14), 0);
11662203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(0x08, 0x12), 0x40);
11663203945Sweongyo	}
11664203945Sweongyo
11665203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11666203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x40);
11667203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0xb00);
11668203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x6);
11669203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0x9d00);
11670203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0xff00, 0xa1);
11671203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11672203945Sweongyo	} else
11673203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x40);
11674203945Sweongyo
11675203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0xff00, 0xb3);
11676203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00);
11677203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB, 0xff00, plp->plp_rxpwroffset);
11678203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RESET_CTL, 0x44);
11679203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RESET_CTL, 0x80);
11680203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, 0xa954);
11681203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_1,
11682203945Sweongyo	    0x2000 | ((uint16_t)plp->plp_rssigs << 10) |
11683203945Sweongyo	    ((uint16_t)plp->plp_rssivc << 4) | plp->plp_rssivf);
11684203945Sweongyo
11685204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
11686204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
11687203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_AFE_ADC_CTL_0, 0x1c);
11688203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_CTL, 0x00ff, 0x8800);
11689203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_1, 0xfc3c, 0x0400);
11690203945Sweongyo	}
11691203945Sweongyo
11692203945Sweongyo	bwn_phy_lp_digflt_save(mac);
11693203945Sweongyo}
11694203945Sweongyo
11695203945Sweongyostatic void
11696203945Sweongyobwn_phy_lp_bbinit_r01(struct bwn_mac *mac)
11697203945Sweongyo{
11698203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11699203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11700287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
11701203945Sweongyo	static const struct bwn_smpair v1[] = {
11702203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 },
11703203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 },
11704203945Sweongyo		{ BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x3c00 },
11705203945Sweongyo		{ BWN_PHY_GAINDIRECTMISMATCH, 0xfff0, 0x0005 },
11706203945Sweongyo		{ BWN_PHY_GAIN_MISMATCH_LIMIT, 0xffc0, 0x001a },
11707203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0xff00, 0x00b3 },
11708203945Sweongyo		{ BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00 }
11709203945Sweongyo	};
11710203945Sweongyo	static const struct bwn_smpair v2[] = {
11711203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11712203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0x3f00, 0x0900 },
11713203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11714203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11715203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x000a },
11716203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0400 },
11717203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x000a },
11718203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0b00 },
11719203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xffc0, 0x000a },
11720203945Sweongyo		{ BWN_PHY_TR_LOOKUP_5, 0xc0ff, 0x0900 },
11721203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xffc0, 0x000a },
11722203945Sweongyo		{ BWN_PHY_TR_LOOKUP_6, 0xc0ff, 0x0b00 },
11723203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xffc0, 0x000a },
11724203945Sweongyo		{ BWN_PHY_TR_LOOKUP_7, 0xc0ff, 0x0900 },
11725203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xffc0, 0x000a },
11726203945Sweongyo		{ BWN_PHY_TR_LOOKUP_8, 0xc0ff, 0x0b00 }
11727203945Sweongyo	};
11728203945Sweongyo	static const struct bwn_smpair v3[] = {
11729203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0001 },
11730203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0400 },
11731203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0001 },
11732203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0500 },
11733203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11734203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0800 },
11735203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11736203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0a00 }
11737203945Sweongyo	};
11738203945Sweongyo	static const struct bwn_smpair v4[] = {
11739203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0004 },
11740203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0800 },
11741203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0004 },
11742203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0c00 },
11743203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
11744203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0100 },
11745203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
11746203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0300 }
11747203945Sweongyo	};
11748203945Sweongyo	static const struct bwn_smpair v5[] = {
11749203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
11750203945Sweongyo		{ BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0900 },
11751203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
11752203945Sweongyo		{ BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
11753203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0006 },
11754203945Sweongyo		{ BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0500 },
11755203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0006 },
11756203945Sweongyo		{ BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0700 }
11757203945Sweongyo	};
11758203945Sweongyo	int i;
11759203945Sweongyo	uint16_t tmp, tmp2;
11760203945Sweongyo
11761203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf7ff);
11762203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL, 0);
11763203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, 0);
11764203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, 0);
11765203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0);
11766203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DAC_CTL, 0x0004);
11767203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0x0078);
11768203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800);
11769203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x0016);
11770203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_0, 0xfff8, 0x0004);
11771203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5400);
11772203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2400);
11773203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
11774203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0x0006);
11775203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_RADIO_CTL, 0xfffe);
11776203945Sweongyo	for (i = 0; i < N(v1); i++)
11777203945Sweongyo		BWN_PHY_SETMASK(mac, v1[i].offset, v1[i].mask, v1[i].set);
11778203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB,
11779203945Sweongyo	    0xff00, plp->plp_rxpwroffset);
11780204922Sweongyo	if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM) &&
11781203945Sweongyo	    ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
11782204922Sweongyo	   (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_PAREF))) {
11783204922Sweongyo		siba_cc_pmu_set_ldovolt(sc->sc_dev, SIBA_LDO_PAREF, 0x28);
11784204922Sweongyo		siba_cc_pmu_set_ldoparef(sc->sc_dev, 1);
11785203945Sweongyo		if (mac->mac_phy.rev == 0)
11786203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT,
11787203945Sweongyo			    0xffcf, 0x0010);
11788203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 60);
11789203945Sweongyo	} else {
11790204922Sweongyo		siba_cc_pmu_set_ldoparef(sc->sc_dev, 0);
11791203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT, 0xffcf, 0x0020);
11792203945Sweongyo		bwn_tab_write(mac, BWN_TAB_2(11, 7), 100);
11793203945Sweongyo	}
11794203945Sweongyo	tmp = plp->plp_rssivf | plp->plp_rssivc << 4 | 0xa000;
11795203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, tmp);
11796204922Sweongyo	if (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_RSSIINV)
11797203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x0aaa);
11798203945Sweongyo	else
11799203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x02aa);
11800203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(11, 1), 24);
11801203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_RADIO_CTL,
11802203945Sweongyo	    0xfff9, (plp->plp_bxarch << 1));
11803203945Sweongyo	if (mac->mac_phy.rev == 1 &&
11804204922Sweongyo	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_FEM_BT)) {
11805203945Sweongyo		for (i = 0; i < N(v2); i++)
11806203945Sweongyo			BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask,
11807203945Sweongyo			    v2[i].set);
11808203945Sweongyo	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ||
11809204922Sweongyo	    (siba_get_pci_subdevice(sc->sc_dev) == 0x048a) ||
11810204922Sweongyo	    ((mac->mac_phy.rev == 0) &&
11811204922Sweongyo	     (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM))) {
11812203945Sweongyo		for (i = 0; i < N(v3); i++)
11813203945Sweongyo			BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask,
11814203945Sweongyo			    v3[i].set);
11815203945Sweongyo	} else if (mac->mac_phy.rev == 1 ||
11816204922Sweongyo		  (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_FEM)) {
11817203945Sweongyo		for (i = 0; i < N(v4); i++)
11818203945Sweongyo			BWN_PHY_SETMASK(mac, v4[i].offset, v4[i].mask,
11819203945Sweongyo			    v4[i].set);
11820203945Sweongyo	} else {
11821203945Sweongyo		for (i = 0; i < N(v5); i++)
11822203945Sweongyo			BWN_PHY_SETMASK(mac, v5[i].offset, v5[i].mask,
11823203945Sweongyo			    v5[i].set);
11824203945Sweongyo	}
11825203945Sweongyo	if (mac->mac_phy.rev == 1 &&
11826204922Sweongyo	    (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_LDO_PAREF)) {
11827203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_5, BWN_PHY_TR_LOOKUP_1);
11828203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_6, BWN_PHY_TR_LOOKUP_2);
11829203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_7, BWN_PHY_TR_LOOKUP_3);
11830203945Sweongyo		BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_8, BWN_PHY_TR_LOOKUP_4);
11831203945Sweongyo	}
11832204922Sweongyo	if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_FEM_BT) &&
11833204922Sweongyo	    (siba_get_chipid(sc->sc_dev) == 0x5354) &&
11834204922Sweongyo	    (siba_get_chippkg(sc->sc_dev) == SIBA_CHIPPACK_BCM4712S)) {
11835203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0006);
11836203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_SELECT, 0x0005);
11837203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_GPIO_OUTEN, 0xffff);
11838203945Sweongyo		bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_PR45960W);
11839203945Sweongyo	}
11840203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
11841203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x8000);
11842203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0040);
11843203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0xa400);
11844203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0x0b00);
11845203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x0007);
11846203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xfff8, 0x0003);
11847203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xffc7, 0x0020);
11848203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
11849203945Sweongyo	} else {
11850203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0x7fff);
11851203945Sweongyo		BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xffbf);
11852203945Sweongyo	}
11853203945Sweongyo	if (mac->mac_phy.rev == 1) {
11854203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_CLIPCTRTHRESH);
11855203945Sweongyo		tmp2 = (tmp & 0x03e0) >> 5;
11856203945Sweongyo		tmp2 |= tmp2 << 5;
11857203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C3, tmp2);
11858203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_GAINDIRECTMISMATCH);
11859203945Sweongyo		tmp2 = (tmp & 0x1f00) >> 8;
11860203945Sweongyo		tmp2 |= tmp2 << 5;
11861203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C4, tmp2);
11862203945Sweongyo		tmp = BWN_PHY_READ(mac, BWN_PHY_VERYLOWGAINDB);
11863203945Sweongyo		tmp2 = tmp & 0x00ff;
11864203945Sweongyo		tmp2 |= tmp << 8;
11865203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_4C5, tmp2);
11866203945Sweongyo	}
11867203945Sweongyo}
11868203945Sweongyo
11869203945Sweongyostruct bwn_b2062_freq {
11870203945Sweongyo	uint16_t		freq;
11871203945Sweongyo	uint8_t			value[6];
11872203945Sweongyo};
11873203945Sweongyo
11874203945Sweongyostatic void
11875203945Sweongyobwn_phy_lp_b2062_init(struct bwn_mac *mac)
11876203945Sweongyo{
11877203945Sweongyo#define	CALC_CTL7(freq, div)						\
11878203945Sweongyo	(((800000000 * (div) + (freq)) / (2 * (freq)) - 8) & 0xff)
11879203945Sweongyo#define	CALC_CTL18(freq, div)						\
11880203945Sweongyo	((((100 * (freq) + 16000000 * (div)) / (32000000 * (div))) - 1) & 0xff)
11881203945Sweongyo#define	CALC_CTL19(freq, div)						\
11882203945Sweongyo	((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff)
11883203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
11884203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11885287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
11886203945Sweongyo	static const struct bwn_b2062_freq freqdata_tab[] = {
11887203945Sweongyo		{ 12000, { 6, 6, 6, 6, 10, 6 } },
11888203945Sweongyo		{ 13000, { 4, 4, 4, 4, 11, 7 } },
11889203945Sweongyo		{ 14400, { 3, 3, 3, 3, 12, 7 } },
11890203945Sweongyo		{ 16200, { 3, 3, 3, 3, 13, 8 } },
11891203945Sweongyo		{ 18000, { 2, 2, 2, 2, 14, 8 } },
11892203945Sweongyo		{ 19200, { 1, 1, 1, 1, 14, 9 } }
11893203945Sweongyo	};
11894203945Sweongyo	static const struct bwn_wpair v1[] = {
11895203945Sweongyo		{ BWN_B2062_N_TXCTL3, 0 },
11896203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0 },
11897203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0 },
11898203945Sweongyo		{ BWN_B2062_N_TXCTL6, 0 },
11899203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0x40 },
11900203945Sweongyo		{ BWN_B2062_N_PDNCTL0, 0 },
11901203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0x10 },
11902203945Sweongyo		{ BWN_B2062_N_CALIB_TS, 0 }
11903203945Sweongyo	};
11904203945Sweongyo	const struct bwn_b2062_freq *f = NULL;
11905203945Sweongyo	uint32_t xtalfreq, ref;
11906203945Sweongyo	unsigned int i;
11907203945Sweongyo
11908203945Sweongyo	bwn_phy_lp_b2062_tblinit(mac);
11909203945Sweongyo
11910203945Sweongyo	for (i = 0; i < N(v1); i++)
11911203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
11912203945Sweongyo	if (mac->mac_phy.rev > 0)
11913203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_BG_CTL1,
11914203945Sweongyo		    (BWN_RF_READ(mac, BWN_B2062_N_COM2) >> 1) | 0x80);
11915203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
11916203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_N_TSSI_CTL0, 0x1);
11917203945Sweongyo	else
11918203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_N_TSSI_CTL0, ~0x1);
11919203945Sweongyo
11920204922Sweongyo	KASSERT(siba_get_cc_caps(sc->sc_dev) & SIBA_CC_CAPS_PMU,
11921203945Sweongyo	    ("%s:%d: fail", __func__, __LINE__));
11922204922Sweongyo	xtalfreq = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
11923203945Sweongyo	KASSERT(xtalfreq != 0, ("%s:%d: fail", __func__, __LINE__));
11924203945Sweongyo
11925203945Sweongyo	if (xtalfreq <= 30000000) {
11926203945Sweongyo		plp->plp_div = 1;
11927203945Sweongyo		BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL1, 0xfffb);
11928203945Sweongyo	} else {
11929203945Sweongyo		plp->plp_div = 2;
11930203945Sweongyo		BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL1, 0x4);
11931203945Sweongyo	}
11932203945Sweongyo
11933203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL7,
11934203945Sweongyo	    CALC_CTL7(xtalfreq, plp->plp_div));
11935203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL18,
11936203945Sweongyo	    CALC_CTL18(xtalfreq, plp->plp_div));
11937203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL19,
11938203945Sweongyo	    CALC_CTL19(xtalfreq, plp->plp_div));
11939203945Sweongyo
11940203945Sweongyo	ref = (1000 * plp->plp_div + 2 * xtalfreq) / (2000 * plp->plp_div);
11941203945Sweongyo	ref &= 0xffff;
11942203945Sweongyo	for (i = 0; i < N(freqdata_tab); i++) {
11943203945Sweongyo		if (ref < freqdata_tab[i].freq) {
11944203945Sweongyo			f = &freqdata_tab[i];
11945203945Sweongyo			break;
11946203945Sweongyo		}
11947203945Sweongyo	}
11948203945Sweongyo	if (f == NULL)
11949203945Sweongyo		f = &freqdata_tab[N(freqdata_tab) - 1];
11950203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL8,
11951203945Sweongyo	    ((uint16_t)(f->value[1]) << 4) | f->value[0]);
11952203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL9,
11953203945Sweongyo	    ((uint16_t)(f->value[3]) << 4) | f->value[2]);
11954203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL10, f->value[4]);
11955203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL11, f->value[5]);
11956203945Sweongyo#undef CALC_CTL7
11957203945Sweongyo#undef CALC_CTL18
11958203945Sweongyo#undef CALC_CTL19
11959203945Sweongyo}
11960203945Sweongyo
11961203945Sweongyostatic void
11962203945Sweongyobwn_phy_lp_b2063_init(struct bwn_mac *mac)
11963203945Sweongyo{
11964203945Sweongyo
11965203945Sweongyo	bwn_phy_lp_b2063_tblinit(mac);
11966203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_LOGEN_SP5, 0);
11967203945Sweongyo	BWN_RF_SET(mac, BWN_B2063_COM8, 0x38);
11968203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_REG_SP1, 0x56);
11969203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_RX_BB_CTL2, ~0x2);
11970203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0);
11971203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP6, 0x20);
11972203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP9, 0x40);
11973203945Sweongyo	if (mac->mac_phy.rev == 2) {
11974203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0xa0);
11975203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP4, 0xa0);
11976203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x18);
11977203945Sweongyo	} else {
11978203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0x20);
11979203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x20);
11980203945Sweongyo	}
11981203945Sweongyo}
11982203945Sweongyo
11983203945Sweongyostatic void
11984203945Sweongyobwn_phy_lp_rxcal_r2(struct bwn_mac *mac)
11985203945Sweongyo{
11986204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
11987203945Sweongyo	static const struct bwn_wpair v1[] = {
11988203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x0 },
11989203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
11990203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
11991203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x15 },
11992203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x70 },
11993203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL4, 0x52 },
11994203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL5, 0x1 },
11995203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7d }
11996203945Sweongyo	};
11997203945Sweongyo	static const struct bwn_wpair v2[] = {
11998203945Sweongyo		{ BWN_B2063_TX_BB_SP3, 0x0 },
11999203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7e },
12000203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL1, 0x7c },
12001203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL2, 0x55 },
12002203945Sweongyo		{ BWN_B2063_RC_CALIB_CTL3, 0x76 }
12003203945Sweongyo	};
12004204922Sweongyo	uint32_t freqxtal = siba_get_cc_pmufreq(sc->sc_dev) * 1000;
12005203945Sweongyo	int i;
12006203945Sweongyo	uint8_t tmp;
12007203945Sweongyo
12008203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_RX_BB_SP8) & 0xff;
12009203945Sweongyo
12010203945Sweongyo	for (i = 0; i < 2; i++)
12011203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12012203945Sweongyo	BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, 0xf7);
12013203945Sweongyo	for (i = 2; i < N(v1); i++)
12014203945Sweongyo		BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
12015203945Sweongyo	for (i = 0; i < 10000; i++) {
12016203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12017203945Sweongyo			break;
12018203945Sweongyo		DELAY(1000);
12019203945Sweongyo	}
12020203945Sweongyo
12021203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12022203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RX_BB_SP8, tmp);
12023203945Sweongyo
12024203945Sweongyo	tmp = BWN_RF_READ(mac, BWN_B2063_TX_BB_SP3) & 0xff;
12025203945Sweongyo
12026203945Sweongyo	for (i = 0; i < N(v2); i++)
12027203945Sweongyo		BWN_RF_WRITE(mac, v2[i].reg, v2[i].value);
12028203945Sweongyo	if (freqxtal == 24000000) {
12029203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0xfc);
12030203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x0);
12031203945Sweongyo	} else {
12032203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0x13);
12033203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x1);
12034203945Sweongyo	}
12035203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0x7d);
12036203945Sweongyo	for (i = 0; i < 10000; i++) {
12037203945Sweongyo		if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
12038203945Sweongyo			break;
12039203945Sweongyo		DELAY(1000);
12040203945Sweongyo	}
12041203945Sweongyo	if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
12042203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, tmp);
12043203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL1, 0x7e);
12044203945Sweongyo}
12045203945Sweongyo
12046203945Sweongyostatic void
12047203945Sweongyobwn_phy_lp_rccal_r12(struct bwn_mac *mac)
12048203945Sweongyo{
12049203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12050203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12051203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12052203945Sweongyo	struct bwn_txgain tx_gains;
12053203945Sweongyo	static const uint32_t pwrtbl[21] = {
12054203945Sweongyo		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
12055203945Sweongyo		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
12056203945Sweongyo		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
12057203945Sweongyo		0x0004c, 0x0002c, 0x0001a,
12058203945Sweongyo	};
12059203945Sweongyo	uint32_t npwr, ipwr, sqpwr, tmp;
12060203945Sweongyo	int loopback, i, j, sum, error;
12061203945Sweongyo	uint16_t save[7];
12062203945Sweongyo	uint8_t txo, bbmult, txpctlmode;
12063203945Sweongyo
12064203945Sweongyo	error = bwn_phy_lp_switch_channel(mac, 7);
12065203945Sweongyo	if (error)
12066203945Sweongyo		device_printf(sc->sc_dev,
12067203945Sweongyo		    "failed to change channel to 7 (%d)\n", error);
12068203945Sweongyo	txo = (BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40) ? 1 : 0;
12069203945Sweongyo	bbmult = bwn_phy_lp_get_bbmult(mac);
12070203945Sweongyo	if (txo)
12071203945Sweongyo		tx_gains = bwn_phy_lp_get_txgain(mac);
12072203945Sweongyo
12073203945Sweongyo	save[0] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_0);
12074203945Sweongyo	save[1] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_VAL_0);
12075203945Sweongyo	save[2] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR);
12076203945Sweongyo	save[3] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVRVAL);
12077203945Sweongyo	save[4] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2);
12078203945Sweongyo	save[5] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2_VAL);
12079203945Sweongyo	save[6] = BWN_PHY_READ(mac, BWN_PHY_LP_PHY_CTL);
12080203945Sweongyo
12081203945Sweongyo	bwn_phy_lp_get_txpctlmode(mac);
12082203945Sweongyo	txpctlmode = plp->plp_txpctlmode;
12083203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
12084203945Sweongyo
12085203945Sweongyo	/* disable CRS */
12086203945Sweongyo	bwn_phy_lp_set_deaf(mac, 1);
12087203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 0, 1);
12088203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffb);
12089203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x4);
12090203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7);
12091203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
12092203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x10);
12093203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12094203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf);
12095203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
12096203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffbf);
12097203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12098203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x7);
12099203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x38);
12100203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f);
12101203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x100);
12102203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfdff);
12103203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL0, 0);
12104203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL1, 1);
12105203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL2, 0x20);
12106203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfbff);
12107203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xf7ff);
12108203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
12109203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45af);
12110203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0x3ff);
12111203945Sweongyo
12112203945Sweongyo	loopback = bwn_phy_lp_loopback(mac);
12113203945Sweongyo	if (loopback == -1)
12114203945Sweongyo		goto done;
12115203945Sweongyo	bwn_phy_lp_set_rxgain_idx(mac, loopback);
12116203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xffbf, 0x40);
12117203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfff8, 0x1);
12118203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xffc7, 0x8);
12119203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f, 0xc0);
12120203945Sweongyo
12121203945Sweongyo	tmp = 0;
12122203945Sweongyo	memset(&ie, 0, sizeof(ie));
12123203945Sweongyo	for (i = 128; i <= 159; i++) {
12124203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2, i);
12125203945Sweongyo		sum = 0;
12126203945Sweongyo		for (j = 5; j <= 25; j++) {
12127203945Sweongyo			bwn_phy_lp_ddfs_turnon(mac, 1, 1, j, j, 0);
12128203945Sweongyo			if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
12129203945Sweongyo				goto done;
12130203945Sweongyo			sqpwr = ie.ie_ipwr + ie.ie_qpwr;
12131203945Sweongyo			ipwr = ((pwrtbl[j - 5] >> 3) + 1) >> 1;
12132203945Sweongyo			npwr = bwn_phy_lp_roundup(sqpwr, (j == 5) ? sqpwr : 0,
12133203945Sweongyo			    12);
12134203945Sweongyo			sum += ((ipwr - npwr) * (ipwr - npwr));
12135203945Sweongyo			if ((i == 128) || (sum < tmp)) {
12136203945Sweongyo				plp->plp_rccap = i;
12137203945Sweongyo				tmp = sum;
12138203945Sweongyo			}
12139203945Sweongyo		}
12140203945Sweongyo	}
12141203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
12142203945Sweongyodone:
12143203945Sweongyo	/* restore CRS */
12144203945Sweongyo	bwn_phy_lp_clear_deaf(mac, 1);
12145203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xff80);
12146203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfc00);
12147203945Sweongyo
12148203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_VAL_0, save[1]);
12149203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, save[0]);
12150203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVRVAL, save[3]);
12151203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, save[2]);
12152203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2_VAL, save[5]);
12153203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, save[4]);
12154203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_LP_PHY_CTL, save[6]);
12155203945Sweongyo
12156203945Sweongyo	bwn_phy_lp_set_bbmult(mac, bbmult);
12157203945Sweongyo	if (txo)
12158203945Sweongyo		bwn_phy_lp_set_txgain(mac, &tx_gains);
12159203945Sweongyo	bwn_phy_lp_set_txpctlmode(mac, txpctlmode);
12160203945Sweongyo	if (plp->plp_rccap)
12161203945Sweongyo		bwn_phy_lp_set_rccap(mac);
12162203945Sweongyo}
12163203945Sweongyo
12164203945Sweongyostatic void
12165203945Sweongyobwn_phy_lp_set_rccap(struct bwn_mac *mac)
12166203945Sweongyo{
12167203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12168203945Sweongyo	uint8_t rc_cap = (plp->plp_rccap & 0x1f) >> 1;
12169203945Sweongyo
12170203945Sweongyo	if (mac->mac_phy.rev == 1)
12171203945Sweongyo		rc_cap = MIN(rc_cap + 5, 15);
12172203945Sweongyo
12173203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2,
12174203945Sweongyo	    MAX(plp->plp_rccap - 4, 0x80));
12175203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, rc_cap | 0x80);
12176203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RXG_CNT16,
12177203945Sweongyo	    ((plp->plp_rccap & 0x1f) >> 2) | 0x80);
12178203945Sweongyo}
12179203945Sweongyo
12180203945Sweongyostatic uint32_t
12181203945Sweongyobwn_phy_lp_roundup(uint32_t value, uint32_t div, uint8_t pre)
12182203945Sweongyo{
12183203945Sweongyo	uint32_t i, q, r;
12184203945Sweongyo
12185203945Sweongyo	if (div == 0)
12186203945Sweongyo		return (0);
12187203945Sweongyo
12188203945Sweongyo	for (i = 0, q = value / div, r = value % div; i < pre; i++) {
12189203945Sweongyo		q <<= 1;
12190203945Sweongyo		if (r << 1 >= div) {
12191203945Sweongyo			q++;
12192203945Sweongyo			r = (r << 1) - div;
12193203945Sweongyo		}
12194203945Sweongyo	}
12195203945Sweongyo	if (r << 1 >= div)
12196203945Sweongyo		q++;
12197203945Sweongyo	return (q);
12198203945Sweongyo}
12199203945Sweongyo
12200203945Sweongyostatic void
12201203945Sweongyobwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *mac)
12202203945Sweongyo{
12203204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12204203945Sweongyo
12205203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0xff);
12206203945Sweongyo	DELAY(20);
12207204922Sweongyo	if (siba_get_chipid(sc->sc_dev) == 0x5354) {
12208203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_N_COM1, 4);
12209203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 4);
12210203945Sweongyo	} else {
12211203945Sweongyo		BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0);
12212203945Sweongyo	}
12213203945Sweongyo	DELAY(5);
12214203945Sweongyo}
12215203945Sweongyo
12216203945Sweongyostatic void
12217203945Sweongyobwn_phy_lp_b2062_vco_calib(struct bwn_mac *mac)
12218203945Sweongyo{
12219203945Sweongyo
12220203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x42);
12221203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x62);
12222203945Sweongyo	DELAY(200);
12223203945Sweongyo}
12224203945Sweongyo
12225203945Sweongyostatic void
12226203945Sweongyobwn_phy_lp_b2062_tblinit(struct bwn_mac *mac)
12227203945Sweongyo{
12228203945Sweongyo#define	FLAG_A	0x01
12229203945Sweongyo#define	FLAG_G	0x02
12230203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12231287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
12232203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = {
12233203945Sweongyo		{ BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12234203945Sweongyo		{ BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, },
12235203945Sweongyo		{ BWN_B2062_N_PDNCTL3, 0x0, 0x0, FLAG_A | FLAG_G, },
12236203945Sweongyo		{ BWN_B2062_N_PDNCTL4, 0x15, 0x2a, FLAG_A | FLAG_G, },
12237203945Sweongyo		{ BWN_B2062_N_LGENC, 0xDB, 0xff, FLAG_A, },
12238203945Sweongyo		{ BWN_B2062_N_LGENATUNE0, 0xdd, 0x0, FLAG_A | FLAG_G, },
12239203945Sweongyo		{ BWN_B2062_N_LGENATUNE2, 0xdd, 0x0, FLAG_A | FLAG_G, },
12240203945Sweongyo		{ BWN_B2062_N_LGENATUNE3, 0x77, 0xB5, FLAG_A | FLAG_G, },
12241203945Sweongyo		{ BWN_B2062_N_LGENACTL3, 0x0, 0xff, FLAG_A | FLAG_G, },
12242203945Sweongyo		{ BWN_B2062_N_LGENACTL7, 0x33, 0x33, FLAG_A | FLAG_G, },
12243203945Sweongyo		{ BWN_B2062_N_RXA_CTL1, 0x0, 0x0, FLAG_G, },
12244203945Sweongyo		{ BWN_B2062_N_RXBB_CTL0, 0x82, 0x80, FLAG_A | FLAG_G, },
12245203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN1, 0x4, 0x4, FLAG_A | FLAG_G, },
12246203945Sweongyo		{ BWN_B2062_N_RXBB_GAIN2, 0x0, 0x0, FLAG_A | FLAG_G, },
12247203945Sweongyo		{ BWN_B2062_N_TXCTL4, 0x3, 0x3, FLAG_A | FLAG_G, },
12248203945Sweongyo		{ BWN_B2062_N_TXCTL5, 0x2, 0x2, FLAG_A | FLAG_G, },
12249203945Sweongyo		{ BWN_B2062_N_TX_TUNE, 0x88, 0x1b, FLAG_A | FLAG_G, },
12250203945Sweongyo		{ BWN_B2062_S_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
12251203945Sweongyo		{ BWN_B2062_S_PDS_CTL0, 0xff, 0xff, FLAG_A | FLAG_G, },
12252203945Sweongyo		{ BWN_B2062_S_LGENG_CTL0, 0xf8, 0xd8, FLAG_A | FLAG_G, },
12253203945Sweongyo		{ BWN_B2062_S_LGENG_CTL1, 0x3c, 0x24, FLAG_A | FLAG_G, },
12254203945Sweongyo		{ BWN_B2062_S_LGENG_CTL8, 0x88, 0x80, FLAG_A | FLAG_G, },
12255203945Sweongyo		{ BWN_B2062_S_LGENG_CTL10, 0x88, 0x80, FLAG_A | FLAG_G, },
12256203945Sweongyo		{ BWN_B2062_S_RFPLLCTL0, 0x98, 0x98, FLAG_A | FLAG_G, },
12257203945Sweongyo		{ BWN_B2062_S_RFPLLCTL1, 0x10, 0x10, FLAG_A | FLAG_G, },
12258203945Sweongyo		{ BWN_B2062_S_RFPLLCTL5, 0x43, 0x43, FLAG_A | FLAG_G, },
12259203945Sweongyo		{ BWN_B2062_S_RFPLLCTL6, 0x47, 0x47, FLAG_A | FLAG_G, },
12260203945Sweongyo		{ BWN_B2062_S_RFPLLCTL7, 0xc, 0xc, FLAG_A | FLAG_G, },
12261203945Sweongyo		{ BWN_B2062_S_RFPLLCTL8, 0x11, 0x11, FLAG_A | FLAG_G, },
12262203945Sweongyo		{ BWN_B2062_S_RFPLLCTL9, 0x11, 0x11, FLAG_A | FLAG_G, },
12263203945Sweongyo		{ BWN_B2062_S_RFPLLCTL10, 0xe, 0xe, FLAG_A | FLAG_G, },
12264203945Sweongyo		{ BWN_B2062_S_RFPLLCTL11, 0x8, 0x8, FLAG_A | FLAG_G, },
12265203945Sweongyo		{ BWN_B2062_S_RFPLLCTL12, 0x33, 0x33, FLAG_A | FLAG_G, },
12266203945Sweongyo		{ BWN_B2062_S_RFPLLCTL13, 0xa, 0xa, FLAG_A | FLAG_G, },
12267203945Sweongyo		{ BWN_B2062_S_RFPLLCTL14, 0x6, 0x6, FLAG_A | FLAG_G, },
12268203945Sweongyo		{ BWN_B2062_S_RFPLLCTL18, 0x3e, 0x3e, FLAG_A | FLAG_G, },
12269203945Sweongyo		{ BWN_B2062_S_RFPLLCTL19, 0x13, 0x13, FLAG_A | FLAG_G, },
12270203945Sweongyo		{ BWN_B2062_S_RFPLLCTL21, 0x62, 0x62, FLAG_A | FLAG_G, },
12271203945Sweongyo		{ BWN_B2062_S_RFPLLCTL22, 0x7, 0x7, FLAG_A | FLAG_G, },
12272203945Sweongyo		{ BWN_B2062_S_RFPLLCTL23, 0x16, 0x16, FLAG_A | FLAG_G, },
12273203945Sweongyo		{ BWN_B2062_S_RFPLLCTL24, 0x5c, 0x5c, FLAG_A | FLAG_G, },
12274203945Sweongyo		{ BWN_B2062_S_RFPLLCTL25, 0x95, 0x95, FLAG_A | FLAG_G, },
12275203945Sweongyo		{ BWN_B2062_S_RFPLLCTL30, 0xa0, 0xa0, FLAG_A | FLAG_G, },
12276203945Sweongyo		{ BWN_B2062_S_RFPLLCTL31, 0x4, 0x4, FLAG_A | FLAG_G, },
12277203945Sweongyo		{ BWN_B2062_S_RFPLLCTL33, 0xcc, 0xcc, FLAG_A | FLAG_G, },
12278203945Sweongyo		{ BWN_B2062_S_RFPLLCTL34, 0x7, 0x7, FLAG_A | FLAG_G, },
12279203945Sweongyo		{ BWN_B2062_S_RXG_CNT8, 0xf, 0xf, FLAG_A, },
12280203945Sweongyo	};
12281203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12282203945Sweongyo	unsigned int i;
12283203945Sweongyo
12284203945Sweongyo	for (i = 0; i < N(bwn_b2062_init_tab); i++) {
12285203945Sweongyo		br = &bwn_b2062_init_tab[i];
12286203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12287203945Sweongyo			if (br->br_flags & FLAG_G)
12288203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12289203945Sweongyo		} else {
12290203945Sweongyo			if (br->br_flags & FLAG_A)
12291203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12292203945Sweongyo		}
12293203945Sweongyo	}
12294203945Sweongyo#undef FLAG_A
12295203945Sweongyo#undef FLAG_B
12296203945Sweongyo}
12297203945Sweongyo
12298203945Sweongyostatic void
12299203945Sweongyobwn_phy_lp_b2063_tblinit(struct bwn_mac *mac)
12300203945Sweongyo{
12301203945Sweongyo#define	FLAG_A	0x01
12302203945Sweongyo#define	FLAG_G	0x02
12303203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12304287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
12305203945Sweongyo	static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = {
12306203945Sweongyo		{ BWN_B2063_COM1, 0x0, 0x0, FLAG_G, },
12307203945Sweongyo		{ BWN_B2063_COM10, 0x1, 0x0, FLAG_A, },
12308203945Sweongyo		{ BWN_B2063_COM16, 0x0, 0x0, FLAG_G, },
12309203945Sweongyo		{ BWN_B2063_COM17, 0x0, 0x0, FLAG_G, },
12310203945Sweongyo		{ BWN_B2063_COM18, 0x0, 0x0, FLAG_G, },
12311203945Sweongyo		{ BWN_B2063_COM19, 0x0, 0x0, FLAG_G, },
12312203945Sweongyo		{ BWN_B2063_COM20, 0x0, 0x0, FLAG_G, },
12313203945Sweongyo		{ BWN_B2063_COM21, 0x0, 0x0, FLAG_G, },
12314203945Sweongyo		{ BWN_B2063_COM22, 0x0, 0x0, FLAG_G, },
12315203945Sweongyo		{ BWN_B2063_COM23, 0x0, 0x0, FLAG_G, },
12316203945Sweongyo		{ BWN_B2063_COM24, 0x0, 0x0, FLAG_G, },
12317203945Sweongyo		{ BWN_B2063_LOGEN_SP1, 0xe8, 0xd4, FLAG_A | FLAG_G, },
12318203945Sweongyo		{ BWN_B2063_LOGEN_SP2, 0xa7, 0x53, FLAG_A | FLAG_G, },
12319203945Sweongyo		{ BWN_B2063_LOGEN_SP4, 0xf0, 0xf, FLAG_A | FLAG_G, },
12320203945Sweongyo		{ BWN_B2063_G_RX_SP1, 0x1f, 0x5e, FLAG_G, },
12321203945Sweongyo		{ BWN_B2063_G_RX_SP2, 0x7f, 0x7e, FLAG_G, },
12322203945Sweongyo		{ BWN_B2063_G_RX_SP3, 0x30, 0xf0, FLAG_G, },
12323203945Sweongyo		{ BWN_B2063_G_RX_SP7, 0x7f, 0x7f, FLAG_A | FLAG_G, },
12324203945Sweongyo		{ BWN_B2063_G_RX_SP10, 0xc, 0xc, FLAG_A | FLAG_G, },
12325203945Sweongyo		{ BWN_B2063_A_RX_SP1, 0x3c, 0x3f, FLAG_A, },
12326203945Sweongyo		{ BWN_B2063_A_RX_SP2, 0xfc, 0xfe, FLAG_A, },
12327203945Sweongyo		{ BWN_B2063_A_RX_SP7, 0x8, 0x8, FLAG_A | FLAG_G, },
12328203945Sweongyo		{ BWN_B2063_RX_BB_SP4, 0x60, 0x60, FLAG_A | FLAG_G, },
12329203945Sweongyo		{ BWN_B2063_RX_BB_SP8, 0x30, 0x30, FLAG_A | FLAG_G, },
12330203945Sweongyo		{ BWN_B2063_TX_RF_SP3, 0xc, 0xb, FLAG_A | FLAG_G, },
12331203945Sweongyo		{ BWN_B2063_TX_RF_SP4, 0x10, 0xf, FLAG_A | FLAG_G, },
12332203945Sweongyo		{ BWN_B2063_PA_SP1, 0x3d, 0xfd, FLAG_A | FLAG_G, },
12333203945Sweongyo		{ BWN_B2063_TX_BB_SP1, 0x2, 0x2, FLAG_A | FLAG_G, },
12334203945Sweongyo		{ BWN_B2063_BANDGAP_CTL1, 0x56, 0x56, FLAG_A | FLAG_G, },
12335203945Sweongyo		{ BWN_B2063_JTAG_VCO2, 0xF7, 0xF7, FLAG_A | FLAG_G, },
12336203945Sweongyo		{ BWN_B2063_G_RX_MIX3, 0x71, 0x71, FLAG_A | FLAG_G, },
12337203945Sweongyo		{ BWN_B2063_G_RX_MIX4, 0x71, 0x71, FLAG_A | FLAG_G, },
12338203945Sweongyo		{ BWN_B2063_A_RX_1ST2, 0xf0, 0x30, FLAG_A, },
12339203945Sweongyo		{ BWN_B2063_A_RX_PS6, 0x77, 0x77, FLAG_A | FLAG_G, },
12340203945Sweongyo		{ BWN_B2063_A_RX_MIX4, 0x3, 0x3, FLAG_A | FLAG_G, },
12341203945Sweongyo		{ BWN_B2063_A_RX_MIX5, 0xf, 0xf, FLAG_A | FLAG_G, },
12342203945Sweongyo		{ BWN_B2063_A_RX_MIX6, 0xf, 0xf, FLAG_A | FLAG_G, },
12343203945Sweongyo		{ BWN_B2063_RX_TIA_CTL1, 0x77, 0x77, FLAG_A | FLAG_G, },
12344203945Sweongyo		{ BWN_B2063_RX_TIA_CTL3, 0x77, 0x77, FLAG_A | FLAG_G, },
12345203945Sweongyo		{ BWN_B2063_RX_BB_CTL2, 0x4, 0x4, FLAG_A | FLAG_G, },
12346203945Sweongyo		{ BWN_B2063_PA_CTL1, 0x0, 0x4, FLAG_A, },
12347203945Sweongyo		{ BWN_B2063_VREG_CTL1, 0x3, 0x3, FLAG_A | FLAG_G, },
12348203945Sweongyo	};
12349203945Sweongyo	const struct bwn_b206x_rfinit_entry *br;
12350203945Sweongyo	unsigned int i;
12351203945Sweongyo
12352203945Sweongyo	for (i = 0; i < N(bwn_b2063_init_tab); i++) {
12353203945Sweongyo		br = &bwn_b2063_init_tab[i];
12354203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12355203945Sweongyo			if (br->br_flags & FLAG_G)
12356203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
12357203945Sweongyo		} else {
12358203945Sweongyo			if (br->br_flags & FLAG_A)
12359203945Sweongyo				BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
12360203945Sweongyo		}
12361203945Sweongyo	}
12362203945Sweongyo#undef FLAG_A
12363203945Sweongyo#undef FLAG_B
12364203945Sweongyo}
12365203945Sweongyo
12366203945Sweongyostatic void
12367203945Sweongyobwn_tab_read_multi(struct bwn_mac *mac, uint32_t typenoffset,
12368203945Sweongyo    int count, void *_data)
12369203945Sweongyo{
12370203945Sweongyo	unsigned int i;
12371203945Sweongyo	uint32_t offset, type;
12372203945Sweongyo	uint8_t *data = _data;
12373203945Sweongyo
12374203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12375203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12376203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12377203945Sweongyo
12378203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12379203945Sweongyo
12380203945Sweongyo	for (i = 0; i < count; i++) {
12381203945Sweongyo		switch (type) {
12382203945Sweongyo		case BWN_TAB_8BIT:
12383203945Sweongyo			*data = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
12384203945Sweongyo			data++;
12385203945Sweongyo			break;
12386203945Sweongyo		case BWN_TAB_16BIT:
12387203945Sweongyo			*((uint16_t *)data) = BWN_PHY_READ(mac,
12388203945Sweongyo			    BWN_PHY_TABLEDATALO);
12389203945Sweongyo			data += 2;
12390203945Sweongyo			break;
12391203945Sweongyo		case BWN_TAB_32BIT:
12392203945Sweongyo			*((uint32_t *)data) = BWN_PHY_READ(mac,
12393203945Sweongyo			    BWN_PHY_TABLEDATAHI);
12394203945Sweongyo			*((uint32_t *)data) <<= 16;
12395203945Sweongyo			*((uint32_t *)data) |= BWN_PHY_READ(mac,
12396203945Sweongyo			    BWN_PHY_TABLEDATALO);
12397203945Sweongyo			data += 4;
12398203945Sweongyo			break;
12399203945Sweongyo		default:
12400203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12401203945Sweongyo		}
12402203945Sweongyo	}
12403203945Sweongyo}
12404203945Sweongyo
12405203945Sweongyostatic void
12406203945Sweongyobwn_tab_write_multi(struct bwn_mac *mac, uint32_t typenoffset,
12407203945Sweongyo    int count, const void *_data)
12408203945Sweongyo{
12409203945Sweongyo	uint32_t offset, type, value;
12410203945Sweongyo	const uint8_t *data = _data;
12411203945Sweongyo	unsigned int i;
12412203945Sweongyo
12413203945Sweongyo	type = BWN_TAB_GETTYPE(typenoffset);
12414203945Sweongyo	offset = BWN_TAB_GETOFFSET(typenoffset);
12415203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
12416203945Sweongyo
12417203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
12418203945Sweongyo
12419203945Sweongyo	for (i = 0; i < count; i++) {
12420203945Sweongyo		switch (type) {
12421203945Sweongyo		case BWN_TAB_8BIT:
12422203945Sweongyo			value = *data;
12423203945Sweongyo			data++;
12424203945Sweongyo			KASSERT(!(value & ~0xff),
12425203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12426203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12427203945Sweongyo			break;
12428203945Sweongyo		case BWN_TAB_16BIT:
12429203945Sweongyo			value = *((const uint16_t *)data);
12430203945Sweongyo			data += 2;
12431203945Sweongyo			KASSERT(!(value & ~0xffff),
12432203945Sweongyo			    ("%s:%d: fail", __func__, __LINE__));
12433203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12434203945Sweongyo			break;
12435203945Sweongyo		case BWN_TAB_32BIT:
12436203945Sweongyo			value = *((const uint32_t *)data);
12437203945Sweongyo			data += 4;
12438203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
12439203945Sweongyo			BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
12440203945Sweongyo			break;
12441203945Sweongyo		default:
12442203945Sweongyo			KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
12443203945Sweongyo		}
12444203945Sweongyo	}
12445203945Sweongyo}
12446203945Sweongyo
12447203945Sweongyostatic struct bwn_txgain
12448203945Sweongyobwn_phy_lp_get_txgain(struct bwn_mac *mac)
12449203945Sweongyo{
12450203945Sweongyo	struct bwn_txgain tg;
12451203945Sweongyo	uint16_t tmp;
12452203945Sweongyo
12453203945Sweongyo	tg.tg_dac = (BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0x380) >> 7;
12454203945Sweongyo	if (mac->mac_phy.rev < 2) {
12455203945Sweongyo		tmp = BWN_PHY_READ(mac,
12456203945Sweongyo		    BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7ff;
12457203945Sweongyo		tg.tg_gm = tmp & 0x0007;
12458203945Sweongyo		tg.tg_pga = (tmp & 0x0078) >> 3;
12459203945Sweongyo		tg.tg_pad = (tmp & 0x780) >> 7;
12460203945Sweongyo		return (tg);
12461203945Sweongyo	}
12462203945Sweongyo
12463203945Sweongyo	tmp = BWN_PHY_READ(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL);
12464203945Sweongyo	tg.tg_pad = BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0xff;
12465203945Sweongyo	tg.tg_gm = tmp & 0xff;
12466203945Sweongyo	tg.tg_pga = (tmp >> 8) & 0xff;
12467203945Sweongyo	return (tg);
12468203945Sweongyo}
12469203945Sweongyo
12470203945Sweongyostatic uint8_t
12471203945Sweongyobwn_phy_lp_get_bbmult(struct bwn_mac *mac)
12472203945Sweongyo{
12473203945Sweongyo
12474203945Sweongyo	return (bwn_tab_read(mac, BWN_TAB_2(0, 87)) & 0xff00) >> 8;
12475203945Sweongyo}
12476203945Sweongyo
12477203945Sweongyostatic void
12478203945Sweongyobwn_phy_lp_set_txgain(struct bwn_mac *mac, struct bwn_txgain *tg)
12479203945Sweongyo{
12480203945Sweongyo	uint16_t pa;
12481203945Sweongyo
12482203945Sweongyo	if (mac->mac_phy.rev < 2) {
12483203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xf800,
12484203945Sweongyo		    (tg->tg_pad << 7) | (tg->tg_pga << 3) | tg->tg_gm);
12485203945Sweongyo		bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12486203945Sweongyo		bwn_phy_lp_set_txgain_override(mac);
12487203945Sweongyo		return;
12488203945Sweongyo	}
12489203945Sweongyo
12490203945Sweongyo	pa = bwn_phy_lp_get_pa_gain(mac);
12491203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
12492203945Sweongyo	    (tg->tg_pga << 8) | tg->tg_gm);
12493203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0x8000,
12494203945Sweongyo	    tg->tg_pad | (pa << 6));
12495203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xfc), (tg->tg_pga << 8) | tg->tg_gm);
12496203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x8000,
12497203945Sweongyo	    tg->tg_pad | (pa << 8));
12498203945Sweongyo	bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
12499203945Sweongyo	bwn_phy_lp_set_txgain_override(mac);
12500203945Sweongyo}
12501203945Sweongyo
12502203945Sweongyostatic void
12503203945Sweongyobwn_phy_lp_set_bbmult(struct bwn_mac *mac, uint8_t bbmult)
12504203945Sweongyo{
12505203945Sweongyo
12506203945Sweongyo	bwn_tab_write(mac, BWN_TAB_2(0, 87), (uint16_t)bbmult << 8);
12507203945Sweongyo}
12508203945Sweongyo
12509203945Sweongyostatic void
12510203945Sweongyobwn_phy_lp_set_trsw_over(struct bwn_mac *mac, uint8_t tx, uint8_t rx)
12511203945Sweongyo{
12512203945Sweongyo	uint16_t trsw = (tx << 1) | rx;
12513203945Sweongyo
12514203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffc, trsw);
12515203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x3);
12516203945Sweongyo}
12517203945Sweongyo
12518203945Sweongyostatic void
12519203945Sweongyobwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain)
12520203945Sweongyo{
12521203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12522287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
12523203945Sweongyo	uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp;
12524203945Sweongyo
12525203945Sweongyo	if (mac->mac_phy.rev < 2) {
12526203945Sweongyo		trsw = gain & 0x1;
12527203945Sweongyo		lna = (gain & 0xfffc) | ((gain & 0xc) >> 2);
12528203945Sweongyo		ext_lna = (gain & 2) >> 1;
12529203945Sweongyo
12530203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12531203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12532203945Sweongyo		    0xfbff, ext_lna << 10);
12533203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12534203945Sweongyo		    0xf7ff, ext_lna << 11);
12535203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
12536203945Sweongyo	} else {
12537203945Sweongyo		low_gain = gain & 0xffff;
12538203945Sweongyo		high_gain = (gain >> 16) & 0xf;
12539203945Sweongyo		ext_lna = (gain >> 21) & 0x1;
12540203945Sweongyo		trsw = ~(gain >> 20) & 0x1;
12541203945Sweongyo
12542203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
12543203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12544203945Sweongyo		    0xfdff, ext_lna << 9);
12545203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12546203945Sweongyo		    0xfbff, ext_lna << 10);
12547203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
12548203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff0, high_gain);
12549203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12550203945Sweongyo			tmp = (gain >> 2) & 0x3;
12551203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
12552203945Sweongyo			    0xe7ff, tmp<<11);
12553203945Sweongyo			BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe6), 0xffe7,
12554203945Sweongyo			    tmp << 3);
12555203945Sweongyo		}
12556203945Sweongyo	}
12557203945Sweongyo
12558203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1);
12559203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
12560203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
12561203945Sweongyo	if (mac->mac_phy.rev >= 2) {
12562203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
12563203945Sweongyo		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
12564203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x400);
12565203945Sweongyo			BWN_PHY_SET(mac, BWN_PHY_OFDM(0xe5), 0x8);
12566203945Sweongyo		}
12567203945Sweongyo		return;
12568203945Sweongyo	}
12569203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x200);
12570203945Sweongyo}
12571203945Sweongyo
12572203945Sweongyostatic void
12573203945Sweongyobwn_phy_lp_set_deaf(struct bwn_mac *mac, uint8_t user)
12574203945Sweongyo{
12575203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12576203945Sweongyo
12577203945Sweongyo	if (user)
12578203945Sweongyo		plp->plp_crsusr_off = 1;
12579203945Sweongyo	else
12580203945Sweongyo		plp->plp_crssys_off = 1;
12581203945Sweongyo
12582203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x80);
12583203945Sweongyo}
12584203945Sweongyo
12585203945Sweongyostatic void
12586203945Sweongyobwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
12587203945Sweongyo{
12588203945Sweongyo	struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
12589203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12590287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
12591203945Sweongyo
12592203945Sweongyo	if (user)
12593203945Sweongyo		plp->plp_crsusr_off = 0;
12594203945Sweongyo	else
12595203945Sweongyo		plp->plp_crssys_off = 0;
12596203945Sweongyo
12597203945Sweongyo	if (plp->plp_crsusr_off || plp->plp_crssys_off)
12598203945Sweongyo		return;
12599203945Sweongyo
12600203945Sweongyo	if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
12601203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x60);
12602203945Sweongyo	else
12603203945Sweongyo		BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x20);
12604203945Sweongyo}
12605203945Sweongyo
12606203945Sweongyostatic unsigned int
12607203945Sweongyobwn_sqrt(struct bwn_mac *mac, unsigned int x)
12608203945Sweongyo{
12609203945Sweongyo	/* Table holding (10 * sqrt(x)) for x between 1 and 256. */
12610203945Sweongyo	static uint8_t sqrt_table[256] = {
12611203945Sweongyo		10, 14, 17, 20, 22, 24, 26, 28,
12612203945Sweongyo		30, 31, 33, 34, 36, 37, 38, 40,
12613203945Sweongyo		41, 42, 43, 44, 45, 46, 47, 48,
12614203945Sweongyo		50, 50, 51, 52, 53, 54, 55, 56,
12615203945Sweongyo		57, 58, 59, 60, 60, 61, 62, 63,
12616203945Sweongyo		64, 64, 65, 66, 67, 67, 68, 69,
12617203945Sweongyo		70, 70, 71, 72, 72, 73, 74, 74,
12618203945Sweongyo		75, 76, 76, 77, 78, 78, 79, 80,
12619203945Sweongyo		80, 81, 81, 82, 83, 83, 84, 84,
12620203945Sweongyo		85, 86, 86, 87, 87, 88, 88, 89,
12621203945Sweongyo		90, 90, 91, 91, 92, 92, 93, 93,
12622203945Sweongyo		94, 94, 95, 95, 96, 96, 97, 97,
12623203945Sweongyo		98, 98, 99, 100, 100, 100, 101, 101,
12624203945Sweongyo		102, 102, 103, 103, 104, 104, 105, 105,
12625203945Sweongyo		106, 106, 107, 107, 108, 108, 109, 109,
12626203945Sweongyo		110, 110, 110, 111, 111, 112, 112, 113,
12627203945Sweongyo		113, 114, 114, 114, 115, 115, 116, 116,
12628203945Sweongyo		117, 117, 117, 118, 118, 119, 119, 120,
12629203945Sweongyo		120, 120, 121, 121, 122, 122, 122, 123,
12630203945Sweongyo		123, 124, 124, 124, 125, 125, 126, 126,
12631203945Sweongyo		126, 127, 127, 128, 128, 128, 129, 129,
12632203945Sweongyo		130, 130, 130, 131, 131, 131, 132, 132,
12633203945Sweongyo		133, 133, 133, 134, 134, 134, 135, 135,
12634203945Sweongyo		136, 136, 136, 137, 137, 137, 138, 138,
12635203945Sweongyo		138, 139, 139, 140, 140, 140, 141, 141,
12636203945Sweongyo		141, 142, 142, 142, 143, 143, 143, 144,
12637203945Sweongyo		144, 144, 145, 145, 145, 146, 146, 146,
12638203945Sweongyo		147, 147, 147, 148, 148, 148, 149, 149,
12639203945Sweongyo		150, 150, 150, 150, 151, 151, 151, 152,
12640203945Sweongyo		152, 152, 153, 153, 153, 154, 154, 154,
12641203945Sweongyo		155, 155, 155, 156, 156, 156, 157, 157,
12642203945Sweongyo		157, 158, 158, 158, 159, 159, 159, 160
12643203945Sweongyo	};
12644203945Sweongyo
12645203945Sweongyo	if (x == 0)
12646203945Sweongyo		return (0);
12647203945Sweongyo	if (x >= 256) {
12648204542Sweongyo		unsigned int tmp;
12649204542Sweongyo
12650204542Sweongyo		for (tmp = 0; x >= (2 * tmp) + 1; x -= (2 * tmp++) + 1)
12651204542Sweongyo			/* do nothing */ ;
12652204542Sweongyo		return (tmp);
12653203945Sweongyo	}
12654203945Sweongyo	return (sqrt_table[x - 1] / 10);
12655203945Sweongyo}
12656203945Sweongyo
12657203945Sweongyostatic int
12658203945Sweongyobwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *mac, uint16_t sample)
12659203945Sweongyo{
12660203945Sweongyo#define	CALC_COEFF(_v, _x, _y, _z)	do {				\
12661203945Sweongyo	int _t;								\
12662203945Sweongyo	_t = _x - 20;							\
12663203945Sweongyo	if (_t >= 0) {							\
12664203945Sweongyo		_v = ((_y << (30 - _x)) + (_z >> (1 + _t))) / (_z >> _t); \
12665203945Sweongyo	} else {							\
12666203945Sweongyo		_v = ((_y << (30 - _x)) + (_z << (-1 - _t))) / (_z << -_t); \
12667203945Sweongyo	}								\
12668203945Sweongyo} while (0)
12669203945Sweongyo#define	CALC_COEFF2(_v, _x, _y, _z)	do {				\
12670203945Sweongyo	int _t;								\
12671203945Sweongyo	_t = _x - 11;							\
12672203945Sweongyo	if (_t >= 0)							\
12673210393Sweongyo		_v = (_y << (31 - _x)) / (_z >> _t);			\
12674203945Sweongyo	else								\
12675210393Sweongyo		_v = (_y << (31 - _x)) / (_z << -_t);			\
12676203945Sweongyo} while (0)
12677203945Sweongyo	struct bwn_phy_lp_iq_est ie;
12678203945Sweongyo	uint16_t v0, v1;
12679203945Sweongyo	int tmp[2], ret;
12680203945Sweongyo
12681203945Sweongyo	v1 = BWN_PHY_READ(mac, BWN_PHY_RX_COMP_COEFF_S);
12682203945Sweongyo	v0 = v1 >> 8;
12683203945Sweongyo	v1 |= 0xff;
12684203945Sweongyo
12685203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, 0x00c0);
12686203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff);
12687203945Sweongyo
12688203945Sweongyo	ret = bwn_phy_lp_rx_iq_est(mac, sample, 32, &ie);
12689203945Sweongyo	if (ret == 0)
12690203945Sweongyo		goto done;
12691203945Sweongyo
12692203945Sweongyo	if (ie.ie_ipwr + ie.ie_qpwr < 2) {
12693203945Sweongyo		ret = 0;
12694203945Sweongyo		goto done;
12695203945Sweongyo	}
12696203945Sweongyo
12697203945Sweongyo	CALC_COEFF(tmp[0], bwn_nbits(ie.ie_iqprod), ie.ie_iqprod, ie.ie_ipwr);
12698203945Sweongyo	CALC_COEFF2(tmp[1], bwn_nbits(ie.ie_qpwr), ie.ie_qpwr, ie.ie_ipwr);
12699203945Sweongyo
12700203945Sweongyo	tmp[1] = -bwn_sqrt(mac, tmp[1] - (tmp[0] * tmp[0]));
12701203945Sweongyo	v0 = tmp[0] >> 3;
12702203945Sweongyo	v1 = tmp[1] >> 4;
12703203945Sweongyodone:
12704203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, v1);
12705203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, v0 << 8);
12706203945Sweongyo	return ret;
12707203945Sweongyo#undef CALC_COEFF
12708203945Sweongyo#undef CALC_COEFF2
12709203945Sweongyo}
12710203945Sweongyo
12711203945Sweongyostatic void
12712203945Sweongyobwn_phy_lp_tblinit_r01(struct bwn_mac *mac)
12713203945Sweongyo{
12714203945Sweongyo	static const uint16_t noisescale[] = {
12715203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12716203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4,
12717203945Sweongyo		0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
12718203945Sweongyo		0xa4a4, 0xa4a4, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12719203945Sweongyo		0x0000, 0x0000, 0x4c00, 0x2d36, 0x0000, 0x0000, 0x4c00, 0x2d36,
12720203945Sweongyo	};
12721203945Sweongyo	static const uint16_t crsgainnft[] = {
12722203945Sweongyo		0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f,
12723203945Sweongyo		0x036f, 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381,
12724203945Sweongyo		0x0374, 0x0381, 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f,
12725203945Sweongyo		0x0040, 0x005e, 0x007f, 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d,
12726203945Sweongyo		0x013d,
12727203945Sweongyo	};
12728203945Sweongyo	static const uint16_t filterctl[] = {
12729203945Sweongyo		0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077,
12730203945Sweongyo		0xff53, 0x0127,
12731203945Sweongyo	};
12732203945Sweongyo	static const uint32_t psctl[] = {
12733203945Sweongyo		0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101,
12734203945Sweongyo		0x00000080, 0x08080101, 0x00000040, 0x08080101, 0x000000c0,
12735203945Sweongyo		0x08a81501, 0x000000c0, 0x0fe8fd01, 0x000000c0, 0x08300105,
12736203945Sweongyo		0x000000c0, 0x08080201, 0x000000c0, 0x08280205, 0x000000c0,
12737203945Sweongyo		0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, 0x08080202,
12738203945Sweongyo		0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
12739203945Sweongyo		0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106,
12740203945Sweongyo		0x000000c0, 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
12741203945Sweongyo	};
12742203945Sweongyo	static const uint16_t ofdmcckgain_r0[] = {
12743203945Sweongyo		0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12744203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12745203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12746203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12747203945Sweongyo		0x755d,
12748203945Sweongyo	};
12749203945Sweongyo	static const uint16_t ofdmcckgain_r1[] = {
12750203945Sweongyo		0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
12751203945Sweongyo		0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
12752203945Sweongyo		0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
12753203945Sweongyo		0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
12754203945Sweongyo		0x755d,
12755203945Sweongyo	};
12756203945Sweongyo	static const uint16_t gaindelta[] = {
12757203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12758203945Sweongyo		0x0000,
12759203945Sweongyo	};
12760203945Sweongyo	static const uint32_t txpwrctl[] = {
12761203945Sweongyo		0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c,
12762203945Sweongyo		0x0000004b, 0x0000004a, 0x00000049, 0x00000048, 0x00000047,
12763203945Sweongyo		0x00000046, 0x00000045, 0x00000044, 0x00000043, 0x00000042,
12764203945Sweongyo		0x00000041, 0x00000040, 0x0000003f, 0x0000003e, 0x0000003d,
12765203945Sweongyo		0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, 0x00000038,
12766203945Sweongyo		0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
12767203945Sweongyo		0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e,
12768203945Sweongyo		0x0000002d, 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029,
12769203945Sweongyo		0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
12770203945Sweongyo		0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001f,
12771203945Sweongyo		0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001a,
12772203945Sweongyo		0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
12773203945Sweongyo		0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000,
12774203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12775203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12776203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12777203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12778203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12779203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12780203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12781203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12782203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12783203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12784203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12785203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12786203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12787203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12788203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12789203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12790203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12791203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12792203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12793203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12794203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12795203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12796203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12797203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12798203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12799203945Sweongyo		0x00000000, 0x00000000, 0x000075a0, 0x000075a0, 0x000075a1,
12800203945Sweongyo		0x000075a1, 0x000075a2, 0x000075a2, 0x000075a3, 0x000075a3,
12801203945Sweongyo		0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, 0x000074b2,
12802203945Sweongyo		0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
12803203945Sweongyo		0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23,
12804203945Sweongyo		0x00006d23, 0x00004660, 0x00004660, 0x00004661, 0x00004661,
12805203945Sweongyo		0x00004662, 0x00004662, 0x00004663, 0x00004663, 0x00003e60,
12806203945Sweongyo		0x00003e60, 0x00003e61, 0x00003e61, 0x00003e62, 0x00003e62,
12807203945Sweongyo		0x00003e63, 0x00003e63, 0x00003660, 0x00003660, 0x00003661,
12808203945Sweongyo		0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
12809203945Sweongyo		0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62,
12810203945Sweongyo		0x00002e62, 0x00002e63, 0x00002e63, 0x00002660, 0x00002660,
12811203945Sweongyo		0x00002661, 0x00002661, 0x00002662, 0x00002662, 0x00002663,
12812203945Sweongyo		0x00002663, 0x000025e0, 0x000025e0, 0x000025e1, 0x000025e1,
12813203945Sweongyo		0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, 0x00001de0,
12814203945Sweongyo		0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
12815203945Sweongyo		0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61,
12816203945Sweongyo		0x00001d61, 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63,
12817203945Sweongyo		0x00001560, 0x00001560, 0x00001561, 0x00001561, 0x00001562,
12818203945Sweongyo		0x00001562, 0x00001563, 0x00001563, 0x00000d60, 0x00000d60,
12819203945Sweongyo		0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, 0x00000d63,
12820203945Sweongyo		0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
12821203945Sweongyo		0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10,
12822203945Sweongyo		0x00000e10, 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12,
12823203945Sweongyo		0x00000e13, 0x00000e13, 0x00000bf0, 0x00000bf0, 0x00000bf1,
12824203945Sweongyo		0x00000bf1, 0x00000bf2, 0x00000bf2, 0x00000bf3, 0x00000bf3,
12825203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12826203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12827203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12828203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12829203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12830203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12831203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12832203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12833203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12834203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12835203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12836203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12837203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12838203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12839203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12840203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12841203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12842203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12843203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12844203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12845203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12846203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12847203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12848203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
12849203945Sweongyo		0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
12850203945Sweongyo		0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc,
12851203945Sweongyo		0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04,
12852203945Sweongyo		0x0000fcff, 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006,
12853203945Sweongyo		0x0000ff03, 0x000007fc, 0x0000fc08, 0x00000203, 0x0000fffb,
12854203945Sweongyo		0x00000600, 0x0000fa01, 0x0000fc03, 0x0000fe06, 0x0000fe00,
12855203945Sweongyo		0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, 0x000004fd,
12856203945Sweongyo		0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
12857203945Sweongyo		0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa,
12858203945Sweongyo		0x00000700, 0x00000305, 0x000004ff, 0x00000801, 0x00000503,
12859203945Sweongyo		0x000005f9, 0x00000404, 0x0000fb08, 0x000005fd, 0x00000501,
12860203945Sweongyo		0x00000405, 0x0000fb03, 0x000007fc, 0x00000403, 0x00000303,
12861203945Sweongyo		0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, 0x0000fe01,
12862203945Sweongyo		0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
12863203945Sweongyo		0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa,
12864203945Sweongyo		0x000003fe, 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06,
12865203945Sweongyo		0x000008fc, 0x00000701, 0x00000504, 0x0000fdfe, 0x0000fdfc,
12866203945Sweongyo		0x000003fe, 0x00000704, 0x000002fc, 0x000004f9, 0x0000fdfd,
12867203945Sweongyo		0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, 0x000004f9,
12868203945Sweongyo		0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
12869203945Sweongyo		0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa,
12870203945Sweongyo		0x00000305, 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc,
12871203945Sweongyo		0x0000fe03, 0x00000701, 0x000001fb, 0x000001f9, 0x00000206,
12872203945Sweongyo		0x000006fd, 0x00000508, 0x00000700, 0x00000304, 0x000005fe,
12873203945Sweongyo		0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, 0x000007f9,
12874203945Sweongyo		0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
12875203945Sweongyo		0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb,
12876203945Sweongyo		0x00000702,
12877203945Sweongyo	};
12878203945Sweongyo
12879203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
12880203945Sweongyo
12881203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
12882203945Sweongyo	    bwn_tab_sigsq_tbl);
12883203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
12884203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(crsgainnft), crsgainnft);
12885203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(8, 0), N(filterctl), filterctl);
12886203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(psctl), psctl);
12887203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
12888203945Sweongyo	    bwn_tab_pllfrac_tbl);
12889203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
12890203945Sweongyo	    bwn_tabl_iqlocal_tbl);
12891203945Sweongyo	if (mac->mac_phy.rev == 0) {
12892203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r0),
12893203945Sweongyo		    ofdmcckgain_r0);
12894203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r0),
12895203945Sweongyo		    ofdmcckgain_r0);
12896203945Sweongyo	} else {
12897203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r1),
12898203945Sweongyo		    ofdmcckgain_r1);
12899203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r1),
12900203945Sweongyo		    ofdmcckgain_r1);
12901203945Sweongyo	}
12902203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(gaindelta), gaindelta);
12903203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(txpwrctl), txpwrctl);
12904203945Sweongyo}
12905203945Sweongyo
12906203945Sweongyostatic void
12907203945Sweongyobwn_phy_lp_tblinit_r2(struct bwn_mac *mac)
12908203945Sweongyo{
12909204922Sweongyo	struct bwn_softc *sc = mac->mac_sc;
12910203945Sweongyo	int i;
12911203945Sweongyo	static const uint16_t noisescale[] = {
12912203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
12913203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
12914203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
12915203945Sweongyo		0x00a4, 0x00a4, 0x0000, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
12916203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
12917203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
12918203945Sweongyo		0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4
12919203945Sweongyo	};
12920203945Sweongyo	static const uint32_t filterctl[] = {
12921203945Sweongyo		0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27,
12922203945Sweongyo		0x0000217f, 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f
12923203945Sweongyo	};
12924203945Sweongyo	static const uint32_t psctl[] = {
12925203945Sweongyo		0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000,
12926203945Sweongyo		0x00002080, 0x00006180, 0x00003002, 0x00000040, 0x00002042,
12927203945Sweongyo		0x00180047, 0x00080043, 0x00000041, 0x000020c1, 0x00046006,
12928203945Sweongyo		0x00042002, 0x00040000, 0x00002003, 0x00180006, 0x00080002
12929203945Sweongyo	};
12930203945Sweongyo	static const uint32_t gainidx[] = {
12931203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12932203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12933203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12934203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x10000001, 0x00000000,
12935203945Sweongyo		0x20000082, 0x00000000, 0x40000104, 0x00000000, 0x60004207,
12936203945Sweongyo		0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
12937203945Sweongyo		0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288,
12938203945Sweongyo		0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
12939203945Sweongyo		0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794,
12940203945Sweongyo		0x00000010, 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011,
12941203945Sweongyo		0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21,
12942203945Sweongyo		0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
12943203945Sweongyo		0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329,
12944203945Sweongyo		0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
12945203945Sweongyo		0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, 0x00000000,
12946203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12947203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12948203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12949203945Sweongyo		0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082,
12950203945Sweongyo		0x00000000, 0x40000104, 0x00000000, 0x60004207, 0x00000001,
12951203945Sweongyo		0x7000838a, 0x00000001, 0xd021050d, 0x00000001, 0xe041c683,
12952203945Sweongyo		0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
12953203945Sweongyo		0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711,
12954203945Sweongyo		0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
12955203945Sweongyo		0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c,
12956203945Sweongyo		0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019,
12957203945Sweongyo		0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, 0xb36811a6,
12958203945Sweongyo		0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
12959203945Sweongyo		0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c,
12960203945Sweongyo		0x0000001a, 0x64ca55ad, 0x0000001a
12961203945Sweongyo	};
12962203945Sweongyo	static const uint16_t auxgainidx[] = {
12963203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12964203945Sweongyo		0x0000, 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000,
12965203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002,
12966203945Sweongyo		0x0004, 0x0016
12967203945Sweongyo	};
12968203945Sweongyo	static const uint16_t swctl[] = {
12969203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
12970203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
12971203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
12972203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
12973203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
12974203945Sweongyo		0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
12975203945Sweongyo		0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
12976203945Sweongyo		0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018
12977203945Sweongyo	};
12978203945Sweongyo	static const uint8_t hf[] = {
12979203945Sweongyo		0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
12980203945Sweongyo		0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17
12981203945Sweongyo	};
12982203945Sweongyo	static const uint32_t gainval[] = {
12983203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
12984203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
12985203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
12986203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
12987203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
12988203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
12989203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12990203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
12991203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
12992203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
12993203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
12994203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
12995203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009,
12996203945Sweongyo		0x000000f1, 0x00000000, 0x00000000
12997203945Sweongyo	};
12998203945Sweongyo	static const uint16_t gain[] = {
12999203945Sweongyo		0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808,
13000203945Sweongyo		0x080a, 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813,
13001203945Sweongyo		0x0814, 0x0816, 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824,
13002203945Sweongyo		0x0830, 0x0834, 0x0837, 0x083b, 0x083f, 0x0840, 0x0844, 0x0857,
13003203945Sweongyo		0x085b, 0x085f, 0x08d7, 0x08db, 0x08df, 0x0957, 0x095b, 0x095f,
13004203945Sweongyo		0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, 0x175f, 0x0000, 0x0000,
13005203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13006203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13007203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13008203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13009203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13010203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13011203945Sweongyo	};
13012203945Sweongyo	static const uint32_t papdeps[] = {
13013203945Sweongyo		0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9,
13014203945Sweongyo		0x00021fdf, 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7,
13015203945Sweongyo		0x0004efc2, 0x00055fb5, 0x0005cfb0, 0x00063fa8, 0x00068fa3,
13016203945Sweongyo		0x00071f98, 0x0007ef92, 0x00084f8b, 0x0008df82, 0x00097f77,
13017203945Sweongyo		0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, 0x000bff41,
13018203945Sweongyo		0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
13019203945Sweongyo		0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15,
13020203945Sweongyo		0x00143f1c, 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f,
13021203945Sweongyo		0x001e6f7e, 0x0021cfa4, 0x0025bfd2, 0x002a2008, 0x002fb047,
13022203945Sweongyo		0x00360090, 0x003d40e0, 0x0045c135, 0x004fb189, 0x005ae1d7,
13023203945Sweongyo		0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, 0x007ff2e3,
13024203945Sweongyo		0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
13025203945Sweongyo		0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506
13026203945Sweongyo	};
13027203945Sweongyo	static const uint32_t papdmult[] = {
13028203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13029203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13030203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13031203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13032203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13033203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13034203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13035203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13036203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13037203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13038203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13039203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13040203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13041203945Sweongyo	};
13042203945Sweongyo	static const uint32_t gainidx_a0[] = {
13043203945Sweongyo		0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
13044203945Sweongyo		0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
13045203945Sweongyo		0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
13046203945Sweongyo		0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
13047203945Sweongyo		0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
13048203945Sweongyo		0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
13049203945Sweongyo		0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
13050203945Sweongyo		0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
13051203945Sweongyo		0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
13052203945Sweongyo		0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
13053203945Sweongyo		0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
13054203945Sweongyo		0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
13055203945Sweongyo		0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
13056203945Sweongyo	};
13057203945Sweongyo	static const uint16_t auxgainidx_a0[] = {
13058203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13059203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000,
13060203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13061203945Sweongyo		0x0002, 0x0014
13062203945Sweongyo	};
13063203945Sweongyo	static const uint32_t gainval_a0[] = {
13064203945Sweongyo		0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
13065203945Sweongyo		0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
13066203945Sweongyo		0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
13067203945Sweongyo		0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
13068203945Sweongyo		0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
13069203945Sweongyo		0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
13070203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13071203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
13072203945Sweongyo		0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
13073203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
13074203945Sweongyo		0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
13075203945Sweongyo		0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
13076203945Sweongyo		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f,
13077203945Sweongyo		0x000000f7, 0x00000000, 0x00000000
13078203945Sweongyo	};
13079203945Sweongyo	static const uint16_t gain_a0[] = {
13080203945Sweongyo		0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b,
13081203945Sweongyo		0x000c, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016,
13082203945Sweongyo		0x0017, 0x001a, 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034,
13083203945Sweongyo		0x0037, 0x003b, 0x003f, 0x0040, 0x0044, 0x0057, 0x005b, 0x005f,
13084203945Sweongyo		0x00d7, 0x00db, 0x00df, 0x0157, 0x015b, 0x015f, 0x0357, 0x035b,
13085203945Sweongyo		0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, 0x0000, 0x0000, 0x0000,
13086203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13087203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13088203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13089203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13090203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13091203945Sweongyo		0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
13092203945Sweongyo	};
13093203945Sweongyo
13094203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
13095203945Sweongyo
13096203945Sweongyo	for (i = 0; i < 704; i++)
13097203945Sweongyo		bwn_tab_write(mac, BWN_TAB_4(7, i), 0);
13098203945Sweongyo
13099203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
13100203945Sweongyo	    bwn_tab_sigsq_tbl);
13101203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
13102203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(11, 0), N(filterctl), filterctl);
13103203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(12, 0), N(psctl), psctl);
13104203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx), gainidx);
13105203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx), auxgainidx);
13106203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(swctl), swctl);
13107203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(16, 0), N(hf), hf);
13108203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval), gainval);
13109203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain), gain);
13110203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
13111203945Sweongyo	    bwn_tab_pllfrac_tbl);
13112203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
13113203945Sweongyo	    bwn_tabl_iqlocal_tbl);
13114203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(papdeps), papdeps);
13115203945Sweongyo	bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(papdmult), papdmult);
13116203945Sweongyo
13117204922Sweongyo	if ((siba_get_chipid(sc->sc_dev) == 0x4325) &&
13118204922Sweongyo	    (siba_get_chiprev(sc->sc_dev) == 0)) {
13119203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx_a0),
13120203945Sweongyo		    gainidx_a0);
13121203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx_a0),
13122203945Sweongyo		    auxgainidx_a0);
13123203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval_a0),
13124203945Sweongyo		    gainval_a0);
13125203945Sweongyo		bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain_a0), gain_a0);
13126203945Sweongyo	}
13127203945Sweongyo}
13128203945Sweongyo
13129203945Sweongyostatic void
13130203945Sweongyobwn_phy_lp_tblinit_txgain(struct bwn_mac *mac)
13131203945Sweongyo{
13132203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
13133287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
13134203945Sweongyo	static struct bwn_txgain_entry txgain_r2[] = {
13135203945Sweongyo		{ 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 },
13136203945Sweongyo		{ 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 },
13137203945Sweongyo		{ 255, 255, 203, 0, 135 }, { 255, 255, 203, 0, 131 },
13138203945Sweongyo		{ 255, 255, 203, 0, 128 }, { 255, 255, 203, 0, 124 },
13139203945Sweongyo		{ 255, 255, 203, 0, 121 }, { 255, 255, 203, 0, 117 },
13140203945Sweongyo		{ 255, 255, 203, 0, 114 }, { 255, 255, 203, 0, 111 },
13141203945Sweongyo		{ 255, 255, 203, 0, 107 }, { 255, 255, 203, 0, 104 },
13142203945Sweongyo		{ 255, 255, 203, 0, 101 }, { 255, 255, 203, 0, 99 },
13143203945Sweongyo		{ 255, 255, 203, 0, 96 }, { 255, 255, 203, 0, 93 },
13144203945Sweongyo		{ 255, 255, 203, 0, 90 }, { 255, 255, 203, 0, 88 },
13145203945Sweongyo		{ 255, 255, 203, 0, 85 }, { 255, 255, 203, 0, 83 },
13146203945Sweongyo		{ 255, 255, 203, 0, 81 }, { 255, 255, 203, 0, 78 },
13147203945Sweongyo		{ 255, 255, 203, 0, 76 }, { 255, 255, 203, 0, 74 },
13148203945Sweongyo		{ 255, 255, 203, 0, 72 }, { 255, 255, 203, 0, 70 },
13149203945Sweongyo		{ 255, 255, 203, 0, 68 }, { 255, 255, 203, 0, 66 },
13150203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13151203945Sweongyo		{ 255, 255, 192, 0, 64 }, { 255, 255, 186, 0, 64 },
13152203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 176, 0, 64 },
13153203945Sweongyo		{ 255, 255, 171, 0, 64 }, { 255, 255, 166, 0, 64 },
13154203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 157, 0, 64 },
13155203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13156203945Sweongyo		{ 255, 255, 144, 0, 64 }, { 255, 255, 140, 0, 64 },
13157203945Sweongyo		{ 255, 255, 136, 0, 64 }, { 255, 255, 132, 0, 64 },
13158203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13159203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13160203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13161203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 105, 0, 64 },
13162203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13163203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13164203945Sweongyo		{ 255, 255, 91, 0, 64 }, { 255, 255, 88, 0, 64 },
13165203945Sweongyo		{ 255, 255, 86, 0, 64 }, { 255, 255, 83, 0, 64 },
13166203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 79, 0, 64 },
13167203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13168203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13169203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13170203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 248, 64, 0, 64 },
13171203945Sweongyo		{ 255, 248, 62, 0, 64 }, { 255, 241, 62, 0, 64 },
13172203945Sweongyo		{ 255, 241, 60, 0, 64 }, { 255, 234, 60, 0, 64 },
13173203945Sweongyo		{ 255, 234, 59, 0, 64 }, { 255, 227, 59, 0, 64 },
13174203945Sweongyo		{ 255, 227, 57, 0, 64 }, { 255, 221, 57, 0, 64 },
13175203945Sweongyo		{ 255, 221, 55, 0, 64 }, { 255, 215, 55, 0, 64 },
13176203945Sweongyo		{ 255, 215, 54, 0, 64 }, { 255, 208, 54, 0, 64 },
13177203945Sweongyo		{ 255, 208, 52, 0, 64 }, { 255, 203, 52, 0, 64 },
13178203945Sweongyo		{ 255, 203, 51, 0, 64 }, { 255, 197, 51, 0, 64 },
13179203945Sweongyo		{ 255, 197, 49, 0, 64 }, { 255, 191, 49, 0, 64 },
13180203945Sweongyo		{ 255, 191, 48, 0, 64 }, { 255, 186, 48, 0, 64 },
13181203945Sweongyo		{ 255, 186, 47, 0, 64 }, { 255, 181, 47, 0, 64 },
13182203945Sweongyo		{ 255, 181, 45, 0, 64 }, { 255, 175, 45, 0, 64 },
13183203945Sweongyo		{ 255, 175, 44, 0, 64 }, { 255, 170, 44, 0, 64 },
13184203945Sweongyo		{ 255, 170, 43, 0, 64 }, { 255, 166, 43, 0, 64 },
13185203945Sweongyo		{ 255, 166, 42, 0, 64 }, { 255, 161, 42, 0, 64 },
13186203945Sweongyo		{ 255, 161, 40, 0, 64 }, { 255, 156, 40, 0, 64 },
13187203945Sweongyo		{ 255, 156, 39, 0, 64 }, { 255, 152, 39, 0, 64 },
13188203945Sweongyo		{ 255, 152, 38, 0, 64 }, { 255, 148, 38, 0, 64 },
13189203945Sweongyo		{ 255, 148, 37, 0, 64 }, { 255, 143, 37, 0, 64 },
13190203945Sweongyo		{ 255, 143, 36, 0, 64 }, { 255, 139, 36, 0, 64 },
13191203945Sweongyo		{ 255, 139, 35, 0, 64 }, { 255, 135, 35, 0, 64 },
13192203945Sweongyo		{ 255, 135, 34, 0, 64 }, { 255, 132, 34, 0, 64 },
13193203945Sweongyo		{ 255, 132, 33, 0, 64 }, { 255, 128, 33, 0, 64 },
13194203945Sweongyo		{ 255, 128, 32, 0, 64 }, { 255, 124, 32, 0, 64 },
13195203945Sweongyo		{ 255, 124, 31, 0, 64 }, { 255, 121, 31, 0, 64 },
13196203945Sweongyo		{ 255, 121, 30, 0, 64 }, { 255, 117, 30, 0, 64 },
13197203945Sweongyo		{ 255, 117, 29, 0, 64 }, { 255, 114, 29, 0, 64 },
13198203945Sweongyo		{ 255, 114, 29, 0, 64 }, { 255, 111, 29, 0, 64 },
13199203945Sweongyo	};
13200203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r2[] = {
13201203945Sweongyo		{ 7, 99, 255, 0, 64 }, { 7, 96, 255, 0, 64 },
13202203945Sweongyo		{ 7, 93, 255, 0, 64 }, { 7, 90, 255, 0, 64 },
13203203945Sweongyo		{ 7, 88, 255, 0, 64 }, { 7, 85, 255, 0, 64 },
13204203945Sweongyo		{ 7, 83, 255, 0, 64 }, { 7, 81, 255, 0, 64 },
13205203945Sweongyo		{ 7, 78, 255, 0, 64 }, { 7, 76, 255, 0, 64 },
13206203945Sweongyo		{ 7, 74, 255, 0, 64 }, { 7, 72, 255, 0, 64 },
13207203945Sweongyo		{ 7, 70, 255, 0, 64 }, { 7, 68, 255, 0, 64 },
13208203945Sweongyo		{ 7, 66, 255, 0, 64 }, { 7, 64, 255, 0, 64 },
13209203945Sweongyo		{ 7, 64, 255, 0, 64 }, { 7, 62, 255, 0, 64 },
13210203945Sweongyo		{ 7, 62, 248, 0, 64 }, { 7, 60, 248, 0, 64 },
13211203945Sweongyo		{ 7, 60, 241, 0, 64 }, { 7, 59, 241, 0, 64 },
13212203945Sweongyo		{ 7, 59, 234, 0, 64 }, { 7, 57, 234, 0, 64 },
13213203945Sweongyo		{ 7, 57, 227, 0, 64 }, { 7, 55, 227, 0, 64 },
13214203945Sweongyo		{ 7, 55, 221, 0, 64 }, { 7, 54, 221, 0, 64 },
13215203945Sweongyo		{ 7, 54, 215, 0, 64 }, { 7, 52, 215, 0, 64 },
13216203945Sweongyo		{ 7, 52, 208, 0, 64 }, { 7, 51, 208, 0, 64 },
13217203945Sweongyo		{ 7, 51, 203, 0, 64 }, { 7, 49, 203, 0, 64 },
13218203945Sweongyo		{ 7, 49, 197, 0, 64 }, { 7, 48, 197, 0, 64 },
13219203945Sweongyo		{ 7, 48, 191, 0, 64 }, { 7, 47, 191, 0, 64 },
13220203945Sweongyo		{ 7, 47, 186, 0, 64 }, { 7, 45, 186, 0, 64 },
13221203945Sweongyo		{ 7, 45, 181, 0, 64 }, { 7, 44, 181, 0, 64 },
13222203945Sweongyo		{ 7, 44, 175, 0, 64 }, { 7, 43, 175, 0, 64 },
13223203945Sweongyo		{ 7, 43, 170, 0, 64 }, { 7, 42, 170, 0, 64 },
13224203945Sweongyo		{ 7, 42, 166, 0, 64 }, { 7, 40, 166, 0, 64 },
13225203945Sweongyo		{ 7, 40, 161, 0, 64 }, { 7, 39, 161, 0, 64 },
13226203945Sweongyo		{ 7, 39, 156, 0, 64 }, { 7, 38, 156, 0, 64 },
13227203945Sweongyo		{ 7, 38, 152, 0, 64 }, { 7, 37, 152, 0, 64 },
13228203945Sweongyo		{ 7, 37, 148, 0, 64 }, { 7, 36, 148, 0, 64 },
13229203945Sweongyo		{ 7, 36, 143, 0, 64 }, { 7, 35, 143, 0, 64 },
13230203945Sweongyo		{ 7, 35, 139, 0, 64 }, { 7, 34, 139, 0, 64 },
13231203945Sweongyo		{ 7, 34, 135, 0, 64 }, { 7, 33, 135, 0, 64 },
13232203945Sweongyo		{ 7, 33, 132, 0, 64 }, { 7, 32, 132, 0, 64 },
13233203945Sweongyo		{ 7, 32, 128, 0, 64 }, { 7, 31, 128, 0, 64 },
13234203945Sweongyo		{ 7, 31, 124, 0, 64 }, { 7, 30, 124, 0, 64 },
13235203945Sweongyo		{ 7, 30, 121, 0, 64 }, { 7, 29, 121, 0, 64 },
13236203945Sweongyo		{ 7, 29, 117, 0, 64 }, { 7, 29, 117, 0, 64 },
13237203945Sweongyo		{ 7, 29, 114, 0, 64 }, { 7, 28, 114, 0, 64 },
13238203945Sweongyo		{ 7, 28, 111, 0, 64 }, { 7, 27, 111, 0, 64 },
13239203945Sweongyo		{ 7, 27, 108, 0, 64 }, { 7, 26, 108, 0, 64 },
13240203945Sweongyo		{ 7, 26, 104, 0, 64 }, { 7, 25, 104, 0, 64 },
13241203945Sweongyo		{ 7, 25, 102, 0, 64 }, { 7, 25, 102, 0, 64 },
13242203945Sweongyo		{ 7, 25, 99, 0, 64 }, { 7, 24, 99, 0, 64 },
13243203945Sweongyo		{ 7, 24, 96, 0, 64 }, { 7, 23, 96, 0, 64 },
13244203945Sweongyo		{ 7, 23, 93, 0, 64 }, { 7, 23, 93, 0, 64 },
13245203945Sweongyo		{ 7, 23, 90, 0, 64 }, { 7, 22, 90, 0, 64 },
13246203945Sweongyo		{ 7, 22, 88, 0, 64 }, { 7, 21, 88, 0, 64 },
13247203945Sweongyo		{ 7, 21, 85, 0, 64 }, { 7, 21, 85, 0, 64 },
13248203945Sweongyo		{ 7, 21, 83, 0, 64 }, { 7, 20, 83, 0, 64 },
13249203945Sweongyo		{ 7, 20, 81, 0, 64 }, { 7, 20, 81, 0, 64 },
13250203945Sweongyo		{ 7, 20, 78, 0, 64 }, { 7, 19, 78, 0, 64 },
13251203945Sweongyo		{ 7, 19, 76, 0, 64 }, { 7, 19, 76, 0, 64 },
13252203945Sweongyo		{ 7, 19, 74, 0, 64 }, { 7, 18, 74, 0, 64 },
13253203945Sweongyo		{ 7, 18, 72, 0, 64 }, { 7, 18, 72, 0, 64 },
13254203945Sweongyo		{ 7, 18, 70, 0, 64 }, { 7, 17, 70, 0, 64 },
13255203945Sweongyo		{ 7, 17, 68, 0, 64 }, { 7, 17, 68, 0, 64 },
13256203945Sweongyo		{ 7, 17, 66, 0, 64 }, { 7, 16, 66, 0, 64 },
13257203945Sweongyo		{ 7, 16, 64, 0, 64 }, { 7, 16, 64, 0, 64 },
13258203945Sweongyo		{ 7, 16, 62, 0, 64 }, { 7, 15, 62, 0, 64 },
13259203945Sweongyo		{ 7, 15, 60, 0, 64 }, { 7, 15, 60, 0, 64 },
13260203945Sweongyo		{ 7, 15, 59, 0, 64 }, { 7, 14, 59, 0, 64 },
13261203945Sweongyo		{ 7, 14, 57, 0, 64 }, { 7, 14, 57, 0, 64 },
13262203945Sweongyo		{ 7, 14, 55, 0, 64 }, { 7, 14, 55, 0, 64 },
13263203945Sweongyo		{ 7, 14, 54, 0, 64 }, { 7, 13, 54, 0, 64 },
13264203945Sweongyo		{ 7, 13, 52, 0, 64 }, { 7, 13, 52, 0, 64 },
13265203945Sweongyo	};
13266203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r2[] = {
13267203945Sweongyo		{ 255, 255, 255, 0, 152 }, { 255, 255, 255, 0, 147 },
13268203945Sweongyo		{ 255, 255, 255, 0, 143 }, { 255, 255, 255, 0, 139 },
13269203945Sweongyo		{ 255, 255, 255, 0, 135 }, { 255, 255, 255, 0, 131 },
13270203945Sweongyo		{ 255, 255, 255, 0, 128 }, { 255, 255, 255, 0, 124 },
13271203945Sweongyo		{ 255, 255, 255, 0, 121 }, { 255, 255, 255, 0, 117 },
13272203945Sweongyo		{ 255, 255, 255, 0, 114 }, { 255, 255, 255, 0, 111 },
13273203945Sweongyo		{ 255, 255, 255, 0, 107 }, { 255, 255, 255, 0, 104 },
13274203945Sweongyo		{ 255, 255, 255, 0, 101 }, { 255, 255, 255, 0, 99 },
13275203945Sweongyo		{ 255, 255, 255, 0, 96 }, { 255, 255, 255, 0, 93 },
13276203945Sweongyo		{ 255, 255, 255, 0, 90 }, { 255, 255, 255, 0, 88 },
13277203945Sweongyo		{ 255, 255, 255, 0, 85 }, { 255, 255, 255, 0, 83 },
13278203945Sweongyo		{ 255, 255, 255, 0, 81 }, { 255, 255, 255, 0, 78 },
13279203945Sweongyo		{ 255, 255, 255, 0, 76 }, { 255, 255, 255, 0, 74 },
13280203945Sweongyo		{ 255, 255, 255, 0, 72 }, { 255, 255, 255, 0, 70 },
13281203945Sweongyo		{ 255, 255, 255, 0, 68 }, { 255, 255, 255, 0, 66 },
13282203945Sweongyo		{ 255, 255, 255, 0, 64 }, { 255, 255, 248, 0, 64 },
13283203945Sweongyo		{ 255, 255, 241, 0, 64 }, { 255, 255, 234, 0, 64 },
13284203945Sweongyo		{ 255, 255, 227, 0, 64 }, { 255, 255, 221, 0, 64 },
13285203945Sweongyo		{ 255, 255, 215, 0, 64 }, { 255, 255, 208, 0, 64 },
13286203945Sweongyo		{ 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
13287203945Sweongyo		{ 255, 255, 191, 0, 64 }, { 255, 255, 186, 0, 64 },
13288203945Sweongyo		{ 255, 255, 181, 0, 64 }, { 255, 255, 175, 0, 64 },
13289203945Sweongyo		{ 255, 255, 170, 0, 64 }, { 255, 255, 166, 0, 64 },
13290203945Sweongyo		{ 255, 255, 161, 0, 64 }, { 255, 255, 156, 0, 64 },
13291203945Sweongyo		{ 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
13292203945Sweongyo		{ 255, 255, 143, 0, 64 }, { 255, 255, 139, 0, 64 },
13293203945Sweongyo		{ 255, 255, 135, 0, 64 }, { 255, 255, 132, 0, 64 },
13294203945Sweongyo		{ 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
13295203945Sweongyo		{ 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
13296203945Sweongyo		{ 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
13297203945Sweongyo		{ 255, 255, 108, 0, 64 }, { 255, 255, 104, 0, 64 },
13298203945Sweongyo		{ 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
13299203945Sweongyo		{ 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
13300203945Sweongyo		{ 255, 255, 90, 0, 64 }, { 255, 255, 88, 0, 64 },
13301203945Sweongyo		{ 255, 255, 85, 0, 64 }, { 255, 255, 83, 0, 64 },
13302203945Sweongyo		{ 255, 255, 81, 0, 64 }, { 255, 255, 78, 0, 64 },
13303203945Sweongyo		{ 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
13304203945Sweongyo		{ 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
13305203945Sweongyo		{ 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
13306203945Sweongyo		{ 255, 255, 64, 0, 64 }, { 255, 255, 64, 0, 64 },
13307203945Sweongyo		{ 255, 255, 62, 0, 64 }, { 255, 248, 62, 0, 64 },
13308203945Sweongyo		{ 255, 248, 60, 0, 64 }, { 255, 241, 60, 0, 64 },
13309203945Sweongyo		{ 255, 241, 59, 0, 64 }, { 255, 234, 59, 0, 64 },
13310203945Sweongyo		{ 255, 234, 57, 0, 64 }, { 255, 227, 57, 0, 64 },
13311203945Sweongyo		{ 255, 227, 55, 0, 64 }, { 255, 221, 55, 0, 64 },
13312203945Sweongyo		{ 255, 221, 54, 0, 64 }, { 255, 215, 54, 0, 64 },
13313203945Sweongyo		{ 255, 215, 52, 0, 64 }, { 255, 208, 52, 0, 64 },
13314203945Sweongyo		{ 255, 208, 51, 0, 64 }, { 255, 203, 51, 0, 64 },
13315203945Sweongyo		{ 255, 203, 49, 0, 64 }, { 255, 197, 49, 0, 64 },
13316203945Sweongyo		{ 255, 197, 48, 0, 64 }, { 255, 191, 48, 0, 64 },
13317203945Sweongyo		{ 255, 191, 47, 0, 64 }, { 255, 186, 47, 0, 64 },
13318203945Sweongyo		{ 255, 186, 45, 0, 64 }, { 255, 181, 45, 0, 64 },
13319203945Sweongyo		{ 255, 181, 44, 0, 64 }, { 255, 175, 44, 0, 64 },
13320203945Sweongyo		{ 255, 175, 43, 0, 64 }, { 255, 170, 43, 0, 64 },
13321203945Sweongyo		{ 255, 170, 42, 0, 64 }, { 255, 166, 42, 0, 64 },
13322203945Sweongyo		{ 255, 166, 40, 0, 64 }, { 255, 161, 40, 0, 64 },
13323203945Sweongyo		{ 255, 161, 39, 0, 64 }, { 255, 156, 39, 0, 64 },
13324203945Sweongyo		{ 255, 156, 38, 0, 64 }, { 255, 152, 38, 0, 64 },
13325203945Sweongyo		{ 255, 152, 37, 0, 64 }, { 255, 148, 37, 0, 64 },
13326203945Sweongyo		{ 255, 148, 36, 0, 64 }, { 255, 143, 36, 0, 64 },
13327203945Sweongyo		{ 255, 143, 35, 0, 64 }, { 255, 139, 35, 0, 64 },
13328203945Sweongyo		{ 255, 139, 34, 0, 64 }, { 255, 135, 34, 0, 64 },
13329203945Sweongyo		{ 255, 135, 33, 0, 64 }, { 255, 132, 33, 0, 64 },
13330203945Sweongyo		{ 255, 132, 32, 0, 64 }, { 255, 128, 32, 0, 64 }
13331203945Sweongyo	};
13332203945Sweongyo	static struct bwn_txgain_entry txgain_r0[] = {
13333203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13334203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13335203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13336203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13337203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13338203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13339203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13340203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13341203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13342203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13343203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13344203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13345203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13346203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13347203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13348203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13349203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13350203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13351203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 13, 0, 68 },
13352203945Sweongyo		{ 7, 15, 13, 0, 66 }, { 7, 15, 13, 0, 64 },
13353203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13354203945Sweongyo		{ 7, 15, 13, 0, 59 }, { 7, 15, 13, 0, 57 },
13355203945Sweongyo		{ 7, 15, 12, 0, 71 }, { 7, 15, 12, 0, 69 },
13356203945Sweongyo		{ 7, 15, 12, 0, 67 }, { 7, 15, 12, 0, 65 },
13357203945Sweongyo		{ 7, 15, 12, 0, 63 }, { 7, 15, 12, 0, 62 },
13358203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 58 },
13359203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 70 },
13360203945Sweongyo		{ 7, 15, 11, 0, 68 }, { 7, 15, 11, 0, 66 },
13361203945Sweongyo		{ 7, 15, 11, 0, 65 }, { 7, 15, 11, 0, 63 },
13362203945Sweongyo		{ 7, 15, 11, 0, 61 }, { 7, 15, 11, 0, 59 },
13363203945Sweongyo		{ 7, 15, 11, 0, 58 }, { 7, 15, 10, 0, 71 },
13364203945Sweongyo		{ 7, 15, 10, 0, 69 }, { 7, 15, 10, 0, 67 },
13365203945Sweongyo		{ 7, 15, 10, 0, 65 }, { 7, 15, 10, 0, 63 },
13366203945Sweongyo		{ 7, 15, 10, 0, 61 }, { 7, 15, 10, 0, 60 },
13367203945Sweongyo		{ 7, 15, 10, 0, 58 }, { 7, 15, 10, 0, 56 },
13368203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13369203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13370203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 60 },
13371203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 14, 9, 0, 72 },
13372203945Sweongyo		{ 7, 14, 9, 0, 70 }, { 7, 14, 9, 0, 68 },
13373203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 64 },
13374203945Sweongyo		{ 7, 14, 9, 0, 62 }, { 7, 14, 9, 0, 60 },
13375203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 13, 9, 0, 72 },
13376203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13377203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13378203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13379203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13380203945Sweongyo		{ 7, 13, 8, 0, 72 }, { 7, 13, 8, 0, 70 },
13381203945Sweongyo		{ 7, 13, 8, 0, 68 }, { 7, 13, 8, 0, 66 },
13382203945Sweongyo		{ 7, 13, 8, 0, 64 }, { 7, 13, 8, 0, 62 },
13383203945Sweongyo		{ 7, 13, 8, 0, 60 }, { 7, 13, 8, 0, 59 },
13384203945Sweongyo		{ 7, 12, 8, 0, 72 }, { 7, 12, 8, 0, 70 },
13385203945Sweongyo		{ 7, 12, 8, 0, 68 }, { 7, 12, 8, 0, 66 },
13386203945Sweongyo		{ 7, 12, 8, 0, 64 }, { 7, 12, 8, 0, 62 },
13387203945Sweongyo		{ 7, 12, 8, 0, 61 }, { 7, 12, 8, 0, 59 },
13388203945Sweongyo		{ 7, 12, 7, 0, 73 }, { 7, 12, 7, 0, 71 },
13389203945Sweongyo		{ 7, 12, 7, 0, 69 }, { 7, 12, 7, 0, 67 },
13390203945Sweongyo		{ 7, 12, 7, 0, 65 }, { 7, 12, 7, 0, 63 },
13391203945Sweongyo		{ 7, 12, 7, 0, 61 }, { 7, 12, 7, 0, 59 },
13392203945Sweongyo		{ 7, 11, 7, 0, 72 }, { 7, 11, 7, 0, 70 },
13393203945Sweongyo		{ 7, 11, 7, 0, 68 }, { 7, 11, 7, 0, 66 },
13394203945Sweongyo		{ 7, 11, 7, 0, 65 }, { 7, 11, 7, 0, 63 },
13395203945Sweongyo		{ 7, 11, 7, 0, 61 }, { 7, 11, 7, 0, 59 },
13396203945Sweongyo		{ 7, 11, 6, 0, 73 }, { 7, 11, 6, 0, 71 }
13397203945Sweongyo	};
13398203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r0[] = {
13399203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13400203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13401203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13402203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13403203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13404203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13405203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13406203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13407203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13408203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13409203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13410203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13411203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13412203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13413203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13414203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13415203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13416203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13417203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13418203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13419203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13420203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13421203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13422203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13423203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13424203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13425203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13426203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13427203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13428203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13429203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13430203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13431203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13432203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 },
13433203945Sweongyo		{ 4, 10, 6, 0, 59 }, { 4, 10, 5, 0, 72 },
13434203945Sweongyo		{ 4, 10, 5, 0, 70 }, { 4, 10, 5, 0, 68 },
13435203945Sweongyo		{ 4, 10, 5, 0, 66 }, { 4, 10, 5, 0, 64 },
13436203945Sweongyo		{ 4, 10, 5, 0, 62 }, { 4, 10, 5, 0, 60 },
13437203945Sweongyo		{ 4, 10, 5, 0, 59 }, { 4, 9, 5, 0, 70 },
13438203945Sweongyo		{ 4, 9, 5, 0, 68 }, { 4, 9, 5, 0, 66 },
13439203945Sweongyo		{ 4, 9, 5, 0, 64 }, { 4, 9, 5, 0, 63 },
13440203945Sweongyo		{ 4, 9, 5, 0, 61 }, { 4, 9, 5, 0, 59 },
13441203945Sweongyo		{ 4, 9, 4, 0, 71 }, { 4, 9, 4, 0, 69 },
13442203945Sweongyo		{ 4, 9, 4, 0, 67 }, { 4, 9, 4, 0, 65 },
13443203945Sweongyo		{ 4, 9, 4, 0, 63 }, { 4, 9, 4, 0, 62 },
13444203945Sweongyo		{ 4, 9, 4, 0, 60 }, { 4, 9, 4, 0, 58 },
13445203945Sweongyo		{ 4, 8, 4, 0, 70 }, { 4, 8, 4, 0, 68 },
13446203945Sweongyo		{ 4, 8, 4, 0, 66 }, { 4, 8, 4, 0, 65 },
13447203945Sweongyo		{ 4, 8, 4, 0, 63 }, { 4, 8, 4, 0, 61 },
13448203945Sweongyo		{ 4, 8, 4, 0, 59 }, { 4, 7, 4, 0, 68 },
13449203945Sweongyo		{ 4, 7, 4, 0, 66 }, { 4, 7, 4, 0, 64 },
13450203945Sweongyo		{ 4, 7, 4, 0, 62 }, { 4, 7, 4, 0, 61 },
13451203945Sweongyo		{ 4, 7, 4, 0, 59 }, { 4, 7, 3, 0, 67 },
13452203945Sweongyo		{ 4, 7, 3, 0, 65 }, { 4, 7, 3, 0, 63 },
13453203945Sweongyo		{ 4, 7, 3, 0, 62 }, { 4, 7, 3, 0, 60 },
13454203945Sweongyo		{ 4, 6, 3, 0, 65 }, { 4, 6, 3, 0, 63 },
13455203945Sweongyo		{ 4, 6, 3, 0, 61 }, { 4, 6, 3, 0, 60 },
13456203945Sweongyo		{ 4, 6, 3, 0, 58 }, { 4, 5, 3, 0, 68 },
13457203945Sweongyo		{ 4, 5, 3, 0, 66 }, { 4, 5, 3, 0, 64 },
13458203945Sweongyo		{ 4, 5, 3, 0, 62 }, { 4, 5, 3, 0, 60 },
13459203945Sweongyo		{ 4, 5, 3, 0, 59 }, { 4, 5, 3, 0, 57 },
13460203945Sweongyo		{ 4, 4, 2, 0, 83 }, { 4, 4, 2, 0, 81 },
13461203945Sweongyo		{ 4, 4, 2, 0, 78 }, { 4, 4, 2, 0, 76 },
13462203945Sweongyo		{ 4, 4, 2, 0, 74 }, { 4, 4, 2, 0, 72 }
13463203945Sweongyo	};
13464203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r0[] = {
13465203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13466203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13467203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13468203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13469203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13470203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13471203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13472203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13473203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13474203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13475203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13476203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13477203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13478203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13479203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13480203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13481203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13482203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13483203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13484203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13485203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13486203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13487203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13488203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13489203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13490203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13491203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13492203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13493203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13494203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13495203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13496203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13497203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13498203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13499203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13500203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13501203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13502203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13503203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13504203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13505203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13506203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13507203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13508203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13509203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13510203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13511203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13512203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13513203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13514203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13515203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13516203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13517203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13518203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13519203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13520203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13521203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13522203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13523203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13524203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13525203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13526203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13527203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13528203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13529203945Sweongyo	};
13530203945Sweongyo	static struct bwn_txgain_entry txgain_r1[] = {
13531203945Sweongyo		{ 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
13532203945Sweongyo		{ 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
13533203945Sweongyo		{ 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
13534203945Sweongyo		{ 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
13535203945Sweongyo		{ 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
13536203945Sweongyo		{ 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
13537203945Sweongyo		{ 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
13538203945Sweongyo		{ 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
13539203945Sweongyo		{ 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
13540203945Sweongyo		{ 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
13541203945Sweongyo		{ 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
13542203945Sweongyo		{ 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
13543203945Sweongyo		{ 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
13544203945Sweongyo		{ 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
13545203945Sweongyo		{ 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
13546203945Sweongyo		{ 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
13547203945Sweongyo		{ 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
13548203945Sweongyo		{ 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
13549203945Sweongyo		{ 7, 15, 13, 0, 70 }, { 7, 15, 14, 0, 68 },
13550203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13551203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13552203945Sweongyo		{ 7, 15, 14, 0, 59 }, { 7, 15, 14, 0, 57 },
13553203945Sweongyo		{ 7, 15, 13, 0, 72 }, { 7, 15, 13, 0, 70 },
13554203945Sweongyo		{ 7, 15, 13, 0, 68 }, { 7, 15, 13, 0, 66 },
13555203945Sweongyo		{ 7, 15, 13, 0, 64 }, { 7, 15, 13, 0, 62 },
13556203945Sweongyo		{ 7, 15, 13, 0, 60 }, { 7, 15, 13, 0, 59 },
13557203945Sweongyo		{ 7, 15, 13, 0, 57 }, { 7, 15, 12, 0, 71 },
13558203945Sweongyo		{ 7, 15, 12, 0, 69 }, { 7, 15, 12, 0, 67 },
13559203945Sweongyo		{ 7, 15, 12, 0, 65 }, { 7, 15, 12, 0, 63 },
13560203945Sweongyo		{ 7, 15, 12, 0, 62 }, { 7, 15, 12, 0, 60 },
13561203945Sweongyo		{ 7, 15, 12, 0, 58 }, { 7, 15, 12, 0, 57 },
13562203945Sweongyo		{ 7, 15, 11, 0, 70 }, { 7, 15, 11, 0, 68 },
13563203945Sweongyo		{ 7, 15, 11, 0, 66 }, { 7, 15, 11, 0, 65 },
13564203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13565203945Sweongyo		{ 7, 15, 11, 0, 59 }, { 7, 15, 11, 0, 58 },
13566203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13567203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13568203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13569203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13570203945Sweongyo		{ 7, 15, 10, 0, 56 }, { 7, 15, 9, 0, 70 },
13571203945Sweongyo		{ 7, 15, 9, 0, 68 }, { 7, 15, 9, 0, 66 },
13572203945Sweongyo		{ 7, 15, 9, 0, 64 }, { 7, 15, 9, 0, 62 },
13573203945Sweongyo		{ 7, 15, 9, 0, 60 }, { 7, 15, 9, 0, 59 },
13574203945Sweongyo		{ 7, 14, 9, 0, 72 }, { 7, 14, 9, 0, 70 },
13575203945Sweongyo		{ 7, 14, 9, 0, 68 }, { 7, 14, 9, 0, 66 },
13576203945Sweongyo		{ 7, 14, 9, 0, 64 }, { 7, 14, 9, 0, 62 },
13577203945Sweongyo		{ 7, 14, 9, 0, 60 }, { 7, 14, 9, 0, 59 },
13578203945Sweongyo		{ 7, 13, 9, 0, 72 }, { 7, 13, 9, 0, 70 },
13579203945Sweongyo		{ 7, 13, 9, 0, 68 }, { 7, 13, 9, 0, 66 },
13580203945Sweongyo		{ 7, 13, 9, 0, 64 }, { 7, 13, 9, 0, 63 },
13581203945Sweongyo		{ 7, 13, 9, 0, 61 }, { 7, 13, 9, 0, 59 },
13582203945Sweongyo		{ 7, 13, 9, 0, 57 }, { 7, 13, 8, 0, 72 },
13583203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13584203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13585203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13586203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 12, 8, 0, 72 },
13587203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13588203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13589203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13590203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 7, 0, 73 },
13591203945Sweongyo		{ 7, 12, 7, 0, 71 }, { 7, 12, 7, 0, 69 },
13592203945Sweongyo		{ 7, 12, 7, 0, 67 }, { 7, 12, 7, 0, 65 },
13593203945Sweongyo		{ 7, 12, 7, 0, 63 }, { 7, 12, 7, 0, 61 },
13594203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 11, 7, 0, 72 },
13595203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13596203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 65 },
13597203945Sweongyo		{ 7, 11, 7, 0, 63 }, { 7, 11, 7, 0, 61 },
13598203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 6, 0, 73 },
13599203945Sweongyo		{ 7, 11, 6, 0, 71 }
13600203945Sweongyo	};
13601203945Sweongyo	static struct bwn_txgain_entry txgain_2ghz_r1[] = {
13602203945Sweongyo		{ 4, 15, 15, 0, 90 }, { 4, 15, 15, 0, 88 },
13603203945Sweongyo		{ 4, 15, 15, 0, 85 }, { 4, 15, 15, 0, 83 },
13604203945Sweongyo		{ 4, 15, 15, 0, 81 }, { 4, 15, 15, 0, 78 },
13605203945Sweongyo		{ 4, 15, 15, 0, 76 }, { 4, 15, 15, 0, 74 },
13606203945Sweongyo		{ 4, 15, 15, 0, 72 }, { 4, 15, 15, 0, 70 },
13607203945Sweongyo		{ 4, 15, 15, 0, 68 }, { 4, 15, 15, 0, 66 },
13608203945Sweongyo		{ 4, 15, 15, 0, 64 }, { 4, 15, 15, 0, 62 },
13609203945Sweongyo		{ 4, 15, 15, 0, 60 }, { 4, 15, 15, 0, 59 },
13610203945Sweongyo		{ 4, 15, 14, 0, 72 }, { 4, 15, 14, 0, 70 },
13611203945Sweongyo		{ 4, 15, 14, 0, 68 }, { 4, 15, 14, 0, 66 },
13612203945Sweongyo		{ 4, 15, 14, 0, 64 }, { 4, 15, 14, 0, 62 },
13613203945Sweongyo		{ 4, 15, 14, 0, 60 }, { 4, 15, 14, 0, 59 },
13614203945Sweongyo		{ 4, 15, 13, 0, 72 }, { 4, 15, 13, 0, 70 },
13615203945Sweongyo		{ 4, 15, 13, 0, 68 }, { 4, 15, 13, 0, 66 },
13616203945Sweongyo		{ 4, 15, 13, 0, 64 }, { 4, 15, 13, 0, 62 },
13617203945Sweongyo		{ 4, 15, 13, 0, 60 }, { 4, 15, 13, 0, 59 },
13618203945Sweongyo		{ 4, 15, 12, 0, 72 }, { 4, 15, 12, 0, 70 },
13619203945Sweongyo		{ 4, 15, 12, 0, 68 }, { 4, 15, 12, 0, 66 },
13620203945Sweongyo		{ 4, 15, 12, 0, 64 }, { 4, 15, 12, 0, 62 },
13621203945Sweongyo		{ 4, 15, 12, 0, 60 }, { 4, 15, 12, 0, 59 },
13622203945Sweongyo		{ 4, 15, 11, 0, 72 }, { 4, 15, 11, 0, 70 },
13623203945Sweongyo		{ 4, 15, 11, 0, 68 }, { 4, 15, 11, 0, 66 },
13624203945Sweongyo		{ 4, 15, 11, 0, 64 }, { 4, 15, 11, 0, 62 },
13625203945Sweongyo		{ 4, 15, 11, 0, 60 }, { 4, 15, 11, 0, 59 },
13626203945Sweongyo		{ 4, 15, 10, 0, 72 }, { 4, 15, 10, 0, 70 },
13627203945Sweongyo		{ 4, 15, 10, 0, 68 }, { 4, 15, 10, 0, 66 },
13628203945Sweongyo		{ 4, 15, 10, 0, 64 }, { 4, 15, 10, 0, 62 },
13629203945Sweongyo		{ 4, 15, 10, 0, 60 }, { 4, 15, 10, 0, 59 },
13630203945Sweongyo		{ 4, 15, 9, 0, 72 }, { 4, 15, 9, 0, 70 },
13631203945Sweongyo		{ 4, 15, 9, 0, 68 }, { 4, 15, 9, 0, 66 },
13632203945Sweongyo		{ 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
13633203945Sweongyo		{ 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
13634203945Sweongyo		{ 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
13635203945Sweongyo		{ 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
13636203945Sweongyo		{ 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
13637203945Sweongyo		{ 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
13638203945Sweongyo		{ 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
13639203945Sweongyo		{ 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
13640203945Sweongyo		{ 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
13641203945Sweongyo		{ 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
13642203945Sweongyo		{ 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
13643203945Sweongyo		{ 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
13644203945Sweongyo		{ 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
13645203945Sweongyo		{ 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
13646203945Sweongyo		{ 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
13647203945Sweongyo		{ 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
13648203945Sweongyo		{ 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
13649203945Sweongyo		{ 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
13650203945Sweongyo		{ 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
13651203945Sweongyo		{ 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
13652203945Sweongyo		{ 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
13653203945Sweongyo		{ 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
13654203945Sweongyo		{ 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
13655203945Sweongyo		{ 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
13656203945Sweongyo		{ 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
13657203945Sweongyo		{ 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
13658203945Sweongyo		{ 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
13659203945Sweongyo		{ 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
13660203945Sweongyo		{ 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
13661203945Sweongyo		{ 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
13662203945Sweongyo		{ 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
13663203945Sweongyo		{ 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
13664203945Sweongyo		{ 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
13665203945Sweongyo		{ 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 }
13666203945Sweongyo	};
13667203945Sweongyo	static struct bwn_txgain_entry txgain_5ghz_r1[] = {
13668203945Sweongyo		{ 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
13669203945Sweongyo		{ 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
13670203945Sweongyo		{ 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
13671203945Sweongyo		{ 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
13672203945Sweongyo		{ 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
13673203945Sweongyo		{ 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
13674203945Sweongyo		{ 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
13675203945Sweongyo		{ 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
13676203945Sweongyo		{ 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
13677203945Sweongyo		{ 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
13678203945Sweongyo		{ 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
13679203945Sweongyo		{ 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
13680203945Sweongyo		{ 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
13681203945Sweongyo		{ 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
13682203945Sweongyo		{ 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
13683203945Sweongyo		{ 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
13684203945Sweongyo		{ 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
13685203945Sweongyo		{ 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
13686203945Sweongyo		{ 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
13687203945Sweongyo		{ 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
13688203945Sweongyo		{ 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
13689203945Sweongyo		{ 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
13690203945Sweongyo		{ 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
13691203945Sweongyo		{ 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
13692203945Sweongyo		{ 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
13693203945Sweongyo		{ 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
13694203945Sweongyo		{ 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
13695203945Sweongyo		{ 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
13696203945Sweongyo		{ 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
13697203945Sweongyo		{ 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
13698203945Sweongyo		{ 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
13699203945Sweongyo		{ 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
13700203945Sweongyo		{ 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
13701203945Sweongyo		{ 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
13702203945Sweongyo		{ 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
13703203945Sweongyo		{ 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
13704203945Sweongyo		{ 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
13705203945Sweongyo		{ 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
13706203945Sweongyo		{ 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
13707203945Sweongyo		{ 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
13708203945Sweongyo		{ 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
13709203945Sweongyo		{ 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
13710203945Sweongyo		{ 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
13711203945Sweongyo		{ 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
13712203945Sweongyo		{ 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
13713203945Sweongyo		{ 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
13714203945Sweongyo		{ 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
13715203945Sweongyo		{ 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
13716203945Sweongyo		{ 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
13717203945Sweongyo		{ 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
13718203945Sweongyo		{ 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
13719203945Sweongyo		{ 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
13720203945Sweongyo		{ 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
13721203945Sweongyo		{ 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
13722203945Sweongyo		{ 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
13723203945Sweongyo		{ 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
13724203945Sweongyo		{ 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
13725203945Sweongyo		{ 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
13726203945Sweongyo		{ 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
13727203945Sweongyo		{ 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
13728203945Sweongyo		{ 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
13729203945Sweongyo		{ 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
13730203945Sweongyo		{ 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
13731203945Sweongyo		{ 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
13732203945Sweongyo	};
13733203945Sweongyo
13734203945Sweongyo	if (mac->mac_phy.rev != 0 && mac->mac_phy.rev != 1) {
13735204922Sweongyo		if (siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA)
13736203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r2);
13737203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13738203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13739203945Sweongyo			    txgain_2ghz_r2);
13740203945Sweongyo		else
13741203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13742203945Sweongyo			    txgain_5ghz_r2);
13743203945Sweongyo		return;
13744203945Sweongyo	}
13745203945Sweongyo
13746203945Sweongyo	if (mac->mac_phy.rev == 0) {
13747204922Sweongyo		if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
13748204922Sweongyo		    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_HGPA))
13749203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r0);
13750203945Sweongyo		else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13751203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13752203945Sweongyo			    txgain_2ghz_r0);
13753203945Sweongyo		else
13754203945Sweongyo			bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
13755203945Sweongyo			    txgain_5ghz_r0);
13756203945Sweongyo		return;
13757203945Sweongyo	}
13758203945Sweongyo
13759204922Sweongyo	if ((siba_sprom_get_bf_hi(sc->sc_dev) & BWN_BFH_NOPA) ||
13760204922Sweongyo	    (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_HGPA))
13761203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r1);
13762203945Sweongyo	else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
13763203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_2ghz_r1);
13764203945Sweongyo	else
13765203945Sweongyo		bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_5ghz_r1);
13766203945Sweongyo}
13767203945Sweongyo
13768203945Sweongyostatic void
13769203945Sweongyobwn_tab_write(struct bwn_mac *mac, uint32_t typeoffset, uint32_t value)
13770203945Sweongyo{
13771203945Sweongyo	uint32_t offset, type;
13772203945Sweongyo
13773203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
13774203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
13775203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
13776203945Sweongyo
13777203945Sweongyo	switch (type) {
13778203945Sweongyo	case BWN_TAB_8BIT:
13779203945Sweongyo		KASSERT(!(value & ~0xff), ("%s:%d: fail", __func__, __LINE__));
13780203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13781203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13782203945Sweongyo		break;
13783203945Sweongyo	case BWN_TAB_16BIT:
13784203945Sweongyo		KASSERT(!(value & ~0xffff),
13785203945Sweongyo		    ("%s:%d: fail", __func__, __LINE__));
13786203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13787203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13788203945Sweongyo		break;
13789203945Sweongyo	case BWN_TAB_32BIT:
13790203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13791203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
13792203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
13793203945Sweongyo		break;
13794203945Sweongyo	default:
13795203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
13796203945Sweongyo	}
13797203945Sweongyo}
13798203945Sweongyo
13799203945Sweongyostatic int
13800203945Sweongyobwn_phy_lp_loopback(struct bwn_mac *mac)
13801203945Sweongyo{
13802203945Sweongyo	struct bwn_phy_lp_iq_est ie;
13803203945Sweongyo	int i, index = -1;
13804203945Sweongyo	uint32_t tmp;
13805203945Sweongyo
13806203945Sweongyo	memset(&ie, 0, sizeof(ie));
13807203945Sweongyo
13808203945Sweongyo	bwn_phy_lp_set_trsw_over(mac, 1, 1);
13809203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 1);
13810203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
13811203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
13812203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
13813203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
13814203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x8);
13815203945Sweongyo	BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, 0x80);
13816203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x80);
13817203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x80);
13818203945Sweongyo	for (i = 0; i < 32; i++) {
13819203945Sweongyo		bwn_phy_lp_set_rxgain_idx(mac, i);
13820203945Sweongyo		bwn_phy_lp_ddfs_turnon(mac, 1, 1, 5, 5, 0);
13821203945Sweongyo		if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
13822203945Sweongyo			continue;
13823203945Sweongyo		tmp = (ie.ie_ipwr + ie.ie_qpwr) / 1000;
13824203945Sweongyo		if ((tmp > 4000) && (tmp < 10000)) {
13825203945Sweongyo			index = i;
13826203945Sweongyo			break;
13827203945Sweongyo		}
13828203945Sweongyo	}
13829203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
13830203945Sweongyo	return (index);
13831203945Sweongyo}
13832203945Sweongyo
13833203945Sweongyostatic void
13834203945Sweongyobwn_phy_lp_set_rxgain_idx(struct bwn_mac *mac, uint16_t idx)
13835203945Sweongyo{
13836203945Sweongyo
13837203945Sweongyo	bwn_phy_lp_set_rxgain(mac, bwn_tab_read(mac, BWN_TAB_2(12, idx)));
13838203945Sweongyo}
13839203945Sweongyo
13840203945Sweongyostatic void
13841203945Sweongyobwn_phy_lp_ddfs_turnon(struct bwn_mac *mac, int i_on, int q_on,
13842203945Sweongyo    int incr1, int incr2, int scale_idx)
13843203945Sweongyo{
13844203945Sweongyo
13845203945Sweongyo	bwn_phy_lp_ddfs_turnoff(mac);
13846203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0xff80);
13847203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0x80ff);
13848203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0xff80, incr1);
13849203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0x80ff, incr2 << 8);
13850203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff7, i_on << 3);
13851203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xffef, q_on << 4);
13852203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xff9f, scale_idx << 5);
13853203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffb);
13854203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_DDFS, 0x2);
13855203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x20);
13856203945Sweongyo}
13857203945Sweongyo
13858203945Sweongyostatic uint8_t
13859203945Sweongyobwn_phy_lp_rx_iq_est(struct bwn_mac *mac, uint16_t sample, uint8_t time,
13860203945Sweongyo    struct bwn_phy_lp_iq_est *ie)
13861203945Sweongyo{
13862203945Sweongyo	int i;
13863203945Sweongyo
13864203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfff7);
13865203945Sweongyo	BWN_PHY_WRITE(mac, BWN_PHY_IQ_NUM_SMPLS_ADDR, sample);
13866203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xff00, time);
13867203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xfeff);
13868203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
13869203945Sweongyo
13870203945Sweongyo	for (i = 0; i < 500; i++) {
13871203945Sweongyo		if (!(BWN_PHY_READ(mac,
13872203945Sweongyo		    BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
13873203945Sweongyo			break;
13874203945Sweongyo		DELAY(1000);
13875203945Sweongyo	}
13876203945Sweongyo	if ((BWN_PHY_READ(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
13877203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
13878203945Sweongyo		return 0;
13879203945Sweongyo	}
13880203945Sweongyo
13881203945Sweongyo	ie->ie_iqprod = BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_HI_ADDR);
13882203945Sweongyo	ie->ie_iqprod <<= 16;
13883203945Sweongyo	ie->ie_iqprod |= BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_LO_ADDR);
13884203945Sweongyo	ie->ie_ipwr = BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_HI_ADDR);
13885203945Sweongyo	ie->ie_ipwr <<= 16;
13886203945Sweongyo	ie->ie_ipwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_LO_ADDR);
13887203945Sweongyo	ie->ie_qpwr = BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR);
13888203945Sweongyo	ie->ie_qpwr <<= 16;
13889203945Sweongyo	ie->ie_qpwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR);
13890203945Sweongyo
13891203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
13892203945Sweongyo	return 1;
13893203945Sweongyo}
13894203945Sweongyo
13895203945Sweongyostatic uint32_t
13896203945Sweongyobwn_tab_read(struct bwn_mac *mac, uint32_t typeoffset)
13897203945Sweongyo{
13898203945Sweongyo	uint32_t offset, type, value;
13899203945Sweongyo
13900203945Sweongyo	type = BWN_TAB_GETTYPE(typeoffset);
13901203945Sweongyo	offset = BWN_TAB_GETOFFSET(typeoffset);
13902203945Sweongyo	KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
13903203945Sweongyo
13904203945Sweongyo	switch (type) {
13905203945Sweongyo	case BWN_TAB_8BIT:
13906203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13907203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
13908203945Sweongyo		break;
13909203945Sweongyo	case BWN_TAB_16BIT:
13910203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13911203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
13912203945Sweongyo		break;
13913203945Sweongyo	case BWN_TAB_32BIT:
13914203945Sweongyo		BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
13915203945Sweongyo		value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATAHI);
13916203945Sweongyo		value <<= 16;
13917203945Sweongyo		value |= BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
13918203945Sweongyo		break;
13919203945Sweongyo	default:
13920203945Sweongyo		KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
13921203945Sweongyo		value = 0;
13922203945Sweongyo	}
13923203945Sweongyo
13924203945Sweongyo	return (value);
13925203945Sweongyo}
13926203945Sweongyo
13927203945Sweongyostatic void
13928203945Sweongyobwn_phy_lp_ddfs_turnoff(struct bwn_mac *mac)
13929203945Sweongyo{
13930203945Sweongyo
13931203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffd);
13932203945Sweongyo	BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0xffdf);
13933203945Sweongyo}
13934203945Sweongyo
13935203945Sweongyostatic void
13936203945Sweongyobwn_phy_lp_set_txgain_dac(struct bwn_mac *mac, uint16_t dac)
13937203945Sweongyo{
13938203945Sweongyo	uint16_t ctl;
13939203945Sweongyo
13940203945Sweongyo	ctl = BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0xc7f;
13941203945Sweongyo	ctl |= dac << 7;
13942203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf000, ctl);
13943203945Sweongyo}
13944203945Sweongyo
13945203945Sweongyostatic void
13946203945Sweongyobwn_phy_lp_set_txgain_pa(struct bwn_mac *mac, uint16_t gain)
13947203945Sweongyo{
13948203945Sweongyo
13949203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0xe03f, gain << 6);
13950203945Sweongyo	BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x80ff, gain << 8);
13951203945Sweongyo}
13952203945Sweongyo
13953203945Sweongyostatic void
13954203945Sweongyobwn_phy_lp_set_txgain_override(struct bwn_mac *mac)
13955203945Sweongyo{
13956203945Sweongyo
13957203945Sweongyo	if (mac->mac_phy.rev < 2)
13958203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
13959203945Sweongyo	else {
13960203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x80);
13961203945Sweongyo		BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x4000);
13962203945Sweongyo	}
13963203945Sweongyo	BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x40);
13964203945Sweongyo}
13965203945Sweongyo
13966203945Sweongyostatic uint16_t
13967203945Sweongyobwn_phy_lp_get_pa_gain(struct bwn_mac *mac)
13968203945Sweongyo{
13969203945Sweongyo
13970203945Sweongyo	return BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0x7f;
13971203945Sweongyo}
13972203945Sweongyo
13973203945Sweongyostatic uint8_t
13974203945Sweongyobwn_nbits(int32_t val)
13975203945Sweongyo{
13976203945Sweongyo	uint32_t tmp;
13977203945Sweongyo	uint8_t nbits = 0;
13978203945Sweongyo
13979203945Sweongyo	for (tmp = abs(val); tmp != 0; tmp >>= 1)
13980203945Sweongyo		nbits++;
13981203945Sweongyo	return (nbits);
13982203945Sweongyo}
13983203945Sweongyo
13984203945Sweongyostatic void
13985203945Sweongyobwn_phy_lp_gaintbl_write_multi(struct bwn_mac *mac, int offset, int count,
13986203945Sweongyo    struct bwn_txgain_entry *table)
13987203945Sweongyo{
13988203945Sweongyo	int i;
13989203945Sweongyo
13990203945Sweongyo	for (i = offset; i < count; i++)
13991203945Sweongyo		bwn_phy_lp_gaintbl_write(mac, i, table[i]);
13992203945Sweongyo}
13993203945Sweongyo
13994203945Sweongyostatic void
13995203945Sweongyobwn_phy_lp_gaintbl_write(struct bwn_mac *mac, int offset,
13996203945Sweongyo    struct bwn_txgain_entry data)
13997203945Sweongyo{
13998203945Sweongyo
13999203945Sweongyo	if (mac->mac_phy.rev >= 2)
14000203945Sweongyo		bwn_phy_lp_gaintbl_write_r2(mac, offset, data);
14001203945Sweongyo	else
14002203945Sweongyo		bwn_phy_lp_gaintbl_write_r01(mac, offset, data);
14003203945Sweongyo}
14004203945Sweongyo
14005203945Sweongyostatic void
14006203945Sweongyobwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset,
14007203945Sweongyo    struct bwn_txgain_entry te)
14008203945Sweongyo{
14009203945Sweongyo	struct bwn_softc *sc = mac->mac_sc;
14010287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
14011203945Sweongyo	uint32_t tmp;
14012203945Sweongyo
14013203945Sweongyo	KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__));
14014203945Sweongyo
14015203945Sweongyo	tmp = (te.te_pad << 16) | (te.te_pga << 8) | te.te_gm;
14016203945Sweongyo	if (mac->mac_phy.rev >= 3) {
14017203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14018203945Sweongyo		    (0x10 << 24) : (0x70 << 24));
14019203945Sweongyo	} else {
14020203945Sweongyo		tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
14021203945Sweongyo		    (0x14 << 24) : (0x7f << 24));
14022203945Sweongyo	}
14023203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0xc0 + offset), tmp);
14024203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(7, 0x140 + offset),
14025203945Sweongyo	    te.te_bbmult << 20 | te.te_dac << 28);
14026203945Sweongyo}
14027203945Sweongyo
14028203945Sweongyostatic void
14029203945Sweongyobwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
14030203945Sweongyo    struct bwn_txgain_entry te)
14031203945Sweongyo{
14032203945Sweongyo
14033203945Sweongyo	KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
14034203945Sweongyo
14035203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0xc0 + offset),
14036203945Sweongyo	    (te.te_pad << 11) | (te.te_pga << 7) | (te.te_gm  << 4) |
14037203945Sweongyo	    te.te_dac);
14038203945Sweongyo	bwn_tab_write(mac, BWN_TAB_4(10, 0x140 + offset), te.te_bbmult << 20);
14039203945Sweongyo}
14040203945Sweongyo
14041203945Sweongyostatic void
14042204257Sweongyobwn_sysctl_node(struct bwn_softc *sc)
14043204257Sweongyo{
14044204257Sweongyo	device_t dev = sc->sc_dev;
14045204257Sweongyo	struct bwn_mac *mac;
14046204257Sweongyo	struct bwn_stats *stats;
14047204257Sweongyo
14048204257Sweongyo	/* XXX assume that count of MAC is only 1. */
14049204257Sweongyo
14050204257Sweongyo	if ((mac = sc->sc_curmac) == NULL)
14051204257Sweongyo		return;
14052204257Sweongyo	stats = &mac->mac_stats;
14053204257Sweongyo
14054217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
14055204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14056204257Sweongyo	    "linknoise", CTLFLAG_RW, &stats->rts, 0, "Noise level");
14057217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
14058204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14059204257Sweongyo	    "rts", CTLFLAG_RW, &stats->rts, 0, "RTS");
14060217323Smdf	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
14061204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14062204257Sweongyo	    "rtsfail", CTLFLAG_RW, &stats->rtsfail, 0, "RTS failed to send");
14063204257Sweongyo
14064204257Sweongyo#ifdef BWN_DEBUG
14065204257Sweongyo	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
14066204257Sweongyo	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
14067204257Sweongyo	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
14068204257Sweongyo#endif
14069204257Sweongyo}
14070204257Sweongyo
14071203945Sweongyostatic device_method_t bwn_methods[] = {
14072203945Sweongyo	/* Device interface */
14073203945Sweongyo	DEVMETHOD(device_probe,		bwn_probe),
14074203945Sweongyo	DEVMETHOD(device_attach,	bwn_attach),
14075203945Sweongyo	DEVMETHOD(device_detach,	bwn_detach),
14076203945Sweongyo	DEVMETHOD(device_suspend,	bwn_suspend),
14077203945Sweongyo	DEVMETHOD(device_resume,	bwn_resume),
14078227848Smarius	DEVMETHOD_END
14079203945Sweongyo};
14080203945Sweongyostatic driver_t bwn_driver = {
14081203945Sweongyo	"bwn",
14082203945Sweongyo	bwn_methods,
14083203945Sweongyo	sizeof(struct bwn_softc)
14084203945Sweongyo};
14085203945Sweongyostatic devclass_t bwn_devclass;
14086203945SweongyoDRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
14087203945SweongyoMODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
14088203945SweongyoMODULE_DEPEND(bwn, wlan, 1, 1, 1);		/* 802.11 media layer */
14089203945SweongyoMODULE_DEPEND(bwn, firmware, 1, 1, 1);		/* firmware support */
14090203945SweongyoMODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
14091