spi-topcliff-pch: supports a spi mode setup and bit order setup by IO control
[zen-stable.git] / drivers / net / wireless / b43legacy / radio.c
blobfcbafcd603ccf1549c112012845dcd4a73a1b10c
1 /*
3 Broadcom B43legacy wireless driver
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Stefano Brivio <stefano.brivio@polimi.it>
7 Michael Buesch <m@bues.ch>
8 Danny van Dyk <kugelfang@gentoo.org>
9 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10 Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
12 Some parts of the code in this file are derived from the ipw2200
13 driver Copyright(c) 2003 - 2004 Intel Corporation.
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; see the file COPYING. If not, write to
27 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
28 Boston, MA 02110-1301, USA.
32 #include <linux/delay.h>
34 #include "b43legacy.h"
35 #include "main.h"
36 #include "phy.h"
37 #include "radio.h"
38 #include "ilt.h"
41 /* Table for b43legacy_radio_calibrationvalue() */
42 static const u16 rcc_table[16] = {
43 0x0002, 0x0003, 0x0001, 0x000F,
44 0x0006, 0x0007, 0x0005, 0x000F,
45 0x000A, 0x000B, 0x0009, 0x000F,
46 0x000E, 0x000F, 0x000D, 0x000F,
49 /* Reverse the bits of a 4bit value.
50 * Example: 1101 is flipped 1011
52 static u16 flip_4bit(u16 value)
54 u16 flipped = 0x0000;
56 B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000));
58 flipped |= (value & 0x0001) << 3;
59 flipped |= (value & 0x0002) << 1;
60 flipped |= (value & 0x0004) >> 1;
61 flipped |= (value & 0x0008) >> 3;
63 return flipped;
66 /* Get the freq, as it has to be written to the device. */
67 static inline
68 u16 channel2freq_bg(u8 channel)
70 /* Frequencies are given as frequencies_bg[index] + 2.4GHz
71 * Starting with channel 1
73 static const u16 frequencies_bg[14] = {
74 12, 17, 22, 27,
75 32, 37, 42, 47,
76 52, 57, 62, 67,
77 72, 84,
80 if (unlikely(channel < 1 || channel > 14)) {
81 printk(KERN_INFO "b43legacy: Channel %d is out of range\n",
82 channel);
83 dump_stack();
84 return 2412;
87 return frequencies_bg[channel - 1];
90 void b43legacy_radio_lock(struct b43legacy_wldev *dev)
92 u32 status;
94 status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
95 B43legacy_WARN_ON(status & B43legacy_MACCTL_RADIOLOCK);
96 status |= B43legacy_MACCTL_RADIOLOCK;
97 b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
98 mmiowb();
99 udelay(10);
102 void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
104 u32 status;
106 b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
107 status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
108 B43legacy_WARN_ON(!(status & B43legacy_MACCTL_RADIOLOCK));
109 status &= ~B43legacy_MACCTL_RADIOLOCK;
110 b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
111 mmiowb();
114 u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset)
116 struct b43legacy_phy *phy = &dev->phy;
118 switch (phy->type) {
119 case B43legacy_PHYTYPE_B:
120 if (phy->radio_ver == 0x2053) {
121 if (offset < 0x70)
122 offset += 0x80;
123 else if (offset < 0x80)
124 offset += 0x70;
125 } else if (phy->radio_ver == 0x2050)
126 offset |= 0x80;
127 else
128 B43legacy_WARN_ON(1);
129 break;
130 case B43legacy_PHYTYPE_G:
131 offset |= 0x80;
132 break;
133 default:
134 B43legacy_BUG_ON(1);
137 b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
138 return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
141 void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val)
143 b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
144 mmiowb();
145 b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);
148 static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,
149 s16 first, s16 second, s16 third)
151 struct b43legacy_phy *phy = &dev->phy;
152 u16 i;
153 u16 start = 0x08;
154 u16 end = 0x18;
155 u16 offset = 0x0400;
156 u16 tmp;
158 if (phy->rev <= 1) {
159 offset = 0x5000;
160 start = 0x10;
161 end = 0x20;
164 for (i = 0; i < 4; i++)
165 b43legacy_ilt_write(dev, offset + i, first);
167 for (i = start; i < end; i++)
168 b43legacy_ilt_write(dev, offset + i, second);
170 if (third != -1) {
171 tmp = ((u16)third << 14) | ((u16)third << 6);
172 b43legacy_phy_write(dev, 0x04A0,
173 (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
174 | tmp);
175 b43legacy_phy_write(dev, 0x04A1,
176 (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
177 | tmp);
178 b43legacy_phy_write(dev, 0x04A2,
179 (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
180 | tmp);
182 b43legacy_dummy_transmission(dev);
185 static void b43legacy_set_original_gains(struct b43legacy_wldev *dev)
187 struct b43legacy_phy *phy = &dev->phy;
188 u16 i;
189 u16 tmp;
190 u16 offset = 0x0400;
191 u16 start = 0x0008;
192 u16 end = 0x0018;
194 if (phy->rev <= 1) {
195 offset = 0x5000;
196 start = 0x0010;
197 end = 0x0020;
200 for (i = 0; i < 4; i++) {
201 tmp = (i & 0xFFFC);
202 tmp |= (i & 0x0001) << 1;
203 tmp |= (i & 0x0002) >> 1;
205 b43legacy_ilt_write(dev, offset + i, tmp);
208 for (i = start; i < end; i++)
209 b43legacy_ilt_write(dev, offset + i, i - start);
211 b43legacy_phy_write(dev, 0x04A0,
212 (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
213 | 0x4040);
214 b43legacy_phy_write(dev, 0x04A1,
215 (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
216 | 0x4040);
217 b43legacy_phy_write(dev, 0x04A2,
218 (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
219 | 0x4000);
220 b43legacy_dummy_transmission(dev);
223 /* Synthetic PU workaround */
224 static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,
225 u8 channel)
227 struct b43legacy_phy *phy = &dev->phy;
229 might_sleep();
231 if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)
232 /* We do not need the workaround. */
233 return;
235 if (channel <= 10)
236 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
237 channel2freq_bg(channel + 4));
238 else
239 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
240 channel2freq_bg(channel));
241 msleep(1);
242 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
243 channel2freq_bg(channel));
246 u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel)
248 struct b43legacy_phy *phy = &dev->phy;
249 u8 ret = 0;
250 u16 saved;
251 u16 rssi;
252 u16 temp;
253 int i;
254 int j = 0;
256 saved = b43legacy_phy_read(dev, 0x0403);
257 b43legacy_radio_selectchannel(dev, channel, 0);
258 b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
259 if (phy->aci_hw_rssi)
260 rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;
261 else
262 rssi = saved & 0x3F;
263 /* clamp temp to signed 5bit */
264 if (rssi > 32)
265 rssi -= 64;
266 for (i = 0; i < 100; i++) {
267 temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;
268 if (temp > 32)
269 temp -= 64;
270 if (temp < rssi)
271 j++;
272 if (j >= 20)
273 ret = 1;
275 b43legacy_phy_write(dev, 0x0403, saved);
277 return ret;
280 u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
282 struct b43legacy_phy *phy = &dev->phy;
283 u8 ret[13];
284 unsigned int channel = phy->channel;
285 unsigned int i;
286 unsigned int j;
287 unsigned int start;
288 unsigned int end;
290 if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
291 return 0;
293 b43legacy_phy_lock(dev);
294 b43legacy_radio_lock(dev);
295 b43legacy_phy_write(dev, 0x0802,
296 b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
297 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
298 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
299 & 0x7FFF);
300 b43legacy_set_all_gains(dev, 3, 8, 1);
302 start = (channel - 5 > 0) ? channel - 5 : 1;
303 end = (channel + 5 < 14) ? channel + 5 : 13;
305 for (i = start; i <= end; i++) {
306 if (abs(channel - i) > 2)
307 ret[i-1] = b43legacy_radio_aci_detect(dev, i);
309 b43legacy_radio_selectchannel(dev, channel, 0);
310 b43legacy_phy_write(dev, 0x0802,
311 (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)
312 | 0x0003);
313 b43legacy_phy_write(dev, 0x0403,
314 b43legacy_phy_read(dev, 0x0403) & 0xFFF8);
315 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
316 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
317 | 0x8000);
318 b43legacy_set_original_gains(dev);
319 for (i = 0; i < 13; i++) {
320 if (!ret[i])
321 continue;
322 end = (i + 5 < 13) ? i + 5 : 13;
323 for (j = i; j < end; j++)
324 ret[j] = 1;
326 b43legacy_radio_unlock(dev);
327 b43legacy_phy_unlock(dev);
329 return ret[channel - 1];
332 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
333 void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val)
335 b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
336 mmiowb();
337 b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);
340 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
341 s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset)
343 u16 val;
345 b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
346 val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);
348 return (s16)val;
351 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
352 void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
354 u16 i;
355 s16 tmp;
357 for (i = 0; i < 64; i++) {
358 tmp = b43legacy_nrssi_hw_read(dev, i);
359 tmp -= val;
360 tmp = clamp_val(tmp, -32, 31);
361 b43legacy_nrssi_hw_write(dev, i, tmp);
365 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
366 void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
368 struct b43legacy_phy *phy = &dev->phy;
369 s16 i;
370 s16 delta;
371 s32 tmp;
373 delta = 0x1F - phy->nrssi[0];
374 for (i = 0; i < 64; i++) {
375 tmp = (i - delta) * phy->nrssislope;
376 tmp /= 0x10000;
377 tmp += 0x3A;
378 tmp = clamp_val(tmp, 0, 0x3F);
379 phy->nrssi_lt[i] = tmp;
383 static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev)
385 struct b43legacy_phy *phy = &dev->phy;
386 u16 backup[20] = { 0 };
387 s16 v47F;
388 u16 i;
389 u16 saved = 0xFFFF;
391 backup[0] = b43legacy_phy_read(dev, 0x0001);
392 backup[1] = b43legacy_phy_read(dev, 0x0811);
393 backup[2] = b43legacy_phy_read(dev, 0x0812);
394 backup[3] = b43legacy_phy_read(dev, 0x0814);
395 backup[4] = b43legacy_phy_read(dev, 0x0815);
396 backup[5] = b43legacy_phy_read(dev, 0x005A);
397 backup[6] = b43legacy_phy_read(dev, 0x0059);
398 backup[7] = b43legacy_phy_read(dev, 0x0058);
399 backup[8] = b43legacy_phy_read(dev, 0x000A);
400 backup[9] = b43legacy_phy_read(dev, 0x0003);
401 backup[10] = b43legacy_radio_read16(dev, 0x007A);
402 backup[11] = b43legacy_radio_read16(dev, 0x0043);
404 b43legacy_phy_write(dev, 0x0429,
405 b43legacy_phy_read(dev, 0x0429) & 0x7FFF);
406 b43legacy_phy_write(dev, 0x0001,
407 (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)
408 | 0x4000);
409 b43legacy_phy_write(dev, 0x0811,
410 b43legacy_phy_read(dev, 0x0811) | 0x000C);
411 b43legacy_phy_write(dev, 0x0812,
412 (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)
413 | 0x0004);
414 b43legacy_phy_write(dev, 0x0802,
415 b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
416 if (phy->rev >= 6) {
417 backup[12] = b43legacy_phy_read(dev, 0x002E);
418 backup[13] = b43legacy_phy_read(dev, 0x002F);
419 backup[14] = b43legacy_phy_read(dev, 0x080F);
420 backup[15] = b43legacy_phy_read(dev, 0x0810);
421 backup[16] = b43legacy_phy_read(dev, 0x0801);
422 backup[17] = b43legacy_phy_read(dev, 0x0060);
423 backup[18] = b43legacy_phy_read(dev, 0x0014);
424 backup[19] = b43legacy_phy_read(dev, 0x0478);
426 b43legacy_phy_write(dev, 0x002E, 0);
427 b43legacy_phy_write(dev, 0x002F, 0);
428 b43legacy_phy_write(dev, 0x080F, 0);
429 b43legacy_phy_write(dev, 0x0810, 0);
430 b43legacy_phy_write(dev, 0x0478,
431 b43legacy_phy_read(dev, 0x0478) | 0x0100);
432 b43legacy_phy_write(dev, 0x0801,
433 b43legacy_phy_read(dev, 0x0801) | 0x0040);
434 b43legacy_phy_write(dev, 0x0060,
435 b43legacy_phy_read(dev, 0x0060) | 0x0040);
436 b43legacy_phy_write(dev, 0x0014,
437 b43legacy_phy_read(dev, 0x0014) | 0x0200);
439 b43legacy_radio_write16(dev, 0x007A,
440 b43legacy_radio_read16(dev, 0x007A) | 0x0070);
441 b43legacy_radio_write16(dev, 0x007A,
442 b43legacy_radio_read16(dev, 0x007A) | 0x0080);
443 udelay(30);
445 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
446 if (v47F >= 0x20)
447 v47F -= 0x40;
448 if (v47F == 31) {
449 for (i = 7; i >= 4; i--) {
450 b43legacy_radio_write16(dev, 0x007B, i);
451 udelay(20);
452 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)
453 & 0x003F);
454 if (v47F >= 0x20)
455 v47F -= 0x40;
456 if (v47F < 31 && saved == 0xFFFF)
457 saved = i;
459 if (saved == 0xFFFF)
460 saved = 4;
461 } else {
462 b43legacy_radio_write16(dev, 0x007A,
463 b43legacy_radio_read16(dev, 0x007A)
464 & 0x007F);
465 b43legacy_phy_write(dev, 0x0814,
466 b43legacy_phy_read(dev, 0x0814) | 0x0001);
467 b43legacy_phy_write(dev, 0x0815,
468 b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
469 b43legacy_phy_write(dev, 0x0811,
470 b43legacy_phy_read(dev, 0x0811) | 0x000C);
471 b43legacy_phy_write(dev, 0x0812,
472 b43legacy_phy_read(dev, 0x0812) | 0x000C);
473 b43legacy_phy_write(dev, 0x0811,
474 b43legacy_phy_read(dev, 0x0811) | 0x0030);
475 b43legacy_phy_write(dev, 0x0812,
476 b43legacy_phy_read(dev, 0x0812) | 0x0030);
477 b43legacy_phy_write(dev, 0x005A, 0x0480);
478 b43legacy_phy_write(dev, 0x0059, 0x0810);
479 b43legacy_phy_write(dev, 0x0058, 0x000D);
480 if (phy->analog == 0)
481 b43legacy_phy_write(dev, 0x0003, 0x0122);
482 else
483 b43legacy_phy_write(dev, 0x000A,
484 b43legacy_phy_read(dev, 0x000A)
485 | 0x2000);
486 b43legacy_phy_write(dev, 0x0814,
487 b43legacy_phy_read(dev, 0x0814) | 0x0004);
488 b43legacy_phy_write(dev, 0x0815,
489 b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
490 b43legacy_phy_write(dev, 0x0003,
491 (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)
492 | 0x0040);
493 b43legacy_radio_write16(dev, 0x007A,
494 b43legacy_radio_read16(dev, 0x007A)
495 | 0x000F);
496 b43legacy_set_all_gains(dev, 3, 0, 1);
497 b43legacy_radio_write16(dev, 0x0043,
498 (b43legacy_radio_read16(dev, 0x0043)
499 & 0x00F0) | 0x000F);
500 udelay(30);
501 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
502 if (v47F >= 0x20)
503 v47F -= 0x40;
504 if (v47F == -32) {
505 for (i = 0; i < 4; i++) {
506 b43legacy_radio_write16(dev, 0x007B, i);
507 udelay(20);
508 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>
509 8) & 0x003F);
510 if (v47F >= 0x20)
511 v47F -= 0x40;
512 if (v47F > -31 && saved == 0xFFFF)
513 saved = i;
515 if (saved == 0xFFFF)
516 saved = 3;
517 } else
518 saved = 0;
520 b43legacy_radio_write16(dev, 0x007B, saved);
522 if (phy->rev >= 6) {
523 b43legacy_phy_write(dev, 0x002E, backup[12]);
524 b43legacy_phy_write(dev, 0x002F, backup[13]);
525 b43legacy_phy_write(dev, 0x080F, backup[14]);
526 b43legacy_phy_write(dev, 0x0810, backup[15]);
528 b43legacy_phy_write(dev, 0x0814, backup[3]);
529 b43legacy_phy_write(dev, 0x0815, backup[4]);
530 b43legacy_phy_write(dev, 0x005A, backup[5]);
531 b43legacy_phy_write(dev, 0x0059, backup[6]);
532 b43legacy_phy_write(dev, 0x0058, backup[7]);
533 b43legacy_phy_write(dev, 0x000A, backup[8]);
534 b43legacy_phy_write(dev, 0x0003, backup[9]);
535 b43legacy_radio_write16(dev, 0x0043, backup[11]);
536 b43legacy_radio_write16(dev, 0x007A, backup[10]);
537 b43legacy_phy_write(dev, 0x0802,
538 b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);
539 b43legacy_phy_write(dev, 0x0429,
540 b43legacy_phy_read(dev, 0x0429) | 0x8000);
541 b43legacy_set_original_gains(dev);
542 if (phy->rev >= 6) {
543 b43legacy_phy_write(dev, 0x0801, backup[16]);
544 b43legacy_phy_write(dev, 0x0060, backup[17]);
545 b43legacy_phy_write(dev, 0x0014, backup[18]);
546 b43legacy_phy_write(dev, 0x0478, backup[19]);
548 b43legacy_phy_write(dev, 0x0001, backup[0]);
549 b43legacy_phy_write(dev, 0x0812, backup[2]);
550 b43legacy_phy_write(dev, 0x0811, backup[1]);
553 void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev)
555 struct b43legacy_phy *phy = &dev->phy;
556 u16 backup[18] = { 0 };
557 u16 tmp;
558 s16 nrssi0;
559 s16 nrssi1;
561 switch (phy->type) {
562 case B43legacy_PHYTYPE_B:
563 backup[0] = b43legacy_radio_read16(dev, 0x007A);
564 backup[1] = b43legacy_radio_read16(dev, 0x0052);
565 backup[2] = b43legacy_radio_read16(dev, 0x0043);
566 backup[3] = b43legacy_phy_read(dev, 0x0030);
567 backup[4] = b43legacy_phy_read(dev, 0x0026);
568 backup[5] = b43legacy_phy_read(dev, 0x0015);
569 backup[6] = b43legacy_phy_read(dev, 0x002A);
570 backup[7] = b43legacy_phy_read(dev, 0x0020);
571 backup[8] = b43legacy_phy_read(dev, 0x005A);
572 backup[9] = b43legacy_phy_read(dev, 0x0059);
573 backup[10] = b43legacy_phy_read(dev, 0x0058);
574 backup[11] = b43legacy_read16(dev, 0x03E2);
575 backup[12] = b43legacy_read16(dev, 0x03E6);
576 backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
578 tmp = b43legacy_radio_read16(dev, 0x007A);
579 tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
580 b43legacy_radio_write16(dev, 0x007A, tmp);
581 b43legacy_phy_write(dev, 0x0030, 0x00FF);
582 b43legacy_write16(dev, 0x03EC, 0x7F7F);
583 b43legacy_phy_write(dev, 0x0026, 0x0000);
584 b43legacy_phy_write(dev, 0x0015,
585 b43legacy_phy_read(dev, 0x0015) | 0x0020);
586 b43legacy_phy_write(dev, 0x002A, 0x08A3);
587 b43legacy_radio_write16(dev, 0x007A,
588 b43legacy_radio_read16(dev, 0x007A)
589 | 0x0080);
591 nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027);
592 b43legacy_radio_write16(dev, 0x007A,
593 b43legacy_radio_read16(dev, 0x007A)
594 & 0x007F);
595 if (phy->analog >= 2)
596 b43legacy_write16(dev, 0x03E6, 0x0040);
597 else if (phy->analog == 0)
598 b43legacy_write16(dev, 0x03E6, 0x0122);
599 else
600 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
601 b43legacy_read16(dev,
602 B43legacy_MMIO_CHANNEL_EXT) & 0x2000);
603 b43legacy_phy_write(dev, 0x0020, 0x3F3F);
604 b43legacy_phy_write(dev, 0x0015, 0xF330);
605 b43legacy_radio_write16(dev, 0x005A, 0x0060);
606 b43legacy_radio_write16(dev, 0x0043,
607 b43legacy_radio_read16(dev, 0x0043)
608 & 0x00F0);
609 b43legacy_phy_write(dev, 0x005A, 0x0480);
610 b43legacy_phy_write(dev, 0x0059, 0x0810);
611 b43legacy_phy_write(dev, 0x0058, 0x000D);
612 udelay(20);
614 nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);
615 b43legacy_phy_write(dev, 0x0030, backup[3]);
616 b43legacy_radio_write16(dev, 0x007A, backup[0]);
617 b43legacy_write16(dev, 0x03E2, backup[11]);
618 b43legacy_phy_write(dev, 0x0026, backup[4]);
619 b43legacy_phy_write(dev, 0x0015, backup[5]);
620 b43legacy_phy_write(dev, 0x002A, backup[6]);
621 b43legacy_synth_pu_workaround(dev, phy->channel);
622 if (phy->analog != 0)
623 b43legacy_write16(dev, 0x03F4, backup[13]);
625 b43legacy_phy_write(dev, 0x0020, backup[7]);
626 b43legacy_phy_write(dev, 0x005A, backup[8]);
627 b43legacy_phy_write(dev, 0x0059, backup[9]);
628 b43legacy_phy_write(dev, 0x0058, backup[10]);
629 b43legacy_radio_write16(dev, 0x0052, backup[1]);
630 b43legacy_radio_write16(dev, 0x0043, backup[2]);
632 if (nrssi0 == nrssi1)
633 phy->nrssislope = 0x00010000;
634 else
635 phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
637 if (nrssi0 <= -4) {
638 phy->nrssi[0] = nrssi0;
639 phy->nrssi[1] = nrssi1;
641 break;
642 case B43legacy_PHYTYPE_G:
643 if (phy->radio_rev >= 9)
644 return;
645 if (phy->radio_rev == 8)
646 b43legacy_calc_nrssi_offset(dev);
648 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
649 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
650 & 0x7FFF);
651 b43legacy_phy_write(dev, 0x0802,
652 b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
653 backup[7] = b43legacy_read16(dev, 0x03E2);
654 b43legacy_write16(dev, 0x03E2,
655 b43legacy_read16(dev, 0x03E2) | 0x8000);
656 backup[0] = b43legacy_radio_read16(dev, 0x007A);
657 backup[1] = b43legacy_radio_read16(dev, 0x0052);
658 backup[2] = b43legacy_radio_read16(dev, 0x0043);
659 backup[3] = b43legacy_phy_read(dev, 0x0015);
660 backup[4] = b43legacy_phy_read(dev, 0x005A);
661 backup[5] = b43legacy_phy_read(dev, 0x0059);
662 backup[6] = b43legacy_phy_read(dev, 0x0058);
663 backup[8] = b43legacy_read16(dev, 0x03E6);
664 backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
665 if (phy->rev >= 3) {
666 backup[10] = b43legacy_phy_read(dev, 0x002E);
667 backup[11] = b43legacy_phy_read(dev, 0x002F);
668 backup[12] = b43legacy_phy_read(dev, 0x080F);
669 backup[13] = b43legacy_phy_read(dev,
670 B43legacy_PHY_G_LO_CONTROL);
671 backup[14] = b43legacy_phy_read(dev, 0x0801);
672 backup[15] = b43legacy_phy_read(dev, 0x0060);
673 backup[16] = b43legacy_phy_read(dev, 0x0014);
674 backup[17] = b43legacy_phy_read(dev, 0x0478);
675 b43legacy_phy_write(dev, 0x002E, 0);
676 b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);
677 switch (phy->rev) {
678 case 4: case 6: case 7:
679 b43legacy_phy_write(dev, 0x0478,
680 b43legacy_phy_read(dev,
681 0x0478) | 0x0100);
682 b43legacy_phy_write(dev, 0x0801,
683 b43legacy_phy_read(dev,
684 0x0801) | 0x0040);
685 break;
686 case 3: case 5:
687 b43legacy_phy_write(dev, 0x0801,
688 b43legacy_phy_read(dev,
689 0x0801) & 0xFFBF);
690 break;
692 b43legacy_phy_write(dev, 0x0060,
693 b43legacy_phy_read(dev, 0x0060)
694 | 0x0040);
695 b43legacy_phy_write(dev, 0x0014,
696 b43legacy_phy_read(dev, 0x0014)
697 | 0x0200);
699 b43legacy_radio_write16(dev, 0x007A,
700 b43legacy_radio_read16(dev, 0x007A)
701 | 0x0070);
702 b43legacy_set_all_gains(dev, 0, 8, 0);
703 b43legacy_radio_write16(dev, 0x007A,
704 b43legacy_radio_read16(dev, 0x007A)
705 & 0x00F7);
706 if (phy->rev >= 2) {
707 b43legacy_phy_write(dev, 0x0811,
708 (b43legacy_phy_read(dev, 0x0811)
709 & 0xFFCF) | 0x0030);
710 b43legacy_phy_write(dev, 0x0812,
711 (b43legacy_phy_read(dev, 0x0812)
712 & 0xFFCF) | 0x0010);
714 b43legacy_radio_write16(dev, 0x007A,
715 b43legacy_radio_read16(dev, 0x007A)
716 | 0x0080);
717 udelay(20);
719 nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
720 if (nrssi0 >= 0x0020)
721 nrssi0 -= 0x0040;
723 b43legacy_radio_write16(dev, 0x007A,
724 b43legacy_radio_read16(dev, 0x007A)
725 & 0x007F);
726 if (phy->analog >= 2)
727 b43legacy_phy_write(dev, 0x0003,
728 (b43legacy_phy_read(dev, 0x0003)
729 & 0xFF9F) | 0x0040);
731 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
732 b43legacy_read16(dev,
733 B43legacy_MMIO_CHANNEL_EXT) | 0x2000);
734 b43legacy_radio_write16(dev, 0x007A,
735 b43legacy_radio_read16(dev, 0x007A)
736 | 0x000F);
737 b43legacy_phy_write(dev, 0x0015, 0xF330);
738 if (phy->rev >= 2) {
739 b43legacy_phy_write(dev, 0x0812,
740 (b43legacy_phy_read(dev, 0x0812)
741 & 0xFFCF) | 0x0020);
742 b43legacy_phy_write(dev, 0x0811,
743 (b43legacy_phy_read(dev, 0x0811)
744 & 0xFFCF) | 0x0020);
747 b43legacy_set_all_gains(dev, 3, 0, 1);
748 if (phy->radio_rev == 8)
749 b43legacy_radio_write16(dev, 0x0043, 0x001F);
750 else {
751 tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;
752 b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);
753 tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;
754 b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);
756 b43legacy_phy_write(dev, 0x005A, 0x0480);
757 b43legacy_phy_write(dev, 0x0059, 0x0810);
758 b43legacy_phy_write(dev, 0x0058, 0x000D);
759 udelay(20);
760 nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
761 if (nrssi1 >= 0x0020)
762 nrssi1 -= 0x0040;
763 if (nrssi0 == nrssi1)
764 phy->nrssislope = 0x00010000;
765 else
766 phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
767 if (nrssi0 >= -4) {
768 phy->nrssi[0] = nrssi1;
769 phy->nrssi[1] = nrssi0;
771 if (phy->rev >= 3) {
772 b43legacy_phy_write(dev, 0x002E, backup[10]);
773 b43legacy_phy_write(dev, 0x002F, backup[11]);
774 b43legacy_phy_write(dev, 0x080F, backup[12]);
775 b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,
776 backup[13]);
778 if (phy->rev >= 2) {
779 b43legacy_phy_write(dev, 0x0812,
780 b43legacy_phy_read(dev, 0x0812)
781 & 0xFFCF);
782 b43legacy_phy_write(dev, 0x0811,
783 b43legacy_phy_read(dev, 0x0811)
784 & 0xFFCF);
787 b43legacy_radio_write16(dev, 0x007A, backup[0]);
788 b43legacy_radio_write16(dev, 0x0052, backup[1]);
789 b43legacy_radio_write16(dev, 0x0043, backup[2]);
790 b43legacy_write16(dev, 0x03E2, backup[7]);
791 b43legacy_write16(dev, 0x03E6, backup[8]);
792 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);
793 b43legacy_phy_write(dev, 0x0015, backup[3]);
794 b43legacy_phy_write(dev, 0x005A, backup[4]);
795 b43legacy_phy_write(dev, 0x0059, backup[5]);
796 b43legacy_phy_write(dev, 0x0058, backup[6]);
797 b43legacy_synth_pu_workaround(dev, phy->channel);
798 b43legacy_phy_write(dev, 0x0802,
799 b43legacy_phy_read(dev, 0x0802) | 0x0003);
800 b43legacy_set_original_gains(dev);
801 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
802 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
803 | 0x8000);
804 if (phy->rev >= 3) {
805 b43legacy_phy_write(dev, 0x0801, backup[14]);
806 b43legacy_phy_write(dev, 0x0060, backup[15]);
807 b43legacy_phy_write(dev, 0x0014, backup[16]);
808 b43legacy_phy_write(dev, 0x0478, backup[17]);
810 b43legacy_nrssi_mem_update(dev);
811 b43legacy_calc_nrssi_threshold(dev);
812 break;
813 default:
814 B43legacy_BUG_ON(1);
818 void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
820 struct b43legacy_phy *phy = &dev->phy;
821 s32 threshold;
822 s32 a;
823 s32 b;
824 s16 tmp16;
825 u16 tmp_u16;
827 switch (phy->type) {
828 case B43legacy_PHYTYPE_B: {
829 if (phy->radio_ver != 0x2050)
830 return;
831 if (!(dev->dev->bus->sprom.boardflags_lo &
832 B43legacy_BFL_RSSI))
833 return;
835 if (phy->radio_rev >= 6) {
836 threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32;
837 threshold += 20 * (phy->nrssi[0] + 1);
838 threshold /= 40;
839 } else
840 threshold = phy->nrssi[1] - 5;
842 threshold = clamp_val(threshold, 0, 0x3E);
843 b43legacy_phy_read(dev, 0x0020); /* dummy read */
844 b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
845 | 0x001C);
847 if (phy->radio_rev >= 6) {
848 b43legacy_phy_write(dev, 0x0087, 0x0E0D);
849 b43legacy_phy_write(dev, 0x0086, 0x0C0B);
850 b43legacy_phy_write(dev, 0x0085, 0x0A09);
851 b43legacy_phy_write(dev, 0x0084, 0x0808);
852 b43legacy_phy_write(dev, 0x0083, 0x0808);
853 b43legacy_phy_write(dev, 0x0082, 0x0604);
854 b43legacy_phy_write(dev, 0x0081, 0x0302);
855 b43legacy_phy_write(dev, 0x0080, 0x0100);
857 break;
859 case B43legacy_PHYTYPE_G:
860 if (!phy->gmode ||
861 !(dev->dev->bus->sprom.boardflags_lo &
862 B43legacy_BFL_RSSI)) {
863 tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
864 if (tmp16 >= 0x20)
865 tmp16 -= 0x40;
866 if (tmp16 < 3)
867 b43legacy_phy_write(dev, 0x048A,
868 (b43legacy_phy_read(dev,
869 0x048A) & 0xF000) | 0x09EB);
870 else
871 b43legacy_phy_write(dev, 0x048A,
872 (b43legacy_phy_read(dev,
873 0x048A) & 0xF000) | 0x0AED);
874 } else {
875 if (phy->interfmode ==
876 B43legacy_RADIO_INTERFMODE_NONWLAN) {
877 a = 0xE;
878 b = 0xA;
879 } else if (!phy->aci_wlan_automatic &&
880 phy->aci_enable) {
881 a = 0x13;
882 b = 0x12;
883 } else {
884 a = 0xE;
885 b = 0x11;
888 a = a * (phy->nrssi[1] - phy->nrssi[0]);
889 a += (phy->nrssi[0] << 6);
890 if (a < 32)
891 a += 31;
892 else
893 a += 32;
894 a = a >> 6;
895 a = clamp_val(a, -31, 31);
897 b = b * (phy->nrssi[1] - phy->nrssi[0]);
898 b += (phy->nrssi[0] << 6);
899 if (b < 32)
900 b += 31;
901 else
902 b += 32;
903 b = b >> 6;
904 b = clamp_val(b, -31, 31);
906 tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
907 tmp_u16 |= ((u32)b & 0x0000003F);
908 tmp_u16 |= (((u32)a & 0x0000003F) << 6);
909 b43legacy_phy_write(dev, 0x048A, tmp_u16);
911 break;
912 default:
913 B43legacy_BUG_ON(1);
917 /* Stack implementation to save/restore values from the
918 * interference mitigation code.
919 * It is save to restore values in random order.
921 static void _stack_save(u32 *_stackptr, size_t *stackidx,
922 u8 id, u16 offset, u16 value)
924 u32 *stackptr = &(_stackptr[*stackidx]);
926 B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
927 B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
928 *stackptr = offset;
929 *stackptr |= ((u32)id) << 13;
930 *stackptr |= ((u32)value) << 16;
931 (*stackidx)++;
932 B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE));
935 static u16 _stack_restore(u32 *stackptr,
936 u8 id, u16 offset)
938 size_t i;
940 B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
941 B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
942 for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) {
943 if ((*stackptr & 0x00001FFF) != offset)
944 continue;
945 if (((*stackptr & 0x00007000) >> 13) != id)
946 continue;
947 return ((*stackptr & 0xFFFF0000) >> 16);
949 B43legacy_BUG_ON(1);
951 return 0;
954 #define phy_stacksave(offset) \
955 do { \
956 _stack_save(stack, &stackidx, 0x1, (offset), \
957 b43legacy_phy_read(dev, (offset))); \
958 } while (0)
959 #define phy_stackrestore(offset) \
960 do { \
961 b43legacy_phy_write(dev, (offset), \
962 _stack_restore(stack, 0x1, \
963 (offset))); \
964 } while (0)
965 #define radio_stacksave(offset) \
966 do { \
967 _stack_save(stack, &stackidx, 0x2, (offset), \
968 b43legacy_radio_read16(dev, (offset))); \
969 } while (0)
970 #define radio_stackrestore(offset) \
971 do { \
972 b43legacy_radio_write16(dev, (offset), \
973 _stack_restore(stack, 0x2, \
974 (offset))); \
975 } while (0)
976 #define ilt_stacksave(offset) \
977 do { \
978 _stack_save(stack, &stackidx, 0x3, (offset), \
979 b43legacy_ilt_read(dev, (offset))); \
980 } while (0)
981 #define ilt_stackrestore(offset) \
982 do { \
983 b43legacy_ilt_write(dev, (offset), \
984 _stack_restore(stack, 0x3, \
985 (offset))); \
986 } while (0)
988 static void
989 b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev,
990 int mode)
992 struct b43legacy_phy *phy = &dev->phy;
993 u16 tmp;
994 u16 flipped;
995 u32 tmp32;
996 size_t stackidx = 0;
997 u32 *stack = phy->interfstack;
999 switch (mode) {
1000 case B43legacy_RADIO_INTERFMODE_NONWLAN:
1001 if (phy->rev != 1) {
1002 b43legacy_phy_write(dev, 0x042B,
1003 b43legacy_phy_read(dev, 0x042B)
1004 | 0x0800);
1005 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1006 b43legacy_phy_read(dev,
1007 B43legacy_PHY_G_CRS) & ~0x4000);
1008 break;
1010 radio_stacksave(0x0078);
1011 tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E);
1012 flipped = flip_4bit(tmp);
1013 if (flipped < 10 && flipped >= 8)
1014 flipped = 7;
1015 else if (flipped >= 10)
1016 flipped -= 3;
1017 flipped = flip_4bit(flipped);
1018 flipped = (flipped << 1) | 0x0020;
1019 b43legacy_radio_write16(dev, 0x0078, flipped);
1021 b43legacy_calc_nrssi_threshold(dev);
1023 phy_stacksave(0x0406);
1024 b43legacy_phy_write(dev, 0x0406, 0x7E28);
1026 b43legacy_phy_write(dev, 0x042B,
1027 b43legacy_phy_read(dev, 0x042B) | 0x0800);
1028 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1029 b43legacy_phy_read(dev,
1030 B43legacy_PHY_RADIO_BITFIELD) | 0x1000);
1032 phy_stacksave(0x04A0);
1033 b43legacy_phy_write(dev, 0x04A0,
1034 (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0)
1035 | 0x0008);
1036 phy_stacksave(0x04A1);
1037 b43legacy_phy_write(dev, 0x04A1,
1038 (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0)
1039 | 0x0605);
1040 phy_stacksave(0x04A2);
1041 b43legacy_phy_write(dev, 0x04A2,
1042 (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0)
1043 | 0x0204);
1044 phy_stacksave(0x04A8);
1045 b43legacy_phy_write(dev, 0x04A8,
1046 (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0)
1047 | 0x0803);
1048 phy_stacksave(0x04AB);
1049 b43legacy_phy_write(dev, 0x04AB,
1050 (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0)
1051 | 0x0605);
1053 phy_stacksave(0x04A7);
1054 b43legacy_phy_write(dev, 0x04A7, 0x0002);
1055 phy_stacksave(0x04A3);
1056 b43legacy_phy_write(dev, 0x04A3, 0x287A);
1057 phy_stacksave(0x04A9);
1058 b43legacy_phy_write(dev, 0x04A9, 0x2027);
1059 phy_stacksave(0x0493);
1060 b43legacy_phy_write(dev, 0x0493, 0x32F5);
1061 phy_stacksave(0x04AA);
1062 b43legacy_phy_write(dev, 0x04AA, 0x2027);
1063 phy_stacksave(0x04AC);
1064 b43legacy_phy_write(dev, 0x04AC, 0x32F5);
1065 break;
1066 case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1067 if (b43legacy_phy_read(dev, 0x0033) & 0x0800)
1068 break;
1070 phy->aci_enable = true;
1072 phy_stacksave(B43legacy_PHY_RADIO_BITFIELD);
1073 phy_stacksave(B43legacy_PHY_G_CRS);
1074 if (phy->rev < 2)
1075 phy_stacksave(0x0406);
1076 else {
1077 phy_stacksave(0x04C0);
1078 phy_stacksave(0x04C1);
1080 phy_stacksave(0x0033);
1081 phy_stacksave(0x04A7);
1082 phy_stacksave(0x04A3);
1083 phy_stacksave(0x04A9);
1084 phy_stacksave(0x04AA);
1085 phy_stacksave(0x04AC);
1086 phy_stacksave(0x0493);
1087 phy_stacksave(0x04A1);
1088 phy_stacksave(0x04A0);
1089 phy_stacksave(0x04A2);
1090 phy_stacksave(0x048A);
1091 phy_stacksave(0x04A8);
1092 phy_stacksave(0x04AB);
1093 if (phy->rev == 2) {
1094 phy_stacksave(0x04AD);
1095 phy_stacksave(0x04AE);
1096 } else if (phy->rev >= 3) {
1097 phy_stacksave(0x04AD);
1098 phy_stacksave(0x0415);
1099 phy_stacksave(0x0416);
1100 phy_stacksave(0x0417);
1101 ilt_stacksave(0x1A00 + 0x2);
1102 ilt_stacksave(0x1A00 + 0x3);
1104 phy_stacksave(0x042B);
1105 phy_stacksave(0x048C);
1107 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1108 b43legacy_phy_read(dev,
1109 B43legacy_PHY_RADIO_BITFIELD) & ~0x1000);
1110 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1111 (b43legacy_phy_read(dev,
1112 B43legacy_PHY_G_CRS)
1113 & 0xFFFC) | 0x0002);
1115 b43legacy_phy_write(dev, 0x0033, 0x0800);
1116 b43legacy_phy_write(dev, 0x04A3, 0x2027);
1117 b43legacy_phy_write(dev, 0x04A9, 0x1CA8);
1118 b43legacy_phy_write(dev, 0x0493, 0x287A);
1119 b43legacy_phy_write(dev, 0x04AA, 0x1CA8);
1120 b43legacy_phy_write(dev, 0x04AC, 0x287A);
1122 b43legacy_phy_write(dev, 0x04A0,
1123 (b43legacy_phy_read(dev, 0x04A0)
1124 & 0xFFC0) | 0x001A);
1125 b43legacy_phy_write(dev, 0x04A7, 0x000D);
1127 if (phy->rev < 2)
1128 b43legacy_phy_write(dev, 0x0406, 0xFF0D);
1129 else if (phy->rev == 2) {
1130 b43legacy_phy_write(dev, 0x04C0, 0xFFFF);
1131 b43legacy_phy_write(dev, 0x04C1, 0x00A9);
1132 } else {
1133 b43legacy_phy_write(dev, 0x04C0, 0x00C1);
1134 b43legacy_phy_write(dev, 0x04C1, 0x0059);
1137 b43legacy_phy_write(dev, 0x04A1,
1138 (b43legacy_phy_read(dev, 0x04A1)
1139 & 0xC0FF) | 0x1800);
1140 b43legacy_phy_write(dev, 0x04A1,
1141 (b43legacy_phy_read(dev, 0x04A1)
1142 & 0xFFC0) | 0x0015);
1143 b43legacy_phy_write(dev, 0x04A8,
1144 (b43legacy_phy_read(dev, 0x04A8)
1145 & 0xCFFF) | 0x1000);
1146 b43legacy_phy_write(dev, 0x04A8,
1147 (b43legacy_phy_read(dev, 0x04A8)
1148 & 0xF0FF) | 0x0A00);
1149 b43legacy_phy_write(dev, 0x04AB,
1150 (b43legacy_phy_read(dev, 0x04AB)
1151 & 0xCFFF) | 0x1000);
1152 b43legacy_phy_write(dev, 0x04AB,
1153 (b43legacy_phy_read(dev, 0x04AB)
1154 & 0xF0FF) | 0x0800);
1155 b43legacy_phy_write(dev, 0x04AB,
1156 (b43legacy_phy_read(dev, 0x04AB)
1157 & 0xFFCF) | 0x0010);
1158 b43legacy_phy_write(dev, 0x04AB,
1159 (b43legacy_phy_read(dev, 0x04AB)
1160 & 0xFFF0) | 0x0005);
1161 b43legacy_phy_write(dev, 0x04A8,
1162 (b43legacy_phy_read(dev, 0x04A8)
1163 & 0xFFCF) | 0x0010);
1164 b43legacy_phy_write(dev, 0x04A8,
1165 (b43legacy_phy_read(dev, 0x04A8)
1166 & 0xFFF0) | 0x0006);
1167 b43legacy_phy_write(dev, 0x04A2,
1168 (b43legacy_phy_read(dev, 0x04A2)
1169 & 0xF0FF) | 0x0800);
1170 b43legacy_phy_write(dev, 0x04A0,
1171 (b43legacy_phy_read(dev, 0x04A0)
1172 & 0xF0FF) | 0x0500);
1173 b43legacy_phy_write(dev, 0x04A2,
1174 (b43legacy_phy_read(dev, 0x04A2)
1175 & 0xFFF0) | 0x000B);
1177 if (phy->rev >= 3) {
1178 b43legacy_phy_write(dev, 0x048A,
1179 b43legacy_phy_read(dev, 0x048A)
1180 & ~0x8000);
1181 b43legacy_phy_write(dev, 0x0415,
1182 (b43legacy_phy_read(dev, 0x0415)
1183 & 0x8000) | 0x36D8);
1184 b43legacy_phy_write(dev, 0x0416,
1185 (b43legacy_phy_read(dev, 0x0416)
1186 & 0x8000) | 0x36D8);
1187 b43legacy_phy_write(dev, 0x0417,
1188 (b43legacy_phy_read(dev, 0x0417)
1189 & 0xFE00) | 0x016D);
1190 } else {
1191 b43legacy_phy_write(dev, 0x048A,
1192 b43legacy_phy_read(dev, 0x048A)
1193 | 0x1000);
1194 b43legacy_phy_write(dev, 0x048A,
1195 (b43legacy_phy_read(dev, 0x048A)
1196 & 0x9FFF) | 0x2000);
1197 tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
1198 B43legacy_UCODEFLAGS_OFFSET);
1199 if (!(tmp32 & 0x800)) {
1200 tmp32 |= 0x800;
1201 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1202 B43legacy_UCODEFLAGS_OFFSET,
1203 tmp32);
1206 if (phy->rev >= 2)
1207 b43legacy_phy_write(dev, 0x042B,
1208 b43legacy_phy_read(dev, 0x042B)
1209 | 0x0800);
1210 b43legacy_phy_write(dev, 0x048C,
1211 (b43legacy_phy_read(dev, 0x048C)
1212 & 0xF0FF) | 0x0200);
1213 if (phy->rev == 2) {
1214 b43legacy_phy_write(dev, 0x04AE,
1215 (b43legacy_phy_read(dev, 0x04AE)
1216 & 0xFF00) | 0x007F);
1217 b43legacy_phy_write(dev, 0x04AD,
1218 (b43legacy_phy_read(dev, 0x04AD)
1219 & 0x00FF) | 0x1300);
1220 } else if (phy->rev >= 6) {
1221 b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F);
1222 b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F);
1223 b43legacy_phy_write(dev, 0x04AD,
1224 b43legacy_phy_read(dev, 0x04AD)
1225 & 0x00FF);
1227 b43legacy_calc_nrssi_slope(dev);
1228 break;
1229 default:
1230 B43legacy_BUG_ON(1);
1234 static void
1235 b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,
1236 int mode)
1238 struct b43legacy_phy *phy = &dev->phy;
1239 u32 tmp32;
1240 u32 *stack = phy->interfstack;
1242 switch (mode) {
1243 case B43legacy_RADIO_INTERFMODE_NONWLAN:
1244 if (phy->rev != 1) {
1245 b43legacy_phy_write(dev, 0x042B,
1246 b43legacy_phy_read(dev, 0x042B)
1247 & ~0x0800);
1248 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1249 b43legacy_phy_read(dev,
1250 B43legacy_PHY_G_CRS) | 0x4000);
1251 break;
1253 phy_stackrestore(0x0078);
1254 b43legacy_calc_nrssi_threshold(dev);
1255 phy_stackrestore(0x0406);
1256 b43legacy_phy_write(dev, 0x042B,
1257 b43legacy_phy_read(dev, 0x042B) & ~0x0800);
1258 if (!dev->bad_frames_preempt)
1259 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1260 b43legacy_phy_read(dev,
1261 B43legacy_PHY_RADIO_BITFIELD)
1262 & ~(1 << 11));
1263 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1264 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
1265 | 0x4000);
1266 phy_stackrestore(0x04A0);
1267 phy_stackrestore(0x04A1);
1268 phy_stackrestore(0x04A2);
1269 phy_stackrestore(0x04A8);
1270 phy_stackrestore(0x04AB);
1271 phy_stackrestore(0x04A7);
1272 phy_stackrestore(0x04A3);
1273 phy_stackrestore(0x04A9);
1274 phy_stackrestore(0x0493);
1275 phy_stackrestore(0x04AA);
1276 phy_stackrestore(0x04AC);
1277 break;
1278 case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1279 if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))
1280 break;
1282 phy->aci_enable = false;
1284 phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);
1285 phy_stackrestore(B43legacy_PHY_G_CRS);
1286 phy_stackrestore(0x0033);
1287 phy_stackrestore(0x04A3);
1288 phy_stackrestore(0x04A9);
1289 phy_stackrestore(0x0493);
1290 phy_stackrestore(0x04AA);
1291 phy_stackrestore(0x04AC);
1292 phy_stackrestore(0x04A0);
1293 phy_stackrestore(0x04A7);
1294 if (phy->rev >= 2) {
1295 phy_stackrestore(0x04C0);
1296 phy_stackrestore(0x04C1);
1297 } else
1298 phy_stackrestore(0x0406);
1299 phy_stackrestore(0x04A1);
1300 phy_stackrestore(0x04AB);
1301 phy_stackrestore(0x04A8);
1302 if (phy->rev == 2) {
1303 phy_stackrestore(0x04AD);
1304 phy_stackrestore(0x04AE);
1305 } else if (phy->rev >= 3) {
1306 phy_stackrestore(0x04AD);
1307 phy_stackrestore(0x0415);
1308 phy_stackrestore(0x0416);
1309 phy_stackrestore(0x0417);
1310 ilt_stackrestore(0x1A00 + 0x2);
1311 ilt_stackrestore(0x1A00 + 0x3);
1313 phy_stackrestore(0x04A2);
1314 phy_stackrestore(0x04A8);
1315 phy_stackrestore(0x042B);
1316 phy_stackrestore(0x048C);
1317 tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
1318 B43legacy_UCODEFLAGS_OFFSET);
1319 if (tmp32 & 0x800) {
1320 tmp32 &= ~0x800;
1321 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1322 B43legacy_UCODEFLAGS_OFFSET,
1323 tmp32);
1325 b43legacy_calc_nrssi_slope(dev);
1326 break;
1327 default:
1328 B43legacy_BUG_ON(1);
1332 #undef phy_stacksave
1333 #undef phy_stackrestore
1334 #undef radio_stacksave
1335 #undef radio_stackrestore
1336 #undef ilt_stacksave
1337 #undef ilt_stackrestore
1339 int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
1340 int mode)
1342 struct b43legacy_phy *phy = &dev->phy;
1343 int currentmode;
1345 if ((phy->type != B43legacy_PHYTYPE_G) ||
1346 (phy->rev == 0) || (!phy->gmode))
1347 return -ENODEV;
1349 phy->aci_wlan_automatic = false;
1350 switch (mode) {
1351 case B43legacy_RADIO_INTERFMODE_AUTOWLAN:
1352 phy->aci_wlan_automatic = true;
1353 if (phy->aci_enable)
1354 mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN;
1355 else
1356 mode = B43legacy_RADIO_INTERFMODE_NONE;
1357 break;
1358 case B43legacy_RADIO_INTERFMODE_NONE:
1359 case B43legacy_RADIO_INTERFMODE_NONWLAN:
1360 case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1361 break;
1362 default:
1363 return -EINVAL;
1366 currentmode = phy->interfmode;
1367 if (currentmode == mode)
1368 return 0;
1369 if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)
1370 b43legacy_radio_interference_mitigation_disable(dev,
1371 currentmode);
1373 if (mode == B43legacy_RADIO_INTERFMODE_NONE) {
1374 phy->aci_enable = false;
1375 phy->aci_hw_rssi = false;
1376 } else
1377 b43legacy_radio_interference_mitigation_enable(dev, mode);
1378 phy->interfmode = mode;
1380 return 0;
1383 u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev)
1385 u16 reg;
1386 u16 index;
1387 u16 ret;
1389 reg = b43legacy_radio_read16(dev, 0x0060);
1390 index = (reg & 0x001E) >> 1;
1391 ret = rcc_table[index] << 1;
1392 ret |= (reg & 0x0001);
1393 ret |= 0x0020;
1395 return ret;
1398 #define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
1399 static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
1401 struct b43legacy_phy *phy = &dev->phy;
1402 u16 loop_or = 0;
1403 u16 adj_loopback_gain = phy->loopback_gain[0];
1404 u8 loop;
1405 u16 extern_lna_control;
1407 if (!phy->gmode)
1408 return 0;
1409 if (!has_loopback_gain(phy)) {
1410 if (phy->rev < 7 || !(dev->dev->bus->sprom.boardflags_lo
1411 & B43legacy_BFL_EXTLNA)) {
1412 switch (lpd) {
1413 case LPD(0, 1, 1):
1414 return 0x0FB2;
1415 case LPD(0, 0, 1):
1416 return 0x00B2;
1417 case LPD(1, 0, 1):
1418 return 0x30B2;
1419 case LPD(1, 0, 0):
1420 return 0x30B3;
1421 default:
1422 B43legacy_BUG_ON(1);
1424 } else {
1425 switch (lpd) {
1426 case LPD(0, 1, 1):
1427 return 0x8FB2;
1428 case LPD(0, 0, 1):
1429 return 0x80B2;
1430 case LPD(1, 0, 1):
1431 return 0x20B2;
1432 case LPD(1, 0, 0):
1433 return 0x20B3;
1434 default:
1435 B43legacy_BUG_ON(1);
1438 } else {
1439 if (phy->radio_rev == 8)
1440 adj_loopback_gain += 0x003E;
1441 else
1442 adj_loopback_gain += 0x0026;
1443 if (adj_loopback_gain >= 0x46) {
1444 adj_loopback_gain -= 0x46;
1445 extern_lna_control = 0x3000;
1446 } else if (adj_loopback_gain >= 0x3A) {
1447 adj_loopback_gain -= 0x3A;
1448 extern_lna_control = 0x2000;
1449 } else if (adj_loopback_gain >= 0x2E) {
1450 adj_loopback_gain -= 0x2E;
1451 extern_lna_control = 0x1000;
1452 } else {
1453 adj_loopback_gain -= 0x10;
1454 extern_lna_control = 0x0000;
1456 for (loop = 0; loop < 16; loop++) {
1457 u16 tmp = adj_loopback_gain - 6 * loop;
1458 if (tmp < 6)
1459 break;
1462 loop_or = (loop << 8) | extern_lna_control;
1463 if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo
1464 & B43legacy_BFL_EXTLNA) {
1465 if (extern_lna_control)
1466 loop_or |= 0x8000;
1467 switch (lpd) {
1468 case LPD(0, 1, 1):
1469 return 0x8F92;
1470 case LPD(0, 0, 1):
1471 return (0x8092 | loop_or);
1472 case LPD(1, 0, 1):
1473 return (0x2092 | loop_or);
1474 case LPD(1, 0, 0):
1475 return (0x2093 | loop_or);
1476 default:
1477 B43legacy_BUG_ON(1);
1479 } else {
1480 switch (lpd) {
1481 case LPD(0, 1, 1):
1482 return 0x0F92;
1483 case LPD(0, 0, 1):
1484 case LPD(1, 0, 1):
1485 return (0x0092 | loop_or);
1486 case LPD(1, 0, 0):
1487 return (0x0093 | loop_or);
1488 default:
1489 B43legacy_BUG_ON(1);
1493 return 0;
1496 u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)
1498 struct b43legacy_phy *phy = &dev->phy;
1499 u16 backup[21] = { 0 };
1500 u16 ret;
1501 u16 i;
1502 u16 j;
1503 u32 tmp1 = 0;
1504 u32 tmp2 = 0;
1506 backup[0] = b43legacy_radio_read16(dev, 0x0043);
1507 backup[14] = b43legacy_radio_read16(dev, 0x0051);
1508 backup[15] = b43legacy_radio_read16(dev, 0x0052);
1509 backup[1] = b43legacy_phy_read(dev, 0x0015);
1510 backup[16] = b43legacy_phy_read(dev, 0x005A);
1511 backup[17] = b43legacy_phy_read(dev, 0x0059);
1512 backup[18] = b43legacy_phy_read(dev, 0x0058);
1513 if (phy->type == B43legacy_PHYTYPE_B) {
1514 backup[2] = b43legacy_phy_read(dev, 0x0030);
1515 backup[3] = b43legacy_read16(dev, 0x03EC);
1516 b43legacy_phy_write(dev, 0x0030, 0x00FF);
1517 b43legacy_write16(dev, 0x03EC, 0x3F3F);
1518 } else {
1519 if (phy->gmode) {
1520 backup[4] = b43legacy_phy_read(dev, 0x0811);
1521 backup[5] = b43legacy_phy_read(dev, 0x0812);
1522 backup[6] = b43legacy_phy_read(dev, 0x0814);
1523 backup[7] = b43legacy_phy_read(dev, 0x0815);
1524 backup[8] = b43legacy_phy_read(dev,
1525 B43legacy_PHY_G_CRS);
1526 backup[9] = b43legacy_phy_read(dev, 0x0802);
1527 b43legacy_phy_write(dev, 0x0814,
1528 (b43legacy_phy_read(dev, 0x0814)
1529 | 0x0003));
1530 b43legacy_phy_write(dev, 0x0815,
1531 (b43legacy_phy_read(dev, 0x0815)
1532 & 0xFFFC));
1533 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1534 (b43legacy_phy_read(dev,
1535 B43legacy_PHY_G_CRS) & 0x7FFF));
1536 b43legacy_phy_write(dev, 0x0802,
1537 (b43legacy_phy_read(dev, 0x0802)
1538 & 0xFFFC));
1539 if (phy->rev > 1) { /* loopback gain enabled */
1540 backup[19] = b43legacy_phy_read(dev, 0x080F);
1541 backup[20] = b43legacy_phy_read(dev, 0x0810);
1542 if (phy->rev >= 3)
1543 b43legacy_phy_write(dev, 0x080F,
1544 0xC020);
1545 else
1546 b43legacy_phy_write(dev, 0x080F,
1547 0x8020);
1548 b43legacy_phy_write(dev, 0x0810, 0x0000);
1550 b43legacy_phy_write(dev, 0x0812,
1551 b43legacy_get_812_value(dev,
1552 LPD(0, 1, 1)));
1553 if (phy->rev < 7 ||
1554 !(dev->dev->bus->sprom.boardflags_lo
1555 & B43legacy_BFL_EXTLNA))
1556 b43legacy_phy_write(dev, 0x0811, 0x01B3);
1557 else
1558 b43legacy_phy_write(dev, 0x0811, 0x09B3);
1561 b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1562 (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)
1563 | 0x8000));
1564 backup[10] = b43legacy_phy_read(dev, 0x0035);
1565 b43legacy_phy_write(dev, 0x0035,
1566 (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));
1567 backup[11] = b43legacy_read16(dev, 0x03E6);
1568 backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
1570 /* Initialization */
1571 if (phy->analog == 0)
1572 b43legacy_write16(dev, 0x03E6, 0x0122);
1573 else {
1574 if (phy->analog >= 2)
1575 b43legacy_phy_write(dev, 0x0003,
1576 (b43legacy_phy_read(dev, 0x0003)
1577 & 0xFFBF) | 0x0040);
1578 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1579 (b43legacy_read16(dev,
1580 B43legacy_MMIO_CHANNEL_EXT) | 0x2000));
1583 ret = b43legacy_radio_calibrationvalue(dev);
1585 if (phy->type == B43legacy_PHYTYPE_B)
1586 b43legacy_radio_write16(dev, 0x0078, 0x0026);
1588 if (phy->gmode)
1589 b43legacy_phy_write(dev, 0x0812,
1590 b43legacy_get_812_value(dev,
1591 LPD(0, 1, 1)));
1592 b43legacy_phy_write(dev, 0x0015, 0xBFAF);
1593 b43legacy_phy_write(dev, 0x002B, 0x1403);
1594 if (phy->gmode)
1595 b43legacy_phy_write(dev, 0x0812,
1596 b43legacy_get_812_value(dev,
1597 LPD(0, 0, 1)));
1598 b43legacy_phy_write(dev, 0x0015, 0xBFA0);
1599 b43legacy_radio_write16(dev, 0x0051,
1600 (b43legacy_radio_read16(dev, 0x0051)
1601 | 0x0004));
1602 if (phy->radio_rev == 8)
1603 b43legacy_radio_write16(dev, 0x0043, 0x001F);
1604 else {
1605 b43legacy_radio_write16(dev, 0x0052, 0x0000);
1606 b43legacy_radio_write16(dev, 0x0043,
1607 (b43legacy_radio_read16(dev, 0x0043)
1608 & 0xFFF0) | 0x0009);
1610 b43legacy_phy_write(dev, 0x0058, 0x0000);
1612 for (i = 0; i < 16; i++) {
1613 b43legacy_phy_write(dev, 0x005A, 0x0480);
1614 b43legacy_phy_write(dev, 0x0059, 0xC810);
1615 b43legacy_phy_write(dev, 0x0058, 0x000D);
1616 if (phy->gmode)
1617 b43legacy_phy_write(dev, 0x0812,
1618 b43legacy_get_812_value(dev,
1619 LPD(1, 0, 1)));
1620 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1621 udelay(10);
1622 if (phy->gmode)
1623 b43legacy_phy_write(dev, 0x0812,
1624 b43legacy_get_812_value(dev,
1625 LPD(1, 0, 1)));
1626 b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1627 udelay(10);
1628 if (phy->gmode)
1629 b43legacy_phy_write(dev, 0x0812,
1630 b43legacy_get_812_value(dev,
1631 LPD(1, 0, 0)));
1632 b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1633 udelay(20);
1634 tmp1 += b43legacy_phy_read(dev, 0x002D);
1635 b43legacy_phy_write(dev, 0x0058, 0x0000);
1636 if (phy->gmode)
1637 b43legacy_phy_write(dev, 0x0812,
1638 b43legacy_get_812_value(dev,
1639 LPD(1, 0, 1)));
1640 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1643 tmp1++;
1644 tmp1 >>= 9;
1645 udelay(10);
1646 b43legacy_phy_write(dev, 0x0058, 0x0000);
1648 for (i = 0; i < 16; i++) {
1649 b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)
1650 | 0x0020);
1651 backup[13] = b43legacy_radio_read16(dev, 0x0078);
1652 udelay(10);
1653 for (j = 0; j < 16; j++) {
1654 b43legacy_phy_write(dev, 0x005A, 0x0D80);
1655 b43legacy_phy_write(dev, 0x0059, 0xC810);
1656 b43legacy_phy_write(dev, 0x0058, 0x000D);
1657 if (phy->gmode)
1658 b43legacy_phy_write(dev, 0x0812,
1659 b43legacy_get_812_value(dev,
1660 LPD(1, 0, 1)));
1661 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1662 udelay(10);
1663 if (phy->gmode)
1664 b43legacy_phy_write(dev, 0x0812,
1665 b43legacy_get_812_value(dev,
1666 LPD(1, 0, 1)));
1667 b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1668 udelay(10);
1669 if (phy->gmode)
1670 b43legacy_phy_write(dev, 0x0812,
1671 b43legacy_get_812_value(dev,
1672 LPD(1, 0, 0)));
1673 b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1674 udelay(10);
1675 tmp2 += b43legacy_phy_read(dev, 0x002D);
1676 b43legacy_phy_write(dev, 0x0058, 0x0000);
1677 if (phy->gmode)
1678 b43legacy_phy_write(dev, 0x0812,
1679 b43legacy_get_812_value(dev,
1680 LPD(1, 0, 1)));
1681 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1683 tmp2++;
1684 tmp2 >>= 8;
1685 if (tmp1 < tmp2)
1686 break;
1689 /* Restore the registers */
1690 b43legacy_phy_write(dev, 0x0015, backup[1]);
1691 b43legacy_radio_write16(dev, 0x0051, backup[14]);
1692 b43legacy_radio_write16(dev, 0x0052, backup[15]);
1693 b43legacy_radio_write16(dev, 0x0043, backup[0]);
1694 b43legacy_phy_write(dev, 0x005A, backup[16]);
1695 b43legacy_phy_write(dev, 0x0059, backup[17]);
1696 b43legacy_phy_write(dev, 0x0058, backup[18]);
1697 b43legacy_write16(dev, 0x03E6, backup[11]);
1698 if (phy->analog != 0)
1699 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);
1700 b43legacy_phy_write(dev, 0x0035, backup[10]);
1701 b43legacy_radio_selectchannel(dev, phy->channel, 1);
1702 if (phy->type == B43legacy_PHYTYPE_B) {
1703 b43legacy_phy_write(dev, 0x0030, backup[2]);
1704 b43legacy_write16(dev, 0x03EC, backup[3]);
1705 } else {
1706 if (phy->gmode) {
1707 b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1708 (b43legacy_read16(dev,
1709 B43legacy_MMIO_PHY_RADIO) & 0x7FFF));
1710 b43legacy_phy_write(dev, 0x0811, backup[4]);
1711 b43legacy_phy_write(dev, 0x0812, backup[5]);
1712 b43legacy_phy_write(dev, 0x0814, backup[6]);
1713 b43legacy_phy_write(dev, 0x0815, backup[7]);
1714 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1715 backup[8]);
1716 b43legacy_phy_write(dev, 0x0802, backup[9]);
1717 if (phy->rev > 1) {
1718 b43legacy_phy_write(dev, 0x080F, backup[19]);
1719 b43legacy_phy_write(dev, 0x0810, backup[20]);
1723 if (i >= 15)
1724 ret = backup[13];
1726 return ret;
1729 static inline
1730 u16 freq_r3A_value(u16 frequency)
1732 u16 value;
1734 if (frequency < 5091)
1735 value = 0x0040;
1736 else if (frequency < 5321)
1737 value = 0x0000;
1738 else if (frequency < 5806)
1739 value = 0x0080;
1740 else
1741 value = 0x0040;
1743 return value;
1746 void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev)
1748 static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
1749 static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
1750 u16 tmp = b43legacy_radio_read16(dev, 0x001E);
1751 int i;
1752 int j;
1754 for (i = 0; i < 5; i++) {
1755 for (j = 0; j < 5; j++) {
1756 if (tmp == (data_high[i] | data_low[j])) {
1757 b43legacy_phy_write(dev, 0x0069, (i - j) << 8 |
1758 0x00C0);
1759 return;
1765 int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
1766 u8 channel,
1767 int synthetic_pu_workaround)
1769 struct b43legacy_phy *phy = &dev->phy;
1771 if (channel == 0xFF) {
1772 switch (phy->type) {
1773 case B43legacy_PHYTYPE_B:
1774 case B43legacy_PHYTYPE_G:
1775 channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;
1776 break;
1777 default:
1778 B43legacy_WARN_ON(1);
1782 /* TODO: Check if channel is valid - return -EINVAL if not */
1783 if (synthetic_pu_workaround)
1784 b43legacy_synth_pu_workaround(dev, channel);
1786 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
1787 channel2freq_bg(channel));
1789 if (channel == 14) {
1790 if (dev->dev->bus->sprom.country_code == 5) /* JAPAN) */
1791 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1792 B43legacy_UCODEFLAGS_OFFSET,
1793 b43legacy_shm_read32(dev,
1794 B43legacy_SHM_SHARED,
1795 B43legacy_UCODEFLAGS_OFFSET)
1796 & ~(1 << 7));
1797 else
1798 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1799 B43legacy_UCODEFLAGS_OFFSET,
1800 b43legacy_shm_read32(dev,
1801 B43legacy_SHM_SHARED,
1802 B43legacy_UCODEFLAGS_OFFSET)
1803 | (1 << 7));
1804 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1805 b43legacy_read16(dev,
1806 B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
1807 } else
1808 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1809 b43legacy_read16(dev,
1810 B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
1812 phy->channel = channel;
1813 /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
1814 * that 2000 usecs might suffice. */
1815 msleep(8);
1817 return 0;
1820 void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
1822 u16 tmp;
1824 val <<= 8;
1825 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
1826 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
1827 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
1828 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
1829 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
1830 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
1833 /* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
1834 static u16 b43legacy_get_txgain_base_band(u16 txpower)
1836 u16 ret;
1838 B43legacy_WARN_ON(txpower > 63);
1840 if (txpower >= 54)
1841 ret = 2;
1842 else if (txpower >= 49)
1843 ret = 4;
1844 else if (txpower >= 44)
1845 ret = 5;
1846 else
1847 ret = 6;
1849 return ret;
1852 /* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
1853 static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
1855 u16 ret;
1857 B43legacy_WARN_ON(txpower > 63);
1859 if (txpower >= 32)
1860 ret = 0;
1861 else if (txpower >= 25)
1862 ret = 1;
1863 else if (txpower >= 20)
1864 ret = 2;
1865 else if (txpower >= 12)
1866 ret = 3;
1867 else
1868 ret = 4;
1870 return ret;
1873 /* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
1874 static u16 b43legacy_get_txgain_dac(u16 txpower)
1876 u16 ret;
1878 B43legacy_WARN_ON(txpower > 63);
1880 if (txpower >= 54)
1881 ret = txpower - 53;
1882 else if (txpower >= 49)
1883 ret = txpower - 42;
1884 else if (txpower >= 44)
1885 ret = txpower - 37;
1886 else if (txpower >= 32)
1887 ret = txpower - 32;
1888 else if (txpower >= 25)
1889 ret = txpower - 20;
1890 else if (txpower >= 20)
1891 ret = txpower - 13;
1892 else if (txpower >= 12)
1893 ret = txpower - 8;
1894 else
1895 ret = txpower;
1897 return ret;
1900 void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
1902 struct b43legacy_phy *phy = &dev->phy;
1903 u16 pamp;
1904 u16 base;
1905 u16 dac;
1906 u16 ilt;
1908 txpower = clamp_val(txpower, 0, 63);
1910 pamp = b43legacy_get_txgain_freq_power_amp(txpower);
1911 pamp <<= 5;
1912 pamp &= 0x00E0;
1913 b43legacy_phy_write(dev, 0x0019, pamp);
1915 base = b43legacy_get_txgain_base_band(txpower);
1916 base &= 0x000F;
1917 b43legacy_phy_write(dev, 0x0017, base | 0x0020);
1919 ilt = b43legacy_ilt_read(dev, 0x3001);
1920 ilt &= 0x0007;
1922 dac = b43legacy_get_txgain_dac(txpower);
1923 dac <<= 3;
1924 dac |= ilt;
1926 b43legacy_ilt_write(dev, 0x3001, dac);
1928 phy->txpwr_offset = txpower;
1930 /* TODO: FuncPlaceholder (Adjust BB loft cancel) */
1933 void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
1934 u16 baseband_attenuation,
1935 u16 radio_attenuation,
1936 u16 txpower)
1938 struct b43legacy_phy *phy = &dev->phy;
1940 if (baseband_attenuation == 0xFFFF)
1941 baseband_attenuation = phy->bbatt;
1942 if (radio_attenuation == 0xFFFF)
1943 radio_attenuation = phy->rfatt;
1944 if (txpower == 0xFFFF)
1945 txpower = phy->txctl1;
1946 phy->bbatt = baseband_attenuation;
1947 phy->rfatt = radio_attenuation;
1948 phy->txctl1 = txpower;
1950 B43legacy_WARN_ON(baseband_attenuation > 11);
1951 if (phy->radio_rev < 6)
1952 B43legacy_WARN_ON(radio_attenuation > 9);
1953 else
1954 B43legacy_WARN_ON(radio_attenuation > 31);
1955 B43legacy_WARN_ON(txpower > 7);
1957 b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
1958 b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
1959 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
1960 radio_attenuation);
1961 if (phy->radio_ver == 0x2050)
1962 b43legacy_radio_write16(dev, 0x0052,
1963 (b43legacy_radio_read16(dev, 0x0052)
1964 & ~0x0070) | ((txpower << 4) & 0x0070));
1965 /* FIXME: The spec is very weird and unclear here. */
1966 if (phy->type == B43legacy_PHYTYPE_G)
1967 b43legacy_phy_lo_adjust(dev, 0);
1970 u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
1972 struct b43legacy_phy *phy = &dev->phy;
1974 if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
1975 return 0;
1976 return 2;
1979 u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
1981 struct b43legacy_phy *phy = &dev->phy;
1982 u16 att = 0xFFFF;
1984 switch (phy->radio_ver) {
1985 case 0x2053:
1986 switch (phy->radio_rev) {
1987 case 1:
1988 att = 6;
1989 break;
1991 break;
1992 case 0x2050:
1993 switch (phy->radio_rev) {
1994 case 0:
1995 att = 5;
1996 break;
1997 case 1:
1998 if (phy->type == B43legacy_PHYTYPE_G) {
1999 if (is_bcm_board_vendor(dev) &&
2000 dev->dev->bus->boardinfo.type == 0x421 &&
2001 dev->dev->bus->boardinfo.rev >= 30)
2002 att = 3;
2003 else if (is_bcm_board_vendor(dev) &&
2004 dev->dev->bus->boardinfo.type == 0x416)
2005 att = 3;
2006 else
2007 att = 1;
2008 } else {
2009 if (is_bcm_board_vendor(dev) &&
2010 dev->dev->bus->boardinfo.type == 0x421 &&
2011 dev->dev->bus->boardinfo.rev >= 30)
2012 att = 7;
2013 else
2014 att = 6;
2016 break;
2017 case 2:
2018 if (phy->type == B43legacy_PHYTYPE_G) {
2019 if (is_bcm_board_vendor(dev) &&
2020 dev->dev->bus->boardinfo.type == 0x421 &&
2021 dev->dev->bus->boardinfo.rev >= 30)
2022 att = 3;
2023 else if (is_bcm_board_vendor(dev) &&
2024 dev->dev->bus->boardinfo.type ==
2025 0x416)
2026 att = 5;
2027 else if (dev->dev->bus->chip_id == 0x4320)
2028 att = 4;
2029 else
2030 att = 3;
2031 } else
2032 att = 6;
2033 break;
2034 case 3:
2035 att = 5;
2036 break;
2037 case 4:
2038 case 5:
2039 att = 1;
2040 break;
2041 case 6:
2042 case 7:
2043 att = 5;
2044 break;
2045 case 8:
2046 att = 0x1A;
2047 break;
2048 case 9:
2049 default:
2050 att = 5;
2053 if (is_bcm_board_vendor(dev) &&
2054 dev->dev->bus->boardinfo.type == 0x421) {
2055 if (dev->dev->bus->boardinfo.rev < 0x43)
2056 att = 2;
2057 else if (dev->dev->bus->boardinfo.rev < 0x51)
2058 att = 3;
2060 if (att == 0xFFFF)
2061 att = 5;
2063 return att;
2066 u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
2068 struct b43legacy_phy *phy = &dev->phy;
2070 if (phy->radio_ver != 0x2050)
2071 return 0;
2072 if (phy->radio_rev == 1)
2073 return 3;
2074 if (phy->radio_rev < 6)
2075 return 2;
2076 if (phy->radio_rev == 8)
2077 return 1;
2078 return 0;
2081 void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
2083 struct b43legacy_phy *phy = &dev->phy;
2084 int err;
2085 u8 channel;
2087 might_sleep();
2089 if (phy->radio_on)
2090 return;
2092 switch (phy->type) {
2093 case B43legacy_PHYTYPE_B:
2094 case B43legacy_PHYTYPE_G:
2095 b43legacy_phy_write(dev, 0x0015, 0x8000);
2096 b43legacy_phy_write(dev, 0x0015, 0xCC00);
2097 b43legacy_phy_write(dev, 0x0015,
2098 (phy->gmode ? 0x00C0 : 0x0000));
2099 if (phy->radio_off_context.valid) {
2100 /* Restore the RFover values. */
2101 b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,
2102 phy->radio_off_context.rfover);
2103 b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
2104 phy->radio_off_context.rfoverval);
2105 phy->radio_off_context.valid = false;
2107 channel = phy->channel;
2108 err = b43legacy_radio_selectchannel(dev,
2109 B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
2110 err |= b43legacy_radio_selectchannel(dev, channel, 0);
2111 B43legacy_WARN_ON(err);
2112 break;
2113 default:
2114 B43legacy_BUG_ON(1);
2116 phy->radio_on = true;
2119 void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force)
2121 struct b43legacy_phy *phy = &dev->phy;
2123 if (!phy->radio_on && !force)
2124 return;
2126 if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
2127 u16 rfover, rfoverval;
2129 rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
2130 rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
2131 if (!force) {
2132 phy->radio_off_context.rfover = rfover;
2133 phy->radio_off_context.rfoverval = rfoverval;
2134 phy->radio_off_context.valid = true;
2136 b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
2137 b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
2138 rfoverval & 0xFF73);
2139 } else
2140 b43legacy_phy_write(dev, 0x0015, 0xAA00);
2141 phy->radio_on = false;
2142 b43legacydbg(dev->wl, "Radio initialized\n");
2145 void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
2147 struct b43legacy_phy *phy = &dev->phy;
2149 switch (phy->type) {
2150 case B43legacy_PHYTYPE_B:
2151 case B43legacy_PHYTYPE_G:
2152 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
2153 0x7F7F);
2154 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
2155 0x7F7F);
2156 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
2157 0x7F7F);
2158 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
2159 0x7F7F);
2160 break;