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