dmaengine: imx-sdma: Let the core do the device node validation
[linux/fpc-iii.git] / drivers / net / wireless / broadcom / b43legacy / radio.c
blobc6db444ea07efc9a1bc11208a74f72debcc26ca0
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 udelay(10);
101 void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
103 u32 status;
105 b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
106 status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
107 B43legacy_WARN_ON(!(status & B43legacy_MACCTL_RADIOLOCK));
108 status &= ~B43legacy_MACCTL_RADIOLOCK;
109 b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
112 u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset)
114 struct b43legacy_phy *phy = &dev->phy;
116 switch (phy->type) {
117 case B43legacy_PHYTYPE_B:
118 if (phy->radio_ver == 0x2053) {
119 if (offset < 0x70)
120 offset += 0x80;
121 else if (offset < 0x80)
122 offset += 0x70;
123 } else if (phy->radio_ver == 0x2050)
124 offset |= 0x80;
125 else
126 B43legacy_WARN_ON(1);
127 break;
128 case B43legacy_PHYTYPE_G:
129 offset |= 0x80;
130 break;
131 default:
132 B43legacy_BUG_ON(1);
135 b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
136 return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
139 void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val)
141 b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
142 b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);
145 static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,
146 s16 first, s16 second, s16 third)
148 struct b43legacy_phy *phy = &dev->phy;
149 u16 i;
150 u16 start = 0x08;
151 u16 end = 0x18;
152 u16 offset = 0x0400;
153 u16 tmp;
155 if (phy->rev <= 1) {
156 offset = 0x5000;
157 start = 0x10;
158 end = 0x20;
161 for (i = 0; i < 4; i++)
162 b43legacy_ilt_write(dev, offset + i, first);
164 for (i = start; i < end; i++)
165 b43legacy_ilt_write(dev, offset + i, second);
167 if (third != -1) {
168 tmp = ((u16)third << 14) | ((u16)third << 6);
169 b43legacy_phy_write(dev, 0x04A0,
170 (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
171 | tmp);
172 b43legacy_phy_write(dev, 0x04A1,
173 (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
174 | tmp);
175 b43legacy_phy_write(dev, 0x04A2,
176 (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
177 | tmp);
179 b43legacy_dummy_transmission(dev);
182 static void b43legacy_set_original_gains(struct b43legacy_wldev *dev)
184 struct b43legacy_phy *phy = &dev->phy;
185 u16 i;
186 u16 tmp;
187 u16 offset = 0x0400;
188 u16 start = 0x0008;
189 u16 end = 0x0018;
191 if (phy->rev <= 1) {
192 offset = 0x5000;
193 start = 0x0010;
194 end = 0x0020;
197 for (i = 0; i < 4; i++) {
198 tmp = (i & 0xFFFC);
199 tmp |= (i & 0x0001) << 1;
200 tmp |= (i & 0x0002) >> 1;
202 b43legacy_ilt_write(dev, offset + i, tmp);
205 for (i = start; i < end; i++)
206 b43legacy_ilt_write(dev, offset + i, i - start);
208 b43legacy_phy_write(dev, 0x04A0,
209 (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
210 | 0x4040);
211 b43legacy_phy_write(dev, 0x04A1,
212 (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
213 | 0x4040);
214 b43legacy_phy_write(dev, 0x04A2,
215 (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
216 | 0x4000);
217 b43legacy_dummy_transmission(dev);
220 /* Synthetic PU workaround */
221 static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,
222 u8 channel)
224 struct b43legacy_phy *phy = &dev->phy;
226 might_sleep();
228 if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)
229 /* We do not need the workaround. */
230 return;
232 if (channel <= 10)
233 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
234 channel2freq_bg(channel + 4));
235 else
236 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
237 channel2freq_bg(channel));
238 msleep(1);
239 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
240 channel2freq_bg(channel));
243 u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel)
245 struct b43legacy_phy *phy = &dev->phy;
246 u8 ret = 0;
247 u16 saved;
248 u16 rssi;
249 u16 temp;
250 int i;
251 int j = 0;
253 saved = b43legacy_phy_read(dev, 0x0403);
254 b43legacy_radio_selectchannel(dev, channel, 0);
255 b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
256 if (phy->aci_hw_rssi)
257 rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;
258 else
259 rssi = saved & 0x3F;
260 /* clamp temp to signed 5bit */
261 if (rssi > 32)
262 rssi -= 64;
263 for (i = 0; i < 100; i++) {
264 temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;
265 if (temp > 32)
266 temp -= 64;
267 if (temp < rssi)
268 j++;
269 if (j >= 20)
270 ret = 1;
272 b43legacy_phy_write(dev, 0x0403, saved);
274 return ret;
277 u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
279 struct b43legacy_phy *phy = &dev->phy;
280 u8 ret[13] = { 0 };
281 unsigned int channel = phy->channel;
282 unsigned int i;
283 unsigned int j;
284 unsigned int start;
285 unsigned int end;
287 if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
288 return 0;
290 b43legacy_phy_lock(dev);
291 b43legacy_radio_lock(dev);
292 b43legacy_phy_write(dev, 0x0802,
293 b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
294 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
295 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
296 & 0x7FFF);
297 b43legacy_set_all_gains(dev, 3, 8, 1);
299 start = (channel - 5 > 0) ? channel - 5 : 1;
300 end = (channel + 5 < 14) ? channel + 5 : 13;
302 for (i = start; i <= end; i++) {
303 if (abs(channel - i) > 2)
304 ret[i-1] = b43legacy_radio_aci_detect(dev, i);
306 b43legacy_radio_selectchannel(dev, channel, 0);
307 b43legacy_phy_write(dev, 0x0802,
308 (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)
309 | 0x0003);
310 b43legacy_phy_write(dev, 0x0403,
311 b43legacy_phy_read(dev, 0x0403) & 0xFFF8);
312 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
313 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
314 | 0x8000);
315 b43legacy_set_original_gains(dev);
316 for (i = 0; i < 13; i++) {
317 if (!ret[i])
318 continue;
319 end = (i + 5 < 13) ? i + 5 : 13;
320 for (j = i; j < end; j++)
321 ret[j] = 1;
323 b43legacy_radio_unlock(dev);
324 b43legacy_phy_unlock(dev);
326 return ret[channel - 1];
329 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
330 void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val)
332 b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
333 b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);
336 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
337 s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset)
339 u16 val;
341 b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
342 val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);
344 return (s16)val;
347 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
348 void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
350 u16 i;
351 s16 tmp;
353 for (i = 0; i < 64; i++) {
354 tmp = b43legacy_nrssi_hw_read(dev, i);
355 tmp -= val;
356 tmp = clamp_val(tmp, -32, 31);
357 b43legacy_nrssi_hw_write(dev, i, tmp);
361 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
362 void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
364 struct b43legacy_phy *phy = &dev->phy;
365 s16 i;
366 s16 delta;
367 s32 tmp;
369 delta = 0x1F - phy->nrssi[0];
370 for (i = 0; i < 64; i++) {
371 tmp = (i - delta) * phy->nrssislope;
372 tmp /= 0x10000;
373 tmp += 0x3A;
374 tmp = clamp_val(tmp, 0, 0x3F);
375 phy->nrssi_lt[i] = tmp;
379 static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev)
381 struct b43legacy_phy *phy = &dev->phy;
382 u16 backup[20] = { 0 };
383 s16 v47F;
384 u16 i;
385 u16 saved = 0xFFFF;
387 backup[0] = b43legacy_phy_read(dev, 0x0001);
388 backup[1] = b43legacy_phy_read(dev, 0x0811);
389 backup[2] = b43legacy_phy_read(dev, 0x0812);
390 backup[3] = b43legacy_phy_read(dev, 0x0814);
391 backup[4] = b43legacy_phy_read(dev, 0x0815);
392 backup[5] = b43legacy_phy_read(dev, 0x005A);
393 backup[6] = b43legacy_phy_read(dev, 0x0059);
394 backup[7] = b43legacy_phy_read(dev, 0x0058);
395 backup[8] = b43legacy_phy_read(dev, 0x000A);
396 backup[9] = b43legacy_phy_read(dev, 0x0003);
397 backup[10] = b43legacy_radio_read16(dev, 0x007A);
398 backup[11] = b43legacy_radio_read16(dev, 0x0043);
400 b43legacy_phy_write(dev, 0x0429,
401 b43legacy_phy_read(dev, 0x0429) & 0x7FFF);
402 b43legacy_phy_write(dev, 0x0001,
403 (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)
404 | 0x4000);
405 b43legacy_phy_write(dev, 0x0811,
406 b43legacy_phy_read(dev, 0x0811) | 0x000C);
407 b43legacy_phy_write(dev, 0x0812,
408 (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)
409 | 0x0004);
410 b43legacy_phy_write(dev, 0x0802,
411 b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
412 if (phy->rev >= 6) {
413 backup[12] = b43legacy_phy_read(dev, 0x002E);
414 backup[13] = b43legacy_phy_read(dev, 0x002F);
415 backup[14] = b43legacy_phy_read(dev, 0x080F);
416 backup[15] = b43legacy_phy_read(dev, 0x0810);
417 backup[16] = b43legacy_phy_read(dev, 0x0801);
418 backup[17] = b43legacy_phy_read(dev, 0x0060);
419 backup[18] = b43legacy_phy_read(dev, 0x0014);
420 backup[19] = b43legacy_phy_read(dev, 0x0478);
422 b43legacy_phy_write(dev, 0x002E, 0);
423 b43legacy_phy_write(dev, 0x002F, 0);
424 b43legacy_phy_write(dev, 0x080F, 0);
425 b43legacy_phy_write(dev, 0x0810, 0);
426 b43legacy_phy_write(dev, 0x0478,
427 b43legacy_phy_read(dev, 0x0478) | 0x0100);
428 b43legacy_phy_write(dev, 0x0801,
429 b43legacy_phy_read(dev, 0x0801) | 0x0040);
430 b43legacy_phy_write(dev, 0x0060,
431 b43legacy_phy_read(dev, 0x0060) | 0x0040);
432 b43legacy_phy_write(dev, 0x0014,
433 b43legacy_phy_read(dev, 0x0014) | 0x0200);
435 b43legacy_radio_write16(dev, 0x007A,
436 b43legacy_radio_read16(dev, 0x007A) | 0x0070);
437 b43legacy_radio_write16(dev, 0x007A,
438 b43legacy_radio_read16(dev, 0x007A) | 0x0080);
439 udelay(30);
441 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
442 if (v47F >= 0x20)
443 v47F -= 0x40;
444 if (v47F == 31) {
445 for (i = 7; i >= 4; i--) {
446 b43legacy_radio_write16(dev, 0x007B, i);
447 udelay(20);
448 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)
449 & 0x003F);
450 if (v47F >= 0x20)
451 v47F -= 0x40;
452 if (v47F < 31 && saved == 0xFFFF)
453 saved = i;
455 if (saved == 0xFFFF)
456 saved = 4;
457 } else {
458 b43legacy_radio_write16(dev, 0x007A,
459 b43legacy_radio_read16(dev, 0x007A)
460 & 0x007F);
461 b43legacy_phy_write(dev, 0x0814,
462 b43legacy_phy_read(dev, 0x0814) | 0x0001);
463 b43legacy_phy_write(dev, 0x0815,
464 b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
465 b43legacy_phy_write(dev, 0x0811,
466 b43legacy_phy_read(dev, 0x0811) | 0x000C);
467 b43legacy_phy_write(dev, 0x0812,
468 b43legacy_phy_read(dev, 0x0812) | 0x000C);
469 b43legacy_phy_write(dev, 0x0811,
470 b43legacy_phy_read(dev, 0x0811) | 0x0030);
471 b43legacy_phy_write(dev, 0x0812,
472 b43legacy_phy_read(dev, 0x0812) | 0x0030);
473 b43legacy_phy_write(dev, 0x005A, 0x0480);
474 b43legacy_phy_write(dev, 0x0059, 0x0810);
475 b43legacy_phy_write(dev, 0x0058, 0x000D);
476 if (phy->analog == 0)
477 b43legacy_phy_write(dev, 0x0003, 0x0122);
478 else
479 b43legacy_phy_write(dev, 0x000A,
480 b43legacy_phy_read(dev, 0x000A)
481 | 0x2000);
482 b43legacy_phy_write(dev, 0x0814,
483 b43legacy_phy_read(dev, 0x0814) | 0x0004);
484 b43legacy_phy_write(dev, 0x0815,
485 b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
486 b43legacy_phy_write(dev, 0x0003,
487 (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)
488 | 0x0040);
489 b43legacy_radio_write16(dev, 0x007A,
490 b43legacy_radio_read16(dev, 0x007A)
491 | 0x000F);
492 b43legacy_set_all_gains(dev, 3, 0, 1);
493 b43legacy_radio_write16(dev, 0x0043,
494 (b43legacy_radio_read16(dev, 0x0043)
495 & 0x00F0) | 0x000F);
496 udelay(30);
497 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
498 if (v47F >= 0x20)
499 v47F -= 0x40;
500 if (v47F == -32) {
501 for (i = 0; i < 4; i++) {
502 b43legacy_radio_write16(dev, 0x007B, i);
503 udelay(20);
504 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>
505 8) & 0x003F);
506 if (v47F >= 0x20)
507 v47F -= 0x40;
508 if (v47F > -31 && saved == 0xFFFF)
509 saved = i;
511 if (saved == 0xFFFF)
512 saved = 3;
513 } else
514 saved = 0;
516 b43legacy_radio_write16(dev, 0x007B, saved);
518 if (phy->rev >= 6) {
519 b43legacy_phy_write(dev, 0x002E, backup[12]);
520 b43legacy_phy_write(dev, 0x002F, backup[13]);
521 b43legacy_phy_write(dev, 0x080F, backup[14]);
522 b43legacy_phy_write(dev, 0x0810, backup[15]);
524 b43legacy_phy_write(dev, 0x0814, backup[3]);
525 b43legacy_phy_write(dev, 0x0815, backup[4]);
526 b43legacy_phy_write(dev, 0x005A, backup[5]);
527 b43legacy_phy_write(dev, 0x0059, backup[6]);
528 b43legacy_phy_write(dev, 0x0058, backup[7]);
529 b43legacy_phy_write(dev, 0x000A, backup[8]);
530 b43legacy_phy_write(dev, 0x0003, backup[9]);
531 b43legacy_radio_write16(dev, 0x0043, backup[11]);
532 b43legacy_radio_write16(dev, 0x007A, backup[10]);
533 b43legacy_phy_write(dev, 0x0802,
534 b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);
535 b43legacy_phy_write(dev, 0x0429,
536 b43legacy_phy_read(dev, 0x0429) | 0x8000);
537 b43legacy_set_original_gains(dev);
538 if (phy->rev >= 6) {
539 b43legacy_phy_write(dev, 0x0801, backup[16]);
540 b43legacy_phy_write(dev, 0x0060, backup[17]);
541 b43legacy_phy_write(dev, 0x0014, backup[18]);
542 b43legacy_phy_write(dev, 0x0478, backup[19]);
544 b43legacy_phy_write(dev, 0x0001, backup[0]);
545 b43legacy_phy_write(dev, 0x0812, backup[2]);
546 b43legacy_phy_write(dev, 0x0811, backup[1]);
549 void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev)
551 struct b43legacy_phy *phy = &dev->phy;
552 u16 backup[18] = { 0 };
553 u16 tmp;
554 s16 nrssi0;
555 s16 nrssi1;
557 switch (phy->type) {
558 case B43legacy_PHYTYPE_B:
559 backup[0] = b43legacy_radio_read16(dev, 0x007A);
560 backup[1] = b43legacy_radio_read16(dev, 0x0052);
561 backup[2] = b43legacy_radio_read16(dev, 0x0043);
562 backup[3] = b43legacy_phy_read(dev, 0x0030);
563 backup[4] = b43legacy_phy_read(dev, 0x0026);
564 backup[5] = b43legacy_phy_read(dev, 0x0015);
565 backup[6] = b43legacy_phy_read(dev, 0x002A);
566 backup[7] = b43legacy_phy_read(dev, 0x0020);
567 backup[8] = b43legacy_phy_read(dev, 0x005A);
568 backup[9] = b43legacy_phy_read(dev, 0x0059);
569 backup[10] = b43legacy_phy_read(dev, 0x0058);
570 backup[11] = b43legacy_read16(dev, 0x03E2);
571 backup[12] = b43legacy_read16(dev, 0x03E6);
572 backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
574 tmp = b43legacy_radio_read16(dev, 0x007A);
575 tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
576 b43legacy_radio_write16(dev, 0x007A, tmp);
577 b43legacy_phy_write(dev, 0x0030, 0x00FF);
578 b43legacy_write16(dev, 0x03EC, 0x7F7F);
579 b43legacy_phy_write(dev, 0x0026, 0x0000);
580 b43legacy_phy_write(dev, 0x0015,
581 b43legacy_phy_read(dev, 0x0015) | 0x0020);
582 b43legacy_phy_write(dev, 0x002A, 0x08A3);
583 b43legacy_radio_write16(dev, 0x007A,
584 b43legacy_radio_read16(dev, 0x007A)
585 | 0x0080);
587 nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027);
588 b43legacy_radio_write16(dev, 0x007A,
589 b43legacy_radio_read16(dev, 0x007A)
590 & 0x007F);
591 if (phy->analog >= 2)
592 b43legacy_write16(dev, 0x03E6, 0x0040);
593 else if (phy->analog == 0)
594 b43legacy_write16(dev, 0x03E6, 0x0122);
595 else
596 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
597 b43legacy_read16(dev,
598 B43legacy_MMIO_CHANNEL_EXT) & 0x2000);
599 b43legacy_phy_write(dev, 0x0020, 0x3F3F);
600 b43legacy_phy_write(dev, 0x0015, 0xF330);
601 b43legacy_radio_write16(dev, 0x005A, 0x0060);
602 b43legacy_radio_write16(dev, 0x0043,
603 b43legacy_radio_read16(dev, 0x0043)
604 & 0x00F0);
605 b43legacy_phy_write(dev, 0x005A, 0x0480);
606 b43legacy_phy_write(dev, 0x0059, 0x0810);
607 b43legacy_phy_write(dev, 0x0058, 0x000D);
608 udelay(20);
610 nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);
611 b43legacy_phy_write(dev, 0x0030, backup[3]);
612 b43legacy_radio_write16(dev, 0x007A, backup[0]);
613 b43legacy_write16(dev, 0x03E2, backup[11]);
614 b43legacy_phy_write(dev, 0x0026, backup[4]);
615 b43legacy_phy_write(dev, 0x0015, backup[5]);
616 b43legacy_phy_write(dev, 0x002A, backup[6]);
617 b43legacy_synth_pu_workaround(dev, phy->channel);
618 if (phy->analog != 0)
619 b43legacy_write16(dev, 0x03F4, backup[13]);
621 b43legacy_phy_write(dev, 0x0020, backup[7]);
622 b43legacy_phy_write(dev, 0x005A, backup[8]);
623 b43legacy_phy_write(dev, 0x0059, backup[9]);
624 b43legacy_phy_write(dev, 0x0058, backup[10]);
625 b43legacy_radio_write16(dev, 0x0052, backup[1]);
626 b43legacy_radio_write16(dev, 0x0043, backup[2]);
628 if (nrssi0 == nrssi1)
629 phy->nrssislope = 0x00010000;
630 else
631 phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
633 if (nrssi0 <= -4) {
634 phy->nrssi[0] = nrssi0;
635 phy->nrssi[1] = nrssi1;
637 break;
638 case B43legacy_PHYTYPE_G:
639 if (phy->radio_rev >= 9)
640 return;
641 if (phy->radio_rev == 8)
642 b43legacy_calc_nrssi_offset(dev);
644 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
645 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
646 & 0x7FFF);
647 b43legacy_phy_write(dev, 0x0802,
648 b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
649 backup[7] = b43legacy_read16(dev, 0x03E2);
650 b43legacy_write16(dev, 0x03E2,
651 b43legacy_read16(dev, 0x03E2) | 0x8000);
652 backup[0] = b43legacy_radio_read16(dev, 0x007A);
653 backup[1] = b43legacy_radio_read16(dev, 0x0052);
654 backup[2] = b43legacy_radio_read16(dev, 0x0043);
655 backup[3] = b43legacy_phy_read(dev, 0x0015);
656 backup[4] = b43legacy_phy_read(dev, 0x005A);
657 backup[5] = b43legacy_phy_read(dev, 0x0059);
658 backup[6] = b43legacy_phy_read(dev, 0x0058);
659 backup[8] = b43legacy_read16(dev, 0x03E6);
660 backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
661 if (phy->rev >= 3) {
662 backup[10] = b43legacy_phy_read(dev, 0x002E);
663 backup[11] = b43legacy_phy_read(dev, 0x002F);
664 backup[12] = b43legacy_phy_read(dev, 0x080F);
665 backup[13] = b43legacy_phy_read(dev,
666 B43legacy_PHY_G_LO_CONTROL);
667 backup[14] = b43legacy_phy_read(dev, 0x0801);
668 backup[15] = b43legacy_phy_read(dev, 0x0060);
669 backup[16] = b43legacy_phy_read(dev, 0x0014);
670 backup[17] = b43legacy_phy_read(dev, 0x0478);
671 b43legacy_phy_write(dev, 0x002E, 0);
672 b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);
673 switch (phy->rev) {
674 case 4: case 6: case 7:
675 b43legacy_phy_write(dev, 0x0478,
676 b43legacy_phy_read(dev,
677 0x0478) | 0x0100);
678 b43legacy_phy_write(dev, 0x0801,
679 b43legacy_phy_read(dev,
680 0x0801) | 0x0040);
681 break;
682 case 3: case 5:
683 b43legacy_phy_write(dev, 0x0801,
684 b43legacy_phy_read(dev,
685 0x0801) & 0xFFBF);
686 break;
688 b43legacy_phy_write(dev, 0x0060,
689 b43legacy_phy_read(dev, 0x0060)
690 | 0x0040);
691 b43legacy_phy_write(dev, 0x0014,
692 b43legacy_phy_read(dev, 0x0014)
693 | 0x0200);
695 b43legacy_radio_write16(dev, 0x007A,
696 b43legacy_radio_read16(dev, 0x007A)
697 | 0x0070);
698 b43legacy_set_all_gains(dev, 0, 8, 0);
699 b43legacy_radio_write16(dev, 0x007A,
700 b43legacy_radio_read16(dev, 0x007A)
701 & 0x00F7);
702 if (phy->rev >= 2) {
703 b43legacy_phy_write(dev, 0x0811,
704 (b43legacy_phy_read(dev, 0x0811)
705 & 0xFFCF) | 0x0030);
706 b43legacy_phy_write(dev, 0x0812,
707 (b43legacy_phy_read(dev, 0x0812)
708 & 0xFFCF) | 0x0010);
710 b43legacy_radio_write16(dev, 0x007A,
711 b43legacy_radio_read16(dev, 0x007A)
712 | 0x0080);
713 udelay(20);
715 nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
716 if (nrssi0 >= 0x0020)
717 nrssi0 -= 0x0040;
719 b43legacy_radio_write16(dev, 0x007A,
720 b43legacy_radio_read16(dev, 0x007A)
721 & 0x007F);
722 if (phy->analog >= 2)
723 b43legacy_phy_write(dev, 0x0003,
724 (b43legacy_phy_read(dev, 0x0003)
725 & 0xFF9F) | 0x0040);
727 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
728 b43legacy_read16(dev,
729 B43legacy_MMIO_CHANNEL_EXT) | 0x2000);
730 b43legacy_radio_write16(dev, 0x007A,
731 b43legacy_radio_read16(dev, 0x007A)
732 | 0x000F);
733 b43legacy_phy_write(dev, 0x0015, 0xF330);
734 if (phy->rev >= 2) {
735 b43legacy_phy_write(dev, 0x0812,
736 (b43legacy_phy_read(dev, 0x0812)
737 & 0xFFCF) | 0x0020);
738 b43legacy_phy_write(dev, 0x0811,
739 (b43legacy_phy_read(dev, 0x0811)
740 & 0xFFCF) | 0x0020);
743 b43legacy_set_all_gains(dev, 3, 0, 1);
744 if (phy->radio_rev == 8)
745 b43legacy_radio_write16(dev, 0x0043, 0x001F);
746 else {
747 tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;
748 b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);
749 tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;
750 b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);
752 b43legacy_phy_write(dev, 0x005A, 0x0480);
753 b43legacy_phy_write(dev, 0x0059, 0x0810);
754 b43legacy_phy_write(dev, 0x0058, 0x000D);
755 udelay(20);
756 nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
757 if (nrssi1 >= 0x0020)
758 nrssi1 -= 0x0040;
759 if (nrssi0 == nrssi1)
760 phy->nrssislope = 0x00010000;
761 else
762 phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
763 if (nrssi0 >= -4) {
764 phy->nrssi[0] = nrssi1;
765 phy->nrssi[1] = nrssi0;
767 if (phy->rev >= 3) {
768 b43legacy_phy_write(dev, 0x002E, backup[10]);
769 b43legacy_phy_write(dev, 0x002F, backup[11]);
770 b43legacy_phy_write(dev, 0x080F, backup[12]);
771 b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,
772 backup[13]);
774 if (phy->rev >= 2) {
775 b43legacy_phy_write(dev, 0x0812,
776 b43legacy_phy_read(dev, 0x0812)
777 & 0xFFCF);
778 b43legacy_phy_write(dev, 0x0811,
779 b43legacy_phy_read(dev, 0x0811)
780 & 0xFFCF);
783 b43legacy_radio_write16(dev, 0x007A, backup[0]);
784 b43legacy_radio_write16(dev, 0x0052, backup[1]);
785 b43legacy_radio_write16(dev, 0x0043, backup[2]);
786 b43legacy_write16(dev, 0x03E2, backup[7]);
787 b43legacy_write16(dev, 0x03E6, backup[8]);
788 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);
789 b43legacy_phy_write(dev, 0x0015, backup[3]);
790 b43legacy_phy_write(dev, 0x005A, backup[4]);
791 b43legacy_phy_write(dev, 0x0059, backup[5]);
792 b43legacy_phy_write(dev, 0x0058, backup[6]);
793 b43legacy_synth_pu_workaround(dev, phy->channel);
794 b43legacy_phy_write(dev, 0x0802,
795 b43legacy_phy_read(dev, 0x0802) | 0x0003);
796 b43legacy_set_original_gains(dev);
797 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
798 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
799 | 0x8000);
800 if (phy->rev >= 3) {
801 b43legacy_phy_write(dev, 0x0801, backup[14]);
802 b43legacy_phy_write(dev, 0x0060, backup[15]);
803 b43legacy_phy_write(dev, 0x0014, backup[16]);
804 b43legacy_phy_write(dev, 0x0478, backup[17]);
806 b43legacy_nrssi_mem_update(dev);
807 b43legacy_calc_nrssi_threshold(dev);
808 break;
809 default:
810 B43legacy_BUG_ON(1);
814 void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
816 struct b43legacy_phy *phy = &dev->phy;
817 s32 threshold;
818 s32 a;
819 s32 b;
820 s16 tmp16;
821 u16 tmp_u16;
823 switch (phy->type) {
824 case B43legacy_PHYTYPE_B: {
825 if (phy->radio_ver != 0x2050)
826 return;
827 if (!(dev->dev->bus->sprom.boardflags_lo &
828 B43legacy_BFL_RSSI))
829 return;
831 if (phy->radio_rev >= 6) {
832 threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32;
833 threshold += 20 * (phy->nrssi[0] + 1);
834 threshold /= 40;
835 } else
836 threshold = phy->nrssi[1] - 5;
838 threshold = clamp_val(threshold, 0, 0x3E);
839 b43legacy_phy_read(dev, 0x0020); /* dummy read */
840 b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
841 | 0x001C);
843 if (phy->radio_rev >= 6) {
844 b43legacy_phy_write(dev, 0x0087, 0x0E0D);
845 b43legacy_phy_write(dev, 0x0086, 0x0C0B);
846 b43legacy_phy_write(dev, 0x0085, 0x0A09);
847 b43legacy_phy_write(dev, 0x0084, 0x0808);
848 b43legacy_phy_write(dev, 0x0083, 0x0808);
849 b43legacy_phy_write(dev, 0x0082, 0x0604);
850 b43legacy_phy_write(dev, 0x0081, 0x0302);
851 b43legacy_phy_write(dev, 0x0080, 0x0100);
853 break;
855 case B43legacy_PHYTYPE_G:
856 if (!phy->gmode ||
857 !(dev->dev->bus->sprom.boardflags_lo &
858 B43legacy_BFL_RSSI)) {
859 tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
860 if (tmp16 >= 0x20)
861 tmp16 -= 0x40;
862 if (tmp16 < 3)
863 b43legacy_phy_write(dev, 0x048A,
864 (b43legacy_phy_read(dev,
865 0x048A) & 0xF000) | 0x09EB);
866 else
867 b43legacy_phy_write(dev, 0x048A,
868 (b43legacy_phy_read(dev,
869 0x048A) & 0xF000) | 0x0AED);
870 } else {
871 if (phy->interfmode ==
872 B43legacy_RADIO_INTERFMODE_NONWLAN) {
873 a = 0xE;
874 b = 0xA;
875 } else if (!phy->aci_wlan_automatic &&
876 phy->aci_enable) {
877 a = 0x13;
878 b = 0x12;
879 } else {
880 a = 0xE;
881 b = 0x11;
884 a = a * (phy->nrssi[1] - phy->nrssi[0]);
885 a += (phy->nrssi[0] << 6);
886 if (a < 32)
887 a += 31;
888 else
889 a += 32;
890 a = a >> 6;
891 a = clamp_val(a, -31, 31);
893 b = b * (phy->nrssi[1] - phy->nrssi[0]);
894 b += (phy->nrssi[0] << 6);
895 if (b < 32)
896 b += 31;
897 else
898 b += 32;
899 b = b >> 6;
900 b = clamp_val(b, -31, 31);
902 tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
903 tmp_u16 |= ((u32)b & 0x0000003F);
904 tmp_u16 |= (((u32)a & 0x0000003F) << 6);
905 b43legacy_phy_write(dev, 0x048A, tmp_u16);
907 break;
908 default:
909 B43legacy_BUG_ON(1);
913 /* Stack implementation to save/restore values from the
914 * interference mitigation code.
915 * It is save to restore values in random order.
917 static void _stack_save(u32 *_stackptr, size_t *stackidx,
918 u8 id, u16 offset, u16 value)
920 u32 *stackptr = &(_stackptr[*stackidx]);
922 B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
923 B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
924 *stackptr = offset;
925 *stackptr |= ((u32)id) << 13;
926 *stackptr |= ((u32)value) << 16;
927 (*stackidx)++;
928 B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE));
931 static u16 _stack_restore(u32 *stackptr,
932 u8 id, u16 offset)
934 size_t i;
936 B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
937 B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
938 for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) {
939 if ((*stackptr & 0x00001FFF) != offset)
940 continue;
941 if (((*stackptr & 0x00007000) >> 13) != id)
942 continue;
943 return ((*stackptr & 0xFFFF0000) >> 16);
945 B43legacy_BUG_ON(1);
947 return 0;
950 #define phy_stacksave(offset) \
951 do { \
952 _stack_save(stack, &stackidx, 0x1, (offset), \
953 b43legacy_phy_read(dev, (offset))); \
954 } while (0)
955 #define phy_stackrestore(offset) \
956 do { \
957 b43legacy_phy_write(dev, (offset), \
958 _stack_restore(stack, 0x1, \
959 (offset))); \
960 } while (0)
961 #define radio_stacksave(offset) \
962 do { \
963 _stack_save(stack, &stackidx, 0x2, (offset), \
964 b43legacy_radio_read16(dev, (offset))); \
965 } while (0)
966 #define radio_stackrestore(offset) \
967 do { \
968 b43legacy_radio_write16(dev, (offset), \
969 _stack_restore(stack, 0x2, \
970 (offset))); \
971 } while (0)
972 #define ilt_stacksave(offset) \
973 do { \
974 _stack_save(stack, &stackidx, 0x3, (offset), \
975 b43legacy_ilt_read(dev, (offset))); \
976 } while (0)
977 #define ilt_stackrestore(offset) \
978 do { \
979 b43legacy_ilt_write(dev, (offset), \
980 _stack_restore(stack, 0x3, \
981 (offset))); \
982 } while (0)
984 static void
985 b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev,
986 int mode)
988 struct b43legacy_phy *phy = &dev->phy;
989 u16 tmp;
990 u16 flipped;
991 u32 tmp32;
992 size_t stackidx = 0;
993 u32 *stack = phy->interfstack;
995 switch (mode) {
996 case B43legacy_RADIO_INTERFMODE_NONWLAN:
997 if (phy->rev != 1) {
998 b43legacy_phy_write(dev, 0x042B,
999 b43legacy_phy_read(dev, 0x042B)
1000 | 0x0800);
1001 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1002 b43legacy_phy_read(dev,
1003 B43legacy_PHY_G_CRS) & ~0x4000);
1004 break;
1006 radio_stacksave(0x0078);
1007 tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E);
1008 flipped = flip_4bit(tmp);
1009 if (flipped < 10 && flipped >= 8)
1010 flipped = 7;
1011 else if (flipped >= 10)
1012 flipped -= 3;
1013 flipped = flip_4bit(flipped);
1014 flipped = (flipped << 1) | 0x0020;
1015 b43legacy_radio_write16(dev, 0x0078, flipped);
1017 b43legacy_calc_nrssi_threshold(dev);
1019 phy_stacksave(0x0406);
1020 b43legacy_phy_write(dev, 0x0406, 0x7E28);
1022 b43legacy_phy_write(dev, 0x042B,
1023 b43legacy_phy_read(dev, 0x042B) | 0x0800);
1024 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1025 b43legacy_phy_read(dev,
1026 B43legacy_PHY_RADIO_BITFIELD) | 0x1000);
1028 phy_stacksave(0x04A0);
1029 b43legacy_phy_write(dev, 0x04A0,
1030 (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0)
1031 | 0x0008);
1032 phy_stacksave(0x04A1);
1033 b43legacy_phy_write(dev, 0x04A1,
1034 (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0)
1035 | 0x0605);
1036 phy_stacksave(0x04A2);
1037 b43legacy_phy_write(dev, 0x04A2,
1038 (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0)
1039 | 0x0204);
1040 phy_stacksave(0x04A8);
1041 b43legacy_phy_write(dev, 0x04A8,
1042 (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0)
1043 | 0x0803);
1044 phy_stacksave(0x04AB);
1045 b43legacy_phy_write(dev, 0x04AB,
1046 (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0)
1047 | 0x0605);
1049 phy_stacksave(0x04A7);
1050 b43legacy_phy_write(dev, 0x04A7, 0x0002);
1051 phy_stacksave(0x04A3);
1052 b43legacy_phy_write(dev, 0x04A3, 0x287A);
1053 phy_stacksave(0x04A9);
1054 b43legacy_phy_write(dev, 0x04A9, 0x2027);
1055 phy_stacksave(0x0493);
1056 b43legacy_phy_write(dev, 0x0493, 0x32F5);
1057 phy_stacksave(0x04AA);
1058 b43legacy_phy_write(dev, 0x04AA, 0x2027);
1059 phy_stacksave(0x04AC);
1060 b43legacy_phy_write(dev, 0x04AC, 0x32F5);
1061 break;
1062 case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1063 if (b43legacy_phy_read(dev, 0x0033) & 0x0800)
1064 break;
1066 phy->aci_enable = true;
1068 phy_stacksave(B43legacy_PHY_RADIO_BITFIELD);
1069 phy_stacksave(B43legacy_PHY_G_CRS);
1070 if (phy->rev < 2)
1071 phy_stacksave(0x0406);
1072 else {
1073 phy_stacksave(0x04C0);
1074 phy_stacksave(0x04C1);
1076 phy_stacksave(0x0033);
1077 phy_stacksave(0x04A7);
1078 phy_stacksave(0x04A3);
1079 phy_stacksave(0x04A9);
1080 phy_stacksave(0x04AA);
1081 phy_stacksave(0x04AC);
1082 phy_stacksave(0x0493);
1083 phy_stacksave(0x04A1);
1084 phy_stacksave(0x04A0);
1085 phy_stacksave(0x04A2);
1086 phy_stacksave(0x048A);
1087 phy_stacksave(0x04A8);
1088 phy_stacksave(0x04AB);
1089 if (phy->rev == 2) {
1090 phy_stacksave(0x04AD);
1091 phy_stacksave(0x04AE);
1092 } else if (phy->rev >= 3) {
1093 phy_stacksave(0x04AD);
1094 phy_stacksave(0x0415);
1095 phy_stacksave(0x0416);
1096 phy_stacksave(0x0417);
1097 ilt_stacksave(0x1A00 + 0x2);
1098 ilt_stacksave(0x1A00 + 0x3);
1100 phy_stacksave(0x042B);
1101 phy_stacksave(0x048C);
1103 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1104 b43legacy_phy_read(dev,
1105 B43legacy_PHY_RADIO_BITFIELD) & ~0x1000);
1106 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1107 (b43legacy_phy_read(dev,
1108 B43legacy_PHY_G_CRS)
1109 & 0xFFFC) | 0x0002);
1111 b43legacy_phy_write(dev, 0x0033, 0x0800);
1112 b43legacy_phy_write(dev, 0x04A3, 0x2027);
1113 b43legacy_phy_write(dev, 0x04A9, 0x1CA8);
1114 b43legacy_phy_write(dev, 0x0493, 0x287A);
1115 b43legacy_phy_write(dev, 0x04AA, 0x1CA8);
1116 b43legacy_phy_write(dev, 0x04AC, 0x287A);
1118 b43legacy_phy_write(dev, 0x04A0,
1119 (b43legacy_phy_read(dev, 0x04A0)
1120 & 0xFFC0) | 0x001A);
1121 b43legacy_phy_write(dev, 0x04A7, 0x000D);
1123 if (phy->rev < 2)
1124 b43legacy_phy_write(dev, 0x0406, 0xFF0D);
1125 else if (phy->rev == 2) {
1126 b43legacy_phy_write(dev, 0x04C0, 0xFFFF);
1127 b43legacy_phy_write(dev, 0x04C1, 0x00A9);
1128 } else {
1129 b43legacy_phy_write(dev, 0x04C0, 0x00C1);
1130 b43legacy_phy_write(dev, 0x04C1, 0x0059);
1133 b43legacy_phy_write(dev, 0x04A1,
1134 (b43legacy_phy_read(dev, 0x04A1)
1135 & 0xC0FF) | 0x1800);
1136 b43legacy_phy_write(dev, 0x04A1,
1137 (b43legacy_phy_read(dev, 0x04A1)
1138 & 0xFFC0) | 0x0015);
1139 b43legacy_phy_write(dev, 0x04A8,
1140 (b43legacy_phy_read(dev, 0x04A8)
1141 & 0xCFFF) | 0x1000);
1142 b43legacy_phy_write(dev, 0x04A8,
1143 (b43legacy_phy_read(dev, 0x04A8)
1144 & 0xF0FF) | 0x0A00);
1145 b43legacy_phy_write(dev, 0x04AB,
1146 (b43legacy_phy_read(dev, 0x04AB)
1147 & 0xCFFF) | 0x1000);
1148 b43legacy_phy_write(dev, 0x04AB,
1149 (b43legacy_phy_read(dev, 0x04AB)
1150 & 0xF0FF) | 0x0800);
1151 b43legacy_phy_write(dev, 0x04AB,
1152 (b43legacy_phy_read(dev, 0x04AB)
1153 & 0xFFCF) | 0x0010);
1154 b43legacy_phy_write(dev, 0x04AB,
1155 (b43legacy_phy_read(dev, 0x04AB)
1156 & 0xFFF0) | 0x0005);
1157 b43legacy_phy_write(dev, 0x04A8,
1158 (b43legacy_phy_read(dev, 0x04A8)
1159 & 0xFFCF) | 0x0010);
1160 b43legacy_phy_write(dev, 0x04A8,
1161 (b43legacy_phy_read(dev, 0x04A8)
1162 & 0xFFF0) | 0x0006);
1163 b43legacy_phy_write(dev, 0x04A2,
1164 (b43legacy_phy_read(dev, 0x04A2)
1165 & 0xF0FF) | 0x0800);
1166 b43legacy_phy_write(dev, 0x04A0,
1167 (b43legacy_phy_read(dev, 0x04A0)
1168 & 0xF0FF) | 0x0500);
1169 b43legacy_phy_write(dev, 0x04A2,
1170 (b43legacy_phy_read(dev, 0x04A2)
1171 & 0xFFF0) | 0x000B);
1173 if (phy->rev >= 3) {
1174 b43legacy_phy_write(dev, 0x048A,
1175 b43legacy_phy_read(dev, 0x048A)
1176 & ~0x8000);
1177 b43legacy_phy_write(dev, 0x0415,
1178 (b43legacy_phy_read(dev, 0x0415)
1179 & 0x8000) | 0x36D8);
1180 b43legacy_phy_write(dev, 0x0416,
1181 (b43legacy_phy_read(dev, 0x0416)
1182 & 0x8000) | 0x36D8);
1183 b43legacy_phy_write(dev, 0x0417,
1184 (b43legacy_phy_read(dev, 0x0417)
1185 & 0xFE00) | 0x016D);
1186 } else {
1187 b43legacy_phy_write(dev, 0x048A,
1188 b43legacy_phy_read(dev, 0x048A)
1189 | 0x1000);
1190 b43legacy_phy_write(dev, 0x048A,
1191 (b43legacy_phy_read(dev, 0x048A)
1192 & 0x9FFF) | 0x2000);
1193 tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
1194 B43legacy_UCODEFLAGS_OFFSET);
1195 if (!(tmp32 & 0x800)) {
1196 tmp32 |= 0x800;
1197 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1198 B43legacy_UCODEFLAGS_OFFSET,
1199 tmp32);
1202 if (phy->rev >= 2)
1203 b43legacy_phy_write(dev, 0x042B,
1204 b43legacy_phy_read(dev, 0x042B)
1205 | 0x0800);
1206 b43legacy_phy_write(dev, 0x048C,
1207 (b43legacy_phy_read(dev, 0x048C)
1208 & 0xF0FF) | 0x0200);
1209 if (phy->rev == 2) {
1210 b43legacy_phy_write(dev, 0x04AE,
1211 (b43legacy_phy_read(dev, 0x04AE)
1212 & 0xFF00) | 0x007F);
1213 b43legacy_phy_write(dev, 0x04AD,
1214 (b43legacy_phy_read(dev, 0x04AD)
1215 & 0x00FF) | 0x1300);
1216 } else if (phy->rev >= 6) {
1217 b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F);
1218 b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F);
1219 b43legacy_phy_write(dev, 0x04AD,
1220 b43legacy_phy_read(dev, 0x04AD)
1221 & 0x00FF);
1223 b43legacy_calc_nrssi_slope(dev);
1224 break;
1225 default:
1226 B43legacy_BUG_ON(1);
1230 static void
1231 b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,
1232 int mode)
1234 struct b43legacy_phy *phy = &dev->phy;
1235 u32 tmp32;
1236 u32 *stack = phy->interfstack;
1238 switch (mode) {
1239 case B43legacy_RADIO_INTERFMODE_NONWLAN:
1240 if (phy->rev != 1) {
1241 b43legacy_phy_write(dev, 0x042B,
1242 b43legacy_phy_read(dev, 0x042B)
1243 & ~0x0800);
1244 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1245 b43legacy_phy_read(dev,
1246 B43legacy_PHY_G_CRS) | 0x4000);
1247 break;
1249 phy_stackrestore(0x0078);
1250 b43legacy_calc_nrssi_threshold(dev);
1251 phy_stackrestore(0x0406);
1252 b43legacy_phy_write(dev, 0x042B,
1253 b43legacy_phy_read(dev, 0x042B) & ~0x0800);
1254 if (!dev->bad_frames_preempt)
1255 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1256 b43legacy_phy_read(dev,
1257 B43legacy_PHY_RADIO_BITFIELD)
1258 & ~(1 << 11));
1259 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1260 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
1261 | 0x4000);
1262 phy_stackrestore(0x04A0);
1263 phy_stackrestore(0x04A1);
1264 phy_stackrestore(0x04A2);
1265 phy_stackrestore(0x04A8);
1266 phy_stackrestore(0x04AB);
1267 phy_stackrestore(0x04A7);
1268 phy_stackrestore(0x04A3);
1269 phy_stackrestore(0x04A9);
1270 phy_stackrestore(0x0493);
1271 phy_stackrestore(0x04AA);
1272 phy_stackrestore(0x04AC);
1273 break;
1274 case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1275 if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))
1276 break;
1278 phy->aci_enable = false;
1280 phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);
1281 phy_stackrestore(B43legacy_PHY_G_CRS);
1282 phy_stackrestore(0x0033);
1283 phy_stackrestore(0x04A3);
1284 phy_stackrestore(0x04A9);
1285 phy_stackrestore(0x0493);
1286 phy_stackrestore(0x04AA);
1287 phy_stackrestore(0x04AC);
1288 phy_stackrestore(0x04A0);
1289 phy_stackrestore(0x04A7);
1290 if (phy->rev >= 2) {
1291 phy_stackrestore(0x04C0);
1292 phy_stackrestore(0x04C1);
1293 } else
1294 phy_stackrestore(0x0406);
1295 phy_stackrestore(0x04A1);
1296 phy_stackrestore(0x04AB);
1297 phy_stackrestore(0x04A8);
1298 if (phy->rev == 2) {
1299 phy_stackrestore(0x04AD);
1300 phy_stackrestore(0x04AE);
1301 } else if (phy->rev >= 3) {
1302 phy_stackrestore(0x04AD);
1303 phy_stackrestore(0x0415);
1304 phy_stackrestore(0x0416);
1305 phy_stackrestore(0x0417);
1306 ilt_stackrestore(0x1A00 + 0x2);
1307 ilt_stackrestore(0x1A00 + 0x3);
1309 phy_stackrestore(0x04A2);
1310 phy_stackrestore(0x04A8);
1311 phy_stackrestore(0x042B);
1312 phy_stackrestore(0x048C);
1313 tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
1314 B43legacy_UCODEFLAGS_OFFSET);
1315 if (tmp32 & 0x800) {
1316 tmp32 &= ~0x800;
1317 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1318 B43legacy_UCODEFLAGS_OFFSET,
1319 tmp32);
1321 b43legacy_calc_nrssi_slope(dev);
1322 break;
1323 default:
1324 B43legacy_BUG_ON(1);
1328 #undef phy_stacksave
1329 #undef phy_stackrestore
1330 #undef radio_stacksave
1331 #undef radio_stackrestore
1332 #undef ilt_stacksave
1333 #undef ilt_stackrestore
1335 int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
1336 int mode)
1338 struct b43legacy_phy *phy = &dev->phy;
1339 int currentmode;
1341 if ((phy->type != B43legacy_PHYTYPE_G) ||
1342 (phy->rev == 0) || (!phy->gmode))
1343 return -ENODEV;
1345 phy->aci_wlan_automatic = false;
1346 switch (mode) {
1347 case B43legacy_RADIO_INTERFMODE_AUTOWLAN:
1348 phy->aci_wlan_automatic = true;
1349 if (phy->aci_enable)
1350 mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN;
1351 else
1352 mode = B43legacy_RADIO_INTERFMODE_NONE;
1353 break;
1354 case B43legacy_RADIO_INTERFMODE_NONE:
1355 case B43legacy_RADIO_INTERFMODE_NONWLAN:
1356 case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1357 break;
1358 default:
1359 return -EINVAL;
1362 currentmode = phy->interfmode;
1363 if (currentmode == mode)
1364 return 0;
1365 if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)
1366 b43legacy_radio_interference_mitigation_disable(dev,
1367 currentmode);
1369 if (mode == B43legacy_RADIO_INTERFMODE_NONE) {
1370 phy->aci_enable = false;
1371 phy->aci_hw_rssi = false;
1372 } else
1373 b43legacy_radio_interference_mitigation_enable(dev, mode);
1374 phy->interfmode = mode;
1376 return 0;
1379 u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev)
1381 u16 reg;
1382 u16 index;
1383 u16 ret;
1385 reg = b43legacy_radio_read16(dev, 0x0060);
1386 index = (reg & 0x001E) >> 1;
1387 ret = rcc_table[index] << 1;
1388 ret |= (reg & 0x0001);
1389 ret |= 0x0020;
1391 return ret;
1394 #define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
1395 static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
1397 struct b43legacy_phy *phy = &dev->phy;
1398 u16 loop_or = 0;
1399 u16 adj_loopback_gain = phy->loopback_gain[0];
1400 u8 loop;
1401 u16 extern_lna_control;
1403 if (!phy->gmode)
1404 return 0;
1405 if (!has_loopback_gain(phy)) {
1406 if (phy->rev < 7 || !(dev->dev->bus->sprom.boardflags_lo
1407 & B43legacy_BFL_EXTLNA)) {
1408 switch (lpd) {
1409 case LPD(0, 1, 1):
1410 return 0x0FB2;
1411 case LPD(0, 0, 1):
1412 return 0x00B2;
1413 case LPD(1, 0, 1):
1414 return 0x30B2;
1415 case LPD(1, 0, 0):
1416 return 0x30B3;
1417 default:
1418 B43legacy_BUG_ON(1);
1420 } else {
1421 switch (lpd) {
1422 case LPD(0, 1, 1):
1423 return 0x8FB2;
1424 case LPD(0, 0, 1):
1425 return 0x80B2;
1426 case LPD(1, 0, 1):
1427 return 0x20B2;
1428 case LPD(1, 0, 0):
1429 return 0x20B3;
1430 default:
1431 B43legacy_BUG_ON(1);
1434 } else {
1435 if (phy->radio_rev == 8)
1436 adj_loopback_gain += 0x003E;
1437 else
1438 adj_loopback_gain += 0x0026;
1439 if (adj_loopback_gain >= 0x46) {
1440 adj_loopback_gain -= 0x46;
1441 extern_lna_control = 0x3000;
1442 } else if (adj_loopback_gain >= 0x3A) {
1443 adj_loopback_gain -= 0x3A;
1444 extern_lna_control = 0x2000;
1445 } else if (adj_loopback_gain >= 0x2E) {
1446 adj_loopback_gain -= 0x2E;
1447 extern_lna_control = 0x1000;
1448 } else {
1449 adj_loopback_gain -= 0x10;
1450 extern_lna_control = 0x0000;
1452 for (loop = 0; loop < 16; loop++) {
1453 u16 tmp = adj_loopback_gain - 6 * loop;
1454 if (tmp < 6)
1455 break;
1458 loop_or = (loop << 8) | extern_lna_control;
1459 if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo
1460 & B43legacy_BFL_EXTLNA) {
1461 if (extern_lna_control)
1462 loop_or |= 0x8000;
1463 switch (lpd) {
1464 case LPD(0, 1, 1):
1465 return 0x8F92;
1466 case LPD(0, 0, 1):
1467 return (0x8092 | loop_or);
1468 case LPD(1, 0, 1):
1469 return (0x2092 | loop_or);
1470 case LPD(1, 0, 0):
1471 return (0x2093 | loop_or);
1472 default:
1473 B43legacy_BUG_ON(1);
1475 } else {
1476 switch (lpd) {
1477 case LPD(0, 1, 1):
1478 return 0x0F92;
1479 case LPD(0, 0, 1):
1480 case LPD(1, 0, 1):
1481 return (0x0092 | loop_or);
1482 case LPD(1, 0, 0):
1483 return (0x0093 | loop_or);
1484 default:
1485 B43legacy_BUG_ON(1);
1489 return 0;
1492 u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)
1494 struct b43legacy_phy *phy = &dev->phy;
1495 u16 backup[21] = { 0 };
1496 u16 ret;
1497 u16 i;
1498 u16 j;
1499 u32 tmp1 = 0;
1500 u32 tmp2 = 0;
1502 backup[0] = b43legacy_radio_read16(dev, 0x0043);
1503 backup[14] = b43legacy_radio_read16(dev, 0x0051);
1504 backup[15] = b43legacy_radio_read16(dev, 0x0052);
1505 backup[1] = b43legacy_phy_read(dev, 0x0015);
1506 backup[16] = b43legacy_phy_read(dev, 0x005A);
1507 backup[17] = b43legacy_phy_read(dev, 0x0059);
1508 backup[18] = b43legacy_phy_read(dev, 0x0058);
1509 if (phy->type == B43legacy_PHYTYPE_B) {
1510 backup[2] = b43legacy_phy_read(dev, 0x0030);
1511 backup[3] = b43legacy_read16(dev, 0x03EC);
1512 b43legacy_phy_write(dev, 0x0030, 0x00FF);
1513 b43legacy_write16(dev, 0x03EC, 0x3F3F);
1514 } else {
1515 if (phy->gmode) {
1516 backup[4] = b43legacy_phy_read(dev, 0x0811);
1517 backup[5] = b43legacy_phy_read(dev, 0x0812);
1518 backup[6] = b43legacy_phy_read(dev, 0x0814);
1519 backup[7] = b43legacy_phy_read(dev, 0x0815);
1520 backup[8] = b43legacy_phy_read(dev,
1521 B43legacy_PHY_G_CRS);
1522 backup[9] = b43legacy_phy_read(dev, 0x0802);
1523 b43legacy_phy_write(dev, 0x0814,
1524 (b43legacy_phy_read(dev, 0x0814)
1525 | 0x0003));
1526 b43legacy_phy_write(dev, 0x0815,
1527 (b43legacy_phy_read(dev, 0x0815)
1528 & 0xFFFC));
1529 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1530 (b43legacy_phy_read(dev,
1531 B43legacy_PHY_G_CRS) & 0x7FFF));
1532 b43legacy_phy_write(dev, 0x0802,
1533 (b43legacy_phy_read(dev, 0x0802)
1534 & 0xFFFC));
1535 if (phy->rev > 1) { /* loopback gain enabled */
1536 backup[19] = b43legacy_phy_read(dev, 0x080F);
1537 backup[20] = b43legacy_phy_read(dev, 0x0810);
1538 if (phy->rev >= 3)
1539 b43legacy_phy_write(dev, 0x080F,
1540 0xC020);
1541 else
1542 b43legacy_phy_write(dev, 0x080F,
1543 0x8020);
1544 b43legacy_phy_write(dev, 0x0810, 0x0000);
1546 b43legacy_phy_write(dev, 0x0812,
1547 b43legacy_get_812_value(dev,
1548 LPD(0, 1, 1)));
1549 if (phy->rev < 7 ||
1550 !(dev->dev->bus->sprom.boardflags_lo
1551 & B43legacy_BFL_EXTLNA))
1552 b43legacy_phy_write(dev, 0x0811, 0x01B3);
1553 else
1554 b43legacy_phy_write(dev, 0x0811, 0x09B3);
1557 b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1558 (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)
1559 | 0x8000));
1560 backup[10] = b43legacy_phy_read(dev, 0x0035);
1561 b43legacy_phy_write(dev, 0x0035,
1562 (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));
1563 backup[11] = b43legacy_read16(dev, 0x03E6);
1564 backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
1566 /* Initialization */
1567 if (phy->analog == 0)
1568 b43legacy_write16(dev, 0x03E6, 0x0122);
1569 else {
1570 if (phy->analog >= 2)
1571 b43legacy_phy_write(dev, 0x0003,
1572 (b43legacy_phy_read(dev, 0x0003)
1573 & 0xFFBF) | 0x0040);
1574 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1575 (b43legacy_read16(dev,
1576 B43legacy_MMIO_CHANNEL_EXT) | 0x2000));
1579 ret = b43legacy_radio_calibrationvalue(dev);
1581 if (phy->type == B43legacy_PHYTYPE_B)
1582 b43legacy_radio_write16(dev, 0x0078, 0x0026);
1584 if (phy->gmode)
1585 b43legacy_phy_write(dev, 0x0812,
1586 b43legacy_get_812_value(dev,
1587 LPD(0, 1, 1)));
1588 b43legacy_phy_write(dev, 0x0015, 0xBFAF);
1589 b43legacy_phy_write(dev, 0x002B, 0x1403);
1590 if (phy->gmode)
1591 b43legacy_phy_write(dev, 0x0812,
1592 b43legacy_get_812_value(dev,
1593 LPD(0, 0, 1)));
1594 b43legacy_phy_write(dev, 0x0015, 0xBFA0);
1595 b43legacy_radio_write16(dev, 0x0051,
1596 (b43legacy_radio_read16(dev, 0x0051)
1597 | 0x0004));
1598 if (phy->radio_rev == 8)
1599 b43legacy_radio_write16(dev, 0x0043, 0x001F);
1600 else {
1601 b43legacy_radio_write16(dev, 0x0052, 0x0000);
1602 b43legacy_radio_write16(dev, 0x0043,
1603 (b43legacy_radio_read16(dev, 0x0043)
1604 & 0xFFF0) | 0x0009);
1606 b43legacy_phy_write(dev, 0x0058, 0x0000);
1608 for (i = 0; i < 16; i++) {
1609 b43legacy_phy_write(dev, 0x005A, 0x0480);
1610 b43legacy_phy_write(dev, 0x0059, 0xC810);
1611 b43legacy_phy_write(dev, 0x0058, 0x000D);
1612 if (phy->gmode)
1613 b43legacy_phy_write(dev, 0x0812,
1614 b43legacy_get_812_value(dev,
1615 LPD(1, 0, 1)));
1616 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1617 udelay(10);
1618 if (phy->gmode)
1619 b43legacy_phy_write(dev, 0x0812,
1620 b43legacy_get_812_value(dev,
1621 LPD(1, 0, 1)));
1622 b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1623 udelay(10);
1624 if (phy->gmode)
1625 b43legacy_phy_write(dev, 0x0812,
1626 b43legacy_get_812_value(dev,
1627 LPD(1, 0, 0)));
1628 b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1629 udelay(20);
1630 tmp1 += b43legacy_phy_read(dev, 0x002D);
1631 b43legacy_phy_write(dev, 0x0058, 0x0000);
1632 if (phy->gmode)
1633 b43legacy_phy_write(dev, 0x0812,
1634 b43legacy_get_812_value(dev,
1635 LPD(1, 0, 1)));
1636 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1639 tmp1++;
1640 tmp1 >>= 9;
1641 udelay(10);
1642 b43legacy_phy_write(dev, 0x0058, 0x0000);
1644 for (i = 0; i < 16; i++) {
1645 b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)
1646 | 0x0020);
1647 backup[13] = b43legacy_radio_read16(dev, 0x0078);
1648 udelay(10);
1649 for (j = 0; j < 16; j++) {
1650 b43legacy_phy_write(dev, 0x005A, 0x0D80);
1651 b43legacy_phy_write(dev, 0x0059, 0xC810);
1652 b43legacy_phy_write(dev, 0x0058, 0x000D);
1653 if (phy->gmode)
1654 b43legacy_phy_write(dev, 0x0812,
1655 b43legacy_get_812_value(dev,
1656 LPD(1, 0, 1)));
1657 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1658 udelay(10);
1659 if (phy->gmode)
1660 b43legacy_phy_write(dev, 0x0812,
1661 b43legacy_get_812_value(dev,
1662 LPD(1, 0, 1)));
1663 b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1664 udelay(10);
1665 if (phy->gmode)
1666 b43legacy_phy_write(dev, 0x0812,
1667 b43legacy_get_812_value(dev,
1668 LPD(1, 0, 0)));
1669 b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1670 udelay(10);
1671 tmp2 += b43legacy_phy_read(dev, 0x002D);
1672 b43legacy_phy_write(dev, 0x0058, 0x0000);
1673 if (phy->gmode)
1674 b43legacy_phy_write(dev, 0x0812,
1675 b43legacy_get_812_value(dev,
1676 LPD(1, 0, 1)));
1677 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1679 tmp2++;
1680 tmp2 >>= 8;
1681 if (tmp1 < tmp2)
1682 break;
1685 /* Restore the registers */
1686 b43legacy_phy_write(dev, 0x0015, backup[1]);
1687 b43legacy_radio_write16(dev, 0x0051, backup[14]);
1688 b43legacy_radio_write16(dev, 0x0052, backup[15]);
1689 b43legacy_radio_write16(dev, 0x0043, backup[0]);
1690 b43legacy_phy_write(dev, 0x005A, backup[16]);
1691 b43legacy_phy_write(dev, 0x0059, backup[17]);
1692 b43legacy_phy_write(dev, 0x0058, backup[18]);
1693 b43legacy_write16(dev, 0x03E6, backup[11]);
1694 if (phy->analog != 0)
1695 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);
1696 b43legacy_phy_write(dev, 0x0035, backup[10]);
1697 b43legacy_radio_selectchannel(dev, phy->channel, 1);
1698 if (phy->type == B43legacy_PHYTYPE_B) {
1699 b43legacy_phy_write(dev, 0x0030, backup[2]);
1700 b43legacy_write16(dev, 0x03EC, backup[3]);
1701 } else {
1702 if (phy->gmode) {
1703 b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1704 (b43legacy_read16(dev,
1705 B43legacy_MMIO_PHY_RADIO) & 0x7FFF));
1706 b43legacy_phy_write(dev, 0x0811, backup[4]);
1707 b43legacy_phy_write(dev, 0x0812, backup[5]);
1708 b43legacy_phy_write(dev, 0x0814, backup[6]);
1709 b43legacy_phy_write(dev, 0x0815, backup[7]);
1710 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1711 backup[8]);
1712 b43legacy_phy_write(dev, 0x0802, backup[9]);
1713 if (phy->rev > 1) {
1714 b43legacy_phy_write(dev, 0x080F, backup[19]);
1715 b43legacy_phy_write(dev, 0x0810, backup[20]);
1719 if (i >= 15)
1720 ret = backup[13];
1722 return ret;
1725 static inline
1726 u16 freq_r3A_value(u16 frequency)
1728 u16 value;
1730 if (frequency < 5091)
1731 value = 0x0040;
1732 else if (frequency < 5321)
1733 value = 0x0000;
1734 else if (frequency < 5806)
1735 value = 0x0080;
1736 else
1737 value = 0x0040;
1739 return value;
1742 int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
1743 u8 channel,
1744 int synthetic_pu_workaround)
1746 struct b43legacy_phy *phy = &dev->phy;
1748 if (channel == 0xFF) {
1749 switch (phy->type) {
1750 case B43legacy_PHYTYPE_B:
1751 case B43legacy_PHYTYPE_G:
1752 channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;
1753 break;
1754 default:
1755 B43legacy_WARN_ON(1);
1759 /* TODO: Check if channel is valid - return -EINVAL if not */
1760 if (synthetic_pu_workaround)
1761 b43legacy_synth_pu_workaround(dev, channel);
1763 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
1764 channel2freq_bg(channel));
1766 if (channel == 14) {
1767 if (dev->dev->bus->sprom.country_code == 5) /* JAPAN) */
1768 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1769 B43legacy_UCODEFLAGS_OFFSET,
1770 b43legacy_shm_read32(dev,
1771 B43legacy_SHM_SHARED,
1772 B43legacy_UCODEFLAGS_OFFSET)
1773 & ~(1 << 7));
1774 else
1775 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1776 B43legacy_UCODEFLAGS_OFFSET,
1777 b43legacy_shm_read32(dev,
1778 B43legacy_SHM_SHARED,
1779 B43legacy_UCODEFLAGS_OFFSET)
1780 | (1 << 7));
1781 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1782 b43legacy_read16(dev,
1783 B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
1784 } else
1785 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1786 b43legacy_read16(dev,
1787 B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
1789 phy->channel = channel;
1790 /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
1791 * that 2000 usecs might suffice. */
1792 msleep(8);
1794 return 0;
1797 void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
1799 u16 tmp;
1801 val <<= 8;
1802 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
1803 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
1804 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
1805 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
1806 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
1807 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
1810 /* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
1811 static u16 b43legacy_get_txgain_base_band(u16 txpower)
1813 u16 ret;
1815 B43legacy_WARN_ON(txpower > 63);
1817 if (txpower >= 54)
1818 ret = 2;
1819 else if (txpower >= 49)
1820 ret = 4;
1821 else if (txpower >= 44)
1822 ret = 5;
1823 else
1824 ret = 6;
1826 return ret;
1829 /* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
1830 static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
1832 u16 ret;
1834 B43legacy_WARN_ON(txpower > 63);
1836 if (txpower >= 32)
1837 ret = 0;
1838 else if (txpower >= 25)
1839 ret = 1;
1840 else if (txpower >= 20)
1841 ret = 2;
1842 else if (txpower >= 12)
1843 ret = 3;
1844 else
1845 ret = 4;
1847 return ret;
1850 /* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
1851 static u16 b43legacy_get_txgain_dac(u16 txpower)
1853 u16 ret;
1855 B43legacy_WARN_ON(txpower > 63);
1857 if (txpower >= 54)
1858 ret = txpower - 53;
1859 else if (txpower >= 49)
1860 ret = txpower - 42;
1861 else if (txpower >= 44)
1862 ret = txpower - 37;
1863 else if (txpower >= 32)
1864 ret = txpower - 32;
1865 else if (txpower >= 25)
1866 ret = txpower - 20;
1867 else if (txpower >= 20)
1868 ret = txpower - 13;
1869 else if (txpower >= 12)
1870 ret = txpower - 8;
1871 else
1872 ret = txpower;
1874 return ret;
1877 void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
1879 struct b43legacy_phy *phy = &dev->phy;
1880 u16 pamp;
1881 u16 base;
1882 u16 dac;
1883 u16 ilt;
1885 txpower = clamp_val(txpower, 0, 63);
1887 pamp = b43legacy_get_txgain_freq_power_amp(txpower);
1888 pamp <<= 5;
1889 pamp &= 0x00E0;
1890 b43legacy_phy_write(dev, 0x0019, pamp);
1892 base = b43legacy_get_txgain_base_band(txpower);
1893 base &= 0x000F;
1894 b43legacy_phy_write(dev, 0x0017, base | 0x0020);
1896 ilt = b43legacy_ilt_read(dev, 0x3001);
1897 ilt &= 0x0007;
1899 dac = b43legacy_get_txgain_dac(txpower);
1900 dac <<= 3;
1901 dac |= ilt;
1903 b43legacy_ilt_write(dev, 0x3001, dac);
1905 phy->txpwr_offset = txpower;
1907 /* TODO: FuncPlaceholder (Adjust BB loft cancel) */
1910 void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
1911 u16 baseband_attenuation,
1912 u16 radio_attenuation,
1913 u16 txpower)
1915 struct b43legacy_phy *phy = &dev->phy;
1917 if (baseband_attenuation == 0xFFFF)
1918 baseband_attenuation = phy->bbatt;
1919 if (radio_attenuation == 0xFFFF)
1920 radio_attenuation = phy->rfatt;
1921 if (txpower == 0xFFFF)
1922 txpower = phy->txctl1;
1923 phy->bbatt = baseband_attenuation;
1924 phy->rfatt = radio_attenuation;
1925 phy->txctl1 = txpower;
1927 B43legacy_WARN_ON(baseband_attenuation > 11);
1928 if (phy->radio_rev < 6)
1929 B43legacy_WARN_ON(radio_attenuation > 9);
1930 else
1931 B43legacy_WARN_ON(radio_attenuation > 31);
1932 B43legacy_WARN_ON(txpower > 7);
1934 b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
1935 b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
1936 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
1937 radio_attenuation);
1938 if (phy->radio_ver == 0x2050)
1939 b43legacy_radio_write16(dev, 0x0052,
1940 (b43legacy_radio_read16(dev, 0x0052)
1941 & ~0x0070) | ((txpower << 4) & 0x0070));
1942 /* FIXME: The spec is very weird and unclear here. */
1943 if (phy->type == B43legacy_PHYTYPE_G)
1944 b43legacy_phy_lo_adjust(dev, 0);
1947 u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
1949 struct b43legacy_phy *phy = &dev->phy;
1951 if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
1952 return 0;
1953 return 2;
1956 u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
1958 struct b43legacy_phy *phy = &dev->phy;
1959 u16 att = 0xFFFF;
1961 switch (phy->radio_ver) {
1962 case 0x2053:
1963 switch (phy->radio_rev) {
1964 case 1:
1965 att = 6;
1966 break;
1968 break;
1969 case 0x2050:
1970 switch (phy->radio_rev) {
1971 case 0:
1972 att = 5;
1973 break;
1974 case 1:
1975 if (phy->type == B43legacy_PHYTYPE_G) {
1976 if (is_bcm_board_vendor(dev) &&
1977 dev->dev->bus->boardinfo.type == 0x421 &&
1978 dev->dev->bus->sprom.board_rev >= 30)
1979 att = 3;
1980 else if (is_bcm_board_vendor(dev) &&
1981 dev->dev->bus->boardinfo.type == 0x416)
1982 att = 3;
1983 else
1984 att = 1;
1985 } else {
1986 if (is_bcm_board_vendor(dev) &&
1987 dev->dev->bus->boardinfo.type == 0x421 &&
1988 dev->dev->bus->sprom.board_rev >= 30)
1989 att = 7;
1990 else
1991 att = 6;
1993 break;
1994 case 2:
1995 if (phy->type == B43legacy_PHYTYPE_G) {
1996 if (is_bcm_board_vendor(dev) &&
1997 dev->dev->bus->boardinfo.type == 0x421 &&
1998 dev->dev->bus->sprom.board_rev >= 30)
1999 att = 3;
2000 else if (is_bcm_board_vendor(dev) &&
2001 dev->dev->bus->boardinfo.type ==
2002 0x416)
2003 att = 5;
2004 else if (dev->dev->bus->chip_id == 0x4320)
2005 att = 4;
2006 else
2007 att = 3;
2008 } else
2009 att = 6;
2010 break;
2011 case 3:
2012 att = 5;
2013 break;
2014 case 4:
2015 case 5:
2016 att = 1;
2017 break;
2018 case 6:
2019 case 7:
2020 att = 5;
2021 break;
2022 case 8:
2023 att = 0x1A;
2024 break;
2025 case 9:
2026 default:
2027 att = 5;
2030 if (is_bcm_board_vendor(dev) &&
2031 dev->dev->bus->boardinfo.type == 0x421) {
2032 if (dev->dev->bus->sprom.board_rev < 0x43)
2033 att = 2;
2034 else if (dev->dev->bus->sprom.board_rev < 0x51)
2035 att = 3;
2037 if (att == 0xFFFF)
2038 att = 5;
2040 return att;
2043 u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
2045 struct b43legacy_phy *phy = &dev->phy;
2047 if (phy->radio_ver != 0x2050)
2048 return 0;
2049 if (phy->radio_rev == 1)
2050 return 3;
2051 if (phy->radio_rev < 6)
2052 return 2;
2053 if (phy->radio_rev == 8)
2054 return 1;
2055 return 0;
2058 void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
2060 struct b43legacy_phy *phy = &dev->phy;
2061 int err;
2062 u8 channel;
2064 might_sleep();
2066 if (phy->radio_on)
2067 return;
2069 switch (phy->type) {
2070 case B43legacy_PHYTYPE_B:
2071 case B43legacy_PHYTYPE_G:
2072 b43legacy_phy_write(dev, 0x0015, 0x8000);
2073 b43legacy_phy_write(dev, 0x0015, 0xCC00);
2074 b43legacy_phy_write(dev, 0x0015,
2075 (phy->gmode ? 0x00C0 : 0x0000));
2076 if (phy->radio_off_context.valid) {
2077 /* Restore the RFover values. */
2078 b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,
2079 phy->radio_off_context.rfover);
2080 b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
2081 phy->radio_off_context.rfoverval);
2082 phy->radio_off_context.valid = false;
2084 channel = phy->channel;
2085 err = b43legacy_radio_selectchannel(dev,
2086 B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
2087 err |= b43legacy_radio_selectchannel(dev, channel, 0);
2088 B43legacy_WARN_ON(err);
2089 break;
2090 default:
2091 B43legacy_BUG_ON(1);
2093 phy->radio_on = true;
2096 void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force)
2098 struct b43legacy_phy *phy = &dev->phy;
2100 if (!phy->radio_on && !force)
2101 return;
2103 if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
2104 u16 rfover, rfoverval;
2106 rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
2107 rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
2108 if (!force) {
2109 phy->radio_off_context.rfover = rfover;
2110 phy->radio_off_context.rfoverval = rfoverval;
2111 phy->radio_off_context.valid = true;
2113 b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
2114 b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
2115 rfoverval & 0xFF73);
2116 } else
2117 b43legacy_phy_write(dev, 0x0015, 0xAA00);
2118 phy->radio_on = false;
2119 b43legacydbg(dev->wl, "Radio initialized\n");
2122 void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
2124 struct b43legacy_phy *phy = &dev->phy;
2126 switch (phy->type) {
2127 case B43legacy_PHYTYPE_B:
2128 case B43legacy_PHYTYPE_G:
2129 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
2130 0x7F7F);
2131 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
2132 0x7F7F);
2133 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
2134 0x7F7F);
2135 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
2136 0x7F7F);
2137 break;