xref: /netbsd-src/sys/dev/usb/if_run.c (revision 90e85cec6c3f50d27f6b8490e5f064fe5cd2bc90)
1*90e85cecSmlelstv /*	$NetBSD: if_run.c,v 1.35 2020/01/04 22:30:06 mlelstv Exp $	*/
29cdb1c70Snonaka /*	$OpenBSD: if_run.c,v 1.90 2012/03/24 15:11:04 jsg Exp $	*/
39cdb1c70Snonaka 
49cdb1c70Snonaka /*-
59cdb1c70Snonaka  * Copyright (c) 2008-2010 Damien Bergamini <damien.bergamini@free.fr>
69cdb1c70Snonaka  *
79cdb1c70Snonaka  * Permission to use, copy, modify, and distribute this software for any
89cdb1c70Snonaka  * purpose with or without fee is hereby granted, provided that the above
99cdb1c70Snonaka  * copyright notice and this permission notice appear in all copies.
109cdb1c70Snonaka  *
119cdb1c70Snonaka  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
129cdb1c70Snonaka  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
139cdb1c70Snonaka  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
149cdb1c70Snonaka  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
159cdb1c70Snonaka  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
169cdb1c70Snonaka  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
179cdb1c70Snonaka  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
189cdb1c70Snonaka  */
199cdb1c70Snonaka 
209cdb1c70Snonaka /*-
21d164e220Smlelstv  * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver.
229cdb1c70Snonaka  * http://www.ralinktech.com/
239cdb1c70Snonaka  */
249cdb1c70Snonaka 
259cdb1c70Snonaka #include <sys/cdefs.h>
26*90e85cecSmlelstv __KERNEL_RCSID(0, "$NetBSD: if_run.c,v 1.35 2020/01/04 22:30:06 mlelstv Exp $");
27a7c71d30Sskrll 
28a7c71d30Sskrll #ifdef _KERNEL_OPT
29a7c71d30Sskrll #include "opt_usb.h"
30a7c71d30Sskrll #endif
319cdb1c70Snonaka 
329cdb1c70Snonaka #include <sys/param.h>
339cdb1c70Snonaka #include <sys/sockio.h>
349cdb1c70Snonaka #include <sys/sysctl.h>
359cdb1c70Snonaka #include <sys/mbuf.h>
369cdb1c70Snonaka #include <sys/kernel.h>
379cdb1c70Snonaka #include <sys/socket.h>
389cdb1c70Snonaka #include <sys/systm.h>
399cdb1c70Snonaka #include <sys/malloc.h>
409cdb1c70Snonaka #include <sys/callout.h>
419cdb1c70Snonaka #include <sys/module.h>
429cdb1c70Snonaka #include <sys/conf.h>
439cdb1c70Snonaka #include <sys/device.h>
44*90e85cecSmlelstv #include <sys/atomic.h>
459cdb1c70Snonaka 
469cdb1c70Snonaka #include <sys/bus.h>
479cdb1c70Snonaka #include <machine/endian.h>
489cdb1c70Snonaka #include <sys/intr.h>
499cdb1c70Snonaka 
509cdb1c70Snonaka #include <net/bpf.h>
519cdb1c70Snonaka #include <net/if.h>
529cdb1c70Snonaka #include <net/if_arp.h>
539cdb1c70Snonaka #include <net/if_dl.h>
549cdb1c70Snonaka #include <net/if_ether.h>
559cdb1c70Snonaka #include <net/if_media.h>
569cdb1c70Snonaka #include <net/if_types.h>
579cdb1c70Snonaka 
589cdb1c70Snonaka #include <net80211/ieee80211_var.h>
599cdb1c70Snonaka #include <net80211/ieee80211_amrr.h>
609cdb1c70Snonaka #include <net80211/ieee80211_radiotap.h>
619cdb1c70Snonaka 
629cdb1c70Snonaka #include <dev/firmload.h>
639cdb1c70Snonaka 
649cdb1c70Snonaka #include <dev/usb/usb.h>
659cdb1c70Snonaka #include <dev/usb/usbdi.h>
669cdb1c70Snonaka #include <dev/usb/usbdivar.h>
679cdb1c70Snonaka #include <dev/usb/usbdi_util.h>
689cdb1c70Snonaka #include <dev/usb/usbdevs.h>
699cdb1c70Snonaka 
709cdb1c70Snonaka #include <dev/ic/rt2860reg.h>		/* shared with ral(4) */
719cdb1c70Snonaka #include <dev/usb/if_runvar.h>
729cdb1c70Snonaka 
739cdb1c70Snonaka #ifdef RUN_DEBUG
749cdb1c70Snonaka #define DPRINTF(x)	do { if (run_debug) printf x; } while (0)
759cdb1c70Snonaka #define DPRINTFN(n, x)	do { if (run_debug >= (n)) printf x; } while (0)
769cdb1c70Snonaka int run_debug = 0;
779cdb1c70Snonaka #else
789cdb1c70Snonaka #define DPRINTF(x)
799cdb1c70Snonaka #define DPRINTFN(n, x)
809cdb1c70Snonaka #endif
819cdb1c70Snonaka 
82faca41fbSmlelstv #define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh)
83faca41fbSmlelstv 
849cdb1c70Snonaka #define USB_ID(v, p)	{ USB_VENDOR_##v, USB_PRODUCT_##v##_##p }
859cdb1c70Snonaka static const struct usb_devno run_devs[] = {
869cdb1c70Snonaka 	USB_ID(ABOCOM,		RT2770),
879cdb1c70Snonaka 	USB_ID(ABOCOM,		RT2870),
889cdb1c70Snonaka 	USB_ID(ABOCOM,		RT3070),
899cdb1c70Snonaka 	USB_ID(ABOCOM,		RT3071),
909cdb1c70Snonaka 	USB_ID(ABOCOM,		RT3072),
919cdb1c70Snonaka 	USB_ID(ABOCOM2,		RT2870_1),
929cdb1c70Snonaka 	USB_ID(ACCTON,		RT2770),
939cdb1c70Snonaka 	USB_ID(ACCTON,		RT2870_1),
949cdb1c70Snonaka 	USB_ID(ACCTON,		RT2870_2),
959cdb1c70Snonaka 	USB_ID(ACCTON,		RT2870_3),
969cdb1c70Snonaka 	USB_ID(ACCTON,		RT2870_4),
979cdb1c70Snonaka 	USB_ID(ACCTON,		RT2870_5),
989cdb1c70Snonaka 	USB_ID(ACCTON,		RT3070),
999cdb1c70Snonaka 	USB_ID(ACCTON,		RT3070_1),
1009cdb1c70Snonaka 	USB_ID(ACCTON,		RT3070_2),
1019cdb1c70Snonaka 	USB_ID(ACCTON,		RT3070_3),
1029cdb1c70Snonaka 	USB_ID(ACCTON,		RT3070_4),
1039cdb1c70Snonaka 	USB_ID(ACCTON,		RT3070_5),
1049cdb1c70Snonaka 	USB_ID(ACCTON,		RT3070_6),
1059cdb1c70Snonaka 	USB_ID(AIRTIES,		RT3070),
1069cdb1c70Snonaka 	USB_ID(AIRTIES,		RT3070_2),
1079cdb1c70Snonaka 	USB_ID(ALLWIN,		RT2070),
1089cdb1c70Snonaka 	USB_ID(ALLWIN,		RT2770),
1099cdb1c70Snonaka 	USB_ID(ALLWIN,		RT2870),
1109cdb1c70Snonaka 	USB_ID(ALLWIN,		RT3070),
1119cdb1c70Snonaka 	USB_ID(ALLWIN,		RT3071),
1129cdb1c70Snonaka 	USB_ID(ALLWIN,		RT3072),
1139cdb1c70Snonaka 	USB_ID(ALLWIN,		RT3572),
1149cdb1c70Snonaka 	USB_ID(AMIGO,		RT2870_1),
1159cdb1c70Snonaka 	USB_ID(AMIGO,		RT2870_2),
1169cdb1c70Snonaka 	USB_ID(AMIT,		CGWLUSB2GNR),
1179cdb1c70Snonaka 	USB_ID(AMIT,		RT2870_1),
1189cdb1c70Snonaka 	USB_ID(AMIT2,		RT2870),
1199cdb1c70Snonaka 	USB_ID(ASUSTEK,		RT2870_1),
1209cdb1c70Snonaka 	USB_ID(ASUSTEK,		RT2870_2),
1219cdb1c70Snonaka 	USB_ID(ASUSTEK,		RT2870_3),
1229cdb1c70Snonaka 	USB_ID(ASUSTEK,		RT2870_4),
1239cdb1c70Snonaka 	USB_ID(ASUSTEK,		RT2870_5),
1249cdb1c70Snonaka 	USB_ID(ASUSTEK,		RT3070),
1259cdb1c70Snonaka 	USB_ID(ASUSTEK,		RT3070_1),
126d164e220Smlelstv 	USB_ID(ASUSTEK,		USBN53),
127d164e220Smlelstv 	USB_ID(ASUSTEK,		USBN66),
1289cdb1c70Snonaka 	USB_ID(ASUSTEK2,	USBN11),
1299cdb1c70Snonaka 	USB_ID(AZUREWAVE,	RT2870_1),
1309cdb1c70Snonaka 	USB_ID(AZUREWAVE,	RT2870_2),
1319cdb1c70Snonaka 	USB_ID(AZUREWAVE,	RT3070),
1329cdb1c70Snonaka 	USB_ID(AZUREWAVE,	RT3070_2),
1339cdb1c70Snonaka 	USB_ID(AZUREWAVE,	RT3070_3),
1349cdb1c70Snonaka 	USB_ID(AZUREWAVE,	RT3070_4),
1359cdb1c70Snonaka 	USB_ID(AZUREWAVE,	RT3070_5),
1369cdb1c70Snonaka 	USB_ID(BELKIN,		F5D8053V3),
1379cdb1c70Snonaka 	USB_ID(BELKIN,		F5D8055),
1389cdb1c70Snonaka 	USB_ID(BELKIN,		F5D8055V2),
1399cdb1c70Snonaka 	USB_ID(BELKIN,		F6D4050V1),
1409cdb1c70Snonaka 	USB_ID(BELKIN,		F6D4050V2),
1419cdb1c70Snonaka 	USB_ID(BELKIN,		F7D1101V2),
1429cdb1c70Snonaka 	USB_ID(BELKIN,		RT2870_1),
1439cdb1c70Snonaka 	USB_ID(BELKIN,		RT2870_2),
144d164e220Smlelstv 	USB_ID(BELKIN,		RTL8192CU_2),
1459cdb1c70Snonaka 	USB_ID(BEWAN,		RT3070),
1469cdb1c70Snonaka 	USB_ID(CISCOLINKSYS,	AE1000),
1479cdb1c70Snonaka 	USB_ID(CISCOLINKSYS,	AM10),
1489cdb1c70Snonaka 	USB_ID(CISCOLINKSYS2,	RT3070),
1499cdb1c70Snonaka 	USB_ID(CISCOLINKSYS3,	RT3070),
1509cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT2870_1),
1519cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT2870_2),
1529cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT2870_3),
1539cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT2870_4),
1549cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT2870_5),
1559cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT2870_6),
1569cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT2870_7),
1579cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT2870_8),
1589cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT3070_1),
1599cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT3070_2),
1609cdb1c70Snonaka 	USB_ID(CONCEPTRONIC,	RT3070_3),
1619cdb1c70Snonaka 	USB_ID(COREGA,		CGWLUSB300GNM),
1629cdb1c70Snonaka 	USB_ID(COREGA,		RT2870_1),
1639cdb1c70Snonaka 	USB_ID(COREGA,		RT2870_2),
1649cdb1c70Snonaka 	USB_ID(COREGA,		RT2870_3),
1659cdb1c70Snonaka 	USB_ID(COREGA,		RT3070),
1669cdb1c70Snonaka 	USB_ID(CYBERTAN,	RT2870),
1679cdb1c70Snonaka 	USB_ID(DLINK,		RT2870),
1689cdb1c70Snonaka 	USB_ID(DLINK,		RT3072),
169d164e220Smlelstv 	USB_ID(DLINK,		DWA127),
170d164e220Smlelstv 	USB_ID(DLINK,		DWA140B3),
171d164e220Smlelstv 	USB_ID(DLINK,		DWA160B2),
172d164e220Smlelstv 	USB_ID(DLINK,		DWA162),
1739cdb1c70Snonaka 	USB_ID(DLINK2,		DWA130),
1749cdb1c70Snonaka 	USB_ID(DLINK2,		RT2870_1),
1759cdb1c70Snonaka 	USB_ID(DLINK2,		RT2870_2),
1769cdb1c70Snonaka 	USB_ID(DLINK2,		RT3070_1),
1779cdb1c70Snonaka 	USB_ID(DLINK2,		RT3070_2),
1789cdb1c70Snonaka 	USB_ID(DLINK2,		RT3070_3),
1799cdb1c70Snonaka 	USB_ID(DLINK2,		RT3070_4),
1809cdb1c70Snonaka 	USB_ID(DLINK2,		RT3070_5),
1819cdb1c70Snonaka 	USB_ID(DLINK2,		RT3072),
1829cdb1c70Snonaka 	USB_ID(DLINK2,		RT3072_1),
1839cdb1c70Snonaka 	USB_ID(DVICO,		RT3070),
1849cdb1c70Snonaka 	USB_ID(EDIMAX,		EW7717),
1859cdb1c70Snonaka 	USB_ID(EDIMAX,		EW7718),
1869cdb1c70Snonaka 	USB_ID(EDIMAX,		EW7722UTN),
1879cdb1c70Snonaka 	USB_ID(EDIMAX,		RT2870_1),
1889cdb1c70Snonaka 	USB_ID(ENCORE,		RT3070),
1899cdb1c70Snonaka 	USB_ID(ENCORE,		RT3070_2),
1909cdb1c70Snonaka 	USB_ID(ENCORE,		RT3070_3),
1919cdb1c70Snonaka 	USB_ID(GIGABYTE,	GNWB31N),
1929cdb1c70Snonaka 	USB_ID(GIGABYTE,	GNWB32L),
1939cdb1c70Snonaka 	USB_ID(GIGABYTE,	RT2870_1),
1949cdb1c70Snonaka 	USB_ID(GIGASET,		RT3070_1),
1959cdb1c70Snonaka 	USB_ID(GIGASET,		RT3070_2),
1969cdb1c70Snonaka 	USB_ID(GUILLEMOT,	HWNU300),
1979cdb1c70Snonaka 	USB_ID(HAWKING,		HWUN2),
1989cdb1c70Snonaka 	USB_ID(HAWKING,		RT2870_1),
1999cdb1c70Snonaka 	USB_ID(HAWKING,		RT2870_2),
2009cdb1c70Snonaka 	USB_ID(HAWKING,		RT2870_3),
2019cdb1c70Snonaka 	USB_ID(HAWKING,		RT2870_4),
2029cdb1c70Snonaka 	USB_ID(HAWKING,		RT2870_5),
2039cdb1c70Snonaka 	USB_ID(HAWKING,		RT3070),
2049cdb1c70Snonaka 	USB_ID(IODATA,		RT3072_1),
2059cdb1c70Snonaka 	USB_ID(IODATA,		RT3072_2),
2069cdb1c70Snonaka 	USB_ID(IODATA,		RT3072_3),
2079cdb1c70Snonaka 	USB_ID(IODATA,		RT3072_4),
2089cdb1c70Snonaka 	USB_ID(LINKSYS4,	RT3070),
2099cdb1c70Snonaka 	USB_ID(LINKSYS4,	WUSB100),
2109cdb1c70Snonaka 	USB_ID(LINKSYS4,	WUSB54GC_3),
2119cdb1c70Snonaka 	USB_ID(LINKSYS4,	WUSB600N),
2129cdb1c70Snonaka 	USB_ID(LINKSYS4,	WUSB600NV2),
2139cdb1c70Snonaka 	USB_ID(LOGITEC,		LANW300NU2),
214d164e220Smlelstv 	USB_ID(LOGITEC,		LANW300NU2S),
215d164e220Smlelstv 	USB_ID(LOGITEC,		LAN_W300ANU2),
216d164e220Smlelstv 	USB_ID(LOGITEC,		LAN_W450ANU2E),
2179cdb1c70Snonaka 	USB_ID(LOGITEC,		RT2870_1),
2189cdb1c70Snonaka 	USB_ID(LOGITEC,		RT2870_2),
2199cdb1c70Snonaka 	USB_ID(LOGITEC,		RT2870_3),
2209cdb1c70Snonaka 	USB_ID(LOGITEC,		RT3020),
2219cdb1c70Snonaka 	USB_ID(MELCO,		RT2870_1),
2229cdb1c70Snonaka 	USB_ID(MELCO,		RT2870_2),
2239cdb1c70Snonaka 	USB_ID(MELCO,		WLIUCAG300N),
2249cdb1c70Snonaka 	USB_ID(MELCO,		WLIUCG300N),
2259cdb1c70Snonaka 	USB_ID(MELCO,		WLIUCG301N),
2269cdb1c70Snonaka 	USB_ID(MELCO,		WLIUCGN),
2279cdb1c70Snonaka 	USB_ID(MELCO,		WLIUCGNHP),
2289cdb1c70Snonaka 	USB_ID(MELCO,		WLIUCGNM),
2299cdb1c70Snonaka 	USB_ID(MELCO,		WLIUCGNM2T),
2309cdb1c70Snonaka 	USB_ID(MOTOROLA4,	RT2770),
2319cdb1c70Snonaka 	USB_ID(MOTOROLA4,	RT3070),
2329cdb1c70Snonaka 	USB_ID(MSI,		RT3070),
2339cdb1c70Snonaka 	USB_ID(MSI,		RT3070_2),
2349cdb1c70Snonaka 	USB_ID(MSI,		RT3070_3),
2359cdb1c70Snonaka 	USB_ID(MSI,		RT3070_4),
2369cdb1c70Snonaka 	USB_ID(MSI,		RT3070_5),
2379cdb1c70Snonaka 	USB_ID(MSI,		RT3070_6),
2389cdb1c70Snonaka 	USB_ID(MSI,		RT3070_7),
2399cdb1c70Snonaka 	USB_ID(MSI,		RT3070_8),
2409cdb1c70Snonaka 	USB_ID(MSI,		RT3070_9),
2419cdb1c70Snonaka 	USB_ID(MSI,		RT3070_10),
2429cdb1c70Snonaka 	USB_ID(MSI,		RT3070_11),
2439cdb1c70Snonaka 	USB_ID(MSI,		RT3070_12),
2449cdb1c70Snonaka 	USB_ID(MSI,		RT3070_13),
2459cdb1c70Snonaka 	USB_ID(MSI,		RT3070_14),
2469cdb1c70Snonaka 	USB_ID(MSI,		RT3070_15),
2479cdb1c70Snonaka 	USB_ID(OVISLINK,	RT3071),
2489cdb1c70Snonaka 	USB_ID(OVISLINK,	RT3072),
2499cdb1c70Snonaka 	USB_ID(PARA,		RT3070),
2509cdb1c70Snonaka 	USB_ID(PEGATRON,	RT2870),
2519cdb1c70Snonaka 	USB_ID(PEGATRON,	RT3070),
2529cdb1c70Snonaka 	USB_ID(PEGATRON,	RT3070_2),
2539cdb1c70Snonaka 	USB_ID(PEGATRON,	RT3070_3),
2549cdb1c70Snonaka 	USB_ID(PEGATRON,	RT3072),
2559cdb1c70Snonaka 	USB_ID(PHILIPS,		RT2870),
2569cdb1c70Snonaka 	USB_ID(PLANEX2,		GWUS300MINIS),
2579cdb1c70Snonaka 	USB_ID(PLANEX2,		GWUSMICRO300),
2589cdb1c70Snonaka 	USB_ID(PLANEX2,		GWUSMICRON),
2599cdb1c70Snonaka 	USB_ID(PLANEX2,		GWUS300MINIX),
2609cdb1c70Snonaka 	USB_ID(PLANEX2,		RT3070),
2619cdb1c70Snonaka 	USB_ID(QCOM,		RT2870),
2629cdb1c70Snonaka 	USB_ID(QUANTA,		RT3070),
2639cdb1c70Snonaka 	USB_ID(RALINK,		RT2070),
2649cdb1c70Snonaka 	USB_ID(RALINK,		RT2770),
2659cdb1c70Snonaka 	USB_ID(RALINK,		RT2870),
2669cdb1c70Snonaka 	USB_ID(RALINK,		RT3070),
2679cdb1c70Snonaka 	USB_ID(RALINK,		RT3071),
2689cdb1c70Snonaka 	USB_ID(RALINK,		RT3072),
2699cdb1c70Snonaka 	USB_ID(RALINK,		RT3370),
2709cdb1c70Snonaka 	USB_ID(RALINK,		RT3572),
271d164e220Smlelstv 	USB_ID(RALINK,		RT3573),
2722c1adfbeShauke 	USB_ID(RALINK,		RT5370),
273faca41fbSmlelstv 	USB_ID(RALINK,		RT5572),
2749cdb1c70Snonaka 	USB_ID(RALINK,		RT8070),
2759cdb1c70Snonaka 	USB_ID(SAMSUNG,		RT2870_1),
2769cdb1c70Snonaka 	USB_ID(SENAO,		RT2870_1),
2779cdb1c70Snonaka 	USB_ID(SENAO,		RT2870_2),
2789cdb1c70Snonaka 	USB_ID(SENAO,		RT2870_3),
2799cdb1c70Snonaka 	USB_ID(SENAO,		RT2870_4),
2809cdb1c70Snonaka 	USB_ID(SENAO,		RT3070),
2819cdb1c70Snonaka 	USB_ID(SENAO,		RT3071),
2829cdb1c70Snonaka 	USB_ID(SENAO,		RT3072),
2839cdb1c70Snonaka 	USB_ID(SENAO,		RT3072_2),
2849cdb1c70Snonaka 	USB_ID(SENAO,		RT3072_3),
2859cdb1c70Snonaka 	USB_ID(SENAO,		RT3072_4),
2869cdb1c70Snonaka 	USB_ID(SENAO,		RT3072_5),
2879cdb1c70Snonaka 	USB_ID(SITECOMEU,	RT2870_1),
2889cdb1c70Snonaka 	USB_ID(SITECOMEU,	RT2870_2),
2899cdb1c70Snonaka 	USB_ID(SITECOMEU,	RT2870_3),
2909cdb1c70Snonaka 	USB_ID(SITECOMEU,	RT3070_1),
291d164e220Smlelstv 	USB_ID(SITECOMEU,	RT3070_3),
2929cdb1c70Snonaka 	USB_ID(SITECOMEU,	RT3072_3),
2939cdb1c70Snonaka 	USB_ID(SITECOMEU,	RT3072_4),
2949cdb1c70Snonaka 	USB_ID(SITECOMEU,	RT3072_5),
295d164e220Smlelstv 	USB_ID(SITECOMEU,	RT3072_6),
2969cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL302),
2979cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL315),
2989cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL321),
2999cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL324),
3009cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL329),
3019cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL343),
3029cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL344),
3039cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL345),
3049cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL349V4),
3059cdb1c70Snonaka 	USB_ID(SITECOMEU,	WL608),
3069cdb1c70Snonaka 	USB_ID(SITECOMEU,	WLA4000),
3079cdb1c70Snonaka 	USB_ID(SITECOMEU,	WLA5000),
3089cdb1c70Snonaka 	USB_ID(SPARKLAN,	RT2870_1),
3099cdb1c70Snonaka 	USB_ID(SPARKLAN,	RT2870_2),
3109cdb1c70Snonaka 	USB_ID(SPARKLAN,	RT3070),
3119cdb1c70Snonaka 	USB_ID(SWEEX2,		LW153),
3129cdb1c70Snonaka 	USB_ID(SWEEX2,		LW303),
3139cdb1c70Snonaka 	USB_ID(SWEEX2,		LW313),
3149cdb1c70Snonaka 	USB_ID(TOSHIBA,		RT3070),
3159cdb1c70Snonaka 	USB_ID(UMEDIA,		RT2870_1),
3169cdb1c70Snonaka 	USB_ID(UMEDIA,		TEW645UB),
3179cdb1c70Snonaka 	USB_ID(ZCOM,		RT2870_1),
3189cdb1c70Snonaka 	USB_ID(ZCOM,		RT2870_2),
3199cdb1c70Snonaka 	USB_ID(ZINWELL,		RT2870_1),
3209cdb1c70Snonaka 	USB_ID(ZINWELL,		RT2870_2),
3219cdb1c70Snonaka 	USB_ID(ZINWELL,		RT3070),
3229cdb1c70Snonaka 	USB_ID(ZINWELL,		RT3072),
3239cdb1c70Snonaka 	USB_ID(ZINWELL,		RT3072_2),
3249cdb1c70Snonaka 	USB_ID(ZYXEL,		NWD2105),
3259cdb1c70Snonaka 	USB_ID(ZYXEL,		NWD211AN),
3269cdb1c70Snonaka 	USB_ID(ZYXEL,		RT2870_1),
3279cdb1c70Snonaka 	USB_ID(ZYXEL,		RT2870_2),
3289cdb1c70Snonaka 	USB_ID(ZYXEL,		RT3070),
3299cdb1c70Snonaka };
3309cdb1c70Snonaka 
3319cdb1c70Snonaka static int		run_match(device_t, cfdata_t, void *);
3329cdb1c70Snonaka static void		run_attach(device_t, device_t, void *);
3339cdb1c70Snonaka static int		run_detach(device_t, int);
3349cdb1c70Snonaka static int		run_activate(device_t, enum devact);
3359cdb1c70Snonaka 
3369cdb1c70Snonaka CFATTACH_DECL_NEW(run, sizeof(struct run_softc),
3379cdb1c70Snonaka 	run_match, run_attach, run_detach, run_activate);
3389cdb1c70Snonaka 
3399cdb1c70Snonaka static int		run_alloc_rx_ring(struct run_softc *);
3409cdb1c70Snonaka static void		run_free_rx_ring(struct run_softc *);
3419cdb1c70Snonaka static int		run_alloc_tx_ring(struct run_softc *, int);
3429cdb1c70Snonaka static void		run_free_tx_ring(struct run_softc *, int);
3439cdb1c70Snonaka static int		run_load_microcode(struct run_softc *);
3449cdb1c70Snonaka static int		run_reset(struct run_softc *);
3459cdb1c70Snonaka static int		run_read(struct run_softc *, uint16_t, uint32_t *);
3469cdb1c70Snonaka static int		run_read_region_1(struct run_softc *, uint16_t,
3479cdb1c70Snonaka 			    uint8_t *, int);
3489cdb1c70Snonaka static int		run_write_2(struct run_softc *, uint16_t, uint16_t);
3499cdb1c70Snonaka static int		run_write(struct run_softc *, uint16_t, uint32_t);
3509cdb1c70Snonaka static int		run_write_region_1(struct run_softc *, uint16_t,
3519cdb1c70Snonaka 			    const uint8_t *, int);
3529cdb1c70Snonaka static int		run_set_region_4(struct run_softc *, uint16_t,
3539cdb1c70Snonaka 			    uint32_t, int);
354faca41fbSmlelstv static int		run_efuse_read(struct run_softc *, uint16_t,
355faca41fbSmlelstv 			    uint16_t *, int);
3569cdb1c70Snonaka static int		run_efuse_read_2(struct run_softc *, uint16_t,
3579cdb1c70Snonaka 			    uint16_t *);
3589cdb1c70Snonaka static int		run_eeprom_read_2(struct run_softc *, uint16_t,
3599cdb1c70Snonaka 			    uint16_t *);
3609cdb1c70Snonaka static int		run_rt2870_rf_write(struct run_softc *, uint8_t,
3619cdb1c70Snonaka 			    uint32_t);
3629cdb1c70Snonaka static int		run_rt3070_rf_read(struct run_softc *, uint8_t,
3639cdb1c70Snonaka 			    uint8_t *);
3649cdb1c70Snonaka static int		run_rt3070_rf_write(struct run_softc *, uint8_t,
3659cdb1c70Snonaka 			    uint8_t);
3669cdb1c70Snonaka static int		run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
3679cdb1c70Snonaka static int		run_bbp_write(struct run_softc *, uint8_t, uint8_t);
3689cdb1c70Snonaka static int		run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
369d164e220Smlelstv static const char *	run_get_rf(uint16_t);
370faca41fbSmlelstv static void		run_rt3593_get_txpower(struct run_softc *);
371faca41fbSmlelstv static void		run_get_txpower(struct run_softc *);
3729cdb1c70Snonaka static int		run_read_eeprom(struct run_softc *);
3739cdb1c70Snonaka static struct ieee80211_node *
3749cdb1c70Snonaka 			run_node_alloc(struct ieee80211_node_table *);
3759cdb1c70Snonaka static int		run_media_change(struct ifnet *);
3769cdb1c70Snonaka static void		run_next_scan(void *);
3779cdb1c70Snonaka static void		run_task(void *);
3789cdb1c70Snonaka static void		run_do_async(struct run_softc *,
3799cdb1c70Snonaka 			    void (*)(struct run_softc *, void *), void *, int);
3809cdb1c70Snonaka static int		run_newstate(struct ieee80211com *,
3819cdb1c70Snonaka 			    enum ieee80211_state, int);
3829cdb1c70Snonaka static void		run_newstate_cb(struct run_softc *, void *);
3839cdb1c70Snonaka static int		run_updateedca(struct ieee80211com *);
3849cdb1c70Snonaka static void		run_updateedca_cb(struct run_softc *, void *);
3859cdb1c70Snonaka #ifdef RUN_HWCRYPTO
3869cdb1c70Snonaka static int		run_set_key(struct ieee80211com *,
3879cdb1c70Snonaka 			    const struct ieee80211_key *, const uint8_t *);
3889cdb1c70Snonaka static void		run_set_key_cb(struct run_softc *, void *);
3899cdb1c70Snonaka static int		run_delete_key(struct ieee80211com *,
3909cdb1c70Snonaka 			    const struct ieee80211_key *);
3919cdb1c70Snonaka static void		run_delete_key_cb(struct run_softc *, void *);
3929cdb1c70Snonaka #endif
3939cdb1c70Snonaka static void		run_calibrate_to(void *);
3949cdb1c70Snonaka static void		run_calibrate_cb(struct run_softc *, void *);
3959cdb1c70Snonaka static void		run_newassoc(struct ieee80211_node *, int);
3969cdb1c70Snonaka static void		run_rx_frame(struct run_softc *, uint8_t *, int);
3974e8e6643Sskrll static void		run_rxeof(struct usbd_xfer *, void *,
3989cdb1c70Snonaka 			    usbd_status);
3994e8e6643Sskrll static void		run_txeof(struct usbd_xfer *, void *,
4009cdb1c70Snonaka 			    usbd_status);
4019cdb1c70Snonaka static int		run_tx(struct run_softc *, struct mbuf *,
4029cdb1c70Snonaka 			    struct ieee80211_node *);
4039cdb1c70Snonaka static void		run_start(struct ifnet *);
4049cdb1c70Snonaka static void		run_watchdog(struct ifnet *);
4059cdb1c70Snonaka static int		run_ioctl(struct ifnet *, u_long, void *);
4069cdb1c70Snonaka static void		run_select_chan_group(struct run_softc *, int);
407faca41fbSmlelstv static void		run_iq_calib(struct run_softc *, u_int);
4089cdb1c70Snonaka static void		run_set_agc(struct run_softc *, uint8_t);
4099cdb1c70Snonaka static void		run_set_rx_antenna(struct run_softc *, int);
4109cdb1c70Snonaka static void		run_rt2870_set_chan(struct run_softc *, u_int);
4119cdb1c70Snonaka static void		run_rt3070_set_chan(struct run_softc *, u_int);
4129cdb1c70Snonaka static void		run_rt3572_set_chan(struct run_softc *, u_int);
413faca41fbSmlelstv static void		run_rt3593_set_chan(struct run_softc *, u_int);
414faca41fbSmlelstv static void		run_rt5390_set_chan(struct run_softc *, u_int);
415faca41fbSmlelstv static void		run_rt5592_set_chan(struct run_softc *, u_int);
4169cdb1c70Snonaka static int		run_set_chan(struct run_softc *,
4179cdb1c70Snonaka 			    struct ieee80211_channel *);
418faca41fbSmlelstv static void		run_updateprot(struct run_softc *);
4199cdb1c70Snonaka static void		run_enable_tsf_sync(struct run_softc *);
4209cdb1c70Snonaka static void		run_enable_mrr(struct run_softc *);
4219cdb1c70Snonaka static void		run_set_txpreamble(struct run_softc *);
4229cdb1c70Snonaka static void		run_set_basicrates(struct run_softc *);
4239cdb1c70Snonaka static void		run_set_leds(struct run_softc *, uint16_t);
4249cdb1c70Snonaka static void		run_set_bssid(struct run_softc *, const uint8_t *);
4259cdb1c70Snonaka static void		run_set_macaddr(struct run_softc *, const uint8_t *);
4269cdb1c70Snonaka static void		run_updateslot(struct ifnet *);
4279cdb1c70Snonaka static void		run_updateslot_cb(struct run_softc *, void *);
4289cdb1c70Snonaka static int8_t		run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
429faca41fbSmlelstv static void		run_rt5390_bbp_init(struct run_softc *);
4309cdb1c70Snonaka static int		run_bbp_init(struct run_softc *);
4319cdb1c70Snonaka static int		run_rt3070_rf_init(struct run_softc *);
432faca41fbSmlelstv static int		run_rt3593_rf_init(struct run_softc *);
433faca41fbSmlelstv static int		run_rt5390_rf_init(struct run_softc *);
4349cdb1c70Snonaka static int		run_rt3070_filter_calib(struct run_softc *, uint8_t,
4359cdb1c70Snonaka 			    uint8_t, uint8_t *);
4369cdb1c70Snonaka static void		run_rt3070_rf_setup(struct run_softc *);
437faca41fbSmlelstv static void		run_rt3593_rf_setup(struct run_softc *);
438faca41fbSmlelstv static void		run_rt5390_rf_setup(struct run_softc *);
4399cdb1c70Snonaka static int		run_txrx_enable(struct run_softc *);
440faca41fbSmlelstv static int     		run_adjust_freq_offset(struct run_softc *);
4419cdb1c70Snonaka static int		run_init(struct ifnet *);
4429cdb1c70Snonaka static void		run_stop(struct ifnet *, int);
4439cdb1c70Snonaka #ifndef IEEE80211_STA_ONLY
4449cdb1c70Snonaka static int		run_setup_beacon(struct run_softc *);
4459cdb1c70Snonaka #endif
4469cdb1c70Snonaka 
4479cdb1c70Snonaka static const struct {
4489cdb1c70Snonaka 	uint32_t reg;
4499cdb1c70Snonaka 	uint32_t val;
4509cdb1c70Snonaka } rt2870_def_mac[] = {
4519cdb1c70Snonaka 	RT2870_DEF_MAC
4529cdb1c70Snonaka };
4539cdb1c70Snonaka 
4549cdb1c70Snonaka static const struct {
4559cdb1c70Snonaka 	uint8_t reg;
4569cdb1c70Snonaka 	uint8_t val;
4579cdb1c70Snonaka } rt2860_def_bbp[] = {
4589cdb1c70Snonaka 	RT2860_DEF_BBP
459faca41fbSmlelstv }, rt5390_def_bbp[] = {
460faca41fbSmlelstv 	RT5390_DEF_BBP
461faca41fbSmlelstv }, rt5592_def_bbp[] = {
462faca41fbSmlelstv 	RT5592_DEF_BBP
463faca41fbSmlelstv };
464faca41fbSmlelstv 
465faca41fbSmlelstv /*
466faca41fbSmlelstv  * Default values for BBP register R196 for RT5592.
467faca41fbSmlelstv  */
468faca41fbSmlelstv static const uint8_t rt5592_bbp_r196[] = {
469faca41fbSmlelstv 	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
470faca41fbSmlelstv 	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
471faca41fbSmlelstv 	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
472faca41fbSmlelstv 	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
473faca41fbSmlelstv 	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
474faca41fbSmlelstv 	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
475faca41fbSmlelstv 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
476faca41fbSmlelstv 	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
477faca41fbSmlelstv 	0x2e, 0x36, 0x30, 0x6e
4789cdb1c70Snonaka };
4799cdb1c70Snonaka 
4809cdb1c70Snonaka static const struct rfprog {
4819cdb1c70Snonaka 	uint8_t chan;
4829cdb1c70Snonaka 	uint32_t r1, r2, r3, r4;
4839cdb1c70Snonaka } rt2860_rf2850[] = {
4849cdb1c70Snonaka 	RT2860_RF2850
4859cdb1c70Snonaka };
4869cdb1c70Snonaka 
4879cdb1c70Snonaka static const struct {
4889cdb1c70Snonaka 	uint8_t n, r, k;
4899cdb1c70Snonaka } rt3070_freqs[] = {
4909cdb1c70Snonaka 	RT3070_RF3052
4919cdb1c70Snonaka };
4929cdb1c70Snonaka 
493faca41fbSmlelstv static const struct rt5592_freqs {
494faca41fbSmlelstv 	uint16_t n;
495faca41fbSmlelstv 	uint8_t k, m, r;
496faca41fbSmlelstv } rt5592_freqs_20mhz[] = {
497faca41fbSmlelstv 	RT5592_RF5592_20MHZ
498faca41fbSmlelstv },rt5592_freqs_40mhz[] = {
499faca41fbSmlelstv 	RT5592_RF5592_40MHZ
500faca41fbSmlelstv };
501faca41fbSmlelstv 
5029cdb1c70Snonaka static const struct {
5039cdb1c70Snonaka 	uint8_t reg;
5049cdb1c70Snonaka 	uint8_t val;
5059cdb1c70Snonaka } rt3070_def_rf[] = {
5069cdb1c70Snonaka 	RT3070_DEF_RF
5079cdb1c70Snonaka }, rt3572_def_rf[] = {
5089cdb1c70Snonaka 	RT3572_DEF_RF
509faca41fbSmlelstv },rt3593_def_rf[] = {
510faca41fbSmlelstv 	RT3593_DEF_RF
511faca41fbSmlelstv },rt5390_def_rf[] = {
512faca41fbSmlelstv 	RT5390_DEF_RF
513faca41fbSmlelstv },rt5392_def_rf[] = {
514faca41fbSmlelstv 	RT5392_DEF_RF
515faca41fbSmlelstv },rt5592_def_rf[] = {
516faca41fbSmlelstv 	RT5592_DEF_RF
517faca41fbSmlelstv },rt5592_2ghz_def_rf[] = {
518faca41fbSmlelstv 	RT5592_2GHZ_DEF_RF
519faca41fbSmlelstv },rt5592_5ghz_def_rf[] = {
520faca41fbSmlelstv 	RT5592_5GHZ_DEF_RF
521faca41fbSmlelstv };
522faca41fbSmlelstv 
523faca41fbSmlelstv static const struct {
524faca41fbSmlelstv 	u_int firstchan;
525faca41fbSmlelstv 	u_int lastchan;
526faca41fbSmlelstv 	uint8_t reg;
527faca41fbSmlelstv 	uint8_t val;
528faca41fbSmlelstv } rt5592_chan_5ghz[] = {
529faca41fbSmlelstv 	RT5592_CHAN_5GHZ
5309cdb1c70Snonaka };
5319cdb1c70Snonaka 
5329cdb1c70Snonaka static int
5339cdb1c70Snonaka firmware_load(const char *dname, const char *iname, uint8_t **ucodep,
5349cdb1c70Snonaka     size_t *sizep)
5359cdb1c70Snonaka {
5369cdb1c70Snonaka 	firmware_handle_t fh;
5379cdb1c70Snonaka 	int error;
5389cdb1c70Snonaka 
5399cdb1c70Snonaka 	if ((error = firmware_open(dname, iname, &fh)) != 0)
5404e8e6643Sskrll 		return error;
5419cdb1c70Snonaka 	*sizep = firmware_get_size(fh);
5429cdb1c70Snonaka 	if ((*ucodep = firmware_malloc(*sizep)) == NULL) {
5439cdb1c70Snonaka 		firmware_close(fh);
5444e8e6643Sskrll 		return ENOMEM;
5459cdb1c70Snonaka 	}
5469cdb1c70Snonaka 	if ((error = firmware_read(fh, 0, *ucodep, *sizep)) != 0)
5479cdb1c70Snonaka 		firmware_free(*ucodep, *sizep);
5489cdb1c70Snonaka 	firmware_close(fh);
5499cdb1c70Snonaka 
5504e8e6643Sskrll 	return error;
5519cdb1c70Snonaka }
5529cdb1c70Snonaka 
5539cdb1c70Snonaka static int
5549cdb1c70Snonaka run_match(device_t parent, cfdata_t match, void *aux)
5559cdb1c70Snonaka {
5569cdb1c70Snonaka 	struct usb_attach_arg *uaa = aux;
5579cdb1c70Snonaka 
5584e8e6643Sskrll 	return (usb_lookup(run_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ?
5599cdb1c70Snonaka 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
5609cdb1c70Snonaka }
5619cdb1c70Snonaka 
5629cdb1c70Snonaka static void
5639cdb1c70Snonaka run_attach(device_t parent, device_t self, void *aux)
5649cdb1c70Snonaka {
5659cdb1c70Snonaka 	struct run_softc *sc = device_private(self);
5669cdb1c70Snonaka 	struct usb_attach_arg *uaa = aux;
5679cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
5689cdb1c70Snonaka 	struct ifnet *ifp = &sc->sc_if;
5699cdb1c70Snonaka 	usb_interface_descriptor_t *id;
5709cdb1c70Snonaka 	usb_endpoint_descriptor_t *ed;
5719cdb1c70Snonaka 	char *devinfop;
5729cdb1c70Snonaka 	int i, nrx, ntx, ntries, error;
5739cdb1c70Snonaka 	uint32_t ver;
5749cdb1c70Snonaka 
5759cdb1c70Snonaka 	aprint_naive("\n");
5769cdb1c70Snonaka 	aprint_normal("\n");
5779cdb1c70Snonaka 
5789cdb1c70Snonaka 	sc->sc_dev = self;
5794e8e6643Sskrll 	sc->sc_udev = uaa->uaa_device;
5809cdb1c70Snonaka 
5819cdb1c70Snonaka 	devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
5829cdb1c70Snonaka 	aprint_normal_dev(sc->sc_dev, "%s\n", devinfop);
5839cdb1c70Snonaka 	usbd_devinfo_free(devinfop);
5849cdb1c70Snonaka 
585897388eaSskrll 	error = usbd_set_config_no(sc->sc_udev, 1, 0);
586897388eaSskrll 	if (error != 0) {
587897388eaSskrll 		aprint_error_dev(sc->sc_dev, "failed to set configuration"
588897388eaSskrll 		    ", err=%s\n", usbd_errstr(error));
5899cdb1c70Snonaka 		return;
5909cdb1c70Snonaka 	}
5919cdb1c70Snonaka 
5929cdb1c70Snonaka 	/* get the first interface handle */
5939cdb1c70Snonaka 	error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface);
5949cdb1c70Snonaka 	if (error != 0) {
5959cdb1c70Snonaka 		aprint_error_dev(sc->sc_dev,
5969cdb1c70Snonaka 		    "could not get interface handle\n");
5979cdb1c70Snonaka 		return;
5989cdb1c70Snonaka 	}
5999cdb1c70Snonaka 
6009cdb1c70Snonaka 	/*
6019cdb1c70Snonaka 	 * Find all bulk endpoints.  There are 7 bulk endpoints: 1 for RX
6029cdb1c70Snonaka 	 * and 6 for TX (4 EDCAs + HCCA + Prio).
6039cdb1c70Snonaka 	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
6049cdb1c70Snonaka 	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
6059cdb1c70Snonaka 	 */
6069cdb1c70Snonaka 	nrx = ntx = 0;
6079cdb1c70Snonaka 	id = usbd_get_interface_descriptor(sc->sc_iface);
6089cdb1c70Snonaka 	for (i = 0; i < id->bNumEndpoints; i++) {
6099cdb1c70Snonaka 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
6109cdb1c70Snonaka 		if (ed == NULL || UE_GET_XFERTYPE(ed->bmAttributes) != UE_BULK)
6119cdb1c70Snonaka 			continue;
6129cdb1c70Snonaka 
6139cdb1c70Snonaka 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) {
6149cdb1c70Snonaka 			sc->rxq.pipe_no = ed->bEndpointAddress;
6159cdb1c70Snonaka 			nrx++;
616d42627d4Sskrll 		} else if (ntx < RUN_MAXEPOUT) {
6179cdb1c70Snonaka 			sc->txq[ntx].pipe_no = ed->bEndpointAddress;
6189cdb1c70Snonaka 			ntx++;
6199cdb1c70Snonaka 		}
6209cdb1c70Snonaka 	}
6219cdb1c70Snonaka 	/* make sure we've got them all */
622d42627d4Sskrll 	if (nrx < 1 || ntx < RUN_MAXEPOUT) {
6239cdb1c70Snonaka 		aprint_error_dev(sc->sc_dev, "missing endpoint\n");
6249cdb1c70Snonaka 		return;
6259cdb1c70Snonaka 	}
6269cdb1c70Snonaka 
6277c64a30eSjmcneill 	usb_init_task(&sc->sc_task, run_task, sc, 0);
6289cdb1c70Snonaka 	callout_init(&sc->scan_to, 0);
6299cdb1c70Snonaka 	callout_setfunc(&sc->scan_to, run_next_scan, sc);
6309cdb1c70Snonaka 	callout_init(&sc->calib_to, 0);
6319cdb1c70Snonaka 	callout_setfunc(&sc->calib_to, run_calibrate_to, sc);
6329cdb1c70Snonaka 
6339cdb1c70Snonaka 	sc->amrr.amrr_min_success_threshold =  1;
6349cdb1c70Snonaka 	sc->amrr.amrr_max_success_threshold = 10;
6359cdb1c70Snonaka 
6369cdb1c70Snonaka 	/* wait for the chip to settle */
6379cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
6389cdb1c70Snonaka 		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0)
6399cdb1c70Snonaka 			return;
6409cdb1c70Snonaka 		if (ver != 0 && ver != 0xffffffff)
6419cdb1c70Snonaka 			break;
6429cdb1c70Snonaka 		DELAY(10);
6439cdb1c70Snonaka 	}
6449cdb1c70Snonaka 	if (ntries == 100) {
6459cdb1c70Snonaka 		aprint_error_dev(sc->sc_dev,
6469cdb1c70Snonaka 		    "timeout waiting for NIC to initialize\n");
6479cdb1c70Snonaka 		return;
6489cdb1c70Snonaka 	}
6499cdb1c70Snonaka 	sc->mac_ver = ver >> 16;
6509cdb1c70Snonaka 	sc->mac_rev = ver & 0xffff;
6519cdb1c70Snonaka 
6529cdb1c70Snonaka 	/* retrieve RF rev. no and various other things from EEPROM */
6539cdb1c70Snonaka 	run_read_eeprom(sc);
6549cdb1c70Snonaka 
6551d5cb2a3Sjakllsch 	aprint_verbose_dev(sc->sc_dev,
6569cdb1c70Snonaka 	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
6579cdb1c70Snonaka 	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev), sc->ntxchains,
6589cdb1c70Snonaka 	    sc->nrxchains, ether_sprintf(ic->ic_myaddr));
6599cdb1c70Snonaka 
6609cdb1c70Snonaka 	ic->ic_ifp = ifp;
6619cdb1c70Snonaka 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
6629cdb1c70Snonaka 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
6639cdb1c70Snonaka 	ic->ic_state = IEEE80211_S_INIT;
6649cdb1c70Snonaka 
6659cdb1c70Snonaka 	/* set device capabilities */
6669cdb1c70Snonaka 	ic->ic_caps =
6679cdb1c70Snonaka 	    IEEE80211_C_MONITOR |	/* monitor mode supported */
6689cdb1c70Snonaka #ifndef IEEE80211_STA_ONLY
6699cdb1c70Snonaka 	    IEEE80211_C_IBSS |		/* IBSS mode supported */
6709cdb1c70Snonaka 	    IEEE80211_C_HOSTAP |	/* HostAP mode supported */
6719cdb1c70Snonaka #endif
6729cdb1c70Snonaka 	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
6739cdb1c70Snonaka 	    IEEE80211_C_SHSLOT |	/* short slot time supported */
6749cdb1c70Snonaka #ifdef RUN_HWCRYPTO
6759cdb1c70Snonaka 	    IEEE80211_C_WEP |		/* WEP */
6769cdb1c70Snonaka 	    IEEE80211_C_TKIP |		/* TKIP */
6779cdb1c70Snonaka 	    IEEE80211_C_AES_CCM |	/* AES CCMP */
6789cdb1c70Snonaka 	    IEEE80211_C_TKIPMIC |	/* TKIPMIC */
6799cdb1c70Snonaka #endif
6809cdb1c70Snonaka 	    IEEE80211_C_WME |		/* WME */
6819cdb1c70Snonaka 	    IEEE80211_C_WPA;		/* WPA/RSN */
6829cdb1c70Snonaka 
6839cdb1c70Snonaka 	if (sc->rf_rev == RT2860_RF_2750 ||
6849cdb1c70Snonaka 	    sc->rf_rev == RT2860_RF_2850 ||
685faca41fbSmlelstv 	    sc->rf_rev == RT3070_RF_3052 ||
686faca41fbSmlelstv 	    sc->rf_rev == RT3070_RF_3053 ||
687faca41fbSmlelstv 	    sc->rf_rev == RT5592_RF_5592) {
6889cdb1c70Snonaka 		/* set supported .11a rates */
6899cdb1c70Snonaka 		ic->ic_sup_rates[IEEE80211_MODE_11A] =
6909cdb1c70Snonaka 		    ieee80211_std_rateset_11a;
6919cdb1c70Snonaka 
6929cdb1c70Snonaka 		/* set supported .11a channels */
6939cdb1c70Snonaka 		for (i = 14; i < (int)__arraycount(rt2860_rf2850); i++) {
6949cdb1c70Snonaka 			uint8_t chan = rt2860_rf2850[i].chan;
6959cdb1c70Snonaka 			ic->ic_channels[chan].ic_freq =
6969cdb1c70Snonaka 			    ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
6979cdb1c70Snonaka 			ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A;
6989cdb1c70Snonaka 		}
6999cdb1c70Snonaka 	}
7009cdb1c70Snonaka 
7019cdb1c70Snonaka 	/* set supported .11b and .11g rates */
7029cdb1c70Snonaka 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
7039cdb1c70Snonaka 	ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
7049cdb1c70Snonaka 
7059cdb1c70Snonaka 	/* set supported .11b and .11g channels (1 through 14) */
7069cdb1c70Snonaka 	for (i = 1; i <= 14; i++) {
7079cdb1c70Snonaka 		ic->ic_channels[i].ic_freq =
7089cdb1c70Snonaka 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
7099cdb1c70Snonaka 		ic->ic_channels[i].ic_flags =
7109cdb1c70Snonaka 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
7119cdb1c70Snonaka 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
7129cdb1c70Snonaka 	}
7139cdb1c70Snonaka 
7149cdb1c70Snonaka 	ifp->if_softc = sc;
7159cdb1c70Snonaka 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
7169cdb1c70Snonaka 	ifp->if_init = run_init;
7179cdb1c70Snonaka 	ifp->if_ioctl = run_ioctl;
7189cdb1c70Snonaka 	ifp->if_start = run_start;
7199cdb1c70Snonaka 	ifp->if_watchdog = run_watchdog;
7209cdb1c70Snonaka 	IFQ_SET_READY(&ifp->if_snd);
7219cdb1c70Snonaka 	memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
7229cdb1c70Snonaka 
7239cdb1c70Snonaka 	if_attach(ifp);
7249cdb1c70Snonaka 	ieee80211_ifattach(ic);
7259cdb1c70Snonaka 	ic->ic_node_alloc = run_node_alloc;
7269cdb1c70Snonaka 	ic->ic_newassoc = run_newassoc;
7279cdb1c70Snonaka 	ic->ic_updateslot = run_updateslot;
7289cdb1c70Snonaka 	ic->ic_wme.wme_update = run_updateedca;
7299cdb1c70Snonaka #ifdef RUN_HWCRYPTO
7309cdb1c70Snonaka 	ic->ic_crypto.cs_key_set = run_set_key;
7319cdb1c70Snonaka 	ic->ic_crypto.cs_key_delete = run_delete_key;
7329cdb1c70Snonaka #endif
7339cdb1c70Snonaka 	/* override state transition machine */
7349cdb1c70Snonaka 	sc->sc_newstate = ic->ic_newstate;
7359cdb1c70Snonaka 	ic->ic_newstate = run_newstate;
7369cdb1c70Snonaka 	ieee80211_media_init(ic, run_media_change, ieee80211_media_status);
7379cdb1c70Snonaka 
7389cdb1c70Snonaka 	bpf_attach2(ifp, DLT_IEEE802_11_RADIO,
7399cdb1c70Snonaka 	    sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN,
7409cdb1c70Snonaka 	    &sc->sc_drvbpf);
7419cdb1c70Snonaka 
7429cdb1c70Snonaka 	sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
7439cdb1c70Snonaka 	sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
7449cdb1c70Snonaka 	sc->sc_rxtap.wr_ihdr.it_present = htole32(RUN_RX_RADIOTAP_PRESENT);
7459cdb1c70Snonaka 
7469cdb1c70Snonaka 	sc->sc_txtap_len = sizeof(sc->sc_txtapu);
7479cdb1c70Snonaka 	sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
7489cdb1c70Snonaka 	sc->sc_txtap.wt_ihdr.it_present = htole32(RUN_TX_RADIOTAP_PRESENT);
7499cdb1c70Snonaka 
7509cdb1c70Snonaka 	ieee80211_announce(ic);
7519cdb1c70Snonaka 
7529cdb1c70Snonaka 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
753b2901b1bSnonaka 
754b2901b1bSnonaka 	if (!pmf_device_register(self, NULL, NULL))
755b2901b1bSnonaka 		aprint_error_dev(self, "couldn't establish power handler\n");
7569cdb1c70Snonaka }
7579cdb1c70Snonaka 
7589cdb1c70Snonaka static int
7599cdb1c70Snonaka run_detach(device_t self, int flags)
7609cdb1c70Snonaka {
7619cdb1c70Snonaka 	struct run_softc *sc = device_private(self);
7629cdb1c70Snonaka 	struct ifnet *ifp = &sc->sc_if;
7639cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
7649cdb1c70Snonaka 	int s;
7659cdb1c70Snonaka 
7669cdb1c70Snonaka 	if (ifp->if_softc == NULL)
7674e8e6643Sskrll 		return 0;
7689cdb1c70Snonaka 
769b2901b1bSnonaka 	pmf_device_deregister(self);
770b2901b1bSnonaka 
771da8283baSmlelstv 	s = splusb();
7729cdb1c70Snonaka 
7739cdb1c70Snonaka 	sc->sc_flags |= RUN_DETACHING;
7749cdb1c70Snonaka 
7759cdb1c70Snonaka 	if (ifp->if_flags & IFF_RUNNING) {
7769cdb1c70Snonaka 		run_stop(ifp, 0);
777080b2b0bSriastradh 		callout_halt(&sc->scan_to, NULL);
778080b2b0bSriastradh 		callout_halt(&sc->calib_to, NULL);
779a1de0147Sriastradh 		usb_rem_task_wait(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER,
780a1de0147Sriastradh 		    NULL);
7819cdb1c70Snonaka 	}
7829cdb1c70Snonaka 
7839cdb1c70Snonaka 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
7849cdb1c70Snonaka 	bpf_detach(ifp);
7859cdb1c70Snonaka 	ieee80211_ifdetach(ic);
7869cdb1c70Snonaka 	if_detach(ifp);
7879cdb1c70Snonaka 
7889cdb1c70Snonaka 	splx(s);
7899cdb1c70Snonaka 
7909cdb1c70Snonaka 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
7919cdb1c70Snonaka 
792faca41fbSmlelstv 	callout_stop(&sc->scan_to);
793faca41fbSmlelstv 	callout_stop(&sc->calib_to);
794faca41fbSmlelstv 
7959cdb1c70Snonaka 	callout_destroy(&sc->scan_to);
7969cdb1c70Snonaka 	callout_destroy(&sc->calib_to);
7979cdb1c70Snonaka 
7984e8e6643Sskrll 	return 0;
7999cdb1c70Snonaka }
8009cdb1c70Snonaka 
8019cdb1c70Snonaka static int
8029cdb1c70Snonaka run_activate(device_t self, enum devact act)
8039cdb1c70Snonaka {
8049cdb1c70Snonaka 	struct run_softc *sc = device_private(self);
8059cdb1c70Snonaka 
8069cdb1c70Snonaka 	switch (act) {
8079cdb1c70Snonaka 	case DVACT_DEACTIVATE:
8089cdb1c70Snonaka 		if_deactivate(sc->sc_ic.ic_ifp);
8094e8e6643Sskrll 		return 0;
8109cdb1c70Snonaka 	default:
8114e8e6643Sskrll 		return EOPNOTSUPP;
8129cdb1c70Snonaka 	}
8139cdb1c70Snonaka }
8149cdb1c70Snonaka 
8159cdb1c70Snonaka static int
8169cdb1c70Snonaka run_alloc_rx_ring(struct run_softc *sc)
8179cdb1c70Snonaka {
8189cdb1c70Snonaka 	struct run_rx_ring *rxq = &sc->rxq;
8199cdb1c70Snonaka 	int i, error;
8209cdb1c70Snonaka 
8219cdb1c70Snonaka 	error = usbd_open_pipe(sc->sc_iface, rxq->pipe_no, 0, &rxq->pipeh);
8229cdb1c70Snonaka 	if (error != 0)
8239cdb1c70Snonaka 		goto fail;
8249cdb1c70Snonaka 
8259cdb1c70Snonaka 	for (i = 0; i < RUN_RX_RING_COUNT; i++) {
8269cdb1c70Snonaka 		struct run_rx_data *data = &rxq->data[i];
8279cdb1c70Snonaka 
8289cdb1c70Snonaka 		data->sc = sc;	/* backpointer for callbacks */
8299cdb1c70Snonaka 
8304e8e6643Sskrll 		error = usbd_create_xfer(sc->rxq.pipeh, RUN_MAX_RXSZ,
831b8421611Sskrll 		    0, 0, &data->xfer);
8324e8e6643Sskrll 		if (error)
8339cdb1c70Snonaka 			goto fail;
8344e8e6643Sskrll 
8354e8e6643Sskrll 		data->buf = usbd_get_buffer(data->xfer);
8369cdb1c70Snonaka 	}
8379cdb1c70Snonaka 	if (error != 0)
8389cdb1c70Snonaka fail:		run_free_rx_ring(sc);
8394e8e6643Sskrll 	return error;
8409cdb1c70Snonaka }
8419cdb1c70Snonaka 
8429cdb1c70Snonaka static void
8439cdb1c70Snonaka run_free_rx_ring(struct run_softc *sc)
8449cdb1c70Snonaka {
8459cdb1c70Snonaka 	struct run_rx_ring *rxq = &sc->rxq;
8469cdb1c70Snonaka 	int i;
8479cdb1c70Snonaka 
8489cdb1c70Snonaka 	if (rxq->pipeh != NULL) {
8499cdb1c70Snonaka 		usbd_abort_pipe(rxq->pipeh);
8509cdb1c70Snonaka 	}
8519cdb1c70Snonaka 	for (i = 0; i < RUN_RX_RING_COUNT; i++) {
8529cdb1c70Snonaka 		if (rxq->data[i].xfer != NULL)
8534e8e6643Sskrll 			usbd_destroy_xfer(rxq->data[i].xfer);
8549cdb1c70Snonaka 		rxq->data[i].xfer = NULL;
8559cdb1c70Snonaka 	}
8564e8e6643Sskrll 	if (rxq->pipeh != NULL) {
8574e8e6643Sskrll 		usbd_close_pipe(rxq->pipeh);
8584e8e6643Sskrll 		rxq->pipeh = NULL;
8594e8e6643Sskrll 	}
8609cdb1c70Snonaka }
8619cdb1c70Snonaka 
8629cdb1c70Snonaka static int
8639cdb1c70Snonaka run_alloc_tx_ring(struct run_softc *sc, int qid)
8649cdb1c70Snonaka {
8659cdb1c70Snonaka 	struct run_tx_ring *txq = &sc->txq[qid];
8669cdb1c70Snonaka 	int i, error;
867d164e220Smlelstv 	uint16_t txwisize;
868d164e220Smlelstv 
869d164e220Smlelstv 	txwisize = sizeof(struct rt2860_txwi);
870d164e220Smlelstv 	if (sc->mac_ver == 0x5592)
871d164e220Smlelstv 		txwisize += sizeof(uint32_t);
8729cdb1c70Snonaka 
8739cdb1c70Snonaka 	txq->cur = txq->queued = 0;
8749cdb1c70Snonaka 
8759cdb1c70Snonaka 	error = usbd_open_pipe(sc->sc_iface, txq->pipe_no, 0, &txq->pipeh);
8769cdb1c70Snonaka 	if (error != 0)
8779cdb1c70Snonaka 		goto fail;
8789cdb1c70Snonaka 
8799cdb1c70Snonaka 	for (i = 0; i < RUN_TX_RING_COUNT; i++) {
8809cdb1c70Snonaka 		struct run_tx_data *data = &txq->data[i];
8819cdb1c70Snonaka 
8829cdb1c70Snonaka 		data->sc = sc;	/* backpointer for callbacks */
8839cdb1c70Snonaka 		data->qid = qid;
8849cdb1c70Snonaka 
8854e8e6643Sskrll 		error = usbd_create_xfer(txq->pipeh, RUN_MAX_TXSZ,
8864e8e6643Sskrll 		    USBD_FORCE_SHORT_XFER, 0, &data->xfer);
8874e8e6643Sskrll 		if (error)
8889cdb1c70Snonaka 			goto fail;
8894e8e6643Sskrll 
8904e8e6643Sskrll 		data->buf = usbd_get_buffer(data->xfer);
8919cdb1c70Snonaka 		/* zeroize the TXD + TXWI part */
892d164e220Smlelstv 		memset(data->buf, 0, sizeof(struct rt2870_txd) + txwisize);
8939cdb1c70Snonaka 	}
8949cdb1c70Snonaka 	if (error != 0)
8959cdb1c70Snonaka fail:		run_free_tx_ring(sc, qid);
8964e8e6643Sskrll 	return error;
8979cdb1c70Snonaka }
8989cdb1c70Snonaka 
8999cdb1c70Snonaka static void
9009cdb1c70Snonaka run_free_tx_ring(struct run_softc *sc, int qid)
9019cdb1c70Snonaka {
9029cdb1c70Snonaka 	struct run_tx_ring *txq = &sc->txq[qid];
9039cdb1c70Snonaka 	int i;
9049cdb1c70Snonaka 
9059cdb1c70Snonaka 	if (txq->pipeh != NULL) {
9069cdb1c70Snonaka 		usbd_abort_pipe(txq->pipeh);
9079cdb1c70Snonaka 		usbd_close_pipe(txq->pipeh);
9089cdb1c70Snonaka 		txq->pipeh = NULL;
9099cdb1c70Snonaka 	}
9109cdb1c70Snonaka 	for (i = 0; i < RUN_TX_RING_COUNT; i++) {
9119cdb1c70Snonaka 		if (txq->data[i].xfer != NULL)
9124e8e6643Sskrll 			usbd_destroy_xfer(txq->data[i].xfer);
9139cdb1c70Snonaka 		txq->data[i].xfer = NULL;
9149cdb1c70Snonaka 	}
9159cdb1c70Snonaka }
9169cdb1c70Snonaka 
9179cdb1c70Snonaka static int
9189cdb1c70Snonaka run_load_microcode(struct run_softc *sc)
9199cdb1c70Snonaka {
9209cdb1c70Snonaka 	usb_device_request_t req;
9219cdb1c70Snonaka 	const char *fwname;
9228317b16eSmartin 	u_char *ucode = NULL;	/* XXX gcc 4.8.3: maybe-uninitialized */
9238317b16eSmartin 	size_t size = 0;	/* XXX gcc 4.8.3: maybe-uninitialized */
9249cdb1c70Snonaka 	uint32_t tmp;
9259cdb1c70Snonaka 	int ntries, error;
9269cdb1c70Snonaka 
9279cdb1c70Snonaka 	/* RT3071/RT3072 use a different firmware */
9289cdb1c70Snonaka 	if (sc->mac_ver != 0x2860 &&
9299cdb1c70Snonaka 	    sc->mac_ver != 0x2872 &&
9309cdb1c70Snonaka 	    sc->mac_ver != 0x3070)
9319cdb1c70Snonaka 		fwname = "run-rt3071";
9329cdb1c70Snonaka 	else
9339cdb1c70Snonaka 		fwname = "run-rt2870";
9349cdb1c70Snonaka 
935c9051a9fSnonaka 	if ((error = firmware_load("run", fwname, &ucode, &size)) != 0) {
9361d5cb2a3Sjakllsch 		device_printf(sc->sc_dev,
9379cdb1c70Snonaka 		    "error %d, could not read firmware %s\n", error, fwname);
9384e8e6643Sskrll 		return error;
9399cdb1c70Snonaka 	}
9409cdb1c70Snonaka 	if (size != 4096) {
9411d5cb2a3Sjakllsch 		device_printf(sc->sc_dev,
9429cdb1c70Snonaka 		    "invalid firmware size (should be 4KB)\n");
9439cdb1c70Snonaka 		firmware_free(ucode, size);
9444e8e6643Sskrll 		return EINVAL;
9459cdb1c70Snonaka 	}
9469cdb1c70Snonaka 
9479cdb1c70Snonaka 	run_read(sc, RT2860_ASIC_VER_ID, &tmp);
9489cdb1c70Snonaka 	/* write microcode image */
9499cdb1c70Snonaka 	run_write_region_1(sc, RT2870_FW_BASE, ucode, size);
9509cdb1c70Snonaka 	firmware_free(ucode, size);
9519cdb1c70Snonaka 	run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
9529cdb1c70Snonaka 	run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
9539cdb1c70Snonaka 
9549cdb1c70Snonaka 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
9559cdb1c70Snonaka 	req.bRequest = RT2870_RESET;
9569cdb1c70Snonaka 	USETW(req.wValue, 8);
9579cdb1c70Snonaka 	USETW(req.wIndex, 0);
9589cdb1c70Snonaka 	USETW(req.wLength, 0);
9599cdb1c70Snonaka 	if ((error = usbd_do_request(sc->sc_udev, &req, NULL)) != 0)
9604e8e6643Sskrll 		return error;
9619cdb1c70Snonaka 
9629cdb1c70Snonaka 	usbd_delay_ms(sc->sc_udev, 10);
963d164e220Smlelstv 	run_write(sc, RT2860_H2M_BBPAGENT, 0);
9649cdb1c70Snonaka 	run_write(sc, RT2860_H2M_MAILBOX, 0);
965d164e220Smlelstv 	run_write(sc, RT2860_H2M_INTSRC, 0);
9669cdb1c70Snonaka 	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
9674e8e6643Sskrll 		return error;
9689cdb1c70Snonaka 
9699cdb1c70Snonaka 	/* wait until microcontroller is ready */
9709cdb1c70Snonaka 	for (ntries = 0; ntries < 1000; ntries++) {
9719cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
9724e8e6643Sskrll 			return error;
9739cdb1c70Snonaka 		if (tmp & RT2860_MCU_READY)
9749cdb1c70Snonaka 			break;
975faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 10);
9769cdb1c70Snonaka 	}
9779cdb1c70Snonaka 	if (ntries == 1000) {
9781d5cb2a3Sjakllsch 		device_printf(sc->sc_dev,
9799cdb1c70Snonaka 		    "timeout waiting for MCU to initialize\n");
9804e8e6643Sskrll 		return ETIMEDOUT;
9819cdb1c70Snonaka 	}
9829cdb1c70Snonaka 
9839cdb1c70Snonaka 	sc->sc_flags |= RUN_FWLOADED;
9849cdb1c70Snonaka 
9859cdb1c70Snonaka 	DPRINTF(("microcode successfully loaded after %d tries\n", ntries));
9864e8e6643Sskrll 	return 0;
9879cdb1c70Snonaka }
9889cdb1c70Snonaka 
9899cdb1c70Snonaka static int
9909cdb1c70Snonaka run_reset(struct run_softc *sc)
9919cdb1c70Snonaka {
9929cdb1c70Snonaka 	usb_device_request_t req;
9939cdb1c70Snonaka 
9949cdb1c70Snonaka 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
9959cdb1c70Snonaka 	req.bRequest = RT2870_RESET;
9969cdb1c70Snonaka 	USETW(req.wValue, 1);
9979cdb1c70Snonaka 	USETW(req.wIndex, 0);
9989cdb1c70Snonaka 	USETW(req.wLength, 0);
9999cdb1c70Snonaka 	return usbd_do_request(sc->sc_udev, &req, NULL);
10009cdb1c70Snonaka }
10019cdb1c70Snonaka 
10029cdb1c70Snonaka static int
10039cdb1c70Snonaka run_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
10049cdb1c70Snonaka {
10059cdb1c70Snonaka 	uint32_t tmp;
10069cdb1c70Snonaka 	int error;
10079cdb1c70Snonaka 
10084e8e6643Sskrll 	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof(tmp));
10099cdb1c70Snonaka 	if (error == 0)
10109cdb1c70Snonaka 		*val = le32toh(tmp);
10119cdb1c70Snonaka 	else
10129cdb1c70Snonaka 		*val = 0xffffffff;
10134e8e6643Sskrll 	return error;
10149cdb1c70Snonaka }
10159cdb1c70Snonaka 
10169cdb1c70Snonaka static int
10179cdb1c70Snonaka run_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
10189cdb1c70Snonaka {
10199cdb1c70Snonaka 	usb_device_request_t req;
10209cdb1c70Snonaka 
10219cdb1c70Snonaka 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
10229cdb1c70Snonaka 	req.bRequest = RT2870_READ_REGION_1;
10239cdb1c70Snonaka 	USETW(req.wValue, 0);
10249cdb1c70Snonaka 	USETW(req.wIndex, reg);
10259cdb1c70Snonaka 	USETW(req.wLength, len);
10269cdb1c70Snonaka 	return usbd_do_request(sc->sc_udev, &req, buf);
10279cdb1c70Snonaka }
10289cdb1c70Snonaka 
10299cdb1c70Snonaka static int
10309cdb1c70Snonaka run_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
10319cdb1c70Snonaka {
10329cdb1c70Snonaka 	usb_device_request_t req;
10339cdb1c70Snonaka 
10349cdb1c70Snonaka 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
10359cdb1c70Snonaka 	req.bRequest = RT2870_WRITE_2;
10369cdb1c70Snonaka 	USETW(req.wValue, val);
10379cdb1c70Snonaka 	USETW(req.wIndex, reg);
10389cdb1c70Snonaka 	USETW(req.wLength, 0);
10399cdb1c70Snonaka 	return usbd_do_request(sc->sc_udev, &req, NULL);
10409cdb1c70Snonaka }
10419cdb1c70Snonaka 
10429cdb1c70Snonaka static int
10439cdb1c70Snonaka run_write(struct run_softc *sc, uint16_t reg, uint32_t val)
10449cdb1c70Snonaka {
10459cdb1c70Snonaka 	int error;
10469cdb1c70Snonaka 
10479cdb1c70Snonaka 	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
10489cdb1c70Snonaka 		error = run_write_2(sc, reg + 2, val >> 16);
10494e8e6643Sskrll 	return error;
10509cdb1c70Snonaka }
10519cdb1c70Snonaka 
10529cdb1c70Snonaka static int
10539cdb1c70Snonaka run_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
10549cdb1c70Snonaka     int len)
10559cdb1c70Snonaka {
10569cdb1c70Snonaka #if 1
10579cdb1c70Snonaka 	int i, error = 0;
10589cdb1c70Snonaka 	/*
10599cdb1c70Snonaka 	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
10609cdb1c70Snonaka 	 * We thus issue multiple WRITE_2 commands instead.
10619cdb1c70Snonaka 	 */
10629cdb1c70Snonaka 	KASSERT((len & 1) == 0);
10639cdb1c70Snonaka 	for (i = 0; i < len && error == 0; i += 2)
10649cdb1c70Snonaka 		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
10654e8e6643Sskrll 	return error;
10669cdb1c70Snonaka #else
10679cdb1c70Snonaka 	usb_device_request_t req;
10689cdb1c70Snonaka 
10699cdb1c70Snonaka 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
10709cdb1c70Snonaka 	req.bRequest = RT2870_WRITE_REGION_1;
10719cdb1c70Snonaka 	USETW(req.wValue, 0);
10729cdb1c70Snonaka 	USETW(req.wIndex, reg);
10739cdb1c70Snonaka 	USETW(req.wLength, len);
107452f0ad4eSgson 	return usbd_do_request(sc->sc_udev, &req, __UNCONST(buf));
10759cdb1c70Snonaka #endif
10769cdb1c70Snonaka }
10779cdb1c70Snonaka 
10789cdb1c70Snonaka static int
10799cdb1c70Snonaka run_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int count)
10809cdb1c70Snonaka {
10819cdb1c70Snonaka 	int error = 0;
10829cdb1c70Snonaka 
10839cdb1c70Snonaka 	for (; count > 0 && error == 0; count--, reg += 4)
10849cdb1c70Snonaka 		error = run_write(sc, reg, val);
10854e8e6643Sskrll 	return error;
10869cdb1c70Snonaka }
10879cdb1c70Snonaka 
10889cdb1c70Snonaka static int
1089faca41fbSmlelstv run_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
10909cdb1c70Snonaka {
10919cdb1c70Snonaka 	uint32_t tmp;
10929cdb1c70Snonaka 	uint16_t reg;
10939cdb1c70Snonaka 	int error, ntries;
10949cdb1c70Snonaka 
10959cdb1c70Snonaka 	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
10964e8e6643Sskrll 		return error;
10979cdb1c70Snonaka 
1098faca41fbSmlelstv 	if (count == 2)
10999cdb1c70Snonaka 		addr *= 2;
11009cdb1c70Snonaka 	/*-
11019cdb1c70Snonaka 	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
11029cdb1c70Snonaka 	 * DATA0: F E D C
11039cdb1c70Snonaka 	 * DATA1: B A 9 8
11049cdb1c70Snonaka 	 * DATA2: 7 6 5 4
11059cdb1c70Snonaka 	 * DATA3: 3 2 1 0
11069cdb1c70Snonaka 	 */
11079cdb1c70Snonaka 	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
11089cdb1c70Snonaka 	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
11099cdb1c70Snonaka 	run_write(sc, RT3070_EFUSE_CTRL, tmp);
11109cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
11119cdb1c70Snonaka 		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
11124e8e6643Sskrll 			return error;
11139cdb1c70Snonaka 		if (!(tmp & RT3070_EFSROM_KICK))
11149cdb1c70Snonaka 			break;
1115faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 2);
11169cdb1c70Snonaka 	}
11179cdb1c70Snonaka 	if (ntries == 100)
11184e8e6643Sskrll 		return ETIMEDOUT;
11199cdb1c70Snonaka 
11209cdb1c70Snonaka 	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
11219cdb1c70Snonaka 		*val = 0xffff;	/* address not found */
11224e8e6643Sskrll 		return 0;
11239cdb1c70Snonaka 	}
11249cdb1c70Snonaka 	/* determine to which 32-bit register our 16-bit word belongs */
11259cdb1c70Snonaka 	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
11269cdb1c70Snonaka 	if ((error = run_read(sc, reg, &tmp)) != 0)
11274e8e6643Sskrll 		return error;
11289cdb1c70Snonaka 
1129d164e220Smlelstv 	tmp >>= (8 * (addr & 0x3));
1130faca41fbSmlelstv 	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
11314e8e6643Sskrll 	return 0;
11329cdb1c70Snonaka }
11339cdb1c70Snonaka 
1134faca41fbSmlelstv /* Read 16-bit from eFUSE ROM for RT3xxxx. */
1135faca41fbSmlelstv static int
1136faca41fbSmlelstv run_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1137faca41fbSmlelstv {
113826ee7ba1Sskrll 	return run_efuse_read(sc, addr, val, 2);
1139faca41fbSmlelstv }
1140faca41fbSmlelstv 
11419cdb1c70Snonaka static int
11429cdb1c70Snonaka run_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
11439cdb1c70Snonaka {
11449cdb1c70Snonaka 	usb_device_request_t req;
11459cdb1c70Snonaka 	uint16_t tmp;
11469cdb1c70Snonaka 	int error;
11479cdb1c70Snonaka 
11489cdb1c70Snonaka 	addr *= 2;
11499cdb1c70Snonaka 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
11509cdb1c70Snonaka 	req.bRequest = RT2870_EEPROM_READ;
11519cdb1c70Snonaka 	USETW(req.wValue, 0);
11529cdb1c70Snonaka 	USETW(req.wIndex, addr);
11534e8e6643Sskrll 	USETW(req.wLength, sizeof(tmp));
11549cdb1c70Snonaka 	error = usbd_do_request(sc->sc_udev, &req, &tmp);
11559cdb1c70Snonaka 	if (error == 0)
11569cdb1c70Snonaka 		*val = le16toh(tmp);
11579cdb1c70Snonaka 	else
11589cdb1c70Snonaka 		*val = 0xffff;
11594e8e6643Sskrll 	return error;
11609cdb1c70Snonaka }
11619cdb1c70Snonaka 
11629cdb1c70Snonaka static __inline int
11639cdb1c70Snonaka run_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
11649cdb1c70Snonaka {
11659cdb1c70Snonaka 
11669cdb1c70Snonaka 	/* either eFUSE ROM or EEPROM */
11679cdb1c70Snonaka 	return sc->sc_srom_read(sc, addr, val);
11689cdb1c70Snonaka }
11699cdb1c70Snonaka 
11709cdb1c70Snonaka static int
11719cdb1c70Snonaka run_rt2870_rf_write(struct run_softc *sc, uint8_t reg, uint32_t val)
11729cdb1c70Snonaka {
11739cdb1c70Snonaka 	uint32_t tmp;
11749cdb1c70Snonaka 	int error, ntries;
11759cdb1c70Snonaka 
11769cdb1c70Snonaka 	for (ntries = 0; ntries < 10; ntries++) {
11779cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
11784e8e6643Sskrll 			return error;
11799cdb1c70Snonaka 		if (!(tmp & RT2860_RF_REG_CTRL))
11809cdb1c70Snonaka 			break;
11819cdb1c70Snonaka 	}
11829cdb1c70Snonaka 	if (ntries == 10)
11834e8e6643Sskrll 		return ETIMEDOUT;
11849cdb1c70Snonaka 
11859cdb1c70Snonaka 	/* RF registers are 24-bit on the RT2860 */
11869cdb1c70Snonaka 	tmp = RT2860_RF_REG_CTRL | 24 << RT2860_RF_REG_WIDTH_SHIFT |
11879cdb1c70Snonaka 	    (val & 0x3fffff) << 2 | (reg & 3);
11889cdb1c70Snonaka 	return run_write(sc, RT2860_RF_CSR_CFG0, tmp);
11899cdb1c70Snonaka }
11909cdb1c70Snonaka 
11919cdb1c70Snonaka static int
11929cdb1c70Snonaka run_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
11939cdb1c70Snonaka {
11949cdb1c70Snonaka 	uint32_t tmp;
11959cdb1c70Snonaka 	int error, ntries;
11969cdb1c70Snonaka 
11979cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
11989cdb1c70Snonaka 		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
11994e8e6643Sskrll 			return error;
12009cdb1c70Snonaka 		if (!(tmp & RT3070_RF_KICK))
12019cdb1c70Snonaka 			break;
12029cdb1c70Snonaka 	}
12039cdb1c70Snonaka 	if (ntries == 100)
12044e8e6643Sskrll 		return ETIMEDOUT;
12059cdb1c70Snonaka 
12069cdb1c70Snonaka 	tmp = RT3070_RF_KICK | reg << 8;
12079cdb1c70Snonaka 	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
12084e8e6643Sskrll 		return error;
12099cdb1c70Snonaka 
12109cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
12119cdb1c70Snonaka 		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
12124e8e6643Sskrll 			return error;
12139cdb1c70Snonaka 		if (!(tmp & RT3070_RF_KICK))
12149cdb1c70Snonaka 			break;
12159cdb1c70Snonaka 	}
12169cdb1c70Snonaka 	if (ntries == 100)
12174e8e6643Sskrll 		return ETIMEDOUT;
12189cdb1c70Snonaka 
12199cdb1c70Snonaka 	*val = tmp & 0xff;
12204e8e6643Sskrll 	return 0;
12219cdb1c70Snonaka }
12229cdb1c70Snonaka 
12239cdb1c70Snonaka static int
12249cdb1c70Snonaka run_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
12259cdb1c70Snonaka {
12269cdb1c70Snonaka 	uint32_t tmp;
12279cdb1c70Snonaka 	int error, ntries;
12289cdb1c70Snonaka 
12299cdb1c70Snonaka 	for (ntries = 0; ntries < 10; ntries++) {
12309cdb1c70Snonaka 		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
12314e8e6643Sskrll 			return error;
12329cdb1c70Snonaka 		if (!(tmp & RT3070_RF_KICK))
12339cdb1c70Snonaka 			break;
12349cdb1c70Snonaka 	}
12359cdb1c70Snonaka 	if (ntries == 10)
12364e8e6643Sskrll 		return ETIMEDOUT;
12379cdb1c70Snonaka 
12389cdb1c70Snonaka 	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
12399cdb1c70Snonaka 	return run_write(sc, RT3070_RF_CSR_CFG, tmp);
12409cdb1c70Snonaka }
12419cdb1c70Snonaka 
12429cdb1c70Snonaka static int
12439cdb1c70Snonaka run_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
12449cdb1c70Snonaka {
12459cdb1c70Snonaka 	uint32_t tmp;
12469cdb1c70Snonaka 	int ntries, error;
12479cdb1c70Snonaka 
12489cdb1c70Snonaka 	for (ntries = 0; ntries < 10; ntries++) {
12499cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
12504e8e6643Sskrll 			return error;
12519cdb1c70Snonaka 		if (!(tmp & RT2860_BBP_CSR_KICK))
12529cdb1c70Snonaka 			break;
12539cdb1c70Snonaka 	}
12549cdb1c70Snonaka 	if (ntries == 10)
12554e8e6643Sskrll 		return ETIMEDOUT;
12569cdb1c70Snonaka 
12579cdb1c70Snonaka 	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
12589cdb1c70Snonaka 	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
12594e8e6643Sskrll 		return error;
12609cdb1c70Snonaka 
12619cdb1c70Snonaka 	for (ntries = 0; ntries < 10; ntries++) {
12629cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
12634e8e6643Sskrll 			return error;
12649cdb1c70Snonaka 		if (!(tmp & RT2860_BBP_CSR_KICK))
12659cdb1c70Snonaka 			break;
12669cdb1c70Snonaka 	}
12679cdb1c70Snonaka 	if (ntries == 10)
12684e8e6643Sskrll 		return ETIMEDOUT;
12699cdb1c70Snonaka 
12709cdb1c70Snonaka 	*val = tmp & 0xff;
12714e8e6643Sskrll 	return 0;
12729cdb1c70Snonaka }
12739cdb1c70Snonaka 
12749cdb1c70Snonaka static int
12759cdb1c70Snonaka run_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
12769cdb1c70Snonaka {
12779cdb1c70Snonaka 	uint32_t tmp;
12789cdb1c70Snonaka 	int ntries, error;
12799cdb1c70Snonaka 
12809cdb1c70Snonaka 	for (ntries = 0; ntries < 10; ntries++) {
12819cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
12824e8e6643Sskrll 			return error;
12839cdb1c70Snonaka 		if (!(tmp & RT2860_BBP_CSR_KICK))
12849cdb1c70Snonaka 			break;
12859cdb1c70Snonaka 	}
12869cdb1c70Snonaka 	if (ntries == 10)
12874e8e6643Sskrll 		return ETIMEDOUT;
12889cdb1c70Snonaka 
12899cdb1c70Snonaka 	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
12909cdb1c70Snonaka 	return run_write(sc, RT2860_BBP_CSR_CFG, tmp);
12919cdb1c70Snonaka }
12929cdb1c70Snonaka 
12939cdb1c70Snonaka /*
12949cdb1c70Snonaka  * Send a command to the 8051 microcontroller unit.
12959cdb1c70Snonaka  */
12969cdb1c70Snonaka static int
12979cdb1c70Snonaka run_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
12989cdb1c70Snonaka {
12999cdb1c70Snonaka 	uint32_t tmp;
13009cdb1c70Snonaka 	int error, ntries;
13019cdb1c70Snonaka 
13029cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
13039cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
13044e8e6643Sskrll 			return error;
13059cdb1c70Snonaka 		if (!(tmp & RT2860_H2M_BUSY))
13069cdb1c70Snonaka 			break;
13079cdb1c70Snonaka 	}
13089cdb1c70Snonaka 	if (ntries == 100)
13094e8e6643Sskrll 		return ETIMEDOUT;
13109cdb1c70Snonaka 
13119cdb1c70Snonaka 	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
13129cdb1c70Snonaka 	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
13139cdb1c70Snonaka 		error = run_write(sc, RT2860_HOST_CMD, cmd);
13144e8e6643Sskrll 	return error;
13159cdb1c70Snonaka }
13169cdb1c70Snonaka 
13179cdb1c70Snonaka /*
13189cdb1c70Snonaka  * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
13199cdb1c70Snonaka  * Used to adjust per-rate Tx power registers.
13209cdb1c70Snonaka  */
13219cdb1c70Snonaka static __inline uint32_t
13229cdb1c70Snonaka b4inc(uint32_t b32, int8_t delta)
13239cdb1c70Snonaka {
13249cdb1c70Snonaka 	int8_t i, b4;
13259cdb1c70Snonaka 
13269cdb1c70Snonaka 	for (i = 0; i < 8; i++) {
13279cdb1c70Snonaka 		b4 = b32 & 0xf;
13289cdb1c70Snonaka 		b4 += delta;
13299cdb1c70Snonaka 		if (b4 < 0)
13309cdb1c70Snonaka 			b4 = 0;
13319cdb1c70Snonaka 		else if (b4 > 0xf)
13329cdb1c70Snonaka 			b4 = 0xf;
13339cdb1c70Snonaka 		b32 = b32 >> 4 | b4 << 28;
13349cdb1c70Snonaka 	}
13354e8e6643Sskrll 	return b32;
13369cdb1c70Snonaka }
13379cdb1c70Snonaka 
13389cdb1c70Snonaka static const char *
1339d164e220Smlelstv run_get_rf(uint16_t rev)
13409cdb1c70Snonaka {
13419cdb1c70Snonaka 	switch (rev) {
13429cdb1c70Snonaka 	case RT2860_RF_2820:	return "RT2820";
13439cdb1c70Snonaka 	case RT2860_RF_2850:	return "RT2850";
13449cdb1c70Snonaka 	case RT2860_RF_2720:	return "RT2720";
13459cdb1c70Snonaka 	case RT2860_RF_2750:	return "RT2750";
13469cdb1c70Snonaka 	case RT3070_RF_3020:	return "RT3020";
13479cdb1c70Snonaka 	case RT3070_RF_2020:	return "RT2020";
13489cdb1c70Snonaka 	case RT3070_RF_3021:	return "RT3021";
13499cdb1c70Snonaka 	case RT3070_RF_3022:	return "RT3022";
13509cdb1c70Snonaka 	case RT3070_RF_3052:	return "RT3052";
1351faca41fbSmlelstv 	case RT3070_RF_3053:    return "RT3053";
1352faca41fbSmlelstv 	case RT5592_RF_5592:    return "RT5592";
1353faca41fbSmlelstv 	case RT5390_RF_5370:    return "RT5370";
1354faca41fbSmlelstv 	case RT5390_RF_5372:    return "RT5372";
13559cdb1c70Snonaka 	}
13569cdb1c70Snonaka 	return "unknown";
13579cdb1c70Snonaka }
13589cdb1c70Snonaka 
1359faca41fbSmlelstv static void
1360faca41fbSmlelstv run_rt3593_get_txpower(struct run_softc *sc)
1361faca41fbSmlelstv {
1362faca41fbSmlelstv 	uint16_t addr, val;
1363faca41fbSmlelstv 	int i;
1364faca41fbSmlelstv 
1365faca41fbSmlelstv 	/* Read power settings for 2GHz channels. */
1366faca41fbSmlelstv 	for (i = 0; i < 14; i += 2) {
1367faca41fbSmlelstv 		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1368faca41fbSmlelstv 		    RT2860_EEPROM_PWR2GHZ_BASE1;
1369faca41fbSmlelstv 		run_srom_read(sc, addr + i / 2, &val);
1370faca41fbSmlelstv 		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1371faca41fbSmlelstv 		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1372faca41fbSmlelstv 
1373faca41fbSmlelstv 		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1374faca41fbSmlelstv 		    RT2860_EEPROM_PWR2GHZ_BASE2;
1375faca41fbSmlelstv 		run_srom_read(sc, addr + i / 2, &val);
1376faca41fbSmlelstv 		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1377faca41fbSmlelstv 		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1378faca41fbSmlelstv 
1379faca41fbSmlelstv 		if (sc->ntxchains == 3) {
1380faca41fbSmlelstv 			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1381faca41fbSmlelstv 			    &val);
1382faca41fbSmlelstv 			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1383faca41fbSmlelstv 			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1384faca41fbSmlelstv 		}
1385faca41fbSmlelstv 	}
1386faca41fbSmlelstv 	/* Fix broken Tx power entries. */
1387faca41fbSmlelstv 	for (i = 0; i < 14; i++) {
1388faca41fbSmlelstv 		if (sc->txpow1[i] > 31)
1389faca41fbSmlelstv 			sc->txpow1[i] = 5;
1390faca41fbSmlelstv 		if (sc->txpow2[i] > 31)
1391faca41fbSmlelstv 			sc->txpow2[i] = 5;
1392faca41fbSmlelstv 		if (sc->ntxchains == 3) {
1393faca41fbSmlelstv 			if (sc->txpow3[i] > 31)
1394faca41fbSmlelstv 				sc->txpow3[i] = 5;
1395faca41fbSmlelstv 		}
1396faca41fbSmlelstv 	}
1397faca41fbSmlelstv 	/* Read power settings for 5GHz channels. */
1398faca41fbSmlelstv 	for (i = 0; i < 40; i += 2) {
1399faca41fbSmlelstv 		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1400faca41fbSmlelstv 		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1401faca41fbSmlelstv 		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1402faca41fbSmlelstv 
1403faca41fbSmlelstv 		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1404faca41fbSmlelstv 		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1405faca41fbSmlelstv 		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1406faca41fbSmlelstv 
1407faca41fbSmlelstv 		if (sc->ntxchains == 3) {
1408faca41fbSmlelstv 			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1409faca41fbSmlelstv 			    &val);
1410faca41fbSmlelstv 			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1411faca41fbSmlelstv 			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1412faca41fbSmlelstv 		}
1413faca41fbSmlelstv 	}
1414faca41fbSmlelstv }
1415faca41fbSmlelstv 
1416faca41fbSmlelstv static void
1417faca41fbSmlelstv run_get_txpower(struct run_softc *sc)
1418faca41fbSmlelstv {
1419faca41fbSmlelstv 	uint16_t val;
1420faca41fbSmlelstv 	int i;
1421faca41fbSmlelstv 
1422faca41fbSmlelstv 	/* Read power settings for 2GHz channels. */
1423faca41fbSmlelstv 	for (i = 0; i < 14; i += 2) {
1424faca41fbSmlelstv 		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1425faca41fbSmlelstv 		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1426faca41fbSmlelstv 		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1427faca41fbSmlelstv 
1428faca41fbSmlelstv 		if (sc->mac_ver != 0x5390) {
1429faca41fbSmlelstv 			run_srom_read(sc,
1430faca41fbSmlelstv 			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1431faca41fbSmlelstv 			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1432faca41fbSmlelstv 			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1433faca41fbSmlelstv 		}
1434faca41fbSmlelstv 	}
1435faca41fbSmlelstv 	/* Fix broken Tx power entries. */
1436faca41fbSmlelstv 	for (i = 0; i < 14; i++) {
1437faca41fbSmlelstv 		if (sc->mac_ver >= 0x5390) {
1438faca41fbSmlelstv 			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 39)
1439faca41fbSmlelstv 				sc->txpow1[i] = 5;
1440faca41fbSmlelstv 		} else {
1441faca41fbSmlelstv 			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1442faca41fbSmlelstv 				sc->txpow1[i] = 5;
1443faca41fbSmlelstv 		}
1444faca41fbSmlelstv 		if (sc->mac_ver > 0x5390) {
1445faca41fbSmlelstv 			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 39)
1446faca41fbSmlelstv 				sc->txpow2[i] = 5;
1447faca41fbSmlelstv 		} else if (sc->mac_ver < 0x5390) {
1448faca41fbSmlelstv 			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1449faca41fbSmlelstv 				sc->txpow2[i] = 5;
1450faca41fbSmlelstv 		}
1451faca41fbSmlelstv 		DPRINTF(("chan %d: power1=%d, power2=%d\n",
1452faca41fbSmlelstv 		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]));
1453faca41fbSmlelstv 	}
1454faca41fbSmlelstv 	/* Read power settings for 5GHz channels. */
1455faca41fbSmlelstv 	for (i = 0; i < 40; i += 2) {
1456faca41fbSmlelstv 		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1457faca41fbSmlelstv 		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1458faca41fbSmlelstv 		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1459faca41fbSmlelstv 
1460faca41fbSmlelstv 		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1461faca41fbSmlelstv 		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1462faca41fbSmlelstv 		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1463faca41fbSmlelstv 	}
1464faca41fbSmlelstv 	/* Fix broken Tx power entries. */
1465faca41fbSmlelstv 	for (i = 0; i < 40; i++ ) {
1466faca41fbSmlelstv 		if (sc->mac_ver != 0x5592) {
1467faca41fbSmlelstv 			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1468faca41fbSmlelstv 				sc->txpow1[14 + i] = 5;
1469faca41fbSmlelstv 			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1470faca41fbSmlelstv 				sc->txpow2[14 + i] = 5;
1471faca41fbSmlelstv 		}
1472faca41fbSmlelstv 		DPRINTF(("chan %d: power1=%d, power2=%d\n",
1473faca41fbSmlelstv 		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1474faca41fbSmlelstv 		    sc->txpow2[14 + i]));
1475faca41fbSmlelstv 	}
1476faca41fbSmlelstv }
1477faca41fbSmlelstv 
14789cdb1c70Snonaka static int
14799cdb1c70Snonaka run_read_eeprom(struct run_softc *sc)
14809cdb1c70Snonaka {
14819cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
14829cdb1c70Snonaka 	int8_t delta_2ghz, delta_5ghz;
14839cdb1c70Snonaka 	uint32_t tmp;
14849cdb1c70Snonaka 	uint16_t val;
14859cdb1c70Snonaka 	int ridx, ant, i;
14869cdb1c70Snonaka 
14879cdb1c70Snonaka 	/* check whether the ROM is eFUSE ROM or EEPROM */
14889cdb1c70Snonaka 	sc->sc_srom_read = run_eeprom_read_2;
14899cdb1c70Snonaka 	if (sc->mac_ver >= 0x3070) {
14909cdb1c70Snonaka 		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
14919cdb1c70Snonaka 		DPRINTF(("EFUSE_CTRL=0x%08x\n", tmp));
14929cdb1c70Snonaka 		if (tmp & RT3070_SEL_EFUSE)
14939cdb1c70Snonaka 			sc->sc_srom_read = run_efuse_read_2;
14949cdb1c70Snonaka 	}
14959cdb1c70Snonaka 
14969cdb1c70Snonaka 	/* read ROM version */
14979cdb1c70Snonaka 	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
14989cdb1c70Snonaka 	DPRINTF(("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8));
14999cdb1c70Snonaka 
15009cdb1c70Snonaka 	/* read MAC address */
15019cdb1c70Snonaka 	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
15029cdb1c70Snonaka 	ic->ic_myaddr[0] = val & 0xff;
15039cdb1c70Snonaka 	ic->ic_myaddr[1] = val >> 8;
15049cdb1c70Snonaka 	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
15059cdb1c70Snonaka 	ic->ic_myaddr[2] = val & 0xff;
15069cdb1c70Snonaka 	ic->ic_myaddr[3] = val >> 8;
15079cdb1c70Snonaka 	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
15089cdb1c70Snonaka 	ic->ic_myaddr[4] = val & 0xff;
15099cdb1c70Snonaka 	ic->ic_myaddr[5] = val >> 8;
15109cdb1c70Snonaka 
1511d164e220Smlelstv 	if (sc->mac_ver < 0x3593) {
15129cdb1c70Snonaka 		/* read vendor BBP settings */
15139cdb1c70Snonaka 		for (i = 0; i < 10; i++) {
15149cdb1c70Snonaka 			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
15159cdb1c70Snonaka 			sc->bbp[i].val = val & 0xff;
15169cdb1c70Snonaka 			sc->bbp[i].reg = val >> 8;
1517d164e220Smlelstv 			DPRINTF(("BBP%d=0x%02x\n", sc->bbp[i].reg,
1518d164e220Smlelstv 			    sc->bbp[i].val));
15199cdb1c70Snonaka 		}
1520faca41fbSmlelstv 
1521d164e220Smlelstv 		if (sc->mac_ver >= 0x3071) {
15229cdb1c70Snonaka 			/* read vendor RF settings */
1523faca41fbSmlelstv 			for (i = 0; i < 8; i++) {
1524d164e220Smlelstv 				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1525d164e220Smlelstv 				    &val);
15269cdb1c70Snonaka 				sc->rf[i].val = val & 0xff;
15279cdb1c70Snonaka 				sc->rf[i].reg = val >> 8;
15289cdb1c70Snonaka 				DPRINTF(("RF%d=0x%02x\n", sc->rf[i].reg,
15299cdb1c70Snonaka 				    sc->rf[i].val));
15309cdb1c70Snonaka 			}
1531d164e220Smlelstv 		}
1532d164e220Smlelstv 	}
15339cdb1c70Snonaka 
15349cdb1c70Snonaka 	/* read RF frequency offset from EEPROM */
1535d164e220Smlelstv 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1536d164e220Smlelstv 	    RT3593_EEPROM_FREQ, &val);
15379cdb1c70Snonaka 	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
15389cdb1c70Snonaka 	DPRINTF(("EEPROM freq offset %d\n", sc->freq & 0xff));
1539d164e220Smlelstv 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1540d164e220Smlelstv 	    RT3593_EEPROM_FREQ, &val);
15419cdb1c70Snonaka 	if ((val >> 8) != 0xff) {
15429cdb1c70Snonaka 		/* read LEDs operating mode */
15439cdb1c70Snonaka 		sc->leds = val >> 8;
1544d164e220Smlelstv 		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1545d164e220Smlelstv 		    RT3593_EEPROM_LED1, &sc->led[0]);
1546d164e220Smlelstv 		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1547d164e220Smlelstv 		    RT3593_EEPROM_LED2, &sc->led[1]);
1548d164e220Smlelstv 		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1549d164e220Smlelstv 		    RT3593_EEPROM_LED3, &sc->led[2]);
15509cdb1c70Snonaka 	} else {
15519cdb1c70Snonaka 		/* broken EEPROM, use default settings */
15529cdb1c70Snonaka 		sc->leds = 0x01;
15539cdb1c70Snonaka 		sc->led[0] = 0x5555;
15549cdb1c70Snonaka 		sc->led[1] = 0x2221;
15559cdb1c70Snonaka 		sc->led[2] = 0x5627;	/* differs from RT2860 */
15569cdb1c70Snonaka 	}
15579cdb1c70Snonaka 	DPRINTF(("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
15589cdb1c70Snonaka 	    sc->leds, sc->led[0], sc->led[1], sc->led[2]));
15599cdb1c70Snonaka 
15609cdb1c70Snonaka 	/* read RF information */
1561d164e220Smlelstv 	if (sc->mac_ver == 0x5390 || sc->mac_ver == 0x5392)
1562d164e220Smlelstv 		run_srom_read(sc, 0x00, &val);
1563d164e220Smlelstv 	else
15649cdb1c70Snonaka 		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
15659cdb1c70Snonaka 	if (val == 0xffff) {
15669cdb1c70Snonaka 		DPRINTF(("invalid EEPROM antenna info, using default\n"));
15679cdb1c70Snonaka 		if (sc->mac_ver == 0x3572) {
15689cdb1c70Snonaka 			/* default to RF3052 2T2R */
15699cdb1c70Snonaka 			sc->rf_rev = RT3070_RF_3052;
15709cdb1c70Snonaka 			sc->ntxchains = 2;
15719cdb1c70Snonaka 			sc->nrxchains = 2;
15729cdb1c70Snonaka 		} else if (sc->mac_ver >= 0x3070) {
15739cdb1c70Snonaka 			/* default to RF3020 1T1R */
15749cdb1c70Snonaka 			sc->rf_rev = RT3070_RF_3020;
15759cdb1c70Snonaka 			sc->ntxchains = 1;
15769cdb1c70Snonaka 			sc->nrxchains = 1;
15779cdb1c70Snonaka 		} else {
15789cdb1c70Snonaka 			/* default to RF2820 1T2R */
15799cdb1c70Snonaka 			sc->rf_rev = RT2860_RF_2820;
15809cdb1c70Snonaka 			sc->ntxchains = 1;
15819cdb1c70Snonaka 			sc->nrxchains = 2;
15829cdb1c70Snonaka 		}
15839cdb1c70Snonaka 	} else {
1584d164e220Smlelstv 		if (sc->mac_ver == 0x5390 || sc->mac_ver == 0x5392) {
1585d164e220Smlelstv 			sc->rf_rev = val;
1586d164e220Smlelstv 			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1587d164e220Smlelstv 		} else
15889cdb1c70Snonaka 			sc->rf_rev = (val >> 8) & 0xf;
15899cdb1c70Snonaka 		sc->ntxchains = (val >> 4) & 0xf;
15909cdb1c70Snonaka 		sc->nrxchains = val & 0xf;
15919cdb1c70Snonaka 	}
1592d164e220Smlelstv 	DPRINTF(("EEPROM RF rev=0x%04x chains=%dT%dR\n",
15939cdb1c70Snonaka 	    sc->rf_rev, sc->ntxchains, sc->nrxchains));
15949cdb1c70Snonaka 
15959cdb1c70Snonaka 	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
15969cdb1c70Snonaka 	DPRINTF(("EEPROM CFG 0x%04x\n", val));
15979cdb1c70Snonaka 	/* check if driver should patch the DAC issue */
15989cdb1c70Snonaka 	if ((val >> 8) != 0xff)
15999cdb1c70Snonaka 		sc->patch_dac = (val >> 15) & 1;
16009cdb1c70Snonaka 	if ((val & 0xff) != 0xff) {
16019cdb1c70Snonaka 		sc->ext_5ghz_lna = (val >> 3) & 1;
16029cdb1c70Snonaka 		sc->ext_2ghz_lna = (val >> 2) & 1;
16039cdb1c70Snonaka 		/* check if RF supports automatic Tx access gain control */
16049cdb1c70Snonaka 		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
16059cdb1c70Snonaka 		/* check if we have a hardware radio switch */
16069cdb1c70Snonaka 		sc->rfswitch = val & 1;
16079cdb1c70Snonaka 	}
16089cdb1c70Snonaka 
1609faca41fbSmlelstv 	/* Read Tx power settings. */
1610faca41fbSmlelstv 	if (sc->mac_ver == 0x3593)
1611faca41fbSmlelstv 		run_rt3593_get_txpower(sc);
1612faca41fbSmlelstv 	else
1613faca41fbSmlelstv 		run_get_txpower(sc);
16149cdb1c70Snonaka 
16159cdb1c70Snonaka 	/* read Tx power compensation for each Tx rate */
16169cdb1c70Snonaka 	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
16179cdb1c70Snonaka 	delta_2ghz = delta_5ghz = 0;
16189cdb1c70Snonaka 	if ((val & 0xff) != 0xff && (val & 0x80)) {
16199cdb1c70Snonaka 		delta_2ghz = val & 0xf;
16209cdb1c70Snonaka 		if (!(val & 0x40))	/* negative number */
16219cdb1c70Snonaka 			delta_2ghz = -delta_2ghz;
16229cdb1c70Snonaka 	}
16239cdb1c70Snonaka 	val >>= 8;
16249cdb1c70Snonaka 	if ((val & 0xff) != 0xff && (val & 0x80)) {
16259cdb1c70Snonaka 		delta_5ghz = val & 0xf;
16269cdb1c70Snonaka 		if (!(val & 0x40))	/* negative number */
16279cdb1c70Snonaka 			delta_5ghz = -delta_5ghz;
16289cdb1c70Snonaka 	}
16299cdb1c70Snonaka 	DPRINTF(("power compensation=%d (2GHz), %d (5GHz)\n",
16309cdb1c70Snonaka 	    delta_2ghz, delta_5ghz));
16319cdb1c70Snonaka 
16329cdb1c70Snonaka 	for (ridx = 0; ridx < 5; ridx++) {
16339cdb1c70Snonaka 		uint32_t reg;
16349cdb1c70Snonaka 
16359cdb1c70Snonaka 		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
16369cdb1c70Snonaka 		reg = val;
16379cdb1c70Snonaka 		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
16389cdb1c70Snonaka 		reg |= (uint32_t)val << 16;
16399cdb1c70Snonaka 
16409cdb1c70Snonaka 		sc->txpow20mhz[ridx] = reg;
16419cdb1c70Snonaka 		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
16429cdb1c70Snonaka 		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
16439cdb1c70Snonaka 
16449cdb1c70Snonaka 		DPRINTF(("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
16459cdb1c70Snonaka 		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
16469cdb1c70Snonaka 		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]));
16479cdb1c70Snonaka 	}
16489cdb1c70Snonaka 
1649d164e220Smlelstv 	DPRINTF(("mac_ver %hx\n", sc->mac_ver));
16509cdb1c70Snonaka 	/* read RSSI offsets and LNA gains from EEPROM */
1651d164e220Smlelstv 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1652d164e220Smlelstv 	    RT3593_EEPROM_RSSI1_2GHZ, &val);
16539cdb1c70Snonaka 	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
16549cdb1c70Snonaka 	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1655d164e220Smlelstv 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1656d164e220Smlelstv 	    RT3593_EEPROM_RSSI2_2GHZ, &val);
16579cdb1c70Snonaka 	if (sc->mac_ver >= 0x3070) {
1658faca41fbSmlelstv 		if (sc->mac_ver == 0x3593) {
1659faca41fbSmlelstv 			sc->txmixgain_2ghz = 0;
1660faca41fbSmlelstv 			sc->rssi_2ghz[2] = val & 0xff; 	/* Ant C */
1661faca41fbSmlelstv 		} else {
16629cdb1c70Snonaka 			/*
16639cdb1c70Snonaka 			 * On RT3070 chips (limited to 2 Rx chains), this ROM
16649cdb1c70Snonaka 			 * field contains the Tx mixer gain for the 2GHz band.
16659cdb1c70Snonaka 			 */
16669cdb1c70Snonaka 			if ((val & 0xff) != 0xff)
16679cdb1c70Snonaka 				sc->txmixgain_2ghz = val & 0x7;
1668faca41fbSmlelstv 		}
16699cdb1c70Snonaka 		DPRINTF(("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz));
16709cdb1c70Snonaka 	} else {
16719cdb1c70Snonaka 		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
16729cdb1c70Snonaka 	}
1673faca41fbSmlelstv 	if (sc->mac_ver == 0x3593)
1674faca41fbSmlelstv 		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
16759cdb1c70Snonaka 	sc->lna[2] = val >> 8;		/* channel group 2 */
16769cdb1c70Snonaka 
1677faca41fbSmlelstv 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1678d164e220Smlelstv 	    RT3593_EEPROM_RSSI1_5GHZ, &val);
16799cdb1c70Snonaka 	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
16809cdb1c70Snonaka 	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1681faca41fbSmlelstv 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1682faca41fbSmlelstv 	    RT3593_EEPROM_RSSI2_5GHZ, &val);
16839cdb1c70Snonaka 	if (sc->mac_ver == 0x3572) {
16849cdb1c70Snonaka 		/*
16859cdb1c70Snonaka 		 * On RT3572 chips (limited to 2 Rx chains), this ROM
16869cdb1c70Snonaka 		 * field contains the Tx mixer gain for the 5GHz band.
16879cdb1c70Snonaka 		 */
16889cdb1c70Snonaka 		if ((val & 0xff) != 0xff)
16899cdb1c70Snonaka 			sc->txmixgain_5ghz = val & 0x7;
16909cdb1c70Snonaka 		DPRINTF(("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz));
16919cdb1c70Snonaka 	} else {
16929cdb1c70Snonaka 		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
16939cdb1c70Snonaka 	}
1694faca41fbSmlelstv 	if (sc->mac_ver == 0x3593) {
1695faca41fbSmlelstv 		sc->txmixgain_5ghz = 0;
1696faca41fbSmlelstv 		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1697faca41fbSmlelstv 	}
16989cdb1c70Snonaka 	sc->lna[3] = val >> 8;		/* channel group 3 */
16999cdb1c70Snonaka 
1700faca41fbSmlelstv 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1701faca41fbSmlelstv 	    RT3593_EEPROM_LNA, &val);
17029cdb1c70Snonaka 	sc->lna[0] = val & 0xff;	/* channel group 0 */
17039cdb1c70Snonaka 	sc->lna[1] = val >> 8;		/* channel group 1 */
17049cdb1c70Snonaka 
17059cdb1c70Snonaka 	/* fix broken 5GHz LNA entries */
17069cdb1c70Snonaka 	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
17079cdb1c70Snonaka 		DPRINTF(("invalid LNA for channel group %d\n", 2));
17089cdb1c70Snonaka 		sc->lna[2] = sc->lna[1];
17099cdb1c70Snonaka 	}
17109cdb1c70Snonaka 	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
17119cdb1c70Snonaka 		DPRINTF(("invalid LNA for channel group %d\n", 3));
17129cdb1c70Snonaka 		sc->lna[3] = sc->lna[1];
17139cdb1c70Snonaka 	}
17149cdb1c70Snonaka 
17159cdb1c70Snonaka 	/* fix broken RSSI offset entries */
17169cdb1c70Snonaka 	for (ant = 0; ant < 3; ant++) {
17179cdb1c70Snonaka 		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
17189cdb1c70Snonaka 			DPRINTF(("invalid RSSI%d offset: %d (2GHz)\n",
17199cdb1c70Snonaka 			    ant + 1, sc->rssi_2ghz[ant]));
17209cdb1c70Snonaka 			sc->rssi_2ghz[ant] = 0;
17219cdb1c70Snonaka 		}
17229cdb1c70Snonaka 		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
17239cdb1c70Snonaka 			DPRINTF(("invalid RSSI%d offset: %d (5GHz)\n",
17249cdb1c70Snonaka 			    ant + 1, sc->rssi_5ghz[ant]));
17259cdb1c70Snonaka 			sc->rssi_5ghz[ant] = 0;
17269cdb1c70Snonaka 		}
17279cdb1c70Snonaka 	}
17284e8e6643Sskrll 	return 0;
17299cdb1c70Snonaka }
17309cdb1c70Snonaka 
17319cdb1c70Snonaka static struct ieee80211_node *
17329cdb1c70Snonaka run_node_alloc(struct ieee80211_node_table *nt)
17339cdb1c70Snonaka {
17349cdb1c70Snonaka 	struct run_node *rn =
17359cdb1c70Snonaka 	    malloc(sizeof(struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO);
17364e8e6643Sskrll 	return rn ? &rn->ni : NULL;
17379cdb1c70Snonaka }
17389cdb1c70Snonaka 
17399cdb1c70Snonaka static int
17409cdb1c70Snonaka run_media_change(struct ifnet *ifp)
17419cdb1c70Snonaka {
17429cdb1c70Snonaka 	struct run_softc *sc = ifp->if_softc;
17439cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
17449cdb1c70Snonaka 	uint8_t rate, ridx;
17459cdb1c70Snonaka 	int error;
17469cdb1c70Snonaka 
17479cdb1c70Snonaka 	error = ieee80211_media_change(ifp);
17489cdb1c70Snonaka 	if (error != ENETRESET)
17494e8e6643Sskrll 		return error;
17509cdb1c70Snonaka 
17519cdb1c70Snonaka 	if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
17529cdb1c70Snonaka 		rate = ic->ic_sup_rates[ic->ic_curmode].
17539cdb1c70Snonaka 		    rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
17549cdb1c70Snonaka 		for (ridx = 0; ridx <= RT2860_RIDX_MAX; ridx++)
17559cdb1c70Snonaka 			if (rt2860_rates[ridx].rate == rate)
17569cdb1c70Snonaka 				break;
17579cdb1c70Snonaka 		sc->fixed_ridx = ridx;
17589cdb1c70Snonaka 	}
17599cdb1c70Snonaka 
17609cdb1c70Snonaka 	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
17619cdb1c70Snonaka 		run_init(ifp);
17629cdb1c70Snonaka 
17634e8e6643Sskrll 	return 0;
17649cdb1c70Snonaka }
17659cdb1c70Snonaka 
17669cdb1c70Snonaka static void
17679cdb1c70Snonaka run_next_scan(void *arg)
17689cdb1c70Snonaka {
17699cdb1c70Snonaka 	struct run_softc *sc = arg;
17709cdb1c70Snonaka 
17719cdb1c70Snonaka 	if (sc->sc_ic.ic_state == IEEE80211_S_SCAN)
17729cdb1c70Snonaka 		ieee80211_next_scan(&sc->sc_ic);
17739cdb1c70Snonaka }
17749cdb1c70Snonaka 
17759cdb1c70Snonaka static void
17769cdb1c70Snonaka run_task(void *arg)
17779cdb1c70Snonaka {
17789cdb1c70Snonaka 	struct run_softc *sc = arg;
17799cdb1c70Snonaka 	struct run_host_cmd_ring *ring = &sc->cmdq;
17809cdb1c70Snonaka 	struct run_host_cmd *cmd;
17819cdb1c70Snonaka 	int s;
17829cdb1c70Snonaka 
17839cdb1c70Snonaka 	/* process host commands */
17849cdb1c70Snonaka 	s = splusb();
17859cdb1c70Snonaka 	while (ring->next != ring->cur) {
17869cdb1c70Snonaka 		cmd = &ring->cmd[ring->next];
17879cdb1c70Snonaka 		splx(s);
1788*90e85cecSmlelstv 		membar_consumer();
17899cdb1c70Snonaka 		/* callback */
17909cdb1c70Snonaka 		cmd->cb(sc, cmd->data);
17919cdb1c70Snonaka 		s = splusb();
1792*90e85cecSmlelstv 		atomic_dec_uint(&ring->queued);
17939cdb1c70Snonaka 		ring->next = (ring->next + 1) % RUN_HOST_CMD_RING_COUNT;
17949cdb1c70Snonaka 	}
17959cdb1c70Snonaka 	wakeup(ring);
17969cdb1c70Snonaka 	splx(s);
17979cdb1c70Snonaka }
17989cdb1c70Snonaka 
17999cdb1c70Snonaka static void
18009cdb1c70Snonaka run_do_async(struct run_softc *sc, void (*cb)(struct run_softc *, void *),
18019cdb1c70Snonaka     void *arg, int len)
18029cdb1c70Snonaka {
18039cdb1c70Snonaka 	struct run_host_cmd_ring *ring = &sc->cmdq;
18049cdb1c70Snonaka 	struct run_host_cmd *cmd;
18059cdb1c70Snonaka 	int s;
18069cdb1c70Snonaka 
18079cdb1c70Snonaka 	if (sc->sc_flags & RUN_DETACHING)
18089cdb1c70Snonaka 		return;
18099cdb1c70Snonaka 
18109cdb1c70Snonaka 	s = splusb();
18119cdb1c70Snonaka 	cmd = &ring->cmd[ring->cur];
18129cdb1c70Snonaka 	cmd->cb = cb;
18139cdb1c70Snonaka 	KASSERT(len <= sizeof(cmd->data));
18149cdb1c70Snonaka 	memcpy(cmd->data, arg, len);
1815*90e85cecSmlelstv 	membar_producer();
18169cdb1c70Snonaka 	ring->cur = (ring->cur + 1) % RUN_HOST_CMD_RING_COUNT;
18179cdb1c70Snonaka 
18189cdb1c70Snonaka 	/* if there is no pending command already, schedule a task */
1819*90e85cecSmlelstv 	if (atomic_inc_uint_nv(&ring->queued) == 1)
18209cdb1c70Snonaka 		usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER);
18219cdb1c70Snonaka 	splx(s);
18229cdb1c70Snonaka }
18239cdb1c70Snonaka 
18249cdb1c70Snonaka static int
18259cdb1c70Snonaka run_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
18269cdb1c70Snonaka {
18279cdb1c70Snonaka 	struct run_softc *sc = ic->ic_ifp->if_softc;
18289cdb1c70Snonaka 	struct run_cmd_newstate cmd;
18299cdb1c70Snonaka 
18309cdb1c70Snonaka 	callout_stop(&sc->scan_to);
18319cdb1c70Snonaka 	callout_stop(&sc->calib_to);
18329cdb1c70Snonaka 
18339cdb1c70Snonaka 	/* do it in a process context */
18349cdb1c70Snonaka 	cmd.state = nstate;
18359cdb1c70Snonaka 	cmd.arg = arg;
18364e8e6643Sskrll 	run_do_async(sc, run_newstate_cb, &cmd, sizeof(cmd));
18374e8e6643Sskrll 	return 0;
18389cdb1c70Snonaka }
18399cdb1c70Snonaka 
18409cdb1c70Snonaka static void
18419cdb1c70Snonaka run_newstate_cb(struct run_softc *sc, void *arg)
18429cdb1c70Snonaka {
18439cdb1c70Snonaka 	struct run_cmd_newstate *cmd = arg;
18449cdb1c70Snonaka 	struct ifnet *ifp = &sc->sc_if;
18459cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
18469cdb1c70Snonaka 	enum ieee80211_state ostate;
18479cdb1c70Snonaka 	struct ieee80211_node *ni;
18489cdb1c70Snonaka 	uint32_t tmp, sta[3];
18499cdb1c70Snonaka 	uint8_t wcid;
18509cdb1c70Snonaka 	int s;
18519cdb1c70Snonaka 
18529cdb1c70Snonaka 	s = splnet();
18539cdb1c70Snonaka 	ostate = ic->ic_state;
18549cdb1c70Snonaka 
18559cdb1c70Snonaka 	if (ostate == IEEE80211_S_RUN) {
18569cdb1c70Snonaka 		/* turn link LED off */
18579cdb1c70Snonaka 		run_set_leds(sc, RT2860_LED_RADIO);
18589cdb1c70Snonaka 	}
18599cdb1c70Snonaka 
18609cdb1c70Snonaka 	switch (cmd->state) {
18619cdb1c70Snonaka 	case IEEE80211_S_INIT:
18629cdb1c70Snonaka 		if (ostate == IEEE80211_S_RUN) {
18639cdb1c70Snonaka 			/* abort TSF synchronization */
18649cdb1c70Snonaka 			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
18659cdb1c70Snonaka 			run_write(sc, RT2860_BCN_TIME_CFG,
18669cdb1c70Snonaka 			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
18679cdb1c70Snonaka 			    RT2860_TBTT_TIMER_EN));
18689cdb1c70Snonaka 		}
18699cdb1c70Snonaka 		break;
18709cdb1c70Snonaka 
18719cdb1c70Snonaka 	case IEEE80211_S_SCAN:
18729cdb1c70Snonaka 		run_set_chan(sc, ic->ic_curchan);
18739cdb1c70Snonaka 		callout_schedule(&sc->scan_to, hz / 5);
18749cdb1c70Snonaka 		break;
18759cdb1c70Snonaka 
18769cdb1c70Snonaka 	case IEEE80211_S_AUTH:
18779cdb1c70Snonaka 	case IEEE80211_S_ASSOC:
18789cdb1c70Snonaka 		run_set_chan(sc, ic->ic_curchan);
18799cdb1c70Snonaka 		break;
18809cdb1c70Snonaka 
18819cdb1c70Snonaka 	case IEEE80211_S_RUN:
18829cdb1c70Snonaka 		run_set_chan(sc, ic->ic_curchan);
18839cdb1c70Snonaka 
18849cdb1c70Snonaka 		ni = ic->ic_bss;
18859cdb1c70Snonaka 
18869cdb1c70Snonaka 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
18879cdb1c70Snonaka 			run_updateslot(ifp);
18889cdb1c70Snonaka 			run_enable_mrr(sc);
18899cdb1c70Snonaka 			run_set_txpreamble(sc);
18909cdb1c70Snonaka 			run_set_basicrates(sc);
18919cdb1c70Snonaka 			run_set_bssid(sc, ni->ni_bssid);
18929cdb1c70Snonaka 		}
18939cdb1c70Snonaka #ifndef IEEE80211_STA_ONLY
18949cdb1c70Snonaka 		if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
18959cdb1c70Snonaka 		    ic->ic_opmode == IEEE80211_M_IBSS)
18969cdb1c70Snonaka 			(void)run_setup_beacon(sc);
18979cdb1c70Snonaka #endif
18989cdb1c70Snonaka 		if (ic->ic_opmode == IEEE80211_M_STA) {
18999cdb1c70Snonaka 			/* add BSS entry to the WCID table */
19009cdb1c70Snonaka 			wcid = RUN_AID2WCID(ni->ni_associd);
19019cdb1c70Snonaka 			run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
19029cdb1c70Snonaka 			    ni->ni_macaddr, IEEE80211_ADDR_LEN);
19039cdb1c70Snonaka 
19049cdb1c70Snonaka 			/* fake a join to init the tx rate */
19059cdb1c70Snonaka 			run_newassoc(ni, 1);
19069cdb1c70Snonaka 		}
19079cdb1c70Snonaka 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
19089cdb1c70Snonaka 			run_enable_tsf_sync(sc);
19099cdb1c70Snonaka 
19109cdb1c70Snonaka 			/* clear statistic registers used by AMRR */
19119cdb1c70Snonaka 			run_read_region_1(sc, RT2860_TX_STA_CNT0,
19124e8e6643Sskrll 			    (uint8_t *)sta, sizeof(sta));
19139cdb1c70Snonaka 			/* start calibration timer */
19149cdb1c70Snonaka 			callout_schedule(&sc->calib_to, hz);
19159cdb1c70Snonaka 		}
19169cdb1c70Snonaka 
19179cdb1c70Snonaka 		/* turn link LED on */
19189cdb1c70Snonaka 		run_set_leds(sc, RT2860_LED_RADIO |
19199cdb1c70Snonaka 		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
19209cdb1c70Snonaka 		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
19219cdb1c70Snonaka 		break;
19229cdb1c70Snonaka 	}
19239cdb1c70Snonaka 	(void)sc->sc_newstate(ic, cmd->state, cmd->arg);
19249cdb1c70Snonaka 	splx(s);
19259cdb1c70Snonaka }
19269cdb1c70Snonaka 
19279cdb1c70Snonaka static int
19289cdb1c70Snonaka run_updateedca(struct ieee80211com *ic)
19299cdb1c70Snonaka {
19309cdb1c70Snonaka 
19319cdb1c70Snonaka 	/* do it in a process context */
19329cdb1c70Snonaka 	run_do_async(ic->ic_ifp->if_softc, run_updateedca_cb, NULL, 0);
19334e8e6643Sskrll 	return 0;
19349cdb1c70Snonaka }
19359cdb1c70Snonaka 
19369cdb1c70Snonaka /* ARGSUSED */
19379cdb1c70Snonaka static void
19389cdb1c70Snonaka run_updateedca_cb(struct run_softc *sc, void *arg)
19399cdb1c70Snonaka {
19409cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
19419cdb1c70Snonaka 	int s, aci;
19429cdb1c70Snonaka 
19439cdb1c70Snonaka 	s = splnet();
19449cdb1c70Snonaka 	/* update MAC TX configuration registers */
19459cdb1c70Snonaka 	for (aci = 0; aci < WME_NUM_AC; aci++) {
19469cdb1c70Snonaka 		run_write(sc, RT2860_EDCA_AC_CFG(aci),
19479cdb1c70Snonaka 		    ic->ic_wme.wme_params[aci].wmep_logcwmax << 16 |
19489cdb1c70Snonaka 		    ic->ic_wme.wme_params[aci].wmep_logcwmin << 12 |
19499cdb1c70Snonaka 		    ic->ic_wme.wme_params[aci].wmep_aifsn  <<  8 |
19509cdb1c70Snonaka 		    ic->ic_wme.wme_params[aci].wmep_txopLimit);
19519cdb1c70Snonaka 	}
19529cdb1c70Snonaka 
19539cdb1c70Snonaka 	/* update SCH/DMA registers too */
19549cdb1c70Snonaka 	run_write(sc, RT2860_WMM_AIFSN_CFG,
19559cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_VO].wmep_aifsn  << 12 |
19569cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_VI].wmep_aifsn  <<  8 |
19579cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_BK].wmep_aifsn  <<  4 |
19589cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_BE].wmep_aifsn);
19599cdb1c70Snonaka 	run_write(sc, RT2860_WMM_CWMIN_CFG,
19609cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_VO].wmep_logcwmin << 12 |
19619cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_VI].wmep_logcwmin <<  8 |
19629cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_BK].wmep_logcwmin <<  4 |
19639cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_BE].wmep_logcwmin);
19649cdb1c70Snonaka 	run_write(sc, RT2860_WMM_CWMAX_CFG,
19659cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_VO].wmep_logcwmax << 12 |
19669cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_VI].wmep_logcwmax <<  8 |
19679cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_BK].wmep_logcwmax <<  4 |
19689cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_BE].wmep_logcwmax);
19699cdb1c70Snonaka 	run_write(sc, RT2860_WMM_TXOP0_CFG,
19709cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_BK].wmep_txopLimit << 16 |
19719cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_BE].wmep_txopLimit);
19729cdb1c70Snonaka 	run_write(sc, RT2860_WMM_TXOP1_CFG,
19739cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_VO].wmep_txopLimit << 16 |
19749cdb1c70Snonaka 	    ic->ic_wme.wme_params[WME_AC_VI].wmep_txopLimit);
19759cdb1c70Snonaka 	splx(s);
19769cdb1c70Snonaka }
19779cdb1c70Snonaka 
19789cdb1c70Snonaka #ifdef RUN_HWCRYPTO
19799cdb1c70Snonaka static int
19809cdb1c70Snonaka run_set_key(struct ieee80211com *ic, const struct ieee80211_key *k,
19819cdb1c70Snonaka     const uint8_t *mac)
19829cdb1c70Snonaka {
19839cdb1c70Snonaka 	struct run_softc *sc = ic->ic_ifp->if_softc;
19849cdb1c70Snonaka 	struct ieee80211_node *ni = ic->ic_bss;
19859cdb1c70Snonaka 	struct run_cmd_key cmd;
19869cdb1c70Snonaka 
19879cdb1c70Snonaka 	/* do it in a process context */
19889cdb1c70Snonaka 	cmd.key = *k;
19899cdb1c70Snonaka 	cmd.associd = (ni != NULL) ? ni->ni_associd : 0;
19904e8e6643Sskrll 	run_do_async(sc, run_set_key_cb, &cmd, sizeof(cmd));
19919cdb1c70Snonaka 	return 1;
19929cdb1c70Snonaka }
19939cdb1c70Snonaka 
19949cdb1c70Snonaka static void
19959cdb1c70Snonaka run_set_key_cb(struct run_softc *sc, void *arg)
19969cdb1c70Snonaka {
19979cdb1c70Snonaka #ifndef IEEE80211_STA_ONLY
19989cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
19999cdb1c70Snonaka #endif
20009cdb1c70Snonaka 	struct run_cmd_key *cmd = arg;
20019cdb1c70Snonaka 	struct ieee80211_key *k = &cmd->key;
20029cdb1c70Snonaka 	uint32_t attr;
20039cdb1c70Snonaka 	uint16_t base;
20049cdb1c70Snonaka 	uint8_t mode, wcid, iv[8];
20059cdb1c70Snonaka 
20069cdb1c70Snonaka 	/* map net80211 cipher to RT2860 security mode */
20079cdb1c70Snonaka 	switch (k->wk_cipher->ic_cipher) {
20089cdb1c70Snonaka 	case IEEE80211_CIPHER_WEP:
20099cdb1c70Snonaka 		k->wk_flags |= IEEE80211_KEY_GROUP; /* XXX */
20109cdb1c70Snonaka 		if (k->wk_keylen == 5)
20119cdb1c70Snonaka 			mode = RT2860_MODE_WEP40;
20129cdb1c70Snonaka 		else
20139cdb1c70Snonaka 			mode = RT2860_MODE_WEP104;
20149cdb1c70Snonaka 		break;
20159cdb1c70Snonaka 	case IEEE80211_CIPHER_TKIP:
20169cdb1c70Snonaka 		mode = RT2860_MODE_TKIP;
20179cdb1c70Snonaka 		break;
20189cdb1c70Snonaka 	case IEEE80211_CIPHER_AES_CCM:
20199cdb1c70Snonaka 		mode = RT2860_MODE_AES_CCMP;
20209cdb1c70Snonaka 		break;
20219cdb1c70Snonaka 	default:
20229cdb1c70Snonaka 		return;
20239cdb1c70Snonaka 	}
20249cdb1c70Snonaka 
20259cdb1c70Snonaka 	if (k->wk_flags & IEEE80211_KEY_GROUP) {
20269cdb1c70Snonaka 		wcid = 0;	/* NB: update WCID0 for group keys */
20279cdb1c70Snonaka 		base = RT2860_SKEY(0, k->wk_keyix);
20289cdb1c70Snonaka 	} else {
20299cdb1c70Snonaka 		wcid = RUN_AID2WCID(cmd->associd);
20309cdb1c70Snonaka 		base = RT2860_PKEY(wcid);
20319cdb1c70Snonaka 	}
20329cdb1c70Snonaka 
20339cdb1c70Snonaka 	if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
20349cdb1c70Snonaka 		run_write_region_1(sc, base, k->wk_key, 16);
20359cdb1c70Snonaka #ifndef IEEE80211_STA_ONLY
20369cdb1c70Snonaka 		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
20379cdb1c70Snonaka 			run_write_region_1(sc, base + 16, &k->wk_key[16], 8);
20389cdb1c70Snonaka 			run_write_region_1(sc, base + 24, &k->wk_key[24], 8);
20399cdb1c70Snonaka 		} else
20409cdb1c70Snonaka #endif
20419cdb1c70Snonaka 		{
20429cdb1c70Snonaka 			run_write_region_1(sc, base + 16, &k->wk_key[24], 8);
20439cdb1c70Snonaka 			run_write_region_1(sc, base + 24, &k->wk_key[16], 8);
20449cdb1c70Snonaka 		}
20459cdb1c70Snonaka 	} else {
20469cdb1c70Snonaka 		/* roundup len to 16-bit: XXX fix write_region_1() instead */
20479cdb1c70Snonaka 		run_write_region_1(sc, base, k->wk_key,
20489cdb1c70Snonaka 		    (k->wk_keylen + 1) & ~1);
20499cdb1c70Snonaka 	}
20509cdb1c70Snonaka 
20519cdb1c70Snonaka 	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
20529cdb1c70Snonaka 	    (k->wk_flags & IEEE80211_KEY_XMIT)) {
20539cdb1c70Snonaka 		/* set initial packet number in IV+EIV */
20549cdb1c70Snonaka 		if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP) {
20554e8e6643Sskrll 			memset(iv, 0, sizeof(iv));
20569cdb1c70Snonaka 			iv[3] = sc->sc_ic.ic_crypto.cs_def_txkey << 6;
20579cdb1c70Snonaka 		} else {
20589cdb1c70Snonaka 			if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
20599cdb1c70Snonaka 				iv[0] = k->wk_keytsc >> 8;
20609cdb1c70Snonaka 				iv[1] = (iv[0] | 0x20) & 0x7f;
20619cdb1c70Snonaka 				iv[2] = k->wk_keytsc;
20629cdb1c70Snonaka 			} else /* CCMP */ {
20639cdb1c70Snonaka 				iv[0] = k->wk_keytsc;
20649cdb1c70Snonaka 				iv[1] = k->wk_keytsc >> 8;
20659cdb1c70Snonaka 				iv[2] = 0;
20669cdb1c70Snonaka 			}
20679cdb1c70Snonaka 			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
20689cdb1c70Snonaka 			iv[4] = k->wk_keytsc >> 16;
20699cdb1c70Snonaka 			iv[5] = k->wk_keytsc >> 24;
20709cdb1c70Snonaka 			iv[6] = k->wk_keytsc >> 32;
20719cdb1c70Snonaka 			iv[7] = k->wk_keytsc >> 40;
20729cdb1c70Snonaka 		}
20739cdb1c70Snonaka 		run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8);
20749cdb1c70Snonaka 	}
20759cdb1c70Snonaka 
20769cdb1c70Snonaka 	if (k->wk_flags & IEEE80211_KEY_GROUP) {
20779cdb1c70Snonaka 		/* install group key */
20789cdb1c70Snonaka 		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
20799cdb1c70Snonaka 		attr &= ~(0xf << (k->wk_keyix * 4));
20809cdb1c70Snonaka 		attr |= mode << (k->wk_keyix * 4);
20819cdb1c70Snonaka 		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
20829cdb1c70Snonaka 	} else {
20839cdb1c70Snonaka 		/* install pairwise key */
20849cdb1c70Snonaka 		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
20859cdb1c70Snonaka 		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
20869cdb1c70Snonaka 		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
20879cdb1c70Snonaka 	}
20889cdb1c70Snonaka }
20899cdb1c70Snonaka 
20909cdb1c70Snonaka static int
20919cdb1c70Snonaka run_delete_key(struct ieee80211com *ic, const struct ieee80211_key *k)
20929cdb1c70Snonaka {
20939cdb1c70Snonaka 	struct run_softc *sc = ic->ic_ifp->if_softc;
20949cdb1c70Snonaka 	struct ieee80211_node *ni = ic->ic_bss;
20959cdb1c70Snonaka 	struct run_cmd_key cmd;
20969cdb1c70Snonaka 
20979cdb1c70Snonaka 	/* do it in a process context */
20989cdb1c70Snonaka 	cmd.key = *k;
20999cdb1c70Snonaka 	cmd.associd = (ni != NULL) ? ni->ni_associd : 0;
21004e8e6643Sskrll 	run_do_async(sc, run_delete_key_cb, &cmd, sizeof(cmd));
21019cdb1c70Snonaka 	return 1;
21029cdb1c70Snonaka }
21039cdb1c70Snonaka 
21049cdb1c70Snonaka static void
21059cdb1c70Snonaka run_delete_key_cb(struct run_softc *sc, void *arg)
21069cdb1c70Snonaka {
21079cdb1c70Snonaka 	struct run_cmd_key *cmd = arg;
21089cdb1c70Snonaka 	struct ieee80211_key *k = &cmd->key;
21099cdb1c70Snonaka 	uint32_t attr;
21109cdb1c70Snonaka 	uint8_t wcid;
21119cdb1c70Snonaka 
21129cdb1c70Snonaka 	if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_WEP)
21139cdb1c70Snonaka 		k->wk_flags |= IEEE80211_KEY_GROUP; /* XXX */
21149cdb1c70Snonaka 
21159cdb1c70Snonaka 	if (k->wk_flags & IEEE80211_KEY_GROUP) {
21169cdb1c70Snonaka 		/* remove group key */
21179cdb1c70Snonaka 		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
21189cdb1c70Snonaka 		attr &= ~(0xf << (k->wk_keyix * 4));
21199cdb1c70Snonaka 		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
21209cdb1c70Snonaka 
21219cdb1c70Snonaka 	} else {
21229cdb1c70Snonaka 		/* remove pairwise key */
21239cdb1c70Snonaka 		wcid = RUN_AID2WCID(cmd->associd);
21249cdb1c70Snonaka 		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
21259cdb1c70Snonaka 		attr &= ~0xf;
21269cdb1c70Snonaka 		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
21279cdb1c70Snonaka 	}
21289cdb1c70Snonaka }
21299cdb1c70Snonaka #endif
21309cdb1c70Snonaka 
21319cdb1c70Snonaka static void
21329cdb1c70Snonaka run_calibrate_to(void *arg)
21339cdb1c70Snonaka {
21349cdb1c70Snonaka 
21359cdb1c70Snonaka 	/* do it in a process context */
21369cdb1c70Snonaka 	run_do_async(arg, run_calibrate_cb, NULL, 0);
21379cdb1c70Snonaka 	/* next timeout will be rescheduled in the calibration task */
21389cdb1c70Snonaka }
21399cdb1c70Snonaka 
21409cdb1c70Snonaka /* ARGSUSED */
21419cdb1c70Snonaka static void
21429cdb1c70Snonaka run_calibrate_cb(struct run_softc *sc, void *arg)
21439cdb1c70Snonaka {
21449cdb1c70Snonaka 	struct ifnet *ifp = &sc->sc_if;
21459cdb1c70Snonaka 	uint32_t sta[3];
21469cdb1c70Snonaka 	int s, error;
21479cdb1c70Snonaka 
21489cdb1c70Snonaka 	/* read statistic counters (clear on read) and update AMRR state */
21499cdb1c70Snonaka 	error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
21504e8e6643Sskrll 	    sizeof(sta));
21519cdb1c70Snonaka 	if (error != 0)
21529cdb1c70Snonaka 		goto skip;
21539cdb1c70Snonaka 
21549cdb1c70Snonaka 	DPRINTF(("retrycnt=%d txcnt=%d failcnt=%d\n",
21559cdb1c70Snonaka 	    le32toh(sta[1]) >> 16, le32toh(sta[1]) & 0xffff,
21569cdb1c70Snonaka 	    le32toh(sta[0]) & 0xffff));
21579cdb1c70Snonaka 
21589cdb1c70Snonaka 	s = splnet();
21599cdb1c70Snonaka 	/* count failed TX as errors */
21609cdb1c70Snonaka 	ifp->if_oerrors += le32toh(sta[0]) & 0xffff;
21619cdb1c70Snonaka 
21629cdb1c70Snonaka 	sc->amn.amn_retrycnt =
21639cdb1c70Snonaka 	    (le32toh(sta[0]) & 0xffff) +	/* failed TX count */
21649cdb1c70Snonaka 	    (le32toh(sta[1]) >> 16);		/* TX retransmission count */
21659cdb1c70Snonaka 
21669cdb1c70Snonaka 	sc->amn.amn_txcnt =
21679cdb1c70Snonaka 	    sc->amn.amn_retrycnt +
21689cdb1c70Snonaka 	    (le32toh(sta[1]) & 0xffff);		/* successful TX count */
21699cdb1c70Snonaka 
21709cdb1c70Snonaka 	ieee80211_amrr_choose(&sc->amrr, sc->sc_ic.ic_bss, &sc->amn);
21719cdb1c70Snonaka 	splx(s);
21729cdb1c70Snonaka 
21739cdb1c70Snonaka skip:	callout_schedule(&sc->calib_to, hz);
21749cdb1c70Snonaka }
21759cdb1c70Snonaka 
21769cdb1c70Snonaka static void
21779cdb1c70Snonaka run_newassoc(struct ieee80211_node *ni, int isnew)
21789cdb1c70Snonaka {
21799cdb1c70Snonaka 	struct run_softc *sc = ni->ni_ic->ic_ifp->if_softc;
21809cdb1c70Snonaka 	struct run_node *rn = (void *)ni;
21819cdb1c70Snonaka 	struct ieee80211_rateset *rs = &ni->ni_rates;
21829cdb1c70Snonaka 	uint8_t rate;
21839cdb1c70Snonaka 	int ridx, i, j;
21849cdb1c70Snonaka 
21859cdb1c70Snonaka 	DPRINTF(("new assoc isnew=%d addr=%s\n",
21869cdb1c70Snonaka 	    isnew, ether_sprintf(ni->ni_macaddr)));
21879cdb1c70Snonaka 
21889cdb1c70Snonaka 	ieee80211_amrr_node_init(&sc->amrr, &sc->amn);
21899cdb1c70Snonaka 	/* start at lowest available bit-rate, AMRR will raise */
21909cdb1c70Snonaka 	ni->ni_txrate = 0;
21919cdb1c70Snonaka 
21929cdb1c70Snonaka 	for (i = 0; i < rs->rs_nrates; i++) {
21939cdb1c70Snonaka 		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
21949cdb1c70Snonaka 		/* convert 802.11 rate to hardware rate index */
21959cdb1c70Snonaka 		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
21969cdb1c70Snonaka 			if (rt2860_rates[ridx].rate == rate)
21979cdb1c70Snonaka 				break;
21989cdb1c70Snonaka 		rn->ridx[i] = ridx;
21999cdb1c70Snonaka 		/* determine rate of control response frames */
22009cdb1c70Snonaka 		for (j = i; j >= 0; j--) {
22019cdb1c70Snonaka 			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
22029cdb1c70Snonaka 			    rt2860_rates[rn->ridx[i]].phy ==
22039cdb1c70Snonaka 			    rt2860_rates[rn->ridx[j]].phy)
22049cdb1c70Snonaka 				break;
22059cdb1c70Snonaka 		}
22069cdb1c70Snonaka 		if (j >= 0) {
22079cdb1c70Snonaka 			rn->ctl_ridx[i] = rn->ridx[j];
22089cdb1c70Snonaka 		} else {
22099cdb1c70Snonaka 			/* no basic rate found, use mandatory one */
22109cdb1c70Snonaka 			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
22119cdb1c70Snonaka 		}
22129cdb1c70Snonaka 		DPRINTF(("rate=0x%02x ridx=%d ctl_ridx=%d\n",
22139cdb1c70Snonaka 		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]));
22149cdb1c70Snonaka 	}
22159cdb1c70Snonaka }
22169cdb1c70Snonaka 
22179cdb1c70Snonaka /*
22189cdb1c70Snonaka  * Return the Rx chain with the highest RSSI for a given frame.
22199cdb1c70Snonaka  */
22209cdb1c70Snonaka static __inline uint8_t
22219cdb1c70Snonaka run_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
22229cdb1c70Snonaka {
22239cdb1c70Snonaka 	uint8_t rxchain = 0;
22249cdb1c70Snonaka 
22259cdb1c70Snonaka 	if (sc->nrxchains > 1) {
22269cdb1c70Snonaka 		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
22279cdb1c70Snonaka 			rxchain = 1;
22289cdb1c70Snonaka 		if (sc->nrxchains > 2)
22299cdb1c70Snonaka 			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
22309cdb1c70Snonaka 				rxchain = 2;
22319cdb1c70Snonaka 	}
22324e8e6643Sskrll 	return rxchain;
22339cdb1c70Snonaka }
22349cdb1c70Snonaka 
22359cdb1c70Snonaka static void
22369cdb1c70Snonaka run_rx_frame(struct run_softc *sc, uint8_t *buf, int dmalen)
22379cdb1c70Snonaka {
22389cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
22399cdb1c70Snonaka 	struct ifnet *ifp = &sc->sc_if;
22409cdb1c70Snonaka 	struct ieee80211_frame *wh;
22419cdb1c70Snonaka 	struct ieee80211_node *ni;
22429cdb1c70Snonaka 	struct rt2870_rxd *rxd;
22439cdb1c70Snonaka 	struct rt2860_rxwi *rxwi;
22449cdb1c70Snonaka 	struct mbuf *m;
22459cdb1c70Snonaka 	uint32_t flags;
2246faca41fbSmlelstv 	uint16_t len, rxwisize, phy;
22479cdb1c70Snonaka 	uint8_t ant, rssi;
22489cdb1c70Snonaka 	int s;
22499cdb1c70Snonaka #ifdef RUN_HWCRYPTO
22509cdb1c70Snonaka 	int decrypted = 0;
22519cdb1c70Snonaka #endif
22529cdb1c70Snonaka 
22539cdb1c70Snonaka 	rxwi = (struct rt2860_rxwi *)buf;
2254d164e220Smlelstv 	rxwisize = sizeof(struct rt2860_rxwi);
2255d164e220Smlelstv 	if (sc->mac_ver == 0x5592)
2256d164e220Smlelstv 		rxwisize += sizeof(uint64_t);
2257d164e220Smlelstv 	else if (sc->mac_ver == 0x3593)
2258d164e220Smlelstv 		rxwisize += sizeof(uint32_t);
22599cdb1c70Snonaka 	len = le16toh(rxwi->len) & 0xfff;
22609cdb1c70Snonaka 	if (__predict_false(len > dmalen)) {
22619cdb1c70Snonaka 		DPRINTF(("bad RXWI length %u > %u\n", len, dmalen));
22629cdb1c70Snonaka 		return;
22639cdb1c70Snonaka 	}
22649cdb1c70Snonaka 	/* Rx descriptor is located at the end */
22659cdb1c70Snonaka 	rxd = (struct rt2870_rxd *)(buf + dmalen);
22669cdb1c70Snonaka 	flags = le32toh(rxd->flags);
22679cdb1c70Snonaka 
22689cdb1c70Snonaka 	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
22699cdb1c70Snonaka 		ifp->if_ierrors++;
22709cdb1c70Snonaka 		return;
22719cdb1c70Snonaka 	}
22729cdb1c70Snonaka 
2273d164e220Smlelstv 	wh = (struct ieee80211_frame *)(buf + rxwisize);
22749cdb1c70Snonaka 
22759cdb1c70Snonaka 	if (__predict_false((flags & RT2860_RX_MICERR))) {
22769cdb1c70Snonaka 		/* report MIC failures to net80211 for TKIP */
22779cdb1c70Snonaka 		ieee80211_notify_michael_failure(ic, wh, 0/* XXX */);
22789cdb1c70Snonaka 		ifp->if_ierrors++;
22799cdb1c70Snonaka 		return;
22809cdb1c70Snonaka 	}
22819cdb1c70Snonaka 
22829cdb1c70Snonaka 	if (flags & RT2860_RX_L2PAD) {
22839cdb1c70Snonaka 		u_int hdrlen = ieee80211_hdrspace(ic, wh);
2284ef294642Smaxv 		memmove((uint8_t *)wh + 2, wh, hdrlen);
22859cdb1c70Snonaka 		wh = (struct ieee80211_frame *)((uint8_t *)wh + 2);
22869cdb1c70Snonaka 	}
22879cdb1c70Snonaka 
2288d164e220Smlelstv #ifdef RUN_HWCRYPTO
2289d164e220Smlelstv 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2290d164e220Smlelstv 		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
2291d164e220Smlelstv 		decrypted = 1;
2292d164e220Smlelstv 	}
2293d164e220Smlelstv #endif
2294d164e220Smlelstv 
22959cdb1c70Snonaka 	/* could use m_devget but net80211 wants contig mgmt frames */
22969cdb1c70Snonaka 	MGETHDR(m, M_DONTWAIT, MT_DATA);
22979cdb1c70Snonaka 	if (__predict_false(m == NULL)) {
22989cdb1c70Snonaka 		ifp->if_ierrors++;
22999cdb1c70Snonaka 		return;
23009cdb1c70Snonaka 	}
23019cdb1c70Snonaka 	if (len > MHLEN) {
23029cdb1c70Snonaka 		MCLGET(m, M_DONTWAIT);
23039cdb1c70Snonaka 		if (__predict_false(!(m->m_flags & M_EXT))) {
23049cdb1c70Snonaka 			ifp->if_ierrors++;
23059cdb1c70Snonaka 			m_freem(m);
23069cdb1c70Snonaka 			return;
23079cdb1c70Snonaka 		}
23089cdb1c70Snonaka 	}
23099cdb1c70Snonaka 	/* finalize mbuf */
2310d938d837Sozaki-r 	m_set_rcvif(m, ifp);
23119cdb1c70Snonaka 	memcpy(mtod(m, void *), wh, len);
23129cdb1c70Snonaka 	m->m_pkthdr.len = m->m_len = len;
23139cdb1c70Snonaka 
23149cdb1c70Snonaka 	ant = run_maxrssi_chain(sc, rxwi);
23159cdb1c70Snonaka 	rssi = rxwi->rssi[ant];
23169cdb1c70Snonaka 
23179cdb1c70Snonaka 	if (__predict_false(sc->sc_drvbpf != NULL)) {
23189cdb1c70Snonaka 		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
23199cdb1c70Snonaka 
23209cdb1c70Snonaka 		tap->wr_flags = 0;
23219cdb1c70Snonaka 		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
23229cdb1c70Snonaka 		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
23239cdb1c70Snonaka 		tap->wr_antsignal = rssi;
23249cdb1c70Snonaka 		tap->wr_antenna = ant;
23259cdb1c70Snonaka 		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
23269cdb1c70Snonaka 		tap->wr_rate = 2;	/* in case it can't be found below */
23279cdb1c70Snonaka 		phy = le16toh(rxwi->phy);
23289cdb1c70Snonaka 		switch (phy & RT2860_PHY_MODE) {
23299cdb1c70Snonaka 		case RT2860_PHY_CCK:
23309cdb1c70Snonaka 			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
23319cdb1c70Snonaka 			case 0:	tap->wr_rate =   2; break;
23329cdb1c70Snonaka 			case 1:	tap->wr_rate =   4; break;
23339cdb1c70Snonaka 			case 2:	tap->wr_rate =  11; break;
23349cdb1c70Snonaka 			case 3:	tap->wr_rate =  22; break;
23359cdb1c70Snonaka 			}
23369cdb1c70Snonaka 			if (phy & RT2860_PHY_SHPRE)
23379cdb1c70Snonaka 				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
23389cdb1c70Snonaka 			break;
23399cdb1c70Snonaka 		case RT2860_PHY_OFDM:
23409cdb1c70Snonaka 			switch (phy & RT2860_PHY_MCS) {
23419cdb1c70Snonaka 			case 0:	tap->wr_rate =  12; break;
23429cdb1c70Snonaka 			case 1:	tap->wr_rate =  18; break;
23439cdb1c70Snonaka 			case 2:	tap->wr_rate =  24; break;
23449cdb1c70Snonaka 			case 3:	tap->wr_rate =  36; break;
23459cdb1c70Snonaka 			case 4:	tap->wr_rate =  48; break;
23469cdb1c70Snonaka 			case 5:	tap->wr_rate =  72; break;
23479cdb1c70Snonaka 			case 6:	tap->wr_rate =  96; break;
23489cdb1c70Snonaka 			case 7:	tap->wr_rate = 108; break;
23499cdb1c70Snonaka 			}
23509cdb1c70Snonaka 			break;
23519cdb1c70Snonaka 		}
23523cd62456Smsaitoh 		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m, BPF_D_IN);
23539cdb1c70Snonaka 	}
23549cdb1c70Snonaka 
23559cdb1c70Snonaka 	s = splnet();
23569cdb1c70Snonaka 	ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
23579cdb1c70Snonaka #ifdef RUN_HWCRYPTO
23589cdb1c70Snonaka 	if (decrypted) {
23599cdb1c70Snonaka 		uint32_t icflags = ic->ic_flags;
23609cdb1c70Snonaka 
23619cdb1c70Snonaka 		ic->ic_flags &= ~IEEE80211_F_DROPUNENC; /* XXX */
23629cdb1c70Snonaka 		ieee80211_input(ic, m, ni, rssi, 0);
23639cdb1c70Snonaka 		ic->ic_flags = icflags;
23649cdb1c70Snonaka 	} else
23659cdb1c70Snonaka #endif
23669cdb1c70Snonaka 	ieee80211_input(ic, m, ni, rssi, 0);
23679cdb1c70Snonaka 
23689cdb1c70Snonaka 	/* node is no longer needed */
23699cdb1c70Snonaka 	ieee80211_free_node(ni);
23709cdb1c70Snonaka 
23719cdb1c70Snonaka 	/*
23729cdb1c70Snonaka 	 * In HostAP mode, ieee80211_input() will enqueue packets in if_snd
23739cdb1c70Snonaka 	 * without calling if_start().
23749cdb1c70Snonaka 	 */
23759cdb1c70Snonaka 	if (!IFQ_IS_EMPTY(&ifp->if_snd) && !(ifp->if_flags & IFF_OACTIVE))
23769cdb1c70Snonaka 		run_start(ifp);
23779cdb1c70Snonaka 
23789cdb1c70Snonaka 	splx(s);
23799cdb1c70Snonaka }
23809cdb1c70Snonaka 
23819cdb1c70Snonaka static void
23824e8e6643Sskrll run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
23839cdb1c70Snonaka {
23849cdb1c70Snonaka 	struct run_rx_data *data = priv;
23859cdb1c70Snonaka 	struct run_softc *sc = data->sc;
23869cdb1c70Snonaka 	uint8_t *buf;
23879cdb1c70Snonaka 	uint32_t dmalen;
23889cdb1c70Snonaka 	int xferlen;
2389d164e220Smlelstv 	uint16_t rxwisize;
23909cdb1c70Snonaka 
23918f96d6f5Smlelstv 	if (__predict_false(sc->sc_flags & RUN_DETACHING))
23928f96d6f5Smlelstv 		return;
23938f96d6f5Smlelstv 
2394d164e220Smlelstv 	rxwisize = sizeof(struct rt2860_rxwi);
2395d164e220Smlelstv 	if (sc->mac_ver == 0x5592)
2396d164e220Smlelstv 		rxwisize += sizeof(uint64_t);
2397d164e220Smlelstv 	else if (sc->mac_ver == 0x3593)
2398d164e220Smlelstv 		rxwisize += sizeof(uint32_t);
2399d164e220Smlelstv 
24009cdb1c70Snonaka 	if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
2401d164e220Smlelstv 		DPRINTF(("RX status=%s\n", usbd_errstr(status)));
24029cdb1c70Snonaka 		if (status == USBD_STALLED)
24039cdb1c70Snonaka 			usbd_clear_endpoint_stall_async(sc->rxq.pipeh);
24049cdb1c70Snonaka 		if (status != USBD_CANCELLED)
24059cdb1c70Snonaka 			goto skip;
24069cdb1c70Snonaka 		return;
24079cdb1c70Snonaka 	}
24089cdb1c70Snonaka 	usbd_get_xfer_status(xfer, NULL, NULL, &xferlen, NULL);
24099cdb1c70Snonaka 
24109cdb1c70Snonaka 	if (__predict_false(xferlen < (int)(sizeof(uint32_t) +
2411d164e220Smlelstv 	    rxwisize + sizeof(struct rt2870_rxd)))) {
24129cdb1c70Snonaka 		DPRINTF(("xfer too short %d\n", xferlen));
24139cdb1c70Snonaka 		goto skip;
24149cdb1c70Snonaka 	}
24159cdb1c70Snonaka 
24169cdb1c70Snonaka 	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
24179cdb1c70Snonaka 	buf = data->buf;
24189cdb1c70Snonaka 	while (xferlen > 8) {
24199cdb1c70Snonaka 		dmalen = le32toh(*(uint32_t *)buf) & 0xffff;
24209cdb1c70Snonaka 
2421faca41fbSmlelstv 		if (__predict_false((dmalen >= (uint32_t)-8) || dmalen == 0 ||
2422faca41fbSmlelstv 		    (dmalen & 3) != 0)) {
24239cdb1c70Snonaka 			DPRINTF(("bad DMA length %u (%x)\n", dmalen, dmalen));
24249cdb1c70Snonaka 			break;
24259cdb1c70Snonaka 		}
24269cdb1c70Snonaka 		if (__predict_false(dmalen + 8 > (uint32_t)xferlen)) {
24279cdb1c70Snonaka 			DPRINTF(("bad DMA length %u > %d\n",
24289cdb1c70Snonaka 			    dmalen + 8, xferlen));
24299cdb1c70Snonaka 			break;
24309cdb1c70Snonaka 		}
24319cdb1c70Snonaka 		run_rx_frame(sc, buf + sizeof(uint32_t), dmalen);
24329cdb1c70Snonaka 		buf += dmalen + 8;
24339cdb1c70Snonaka 		xferlen -= dmalen + 8;
24349cdb1c70Snonaka 	}
24359cdb1c70Snonaka 
24369cdb1c70Snonaka skip:	/* setup a new transfer */
24374e8e6643Sskrll 	usbd_setup_xfer(xfer, data, data->buf, RUN_MAX_RXSZ,
24384e8e6643Sskrll 	    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, run_rxeof);
2439d164e220Smlelstv 	status = usbd_transfer(xfer);
2440d164e220Smlelstv 	if (status != USBD_NORMAL_COMPLETION &&
2441d164e220Smlelstv 	    status != USBD_IN_PROGRESS)
2442d164e220Smlelstv 		device_printf(sc->sc_dev, "requeuing rx failed: %s\n",
2443d164e220Smlelstv 		    usbd_errstr(status));
24449cdb1c70Snonaka }
24459cdb1c70Snonaka 
24469cdb1c70Snonaka static void
24474e8e6643Sskrll run_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
24489cdb1c70Snonaka {
24499cdb1c70Snonaka 	struct run_tx_data *data = priv;
24509cdb1c70Snonaka 	struct run_softc *sc = data->sc;
24519cdb1c70Snonaka 	struct run_tx_ring *txq = &sc->txq[data->qid];
24529cdb1c70Snonaka 	struct ifnet *ifp = &sc->sc_if;
24539cdb1c70Snonaka 	int s;
24549cdb1c70Snonaka 
2455d164e220Smlelstv 	s = splnet();
2456d164e220Smlelstv 	txq->queued--;
2457d164e220Smlelstv 	sc->qfullmsk &= ~(1 << data->qid);
2458d164e220Smlelstv 
24599cdb1c70Snonaka 	if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
2460d164e220Smlelstv 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
2461d164e220Smlelstv 			return;
2462d164e220Smlelstv 
2463d164e220Smlelstv 		DPRINTF(("%s: usb error on tx: %s\n",
2464d164e220Smlelstv 			device_xname(sc->sc_dev), usbd_errstr(status)));
24659cdb1c70Snonaka 		if (status == USBD_STALLED)
24669cdb1c70Snonaka 			usbd_clear_endpoint_stall_async(txq->pipeh);
24679cdb1c70Snonaka 		ifp->if_oerrors++;
2468d164e220Smlelstv 		splx(s);
24699cdb1c70Snonaka 		return;
24709cdb1c70Snonaka 	}
24719cdb1c70Snonaka 
24729cdb1c70Snonaka 	sc->sc_tx_timer = 0;
24739cdb1c70Snonaka 	ifp->if_opackets++;
24749cdb1c70Snonaka 	ifp->if_flags &= ~IFF_OACTIVE;
24759cdb1c70Snonaka 	run_start(ifp);
24769cdb1c70Snonaka 	splx(s);
24779cdb1c70Snonaka }
24789cdb1c70Snonaka 
24799cdb1c70Snonaka static int
24809cdb1c70Snonaka run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
24819cdb1c70Snonaka {
24829cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
24839cdb1c70Snonaka 	struct run_node *rn = (void *)ni;
24849cdb1c70Snonaka 	struct ieee80211_frame *wh;
24859cdb1c70Snonaka #ifndef RUN_HWCRYPTO
24869cdb1c70Snonaka 	struct ieee80211_key *k;
24879cdb1c70Snonaka #endif
24889cdb1c70Snonaka 	struct run_tx_ring *ring;
24899cdb1c70Snonaka 	struct run_tx_data *data;
24909cdb1c70Snonaka 	struct rt2870_txd *txd;
24919cdb1c70Snonaka 	struct rt2860_txwi *txwi;
2492d164e220Smlelstv 	uint16_t qos, dur, mcs;
2493d164e220Smlelstv 	uint16_t txwisize;
2494d164e220Smlelstv 	uint8_t type, tid, qid;
2495d164e220Smlelstv 	int hasqos, ridx, ctl_ridx, xferlen;
2496faca41fbSmlelstv 	uint8_t pad;
2497d164e220Smlelstv 	usbd_status status;
24989cdb1c70Snonaka 
24999cdb1c70Snonaka 	wh = mtod(m, struct ieee80211_frame *);
25009cdb1c70Snonaka 
25019cdb1c70Snonaka #ifndef RUN_HWCRYPTO
25029cdb1c70Snonaka 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
25039cdb1c70Snonaka 		k = ieee80211_crypto_encap(ic, ni, m);
25049cdb1c70Snonaka 		if (k == NULL) {
25059cdb1c70Snonaka 			m_freem(m);
25064e8e6643Sskrll 			return ENOBUFS;
25079cdb1c70Snonaka 		}
25089cdb1c70Snonaka 
25099cdb1c70Snonaka 		/* packet header may have moved, reset our local pointer */
25109cdb1c70Snonaka 		wh = mtod(m, struct ieee80211_frame *);
25119cdb1c70Snonaka 	}
25129cdb1c70Snonaka #endif
25139cdb1c70Snonaka 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
25149cdb1c70Snonaka 
251589f5489aSchristos 	if ((hasqos = ieee80211_has_qos(wh))) {
25169cdb1c70Snonaka 		qos = ((struct ieee80211_qosframe *)wh)->i_qos[0];
25179cdb1c70Snonaka 		tid = qos & IEEE80211_QOS_TID;
25189cdb1c70Snonaka 		qid = TID_TO_WME_AC(tid);
25199cdb1c70Snonaka 	} else {
2520d164e220Smlelstv 		qos = 0;
25219cdb1c70Snonaka 		tid = 0;
25229cdb1c70Snonaka 		qid = WME_AC_BE;
25239cdb1c70Snonaka 	}
25249cdb1c70Snonaka 	ring = &sc->txq[qid];
25259cdb1c70Snonaka 	data = &ring->data[ring->cur];
25269cdb1c70Snonaka 
25279cdb1c70Snonaka 	/* pickup a rate index */
25289cdb1c70Snonaka 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
25299cdb1c70Snonaka 	    type != IEEE80211_FC0_TYPE_DATA) {
25309cdb1c70Snonaka 		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
25319cdb1c70Snonaka 		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
25329cdb1c70Snonaka 		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
25339cdb1c70Snonaka 	} else if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
25349cdb1c70Snonaka 		ridx = sc->fixed_ridx;
25359cdb1c70Snonaka 		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
25369cdb1c70Snonaka 	} else {
25379cdb1c70Snonaka 		ridx = rn->ridx[ni->ni_txrate];
25389cdb1c70Snonaka 		ctl_ridx = rn->ctl_ridx[ni->ni_txrate];
25399cdb1c70Snonaka 	}
25409cdb1c70Snonaka 
25419cdb1c70Snonaka 	/* get MCS code from rate index */
25429cdb1c70Snonaka 	mcs = rt2860_rates[ridx].mcs;
25439cdb1c70Snonaka 
2544d164e220Smlelstv 	txwisize = sizeof(struct rt2860_txwi);
2545d164e220Smlelstv 	if (sc->mac_ver == 0x5592)
2546d164e220Smlelstv 		txwisize += sizeof(uint32_t);
2547faca41fbSmlelstv 	xferlen = txwisize + m->m_pkthdr.len;
2548d164e220Smlelstv 
25499cdb1c70Snonaka 	/* roundup to 32-bit alignment */
25509cdb1c70Snonaka 	xferlen = (xferlen + 3) & ~3;
25519cdb1c70Snonaka 
25529cdb1c70Snonaka 	txd = (struct rt2870_txd *)data->buf;
25539cdb1c70Snonaka 	txd->flags = RT2860_TX_QSEL_EDCA;
25549cdb1c70Snonaka 	txd->len = htole16(xferlen);
25559cdb1c70Snonaka 
2556faca41fbSmlelstv 	/*
2557faca41fbSmlelstv 	 * Ether both are true or both are false, the header
2558faca41fbSmlelstv 	 * are nicely aligned to 32-bit. So, no L2 padding.
2559faca41fbSmlelstv 	 */
2560faca41fbSmlelstv 	if (IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
2561faca41fbSmlelstv 		pad = 0;
2562faca41fbSmlelstv 	else
2563faca41fbSmlelstv 		pad = 2;
2564faca41fbSmlelstv 
25659cdb1c70Snonaka 	/* setup TX Wireless Information */
25669cdb1c70Snonaka 	txwi = (struct rt2860_txwi *)(txd + 1);
25679cdb1c70Snonaka 	txwi->flags = 0;
25689cdb1c70Snonaka 	txwi->xflags = hasqos ? 0 : RT2860_TX_NSEQ;
25699cdb1c70Snonaka 	txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ?
25709cdb1c70Snonaka 	    RUN_AID2WCID(ni->ni_associd) : 0xff;
2571faca41fbSmlelstv 	txwi->len = htole16(m->m_pkthdr.len - pad);
25729cdb1c70Snonaka 	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
25739cdb1c70Snonaka 		txwi->phy = htole16(RT2860_PHY_CCK);
25749cdb1c70Snonaka 		if (ridx != RT2860_RIDX_CCK1 &&
25759cdb1c70Snonaka 		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
25769cdb1c70Snonaka 			mcs |= RT2860_PHY_SHPRE;
25779cdb1c70Snonaka 	} else
2578faca41fbSmlelstv 		mcs |= RT2860_PHY_OFDM;
2579d164e220Smlelstv 	txwi->phy = htole16(mcs);
25809cdb1c70Snonaka 
25819cdb1c70Snonaka 	txwi->txop = RT2860_TX_TXOP_BACKOFF;
25829cdb1c70Snonaka 
25839cdb1c70Snonaka 	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
25849cdb1c70Snonaka 	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
25859cdb1c70Snonaka 	    IEEE80211_QOS_ACKPOLICY_NOACK)) {
25869cdb1c70Snonaka 		txwi->xflags |= RT2860_TX_ACK;
25879cdb1c70Snonaka 		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
25889cdb1c70Snonaka 			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
25899cdb1c70Snonaka 		else
25909cdb1c70Snonaka 			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
25919cdb1c70Snonaka 		*(uint16_t *)wh->i_dur = htole16(dur);
25929cdb1c70Snonaka 	}
25939cdb1c70Snonaka 
25949cdb1c70Snonaka #ifndef IEEE80211_STA_ONLY
25959cdb1c70Snonaka 	/* ask MAC to insert timestamp into probe responses */
25969cdb1c70Snonaka 	if ((wh->i_fc[0] &
25979cdb1c70Snonaka 	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
25989cdb1c70Snonaka 	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
25999cdb1c70Snonaka 	    /* NOTE: beacons do not pass through tx_data() */
26009cdb1c70Snonaka 		txwi->flags |= RT2860_TX_TS;
26019cdb1c70Snonaka #endif
26029cdb1c70Snonaka 
26039cdb1c70Snonaka 	if (__predict_false(sc->sc_drvbpf != NULL)) {
26049cdb1c70Snonaka 		struct run_tx_radiotap_header *tap = &sc->sc_txtap;
26059cdb1c70Snonaka 
26069cdb1c70Snonaka 		tap->wt_flags = 0;
26079cdb1c70Snonaka 		tap->wt_rate = rt2860_rates[ridx].rate;
26089cdb1c70Snonaka 		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
26099cdb1c70Snonaka 		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
26109cdb1c70Snonaka 		tap->wt_hwqueue = qid;
26119cdb1c70Snonaka 		if (mcs & RT2860_PHY_SHPRE)
26129cdb1c70Snonaka 			tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
26139cdb1c70Snonaka 
26143cd62456Smsaitoh 		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m, BPF_D_OUT);
26159cdb1c70Snonaka 	}
26169cdb1c70Snonaka 
2617faca41fbSmlelstv 	m_copydata(m, 0, m->m_pkthdr.len, ((uint8_t *)txwi) + txwisize);
26189cdb1c70Snonaka 	m_freem(m);
26199cdb1c70Snonaka 
26209cdb1c70Snonaka 	xferlen += sizeof(*txd) + 4;
26219cdb1c70Snonaka 
26224e8e6643Sskrll 	usbd_setup_xfer(data->xfer, data, data->buf, xferlen,
26234e8e6643Sskrll 	    USBD_FORCE_SHORT_XFER, RUN_TX_TIMEOUT, run_txeof);
2624d164e220Smlelstv 	status = usbd_transfer(data->xfer);
2625d164e220Smlelstv 	if (__predict_false(status != USBD_IN_PROGRESS &&
2626d164e220Smlelstv 	    status != USBD_NORMAL_COMPLETION)) {
2627d164e220Smlelstv 		device_printf(sc->sc_dev, "queuing tx failed: %s\n",
2628d164e220Smlelstv 		    usbd_errstr(status));
2629d164e220Smlelstv 		return EIO;
2630d164e220Smlelstv 	}
26319cdb1c70Snonaka 
26329cdb1c70Snonaka 	ieee80211_free_node(ni);
26339cdb1c70Snonaka 
26349cdb1c70Snonaka 	ring->cur = (ring->cur + 1) % RUN_TX_RING_COUNT;
26359cdb1c70Snonaka 	if (++ring->queued >= RUN_TX_RING_COUNT)
26369cdb1c70Snonaka 		sc->qfullmsk |= 1 << qid;
26379cdb1c70Snonaka 
26384e8e6643Sskrll 	return 0;
26399cdb1c70Snonaka }
26409cdb1c70Snonaka 
26419cdb1c70Snonaka static void
26429cdb1c70Snonaka run_start(struct ifnet *ifp)
26439cdb1c70Snonaka {
26449cdb1c70Snonaka 	struct run_softc *sc = ifp->if_softc;
26459cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
26469cdb1c70Snonaka 	struct ether_header *eh;
26479cdb1c70Snonaka 	struct ieee80211_node *ni;
26489cdb1c70Snonaka 	struct mbuf *m;
26499cdb1c70Snonaka 
26509cdb1c70Snonaka 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
26519cdb1c70Snonaka 		return;
26529cdb1c70Snonaka 
26539cdb1c70Snonaka 	for (;;) {
26549cdb1c70Snonaka 		if (sc->qfullmsk != 0) {
26559cdb1c70Snonaka 			ifp->if_flags |= IFF_OACTIVE;
26569cdb1c70Snonaka 			break;
26579cdb1c70Snonaka 		}
26589cdb1c70Snonaka 		/* send pending management frames first */
26599cdb1c70Snonaka 		IF_DEQUEUE(&ic->ic_mgtq, m);
26609cdb1c70Snonaka 		if (m != NULL) {
2661ea0349e7Sozaki-r 			ni = M_GETCTX(m, struct ieee80211_node *);
26626bbd2477Sozaki-r 			M_CLEARCTX(m);
26639cdb1c70Snonaka 			goto sendit;
26649cdb1c70Snonaka 		}
26659cdb1c70Snonaka 		if (ic->ic_state != IEEE80211_S_RUN)
26669cdb1c70Snonaka 			break;
26679cdb1c70Snonaka 
26689cdb1c70Snonaka 		/* encapsulate and send data frames */
26699cdb1c70Snonaka 		IFQ_DEQUEUE(&ifp->if_snd, m);
26709cdb1c70Snonaka 		if (m == NULL)
26719cdb1c70Snonaka 			break;
26729cdb1c70Snonaka 		if (m->m_len < (int)sizeof(*eh) &&
26739cdb1c70Snonaka 		    (m = m_pullup(m, sizeof(*eh))) == NULL) {
26749cdb1c70Snonaka 			ifp->if_oerrors++;
26759cdb1c70Snonaka 			continue;
26769cdb1c70Snonaka 		}
26779cdb1c70Snonaka 
26789cdb1c70Snonaka 		eh = mtod(m, struct ether_header *);
26799cdb1c70Snonaka 		ni = ieee80211_find_txnode(ic, eh->ether_dhost);
26809cdb1c70Snonaka 		if (ni == NULL) {
26819cdb1c70Snonaka 			m_freem(m);
26829cdb1c70Snonaka 			ifp->if_oerrors++;
26839cdb1c70Snonaka 			continue;
26849cdb1c70Snonaka 		}
26859cdb1c70Snonaka 
26863cd62456Smsaitoh 		bpf_mtap(ifp, m, BPF_D_OUT);
26879cdb1c70Snonaka 
26889cdb1c70Snonaka 		if ((m = ieee80211_encap(ic, m, ni)) == NULL) {
26899cdb1c70Snonaka 			ieee80211_free_node(ni);
26909cdb1c70Snonaka 			ifp->if_oerrors++;
26919cdb1c70Snonaka 			continue;
26929cdb1c70Snonaka 		}
26939cdb1c70Snonaka sendit:
26943cd62456Smsaitoh 		bpf_mtap3(ic->ic_rawbpf, m, BPF_D_OUT);
26959cdb1c70Snonaka 
26969cdb1c70Snonaka 		if (run_tx(sc, m, ni) != 0) {
26979cdb1c70Snonaka 			ieee80211_free_node(ni);
26989cdb1c70Snonaka 			ifp->if_oerrors++;
26999cdb1c70Snonaka 			continue;
27009cdb1c70Snonaka 		}
27019cdb1c70Snonaka 
27029cdb1c70Snonaka 		sc->sc_tx_timer = 5;
27039cdb1c70Snonaka 		ifp->if_timer = 1;
27049cdb1c70Snonaka 	}
27059cdb1c70Snonaka }
27069cdb1c70Snonaka 
27079cdb1c70Snonaka static void
27089cdb1c70Snonaka run_watchdog(struct ifnet *ifp)
27099cdb1c70Snonaka {
27109cdb1c70Snonaka 	struct run_softc *sc = ifp->if_softc;
27119cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
27129cdb1c70Snonaka 
27139cdb1c70Snonaka 	ifp->if_timer = 0;
27149cdb1c70Snonaka 
27159cdb1c70Snonaka 	if (sc->sc_tx_timer > 0) {
27169cdb1c70Snonaka 		if (--sc->sc_tx_timer == 0) {
27171d5cb2a3Sjakllsch 			device_printf(sc->sc_dev, "device timeout\n");
27189cdb1c70Snonaka 			/* run_init(ifp); XXX needs a process context! */
27199cdb1c70Snonaka 			ifp->if_oerrors++;
27209cdb1c70Snonaka 			return;
27219cdb1c70Snonaka 		}
27229cdb1c70Snonaka 		ifp->if_timer = 1;
27239cdb1c70Snonaka 	}
27249cdb1c70Snonaka 
27259cdb1c70Snonaka 	ieee80211_watchdog(ic);
27269cdb1c70Snonaka }
27279cdb1c70Snonaka 
27289cdb1c70Snonaka static int
27299cdb1c70Snonaka run_ioctl(struct ifnet *ifp, u_long cmd, void *data)
27309cdb1c70Snonaka {
27319cdb1c70Snonaka 	struct run_softc *sc = ifp->if_softc;
27329cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
27339cdb1c70Snonaka 	int s, error = 0;
27349cdb1c70Snonaka 
27359cdb1c70Snonaka 	s = splnet();
27369cdb1c70Snonaka 
27379cdb1c70Snonaka 	switch (cmd) {
27389cdb1c70Snonaka 	case SIOCSIFFLAGS:
27399cdb1c70Snonaka 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
27409cdb1c70Snonaka 			break;
27419cdb1c70Snonaka 		switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
27429cdb1c70Snonaka 		case IFF_UP|IFF_RUNNING:
27439cdb1c70Snonaka 			break;
27449cdb1c70Snonaka 		case IFF_UP:
27459cdb1c70Snonaka 			run_init(ifp);
27469cdb1c70Snonaka 			break;
27479cdb1c70Snonaka 		case IFF_RUNNING:
27489cdb1c70Snonaka 			run_stop(ifp, 1);
27499cdb1c70Snonaka 			break;
27509cdb1c70Snonaka 		case 0:
27519cdb1c70Snonaka 			break;
27529cdb1c70Snonaka 		}
27539cdb1c70Snonaka 		break;
27549cdb1c70Snonaka 
27559cdb1c70Snonaka 	case SIOCADDMULTI:
27569cdb1c70Snonaka 	case SIOCDELMULTI:
27579cdb1c70Snonaka 		if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
27589cdb1c70Snonaka 			/* setup multicast filter, etc */
27599cdb1c70Snonaka 			error = 0;
27609cdb1c70Snonaka 		}
27619cdb1c70Snonaka 		break;
27629cdb1c70Snonaka 
27639cdb1c70Snonaka 	default:
27649cdb1c70Snonaka 		error = ieee80211_ioctl(ic, cmd, data);
27659cdb1c70Snonaka 		break;
27669cdb1c70Snonaka 	}
27679cdb1c70Snonaka 
27689cdb1c70Snonaka 	if (error == ENETRESET) {
27699cdb1c70Snonaka 		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
27709cdb1c70Snonaka 		    (IFF_UP | IFF_RUNNING)) {
27719cdb1c70Snonaka 			run_init(ifp);
27729cdb1c70Snonaka 		}
27739cdb1c70Snonaka 		error = 0;
27749cdb1c70Snonaka 	}
27759cdb1c70Snonaka 
27769cdb1c70Snonaka 	splx(s);
27779cdb1c70Snonaka 
27784e8e6643Sskrll 	return error;
27799cdb1c70Snonaka }
27809cdb1c70Snonaka 
27819cdb1c70Snonaka static void
27829cdb1c70Snonaka run_select_chan_group(struct run_softc *sc, int group)
27839cdb1c70Snonaka {
27849cdb1c70Snonaka 	uint32_t tmp;
27859cdb1c70Snonaka 	uint8_t agc;
27869cdb1c70Snonaka 
27879cdb1c70Snonaka 	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
27889cdb1c70Snonaka 	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
27899cdb1c70Snonaka 	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
2790d164e220Smlelstv 	if (sc->mac_ver < 0x3572)
27919cdb1c70Snonaka 		run_bbp_write(sc, 86, 0x00);
27929cdb1c70Snonaka 
2793d164e220Smlelstv 	if (sc->mac_ver == 0x3593) {
2794d164e220Smlelstv 		run_bbp_write(sc, 77, 0x98);
2795d164e220Smlelstv 		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
2796d164e220Smlelstv 	}
2797d164e220Smlelstv 
27989cdb1c70Snonaka 	if (group == 0) {
27999cdb1c70Snonaka 		if (sc->ext_2ghz_lna) {
2800d164e220Smlelstv 			if (sc->mac_ver >= 0x5390)
2801d164e220Smlelstv 				run_bbp_write(sc, 75, 0x52);
2802d164e220Smlelstv 			else {
28039cdb1c70Snonaka 				run_bbp_write(sc, 82, 0x62);
28049cdb1c70Snonaka 				run_bbp_write(sc, 75, 0x46);
28059cdb1c70Snonaka 			}
28069cdb1c70Snonaka 		} else {
2807d164e220Smlelstv 			if (sc->mac_ver == 0x5592) {
2808d164e220Smlelstv 				run_bbp_write(sc, 79, 0x1c);
2809d164e220Smlelstv 				run_bbp_write(sc, 80, 0x0e);
2810d164e220Smlelstv 				run_bbp_write(sc, 81, 0x3a);
2811d164e220Smlelstv 				run_bbp_write(sc, 82, 0x62);
2812d164e220Smlelstv 
2813d164e220Smlelstv 				run_bbp_write(sc, 195, 0x80);
2814d164e220Smlelstv 				run_bbp_write(sc, 196, 0xe0);
2815d164e220Smlelstv 				run_bbp_write(sc, 195, 0x81);
2816d164e220Smlelstv 				run_bbp_write(sc, 196, 0x1f);
2817d164e220Smlelstv 				run_bbp_write(sc, 195, 0x82);
2818d164e220Smlelstv 				run_bbp_write(sc, 196, 0x38);
2819d164e220Smlelstv 				run_bbp_write(sc, 195, 0x83);
2820d164e220Smlelstv 				run_bbp_write(sc, 196, 0x32);
2821d164e220Smlelstv 				run_bbp_write(sc, 195, 0x85);
2822d164e220Smlelstv 				run_bbp_write(sc, 196, 0x28);
2823d164e220Smlelstv 				run_bbp_write(sc, 195, 0x86);
2824d164e220Smlelstv 				run_bbp_write(sc, 196, 0x19);
2825d164e220Smlelstv 			} else if (sc->mac_ver >= 0x5390) {
2826d164e220Smlelstv 				run_bbp_write(sc, 75, 0x50);
2827d164e220Smlelstv 			} else {
2828d164e220Smlelstv 				run_bbp_write(sc, 82,
2829d164e220Smlelstv 				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
2830d164e220Smlelstv 				run_bbp_write(sc, 75, 0x50);
2831d164e220Smlelstv 			}
2832d164e220Smlelstv 		}
2833d164e220Smlelstv 	} else {
2834d164e220Smlelstv 		if (sc->mac_ver == 0x5592) {
2835d164e220Smlelstv 			run_bbp_write(sc, 79, 0x18);
2836d164e220Smlelstv 			run_bbp_write(sc, 80, 0x08);
2837d164e220Smlelstv 			run_bbp_write(sc, 81, 0x38);
2838d164e220Smlelstv 			run_bbp_write(sc, 82, 0x92);
2839d164e220Smlelstv 
2840d164e220Smlelstv 			run_bbp_write(sc, 195, 0x80);
2841d164e220Smlelstv 			run_bbp_write(sc, 196, 0xf0);
2842d164e220Smlelstv 			run_bbp_write(sc, 195, 0x81);
2843d164e220Smlelstv 			run_bbp_write(sc, 196, 0x1e);
2844d164e220Smlelstv 			run_bbp_write(sc, 195, 0x82);
2845d164e220Smlelstv 			run_bbp_write(sc, 196, 0x28);
2846d164e220Smlelstv 			run_bbp_write(sc, 195, 0x83);
2847d164e220Smlelstv 			run_bbp_write(sc, 196, 0x20);
2848d164e220Smlelstv 			run_bbp_write(sc, 195, 0x85);
2849d164e220Smlelstv 			run_bbp_write(sc, 196, 0x7f);
2850d164e220Smlelstv 			run_bbp_write(sc, 195, 0x86);
2851d164e220Smlelstv 			run_bbp_write(sc, 196, 0x7f);
2852d164e220Smlelstv 		} else if (sc->mac_ver == 0x3572)
28539cdb1c70Snonaka 			run_bbp_write(sc, 82, 0x94);
28549cdb1c70Snonaka 		else
2855d164e220Smlelstv 			run_bbp_write(sc, 82,
2856d164e220Smlelstv 			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
28579cdb1c70Snonaka 		if (sc->ext_5ghz_lna)
28589cdb1c70Snonaka 			run_bbp_write(sc, 75, 0x46);
28599cdb1c70Snonaka 		else
28609cdb1c70Snonaka 			run_bbp_write(sc, 75, 0x50);
28619cdb1c70Snonaka 	}
28629cdb1c70Snonaka 
28639cdb1c70Snonaka 	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
28649cdb1c70Snonaka 	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
28659cdb1c70Snonaka 	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
28669cdb1c70Snonaka 	run_write(sc, RT2860_TX_BAND_CFG, tmp);
28679cdb1c70Snonaka 
28689cdb1c70Snonaka 	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
28699cdb1c70Snonaka 	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
2870d164e220Smlelstv 	if (sc->mac_ver == 0x3593)
2871d164e220Smlelstv 		tmp |= RT3593_LNA_PE_G2_EN | RT3593_LNA_PE_A2_EN;
28729cdb1c70Snonaka 	if (sc->nrxchains > 1)
28739cdb1c70Snonaka 		tmp |= RT2860_LNA_PE1_EN;
28749cdb1c70Snonaka 	if (group == 0) {	/* 2GHz */
28759cdb1c70Snonaka 		tmp |= RT2860_PA_PE_G0_EN;
28769cdb1c70Snonaka 		if (sc->ntxchains > 1)
28779cdb1c70Snonaka 			tmp |= RT2860_PA_PE_G1_EN;
28789cdb1c70Snonaka 	} else {		/* 5GHz */
28799cdb1c70Snonaka 		tmp |= RT2860_PA_PE_A0_EN;
28809cdb1c70Snonaka 		if (sc->ntxchains > 1)
28819cdb1c70Snonaka 			tmp |= RT2860_PA_PE_A1_EN;
2882d164e220Smlelstv 		if (sc->mac_ver == 0x3593) {
2883d164e220Smlelstv 			if (sc->ntxchains > 2)
2884d164e220Smlelstv 				tmp |= RT3593_PA_PE_G2_EN;
2885d164e220Smlelstv 		}
28869cdb1c70Snonaka 	}
28879cdb1c70Snonaka 	if (sc->mac_ver == 0x3572) {
28889cdb1c70Snonaka 		run_rt3070_rf_write(sc, 8, 0x00);
28899cdb1c70Snonaka 		run_write(sc, RT2860_TX_PIN_CFG, tmp);
28909cdb1c70Snonaka 		run_rt3070_rf_write(sc, 8, 0x80);
28919cdb1c70Snonaka 	} else
28929cdb1c70Snonaka 		run_write(sc, RT2860_TX_PIN_CFG, tmp);
28939cdb1c70Snonaka 
2894d164e220Smlelstv 	if (sc->mac_ver == 0x5592) {
2895d164e220Smlelstv 		run_bbp_write(sc, 195, 0x8d);
2896d164e220Smlelstv 		run_bbp_write(sc, 196, 0x1a);
2897d164e220Smlelstv 	}
2898d164e220Smlelstv 
2899d164e220Smlelstv 	if (sc->mac_ver == 0x3593) {
2900d164e220Smlelstv 		run_read(sc, RT2860_GPIO_CTRL, &tmp);
2901d164e220Smlelstv 		tmp &= ~0x01010000;
2902d164e220Smlelstv 		if (group == 0)
2903d164e220Smlelstv 			tmp |= 0x00010000;
2904d164e220Smlelstv 		tmp = (tmp & ~0x00009090) | 0x00000090;
2905d164e220Smlelstv 		run_write(sc, RT2860_GPIO_CTRL, tmp);
2906d164e220Smlelstv 	}
2907d164e220Smlelstv 
29089cdb1c70Snonaka 	/* set initial AGC value */
29099cdb1c70Snonaka 	if (group == 0) {       /* 2GHz band */
29109cdb1c70Snonaka 		if (sc->mac_ver >= 0x3070)
29119cdb1c70Snonaka 			agc = 0x1c + sc->lna[0] * 2;
29129cdb1c70Snonaka 		else
29139cdb1c70Snonaka 			agc = 0x2e + sc->lna[0];
29149cdb1c70Snonaka 	} else {		/* 5GHz band */
29159cdb1c70Snonaka 		if (sc->mac_ver == 0x3572)
29169cdb1c70Snonaka 			agc = 0x22 + (sc->lna[group] * 5) / 3;
29179cdb1c70Snonaka 		else
29189cdb1c70Snonaka 			agc = 0x32 + (sc->lna[group] * 5) / 3;
29199cdb1c70Snonaka 	}
29209cdb1c70Snonaka 	run_set_agc(sc, agc);
29219cdb1c70Snonaka }
29229cdb1c70Snonaka 
29239cdb1c70Snonaka static void
29249cdb1c70Snonaka run_rt2870_set_chan(struct run_softc *sc, u_int chan)
29259cdb1c70Snonaka {
29269cdb1c70Snonaka 	const struct rfprog *rfprog = rt2860_rf2850;
29279cdb1c70Snonaka 	uint32_t r2, r3, r4;
29289cdb1c70Snonaka 	int8_t txpow1, txpow2;
29299cdb1c70Snonaka 	int i;
29309cdb1c70Snonaka 
29319cdb1c70Snonaka 	/* find the settings for this channel (we know it exists) */
29329cdb1c70Snonaka 	for (i = 0; rfprog[i].chan != chan; i++);
29339cdb1c70Snonaka 
29349cdb1c70Snonaka 	r2 = rfprog[i].r2;
29359cdb1c70Snonaka 	if (sc->ntxchains == 1)
29369cdb1c70Snonaka 		r2 |= 1 << 12;		/* 1T: disable Tx chain 2 */
29379cdb1c70Snonaka 	if (sc->nrxchains == 1)
29389cdb1c70Snonaka 		r2 |= 1 << 15 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
29399cdb1c70Snonaka 	else if (sc->nrxchains == 2)
29409cdb1c70Snonaka 		r2 |= 1 << 4;		/* 2R: disable Rx chain 3 */
29419cdb1c70Snonaka 
29429cdb1c70Snonaka 	/* use Tx power values from EEPROM */
29439cdb1c70Snonaka 	txpow1 = sc->txpow1[i];
29449cdb1c70Snonaka 	txpow2 = sc->txpow2[i];
29459cdb1c70Snonaka 	if (chan > 14) {
29469cdb1c70Snonaka 		if (txpow1 >= 0)
29479cdb1c70Snonaka 			txpow1 = txpow1 << 1 | 1;
29489cdb1c70Snonaka 		else
29499cdb1c70Snonaka 			txpow1 = (7 + txpow1) << 1;
29509cdb1c70Snonaka 		if (txpow2 >= 0)
29519cdb1c70Snonaka 			txpow2 = txpow2 << 1 | 1;
29529cdb1c70Snonaka 		else
29539cdb1c70Snonaka 			txpow2 = (7 + txpow2) << 1;
29549cdb1c70Snonaka 	}
29559cdb1c70Snonaka 	r3 = rfprog[i].r3 | txpow1 << 7;
29569cdb1c70Snonaka 	r4 = rfprog[i].r4 | sc->freq << 13 | txpow2 << 4;
29579cdb1c70Snonaka 
29589cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
29599cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF2, r2);
29609cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF3, r3);
29619cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF4, r4);
29629cdb1c70Snonaka 
2963faca41fbSmlelstv 	usbd_delay_ms(sc->sc_udev, 10);
29649cdb1c70Snonaka 
29659cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
29669cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF2, r2);
29679cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF3, r3 | 1);
29689cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF4, r4);
29699cdb1c70Snonaka 
2970faca41fbSmlelstv 	usbd_delay_ms(sc->sc_udev, 10);
29719cdb1c70Snonaka 
29729cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
29739cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF2, r2);
29749cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF3, r3);
29759cdb1c70Snonaka 	run_rt2870_rf_write(sc, RT2860_RF4, r4);
29769cdb1c70Snonaka }
29779cdb1c70Snonaka 
29789cdb1c70Snonaka static void
29799cdb1c70Snonaka run_rt3070_set_chan(struct run_softc *sc, u_int chan)
29809cdb1c70Snonaka {
29819cdb1c70Snonaka 	int8_t txpow1, txpow2;
29829cdb1c70Snonaka 	uint8_t rf;
29839cdb1c70Snonaka 	int i;
29849cdb1c70Snonaka 
29859cdb1c70Snonaka 	KASSERT(chan >= 1 && chan <= 14);	/* RT3070 is 2GHz only */
29869cdb1c70Snonaka 
29879cdb1c70Snonaka 	/* find the settings for this channel (we know it exists) */
29889cdb1c70Snonaka 	for (i = 0; rt2860_rf2850[i].chan != chan; i++)
29899cdb1c70Snonaka 		continue;
29909cdb1c70Snonaka 
29919cdb1c70Snonaka 	/* use Tx power values from EEPROM */
29929cdb1c70Snonaka 	txpow1 = sc->txpow1[i];
29939cdb1c70Snonaka 	txpow2 = sc->txpow2[i];
29949cdb1c70Snonaka 
29959cdb1c70Snonaka 	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
29969cdb1c70Snonaka 	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
29979cdb1c70Snonaka 	run_rt3070_rf_read(sc, 6, &rf);
29989cdb1c70Snonaka 	rf = (rf & ~0x03) | rt3070_freqs[i].r;
29999cdb1c70Snonaka 	run_rt3070_rf_write(sc, 6, rf);
30009cdb1c70Snonaka 
30019cdb1c70Snonaka 	/* set Tx0 power */
30029cdb1c70Snonaka 	run_rt3070_rf_read(sc, 12, &rf);
30039cdb1c70Snonaka 	rf = (rf & ~0x1f) | txpow1;
30049cdb1c70Snonaka 	run_rt3070_rf_write(sc, 12, rf);
30059cdb1c70Snonaka 
30069cdb1c70Snonaka 	/* set Tx1 power */
30079cdb1c70Snonaka 	run_rt3070_rf_read(sc, 13, &rf);
30089cdb1c70Snonaka 	rf = (rf & ~0x1f) | txpow2;
30099cdb1c70Snonaka 	run_rt3070_rf_write(sc, 13, rf);
30109cdb1c70Snonaka 
30119cdb1c70Snonaka 	run_rt3070_rf_read(sc, 1, &rf);
30129cdb1c70Snonaka 	rf &= ~0xfc;
30139cdb1c70Snonaka 	if (sc->ntxchains == 1)
30149cdb1c70Snonaka 		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
30159cdb1c70Snonaka 	else if (sc->ntxchains == 2)
30169cdb1c70Snonaka 		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
30179cdb1c70Snonaka 	if (sc->nrxchains == 1)
30189cdb1c70Snonaka 		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
30199cdb1c70Snonaka 	else if (sc->nrxchains == 2)
30209cdb1c70Snonaka 		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
30219cdb1c70Snonaka 	run_rt3070_rf_write(sc, 1, rf);
30229cdb1c70Snonaka 
30239cdb1c70Snonaka 	/* set RF offset */
30249cdb1c70Snonaka 	run_rt3070_rf_read(sc, 23, &rf);
30259cdb1c70Snonaka 	rf = (rf & ~0x7f) | sc->freq;
30269cdb1c70Snonaka 	run_rt3070_rf_write(sc, 23, rf);
30279cdb1c70Snonaka 
30289cdb1c70Snonaka 	/* program RF filter */
30299cdb1c70Snonaka 	run_rt3070_rf_read(sc, 24, &rf);        /* Tx */
30309cdb1c70Snonaka 	rf = (rf & ~0x3f) | sc->rf24_20mhz;
30319cdb1c70Snonaka 	run_rt3070_rf_write(sc, 24, rf);
30329cdb1c70Snonaka 	run_rt3070_rf_read(sc, 31, &rf);        /* Rx */
30339cdb1c70Snonaka 	rf = (rf & ~0x3f) | sc->rf24_20mhz;
30349cdb1c70Snonaka 	run_rt3070_rf_write(sc, 31, rf);
30359cdb1c70Snonaka 
30369cdb1c70Snonaka 	/* enable RF tuning */
30379cdb1c70Snonaka 	run_rt3070_rf_read(sc, 7, &rf);
30389cdb1c70Snonaka 	run_rt3070_rf_write(sc, 7, rf | 0x01);
30399cdb1c70Snonaka }
30409cdb1c70Snonaka 
30419cdb1c70Snonaka static void
30429cdb1c70Snonaka run_rt3572_set_chan(struct run_softc *sc, u_int chan)
30439cdb1c70Snonaka {
30449cdb1c70Snonaka 	int8_t txpow1, txpow2;
30459cdb1c70Snonaka 	uint32_t tmp;
30469cdb1c70Snonaka 	uint8_t rf;
30479cdb1c70Snonaka 	int i;
30489cdb1c70Snonaka 
30499cdb1c70Snonaka 	/* find the settings for this channel (we know it exists) */
30509cdb1c70Snonaka 	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
30519cdb1c70Snonaka 
30529cdb1c70Snonaka 	/* use Tx power values from EEPROM */
30539cdb1c70Snonaka 	txpow1 = sc->txpow1[i];
30549cdb1c70Snonaka 	txpow2 = sc->txpow2[i];
30559cdb1c70Snonaka 
30569cdb1c70Snonaka 	if (chan <= 14) {
30579cdb1c70Snonaka 		run_bbp_write(sc, 25, sc->bbp25);
30589cdb1c70Snonaka 		run_bbp_write(sc, 26, sc->bbp26);
30599cdb1c70Snonaka 	} else {
30609cdb1c70Snonaka 		/* enable IQ phase correction */
30619cdb1c70Snonaka 		run_bbp_write(sc, 25, 0x09);
30629cdb1c70Snonaka 		run_bbp_write(sc, 26, 0xff);
30639cdb1c70Snonaka 	}
30649cdb1c70Snonaka 
30659cdb1c70Snonaka 	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
30669cdb1c70Snonaka 	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
30679cdb1c70Snonaka 	run_rt3070_rf_read(sc, 6, &rf);
30689cdb1c70Snonaka 	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
30699cdb1c70Snonaka 	rf |= (chan <= 14) ? 0x08 : 0x04;
30709cdb1c70Snonaka 	run_rt3070_rf_write(sc, 6, rf);
30719cdb1c70Snonaka 
30729cdb1c70Snonaka 	/* set PLL mode */
30739cdb1c70Snonaka 	run_rt3070_rf_read(sc, 5, &rf);
30749cdb1c70Snonaka 	rf &= ~(0x08 | 0x04);
30759cdb1c70Snonaka 	rf |= (chan <= 14) ? 0x04 : 0x08;
30769cdb1c70Snonaka 	run_rt3070_rf_write(sc, 5, rf);
30779cdb1c70Snonaka 
30789cdb1c70Snonaka 	/* set Tx power for chain 0 */
30799cdb1c70Snonaka 	if (chan <= 14)
30809cdb1c70Snonaka 		rf = 0x60 | txpow1;
30819cdb1c70Snonaka 	else
30829cdb1c70Snonaka 		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
30839cdb1c70Snonaka 	run_rt3070_rf_write(sc, 12, rf);
30849cdb1c70Snonaka 
30859cdb1c70Snonaka 	/* set Tx power for chain 1 */
30869cdb1c70Snonaka 	if (chan <= 14)
30879cdb1c70Snonaka 		rf = 0x60 | txpow2;
30889cdb1c70Snonaka 	else
30899cdb1c70Snonaka 		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
30909cdb1c70Snonaka 	run_rt3070_rf_write(sc, 13, rf);
30919cdb1c70Snonaka 
30929cdb1c70Snonaka 	/* set Tx/Rx streams */
30939cdb1c70Snonaka 	run_rt3070_rf_read(sc, 1, &rf);
30949cdb1c70Snonaka 	rf &= ~0xfc;
30959cdb1c70Snonaka 	if (sc->ntxchains == 1)
30969cdb1c70Snonaka 		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
30979cdb1c70Snonaka 	else if (sc->ntxchains == 2)
30989cdb1c70Snonaka 		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
30999cdb1c70Snonaka 	if (sc->nrxchains == 1)
31009cdb1c70Snonaka 		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
31019cdb1c70Snonaka 	else if (sc->nrxchains == 2)
31029cdb1c70Snonaka 		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
31039cdb1c70Snonaka 	run_rt3070_rf_write(sc, 1, rf);
31049cdb1c70Snonaka 
31059cdb1c70Snonaka 	/* set RF offset */
31069cdb1c70Snonaka 	run_rt3070_rf_read(sc, 23, &rf);
31079cdb1c70Snonaka 	rf = (rf & ~0x7f) | sc->freq;
31089cdb1c70Snonaka 	run_rt3070_rf_write(sc, 23, rf);
31099cdb1c70Snonaka 
31109cdb1c70Snonaka 	/* program RF filter */
31119cdb1c70Snonaka 	rf = sc->rf24_20mhz;
31129cdb1c70Snonaka 	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
31139cdb1c70Snonaka 	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
31149cdb1c70Snonaka 
31159cdb1c70Snonaka 	/* enable RF tuning */
31169cdb1c70Snonaka 	run_rt3070_rf_read(sc, 7, &rf);
31179cdb1c70Snonaka 	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
31189cdb1c70Snonaka 	run_rt3070_rf_write(sc, 7, rf);
31199cdb1c70Snonaka 
31209cdb1c70Snonaka 	/* TSSI */
31219cdb1c70Snonaka 	rf = (chan <= 14) ? 0xc3 : 0xc0;
31229cdb1c70Snonaka 	run_rt3070_rf_write(sc, 9, rf);
31239cdb1c70Snonaka 
31249cdb1c70Snonaka 	/* set loop filter 1 */
31259cdb1c70Snonaka 	run_rt3070_rf_write(sc, 10, 0xf1);
31269cdb1c70Snonaka 	/* set loop filter 2 */
31279cdb1c70Snonaka 	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
31289cdb1c70Snonaka 
31299cdb1c70Snonaka 	/* set tx_mx2_ic */
31309cdb1c70Snonaka 	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
31319cdb1c70Snonaka 	/* set tx_mx1_ic */
31329cdb1c70Snonaka 	if (chan <= 14)
31339cdb1c70Snonaka 		rf = 0x48 | sc->txmixgain_2ghz;
31349cdb1c70Snonaka 	else
31359cdb1c70Snonaka 		rf = 0x78 | sc->txmixgain_5ghz;
31369cdb1c70Snonaka 	run_rt3070_rf_write(sc, 16, rf);
31379cdb1c70Snonaka 
31389cdb1c70Snonaka 	/* set tx_lo1 */
31399cdb1c70Snonaka 	run_rt3070_rf_write(sc, 17, 0x23);
31409cdb1c70Snonaka 	/* set tx_lo2 */
31419cdb1c70Snonaka 	if (chan <= 14)
31429cdb1c70Snonaka 		rf = 0x93;
31439cdb1c70Snonaka 	else if (chan <= 64)
31449cdb1c70Snonaka 		rf = 0xb7;
31459cdb1c70Snonaka 	else if (chan <= 128)
31469cdb1c70Snonaka 		rf = 0x74;
31479cdb1c70Snonaka 	else
31489cdb1c70Snonaka 		rf = 0x72;
31499cdb1c70Snonaka 	run_rt3070_rf_write(sc, 19, rf);
31509cdb1c70Snonaka 
31519cdb1c70Snonaka 	/* set rx_lo1 */
31529cdb1c70Snonaka 	if (chan <= 14)
31539cdb1c70Snonaka 		rf = 0xb3;
31549cdb1c70Snonaka 	else if (chan <= 64)
31559cdb1c70Snonaka 		rf = 0xf6;
31569cdb1c70Snonaka 	else if (chan <= 128)
31579cdb1c70Snonaka 		rf = 0xf4;
31589cdb1c70Snonaka 	else
31599cdb1c70Snonaka 		rf = 0xf3;
31609cdb1c70Snonaka 	run_rt3070_rf_write(sc, 20, rf);
31619cdb1c70Snonaka 
31629cdb1c70Snonaka 	/* set pfd_delay */
31639cdb1c70Snonaka 	if (chan <= 14)
31649cdb1c70Snonaka 		rf = 0x15;
31659cdb1c70Snonaka 	else if (chan <= 64)
31669cdb1c70Snonaka 		rf = 0x3d;
31679cdb1c70Snonaka 	else
31689cdb1c70Snonaka 		rf = 0x01;
31699cdb1c70Snonaka 	run_rt3070_rf_write(sc, 25, rf);
31709cdb1c70Snonaka 
31719cdb1c70Snonaka 	/* set rx_lo2 */
31729cdb1c70Snonaka 	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
31739cdb1c70Snonaka 	/* set ldo_rf_vc */
31749cdb1c70Snonaka 	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
31759cdb1c70Snonaka 	/* set drv_cc */
31769cdb1c70Snonaka 	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
31779cdb1c70Snonaka 
31789cdb1c70Snonaka 	run_read(sc, RT2860_GPIO_CTRL, &tmp);
31799cdb1c70Snonaka 	tmp &= ~0x8080;
31809cdb1c70Snonaka 	if (chan <= 14)
31819cdb1c70Snonaka 		tmp |= 0x80;
31829cdb1c70Snonaka 	run_write(sc, RT2860_GPIO_CTRL, tmp);
31839cdb1c70Snonaka 
31849cdb1c70Snonaka 	/* enable RF tuning */
31859cdb1c70Snonaka 	run_rt3070_rf_read(sc, 7, &rf);
31869cdb1c70Snonaka 	run_rt3070_rf_write(sc, 7, rf | 0x01);
31879cdb1c70Snonaka 
3188faca41fbSmlelstv 	usbd_delay_ms(sc->sc_udev, 2);
3189faca41fbSmlelstv }
3190faca41fbSmlelstv 
3191faca41fbSmlelstv static void
3192faca41fbSmlelstv run_rt3593_set_chan(struct run_softc *sc, u_int chan)
3193faca41fbSmlelstv {
3194faca41fbSmlelstv 	int8_t txpow1, txpow2, txpow3;
3195faca41fbSmlelstv 	uint8_t h20mhz, rf;
3196faca41fbSmlelstv 	int i;
3197faca41fbSmlelstv 
3198faca41fbSmlelstv 	/* find the settings for this channel (we know it exists) */
3199faca41fbSmlelstv 	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
3200faca41fbSmlelstv 
3201faca41fbSmlelstv 	/* use Tx power values from EEPROM */
3202faca41fbSmlelstv 	txpow1 = sc->txpow1[i];
3203faca41fbSmlelstv 	txpow2 = sc->txpow2[i];
3204faca41fbSmlelstv 	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
3205faca41fbSmlelstv 
3206faca41fbSmlelstv 	if (chan <= 14) {
3207faca41fbSmlelstv 		run_bbp_write(sc, 25, sc->bbp25);
3208faca41fbSmlelstv 		run_bbp_write(sc, 26, sc->bbp26);
3209faca41fbSmlelstv 	} else {
3210faca41fbSmlelstv 		/* Enable IQ phase correction. */
3211faca41fbSmlelstv 		run_bbp_write(sc, 25, 0x09);
3212faca41fbSmlelstv 		run_bbp_write(sc, 26, 0xff);
3213faca41fbSmlelstv 	}
3214faca41fbSmlelstv 
3215faca41fbSmlelstv 	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
3216faca41fbSmlelstv 	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
3217faca41fbSmlelstv 	run_rt3070_rf_read(sc, 11, &rf);
3218faca41fbSmlelstv 	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
3219faca41fbSmlelstv 	run_rt3070_rf_write(sc, 11, rf);
3220faca41fbSmlelstv 
3221faca41fbSmlelstv 	/* Set pll_idoh. */
3222faca41fbSmlelstv 	run_rt3070_rf_read(sc, 11, &rf);
3223faca41fbSmlelstv 	rf &= ~0x4c;
3224faca41fbSmlelstv 	rf |= (chan <= 14) ? 0x44 : 0x48;
3225faca41fbSmlelstv 	run_rt3070_rf_write(sc, 11, rf);
3226faca41fbSmlelstv 
3227faca41fbSmlelstv 	if (chan <= 14)
3228faca41fbSmlelstv 		rf = txpow1 & 0x1f;
3229faca41fbSmlelstv 	else
3230faca41fbSmlelstv 		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
3231faca41fbSmlelstv 	run_rt3070_rf_write(sc, 53, rf);
3232faca41fbSmlelstv 
3233faca41fbSmlelstv 	if (chan <= 14)
3234faca41fbSmlelstv 		rf = txpow2 & 0x1f;
3235faca41fbSmlelstv 	else
3236faca41fbSmlelstv 		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
3237faca41fbSmlelstv 	run_rt3070_rf_write(sc, 55, rf);
3238faca41fbSmlelstv 
3239faca41fbSmlelstv 	if (chan <= 14)
3240faca41fbSmlelstv 		rf = txpow3 & 0x1f;
3241faca41fbSmlelstv 	else
3242faca41fbSmlelstv 		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
3243faca41fbSmlelstv 	run_rt3070_rf_write(sc, 54, rf);
3244faca41fbSmlelstv 
3245faca41fbSmlelstv 	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
3246faca41fbSmlelstv 	if (sc->ntxchains == 3)
3247faca41fbSmlelstv 		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
3248faca41fbSmlelstv 	else
3249faca41fbSmlelstv 		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
3250faca41fbSmlelstv 	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
3251faca41fbSmlelstv 	run_rt3070_rf_write(sc, 1, rf);
3252faca41fbSmlelstv 
3253faca41fbSmlelstv 	run_adjust_freq_offset(sc);
3254faca41fbSmlelstv 
3255faca41fbSmlelstv 	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
3256faca41fbSmlelstv 
3257faca41fbSmlelstv 	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
3258faca41fbSmlelstv 	run_rt3070_rf_read(sc, 30, &rf);
3259faca41fbSmlelstv 	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
3260faca41fbSmlelstv 	run_rt3070_rf_write(sc, 30, rf);
3261faca41fbSmlelstv 
3262faca41fbSmlelstv 	run_rt3070_rf_read(sc, 36, &rf);
3263faca41fbSmlelstv 	if (chan <= 14)
3264faca41fbSmlelstv 		rf |= 0x80;
3265faca41fbSmlelstv 	else
3266faca41fbSmlelstv 		rf &= ~0x80;
3267faca41fbSmlelstv 	run_rt3070_rf_write(sc, 36, rf);
3268faca41fbSmlelstv 
3269faca41fbSmlelstv 	/* Set vcolo_bs. */
3270faca41fbSmlelstv 	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
3271faca41fbSmlelstv 	/* Set pfd_delay. */
3272faca41fbSmlelstv 	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
3273faca41fbSmlelstv 
3274faca41fbSmlelstv 	/* Set vco bias current control. */
3275faca41fbSmlelstv 	run_rt3070_rf_read(sc, 6, &rf);
3276faca41fbSmlelstv 	rf &= ~0xc0;
3277faca41fbSmlelstv 	if (chan <= 14)
3278faca41fbSmlelstv 		rf |= 0x40;
3279faca41fbSmlelstv 	else if (chan <= 128)
3280faca41fbSmlelstv 		rf |= 0x80;
3281faca41fbSmlelstv 	else
3282faca41fbSmlelstv 		rf |= 0x40;
3283faca41fbSmlelstv 	run_rt3070_rf_write(sc, 6, rf);
3284faca41fbSmlelstv 
3285faca41fbSmlelstv 	run_rt3070_rf_read(sc, 30, &rf);
3286faca41fbSmlelstv 	rf = (rf & ~0x18) | 0x10;
3287faca41fbSmlelstv 	run_rt3070_rf_write(sc, 30, rf);
3288faca41fbSmlelstv 
3289faca41fbSmlelstv 	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
3290faca41fbSmlelstv 	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
3291faca41fbSmlelstv 
3292faca41fbSmlelstv 	run_rt3070_rf_read(sc, 51, &rf);
3293faca41fbSmlelstv 	rf = (rf & ~0x03) | 0x01;
3294faca41fbSmlelstv 	run_rt3070_rf_write(sc, 51, rf);
3295faca41fbSmlelstv 	/* Set tx_mx1_cc. */
3296faca41fbSmlelstv 	run_rt3070_rf_read(sc, 51, &rf);
3297faca41fbSmlelstv 	rf &= ~0x1c;
3298faca41fbSmlelstv 	rf |= (chan <= 14) ? 0x14 : 0x10;
3299faca41fbSmlelstv 	run_rt3070_rf_write(sc, 51, rf);
3300faca41fbSmlelstv 	/* Set tx_mx1_ic. */
3301faca41fbSmlelstv 	run_rt3070_rf_read(sc, 51, &rf);
3302faca41fbSmlelstv 	rf &= ~0xe0;
3303faca41fbSmlelstv 	rf |= (chan <= 14) ? 0x60 : 0x40;
3304faca41fbSmlelstv 	run_rt3070_rf_write(sc, 51, rf);
3305faca41fbSmlelstv 	/* Set tx_lo1_ic. */
3306faca41fbSmlelstv 	run_rt3070_rf_read(sc, 49, &rf);
3307faca41fbSmlelstv 	rf &= ~0x1c;
3308faca41fbSmlelstv 	rf |= (chan <= 14) ? 0x0c : 0x08;
3309faca41fbSmlelstv 	run_rt3070_rf_write(sc, 49, rf);
3310faca41fbSmlelstv 	/* Set tx_lo1_en. */
3311faca41fbSmlelstv 	run_rt3070_rf_read(sc, 50, &rf);
3312faca41fbSmlelstv 	run_rt3070_rf_write(sc, 50, rf & ~0x20);
3313faca41fbSmlelstv 	/* Set drv_cc. */
3314faca41fbSmlelstv 	run_rt3070_rf_read(sc, 57, &rf);
3315faca41fbSmlelstv 	rf &= ~0xfc;
3316faca41fbSmlelstv 	rf |= (chan <= 14) ?  0x6c : 0x3c;
3317faca41fbSmlelstv 	run_rt3070_rf_write(sc, 57, rf);
3318faca41fbSmlelstv 	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
3319faca41fbSmlelstv 	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
3320faca41fbSmlelstv 	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
3321faca41fbSmlelstv 	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
3322faca41fbSmlelstv 	/* Enable VCO calibration. */
3323faca41fbSmlelstv 	run_rt3070_rf_read(sc, 3, &rf);
3324faca41fbSmlelstv 	rf &= ~RT5390_VCOCAL;
3325faca41fbSmlelstv 	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
3326faca41fbSmlelstv 	run_rt3070_rf_write(sc, 3, rf);
3327faca41fbSmlelstv 
3328faca41fbSmlelstv 	if (chan <= 14)
3329faca41fbSmlelstv 		rf = 0x23;
3330faca41fbSmlelstv 	else if (chan <= 64)
3331faca41fbSmlelstv 		rf = 0x36;
3332faca41fbSmlelstv 	else if (chan <= 128)
3333faca41fbSmlelstv 		rf = 0x32;
3334faca41fbSmlelstv 	else
3335faca41fbSmlelstv 		rf = 0x30;
3336faca41fbSmlelstv 	run_rt3070_rf_write(sc, 39, rf);
3337faca41fbSmlelstv 	if (chan <= 14)
3338faca41fbSmlelstv 		rf = 0xbb;
3339faca41fbSmlelstv 	else if (chan <= 64)
3340faca41fbSmlelstv 		rf = 0xeb;
3341faca41fbSmlelstv 	else if (chan <= 128)
3342faca41fbSmlelstv 		rf = 0xb3;
3343faca41fbSmlelstv 	else
3344faca41fbSmlelstv 		rf = 0x9b;
3345faca41fbSmlelstv 	run_rt3070_rf_write(sc, 45, rf);
3346faca41fbSmlelstv 
3347faca41fbSmlelstv 	/* Set FEQ/AEQ control. */
3348faca41fbSmlelstv 	run_bbp_write(sc, 105, 0x34);
3349faca41fbSmlelstv }
3350faca41fbSmlelstv 
3351faca41fbSmlelstv static void
3352faca41fbSmlelstv run_rt5390_set_chan(struct run_softc *sc, u_int chan)
3353faca41fbSmlelstv {
3354faca41fbSmlelstv 	int8_t txpow1, txpow2;
3355faca41fbSmlelstv 	uint8_t rf;
3356faca41fbSmlelstv 	int i;
3357faca41fbSmlelstv 
3358faca41fbSmlelstv 	/* find the settings for this channel (we know it exists) */
3359faca41fbSmlelstv 	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
3360faca41fbSmlelstv 
3361faca41fbSmlelstv 	/* use Tx power values from EEPROM */
3362faca41fbSmlelstv 	txpow1 = sc->txpow1[i];
3363faca41fbSmlelstv 	txpow2 = sc->txpow2[i];
3364faca41fbSmlelstv 
3365faca41fbSmlelstv 	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
3366faca41fbSmlelstv 	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
3367faca41fbSmlelstv 	run_rt3070_rf_read(sc, 11, &rf);
3368faca41fbSmlelstv 	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
3369faca41fbSmlelstv 	run_rt3070_rf_write(sc, 11, rf);
3370faca41fbSmlelstv 
3371faca41fbSmlelstv 	run_rt3070_rf_read(sc, 49, &rf);
3372faca41fbSmlelstv 	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
3373faca41fbSmlelstv 	/* The valid range of the RF R49 is 0x00 to 0x27. */
3374faca41fbSmlelstv 	if ((rf & 0x3f) > 0x27)
3375faca41fbSmlelstv 		rf = (rf & ~0x3f) | 0x27;
3376faca41fbSmlelstv 	run_rt3070_rf_write(sc, 49, rf);
3377faca41fbSmlelstv 
3378faca41fbSmlelstv 	if (sc->mac_ver == 0x5392) {
3379faca41fbSmlelstv 		run_rt3070_rf_read(sc, 50, &rf);
3380faca41fbSmlelstv 		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
3381faca41fbSmlelstv 		/* The valid range of the RF R50 is 0x00 to 0x27. */
3382faca41fbSmlelstv 		if ((rf & 0x3f) > 0x27)
3383faca41fbSmlelstv 			rf = (rf & ~0x3f) | 0x27;
3384faca41fbSmlelstv 		run_rt3070_rf_write(sc, 50, rf);
3385faca41fbSmlelstv 	}
3386faca41fbSmlelstv 
3387faca41fbSmlelstv 	run_rt3070_rf_read(sc, 1, &rf);
3388faca41fbSmlelstv 	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
3389faca41fbSmlelstv 	if (sc->mac_ver == 0x5392)
3390faca41fbSmlelstv 		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
3391faca41fbSmlelstv 	run_rt3070_rf_write(sc, 1, rf);
3392faca41fbSmlelstv 
3393faca41fbSmlelstv 	if (sc->mac_ver != 0x5392) {
3394faca41fbSmlelstv 		run_rt3070_rf_read(sc, 2, &rf);
3395faca41fbSmlelstv 		rf |= 0x80;
3396faca41fbSmlelstv 		run_rt3070_rf_write(sc, 2, rf);
3397faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 10);
3398faca41fbSmlelstv 		rf &= 0x7f;
3399faca41fbSmlelstv 		run_rt3070_rf_write(sc, 2, rf);
3400faca41fbSmlelstv 	}
3401faca41fbSmlelstv 
3402faca41fbSmlelstv 	run_adjust_freq_offset(sc);
3403faca41fbSmlelstv 
3404faca41fbSmlelstv 	if (sc->mac_ver == 0x5392) {
3405faca41fbSmlelstv 		/* Fix for RT5392C. */
3406faca41fbSmlelstv 		if (sc->mac_rev >= 0x0223) {
3407faca41fbSmlelstv 			if (chan <= 4)
3408faca41fbSmlelstv 				rf = 0x0f;
3409faca41fbSmlelstv 			else if (chan >= 5 && chan <= 7)
3410faca41fbSmlelstv 				rf = 0x0e;
3411faca41fbSmlelstv 			else
3412faca41fbSmlelstv 				rf = 0x0d;
3413faca41fbSmlelstv 			run_rt3070_rf_write(sc, 23, rf);
3414faca41fbSmlelstv 
3415faca41fbSmlelstv 			if (chan <= 4)
3416faca41fbSmlelstv 				rf = 0x0c;
3417faca41fbSmlelstv 			else if (chan == 5)
3418faca41fbSmlelstv 				rf = 0x0b;
3419faca41fbSmlelstv 			else if (chan >= 6 && chan <= 7)
3420faca41fbSmlelstv 				rf = 0x0a;
3421faca41fbSmlelstv 			else if (chan >= 8 && chan <= 10)
3422faca41fbSmlelstv 				rf = 0x09;
3423faca41fbSmlelstv 			else
3424faca41fbSmlelstv 				rf = 0x08;
3425faca41fbSmlelstv 			run_rt3070_rf_write(sc, 59, rf);
3426faca41fbSmlelstv 		} else {
3427faca41fbSmlelstv 			if (chan <= 11)
3428faca41fbSmlelstv 				rf = 0x0f;
3429faca41fbSmlelstv 			else
3430faca41fbSmlelstv 				rf = 0x0b;
3431faca41fbSmlelstv 			run_rt3070_rf_write(sc, 59, rf);
3432faca41fbSmlelstv 		}
3433faca41fbSmlelstv 	} else {
3434faca41fbSmlelstv 		/* Fix for RT5390F. */
3435faca41fbSmlelstv 		if (sc->mac_rev >= 0x0502) {
3436faca41fbSmlelstv 			if (chan <= 11)
3437faca41fbSmlelstv 				rf = 0x43;
3438faca41fbSmlelstv 			else
3439faca41fbSmlelstv 				rf = 0x23;
3440faca41fbSmlelstv 			run_rt3070_rf_write(sc, 55, rf);
3441faca41fbSmlelstv 
3442faca41fbSmlelstv 			if (chan <= 11)
3443faca41fbSmlelstv 				rf = 0x0f;
3444faca41fbSmlelstv 			else if (chan == 12)
3445faca41fbSmlelstv 				rf = 0x0d;
3446faca41fbSmlelstv 			else
3447faca41fbSmlelstv 				rf = 0x0b;
3448faca41fbSmlelstv 			run_rt3070_rf_write(sc, 59, rf);
3449faca41fbSmlelstv 		} else {
3450faca41fbSmlelstv 			run_rt3070_rf_write(sc, 55, 0x44);
3451faca41fbSmlelstv 			run_rt3070_rf_write(sc, 59, 0x8f);
3452faca41fbSmlelstv 		}
3453faca41fbSmlelstv 	}
3454faca41fbSmlelstv 
3455faca41fbSmlelstv 	/* Enable VCO calibration. */
3456faca41fbSmlelstv 	run_rt3070_rf_read(sc, 3, &rf);
3457faca41fbSmlelstv 	rf |= RT5390_VCOCAL;
3458faca41fbSmlelstv 	run_rt3070_rf_write(sc, 3, rf);
3459faca41fbSmlelstv }
3460faca41fbSmlelstv 
3461faca41fbSmlelstv static void
3462faca41fbSmlelstv run_rt5592_set_chan(struct run_softc *sc, u_int chan)
3463faca41fbSmlelstv {
3464faca41fbSmlelstv 	const struct rt5592_freqs *freqs;
3465faca41fbSmlelstv 	uint32_t tmp;
3466faca41fbSmlelstv 	uint8_t reg, rf, txpow_bound;
3467faca41fbSmlelstv 	int8_t txpow1, txpow2;
3468faca41fbSmlelstv 	int i;
3469faca41fbSmlelstv 
3470faca41fbSmlelstv 	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
3471faca41fbSmlelstv 	freqs = (tmp & RT5592_SEL_XTAL) ?
3472faca41fbSmlelstv 	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
3473faca41fbSmlelstv 
3474faca41fbSmlelstv 	/* find the settings for this channel (we know it exists) */
3475faca41fbSmlelstv 	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
3476faca41fbSmlelstv 
3477faca41fbSmlelstv 	/* use Tx power values from EEPROM */
3478faca41fbSmlelstv 	txpow1 = sc->txpow1[i];
3479faca41fbSmlelstv 	txpow2 = sc->txpow2[i];
3480faca41fbSmlelstv 
3481faca41fbSmlelstv 	run_read(sc, RT3070_LDO_CFG0, &tmp);
3482faca41fbSmlelstv 	tmp &= ~0x1c000000;
3483faca41fbSmlelstv 	if (chan > 14)
3484faca41fbSmlelstv 		tmp |= 0x14000000;
3485faca41fbSmlelstv 	run_write(sc, RT3070_LDO_CFG0, tmp);
3486faca41fbSmlelstv 
3487faca41fbSmlelstv 	/* N setting. */
3488faca41fbSmlelstv 	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
3489faca41fbSmlelstv 	run_rt3070_rf_read(sc, 9, &rf);
3490faca41fbSmlelstv 	rf &= ~(1 << 4);
3491faca41fbSmlelstv 	rf |= ((freqs->n & 0x0100) >> 8) << 4;
3492faca41fbSmlelstv 	run_rt3070_rf_write(sc, 9, rf);
3493faca41fbSmlelstv 
3494faca41fbSmlelstv 	/* K setting. */
3495faca41fbSmlelstv 	run_rt3070_rf_read(sc, 9, &rf);
3496faca41fbSmlelstv 	rf &= ~0x0f;
3497faca41fbSmlelstv 	rf |= (freqs->k & 0x0f);
3498faca41fbSmlelstv 	run_rt3070_rf_write(sc, 9, rf);
3499faca41fbSmlelstv 
3500faca41fbSmlelstv 	/* Mode setting. */
3501faca41fbSmlelstv 	run_rt3070_rf_read(sc, 11, &rf);
3502faca41fbSmlelstv 	rf &= ~0x0c;
3503faca41fbSmlelstv 	rf |= ((freqs->m - 0x8) & 0x3) << 2;
3504faca41fbSmlelstv 	run_rt3070_rf_write(sc, 11, rf);
3505faca41fbSmlelstv 	run_rt3070_rf_read(sc, 9, &rf);
3506faca41fbSmlelstv 	rf &= ~(1 << 7);
3507faca41fbSmlelstv 	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
3508faca41fbSmlelstv 	run_rt3070_rf_write(sc, 9, rf);
3509faca41fbSmlelstv 
3510faca41fbSmlelstv 	/* R setting. */
3511faca41fbSmlelstv 	run_rt3070_rf_read(sc, 11, &rf);
3512faca41fbSmlelstv 	rf &= ~0x03;
3513faca41fbSmlelstv 	rf |= (freqs->r - 0x1);
3514faca41fbSmlelstv 	run_rt3070_rf_write(sc, 11, rf);
3515faca41fbSmlelstv 
3516faca41fbSmlelstv 	if (chan <= 14) {
3517faca41fbSmlelstv 		/* Initialize RF registers for 2GHZ. */
3518faca41fbSmlelstv 		for (i = 0; i < (int)__arraycount(rt5592_2ghz_def_rf); i++) {
3519faca41fbSmlelstv 			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
3520faca41fbSmlelstv 			    rt5592_2ghz_def_rf[i].val);
3521faca41fbSmlelstv 		}
3522faca41fbSmlelstv 
3523faca41fbSmlelstv 		rf = (chan <= 10) ? 0x07 : 0x06;
3524faca41fbSmlelstv 		run_rt3070_rf_write(sc, 23, rf);
3525faca41fbSmlelstv 		run_rt3070_rf_write(sc, 59, rf);
3526faca41fbSmlelstv 
3527faca41fbSmlelstv 		run_rt3070_rf_write(sc, 55, 0x43);
3528faca41fbSmlelstv 
3529faca41fbSmlelstv 		/*
3530faca41fbSmlelstv 		 * RF R49/R50 Tx power ALC code.
3531faca41fbSmlelstv 		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
3532faca41fbSmlelstv 		 */
3533faca41fbSmlelstv 		reg = 2;
3534faca41fbSmlelstv 		txpow_bound = 0x27;
3535faca41fbSmlelstv 	} else {
3536faca41fbSmlelstv 		/* Initialize RF registers for 5GHZ. */
3537faca41fbSmlelstv 		for (i = 0; i < (int)__arraycount(rt5592_5ghz_def_rf); i++) {
3538faca41fbSmlelstv 			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
3539faca41fbSmlelstv 			    rt5592_5ghz_def_rf[i].val);
3540faca41fbSmlelstv 		}
3541faca41fbSmlelstv 		for (i = 0; i < (int)__arraycount(rt5592_chan_5ghz); i++) {
3542faca41fbSmlelstv 			if (chan >= rt5592_chan_5ghz[i].firstchan &&
3543faca41fbSmlelstv 			    chan <= rt5592_chan_5ghz[i].lastchan) {
3544faca41fbSmlelstv 				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
3545faca41fbSmlelstv 				    rt5592_chan_5ghz[i].val);
3546faca41fbSmlelstv 			}
3547faca41fbSmlelstv 		}
3548faca41fbSmlelstv 
3549faca41fbSmlelstv 		/*
3550faca41fbSmlelstv 		 * RF R49/R50 Tx power ALC code.
3551faca41fbSmlelstv 		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
3552faca41fbSmlelstv 		 */
3553faca41fbSmlelstv 		reg = 3;
3554faca41fbSmlelstv 		txpow_bound = 0x2b;
3555faca41fbSmlelstv 	}
3556faca41fbSmlelstv 
3557faca41fbSmlelstv 	/* RF R49 ch0 Tx power ALC code. */
3558faca41fbSmlelstv 	run_rt3070_rf_read(sc, 49, &rf);
3559faca41fbSmlelstv 	rf &= ~0xc0;
3560faca41fbSmlelstv 	rf |= (reg << 6);
3561faca41fbSmlelstv 	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
3562faca41fbSmlelstv 	if ((rf & 0x3f) > txpow_bound)
3563faca41fbSmlelstv 		rf = (rf & ~0x3f) | txpow_bound;
3564faca41fbSmlelstv 	run_rt3070_rf_write(sc, 49, rf);
3565faca41fbSmlelstv 
3566faca41fbSmlelstv 	/* RF R50 ch1 Tx power ALC code. */
3567faca41fbSmlelstv 	run_rt3070_rf_read(sc, 50, &rf);
3568faca41fbSmlelstv 	rf &= ~(1 << 7 | 1 << 6);
3569faca41fbSmlelstv 	rf |= (reg << 6);
3570faca41fbSmlelstv 	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
3571faca41fbSmlelstv 	if ((rf & 0x3f) > txpow_bound)
3572faca41fbSmlelstv 		rf = (rf & ~0x3f) | txpow_bound;
3573faca41fbSmlelstv 	run_rt3070_rf_write(sc, 50, rf);
3574faca41fbSmlelstv 
3575faca41fbSmlelstv 	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
3576faca41fbSmlelstv 	run_rt3070_rf_read(sc, 1, &rf);
3577faca41fbSmlelstv 	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
3578faca41fbSmlelstv 	if (sc->ntxchains > 1)
3579faca41fbSmlelstv 		rf |= RT3070_TX1_PD;
3580faca41fbSmlelstv 	if (sc->nrxchains > 1)
3581faca41fbSmlelstv 		rf |= RT3070_RX1_PD;
3582faca41fbSmlelstv 	run_rt3070_rf_write(sc, 1, rf);
3583faca41fbSmlelstv 
3584faca41fbSmlelstv 	run_rt3070_rf_write(sc, 6, 0xe4);
3585faca41fbSmlelstv 
3586faca41fbSmlelstv 	run_rt3070_rf_write(sc, 30, 0x10);
3587faca41fbSmlelstv 	run_rt3070_rf_write(sc, 31, 0x80);
3588faca41fbSmlelstv 	run_rt3070_rf_write(sc, 32, 0x80);
3589faca41fbSmlelstv 
3590faca41fbSmlelstv 	run_adjust_freq_offset(sc);
3591faca41fbSmlelstv 
3592faca41fbSmlelstv 	/* Enable VCO calibration. */
3593faca41fbSmlelstv 	run_rt3070_rf_read(sc, 3, &rf);
3594faca41fbSmlelstv 	rf |= RT5390_VCOCAL;
3595faca41fbSmlelstv 	run_rt3070_rf_write(sc, 3, rf);
3596faca41fbSmlelstv }
3597faca41fbSmlelstv 
3598faca41fbSmlelstv static void
3599faca41fbSmlelstv run_iq_calib(struct run_softc *sc, u_int chan)
3600faca41fbSmlelstv {
3601faca41fbSmlelstv 	uint16_t val;
3602faca41fbSmlelstv 
3603faca41fbSmlelstv 	/* Tx0 IQ gain. */
3604faca41fbSmlelstv 	run_bbp_write(sc, 158, 0x2c);
3605faca41fbSmlelstv 	if (chan <= 14)
3606faca41fbSmlelstv 		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3607faca41fbSmlelstv 	else if (chan <= 64) {
3608faca41fbSmlelstv 		run_efuse_read(sc,
3609faca41fbSmlelstv 		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3610faca41fbSmlelstv 		    &val, 1);
3611faca41fbSmlelstv 	} else if (chan <= 138) {
3612faca41fbSmlelstv 		run_efuse_read(sc,
3613faca41fbSmlelstv 		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3614faca41fbSmlelstv 		    &val, 1);
3615faca41fbSmlelstv 	} else if (chan <= 165) {
3616faca41fbSmlelstv 		run_efuse_read(sc,
3617faca41fbSmlelstv 	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3618faca41fbSmlelstv 		    &val, 1);
3619faca41fbSmlelstv 	} else
3620faca41fbSmlelstv 		val = 0;
3621faca41fbSmlelstv 	run_bbp_write(sc, 159, val);
3622faca41fbSmlelstv 
3623faca41fbSmlelstv 	/* Tx0 IQ phase. */
3624faca41fbSmlelstv 	run_bbp_write(sc, 158, 0x2d);
3625faca41fbSmlelstv 	if (chan <= 14) {
3626faca41fbSmlelstv 		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3627faca41fbSmlelstv 		    &val, 1);
3628faca41fbSmlelstv 	} else if (chan <= 64) {
3629faca41fbSmlelstv 		run_efuse_read(sc,
3630faca41fbSmlelstv 		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3631faca41fbSmlelstv 		    &val, 1);
3632faca41fbSmlelstv 	} else if (chan <= 138) {
3633faca41fbSmlelstv 		run_efuse_read(sc,
3634faca41fbSmlelstv 		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3635faca41fbSmlelstv 		    &val, 1);
3636faca41fbSmlelstv 	} else if (chan <= 165) {
3637faca41fbSmlelstv 		run_efuse_read(sc,
3638faca41fbSmlelstv 		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3639faca41fbSmlelstv 		    &val, 1);
3640faca41fbSmlelstv 	} else
3641faca41fbSmlelstv 		val = 0;
3642faca41fbSmlelstv 	run_bbp_write(sc, 159, val);
3643faca41fbSmlelstv 
3644faca41fbSmlelstv 	/* Tx1 IQ gain. */
3645faca41fbSmlelstv 	run_bbp_write(sc, 158, 0x4a);
3646faca41fbSmlelstv 	if (chan <= 14) {
3647faca41fbSmlelstv 		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3648faca41fbSmlelstv 		    &val, 1);
3649faca41fbSmlelstv 	} else if (chan <= 64) {
3650faca41fbSmlelstv 		run_efuse_read(sc,
3651faca41fbSmlelstv 		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3652faca41fbSmlelstv 		    &val, 1);
3653faca41fbSmlelstv 	} else if (chan <= 138) {
3654faca41fbSmlelstv 		run_efuse_read(sc,
3655faca41fbSmlelstv 		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3656faca41fbSmlelstv 		    &val, 1);
3657faca41fbSmlelstv 	} else if (chan <= 165) {
3658faca41fbSmlelstv 		run_efuse_read(sc,
3659faca41fbSmlelstv 		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3660faca41fbSmlelstv 		    &val, 1);
3661faca41fbSmlelstv 	} else
3662faca41fbSmlelstv 		val = 0;
3663faca41fbSmlelstv 	run_bbp_write(sc, 159, val);
3664faca41fbSmlelstv 
3665faca41fbSmlelstv 	/* Tx1 IQ phase. */
3666faca41fbSmlelstv 	run_bbp_write(sc, 158, 0x4b);
3667faca41fbSmlelstv 	if (chan <= 14) {
3668faca41fbSmlelstv 		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3669faca41fbSmlelstv 		    &val, 1);
3670faca41fbSmlelstv 	} else if (chan <= 64) {
3671faca41fbSmlelstv 		run_efuse_read(sc,
3672faca41fbSmlelstv 		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3673faca41fbSmlelstv 		    &val, 1);
3674faca41fbSmlelstv 	} else if (chan <= 138) {
3675faca41fbSmlelstv 		run_efuse_read(sc,
3676faca41fbSmlelstv 		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3677faca41fbSmlelstv 		    &val, 1);
3678faca41fbSmlelstv 	} else if (chan <= 165) {
3679faca41fbSmlelstv 		run_efuse_read(sc,
3680faca41fbSmlelstv 		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3681faca41fbSmlelstv 		    &val, 1);
3682faca41fbSmlelstv 	} else
3683faca41fbSmlelstv 		val = 0;
3684faca41fbSmlelstv 	run_bbp_write(sc, 159, val);
3685faca41fbSmlelstv 
3686faca41fbSmlelstv 	/* RF IQ compensation control. */
3687faca41fbSmlelstv 	run_bbp_write(sc, 158, 0x04);
3688faca41fbSmlelstv 	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3689faca41fbSmlelstv 	    &val, 1);
3690faca41fbSmlelstv 	run_bbp_write(sc, 159, val);
3691faca41fbSmlelstv 
3692faca41fbSmlelstv 	/* RF IQ imbalance compensation control. */
3693faca41fbSmlelstv 	run_bbp_write(sc, 158, 0x03);
3694faca41fbSmlelstv 	run_efuse_read(sc,
3695faca41fbSmlelstv 	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3696faca41fbSmlelstv 	run_bbp_write(sc, 159, val);
36979cdb1c70Snonaka }
36989cdb1c70Snonaka 
36999cdb1c70Snonaka static void
37009cdb1c70Snonaka run_set_agc(struct run_softc *sc, uint8_t agc)
37019cdb1c70Snonaka {
37029cdb1c70Snonaka 	uint8_t bbp;
37039cdb1c70Snonaka 
37049cdb1c70Snonaka 	if (sc->mac_ver == 0x3572) {
37059cdb1c70Snonaka 		run_bbp_read(sc, 27, &bbp);
37069cdb1c70Snonaka 		bbp &= ~(0x3 << 5);
37079cdb1c70Snonaka 		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
37089cdb1c70Snonaka 		run_bbp_write(sc, 66, agc);
37099cdb1c70Snonaka 		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
37109cdb1c70Snonaka 		run_bbp_write(sc, 66, agc);
37119cdb1c70Snonaka 	} else
37129cdb1c70Snonaka 		run_bbp_write(sc, 66, agc);
37139cdb1c70Snonaka }
37149cdb1c70Snonaka 
37159cdb1c70Snonaka static void
37169cdb1c70Snonaka run_set_rx_antenna(struct run_softc *sc, int aux)
37179cdb1c70Snonaka {
37189cdb1c70Snonaka 	uint32_t tmp;
3719faca41fbSmlelstv 	uint8_t bbp152;
37209cdb1c70Snonaka 
3721d164e220Smlelstv 	if (aux) {
3722faca41fbSmlelstv 		if (sc->rf_rev == RT5390_RF_5370) {
3723faca41fbSmlelstv 			run_bbp_read(sc, 152, &bbp152);
3724faca41fbSmlelstv 			bbp152 &= ~0x80;
3725d164e220Smlelstv 			run_bbp_write(sc, 152, bbp152);
3726d164e220Smlelstv 		} else {
3727d164e220Smlelstv 			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
3728d164e220Smlelstv 			run_read(sc, RT2860_GPIO_CTRL, &tmp);
3729d164e220Smlelstv 			tmp &= ~0x0808;
3730d164e220Smlelstv 			tmp |= 0x08;
3731d164e220Smlelstv 			run_write(sc, RT2860_GPIO_CTRL, tmp);
3732d164e220Smlelstv 		}
3733d164e220Smlelstv 	} else {
3734d164e220Smlelstv 		if (sc->rf_rev == RT5390_RF_5370) {
3735d164e220Smlelstv 			run_bbp_read(sc, 152, &bbp152);
3736faca41fbSmlelstv 			bbp152 |= 0x80;
3737faca41fbSmlelstv 			run_bbp_write(sc, 152, bbp152);
3738faca41fbSmlelstv 		} else {
37399cdb1c70Snonaka 			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, !aux);
37409cdb1c70Snonaka 			run_read(sc, RT2860_GPIO_CTRL, &tmp);
37419cdb1c70Snonaka 			tmp &= ~0x0808;
37429cdb1c70Snonaka 			run_write(sc, RT2860_GPIO_CTRL, tmp);
37439cdb1c70Snonaka 		}
3744faca41fbSmlelstv 	}
3745d164e220Smlelstv }
37469cdb1c70Snonaka 
37479cdb1c70Snonaka static int
37489cdb1c70Snonaka run_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
37499cdb1c70Snonaka {
37509cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
37519cdb1c70Snonaka 	u_int chan, group;
37529cdb1c70Snonaka 
37539cdb1c70Snonaka 	chan = ieee80211_chan2ieee(ic, c);
37549cdb1c70Snonaka 	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
37554e8e6643Sskrll 		return EINVAL;
37569cdb1c70Snonaka 
3757faca41fbSmlelstv 	if (sc->mac_ver == 0x5592)
3758faca41fbSmlelstv 		run_rt5592_set_chan(sc, chan);
3759faca41fbSmlelstv 	else if (sc->mac_ver >= 0x5390)
3760faca41fbSmlelstv 		run_rt5390_set_chan(sc, chan);
3761faca41fbSmlelstv 	else if (sc->mac_ver == 0x3593)
3762faca41fbSmlelstv 		run_rt3593_set_chan(sc, chan);
3763faca41fbSmlelstv 	else if (sc->mac_ver == 0x3572)
37649cdb1c70Snonaka 		run_rt3572_set_chan(sc, chan);
37659cdb1c70Snonaka 	else if (sc->mac_ver >= 0x3070)
37669cdb1c70Snonaka 		run_rt3070_set_chan(sc, chan);
37679cdb1c70Snonaka 	else
37689cdb1c70Snonaka 		run_rt2870_set_chan(sc, chan);
37699cdb1c70Snonaka 
37709cdb1c70Snonaka 	/* determine channel group */
37719cdb1c70Snonaka 	if (chan <= 14)
37729cdb1c70Snonaka 		group = 0;
37739cdb1c70Snonaka 	else if (chan <= 64)
37749cdb1c70Snonaka 		group = 1;
37759cdb1c70Snonaka 	else if (chan <= 128)
37769cdb1c70Snonaka 		group = 2;
37779cdb1c70Snonaka 	else
37789cdb1c70Snonaka 		group = 3;
37799cdb1c70Snonaka 
37809cdb1c70Snonaka 	/* XXX necessary only when group has changed! */
37819cdb1c70Snonaka 	run_select_chan_group(sc, group);
37829cdb1c70Snonaka 
3783faca41fbSmlelstv 	usbd_delay_ms(sc->sc_udev, 10);
3784faca41fbSmlelstv 
3785faca41fbSmlelstv 	/* Perform IQ calibration. */
3786faca41fbSmlelstv 	if (sc->mac_ver >= 0x5392)
3787faca41fbSmlelstv 		run_iq_calib(sc, chan);
3788faca41fbSmlelstv 
37894e8e6643Sskrll 	return 0;
37909cdb1c70Snonaka }
37919cdb1c70Snonaka 
37929cdb1c70Snonaka static void
3793faca41fbSmlelstv run_updateprot(struct run_softc *sc)
3794faca41fbSmlelstv {
3795faca41fbSmlelstv 	struct ieee80211com *ic = &sc->sc_ic;
3796faca41fbSmlelstv 	uint32_t tmp;
3797faca41fbSmlelstv 
3798faca41fbSmlelstv 	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
3799faca41fbSmlelstv 	/* setup protection frame rate (MCS code) */
3800faca41fbSmlelstv 	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
3801faca41fbSmlelstv 	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
3802faca41fbSmlelstv 	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
3803faca41fbSmlelstv 
3804faca41fbSmlelstv 	/* CCK frames don't require protection */
3805faca41fbSmlelstv 	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
3806faca41fbSmlelstv 	if (ic->ic_flags & IEEE80211_F_USEPROT) {
3807faca41fbSmlelstv 		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
3808faca41fbSmlelstv 			tmp |= RT2860_PROT_CTRL_RTS_CTS;
3809faca41fbSmlelstv 		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
3810faca41fbSmlelstv 			tmp |= RT2860_PROT_CTRL_CTS;
3811faca41fbSmlelstv 	}
3812faca41fbSmlelstv 	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
3813faca41fbSmlelstv }
3814faca41fbSmlelstv 
3815faca41fbSmlelstv static void
38169cdb1c70Snonaka run_enable_tsf_sync(struct run_softc *sc)
38179cdb1c70Snonaka {
38189cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
38199cdb1c70Snonaka 	uint32_t tmp;
38209cdb1c70Snonaka 
38219cdb1c70Snonaka 	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
38229cdb1c70Snonaka 	tmp &= ~0x1fffff;
38239cdb1c70Snonaka 	tmp |= ic->ic_bss->ni_intval * 16;
38249cdb1c70Snonaka 	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
38259cdb1c70Snonaka 	if (ic->ic_opmode == IEEE80211_M_STA) {
38269cdb1c70Snonaka 		/*
38279cdb1c70Snonaka 		 * Local TSF is always updated with remote TSF on beacon
38289cdb1c70Snonaka 		 * reception.
38299cdb1c70Snonaka 		 */
38309cdb1c70Snonaka 		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
38319cdb1c70Snonaka 	}
38329cdb1c70Snonaka #ifndef IEEE80211_STA_ONLY
38339cdb1c70Snonaka 	else if (ic->ic_opmode == IEEE80211_M_IBSS) {
38349cdb1c70Snonaka 		tmp |= RT2860_BCN_TX_EN;
38359cdb1c70Snonaka 		/*
38369cdb1c70Snonaka 		 * Local TSF is updated with remote TSF on beacon reception
38379cdb1c70Snonaka 		 * only if the remote TSF is greater than local TSF.
38389cdb1c70Snonaka 		 */
38399cdb1c70Snonaka 		tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
38409cdb1c70Snonaka 	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
38419cdb1c70Snonaka 		tmp |= RT2860_BCN_TX_EN;
38429cdb1c70Snonaka 		/* SYNC with nobody */
38439cdb1c70Snonaka 		tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
38449cdb1c70Snonaka 	}
38459cdb1c70Snonaka #endif
38469cdb1c70Snonaka 	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
38479cdb1c70Snonaka }
38489cdb1c70Snonaka 
38499cdb1c70Snonaka static void
38509cdb1c70Snonaka run_enable_mrr(struct run_softc *sc)
38519cdb1c70Snonaka {
38529cdb1c70Snonaka #define CCK(mcs)	(mcs)
38539cdb1c70Snonaka #define OFDM(mcs)	(1 << 3 | (mcs))
38549cdb1c70Snonaka 	run_write(sc, RT2860_LG_FBK_CFG0,
38559cdb1c70Snonaka 	    OFDM(6) << 28 |	/* 54->48 */
38569cdb1c70Snonaka 	    OFDM(5) << 24 |	/* 48->36 */
38579cdb1c70Snonaka 	    OFDM(4) << 20 |	/* 36->24 */
38589cdb1c70Snonaka 	    OFDM(3) << 16 |	/* 24->18 */
38599cdb1c70Snonaka 	    OFDM(2) << 12 |	/* 18->12 */
38609cdb1c70Snonaka 	    OFDM(1) <<  8 |	/* 12-> 9 */
38619cdb1c70Snonaka 	    OFDM(0) <<  4 |	/*  9-> 6 */
38629cdb1c70Snonaka 	    OFDM(0));		/*  6-> 6 */
38639cdb1c70Snonaka 
38649cdb1c70Snonaka 	run_write(sc, RT2860_LG_FBK_CFG1,
38659cdb1c70Snonaka 	    CCK(2) << 12 |	/* 11->5.5 */
38669cdb1c70Snonaka 	    CCK(1) <<  8 |	/* 5.5-> 2 */
38679cdb1c70Snonaka 	    CCK(0) <<  4 |	/*   2-> 1 */
38689cdb1c70Snonaka 	    CCK(0));		/*   1-> 1 */
38699cdb1c70Snonaka #undef OFDM
38709cdb1c70Snonaka #undef CCK
38719cdb1c70Snonaka }
38729cdb1c70Snonaka 
38739cdb1c70Snonaka static void
38749cdb1c70Snonaka run_set_txpreamble(struct run_softc *sc)
38759cdb1c70Snonaka {
38769cdb1c70Snonaka 	uint32_t tmp;
38779cdb1c70Snonaka 
38789cdb1c70Snonaka 	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
38799cdb1c70Snonaka 	if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE)
38809cdb1c70Snonaka 		tmp |= RT2860_CCK_SHORT_EN;
38819cdb1c70Snonaka 	else
38829cdb1c70Snonaka 		tmp &= ~RT2860_CCK_SHORT_EN;
38839cdb1c70Snonaka 	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
38849cdb1c70Snonaka }
38859cdb1c70Snonaka 
38869cdb1c70Snonaka static void
38879cdb1c70Snonaka run_set_basicrates(struct run_softc *sc)
38889cdb1c70Snonaka {
38899cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
38909cdb1c70Snonaka 
38919cdb1c70Snonaka 	/* set basic rates mask */
38929cdb1c70Snonaka 	if (ic->ic_curmode == IEEE80211_MODE_11B)
38939cdb1c70Snonaka 		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
38949cdb1c70Snonaka 	else if (ic->ic_curmode == IEEE80211_MODE_11A)
38959cdb1c70Snonaka 		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
38969cdb1c70Snonaka 	else	/* 11g */
38979cdb1c70Snonaka 		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
38989cdb1c70Snonaka }
38999cdb1c70Snonaka 
39009cdb1c70Snonaka static void
39019cdb1c70Snonaka run_set_leds(struct run_softc *sc, uint16_t which)
39029cdb1c70Snonaka {
39039cdb1c70Snonaka 
39049cdb1c70Snonaka 	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
39059cdb1c70Snonaka 	    which | (sc->leds & 0x7f));
39069cdb1c70Snonaka }
39079cdb1c70Snonaka 
39089cdb1c70Snonaka static void
39099cdb1c70Snonaka run_set_bssid(struct run_softc *sc, const uint8_t *bssid)
39109cdb1c70Snonaka {
39119cdb1c70Snonaka 
39129cdb1c70Snonaka 	run_write(sc, RT2860_MAC_BSSID_DW0,
39139cdb1c70Snonaka 	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
39149cdb1c70Snonaka 	run_write(sc, RT2860_MAC_BSSID_DW1,
39159cdb1c70Snonaka 	    bssid[4] | bssid[5] << 8);
39169cdb1c70Snonaka }
39179cdb1c70Snonaka 
39189cdb1c70Snonaka static void
39199cdb1c70Snonaka run_set_macaddr(struct run_softc *sc, const uint8_t *addr)
39209cdb1c70Snonaka {
39219cdb1c70Snonaka 
39229cdb1c70Snonaka 	run_write(sc, RT2860_MAC_ADDR_DW0,
39239cdb1c70Snonaka 	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
39249cdb1c70Snonaka 	run_write(sc, RT2860_MAC_ADDR_DW1,
39259cdb1c70Snonaka 	    addr[4] | addr[5] << 8 | 0xff << 16);
39269cdb1c70Snonaka }
39279cdb1c70Snonaka 
39289cdb1c70Snonaka static void
39299cdb1c70Snonaka run_updateslot(struct ifnet *ifp)
39309cdb1c70Snonaka {
39319cdb1c70Snonaka 
39329cdb1c70Snonaka 	/* do it in a process context */
39339cdb1c70Snonaka 	run_do_async(ifp->if_softc, run_updateslot_cb, NULL, 0);
39349cdb1c70Snonaka }
39359cdb1c70Snonaka 
39369cdb1c70Snonaka /* ARGSUSED */
39379cdb1c70Snonaka static void
39389cdb1c70Snonaka run_updateslot_cb(struct run_softc *sc, void *arg)
39399cdb1c70Snonaka {
39409cdb1c70Snonaka 	uint32_t tmp;
39419cdb1c70Snonaka 
39429cdb1c70Snonaka 	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
39439cdb1c70Snonaka 	tmp &= ~0xff;
39449cdb1c70Snonaka 	tmp |= (sc->sc_ic.ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
39459cdb1c70Snonaka 	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
39469cdb1c70Snonaka }
39479cdb1c70Snonaka 
39489cdb1c70Snonaka static int8_t
39499cdb1c70Snonaka run_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
39509cdb1c70Snonaka {
39519cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
39529cdb1c70Snonaka 	struct ieee80211_channel *c = ic->ic_curchan;
39539cdb1c70Snonaka 	int delta;
39549cdb1c70Snonaka 
39559cdb1c70Snonaka 	if (IEEE80211_IS_CHAN_5GHZ(c)) {
39569cdb1c70Snonaka 		u_int chan = ieee80211_chan2ieee(ic, c);
39579cdb1c70Snonaka 		delta = sc->rssi_5ghz[rxchain];
39589cdb1c70Snonaka 
39599cdb1c70Snonaka 		/* determine channel group */
39609cdb1c70Snonaka 		if (chan <= 64)
39619cdb1c70Snonaka 			delta -= sc->lna[1];
39629cdb1c70Snonaka 		else if (chan <= 128)
39639cdb1c70Snonaka 			delta -= sc->lna[2];
39649cdb1c70Snonaka 		else
39659cdb1c70Snonaka 			delta -= sc->lna[3];
39669cdb1c70Snonaka 	} else
39679cdb1c70Snonaka 		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
39689cdb1c70Snonaka 
39694e8e6643Sskrll 	return -12 - delta - rssi;
39709cdb1c70Snonaka }
39719cdb1c70Snonaka 
3972faca41fbSmlelstv static void
3973faca41fbSmlelstv run_rt5390_bbp_init(struct run_softc *sc)
3974faca41fbSmlelstv {
3975faca41fbSmlelstv 	u_int i;
3976faca41fbSmlelstv 	uint8_t bbp;
3977faca41fbSmlelstv 
3978faca41fbSmlelstv 	/* Apply maximum likelihood detection for 2 stream case. */
3979faca41fbSmlelstv 	run_bbp_read(sc, 105, &bbp);
3980faca41fbSmlelstv 	if (sc->nrxchains > 1)
3981faca41fbSmlelstv 		run_bbp_write(sc, 105, bbp | RT5390_MLD);
3982faca41fbSmlelstv 
3983faca41fbSmlelstv 	/* Avoid data lost and CRC error. */
3984faca41fbSmlelstv 	run_bbp_read(sc, 4, &bbp);
3985faca41fbSmlelstv 	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
3986faca41fbSmlelstv 
3987faca41fbSmlelstv 	if (sc->mac_ver == 0x5592) {
3988faca41fbSmlelstv 		for (i = 0; i < (int)__arraycount(rt5592_def_bbp); i++) {
3989faca41fbSmlelstv 			run_bbp_write(sc, rt5592_def_bbp[i].reg,
3990faca41fbSmlelstv 			    rt5592_def_bbp[i].val);
3991faca41fbSmlelstv 		}
3992faca41fbSmlelstv 		for (i = 0; i < (int)__arraycount(rt5592_bbp_r196); i++) {
3993faca41fbSmlelstv 			run_bbp_write(sc, 195, i + 0x80);
3994faca41fbSmlelstv 			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
3995faca41fbSmlelstv 		}
3996faca41fbSmlelstv 	} else {
3997faca41fbSmlelstv 		for (i = 0; i < (int)__arraycount(rt5390_def_bbp); i++) {
3998faca41fbSmlelstv 			run_bbp_write(sc, rt5390_def_bbp[i].reg,
3999faca41fbSmlelstv 			    rt5390_def_bbp[i].val);
4000faca41fbSmlelstv 		}
4001faca41fbSmlelstv 	}
4002faca41fbSmlelstv 	if (sc->mac_ver == 0x5392) {
4003faca41fbSmlelstv 		run_bbp_write(sc, 88, 0x90);
4004faca41fbSmlelstv 		run_bbp_write(sc, 95, 0x9a);
4005faca41fbSmlelstv 		run_bbp_write(sc, 98, 0x12);
4006faca41fbSmlelstv 		run_bbp_write(sc, 106, 0x12);
4007faca41fbSmlelstv 		run_bbp_write(sc, 134, 0xd0);
4008faca41fbSmlelstv 		run_bbp_write(sc, 135, 0xf6);
4009faca41fbSmlelstv 		run_bbp_write(sc, 148, 0x84);
4010faca41fbSmlelstv 	}
4011faca41fbSmlelstv 
4012faca41fbSmlelstv 	run_bbp_read(sc, 152, &bbp);
4013faca41fbSmlelstv 	run_bbp_write(sc, 152, bbp | 0x80);
4014faca41fbSmlelstv 
4015faca41fbSmlelstv 	/* Fix BBP254 for RT5592C. */
4016faca41fbSmlelstv 	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
4017faca41fbSmlelstv 		run_bbp_read(sc, 254, &bbp);
4018faca41fbSmlelstv 		run_bbp_write(sc, 254, bbp | 0x80);
4019faca41fbSmlelstv 	}
4020faca41fbSmlelstv 
4021faca41fbSmlelstv 	/* Disable hardware antenna diversity. */
4022faca41fbSmlelstv 	if (sc->mac_ver == 0x5390)
4023faca41fbSmlelstv 		run_bbp_write(sc, 154, 0);
4024faca41fbSmlelstv 
4025faca41fbSmlelstv 	/* Initialize Rx CCK/OFDM frequency offset report. */
4026faca41fbSmlelstv 	run_bbp_write(sc, 142, 1);
4027faca41fbSmlelstv 	run_bbp_write(sc, 143, 57);
4028faca41fbSmlelstv }
4029faca41fbSmlelstv 
40309cdb1c70Snonaka static int
40319cdb1c70Snonaka run_bbp_init(struct run_softc *sc)
40329cdb1c70Snonaka {
40339cdb1c70Snonaka 	int i, error, ntries;
40349cdb1c70Snonaka 	uint8_t bbp0;
40359cdb1c70Snonaka 
40369cdb1c70Snonaka 	/* wait for BBP to wake up */
40379cdb1c70Snonaka 	for (ntries = 0; ntries < 20; ntries++) {
40389cdb1c70Snonaka 		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
40394e8e6643Sskrll 			return error;
40409cdb1c70Snonaka 		if (bbp0 != 0 && bbp0 != 0xff)
40419cdb1c70Snonaka 			break;
40429cdb1c70Snonaka 	}
40439cdb1c70Snonaka 	if (ntries == 20)
40444e8e6643Sskrll 		return ETIMEDOUT;
40459cdb1c70Snonaka 
40469cdb1c70Snonaka 	/* initialize BBP registers to default values */
4047faca41fbSmlelstv 	if (sc->mac_ver >= 0x5390)
4048faca41fbSmlelstv 		run_rt5390_bbp_init(sc);
4049faca41fbSmlelstv 	else {
40509cdb1c70Snonaka 		for (i = 0; i < (int)__arraycount(rt2860_def_bbp); i++) {
40519cdb1c70Snonaka 			run_bbp_write(sc, rt2860_def_bbp[i].reg,
40529cdb1c70Snonaka 			    rt2860_def_bbp[i].val);
40539cdb1c70Snonaka 		}
4054faca41fbSmlelstv 	}
4055faca41fbSmlelstv 
4056faca41fbSmlelstv 	if (sc->mac_ver == 0x3593) {
4057faca41fbSmlelstv 		run_bbp_write(sc, 79, 0x13);
4058faca41fbSmlelstv 		run_bbp_write(sc, 80, 0x05);
4059faca41fbSmlelstv 		run_bbp_write(sc, 81, 0x33);
4060faca41fbSmlelstv 		run_bbp_write(sc, 86, 0x46);
4061faca41fbSmlelstv 		run_bbp_write(sc, 137, 0x0f);
4062faca41fbSmlelstv 	}
40639cdb1c70Snonaka 
40649cdb1c70Snonaka 	/* fix BBP84 for RT2860E */
40659cdb1c70Snonaka 	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
40669cdb1c70Snonaka 		run_bbp_write(sc, 84, 0x19);
40679cdb1c70Snonaka 
4068d164e220Smlelstv 	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
4069d164e220Smlelstv 	    sc->mac_ver != 0x5592)) {
40709cdb1c70Snonaka 		run_bbp_write(sc, 79, 0x13);
40719cdb1c70Snonaka 		run_bbp_write(sc, 80, 0x05);
40729cdb1c70Snonaka 		run_bbp_write(sc, 81, 0x33);
40739cdb1c70Snonaka 	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
40749cdb1c70Snonaka 		run_bbp_write(sc, 69, 0x16);
40759cdb1c70Snonaka 		run_bbp_write(sc, 73, 0x12);
40769cdb1c70Snonaka 	}
40774e8e6643Sskrll 	return 0;
40789cdb1c70Snonaka }
40799cdb1c70Snonaka 
40809cdb1c70Snonaka static int
40819cdb1c70Snonaka run_rt3070_rf_init(struct run_softc *sc)
40829cdb1c70Snonaka {
40839cdb1c70Snonaka 	uint32_t tmp;
40849cdb1c70Snonaka 	uint8_t rf, target, bbp4;
40859cdb1c70Snonaka 	int i;
40869cdb1c70Snonaka 
40879cdb1c70Snonaka 	run_rt3070_rf_read(sc, 30, &rf);
40889cdb1c70Snonaka 	/* toggle RF R30 bit 7 */
40899cdb1c70Snonaka 	run_rt3070_rf_write(sc, 30, rf | 0x80);
4090faca41fbSmlelstv 	usbd_delay_ms(sc->sc_udev, 10);
40919cdb1c70Snonaka 	run_rt3070_rf_write(sc, 30, rf & ~0x80);
40929cdb1c70Snonaka 
40939cdb1c70Snonaka 	/* initialize RF registers to default value */
40949cdb1c70Snonaka 	if (sc->mac_ver == 0x3572) {
40959cdb1c70Snonaka 		for (i = 0; i < (int)__arraycount(rt3572_def_rf); i++) {
40969cdb1c70Snonaka 			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
40979cdb1c70Snonaka 			    rt3572_def_rf[i].val);
40989cdb1c70Snonaka 		}
40999cdb1c70Snonaka 	} else {
41009cdb1c70Snonaka 		for (i = 0; i < (int)__arraycount(rt3070_def_rf); i++) {
41019cdb1c70Snonaka 			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
41029cdb1c70Snonaka 			    rt3070_def_rf[i].val);
41039cdb1c70Snonaka 		}
41049cdb1c70Snonaka 	}
41059cdb1c70Snonaka 	if (sc->mac_ver == 0x3572) {
41069cdb1c70Snonaka 		run_rt3070_rf_read(sc, 6, &rf);
41079cdb1c70Snonaka 		run_rt3070_rf_write(sc, 6, rf | 0x40);
4108faca41fbSmlelstv 		run_rt3070_rf_write(sc, 31, 0x14);
41099cdb1c70Snonaka 
41109cdb1c70Snonaka 		run_read(sc, RT3070_LDO_CFG0, &tmp);
4111faca41fbSmlelstv 		tmp &= ~0x1f000000;
4112faca41fbSmlelstv 		if (sc->mac_rev < 0x0211 && sc->patch_dac)
4113faca41fbSmlelstv 			tmp |= 0x0d000000;	/* 1.3V */
4114faca41fbSmlelstv 		else
4115faca41fbSmlelstv 			tmp |= 0x01000000;	/* 1.2V */
41169cdb1c70Snonaka 		run_write(sc, RT3070_LDO_CFG0, tmp);
41179cdb1c70Snonaka 	} else if (sc->mac_ver == 0x3071) {
41189cdb1c70Snonaka 		run_rt3070_rf_read(sc, 6, &rf);
41199cdb1c70Snonaka 		run_rt3070_rf_write(sc, 6, rf | 0x40);
41209cdb1c70Snonaka 		run_rt3070_rf_write(sc, 31, 0x14);
41219cdb1c70Snonaka 
41229cdb1c70Snonaka 		run_read(sc, RT3070_LDO_CFG0, &tmp);
41239cdb1c70Snonaka 		tmp &= ~0x1f000000;
41249cdb1c70Snonaka 		if (sc->mac_rev < 0x0211)
41259cdb1c70Snonaka 			tmp |= 0x0d000000;	/* 1.35V */
41269cdb1c70Snonaka 		else
41279cdb1c70Snonaka 			tmp |= 0x01000000;	/* 1.2V */
41289cdb1c70Snonaka 		run_write(sc, RT3070_LDO_CFG0, tmp);
41299cdb1c70Snonaka 
41309cdb1c70Snonaka 		/* patch LNA_PE_G1 */
41319cdb1c70Snonaka 		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
41329cdb1c70Snonaka 		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
4133d164e220Smlelstv 	} else if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
4134d164e220Smlelstv 		/*
4135d164e220Smlelstv 		 * Change voltage from 1.2V to 1.35V for RT3070.
4136d164e220Smlelstv 		 * The DAC issue (RT3070_LD0_CFG0) has been fixed
4137d164e220Smlelstv 		 * in RT3070(F).
4138d164e220Smlelstv 		 */
41399cdb1c70Snonaka 		run_read(sc, RT3070_LDO_CFG0, &tmp);
41409cdb1c70Snonaka 		tmp = (tmp & ~0x0f000000) | 0x0d000000;
41419cdb1c70Snonaka 		run_write(sc, RT3070_LDO_CFG0, tmp);
41429cdb1c70Snonaka 	}
41439cdb1c70Snonaka 
41449cdb1c70Snonaka 	/* select 20MHz bandwidth */
41459cdb1c70Snonaka 	run_rt3070_rf_read(sc, 31, &rf);
41469cdb1c70Snonaka 	run_rt3070_rf_write(sc, 31, rf & ~0x20);
41479cdb1c70Snonaka 
41489cdb1c70Snonaka 	/* calibrate filter for 20MHz bandwidth */
41499cdb1c70Snonaka 	sc->rf24_20mhz = 0x1f;	/* default value */
41509cdb1c70Snonaka 	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
41519cdb1c70Snonaka 	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
41529cdb1c70Snonaka 
41539cdb1c70Snonaka 	/* select 40MHz bandwidth */
41549cdb1c70Snonaka 	run_bbp_read(sc, 4, &bbp4);
41559cdb1c70Snonaka 	run_bbp_write(sc, 4, (bbp4 & ~0x08) | 0x10);
41569cdb1c70Snonaka 	run_rt3070_rf_read(sc, 31, &rf);
41579cdb1c70Snonaka 	run_rt3070_rf_write(sc, 31, rf | 0x20);
41589cdb1c70Snonaka 
41599cdb1c70Snonaka 	/* calibrate filter for 40MHz bandwidth */
41609cdb1c70Snonaka 	sc->rf24_40mhz = 0x2f;	/* default value */
41619cdb1c70Snonaka 	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
41629cdb1c70Snonaka 	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
41639cdb1c70Snonaka 
41649cdb1c70Snonaka 	/* go back to 20MHz bandwidth */
41659cdb1c70Snonaka 	run_bbp_read(sc, 4, &bbp4);
41669cdb1c70Snonaka 	run_bbp_write(sc, 4, bbp4 & ~0x18);
41679cdb1c70Snonaka 
41689cdb1c70Snonaka 	if (sc->mac_ver == 0x3572) {
41699cdb1c70Snonaka 		/* save default BBP registers 25 and 26 values */
41709cdb1c70Snonaka 		run_bbp_read(sc, 25, &sc->bbp25);
41719cdb1c70Snonaka 		run_bbp_read(sc, 26, &sc->bbp26);
41729cdb1c70Snonaka 	} else if (sc->mac_rev < 0x0211)
41739cdb1c70Snonaka 		run_rt3070_rf_write(sc, 27, 0x03);
41749cdb1c70Snonaka 
41759cdb1c70Snonaka 	run_read(sc, RT3070_OPT_14, &tmp);
41769cdb1c70Snonaka 	run_write(sc, RT3070_OPT_14, tmp | 1);
41779cdb1c70Snonaka 
41789cdb1c70Snonaka 	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
41799cdb1c70Snonaka 		run_rt3070_rf_read(sc, 17, &rf);
41809cdb1c70Snonaka 		rf &= ~RT3070_TX_LO1;
41819cdb1c70Snonaka 		if ((sc->mac_ver == 0x3070 ||
41829cdb1c70Snonaka 		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
41839cdb1c70Snonaka 		    !sc->ext_2ghz_lna)
41849cdb1c70Snonaka 			rf |= 0x20;	/* fix for long range Rx issue */
41859cdb1c70Snonaka 		if (sc->txmixgain_2ghz >= 1)
41869cdb1c70Snonaka 			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
41879cdb1c70Snonaka 		run_rt3070_rf_write(sc, 17, rf);
41889cdb1c70Snonaka 	}
41899cdb1c70Snonaka 	if (sc->mac_ver == 0x3071) {
41909cdb1c70Snonaka 		run_rt3070_rf_read(sc, 1, &rf);
41919cdb1c70Snonaka 		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
41929cdb1c70Snonaka 		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
41939cdb1c70Snonaka 		run_rt3070_rf_write(sc, 1, rf);
41949cdb1c70Snonaka 
41959cdb1c70Snonaka 		run_rt3070_rf_read(sc, 15, &rf);
41969cdb1c70Snonaka 		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
41979cdb1c70Snonaka 
41989cdb1c70Snonaka 		run_rt3070_rf_read(sc, 20, &rf);
41999cdb1c70Snonaka 		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
42009cdb1c70Snonaka 
42019cdb1c70Snonaka 		run_rt3070_rf_read(sc, 21, &rf);
42029cdb1c70Snonaka 		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
42039cdb1c70Snonaka 	}
42049cdb1c70Snonaka 	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
42059cdb1c70Snonaka 		/* fix Tx to Rx IQ glitch by raising RF voltage */
42069cdb1c70Snonaka 		run_rt3070_rf_read(sc, 27, &rf);
42079cdb1c70Snonaka 		rf &= ~0x77;
42089cdb1c70Snonaka 		if (sc->mac_rev < 0x0211)
42099cdb1c70Snonaka 			rf |= 0x03;
42109cdb1c70Snonaka 		run_rt3070_rf_write(sc, 27, rf);
42119cdb1c70Snonaka 	}
42124e8e6643Sskrll 	return 0;
42139cdb1c70Snonaka }
42149cdb1c70Snonaka 
42159cdb1c70Snonaka static int
4216faca41fbSmlelstv run_rt3593_rf_init(struct run_softc *sc)
4217faca41fbSmlelstv {
4218faca41fbSmlelstv 	uint32_t tmp;
4219faca41fbSmlelstv 	uint8_t rf;
4220faca41fbSmlelstv 	int i;
4221faca41fbSmlelstv 
4222faca41fbSmlelstv 	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
4223faca41fbSmlelstv 	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
4224faca41fbSmlelstv 	tmp &= ~(1 << 4 | 1 << 7);
4225faca41fbSmlelstv 	run_write(sc, RT3070_GPIO_SWITCH, tmp);
4226faca41fbSmlelstv 
4227faca41fbSmlelstv 	/* Initialize RF registers to default value. */
4228faca41fbSmlelstv 	for (i = 0; i < __arraycount(rt3593_def_rf); i++) {
4229faca41fbSmlelstv 		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
4230faca41fbSmlelstv 			rt3593_def_rf[i].val);
4231faca41fbSmlelstv 	}
4232faca41fbSmlelstv 
4233faca41fbSmlelstv 	/* Toggle RF R2 to initiate calibration. */
4234faca41fbSmlelstv 	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
4235faca41fbSmlelstv 
4236faca41fbSmlelstv 	/* Initialize RF frequency offset. */
4237faca41fbSmlelstv 	run_adjust_freq_offset(sc);
4238faca41fbSmlelstv 
4239faca41fbSmlelstv 	run_rt3070_rf_read(sc, 18, &rf);
4240faca41fbSmlelstv 	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
4241faca41fbSmlelstv 
4242faca41fbSmlelstv 	/*
4243faca41fbSmlelstv 	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
4244faca41fbSmlelstv 	 * decrease voltage back to 1.2V.
4245faca41fbSmlelstv 	 */
4246faca41fbSmlelstv 	run_read(sc, RT3070_LDO_CFG0, &tmp);
4247faca41fbSmlelstv 	tmp = (tmp & ~0x1f000000) | 0x0d000000;
4248faca41fbSmlelstv 	run_write(sc, RT3070_LDO_CFG0, tmp);
4249faca41fbSmlelstv 	usbd_delay_ms(sc->sc_udev, 1);
4250faca41fbSmlelstv 	tmp = (tmp & ~0x1f000000) | 0x01000000;
4251faca41fbSmlelstv 	run_write(sc, RT3070_LDO_CFG0, tmp);
4252faca41fbSmlelstv 
4253faca41fbSmlelstv 	sc->rf24_20mhz = 0x1f;
4254faca41fbSmlelstv 	sc->rf24_40mhz = 0x2f;
4255faca41fbSmlelstv 
4256faca41fbSmlelstv 	/* Save default BBP registers 25 and 26 values. */
4257faca41fbSmlelstv 	run_bbp_read(sc, 25, &sc->bbp25);
4258faca41fbSmlelstv 	run_bbp_read(sc, 26, &sc->bbp26);
4259faca41fbSmlelstv 
4260faca41fbSmlelstv 	run_read(sc, RT3070_OPT_14, &tmp);
4261faca41fbSmlelstv 	run_write(sc, RT3070_OPT_14, tmp | 1);
426226ee7ba1Sskrll 	return 0;
4263faca41fbSmlelstv }
4264faca41fbSmlelstv 
4265faca41fbSmlelstv static int
4266faca41fbSmlelstv run_rt5390_rf_init(struct run_softc *sc)
4267faca41fbSmlelstv {
4268faca41fbSmlelstv 	uint32_t tmp;
4269faca41fbSmlelstv 	uint8_t rf;
4270faca41fbSmlelstv 	int i;
4271faca41fbSmlelstv 
4272faca41fbSmlelstv 	/* Toggle RF R2 to initiate calibration. */
4273faca41fbSmlelstv 	if (sc->mac_ver == 0x5390) {
4274faca41fbSmlelstv 		run_rt3070_rf_read(sc, 2, &rf);
4275faca41fbSmlelstv 		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
4276faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 10);
4277faca41fbSmlelstv 		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
4278faca41fbSmlelstv 	} else {
4279faca41fbSmlelstv 		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
4280faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 10);
4281faca41fbSmlelstv 	}
4282faca41fbSmlelstv 
4283faca41fbSmlelstv 	/* Initialize RF registers to default value. */
4284faca41fbSmlelstv 	if (sc->mac_ver == 0x5592) {
4285faca41fbSmlelstv 		for (i = 0; i < __arraycount(rt5592_def_rf); i++) {
4286faca41fbSmlelstv 			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
4287faca41fbSmlelstv 			    rt5592_def_rf[i].val);
4288faca41fbSmlelstv 		}
4289faca41fbSmlelstv 		/* Initialize RF frequency offset. */
4290faca41fbSmlelstv 		run_adjust_freq_offset(sc);
4291faca41fbSmlelstv 	} else if (sc->mac_ver == 0x5392) {
4292faca41fbSmlelstv 		for (i = 0; i < __arraycount(rt5392_def_rf); i++) {
4293faca41fbSmlelstv 			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
4294faca41fbSmlelstv 			    rt5392_def_rf[i].val);
4295faca41fbSmlelstv 		}
4296faca41fbSmlelstv 		if (sc->mac_rev >= 0x0223) {
4297faca41fbSmlelstv 			run_rt3070_rf_write(sc, 23, 0x0f);
4298faca41fbSmlelstv 			run_rt3070_rf_write(sc, 24, 0x3e);
4299faca41fbSmlelstv 			run_rt3070_rf_write(sc, 51, 0x32);
4300faca41fbSmlelstv 			run_rt3070_rf_write(sc, 53, 0x22);
4301faca41fbSmlelstv 			run_rt3070_rf_write(sc, 56, 0xc1);
4302faca41fbSmlelstv 			run_rt3070_rf_write(sc, 59, 0x0f);
4303faca41fbSmlelstv 		}
4304faca41fbSmlelstv 	} else {
4305faca41fbSmlelstv 		for (i = 0; i < __arraycount(rt5390_def_rf); i++) {
4306faca41fbSmlelstv 			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
4307faca41fbSmlelstv 			    rt5390_def_rf[i].val);
4308faca41fbSmlelstv 		}
4309faca41fbSmlelstv 		if (sc->mac_rev >= 0x0502) {
4310faca41fbSmlelstv 			run_rt3070_rf_write(sc, 6, 0xe0);
4311faca41fbSmlelstv 			run_rt3070_rf_write(sc, 25, 0x80);
4312faca41fbSmlelstv 			run_rt3070_rf_write(sc, 46, 0x73);
4313faca41fbSmlelstv 			run_rt3070_rf_write(sc, 53, 0x00);
4314faca41fbSmlelstv 			run_rt3070_rf_write(sc, 56, 0x42);
4315faca41fbSmlelstv 			run_rt3070_rf_write(sc, 61, 0xd1);
4316faca41fbSmlelstv 		}
4317faca41fbSmlelstv 	}
4318faca41fbSmlelstv 
4319faca41fbSmlelstv 	sc->rf24_20mhz = 0x1f;  /* default value */
4320faca41fbSmlelstv 	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
4321faca41fbSmlelstv 
4322faca41fbSmlelstv 	if (sc->mac_rev < 0x0211)
4323faca41fbSmlelstv 		run_rt3070_rf_write(sc, 27, 0x3);
4324faca41fbSmlelstv 
4325faca41fbSmlelstv 	run_read(sc, RT3070_OPT_14, &tmp);
4326faca41fbSmlelstv 	run_write(sc, RT3070_OPT_14, tmp | 1);
432726ee7ba1Sskrll 	return 0;
4328faca41fbSmlelstv }
4329faca41fbSmlelstv 
4330faca41fbSmlelstv static int
43319cdb1c70Snonaka run_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
43329cdb1c70Snonaka     uint8_t *val)
43339cdb1c70Snonaka {
43349cdb1c70Snonaka 	uint8_t rf22, rf24;
43359cdb1c70Snonaka 	uint8_t bbp55_pb, bbp55_sb, delta;
43369cdb1c70Snonaka 	int ntries;
43379cdb1c70Snonaka 
43389cdb1c70Snonaka 	/* program filter */
43399cdb1c70Snonaka 	run_rt3070_rf_read(sc, 24, &rf24);
43409cdb1c70Snonaka 	rf24 = (rf24 & 0xc0) | init;    /* initial filter value */
43419cdb1c70Snonaka 	run_rt3070_rf_write(sc, 24, rf24);
43429cdb1c70Snonaka 
43439cdb1c70Snonaka 	/* enable baseband loopback mode */
43449cdb1c70Snonaka 	run_rt3070_rf_read(sc, 22, &rf22);
43459cdb1c70Snonaka 	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
43469cdb1c70Snonaka 
43479cdb1c70Snonaka 	/* set power and frequency of passband test tone */
43489cdb1c70Snonaka 	run_bbp_write(sc, 24, 0x00);
43499cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
43509cdb1c70Snonaka 		/* transmit test tone */
43519cdb1c70Snonaka 		run_bbp_write(sc, 25, 0x90);
4352faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 10);
43539cdb1c70Snonaka 		/* read received power */
43549cdb1c70Snonaka 		run_bbp_read(sc, 55, &bbp55_pb);
43559cdb1c70Snonaka 		if (bbp55_pb != 0)
43569cdb1c70Snonaka 			break;
43579cdb1c70Snonaka 	}
43589cdb1c70Snonaka 	if (ntries == 100)
43594e8e6643Sskrll 		return ETIMEDOUT;
43609cdb1c70Snonaka 
43619cdb1c70Snonaka 	/* set power and frequency of stopband test tone */
43629cdb1c70Snonaka 	run_bbp_write(sc, 24, 0x06);
43639cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
43649cdb1c70Snonaka 		/* transmit test tone */
43659cdb1c70Snonaka 		run_bbp_write(sc, 25, 0x90);
4366faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 10);
43679cdb1c70Snonaka 		/* read received power */
43689cdb1c70Snonaka 		run_bbp_read(sc, 55, &bbp55_sb);
43699cdb1c70Snonaka 
43709cdb1c70Snonaka 		delta = bbp55_pb - bbp55_sb;
43719cdb1c70Snonaka 		if (delta > target)
43729cdb1c70Snonaka 			break;
43739cdb1c70Snonaka 
43749cdb1c70Snonaka 		/* reprogram filter */
43759cdb1c70Snonaka 		rf24++;
43769cdb1c70Snonaka 		run_rt3070_rf_write(sc, 24, rf24);
43779cdb1c70Snonaka 	}
43789cdb1c70Snonaka 	if (ntries < 100) {
43799cdb1c70Snonaka 		if (rf24 != init)
43809cdb1c70Snonaka 			rf24--;	/* backtrack */
43819cdb1c70Snonaka 		*val = rf24;
43829cdb1c70Snonaka 		run_rt3070_rf_write(sc, 24, rf24);
43839cdb1c70Snonaka 	}
43849cdb1c70Snonaka 
43859cdb1c70Snonaka 	/* restore initial state */
43869cdb1c70Snonaka 	run_bbp_write(sc, 24, 0x00);
43879cdb1c70Snonaka 
43889cdb1c70Snonaka 	/* disable baseband loopback mode */
43899cdb1c70Snonaka 	run_rt3070_rf_read(sc, 22, &rf22);
43909cdb1c70Snonaka 	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
43919cdb1c70Snonaka 
43924e8e6643Sskrll 	return 0;
43939cdb1c70Snonaka }
43949cdb1c70Snonaka 
43959cdb1c70Snonaka static void
43969cdb1c70Snonaka run_rt3070_rf_setup(struct run_softc *sc)
43979cdb1c70Snonaka {
43989cdb1c70Snonaka 	uint8_t bbp, rf;
43999cdb1c70Snonaka 	int i;
44009cdb1c70Snonaka 
44019cdb1c70Snonaka 	if (sc->mac_ver == 0x3572) {
44029cdb1c70Snonaka 		/* enable DC filter */
44039cdb1c70Snonaka 		if (sc->mac_rev >= 0x0201)
44049cdb1c70Snonaka 			run_bbp_write(sc, 103, 0xc0);
44059cdb1c70Snonaka 
44069cdb1c70Snonaka 		run_bbp_read(sc, 138, &bbp);
44079cdb1c70Snonaka 		if (sc->ntxchains == 1)
44089cdb1c70Snonaka 			bbp |= 0x20;	/* turn off DAC1 */
44099cdb1c70Snonaka 		if (sc->nrxchains == 1)
44109cdb1c70Snonaka 			bbp &= ~0x02;	/* turn off ADC1 */
44119cdb1c70Snonaka 		run_bbp_write(sc, 138, bbp);
44129cdb1c70Snonaka 
44139cdb1c70Snonaka 		if (sc->mac_rev >= 0x0211) {
44149cdb1c70Snonaka 			/* improve power consumption */
44159cdb1c70Snonaka 			run_bbp_read(sc, 31, &bbp);
44169cdb1c70Snonaka 			run_bbp_write(sc, 31, bbp & ~0x03);
44179cdb1c70Snonaka 		}
44189cdb1c70Snonaka 
44199cdb1c70Snonaka 		run_rt3070_rf_read(sc, 16, &rf);
44209cdb1c70Snonaka 		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
44219cdb1c70Snonaka 		run_rt3070_rf_write(sc, 16, rf);
44229cdb1c70Snonaka 	} else if (sc->mac_ver == 0x3071) {
44239cdb1c70Snonaka 		/* enable DC filter */
44249cdb1c70Snonaka 		if (sc->mac_rev >= 0x0201)
44259cdb1c70Snonaka 			run_bbp_write(sc, 103, 0xc0);
44269cdb1c70Snonaka 
44279cdb1c70Snonaka 		run_bbp_read(sc, 138, &bbp);
44289cdb1c70Snonaka 		if (sc->ntxchains == 1)
44299cdb1c70Snonaka 			bbp |= 0x20;	/* turn off DAC1 */
44309cdb1c70Snonaka 		if (sc->nrxchains == 1)
44319cdb1c70Snonaka 			bbp &= ~0x02;	/* turn off ADC1 */
44329cdb1c70Snonaka 		run_bbp_write(sc, 138, bbp);
44339cdb1c70Snonaka 
44349cdb1c70Snonaka 		if (sc->mac_rev >= 0x0211) {
44359cdb1c70Snonaka 			/* improve power consumption */
44369cdb1c70Snonaka 			run_bbp_read(sc, 31, &bbp);
44379cdb1c70Snonaka 			run_bbp_write(sc, 31, bbp & ~0x03);
44389cdb1c70Snonaka 		}
44399cdb1c70Snonaka 
44409cdb1c70Snonaka 		run_write(sc, RT2860_TX_SW_CFG1, 0);
44419cdb1c70Snonaka 		if (sc->mac_rev < 0x0211) {
44429cdb1c70Snonaka 			run_write(sc, RT2860_TX_SW_CFG2,
44439cdb1c70Snonaka 			    sc->patch_dac ? 0x2c : 0x0f);
44449cdb1c70Snonaka 		} else
44459cdb1c70Snonaka 			run_write(sc, RT2860_TX_SW_CFG2, 0);
44469cdb1c70Snonaka 	} else if (sc->mac_ver == 0x3070) {
44479cdb1c70Snonaka 		if (sc->mac_rev >= 0x0201) {
44489cdb1c70Snonaka 			/* enable DC filter */
44499cdb1c70Snonaka 			run_bbp_write(sc, 103, 0xc0);
44509cdb1c70Snonaka 
44519cdb1c70Snonaka 			/* improve power consumption */
44529cdb1c70Snonaka 			run_bbp_read(sc, 31, &bbp);
44539cdb1c70Snonaka 			run_bbp_write(sc, 31, bbp & ~0x03);
44549cdb1c70Snonaka 		}
44559cdb1c70Snonaka 
44569cdb1c70Snonaka 		if (sc->mac_rev < 0x0211) {
44579cdb1c70Snonaka 			run_write(sc, RT2860_TX_SW_CFG1, 0);
44589cdb1c70Snonaka 			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
44599cdb1c70Snonaka 		} else
44609cdb1c70Snonaka 			run_write(sc, RT2860_TX_SW_CFG2, 0);
44619cdb1c70Snonaka 	}
44629cdb1c70Snonaka 
44639cdb1c70Snonaka 	/* initialize RF registers from ROM for >=RT3071*/
44649cdb1c70Snonaka 	if (sc->mac_ver >= 0x3071) {
44659cdb1c70Snonaka 		for (i = 0; i < 10; i++) {
44669cdb1c70Snonaka 			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
44679cdb1c70Snonaka 				continue;
44689cdb1c70Snonaka 			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
44699cdb1c70Snonaka 		}
44709cdb1c70Snonaka 	}
44719cdb1c70Snonaka }
44729cdb1c70Snonaka 
4473faca41fbSmlelstv static void
4474faca41fbSmlelstv run_rt3593_rf_setup(struct run_softc *sc)
4475faca41fbSmlelstv {
4476faca41fbSmlelstv 	uint8_t bbp, rf;
4477faca41fbSmlelstv 
4478faca41fbSmlelstv 	if (sc->mac_rev >= 0x0211) {
4479faca41fbSmlelstv 		/* Enable DC filter. */
4480faca41fbSmlelstv 		run_bbp_write(sc, 103, 0xc0);
4481faca41fbSmlelstv 	}
4482faca41fbSmlelstv 	run_write(sc, RT2860_TX_SW_CFG1, 0);
4483faca41fbSmlelstv 	if (sc->mac_rev < 0x0211) {
4484faca41fbSmlelstv 		run_write(sc, RT2860_TX_SW_CFG2,
4485faca41fbSmlelstv 		    sc->patch_dac ? 0x2c : 0x0f);
4486faca41fbSmlelstv 	} else
4487faca41fbSmlelstv 		run_write(sc, RT2860_TX_SW_CFG2, 0);
4488faca41fbSmlelstv 
4489faca41fbSmlelstv 	run_rt3070_rf_read(sc, 50, &rf);
4490faca41fbSmlelstv 	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
4491faca41fbSmlelstv 
4492faca41fbSmlelstv 	run_rt3070_rf_read(sc, 51, &rf);
4493faca41fbSmlelstv 	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
4494faca41fbSmlelstv 	    ((sc->txmixgain_2ghz & 0x07) << 2);
4495faca41fbSmlelstv 	run_rt3070_rf_write(sc, 51, rf);
4496faca41fbSmlelstv 
4497faca41fbSmlelstv 	run_rt3070_rf_read(sc, 38, &rf);
4498faca41fbSmlelstv 	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
4499faca41fbSmlelstv 
4500faca41fbSmlelstv 	run_rt3070_rf_read(sc, 39, &rf);
4501faca41fbSmlelstv 	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
4502faca41fbSmlelstv 
4503faca41fbSmlelstv 	run_rt3070_rf_read(sc, 1, &rf);
4504faca41fbSmlelstv 	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
4505faca41fbSmlelstv 
4506faca41fbSmlelstv 	run_rt3070_rf_read(sc, 30, &rf);
4507faca41fbSmlelstv 	rf = (rf & ~0x18) | 0x10;
4508faca41fbSmlelstv 	run_rt3070_rf_write(sc, 30, rf);
4509faca41fbSmlelstv 
4510faca41fbSmlelstv 	/* Apply maximum likelihood detection for 2 stream case. */
4511faca41fbSmlelstv 	run_bbp_read(sc, 105, &bbp);
4512faca41fbSmlelstv 	if (sc->nrxchains > 1)
4513faca41fbSmlelstv 		run_bbp_write(sc, 105, bbp | RT5390_MLD);
4514faca41fbSmlelstv 
4515faca41fbSmlelstv 	/* Avoid data lost and CRC error. */
4516faca41fbSmlelstv 	run_bbp_read(sc, 4, &bbp);
4517faca41fbSmlelstv 	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
4518faca41fbSmlelstv 
4519faca41fbSmlelstv 	run_bbp_write(sc, 92, 0x02);
4520faca41fbSmlelstv 	run_bbp_write(sc, 82, 0x82);
4521faca41fbSmlelstv 	run_bbp_write(sc, 106, 0x05);
4522faca41fbSmlelstv 	run_bbp_write(sc, 104, 0x92);
4523faca41fbSmlelstv 	run_bbp_write(sc, 88, 0x90);
4524faca41fbSmlelstv 	run_bbp_write(sc, 148, 0xc8);
4525faca41fbSmlelstv 	run_bbp_write(sc, 47, 0x48);
4526faca41fbSmlelstv 	run_bbp_write(sc, 120, 0x50);
4527faca41fbSmlelstv 
4528faca41fbSmlelstv 	run_bbp_write(sc, 163, 0x9d);
4529faca41fbSmlelstv 
4530faca41fbSmlelstv 	/* SNR mapping. */
4531faca41fbSmlelstv 	run_bbp_write(sc, 142, 0x06);
4532faca41fbSmlelstv 	run_bbp_write(sc, 143, 0xa0);
4533faca41fbSmlelstv 	run_bbp_write(sc, 142, 0x07);
4534faca41fbSmlelstv 	run_bbp_write(sc, 143, 0xa1);
4535faca41fbSmlelstv 	run_bbp_write(sc, 142, 0x08);
4536faca41fbSmlelstv 	run_bbp_write(sc, 143, 0xa2);
4537faca41fbSmlelstv 
4538faca41fbSmlelstv 	run_bbp_write(sc, 31, 0x08);
4539faca41fbSmlelstv 	run_bbp_write(sc, 68, 0x0b);
4540faca41fbSmlelstv 	run_bbp_write(sc, 105, 0x04);
4541faca41fbSmlelstv }
4542faca41fbSmlelstv 
4543faca41fbSmlelstv static void
4544faca41fbSmlelstv run_rt5390_rf_setup(struct run_softc *sc)
4545faca41fbSmlelstv {
4546faca41fbSmlelstv 	uint8_t bbp, rf;
4547faca41fbSmlelstv 
4548faca41fbSmlelstv 	if (sc->mac_rev >= 0x0211) {
4549faca41fbSmlelstv 		/* Enable DC filter. */
4550faca41fbSmlelstv 		run_bbp_write(sc, 103, 0xc0);
4551faca41fbSmlelstv 
4552faca41fbSmlelstv 		if (sc->mac_ver != 0x5592) {
4553faca41fbSmlelstv 			/* Improve power consumption. */
4554faca41fbSmlelstv 			run_bbp_read(sc, 31, &bbp);
4555faca41fbSmlelstv 			run_bbp_write(sc, 31, bbp & ~0x03);
4556faca41fbSmlelstv 		}
4557faca41fbSmlelstv 	}
4558faca41fbSmlelstv 
4559faca41fbSmlelstv 	run_bbp_read(sc, 138, &bbp);
4560faca41fbSmlelstv 	if (sc->ntxchains == 1)
4561faca41fbSmlelstv 		bbp |= 0x20;    /* turn off DAC1 */
4562faca41fbSmlelstv 	if (sc->nrxchains == 1)
4563faca41fbSmlelstv 		bbp &= ~0x02;   /* turn off ADC1 */
4564faca41fbSmlelstv 	run_bbp_write(sc, 138, bbp);
4565faca41fbSmlelstv 
4566faca41fbSmlelstv 	run_rt3070_rf_read(sc, 38, &rf);
4567faca41fbSmlelstv 	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
4568faca41fbSmlelstv 
4569faca41fbSmlelstv 	run_rt3070_rf_read(sc, 39, &rf);
4570faca41fbSmlelstv 	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
4571faca41fbSmlelstv 
4572faca41fbSmlelstv 	/* Avoid data lost and CRC error. */
4573faca41fbSmlelstv 	run_bbp_read(sc, 4, &bbp);
4574faca41fbSmlelstv 	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
4575faca41fbSmlelstv 
4576faca41fbSmlelstv 	run_rt3070_rf_read(sc, 30, &rf);
4577faca41fbSmlelstv 	rf = (rf & ~0x18) | 0x10;
4578faca41fbSmlelstv 	run_rt3070_rf_write(sc, 30, rf);
4579faca41fbSmlelstv 
4580faca41fbSmlelstv 	if (sc->mac_ver != 0x5592) {
4581faca41fbSmlelstv 		run_write(sc, RT2860_TX_SW_CFG1, 0);
4582faca41fbSmlelstv 		if (sc->mac_rev < 0x0211) {
4583faca41fbSmlelstv 			run_write(sc, RT2860_TX_SW_CFG2,
4584faca41fbSmlelstv 			    sc->patch_dac ? 0x2c : 0x0f);
4585faca41fbSmlelstv 		} else
4586faca41fbSmlelstv 			run_write(sc, RT2860_TX_SW_CFG2, 0);
4587faca41fbSmlelstv 	}
4588faca41fbSmlelstv }
4589faca41fbSmlelstv 
45909cdb1c70Snonaka static int
45919cdb1c70Snonaka run_txrx_enable(struct run_softc *sc)
45929cdb1c70Snonaka {
45939cdb1c70Snonaka 	uint32_t tmp;
45949cdb1c70Snonaka 	int error, ntries;
45959cdb1c70Snonaka 
45969cdb1c70Snonaka 	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
45979cdb1c70Snonaka 	for (ntries = 0; ntries < 200; ntries++) {
45989cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
45994e8e6643Sskrll 			return error;
46009cdb1c70Snonaka 		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
46019cdb1c70Snonaka 			break;
4602faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 50);
46039cdb1c70Snonaka 	}
46049cdb1c70Snonaka 	if (ntries == 200)
46054e8e6643Sskrll 		return ETIMEDOUT;
46069cdb1c70Snonaka 
4607faca41fbSmlelstv 	usbd_delay_ms(sc->sc_udev, 50);
46089cdb1c70Snonaka 
46099cdb1c70Snonaka 	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
46109cdb1c70Snonaka 	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
46119cdb1c70Snonaka 
46129cdb1c70Snonaka 	/* enable Rx bulk aggregation (set timeout and limit) */
46139cdb1c70Snonaka 	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
46149cdb1c70Snonaka 	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
46159cdb1c70Snonaka 	run_write(sc, RT2860_USB_DMA_CFG, tmp);
46169cdb1c70Snonaka 
46179cdb1c70Snonaka 	/* set Rx filter */
46189cdb1c70Snonaka 	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
46199cdb1c70Snonaka 	if (sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR) {
46209cdb1c70Snonaka 		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
46219cdb1c70Snonaka 		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
46229cdb1c70Snonaka 		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
46239cdb1c70Snonaka 		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
46249cdb1c70Snonaka 		if (sc->sc_ic.ic_opmode == IEEE80211_M_STA)
46259cdb1c70Snonaka 			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
46269cdb1c70Snonaka 	}
46279cdb1c70Snonaka 	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
46289cdb1c70Snonaka 
46299cdb1c70Snonaka 	run_write(sc, RT2860_MAC_SYS_CTRL,
46309cdb1c70Snonaka 	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
46319cdb1c70Snonaka 
46324e8e6643Sskrll 	return 0;
46339cdb1c70Snonaka }
46349cdb1c70Snonaka 
46359cdb1c70Snonaka static int
4636faca41fbSmlelstv run_adjust_freq_offset(struct run_softc *sc)
4637faca41fbSmlelstv {
4638faca41fbSmlelstv 	uint8_t rf, tmp;
4639faca41fbSmlelstv 
4640faca41fbSmlelstv 	run_rt3070_rf_read(sc, 17, &rf);
4641faca41fbSmlelstv 	tmp = rf;
4642faca41fbSmlelstv 	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
4643faca41fbSmlelstv 	rf = MIN(rf, 0x5f);
4644faca41fbSmlelstv 
4645faca41fbSmlelstv 	if (tmp != rf)
4646faca41fbSmlelstv 		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
4647faca41fbSmlelstv 
464826ee7ba1Sskrll 	return 0;
4649faca41fbSmlelstv }
4650faca41fbSmlelstv 
4651faca41fbSmlelstv static int
46529cdb1c70Snonaka run_init(struct ifnet *ifp)
46539cdb1c70Snonaka {
46549cdb1c70Snonaka 	struct run_softc *sc = ifp->if_softc;
46559cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
46569cdb1c70Snonaka 	uint32_t tmp;
46579cdb1c70Snonaka 	uint8_t bbp1, bbp3;
46589cdb1c70Snonaka 	int i, error, qid, ridx, ntries;
4659d164e220Smlelstv 	usbd_status status;
46609cdb1c70Snonaka 
46619cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
46629cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_ASIC_VER_ID, &tmp)) != 0)
46639cdb1c70Snonaka 			goto fail;
46649cdb1c70Snonaka 		if (tmp != 0 && tmp != 0xffffffff)
46659cdb1c70Snonaka 			break;
4666faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 10);
46679cdb1c70Snonaka 	}
46689cdb1c70Snonaka 	if (ntries == 100) {
46699cdb1c70Snonaka 		error = ETIMEDOUT;
46709cdb1c70Snonaka 		goto fail;
46719cdb1c70Snonaka 	}
46729cdb1c70Snonaka 
46739cdb1c70Snonaka 	if ((sc->sc_flags & RUN_FWLOADED) == 0 &&
46749cdb1c70Snonaka 	    (error = run_load_microcode(sc)) != 0) {
46751d5cb2a3Sjakllsch 		device_printf(sc->sc_dev,
46769cdb1c70Snonaka 		    "could not load 8051 microcode\n");
46779cdb1c70Snonaka 		goto fail;
46789cdb1c70Snonaka 	}
46799cdb1c70Snonaka 
46809cdb1c70Snonaka 	if (ifp->if_flags & IFF_RUNNING)
46819cdb1c70Snonaka 		run_stop(ifp, 0);
46829cdb1c70Snonaka 
46839cdb1c70Snonaka 	/* init host command ring */
46849cdb1c70Snonaka 	sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0;
46859cdb1c70Snonaka 
46869cdb1c70Snonaka 	/* init Tx rings (4 EDCAs) */
46879cdb1c70Snonaka 	for (qid = 0; qid < 4; qid++) {
46889cdb1c70Snonaka 		if ((error = run_alloc_tx_ring(sc, qid)) != 0)
46899cdb1c70Snonaka 			goto fail;
46909cdb1c70Snonaka 	}
46919cdb1c70Snonaka 	/* init Rx ring */
46929cdb1c70Snonaka 	if ((error = run_alloc_rx_ring(sc)) != 0)
46939cdb1c70Snonaka 		goto fail;
46949cdb1c70Snonaka 
46959cdb1c70Snonaka 	IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl));
46969cdb1c70Snonaka 	run_set_macaddr(sc, ic->ic_myaddr);
46979cdb1c70Snonaka 
46989cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
46999cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
47009cdb1c70Snonaka 			goto fail;
47019cdb1c70Snonaka 		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
47029cdb1c70Snonaka 			break;
4703faca41fbSmlelstv 		usbd_delay_ms(sc->sc_udev, 10);
47049cdb1c70Snonaka 	}
47059cdb1c70Snonaka 	if (ntries == 100) {
47061d5cb2a3Sjakllsch 		device_printf(sc->sc_dev,
47079cdb1c70Snonaka 		    "timeout waiting for DMA engine\n");
47089cdb1c70Snonaka 		error = ETIMEDOUT;
47099cdb1c70Snonaka 		goto fail;
47109cdb1c70Snonaka 	}
47119cdb1c70Snonaka 	tmp &= 0xff0;
47129cdb1c70Snonaka 	tmp |= RT2860_TX_WB_DDONE;
47139cdb1c70Snonaka 	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
47149cdb1c70Snonaka 
47159cdb1c70Snonaka 	/* turn off PME_OEN to solve high-current issue */
47169cdb1c70Snonaka 	run_read(sc, RT2860_SYS_CTRL, &tmp);
47179cdb1c70Snonaka 	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
47189cdb1c70Snonaka 
47199cdb1c70Snonaka 	run_write(sc, RT2860_MAC_SYS_CTRL,
47209cdb1c70Snonaka 	    RT2860_BBP_HRST | RT2860_MAC_SRST);
47219cdb1c70Snonaka 	run_write(sc, RT2860_USB_DMA_CFG, 0);
47229cdb1c70Snonaka 
47239cdb1c70Snonaka 	if ((error = run_reset(sc)) != 0) {
47241d5cb2a3Sjakllsch 		device_printf(sc->sc_dev, "could not reset chipset\n");
47259cdb1c70Snonaka 		goto fail;
47269cdb1c70Snonaka 	}
47279cdb1c70Snonaka 
47289cdb1c70Snonaka 	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
47299cdb1c70Snonaka 
47309cdb1c70Snonaka 	/* init Tx power for all Tx rates (from EEPROM) */
47319cdb1c70Snonaka 	for (ridx = 0; ridx < 5; ridx++) {
47329cdb1c70Snonaka 		if (sc->txpow20mhz[ridx] == 0xffffffff)
47339cdb1c70Snonaka 			continue;
47349cdb1c70Snonaka 		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
47359cdb1c70Snonaka 	}
47369cdb1c70Snonaka 
47379cdb1c70Snonaka 	for (i = 0; i < (int)__arraycount(rt2870_def_mac); i++)
47389cdb1c70Snonaka 		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
47399cdb1c70Snonaka 	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
47409cdb1c70Snonaka 	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
47419cdb1c70Snonaka 	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
47429cdb1c70Snonaka 
4743faca41fbSmlelstv 	if (sc->mac_ver >= 0x5390) {
4744faca41fbSmlelstv 		run_write(sc, RT2860_TX_SW_CFG0,
4745faca41fbSmlelstv 		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
4746faca41fbSmlelstv 		if (sc->mac_ver >= 0x5392) {
4747faca41fbSmlelstv 			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
4748faca41fbSmlelstv 			if (sc->mac_ver == 0x5592) {
4749faca41fbSmlelstv 				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
4750faca41fbSmlelstv 				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
4751faca41fbSmlelstv 			} else {
4752faca41fbSmlelstv 				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
4753faca41fbSmlelstv 				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
4754faca41fbSmlelstv 			}
4755faca41fbSmlelstv 		}
4756faca41fbSmlelstv 	} else if (sc->mac_ver >= 0x3593) {
4757faca41fbSmlelstv 		run_write(sc, RT2860_TX_SW_CFG0,
4758faca41fbSmlelstv 		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
4759faca41fbSmlelstv 	} else if (sc->mac_ver >= 0x3070) {
47609cdb1c70Snonaka 		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
47619cdb1c70Snonaka 		run_write(sc, RT2860_TX_SW_CFG0,
47629cdb1c70Snonaka 		    4 << RT2860_DLY_PAPE_EN_SHIFT);
47639cdb1c70Snonaka 	}
47649cdb1c70Snonaka 
47659cdb1c70Snonaka 	/* wait while MAC is busy */
47669cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
47679cdb1c70Snonaka 		if ((error = run_read(sc, RT2860_MAC_STATUS_REG, &tmp)) != 0)
47689cdb1c70Snonaka 			goto fail;
47699cdb1c70Snonaka 		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
47709cdb1c70Snonaka 			break;
47719cdb1c70Snonaka 		DELAY(1000);
47729cdb1c70Snonaka 	}
47739cdb1c70Snonaka 	if (ntries == 100) {
47749cdb1c70Snonaka 		error = ETIMEDOUT;
47759cdb1c70Snonaka 		goto fail;
47769cdb1c70Snonaka 	}
47779cdb1c70Snonaka 
47789cdb1c70Snonaka 	/* clear Host to MCU mailbox */
47799cdb1c70Snonaka 	run_write(sc, RT2860_H2M_BBPAGENT, 0);
47809cdb1c70Snonaka 	run_write(sc, RT2860_H2M_MAILBOX, 0);
4781faca41fbSmlelstv 	usbd_delay_ms(sc->sc_udev, 10);
47829cdb1c70Snonaka 
47839cdb1c70Snonaka 	if ((error = run_bbp_init(sc)) != 0) {
47841d5cb2a3Sjakllsch 		device_printf(sc->sc_dev, "could not initialize BBP\n");
47859cdb1c70Snonaka 		goto fail;
47869cdb1c70Snonaka 	}
47879cdb1c70Snonaka 
4788faca41fbSmlelstv 	/* abort TSF synchronization */
47899cdb1c70Snonaka 	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
47909cdb1c70Snonaka 	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
47919cdb1c70Snonaka 	    RT2860_TBTT_TIMER_EN);
47929cdb1c70Snonaka 	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
47939cdb1c70Snonaka 
47949cdb1c70Snonaka 	/* clear RX WCID search table */
47959cdb1c70Snonaka 	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
47969cdb1c70Snonaka 	/* clear Pair-wise key table */
47979cdb1c70Snonaka 	run_set_region_4(sc, RT2860_PKEY(0), 0, 2048);
47989cdb1c70Snonaka 	/* clear IV/EIV table */
47999cdb1c70Snonaka 	run_set_region_4(sc, RT2860_IVEIV(0), 0, 512);
48009cdb1c70Snonaka 	/* clear WCID attribute table */
48019cdb1c70Snonaka 	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
48029cdb1c70Snonaka 	/* clear shared key table */
48039cdb1c70Snonaka 	run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
48049cdb1c70Snonaka 	/* clear shared key mode */
48059cdb1c70Snonaka 	run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
48069cdb1c70Snonaka 
4807faca41fbSmlelstv 	/* clear RX WCID search table */
4808faca41fbSmlelstv 	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
4809faca41fbSmlelstv 	/* clear WCID attribute table */
4810faca41fbSmlelstv 	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
4811faca41fbSmlelstv 
48129cdb1c70Snonaka 	run_read(sc, RT2860_US_CYC_CNT, &tmp);
48139cdb1c70Snonaka 	tmp = (tmp & ~0xff) | 0x1e;
48149cdb1c70Snonaka 	run_write(sc, RT2860_US_CYC_CNT, tmp);
48159cdb1c70Snonaka 
48169cdb1c70Snonaka 	if (sc->mac_rev != 0x0101)
48179cdb1c70Snonaka 		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
48189cdb1c70Snonaka 
48199cdb1c70Snonaka 	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
48209cdb1c70Snonaka 	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
48219cdb1c70Snonaka 
48229cdb1c70Snonaka 	/* write vendor-specific BBP values (from EEPROM) */
4823faca41fbSmlelstv 	if (sc->mac_ver < 0x3593) {
4824faca41fbSmlelstv 		for (i = 0; i < 10; i++) {
48259cdb1c70Snonaka 			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
48269cdb1c70Snonaka 				continue;
48279cdb1c70Snonaka 			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
48289cdb1c70Snonaka 		}
4829faca41fbSmlelstv 	}
48309cdb1c70Snonaka 
48319cdb1c70Snonaka 	/* select Main antenna for 1T1R devices */
4832faca41fbSmlelstv 	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
48339cdb1c70Snonaka 		run_set_rx_antenna(sc, 0);
48349cdb1c70Snonaka 
48359cdb1c70Snonaka 	/* send LEDs operating mode to microcontroller */
48369cdb1c70Snonaka 	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
48379cdb1c70Snonaka 	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
48389cdb1c70Snonaka 	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
48399cdb1c70Snonaka 
4840faca41fbSmlelstv 	if (sc->mac_ver >= 0x5390)
4841faca41fbSmlelstv 		run_rt5390_rf_init(sc);
4842faca41fbSmlelstv 	else if (sc->mac_ver == 0x3593)
4843faca41fbSmlelstv 		run_rt3593_rf_init(sc);
4844faca41fbSmlelstv 	else if (sc->mac_ver >= 0x3070)
48459cdb1c70Snonaka 		run_rt3070_rf_init(sc);
48469cdb1c70Snonaka 
48479cdb1c70Snonaka 	/* disable non-existing Rx chains */
48489cdb1c70Snonaka 	run_bbp_read(sc, 3, &bbp3);
48499cdb1c70Snonaka 	bbp3 &= ~(1 << 3 | 1 << 4);
48509cdb1c70Snonaka 	if (sc->nrxchains == 2)
48519cdb1c70Snonaka 		bbp3 |= 1 << 3;
48529cdb1c70Snonaka 	else if (sc->nrxchains == 3)
48539cdb1c70Snonaka 		bbp3 |= 1 << 4;
48549cdb1c70Snonaka 	run_bbp_write(sc, 3, bbp3);
48559cdb1c70Snonaka 
48569cdb1c70Snonaka 	/* disable non-existing Tx chains */
48579cdb1c70Snonaka 	run_bbp_read(sc, 1, &bbp1);
48589cdb1c70Snonaka 	if (sc->ntxchains == 1)
48599cdb1c70Snonaka 		bbp1 &= ~(1 << 3 | 1 << 4);
48609cdb1c70Snonaka 	run_bbp_write(sc, 1, bbp1);
48619cdb1c70Snonaka 
4862faca41fbSmlelstv 	if (sc->mac_ver >= 0x5390)
4863faca41fbSmlelstv 		run_rt5390_rf_setup(sc);
4864faca41fbSmlelstv 	else if (sc->mac_ver == 0x3593)
4865faca41fbSmlelstv 		run_rt3593_rf_setup(sc);
4866faca41fbSmlelstv 	else if (sc->mac_ver >= 0x3070)
48679cdb1c70Snonaka 		run_rt3070_rf_setup(sc);
48689cdb1c70Snonaka 
48699cdb1c70Snonaka 	/* select default channel */
48709cdb1c70Snonaka 	run_set_chan(sc, ic->ic_curchan);
48719cdb1c70Snonaka 
4872faca41fbSmlelstv 	/* setup initial protection mode */
4873faca41fbSmlelstv 	run_updateprot(sc);
4874faca41fbSmlelstv 
48759cdb1c70Snonaka 	/* turn radio LED on */
48769cdb1c70Snonaka 	run_set_leds(sc, RT2860_LED_RADIO);
48779cdb1c70Snonaka 
48789cdb1c70Snonaka #ifdef RUN_HWCRYPTO
48799cdb1c70Snonaka 	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
48809cdb1c70Snonaka 		/* install WEP keys */
48819cdb1c70Snonaka 		for (i = 0; i < IEEE80211_WEP_NKID; i++)
48829cdb1c70Snonaka 			(void)run_set_key(ic, &ic->ic_crypto.cs_nw_keys[i],
48839cdb1c70Snonaka 			    NULL);
48849cdb1c70Snonaka 	}
48859cdb1c70Snonaka #endif
48869cdb1c70Snonaka 
48879cdb1c70Snonaka 	for (i = 0; i < RUN_RX_RING_COUNT; i++) {
48889cdb1c70Snonaka 		struct run_rx_data *data = &sc->rxq.data[i];
48899cdb1c70Snonaka 
48904e8e6643Sskrll 		usbd_setup_xfer(data->xfer, data, data->buf, RUN_MAX_RXSZ,
48914e8e6643Sskrll 		    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, run_rxeof);
4892d164e220Smlelstv 		status = usbd_transfer(data->xfer);
4893d164e220Smlelstv 		if (status != USBD_NORMAL_COMPLETION &&
4894d164e220Smlelstv 		    status != USBD_IN_PROGRESS) {
4895d164e220Smlelstv 			device_printf(sc->sc_dev, "queuing rx failed: %s\n",
4896d164e220Smlelstv 			    usbd_errstr(status));
4897d164e220Smlelstv 			error = EIO;
48989cdb1c70Snonaka 			goto fail;
48999cdb1c70Snonaka 		}
4900d164e220Smlelstv 	}
49019cdb1c70Snonaka 
49029cdb1c70Snonaka 	if ((error = run_txrx_enable(sc)) != 0)
49039cdb1c70Snonaka 		goto fail;
49049cdb1c70Snonaka 
49059cdb1c70Snonaka 	ifp->if_flags &= ~IFF_OACTIVE;
49069cdb1c70Snonaka 	ifp->if_flags |= IFF_RUNNING;
49079cdb1c70Snonaka 
49089cdb1c70Snonaka 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
49099cdb1c70Snonaka 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
49109cdb1c70Snonaka 	else
49119cdb1c70Snonaka 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
49129cdb1c70Snonaka 
49139cdb1c70Snonaka 	if (error != 0)
49149cdb1c70Snonaka fail:		run_stop(ifp, 1);
49154e8e6643Sskrll 	return error;
49169cdb1c70Snonaka }
49179cdb1c70Snonaka 
49189cdb1c70Snonaka static void
49199cdb1c70Snonaka run_stop(struct ifnet *ifp, int disable)
49209cdb1c70Snonaka {
49219cdb1c70Snonaka 	struct run_softc *sc = ifp->if_softc;
49229cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
49239cdb1c70Snonaka 	uint32_t tmp;
49249cdb1c70Snonaka 	int ntries, qid;
49259cdb1c70Snonaka 
49269cdb1c70Snonaka 	if (ifp->if_flags & IFF_RUNNING)
49279cdb1c70Snonaka 		run_set_leds(sc, 0);	/* turn all LEDs off */
49289cdb1c70Snonaka 
49299cdb1c70Snonaka 	sc->sc_tx_timer = 0;
49309cdb1c70Snonaka 	ifp->if_timer = 0;
49319cdb1c70Snonaka 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
49329cdb1c70Snonaka 
49339cdb1c70Snonaka 	callout_stop(&sc->scan_to);
49349cdb1c70Snonaka 	callout_stop(&sc->calib_to);
49359cdb1c70Snonaka 
49369cdb1c70Snonaka 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
49379cdb1c70Snonaka 	/* wait for all queued asynchronous commands to complete */
49389cdb1c70Snonaka 	while (sc->cmdq.queued > 0)
49399cdb1c70Snonaka 		tsleep(&sc->cmdq, 0, "cmdq", 0);
49409cdb1c70Snonaka 
49419cdb1c70Snonaka 	/* disable Tx/Rx */
49429cdb1c70Snonaka 	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
49439cdb1c70Snonaka 	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
49449cdb1c70Snonaka 	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
49459cdb1c70Snonaka 
49469cdb1c70Snonaka 	/* wait for pending Tx to complete */
49479cdb1c70Snonaka 	for (ntries = 0; ntries < 100; ntries++) {
49489cdb1c70Snonaka 		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0)
49499cdb1c70Snonaka 			break;
49509cdb1c70Snonaka 		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0)
49519cdb1c70Snonaka 			break;
49529cdb1c70Snonaka 	}
49539cdb1c70Snonaka 	DELAY(1000);
49549cdb1c70Snonaka 	run_write(sc, RT2860_USB_DMA_CFG, 0);
49559cdb1c70Snonaka 
49569cdb1c70Snonaka 	/* reset adapter */
49579cdb1c70Snonaka 	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
49589cdb1c70Snonaka 	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
49599cdb1c70Snonaka 
49609cdb1c70Snonaka 	/* reset Tx and Rx rings */
49619cdb1c70Snonaka 	sc->qfullmsk = 0;
49629cdb1c70Snonaka 	for (qid = 0; qid < 4; qid++)
49639cdb1c70Snonaka 		run_free_tx_ring(sc, qid);
49649cdb1c70Snonaka 	run_free_rx_ring(sc);
49659cdb1c70Snonaka }
49669cdb1c70Snonaka 
49679cdb1c70Snonaka #ifndef IEEE80211_STA_ONLY
49689cdb1c70Snonaka static int
49699cdb1c70Snonaka run_setup_beacon(struct run_softc *sc)
49709cdb1c70Snonaka {
49719cdb1c70Snonaka 	struct ieee80211com *ic = &sc->sc_ic;
49729cdb1c70Snonaka 	struct rt2860_txwi txwi;
49739cdb1c70Snonaka 	struct mbuf *m;
4974faca41fbSmlelstv 	uint16_t txwisize;
49759cdb1c70Snonaka 	int ridx;
49769cdb1c70Snonaka 
49779cdb1c70Snonaka 	if ((m = ieee80211_beacon_alloc(ic, ic->ic_bss, &sc->sc_bo)) == NULL)
49784e8e6643Sskrll 		return ENOBUFS;
49799cdb1c70Snonaka 
49804e8e6643Sskrll 	memset(&txwi, 0, sizeof(txwi));
49819cdb1c70Snonaka 	txwi.wcid = 0xff;
49829cdb1c70Snonaka 	txwi.len = htole16(m->m_pkthdr.len);
49839cdb1c70Snonaka 	/* send beacons at the lowest available rate */
49849cdb1c70Snonaka 	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
49859cdb1c70Snonaka 	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
49869cdb1c70Snonaka 	txwi.phy = htole16(rt2860_rates[ridx].mcs);
49879cdb1c70Snonaka 	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
49889cdb1c70Snonaka 		txwi.phy |= htole16(RT2860_PHY_OFDM);
49899cdb1c70Snonaka 	txwi.txop = RT2860_TX_TXOP_HT;
49909cdb1c70Snonaka 	txwi.flags = RT2860_TX_TS;
49919cdb1c70Snonaka 
4992faca41fbSmlelstv 	txwisize = (sc->mac_ver == 0x5592) ?
4993faca41fbSmlelstv 	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
49949cdb1c70Snonaka 	run_write_region_1(sc, RT2860_BCN_BASE(0),
4995faca41fbSmlelstv 	    (uint8_t *)&txwi, txwisize);
4996faca41fbSmlelstv 	run_write_region_1(sc, RT2860_BCN_BASE(0) + txwisize,
4997faca41fbSmlelstv 	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
49989cdb1c70Snonaka 
49999cdb1c70Snonaka 	m_freem(m);
50009cdb1c70Snonaka 
50014e8e6643Sskrll 	return 0;
50029cdb1c70Snonaka }
50039cdb1c70Snonaka #endif
50049cdb1c70Snonaka 
500560d3fae6Schristos MODULE(MODULE_CLASS_DRIVER, if_run, NULL);
50069cdb1c70Snonaka 
50079cdb1c70Snonaka #ifdef _MODULE
50089cdb1c70Snonaka #include "ioconf.c"
50099cdb1c70Snonaka #endif
50109cdb1c70Snonaka 
50119cdb1c70Snonaka static int
50129cdb1c70Snonaka if_run_modcmd(modcmd_t cmd, void *arg)
50139cdb1c70Snonaka {
50149cdb1c70Snonaka 	int error = 0;
50159cdb1c70Snonaka 
50169cdb1c70Snonaka 	switch (cmd) {
50179cdb1c70Snonaka 	case MODULE_CMD_INIT:
50189cdb1c70Snonaka #ifdef _MODULE
50199cdb1c70Snonaka 		error = config_init_component(cfdriver_ioconf_run,
50209cdb1c70Snonaka 		    cfattach_ioconf_run, cfdata_ioconf_run);
50219cdb1c70Snonaka #endif
50224e8e6643Sskrll 		return error;
50239cdb1c70Snonaka 	case MODULE_CMD_FINI:
50249cdb1c70Snonaka #ifdef _MODULE
50259cdb1c70Snonaka 		error = config_fini_component(cfdriver_ioconf_run,
50269cdb1c70Snonaka 		    cfattach_ioconf_run, cfdata_ioconf_run);
50279cdb1c70Snonaka #endif
50284e8e6643Sskrll 		return error;
50299cdb1c70Snonaka 	default:
50304e8e6643Sskrll 		return ENOTTY;
50319cdb1c70Snonaka 	}
50329cdb1c70Snonaka }
5033