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