3 * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
4 * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include "rt2870_rf.h"
20 #include "rt2870_reg.h"
21 #include "rt2870_eeprom.h"
22 #include "rt2870_io.h"
23 #include "rt2870_debug.h"
29 static const struct rt2870_rf_prog
32 uint32_t r1
, r2
, r3
, r4
;
35 { 1, 0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b },
36 { 2, 0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f },
37 { 3, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b },
38 { 4, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f },
39 { 5, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b },
40 { 6, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f },
41 { 7, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b },
42 { 8, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f },
43 { 9, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b },
44 { 10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f },
45 { 11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b },
46 { 12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f },
47 { 13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b },
48 { 14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193 },
49 { 36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3 },
50 { 38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193 },
51 { 40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183 },
52 { 44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3 },
53 { 46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b },
54 { 48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b },
55 { 52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193 },
56 { 54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3 },
57 { 56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b },
58 { 60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183 },
59 { 62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193 },
60 { 64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3 },
61 { 100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783 },
62 { 102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793 },
63 { 104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3 },
64 { 108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193 },
65 { 110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183 },
66 { 112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b },
67 { 116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3 },
68 { 118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193 },
69 { 120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183 },
70 { 124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193 },
71 { 126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b },
72 { 128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3 },
73 { 132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b },
74 { 134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193 },
75 { 136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b },
76 { 140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183 },
77 { 149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7 },
78 { 151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187 },
79 { 153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f },
80 { 157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f },
81 { 159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7 },
82 { 161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187 },
83 { 165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197 },
84 { 184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b },
85 { 188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13 },
86 { 192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b },
87 { 196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23 },
88 { 208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13 },
89 { 212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b },
90 { 216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23 },
96 const char *rt2870_rf_name(int rf_rev
)
100 case RT2870_EEPROM_RF_2820
:
103 case RT2870_EEPROM_RF_2850
:
106 case RT2870_EEPROM_RF_2720
:
109 case RT2870_EEPROM_RF_2750
:
112 case RT2870_EEPROM_RF_3020
:
115 case RT2870_EEPROM_RF_2020
:
124 * rt2870_rf_select_chan_group
126 void rt2870_rf_select_chan_group(struct rt2870_softc
*sc
,
127 struct ieee80211_channel
*c
)
130 struct ieee80211com
*ic
;
137 chan
= ieee80211_chan2ieee(ic
, c
);
138 if (chan
== 0 || chan
== IEEE80211_CHAN_ANY
)
145 else if (chan
<= 128)
150 rt2870_io_bbp_write(sc
, 62, 0x37 - sc
->lna_gain
[group
]);
151 rt2870_io_bbp_write(sc
, 63, 0x37 - sc
->lna_gain
[group
]);
152 rt2870_io_bbp_write(sc
, 64, 0x37 - sc
->lna_gain
[group
]);
153 rt2870_io_bbp_write(sc
, 86, 0x00);
157 if (sc
->ext_lna_2ghz
)
159 rt2870_io_bbp_write(sc
, 82, 0x62);
160 rt2870_io_bbp_write(sc
, 75, 0x46);
164 rt2870_io_bbp_write(sc
, 82, 0x84);
165 rt2870_io_bbp_write(sc
, 75, 0x50);
170 rt2870_io_bbp_write(sc
, 82, 0xf2);
172 if (sc
->ext_lna_5ghz
)
173 rt2870_io_bbp_write(sc
, 75, 0x46);
175 rt2870_io_bbp_write(sc
, 75, 0x50);
180 tmp
= 0x2e + sc
->lna_gain
[group
];
184 if ((ic
->ic_flags
& IEEE80211_F_SCAN
) || !IEEE80211_IS_CHAN_HT40(c
))
185 tmp
= 0x32 + sc
->lna_gain
[group
] * 5 / 3;
187 tmp
= 0x3a + sc
->lna_gain
[group
] * 5 / 3;
190 rt2870_io_bbp_write(sc
, 66, tmp
);
192 tmp
= RT2870_REG_RFTR_ENABLE
|
193 RT2870_REG_TRSW_ENABLE
|
194 RT2870_REG_LNA_PE_G1_ENABLE
|
195 RT2870_REG_LNA_PE_A1_ENABLE
|
196 RT2870_REG_LNA_PE_G0_ENABLE
|
197 RT2870_REG_LNA_PE_A0_ENABLE
;
200 tmp
|= RT2870_REG_PA_PE_G1_ENABLE
|
201 RT2870_REG_PA_PE_G0_ENABLE
;
203 tmp
|= RT2870_REG_PA_PE_A1_ENABLE
|
204 RT2870_REG_PA_PE_A0_ENABLE
;
206 if (sc
->ntxpath
== 1)
207 tmp
&= ~(RT2870_REG_PA_PE_G1_ENABLE
| RT2870_REG_PA_PE_A1_ENABLE
);
209 if (sc
->nrxpath
== 1)
210 tmp
&= ~(RT2870_REG_LNA_PE_G1_ENABLE
| RT2870_REG_LNA_PE_A1_ENABLE
);
212 rt2870_io_mac_write(sc
, RT2870_REG_TX_PIN_CFG
, tmp
);
214 tmp
= rt2870_io_mac_read(sc
, RT2870_REG_TX_BAND_CFG
);
216 tmp
&= ~(RT2870_REG_TX_BAND_BG
| RT2870_REG_TX_BAND_A
| RT2870_REG_TX_BAND_HT40_ABOVE
);
219 tmp
|= RT2870_REG_TX_BAND_BG
;
221 tmp
|= RT2870_REG_TX_BAND_A
;
223 /* set central channel position */
225 if (IEEE80211_IS_CHAN_HT40U(c
))
226 tmp
|= RT2870_REG_TX_BAND_HT40_BELOW
;
227 else if (IEEE80211_IS_CHAN_HT40D(c
))
228 tmp
|= RT2870_REG_TX_BAND_HT40_ABOVE
;
230 tmp
|= RT2870_REG_TX_BAND_HT40_BELOW
;
232 rt2870_io_mac_write(sc
, RT2870_REG_TX_BAND_CFG
, tmp
);
234 /* set bandwidth (20MHz or 40MHz) */
236 tmp
= rt2870_io_bbp_read(sc
, 4);
240 if (IEEE80211_IS_CHAN_HT40(c
))
243 rt2870_io_bbp_write(sc
, 4, tmp
);
245 /* set central channel position */
247 tmp
= rt2870_io_bbp_read(sc
, 3);
251 if (IEEE80211_IS_CHAN_HT40D(c
))
254 rt2870_io_bbp_write(sc
, 3, tmp
);
256 if (sc
->mac_rev
== 0x28600100)
258 if (!IEEE80211_IS_CHAN_HT40(c
))
260 rt2870_io_bbp_write(sc
, 69, 0x16);
261 rt2870_io_bbp_write(sc
, 70, 0x08);
262 rt2870_io_bbp_write(sc
, 73, 0x12);
266 rt2870_io_bbp_write(sc
, 69, 0x1a);
267 rt2870_io_bbp_write(sc
, 70, 0x0a);
268 rt2870_io_bbp_write(sc
, 73, 0x16);
276 void rt2870_rf_set_chan(struct rt2870_softc
*sc
,
277 struct ieee80211_channel
*c
)
280 struct ieee80211com
*ic
;
281 const struct rt2870_rf_prog
*prog
;
282 uint32_t r1
, r2
, r3
, r4
;
283 int8_t txpow1
, txpow2
;
288 prog
= rt2870_rf_2850
;
290 /* get central channel position */
292 chan
= ieee80211_chan2ieee(ic
, c
);
294 if (IEEE80211_IS_CHAN_HT40U(c
))
296 else if (IEEE80211_IS_CHAN_HT40D(c
))
299 RT2870_DPRINTF(sc
, RT2870_DEBUG_CHAN
,
300 "%s: RF set channel: channel=%u, HT%s%s\n",
301 device_get_nameunit(sc
->dev
),
302 ieee80211_chan2ieee(ic
, c
),
303 !IEEE80211_IS_CHAN_HT(c
) ? " disabled" :
304 IEEE80211_IS_CHAN_HT20(c
) ? "20":
305 IEEE80211_IS_CHAN_HT40U(c
) ? "40U" : "40D",
306 (ic
->ic_flags
& IEEE80211_F_SCAN
) ? ", scanning" : "");
308 if (chan
== 0 || chan
== IEEE80211_CHAN_ANY
)
311 for (i
= 0; prog
[i
].chan
!= chan
; i
++);
318 txpow1
= sc
->txpow1
[i
];
319 txpow2
= sc
->txpow2
[i
];
321 if (sc
->ntxpath
== 1)
324 if (sc
->nrxpath
== 2)
326 else if (sc
->nrxpath
== 1)
327 r2
|= (1 << 17) | (1 << 6);
329 if (IEEE80211_IS_CHAN_2GHZ(c
))
331 r3
= (r3
& 0xffffc1ff) | (txpow1
<< 9);
332 r4
= (r4
& ~0x001f87c0) | (sc
->rf_freq_off
<< 15) | (txpow2
<< 6);
336 r3
= r3
& 0xffffc1ff;
337 r4
= (r4
& ~0x001f87c0) | (sc
->rf_freq_off
<< 15);
339 if (txpow1
>= RT2870_EEPROM_TXPOW_5GHZ_MIN
&& txpow1
< 0)
341 txpow1
= (-RT2870_EEPROM_TXPOW_5GHZ_MIN
+ txpow1
);
342 if (txpow1
> RT2870_EEPROM_TXPOW_5GHZ_MAX
)
343 txpow1
= RT2870_EEPROM_TXPOW_5GHZ_MAX
;
345 r3
|= (txpow1
<< 10);
349 if (txpow1
> RT2870_EEPROM_TXPOW_5GHZ_MAX
)
350 txpow1
= RT2870_EEPROM_TXPOW_5GHZ_MAX
;
352 r3
|= (txpow1
<< 10) | (1 << 9);
355 if (txpow2
>= RT2870_EEPROM_TXPOW_5GHZ_MIN
&& txpow2
< 0)
357 txpow2
= (-RT2870_EEPROM_TXPOW_5GHZ_MIN
+ txpow2
);
358 if (txpow2
> RT2870_EEPROM_TXPOW_5GHZ_MAX
)
359 txpow2
= RT2870_EEPROM_TXPOW_5GHZ_MAX
;
365 if (txpow2
> RT2870_EEPROM_TXPOW_5GHZ_MAX
)
366 txpow2
= RT2870_EEPROM_TXPOW_5GHZ_MAX
;
368 r4
|= (txpow2
<< 7) | (1 << 6);
372 if (!(ic
->ic_flags
& IEEE80211_F_SCAN
) && IEEE80211_IS_CHAN_HT40(c
))
375 rt2870_io_rf_write(sc
, RT2870_REG_RF_R1
, r1
);
376 rt2870_io_rf_write(sc
, RT2870_REG_RF_R2
, r2
);
377 rt2870_io_rf_write(sc
, RT2870_REG_RF_R3
, r3
& ~(1 << 2));
378 rt2870_io_rf_write(sc
, RT2870_REG_RF_R4
, r4
);
382 rt2870_io_rf_write(sc
, RT2870_REG_RF_R1
, r1
);
383 rt2870_io_rf_write(sc
, RT2870_REG_RF_R2
, r2
);
384 rt2870_io_rf_write(sc
, RT2870_REG_RF_R3
, r3
| (1 << 2));
385 rt2870_io_rf_write(sc
, RT2870_REG_RF_R4
, r4
);
389 rt2870_io_rf_write(sc
, RT2870_REG_RF_R1
, r1
);
390 rt2870_io_rf_write(sc
, RT2870_REG_RF_R2
, r2
);
391 rt2870_io_rf_write(sc
, RT2870_REG_RF_R3
, r3
& ~(1 << 2));
392 rt2870_io_rf_write(sc
, RT2870_REG_RF_R4
, r4
);
394 rt2870_rf_select_chan_group(sc
, c
);