xref: /openbsd-src/sys/dev/usb/if_run.c (revision 81508fe356eb7772a68118f65f91723ce5261d7d)
1*81508fe3Sjsg /*	$OpenBSD: if_run.c,v 1.140 2024/05/23 03:21:08 jsg Exp $	*/
230aa40ebSdamien 
330aa40ebSdamien /*-
46df15833Sdamien  * Copyright (c) 2008-2010 Damien Bergamini <damien.bergamini@free.fr>
5d80de052Sstsp  * Copyright (c) 2013-2014 Kevin Lo
630aa40ebSdamien  *
730aa40ebSdamien  * Permission to use, copy, modify, and distribute this software for any
830aa40ebSdamien  * purpose with or without fee is hereby granted, provided that the above
930aa40ebSdamien  * copyright notice and this permission notice appear in all copies.
1030aa40ebSdamien  *
1130aa40ebSdamien  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1230aa40ebSdamien  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1330aa40ebSdamien  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1430aa40ebSdamien  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1530aa40ebSdamien  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1630aa40ebSdamien  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1730aa40ebSdamien  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1830aa40ebSdamien  */
1930aa40ebSdamien 
2030aa40ebSdamien /*-
21d80de052Sstsp  * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver.
2230aa40ebSdamien  * http://www.ralinktech.com/
2330aa40ebSdamien  */
2430aa40ebSdamien 
2530aa40ebSdamien #include "bpfilter.h"
2630aa40ebSdamien 
2730aa40ebSdamien #include <sys/param.h>
2830aa40ebSdamien #include <sys/sockio.h>
2930aa40ebSdamien #include <sys/mbuf.h>
3030aa40ebSdamien #include <sys/systm.h>
3130aa40ebSdamien #include <sys/timeout.h>
3230aa40ebSdamien #include <sys/device.h>
339b18ffb8Sguenther #include <sys/endian.h>
3430aa40ebSdamien 
3530aa40ebSdamien #include <machine/intr.h>
3630aa40ebSdamien 
3730aa40ebSdamien #if NBPFILTER > 0
3830aa40ebSdamien #include <net/bpf.h>
3930aa40ebSdamien #endif
4030aa40ebSdamien #include <net/if.h>
4130aa40ebSdamien #include <net/if_dl.h>
4230aa40ebSdamien #include <net/if_media.h>
4330aa40ebSdamien 
4430aa40ebSdamien #include <netinet/in.h>
4530aa40ebSdamien #include <netinet/if_ether.h>
4630aa40ebSdamien 
4730aa40ebSdamien #include <net80211/ieee80211_var.h>
4830aa40ebSdamien #include <net80211/ieee80211_amrr.h>
4930aa40ebSdamien #include <net80211/ieee80211_radiotap.h>
5030aa40ebSdamien 
5130aa40ebSdamien #include <dev/usb/usb.h>
5230aa40ebSdamien #include <dev/usb/usbdi.h>
5330aa40ebSdamien #include <dev/usb/usbdi_util.h>
5430aa40ebSdamien #include <dev/usb/usbdevs.h>
5530aa40ebSdamien 
5630aa40ebSdamien #include <dev/ic/rt2860reg.h>		/* shared with ral(4) */
5730aa40ebSdamien #include <dev/usb/if_runvar.h>
5830aa40ebSdamien 
5930aa40ebSdamien #ifdef RUN_DEBUG
6030aa40ebSdamien #define DPRINTF(x)	do { if (run_debug) printf x; } while (0)
6130aa40ebSdamien #define DPRINTFN(n, x)	do { if (run_debug >= (n)) printf x; } while (0)
6230aa40ebSdamien int run_debug = 0;
6330aa40ebSdamien #else
6430aa40ebSdamien #define DPRINTF(x)
6530aa40ebSdamien #define DPRINTFN(n, x)
6630aa40ebSdamien #endif
6730aa40ebSdamien 
6830aa40ebSdamien #define USB_ID(v, p)	{ USB_VENDOR_##v, USB_PRODUCT_##v##_##p }
6930aa40ebSdamien static const struct usb_devno run_devs[] = {
70d25a991fSdamien 	USB_ID(ABOCOM,		RT2770),
71d25a991fSdamien 	USB_ID(ABOCOM,		RT2870),
72d25a991fSdamien 	USB_ID(ABOCOM,		RT3070),
73d25a991fSdamien 	USB_ID(ABOCOM,		RT3071),
74d25a991fSdamien 	USB_ID(ABOCOM,		RT3072),
75d25a991fSdamien 	USB_ID(ABOCOM2,		RT2870_1),
76d25a991fSdamien 	USB_ID(ACCTON,		RT2770),
77d25a991fSdamien 	USB_ID(ACCTON,		RT2870_1),
78d25a991fSdamien 	USB_ID(ACCTON,		RT2870_2),
79d25a991fSdamien 	USB_ID(ACCTON,		RT2870_3),
80d25a991fSdamien 	USB_ID(ACCTON,		RT2870_4),
81d25a991fSdamien 	USB_ID(ACCTON,		RT2870_5),
8222a9c20aSdamien 	USB_ID(ACCTON,		RT3070),
83b543da8fSdamien 	USB_ID(ACCTON,		RT3070_1),
84b543da8fSdamien 	USB_ID(ACCTON,		RT3070_2),
85b543da8fSdamien 	USB_ID(ACCTON,		RT3070_3),
86b543da8fSdamien 	USB_ID(ACCTON,		RT3070_4),
8722a9c20aSdamien 	USB_ID(ACCTON,		RT3070_5),
88faf60a06Sjsg 	USB_ID(ACCTON,		RT3070_6),
89d25a991fSdamien 	USB_ID(AIRTIES,		RT3070),
90faf60a06Sjsg 	USB_ID(AIRTIES,		RT3070_2),
9194416ec4Sdamien 	USB_ID(ALLWIN,		RT2070),
9294416ec4Sdamien 	USB_ID(ALLWIN,		RT2770),
9394416ec4Sdamien 	USB_ID(ALLWIN,		RT2870),
9494416ec4Sdamien 	USB_ID(ALLWIN,		RT3070),
9594416ec4Sdamien 	USB_ID(ALLWIN,		RT3071),
9694416ec4Sdamien 	USB_ID(ALLWIN,		RT3072),
9794416ec4Sdamien 	USB_ID(ALLWIN,		RT3572),
9810a4818eSdamien 	USB_ID(AMIGO,		RT2870_1),
9910a4818eSdamien 	USB_ID(AMIGO,		RT2870_2),
100d25a991fSdamien 	USB_ID(AMIT,		CGWLUSB2GNR),
101d25a991fSdamien 	USB_ID(AMIT,		RT2870_1),
102d25a991fSdamien 	USB_ID(AMIT2,		RT2870),
103d25a991fSdamien 	USB_ID(ASUS,		RT2870_1),
104d25a991fSdamien 	USB_ID(ASUS,		RT2870_2),
105d25a991fSdamien 	USB_ID(ASUS,		RT2870_3),
10610a4818eSdamien 	USB_ID(ASUS,		RT2870_4),
10710a4818eSdamien 	USB_ID(ASUS,		RT2870_5),
10822a9c20aSdamien 	USB_ID(ASUS,		RT3070_1),
10925cf3133Sjsg 	USB_ID(ASUS,		USBN13),
11025cf3133Sjsg 	USB_ID(ASUS,		USBN53),
111d80de052Sstsp 	USB_ID(ASUS,		USBN66),
112d25a991fSdamien 	USB_ID(ASUS2,		USBN11),
113d25a991fSdamien 	USB_ID(AZUREWAVE,	RT2870_1),
11410a4818eSdamien 	USB_ID(AZUREWAVE,	RT2870_2),
115b543da8fSdamien 	USB_ID(AZUREWAVE,	RT3070_1),
116b543da8fSdamien 	USB_ID(AZUREWAVE,	RT3070_2),
117b543da8fSdamien 	USB_ID(AZUREWAVE,	RT3070_3),
118faf60a06Sjsg 	USB_ID(AZUREWAVE,	RT3070_4),
119faf60a06Sjsg 	USB_ID(AZUREWAVE,	RT3070_5),
120d80de052Sstsp 	USB_ID(BELKIN,		F9L1103),
121d25a991fSdamien 	USB_ID(BELKIN,		F5D8053V3),
122d25a991fSdamien 	USB_ID(BELKIN,		F5D8055),
12313d1a8f1Shalex 	USB_ID(BELKIN,		F5D8055V2),
124d25a991fSdamien 	USB_ID(BELKIN,		F6D4050V1),
12566330f63Sjasper 	USB_ID(BELKIN,		F6D4050V2),
126faf60a06Sjsg 	USB_ID(BELKIN,		F7D1101V2),
127d25a991fSdamien 	USB_ID(BELKIN,		RT2870_1),
128d25a991fSdamien 	USB_ID(BELKIN,		RT2870_2),
129faf60a06Sjsg 	USB_ID(BEWAN,		RT3070),
130faf60a06Sjsg 	USB_ID(CISCOLINKSYS,	AE1000),
131faf60a06Sjsg 	USB_ID(CISCOLINKSYS,	AM10),
132b543da8fSdamien 	USB_ID(CISCOLINKSYS2,	RT3070),
13322a9c20aSdamien 	USB_ID(CISCOLINKSYS3,	RT3070),
134d25a991fSdamien 	USB_ID(CONCEPTRONIC2,	RT2870_1),
135d25a991fSdamien 	USB_ID(CONCEPTRONIC2,	RT2870_2),
136d25a991fSdamien 	USB_ID(CONCEPTRONIC2,	RT2870_3),
137d25a991fSdamien 	USB_ID(CONCEPTRONIC2,	RT2870_5),
138d25a991fSdamien 	USB_ID(CONCEPTRONIC2,	RT2870_6),
139d25a991fSdamien 	USB_ID(CONCEPTRONIC2,	RT2870_7),
140d25a991fSdamien 	USB_ID(CONCEPTRONIC2,	RT2870_8),
14122a9c20aSdamien 	USB_ID(CONCEPTRONIC2,	RT3070_1),
14222a9c20aSdamien 	USB_ID(CONCEPTRONIC2,	RT3070_2),
14357cd9f0cStedu 	USB_ID(CONCEPTRONIC2,	RT3070_3),
144d25a991fSdamien 	USB_ID(CONCEPTRONIC2,	VIGORN61),
145d25a991fSdamien 	USB_ID(COREGA,		CGWLUSB300GNM),
146d25a991fSdamien 	USB_ID(COREGA,		RT2870_1),
147d25a991fSdamien 	USB_ID(COREGA,		RT2870_2),
148d25a991fSdamien 	USB_ID(COREGA,		RT2870_3),
149b543da8fSdamien 	USB_ID(COREGA,		RT3070),
150d25a991fSdamien 	USB_ID(CYBERTAN,	RT2870),
151f9a9fbedSzhuk 	USB_ID(DLINK,		DWA125B2),
15225cf3133Sjsg 	USB_ID(DLINK,		DWA127),
153cc2c4b1aSstsp 	USB_ID(DLINK,		DWA130F1),
1544057595dSstsp 	USB_ID(DLINK,		DWA137A1),
155d80de052Sstsp 	USB_ID(DLINK,		DWA140B3),
1564057595dSstsp 	USB_ID(DLINK,		DWA140D1),
157d80de052Sstsp 	USB_ID(DLINK,		DWA160B2),
158d80de052Sstsp 	USB_ID(DLINK,	 	DWA162),
159d25a991fSdamien 	USB_ID(DLINK,		RT2870),
160d25a991fSdamien 	USB_ID(DLINK,		RT3072),
161d25a991fSdamien 	USB_ID(DLINK2,		DWA130),
162d25a991fSdamien 	USB_ID(DLINK2,		RT2870_1),
163d25a991fSdamien 	USB_ID(DLINK2,		RT2870_2),
1643466c6bfSdamien 	USB_ID(DLINK2,		RT3070_1),
1653466c6bfSdamien 	USB_ID(DLINK2,		RT3070_2),
1663466c6bfSdamien 	USB_ID(DLINK2,		RT3070_3),
167b543da8fSdamien 	USB_ID(DLINK2,		RT3070_4),
16822a9c20aSdamien 	USB_ID(DLINK2,		RT3070_5),
169d25a991fSdamien 	USB_ID(DLINK2,		RT3072),
17022a9c20aSdamien 	USB_ID(DLINK2,		RT3072_1),
171faf60a06Sjsg 	USB_ID(DVICO,		RT3070),
172d25a991fSdamien 	USB_ID(EDIMAX,		EW7717),
173d25a991fSdamien 	USB_ID(EDIMAX,		EW7718),
174faf60a06Sjsg 	USB_ID(EDIMAX,		EW7722UTN),
175d25a991fSdamien 	USB_ID(EDIMAX,		RT2870_1),
176b543da8fSdamien 	USB_ID(ENCORE,		RT3070_1),
177b543da8fSdamien 	USB_ID(ENCORE,		RT3070_2),
178b543da8fSdamien 	USB_ID(ENCORE,		RT3070_3),
179d25a991fSdamien 	USB_ID(GIGABYTE,	GNWB31N),
180d25a991fSdamien 	USB_ID(GIGABYTE,	GNWB32L),
181d25a991fSdamien 	USB_ID(GIGABYTE,	RT2870_1),
182b543da8fSdamien 	USB_ID(GIGASET,		RT3070_1),
183b543da8fSdamien 	USB_ID(GIGASET,		RT3070_2),
184504ec6dfSdamien 	USB_ID(GUILLEMOT,	HWNU300),
185d9154ed0Sdamien 	USB_ID(HAWKING,		HWDN2),
186d25a991fSdamien 	USB_ID(HAWKING,		HWUN2),
187d25a991fSdamien 	USB_ID(HAWKING,		RT2870_1),
188d25a991fSdamien 	USB_ID(HAWKING,		RT2870_2),
189d9154ed0Sdamien 	USB_ID(HAWKING,		RT2870_3),
190d9154ed0Sdamien 	USB_ID(HAWKING,		RT2870_4),
191d9154ed0Sdamien 	USB_ID(HAWKING,		RT2870_5),
192b543da8fSdamien 	USB_ID(IODATA,		RT3072_1),
193b543da8fSdamien 	USB_ID(IODATA,		RT3072_2),
194b543da8fSdamien 	USB_ID(IODATA,		RT3072_3),
195b543da8fSdamien 	USB_ID(IODATA,		RT3072_4),
19622a9c20aSdamien 	USB_ID(LINKSYS4,	RT3070),
197d25a991fSdamien 	USB_ID(LINKSYS4,	WUSB100),
1988bfd3c3dSdamien 	USB_ID(LINKSYS4,	WUSB54GCV3),
199d25a991fSdamien 	USB_ID(LINKSYS4,	WUSB600N),
200dbc2be93Sdamien 	USB_ID(LINKSYS4,	WUSB600NV2),
20125cf3133Sjsg 	USB_ID(LOGITEC,		LANW150NU2),
202faf60a06Sjsg 	USB_ID(LOGITEC,		LANW300NU2),
20325cf3133Sjsg 	USB_ID(LOGITEC,		LANW300NU2S),
204d25a991fSdamien 	USB_ID(LOGITEC,		RT2870_1),
205d25a991fSdamien 	USB_ID(LOGITEC,		RT2870_2),
206d25a991fSdamien 	USB_ID(LOGITEC,		RT2870_3),
20722a9c20aSdamien 	USB_ID(MELCO,		RT2870_1),
20822a9c20aSdamien 	USB_ID(MELCO,		RT2870_2),
209d25a991fSdamien 	USB_ID(MELCO,		WLIUCAG300N),
210d25a991fSdamien 	USB_ID(MELCO,		WLIUCG300N),
211faf60a06Sjsg 	USB_ID(MELCO,		WLIUCG301N),
212d25a991fSdamien 	USB_ID(MELCO,		WLIUCGN),
2133124ddf2Sdamien 	USB_ID(MELCO,		WLIUCGNHP),
21424be49d2Sdamien 	USB_ID(MELCO,		WLIUCGNM),
21525cf3133Sjsg 	USB_ID(MELCO,		WLIUCGNM2),
216dbc2be93Sdamien 	USB_ID(MOTOROLA4,	RT2770),
21722a9c20aSdamien 	USB_ID(MOTOROLA4,	RT3070),
218b543da8fSdamien 	USB_ID(MSI,		RT3070_1),
219b543da8fSdamien 	USB_ID(MSI,		RT3070_2),
220b543da8fSdamien 	USB_ID(MSI,		RT3070_3),
221b543da8fSdamien 	USB_ID(MSI,		RT3070_4),
222b543da8fSdamien 	USB_ID(MSI,		RT3070_5),
223b543da8fSdamien 	USB_ID(MSI,		RT3070_6),
224b543da8fSdamien 	USB_ID(MSI,		RT3070_7),
22522a9c20aSdamien 	USB_ID(MSI,		RT3070_8),
22622a9c20aSdamien 	USB_ID(MSI,		RT3070_9),
22722a9c20aSdamien 	USB_ID(MSI,		RT3070_10),
22822a9c20aSdamien 	USB_ID(MSI,		RT3070_11),
229faf60a06Sjsg 	USB_ID(MSI,		RT3070_12),
230faf60a06Sjsg 	USB_ID(MSI,		RT3070_13),
231faf60a06Sjsg 	USB_ID(MSI,		RT3070_14),
232faf60a06Sjsg 	USB_ID(MSI,		RT3070_15),
233faf60a06Sjsg 	USB_ID(OVISLINK,	RT3071),
2348bd27983Sdamien 	USB_ID(OVISLINK,	RT3072),
235b543da8fSdamien 	USB_ID(PARA,		RT3070),
23610a4818eSdamien 	USB_ID(PEGATRON,	RT2870),
237d25a991fSdamien 	USB_ID(PEGATRON,	RT3070),
2383466c6bfSdamien 	USB_ID(PEGATRON,	RT3070_2),
2398bd27983Sdamien 	USB_ID(PEGATRON,	RT3070_3),
240faf60a06Sjsg 	USB_ID(PEGATRON,	RT3072),
241d25a991fSdamien 	USB_ID(PHILIPS,		RT2870),
242d25a991fSdamien 	USB_ID(PLANEX2,		GWUS300MINIS),
24324be49d2Sdamien 	USB_ID(PLANEX2,		GWUSMICRO300),
244d25a991fSdamien 	USB_ID(PLANEX2,		GWUSMICRON),
245d25a991fSdamien 	USB_ID(PLANEX2,		RT2870),
246d25a991fSdamien 	USB_ID(PLANEX2,		RT3070),
24710a4818eSdamien 	USB_ID(QCOM,		RT2870),
248d25a991fSdamien 	USB_ID(QUANTA,		RT3070),
24910a4818eSdamien 	USB_ID(RALINK,		RT2070),
25030aa40ebSdamien 	USB_ID(RALINK,		RT2770),
25130aa40ebSdamien 	USB_ID(RALINK,		RT2870),
25230aa40ebSdamien 	USB_ID(RALINK,		RT3070),
25330aa40ebSdamien 	USB_ID(RALINK,		RT3071),
25430aa40ebSdamien 	USB_ID(RALINK,		RT3072),
25522a9c20aSdamien 	USB_ID(RALINK,		RT3370),
256dbc2be93Sdamien 	USB_ID(RALINK,		RT3572),
257d80de052Sstsp 	USB_ID(RALINK,		RT3573),
258d80de052Sstsp 	USB_ID(RALINK,		RT5370),
2593d28c107Sstsp 	USB_ID(RALINK,		RT5372),
26031c5b01bSstsp 	USB_ID(RALINK,		RT5572),
26122a9c20aSdamien 	USB_ID(RALINK,		RT8070),
262d80de052Sstsp 	USB_ID(SAMSUNG,		WIS09ABGN),
263d25a991fSdamien 	USB_ID(SAMSUNG2,	RT2870_1),
26430aa40ebSdamien 	USB_ID(SENAO,		RT2870_1),
26530aa40ebSdamien 	USB_ID(SENAO,		RT2870_2),
26610a4818eSdamien 	USB_ID(SENAO,		RT2870_3),
26710a4818eSdamien 	USB_ID(SENAO,		RT2870_4),
26830aa40ebSdamien 	USB_ID(SENAO,		RT3070),
2697a18474dSdamien 	USB_ID(SENAO,		RT3071),
270b543da8fSdamien 	USB_ID(SENAO,		RT3072_1),
271b543da8fSdamien 	USB_ID(SENAO,		RT3072_2),
272b543da8fSdamien 	USB_ID(SENAO,		RT3072_3),
273b543da8fSdamien 	USB_ID(SENAO,		RT3072_4),
274b543da8fSdamien 	USB_ID(SENAO,		RT3072_5),
275d80de052Sstsp 	USB_ID(SITECOMEU,	WL302),
276d80de052Sstsp 	USB_ID(SITECOMEU,	WL315),
277d80de052Sstsp 	USB_ID(SITECOMEU,	WL321),
278d80de052Sstsp 	USB_ID(SITECOMEU,	RT3070_3),
279d80de052Sstsp 	USB_ID(SITECOMEU,	WL302),
280d80de052Sstsp 	USB_ID(SITECOMEU,	WL344),
281d80de052Sstsp 	USB_ID(SITECOMEU,	WL329),
282d80de052Sstsp 	USB_ID(SITECOMEU,	WL345),
283d25a991fSdamien 	USB_ID(SITECOMEU,	RT2870_1),
284d25a991fSdamien 	USB_ID(SITECOMEU,	RT2870_2),
285d25a991fSdamien 	USB_ID(SITECOMEU,	RT2870_3),
286faf60a06Sjsg 	USB_ID(SITECOMEU,	RT3070_1),
287b543da8fSdamien 	USB_ID(SITECOMEU,	RT3072_3),
288b543da8fSdamien 	USB_ID(SITECOMEU,	RT3072_4),
289faf60a06Sjsg 	USB_ID(SITECOMEU,	RT3072_5),
290d80de052Sstsp 	USB_ID(SITECOMEU,	RT3072_6),
2917fb3a883Sdamien 	USB_ID(SITECOMEU,	WL302),
2927fb3a883Sdamien 	USB_ID(SITECOMEU,	WL315),
2937fb3a883Sdamien 	USB_ID(SITECOMEU,	WL321),
2947fb3a883Sdamien 	USB_ID(SITECOMEU,	WL324),
2957fb3a883Sdamien 	USB_ID(SITECOMEU,	WL329),
2967fb3a883Sdamien 	USB_ID(SITECOMEU,	WL343),
2977fb3a883Sdamien 	USB_ID(SITECOMEU,	WL344),
2987fb3a883Sdamien 	USB_ID(SITECOMEU,	WL345),
2997fb3a883Sdamien 	USB_ID(SITECOMEU,	WL349V4),
300901befc6Sdamien 	USB_ID(SITECOMEU,	WL608),
301faf60a06Sjsg 	USB_ID(SITECOMEU,	WLA4000),
302faf60a06Sjsg 	USB_ID(SITECOMEU,	WLA5000),
303d25a991fSdamien 	USB_ID(SPARKLAN,	RT2870_1),
304faf60a06Sjsg 	USB_ID(SPARKLAN,	RT2870_2),
30510a4818eSdamien 	USB_ID(SPARKLAN,	RT3070),
306f26e83f9Sdamien 	USB_ID(SWEEX2,		LW153),
307d25a991fSdamien 	USB_ID(SWEEX2,		LW303),
308d25a991fSdamien 	USB_ID(SWEEX2,		LW313),
30922a9c20aSdamien 	USB_ID(TOSHIBA,		RT3070),
31030aa40ebSdamien 	USB_ID(UMEDIA,		RT2870_1),
311faf60a06Sjsg 	USB_ID(UMEDIA,		TEW645UB),
312d25a991fSdamien 	USB_ID(ZCOM,		RT2870_1),
313d25a991fSdamien 	USB_ID(ZCOM,		RT2870_2),
31430aa40ebSdamien 	USB_ID(ZINWELL,		RT2870_1),
31530aa40ebSdamien 	USB_ID(ZINWELL,		RT2870_2),
3163466c6bfSdamien 	USB_ID(ZINWELL,		RT3070),
317b543da8fSdamien 	USB_ID(ZINWELL,		RT3072_1),
318b543da8fSdamien 	USB_ID(ZINWELL,		RT3072_2),
319faf60a06Sjsg 	USB_ID(ZYXEL,		NWD2105),
320faf60a06Sjsg 	USB_ID(ZYXEL,		NWD211AN),
32122a9c20aSdamien 	USB_ID(ZYXEL,		RT2870_1),
322faf60a06Sjsg 	USB_ID(ZYXEL,		RT2870_2),
323faf60a06Sjsg 	USB_ID(ZYXEL,		RT3070)
32430aa40ebSdamien };
32530aa40ebSdamien 
32630aa40ebSdamien int		run_match(struct device *, void *, void *);
32730aa40ebSdamien void		run_attach(struct device *, struct device *, void *);
32830aa40ebSdamien int		run_detach(struct device *, int);
32930aa40ebSdamien int		run_alloc_rx_ring(struct run_softc *);
33030aa40ebSdamien void		run_free_rx_ring(struct run_softc *);
33130aa40ebSdamien int		run_alloc_tx_ring(struct run_softc *, int);
33230aa40ebSdamien void		run_free_tx_ring(struct run_softc *, int);
33330aa40ebSdamien int		run_load_microcode(struct run_softc *);
33430aa40ebSdamien int		run_reset(struct run_softc *);
33530aa40ebSdamien int		run_read(struct run_softc *, uint16_t, uint32_t *);
33630aa40ebSdamien int		run_read_region_1(struct run_softc *, uint16_t, uint8_t *,
33730aa40ebSdamien 		    int);
33830aa40ebSdamien int		run_write_2(struct run_softc *, uint16_t, uint16_t);
33930aa40ebSdamien int		run_write(struct run_softc *, uint16_t, uint32_t);
34030aa40ebSdamien int		run_write_region_1(struct run_softc *, uint16_t,
34130aa40ebSdamien 		    const uint8_t *, int);
34230aa40ebSdamien int		run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
343d80de052Sstsp int		run_efuse_read(struct run_softc *, uint16_t, uint16_t *);
34430aa40ebSdamien int		run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
34530aa40ebSdamien int		run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
3462548be7aSmlarkin int		run_rt2870_rf_write(struct run_softc *, uint8_t, uint32_t);
34730aa40ebSdamien int		run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
34830aa40ebSdamien int		run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
34930aa40ebSdamien int		run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
35030aa40ebSdamien int		run_bbp_write(struct run_softc *, uint8_t, uint8_t);
35130aa40ebSdamien int		run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
35230aa40ebSdamien const char *	run_get_rf(int);
353d80de052Sstsp void		run_get_txpower(struct run_softc *);
354d80de052Sstsp void		run_rt3593_get_txpower(struct run_softc *);
35530aa40ebSdamien int		run_read_eeprom(struct run_softc *);
35630aa40ebSdamien struct		ieee80211_node *run_node_alloc(struct ieee80211com *);
35730aa40ebSdamien int		run_media_change(struct ifnet *);
35830aa40ebSdamien void		run_next_scan(void *);
35930aa40ebSdamien void		run_task(void *);
36030aa40ebSdamien void		run_do_async(struct run_softc *, void (*)(struct run_softc *,
36130aa40ebSdamien 		    void *), void *, int);
36230aa40ebSdamien int		run_newstate(struct ieee80211com *, enum ieee80211_state, int);
36330aa40ebSdamien void		run_newstate_cb(struct run_softc *, void *);
36430aa40ebSdamien void		run_updateedca(struct ieee80211com *);
36530aa40ebSdamien void		run_updateedca_cb(struct run_softc *, void *);
36630aa40ebSdamien int		run_set_key(struct ieee80211com *, struct ieee80211_node *,
36730aa40ebSdamien 		    struct ieee80211_key *);
36830aa40ebSdamien void		run_set_key_cb(struct run_softc *, void *);
36930aa40ebSdamien void		run_delete_key(struct ieee80211com *, struct ieee80211_node *,
37030aa40ebSdamien 		    struct ieee80211_key *);
37130aa40ebSdamien void		run_delete_key_cb(struct run_softc *, void *);
37230aa40ebSdamien void		run_calibrate_to(void *);
37330aa40ebSdamien void		run_calibrate_cb(struct run_softc *, void *);
37430aa40ebSdamien void		run_newassoc(struct ieee80211com *, struct ieee80211_node *,
37530aa40ebSdamien 		    int);
3768fbaf8a2Sstsp void		run_rx_frame(struct run_softc *, uint8_t *, int,
3778fbaf8a2Sstsp 		    struct mbuf_list *);
378ab0b1be7Smglocker void		run_rxeof(struct usbd_xfer *, void *, usbd_status);
379ab0b1be7Smglocker void		run_txeof(struct usbd_xfer *, void *, usbd_status);
38030aa40ebSdamien int		run_tx(struct run_softc *, struct mbuf *,
38130aa40ebSdamien 		    struct ieee80211_node *);
38230aa40ebSdamien void		run_start(struct ifnet *);
38330aa40ebSdamien void		run_watchdog(struct ifnet *);
38430aa40ebSdamien int		run_ioctl(struct ifnet *, u_long, caddr_t);
385d80de052Sstsp void		run_iq_calib(struct run_softc *, u_int);
38630aa40ebSdamien void		run_select_chan_group(struct run_softc *, int);
3875f5eab5eSdamien void		run_set_agc(struct run_softc *, uint8_t);
388cd4f4e38Sdamien void		run_set_rx_antenna(struct run_softc *, int);
38930aa40ebSdamien void		run_rt2870_set_chan(struct run_softc *, u_int);
39030aa40ebSdamien void		run_rt3070_set_chan(struct run_softc *, u_int);
39118327d80Sdamien void		run_rt3572_set_chan(struct run_softc *, u_int);
392d80de052Sstsp void		run_rt3593_set_chan(struct run_softc *, u_int);
393d80de052Sstsp void		run_rt5390_set_chan(struct run_softc *, u_int);
394d80de052Sstsp void		run_rt5592_set_chan(struct run_softc *, u_int);
39530aa40ebSdamien int		run_set_chan(struct run_softc *, struct ieee80211_channel *);
39630aa40ebSdamien void		run_enable_tsf_sync(struct run_softc *);
39730aa40ebSdamien void		run_enable_mrr(struct run_softc *);
39830aa40ebSdamien void		run_set_txpreamble(struct run_softc *);
39930aa40ebSdamien void		run_set_basicrates(struct run_softc *);
40030aa40ebSdamien void		run_set_leds(struct run_softc *, uint16_t);
40130aa40ebSdamien void		run_set_bssid(struct run_softc *, const uint8_t *);
40230aa40ebSdamien void		run_set_macaddr(struct run_softc *, const uint8_t *);
40330aa40ebSdamien void		run_updateslot(struct ieee80211com *);
40430aa40ebSdamien void		run_updateslot_cb(struct run_softc *, void *);
40530aa40ebSdamien #if NBPFILTER > 0
40630aa40ebSdamien int8_t		run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
40730aa40ebSdamien #endif
408d80de052Sstsp void		run_rt5390_bbp_init(struct run_softc *);
40930aa40ebSdamien int		run_bbp_init(struct run_softc *);
41030aa40ebSdamien int		run_rt3070_rf_init(struct run_softc *);
411d80de052Sstsp void		run_rt3593_rf_init(struct run_softc *);
412d80de052Sstsp void		run_rt5390_rf_init(struct run_softc *);
41330aa40ebSdamien int		run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
41430aa40ebSdamien 		    uint8_t *);
415e56800d9Sdamien void		run_rt3070_rf_setup(struct run_softc *);
416d80de052Sstsp void		run_rt3593_rf_setup(struct run_softc *);
417d80de052Sstsp void		run_rt5390_rf_setup(struct run_softc *);
41830aa40ebSdamien int		run_txrx_enable(struct run_softc *);
419d80de052Sstsp void		run_adjust_freq_offset(struct run_softc *);
42030aa40ebSdamien int		run_init(struct ifnet *);
42130aa40ebSdamien void		run_stop(struct ifnet *, int);
42230aa40ebSdamien 
42330aa40ebSdamien struct cfdriver run_cd = {
42430aa40ebSdamien 	NULL, "run", DV_IFNET
42530aa40ebSdamien };
42630aa40ebSdamien 
42730aa40ebSdamien const struct cfattach run_ca = {
42853c6612dSmpi 	sizeof (struct run_softc), run_match, run_attach, run_detach
42930aa40ebSdamien };
43030aa40ebSdamien 
43130aa40ebSdamien static const struct {
43230aa40ebSdamien 	uint32_t	reg;
43330aa40ebSdamien 	uint32_t	val;
43430aa40ebSdamien } rt2870_def_mac[] = {
43530aa40ebSdamien 	RT2870_DEF_MAC
43630aa40ebSdamien };
43730aa40ebSdamien 
43830aa40ebSdamien static const struct {
43930aa40ebSdamien 	uint8_t	reg;
44030aa40ebSdamien 	uint8_t	val;
44130aa40ebSdamien } rt2860_def_bbp[] = {
44230aa40ebSdamien 	RT2860_DEF_BBP
443d80de052Sstsp },rt5390_def_bbp[] = {
444d80de052Sstsp 	RT5390_DEF_BBP
445d80de052Sstsp },rt5592_def_bbp[] = {
446d80de052Sstsp 	RT5592_DEF_BBP
447d80de052Sstsp };
448d80de052Sstsp 
449d80de052Sstsp /*
450d80de052Sstsp  * Default values for BBP register R196 for RT5592.
451d80de052Sstsp  */
452d80de052Sstsp static const uint8_t rt5592_bbp_r196[] = {
453d80de052Sstsp 	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
454d80de052Sstsp 	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
455d80de052Sstsp 	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
456d80de052Sstsp 	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
457d80de052Sstsp 	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
458d80de052Sstsp 	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
459d80de052Sstsp 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
460d80de052Sstsp 	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
461d80de052Sstsp 	0x2e, 0x36, 0x30, 0x6e
46230aa40ebSdamien };
46330aa40ebSdamien 
46430aa40ebSdamien static const struct rfprog {
46530aa40ebSdamien 	uint8_t		chan;
46630aa40ebSdamien 	uint32_t	r1, r2, r3, r4;
46730aa40ebSdamien } rt2860_rf2850[] = {
46830aa40ebSdamien 	RT2860_RF2850
46930aa40ebSdamien };
47030aa40ebSdamien 
47130aa40ebSdamien struct {
47230aa40ebSdamien 	uint8_t	n, r, k;
4738bab76d8Sdamien } rt3070_freqs[] = {
4748bab76d8Sdamien 	RT3070_RF3052
47530aa40ebSdamien };
47630aa40ebSdamien 
477d80de052Sstsp static const struct rt5592_freqs {
478d80de052Sstsp 	uint16_t	n;
479d80de052Sstsp 	uint8_t		k, m, r;
480d80de052Sstsp } rt5592_freqs_20mhz[] = {
481d80de052Sstsp 	RT5592_RF5592_20MHZ
482d80de052Sstsp },rt5592_freqs_40mhz[] = {
483d80de052Sstsp 	RT5592_RF5592_40MHZ
484d80de052Sstsp };
485d80de052Sstsp 
48630aa40ebSdamien static const struct {
48730aa40ebSdamien 	uint8_t	reg;
48830aa40ebSdamien 	uint8_t	val;
48930aa40ebSdamien } rt3070_def_rf[] = {
49030aa40ebSdamien 	RT3070_DEF_RF
4918bab76d8Sdamien },rt3572_def_rf[] = {
4928bab76d8Sdamien 	RT3572_DEF_RF
493d80de052Sstsp },rt3593_def_rf[] = {
494d80de052Sstsp 	RT3593_DEF_RF
495d80de052Sstsp },rt5390_def_rf[] = {
496d80de052Sstsp 	RT5390_DEF_RF
497d80de052Sstsp },rt5392_def_rf[] = {
498d80de052Sstsp 	RT5392_DEF_RF
499d80de052Sstsp },rt5592_def_rf[] = {
500d80de052Sstsp 	RT5592_DEF_RF
501d80de052Sstsp },rt5592_2ghz_def_rf[] = {
502d80de052Sstsp 	RT5592_2GHZ_DEF_RF
503d80de052Sstsp },rt5592_5ghz_def_rf[] = {
504d80de052Sstsp 	RT5592_5GHZ_DEF_RF
505d80de052Sstsp };
506d80de052Sstsp 
507d80de052Sstsp static const struct {
508d80de052Sstsp 	u_int	firstchan;
509d80de052Sstsp 	u_int	lastchan;
510d80de052Sstsp 	uint8_t	reg;
511d80de052Sstsp 	uint8_t	val;
512d80de052Sstsp } rt5592_chan_5ghz[] = {
513d80de052Sstsp 	RT5592_CHAN_5GHZ
51430aa40ebSdamien };
51530aa40ebSdamien 
51630aa40ebSdamien int
run_match(struct device * parent,void * match,void * aux)51730aa40ebSdamien run_match(struct device *parent, void *match, void *aux)
51830aa40ebSdamien {
51930aa40ebSdamien 	struct usb_attach_arg *uaa = aux;
52030aa40ebSdamien 
5217ebc5b51Smpi 	if (uaa->iface == NULL || uaa->configno != 1)
52230aa40ebSdamien 		return UMATCH_NONE;
52330aa40ebSdamien 
52430aa40ebSdamien 	return (usb_lookup(run_devs, uaa->vendor, uaa->product) != NULL) ?
5257ebc5b51Smpi 	    UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE;
52630aa40ebSdamien }
52730aa40ebSdamien 
52830aa40ebSdamien void
run_attach(struct device * parent,struct device * self,void * aux)52930aa40ebSdamien run_attach(struct device *parent, struct device *self, void *aux)
53030aa40ebSdamien {
53130aa40ebSdamien 	struct run_softc *sc = (struct run_softc *)self;
53230aa40ebSdamien 	struct usb_attach_arg *uaa = aux;
53330aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
53430aa40ebSdamien 	struct ifnet *ifp = &ic->ic_if;
53530aa40ebSdamien 	usb_interface_descriptor_t *id;
53630aa40ebSdamien 	usb_endpoint_descriptor_t *ed;
5377ebc5b51Smpi 	int i, nrx, ntx, ntries;
5386755f0faSdamien 	uint32_t ver;
53930aa40ebSdamien 
54030aa40ebSdamien 	sc->sc_udev = uaa->device;
5417ebc5b51Smpi 	sc->sc_iface = uaa->iface;
54230aa40ebSdamien 
54330aa40ebSdamien 	/*
54430aa40ebSdamien 	 * Find all bulk endpoints.  There are 7 bulk endpoints: 1 for RX
54530aa40ebSdamien 	 * and 6 for TX (4 EDCAs + HCCA + Prio).
5465892192bSdamien 	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
5475892192bSdamien 	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
54830aa40ebSdamien 	 */
54930aa40ebSdamien 	nrx = ntx = 0;
55030aa40ebSdamien 	id = usbd_get_interface_descriptor(sc->sc_iface);
55130aa40ebSdamien 	for (i = 0; i < id->bNumEndpoints; i++) {
55230aa40ebSdamien 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
55330aa40ebSdamien 		if (ed == NULL || UE_GET_XFERTYPE(ed->bmAttributes) != UE_BULK)
55430aa40ebSdamien 			continue;
55530aa40ebSdamien 
55630aa40ebSdamien 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) {
55730aa40ebSdamien 			sc->rxq.pipe_no = ed->bEndpointAddress;
55830aa40ebSdamien 			nrx++;
5595892192bSdamien 		} else if (ntx < 4) {
56030aa40ebSdamien 			sc->txq[ntx].pipe_no = ed->bEndpointAddress;
56130aa40ebSdamien 			ntx++;
56230aa40ebSdamien 		}
56330aa40ebSdamien 	}
56430aa40ebSdamien 	/* make sure we've got them all */
5655892192bSdamien 	if (nrx < 1 || ntx < 4) {
56630aa40ebSdamien 		printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
56730aa40ebSdamien 		return;
56830aa40ebSdamien 	}
56930aa40ebSdamien 
570c33449aaSjakemsr 	usb_init_task(&sc->sc_task, run_task, sc, USB_TASK_TYPE_GENERIC);
57130aa40ebSdamien 	timeout_set(&sc->scan_to, run_next_scan, sc);
57230aa40ebSdamien 	timeout_set(&sc->calib_to, run_calibrate_to, sc);
57330aa40ebSdamien 
57430aa40ebSdamien 	sc->amrr.amrr_min_success_threshold =  1;
57530aa40ebSdamien 	sc->amrr.amrr_max_success_threshold = 10;
57630aa40ebSdamien 
57730aa40ebSdamien 	/* wait for the chip to settle */
57830aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
5796755f0faSdamien 		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0)
58030aa40ebSdamien 			return;
5816755f0faSdamien 		if (ver != 0 && ver != 0xffffffff)
58230aa40ebSdamien 			break;
58330aa40ebSdamien 		DELAY(10);
58430aa40ebSdamien 	}
58530aa40ebSdamien 	if (ntries == 100) {
58630aa40ebSdamien 		printf("%s: timeout waiting for NIC to initialize\n",
58730aa40ebSdamien 		    sc->sc_dev.dv_xname);
58830aa40ebSdamien 		return;
58930aa40ebSdamien 	}
5906755f0faSdamien 	sc->mac_ver = ver >> 16;
5916755f0faSdamien 	sc->mac_rev = ver & 0xffff;
59230aa40ebSdamien 
59330aa40ebSdamien 	/* retrieve RF rev. no and various other things from EEPROM */
59430aa40ebSdamien 	run_read_eeprom(sc);
59530aa40ebSdamien 
59630aa40ebSdamien 	printf("%s: MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), "
5976755f0faSdamien 	    "address %s\n", sc->sc_dev.dv_xname, sc->mac_ver,
5986755f0faSdamien 	    sc->mac_rev, run_get_rf(sc->rf_rev), sc->ntxchains,
59930aa40ebSdamien 	    sc->nrxchains, ether_sprintf(ic->ic_myaddr));
60030aa40ebSdamien 
60130aa40ebSdamien 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
60230aa40ebSdamien 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
60330aa40ebSdamien 	ic->ic_state = IEEE80211_S_INIT;
60430aa40ebSdamien 
60530aa40ebSdamien 	/* set device capabilities */
60630aa40ebSdamien 	ic->ic_caps =
60730aa40ebSdamien 	    IEEE80211_C_MONITOR |	/* monitor mode supported */
60830aa40ebSdamien 	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
60930aa40ebSdamien 	    IEEE80211_C_SHSLOT |	/* short slot time supported */
61030aa40ebSdamien 	    IEEE80211_C_WEP |		/* WEP */
61130aa40ebSdamien 	    IEEE80211_C_RSN;		/* WPA/RSN */
61230aa40ebSdamien 
61318327d80Sdamien 	if (sc->rf_rev == RT2860_RF_2750 ||
61418327d80Sdamien 	    sc->rf_rev == RT2860_RF_2850 ||
615d80de052Sstsp 	    sc->rf_rev == RT3070_RF_3052 ||
616d80de052Sstsp 	    sc->rf_rev == RT3070_RF_3053 ||
617d80de052Sstsp 	    sc->rf_rev == RT5592_RF_5592) {
61830aa40ebSdamien 		/* set supported .11a rates */
61930aa40ebSdamien 		ic->ic_sup_rates[IEEE80211_MODE_11A] =
62030aa40ebSdamien 		    ieee80211_std_rateset_11a;
62130aa40ebSdamien 
62230aa40ebSdamien 		/* set supported .11a channels */
62330aa40ebSdamien 		for (i = 14; i < nitems(rt2860_rf2850); i++) {
62430aa40ebSdamien 			uint8_t chan = rt2860_rf2850[i].chan;
62530aa40ebSdamien 			ic->ic_channels[chan].ic_freq =
62630aa40ebSdamien 			    ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
62730aa40ebSdamien 			ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A;
62830aa40ebSdamien 		}
62930aa40ebSdamien 	}
63030aa40ebSdamien 
63130aa40ebSdamien 	/* set supported .11b and .11g rates */
63230aa40ebSdamien 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
63330aa40ebSdamien 	ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
63430aa40ebSdamien 
63530aa40ebSdamien 	/* set supported .11b and .11g channels (1 through 14) */
63630aa40ebSdamien 	for (i = 1; i <= 14; i++) {
63730aa40ebSdamien 		ic->ic_channels[i].ic_freq =
63830aa40ebSdamien 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
63930aa40ebSdamien 		ic->ic_channels[i].ic_flags =
64030aa40ebSdamien 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
64130aa40ebSdamien 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
64230aa40ebSdamien 	}
64330aa40ebSdamien 
64430aa40ebSdamien 	ifp->if_softc = sc;
64530aa40ebSdamien 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
64630aa40ebSdamien 	ifp->if_ioctl = run_ioctl;
64730aa40ebSdamien 	ifp->if_start = run_start;
64830aa40ebSdamien 	ifp->if_watchdog = run_watchdog;
64930aa40ebSdamien 	memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
65030aa40ebSdamien 
65130aa40ebSdamien 	if_attach(ifp);
65230aa40ebSdamien 	ieee80211_ifattach(ifp);
65330aa40ebSdamien 	ic->ic_node_alloc = run_node_alloc;
65430aa40ebSdamien 	ic->ic_newassoc = run_newassoc;
65530aa40ebSdamien 	ic->ic_updateslot = run_updateslot;
65630aa40ebSdamien 	ic->ic_updateedca = run_updateedca;
65730aa40ebSdamien 	ic->ic_set_key = run_set_key;
65830aa40ebSdamien 	ic->ic_delete_key = run_delete_key;
65930aa40ebSdamien 	/* override state transition machine */
66030aa40ebSdamien 	sc->sc_newstate = ic->ic_newstate;
66130aa40ebSdamien 	ic->ic_newstate = run_newstate;
66230aa40ebSdamien 	ieee80211_media_init(ifp, run_media_change, ieee80211_media_status);
66330aa40ebSdamien 
66430aa40ebSdamien #if NBPFILTER > 0
66530aa40ebSdamien 	bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
66630aa40ebSdamien 	    sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
66730aa40ebSdamien 
66830aa40ebSdamien 	sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
66930aa40ebSdamien 	sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
67030aa40ebSdamien 	sc->sc_rxtap.wr_ihdr.it_present = htole32(RUN_RX_RADIOTAP_PRESENT);
67130aa40ebSdamien 
67230aa40ebSdamien 	sc->sc_txtap_len = sizeof sc->sc_txtapu;
67330aa40ebSdamien 	sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
67430aa40ebSdamien 	sc->sc_txtap.wt_ihdr.it_present = htole32(RUN_TX_RADIOTAP_PRESENT);
67530aa40ebSdamien #endif
67630aa40ebSdamien }
67730aa40ebSdamien 
67830aa40ebSdamien int
run_detach(struct device * self,int flags)67930aa40ebSdamien run_detach(struct device *self, int flags)
68030aa40ebSdamien {
68130aa40ebSdamien 	struct run_softc *sc = (struct run_softc *)self;
68230aa40ebSdamien 	struct ifnet *ifp = &sc->sc_ic.ic_if;
68330aa40ebSdamien 	int qid, s;
68430aa40ebSdamien 
68512136ef5Sjakemsr 	s = splusb();
68630aa40ebSdamien 
687c7438bddSjakemsr 	if (timeout_initialized(&sc->scan_to))
68830aa40ebSdamien 		timeout_del(&sc->scan_to);
689c7438bddSjakemsr 	if (timeout_initialized(&sc->calib_to))
69030aa40ebSdamien 		timeout_del(&sc->calib_to);
69130aa40ebSdamien 
69212136ef5Sjakemsr 	/* wait for all queued asynchronous commands to complete */
69312136ef5Sjakemsr 	usb_rem_wait_task(sc->sc_udev, &sc->sc_task);
69412136ef5Sjakemsr 
69512136ef5Sjakemsr 	usbd_ref_wait(sc->sc_udev);
69612136ef5Sjakemsr 
6979f3a1e51Sdamien 	if (ifp->if_softc != NULL) {
698de6cd8fbSdlg 		ifp->if_flags &= ~IFF_RUNNING;
699de6cd8fbSdlg 		ifq_clr_oactive(&ifp->if_snd);
70030aa40ebSdamien 		ieee80211_ifdetach(ifp);
70130aa40ebSdamien 		if_detach(ifp);
70230aa40ebSdamien 	}
70330aa40ebSdamien 
7045892192bSdamien 	for (qid = 0; qid < 4; qid++)
70530aa40ebSdamien 		run_free_tx_ring(sc, qid);
70630aa40ebSdamien 	run_free_rx_ring(sc);
70730aa40ebSdamien 
70830aa40ebSdamien 	splx(s);
70930aa40ebSdamien 
71030aa40ebSdamien 	return 0;
71130aa40ebSdamien }
71230aa40ebSdamien 
71330aa40ebSdamien int
run_alloc_rx_ring(struct run_softc * sc)71430aa40ebSdamien run_alloc_rx_ring(struct run_softc *sc)
71530aa40ebSdamien {
71630aa40ebSdamien 	struct run_rx_ring *rxq = &sc->rxq;
71730aa40ebSdamien 	int i, error;
71830aa40ebSdamien 
71930aa40ebSdamien 	error = usbd_open_pipe(sc->sc_iface, rxq->pipe_no, 0, &rxq->pipeh);
72030aa40ebSdamien 	if (error != 0)
72130aa40ebSdamien 		goto fail;
72230aa40ebSdamien 
72330aa40ebSdamien 	for (i = 0; i < RUN_RX_RING_COUNT; i++) {
72430aa40ebSdamien 		struct run_rx_data *data = &rxq->data[i];
72530aa40ebSdamien 
72630aa40ebSdamien 		data->sc = sc;	/* backpointer for callbacks */
72730aa40ebSdamien 
72830aa40ebSdamien 		data->xfer = usbd_alloc_xfer(sc->sc_udev);
72930aa40ebSdamien 		if (data->xfer == NULL) {
73030aa40ebSdamien 			error = ENOMEM;
73130aa40ebSdamien 			goto fail;
73230aa40ebSdamien 		}
73330aa40ebSdamien 		data->buf = usbd_alloc_buffer(data->xfer, RUN_MAX_RXSZ);
73430aa40ebSdamien 		if (data->buf == NULL) {
73530aa40ebSdamien 			error = ENOMEM;
73630aa40ebSdamien 			goto fail;
73730aa40ebSdamien 		}
73830aa40ebSdamien 	}
73930aa40ebSdamien 	if (error != 0)
74030aa40ebSdamien fail:		run_free_rx_ring(sc);
74130aa40ebSdamien 	return error;
74230aa40ebSdamien }
74330aa40ebSdamien 
74430aa40ebSdamien void
run_free_rx_ring(struct run_softc * sc)74530aa40ebSdamien run_free_rx_ring(struct run_softc *sc)
74630aa40ebSdamien {
74730aa40ebSdamien 	struct run_rx_ring *rxq = &sc->rxq;
74830aa40ebSdamien 	int i;
74930aa40ebSdamien 
75030aa40ebSdamien 	if (rxq->pipeh != NULL) {
75130aa40ebSdamien 		usbd_close_pipe(rxq->pipeh);
75230aa40ebSdamien 		rxq->pipeh = NULL;
75330aa40ebSdamien 	}
75430aa40ebSdamien 	for (i = 0; i < RUN_RX_RING_COUNT; i++) {
75530aa40ebSdamien 		if (rxq->data[i].xfer != NULL)
75630aa40ebSdamien 			usbd_free_xfer(rxq->data[i].xfer);
75730aa40ebSdamien 		rxq->data[i].xfer = NULL;
75830aa40ebSdamien 	}
75930aa40ebSdamien }
76030aa40ebSdamien 
76130aa40ebSdamien int
run_alloc_tx_ring(struct run_softc * sc,int qid)76230aa40ebSdamien run_alloc_tx_ring(struct run_softc *sc, int qid)
76330aa40ebSdamien {
76430aa40ebSdamien 	struct run_tx_ring *txq = &sc->txq[qid];
76530aa40ebSdamien 	int i, error;
7668bad3cf5Sstsp 	uint16_t txwisize;
7678bad3cf5Sstsp 
7688bad3cf5Sstsp 	txwisize = sizeof(struct rt2860_txwi);
7698bad3cf5Sstsp 	if (sc->mac_ver == 0x5592)
7708bad3cf5Sstsp 		txwisize += sizeof(uint32_t);
77130aa40ebSdamien 
77230aa40ebSdamien 	txq->cur = txq->queued = 0;
77330aa40ebSdamien 
77430aa40ebSdamien 	error = usbd_open_pipe(sc->sc_iface, txq->pipe_no, 0, &txq->pipeh);
77530aa40ebSdamien 	if (error != 0)
77630aa40ebSdamien 		goto fail;
77730aa40ebSdamien 
77830aa40ebSdamien 	for (i = 0; i < RUN_TX_RING_COUNT; i++) {
77930aa40ebSdamien 		struct run_tx_data *data = &txq->data[i];
78030aa40ebSdamien 
78130aa40ebSdamien 		data->sc = sc;	/* backpointer for callbacks */
78230aa40ebSdamien 		data->qid = qid;
78330aa40ebSdamien 
78430aa40ebSdamien 		data->xfer = usbd_alloc_xfer(sc->sc_udev);
78530aa40ebSdamien 		if (data->xfer == NULL) {
78630aa40ebSdamien 			error = ENOMEM;
78730aa40ebSdamien 			goto fail;
78830aa40ebSdamien 		}
78930aa40ebSdamien 		data->buf = usbd_alloc_buffer(data->xfer, RUN_MAX_TXSZ);
79030aa40ebSdamien 		if (data->buf == NULL) {
79130aa40ebSdamien 			error = ENOMEM;
79230aa40ebSdamien 			goto fail;
79330aa40ebSdamien 		}
79430aa40ebSdamien 		/* zeroize the TXD + TXWI part */
7958bad3cf5Sstsp 		memset(data->buf, 0, sizeof(struct rt2870_txd) + txwisize);
79630aa40ebSdamien 	}
79730aa40ebSdamien 	if (error != 0)
79830aa40ebSdamien fail:		run_free_tx_ring(sc, qid);
79930aa40ebSdamien 	return error;
80030aa40ebSdamien }
80130aa40ebSdamien 
80230aa40ebSdamien void
run_free_tx_ring(struct run_softc * sc,int qid)80330aa40ebSdamien run_free_tx_ring(struct run_softc *sc, int qid)
80430aa40ebSdamien {
80530aa40ebSdamien 	struct run_tx_ring *txq = &sc->txq[qid];
80630aa40ebSdamien 	int i;
80730aa40ebSdamien 
80830aa40ebSdamien 	if (txq->pipeh != NULL) {
80930aa40ebSdamien 		usbd_close_pipe(txq->pipeh);
81030aa40ebSdamien 		txq->pipeh = NULL;
81130aa40ebSdamien 	}
81230aa40ebSdamien 	for (i = 0; i < RUN_TX_RING_COUNT; i++) {
81330aa40ebSdamien 		if (txq->data[i].xfer != NULL)
81430aa40ebSdamien 			usbd_free_xfer(txq->data[i].xfer);
81530aa40ebSdamien 		txq->data[i].xfer = NULL;
81630aa40ebSdamien 	}
81730aa40ebSdamien }
81830aa40ebSdamien 
81930aa40ebSdamien int
run_load_microcode(struct run_softc * sc)82030aa40ebSdamien run_load_microcode(struct run_softc *sc)
82130aa40ebSdamien {
82230aa40ebSdamien 	usb_device_request_t req;
82394a7fcd3Sdamien 	const char *fwname;
82494a7fcd3Sdamien 	u_char *ucode;
82530aa40ebSdamien 	size_t size;
82630aa40ebSdamien 	uint32_t tmp;
82730aa40ebSdamien 	int ntries, error;
82830aa40ebSdamien 
82994a7fcd3Sdamien 	/* RT3071/RT3072 use a different firmware */
8306755f0faSdamien 	if (sc->mac_ver != 0x2860 &&
8316755f0faSdamien 	    sc->mac_ver != 0x2872 &&
8326755f0faSdamien 	    sc->mac_ver != 0x3070)
83394a7fcd3Sdamien 		fwname = "run-rt3071";
83494a7fcd3Sdamien 	else
83594a7fcd3Sdamien 		fwname = "run-rt2870";
83694a7fcd3Sdamien 
83794a7fcd3Sdamien 	if ((error = loadfirmware(fwname, &ucode, &size)) != 0) {
83830aa40ebSdamien 		printf("%s: failed loadfirmware of file %s (error %d)\n",
83994a7fcd3Sdamien 		    sc->sc_dev.dv_xname, fwname, error);
84030aa40ebSdamien 		return error;
84130aa40ebSdamien 	}
84294a7fcd3Sdamien 	if (size != 4096) {
84394a7fcd3Sdamien 		printf("%s: invalid firmware size (should be 4KB)\n",
84430aa40ebSdamien 		    sc->sc_dev.dv_xname);
845c9ee9455Sderaadt 		free(ucode, M_DEVBUF, size);
84630aa40ebSdamien 		return EINVAL;
84730aa40ebSdamien 	}
84830aa40ebSdamien 
84930aa40ebSdamien 	/* write microcode image */
85094a7fcd3Sdamien 	run_write_region_1(sc, RT2870_FW_BASE, ucode, size);
851c9ee9455Sderaadt 	free(ucode, M_DEVBUF, size);
85230aa40ebSdamien 	run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
85330aa40ebSdamien 	run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
85430aa40ebSdamien 
85530aa40ebSdamien 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
85630aa40ebSdamien 	req.bRequest = RT2870_RESET;
85730aa40ebSdamien 	USETW(req.wValue, 8);
85830aa40ebSdamien 	USETW(req.wIndex, 0);
85930aa40ebSdamien 	USETW(req.wLength, 0);
86030aa40ebSdamien 	if ((error = usbd_do_request(sc->sc_udev, &req, NULL)) != 0)
86130aa40ebSdamien 		return error;
86230aa40ebSdamien 
86330aa40ebSdamien 	usbd_delay_ms(sc->sc_udev, 10);
864d80de052Sstsp 	run_write(sc, RT2860_H2M_BBPAGENT, 0);
86530aa40ebSdamien 	run_write(sc, RT2860_H2M_MAILBOX, 0);
866d80de052Sstsp 	run_write(sc, RT2860_H2M_INTSRC, 0);
86760b75e11Sdamien 	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
86830aa40ebSdamien 		return error;
86930aa40ebSdamien 
87030aa40ebSdamien 	/* wait until microcontroller is ready */
87130aa40ebSdamien 	for (ntries = 0; ntries < 1000; ntries++) {
87230aa40ebSdamien 		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
87330aa40ebSdamien 			return error;
87430aa40ebSdamien 		if (tmp & RT2860_MCU_READY)
87530aa40ebSdamien 			break;
87630aa40ebSdamien 		DELAY(1000);
87730aa40ebSdamien 	}
87830aa40ebSdamien 	if (ntries == 1000) {
87930aa40ebSdamien 		printf("%s: timeout waiting for MCU to initialize\n",
88030aa40ebSdamien 		    sc->sc_dev.dv_xname);
88130aa40ebSdamien 		return ETIMEDOUT;
88230aa40ebSdamien 	}
88330aa40ebSdamien 	DPRINTF(("microcode successfully loaded after %d tries\n", ntries));
88430aa40ebSdamien 	return 0;
88530aa40ebSdamien }
88630aa40ebSdamien 
88730aa40ebSdamien int
run_reset(struct run_softc * sc)88830aa40ebSdamien run_reset(struct run_softc *sc)
88930aa40ebSdamien {
89030aa40ebSdamien 	usb_device_request_t req;
89130aa40ebSdamien 
89230aa40ebSdamien 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
89330aa40ebSdamien 	req.bRequest = RT2870_RESET;
89430aa40ebSdamien 	USETW(req.wValue, 1);
89530aa40ebSdamien 	USETW(req.wIndex, 0);
89630aa40ebSdamien 	USETW(req.wLength, 0);
89730aa40ebSdamien 	return usbd_do_request(sc->sc_udev, &req, NULL);
89830aa40ebSdamien }
89930aa40ebSdamien 
90030aa40ebSdamien int
run_read(struct run_softc * sc,uint16_t reg,uint32_t * val)90130aa40ebSdamien run_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
90230aa40ebSdamien {
90330aa40ebSdamien 	uint32_t tmp;
90430aa40ebSdamien 	int error;
90530aa40ebSdamien 
90630aa40ebSdamien 	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
90730aa40ebSdamien 	if (error == 0)
90830aa40ebSdamien 		*val = letoh32(tmp);
90930aa40ebSdamien 	else
91030aa40ebSdamien 		*val = 0xffffffff;
91130aa40ebSdamien 	return error;
91230aa40ebSdamien }
91330aa40ebSdamien 
91430aa40ebSdamien int
run_read_region_1(struct run_softc * sc,uint16_t reg,uint8_t * buf,int len)91530aa40ebSdamien run_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
91630aa40ebSdamien {
91730aa40ebSdamien 	usb_device_request_t req;
91830aa40ebSdamien 
91930aa40ebSdamien 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
92030aa40ebSdamien 	req.bRequest = RT2870_READ_REGION_1;
92130aa40ebSdamien 	USETW(req.wValue, 0);
92230aa40ebSdamien 	USETW(req.wIndex, reg);
92330aa40ebSdamien 	USETW(req.wLength, len);
92430aa40ebSdamien 	return usbd_do_request(sc->sc_udev, &req, buf);
92530aa40ebSdamien }
92630aa40ebSdamien 
92730aa40ebSdamien int
run_write_2(struct run_softc * sc,uint16_t reg,uint16_t val)92830aa40ebSdamien run_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
92930aa40ebSdamien {
93030aa40ebSdamien 	usb_device_request_t req;
93130aa40ebSdamien 
93230aa40ebSdamien 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
93330aa40ebSdamien 	req.bRequest = RT2870_WRITE_2;
93430aa40ebSdamien 	USETW(req.wValue, val);
93530aa40ebSdamien 	USETW(req.wIndex, reg);
93630aa40ebSdamien 	USETW(req.wLength, 0);
93730aa40ebSdamien 	return usbd_do_request(sc->sc_udev, &req, NULL);
93830aa40ebSdamien }
93930aa40ebSdamien 
94030aa40ebSdamien int
run_write(struct run_softc * sc,uint16_t reg,uint32_t val)94130aa40ebSdamien run_write(struct run_softc *sc, uint16_t reg, uint32_t val)
94230aa40ebSdamien {
94330aa40ebSdamien 	int error;
94430aa40ebSdamien 
94530aa40ebSdamien 	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
94630aa40ebSdamien 		error = run_write_2(sc, reg + 2, val >> 16);
94730aa40ebSdamien 	return error;
94830aa40ebSdamien }
94930aa40ebSdamien 
95030aa40ebSdamien int
run_write_region_1(struct run_softc * sc,uint16_t reg,const uint8_t * buf,int len)95130aa40ebSdamien run_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
95230aa40ebSdamien     int len)
95330aa40ebSdamien {
95430aa40ebSdamien #if 1
95530aa40ebSdamien 	int i, error = 0;
95630aa40ebSdamien 	/*
95730aa40ebSdamien 	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
95830aa40ebSdamien 	 * We thus issue multiple WRITE_2 commands instead.
95930aa40ebSdamien 	 */
96030aa40ebSdamien 	KASSERT((len & 1) == 0);
96130aa40ebSdamien 	for (i = 0; i < len && error == 0; i += 2)
96230aa40ebSdamien 		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
96330aa40ebSdamien 	return error;
96430aa40ebSdamien #else
96530aa40ebSdamien 	usb_device_request_t req;
96630aa40ebSdamien 
96730aa40ebSdamien 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
96830aa40ebSdamien 	req.bRequest = RT2870_WRITE_REGION_1;
96930aa40ebSdamien 	USETW(req.wValue, 0);
97030aa40ebSdamien 	USETW(req.wIndex, reg);
97130aa40ebSdamien 	USETW(req.wLength, len);
97230aa40ebSdamien 	return usbd_do_request(sc->sc_udev, &req, buf);
97330aa40ebSdamien #endif
97430aa40ebSdamien }
97530aa40ebSdamien 
97630aa40ebSdamien int
run_set_region_4(struct run_softc * sc,uint16_t reg,uint32_t val,int count)977b710740dSdamien run_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int count)
97830aa40ebSdamien {
979b710740dSdamien 	int error = 0;
98030aa40ebSdamien 
981b710740dSdamien 	for (; count > 0 && error == 0; count--, reg += 4)
982b710740dSdamien 		error = run_write(sc, reg, val);
98330aa40ebSdamien 	return error;
98430aa40ebSdamien }
98530aa40ebSdamien 
986d80de052Sstsp /* Read 16-bit from eFUSE ROM. */
987d80de052Sstsp int
run_efuse_read(struct run_softc * sc,uint16_t addr,uint16_t * val)988d80de052Sstsp run_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
989d80de052Sstsp {
990d80de052Sstsp 	uint32_t tmp;
991d80de052Sstsp 	uint16_t reg;
992d80de052Sstsp 	int error, ntries;
993d80de052Sstsp 
994d80de052Sstsp 	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
995d80de052Sstsp 		return error;
996d80de052Sstsp 
997d80de052Sstsp 	/*-
998d80de052Sstsp 	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
999d80de052Sstsp 	 * DATA0: F E D C
1000d80de052Sstsp 	 * DATA1: B A 9 8
1001d80de052Sstsp 	 * DATA2: 7 6 5 4
1002d80de052Sstsp 	 * DATA3: 3 2 1 0
1003d80de052Sstsp 	 */
1004d80de052Sstsp 	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1005d80de052Sstsp 	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1006d80de052Sstsp 	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1007d80de052Sstsp 	for (ntries = 0; ntries < 100; ntries++) {
1008d80de052Sstsp 		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1009d80de052Sstsp 			return error;
1010d80de052Sstsp 		if (!(tmp & RT3070_EFSROM_KICK))
1011d80de052Sstsp 			break;
1012d80de052Sstsp 		DELAY(2);
1013d80de052Sstsp 	}
1014d80de052Sstsp 	if (ntries == 100)
1015d80de052Sstsp 		return ETIMEDOUT;
1016d80de052Sstsp 
1017d80de052Sstsp 	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1018d80de052Sstsp 		*val = 0xffff;	/* address not found */
1019d80de052Sstsp 		return 0;
1020d80de052Sstsp 	}
1021d80de052Sstsp 	/* determine to which 32-bit register our 16-bit word belongs */
1022d80de052Sstsp 	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1023d80de052Sstsp 	if ((error = run_read(sc, reg, &tmp)) != 0)
1024d80de052Sstsp 		return error;
1025d80de052Sstsp 
1026d80de052Sstsp 	tmp >>= (8 * (addr & 0x3));
1027d80de052Sstsp 	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1028d80de052Sstsp 	return 0;
1029d80de052Sstsp }
1030d80de052Sstsp 
1031d80de052Sstsp /* Read 16-bit from eFUSE ROM for RT3xxx. */
103230aa40ebSdamien int
run_efuse_read_2(struct run_softc * sc,uint16_t addr,uint16_t * val)103330aa40ebSdamien run_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
103430aa40ebSdamien {
103530aa40ebSdamien 	uint32_t tmp;
103630aa40ebSdamien 	uint16_t reg;
103730aa40ebSdamien 	int error, ntries;
103830aa40ebSdamien 
103930aa40ebSdamien 	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
104030aa40ebSdamien 		return error;
104130aa40ebSdamien 
104230aa40ebSdamien 	addr *= 2;
10438015804dSdamien 	/*-
10448015804dSdamien 	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
10458015804dSdamien 	 * DATA0: F E D C
10468015804dSdamien 	 * DATA1: B A 9 8
10478015804dSdamien 	 * DATA2: 7 6 5 4
10488015804dSdamien 	 * DATA3: 3 2 1 0
10498015804dSdamien 	 */
1050a4d59ed3Sdamien 	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
10518015804dSdamien 	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
105230aa40ebSdamien 	run_write(sc, RT3070_EFUSE_CTRL, tmp);
105330aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
105430aa40ebSdamien 		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
105530aa40ebSdamien 			return error;
105630aa40ebSdamien 		if (!(tmp & RT3070_EFSROM_KICK))
105730aa40ebSdamien 			break;
105830aa40ebSdamien 		DELAY(2);
105930aa40ebSdamien 	}
106030aa40ebSdamien 	if (ntries == 100)
106130aa40ebSdamien 		return ETIMEDOUT;
106230aa40ebSdamien 
106330aa40ebSdamien 	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
106430aa40ebSdamien 		*val = 0xffff;	/* address not found */
106530aa40ebSdamien 		return 0;
106630aa40ebSdamien 	}
10678015804dSdamien 	/* determine to which 32-bit register our 16-bit word belongs */
106830aa40ebSdamien 	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
106930aa40ebSdamien 	if ((error = run_read(sc, reg, &tmp)) != 0)
107030aa40ebSdamien 		return error;
107130aa40ebSdamien 
10728015804dSdamien 	*val = (addr & 2) ? tmp >> 16 : tmp & 0xffff;
107330aa40ebSdamien 	return 0;
107430aa40ebSdamien }
107530aa40ebSdamien 
107630aa40ebSdamien int
run_eeprom_read_2(struct run_softc * sc,uint16_t addr,uint16_t * val)107730aa40ebSdamien run_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
107830aa40ebSdamien {
107930aa40ebSdamien 	usb_device_request_t req;
108030aa40ebSdamien 	uint16_t tmp;
108130aa40ebSdamien 	int error;
108230aa40ebSdamien 
108330aa40ebSdamien 	addr *= 2;
108430aa40ebSdamien 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
108530aa40ebSdamien 	req.bRequest = RT2870_EEPROM_READ;
108630aa40ebSdamien 	USETW(req.wValue, 0);
108730aa40ebSdamien 	USETW(req.wIndex, addr);
108830aa40ebSdamien 	USETW(req.wLength, sizeof tmp);
108930aa40ebSdamien 	error = usbd_do_request(sc->sc_udev, &req, &tmp);
109030aa40ebSdamien 	if (error == 0)
109130aa40ebSdamien 		*val = letoh16(tmp);
109230aa40ebSdamien 	else
109330aa40ebSdamien 		*val = 0xffff;
109430aa40ebSdamien 	return error;
109530aa40ebSdamien }
109630aa40ebSdamien 
109730aa40ebSdamien static __inline int
run_srom_read(struct run_softc * sc,uint16_t addr,uint16_t * val)109830aa40ebSdamien run_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
109930aa40ebSdamien {
110030aa40ebSdamien 	/* either eFUSE ROM or EEPROM */
110130aa40ebSdamien 	return sc->sc_srom_read(sc, addr, val);
110230aa40ebSdamien }
110330aa40ebSdamien 
110430aa40ebSdamien int
run_rt2870_rf_write(struct run_softc * sc,uint8_t reg,uint32_t val)11052548be7aSmlarkin run_rt2870_rf_write(struct run_softc *sc, uint8_t reg, uint32_t val)
110630aa40ebSdamien {
110730aa40ebSdamien 	uint32_t tmp;
110830aa40ebSdamien 	int error, ntries;
110930aa40ebSdamien 
111030aa40ebSdamien 	for (ntries = 0; ntries < 10; ntries++) {
111130aa40ebSdamien 		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
111230aa40ebSdamien 			return error;
111330aa40ebSdamien 		if (!(tmp & RT2860_RF_REG_CTRL))
111430aa40ebSdamien 			break;
111530aa40ebSdamien 	}
111630aa40ebSdamien 	if (ntries == 10)
111730aa40ebSdamien 		return ETIMEDOUT;
111830aa40ebSdamien 
11192548be7aSmlarkin 	/* RF registers are 24-bit on the RT2860 */
11202548be7aSmlarkin 	tmp = RT2860_RF_REG_CTRL | 24 << RT2860_RF_REG_WIDTH_SHIFT |
11212548be7aSmlarkin 	    (val & 0x3fffff) << 2 | (reg & 3);
11222548be7aSmlarkin 	return run_write(sc, RT2860_RF_CSR_CFG0, tmp);
112330aa40ebSdamien }
112430aa40ebSdamien 
112530aa40ebSdamien int
run_rt3070_rf_read(struct run_softc * sc,uint8_t reg,uint8_t * val)112630aa40ebSdamien run_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
112730aa40ebSdamien {
112830aa40ebSdamien 	uint32_t tmp;
112930aa40ebSdamien 	int error, ntries;
113030aa40ebSdamien 
113130aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
113230aa40ebSdamien 		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
113330aa40ebSdamien 			return error;
113430aa40ebSdamien 		if (!(tmp & RT3070_RF_KICK))
113530aa40ebSdamien 			break;
113630aa40ebSdamien 	}
113730aa40ebSdamien 	if (ntries == 100)
113830aa40ebSdamien 		return ETIMEDOUT;
113930aa40ebSdamien 
114030aa40ebSdamien 	tmp = RT3070_RF_KICK | reg << 8;
114130aa40ebSdamien 	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
114230aa40ebSdamien 		return error;
114330aa40ebSdamien 
114430aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
114530aa40ebSdamien 		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
114630aa40ebSdamien 			return error;
114730aa40ebSdamien 		if (!(tmp & RT3070_RF_KICK))
114830aa40ebSdamien 			break;
114930aa40ebSdamien 	}
115030aa40ebSdamien 	if (ntries == 100)
115130aa40ebSdamien 		return ETIMEDOUT;
115230aa40ebSdamien 
115330aa40ebSdamien 	*val = tmp & 0xff;
115430aa40ebSdamien 	return 0;
115530aa40ebSdamien }
115630aa40ebSdamien 
115730aa40ebSdamien int
run_rt3070_rf_write(struct run_softc * sc,uint8_t reg,uint8_t val)115830aa40ebSdamien run_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
115930aa40ebSdamien {
116030aa40ebSdamien 	uint32_t tmp;
116130aa40ebSdamien 	int error, ntries;
116230aa40ebSdamien 
116330aa40ebSdamien 	for (ntries = 0; ntries < 10; ntries++) {
116430aa40ebSdamien 		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
116530aa40ebSdamien 			return error;
116630aa40ebSdamien 		if (!(tmp & RT3070_RF_KICK))
116730aa40ebSdamien 			break;
116830aa40ebSdamien 	}
116930aa40ebSdamien 	if (ntries == 10)
117030aa40ebSdamien 		return ETIMEDOUT;
117130aa40ebSdamien 
1172cd4f4e38Sdamien 	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
117330aa40ebSdamien 	return run_write(sc, RT3070_RF_CSR_CFG, tmp);
117430aa40ebSdamien }
117530aa40ebSdamien 
117630aa40ebSdamien int
run_bbp_read(struct run_softc * sc,uint8_t reg,uint8_t * val)117730aa40ebSdamien run_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
117830aa40ebSdamien {
117930aa40ebSdamien 	uint32_t tmp;
118030aa40ebSdamien 	int ntries, error;
118130aa40ebSdamien 
118230aa40ebSdamien 	for (ntries = 0; ntries < 10; ntries++) {
118330aa40ebSdamien 		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
118430aa40ebSdamien 			return error;
118530aa40ebSdamien 		if (!(tmp & RT2860_BBP_CSR_KICK))
118630aa40ebSdamien 			break;
118730aa40ebSdamien 	}
118830aa40ebSdamien 	if (ntries == 10)
118930aa40ebSdamien 		return ETIMEDOUT;
119030aa40ebSdamien 
119130aa40ebSdamien 	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
119230aa40ebSdamien 	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
119330aa40ebSdamien 		return error;
119430aa40ebSdamien 
119530aa40ebSdamien 	for (ntries = 0; ntries < 10; ntries++) {
119630aa40ebSdamien 		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
119730aa40ebSdamien 			return error;
119830aa40ebSdamien 		if (!(tmp & RT2860_BBP_CSR_KICK))
119930aa40ebSdamien 			break;
120030aa40ebSdamien 	}
120130aa40ebSdamien 	if (ntries == 10)
120230aa40ebSdamien 		return ETIMEDOUT;
120330aa40ebSdamien 
120430aa40ebSdamien 	*val = tmp & 0xff;
120530aa40ebSdamien 	return 0;
120630aa40ebSdamien }
120730aa40ebSdamien 
120830aa40ebSdamien int
run_bbp_write(struct run_softc * sc,uint8_t reg,uint8_t val)120930aa40ebSdamien run_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
121030aa40ebSdamien {
121130aa40ebSdamien 	uint32_t tmp;
121230aa40ebSdamien 	int ntries, error;
121330aa40ebSdamien 
121430aa40ebSdamien 	for (ntries = 0; ntries < 10; ntries++) {
121530aa40ebSdamien 		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
121630aa40ebSdamien 			return error;
121730aa40ebSdamien 		if (!(tmp & RT2860_BBP_CSR_KICK))
121830aa40ebSdamien 			break;
121930aa40ebSdamien 	}
122030aa40ebSdamien 	if (ntries == 10)
122130aa40ebSdamien 		return ETIMEDOUT;
122230aa40ebSdamien 
122330aa40ebSdamien 	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
122430aa40ebSdamien 	return run_write(sc, RT2860_BBP_CSR_CFG, tmp);
122530aa40ebSdamien }
122630aa40ebSdamien 
122730aa40ebSdamien /*
122830aa40ebSdamien  * Send a command to the 8051 microcontroller unit.
122930aa40ebSdamien  */
123030aa40ebSdamien int
run_mcu_cmd(struct run_softc * sc,uint8_t cmd,uint16_t arg)123130aa40ebSdamien run_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
123230aa40ebSdamien {
123330aa40ebSdamien 	uint32_t tmp;
123430aa40ebSdamien 	int error, ntries;
123530aa40ebSdamien 
123630aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
123730aa40ebSdamien 		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
123830aa40ebSdamien 			return error;
123930aa40ebSdamien 		if (!(tmp & RT2860_H2M_BUSY))
124030aa40ebSdamien 			break;
124130aa40ebSdamien 	}
124230aa40ebSdamien 	if (ntries == 100)
124330aa40ebSdamien 		return ETIMEDOUT;
124430aa40ebSdamien 
1245cd4f4e38Sdamien 	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
124630aa40ebSdamien 	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
124730aa40ebSdamien 		error = run_write(sc, RT2860_HOST_CMD, cmd);
124830aa40ebSdamien 	return error;
124930aa40ebSdamien }
125030aa40ebSdamien 
125130aa40ebSdamien /*
125230aa40ebSdamien  * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
125330aa40ebSdamien  * Used to adjust per-rate Tx power registers.
125430aa40ebSdamien  */
125530aa40ebSdamien static __inline uint32_t
b4inc(uint32_t b32,int8_t delta)125630aa40ebSdamien b4inc(uint32_t b32, int8_t delta)
125730aa40ebSdamien {
125830aa40ebSdamien 	int8_t i, b4;
125930aa40ebSdamien 
126030aa40ebSdamien 	for (i = 0; i < 8; i++) {
126130aa40ebSdamien 		b4 = b32 & 0xf;
126230aa40ebSdamien 		b4 += delta;
126330aa40ebSdamien 		if (b4 < 0)
126430aa40ebSdamien 			b4 = 0;
126530aa40ebSdamien 		else if (b4 > 0xf)
126630aa40ebSdamien 			b4 = 0xf;
126730aa40ebSdamien 		b32 = b32 >> 4 | b4 << 28;
126830aa40ebSdamien 	}
126930aa40ebSdamien 	return b32;
127030aa40ebSdamien }
127130aa40ebSdamien 
127230aa40ebSdamien const char *
run_get_rf(int rev)127330aa40ebSdamien run_get_rf(int rev)
127430aa40ebSdamien {
127530aa40ebSdamien 	switch (rev) {
127630aa40ebSdamien 	case RT2860_RF_2820:	return "RT2820";
127730aa40ebSdamien 	case RT2860_RF_2850:	return "RT2850";
127830aa40ebSdamien 	case RT2860_RF_2720:	return "RT2720";
127930aa40ebSdamien 	case RT2860_RF_2750:	return "RT2750";
128030aa40ebSdamien 	case RT3070_RF_3020:	return "RT3020";
128130aa40ebSdamien 	case RT3070_RF_2020:	return "RT2020";
128230aa40ebSdamien 	case RT3070_RF_3021:	return "RT3021";
128330aa40ebSdamien 	case RT3070_RF_3022:	return "RT3022";
12845661a35fSdamien 	case RT3070_RF_3052:	return "RT3052";
1285d80de052Sstsp 	case RT3070_RF_3053:	return "RT3053";
1286d80de052Sstsp 	case RT5592_RF_5592:	return "RT5592";
1287d80de052Sstsp 	case RT5390_RF_5370:	return "RT5370";
1288d80de052Sstsp 	case RT5390_RF_5372:	return "RT5372";
128930aa40ebSdamien 	}
129030aa40ebSdamien 	return "unknown";
129130aa40ebSdamien }
129230aa40ebSdamien 
1293d80de052Sstsp void
run_rt3593_get_txpower(struct run_softc * sc)1294d80de052Sstsp run_rt3593_get_txpower(struct run_softc *sc)
1295d80de052Sstsp {
1296d80de052Sstsp 	uint16_t addr, val;
1297d80de052Sstsp 	int i;
1298d80de052Sstsp 
1299d80de052Sstsp 	/* Read power settings for 2GHz channels. */
1300d80de052Sstsp 	for (i = 0; i < 14; i += 2) {
1301d80de052Sstsp 		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1302d80de052Sstsp 		    RT2860_EEPROM_PWR2GHZ_BASE1;
1303d80de052Sstsp 		run_srom_read(sc, addr + i / 2, &val);
1304d80de052Sstsp 		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1305d80de052Sstsp 		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1306d80de052Sstsp 
1307d80de052Sstsp 		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1308d80de052Sstsp 		    RT2860_EEPROM_PWR2GHZ_BASE2;
1309d80de052Sstsp 		run_srom_read(sc, addr + i / 2, &val);
1310d80de052Sstsp 		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1311d80de052Sstsp 		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1312d80de052Sstsp 
1313d80de052Sstsp 		if (sc->ntxchains == 3) {
1314d80de052Sstsp 			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1315d80de052Sstsp 			    &val);
1316d80de052Sstsp 			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1317d80de052Sstsp 			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1318d80de052Sstsp 		}
1319d80de052Sstsp 	}
1320d80de052Sstsp 	/* Fix broken Tx power entries. */
1321d80de052Sstsp 	for (i = 0; i < 14; i++) {
1322d80de052Sstsp 		if (sc->txpow1[i] > 31)
1323d80de052Sstsp 			sc->txpow1[i] = 5;
1324d80de052Sstsp 		if (sc->txpow2[i] > 31)
1325d80de052Sstsp 			sc->txpow2[i] = 5;
1326d80de052Sstsp 		if (sc->ntxchains == 3) {
1327d80de052Sstsp 			if (sc->txpow3[i] > 31)
1328d80de052Sstsp 				sc->txpow3[i] = 5;
1329d80de052Sstsp 		}
1330d80de052Sstsp 	}
1331d80de052Sstsp 	/* Read power settings for 5GHz channels. */
1332d80de052Sstsp 	for (i = 0; i < 40; i += 2) {
1333d80de052Sstsp 		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1334d80de052Sstsp 		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1335d80de052Sstsp 		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1336d80de052Sstsp 
1337d80de052Sstsp 		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1338d80de052Sstsp 		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1339d80de052Sstsp 		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1340d80de052Sstsp 
1341d80de052Sstsp 		if (sc->ntxchains == 3) {
1342d80de052Sstsp 			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1343d80de052Sstsp 			    &val);
1344d80de052Sstsp 			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1345d80de052Sstsp 			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1346d80de052Sstsp 		}
1347d80de052Sstsp 	}
1348d80de052Sstsp }
1349d80de052Sstsp 
1350d80de052Sstsp void
run_get_txpower(struct run_softc * sc)1351d80de052Sstsp run_get_txpower(struct run_softc *sc)
1352d80de052Sstsp {
1353d80de052Sstsp 	uint16_t val;
1354d80de052Sstsp 	int i;
1355d80de052Sstsp 
1356d80de052Sstsp 	/* Read power settings for 2GHz channels. */
1357d80de052Sstsp 	for (i = 0; i < 14; i += 2) {
1358d80de052Sstsp 		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1359d80de052Sstsp 		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1360d80de052Sstsp 		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1361d80de052Sstsp 
1362d80de052Sstsp 		if (sc->mac_ver != 0x5390) {
1363d80de052Sstsp 			run_srom_read(sc,
1364d80de052Sstsp 			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1365d80de052Sstsp 			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1366d80de052Sstsp 			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1367d80de052Sstsp 		}
1368d80de052Sstsp 	}
1369d80de052Sstsp 	/* Fix broken Tx power entries. */
1370d80de052Sstsp 	for (i = 0; i < 14; i++) {
1371d80de052Sstsp 		if (sc->mac_ver >= 0x5390) {
1372d80de052Sstsp 			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
1373d80de052Sstsp 				sc->txpow1[i] = 5;
1374d80de052Sstsp 		} else {
1375d80de052Sstsp 			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1376d80de052Sstsp 				sc->txpow1[i] = 5;
1377d80de052Sstsp 		}
1378d80de052Sstsp 		if (sc->mac_ver > 0x5390) {
1379d80de052Sstsp 			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
1380d80de052Sstsp 				sc->txpow2[i] = 5;
1381d80de052Sstsp 		} else if (sc->mac_ver < 0x5390) {
1382d80de052Sstsp 			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1383d80de052Sstsp 				sc->txpow2[i] = 5;
1384d80de052Sstsp 		}
1385d80de052Sstsp 		DPRINTF(("chan %d: power1=%d, power2=%d\n",
1386d80de052Sstsp 		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]));
1387d80de052Sstsp 	}
1388d80de052Sstsp 	/* Read power settings for 5GHz channels. */
1389d80de052Sstsp 	for (i = 0; i < 40; i += 2) {
1390d80de052Sstsp 		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1391d80de052Sstsp 		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1392d80de052Sstsp 		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1393d80de052Sstsp 
1394d80de052Sstsp 		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1395d80de052Sstsp 		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1396d80de052Sstsp 		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1397d80de052Sstsp 	}
1398d80de052Sstsp 	/* Fix broken Tx power entries. */
1399d80de052Sstsp 	for (i = 0; i < 40; i++ ) {
1400d80de052Sstsp 		if (sc->mac_ver != 0x5592) {
1401d80de052Sstsp 			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1402d80de052Sstsp 				sc->txpow1[14 + i] = 5;
1403d80de052Sstsp 			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1404d80de052Sstsp 				sc->txpow2[14 + i] = 5;
1405d80de052Sstsp 		}
1406d80de052Sstsp 		DPRINTF(("chan %d: power1=%d, power2=%d\n",
1407d80de052Sstsp 		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1408d80de052Sstsp 		    sc->txpow2[14 + i]));
1409d80de052Sstsp 	}
1410d80de052Sstsp }
1411d80de052Sstsp 
141230aa40ebSdamien int
run_read_eeprom(struct run_softc * sc)141330aa40ebSdamien run_read_eeprom(struct run_softc *sc)
141430aa40ebSdamien {
141530aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
141630aa40ebSdamien 	int8_t delta_2ghz, delta_5ghz;
141730aa40ebSdamien 	uint32_t tmp;
141830aa40ebSdamien 	uint16_t val;
141930aa40ebSdamien 	int ridx, ant, i;
142030aa40ebSdamien 
142130aa40ebSdamien 	/* check whether the ROM is eFUSE ROM or EEPROM */
142230aa40ebSdamien 	sc->sc_srom_read = run_eeprom_read_2;
14236755f0faSdamien 	if (sc->mac_ver >= 0x3070) {
142430aa40ebSdamien 		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1425a4d59ed3Sdamien 		DPRINTF(("EFUSE_CTRL=0x%08x\n", tmp));
1426d80de052Sstsp 		if (tmp & RT3070_SEL_EFUSE || sc->mac_ver == 0x3593)
142730aa40ebSdamien 			sc->sc_srom_read = run_efuse_read_2;
142830aa40ebSdamien 	}
142930aa40ebSdamien 
1430a4d59ed3Sdamien 	/* read ROM version */
143130aa40ebSdamien 	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
143230aa40ebSdamien 	DPRINTF(("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8));
143330aa40ebSdamien 
143430aa40ebSdamien 	/* read MAC address */
143530aa40ebSdamien 	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
143630aa40ebSdamien 	ic->ic_myaddr[0] = val & 0xff;
143730aa40ebSdamien 	ic->ic_myaddr[1] = val >> 8;
143830aa40ebSdamien 	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
143930aa40ebSdamien 	ic->ic_myaddr[2] = val & 0xff;
144030aa40ebSdamien 	ic->ic_myaddr[3] = val >> 8;
144130aa40ebSdamien 	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
144230aa40ebSdamien 	ic->ic_myaddr[4] = val & 0xff;
144330aa40ebSdamien 	ic->ic_myaddr[5] = val >> 8;
144430aa40ebSdamien 
1445d80de052Sstsp 	if (sc->mac_ver < 0x3593) {
1446f19591d0Sdamien 		/* read vendor BBP settings */
1447f19591d0Sdamien 		for (i = 0; i < 10; i++) {
144830aa40ebSdamien 			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
144930aa40ebSdamien 			sc->bbp[i].val = val & 0xff;
145030aa40ebSdamien 			sc->bbp[i].reg = val >> 8;
1451d80de052Sstsp 			DPRINTF(("BBP%d=0x%02x\n", sc->bbp[i].reg,
1452d80de052Sstsp 			    sc->bbp[i].val));
145330aa40ebSdamien 		}
1454f19591d0Sdamien 		if (sc->mac_ver >= 0x3071) {
1455f19591d0Sdamien 			/* read vendor RF settings */
1456f19591d0Sdamien 			for (i = 0; i < 10; i++) {
1457d80de052Sstsp 				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1458d80de052Sstsp 				    &val);
1459f19591d0Sdamien 				sc->rf[i].val = val & 0xff;
1460f19591d0Sdamien 				sc->rf[i].reg = val >> 8;
1461f19591d0Sdamien 				DPRINTF(("RF%d=0x%02x\n", sc->rf[i].reg,
1462f19591d0Sdamien 				    sc->rf[i].val));
1463f19591d0Sdamien 			}
1464f19591d0Sdamien 		}
1465d80de052Sstsp 	}
146630aa40ebSdamien 
146730aa40ebSdamien 	/* read RF frequency offset from EEPROM */
1468d80de052Sstsp 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1469d80de052Sstsp 	    RT3593_EEPROM_FREQ, &val);
147030aa40ebSdamien 	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
147130aa40ebSdamien 	DPRINTF(("EEPROM freq offset %d\n", sc->freq & 0xff));
1472d80de052Sstsp 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1473d80de052Sstsp 	    RT3593_EEPROM_FREQ_LEDS, &val);
1474f19591d0Sdamien 	if ((val >> 8) != 0xff) {
147530aa40ebSdamien 		/* read LEDs operating mode */
1476f19591d0Sdamien 		sc->leds = val >> 8;
1477d80de052Sstsp 		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1478d80de052Sstsp 		    RT3593_EEPROM_LED1, &sc->led[0]);
1479d80de052Sstsp 		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1480d80de052Sstsp 		    RT3593_EEPROM_LED2, &sc->led[1]);
1481d80de052Sstsp 		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1482d80de052Sstsp 		    RT3593_EEPROM_LED3, &sc->led[2]);
148330aa40ebSdamien 	} else {
148430aa40ebSdamien 		/* broken EEPROM, use default settings */
148530aa40ebSdamien 		sc->leds = 0x01;
148630aa40ebSdamien 		sc->led[0] = 0x5555;
148730aa40ebSdamien 		sc->led[1] = 0x2221;
14888015804dSdamien 		sc->led[2] = 0x5627;	/* differs from RT2860 */
148930aa40ebSdamien 	}
149030aa40ebSdamien 	DPRINTF(("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
149130aa40ebSdamien 	    sc->leds, sc->led[0], sc->led[1], sc->led[2]));
149230aa40ebSdamien 
149330aa40ebSdamien 	/* read RF information */
1494d80de052Sstsp 	if (sc->mac_ver == 0x5390 || sc->mac_ver == 0x5392)
1495d80de052Sstsp 		run_srom_read(sc, 0x00, &val);
1496d80de052Sstsp 	else
149730aa40ebSdamien 		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
149830aa40ebSdamien 	if (val == 0xffff) {
149930aa40ebSdamien 		DPRINTF(("invalid EEPROM antenna info, using default\n"));
1500f19591d0Sdamien 		if (sc->mac_ver == 0x3572) {
1501f19591d0Sdamien 			/* default to RF3052 2T2R */
1502f19591d0Sdamien 			sc->rf_rev = RT3070_RF_3052;
1503f19591d0Sdamien 			sc->ntxchains = 2;
1504f19591d0Sdamien 			sc->nrxchains = 2;
1505f19591d0Sdamien 		} else if (sc->mac_ver >= 0x3070) {
15068015804dSdamien 			/* default to RF3020 1T1R */
15078015804dSdamien 			sc->rf_rev = RT3070_RF_3020;
15088015804dSdamien 			sc->ntxchains = 1;
15098015804dSdamien 			sc->nrxchains = 1;
15108015804dSdamien 		} else {
15118015804dSdamien 			/* default to RF2820 1T2R */
151230aa40ebSdamien 			sc->rf_rev = RT2860_RF_2820;
151330aa40ebSdamien 			sc->ntxchains = 1;
151430aa40ebSdamien 			sc->nrxchains = 2;
15158015804dSdamien 		}
151630aa40ebSdamien 	} else {
1517d80de052Sstsp 		if (sc->mac_ver == 0x5390 || sc->mac_ver == 0x5392) {
1518d80de052Sstsp 			sc->rf_rev = val;
1519d80de052Sstsp 			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1520d80de052Sstsp 		} else
152130aa40ebSdamien 			sc->rf_rev = (val >> 8) & 0xf;
152230aa40ebSdamien 		sc->ntxchains = (val >> 4) & 0xf;
152330aa40ebSdamien 		sc->nrxchains = val & 0xf;
152430aa40ebSdamien 	}
152530aa40ebSdamien 	DPRINTF(("EEPROM RF rev=0x%02x chains=%dT%dR\n",
152630aa40ebSdamien 	    sc->rf_rev, sc->ntxchains, sc->nrxchains));
152730aa40ebSdamien 
1528d80de052Sstsp 	/* check if RF supports automatic Tx access gain control */
152930aa40ebSdamien 	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
153030aa40ebSdamien 	DPRINTF(("EEPROM CFG 0x%04x\n", val));
1531f19591d0Sdamien 	/* check if driver should patch the DAC issue */
1532f19591d0Sdamien 	if ((val >> 8) != 0xff)
1533f19591d0Sdamien 		sc->patch_dac = (val >> 15) & 1;
153430aa40ebSdamien 	if ((val & 0xff) != 0xff) {
153530aa40ebSdamien 		sc->ext_5ghz_lna = (val >> 3) & 1;
153630aa40ebSdamien 		sc->ext_2ghz_lna = (val >> 2) & 1;
1537f19591d0Sdamien 		/* check if RF supports automatic Tx access gain control */
153830aa40ebSdamien 		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1539f19591d0Sdamien 		/* check if we have a hardware radio switch */
1540f19591d0Sdamien 		sc->rfswitch = val & 1;
154130aa40ebSdamien 	}
154230aa40ebSdamien 
1543d80de052Sstsp 	/* Read Tx power settings. */
1544d80de052Sstsp 	if (sc->mac_ver == 0x3593)
1545d80de052Sstsp 		run_rt3593_get_txpower(sc);
1546d80de052Sstsp 	else
1547d80de052Sstsp 		run_get_txpower(sc);
154830aa40ebSdamien 
154930aa40ebSdamien 	/* read Tx power compensation for each Tx rate */
155030aa40ebSdamien 	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
155130aa40ebSdamien 	delta_2ghz = delta_5ghz = 0;
155230aa40ebSdamien 	if ((val & 0xff) != 0xff && (val & 0x80)) {
155330aa40ebSdamien 		delta_2ghz = val & 0xf;
155430aa40ebSdamien 		if (!(val & 0x40))	/* negative number */
155530aa40ebSdamien 			delta_2ghz = -delta_2ghz;
155630aa40ebSdamien 	}
155730aa40ebSdamien 	val >>= 8;
155830aa40ebSdamien 	if ((val & 0xff) != 0xff && (val & 0x80)) {
155930aa40ebSdamien 		delta_5ghz = val & 0xf;
156030aa40ebSdamien 		if (!(val & 0x40))	/* negative number */
156130aa40ebSdamien 			delta_5ghz = -delta_5ghz;
156230aa40ebSdamien 	}
156330aa40ebSdamien 	DPRINTF(("power compensation=%d (2GHz), %d (5GHz)\n",
156430aa40ebSdamien 	    delta_2ghz, delta_5ghz));
156530aa40ebSdamien 
156630aa40ebSdamien 	for (ridx = 0; ridx < 5; ridx++) {
156730aa40ebSdamien 		uint32_t reg;
156830aa40ebSdamien 
15696224bd02Sdamien 		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
15706224bd02Sdamien 		reg = val;
15716224bd02Sdamien 		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
15726224bd02Sdamien 		reg |= (uint32_t)val << 16;
157330aa40ebSdamien 
157430aa40ebSdamien 		sc->txpow20mhz[ridx] = reg;
157530aa40ebSdamien 		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
157630aa40ebSdamien 		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
157730aa40ebSdamien 
157830aa40ebSdamien 		DPRINTF(("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
157930aa40ebSdamien 		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
158030aa40ebSdamien 		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]));
158130aa40ebSdamien 	}
158230aa40ebSdamien 
158330aa40ebSdamien 	/* read RSSI offsets and LNA gains from EEPROM */
1584d80de052Sstsp 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1585d80de052Sstsp 	    RT3593_EEPROM_RSSI1_2GHZ, &val);
158630aa40ebSdamien 	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
158730aa40ebSdamien 	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1588d80de052Sstsp 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1589d80de052Sstsp 	    RT3593_EEPROM_RSSI2_2GHZ, &val);
1590f19591d0Sdamien 	if (sc->mac_ver >= 0x3070) {
1591d80de052Sstsp 		if (sc->mac_ver == 0x3593) {
1592d80de052Sstsp 			sc->txmixgain_2ghz = 0;
1593d80de052Sstsp 			sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1594d80de052Sstsp 		} else {
1595f19591d0Sdamien 			/*
1596f19591d0Sdamien 			 * On RT3070 chips (limited to 2 Rx chains), this ROM
1597f19591d0Sdamien 			 * field contains the Tx mixer gain for the 2GHz band.
1598f19591d0Sdamien 			 */
1599f19591d0Sdamien 			if ((val & 0xff) != 0xff)
1600f19591d0Sdamien 				sc->txmixgain_2ghz = val & 0x7;
1601d80de052Sstsp 		}
1602f19591d0Sdamien 		DPRINTF(("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz));
1603f19591d0Sdamien 	} else
160430aa40ebSdamien 		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1605d80de052Sstsp 	if (sc->mac_ver == 0x3593)
1606d80de052Sstsp 		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
160730aa40ebSdamien 	sc->lna[2] = val >> 8;		/* channel group 2 */
160830aa40ebSdamien 
1609d80de052Sstsp 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1610d80de052Sstsp 	    RT3593_EEPROM_RSSI1_5GHZ, &val);
161130aa40ebSdamien 	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
161230aa40ebSdamien 	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1613d80de052Sstsp 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1614d80de052Sstsp 	    RT3593_EEPROM_RSSI2_5GHZ, &val);
1615f19591d0Sdamien 	if (sc->mac_ver == 0x3572) {
1616f19591d0Sdamien 		/*
1617f19591d0Sdamien 		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1618f19591d0Sdamien 		 * field contains the Tx mixer gain for the 5GHz band.
1619f19591d0Sdamien 		 */
1620f19591d0Sdamien 		if ((val & 0xff) != 0xff)
1621f19591d0Sdamien 			sc->txmixgain_5ghz = val & 0x7;
1622f19591d0Sdamien 		DPRINTF(("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz));
1623f19591d0Sdamien 	} else
162430aa40ebSdamien 		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1625d80de052Sstsp 	if (sc->mac_ver == 0x3593) {
1626d80de052Sstsp 		sc->txmixgain_5ghz = 0;
1627d80de052Sstsp 		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1628d80de052Sstsp 	}
162930aa40ebSdamien 	sc->lna[3] = val >> 8;		/* channel group 3 */
163030aa40ebSdamien 
1631d80de052Sstsp 	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1632d80de052Sstsp 	    RT3593_EEPROM_LNA, &val);
163330aa40ebSdamien 	sc->lna[0] = val & 0xff;	/* channel group 0 */
163430aa40ebSdamien 	sc->lna[1] = val >> 8;		/* channel group 1 */
163530aa40ebSdamien 
163630aa40ebSdamien 	/* fix broken 5GHz LNA entries */
163730aa40ebSdamien 	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
163830aa40ebSdamien 		DPRINTF(("invalid LNA for channel group %d\n", 2));
163930aa40ebSdamien 		sc->lna[2] = sc->lna[1];
164030aa40ebSdamien 	}
164130aa40ebSdamien 	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
164230aa40ebSdamien 		DPRINTF(("invalid LNA for channel group %d\n", 3));
164330aa40ebSdamien 		sc->lna[3] = sc->lna[1];
164430aa40ebSdamien 	}
164530aa40ebSdamien 
164630aa40ebSdamien 	/* fix broken RSSI offset entries */
164730aa40ebSdamien 	for (ant = 0; ant < 3; ant++) {
164830aa40ebSdamien 		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
164930aa40ebSdamien 			DPRINTF(("invalid RSSI%d offset: %d (2GHz)\n",
165030aa40ebSdamien 			    ant + 1, sc->rssi_2ghz[ant]));
165130aa40ebSdamien 			sc->rssi_2ghz[ant] = 0;
165230aa40ebSdamien 		}
165330aa40ebSdamien 		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
165430aa40ebSdamien 			DPRINTF(("invalid RSSI%d offset: %d (5GHz)\n",
165530aa40ebSdamien 			    ant + 1, sc->rssi_5ghz[ant]));
165630aa40ebSdamien 			sc->rssi_5ghz[ant] = 0;
165730aa40ebSdamien 		}
165830aa40ebSdamien 	}
165930aa40ebSdamien 	return 0;
166030aa40ebSdamien }
166130aa40ebSdamien 
166230aa40ebSdamien struct ieee80211_node *
run_node_alloc(struct ieee80211com * ic)166330aa40ebSdamien run_node_alloc(struct ieee80211com *ic)
166430aa40ebSdamien {
16658985a220Smglocker 	return malloc(sizeof (struct run_node), M_USBDEV, M_NOWAIT | M_ZERO);
166630aa40ebSdamien }
166730aa40ebSdamien 
166830aa40ebSdamien int
run_media_change(struct ifnet * ifp)166930aa40ebSdamien run_media_change(struct ifnet *ifp)
167030aa40ebSdamien {
167130aa40ebSdamien 	struct run_softc *sc = ifp->if_softc;
167230aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
167330aa40ebSdamien 	uint8_t rate, ridx;
167430aa40ebSdamien 	int error;
167530aa40ebSdamien 
167630aa40ebSdamien 	error = ieee80211_media_change(ifp);
167730aa40ebSdamien 	if (error != ENETRESET)
167830aa40ebSdamien 		return error;
167930aa40ebSdamien 
168030aa40ebSdamien 	if (ic->ic_fixed_rate != -1) {
168130aa40ebSdamien 		rate = ic->ic_sup_rates[ic->ic_curmode].
168230aa40ebSdamien 		    rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
168330aa40ebSdamien 		for (ridx = 0; ridx <= RT2860_RIDX_MAX; ridx++)
168430aa40ebSdamien 			if (rt2860_rates[ridx].rate == rate)
168530aa40ebSdamien 				break;
168630aa40ebSdamien 		sc->fixed_ridx = ridx;
168730aa40ebSdamien 	}
168830aa40ebSdamien 
168939c928acSdamien 	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
169039c928acSdamien 	    (IFF_UP | IFF_RUNNING)) {
169139c928acSdamien 		run_stop(ifp, 0);
16922e342c84Skevlo 		error = run_init(ifp);
169339c928acSdamien 	}
169430aa40ebSdamien 
16952e342c84Skevlo 	return error;
169630aa40ebSdamien }
169730aa40ebSdamien 
169830aa40ebSdamien void
run_next_scan(void * arg)169930aa40ebSdamien run_next_scan(void *arg)
170030aa40ebSdamien {
170130aa40ebSdamien 	struct run_softc *sc = arg;
1702ac5ee598Sstsp 	int s;
170330aa40ebSdamien 
170412136ef5Sjakemsr 	if (usbd_is_dying(sc->sc_udev))
170512136ef5Sjakemsr 		return;
170612136ef5Sjakemsr 
170712136ef5Sjakemsr 	usbd_ref_incr(sc->sc_udev);
170812136ef5Sjakemsr 
1709ac5ee598Sstsp 	s = splnet();
171030aa40ebSdamien 	if (sc->sc_ic.ic_state == IEEE80211_S_SCAN)
171130aa40ebSdamien 		ieee80211_next_scan(&sc->sc_ic.ic_if);
1712ac5ee598Sstsp 	splx(s);
171312136ef5Sjakemsr 
171412136ef5Sjakemsr 	usbd_ref_decr(sc->sc_udev);
171530aa40ebSdamien }
171630aa40ebSdamien 
171730aa40ebSdamien void
run_task(void * arg)171830aa40ebSdamien run_task(void *arg)
171930aa40ebSdamien {
172030aa40ebSdamien 	struct run_softc *sc = arg;
172130aa40ebSdamien 	struct run_host_cmd_ring *ring = &sc->cmdq;
172230aa40ebSdamien 	struct run_host_cmd *cmd;
172330aa40ebSdamien 	int s;
172430aa40ebSdamien 
172512136ef5Sjakemsr 	if (usbd_is_dying(sc->sc_udev))
172612136ef5Sjakemsr 		return;
172712136ef5Sjakemsr 
172830aa40ebSdamien 	/* process host commands */
172930aa40ebSdamien 	s = splusb();
173030aa40ebSdamien 	while (ring->next != ring->cur) {
173130aa40ebSdamien 		cmd = &ring->cmd[ring->next];
173230aa40ebSdamien 		splx(s);
1733cd4f4e38Sdamien 		/* callback */
173430aa40ebSdamien 		cmd->cb(sc, cmd->data);
173530aa40ebSdamien 		s = splusb();
173630aa40ebSdamien 		ring->queued--;
173730aa40ebSdamien 		ring->next = (ring->next + 1) % RUN_HOST_CMD_RING_COUNT;
173830aa40ebSdamien 	}
173930aa40ebSdamien 	splx(s);
174030aa40ebSdamien }
174130aa40ebSdamien 
174230aa40ebSdamien void
run_do_async(struct run_softc * sc,void (* cb)(struct run_softc *,void *),void * arg,int len)174330aa40ebSdamien run_do_async(struct run_softc *sc, void (*cb)(struct run_softc *, void *),
174430aa40ebSdamien     void *arg, int len)
174530aa40ebSdamien {
174630aa40ebSdamien 	struct run_host_cmd_ring *ring = &sc->cmdq;
174730aa40ebSdamien 	struct run_host_cmd *cmd;
174830aa40ebSdamien 	int s;
174930aa40ebSdamien 
175012136ef5Sjakemsr 	if (usbd_is_dying(sc->sc_udev))
175112136ef5Sjakemsr 		return;
175212136ef5Sjakemsr 
175330aa40ebSdamien 	s = splusb();
175430aa40ebSdamien 	cmd = &ring->cmd[ring->cur];
175530aa40ebSdamien 	cmd->cb = cb;
175630aa40ebSdamien 	KASSERT(len <= sizeof (cmd->data));
175730aa40ebSdamien 	memcpy(cmd->data, arg, len);
175830aa40ebSdamien 	ring->cur = (ring->cur + 1) % RUN_HOST_CMD_RING_COUNT;
175930aa40ebSdamien 
176030aa40ebSdamien 	/* if there is no pending command already, schedule a task */
176130aa40ebSdamien 	if (++ring->queued == 1)
176230aa40ebSdamien 		usb_add_task(sc->sc_udev, &sc->sc_task);
176330aa40ebSdamien 	splx(s);
176430aa40ebSdamien }
176530aa40ebSdamien 
176630aa40ebSdamien int
run_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)176730aa40ebSdamien run_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
176830aa40ebSdamien {
176930aa40ebSdamien 	struct run_softc *sc = ic->ic_softc;
177030aa40ebSdamien 	struct run_cmd_newstate cmd;
177130aa40ebSdamien 
177230aa40ebSdamien 	/* do it in a process context */
177330aa40ebSdamien 	cmd.state = nstate;
177430aa40ebSdamien 	cmd.arg = arg;
177530aa40ebSdamien 	run_do_async(sc, run_newstate_cb, &cmd, sizeof cmd);
177630aa40ebSdamien 	return 0;
177730aa40ebSdamien }
177830aa40ebSdamien 
177930aa40ebSdamien void
run_newstate_cb(struct run_softc * sc,void * arg)178030aa40ebSdamien run_newstate_cb(struct run_softc *sc, void *arg)
178130aa40ebSdamien {
178230aa40ebSdamien 	struct run_cmd_newstate *cmd = arg;
178330aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
178430aa40ebSdamien 	enum ieee80211_state ostate;
178530aa40ebSdamien 	struct ieee80211_node *ni;
178630aa40ebSdamien 	uint32_t tmp, sta[3];
178730aa40ebSdamien 	uint8_t wcid;
178830aa40ebSdamien 	int s;
178930aa40ebSdamien 
179030aa40ebSdamien 	s = splnet();
179130aa40ebSdamien 	ostate = ic->ic_state;
179230aa40ebSdamien 
179330aa40ebSdamien 	if (ostate == IEEE80211_S_RUN) {
179430aa40ebSdamien 		/* turn link LED off */
179530aa40ebSdamien 		run_set_leds(sc, RT2860_LED_RADIO);
179630aa40ebSdamien 	}
179730aa40ebSdamien 
179830aa40ebSdamien 	switch (cmd->state) {
179930aa40ebSdamien 	case IEEE80211_S_INIT:
180030aa40ebSdamien 		if (ostate == IEEE80211_S_RUN) {
180130aa40ebSdamien 			/* abort TSF synchronization */
180230aa40ebSdamien 			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
180330aa40ebSdamien 			run_write(sc, RT2860_BCN_TIME_CFG,
180430aa40ebSdamien 			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
180530aa40ebSdamien 			    RT2860_TBTT_TIMER_EN));
180630aa40ebSdamien 		}
180730aa40ebSdamien 		break;
180830aa40ebSdamien 
180930aa40ebSdamien 	case IEEE80211_S_SCAN:
181030aa40ebSdamien 		run_set_chan(sc, ic->ic_bss->ni_chan);
181112136ef5Sjakemsr 		if (!usbd_is_dying(sc->sc_udev))
181230aa40ebSdamien 			timeout_add_msec(&sc->scan_to, 200);
181330aa40ebSdamien 		break;
181430aa40ebSdamien 
181530aa40ebSdamien 	case IEEE80211_S_AUTH:
181630aa40ebSdamien 	case IEEE80211_S_ASSOC:
181730aa40ebSdamien 		run_set_chan(sc, ic->ic_bss->ni_chan);
181830aa40ebSdamien 		break;
181930aa40ebSdamien 
182030aa40ebSdamien 	case IEEE80211_S_RUN:
182130aa40ebSdamien 		run_set_chan(sc, ic->ic_bss->ni_chan);
182230aa40ebSdamien 
182330aa40ebSdamien 		ni = ic->ic_bss;
182430aa40ebSdamien 
182530aa40ebSdamien 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
182630aa40ebSdamien 			run_updateslot(ic);
182730aa40ebSdamien 			run_enable_mrr(sc);
182830aa40ebSdamien 			run_set_txpreamble(sc);
182930aa40ebSdamien 			run_set_basicrates(sc);
183030aa40ebSdamien 			run_set_bssid(sc, ni->ni_bssid);
183130aa40ebSdamien 		}
183230aa40ebSdamien 		if (ic->ic_opmode == IEEE80211_M_STA) {
183330aa40ebSdamien 			/* add BSS entry to the WCID table */
183430aa40ebSdamien 			wcid = RUN_AID2WCID(ni->ni_associd);
183530aa40ebSdamien 			run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
183630aa40ebSdamien 			    ni->ni_macaddr, IEEE80211_ADDR_LEN);
183730aa40ebSdamien 
183830aa40ebSdamien 			/* fake a join to init the tx rate */
183930aa40ebSdamien 			run_newassoc(ic, ni, 1);
184030aa40ebSdamien 		}
184130aa40ebSdamien 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
184230aa40ebSdamien 			run_enable_tsf_sync(sc);
184330aa40ebSdamien 
184430aa40ebSdamien 			/* clear statistic registers used by AMRR */
184530aa40ebSdamien 			run_read_region_1(sc, RT2860_TX_STA_CNT0,
184630aa40ebSdamien 			    (uint8_t *)sta, sizeof sta);
184730aa40ebSdamien 			/* start calibration timer */
184812136ef5Sjakemsr 			if (!usbd_is_dying(sc->sc_udev))
184930aa40ebSdamien 				timeout_add_sec(&sc->calib_to, 1);
185030aa40ebSdamien 		}
185130aa40ebSdamien 
185230aa40ebSdamien 		/* turn link LED on */
185330aa40ebSdamien 		run_set_leds(sc, RT2860_LED_RADIO |
185430aa40ebSdamien 		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan) ?
185530aa40ebSdamien 		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
185630aa40ebSdamien 		break;
185730aa40ebSdamien 	}
185830aa40ebSdamien 	(void)sc->sc_newstate(ic, cmd->state, cmd->arg);
185930aa40ebSdamien 	splx(s);
186030aa40ebSdamien }
186130aa40ebSdamien 
186230aa40ebSdamien void
run_updateedca(struct ieee80211com * ic)186330aa40ebSdamien run_updateedca(struct ieee80211com *ic)
186430aa40ebSdamien {
186530aa40ebSdamien 	/* do it in a process context */
186630aa40ebSdamien 	run_do_async(ic->ic_softc, run_updateedca_cb, NULL, 0);
186730aa40ebSdamien }
186830aa40ebSdamien 
186930aa40ebSdamien void
run_updateedca_cb(struct run_softc * sc,void * arg)187030aa40ebSdamien run_updateedca_cb(struct run_softc *sc, void *arg)
187130aa40ebSdamien {
187230aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
187330aa40ebSdamien 	int s, aci;
187430aa40ebSdamien 
187530aa40ebSdamien 	s = splnet();
187630aa40ebSdamien 	/* update MAC TX configuration registers */
187730aa40ebSdamien 	for (aci = 0; aci < EDCA_NUM_AC; aci++) {
187830aa40ebSdamien 		run_write(sc, RT2860_EDCA_AC_CFG(aci),
187930aa40ebSdamien 		    ic->ic_edca_ac[aci].ac_ecwmax << 16 |
188030aa40ebSdamien 		    ic->ic_edca_ac[aci].ac_ecwmin << 12 |
188130aa40ebSdamien 		    ic->ic_edca_ac[aci].ac_aifsn  <<  8 |
188230aa40ebSdamien 		    ic->ic_edca_ac[aci].ac_txoplimit);
188330aa40ebSdamien 	}
188430aa40ebSdamien 
188530aa40ebSdamien 	/* update SCH/DMA registers too */
188630aa40ebSdamien 	run_write(sc, RT2860_WMM_AIFSN_CFG,
188730aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_VO].ac_aifsn  << 12 |
188830aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_VI].ac_aifsn  <<  8 |
188930aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_BK].ac_aifsn  <<  4 |
189030aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_BE].ac_aifsn);
189130aa40ebSdamien 	run_write(sc, RT2860_WMM_CWMIN_CFG,
189230aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_VO].ac_ecwmin << 12 |
189330aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_VI].ac_ecwmin <<  8 |
189430aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_BK].ac_ecwmin <<  4 |
189530aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_BE].ac_ecwmin);
189630aa40ebSdamien 	run_write(sc, RT2860_WMM_CWMAX_CFG,
189730aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_VO].ac_ecwmax << 12 |
189830aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_VI].ac_ecwmax <<  8 |
189930aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_BK].ac_ecwmax <<  4 |
190030aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_BE].ac_ecwmax);
190130aa40ebSdamien 	run_write(sc, RT2860_WMM_TXOP0_CFG,
190230aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_BK].ac_txoplimit << 16 |
190330aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_BE].ac_txoplimit);
190430aa40ebSdamien 	run_write(sc, RT2860_WMM_TXOP1_CFG,
190530aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_VO].ac_txoplimit << 16 |
190630aa40ebSdamien 	    ic->ic_edca_ac[EDCA_AC_VI].ac_txoplimit);
190730aa40ebSdamien 	splx(s);
190830aa40ebSdamien }
190930aa40ebSdamien 
191030aa40ebSdamien int
run_set_key(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_key * k)191130aa40ebSdamien run_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
191230aa40ebSdamien     struct ieee80211_key *k)
191330aa40ebSdamien {
191430aa40ebSdamien 	struct run_softc *sc = ic->ic_softc;
191530aa40ebSdamien 	struct run_cmd_key cmd;
191630aa40ebSdamien 
19170760dad6Sdamien 	/* defer setting of WEP keys until interface is brought up */
19180760dad6Sdamien 	if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
19190760dad6Sdamien 	    (IFF_UP | IFF_RUNNING))
19200760dad6Sdamien 		return 0;
19210760dad6Sdamien 
192230aa40ebSdamien 	/* do it in a process context */
192330aa40ebSdamien 	cmd.key = *k;
1924cf67a9a2Skrw 	cmd.ni = ni;
192530aa40ebSdamien 	run_do_async(sc, run_set_key_cb, &cmd, sizeof cmd);
1926cf67a9a2Skrw 	sc->sc_key_tasks++;
1927cf67a9a2Skrw 
1928cf67a9a2Skrw 	return EBUSY;
192930aa40ebSdamien }
193030aa40ebSdamien 
193130aa40ebSdamien void
run_set_key_cb(struct run_softc * sc,void * arg)193230aa40ebSdamien run_set_key_cb(struct run_softc *sc, void *arg)
193330aa40ebSdamien {
1934cf67a9a2Skrw 	struct ieee80211com *ic = &sc->sc_ic;
193530aa40ebSdamien 	struct run_cmd_key *cmd = arg;
193630aa40ebSdamien 	struct ieee80211_key *k = &cmd->key;
193730aa40ebSdamien 	uint32_t attr;
193830aa40ebSdamien 	uint16_t base;
193930aa40ebSdamien 	uint8_t mode, wcid, iv[8];
194030aa40ebSdamien 
1941cf67a9a2Skrw 	sc->sc_key_tasks--;
1942cf67a9a2Skrw 
194330aa40ebSdamien 	/* map net80211 cipher to RT2860 security mode */
194430aa40ebSdamien 	switch (k->k_cipher) {
194530aa40ebSdamien 	case IEEE80211_CIPHER_WEP40:
194630aa40ebSdamien 		mode = RT2860_MODE_WEP40;
194730aa40ebSdamien 		break;
194830aa40ebSdamien 	case IEEE80211_CIPHER_WEP104:
194930aa40ebSdamien 		mode = RT2860_MODE_WEP104;
195030aa40ebSdamien 		break;
195130aa40ebSdamien 	case IEEE80211_CIPHER_TKIP:
195230aa40ebSdamien 		mode = RT2860_MODE_TKIP;
195330aa40ebSdamien 		break;
195430aa40ebSdamien 	case IEEE80211_CIPHER_CCMP:
195530aa40ebSdamien 		mode = RT2860_MODE_AES_CCMP;
195630aa40ebSdamien 		break;
195730aa40ebSdamien 	default:
1958cf67a9a2Skrw 		IEEE80211_SEND_MGMT(ic, cmd->ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
1959cf67a9a2Skrw 		    IEEE80211_REASON_AUTH_LEAVE);
1960cf67a9a2Skrw 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
196130aa40ebSdamien 		return;
196230aa40ebSdamien 	}
196330aa40ebSdamien 
196430aa40ebSdamien 	if (k->k_flags & IEEE80211_KEY_GROUP) {
196530aa40ebSdamien 		wcid = 0;	/* NB: update WCID0 for group keys */
196630aa40ebSdamien 		base = RT2860_SKEY(0, k->k_id);
196730aa40ebSdamien 	} else {
19680ff00077Skrw 		wcid = (cmd->ni != NULL) ? RUN_AID2WCID(cmd->ni->ni_associd) : 0;
196930aa40ebSdamien 		base = RT2860_PKEY(wcid);
197030aa40ebSdamien 	}
197130aa40ebSdamien 
197230aa40ebSdamien 	if (k->k_cipher == IEEE80211_CIPHER_TKIP) {
197330aa40ebSdamien 		run_write_region_1(sc, base, k->k_key, 16);
197430aa40ebSdamien 		run_write_region_1(sc, base + 16, &k->k_key[24], 8);
197530aa40ebSdamien 		run_write_region_1(sc, base + 24, &k->k_key[16], 8);
1976cd4f4e38Sdamien 	} else {
1977cd4f4e38Sdamien 		/* roundup len to 16-bit: XXX fix write_region_1() instead */
1978cd4f4e38Sdamien 		run_write_region_1(sc, base, k->k_key, (k->k_len + 1) & ~1);
1979cd4f4e38Sdamien 	}
198030aa40ebSdamien 
198130aa40ebSdamien 	if (!(k->k_flags & IEEE80211_KEY_GROUP) ||
198230aa40ebSdamien 	    (k->k_flags & IEEE80211_KEY_TX)) {
198330aa40ebSdamien 		/* set initial packet number in IV+EIV */
19847fc7fafeSdamien 		if (k->k_cipher == IEEE80211_CIPHER_WEP40 ||
19857fc7fafeSdamien 		    k->k_cipher == IEEE80211_CIPHER_WEP104) {
1986cd4f4e38Sdamien 			memset(iv, 0, sizeof iv);
1987cd4f4e38Sdamien 			iv[3] = sc->sc_ic.ic_def_txkey << 6;
198830aa40ebSdamien 		} else {
198930aa40ebSdamien 			if (k->k_cipher == IEEE80211_CIPHER_TKIP) {
199030aa40ebSdamien 				iv[0] = k->k_tsc >> 8;
199130aa40ebSdamien 				iv[1] = (iv[0] | 0x20) & 0x7f;
199230aa40ebSdamien 				iv[2] = k->k_tsc;
199330aa40ebSdamien 			} else /* CCMP */ {
199430aa40ebSdamien 				iv[0] = k->k_tsc;
199530aa40ebSdamien 				iv[1] = k->k_tsc >> 8;
199630aa40ebSdamien 				iv[2] = 0;
199730aa40ebSdamien 			}
199830aa40ebSdamien 			iv[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV;
199930aa40ebSdamien 			iv[4] = k->k_tsc >> 16;
200030aa40ebSdamien 			iv[5] = k->k_tsc >> 24;
200130aa40ebSdamien 			iv[6] = k->k_tsc >> 32;
200230aa40ebSdamien 			iv[7] = k->k_tsc >> 40;
200330aa40ebSdamien 		}
200430aa40ebSdamien 		run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8);
200530aa40ebSdamien 	}
200630aa40ebSdamien 
200730aa40ebSdamien 	if (k->k_flags & IEEE80211_KEY_GROUP) {
200830aa40ebSdamien 		/* install group key */
200930aa40ebSdamien 		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
201030aa40ebSdamien 		attr &= ~(0xf << (k->k_id * 4));
201130aa40ebSdamien 		attr |= mode << (k->k_id * 4);
201230aa40ebSdamien 		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
201330aa40ebSdamien 	} else {
201430aa40ebSdamien 		/* install pairwise key */
201530aa40ebSdamien 		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
201630aa40ebSdamien 		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
201730aa40ebSdamien 		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
201830aa40ebSdamien 	}
2019cf67a9a2Skrw 
2020cf67a9a2Skrw 	if (sc->sc_key_tasks == 0) {
20210ff00077Skrw 		if (cmd->ni != NULL)
2022cf67a9a2Skrw 			cmd->ni->ni_port_valid = 1;
2023cf67a9a2Skrw 		ieee80211_set_link_state(ic, LINK_STATE_UP);
2024cf67a9a2Skrw 	}
202530aa40ebSdamien }
202630aa40ebSdamien 
202730aa40ebSdamien void
run_delete_key(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_key * k)202830aa40ebSdamien run_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
202930aa40ebSdamien     struct ieee80211_key *k)
203030aa40ebSdamien {
203130aa40ebSdamien 	struct run_softc *sc = ic->ic_softc;
203230aa40ebSdamien 	struct run_cmd_key cmd;
203330aa40ebSdamien 
20342563814dSdamien 	if (!(ic->ic_if.if_flags & IFF_RUNNING) ||
20352563814dSdamien 	    ic->ic_state != IEEE80211_S_RUN)
203630aa40ebSdamien 		return;	/* nothing to do */
203730aa40ebSdamien 
203830aa40ebSdamien 	/* do it in a process context */
203930aa40ebSdamien 	cmd.key = *k;
2040cf67a9a2Skrw 	cmd.ni = ni;
204130aa40ebSdamien 	run_do_async(sc, run_delete_key_cb, &cmd, sizeof cmd);
204230aa40ebSdamien }
204330aa40ebSdamien 
204430aa40ebSdamien void
run_delete_key_cb(struct run_softc * sc,void * arg)204530aa40ebSdamien run_delete_key_cb(struct run_softc *sc, void *arg)
204630aa40ebSdamien {
204730aa40ebSdamien 	struct run_cmd_key *cmd = arg;
204830aa40ebSdamien 	struct ieee80211_key *k = &cmd->key;
204930aa40ebSdamien 	uint32_t attr;
205030aa40ebSdamien 	uint8_t wcid;
205130aa40ebSdamien 
205230aa40ebSdamien 	if (k->k_flags & IEEE80211_KEY_GROUP) {
205330aa40ebSdamien 		/* remove group key */
205430aa40ebSdamien 		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
205530aa40ebSdamien 		attr &= ~(0xf << (k->k_id * 4));
205630aa40ebSdamien 		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
205730aa40ebSdamien 
205830aa40ebSdamien 	} else {
205930aa40ebSdamien 		/* remove pairwise key */
20600ff00077Skrw 		wcid = (cmd->ni != NULL) ? RUN_AID2WCID(cmd->ni->ni_associd) : 0;
206130aa40ebSdamien 		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
206230aa40ebSdamien 		attr &= ~0xf;
206330aa40ebSdamien 		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
206430aa40ebSdamien 	}
206530aa40ebSdamien }
206630aa40ebSdamien 
206730aa40ebSdamien void
run_calibrate_to(void * arg)206830aa40ebSdamien run_calibrate_to(void *arg)
206930aa40ebSdamien {
207030aa40ebSdamien 	/* do it in a process context */
207130aa40ebSdamien 	run_do_async(arg, run_calibrate_cb, NULL, 0);
207230aa40ebSdamien 	/* next timeout will be rescheduled in the calibration task */
207330aa40ebSdamien }
207430aa40ebSdamien 
207530aa40ebSdamien void
run_calibrate_cb(struct run_softc * sc,void * arg)207630aa40ebSdamien run_calibrate_cb(struct run_softc *sc, void *arg)
207730aa40ebSdamien {
207830aa40ebSdamien 	struct ifnet *ifp = &sc->sc_ic.ic_if;
207930aa40ebSdamien 	uint32_t sta[3];
208030aa40ebSdamien 	int s, error;
208130aa40ebSdamien 
208230aa40ebSdamien 	/* read statistic counters (clear on read) and update AMRR state */
208330aa40ebSdamien 	error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
208430aa40ebSdamien 	    sizeof sta);
208530aa40ebSdamien 	if (error != 0)
208630aa40ebSdamien 		goto skip;
208730aa40ebSdamien 
208830aa40ebSdamien 	DPRINTF(("retrycnt=%d txcnt=%d failcnt=%d\n",
208930aa40ebSdamien 	    letoh32(sta[1]) >> 16, letoh32(sta[1]) & 0xffff,
209030aa40ebSdamien 	    letoh32(sta[0]) & 0xffff));
209130aa40ebSdamien 
209230aa40ebSdamien 	s = splnet();
209330aa40ebSdamien 	/* count failed TX as errors */
209430aa40ebSdamien 	ifp->if_oerrors += letoh32(sta[0]) & 0xffff;
209530aa40ebSdamien 
209630aa40ebSdamien 	sc->amn.amn_retrycnt =
209730aa40ebSdamien 	    (letoh32(sta[0]) & 0xffff) +	/* failed TX count */
209830aa40ebSdamien 	    (letoh32(sta[1]) >> 16);		/* TX retransmission count */
209930aa40ebSdamien 
210030aa40ebSdamien 	sc->amn.amn_txcnt =
210130aa40ebSdamien 	    sc->amn.amn_retrycnt +
210230aa40ebSdamien 	    (letoh32(sta[1]) & 0xffff);		/* successful TX count */
210330aa40ebSdamien 
210430aa40ebSdamien 	ieee80211_amrr_choose(&sc->amrr, sc->sc_ic.ic_bss, &sc->amn);
210530aa40ebSdamien 	splx(s);
210630aa40ebSdamien 
210712136ef5Sjakemsr skip:
210812136ef5Sjakemsr 	if (!usbd_is_dying(sc->sc_udev))
210912136ef5Sjakemsr 		timeout_add_sec(&sc->calib_to, 1);
211030aa40ebSdamien }
211130aa40ebSdamien 
211230aa40ebSdamien void
run_newassoc(struct ieee80211com * ic,struct ieee80211_node * ni,int isnew)211330aa40ebSdamien run_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
211430aa40ebSdamien {
211530aa40ebSdamien 	struct run_softc *sc = ic->ic_softc;
211630aa40ebSdamien 	struct run_node *rn = (void *)ni;
211730aa40ebSdamien 	struct ieee80211_rateset *rs = &ni->ni_rates;
211830aa40ebSdamien 	uint8_t rate;
211930aa40ebSdamien 	int ridx, i, j;
212030aa40ebSdamien 
212130aa40ebSdamien 	DPRINTF(("new assoc isnew=%d addr=%s\n",
212230aa40ebSdamien 	    isnew, ether_sprintf(ni->ni_macaddr)));
212330aa40ebSdamien 
212430aa40ebSdamien 	ieee80211_amrr_node_init(&sc->amrr, &sc->amn);
212530aa40ebSdamien 	/* start at lowest available bit-rate, AMRR will raise */
212630aa40ebSdamien 	ni->ni_txrate = 0;
212730aa40ebSdamien 
212830aa40ebSdamien 	for (i = 0; i < rs->rs_nrates; i++) {
212930aa40ebSdamien 		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
213030aa40ebSdamien 		/* convert 802.11 rate to hardware rate index */
21312c0c7625Soga 		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
213230aa40ebSdamien 			if (rt2860_rates[ridx].rate == rate)
213330aa40ebSdamien 				break;
213430aa40ebSdamien 		rn->ridx[i] = ridx;
213530aa40ebSdamien 		/* determine rate of control response frames */
213630aa40ebSdamien 		for (j = i; j >= 0; j--) {
213730aa40ebSdamien 			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
213830aa40ebSdamien 			    rt2860_rates[rn->ridx[i]].phy ==
213930aa40ebSdamien 			    rt2860_rates[rn->ridx[j]].phy)
214030aa40ebSdamien 				break;
214130aa40ebSdamien 		}
214230aa40ebSdamien 		if (j >= 0) {
214330aa40ebSdamien 			rn->ctl_ridx[i] = rn->ridx[j];
214430aa40ebSdamien 		} else {
214530aa40ebSdamien 			/* no basic rate found, use mandatory one */
214630aa40ebSdamien 			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
214730aa40ebSdamien 		}
214830aa40ebSdamien 		DPRINTF(("rate=0x%02x ridx=%d ctl_ridx=%d\n",
214930aa40ebSdamien 		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]));
215030aa40ebSdamien 	}
215130aa40ebSdamien }
215230aa40ebSdamien 
215330aa40ebSdamien /*
215430aa40ebSdamien  * Return the Rx chain with the highest RSSI for a given frame.
215530aa40ebSdamien  */
215630aa40ebSdamien static __inline uint8_t
run_maxrssi_chain(struct run_softc * sc,const struct rt2860_rxwi * rxwi)215730aa40ebSdamien run_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
215830aa40ebSdamien {
215930aa40ebSdamien 	uint8_t rxchain = 0;
216030aa40ebSdamien 
216130aa40ebSdamien 	if (sc->nrxchains > 1) {
216230aa40ebSdamien 		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
216330aa40ebSdamien 			rxchain = 1;
216430aa40ebSdamien 		if (sc->nrxchains > 2)
216530aa40ebSdamien 			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
216630aa40ebSdamien 				rxchain = 2;
216730aa40ebSdamien 	}
216830aa40ebSdamien 	return rxchain;
216930aa40ebSdamien }
217030aa40ebSdamien 
217130aa40ebSdamien void
run_rx_frame(struct run_softc * sc,uint8_t * buf,int dmalen,struct mbuf_list * ml)21728fbaf8a2Sstsp run_rx_frame(struct run_softc *sc, uint8_t *buf, int dmalen,
21738fbaf8a2Sstsp     struct mbuf_list *ml)
217430aa40ebSdamien {
217530aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
217630aa40ebSdamien 	struct ifnet *ifp = &ic->ic_if;
217730aa40ebSdamien 	struct ieee80211_frame *wh;
217830aa40ebSdamien 	struct ieee80211_rxinfo rxi;
217930aa40ebSdamien 	struct ieee80211_node *ni;
218030aa40ebSdamien 	struct rt2870_rxd *rxd;
218130aa40ebSdamien 	struct rt2860_rxwi *rxwi;
218230aa40ebSdamien 	struct mbuf *m;
218330aa40ebSdamien 	uint32_t flags;
21840e43911fSreyk 	uint16_t len;
21850e43911fSreyk #if NBPFILTER > 0
21860e43911fSreyk 	uint16_t phy;
21870e43911fSreyk #endif
2188d80de052Sstsp 	uint16_t rxwisize;
218930aa40ebSdamien 	uint8_t ant, rssi;
219030aa40ebSdamien 	int s;
219130aa40ebSdamien 
219230aa40ebSdamien 	rxwi = (struct rt2860_rxwi *)buf;
2193d80de052Sstsp 	rxwisize = sizeof(struct rt2860_rxwi);
2194d80de052Sstsp 	if (sc->mac_ver == 0x5592)
2195d80de052Sstsp 		rxwisize += sizeof(uint64_t);
2196d80de052Sstsp 	else if (sc->mac_ver == 0x3593)
2197d80de052Sstsp 		rxwisize += sizeof(uint32_t);
219830aa40ebSdamien 	len = letoh16(rxwi->len) & 0xfff;
219930aa40ebSdamien 	if (__predict_false(len > dmalen)) {
220030aa40ebSdamien 		DPRINTF(("bad RXWI length %u > %u\n", len, dmalen));
220130aa40ebSdamien 		return;
220230aa40ebSdamien 	}
220379d0d5f8Skevlo 	if (len > MCLBYTES) {
220479d0d5f8Skevlo 		DPRINTF(("frame too large (length=%d)\n", len));
220579d0d5f8Skevlo 		ifp->if_ierrors++;
220679d0d5f8Skevlo 		return;
220779d0d5f8Skevlo 	}
220830aa40ebSdamien 	/* Rx descriptor is located at the end */
220930aa40ebSdamien 	rxd = (struct rt2870_rxd *)(buf + dmalen);
221030aa40ebSdamien 	flags = letoh32(rxd->flags);
221130aa40ebSdamien 
221230aa40ebSdamien 	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
221330aa40ebSdamien 		ifp->if_ierrors++;
221430aa40ebSdamien 		return;
221530aa40ebSdamien 	}
221630aa40ebSdamien 
221730aa40ebSdamien 	if (__predict_false((flags & RT2860_RX_MICERR))) {
221830aa40ebSdamien 		/* report MIC failures to net80211 for TKIP */
221930aa40ebSdamien 		ic->ic_stats.is_rx_locmicfail++;
222030aa40ebSdamien 		ieee80211_michael_mic_failure(ic, 0/* XXX */);
222130aa40ebSdamien 		ifp->if_ierrors++;
222230aa40ebSdamien 		return;
222330aa40ebSdamien 	}
222430aa40ebSdamien 
2225d80de052Sstsp 	wh = (struct ieee80211_frame *)(buf + rxwisize);
222652a13037Sstsp 	memset(&rxi, 0, sizeof(rxi));
222730aa40ebSdamien 	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
222830aa40ebSdamien 		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
222930aa40ebSdamien 		rxi.rxi_flags |= IEEE80211_RXI_HWDEC;
223030aa40ebSdamien 	}
223130aa40ebSdamien 
22328ca7058fSdamien 	if (flags & RT2860_RX_L2PAD) {
223330aa40ebSdamien 		u_int hdrlen = ieee80211_get_hdrlen(wh);
22349b2ad23fSderaadt 		memmove((caddr_t)wh + 2, wh, hdrlen);
223530aa40ebSdamien 		wh = (struct ieee80211_frame *)((caddr_t)wh + 2);
223630aa40ebSdamien 	}
223730aa40ebSdamien 
2238c4a33c5cSdamien 	/* could use m_devget but net80211 wants contig mgmt frames */
223930aa40ebSdamien 	MGETHDR(m, M_DONTWAIT, MT_DATA);
224030aa40ebSdamien 	if (__predict_false(m == NULL)) {
224130aa40ebSdamien 		ifp->if_ierrors++;
224230aa40ebSdamien 		return;
224330aa40ebSdamien 	}
224430aa40ebSdamien 	if (len > MHLEN) {
224530aa40ebSdamien 		MCLGET(m, M_DONTWAIT);
224630aa40ebSdamien 		if (__predict_false(!(m->m_flags & M_EXT))) {
224730aa40ebSdamien 			ifp->if_ierrors++;
224830aa40ebSdamien 			m_freem(m);
224930aa40ebSdamien 			return;
225030aa40ebSdamien 		}
225130aa40ebSdamien 	}
225230aa40ebSdamien 	/* finalize mbuf */
225330aa40ebSdamien 	memcpy(mtod(m, caddr_t), wh, len);
225430aa40ebSdamien 	m->m_pkthdr.len = m->m_len = len;
225530aa40ebSdamien 
225630aa40ebSdamien 	ant = run_maxrssi_chain(sc, rxwi);
225730aa40ebSdamien 	rssi = rxwi->rssi[ant];
225830aa40ebSdamien 
225930aa40ebSdamien #if NBPFILTER > 0
226030aa40ebSdamien 	if (__predict_false(sc->sc_drvbpf != NULL)) {
226130aa40ebSdamien 		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
226230aa40ebSdamien 		struct mbuf mb;
226330aa40ebSdamien 
226430aa40ebSdamien 		tap->wr_flags = 0;
226530aa40ebSdamien 		tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
226630aa40ebSdamien 		tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
226730aa40ebSdamien 		tap->wr_antsignal = rssi;
226830aa40ebSdamien 		tap->wr_antenna = ant;
226930aa40ebSdamien 		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
227030aa40ebSdamien 		tap->wr_rate = 2;	/* in case it can't be found below */
227130aa40ebSdamien 		phy = letoh16(rxwi->phy);
227230aa40ebSdamien 		switch (phy & RT2860_PHY_MODE) {
227330aa40ebSdamien 		case RT2860_PHY_CCK:
227430aa40ebSdamien 			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
227530aa40ebSdamien 			case 0:	tap->wr_rate =   2; break;
227630aa40ebSdamien 			case 1:	tap->wr_rate =   4; break;
227730aa40ebSdamien 			case 2:	tap->wr_rate =  11; break;
227830aa40ebSdamien 			case 3:	tap->wr_rate =  22; break;
227930aa40ebSdamien 			}
228030aa40ebSdamien 			if (phy & RT2860_PHY_SHPRE)
228130aa40ebSdamien 				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
228230aa40ebSdamien 			break;
228330aa40ebSdamien 		case RT2860_PHY_OFDM:
228430aa40ebSdamien 			switch (phy & RT2860_PHY_MCS) {
228530aa40ebSdamien 			case 0:	tap->wr_rate =  12; break;
228630aa40ebSdamien 			case 1:	tap->wr_rate =  18; break;
228730aa40ebSdamien 			case 2:	tap->wr_rate =  24; break;
228830aa40ebSdamien 			case 3:	tap->wr_rate =  36; break;
228930aa40ebSdamien 			case 4:	tap->wr_rate =  48; break;
229030aa40ebSdamien 			case 5:	tap->wr_rate =  72; break;
229130aa40ebSdamien 			case 6:	tap->wr_rate =  96; break;
229230aa40ebSdamien 			case 7:	tap->wr_rate = 108; break;
229330aa40ebSdamien 			}
229430aa40ebSdamien 			break;
229530aa40ebSdamien 		}
229630aa40ebSdamien 		mb.m_data = (caddr_t)tap;
229730aa40ebSdamien 		mb.m_len = sc->sc_rxtap_len;
229830aa40ebSdamien 		mb.m_next = m;
229930aa40ebSdamien 		mb.m_nextpkt = NULL;
230030aa40ebSdamien 		mb.m_type = 0;
230130aa40ebSdamien 		mb.m_flags = 0;
230230aa40ebSdamien 		bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
230330aa40ebSdamien 	}
230430aa40ebSdamien #endif
230530aa40ebSdamien 
230630aa40ebSdamien 	s = splnet();
230730aa40ebSdamien 	ni = ieee80211_find_rxnode(ic, wh);
230830aa40ebSdamien 	rxi.rxi_rssi = rssi;
23098fbaf8a2Sstsp 	ieee80211_inputm(ifp, m, ni, &rxi, ml);
231030aa40ebSdamien 
231130aa40ebSdamien 	/* node is no longer needed */
231230aa40ebSdamien 	ieee80211_release_node(ic, ni);
231330aa40ebSdamien 	splx(s);
231430aa40ebSdamien }
231530aa40ebSdamien 
231630aa40ebSdamien void
run_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)2317ab0b1be7Smglocker run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
231830aa40ebSdamien {
23198fbaf8a2Sstsp 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
232030aa40ebSdamien 	struct run_rx_data *data = priv;
232130aa40ebSdamien 	struct run_softc *sc = data->sc;
232230aa40ebSdamien 	uint8_t *buf;
232330aa40ebSdamien 	uint32_t dmalen;
232430aa40ebSdamien 	int xferlen;
23258bad3cf5Sstsp 	uint16_t rxwisize;
23268bad3cf5Sstsp 
23278bad3cf5Sstsp 	rxwisize = sizeof(struct rt2860_rxwi);
23288bad3cf5Sstsp 	if (sc->mac_ver == 0x5592)
23298bad3cf5Sstsp 		rxwisize += sizeof(uint64_t);
23308bad3cf5Sstsp 	else if (sc->mac_ver == 0x3593)
23318bad3cf5Sstsp 		rxwisize += sizeof(uint32_t);
233230aa40ebSdamien 
233330aa40ebSdamien 	if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
233430aa40ebSdamien 		DPRINTF(("RX status=%d\n", status));
233530aa40ebSdamien 		if (status == USBD_STALLED)
233630aa40ebSdamien 			usbd_clear_endpoint_stall_async(sc->rxq.pipeh);
233730aa40ebSdamien 		if (status != USBD_CANCELLED)
233830aa40ebSdamien 			goto skip;
233930aa40ebSdamien 		return;
234030aa40ebSdamien 	}
234130aa40ebSdamien 	usbd_get_xfer_status(xfer, NULL, NULL, &xferlen, NULL);
234230aa40ebSdamien 
23438bad3cf5Sstsp 	if (__predict_false(xferlen < sizeof (uint32_t) + rxwisize +
23448bad3cf5Sstsp 	    sizeof(struct rt2870_rxd))) {
234530aa40ebSdamien 		DPRINTF(("xfer too short %d\n", xferlen));
234630aa40ebSdamien 		goto skip;
234730aa40ebSdamien 	}
234830aa40ebSdamien 
234930aa40ebSdamien 	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
235030aa40ebSdamien 	buf = data->buf;
235130aa40ebSdamien 	while (xferlen > 8) {
235230aa40ebSdamien 		dmalen = letoh32(*(uint32_t *)buf) & 0xffff;
235330aa40ebSdamien 
235430aa40ebSdamien 		if (__predict_false(dmalen == 0 || (dmalen & 3) != 0)) {
2355523b8010Sdamien 			DPRINTF(("bad DMA length %u\n", dmalen));
235630aa40ebSdamien 			break;
235730aa40ebSdamien 		}
235830aa40ebSdamien 		if (__predict_false(dmalen + 8 > xferlen)) {
235930aa40ebSdamien 			DPRINTF(("bad DMA length %u > %d\n",
236030aa40ebSdamien 			    dmalen + 8, xferlen));
236130aa40ebSdamien 			break;
236230aa40ebSdamien 		}
23638fbaf8a2Sstsp 		run_rx_frame(sc, buf + sizeof (uint32_t), dmalen, &ml);
236430aa40ebSdamien 		buf += dmalen + 8;
236530aa40ebSdamien 		xferlen -= dmalen + 8;
236630aa40ebSdamien 	}
23678fbaf8a2Sstsp 	if_input(&sc->sc_ic.ic_if, &ml);
236830aa40ebSdamien 
236930aa40ebSdamien skip:	/* setup a new transfer */
237030aa40ebSdamien 	usbd_setup_xfer(xfer, sc->rxq.pipeh, data, data->buf, RUN_MAX_RXSZ,
237130aa40ebSdamien 	    USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, run_rxeof);
237230aa40ebSdamien 	(void)usbd_transfer(data->xfer);
237330aa40ebSdamien }
237430aa40ebSdamien 
237530aa40ebSdamien void
run_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)2376ab0b1be7Smglocker run_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
237730aa40ebSdamien {
237830aa40ebSdamien 	struct run_tx_data *data = priv;
237930aa40ebSdamien 	struct run_softc *sc = data->sc;
238030aa40ebSdamien 	struct run_tx_ring *txq = &sc->txq[data->qid];
238130aa40ebSdamien 	struct ifnet *ifp = &sc->sc_ic.ic_if;
238230aa40ebSdamien 	int s;
238330aa40ebSdamien 
2384ba34d050Sdamien 	s = splnet();
2385ba34d050Sdamien 	txq->queued--;
2386ba34d050Sdamien 	sc->qfullmsk &= ~(1 << data->qid);
2387ba34d050Sdamien 
238830aa40ebSdamien 	if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
238930aa40ebSdamien 		DPRINTF(("TX status=%d\n", status));
239030aa40ebSdamien 		if (status == USBD_STALLED)
239130aa40ebSdamien 			usbd_clear_endpoint_stall_async(txq->pipeh);
239230aa40ebSdamien 		ifp->if_oerrors++;
2393ba34d050Sdamien 		splx(s);
239430aa40ebSdamien 		return;
239530aa40ebSdamien 	}
239630aa40ebSdamien 
239730aa40ebSdamien 	sc->sc_tx_timer = 0;
2398de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
239930aa40ebSdamien 	run_start(ifp);
240030aa40ebSdamien 	splx(s);
240130aa40ebSdamien }
240230aa40ebSdamien 
240330aa40ebSdamien int
run_tx(struct run_softc * sc,struct mbuf * m,struct ieee80211_node * ni)240430aa40ebSdamien run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
240530aa40ebSdamien {
240630aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
240730aa40ebSdamien 	struct run_node *rn = (void *)ni;
240830aa40ebSdamien 	struct ieee80211_frame *wh;
240930aa40ebSdamien 	struct run_tx_ring *ring;
241030aa40ebSdamien 	struct run_tx_data *data;
241130aa40ebSdamien 	struct rt2870_txd *txd;
241230aa40ebSdamien 	struct rt2860_txwi *txwi;
241330aa40ebSdamien 	uint16_t qos, dur;
24148bad3cf5Sstsp 	uint16_t txwisize;
241530aa40ebSdamien 	uint8_t type, mcs, tid, qid;
241630aa40ebSdamien 	int error, hasqos, ridx, ctl_ridx, xferlen;
241730aa40ebSdamien 
241830aa40ebSdamien 	wh = mtod(m, struct ieee80211_frame *);
241930aa40ebSdamien 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
242030aa40ebSdamien 
242130aa40ebSdamien 	if ((hasqos = ieee80211_has_qos(wh))) {
242230aa40ebSdamien 		qos = ieee80211_get_qos(wh);
242330aa40ebSdamien 		tid = qos & IEEE80211_QOS_TID;
242430aa40ebSdamien 		qid = ieee80211_up_to_ac(ic, tid);
242530aa40ebSdamien 	} else {
24263dc83bf9Shaesbaert 		qos = 0;
242730aa40ebSdamien 		tid = 0;
242830aa40ebSdamien 		qid = EDCA_AC_BE;
242930aa40ebSdamien 	}
243030aa40ebSdamien 	ring = &sc->txq[qid];
243130aa40ebSdamien 	data = &ring->data[ring->cur];
243230aa40ebSdamien 
243330aa40ebSdamien 	/* pickup a rate index */
243430aa40ebSdamien 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
243530aa40ebSdamien 	    type != IEEE80211_FC0_TYPE_DATA) {
243630aa40ebSdamien 		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
243730aa40ebSdamien 		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
243830aa40ebSdamien 		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
243930aa40ebSdamien 	} else if (ic->ic_fixed_rate != -1) {
244030aa40ebSdamien 		ridx = sc->fixed_ridx;
244130aa40ebSdamien 		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
244230aa40ebSdamien 	} else {
244330aa40ebSdamien 		ridx = rn->ridx[ni->ni_txrate];
244430aa40ebSdamien 		ctl_ridx = rn->ctl_ridx[ni->ni_txrate];
244530aa40ebSdamien 	}
244630aa40ebSdamien 
244730aa40ebSdamien 	/* get MCS code from rate index */
244830aa40ebSdamien 	mcs = rt2860_rates[ridx].mcs;
244930aa40ebSdamien 
24508bad3cf5Sstsp 	txwisize = sizeof(struct rt2860_txwi);
24518bad3cf5Sstsp 	if (sc->mac_ver == 0x5592)
24528bad3cf5Sstsp 		txwisize += sizeof(uint32_t);
24538bad3cf5Sstsp 	xferlen = txwisize + m->m_pkthdr.len;
24548bad3cf5Sstsp 
245530aa40ebSdamien 	/* roundup to 32-bit alignment */
245630aa40ebSdamien 	xferlen = (xferlen + 3) & ~3;
245730aa40ebSdamien 
245830aa40ebSdamien 	txd = (struct rt2870_txd *)data->buf;
245930aa40ebSdamien 	txd->flags = RT2860_TX_QSEL_EDCA;
246030aa40ebSdamien 	txd->len = htole16(xferlen);
246130aa40ebSdamien 
246230aa40ebSdamien 	/* setup TX Wireless Information */
246330aa40ebSdamien 	txwi = (struct rt2860_txwi *)(txd + 1);
246430aa40ebSdamien 	txwi->flags = 0;
2465bd510035Sdamien 	txwi->xflags = hasqos ? 0 : RT2860_TX_NSEQ;
246630aa40ebSdamien 	txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ?
246730aa40ebSdamien 	    RUN_AID2WCID(ni->ni_associd) : 0xff;
246830aa40ebSdamien 	txwi->len = htole16(m->m_pkthdr.len);
246930aa40ebSdamien 	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
247030aa40ebSdamien 		txwi->phy = htole16(RT2860_PHY_CCK);
247130aa40ebSdamien 		if (ridx != RT2860_RIDX_CCK1 &&
247230aa40ebSdamien 		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
247330aa40ebSdamien 			mcs |= RT2860_PHY_SHPRE;
247430aa40ebSdamien 	} else
247530aa40ebSdamien 		txwi->phy = htole16(RT2860_PHY_OFDM);
247630aa40ebSdamien 	txwi->phy |= htole16(mcs);
247730aa40ebSdamien 
247830aa40ebSdamien 	txwi->txop = RT2860_TX_TXOP_BACKOFF;
247930aa40ebSdamien 
248030aa40ebSdamien 	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
2481b9864d55Sdamien 	    (!hasqos || (qos & IEEE80211_QOS_ACK_POLICY_MASK) !=
248230aa40ebSdamien 	     IEEE80211_QOS_ACK_POLICY_NOACK)) {
248330aa40ebSdamien 		txwi->xflags |= RT2860_TX_ACK;
248430aa40ebSdamien 		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
248530aa40ebSdamien 			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
248630aa40ebSdamien 		else
248730aa40ebSdamien 			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
2488970cc175Sdamien 		*(uint16_t *)wh->i_dur = htole16(dur);
248930aa40ebSdamien 	}
249030aa40ebSdamien 
2491773b33c5Sdamien #if NBPFILTER > 0
2492773b33c5Sdamien 	if (__predict_false(sc->sc_drvbpf != NULL)) {
2493773b33c5Sdamien 		struct run_tx_radiotap_header *tap = &sc->sc_txtap;
2494773b33c5Sdamien 		struct mbuf mb;
2495773b33c5Sdamien 
2496773b33c5Sdamien 		tap->wt_flags = 0;
2497773b33c5Sdamien 		tap->wt_rate = rt2860_rates[ridx].rate;
2498773b33c5Sdamien 		tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
2499773b33c5Sdamien 		tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
2500773b33c5Sdamien 		if (mcs & RT2860_PHY_SHPRE)
2501773b33c5Sdamien 			tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2502773b33c5Sdamien 
2503773b33c5Sdamien 		mb.m_data = (caddr_t)tap;
2504773b33c5Sdamien 		mb.m_len = sc->sc_txtap_len;
2505773b33c5Sdamien 		mb.m_next = m;
2506773b33c5Sdamien 		mb.m_nextpkt = NULL;
2507773b33c5Sdamien 		mb.m_type = 0;
2508773b33c5Sdamien 		mb.m_flags = 0;
2509773b33c5Sdamien 		bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
2510773b33c5Sdamien 	}
2511773b33c5Sdamien #endif
2512773b33c5Sdamien 
25138bad3cf5Sstsp 	m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)txwi + txwisize);
251430aa40ebSdamien 	m_freem(m);
251530aa40ebSdamien 
251630aa40ebSdamien 	xferlen += sizeof (*txd) + 4;
251730aa40ebSdamien 
251830aa40ebSdamien 	usbd_setup_xfer(data->xfer, ring->pipeh, data, data->buf, xferlen,
251930aa40ebSdamien 	    USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RUN_TX_TIMEOUT, run_txeof);
252030aa40ebSdamien 	error = usbd_transfer(data->xfer);
252130aa40ebSdamien 	if (__predict_false(error != USBD_IN_PROGRESS && error != 0))
252230aa40ebSdamien 		return error;
252330aa40ebSdamien 
25241b0b2675Sdamien 	ieee80211_release_node(ic, ni);
25251b0b2675Sdamien 
252630aa40ebSdamien 	ring->cur = (ring->cur + 1) % RUN_TX_RING_COUNT;
252730aa40ebSdamien 	if (++ring->queued >= RUN_TX_RING_COUNT)
252830aa40ebSdamien 		sc->qfullmsk |= 1 << qid;
252930aa40ebSdamien 
253030aa40ebSdamien 	return 0;
253130aa40ebSdamien }
253230aa40ebSdamien 
253330aa40ebSdamien void
run_start(struct ifnet * ifp)253430aa40ebSdamien run_start(struct ifnet *ifp)
253530aa40ebSdamien {
253630aa40ebSdamien 	struct run_softc *sc = ifp->if_softc;
253730aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
253830aa40ebSdamien 	struct ieee80211_node *ni;
253930aa40ebSdamien 	struct mbuf *m;
254030aa40ebSdamien 
2541de6cd8fbSdlg 	if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
254230aa40ebSdamien 		return;
254330aa40ebSdamien 
254430aa40ebSdamien 	for (;;) {
254530aa40ebSdamien 		if (sc->qfullmsk != 0) {
2546de6cd8fbSdlg 			ifq_set_oactive(&ifp->if_snd);
254730aa40ebSdamien 			break;
254830aa40ebSdamien 		}
254930aa40ebSdamien 		/* send pending management frames first */
2550351e1934Sdlg 		m = mq_dequeue(&ic->ic_mgtq);
255130aa40ebSdamien 		if (m != NULL) {
25526da4b19dSmpi 			ni = m->m_pkthdr.ph_cookie;
255330aa40ebSdamien 			goto sendit;
255430aa40ebSdamien 		}
255530aa40ebSdamien 		if (ic->ic_state != IEEE80211_S_RUN)
255630aa40ebSdamien 			break;
255730aa40ebSdamien 
255830aa40ebSdamien 		/* encapsulate and send data frames */
255963bcfa73Spatrick 		m = ifq_dequeue(&ifp->if_snd);
256030aa40ebSdamien 		if (m == NULL)
256130aa40ebSdamien 			break;
256230aa40ebSdamien #if NBPFILTER > 0
256330aa40ebSdamien 		if (ifp->if_bpf != NULL)
256430aa40ebSdamien 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
256530aa40ebSdamien #endif
256630aa40ebSdamien 		if ((m = ieee80211_encap(ifp, m, &ni)) == NULL)
256730aa40ebSdamien 			continue;
256830aa40ebSdamien sendit:
256930aa40ebSdamien #if NBPFILTER > 0
257030aa40ebSdamien 		if (ic->ic_rawbpf != NULL)
257130aa40ebSdamien 			bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
257230aa40ebSdamien #endif
257330aa40ebSdamien 		if (run_tx(sc, m, ni) != 0) {
25741b0b2675Sdamien 			ieee80211_release_node(ic, ni);
257530aa40ebSdamien 			ifp->if_oerrors++;
257630aa40ebSdamien 			continue;
257730aa40ebSdamien 		}
257830aa40ebSdamien 
257930aa40ebSdamien 		sc->sc_tx_timer = 5;
258030aa40ebSdamien 		ifp->if_timer = 1;
258130aa40ebSdamien 	}
258230aa40ebSdamien }
258330aa40ebSdamien 
258430aa40ebSdamien void
run_watchdog(struct ifnet * ifp)258530aa40ebSdamien run_watchdog(struct ifnet *ifp)
258630aa40ebSdamien {
258730aa40ebSdamien 	struct run_softc *sc = ifp->if_softc;
258830aa40ebSdamien 
258930aa40ebSdamien 	ifp->if_timer = 0;
259030aa40ebSdamien 
259130aa40ebSdamien 	if (sc->sc_tx_timer > 0) {
259230aa40ebSdamien 		if (--sc->sc_tx_timer == 0) {
259330aa40ebSdamien 			printf("%s: device timeout\n", sc->sc_dev.dv_xname);
259430aa40ebSdamien 			/* run_init(ifp); XXX needs a process context! */
259530aa40ebSdamien 			ifp->if_oerrors++;
259630aa40ebSdamien 			return;
259730aa40ebSdamien 		}
259830aa40ebSdamien 		ifp->if_timer = 1;
259930aa40ebSdamien 	}
260030aa40ebSdamien 
260130aa40ebSdamien 	ieee80211_watchdog(ifp);
260230aa40ebSdamien }
260330aa40ebSdamien 
260430aa40ebSdamien int
run_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)260530aa40ebSdamien run_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
260630aa40ebSdamien {
260730aa40ebSdamien 	struct run_softc *sc = ifp->if_softc;
260830aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
260930aa40ebSdamien 	int s, error = 0;
261030aa40ebSdamien 
261112136ef5Sjakemsr 	if (usbd_is_dying(sc->sc_udev))
261212136ef5Sjakemsr 		return ENXIO;
261312136ef5Sjakemsr 
261412136ef5Sjakemsr 	usbd_ref_incr(sc->sc_udev);
261512136ef5Sjakemsr 
261630aa40ebSdamien 	s = splnet();
261730aa40ebSdamien 
261830aa40ebSdamien 	switch (cmd) {
261930aa40ebSdamien 	case SIOCSIFADDR:
262030aa40ebSdamien 		ifp->if_flags |= IFF_UP;
262130aa40ebSdamien 		/* FALLTHROUGH */
262230aa40ebSdamien 	case SIOCSIFFLAGS:
262330aa40ebSdamien 		if (ifp->if_flags & IFF_UP) {
262430aa40ebSdamien 			if (!(ifp->if_flags & IFF_RUNNING))
262530aa40ebSdamien 				run_init(ifp);
262630aa40ebSdamien 		} else {
262730aa40ebSdamien 			if (ifp->if_flags & IFF_RUNNING)
262830aa40ebSdamien 				run_stop(ifp, 1);
262930aa40ebSdamien 		}
263030aa40ebSdamien 		break;
263130aa40ebSdamien 
263230aa40ebSdamien 	case SIOCS80211CHANNEL:
263330aa40ebSdamien 		/*
263430aa40ebSdamien 		 * This allows for fast channel switching in monitor mode
263539c928acSdamien 		 * (used by kismet).
263630aa40ebSdamien 		 */
263730aa40ebSdamien 		error = ieee80211_ioctl(ifp, cmd, data);
263830aa40ebSdamien 		if (error == ENETRESET &&
263930aa40ebSdamien 		    ic->ic_opmode == IEEE80211_M_MONITOR) {
264030aa40ebSdamien 			if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
264130aa40ebSdamien 			    (IFF_UP | IFF_RUNNING))
264230aa40ebSdamien 				run_set_chan(sc, ic->ic_ibss_chan);
264330aa40ebSdamien 			error = 0;
264430aa40ebSdamien 		}
264530aa40ebSdamien 		break;
264630aa40ebSdamien 
264730aa40ebSdamien 	default:
264830aa40ebSdamien 		error = ieee80211_ioctl(ifp, cmd, data);
264930aa40ebSdamien 	}
265030aa40ebSdamien 
265130aa40ebSdamien 	if (error == ENETRESET) {
265230aa40ebSdamien 		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
265339c928acSdamien 		    (IFF_UP | IFF_RUNNING)) {
265439c928acSdamien 			run_stop(ifp, 0);
265530aa40ebSdamien 			run_init(ifp);
265639c928acSdamien 		}
265730aa40ebSdamien 		error = 0;
265830aa40ebSdamien 	}
265930aa40ebSdamien 
266030aa40ebSdamien 	splx(s);
266130aa40ebSdamien 
266212136ef5Sjakemsr 	usbd_ref_decr(sc->sc_udev);
266312136ef5Sjakemsr 
266430aa40ebSdamien 	return error;
266530aa40ebSdamien }
266630aa40ebSdamien 
266730aa40ebSdamien void
run_iq_calib(struct run_softc * sc,u_int chan)2668d80de052Sstsp run_iq_calib(struct run_softc *sc, u_int chan)
2669d80de052Sstsp {
2670d80de052Sstsp 	uint16_t val;
2671d80de052Sstsp 
2672d80de052Sstsp 	/* Tx0 IQ gain. */
2673d80de052Sstsp 	run_bbp_write(sc, 158, 0x2c);
2674d80de052Sstsp 	if (chan <= 14)
2675d80de052Sstsp 		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val);
2676d80de052Sstsp 	else if (chan <= 64) {
2677d80de052Sstsp 		run_efuse_read(sc,
2678d80de052Sstsp 		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ, &val);
2679d80de052Sstsp 	} else if (chan <= 138) {
2680d80de052Sstsp 		run_efuse_read(sc,
2681d80de052Sstsp 		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ, &val);
2682d80de052Sstsp 	} else if (chan <= 165) {
2683d80de052Sstsp 		run_efuse_read(sc,
2684d80de052Sstsp 	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
2685d80de052Sstsp 		    &val);
2686d80de052Sstsp 	} else
2687d80de052Sstsp 		val = 0;
2688d80de052Sstsp 	run_bbp_write(sc, 159, val);
2689d80de052Sstsp 
2690d80de052Sstsp 	/* Tx0 IQ phase. */
2691d80de052Sstsp 	run_bbp_write(sc, 158, 0x2d);
2692d80de052Sstsp 	if (chan <= 14) {
2693d80de052Sstsp 		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ, &val);
2694d80de052Sstsp 	} else if (chan <= 64) {
2695d80de052Sstsp 		run_efuse_read(sc,
2696d80de052Sstsp 		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ, &val);
2697d80de052Sstsp 	} else if (chan <= 138) {
2698d80de052Sstsp 		run_efuse_read(sc,
2699d80de052Sstsp 		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ, &val);
2700d80de052Sstsp 	} else if (chan <= 165) {
2701d80de052Sstsp 		run_efuse_read(sc,
2702d80de052Sstsp 		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ, &val);
2703d80de052Sstsp 	} else
2704d80de052Sstsp 		val = 0;
2705d80de052Sstsp 	run_bbp_write(sc, 159, val);
2706d80de052Sstsp 
2707d80de052Sstsp 	/* Tx1 IQ gain. */
2708d80de052Sstsp 	run_bbp_write(sc, 158, 0x4a);
2709d80de052Sstsp 	if (chan <= 14) {
2710d80de052Sstsp 		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ, &val);
2711d80de052Sstsp 	} else if (chan <= 64) {
2712d80de052Sstsp 		run_efuse_read(sc,
2713d80de052Sstsp 		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ, &val);
2714d80de052Sstsp 	} else if (chan <= 138) {
2715d80de052Sstsp 		run_efuse_read(sc,
2716d80de052Sstsp 		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ, &val);
2717d80de052Sstsp 	} else if (chan <= 165) {
2718d80de052Sstsp 		run_efuse_read(sc,
2719d80de052Sstsp 		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ, &val);
2720d80de052Sstsp 	} else
2721d80de052Sstsp 		val = 0;
2722d80de052Sstsp 	run_bbp_write(sc, 159, val);
2723d80de052Sstsp 
2724d80de052Sstsp 	/* Tx1 IQ phase. */
2725d80de052Sstsp 	run_bbp_write(sc, 158, 0x4b);
2726d80de052Sstsp 	if (chan <= 14) {
2727d80de052Sstsp 		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ, &val);
2728d80de052Sstsp 	} else if (chan <= 64) {
2729d80de052Sstsp 		run_efuse_read(sc,
2730d80de052Sstsp 		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ, &val);
2731d80de052Sstsp 	} else if (chan <= 138) {
2732d80de052Sstsp 		run_efuse_read(sc,
2733d80de052Sstsp 		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ, &val);
2734d80de052Sstsp 	} else if (chan <= 165) {
2735d80de052Sstsp 		run_efuse_read(sc,
2736d80de052Sstsp 		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ, &val);
2737d80de052Sstsp 	} else
2738d80de052Sstsp 		val = 0;
2739d80de052Sstsp 	run_bbp_write(sc, 159, val);
2740d80de052Sstsp 
2741d80de052Sstsp 	/* RF IQ compensation control. */
2742d80de052Sstsp 	run_bbp_write(sc, 158, 0x04);
2743d80de052Sstsp 	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL, &val);
2744d80de052Sstsp 	run_bbp_write(sc, 159, val);
2745d80de052Sstsp 
2746d80de052Sstsp 	/* RF IQ imbalance compensation control. */
2747d80de052Sstsp 	run_bbp_write(sc, 158, 0x03);
2748d80de052Sstsp 	run_efuse_read(sc,
2749d80de052Sstsp 	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val);
2750d80de052Sstsp 	run_bbp_write(sc, 159, val);
2751d80de052Sstsp }
2752d80de052Sstsp 
2753d80de052Sstsp void
run_select_chan_group(struct run_softc * sc,int group)275430aa40ebSdamien run_select_chan_group(struct run_softc *sc, int group)
275530aa40ebSdamien {
275630aa40ebSdamien 	uint32_t tmp;
27575f5eab5eSdamien 	uint8_t agc;
275830aa40ebSdamien 
275930aa40ebSdamien 	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
276030aa40ebSdamien 	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
276130aa40ebSdamien 	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
2762d80de052Sstsp 	if (sc->mac_ver < 0x3572)
276330aa40ebSdamien 		run_bbp_write(sc, 86, 0x00);
276430aa40ebSdamien 
2765d80de052Sstsp 	if (sc->mac_ver == 0x3593) {
2766d80de052Sstsp 		run_bbp_write(sc, 77, 0x98);
2767d80de052Sstsp 		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
2768d80de052Sstsp 	}
2769d80de052Sstsp 
277030aa40ebSdamien 	if (group == 0) {
277130aa40ebSdamien 		if (sc->ext_2ghz_lna) {
2772d80de052Sstsp 			if (sc->mac_ver >= 0x5390)
2773d80de052Sstsp 				run_bbp_write(sc, 75, 0x52);
2774d80de052Sstsp 			else {
277530aa40ebSdamien 				run_bbp_write(sc, 82, 0x62);
277630aa40ebSdamien 				run_bbp_write(sc, 75, 0x46);
277730aa40ebSdamien 			}
277830aa40ebSdamien 		} else {
2779d80de052Sstsp 			if (sc->mac_ver == 0x5592) {
2780d80de052Sstsp 				run_bbp_write(sc, 79, 0x1c);
2781d80de052Sstsp 				run_bbp_write(sc, 80, 0x0e);
2782d80de052Sstsp 				run_bbp_write(sc, 81, 0x3a);
2783d80de052Sstsp 				run_bbp_write(sc, 82, 0x62);
2784d80de052Sstsp 
2785d80de052Sstsp 				run_bbp_write(sc, 195, 0x80);
2786d80de052Sstsp 				run_bbp_write(sc, 196, 0xe0);
2787d80de052Sstsp 				run_bbp_write(sc, 195, 0x81);
2788d80de052Sstsp 				run_bbp_write(sc, 196, 0x1f);
2789d80de052Sstsp 				run_bbp_write(sc, 195, 0x82);
2790d80de052Sstsp 				run_bbp_write(sc, 196, 0x38);
2791d80de052Sstsp 				run_bbp_write(sc, 195, 0x83);
2792d80de052Sstsp 				run_bbp_write(sc, 196, 0x32);
2793d80de052Sstsp 				run_bbp_write(sc, 195, 0x85);
2794d80de052Sstsp 				run_bbp_write(sc, 196, 0x28);
2795d80de052Sstsp 				run_bbp_write(sc, 195, 0x86);
2796d80de052Sstsp 				run_bbp_write(sc, 196, 0x19);
2797d80de052Sstsp 			} else if (sc->mac_ver >= 0x5390)
2798d80de052Sstsp 				run_bbp_write(sc, 75, 0x50);
2799d80de052Sstsp 			else {
2800d80de052Sstsp 				run_bbp_write(sc, 82,
2801d80de052Sstsp 				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
2802d80de052Sstsp 				run_bbp_write(sc, 75, 0x50);
2803d80de052Sstsp 			}
2804d80de052Sstsp 		}
2805d80de052Sstsp 	} else {
2806d80de052Sstsp 		if (sc->mac_ver == 0x5592) {
2807d80de052Sstsp 			run_bbp_write(sc, 79, 0x18);
2808d80de052Sstsp 			run_bbp_write(sc, 80, 0x08);
2809d80de052Sstsp 			run_bbp_write(sc, 81, 0x38);
2810d80de052Sstsp 			run_bbp_write(sc, 82, 0x92);
2811d80de052Sstsp 
2812d80de052Sstsp 			run_bbp_write(sc, 195, 0x80);
2813d80de052Sstsp 			run_bbp_write(sc, 196, 0xf0);
2814d80de052Sstsp 			run_bbp_write(sc, 195, 0x81);
2815d80de052Sstsp 			run_bbp_write(sc, 196, 0x1e);
2816d80de052Sstsp 			run_bbp_write(sc, 195, 0x82);
2817d80de052Sstsp 			run_bbp_write(sc, 196, 0x28);
2818d80de052Sstsp 			run_bbp_write(sc, 195, 0x83);
2819d80de052Sstsp 			run_bbp_write(sc, 196, 0x20);
2820d80de052Sstsp 			run_bbp_write(sc, 195, 0x85);
2821d80de052Sstsp 			run_bbp_write(sc, 196, 0x7f);
2822d80de052Sstsp 			run_bbp_write(sc, 195, 0x86);
2823d80de052Sstsp 			run_bbp_write(sc, 196, 0x7f);
2824d80de052Sstsp 		} else if (sc->mac_ver == 0x3572)
28259807c12dSdamien 			run_bbp_write(sc, 82, 0x94);
28269807c12dSdamien 		else
2827d80de052Sstsp 			run_bbp_write(sc, 82,
2828d80de052Sstsp 			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
28299807c12dSdamien 		if (sc->ext_5ghz_lna)
283030aa40ebSdamien 			run_bbp_write(sc, 75, 0x46);
28319807c12dSdamien 		else
283230aa40ebSdamien 			run_bbp_write(sc, 75, 0x50);
283330aa40ebSdamien 	}
283430aa40ebSdamien 
283530aa40ebSdamien 	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
283630aa40ebSdamien 	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
283730aa40ebSdamien 	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
283830aa40ebSdamien 	run_write(sc, RT2860_TX_BAND_CFG, tmp);
283930aa40ebSdamien 
284030aa40ebSdamien 	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
284165a39fb3Sdamien 	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
2842d80de052Sstsp 	if (sc->mac_ver == 0x3593)
2843d80de052Sstsp 		tmp |= 1 << 29 | 1 << 28;
284465a39fb3Sdamien 	if (sc->nrxchains > 1)
284565a39fb3Sdamien 		tmp |= RT2860_LNA_PE1_EN;
284630aa40ebSdamien 	if (group == 0) {	/* 2GHz */
284765a39fb3Sdamien 		tmp |= RT2860_PA_PE_G0_EN;
284830aa40ebSdamien 		if (sc->ntxchains > 1)
284930aa40ebSdamien 			tmp |= RT2860_PA_PE_G1_EN;
2850d80de052Sstsp 		if (sc->mac_ver == 0x3593) {
2851d80de052Sstsp 			if (sc->ntxchains > 2)
2852d80de052Sstsp 				tmp |= 1 << 25;
2853d80de052Sstsp 		}
285430aa40ebSdamien 	} else {		/* 5GHz */
285565a39fb3Sdamien 		tmp |= RT2860_PA_PE_A0_EN;
285630aa40ebSdamien 		if (sc->ntxchains > 1)
285730aa40ebSdamien 			tmp |= RT2860_PA_PE_A1_EN;
285830aa40ebSdamien 	}
285997f89110Sdamien 	if (sc->mac_ver == 0x3572) {
286097f89110Sdamien 		run_rt3070_rf_write(sc, 8, 0x00);
286197f89110Sdamien 		run_write(sc, RT2860_TX_PIN_CFG, tmp);
286297f89110Sdamien 		run_rt3070_rf_write(sc, 8, 0x80);
286397f89110Sdamien 	} else
286430aa40ebSdamien 		run_write(sc, RT2860_TX_PIN_CFG, tmp);
286530aa40ebSdamien 
2866d80de052Sstsp 	if (sc->mac_ver == 0x5592) {
2867d80de052Sstsp 		run_bbp_write(sc, 195, 0x8d);
2868d80de052Sstsp 		run_bbp_write(sc, 196, 0x1a);
2869d80de052Sstsp 	}
2870d80de052Sstsp 
2871d80de052Sstsp 	if (sc->mac_ver == 0x3593) {
2872d80de052Sstsp 		run_read(sc, RT2860_GPIO_CTRL, &tmp);
2873d80de052Sstsp 		tmp &= ~0x01010000;
2874d80de052Sstsp 		if (group == 0)
2875d80de052Sstsp 			tmp |= 0x00010000;
2876d80de052Sstsp 		tmp = (tmp & ~0x00009090) | 0x00000090;
2877d80de052Sstsp 		run_write(sc, RT2860_GPIO_CTRL, tmp);
2878d80de052Sstsp 	}
2879d80de052Sstsp 
288030aa40ebSdamien 	/* set initial AGC value */
28815f5eab5eSdamien 	if (group == 0) {	/* 2GHz band */
28825f5eab5eSdamien 		if (sc->mac_ver >= 0x3070)
28835f5eab5eSdamien 			agc = 0x1c + sc->lna[0] * 2;
288430aa40ebSdamien 		else
28855f5eab5eSdamien 			agc = 0x2e + sc->lna[0];
28865f5eab5eSdamien 	} else {		/* 5GHz band */
2887d80de052Sstsp 		if (sc->mac_ver == 0x5592)
2888d80de052Sstsp 			agc = 0x24 + sc->lna[group] * 2;
2889d80de052Sstsp 		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
28905f5eab5eSdamien 			agc = 0x22 + (sc->lna[group] * 5) / 3;
28915f5eab5eSdamien 		else
28925f5eab5eSdamien 			agc = 0x32 + (sc->lna[group] * 5) / 3;
28935f5eab5eSdamien 	}
28945f5eab5eSdamien 	run_set_agc(sc, agc);
289530aa40ebSdamien }
289630aa40ebSdamien 
289730aa40ebSdamien void
run_rt2870_set_chan(struct run_softc * sc,u_int chan)289830aa40ebSdamien run_rt2870_set_chan(struct run_softc *sc, u_int chan)
289930aa40ebSdamien {
290030aa40ebSdamien 	const struct rfprog *rfprog = rt2860_rf2850;
290130aa40ebSdamien 	uint32_t r2, r3, r4;
290230aa40ebSdamien 	int8_t txpow1, txpow2;
290330aa40ebSdamien 	int i;
290430aa40ebSdamien 
290530aa40ebSdamien 	/* find the settings for this channel (we know it exists) */
290636dba039Sjsg 	for (i = 0; rfprog[i].chan != chan; i++)
290736dba039Sjsg 		;
290830aa40ebSdamien 
290930aa40ebSdamien 	r2 = rfprog[i].r2;
291030aa40ebSdamien 	if (sc->ntxchains == 1)
29112548be7aSmlarkin 		r2 |= 1 << 12;		/* 1T: disable Tx chain 2 */
291230aa40ebSdamien 	if (sc->nrxchains == 1)
29132548be7aSmlarkin 		r2 |= 1 << 15 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
291430aa40ebSdamien 	else if (sc->nrxchains == 2)
29152548be7aSmlarkin 		r2 |= 1 << 4;		/* 2R: disable Rx chain 3 */
291630aa40ebSdamien 
291730aa40ebSdamien 	/* use Tx power values from EEPROM */
291830aa40ebSdamien 	txpow1 = sc->txpow1[i];
291930aa40ebSdamien 	txpow2 = sc->txpow2[i];
292030aa40ebSdamien 	if (chan > 14) {
29212548be7aSmlarkin 		if (txpow1 >= 0)
29222548be7aSmlarkin 			txpow1 = txpow1 << 1 | 1;
29232548be7aSmlarkin 		else
29242548be7aSmlarkin 			txpow1 = (7 + txpow1) << 1;
29252548be7aSmlarkin 		if (txpow2 >= 0)
29262548be7aSmlarkin 			txpow2 = txpow2 << 1 | 1;
29272548be7aSmlarkin 		else
29282548be7aSmlarkin 			txpow2 = (7 + txpow2) << 1;
29292548be7aSmlarkin 	}
29302548be7aSmlarkin 	r3 = rfprog[i].r3 | txpow1 << 7;
29312548be7aSmlarkin 	r4 = rfprog[i].r4 | sc->freq << 13 | txpow2 << 4;
2932d80de052Sstsp 
29332548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
29342548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF2, r2);
29352548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF3, r3);
29362548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF4, r4);
293730aa40ebSdamien 
293830aa40ebSdamien 	DELAY(200);
293930aa40ebSdamien 
29402548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
29412548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF2, r2);
29422548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF3, r3 | 1);
29432548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF4, r4);
294430aa40ebSdamien 
294530aa40ebSdamien 	DELAY(200);
294630aa40ebSdamien 
29472548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
29482548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF2, r2);
29492548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF3, r3);
29502548be7aSmlarkin 	run_rt2870_rf_write(sc, RT2860_RF4, r4);
295130aa40ebSdamien }
295230aa40ebSdamien 
295330aa40ebSdamien void
run_rt3070_set_chan(struct run_softc * sc,u_int chan)295430aa40ebSdamien run_rt3070_set_chan(struct run_softc *sc, u_int chan)
295530aa40ebSdamien {
2956773b33c5Sdamien 	int8_t txpow1, txpow2;
2957773b33c5Sdamien 	uint8_t rf;
29580303be40Sdamien 	int i;
2959773b33c5Sdamien 
29600303be40Sdamien 	/* find the settings for this channel (we know it exists) */
296136dba039Sjsg 	for (i = 0; rt2860_rf2850[i].chan != chan; i++)
296236dba039Sjsg 		;
296330aa40ebSdamien 
29640303be40Sdamien 	/* use Tx power values from EEPROM */
29650303be40Sdamien 	txpow1 = sc->txpow1[i];
29660303be40Sdamien 	txpow2 = sc->txpow2[i];
29670303be40Sdamien 
29680303be40Sdamien 	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
2969d80de052Sstsp 
2970d80de052Sstsp 	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
2971d80de052Sstsp 	run_rt3070_rf_read(sc, 3, &rf);
2972d80de052Sstsp 	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
2973d80de052Sstsp 	run_rt3070_rf_write(sc, 3, rf);
2974d80de052Sstsp 
2975773b33c5Sdamien 	run_rt3070_rf_read(sc, 6, &rf);
29760303be40Sdamien 	rf = (rf & ~0x03) | rt3070_freqs[i].r;
2977773b33c5Sdamien 	run_rt3070_rf_write(sc, 6, rf);
297830aa40ebSdamien 
2979773b33c5Sdamien 	/* set Tx0 power */
2980773b33c5Sdamien 	run_rt3070_rf_read(sc, 12, &rf);
2981773b33c5Sdamien 	rf = (rf & ~0x1f) | txpow1;
2982773b33c5Sdamien 	run_rt3070_rf_write(sc, 12, rf);
2983773b33c5Sdamien 
2984773b33c5Sdamien 	/* set Tx1 power */
2985773b33c5Sdamien 	run_rt3070_rf_read(sc, 13, &rf);
2986773b33c5Sdamien 	rf = (rf & ~0x1f) | txpow2;
2987773b33c5Sdamien 	run_rt3070_rf_write(sc, 13, rf);
2988773b33c5Sdamien 
2989773b33c5Sdamien 	run_rt3070_rf_read(sc, 1, &rf);
2990773b33c5Sdamien 	rf &= ~0xfc;
2991773b33c5Sdamien 	if (sc->ntxchains == 1)
2992773b33c5Sdamien 		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
2993773b33c5Sdamien 	else if (sc->ntxchains == 2)
2994773b33c5Sdamien 		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
2995773b33c5Sdamien 	if (sc->nrxchains == 1)
2996773b33c5Sdamien 		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
2997773b33c5Sdamien 	else if (sc->nrxchains == 2)
2998773b33c5Sdamien 		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
2999773b33c5Sdamien 	run_rt3070_rf_write(sc, 1, rf);
300030aa40ebSdamien 
300130aa40ebSdamien 	/* set RF offset */
3002773b33c5Sdamien 	run_rt3070_rf_read(sc, 23, &rf);
3003773b33c5Sdamien 	rf = (rf & ~0x7f) | sc->freq;
3004773b33c5Sdamien 	run_rt3070_rf_write(sc, 23, rf);
300530aa40ebSdamien 
300630aa40ebSdamien 	/* program RF filter */
30070303be40Sdamien 	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
30080303be40Sdamien 	rf = (rf & ~0x3f) | sc->rf24_20mhz;
30090303be40Sdamien 	run_rt3070_rf_write(sc, 24, rf);
30100303be40Sdamien 	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
30110303be40Sdamien 	rf = (rf & ~0x3f) | sc->rf24_20mhz;
30120303be40Sdamien 	run_rt3070_rf_write(sc, 31, rf);
301330aa40ebSdamien 
301430aa40ebSdamien 	/* enable RF tuning */
3015773b33c5Sdamien 	run_rt3070_rf_read(sc, 7, &rf);
3016773b33c5Sdamien 	run_rt3070_rf_write(sc, 7, rf | 0x01);
301730aa40ebSdamien }
301830aa40ebSdamien 
3019cd4f4e38Sdamien void
run_rt3572_set_chan(struct run_softc * sc,u_int chan)302018327d80Sdamien run_rt3572_set_chan(struct run_softc *sc, u_int chan)
302118327d80Sdamien {
302218327d80Sdamien 	int8_t txpow1, txpow2;
302318327d80Sdamien 	uint32_t tmp;
302418327d80Sdamien 	uint8_t rf;
302518327d80Sdamien 	int i;
302618327d80Sdamien 
302718327d80Sdamien 	/* find the settings for this channel (we know it exists) */
302836dba039Sjsg 	for (i = 0; rt2860_rf2850[i].chan != chan; i++)
302936dba039Sjsg 		;
303018327d80Sdamien 
303118327d80Sdamien 	/* use Tx power values from EEPROM */
303218327d80Sdamien 	txpow1 = sc->txpow1[i];
303318327d80Sdamien 	txpow2 = sc->txpow2[i];
303418327d80Sdamien 
303518327d80Sdamien 	if (chan <= 14) {
303618327d80Sdamien 		run_bbp_write(sc, 25, sc->bbp25);
303718327d80Sdamien 		run_bbp_write(sc, 26, sc->bbp26);
303818327d80Sdamien 	} else {
303918327d80Sdamien 		/* enable IQ phase correction */
304018327d80Sdamien 		run_bbp_write(sc, 25, 0x09);
304118327d80Sdamien 		run_bbp_write(sc, 26, 0xff);
304218327d80Sdamien 	}
304318327d80Sdamien 
304418327d80Sdamien 	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
304518327d80Sdamien 	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
304618327d80Sdamien 	run_rt3070_rf_read(sc, 6, &rf);
304718327d80Sdamien 	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
304818327d80Sdamien 	rf |= (chan <= 14) ? 0x08 : 0x04;
304918327d80Sdamien 	run_rt3070_rf_write(sc, 6, rf);
305018327d80Sdamien 
305118327d80Sdamien 	/* set PLL mode */
305218327d80Sdamien 	run_rt3070_rf_read(sc, 5, &rf);
305318327d80Sdamien 	rf &= ~(0x08 | 0x04);
305418327d80Sdamien 	rf |= (chan <= 14) ? 0x04 : 0x08;
305518327d80Sdamien 	run_rt3070_rf_write(sc, 5, rf);
305618327d80Sdamien 
305718327d80Sdamien 	/* set Tx power for chain 0 */
305818327d80Sdamien 	if (chan <= 14)
305918327d80Sdamien 		rf = 0x60 | txpow1;
306018327d80Sdamien 	else
306118327d80Sdamien 		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
306218327d80Sdamien 	run_rt3070_rf_write(sc, 12, rf);
306318327d80Sdamien 
306418327d80Sdamien 	/* set Tx power for chain 1 */
306518327d80Sdamien 	if (chan <= 14)
306618327d80Sdamien 		rf = 0x60 | txpow2;
306718327d80Sdamien 	else
306818327d80Sdamien 		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
306918327d80Sdamien 	run_rt3070_rf_write(sc, 13, rf);
307018327d80Sdamien 
307118327d80Sdamien 	/* set Tx/Rx streams */
307218327d80Sdamien 	run_rt3070_rf_read(sc, 1, &rf);
307318327d80Sdamien 	rf &= ~0xfc;
307418327d80Sdamien 	if (sc->ntxchains == 1)
30750303be40Sdamien 		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
307618327d80Sdamien 	else if (sc->ntxchains == 2)
30770303be40Sdamien 		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
307818327d80Sdamien 	if (sc->nrxchains == 1)
30790303be40Sdamien 		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
308018327d80Sdamien 	else if (sc->nrxchains == 2)
30810303be40Sdamien 		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
308218327d80Sdamien 	run_rt3070_rf_write(sc, 1, rf);
308318327d80Sdamien 
308418327d80Sdamien 	/* set RF offset */
308518327d80Sdamien 	run_rt3070_rf_read(sc, 23, &rf);
308618327d80Sdamien 	rf = (rf & ~0x7f) | sc->freq;
308718327d80Sdamien 	run_rt3070_rf_write(sc, 23, rf);
308818327d80Sdamien 
308918327d80Sdamien 	/* program RF filter */
309018327d80Sdamien 	rf = sc->rf24_20mhz;
309118327d80Sdamien 	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
309218327d80Sdamien 	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
309318327d80Sdamien 
309418327d80Sdamien 	/* enable RF tuning */
309518327d80Sdamien 	run_rt3070_rf_read(sc, 7, &rf);
309618327d80Sdamien 	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
309718327d80Sdamien 	run_rt3070_rf_write(sc, 7, rf);
309818327d80Sdamien 
309918327d80Sdamien 	/* TSSI */
310018327d80Sdamien 	rf = (chan <= 14) ? 0xc3 : 0xc0;
310118327d80Sdamien 	run_rt3070_rf_write(sc, 9, rf);
310218327d80Sdamien 
310318327d80Sdamien 	/* set loop filter 1 */
310418327d80Sdamien 	run_rt3070_rf_write(sc, 10, 0xf1);
310518327d80Sdamien 	/* set loop filter 2 */
310618327d80Sdamien 	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
310718327d80Sdamien 
310818327d80Sdamien 	/* set tx_mx2_ic */
310918327d80Sdamien 	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
311018327d80Sdamien 	/* set tx_mx1_ic */
311118327d80Sdamien 	if (chan <= 14)
311218327d80Sdamien 		rf = 0x48 | sc->txmixgain_2ghz;
311318327d80Sdamien 	else
311418327d80Sdamien 		rf = 0x78 | sc->txmixgain_5ghz;
311518327d80Sdamien 	run_rt3070_rf_write(sc, 16, rf);
311618327d80Sdamien 
311718327d80Sdamien 	/* set tx_lo1 */
311818327d80Sdamien 	run_rt3070_rf_write(sc, 17, 0x23);
311918327d80Sdamien 	/* set tx_lo2 */
312018327d80Sdamien 	if (chan <= 14)
312118327d80Sdamien 		rf = 0x93;
312218327d80Sdamien 	else if (chan <= 64)
312318327d80Sdamien 		rf = 0xb7;
312418327d80Sdamien 	else if (chan <= 128)
312518327d80Sdamien 		rf = 0x74;
312618327d80Sdamien 	else
312718327d80Sdamien 		rf = 0x72;
312818327d80Sdamien 	run_rt3070_rf_write(sc, 19, rf);
312918327d80Sdamien 
313018327d80Sdamien 	/* set rx_lo1 */
313118327d80Sdamien 	if (chan <= 14)
313218327d80Sdamien 		rf = 0xb3;
313318327d80Sdamien 	else if (chan <= 64)
313418327d80Sdamien 		rf = 0xf6;
313518327d80Sdamien 	else if (chan <= 128)
313618327d80Sdamien 		rf = 0xf4;
313718327d80Sdamien 	else
313818327d80Sdamien 		rf = 0xf3;
313918327d80Sdamien 	run_rt3070_rf_write(sc, 20, rf);
314018327d80Sdamien 
314118327d80Sdamien 	/* set pfd_delay */
314218327d80Sdamien 	if (chan <= 14)
314318327d80Sdamien 		rf = 0x15;
314418327d80Sdamien 	else if (chan <= 64)
314518327d80Sdamien 		rf = 0x3d;
314618327d80Sdamien 	else
314718327d80Sdamien 		rf = 0x01;
314818327d80Sdamien 	run_rt3070_rf_write(sc, 25, rf);
314918327d80Sdamien 
315018327d80Sdamien 	/* set rx_lo2 */
315118327d80Sdamien 	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
315218327d80Sdamien 	/* set ldo_rf_vc */
315318327d80Sdamien 	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
315418327d80Sdamien 	/* set drv_cc */
315518327d80Sdamien 	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
315618327d80Sdamien 
315718327d80Sdamien 	run_read(sc, RT2860_GPIO_CTRL, &tmp);
315818327d80Sdamien 	tmp &= ~0x8080;
315918327d80Sdamien 	if (chan <= 14)
316018327d80Sdamien 		tmp |= 0x80;
316118327d80Sdamien 	run_write(sc, RT2860_GPIO_CTRL, tmp);
316218327d80Sdamien 
316318327d80Sdamien 	/* enable RF tuning */
316418327d80Sdamien 	run_rt3070_rf_read(sc, 7, &rf);
316518327d80Sdamien 	run_rt3070_rf_write(sc, 7, rf | 0x01);
316618327d80Sdamien 
316718327d80Sdamien 	DELAY(2000);
316818327d80Sdamien }
316918327d80Sdamien 
317018327d80Sdamien void
run_rt3593_set_chan(struct run_softc * sc,u_int chan)3171d80de052Sstsp run_rt3593_set_chan(struct run_softc *sc, u_int chan)
3172d80de052Sstsp {
3173d80de052Sstsp 	int8_t txpow1, txpow2, txpow3;
3174d80de052Sstsp 	uint8_t h20mhz, rf;
3175d80de052Sstsp 	int i;
3176d80de052Sstsp 
3177d80de052Sstsp 	/* find the settings for this channel (we know it exists) */
317836dba039Sjsg 	for (i = 0; rt2860_rf2850[i].chan != chan; i++)
317936dba039Sjsg 		;
3180d80de052Sstsp 
3181d80de052Sstsp 	/* use Tx power values from EEPROM */
3182d80de052Sstsp 	txpow1 = sc->txpow1[i];
3183d80de052Sstsp 	txpow2 = sc->txpow2[i];
3184d80de052Sstsp 	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
3185d80de052Sstsp 
3186d80de052Sstsp 	if (chan <= 14) {
3187d80de052Sstsp 		run_bbp_write(sc, 25, sc->bbp25);
3188d80de052Sstsp 		run_bbp_write(sc, 26, sc->bbp26);
3189d80de052Sstsp 	} else {
3190d80de052Sstsp 		/* Enable IQ phase correction. */
3191d80de052Sstsp 		run_bbp_write(sc, 25, 0x09);
3192d80de052Sstsp 		run_bbp_write(sc, 26, 0xff);
3193d80de052Sstsp 	}
3194d80de052Sstsp 
3195d80de052Sstsp 	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
3196d80de052Sstsp 	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
3197d80de052Sstsp 	run_rt3070_rf_read(sc, 11, &rf);
3198d80de052Sstsp 	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
3199d80de052Sstsp 	run_rt3070_rf_write(sc, 11, rf);
3200d80de052Sstsp 
3201d80de052Sstsp 	/* Set pll_idoh. */
3202d80de052Sstsp 	run_rt3070_rf_read(sc, 11, &rf);
3203d80de052Sstsp 	rf &= ~0x4c;
3204d80de052Sstsp 	rf |= (chan <= 14) ? 0x44 : 0x48;
3205d80de052Sstsp 	run_rt3070_rf_write(sc, 11, rf);
3206d80de052Sstsp 
3207d80de052Sstsp 	if (chan <= 14)
3208d80de052Sstsp 		rf = txpow1 & 0x1f;
3209d80de052Sstsp 	else
3210d80de052Sstsp 		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
3211d80de052Sstsp 	run_rt3070_rf_write(sc, 53, rf);
3212d80de052Sstsp 
3213d80de052Sstsp 	if (chan <= 14)
3214d80de052Sstsp 		rf = txpow2 & 0x1f;
3215d80de052Sstsp 	else
3216d80de052Sstsp 		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
3217d80de052Sstsp 	run_rt3070_rf_write(sc, 55, rf);
3218d80de052Sstsp 
3219d80de052Sstsp 	if (chan <= 14)
3220d80de052Sstsp 		rf = txpow3 & 0x1f;
3221d80de052Sstsp 	else
3222d80de052Sstsp 		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
3223d80de052Sstsp 	run_rt3070_rf_write(sc, 54, rf);
3224d80de052Sstsp 
3225d80de052Sstsp 	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
3226d80de052Sstsp 	if (sc->ntxchains == 3)
3227d80de052Sstsp 		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
3228d80de052Sstsp 	else
3229d80de052Sstsp 		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
3230d80de052Sstsp 	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
3231d80de052Sstsp 	run_rt3070_rf_write(sc, 1, rf);
3232d80de052Sstsp 
3233d80de052Sstsp 	run_adjust_freq_offset(sc);
3234d80de052Sstsp 
3235d80de052Sstsp 	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
3236d80de052Sstsp 
3237d80de052Sstsp 	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
3238d80de052Sstsp 	run_rt3070_rf_read(sc, 30, &rf);
3239d80de052Sstsp 	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
3240d80de052Sstsp 	run_rt3070_rf_write(sc, 30, rf);
3241d80de052Sstsp 
3242d80de052Sstsp 	run_rt3070_rf_read(sc, 36, &rf);
3243d80de052Sstsp 	if (chan <= 14)
3244d80de052Sstsp 		rf |= 0x80;
3245d80de052Sstsp 	else
3246d80de052Sstsp 		rf &= ~0x80;
3247d80de052Sstsp 	run_rt3070_rf_write(sc, 36, rf);
3248d80de052Sstsp 
3249d80de052Sstsp 	/* Set vcolo_bs. */
3250d80de052Sstsp 	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
3251d80de052Sstsp 	/* Set pfd_delay. */
3252d80de052Sstsp 	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
3253d80de052Sstsp 
3254d80de052Sstsp 	/* Set vco bias current control. */
3255d80de052Sstsp 	run_rt3070_rf_read(sc, 6, &rf);
3256d80de052Sstsp 	rf &= ~0xc0;
3257d80de052Sstsp 	if (chan <= 14)
3258d80de052Sstsp 		rf |= 0x40;
3259d80de052Sstsp 	else if (chan <= 128)
3260d80de052Sstsp 		rf |= 0x80;
3261d80de052Sstsp 	else
3262d80de052Sstsp 		rf |= 0x40;
3263d80de052Sstsp 	run_rt3070_rf_write(sc, 6, rf);
3264d80de052Sstsp 
3265d80de052Sstsp 	run_rt3070_rf_read(sc, 30, &rf);
3266d80de052Sstsp 	rf = (rf & ~0x18) | 0x10;
3267d80de052Sstsp 	run_rt3070_rf_write(sc, 30, rf);
3268d80de052Sstsp 
3269d80de052Sstsp 	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
3270d80de052Sstsp 	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
3271d80de052Sstsp 
3272d80de052Sstsp 	run_rt3070_rf_read(sc, 51, &rf);
3273d80de052Sstsp 	rf = (rf & ~0x03) | 0x01;
3274d80de052Sstsp 	run_rt3070_rf_write(sc, 51, rf);
3275d80de052Sstsp 	/* Set tx_mx1_cc. */
3276d80de052Sstsp 	run_rt3070_rf_read(sc, 51, &rf);
3277d80de052Sstsp 	rf &= ~0x1c;
3278d80de052Sstsp 	rf |= (chan <= 14) ? 0x14 : 0x10;
3279d80de052Sstsp 	run_rt3070_rf_write(sc, 51, rf);
3280d80de052Sstsp 	/* Set tx_mx1_ic. */
3281d80de052Sstsp 	run_rt3070_rf_read(sc, 51, &rf);
3282d80de052Sstsp 	rf &= ~0xe0;
3283d80de052Sstsp 	rf |= (chan <= 14) ? 0x60 : 0x40;
3284d80de052Sstsp 	run_rt3070_rf_write(sc, 51, rf);
3285d80de052Sstsp 	/* Set tx_lo1_ic. */
3286d80de052Sstsp 	run_rt3070_rf_read(sc, 49, &rf);
3287d80de052Sstsp 	rf &= ~0x1c;
3288d80de052Sstsp 	rf |= (chan <= 14) ? 0x0c : 0x08;
3289d80de052Sstsp 	run_rt3070_rf_write(sc, 49, rf);
3290d80de052Sstsp 	/* Set tx_lo1_en. */
3291d80de052Sstsp 	run_rt3070_rf_read(sc, 50, &rf);
3292d80de052Sstsp 	run_rt3070_rf_write(sc, 50, rf & ~0x20);
3293d80de052Sstsp 	/* Set drv_cc. */
3294d80de052Sstsp 	run_rt3070_rf_read(sc, 57, &rf);
3295d80de052Sstsp 	rf &= ~0xfc;
3296d80de052Sstsp 	rf |= (chan <= 14) ?  0x6c : 0x3c;
3297d80de052Sstsp 	run_rt3070_rf_write(sc, 57, rf);
3298d80de052Sstsp 	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
3299d80de052Sstsp 	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
3300d80de052Sstsp 	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
3301d80de052Sstsp 	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
3302d80de052Sstsp 	/* Enable VCO calibration. */
3303d80de052Sstsp 	run_rt3070_rf_read(sc, 3, &rf);
3304d80de052Sstsp 	rf &= ~RT3593_VCOCAL;
3305d80de052Sstsp 	rf |= (chan <= 14) ? RT3593_VCOCAL : 0xbe;
3306d80de052Sstsp 	run_rt3070_rf_write(sc, 3, rf);
3307d80de052Sstsp 
3308d80de052Sstsp 	if (chan <= 14)
3309d80de052Sstsp 		rf = 0x23;
3310d80de052Sstsp 	else if (chan <= 64)
3311d80de052Sstsp 		rf = 0x36;
3312d80de052Sstsp 	else if (chan <= 128)
3313d80de052Sstsp 		rf = 0x32;
3314d80de052Sstsp 	else
3315d80de052Sstsp 		rf = 0x30;
3316d80de052Sstsp 	run_rt3070_rf_write(sc, 39, rf);
3317d80de052Sstsp 	if (chan <= 14)
3318d80de052Sstsp 		rf = 0xbb;
3319d80de052Sstsp 	else if (chan <= 64)
3320d80de052Sstsp 		rf = 0xeb;
3321d80de052Sstsp 	else if (chan <= 128)
3322d80de052Sstsp 		rf = 0xb3;
3323d80de052Sstsp 	else
3324d80de052Sstsp 		rf = 0x9b;
3325d80de052Sstsp 	run_rt3070_rf_write(sc, 45, rf);
3326d80de052Sstsp 
3327d80de052Sstsp 	/* Set FEQ/AEQ control. */
3328d80de052Sstsp 	run_bbp_write(sc, 105, 0x34);
3329d80de052Sstsp }
3330d80de052Sstsp 
3331d80de052Sstsp void
run_rt5390_set_chan(struct run_softc * sc,u_int chan)3332d80de052Sstsp run_rt5390_set_chan(struct run_softc *sc, u_int chan)
3333d80de052Sstsp {
3334d80de052Sstsp 	int8_t txpow1, txpow2;
3335d80de052Sstsp 	uint8_t rf;
3336d80de052Sstsp 	int i;
3337d80de052Sstsp 
3338d80de052Sstsp 	/* find the settings for this channel (we know it exists) */
333936dba039Sjsg 	for (i = 0; rt2860_rf2850[i].chan != chan; i++)
334036dba039Sjsg 		;
3341d80de052Sstsp 
3342d80de052Sstsp 	/* use Tx power values from EEPROM */
3343d80de052Sstsp 	txpow1 = sc->txpow1[i];
3344d80de052Sstsp 	txpow2 = sc->txpow2[i];
3345d80de052Sstsp 
3346d80de052Sstsp 	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
3347d80de052Sstsp 	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
3348d80de052Sstsp 	run_rt3070_rf_read(sc, 11, &rf);
3349d80de052Sstsp 	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
3350d80de052Sstsp 	run_rt3070_rf_write(sc, 11, rf);
3351d80de052Sstsp 
3352d80de052Sstsp 	run_rt3070_rf_read(sc, 49, &rf);
3353d80de052Sstsp 	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
3354d80de052Sstsp 	/* The valid range of the RF R49 is 0x00 to 0x27. */
3355d80de052Sstsp 	if ((rf & 0x3f) > 0x27)
3356d80de052Sstsp 		rf = (rf & ~0x3f) | 0x27;
3357d80de052Sstsp 	run_rt3070_rf_write(sc, 49, rf);
3358d80de052Sstsp 
3359d80de052Sstsp 	if (sc->mac_ver == 0x5392) {
3360d80de052Sstsp 		run_rt3070_rf_read(sc, 50, &rf);
3361d80de052Sstsp 		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
3362d80de052Sstsp 		/* The valid range of the RF R50 is 0x00 to 0x27. */
3363d80de052Sstsp 		if ((rf & 0x3f) > 0x27)
3364d80de052Sstsp 			rf = (rf & ~0x3f) | 0x27;
3365d80de052Sstsp 		run_rt3070_rf_write(sc, 50, rf);
3366d80de052Sstsp 	}
3367d80de052Sstsp 
3368d80de052Sstsp 	run_rt3070_rf_read(sc, 1, &rf);
3369d80de052Sstsp 	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
3370d80de052Sstsp 	if (sc->mac_ver == 0x5392)
3371d80de052Sstsp 		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
3372d80de052Sstsp 	run_rt3070_rf_write(sc, 1, rf);
3373d80de052Sstsp 
3374d80de052Sstsp 	if (sc->mac_ver != 0x5392) {
3375d80de052Sstsp 		run_rt3070_rf_read(sc, 2, &rf);
3376d80de052Sstsp 		rf |= 0x80;
3377d80de052Sstsp 		run_rt3070_rf_write(sc, 2, rf);
3378d80de052Sstsp 		DELAY(10);
3379d80de052Sstsp 		rf &= 0x7f;
3380d80de052Sstsp 		run_rt3070_rf_write(sc, 2, rf);
3381d80de052Sstsp 	}
3382d80de052Sstsp 
3383d80de052Sstsp 	run_adjust_freq_offset(sc);
3384d80de052Sstsp 
3385d80de052Sstsp 	if (sc->mac_ver == 0x5392) {
3386d80de052Sstsp 		/* Fix for RT5392C. */
3387d80de052Sstsp 		if (sc->mac_rev >= 0x0223) {
3388d80de052Sstsp 			if (chan <= 4)
3389d80de052Sstsp 				rf = 0x0f;
3390d80de052Sstsp 			else if (chan >= 5 && chan <= 7)
3391d80de052Sstsp 				rf = 0x0e;
3392d80de052Sstsp 			else
3393d80de052Sstsp 				rf = 0x0d;
3394d80de052Sstsp 			run_rt3070_rf_write(sc, 23, rf);
3395d80de052Sstsp 
3396d80de052Sstsp 			if (chan <= 4)
3397d80de052Sstsp 				rf = 0x0c;
3398d80de052Sstsp 			else if (chan == 5)
3399d80de052Sstsp 				rf = 0x0b;
3400d80de052Sstsp 			else if (chan >= 6 && chan <= 7)
3401d80de052Sstsp 				rf = 0x0a;
3402d80de052Sstsp 			else if (chan >= 8 && chan <= 10)
3403d80de052Sstsp 				rf = 0x09;
3404d80de052Sstsp 			else
3405d80de052Sstsp 				rf = 0x08;
3406d80de052Sstsp 			run_rt3070_rf_write(sc, 59, rf);
3407d80de052Sstsp 		} else {
3408d80de052Sstsp 			if (chan <= 11)
3409d80de052Sstsp 				rf = 0x0f;
3410d80de052Sstsp 			else
3411d80de052Sstsp 				rf = 0x0b;
3412d80de052Sstsp 			run_rt3070_rf_write(sc, 59, rf);
3413d80de052Sstsp 		}
3414d80de052Sstsp 	} else {
3415d80de052Sstsp 		/* Fix for RT5390F. */
3416d80de052Sstsp 		if (sc->mac_rev >= 0x0502) {
3417d80de052Sstsp 			if (chan <= 11)
3418d80de052Sstsp 				rf = 0x43;
3419d80de052Sstsp 			else
3420d80de052Sstsp 				rf = 0x23;
3421d80de052Sstsp 			run_rt3070_rf_write(sc, 55, rf);
3422d80de052Sstsp 
3423d80de052Sstsp 			if (chan <= 11)
3424d80de052Sstsp 				rf = 0x0f;
3425d80de052Sstsp 			else if (chan == 12)
3426d80de052Sstsp 				rf = 0x0d;
3427d80de052Sstsp 			else
3428d80de052Sstsp 				rf = 0x0b;
3429d80de052Sstsp 			run_rt3070_rf_write(sc, 59, rf);
3430d80de052Sstsp 		} else {
3431d80de052Sstsp 			run_rt3070_rf_write(sc, 55, 0x44);
3432d80de052Sstsp 			run_rt3070_rf_write(sc, 59, 0x8f);
3433d80de052Sstsp 		}
3434d80de052Sstsp 	}
3435d80de052Sstsp 
3436d80de052Sstsp 	/* Enable VCO calibration. */
3437d80de052Sstsp 	run_rt3070_rf_read(sc, 3, &rf);
3438d80de052Sstsp 	rf |= RT3593_VCOCAL;
3439d80de052Sstsp 	run_rt3070_rf_write(sc, 3, rf);
3440d80de052Sstsp }
3441d80de052Sstsp 
3442d80de052Sstsp void
run_rt5592_set_chan(struct run_softc * sc,u_int chan)3443d80de052Sstsp run_rt5592_set_chan(struct run_softc *sc, u_int chan)
3444d80de052Sstsp {
3445d80de052Sstsp 	const struct rt5592_freqs *freqs;
3446d80de052Sstsp 	uint32_t tmp;
3447d80de052Sstsp 	uint8_t reg, rf, txpow_bound;
3448d80de052Sstsp 	int8_t txpow1, txpow2;
3449d80de052Sstsp 	int i;
3450d80de052Sstsp 
3451d80de052Sstsp 	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
3452d80de052Sstsp 	freqs = (tmp & RT5592_SEL_XTAL) ?
3453d80de052Sstsp 	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
3454d80de052Sstsp 
3455d80de052Sstsp 	/* find the settings for this channel (we know it exists) */
345636dba039Sjsg 	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++)
345736dba039Sjsg 		;
3458d80de052Sstsp 
3459d80de052Sstsp 	/* use Tx power values from EEPROM */
3460d80de052Sstsp 	txpow1 = sc->txpow1[i];
3461d80de052Sstsp 	txpow2 = sc->txpow2[i];
3462d80de052Sstsp 
3463d80de052Sstsp 	run_read(sc, RT3070_LDO_CFG0, &tmp);
3464d80de052Sstsp 	tmp &= ~0x1c000000;
3465d80de052Sstsp 	if (chan > 14)
3466d80de052Sstsp 		tmp |= 0x14000000;
3467d80de052Sstsp 	run_write(sc, RT3070_LDO_CFG0, tmp);
3468d80de052Sstsp 
3469d80de052Sstsp 	/* N setting. */
3470d80de052Sstsp 	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
3471d80de052Sstsp 	run_rt3070_rf_read(sc, 9, &rf);
3472d80de052Sstsp 	rf &= ~(1 << 4);
3473d80de052Sstsp 	rf |= ((freqs->n & 0x0100) >> 8) << 4;
3474d80de052Sstsp 	run_rt3070_rf_write(sc, 9, rf);
3475d80de052Sstsp 
3476d80de052Sstsp 	/* K setting. */
3477d80de052Sstsp 	run_rt3070_rf_read(sc, 9, &rf);
3478d80de052Sstsp 	rf &= ~0x0f;
3479d80de052Sstsp 	rf |= (freqs->k & 0x0f);
3480d80de052Sstsp 	run_rt3070_rf_write(sc, 9, rf);
3481d80de052Sstsp 
3482d80de052Sstsp 	/* Mode setting. */
3483d80de052Sstsp 	run_rt3070_rf_read(sc, 11, &rf);
3484d80de052Sstsp 	rf &= ~0x0c;
3485d80de052Sstsp 	rf |= ((freqs->m - 0x8) & 0x3) << 2;
3486d80de052Sstsp 	run_rt3070_rf_write(sc, 11, rf);
3487d80de052Sstsp 	run_rt3070_rf_read(sc, 9, &rf);
3488d80de052Sstsp 	rf &= ~(1 << 7);
3489d80de052Sstsp 	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
3490d80de052Sstsp 	run_rt3070_rf_write(sc, 9, rf);
3491d80de052Sstsp 
3492d80de052Sstsp 	/* R setting. */
3493d80de052Sstsp 	run_rt3070_rf_read(sc, 11, &rf);
3494d80de052Sstsp 	rf &= ~0x03;
3495d80de052Sstsp 	rf |= (freqs->r - 0x1);
3496d80de052Sstsp 	run_rt3070_rf_write(sc, 11, rf);
3497d80de052Sstsp 
3498d80de052Sstsp 	if (chan <= 14) {
3499d80de052Sstsp 		/* Initialize RF registers for 2GHZ. */
3500d80de052Sstsp 		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
3501d80de052Sstsp 			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
3502d80de052Sstsp 			    rt5592_2ghz_def_rf[i].val);
3503d80de052Sstsp 		}
3504d80de052Sstsp 
3505d80de052Sstsp 		rf = (chan <= 10) ? 0x07 : 0x06;
3506d80de052Sstsp 		run_rt3070_rf_write(sc, 23, rf);
3507d80de052Sstsp 		run_rt3070_rf_write(sc, 59, rf);
3508d80de052Sstsp 
3509d80de052Sstsp 		run_rt3070_rf_write(sc, 55, 0x43);
3510d80de052Sstsp 
3511d80de052Sstsp 		/*
3512d80de052Sstsp 		 * RF R49/R50 Tx power ALC code.
3513d80de052Sstsp 		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
3514d80de052Sstsp 		 */
3515d80de052Sstsp 		reg = 2;
3516d80de052Sstsp 		txpow_bound = 0x27;
3517d80de052Sstsp 	} else {
3518d80de052Sstsp 		/* Initialize RF registers for 5GHZ. */
3519d80de052Sstsp 		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
3520d80de052Sstsp 			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
3521d80de052Sstsp 			    rt5592_5ghz_def_rf[i].val);
3522d80de052Sstsp 		}
3523d80de052Sstsp 		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
3524d80de052Sstsp 			if (chan >= rt5592_chan_5ghz[i].firstchan &&
3525d80de052Sstsp 			    chan <= rt5592_chan_5ghz[i].lastchan) {
3526d80de052Sstsp 				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
3527d80de052Sstsp 				    rt5592_chan_5ghz[i].val);
3528d80de052Sstsp 			}
3529d80de052Sstsp 		}
3530d80de052Sstsp 
3531d80de052Sstsp 		/*
3532d80de052Sstsp 		 * RF R49/R50 Tx power ALC code.
3533d80de052Sstsp 		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
3534d80de052Sstsp 		 */
3535d80de052Sstsp 		reg = 3;
3536d80de052Sstsp 		txpow_bound = 0x2b;
3537d80de052Sstsp 	}
3538d80de052Sstsp 
3539d80de052Sstsp 	/* RF R49 ch0 Tx power ALC code. */
3540d80de052Sstsp 	run_rt3070_rf_read(sc, 49, &rf);
3541d80de052Sstsp 	rf &= ~0xc0;
3542d80de052Sstsp 	rf |= (reg << 6);
3543d80de052Sstsp 	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
3544d80de052Sstsp 	if ((rf & 0x3f) > txpow_bound)
3545d80de052Sstsp 		rf = (rf & ~0x3f) | txpow_bound;
3546d80de052Sstsp 	run_rt3070_rf_write(sc, 49, rf);
3547d80de052Sstsp 
3548d80de052Sstsp 	/* RF R50 ch1 Tx power ALC code. */
3549d80de052Sstsp 	run_rt3070_rf_read(sc, 50, &rf);
3550d80de052Sstsp 	rf &= ~(1 << 7 | 1 << 6);
3551d80de052Sstsp 	rf |= (reg << 6);
3552d80de052Sstsp 	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
3553d80de052Sstsp 	if ((rf & 0x3f) > txpow_bound)
3554d80de052Sstsp 		rf = (rf & ~0x3f) | txpow_bound;
3555d80de052Sstsp 	run_rt3070_rf_write(sc, 50, rf);
3556d80de052Sstsp 
3557d80de052Sstsp 	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
3558d80de052Sstsp 	run_rt3070_rf_read(sc, 1, &rf);
3559d80de052Sstsp 	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
3560d80de052Sstsp 	if (sc->ntxchains > 1)
3561d80de052Sstsp 		rf |= RT3070_TX1_PD;
3562d80de052Sstsp 	if (sc->nrxchains > 1)
3563d80de052Sstsp 		rf |= RT3070_RX1_PD;
3564d80de052Sstsp 	run_rt3070_rf_write(sc, 1, rf);
3565d80de052Sstsp 
3566d80de052Sstsp 	run_rt3070_rf_write(sc, 6, 0xe4);
3567d80de052Sstsp 
3568d80de052Sstsp 	run_rt3070_rf_write(sc, 30, 0x10);
3569d80de052Sstsp 	run_rt3070_rf_write(sc, 31, 0x80);
3570d80de052Sstsp 	run_rt3070_rf_write(sc, 32, 0x80);
3571d80de052Sstsp 
3572d80de052Sstsp 	run_adjust_freq_offset(sc);
3573d80de052Sstsp 
3574d80de052Sstsp 	/* Enable VCO calibration. */
3575d80de052Sstsp 	run_rt3070_rf_read(sc, 3, &rf);
3576d80de052Sstsp 	rf |= RT3593_VCOCAL;
3577d80de052Sstsp 	run_rt3070_rf_write(sc, 3, rf);
3578d80de052Sstsp }
3579d80de052Sstsp 
3580d80de052Sstsp void
run_set_agc(struct run_softc * sc,uint8_t agc)35815f5eab5eSdamien run_set_agc(struct run_softc *sc, uint8_t agc)
35825f5eab5eSdamien {
35835f5eab5eSdamien 	uint8_t bbp;
35845f5eab5eSdamien 
35855f5eab5eSdamien 	if (sc->mac_ver == 0x3572) {
35865f5eab5eSdamien 		run_bbp_read(sc, 27, &bbp);
35875f5eab5eSdamien 		bbp &= ~(0x3 << 5);
35885f5eab5eSdamien 		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
35895f5eab5eSdamien 		run_bbp_write(sc, 66, agc);
35905f5eab5eSdamien 		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
35915f5eab5eSdamien 		run_bbp_write(sc, 66, agc);
35925f5eab5eSdamien 	} else
35935f5eab5eSdamien 		run_bbp_write(sc, 66, agc);
35945f5eab5eSdamien }
35955f5eab5eSdamien 
35965f5eab5eSdamien void
run_set_rx_antenna(struct run_softc * sc,int aux)3597cd4f4e38Sdamien run_set_rx_antenna(struct run_softc *sc, int aux)
3598cd4f4e38Sdamien {
3599cd4f4e38Sdamien 	uint32_t tmp;
3600d80de052Sstsp 	uint8_t bbp152;
3601cd4f4e38Sdamien 
3602d80de052Sstsp 	if (aux) {
3603d80de052Sstsp 		if (sc->rf_rev == RT5390_RF_5370) {
3604d80de052Sstsp 			run_bbp_read(sc, 152, &bbp152);
3605d80de052Sstsp 			run_bbp_write(sc, 152, bbp152 & ~0x80);
3606d80de052Sstsp 		} else {
3607d80de052Sstsp 			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
3608cd4f4e38Sdamien 			run_read(sc, RT2860_GPIO_CTRL, &tmp);
3609d80de052Sstsp 			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
3610d80de052Sstsp 		}
3611d80de052Sstsp 	} else {
3612d80de052Sstsp 		if (sc->rf_rev == RT5390_RF_5370) {
3613d80de052Sstsp 			run_bbp_read(sc, 152, &bbp152);
3614d80de052Sstsp 			run_bbp_write(sc, 152, bbp152 | 0x80);
3615d80de052Sstsp 		} else {
3616d80de052Sstsp 			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
3617d80de052Sstsp 			run_read(sc, RT2860_GPIO_CTRL, &tmp);
3618d80de052Sstsp 			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
3619d80de052Sstsp 		}
3620d80de052Sstsp 	}
3621cd4f4e38Sdamien }
3622cd4f4e38Sdamien 
362330aa40ebSdamien int
run_set_chan(struct run_softc * sc,struct ieee80211_channel * c)362430aa40ebSdamien run_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
362530aa40ebSdamien {
362630aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
362730aa40ebSdamien 	u_int chan, group;
362830aa40ebSdamien 
362930aa40ebSdamien 	chan = ieee80211_chan2ieee(ic, c);
363030aa40ebSdamien 	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
363130aa40ebSdamien 		return EINVAL;
363230aa40ebSdamien 
3633d80de052Sstsp 	if (sc->mac_ver == 0x5592)
3634d80de052Sstsp 		run_rt5592_set_chan(sc, chan);
3635d80de052Sstsp 	else if (sc->mac_ver >= 0x5390)
3636d80de052Sstsp 		run_rt5390_set_chan(sc, chan);
3637d80de052Sstsp 	else if (sc->mac_ver == 0x3593)
3638d80de052Sstsp 		run_rt3593_set_chan(sc, chan);
3639d80de052Sstsp 	else if (sc->mac_ver == 0x3572)
364018327d80Sdamien 		run_rt3572_set_chan(sc, chan);
364118327d80Sdamien 	else if (sc->mac_ver >= 0x3070)
364230aa40ebSdamien 		run_rt3070_set_chan(sc, chan);
364330aa40ebSdamien 	else
364430aa40ebSdamien 		run_rt2870_set_chan(sc, chan);
364530aa40ebSdamien 
364630aa40ebSdamien 	/* determine channel group */
364730aa40ebSdamien 	if (chan <= 14)
364830aa40ebSdamien 		group = 0;
364930aa40ebSdamien 	else if (chan <= 64)
365030aa40ebSdamien 		group = 1;
365130aa40ebSdamien 	else if (chan <= 128)
365230aa40ebSdamien 		group = 2;
365330aa40ebSdamien 	else
365430aa40ebSdamien 		group = 3;
365530aa40ebSdamien 
365630aa40ebSdamien 	/* XXX necessary only when group has changed! */
365730aa40ebSdamien 	run_select_chan_group(sc, group);
365830aa40ebSdamien 
365930aa40ebSdamien 	DELAY(1000);
3660d80de052Sstsp 
3661d80de052Sstsp 	/* Perform IQ calibration. */
3662d80de052Sstsp 	if (sc->mac_ver >= 0x5392)
3663d80de052Sstsp 		run_iq_calib(sc, chan);
3664d80de052Sstsp 
366530aa40ebSdamien 	return 0;
366630aa40ebSdamien }
366730aa40ebSdamien 
366830aa40ebSdamien void
run_enable_tsf_sync(struct run_softc * sc)366930aa40ebSdamien run_enable_tsf_sync(struct run_softc *sc)
367030aa40ebSdamien {
367130aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
367230aa40ebSdamien 	uint32_t tmp;
367330aa40ebSdamien 
367430aa40ebSdamien 	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
367530aa40ebSdamien 	tmp &= ~0x1fffff;
367630aa40ebSdamien 	tmp |= ic->ic_bss->ni_intval * 16;
367730aa40ebSdamien 	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
367830aa40ebSdamien 	/* local TSF is always updated with remote TSF on beacon reception */
367930aa40ebSdamien 	tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
368030aa40ebSdamien 	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
368130aa40ebSdamien }
368230aa40ebSdamien 
368330aa40ebSdamien void
run_enable_mrr(struct run_softc * sc)368430aa40ebSdamien run_enable_mrr(struct run_softc *sc)
368530aa40ebSdamien {
368630aa40ebSdamien #define CCK(mcs)	(mcs)
368730aa40ebSdamien #define OFDM(mcs)	(1 << 3 | (mcs))
368830aa40ebSdamien 	run_write(sc, RT2860_LG_FBK_CFG0,
368930aa40ebSdamien 	    OFDM(6) << 28 |	/* 54->48 */
369030aa40ebSdamien 	    OFDM(5) << 24 |	/* 48->36 */
369130aa40ebSdamien 	    OFDM(4) << 20 |	/* 36->24 */
369230aa40ebSdamien 	    OFDM(3) << 16 |	/* 24->18 */
369330aa40ebSdamien 	    OFDM(2) << 12 |	/* 18->12 */
369430aa40ebSdamien 	    OFDM(1) <<  8 |	/* 12-> 9 */
369530aa40ebSdamien 	    OFDM(0) <<  4 |	/*  9-> 6 */
369630aa40ebSdamien 	    OFDM(0));		/*  6-> 6 */
369730aa40ebSdamien 
369830aa40ebSdamien 	run_write(sc, RT2860_LG_FBK_CFG1,
369930aa40ebSdamien 	    CCK(2) << 12 |	/* 11->5.5 */
370030aa40ebSdamien 	    CCK(1) <<  8 |	/* 5.5-> 2 */
370130aa40ebSdamien 	    CCK(0) <<  4 |	/*   2-> 1 */
370230aa40ebSdamien 	    CCK(0));		/*   1-> 1 */
370330aa40ebSdamien #undef OFDM
370430aa40ebSdamien #undef CCK
370530aa40ebSdamien }
370630aa40ebSdamien 
370730aa40ebSdamien void
run_set_txpreamble(struct run_softc * sc)370830aa40ebSdamien run_set_txpreamble(struct run_softc *sc)
370930aa40ebSdamien {
371030aa40ebSdamien 	uint32_t tmp;
371130aa40ebSdamien 
371230aa40ebSdamien 	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
371330aa40ebSdamien 	if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE)
371430aa40ebSdamien 		tmp |= RT2860_CCK_SHORT_EN;
371530aa40ebSdamien 	else
371630aa40ebSdamien 		tmp &= ~RT2860_CCK_SHORT_EN;
371730aa40ebSdamien 	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
371830aa40ebSdamien }
371930aa40ebSdamien 
372030aa40ebSdamien void
run_set_basicrates(struct run_softc * sc)372130aa40ebSdamien run_set_basicrates(struct run_softc *sc)
372230aa40ebSdamien {
372330aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
372430aa40ebSdamien 
372530aa40ebSdamien 	/* set basic rates mask */
372630aa40ebSdamien 	if (ic->ic_curmode == IEEE80211_MODE_11B)
372730aa40ebSdamien 		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
372830aa40ebSdamien 	else if (ic->ic_curmode == IEEE80211_MODE_11A)
372930aa40ebSdamien 		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
373030aa40ebSdamien 	else	/* 11g */
373130aa40ebSdamien 		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
373230aa40ebSdamien }
373330aa40ebSdamien 
373430aa40ebSdamien void
run_set_leds(struct run_softc * sc,uint16_t which)373530aa40ebSdamien run_set_leds(struct run_softc *sc, uint16_t which)
373630aa40ebSdamien {
373730aa40ebSdamien 	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
373830aa40ebSdamien 	    which | (sc->leds & 0x7f));
373930aa40ebSdamien }
374030aa40ebSdamien 
374130aa40ebSdamien void
run_set_bssid(struct run_softc * sc,const uint8_t * bssid)374230aa40ebSdamien run_set_bssid(struct run_softc *sc, const uint8_t *bssid)
374330aa40ebSdamien {
374430aa40ebSdamien 	run_write(sc, RT2860_MAC_BSSID_DW0,
374530aa40ebSdamien 	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
374630aa40ebSdamien 	run_write(sc, RT2860_MAC_BSSID_DW1,
374730aa40ebSdamien 	    bssid[4] | bssid[5] << 8);
374830aa40ebSdamien }
374930aa40ebSdamien 
375030aa40ebSdamien void
run_set_macaddr(struct run_softc * sc,const uint8_t * addr)375130aa40ebSdamien run_set_macaddr(struct run_softc *sc, const uint8_t *addr)
375230aa40ebSdamien {
375330aa40ebSdamien 	run_write(sc, RT2860_MAC_ADDR_DW0,
375430aa40ebSdamien 	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
375530aa40ebSdamien 	run_write(sc, RT2860_MAC_ADDR_DW1,
3756c4a33c5cSdamien 	    addr[4] | addr[5] << 8 | 0xff << 16);
375730aa40ebSdamien }
375830aa40ebSdamien 
375930aa40ebSdamien void
run_updateslot(struct ieee80211com * ic)376030aa40ebSdamien run_updateslot(struct ieee80211com *ic)
376130aa40ebSdamien {
376230aa40ebSdamien 	/* do it in a process context */
376330aa40ebSdamien 	run_do_async(ic->ic_softc, run_updateslot_cb, NULL, 0);
376430aa40ebSdamien }
376530aa40ebSdamien 
376630aa40ebSdamien void
run_updateslot_cb(struct run_softc * sc,void * arg)376730aa40ebSdamien run_updateslot_cb(struct run_softc *sc, void *arg)
376830aa40ebSdamien {
376930aa40ebSdamien 	uint32_t tmp;
377030aa40ebSdamien 
377130aa40ebSdamien 	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
377230aa40ebSdamien 	tmp &= ~0xff;
37738443256dSkevlo 	tmp |= (sc->sc_ic.ic_flags & IEEE80211_F_SHSLOT) ?
37748443256dSkevlo 	    IEEE80211_DUR_DS_SHSLOT : IEEE80211_DUR_DS_SLOT;
377530aa40ebSdamien 	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
377630aa40ebSdamien }
377730aa40ebSdamien 
377830aa40ebSdamien #if NBPFILTER > 0
377930aa40ebSdamien int8_t
run_rssi2dbm(struct run_softc * sc,uint8_t rssi,uint8_t rxchain)378030aa40ebSdamien run_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
378130aa40ebSdamien {
378230aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
378330aa40ebSdamien 	struct ieee80211_channel *c = ic->ic_ibss_chan;
378430aa40ebSdamien 	int delta;
378530aa40ebSdamien 
378630aa40ebSdamien 	if (IEEE80211_IS_CHAN_5GHZ(c)) {
378730aa40ebSdamien 		u_int chan = ieee80211_chan2ieee(ic, c);
378830aa40ebSdamien 		delta = sc->rssi_5ghz[rxchain];
378930aa40ebSdamien 
379030aa40ebSdamien 		/* determine channel group */
379130aa40ebSdamien 		if (chan <= 64)
379230aa40ebSdamien 			delta -= sc->lna[1];
379330aa40ebSdamien 		else if (chan <= 128)
379430aa40ebSdamien 			delta -= sc->lna[2];
379530aa40ebSdamien 		else
379630aa40ebSdamien 			delta -= sc->lna[3];
379730aa40ebSdamien 	} else
379830aa40ebSdamien 		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
379930aa40ebSdamien 
380030aa40ebSdamien 	return -12 - delta - rssi;
380130aa40ebSdamien }
380230aa40ebSdamien #endif
380330aa40ebSdamien 
3804d80de052Sstsp void
run_rt5390_bbp_init(struct run_softc * sc)3805d80de052Sstsp run_rt5390_bbp_init(struct run_softc *sc)
3806d80de052Sstsp {
3807d80de052Sstsp 	int i;
3808d80de052Sstsp 	uint8_t bbp;
3809d80de052Sstsp 
3810d80de052Sstsp 	/* Apply maximum likelihood detection for 2 stream case. */
3811d80de052Sstsp 	run_bbp_read(sc, 105, &bbp);
3812d80de052Sstsp 	if (sc->nrxchains > 1)
3813d80de052Sstsp 		run_bbp_write(sc, 105, bbp | RT5390_MLD);
3814d80de052Sstsp 
3815d80de052Sstsp 	/* Avoid data lost and CRC error. */
3816d80de052Sstsp 	run_bbp_read(sc, 4, &bbp);
3817d80de052Sstsp 	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
3818d80de052Sstsp 
3819d80de052Sstsp 	if (sc->mac_ver == 0x5592) {
3820d80de052Sstsp 		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
3821d80de052Sstsp 			run_bbp_write(sc, rt5592_def_bbp[i].reg,
3822d80de052Sstsp 			    rt5592_def_bbp[i].val);
3823d80de052Sstsp 		}
3824d80de052Sstsp 		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
3825d80de052Sstsp 			run_bbp_write(sc, 195, i + 0x80);
3826d80de052Sstsp 			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
3827d80de052Sstsp 		}
3828d80de052Sstsp 	} else {
3829d80de052Sstsp 		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
3830d80de052Sstsp 			run_bbp_write(sc, rt5390_def_bbp[i].reg,
3831d80de052Sstsp 			    rt5390_def_bbp[i].val);
3832d80de052Sstsp 		}
3833d80de052Sstsp 	}
3834d80de052Sstsp 	if (sc->mac_ver == 0x5392) {
3835d80de052Sstsp 		run_bbp_write(sc, 88, 0x90);
3836d80de052Sstsp 		run_bbp_write(sc, 95, 0x9a);
3837d80de052Sstsp 		run_bbp_write(sc, 98, 0x12);
3838d80de052Sstsp 		run_bbp_write(sc, 106, 0x12);
3839d80de052Sstsp 		run_bbp_write(sc, 134, 0xd0);
3840d80de052Sstsp 		run_bbp_write(sc, 135, 0xf6);
3841d80de052Sstsp 		run_bbp_write(sc, 148, 0x84);
3842d80de052Sstsp 	}
3843d80de052Sstsp 
3844d80de052Sstsp 	run_bbp_read(sc, 152, &bbp);
3845d80de052Sstsp 	run_bbp_write(sc, 152, bbp | 0x80);
3846d80de052Sstsp 
3847d80de052Sstsp 	/* Fix BBP254 for RT5592C. */
3848d80de052Sstsp 	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
3849d80de052Sstsp 		run_bbp_read(sc, 254, &bbp);
3850d80de052Sstsp 		run_bbp_write(sc, 254, bbp | 0x80);
3851d80de052Sstsp 	}
3852d80de052Sstsp 
3853d80de052Sstsp 	/* Disable hardware antenna diversity. */
3854d80de052Sstsp 	if (sc->mac_ver == 0x5390)
3855d80de052Sstsp 		run_bbp_write(sc, 154, 0);
3856d80de052Sstsp 
3857d80de052Sstsp 	/* Initialize Rx CCK/OFDM frequency offset report. */
3858d80de052Sstsp 	run_bbp_write(sc, 142, 1);
3859d80de052Sstsp 	run_bbp_write(sc, 143, 57);
3860d80de052Sstsp }
3861d80de052Sstsp 
386230aa40ebSdamien int
run_bbp_init(struct run_softc * sc)386330aa40ebSdamien run_bbp_init(struct run_softc *sc)
386430aa40ebSdamien {
386530aa40ebSdamien 	int i, error, ntries;
386630aa40ebSdamien 	uint8_t bbp0;
386730aa40ebSdamien 
386830aa40ebSdamien 	/* wait for BBP to wake up */
386930aa40ebSdamien 	for (ntries = 0; ntries < 20; ntries++) {
387030aa40ebSdamien 		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
387130aa40ebSdamien 			return error;
387230aa40ebSdamien 		if (bbp0 != 0 && bbp0 != 0xff)
387330aa40ebSdamien 			break;
387430aa40ebSdamien 	}
387530aa40ebSdamien 	if (ntries == 20)
387630aa40ebSdamien 		return ETIMEDOUT;
387730aa40ebSdamien 
387830aa40ebSdamien 	/* initialize BBP registers to default values */
3879d80de052Sstsp 	if (sc->mac_ver >= 0x5390)
3880d80de052Sstsp 		run_rt5390_bbp_init(sc);
3881d80de052Sstsp 	else {
388230aa40ebSdamien 		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
388330aa40ebSdamien 			run_bbp_write(sc, rt2860_def_bbp[i].reg,
388430aa40ebSdamien 			    rt2860_def_bbp[i].val);
388530aa40ebSdamien 		}
3886d80de052Sstsp 	}
3887d80de052Sstsp 
3888d80de052Sstsp 	if (sc->mac_ver == 0x3593) {
3889d80de052Sstsp 		run_bbp_write(sc, 79, 0x13);
3890d80de052Sstsp 		run_bbp_write(sc, 80, 0x05);
3891d80de052Sstsp 		run_bbp_write(sc, 81, 0x33);
3892d80de052Sstsp 		run_bbp_write(sc, 86, 0x46);
3893d80de052Sstsp 		run_bbp_write(sc, 137, 0x0f);
3894d80de052Sstsp 	}
389530aa40ebSdamien 
389630aa40ebSdamien 	/* fix BBP84 for RT2860E */
38976755f0faSdamien 	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
389830aa40ebSdamien 		run_bbp_write(sc, 84, 0x19);
389930aa40ebSdamien 
3900d80de052Sstsp 	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
3901d80de052Sstsp 	    sc->mac_ver != 0x5592)) {
3902cd4f4e38Sdamien 		run_bbp_write(sc, 79, 0x13);
3903cd4f4e38Sdamien 		run_bbp_write(sc, 80, 0x05);
3904cd4f4e38Sdamien 		run_bbp_write(sc, 81, 0x33);
39056755f0faSdamien 	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
390630aa40ebSdamien 		run_bbp_write(sc, 69, 0x16);
390730aa40ebSdamien 		run_bbp_write(sc, 73, 0x12);
390830aa40ebSdamien 	}
390930aa40ebSdamien 	return 0;
391030aa40ebSdamien }
391130aa40ebSdamien 
391230aa40ebSdamien int
run_rt3070_rf_init(struct run_softc * sc)391330aa40ebSdamien run_rt3070_rf_init(struct run_softc *sc)
391430aa40ebSdamien {
391530aa40ebSdamien 	uint32_t tmp;
3916d80de052Sstsp 	uint8_t bbp4, mingain, rf, target;
391730aa40ebSdamien 	int i;
391830aa40ebSdamien 
3919773b33c5Sdamien 	run_rt3070_rf_read(sc, 30, &rf);
392030aa40ebSdamien 	/* toggle RF R30 bit 7 */
3921773b33c5Sdamien 	run_rt3070_rf_write(sc, 30, rf | 0x80);
392230aa40ebSdamien 	DELAY(1000);
3923773b33c5Sdamien 	run_rt3070_rf_write(sc, 30, rf & ~0x80);
392430aa40ebSdamien 
392530aa40ebSdamien 	/* initialize RF registers to default value */
3926e126fc7bSdamien 	if (sc->mac_ver == 0x3572) {
3927e126fc7bSdamien 		for (i = 0; i < nitems(rt3572_def_rf); i++) {
3928e126fc7bSdamien 			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
3929e126fc7bSdamien 			    rt3572_def_rf[i].val);
3930e126fc7bSdamien 		}
393183a9125aSdamien 	} else {
393283a9125aSdamien 		for (i = 0; i < nitems(rt3070_def_rf); i++) {
393383a9125aSdamien 			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
393483a9125aSdamien 			    rt3070_def_rf[i].val);
393583a9125aSdamien 		}
3936e126fc7bSdamien 	}
3937d80de052Sstsp 	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
3938d80de052Sstsp 		/*
3939d80de052Sstsp 		 * Change voltage from 1.2V to 1.35V for RT3070.
3940d80de052Sstsp 		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
3941d80de052Sstsp 		 * in RT3070(F).
3942d80de052Sstsp 		 */
394330aa40ebSdamien 		run_read(sc, RT3070_LDO_CFG0, &tmp);
3944d80de052Sstsp 		tmp = (tmp & ~0x0f000000) | 0x0d000000;
394530aa40ebSdamien 		run_write(sc, RT3070_LDO_CFG0, tmp);
394630aa40ebSdamien 
39476755f0faSdamien 	} else if (sc->mac_ver == 0x3071) {
3948773b33c5Sdamien 		run_rt3070_rf_read(sc, 6, &rf);
3949773b33c5Sdamien 		run_rt3070_rf_write(sc, 6, rf | 0x40);
395030aa40ebSdamien 		run_rt3070_rf_write(sc, 31, 0x14);
395130aa40ebSdamien 
395230aa40ebSdamien 		run_read(sc, RT3070_LDO_CFG0, &tmp);
395330aa40ebSdamien 		tmp &= ~0x1f000000;
39546755f0faSdamien 		if (sc->mac_rev < 0x0211)
3955e126fc7bSdamien 			tmp |= 0x0d000000;	/* 1.35V */
395630aa40ebSdamien 		else
3957e126fc7bSdamien 			tmp |= 0x01000000;	/* 1.2V */
395830aa40ebSdamien 		run_write(sc, RT3070_LDO_CFG0, tmp);
395930aa40ebSdamien 
396030aa40ebSdamien 		/* patch LNA_PE_G1 */
396130aa40ebSdamien 		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
396230aa40ebSdamien 		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
3963e126fc7bSdamien 
3964d80de052Sstsp 	} else if (sc->mac_ver == 0x3572) {
3965d80de052Sstsp 		run_rt3070_rf_read(sc, 6, &rf);
3966d80de052Sstsp 		run_rt3070_rf_write(sc, 6, rf | 0x40);
3967e126fc7bSdamien 		/* increase voltage from 1.2V to 1.35V */
3968e126fc7bSdamien 		run_read(sc, RT3070_LDO_CFG0, &tmp);
3969d80de052Sstsp 		tmp = (tmp & ~0x1f000000) | 0x0d000000;
3970e126fc7bSdamien 		run_write(sc, RT3070_LDO_CFG0, tmp);
3971d80de052Sstsp 
3972d80de052Sstsp 		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
3973d80de052Sstsp 			DELAY(1);	/* wait for 1msec */
3974d80de052Sstsp 			/* decrease voltage back to 1.2V */
3975d80de052Sstsp 			tmp = (tmp & ~0x1f000000) | 0x01000000;
3976d80de052Sstsp 			run_write(sc, RT3070_LDO_CFG0, tmp);
3977d80de052Sstsp 		}
397830aa40ebSdamien 	}
397930aa40ebSdamien 
3980cd4f4e38Sdamien 	/* select 20MHz bandwidth */
3981cd4f4e38Sdamien 	run_rt3070_rf_read(sc, 31, &rf);
3982cd4f4e38Sdamien 	run_rt3070_rf_write(sc, 31, rf & ~0x20);
3983cd4f4e38Sdamien 
398430aa40ebSdamien 	/* calibrate filter for 20MHz bandwidth */
398530aa40ebSdamien 	sc->rf24_20mhz = 0x1f;	/* default value */
398636a1ddbaSdamien 	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
398736a1ddbaSdamien 	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
398830aa40ebSdamien 
398930aa40ebSdamien 	/* select 40MHz bandwidth */
399030aa40ebSdamien 	run_bbp_read(sc, 4, &bbp4);
3991d80de052Sstsp 	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
3992e56800d9Sdamien 	run_rt3070_rf_read(sc, 31, &rf);
3993e56800d9Sdamien 	run_rt3070_rf_write(sc, 31, rf | 0x20);
399430aa40ebSdamien 
399530aa40ebSdamien 	/* calibrate filter for 40MHz bandwidth */
399630aa40ebSdamien 	sc->rf24_40mhz = 0x2f;	/* default value */
399736a1ddbaSdamien 	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
399836a1ddbaSdamien 	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
399930aa40ebSdamien 
400030aa40ebSdamien 	/* go back to 20MHz bandwidth */
400130aa40ebSdamien 	run_bbp_read(sc, 4, &bbp4);
400230aa40ebSdamien 	run_bbp_write(sc, 4, bbp4 & ~0x18);
400330aa40ebSdamien 
4004e56800d9Sdamien 	if (sc->mac_ver == 0x3572) {
4005e56800d9Sdamien 		/* save default BBP registers 25 and 26 values */
4006e56800d9Sdamien 		run_bbp_read(sc, 25, &sc->bbp25);
4007e56800d9Sdamien 		run_bbp_read(sc, 26, &sc->bbp26);
4008e56800d9Sdamien 
4009d80de052Sstsp 	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
401030aa40ebSdamien 		run_rt3070_rf_write(sc, 27, 0x03);
401130aa40ebSdamien 
401230aa40ebSdamien 	run_read(sc, RT3070_OPT_14, &tmp);
401330aa40ebSdamien 	run_write(sc, RT3070_OPT_14, tmp | 1);
401430aa40ebSdamien 
4015e56800d9Sdamien 	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
4016e56800d9Sdamien 		run_rt3070_rf_read(sc, 17, &rf);
4017e56800d9Sdamien 		rf &= ~RT3070_TX_LO1;
4018e56800d9Sdamien 		if ((sc->mac_ver == 0x3070 ||
4019e56800d9Sdamien 		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
4020e56800d9Sdamien 		    !sc->ext_2ghz_lna)
4021e56800d9Sdamien 			rf |= 0x20;	/* fix for long range Rx issue */
4022d80de052Sstsp 		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
4023d80de052Sstsp 		if (sc->txmixgain_2ghz >= mingain)
4024e56800d9Sdamien 			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
4025e56800d9Sdamien 		run_rt3070_rf_write(sc, 17, rf);
4026dbc2be93Sdamien 	}
40276755f0faSdamien 	if (sc->mac_ver == 0x3071) {
4028773b33c5Sdamien 		run_rt3070_rf_read(sc, 1, &rf);
4029773b33c5Sdamien 		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
4030773b33c5Sdamien 		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
4031773b33c5Sdamien 		run_rt3070_rf_write(sc, 1, rf);
4032773b33c5Sdamien 
4033773b33c5Sdamien 		run_rt3070_rf_read(sc, 15, &rf);
4034773b33c5Sdamien 		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
4035773b33c5Sdamien 
4036773b33c5Sdamien 		run_rt3070_rf_read(sc, 20, &rf);
4037773b33c5Sdamien 		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
4038773b33c5Sdamien 
4039773b33c5Sdamien 		run_rt3070_rf_read(sc, 21, &rf);
4040773b33c5Sdamien 		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
4041e56800d9Sdamien 	}
4042e56800d9Sdamien 	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
40430230d62dSdamien 		/* fix Tx to Rx IQ glitch by raising RF voltage */
4044773b33c5Sdamien 		run_rt3070_rf_read(sc, 27, &rf);
4045773b33c5Sdamien 		rf &= ~0x77;
40466755f0faSdamien 		if (sc->mac_rev < 0x0211)
4047773b33c5Sdamien 			rf |= 0x03;
4048773b33c5Sdamien 		run_rt3070_rf_write(sc, 27, rf);
4049773b33c5Sdamien 	}
405030aa40ebSdamien 	return 0;
405130aa40ebSdamien }
405230aa40ebSdamien 
4053d80de052Sstsp void
run_rt3593_rf_init(struct run_softc * sc)4054d80de052Sstsp run_rt3593_rf_init(struct run_softc *sc)
4055d80de052Sstsp {
4056d80de052Sstsp 	uint32_t tmp;
4057d80de052Sstsp 	uint8_t rf;
4058d80de052Sstsp 	int i;
4059d80de052Sstsp 
4060d80de052Sstsp 	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
4061d80de052Sstsp 	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
4062d80de052Sstsp 	tmp &= ~(1 << 4 | 1 << 7);
4063d80de052Sstsp 	run_write(sc, RT3070_GPIO_SWITCH, tmp);
4064d80de052Sstsp 
4065d80de052Sstsp 	/* Initialize RF registers to default value. */
4066d80de052Sstsp 	for (i = 0; i < nitems(rt3593_def_rf); i++) {
4067d80de052Sstsp 		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
4068d80de052Sstsp 		    rt3593_def_rf[i].val);
4069d80de052Sstsp 	}
4070d80de052Sstsp 
4071d80de052Sstsp 	/* Toggle RF R2 to initiate calibration. */
4072d80de052Sstsp 	run_rt3070_rf_write(sc, 2, RT3593_RESCAL);
4073d80de052Sstsp 
4074d80de052Sstsp 	/* Initialize RF frequency offset. */
4075d80de052Sstsp 	run_adjust_freq_offset(sc);
4076d80de052Sstsp 
4077d80de052Sstsp 	run_rt3070_rf_read(sc, 18, &rf);
4078d80de052Sstsp 	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
4079d80de052Sstsp 
4080d80de052Sstsp 	/*
4081d80de052Sstsp 	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
4082d80de052Sstsp 	 * decrease voltage back to 1.2V.
4083d80de052Sstsp 	 */
4084d80de052Sstsp 	run_read(sc, RT3070_LDO_CFG0, &tmp);
4085d80de052Sstsp 	tmp = (tmp & ~0x1f000000) | 0x0d000000;
4086d80de052Sstsp 	run_write(sc, RT3070_LDO_CFG0, tmp);
4087d80de052Sstsp 	DELAY(1);
4088d80de052Sstsp 	tmp = (tmp & ~0x1f000000) | 0x01000000;
4089d80de052Sstsp 	run_write(sc, RT3070_LDO_CFG0, tmp);
4090d80de052Sstsp 
4091d80de052Sstsp 	sc->rf24_20mhz = 0x1f;
4092d80de052Sstsp 	sc->rf24_40mhz = 0x2f;
4093d80de052Sstsp 
4094d80de052Sstsp 	/* Save default BBP registers 25 and 26 values. */
4095d80de052Sstsp 	run_bbp_read(sc, 25, &sc->bbp25);
4096d80de052Sstsp 	run_bbp_read(sc, 26, &sc->bbp26);
4097d80de052Sstsp 
4098d80de052Sstsp 	run_read(sc, RT3070_OPT_14, &tmp);
4099d80de052Sstsp 	run_write(sc, RT3070_OPT_14, tmp | 1);
4100d80de052Sstsp }
4101d80de052Sstsp 
4102d80de052Sstsp void
run_rt5390_rf_init(struct run_softc * sc)4103d80de052Sstsp run_rt5390_rf_init(struct run_softc *sc)
4104d80de052Sstsp {
4105d80de052Sstsp 	uint32_t tmp;
4106d80de052Sstsp 	uint8_t rf;
4107d80de052Sstsp 	int i;
4108d80de052Sstsp 
4109d80de052Sstsp 	/* Toggle RF R2 to initiate calibration. */
4110d80de052Sstsp 	if (sc->mac_ver == 0x5390) {
4111d80de052Sstsp 		run_rt3070_rf_read(sc, 2, &rf);
4112d80de052Sstsp 		run_rt3070_rf_write(sc, 2, rf | RT3593_RESCAL);
4113d80de052Sstsp 		DELAY(10);
4114d80de052Sstsp 		run_rt3070_rf_write(sc, 2, rf & ~RT3593_RESCAL);
4115d80de052Sstsp 	} else {
4116d80de052Sstsp 		run_rt3070_rf_write(sc, 2, RT3593_RESCAL);
4117d80de052Sstsp 		DELAY(10);
4118d80de052Sstsp 	}
4119d80de052Sstsp 
4120d80de052Sstsp 	/* Initialize RF registers to default value. */
4121d80de052Sstsp 	if (sc->mac_ver == 0x5592) {
4122d80de052Sstsp 		for (i = 0; i < nitems(rt5592_def_rf); i++) {
4123d80de052Sstsp 			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
4124d80de052Sstsp 			    rt5592_def_rf[i].val);
4125d80de052Sstsp 		}
4126d80de052Sstsp 		/* Initialize RF frequency offset. */
4127d80de052Sstsp 		run_adjust_freq_offset(sc);
4128d80de052Sstsp 	} else if (sc->mac_ver == 0x5392) {
4129d80de052Sstsp 		for (i = 0; i < nitems(rt5392_def_rf); i++) {
4130d80de052Sstsp 			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
4131d80de052Sstsp 			    rt5392_def_rf[i].val);
4132d80de052Sstsp 		}
4133d80de052Sstsp 		if (sc->mac_rev >= 0x0223) {
4134d80de052Sstsp 			run_rt3070_rf_write(sc, 23, 0x0f);
4135d80de052Sstsp 			run_rt3070_rf_write(sc, 24, 0x3e);
4136d80de052Sstsp 			run_rt3070_rf_write(sc, 51, 0x32);
4137d80de052Sstsp 			run_rt3070_rf_write(sc, 53, 0x22);
4138d80de052Sstsp 			run_rt3070_rf_write(sc, 56, 0xc1);
4139d80de052Sstsp 			run_rt3070_rf_write(sc, 59, 0x0f);
4140d80de052Sstsp 		}
4141d80de052Sstsp 	} else {
4142d80de052Sstsp 		for (i = 0; i < nitems(rt5390_def_rf); i++) {
4143d80de052Sstsp 			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
4144d80de052Sstsp 			    rt5390_def_rf[i].val);
4145d80de052Sstsp 		}
4146d80de052Sstsp 		if (sc->mac_rev >= 0x0502) {
4147d80de052Sstsp 			run_rt3070_rf_write(sc, 6, 0xe0);
4148d80de052Sstsp 			run_rt3070_rf_write(sc, 25, 0x80);
4149d80de052Sstsp 			run_rt3070_rf_write(sc, 46, 0x73);
4150d80de052Sstsp 			run_rt3070_rf_write(sc, 53, 0x00);
4151d80de052Sstsp 			run_rt3070_rf_write(sc, 56, 0x42);
4152d80de052Sstsp 			run_rt3070_rf_write(sc, 61, 0xd1);
4153d80de052Sstsp 		}
4154d80de052Sstsp 	}
4155d80de052Sstsp 
4156d80de052Sstsp 	sc->rf24_20mhz = 0x1f;	/* default value */
4157d80de052Sstsp 	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
4158d80de052Sstsp 
4159d80de052Sstsp 	if (sc->mac_rev < 0x0211)
4160d80de052Sstsp 		run_rt3070_rf_write(sc, 27, 0x3);
4161d80de052Sstsp 
4162d80de052Sstsp 	run_read(sc, RT3070_OPT_14, &tmp);
4163d80de052Sstsp 	run_write(sc, RT3070_OPT_14, tmp | 1);
4164d80de052Sstsp }
4165d80de052Sstsp 
416630aa40ebSdamien int
run_rt3070_filter_calib(struct run_softc * sc,uint8_t init,uint8_t target,uint8_t * val)416730aa40ebSdamien run_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
416830aa40ebSdamien     uint8_t *val)
416930aa40ebSdamien {
417030aa40ebSdamien 	uint8_t rf22, rf24;
417130aa40ebSdamien 	uint8_t bbp55_pb, bbp55_sb, delta;
417230aa40ebSdamien 	int ntries;
417330aa40ebSdamien 
417430aa40ebSdamien 	/* program filter */
4175e56800d9Sdamien 	run_rt3070_rf_read(sc, 24, &rf24);
4176e56800d9Sdamien 	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
417730aa40ebSdamien 	run_rt3070_rf_write(sc, 24, rf24);
417830aa40ebSdamien 
417930aa40ebSdamien 	/* enable baseband loopback mode */
418030aa40ebSdamien 	run_rt3070_rf_read(sc, 22, &rf22);
4181773b33c5Sdamien 	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
418230aa40ebSdamien 
418330aa40ebSdamien 	/* set power and frequency of passband test tone */
418430aa40ebSdamien 	run_bbp_write(sc, 24, 0x00);
418530aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
418630aa40ebSdamien 		/* transmit test tone */
418730aa40ebSdamien 		run_bbp_write(sc, 25, 0x90);
418830aa40ebSdamien 		DELAY(1000);
418930aa40ebSdamien 		/* read received power */
419030aa40ebSdamien 		run_bbp_read(sc, 55, &bbp55_pb);
419130aa40ebSdamien 		if (bbp55_pb != 0)
419230aa40ebSdamien 			break;
419330aa40ebSdamien 	}
419430aa40ebSdamien 	if (ntries == 100)
419530aa40ebSdamien 		return ETIMEDOUT;
419630aa40ebSdamien 
419730aa40ebSdamien 	/* set power and frequency of stopband test tone */
419830aa40ebSdamien 	run_bbp_write(sc, 24, 0x06);
419930aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
420030aa40ebSdamien 		/* transmit test tone */
420130aa40ebSdamien 		run_bbp_write(sc, 25, 0x90);
420230aa40ebSdamien 		DELAY(1000);
420330aa40ebSdamien 		/* read received power */
420430aa40ebSdamien 		run_bbp_read(sc, 55, &bbp55_sb);
420530aa40ebSdamien 
420630aa40ebSdamien 		delta = bbp55_pb - bbp55_sb;
4207cd4f4e38Sdamien 		if (delta > target)
420830aa40ebSdamien 			break;
420930aa40ebSdamien 
421030aa40ebSdamien 		/* reprogram filter */
4211cd4f4e38Sdamien 		rf24++;
421230aa40ebSdamien 		run_rt3070_rf_write(sc, 24, rf24);
421330aa40ebSdamien 	}
421430aa40ebSdamien 	if (ntries < 100) {
4215cd4f4e38Sdamien 		if (rf24 != init)
4216cd4f4e38Sdamien 			rf24--;	/* backtrack */
421730aa40ebSdamien 		*val = rf24;
421830aa40ebSdamien 		run_rt3070_rf_write(sc, 24, rf24);
421930aa40ebSdamien 	}
422030aa40ebSdamien 
422130aa40ebSdamien 	/* restore initial state */
422230aa40ebSdamien 	run_bbp_write(sc, 24, 0x00);
422330aa40ebSdamien 
422430aa40ebSdamien 	/* disable baseband loopback mode */
422530aa40ebSdamien 	run_rt3070_rf_read(sc, 22, &rf22);
4226773b33c5Sdamien 	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
422730aa40ebSdamien 
422830aa40ebSdamien 	return 0;
422930aa40ebSdamien }
423030aa40ebSdamien 
4231e56800d9Sdamien void
run_rt3070_rf_setup(struct run_softc * sc)4232e56800d9Sdamien run_rt3070_rf_setup(struct run_softc *sc)
4233e56800d9Sdamien {
4234e56800d9Sdamien 	uint8_t bbp, rf;
4235e56800d9Sdamien 	int i;
4236e56800d9Sdamien 
4237e56800d9Sdamien 	if (sc->mac_ver == 0x3572) {
4238e56800d9Sdamien 		/* enable DC filter */
4239e56800d9Sdamien 		if (sc->mac_rev >= 0x0201)
4240e56800d9Sdamien 			run_bbp_write(sc, 103, 0xc0);
4241e56800d9Sdamien 
4242e56800d9Sdamien 		run_bbp_read(sc, 138, &bbp);
4243e56800d9Sdamien 		if (sc->ntxchains == 1)
4244e56800d9Sdamien 			bbp |= 0x20;	/* turn off DAC1 */
4245e56800d9Sdamien 		if (sc->nrxchains == 1)
4246e56800d9Sdamien 			bbp &= ~0x02;	/* turn off ADC1 */
4247e56800d9Sdamien 		run_bbp_write(sc, 138, bbp);
4248e56800d9Sdamien 
4249e56800d9Sdamien 		if (sc->mac_rev >= 0x0211) {
4250e56800d9Sdamien 			/* improve power consumption */
4251e56800d9Sdamien 			run_bbp_read(sc, 31, &bbp);
4252e56800d9Sdamien 			run_bbp_write(sc, 31, bbp & ~0x03);
4253e56800d9Sdamien 		}
4254e56800d9Sdamien 
4255e56800d9Sdamien 		run_rt3070_rf_read(sc, 16, &rf);
4256e56800d9Sdamien 		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
4257e56800d9Sdamien 		run_rt3070_rf_write(sc, 16, rf);
4258e56800d9Sdamien 
4259e56800d9Sdamien 	} else if (sc->mac_ver == 0x3071) {
4260e56800d9Sdamien 		/* enable DC filter */
4261d80de052Sstsp 		if (sc->mac_rev >= 0x0211) {
4262e56800d9Sdamien 			run_bbp_write(sc, 103, 0xc0);
4263e56800d9Sdamien 
4264d80de052Sstsp 			/* improve power consumption */
4265d80de052Sstsp 			run_bbp_read(sc, 31, &bbp);
4266d80de052Sstsp 			run_bbp_write(sc, 31, bbp & ~0x03);
4267d80de052Sstsp 		}
4268d80de052Sstsp 
4269e56800d9Sdamien 		run_bbp_read(sc, 138, &bbp);
4270e56800d9Sdamien 		if (sc->ntxchains == 1)
4271e56800d9Sdamien 			bbp |= 0x20;	/* turn off DAC1 */
4272e56800d9Sdamien 		if (sc->nrxchains == 1)
4273e56800d9Sdamien 			bbp &= ~0x02;	/* turn off ADC1 */
4274e56800d9Sdamien 		run_bbp_write(sc, 138, bbp);
4275e56800d9Sdamien 
4276e56800d9Sdamien 		run_write(sc, RT2860_TX_SW_CFG1, 0);
4277e56800d9Sdamien 		if (sc->mac_rev < 0x0211) {
4278e56800d9Sdamien 			run_write(sc, RT2860_TX_SW_CFG2,
4279e56800d9Sdamien 			    sc->patch_dac ? 0x2c : 0x0f);
4280e56800d9Sdamien 		} else
4281e56800d9Sdamien 			run_write(sc, RT2860_TX_SW_CFG2, 0);
4282e56800d9Sdamien 
4283e56800d9Sdamien 	} else if (sc->mac_ver == 0x3070) {
4284e56800d9Sdamien 		if (sc->mac_rev >= 0x0201) {
4285e56800d9Sdamien 			/* enable DC filter */
4286e56800d9Sdamien 			run_bbp_write(sc, 103, 0xc0);
4287e56800d9Sdamien 
4288e56800d9Sdamien 			/* improve power consumption */
4289e56800d9Sdamien 			run_bbp_read(sc, 31, &bbp);
4290e56800d9Sdamien 			run_bbp_write(sc, 31, bbp & ~0x03);
4291e56800d9Sdamien 		}
4292e56800d9Sdamien 
4293d80de052Sstsp 		if (sc->mac_rev < 0x0201) {
4294e56800d9Sdamien 			run_write(sc, RT2860_TX_SW_CFG1, 0);
4295e56800d9Sdamien 			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
4296e56800d9Sdamien 		} else
4297e56800d9Sdamien 			run_write(sc, RT2860_TX_SW_CFG2, 0);
4298e56800d9Sdamien 	}
4299e56800d9Sdamien 
4300e56800d9Sdamien 	/* initialize RF registers from ROM for >=RT3071*/
4301e56800d9Sdamien 	if (sc->mac_ver >= 0x3071) {
4302e56800d9Sdamien 		for (i = 0; i < 10; i++) {
4303bde17d39Sdamien 			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
4304e56800d9Sdamien 				continue;
4305e56800d9Sdamien 			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
4306e56800d9Sdamien 		}
4307e56800d9Sdamien 	}
4308e56800d9Sdamien }
4309e56800d9Sdamien 
4310d80de052Sstsp void
run_rt3593_rf_setup(struct run_softc * sc)4311d80de052Sstsp run_rt3593_rf_setup(struct run_softc *sc)
4312d80de052Sstsp {
4313d80de052Sstsp 	uint8_t bbp, rf;
4314d80de052Sstsp 
4315d80de052Sstsp 	if (sc->mac_rev >= 0x0211) {
4316d80de052Sstsp 		/* Enable DC filter. */
4317d80de052Sstsp 		run_bbp_write(sc, 103, 0xc0);
4318d80de052Sstsp 	}
4319d80de052Sstsp 	run_write(sc, RT2860_TX_SW_CFG1, 0);
4320d80de052Sstsp 	if (sc->mac_rev < 0x0211) {
4321d80de052Sstsp 		run_write(sc, RT2860_TX_SW_CFG2,
4322d80de052Sstsp 		    sc->patch_dac ? 0x2c : 0x0f);
4323d80de052Sstsp 	} else
4324d80de052Sstsp 		run_write(sc, RT2860_TX_SW_CFG2, 0);
4325d80de052Sstsp 
4326d80de052Sstsp 	run_rt3070_rf_read(sc, 50, &rf);
4327d80de052Sstsp 	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
4328d80de052Sstsp 
4329d80de052Sstsp 	run_rt3070_rf_read(sc, 51, &rf);
4330d80de052Sstsp 	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
4331d80de052Sstsp 	    ((sc->txmixgain_2ghz & 0x07) << 2);
4332d80de052Sstsp 	run_rt3070_rf_write(sc, 51, rf);
4333d80de052Sstsp 
4334d80de052Sstsp 	run_rt3070_rf_read(sc, 38, &rf);
4335d80de052Sstsp 	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
4336d80de052Sstsp 
4337d80de052Sstsp 	run_rt3070_rf_read(sc, 39, &rf);
4338d80de052Sstsp 	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
4339d80de052Sstsp 
4340d80de052Sstsp 	run_rt3070_rf_read(sc, 1, &rf);
4341d80de052Sstsp 	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
4342d80de052Sstsp 
4343d80de052Sstsp 	run_rt3070_rf_read(sc, 30, &rf);
4344d80de052Sstsp 	rf = (rf & ~0x18) | 0x10;
4345d80de052Sstsp 	run_rt3070_rf_write(sc, 30, rf);
4346d80de052Sstsp 
4347d80de052Sstsp 	/* Apply maximum likelihood detection for 2 stream case. */
4348d80de052Sstsp 	run_bbp_read(sc, 105, &bbp);
4349d80de052Sstsp 	if (sc->nrxchains > 1)
4350d80de052Sstsp 		run_bbp_write(sc, 105, bbp | RT5390_MLD);
4351d80de052Sstsp 
4352d80de052Sstsp 	/* Avoid data lost and CRC error. */
4353d80de052Sstsp 	run_bbp_read(sc, 4, &bbp);
4354d80de052Sstsp 	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
4355d80de052Sstsp 
4356d80de052Sstsp 	run_bbp_write(sc, 92, 0x02);
4357d80de052Sstsp 	run_bbp_write(sc, 82, 0x82);
4358d80de052Sstsp 	run_bbp_write(sc, 106, 0x05);
4359d80de052Sstsp 	run_bbp_write(sc, 104, 0x92);
4360d80de052Sstsp 	run_bbp_write(sc, 88, 0x90);
4361d80de052Sstsp 	run_bbp_write(sc, 148, 0xc8);
4362d80de052Sstsp 	run_bbp_write(sc, 47, 0x48);
4363d80de052Sstsp 	run_bbp_write(sc, 120, 0x50);
4364d80de052Sstsp 
4365d80de052Sstsp 	run_bbp_write(sc, 163, 0x9d);
4366d80de052Sstsp 
4367d80de052Sstsp 	/* SNR mapping. */
4368d80de052Sstsp 	run_bbp_write(sc, 142, 0x06);
4369d80de052Sstsp 	run_bbp_write(sc, 143, 0xa0);
4370d80de052Sstsp 	run_bbp_write(sc, 142, 0x07);
4371d80de052Sstsp 	run_bbp_write(sc, 143, 0xa1);
4372d80de052Sstsp 	run_bbp_write(sc, 142, 0x08);
4373d80de052Sstsp 	run_bbp_write(sc, 143, 0xa2);
4374d80de052Sstsp 
4375d80de052Sstsp 	run_bbp_write(sc, 31, 0x08);
4376d80de052Sstsp 	run_bbp_write(sc, 68, 0x0b);
4377d80de052Sstsp 	run_bbp_write(sc, 105, 0x04);
4378d80de052Sstsp }
4379d80de052Sstsp 
4380d80de052Sstsp void
run_rt5390_rf_setup(struct run_softc * sc)4381d80de052Sstsp run_rt5390_rf_setup(struct run_softc *sc)
4382d80de052Sstsp {
4383d80de052Sstsp 	uint8_t bbp, rf;
4384d80de052Sstsp 
4385d80de052Sstsp 	if (sc->mac_rev >= 0x0211) {
4386d80de052Sstsp 		/* Enable DC filter. */
4387d80de052Sstsp 		run_bbp_write(sc, 103, 0xc0);
4388d80de052Sstsp 
4389d80de052Sstsp 		if (sc->mac_ver != 0x5592) {
4390d80de052Sstsp 			/* Improve power consumption. */
4391d80de052Sstsp 			run_bbp_read(sc, 31, &bbp);
4392d80de052Sstsp 			run_bbp_write(sc, 31, bbp & ~0x03);
4393d80de052Sstsp 		}
4394d80de052Sstsp 	}
4395d80de052Sstsp 
4396d80de052Sstsp 	run_bbp_read(sc, 138, &bbp);
4397d80de052Sstsp 	if (sc->ntxchains == 1)
4398d80de052Sstsp 		bbp |= 0x20;	/* turn off DAC1 */
4399d80de052Sstsp 	if (sc->nrxchains == 1)
4400d80de052Sstsp 		bbp &= ~0x02;	/* turn off ADC1 */
4401d80de052Sstsp 	run_bbp_write(sc, 138, bbp);
4402d80de052Sstsp 
4403d80de052Sstsp 	run_rt3070_rf_read(sc, 38, &rf);
4404d80de052Sstsp 	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
4405d80de052Sstsp 
4406d80de052Sstsp 	run_rt3070_rf_read(sc, 39, &rf);
4407d80de052Sstsp 	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
4408d80de052Sstsp 
4409d80de052Sstsp 	/* Avoid data lost and CRC error. */
4410d80de052Sstsp 	run_bbp_read(sc, 4, &bbp);
4411d80de052Sstsp 	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
4412d80de052Sstsp 
4413d80de052Sstsp 	run_rt3070_rf_read(sc, 30, &rf);
4414d80de052Sstsp 	rf = (rf & ~0x18) | 0x10;
4415d80de052Sstsp 	run_rt3070_rf_write(sc, 30, rf);
4416d80de052Sstsp 
4417d80de052Sstsp 	if (sc->mac_ver != 0x5592) {
4418d80de052Sstsp 		run_write(sc, RT2860_TX_SW_CFG1, 0);
4419d80de052Sstsp 		if (sc->mac_rev < 0x0211) {
4420d80de052Sstsp 			run_write(sc, RT2860_TX_SW_CFG2,
4421d80de052Sstsp 			    sc->patch_dac ? 0x2c : 0x0f);
4422d80de052Sstsp 		} else
4423d80de052Sstsp 			run_write(sc, RT2860_TX_SW_CFG2, 0);
4424d80de052Sstsp 	}
4425d80de052Sstsp }
4426d80de052Sstsp 
442730aa40ebSdamien int
run_txrx_enable(struct run_softc * sc)442830aa40ebSdamien run_txrx_enable(struct run_softc *sc)
442930aa40ebSdamien {
443030aa40ebSdamien 	uint32_t tmp;
443130aa40ebSdamien 	int error, ntries;
443230aa40ebSdamien 
443330aa40ebSdamien 	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
443430aa40ebSdamien 	for (ntries = 0; ntries < 200; ntries++) {
443530aa40ebSdamien 		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
443630aa40ebSdamien 			return error;
443730aa40ebSdamien 		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
443830aa40ebSdamien 			break;
443930aa40ebSdamien 		DELAY(1000);
444030aa40ebSdamien 	}
444130aa40ebSdamien 	if (ntries == 200)
444230aa40ebSdamien 		return ETIMEDOUT;
444330aa40ebSdamien 
444430aa40ebSdamien 	DELAY(50);
444530aa40ebSdamien 
444630aa40ebSdamien 	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
444730aa40ebSdamien 	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
444830aa40ebSdamien 
4449c4a33c5cSdamien 	/* enable Rx bulk aggregation (set timeout and limit) */
4450c4a33c5cSdamien 	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
4451c4a33c5cSdamien 	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
445230aa40ebSdamien 	run_write(sc, RT2860_USB_DMA_CFG, tmp);
445330aa40ebSdamien 
445430aa40ebSdamien 	/* set Rx filter */
445530aa40ebSdamien 	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
445630aa40ebSdamien 	if (sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR) {
445730aa40ebSdamien 		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
445830aa40ebSdamien 		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
445930aa40ebSdamien 		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
446030aa40ebSdamien 		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
446130aa40ebSdamien 		if (sc->sc_ic.ic_opmode == IEEE80211_M_STA)
446230aa40ebSdamien 			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
446330aa40ebSdamien 	}
446430aa40ebSdamien 	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
446530aa40ebSdamien 
446630aa40ebSdamien 	run_write(sc, RT2860_MAC_SYS_CTRL,
446730aa40ebSdamien 	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
446830aa40ebSdamien 
446930aa40ebSdamien 	return 0;
447030aa40ebSdamien }
447130aa40ebSdamien 
4472d80de052Sstsp void
run_adjust_freq_offset(struct run_softc * sc)4473d80de052Sstsp run_adjust_freq_offset(struct run_softc *sc)
4474d80de052Sstsp {
4475d80de052Sstsp 	uint8_t rf, tmp;
4476d80de052Sstsp 
4477d80de052Sstsp 	run_rt3070_rf_read(sc, 17, &rf);
4478d80de052Sstsp 	tmp = rf;
4479d80de052Sstsp 	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
4480d80de052Sstsp 	rf = MIN(rf, 0x5f);
4481d80de052Sstsp 
4482d80de052Sstsp 	if (tmp != rf)
4483d80de052Sstsp 		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
4484d80de052Sstsp }
4485d80de052Sstsp 
448630aa40ebSdamien int
run_init(struct ifnet * ifp)448730aa40ebSdamien run_init(struct ifnet *ifp)
448830aa40ebSdamien {
448930aa40ebSdamien 	struct run_softc *sc = ifp->if_softc;
449030aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
449130aa40ebSdamien 	uint32_t tmp;
449230aa40ebSdamien 	uint8_t bbp1, bbp3;
4493cd4f4e38Sdamien 	int i, error, qid, ridx, ntries;
449430aa40ebSdamien 
449512136ef5Sjakemsr 	if (usbd_is_dying(sc->sc_udev))
449612136ef5Sjakemsr 		return ENXIO;
449712136ef5Sjakemsr 
449830aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
449930aa40ebSdamien 		if ((error = run_read(sc, RT2860_ASIC_VER_ID, &tmp)) != 0)
45002563814dSdamien 			goto fail;
450130aa40ebSdamien 		if (tmp != 0 && tmp != 0xffffffff)
450230aa40ebSdamien 			break;
450330aa40ebSdamien 		DELAY(10);
450430aa40ebSdamien 	}
450530aa40ebSdamien 	if (ntries == 100) {
450630aa40ebSdamien 		error = ETIMEDOUT;
450730aa40ebSdamien 		goto fail;
450830aa40ebSdamien 	}
450930aa40ebSdamien 
451030aa40ebSdamien 	if ((error = run_load_microcode(sc)) != 0) {
451130aa40ebSdamien 		printf("%s: could not load 8051 microcode\n",
451230aa40ebSdamien 		    sc->sc_dev.dv_xname);
451330aa40ebSdamien 		goto fail;
451430aa40ebSdamien 	}
451530aa40ebSdamien 
451630aa40ebSdamien 	/* init host command ring */
451730aa40ebSdamien 	sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0;
451830aa40ebSdamien 
45195892192bSdamien 	/* init Tx rings (4 EDCAs) */
45205892192bSdamien 	for (qid = 0; qid < 4; qid++) {
452130aa40ebSdamien 		if ((error = run_alloc_tx_ring(sc, qid)) != 0)
452230aa40ebSdamien 			goto fail;
452330aa40ebSdamien 	}
452430aa40ebSdamien 	/* init Rx ring */
452530aa40ebSdamien 	if ((error = run_alloc_rx_ring(sc)) != 0)
452630aa40ebSdamien 		goto fail;
452730aa40ebSdamien 
452830aa40ebSdamien 	IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
452930aa40ebSdamien 	run_set_macaddr(sc, ic->ic_myaddr);
453030aa40ebSdamien 
453130aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
45322563814dSdamien 		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
45332563814dSdamien 			goto fail;
453430aa40ebSdamien 		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
453530aa40ebSdamien 			break;
453630aa40ebSdamien 		DELAY(1000);
453730aa40ebSdamien 	}
453830aa40ebSdamien 	if (ntries == 100) {
453930aa40ebSdamien 		printf("%s: timeout waiting for DMA engine\n",
454030aa40ebSdamien 		    sc->sc_dev.dv_xname);
454130aa40ebSdamien 		error = ETIMEDOUT;
454230aa40ebSdamien 		goto fail;
454330aa40ebSdamien 	}
454430aa40ebSdamien 	tmp &= 0xff0;
454530aa40ebSdamien 	tmp |= RT2860_TX_WB_DDONE;
454630aa40ebSdamien 	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
454730aa40ebSdamien 
454830aa40ebSdamien 	/* turn off PME_OEN to solve high-current issue */
454930aa40ebSdamien 	run_read(sc, RT2860_SYS_CTRL, &tmp);
455030aa40ebSdamien 	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
455130aa40ebSdamien 
455230aa40ebSdamien 	run_write(sc, RT2860_MAC_SYS_CTRL,
455330aa40ebSdamien 	    RT2860_BBP_HRST | RT2860_MAC_SRST);
455430aa40ebSdamien 	run_write(sc, RT2860_USB_DMA_CFG, 0);
455530aa40ebSdamien 
455630aa40ebSdamien 	if ((error = run_reset(sc)) != 0) {
455730aa40ebSdamien 		printf("%s: could not reset chipset\n", sc->sc_dev.dv_xname);
455830aa40ebSdamien 		goto fail;
455930aa40ebSdamien 	}
456030aa40ebSdamien 
456130aa40ebSdamien 	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
456230aa40ebSdamien 
456330aa40ebSdamien 	/* init Tx power for all Tx rates (from EEPROM) */
456430aa40ebSdamien 	for (ridx = 0; ridx < 5; ridx++) {
456530aa40ebSdamien 		if (sc->txpow20mhz[ridx] == 0xffffffff)
456630aa40ebSdamien 			continue;
456730aa40ebSdamien 		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
456830aa40ebSdamien 	}
456930aa40ebSdamien 
457030aa40ebSdamien 	for (i = 0; i < nitems(rt2870_def_mac); i++)
457130aa40ebSdamien 		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
457230aa40ebSdamien 	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
457330aa40ebSdamien 	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
457430aa40ebSdamien 	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
457530aa40ebSdamien 
4576d80de052Sstsp 	if (sc->mac_ver >= 0x5390) {
4577d80de052Sstsp 		run_write(sc, RT2860_TX_SW_CFG0,
4578d80de052Sstsp 		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
4579d80de052Sstsp 		if (sc->mac_ver >= 0x5392) {
4580d80de052Sstsp 			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
4581d80de052Sstsp 			if (sc->mac_ver == 0x5592) {
4582d80de052Sstsp 				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
4583d80de052Sstsp 				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
4584d80de052Sstsp 			} else {
4585d80de052Sstsp 				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
4586d80de052Sstsp 				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
4587d80de052Sstsp 			}
4588d80de052Sstsp 		}
4589d80de052Sstsp 	} else if (sc->mac_ver == 0x3593) {
4590d80de052Sstsp 		run_write(sc, RT2860_TX_SW_CFG0,
4591d80de052Sstsp 		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
4592d80de052Sstsp 	} else if (sc->mac_ver >= 0x3070) {
459330aa40ebSdamien 		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
459430aa40ebSdamien 		run_write(sc, RT2860_TX_SW_CFG0,
459530aa40ebSdamien 		    4 << RT2860_DLY_PAPE_EN_SHIFT);
459630aa40ebSdamien 	}
459730aa40ebSdamien 
459830aa40ebSdamien 	/* wait while MAC is busy */
459930aa40ebSdamien 	for (ntries = 0; ntries < 100; ntries++) {
46002563814dSdamien 		if ((error = run_read(sc, RT2860_MAC_STATUS_REG, &tmp)) != 0)
46012563814dSdamien 			goto fail;
460230aa40ebSdamien 		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
460330aa40ebSdamien 			break;
460430aa40ebSdamien 		DELAY(1000);
460530aa40ebSdamien 	}
460630aa40ebSdamien 	if (ntries == 100) {
460730aa40ebSdamien 		error = ETIMEDOUT;
460830aa40ebSdamien 		goto fail;
460930aa40ebSdamien 	}
461030aa40ebSdamien 
461130aa40ebSdamien 	/* clear Host to MCU mailbox */
461230aa40ebSdamien 	run_write(sc, RT2860_H2M_BBPAGENT, 0);
461330aa40ebSdamien 	run_write(sc, RT2860_H2M_MAILBOX, 0);
461430aa40ebSdamien 	DELAY(1000);
461530aa40ebSdamien 
461630aa40ebSdamien 	if ((error = run_bbp_init(sc)) != 0) {
461730aa40ebSdamien 		printf("%s: could not initialize BBP\n", sc->sc_dev.dv_xname);
461830aa40ebSdamien 		goto fail;
461930aa40ebSdamien 	}
462030aa40ebSdamien 
4621d80de052Sstsp 	/* abort TSF synchronization */
462230aa40ebSdamien 	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
462330aa40ebSdamien 	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
462430aa40ebSdamien 	    RT2860_TBTT_TIMER_EN);
462530aa40ebSdamien 	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
462630aa40ebSdamien 
462730aa40ebSdamien 	/* clear RX WCID search table */
4628cd4f4e38Sdamien 	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
462930aa40ebSdamien 	/* clear WCID attribute table */
4630cd4f4e38Sdamien 	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
4631cd4f4e38Sdamien 	/* clear shared key table */
4632cd4f4e38Sdamien 	run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
463330aa40ebSdamien 	/* clear shared key mode */
463430aa40ebSdamien 	run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
463530aa40ebSdamien 
463630aa40ebSdamien 	run_read(sc, RT2860_US_CYC_CNT, &tmp);
463730aa40ebSdamien 	tmp = (tmp & ~0xff) | 0x1e;
463830aa40ebSdamien 	run_write(sc, RT2860_US_CYC_CNT, tmp);
463930aa40ebSdamien 
4640e56800d9Sdamien 	if (sc->mac_rev != 0x0101)
464130aa40ebSdamien 		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
464230aa40ebSdamien 
464330aa40ebSdamien 	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
464430aa40ebSdamien 	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
464530aa40ebSdamien 
464630aa40ebSdamien 	/* write vendor-specific BBP values (from EEPROM) */
4647d80de052Sstsp 	if (sc->mac_ver < 0x3593) {
464830aa40ebSdamien 		for (i = 0; i < 8; i++) {
464930aa40ebSdamien 			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
465030aa40ebSdamien 				continue;
465130aa40ebSdamien 			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
465230aa40ebSdamien 		}
4653d80de052Sstsp 	}
465430aa40ebSdamien 
4655cd4f4e38Sdamien 	/* select Main antenna for 1T1R devices */
4656d80de052Sstsp 	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
4657cd4f4e38Sdamien 		run_set_rx_antenna(sc, 0);
4658cd4f4e38Sdamien 
465930aa40ebSdamien 	/* send LEDs operating mode to microcontroller */
466030aa40ebSdamien 	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
466130aa40ebSdamien 	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
466230aa40ebSdamien 	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
466330aa40ebSdamien 
4664d80de052Sstsp 	if (sc->mac_ver >= 0x5390)
4665d80de052Sstsp 		run_rt5390_rf_init(sc);
4666d80de052Sstsp 	else if (sc->mac_ver == 0x3593)
4667d80de052Sstsp 		run_rt3593_rf_init(sc);
4668d80de052Sstsp 	else if (sc->mac_ver >= 0x3070)
4669e56800d9Sdamien 		run_rt3070_rf_init(sc);
4670e56800d9Sdamien 
467130aa40ebSdamien 	/* disable non-existing Rx chains */
467230aa40ebSdamien 	run_bbp_read(sc, 3, &bbp3);
467330aa40ebSdamien 	bbp3 &= ~(1 << 3 | 1 << 4);
467430aa40ebSdamien 	if (sc->nrxchains == 2)
467530aa40ebSdamien 		bbp3 |= 1 << 3;
467630aa40ebSdamien 	else if (sc->nrxchains == 3)
467730aa40ebSdamien 		bbp3 |= 1 << 4;
467830aa40ebSdamien 	run_bbp_write(sc, 3, bbp3);
467930aa40ebSdamien 
468030aa40ebSdamien 	/* disable non-existing Tx chains */
468130aa40ebSdamien 	run_bbp_read(sc, 1, &bbp1);
468230aa40ebSdamien 	if (sc->ntxchains == 1)
468330aa40ebSdamien 		bbp1 &= ~(1 << 3 | 1 << 4);
468430aa40ebSdamien 	run_bbp_write(sc, 1, bbp1);
468530aa40ebSdamien 
4686d80de052Sstsp 	if (sc->mac_ver >= 0x5390)
4687d80de052Sstsp 		run_rt5390_rf_setup(sc);
4688d80de052Sstsp 	else if (sc->mac_ver == 0x3593)
4689d80de052Sstsp 		run_rt3593_rf_setup(sc);
4690d80de052Sstsp 	else if (sc->mac_ver >= 0x3070)
4691e56800d9Sdamien 		run_rt3070_rf_setup(sc);
469230aa40ebSdamien 
469330aa40ebSdamien 	/* select default channel */
469430aa40ebSdamien 	ic->ic_bss->ni_chan = ic->ic_ibss_chan;
469530aa40ebSdamien 	run_set_chan(sc, ic->ic_ibss_chan);
469630aa40ebSdamien 
469730aa40ebSdamien 	/* turn radio LED on */
469830aa40ebSdamien 	run_set_leds(sc, RT2860_LED_RADIO);
469930aa40ebSdamien 
470030aa40ebSdamien 	for (i = 0; i < RUN_RX_RING_COUNT; i++) {
470130aa40ebSdamien 		struct run_rx_data *data = &sc->rxq.data[i];
470230aa40ebSdamien 
470330aa40ebSdamien 		usbd_setup_xfer(data->xfer, sc->rxq.pipeh, data, data->buf,
470430aa40ebSdamien 		    RUN_MAX_RXSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
470530aa40ebSdamien 		    USBD_NO_TIMEOUT, run_rxeof);
470630aa40ebSdamien 		error = usbd_transfer(data->xfer);
470730aa40ebSdamien 		if (error != 0 && error != USBD_IN_PROGRESS)
470830aa40ebSdamien 			goto fail;
470930aa40ebSdamien 	}
471030aa40ebSdamien 
471130aa40ebSdamien 	if ((error = run_txrx_enable(sc)) != 0)
47122563814dSdamien 		goto fail;
471330aa40ebSdamien 
471430aa40ebSdamien 	ifp->if_flags |= IFF_RUNNING;
4715de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
471630aa40ebSdamien 
47170760dad6Sdamien 	if (ic->ic_flags & IEEE80211_F_WEPON) {
47180760dad6Sdamien 		/* install WEP keys */
47190ff00077Skrw 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
47200ff00077Skrw 			if (ic->ic_nw_keys[i].k_cipher != IEEE80211_CIPHER_NONE)
47210760dad6Sdamien 				(void)run_set_key(ic, NULL, &ic->ic_nw_keys[i]);
47220760dad6Sdamien 		}
47230ff00077Skrw 	}
47240760dad6Sdamien 
472530aa40ebSdamien 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
472630aa40ebSdamien 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
472730aa40ebSdamien 	else
472830aa40ebSdamien 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
472930aa40ebSdamien 
473030aa40ebSdamien 	if (error != 0)
473130aa40ebSdamien fail:		run_stop(ifp, 1);
473230aa40ebSdamien 	return error;
473330aa40ebSdamien }
473430aa40ebSdamien 
473530aa40ebSdamien void
run_stop(struct ifnet * ifp,int disable)473630aa40ebSdamien run_stop(struct ifnet *ifp, int disable)
473730aa40ebSdamien {
473830aa40ebSdamien 	struct run_softc *sc = ifp->if_softc;
473930aa40ebSdamien 	struct ieee80211com *ic = &sc->sc_ic;
474030aa40ebSdamien 	uint32_t tmp;
47418015804dSdamien 	int s, ntries, qid;
474230aa40ebSdamien 
474330aa40ebSdamien 	if (ifp->if_flags & IFF_RUNNING)
474430aa40ebSdamien 		run_set_leds(sc, 0);	/* turn all LEDs off */
474530aa40ebSdamien 
474630aa40ebSdamien 	sc->sc_tx_timer = 0;
474730aa40ebSdamien 	ifp->if_timer = 0;
4748de6cd8fbSdlg 	ifp->if_flags &= ~IFF_RUNNING;
4749de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
475030aa40ebSdamien 
475130aa40ebSdamien 	timeout_del(&sc->scan_to);
475230aa40ebSdamien 	timeout_del(&sc->calib_to);
475330aa40ebSdamien 
475430aa40ebSdamien 	s = splusb();
475530aa40ebSdamien 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
475630aa40ebSdamien 	/* wait for all queued asynchronous commands to complete */
47575ad57547Sjakemsr 	usb_wait_task(sc->sc_udev, &sc->sc_task);
475830aa40ebSdamien 	splx(s);
475930aa40ebSdamien 
4760d80de052Sstsp 	/* Disable Tx/Rx DMA. */
4761d80de052Sstsp 	run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp);
4762d80de052Sstsp 	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
4763d80de052Sstsp 	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
4764d80de052Sstsp 
4765d80de052Sstsp 	for (ntries = 0; ntries < 100; ntries++) {
4766d80de052Sstsp 		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
4767d80de052Sstsp 			break;
4768d80de052Sstsp 		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
4769d80de052Sstsp 			break;
4770d80de052Sstsp 		DELAY(10);
4771d80de052Sstsp 	}
4772d80de052Sstsp 	if (ntries == 100) {
4773d80de052Sstsp 		printf("%s: timeout waiting for DMA engine\n",
4774d80de052Sstsp 		    sc->sc_dev.dv_xname);
4775d80de052Sstsp 	}
4776d80de052Sstsp 
477730aa40ebSdamien 	/* disable Tx/Rx */
477830aa40ebSdamien 	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
477930aa40ebSdamien 	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
478030aa40ebSdamien 	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
478130aa40ebSdamien 
47828015804dSdamien 	/* wait for pending Tx to complete */
47838015804dSdamien 	for (ntries = 0; ntries < 100; ntries++) {
47848015804dSdamien 		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0)
47858015804dSdamien 			break;
47868015804dSdamien 		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0)
47878015804dSdamien 			break;
47888015804dSdamien 	}
47898015804dSdamien 	DELAY(1000);
479030aa40ebSdamien 	run_write(sc, RT2860_USB_DMA_CFG, 0);
479130aa40ebSdamien 
479230aa40ebSdamien 	/* reset adapter */
479330aa40ebSdamien 	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
479430aa40ebSdamien 	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
479530aa40ebSdamien 
479630aa40ebSdamien 	/* reset Tx and Rx rings */
479730aa40ebSdamien 	sc->qfullmsk = 0;
47985892192bSdamien 	for (qid = 0; qid < 4; qid++)
479930aa40ebSdamien 		run_free_tx_ring(sc, qid);
480030aa40ebSdamien 	run_free_rx_ring(sc);
480130aa40ebSdamien }
4802