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