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 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 }
2110