blob: 2abf125aa2cf63698d87d3cb92de7392f608e7b9 [file] [log] [blame]
Michael Buesche4d6b792007-09-18 15:39:42 -04001/*
2
3 Broadcom B43 wireless driver
4
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Stefano Brivio1f21ad22007-11-06 22:49:20 +01006 Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
Michael Buesche4d6b792007-09-18 15:39:42 -04007 Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
8 Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
9 Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; see the file COPYING. If not, write to
23 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
24 Boston, MA 02110-1301, USA.
25
26*/
27
28#include <linux/delay.h>
Geert Uytterhoeven50e36eb2007-10-13 14:31:30 +020029#include <linux/io.h>
Michael Buesche4d6b792007-09-18 15:39:42 -040030#include <linux/types.h>
31
32#include "b43.h"
33#include "phy.h"
Michael Buesch424047e2008-01-09 16:13:56 +010034#include "nphy.h"
Michael Buesche4d6b792007-09-18 15:39:42 -040035#include "main.h"
36#include "tables.h"
37#include "lo.h"
Stefano Brivio61bca6e2007-11-06 22:49:05 +010038#include "wa.h"
39
Michael Buesche4d6b792007-09-18 15:39:42 -040040
41static const s8 b43_tssi2dbm_b_table[] = {
42 0x4D, 0x4C, 0x4B, 0x4A,
43 0x4A, 0x49, 0x48, 0x47,
44 0x47, 0x46, 0x45, 0x45,
45 0x44, 0x43, 0x42, 0x42,
46 0x41, 0x40, 0x3F, 0x3E,
47 0x3D, 0x3C, 0x3B, 0x3A,
48 0x39, 0x38, 0x37, 0x36,
49 0x35, 0x34, 0x32, 0x31,
50 0x30, 0x2F, 0x2D, 0x2C,
51 0x2B, 0x29, 0x28, 0x26,
52 0x25, 0x23, 0x21, 0x1F,
53 0x1D, 0x1A, 0x17, 0x14,
54 0x10, 0x0C, 0x06, 0x00,
55 -7, -7, -7, -7,
56 -7, -7, -7, -7,
57 -7, -7, -7, -7,
58};
59
60static const s8 b43_tssi2dbm_g_table[] = {
61 77, 77, 77, 76,
62 76, 76, 75, 75,
63 74, 74, 73, 73,
64 73, 72, 72, 71,
65 71, 70, 70, 69,
66 68, 68, 67, 67,
67 66, 65, 65, 64,
68 63, 63, 62, 61,
69 60, 59, 58, 57,
70 56, 55, 54, 53,
71 52, 50, 49, 47,
72 45, 43, 40, 37,
73 33, 28, 22, 14,
74 5, -7, -20, -20,
75 -20, -20, -20, -20,
76 -20, -20, -20, -20,
77};
78
79const u8 b43_radio_channel_codes_bg[] = {
80 12, 17, 22, 27,
81 32, 37, 42, 47,
82 52, 57, 62, 67,
83 72, 84,
84};
85
86static void b43_phy_initg(struct b43_wldev *dev);
87
88/* Reverse the bits of a 4bit value.
89 * Example: 1101 is flipped 1011
90 */
91static u16 flip_4bit(u16 value)
92{
93 u16 flipped = 0x0000;
94
95 B43_WARN_ON(value & ~0x000F);
96
97 flipped |= (value & 0x0001) << 3;
98 flipped |= (value & 0x0002) << 1;
99 flipped |= (value & 0x0004) >> 1;
100 flipped |= (value & 0x0008) >> 3;
101
102 return flipped;
103}
104
105static void generate_rfatt_list(struct b43_wldev *dev,
106 struct b43_rfatt_list *list)
107{
108 struct b43_phy *phy = &dev->phy;
109
110 /* APHY.rev < 5 || GPHY.rev < 6 */
111 static const struct b43_rfatt rfatt_0[] = {
112 {.att = 3,.with_padmix = 0,},
113 {.att = 1,.with_padmix = 0,},
114 {.att = 5,.with_padmix = 0,},
115 {.att = 7,.with_padmix = 0,},
116 {.att = 9,.with_padmix = 0,},
117 {.att = 2,.with_padmix = 0,},
118 {.att = 0,.with_padmix = 0,},
119 {.att = 4,.with_padmix = 0,},
120 {.att = 6,.with_padmix = 0,},
121 {.att = 8,.with_padmix = 0,},
122 {.att = 1,.with_padmix = 1,},
123 {.att = 2,.with_padmix = 1,},
124 {.att = 3,.with_padmix = 1,},
125 {.att = 4,.with_padmix = 1,},
126 };
127 /* Radio.rev == 8 && Radio.version == 0x2050 */
128 static const struct b43_rfatt rfatt_1[] = {
129 {.att = 2,.with_padmix = 1,},
130 {.att = 4,.with_padmix = 1,},
131 {.att = 6,.with_padmix = 1,},
132 {.att = 8,.with_padmix = 1,},
133 {.att = 10,.with_padmix = 1,},
134 {.att = 12,.with_padmix = 1,},
135 {.att = 14,.with_padmix = 1,},
136 };
137 /* Otherwise */
138 static const struct b43_rfatt rfatt_2[] = {
139 {.att = 0,.with_padmix = 1,},
140 {.att = 2,.with_padmix = 1,},
141 {.att = 4,.with_padmix = 1,},
142 {.att = 6,.with_padmix = 1,},
143 {.att = 8,.with_padmix = 1,},
144 {.att = 9,.with_padmix = 1,},
145 {.att = 9,.with_padmix = 1,},
146 };
147
148 if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) ||
149 (phy->type == B43_PHYTYPE_G && phy->rev < 6)) {
150 /* Software pctl */
151 list->list = rfatt_0;
152 list->len = ARRAY_SIZE(rfatt_0);
153 list->min_val = 0;
154 list->max_val = 9;
155 return;
156 }
157 if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
158 /* Hardware pctl */
159 list->list = rfatt_1;
160 list->len = ARRAY_SIZE(rfatt_1);
161 list->min_val = 2;
162 list->max_val = 14;
163 return;
164 }
165 /* Hardware pctl */
166 list->list = rfatt_2;
167 list->len = ARRAY_SIZE(rfatt_2);
168 list->min_val = 0;
169 list->max_val = 9;
170}
171
172static void generate_bbatt_list(struct b43_wldev *dev,
173 struct b43_bbatt_list *list)
174{
175 static const struct b43_bbatt bbatt_0[] = {
176 {.att = 0,},
177 {.att = 1,},
178 {.att = 2,},
179 {.att = 3,},
180 {.att = 4,},
181 {.att = 5,},
182 {.att = 6,},
183 {.att = 7,},
184 {.att = 8,},
185 };
186
187 list->list = bbatt_0;
188 list->len = ARRAY_SIZE(bbatt_0);
189 list->min_val = 0;
190 list->max_val = 8;
191}
192
193bool b43_has_hardware_pctl(struct b43_phy *phy)
194{
195 if (!phy->hardware_power_control)
196 return 0;
197 switch (phy->type) {
198 case B43_PHYTYPE_A:
199 if (phy->rev >= 5)
200 return 1;
201 break;
202 case B43_PHYTYPE_G:
203 if (phy->rev >= 6)
204 return 1;
205 break;
206 default:
207 B43_WARN_ON(1);
208 }
209 return 0;
210}
211
212static void b43_shm_clear_tssi(struct b43_wldev *dev)
213{
214 struct b43_phy *phy = &dev->phy;
215
216 switch (phy->type) {
217 case B43_PHYTYPE_A:
218 b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F);
219 b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F);
220 break;
221 case B43_PHYTYPE_B:
222 case B43_PHYTYPE_G:
223 b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
224 b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
225 b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
226 b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
227 break;
228 }
229}
230
Michael Bueschf31800d2008-01-09 19:08:49 +0100231/* Lock the PHY registers against concurrent access from the microcode.
232 * This lock is nonrecursive. */
233void b43_phy_lock(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -0400234{
Michael Bueschf31800d2008-01-09 19:08:49 +0100235#if B43_DEBUG
236 B43_WARN_ON(dev->phy.phy_locked);
237 dev->phy.phy_locked = 1;
238#endif
239 B43_WARN_ON(dev->dev->id.revision < 3);
Michael Buesche4d6b792007-09-18 15:39:42 -0400240
Michael Bueschf31800d2008-01-09 19:08:49 +0100241 if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
242 b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
Michael Buesche4d6b792007-09-18 15:39:42 -0400243}
244
Michael Bueschf31800d2008-01-09 19:08:49 +0100245void b43_phy_unlock(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -0400246{
Michael Bueschf31800d2008-01-09 19:08:49 +0100247#if B43_DEBUG
248 B43_WARN_ON(!dev->phy.phy_locked);
249 dev->phy.phy_locked = 0;
250#endif
251 B43_WARN_ON(dev->dev->id.revision < 3);
Michael Buesche4d6b792007-09-18 15:39:42 -0400252
Michael Bueschf31800d2008-01-09 19:08:49 +0100253 if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
254 b43_power_saving_ctl_bits(dev, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -0400255}
256
257/* Different PHYs require different register routing flags.
258 * This adjusts (and does sanity checks on) the routing flags.
259 */
260static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy,
261 u16 offset, struct b43_wldev *dev)
262{
263 if (phy->type == B43_PHYTYPE_A) {
264 /* OFDM registers are base-registers for the A-PHY. */
Michael Buesch52507032008-01-09 18:39:09 +0100265 if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
266 offset &= ~B43_PHYROUTE;
267 offset |= B43_PHYROUTE_BASE;
Michael Buesche4d6b792007-09-18 15:39:42 -0400268 }
269 }
270
Michael Buesch52507032008-01-09 18:39:09 +0100271#if B43_DEBUG
272 if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
273 /* Ext-G registers are only available on G-PHYs */
274 if (phy->type != B43_PHYTYPE_G) {
275 b43err(dev->wl, "Invalid EXT-G PHY access at "
276 "0x%04X on PHY type %u\n", offset, phy->type);
277 dump_stack();
278 }
279 }
280 if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) {
281 /* N-BMODE registers are only available on N-PHYs */
282 if (phy->type != B43_PHYTYPE_N) {
283 b43err(dev->wl, "Invalid N-BMODE PHY access at "
284 "0x%04X on PHY type %u\n", offset, phy->type);
285 dump_stack();
286 }
287 }
288#endif /* B43_DEBUG */
289
Michael Buesche4d6b792007-09-18 15:39:42 -0400290 return offset;
291}
292
293u16 b43_phy_read(struct b43_wldev * dev, u16 offset)
294{
295 struct b43_phy *phy = &dev->phy;
296
297 offset = adjust_phyreg_for_phytype(phy, offset, dev);
298 b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
299 return b43_read16(dev, B43_MMIO_PHY_DATA);
300}
301
302void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
303{
304 struct b43_phy *phy = &dev->phy;
305
306 offset = adjust_phyreg_for_phytype(phy, offset, dev);
307 b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
Michael Buesche4d6b792007-09-18 15:39:42 -0400308 b43_write16(dev, B43_MMIO_PHY_DATA, val);
309}
310
Michael Buesche4d6b792007-09-18 15:39:42 -0400311/* Adjust the transmission power output (G-PHY) */
312void b43_set_txpower_g(struct b43_wldev *dev,
313 const struct b43_bbatt *bbatt,
314 const struct b43_rfatt *rfatt, u8 tx_control)
315{
316 struct b43_phy *phy = &dev->phy;
317 struct b43_txpower_lo_control *lo = phy->lo_control;
318 u16 bb, rf;
319 u16 tx_bias, tx_magn;
320
321 bb = bbatt->att;
322 rf = rfatt->att;
323 tx_bias = lo->tx_bias;
324 tx_magn = lo->tx_magn;
325 if (unlikely(tx_bias == 0xFF))
326 tx_bias = 0;
327
328 /* Save the values for later */
329 phy->tx_control = tx_control;
330 memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
331 memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
332
333 if (b43_debug(dev, B43_DBG_XMITPOWER)) {
334 b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), "
335 "rfatt(%u), tx_control(0x%02X), "
336 "tx_bias(0x%02X), tx_magn(0x%02X)\n",
337 bb, rf, tx_control, tx_bias, tx_magn);
338 }
339
340 b43_phy_set_baseband_attenuation(dev, bb);
341 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf);
342 if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
343 b43_radio_write16(dev, 0x43,
344 (rf & 0x000F) | (tx_control & 0x0070));
345 } else {
346 b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
347 & 0xFFF0) | (rf & 0x000F));
348 b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
349 & ~0x0070) | (tx_control &
350 0x0070));
351 }
352 if (has_tx_magnification(phy)) {
353 b43_radio_write16(dev, 0x52, tx_magn | tx_bias);
354 } else {
355 b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
356 & 0xFFF0) | (tx_bias & 0x000F));
357 }
358 if (phy->type == B43_PHYTYPE_G)
359 b43_lo_g_adjust(dev);
360}
361
362static void default_baseband_attenuation(struct b43_wldev *dev,
363 struct b43_bbatt *bb)
364{
365 struct b43_phy *phy = &dev->phy;
366
367 if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
368 bb->att = 0;
369 else
370 bb->att = 2;
371}
372
373static void default_radio_attenuation(struct b43_wldev *dev,
374 struct b43_rfatt *rf)
375{
376 struct ssb_bus *bus = dev->dev->bus;
377 struct b43_phy *phy = &dev->phy;
378
379 rf->with_padmix = 0;
380
381 if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
382 bus->boardinfo.type == SSB_BOARD_BCM4309G) {
383 if (bus->boardinfo.rev < 0x43) {
384 rf->att = 2;
385 return;
386 } else if (bus->boardinfo.rev < 0x51) {
387 rf->att = 3;
388 return;
389 }
390 }
391
392 if (phy->type == B43_PHYTYPE_A) {
393 rf->att = 0x60;
394 return;
395 }
396
397 switch (phy->radio_ver) {
398 case 0x2053:
399 switch (phy->radio_rev) {
400 case 1:
401 rf->att = 6;
402 return;
403 }
404 break;
405 case 0x2050:
406 switch (phy->radio_rev) {
407 case 0:
408 rf->att = 5;
409 return;
410 case 1:
411 if (phy->type == B43_PHYTYPE_G) {
412 if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
413 && bus->boardinfo.type == SSB_BOARD_BCM4309G
414 && bus->boardinfo.rev >= 30)
415 rf->att = 3;
416 else if (bus->boardinfo.vendor ==
417 SSB_BOARDVENDOR_BCM
418 && bus->boardinfo.type ==
419 SSB_BOARD_BU4306)
420 rf->att = 3;
421 else
422 rf->att = 1;
423 } else {
424 if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
425 && bus->boardinfo.type == SSB_BOARD_BCM4309G
426 && bus->boardinfo.rev >= 30)
427 rf->att = 7;
428 else
429 rf->att = 6;
430 }
431 return;
432 case 2:
433 if (phy->type == B43_PHYTYPE_G) {
434 if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
435 && bus->boardinfo.type == SSB_BOARD_BCM4309G
436 && bus->boardinfo.rev >= 30)
437 rf->att = 3;
438 else if (bus->boardinfo.vendor ==
439 SSB_BOARDVENDOR_BCM
440 && bus->boardinfo.type ==
441 SSB_BOARD_BU4306)
442 rf->att = 5;
443 else if (bus->chip_id == 0x4320)
444 rf->att = 4;
445 else
446 rf->att = 3;
447 } else
448 rf->att = 6;
449 return;
450 case 3:
451 rf->att = 5;
452 return;
453 case 4:
454 case 5:
455 rf->att = 1;
456 return;
457 case 6:
458 case 7:
459 rf->att = 5;
460 return;
461 case 8:
462 rf->att = 0xA;
463 rf->with_padmix = 1;
464 return;
465 case 9:
466 default:
467 rf->att = 5;
468 return;
469 }
470 }
471 rf->att = 5;
472}
473
474static u16 default_tx_control(struct b43_wldev *dev)
475{
476 struct b43_phy *phy = &dev->phy;
477
478 if (phy->radio_ver != 0x2050)
479 return 0;
480 if (phy->radio_rev == 1)
481 return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX;
482 if (phy->radio_rev < 6)
483 return B43_TXCTL_PA2DB;
484 if (phy->radio_rev == 8)
485 return B43_TXCTL_TXMIX;
486 return 0;
487}
488
489/* This func is called "PHY calibrate" in the specs... */
490void b43_phy_early_init(struct b43_wldev *dev)
491{
492 struct b43_phy *phy = &dev->phy;
493 struct b43_txpower_lo_control *lo = phy->lo_control;
494
495 default_baseband_attenuation(dev, &phy->bbatt);
496 default_radio_attenuation(dev, &phy->rfatt);
497 phy->tx_control = (default_tx_control(dev) << 4);
498
499 /* Commit previous writes */
500 b43_read32(dev, B43_MMIO_MACCTL);
501
502 if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) {
503 generate_rfatt_list(dev, &lo->rfatt_list);
504 generate_bbatt_list(dev, &lo->bbatt_list);
505 }
506 if (phy->type == B43_PHYTYPE_G && phy->rev == 1) {
507 /* Workaround: Temporarly disable gmode through the early init
508 * phase, as the gmode stuff is not needed for phy rev 1 */
509 phy->gmode = 0;
510 b43_wireless_core_reset(dev, 0);
511 b43_phy_initg(dev);
512 phy->gmode = 1;
513 b43_wireless_core_reset(dev, B43_TMSLOW_GMODE);
514 }
515}
516
517/* GPHY_TSSI_Power_Lookup_Table_Init */
518static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev)
519{
520 struct b43_phy *phy = &dev->phy;
521 int i;
522 u16 value;
523
524 for (i = 0; i < 32; i++)
525 b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]);
526 for (i = 32; i < 64; i++)
527 b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]);
528 for (i = 0; i < 64; i += 2) {
529 value = (u16) phy->tssi2dbm[i];
530 value |= ((u16) phy->tssi2dbm[i + 1]) << 8;
531 b43_phy_write(dev, 0x380 + (i / 2), value);
532 }
533}
534
535/* GPHY_Gain_Lookup_Table_Init */
536static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
537{
538 struct b43_phy *phy = &dev->phy;
539 struct b43_txpower_lo_control *lo = phy->lo_control;
540 u16 nr_written = 0;
541 u16 tmp;
542 u8 rf, bb;
543
544 if (!lo->lo_measured) {
545 b43_phy_write(dev, 0x3FF, 0);
546 return;
547 }
548
549 for (rf = 0; rf < lo->rfatt_list.len; rf++) {
550 for (bb = 0; bb < lo->bbatt_list.len; bb++) {
551 if (nr_written >= 0x40)
552 return;
553 tmp = lo->bbatt_list.list[bb].att;
554 tmp <<= 8;
555 if (phy->radio_rev == 8)
556 tmp |= 0x50;
557 else
558 tmp |= 0x40;
559 tmp |= lo->rfatt_list.list[rf].att;
560 b43_phy_write(dev, 0x3C0 + nr_written, tmp);
561 nr_written++;
562 }
563 }
564}
565
566/* GPHY_DC_Lookup_Table */
567void b43_gphy_dc_lt_init(struct b43_wldev *dev)
568{
569 struct b43_phy *phy = &dev->phy;
570 struct b43_txpower_lo_control *lo = phy->lo_control;
571 struct b43_loctl *loctl0;
572 struct b43_loctl *loctl1;
573 int i;
574 int rf_offset, bb_offset;
575 u16 tmp;
576
577 for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) {
578 rf_offset = i / lo->rfatt_list.len;
579 bb_offset = i % lo->rfatt_list.len;
580
581 loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset],
582 &lo->bbatt_list.list[bb_offset]);
583 if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) {
584 rf_offset = (i + 1) / lo->rfatt_list.len;
585 bb_offset = (i + 1) % lo->rfatt_list.len;
586
587 loctl1 =
588 b43_get_lo_g_ctl(dev,
589 &lo->rfatt_list.list[rf_offset],
590 &lo->bbatt_list.list[bb_offset]);
591 } else
592 loctl1 = loctl0;
593
594 tmp = ((u16) loctl0->q & 0xF);
595 tmp |= ((u16) loctl0->i & 0xF) << 4;
596 tmp |= ((u16) loctl1->q & 0xF) << 8;
597 tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME?
598 b43_phy_write(dev, 0x3A0 + (i / 2), tmp);
599 }
600}
601
602static void hardware_pctl_init_aphy(struct b43_wldev *dev)
603{
604 //TODO
605}
606
607static void hardware_pctl_init_gphy(struct b43_wldev *dev)
608{
609 struct b43_phy *phy = &dev->phy;
610
611 b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0)
612 | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
613 b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00)
614 | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
615 b43_gphy_tssi_power_lt_init(dev);
616 b43_gphy_gain_lt_init(dev);
617 b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF);
618 b43_phy_write(dev, 0x0014, 0x0000);
619
620 B43_WARN_ON(phy->rev < 6);
621 b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
622 | 0x0800);
623 b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
624 & 0xFEFF);
625 b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
626 & 0xFFBF);
627
628 b43_gphy_dc_lt_init(dev);
629}
630
631/* HardwarePowerControl init for A and G PHY */
632static void b43_hardware_pctl_init(struct b43_wldev *dev)
633{
634 struct b43_phy *phy = &dev->phy;
635
636 if (!b43_has_hardware_pctl(phy)) {
637 /* No hardware power control */
638 b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL);
639 return;
640 }
641 /* Init the hwpctl related hardware */
642 switch (phy->type) {
643 case B43_PHYTYPE_A:
644 hardware_pctl_init_aphy(dev);
645 break;
646 case B43_PHYTYPE_G:
647 hardware_pctl_init_gphy(dev);
648 break;
649 default:
650 B43_WARN_ON(1);
651 }
652 /* Enable hardware pctl in firmware. */
653 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL);
654}
655
656static void b43_hardware_pctl_early_init(struct b43_wldev *dev)
657{
658 struct b43_phy *phy = &dev->phy;
659
660 if (!b43_has_hardware_pctl(phy)) {
661 b43_phy_write(dev, 0x047A, 0xC111);
662 return;
663 }
664
665 b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF);
666 b43_phy_write(dev, 0x002F, 0x0202);
667 b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002);
668 b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000);
669 if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
670 b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
671 & 0xFF0F) | 0x0010);
672 b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
673 | 0x8000);
674 b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
675 & 0xFFC0) | 0x0010);
676 b43_phy_write(dev, 0x002E, 0xC07F);
677 b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
678 | 0x0400);
679 } else {
680 b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
681 | 0x0200);
682 b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
683 | 0x0400);
684 b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
685 & 0x7FFF);
686 b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F)
687 & 0xFFFE);
688 b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
689 & 0xFFC0) | 0x0010);
690 b43_phy_write(dev, 0x002E, 0xC07F);
691 b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
692 & 0xFF0F) | 0x0010);
693 }
694}
695
696/* Intialize B/G PHY power control
697 * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
698 */
699static void b43_phy_init_pctl(struct b43_wldev *dev)
700{
701 struct ssb_bus *bus = dev->dev->bus;
702 struct b43_phy *phy = &dev->phy;
703 struct b43_rfatt old_rfatt;
704 struct b43_bbatt old_bbatt;
705 u8 old_tx_control = 0;
706
707 if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
708 (bus->boardinfo.type == SSB_BOARD_BU4306))
709 return;
710
711 b43_phy_write(dev, 0x0028, 0x8018);
712
713 /* This does something with the Analog... */
714 b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0)
715 & 0xFFDF);
716
717 if (phy->type == B43_PHYTYPE_G && !phy->gmode)
718 return;
719 b43_hardware_pctl_early_init(dev);
720 if (phy->cur_idle_tssi == 0) {
721 if (phy->radio_ver == 0x2050 && phy->analog == 0) {
722 b43_radio_write16(dev, 0x0076,
723 (b43_radio_read16(dev, 0x0076)
724 & 0x00F7) | 0x0084);
725 } else {
726 struct b43_rfatt rfatt;
727 struct b43_bbatt bbatt;
728
729 memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt));
730 memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt));
731 old_tx_control = phy->tx_control;
732
733 bbatt.att = 11;
734 if (phy->radio_rev == 8) {
735 rfatt.att = 15;
736 rfatt.with_padmix = 1;
737 } else {
738 rfatt.att = 9;
739 rfatt.with_padmix = 0;
740 }
741 b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
742 }
743 b43_dummy_transmission(dev);
744 phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
745 if (B43_DEBUG) {
746 /* Current-Idle-TSSI sanity check. */
747 if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) {
748 b43dbg(dev->wl,
749 "!WARNING! Idle-TSSI phy->cur_idle_tssi "
750 "measuring failed. (cur=%d, tgt=%d). Disabling TX power "
751 "adjustment.\n", phy->cur_idle_tssi,
752 phy->tgt_idle_tssi);
753 phy->cur_idle_tssi = 0;
754 }
755 }
756 if (phy->radio_ver == 0x2050 && phy->analog == 0) {
757 b43_radio_write16(dev, 0x0076,
758 b43_radio_read16(dev, 0x0076)
759 & 0xFF7B);
760 } else {
761 b43_set_txpower_g(dev, &old_bbatt,
762 &old_rfatt, old_tx_control);
763 }
764 }
765 b43_hardware_pctl_init(dev);
766 b43_shm_clear_tssi(dev);
767}
768
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100769static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable)
Michael Buesche4d6b792007-09-18 15:39:42 -0400770{
Michael Buesche4d6b792007-09-18 15:39:42 -0400771 int i;
772
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100773 if (dev->phy.rev < 3) {
774 if (enable)
775 for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
776 b43_ofdmtab_write16(dev,
777 B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8);
778 b43_ofdmtab_write16(dev,
779 B43_OFDMTAB_WRSSI, i, 0xFFF8);
780 }
Michael Buesche4d6b792007-09-18 15:39:42 -0400781 else
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100782 for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
783 b43_ofdmtab_write16(dev,
784 B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]);
785 b43_ofdmtab_write16(dev,
786 B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]);
787 }
788 } else {
789 if (enable)
790 for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++)
791 b43_ofdmtab_write16(dev,
792 B43_OFDMTAB_WRSSI, i, 0x0820);
Michael Buesche4d6b792007-09-18 15:39:42 -0400793 else
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100794 for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++)
795 b43_ofdmtab_write16(dev,
796 B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]);
Michael Buesche4d6b792007-09-18 15:39:42 -0400797 }
Michael Buesche4d6b792007-09-18 15:39:42 -0400798}
799
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100800static void b43_phy_ww(struct b43_wldev *dev)
Michael Buesche4d6b792007-09-18 15:39:42 -0400801{
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100802 u16 b, curr_s, best_s = 0xFFFF;
803 int i;
Michael Buesche4d6b792007-09-18 15:39:42 -0400804
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100805 b43_phy_write(dev, B43_PHY_CRS0,
806 b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN);
807 b43_phy_write(dev, B43_PHY_OFDM(0x1B),
808 b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000);
809 b43_phy_write(dev, B43_PHY_OFDM(0x82),
810 (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300);
811 b43_radio_write16(dev, 0x0009,
812 b43_radio_read16(dev, 0x0009) | 0x0080);
813 b43_radio_write16(dev, 0x0012,
814 (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002);
815 b43_wa_initgains(dev);
816 b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5);
817 b = b43_phy_read(dev, B43_PHY_PWRDOWN);
818 b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005);
819 b43_radio_write16(dev, 0x0004,
820 b43_radio_read16(dev, 0x0004) | 0x0004);
821 for (i = 0x10; i <= 0x20; i++) {
822 b43_radio_write16(dev, 0x0013, i);
823 curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF;
824 if (!curr_s) {
825 best_s = 0x0000;
826 break;
827 } else if (curr_s >= 0x0080)
828 curr_s = 0x0100 - curr_s;
829 if (curr_s < best_s)
830 best_s = curr_s;
Michael Buesche4d6b792007-09-18 15:39:42 -0400831 }
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100832 b43_phy_write(dev, B43_PHY_PWRDOWN, b);
833 b43_radio_write16(dev, 0x0004,
834 b43_radio_read16(dev, 0x0004) & 0xFFFB);
835 b43_radio_write16(dev, 0x0013, best_s);
836 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC);
837 b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80);
838 b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00);
839 b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0);
840 b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0);
841 b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF);
842 b43_phy_write(dev, B43_PHY_OFDM(0xBB),
843 (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
844 b43_phy_write(dev, B43_PHY_OFDM61,
845 (b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120);
846 b43_phy_write(dev, B43_PHY_OFDM(0x13),
847 (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
848 b43_phy_write(dev, B43_PHY_OFDM(0x14),
849 (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000);
850 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017);
851 for (i = 0; i < 6; i++)
852 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F);
853 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E);
854 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011);
855 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013);
856 b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030);
857 b43_phy_write(dev, B43_PHY_CRS0,
858 b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
Michael Buesche4d6b792007-09-18 15:39:42 -0400859}
860
861/* Initialize APHY. This is also called for the GPHY in some cases. */
862static void b43_phy_inita(struct b43_wldev *dev)
863{
864 struct ssb_bus *bus = dev->dev->bus;
865 struct b43_phy *phy = &dev->phy;
Michael Buesche4d6b792007-09-18 15:39:42 -0400866
867 might_sleep();
868
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100869 if (phy->rev >= 6) {
870 if (phy->type == B43_PHYTYPE_A)
871 b43_phy_write(dev, B43_PHY_OFDM(0x1B),
872 b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000);
873 if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
874 b43_phy_write(dev, B43_PHY_ENCORE,
875 b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010);
876 else
877 b43_phy_write(dev, B43_PHY_ENCORE,
878 b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010);
879 }
880
881 b43_wa_all(dev);
882
Michael Buesche4d6b792007-09-18 15:39:42 -0400883 if (phy->type == B43_PHYTYPE_A) {
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100884 if (phy->gmode && (phy->rev < 3))
885 b43_phy_write(dev, 0x0034,
886 b43_phy_read(dev, 0x0034) | 0x0001);
887 b43_phy_rssiagc(dev, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -0400888
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100889 b43_phy_write(dev, B43_PHY_CRS0,
890 b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
Michael Buesche4d6b792007-09-18 15:39:42 -0400891
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100892 b43_radio_init2060(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -0400893
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100894 if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
895 ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
896 (bus->boardinfo.type == SSB_BOARD_BU4309))) {
897 ; //TODO: A PHY LO
Michael Buesche4d6b792007-09-18 15:39:42 -0400898 }
Michael Buesche4d6b792007-09-18 15:39:42 -0400899
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100900 if (phy->rev >= 3)
901 b43_phy_ww(dev);
902
903 hardware_pctl_init_aphy(dev);
904
905 //TODO: radar detection
Michael Buesche4d6b792007-09-18 15:39:42 -0400906 }
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100907
908 if ((phy->type == B43_PHYTYPE_G) &&
Larry Finger95de2842007-11-09 16:57:18 -0600909 (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
Stefano Brivio61bca6e2007-11-06 22:49:05 +0100910 b43_phy_write(dev, B43_PHY_OFDM(0x6E),
911 (b43_phy_read(dev, B43_PHY_OFDM(0x6E))
912 & 0xE000) | 0x3CF);
913 }
Michael Buesche4d6b792007-09-18 15:39:42 -0400914}
915
916static void b43_phy_initb2(struct b43_wldev *dev)
917{
918 struct b43_phy *phy = &dev->phy;
919 u16 offset, val;
920
921 b43_write16(dev, 0x03EC, 0x3F22);
922 b43_phy_write(dev, 0x0020, 0x301C);
923 b43_phy_write(dev, 0x0026, 0x0000);
924 b43_phy_write(dev, 0x0030, 0x00C6);
925 b43_phy_write(dev, 0x0088, 0x3E00);
926 val = 0x3C3D;
927 for (offset = 0x0089; offset < 0x00A7; offset++) {
928 b43_phy_write(dev, offset, val);
929 val -= 0x0202;
930 }
931 b43_phy_write(dev, 0x03E4, 0x3000);
Michael Bueschfda9abc2007-09-20 22:14:18 +0200932 b43_radio_selectchannel(dev, phy->channel, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -0400933 if (phy->radio_ver != 0x2050) {
934 b43_radio_write16(dev, 0x0075, 0x0080);
935 b43_radio_write16(dev, 0x0079, 0x0081);
936 }
937 b43_radio_write16(dev, 0x0050, 0x0020);
938 b43_radio_write16(dev, 0x0050, 0x0023);
939 if (phy->radio_ver == 0x2050) {
940 b43_radio_write16(dev, 0x0050, 0x0020);
941 b43_radio_write16(dev, 0x005A, 0x0070);
942 b43_radio_write16(dev, 0x005B, 0x007B);
943 b43_radio_write16(dev, 0x005C, 0x00B0);
944 b43_radio_write16(dev, 0x007A, 0x000F);
945 b43_phy_write(dev, 0x0038, 0x0677);
946 b43_radio_init2050(dev);
947 }
948 b43_phy_write(dev, 0x0014, 0x0080);
949 b43_phy_write(dev, 0x0032, 0x00CA);
950 b43_phy_write(dev, 0x0032, 0x00CC);
951 b43_phy_write(dev, 0x0035, 0x07C2);
952 b43_lo_b_measure(dev);
953 b43_phy_write(dev, 0x0026, 0xCC00);
954 if (phy->radio_ver != 0x2050)
955 b43_phy_write(dev, 0x0026, 0xCE00);
956 b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000);
957 b43_phy_write(dev, 0x002A, 0x88A3);
958 if (phy->radio_ver != 0x2050)
959 b43_phy_write(dev, 0x002A, 0x88C2);
960 b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
961 b43_phy_init_pctl(dev);
962}
963
964static void b43_phy_initb4(struct b43_wldev *dev)
965{
966 struct b43_phy *phy = &dev->phy;
967 u16 offset, val;
968
969 b43_write16(dev, 0x03EC, 0x3F22);
970 b43_phy_write(dev, 0x0020, 0x301C);
971 b43_phy_write(dev, 0x0026, 0x0000);
972 b43_phy_write(dev, 0x0030, 0x00C6);
973 b43_phy_write(dev, 0x0088, 0x3E00);
974 val = 0x3C3D;
975 for (offset = 0x0089; offset < 0x00A7; offset++) {
976 b43_phy_write(dev, offset, val);
977 val -= 0x0202;
978 }
979 b43_phy_write(dev, 0x03E4, 0x3000);
Michael Bueschfda9abc2007-09-20 22:14:18 +0200980 b43_radio_selectchannel(dev, phy->channel, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -0400981 if (phy->radio_ver != 0x2050) {
982 b43_radio_write16(dev, 0x0075, 0x0080);
983 b43_radio_write16(dev, 0x0079, 0x0081);
984 }
985 b43_radio_write16(dev, 0x0050, 0x0020);
986 b43_radio_write16(dev, 0x0050, 0x0023);
987 if (phy->radio_ver == 0x2050) {
988 b43_radio_write16(dev, 0x0050, 0x0020);
989 b43_radio_write16(dev, 0x005A, 0x0070);
990 b43_radio_write16(dev, 0x005B, 0x007B);
991 b43_radio_write16(dev, 0x005C, 0x00B0);
992 b43_radio_write16(dev, 0x007A, 0x000F);
993 b43_phy_write(dev, 0x0038, 0x0677);
994 b43_radio_init2050(dev);
995 }
996 b43_phy_write(dev, 0x0014, 0x0080);
997 b43_phy_write(dev, 0x0032, 0x00CA);
998 if (phy->radio_ver == 0x2050)
999 b43_phy_write(dev, 0x0032, 0x00E0);
1000 b43_phy_write(dev, 0x0035, 0x07C2);
1001
1002 b43_lo_b_measure(dev);
1003
1004 b43_phy_write(dev, 0x0026, 0xCC00);
1005 if (phy->radio_ver == 0x2050)
1006 b43_phy_write(dev, 0x0026, 0xCE00);
1007 b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100);
1008 b43_phy_write(dev, 0x002A, 0x88A3);
1009 if (phy->radio_ver == 0x2050)
1010 b43_phy_write(dev, 0x002A, 0x88C2);
1011 b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
Larry Finger95de2842007-11-09 16:57:18 -06001012 if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001013 b43_calc_nrssi_slope(dev);
1014 b43_calc_nrssi_threshold(dev);
1015 }
1016 b43_phy_init_pctl(dev);
1017}
1018
1019static void b43_phy_initb5(struct b43_wldev *dev)
1020{
1021 struct ssb_bus *bus = dev->dev->bus;
1022 struct b43_phy *phy = &dev->phy;
1023 u16 offset, value;
1024 u8 old_channel;
1025
1026 if (phy->analog == 1) {
1027 b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
1028 | 0x0050);
1029 }
1030 if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
1031 (bus->boardinfo.type != SSB_BOARD_BU4306)) {
1032 value = 0x2120;
1033 for (offset = 0x00A8; offset < 0x00C7; offset++) {
1034 b43_phy_write(dev, offset, value);
1035 value += 0x202;
1036 }
1037 }
1038 b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF)
1039 | 0x0700);
1040 if (phy->radio_ver == 0x2050)
1041 b43_phy_write(dev, 0x0038, 0x0667);
1042
1043 if (phy->gmode || phy->rev >= 2) {
1044 if (phy->radio_ver == 0x2050) {
1045 b43_radio_write16(dev, 0x007A,
1046 b43_radio_read16(dev, 0x007A)
1047 | 0x0020);
1048 b43_radio_write16(dev, 0x0051,
1049 b43_radio_read16(dev, 0x0051)
1050 | 0x0004);
1051 }
1052 b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000);
1053
1054 b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
1055 b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
1056
1057 b43_phy_write(dev, 0x001C, 0x186A);
1058
1059 b43_phy_write(dev, 0x0013,
1060 (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900);
1061 b43_phy_write(dev, 0x0035,
1062 (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064);
1063 b43_phy_write(dev, 0x005D,
1064 (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A);
1065 }
1066
1067 if (dev->bad_frames_preempt) {
1068 b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
1069 b43_phy_read(dev,
1070 B43_PHY_RADIO_BITFIELD) | (1 << 11));
1071 }
1072
1073 if (phy->analog == 1) {
1074 b43_phy_write(dev, 0x0026, 0xCE00);
1075 b43_phy_write(dev, 0x0021, 0x3763);
1076 b43_phy_write(dev, 0x0022, 0x1BC3);
1077 b43_phy_write(dev, 0x0023, 0x06F9);
1078 b43_phy_write(dev, 0x0024, 0x037E);
1079 } else
1080 b43_phy_write(dev, 0x0026, 0xCC00);
1081 b43_phy_write(dev, 0x0030, 0x00C6);
1082 b43_write16(dev, 0x03EC, 0x3F22);
1083
1084 if (phy->analog == 1)
1085 b43_phy_write(dev, 0x0020, 0x3E1C);
1086 else
1087 b43_phy_write(dev, 0x0020, 0x301C);
1088
1089 if (phy->analog == 0)
1090 b43_write16(dev, 0x03E4, 0x3000);
1091
1092 old_channel = phy->channel;
1093 /* Force to channel 7, even if not supported. */
1094 b43_radio_selectchannel(dev, 7, 0);
1095
1096 if (phy->radio_ver != 0x2050) {
1097 b43_radio_write16(dev, 0x0075, 0x0080);
1098 b43_radio_write16(dev, 0x0079, 0x0081);
1099 }
1100
1101 b43_radio_write16(dev, 0x0050, 0x0020);
1102 b43_radio_write16(dev, 0x0050, 0x0023);
1103
1104 if (phy->radio_ver == 0x2050) {
1105 b43_radio_write16(dev, 0x0050, 0x0020);
1106 b43_radio_write16(dev, 0x005A, 0x0070);
1107 }
1108
1109 b43_radio_write16(dev, 0x005B, 0x007B);
1110 b43_radio_write16(dev, 0x005C, 0x00B0);
1111
1112 b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007);
1113
1114 b43_radio_selectchannel(dev, old_channel, 0);
1115
1116 b43_phy_write(dev, 0x0014, 0x0080);
1117 b43_phy_write(dev, 0x0032, 0x00CA);
1118 b43_phy_write(dev, 0x002A, 0x88A3);
1119
1120 b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
1121
1122 if (phy->radio_ver == 0x2050)
1123 b43_radio_write16(dev, 0x005D, 0x000D);
1124
1125 b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004);
1126}
1127
1128static void b43_phy_initb6(struct b43_wldev *dev)
1129{
1130 struct b43_phy *phy = &dev->phy;
1131 u16 offset, val;
1132 u8 old_channel;
1133
1134 b43_phy_write(dev, 0x003E, 0x817A);
1135 b43_radio_write16(dev, 0x007A,
1136 (b43_radio_read16(dev, 0x007A) | 0x0058));
1137 if (phy->radio_rev == 4 || phy->radio_rev == 5) {
1138 b43_radio_write16(dev, 0x51, 0x37);
1139 b43_radio_write16(dev, 0x52, 0x70);
1140 b43_radio_write16(dev, 0x53, 0xB3);
1141 b43_radio_write16(dev, 0x54, 0x9B);
1142 b43_radio_write16(dev, 0x5A, 0x88);
1143 b43_radio_write16(dev, 0x5B, 0x88);
1144 b43_radio_write16(dev, 0x5D, 0x88);
1145 b43_radio_write16(dev, 0x5E, 0x88);
1146 b43_radio_write16(dev, 0x7D, 0x88);
1147 b43_hf_write(dev, b43_hf_read(dev)
1148 | B43_HF_TSSIRPSMW);
1149 }
1150 B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */
1151 if (phy->radio_rev == 8) {
1152 b43_radio_write16(dev, 0x51, 0);
1153 b43_radio_write16(dev, 0x52, 0x40);
1154 b43_radio_write16(dev, 0x53, 0xB7);
1155 b43_radio_write16(dev, 0x54, 0x98);
1156 b43_radio_write16(dev, 0x5A, 0x88);
1157 b43_radio_write16(dev, 0x5B, 0x6B);
1158 b43_radio_write16(dev, 0x5C, 0x0F);
Larry Finger95de2842007-11-09 16:57:18 -06001159 if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001160 b43_radio_write16(dev, 0x5D, 0xFA);
1161 b43_radio_write16(dev, 0x5E, 0xD8);
1162 } else {
1163 b43_radio_write16(dev, 0x5D, 0xF5);
1164 b43_radio_write16(dev, 0x5E, 0xB8);
1165 }
1166 b43_radio_write16(dev, 0x0073, 0x0003);
1167 b43_radio_write16(dev, 0x007D, 0x00A8);
1168 b43_radio_write16(dev, 0x007C, 0x0001);
1169 b43_radio_write16(dev, 0x007E, 0x0008);
1170 }
1171 val = 0x1E1F;
1172 for (offset = 0x0088; offset < 0x0098; offset++) {
1173 b43_phy_write(dev, offset, val);
1174 val -= 0x0202;
1175 }
1176 val = 0x3E3F;
1177 for (offset = 0x0098; offset < 0x00A8; offset++) {
1178 b43_phy_write(dev, offset, val);
1179 val -= 0x0202;
1180 }
1181 val = 0x2120;
1182 for (offset = 0x00A8; offset < 0x00C8; offset++) {
1183 b43_phy_write(dev, offset, (val & 0x3F3F));
1184 val += 0x0202;
1185 }
1186 if (phy->type == B43_PHYTYPE_G) {
1187 b43_radio_write16(dev, 0x007A,
1188 b43_radio_read16(dev, 0x007A) | 0x0020);
1189 b43_radio_write16(dev, 0x0051,
1190 b43_radio_read16(dev, 0x0051) | 0x0004);
1191 b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
1192 b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
1193 b43_phy_write(dev, 0x5B, 0);
1194 b43_phy_write(dev, 0x5C, 0);
1195 }
1196
1197 old_channel = phy->channel;
1198 if (old_channel >= 8)
1199 b43_radio_selectchannel(dev, 1, 0);
1200 else
1201 b43_radio_selectchannel(dev, 13, 0);
1202
1203 b43_radio_write16(dev, 0x0050, 0x0020);
1204 b43_radio_write16(dev, 0x0050, 0x0023);
1205 udelay(40);
1206 if (phy->radio_rev < 6 || phy->radio_rev == 8) {
1207 b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C)
1208 | 0x0002));
1209 b43_radio_write16(dev, 0x50, 0x20);
1210 }
1211 if (phy->radio_rev <= 2) {
1212 b43_radio_write16(dev, 0x7C, 0x20);
1213 b43_radio_write16(dev, 0x5A, 0x70);
1214 b43_radio_write16(dev, 0x5B, 0x7B);
1215 b43_radio_write16(dev, 0x5C, 0xB0);
1216 }
1217 b43_radio_write16(dev, 0x007A,
1218 (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007);
1219
1220 b43_radio_selectchannel(dev, old_channel, 0);
1221
1222 b43_phy_write(dev, 0x0014, 0x0200);
1223 if (phy->radio_rev >= 6)
1224 b43_phy_write(dev, 0x2A, 0x88C2);
1225 else
1226 b43_phy_write(dev, 0x2A, 0x8AC0);
1227 b43_phy_write(dev, 0x0038, 0x0668);
1228 b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
1229 if (phy->radio_rev <= 5) {
1230 b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D)
1231 & 0xFF80) | 0x0003);
1232 }
1233 if (phy->radio_rev <= 2)
1234 b43_radio_write16(dev, 0x005D, 0x000D);
1235
1236 if (phy->analog == 4) {
1237 b43_write16(dev, 0x3E4, 9);
1238 b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61)
1239 & 0x0FFF);
1240 } else {
1241 b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
1242 | 0x0004);
1243 }
1244 if (phy->type == B43_PHYTYPE_B) {
1245 b43_write16(dev, 0x03E6, 0x8140);
1246 b43_phy_write(dev, 0x0016, 0x0410);
1247 b43_phy_write(dev, 0x0017, 0x0820);
1248 b43_phy_write(dev, 0x0062, 0x0007);
1249 b43_radio_init2050(dev);
1250 b43_lo_g_measure(dev);
Larry Finger95de2842007-11-09 16:57:18 -06001251 if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001252 b43_calc_nrssi_slope(dev);
1253 b43_calc_nrssi_threshold(dev);
1254 }
1255 b43_phy_init_pctl(dev);
1256 } else if (phy->type == B43_PHYTYPE_G)
1257 b43_write16(dev, 0x03E6, 0x0);
1258}
1259
1260static void b43_calc_loopback_gain(struct b43_wldev *dev)
1261{
1262 struct b43_phy *phy = &dev->phy;
1263 u16 backup_phy[16] = { 0 };
1264 u16 backup_radio[3];
1265 u16 backup_bband;
1266 u16 i, j, loop_i_max;
1267 u16 trsw_rx;
1268 u16 loop1_outer_done, loop1_inner_done;
1269
1270 backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0);
1271 backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
1272 backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER);
1273 backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL);
1274 if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
1275 backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
1276 backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
1277 }
Michael Buesch52507032008-01-09 18:39:09 +01001278 backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A));
1279 backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59));
1280 backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58));
1281 backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A));
1282 backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03));
Michael Buesche4d6b792007-09-18 15:39:42 -04001283 backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
1284 backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
Michael Buesch52507032008-01-09 18:39:09 +01001285 backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B));
Michael Buesche4d6b792007-09-18 15:39:42 -04001286 backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
1287 backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
1288 backup_bband = phy->bbatt.att;
1289 backup_radio[0] = b43_radio_read16(dev, 0x52);
1290 backup_radio[1] = b43_radio_read16(dev, 0x43);
1291 backup_radio[2] = b43_radio_read16(dev, 0x7A);
1292
1293 b43_phy_write(dev, B43_PHY_CRS0,
1294 b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF);
1295 b43_phy_write(dev, B43_PHY_CCKBBANDCFG,
1296 b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000);
1297 b43_phy_write(dev, B43_PHY_RFOVER,
1298 b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002);
1299 b43_phy_write(dev, B43_PHY_RFOVERVAL,
1300 b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD);
1301 b43_phy_write(dev, B43_PHY_RFOVER,
1302 b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001);
1303 b43_phy_write(dev, B43_PHY_RFOVERVAL,
1304 b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE);
1305 if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
1306 b43_phy_write(dev, B43_PHY_ANALOGOVER,
1307 b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001);
1308 b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
1309 b43_phy_read(dev,
1310 B43_PHY_ANALOGOVERVAL) & 0xFFFE);
1311 b43_phy_write(dev, B43_PHY_ANALOGOVER,
1312 b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002);
1313 b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
1314 b43_phy_read(dev,
1315 B43_PHY_ANALOGOVERVAL) & 0xFFFD);
1316 }
1317 b43_phy_write(dev, B43_PHY_RFOVER,
1318 b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C);
1319 b43_phy_write(dev, B43_PHY_RFOVERVAL,
1320 b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C);
1321 b43_phy_write(dev, B43_PHY_RFOVER,
1322 b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030);
1323 b43_phy_write(dev, B43_PHY_RFOVERVAL,
1324 (b43_phy_read(dev, B43_PHY_RFOVERVAL)
1325 & 0xFFCF) | 0x10);
1326
Michael Buesch52507032008-01-09 18:39:09 +01001327 b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
1328 b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
1329 b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
Michael Buesche4d6b792007-09-18 15:39:42 -04001330
Michael Buesch52507032008-01-09 18:39:09 +01001331 b43_phy_write(dev, B43_PHY_CCK(0x0A),
1332 b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000);
Michael Buesche4d6b792007-09-18 15:39:42 -04001333 if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
1334 b43_phy_write(dev, B43_PHY_ANALOGOVER,
1335 b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
1336 b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
1337 b43_phy_read(dev,
1338 B43_PHY_ANALOGOVERVAL) & 0xFFFB);
1339 }
Michael Buesch52507032008-01-09 18:39:09 +01001340 b43_phy_write(dev, B43_PHY_CCK(0x03),
1341 (b43_phy_read(dev, B43_PHY_CCK(0x03))
Michael Buesche4d6b792007-09-18 15:39:42 -04001342 & 0xFF9F) | 0x40);
1343
1344 if (phy->radio_rev == 8) {
1345 b43_radio_write16(dev, 0x43, 0x000F);
1346 } else {
1347 b43_radio_write16(dev, 0x52, 0);
1348 b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
1349 & 0xFFF0) | 0x9);
1350 }
1351 b43_phy_set_baseband_attenuation(dev, 11);
1352
1353 if (phy->rev >= 3)
1354 b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
1355 else
1356 b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
1357 b43_phy_write(dev, B43_PHY_LO_CTL, 0);
1358
Michael Buesch52507032008-01-09 18:39:09 +01001359 b43_phy_write(dev, B43_PHY_CCK(0x2B),
1360 (b43_phy_read(dev, B43_PHY_CCK(0x2B))
Michael Buesche4d6b792007-09-18 15:39:42 -04001361 & 0xFFC0) | 0x01);
Michael Buesch52507032008-01-09 18:39:09 +01001362 b43_phy_write(dev, B43_PHY_CCK(0x2B),
1363 (b43_phy_read(dev, B43_PHY_CCK(0x2B))
Michael Buesche4d6b792007-09-18 15:39:42 -04001364 & 0xC0FF) | 0x800);
1365
1366 b43_phy_write(dev, B43_PHY_RFOVER,
1367 b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100);
1368 b43_phy_write(dev, B43_PHY_RFOVERVAL,
1369 b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
1370
Larry Finger95de2842007-11-09 16:57:18 -06001371 if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001372 if (phy->rev >= 7) {
1373 b43_phy_write(dev, B43_PHY_RFOVER,
1374 b43_phy_read(dev, B43_PHY_RFOVER)
1375 | 0x0800);
1376 b43_phy_write(dev, B43_PHY_RFOVERVAL,
1377 b43_phy_read(dev, B43_PHY_RFOVERVAL)
1378 | 0x8000);
1379 }
1380 }
1381 b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A)
1382 & 0x00F7);
1383
1384 j = 0;
1385 loop_i_max = (phy->radio_rev == 8) ? 15 : 9;
1386 for (i = 0; i < loop_i_max; i++) {
1387 for (j = 0; j < 16; j++) {
1388 b43_radio_write16(dev, 0x43, i);
1389 b43_phy_write(dev, B43_PHY_RFOVERVAL,
1390 (b43_phy_read(dev, B43_PHY_RFOVERVAL)
1391 & 0xF0FF) | (j << 8));
1392 b43_phy_write(dev, B43_PHY_PGACTL,
1393 (b43_phy_read(dev, B43_PHY_PGACTL)
1394 & 0x0FFF) | 0xA000);
1395 b43_phy_write(dev, B43_PHY_PGACTL,
1396 b43_phy_read(dev, B43_PHY_PGACTL)
1397 | 0xF000);
1398 udelay(20);
1399 if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
1400 goto exit_loop1;
1401 }
1402 }
1403 exit_loop1:
1404 loop1_outer_done = i;
1405 loop1_inner_done = j;
1406 if (j >= 8) {
1407 b43_phy_write(dev, B43_PHY_RFOVERVAL,
1408 b43_phy_read(dev, B43_PHY_RFOVERVAL)
1409 | 0x30);
1410 trsw_rx = 0x1B;
1411 for (j = j - 8; j < 16; j++) {
1412 b43_phy_write(dev, B43_PHY_RFOVERVAL,
1413 (b43_phy_read(dev, B43_PHY_RFOVERVAL)
1414 & 0xF0FF) | (j << 8));
1415 b43_phy_write(dev, B43_PHY_PGACTL,
1416 (b43_phy_read(dev, B43_PHY_PGACTL)
1417 & 0x0FFF) | 0xA000);
1418 b43_phy_write(dev, B43_PHY_PGACTL,
1419 b43_phy_read(dev, B43_PHY_PGACTL)
1420 | 0xF000);
1421 udelay(20);
1422 trsw_rx -= 3;
1423 if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
1424 goto exit_loop2;
1425 }
1426 } else
1427 trsw_rx = 0x18;
1428 exit_loop2:
1429
1430 if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
1431 b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
1432 b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
1433 }
Michael Buesch52507032008-01-09 18:39:09 +01001434 b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]);
1435 b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]);
1436 b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]);
1437 b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]);
1438 b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]);
Michael Buesche4d6b792007-09-18 15:39:42 -04001439 b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
1440 b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
Michael Buesch52507032008-01-09 18:39:09 +01001441 b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]);
Michael Buesche4d6b792007-09-18 15:39:42 -04001442 b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
1443
1444 b43_phy_set_baseband_attenuation(dev, backup_bband);
1445
1446 b43_radio_write16(dev, 0x52, backup_radio[0]);
1447 b43_radio_write16(dev, 0x43, backup_radio[1]);
1448 b43_radio_write16(dev, 0x7A, backup_radio[2]);
1449
1450 b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003);
1451 udelay(10);
1452 b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]);
1453 b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]);
1454 b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]);
1455 b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]);
1456
1457 phy->max_lb_gain =
1458 ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
1459 phy->trsw_rx_gain = trsw_rx * 2;
1460}
1461
1462static void b43_phy_initg(struct b43_wldev *dev)
1463{
1464 struct b43_phy *phy = &dev->phy;
1465 u16 tmp;
1466
1467 if (phy->rev == 1)
1468 b43_phy_initb5(dev);
1469 else
1470 b43_phy_initb6(dev);
1471
1472 if (phy->rev >= 2 || phy->gmode)
1473 b43_phy_inita(dev);
1474
1475 if (phy->rev >= 2) {
1476 b43_phy_write(dev, B43_PHY_ANALOGOVER, 0);
1477 b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0);
1478 }
1479 if (phy->rev == 2) {
1480 b43_phy_write(dev, B43_PHY_RFOVER, 0);
1481 b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
1482 }
1483 if (phy->rev > 5) {
1484 b43_phy_write(dev, B43_PHY_RFOVER, 0x400);
1485 b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
1486 }
1487 if (phy->gmode || phy->rev >= 2) {
1488 tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM);
1489 tmp &= B43_PHYVER_VERSION;
1490 if (tmp == 3 || tmp == 5) {
1491 b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816);
1492 b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006);
1493 }
1494 if (tmp == 5) {
1495 b43_phy_write(dev, B43_PHY_OFDM(0xCC),
1496 (b43_phy_read(dev, B43_PHY_OFDM(0xCC))
1497 & 0x00FF) | 0x1F00);
1498 }
1499 }
1500 if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
1501 b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78);
1502 if (phy->radio_rev == 8) {
1503 b43_phy_write(dev, B43_PHY_EXTG(0x01),
1504 b43_phy_read(dev, B43_PHY_EXTG(0x01))
1505 | 0x80);
1506 b43_phy_write(dev, B43_PHY_OFDM(0x3E),
1507 b43_phy_read(dev, B43_PHY_OFDM(0x3E))
1508 | 0x4);
1509 }
1510 if (has_loopback_gain(phy))
1511 b43_calc_loopback_gain(dev);
1512
1513 if (phy->radio_rev != 8) {
1514 if (phy->initval == 0xFFFF)
1515 phy->initval = b43_radio_init2050(dev);
1516 else
1517 b43_radio_write16(dev, 0x0078, phy->initval);
1518 }
1519 if (phy->lo_control->tx_bias == 0xFF) {
1520 b43_lo_g_measure(dev);
1521 } else {
1522 if (has_tx_magnification(phy)) {
1523 b43_radio_write16(dev, 0x52,
1524 (b43_radio_read16(dev, 0x52) & 0xFF00)
1525 | phy->lo_control->tx_bias | phy->
1526 lo_control->tx_magn);
1527 } else {
1528 b43_radio_write16(dev, 0x52,
1529 (b43_radio_read16(dev, 0x52) & 0xFFF0)
1530 | phy->lo_control->tx_bias);
1531 }
1532 if (phy->rev >= 6) {
Michael Buesch52507032008-01-09 18:39:09 +01001533 b43_phy_write(dev, B43_PHY_CCK(0x36),
1534 (b43_phy_read(dev, B43_PHY_CCK(0x36))
Michael Buesche4d6b792007-09-18 15:39:42 -04001535 & 0x0FFF) | (phy->lo_control->
1536 tx_bias << 12));
1537 }
Larry Finger95de2842007-11-09 16:57:18 -06001538 if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
Michael Buesch52507032008-01-09 18:39:09 +01001539 b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
Michael Buesche4d6b792007-09-18 15:39:42 -04001540 else
Michael Buesch52507032008-01-09 18:39:09 +01001541 b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
Michael Buesche4d6b792007-09-18 15:39:42 -04001542 if (phy->rev < 2)
Michael Buesch52507032008-01-09 18:39:09 +01001543 b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
Michael Buesche4d6b792007-09-18 15:39:42 -04001544 else
Michael Buesch52507032008-01-09 18:39:09 +01001545 b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
Michael Buesche4d6b792007-09-18 15:39:42 -04001546 }
1547 if (phy->gmode || phy->rev >= 2) {
1548 b43_lo_g_adjust(dev);
1549 b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
1550 }
1551
Larry Finger95de2842007-11-09 16:57:18 -06001552 if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04001553 /* The specs state to update the NRSSI LT with
1554 * the value 0x7FFFFFFF here. I think that is some weird
1555 * compiler optimization in the original driver.
1556 * Essentially, what we do here is resetting all NRSSI LT
1557 * entries to -32 (see the limit_value() in nrssi_hw_update())
1558 */
1559 b43_nrssi_hw_update(dev, 0xFFFF); //FIXME?
1560 b43_calc_nrssi_threshold(dev);
1561 } else if (phy->gmode || phy->rev >= 2) {
1562 if (phy->nrssi[0] == -1000) {
1563 B43_WARN_ON(phy->nrssi[1] != -1000);
1564 b43_calc_nrssi_slope(dev);
1565 } else
1566 b43_calc_nrssi_threshold(dev);
1567 }
1568 if (phy->radio_rev == 8)
1569 b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230);
1570 b43_phy_init_pctl(dev);
1571 /* FIXME: The spec says in the following if, the 0 should be replaced
1572 'if OFDM may not be used in the current locale'
1573 but OFDM is legal everywhere */
1574 if ((dev->dev->bus->chip_id == 0x4306
1575 && dev->dev->bus->chip_package == 2) || 0) {
1576 b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
1577 & 0xBFFF);
1578 b43_phy_write(dev, B43_PHY_OFDM(0xC3),
1579 b43_phy_read(dev, B43_PHY_OFDM(0xC3))
1580 & 0x7FFF);
1581 }
1582}
1583
1584/* Set the baseband attenuation value on chip. */
1585void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
1586 u16 baseband_attenuation)
1587{
1588 struct b43_phy *phy = &dev->phy;
1589
1590 if (phy->analog == 0) {
1591 b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0)
1592 & 0xFFF0) |
1593 baseband_attenuation);
1594 } else if (phy->analog > 1) {
1595 b43_phy_write(dev, B43_PHY_DACCTL,
1596 (b43_phy_read(dev, B43_PHY_DACCTL)
1597 & 0xFFC3) | (baseband_attenuation << 2));
1598 } else {
1599 b43_phy_write(dev, B43_PHY_DACCTL,
1600 (b43_phy_read(dev, B43_PHY_DACCTL)
1601 & 0xFF87) | (baseband_attenuation << 3));
1602 }
1603}
1604
1605/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
1606 * This function converts a TSSI value to dBm in Q5.2
1607 */
1608static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
1609{
1610 struct b43_phy *phy = &dev->phy;
1611 s8 dbm = 0;
1612 s32 tmp;
1613
1614 tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi);
1615
1616 switch (phy->type) {
1617 case B43_PHYTYPE_A:
1618 tmp += 0x80;
1619 tmp = limit_value(tmp, 0x00, 0xFF);
1620 dbm = phy->tssi2dbm[tmp];
1621 //TODO: There's a FIXME on the specs
1622 break;
1623 case B43_PHYTYPE_B:
1624 case B43_PHYTYPE_G:
1625 tmp = limit_value(tmp, 0x00, 0x3F);
1626 dbm = phy->tssi2dbm[tmp];
1627 break;
1628 default:
1629 B43_WARN_ON(1);
1630 }
1631
1632 return dbm;
1633}
1634
1635void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
1636 int *_bbatt, int *_rfatt)
1637{
1638 int rfatt = *_rfatt;
1639 int bbatt = *_bbatt;
1640 struct b43_txpower_lo_control *lo = dev->phy.lo_control;
1641
1642 /* Get baseband and radio attenuation values into their permitted ranges.
1643 * Radio attenuation affects power level 4 times as much as baseband. */
1644
1645 /* Range constants */
1646 const int rf_min = lo->rfatt_list.min_val;
1647 const int rf_max = lo->rfatt_list.max_val;
1648 const int bb_min = lo->bbatt_list.min_val;
1649 const int bb_max = lo->bbatt_list.max_val;
1650
1651 while (1) {
1652 if (rfatt > rf_max && bbatt > bb_max - 4)
1653 break; /* Can not get it into ranges */
1654 if (rfatt < rf_min && bbatt < bb_min + 4)
1655 break; /* Can not get it into ranges */
1656 if (bbatt > bb_max && rfatt > rf_max - 1)
1657 break; /* Can not get it into ranges */
1658 if (bbatt < bb_min && rfatt < rf_min + 1)
1659 break; /* Can not get it into ranges */
1660
1661 if (bbatt > bb_max) {
1662 bbatt -= 4;
1663 rfatt += 1;
1664 continue;
1665 }
1666 if (bbatt < bb_min) {
1667 bbatt += 4;
1668 rfatt -= 1;
1669 continue;
1670 }
1671 if (rfatt > rf_max) {
1672 rfatt -= 1;
1673 bbatt += 4;
1674 continue;
1675 }
1676 if (rfatt < rf_min) {
1677 rfatt += 1;
1678 bbatt -= 4;
1679 continue;
1680 }
1681 break;
1682 }
1683
1684 *_rfatt = limit_value(rfatt, rf_min, rf_max);
1685 *_bbatt = limit_value(bbatt, bb_min, bb_max);
1686}
1687
1688/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
1689void b43_phy_xmitpower(struct b43_wldev *dev)
1690{
1691 struct ssb_bus *bus = dev->dev->bus;
1692 struct b43_phy *phy = &dev->phy;
1693
1694 if (phy->cur_idle_tssi == 0)
1695 return;
1696 if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
1697 (bus->boardinfo.type == SSB_BOARD_BU4306))
1698 return;
1699#ifdef CONFIG_B43_DEBUG
1700 if (phy->manual_txpower_control)
1701 return;
1702#endif
1703
1704 switch (phy->type) {
1705 case B43_PHYTYPE_A:{
1706
1707 //TODO: Nothing for A PHYs yet :-/
1708
1709 break;
1710 }
1711 case B43_PHYTYPE_B:
1712 case B43_PHYTYPE_G:{
1713 u16 tmp;
1714 s8 v0, v1, v2, v3;
1715 s8 average;
1716 int max_pwr;
1717 int desired_pwr, estimated_pwr, pwr_adjust;
1718 int rfatt_delta, bbatt_delta;
1719 int rfatt, bbatt;
1720 u8 tx_control;
Michael Buesche4d6b792007-09-18 15:39:42 -04001721
1722 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
1723 v0 = (s8) (tmp & 0x00FF);
1724 v1 = (s8) ((tmp & 0xFF00) >> 8);
1725 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A);
1726 v2 = (s8) (tmp & 0x00FF);
1727 v3 = (s8) ((tmp & 0xFF00) >> 8);
1728 tmp = 0;
1729
1730 if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
1731 || v3 == 0x7F) {
1732 tmp =
1733 b43_shm_read16(dev, B43_SHM_SHARED, 0x0070);
1734 v0 = (s8) (tmp & 0x00FF);
1735 v1 = (s8) ((tmp & 0xFF00) >> 8);
1736 tmp =
1737 b43_shm_read16(dev, B43_SHM_SHARED, 0x0072);
1738 v2 = (s8) (tmp & 0x00FF);
1739 v3 = (s8) ((tmp & 0xFF00) >> 8);
1740 if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
1741 || v3 == 0x7F)
1742 return;
1743 v0 = (v0 + 0x20) & 0x3F;
1744 v1 = (v1 + 0x20) & 0x3F;
1745 v2 = (v2 + 0x20) & 0x3F;
1746 v3 = (v3 + 0x20) & 0x3F;
1747 tmp = 1;
1748 }
1749 b43_shm_clear_tssi(dev);
1750
1751 average = (v0 + v1 + v2 + v3 + 2) / 4;
1752
1753 if (tmp
1754 && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) &
1755 0x8))
1756 average -= 13;
1757
1758 estimated_pwr =
1759 b43_phy_estimate_power_out(dev, average);
1760
Larry Finger95de2842007-11-09 16:57:18 -06001761 max_pwr = dev->dev->bus->sprom.maxpwr_bg;
1762 if ((dev->dev->bus->sprom.boardflags_lo
1763 & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G))
Michael Buesche4d6b792007-09-18 15:39:42 -04001764 max_pwr -= 0x3;
1765 if (unlikely(max_pwr <= 0)) {
1766 b43warn(dev->wl,
1767 "Invalid max-TX-power value in SPROM.\n");
1768 max_pwr = 60; /* fake it */
Larry Finger95de2842007-11-09 16:57:18 -06001769 dev->dev->bus->sprom.maxpwr_bg = max_pwr;
Michael Buesche4d6b792007-09-18 15:39:42 -04001770 }
1771
1772 /*TODO:
1773 max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr)
1774 where REG is the max power as per the regulatory domain
1775 */
1776
1777 /* Get desired power (in Q5.2) */
1778 desired_pwr = INT_TO_Q52(phy->power_level);
1779 /* And limit it. max_pwr already is Q5.2 */
1780 desired_pwr = limit_value(desired_pwr, 0, max_pwr);
1781 if (b43_debug(dev, B43_DBG_XMITPOWER)) {
1782 b43dbg(dev->wl,
1783 "Current TX power output: " Q52_FMT
1784 " dBm, " "Desired TX power output: "
1785 Q52_FMT " dBm\n", Q52_ARG(estimated_pwr),
1786 Q52_ARG(desired_pwr));
1787 }
1788
1789 /* Calculate the adjustment delta. */
1790 pwr_adjust = desired_pwr - estimated_pwr;
1791
1792 /* RF attenuation delta. */
1793 rfatt_delta = ((pwr_adjust + 7) / 8);
1794 /* Lower attenuation => Bigger power output. Negate it. */
1795 rfatt_delta = -rfatt_delta;
1796
1797 /* Baseband attenuation delta. */
1798 bbatt_delta = pwr_adjust / 2;
1799 /* Lower attenuation => Bigger power output. Negate it. */
1800 bbatt_delta = -bbatt_delta;
1801 /* RF att affects power level 4 times as much as
1802 * Baseband attennuation. Subtract it. */
1803 bbatt_delta -= 4 * rfatt_delta;
1804
1805 /* So do we finally need to adjust something? */
1806 if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
1807 b43_lo_g_ctl_mark_cur_used(dev);
1808 return;
1809 }
1810
1811 /* Calculate the new attenuation values. */
1812 bbatt = phy->bbatt.att;
1813 bbatt += bbatt_delta;
1814 rfatt = phy->rfatt.att;
1815 rfatt += rfatt_delta;
1816
1817 b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
1818 tx_control = phy->tx_control;
1819 if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
1820 if (rfatt <= 1) {
1821 if (tx_control == 0) {
1822 tx_control =
1823 B43_TXCTL_PA2DB |
1824 B43_TXCTL_TXMIX;
1825 rfatt += 2;
1826 bbatt += 2;
Larry Finger95de2842007-11-09 16:57:18 -06001827 } else if (dev->dev->bus->sprom.
Michael Buesche4d6b792007-09-18 15:39:42 -04001828 boardflags_lo &
1829 B43_BFL_PACTRL) {
1830 bbatt += 4 * (rfatt - 2);
1831 rfatt = 2;
1832 }
1833 } else if (rfatt > 4 && tx_control) {
1834 tx_control = 0;
1835 if (bbatt < 3) {
1836 rfatt -= 3;
1837 bbatt += 2;
1838 } else {
1839 rfatt -= 2;
1840 bbatt -= 2;
1841 }
1842 }
1843 }
1844 /* Save the control values */
1845 phy->tx_control = tx_control;
1846 b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
1847 phy->rfatt.att = rfatt;
1848 phy->bbatt.att = bbatt;
1849
1850 /* Adjust the hardware */
Michael Bueschf31800d2008-01-09 19:08:49 +01001851 b43_phy_lock(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001852 b43_radio_lock(dev);
1853 b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
1854 phy->tx_control);
1855 b43_lo_g_ctl_mark_cur_used(dev);
1856 b43_radio_unlock(dev);
Michael Bueschf31800d2008-01-09 19:08:49 +01001857 b43_phy_unlock(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001858 break;
1859 }
1860 default:
1861 B43_WARN_ON(1);
1862 }
1863}
1864
1865static inline s32 b43_tssi2dbm_ad(s32 num, s32 den)
1866{
1867 if (num < 0)
1868 return num / den;
1869 else
1870 return (num + den / 2) / den;
1871}
1872
1873static inline
1874 s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2)
1875{
1876 s32 m1, m2, f = 256, q, delta;
1877 s8 i = 0;
1878
1879 m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
1880 m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
1881 do {
1882 if (i > 15)
1883 return -EINVAL;
1884 q = b43_tssi2dbm_ad(f * 4096 -
1885 b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
1886 delta = abs(q - f);
1887 f = q;
1888 i++;
1889 } while (delta >= 2);
1890 entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
1891 return 0;
1892}
1893
1894/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
1895int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
1896{
1897 struct b43_phy *phy = &dev->phy;
1898 s16 pab0, pab1, pab2;
1899 u8 idx;
1900 s8 *dyn_tssi2dbm;
1901
1902 if (phy->type == B43_PHYTYPE_A) {
Larry Finger95de2842007-11-09 16:57:18 -06001903 pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
1904 pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
1905 pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
Michael Buesche4d6b792007-09-18 15:39:42 -04001906 } else {
Larry Finger95de2842007-11-09 16:57:18 -06001907 pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
1908 pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
1909 pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
Michael Buesche4d6b792007-09-18 15:39:42 -04001910 }
1911
1912 if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
1913 phy->tgt_idle_tssi = 0x34;
1914 phy->tssi2dbm = b43_tssi2dbm_b_table;
1915 return 0;
1916 }
1917
1918 if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
1919 pab0 != -1 && pab1 != -1 && pab2 != -1) {
1920 /* The pabX values are set in SPROM. Use them. */
1921 if (phy->type == B43_PHYTYPE_A) {
Larry Finger95de2842007-11-09 16:57:18 -06001922 if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
1923 (s8) dev->dev->bus->sprom.itssi_a != -1)
Michael Buesche4d6b792007-09-18 15:39:42 -04001924 phy->tgt_idle_tssi =
Larry Finger95de2842007-11-09 16:57:18 -06001925 (s8) (dev->dev->bus->sprom.itssi_a);
Michael Buesche4d6b792007-09-18 15:39:42 -04001926 else
1927 phy->tgt_idle_tssi = 62;
1928 } else {
Larry Finger95de2842007-11-09 16:57:18 -06001929 if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
1930 (s8) dev->dev->bus->sprom.itssi_bg != -1)
Michael Buesche4d6b792007-09-18 15:39:42 -04001931 phy->tgt_idle_tssi =
Larry Finger95de2842007-11-09 16:57:18 -06001932 (s8) (dev->dev->bus->sprom.itssi_bg);
Michael Buesche4d6b792007-09-18 15:39:42 -04001933 else
1934 phy->tgt_idle_tssi = 62;
1935 }
1936 dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
1937 if (dyn_tssi2dbm == NULL) {
Joe Perches8376e7a2007-11-19 17:48:27 -08001938 b43err(dev->wl, "Could not allocate memory "
Michael Buesche4d6b792007-09-18 15:39:42 -04001939 "for tssi2dbm table\n");
1940 return -ENOMEM;
1941 }
1942 for (idx = 0; idx < 64; idx++)
1943 if (b43_tssi2dbm_entry
1944 (dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
1945 phy->tssi2dbm = NULL;
1946 b43err(dev->wl, "Could not generate "
1947 "tssi2dBm table\n");
1948 kfree(dyn_tssi2dbm);
1949 return -ENODEV;
1950 }
1951 phy->tssi2dbm = dyn_tssi2dbm;
1952 phy->dyn_tssi_tbl = 1;
1953 } else {
1954 /* pabX values not set in SPROM. */
1955 switch (phy->type) {
1956 case B43_PHYTYPE_A:
1957 /* APHY needs a generated table. */
1958 phy->tssi2dbm = NULL;
1959 b43err(dev->wl, "Could not generate tssi2dBm "
1960 "table (wrong SPROM info)!\n");
1961 return -ENODEV;
1962 case B43_PHYTYPE_B:
1963 phy->tgt_idle_tssi = 0x34;
1964 phy->tssi2dbm = b43_tssi2dbm_b_table;
1965 break;
1966 case B43_PHYTYPE_G:
1967 phy->tgt_idle_tssi = 0x34;
1968 phy->tssi2dbm = b43_tssi2dbm_g_table;
1969 break;
1970 }
1971 }
1972
1973 return 0;
1974}
1975
1976int b43_phy_init(struct b43_wldev *dev)
1977{
1978 struct b43_phy *phy = &dev->phy;
Michael Buesch424047e2008-01-09 16:13:56 +01001979 bool unsupported = 0;
1980 int err = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04001981
1982 switch (phy->type) {
1983 case B43_PHYTYPE_A:
Michael Buesch424047e2008-01-09 16:13:56 +01001984 if (phy->rev == 2 || phy->rev == 3)
Michael Buesche4d6b792007-09-18 15:39:42 -04001985 b43_phy_inita(dev);
Michael Buesch424047e2008-01-09 16:13:56 +01001986 else
1987 unsupported = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04001988 break;
1989 case B43_PHYTYPE_B:
1990 switch (phy->rev) {
1991 case 2:
1992 b43_phy_initb2(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001993 break;
1994 case 4:
1995 b43_phy_initb4(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001996 break;
1997 case 5:
1998 b43_phy_initb5(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04001999 break;
2000 case 6:
2001 b43_phy_initb6(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002002 break;
Michael Buesch424047e2008-01-09 16:13:56 +01002003 default:
2004 unsupported = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04002005 }
2006 break;
2007 case B43_PHYTYPE_G:
2008 b43_phy_initg(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002009 break;
Michael Buesch424047e2008-01-09 16:13:56 +01002010 case B43_PHYTYPE_N:
2011 err = b43_phy_initn(dev);
2012 break;
2013 default:
2014 unsupported = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04002015 }
Michael Buesch424047e2008-01-09 16:13:56 +01002016 if (unsupported)
Michael Buesche4d6b792007-09-18 15:39:42 -04002017 b43err(dev->wl, "Unknown PHYTYPE found\n");
2018
2019 return err;
2020}
2021
2022void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
2023{
2024 struct b43_phy *phy = &dev->phy;
2025 u32 hf;
2026 u16 tmp;
2027 int autodiv = 0;
2028
2029 if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
2030 autodiv = 1;
2031
2032 hf = b43_hf_read(dev);
2033 hf &= ~B43_HF_ANTDIVHELP;
2034 b43_hf_write(dev, hf);
2035
2036 switch (phy->type) {
2037 case B43_PHYTYPE_A:
2038 case B43_PHYTYPE_G:
2039 tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
2040 tmp &= ~B43_PHY_BBANDCFG_RXANT;
2041 tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
2042 << B43_PHY_BBANDCFG_RXANT_SHIFT;
2043 b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
2044
2045 if (autodiv) {
2046 tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
2047 if (antenna == B43_ANTENNA_AUTO0)
2048 tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
2049 else
2050 tmp |= B43_PHY_ANTDWELL_AUTODIV1;
2051 b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
2052 }
2053 if (phy->type == B43_PHYTYPE_G) {
2054 tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT);
2055 if (autodiv)
2056 tmp |= B43_PHY_ANTWRSETT_ARXDIV;
2057 else
2058 tmp &= ~B43_PHY_ANTWRSETT_ARXDIV;
2059 b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp);
2060 if (phy->rev >= 2) {
2061 tmp = b43_phy_read(dev, B43_PHY_OFDM61);
2062 tmp |= B43_PHY_OFDM61_10;
2063 b43_phy_write(dev, B43_PHY_OFDM61, tmp);
2064
2065 tmp =
2066 b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK);
2067 tmp = (tmp & 0xFF00) | 0x15;
2068 b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK,
2069 tmp);
2070
2071 if (phy->rev == 2) {
2072 b43_phy_write(dev, B43_PHY_ADIVRELATED,
2073 8);
2074 } else {
2075 tmp =
2076 b43_phy_read(dev,
2077 B43_PHY_ADIVRELATED);
2078 tmp = (tmp & 0xFF00) | 8;
2079 b43_phy_write(dev, B43_PHY_ADIVRELATED,
2080 tmp);
2081 }
2082 }
2083 if (phy->rev >= 6)
2084 b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC);
2085 } else {
2086 if (phy->rev < 3) {
2087 tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
2088 tmp = (tmp & 0xFF00) | 0x24;
2089 b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
2090 } else {
2091 tmp = b43_phy_read(dev, B43_PHY_OFDM61);
2092 tmp |= 0x10;
2093 b43_phy_write(dev, B43_PHY_OFDM61, tmp);
2094 if (phy->analog == 3) {
2095 b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
2096 0x1D);
2097 b43_phy_write(dev, B43_PHY_ADIVRELATED,
2098 8);
2099 } else {
2100 b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
2101 0x3A);
2102 tmp =
2103 b43_phy_read(dev,
2104 B43_PHY_ADIVRELATED);
2105 tmp = (tmp & 0xFF00) | 8;
2106 b43_phy_write(dev, B43_PHY_ADIVRELATED,
2107 tmp);
2108 }
2109 }
2110 }
2111 break;
2112 case B43_PHYTYPE_B:
2113 tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
2114 tmp &= ~B43_PHY_BBANDCFG_RXANT;
2115 tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
2116 << B43_PHY_BBANDCFG_RXANT_SHIFT;
2117 b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp);
2118 break;
2119 default:
2120 B43_WARN_ON(1);
2121 }
2122
2123 hf |= B43_HF_ANTDIVHELP;
2124 b43_hf_write(dev, hf);
2125}
2126
2127/* Get the freq, as it has to be written to the device. */
2128static inline u16 channel2freq_bg(u8 channel)
2129{
2130 B43_WARN_ON(!(channel >= 1 && channel <= 14));
2131
2132 return b43_radio_channel_codes_bg[channel - 1];
2133}
2134
2135/* Get the freq, as it has to be written to the device. */
2136static inline u16 channel2freq_a(u8 channel)
2137{
2138 B43_WARN_ON(channel > 200);
2139
2140 return (5000 + 5 * channel);
2141}
2142
2143void b43_radio_lock(struct b43_wldev *dev)
2144{
2145 u32 macctl;
2146
2147 macctl = b43_read32(dev, B43_MMIO_MACCTL);
Michael Bueschf31800d2008-01-09 19:08:49 +01002148 B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
Michael Buesche4d6b792007-09-18 15:39:42 -04002149 macctl |= B43_MACCTL_RADIOLOCK;
2150 b43_write32(dev, B43_MMIO_MACCTL, macctl);
2151 /* Commit the write and wait for the device
2152 * to exit any radio register access. */
2153 b43_read32(dev, B43_MMIO_MACCTL);
2154 udelay(10);
2155}
2156
2157void b43_radio_unlock(struct b43_wldev *dev)
2158{
2159 u32 macctl;
2160
2161 /* Commit any write */
2162 b43_read16(dev, B43_MMIO_PHY_VER);
2163 /* unlock */
2164 macctl = b43_read32(dev, B43_MMIO_MACCTL);
Michael Bueschf31800d2008-01-09 19:08:49 +01002165 B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
Michael Buesche4d6b792007-09-18 15:39:42 -04002166 macctl &= ~B43_MACCTL_RADIOLOCK;
2167 b43_write32(dev, B43_MMIO_MACCTL, macctl);
2168}
2169
2170u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
2171{
2172 struct b43_phy *phy = &dev->phy;
2173
Michael Buesch52507032008-01-09 18:39:09 +01002174 /* Offset 1 is a 32-bit register. */
2175 B43_WARN_ON(offset == 1);
2176
Michael Buesche4d6b792007-09-18 15:39:42 -04002177 switch (phy->type) {
2178 case B43_PHYTYPE_A:
Michael Buesch52507032008-01-09 18:39:09 +01002179 offset |= 0x40;
Michael Buesche4d6b792007-09-18 15:39:42 -04002180 break;
2181 case B43_PHYTYPE_B:
2182 if (phy->radio_ver == 0x2053) {
2183 if (offset < 0x70)
2184 offset += 0x80;
2185 else if (offset < 0x80)
2186 offset += 0x70;
2187 } else if (phy->radio_ver == 0x2050) {
2188 offset |= 0x80;
2189 } else
2190 B43_WARN_ON(1);
2191 break;
2192 case B43_PHYTYPE_G:
2193 offset |= 0x80;
2194 break;
Michael Buesch52507032008-01-09 18:39:09 +01002195 case B43_PHYTYPE_N:
2196 offset |= 0x100;
2197 break;
2198 case B43_PHYTYPE_LP:
2199 /* No adjustment required. */
2200 break;
2201 default:
2202 B43_WARN_ON(1);
Michael Buesche4d6b792007-09-18 15:39:42 -04002203 }
2204
2205 b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
2206 return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
2207}
2208
2209void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
2210{
Michael Buesch52507032008-01-09 18:39:09 +01002211 /* Offset 1 is a 32-bit register. */
2212 B43_WARN_ON(offset == 1);
2213
Michael Buesche4d6b792007-09-18 15:39:42 -04002214 b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
Michael Buesche4d6b792007-09-18 15:39:42 -04002215 b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val);
2216}
2217
2218static void b43_set_all_gains(struct b43_wldev *dev,
2219 s16 first, s16 second, s16 third)
2220{
2221 struct b43_phy *phy = &dev->phy;
2222 u16 i;
2223 u16 start = 0x08, end = 0x18;
2224 u16 tmp;
2225 u16 table;
2226
2227 if (phy->rev <= 1) {
2228 start = 0x10;
2229 end = 0x20;
2230 }
2231
2232 table = B43_OFDMTAB_GAINX;
2233 if (phy->rev <= 1)
2234 table = B43_OFDMTAB_GAINX_R1;
2235 for (i = 0; i < 4; i++)
2236 b43_ofdmtab_write16(dev, table, i, first);
2237
2238 for (i = start; i < end; i++)
2239 b43_ofdmtab_write16(dev, table, i, second);
2240
2241 if (third != -1) {
2242 tmp = ((u16) third << 14) | ((u16) third << 6);
2243 b43_phy_write(dev, 0x04A0,
2244 (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp);
2245 b43_phy_write(dev, 0x04A1,
2246 (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp);
2247 b43_phy_write(dev, 0x04A2,
2248 (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp);
2249 }
2250 b43_dummy_transmission(dev);
2251}
2252
2253static void b43_set_original_gains(struct b43_wldev *dev)
2254{
2255 struct b43_phy *phy = &dev->phy;
2256 u16 i, tmp;
2257 u16 table;
2258 u16 start = 0x0008, end = 0x0018;
2259
2260 if (phy->rev <= 1) {
2261 start = 0x0010;
2262 end = 0x0020;
2263 }
2264
2265 table = B43_OFDMTAB_GAINX;
2266 if (phy->rev <= 1)
2267 table = B43_OFDMTAB_GAINX_R1;
2268 for (i = 0; i < 4; i++) {
2269 tmp = (i & 0xFFFC);
2270 tmp |= (i & 0x0001) << 1;
2271 tmp |= (i & 0x0002) >> 1;
2272
2273 b43_ofdmtab_write16(dev, table, i, tmp);
2274 }
2275
2276 for (i = start; i < end; i++)
2277 b43_ofdmtab_write16(dev, table, i, i - start);
2278
2279 b43_phy_write(dev, 0x04A0,
2280 (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040);
2281 b43_phy_write(dev, 0x04A1,
2282 (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040);
2283 b43_phy_write(dev, 0x04A2,
2284 (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000);
2285 b43_dummy_transmission(dev);
2286}
2287
2288/* Synthetic PU workaround */
2289static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel)
2290{
2291 struct b43_phy *phy = &dev->phy;
2292
2293 might_sleep();
2294
2295 if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
2296 /* We do not need the workaround. */
2297 return;
2298 }
2299
2300 if (channel <= 10) {
2301 b43_write16(dev, B43_MMIO_CHANNEL,
2302 channel2freq_bg(channel + 4));
2303 } else {
2304 b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1));
2305 }
2306 msleep(1);
2307 b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
2308}
2309
2310u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel)
2311{
2312 struct b43_phy *phy = &dev->phy;
2313 u8 ret = 0;
2314 u16 saved, rssi, temp;
2315 int i, j = 0;
2316
2317 saved = b43_phy_read(dev, 0x0403);
2318 b43_radio_selectchannel(dev, channel, 0);
2319 b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
2320 if (phy->aci_hw_rssi)
2321 rssi = b43_phy_read(dev, 0x048A) & 0x3F;
2322 else
2323 rssi = saved & 0x3F;
2324 /* clamp temp to signed 5bit */
2325 if (rssi > 32)
2326 rssi -= 64;
2327 for (i = 0; i < 100; i++) {
2328 temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F;
2329 if (temp > 32)
2330 temp -= 64;
2331 if (temp < rssi)
2332 j++;
2333 if (j >= 20)
2334 ret = 1;
2335 }
2336 b43_phy_write(dev, 0x0403, saved);
2337
2338 return ret;
2339}
2340
2341u8 b43_radio_aci_scan(struct b43_wldev * dev)
2342{
2343 struct b43_phy *phy = &dev->phy;
2344 u8 ret[13];
2345 unsigned int channel = phy->channel;
2346 unsigned int i, j, start, end;
Michael Buesche4d6b792007-09-18 15:39:42 -04002347
2348 if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
2349 return 0;
2350
Michael Bueschf31800d2008-01-09 19:08:49 +01002351 b43_phy_lock(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002352 b43_radio_lock(dev);
2353 b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
2354 b43_phy_write(dev, B43_PHY_G_CRS,
2355 b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
2356 b43_set_all_gains(dev, 3, 8, 1);
2357
2358 start = (channel - 5 > 0) ? channel - 5 : 1;
2359 end = (channel + 5 < 14) ? channel + 5 : 13;
2360
2361 for (i = start; i <= end; i++) {
2362 if (abs(channel - i) > 2)
2363 ret[i - 1] = b43_radio_aci_detect(dev, i);
2364 }
2365 b43_radio_selectchannel(dev, channel, 0);
2366 b43_phy_write(dev, 0x0802,
2367 (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003);
2368 b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8);
2369 b43_phy_write(dev, B43_PHY_G_CRS,
2370 b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
2371 b43_set_original_gains(dev);
2372 for (i = 0; i < 13; i++) {
2373 if (!ret[i])
2374 continue;
2375 end = (i + 5 < 13) ? i + 5 : 13;
2376 for (j = i; j < end; j++)
2377 ret[j] = 1;
2378 }
2379 b43_radio_unlock(dev);
Michael Bueschf31800d2008-01-09 19:08:49 +01002380 b43_phy_unlock(dev);
Michael Buesche4d6b792007-09-18 15:39:42 -04002381
2382 return ret[channel - 1];
2383}
2384
2385/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
2386void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
2387{
2388 b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
2389 mmiowb();
2390 b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
2391}
2392
2393/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
2394s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
2395{
2396 u16 val;
2397
2398 b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
2399 val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA);
2400
2401 return (s16) val;
2402}
2403
2404/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
2405void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
2406{
2407 u16 i;
2408 s16 tmp;
2409
2410 for (i = 0; i < 64; i++) {
2411 tmp = b43_nrssi_hw_read(dev, i);
2412 tmp -= val;
2413 tmp = limit_value(tmp, -32, 31);
2414 b43_nrssi_hw_write(dev, i, tmp);
2415 }
2416}
2417
2418/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
2419void b43_nrssi_mem_update(struct b43_wldev *dev)
2420{
2421 struct b43_phy *phy = &dev->phy;
2422 s16 i, delta;
2423 s32 tmp;
2424
2425 delta = 0x1F - phy->nrssi[0];
2426 for (i = 0; i < 64; i++) {
2427 tmp = (i - delta) * phy->nrssislope;
2428 tmp /= 0x10000;
2429 tmp += 0x3A;
2430 tmp = limit_value(tmp, 0, 0x3F);
2431 phy->nrssi_lt[i] = tmp;
2432 }
2433}
2434
2435static void b43_calc_nrssi_offset(struct b43_wldev *dev)
2436{
2437 struct b43_phy *phy = &dev->phy;
2438 u16 backup[20] = { 0 };
2439 s16 v47F;
2440 u16 i;
2441 u16 saved = 0xFFFF;
2442
2443 backup[0] = b43_phy_read(dev, 0x0001);
2444 backup[1] = b43_phy_read(dev, 0x0811);
2445 backup[2] = b43_phy_read(dev, 0x0812);
2446 if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
2447 backup[3] = b43_phy_read(dev, 0x0814);
2448 backup[4] = b43_phy_read(dev, 0x0815);
2449 }
2450 backup[5] = b43_phy_read(dev, 0x005A);
2451 backup[6] = b43_phy_read(dev, 0x0059);
2452 backup[7] = b43_phy_read(dev, 0x0058);
2453 backup[8] = b43_phy_read(dev, 0x000A);
2454 backup[9] = b43_phy_read(dev, 0x0003);
2455 backup[10] = b43_radio_read16(dev, 0x007A);
2456 backup[11] = b43_radio_read16(dev, 0x0043);
2457
2458 b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF);
2459 b43_phy_write(dev, 0x0001,
2460 (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000);
2461 b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
2462 b43_phy_write(dev, 0x0812,
2463 (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004);
2464 b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
2465 if (phy->rev >= 6) {
2466 backup[12] = b43_phy_read(dev, 0x002E);
2467 backup[13] = b43_phy_read(dev, 0x002F);
2468 backup[14] = b43_phy_read(dev, 0x080F);
2469 backup[15] = b43_phy_read(dev, 0x0810);
2470 backup[16] = b43_phy_read(dev, 0x0801);
2471 backup[17] = b43_phy_read(dev, 0x0060);
2472 backup[18] = b43_phy_read(dev, 0x0014);
2473 backup[19] = b43_phy_read(dev, 0x0478);
2474
2475 b43_phy_write(dev, 0x002E, 0);
2476 b43_phy_write(dev, 0x002F, 0);
2477 b43_phy_write(dev, 0x080F, 0);
2478 b43_phy_write(dev, 0x0810, 0);
2479 b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100);
2480 b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040);
2481 b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040);
2482 b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200);
2483 }
2484 b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070);
2485 b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080);
2486 udelay(30);
2487
2488 v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
2489 if (v47F >= 0x20)
2490 v47F -= 0x40;
2491 if (v47F == 31) {
2492 for (i = 7; i >= 4; i--) {
2493 b43_radio_write16(dev, 0x007B, i);
2494 udelay(20);
2495 v47F =
2496 (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
2497 if (v47F >= 0x20)
2498 v47F -= 0x40;
2499 if (v47F < 31 && saved == 0xFFFF)
2500 saved = i;
2501 }
2502 if (saved == 0xFFFF)
2503 saved = 4;
2504 } else {
2505 b43_radio_write16(dev, 0x007A,
2506 b43_radio_read16(dev, 0x007A) & 0x007F);
2507 if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
2508 b43_phy_write(dev, 0x0814,
2509 b43_phy_read(dev, 0x0814) | 0x0001);
2510 b43_phy_write(dev, 0x0815,
2511 b43_phy_read(dev, 0x0815) & 0xFFFE);
2512 }
2513 b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
2514 b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C);
2515 b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030);
2516 b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030);
2517 b43_phy_write(dev, 0x005A, 0x0480);
2518 b43_phy_write(dev, 0x0059, 0x0810);
2519 b43_phy_write(dev, 0x0058, 0x000D);
2520 if (phy->rev == 0) {
2521 b43_phy_write(dev, 0x0003, 0x0122);
2522 } else {
2523 b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A)
2524 | 0x2000);
2525 }
2526 if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
2527 b43_phy_write(dev, 0x0814,
2528 b43_phy_read(dev, 0x0814) | 0x0004);
2529 b43_phy_write(dev, 0x0815,
2530 b43_phy_read(dev, 0x0815) & 0xFFFB);
2531 }
2532 b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F)
2533 | 0x0040);
2534 b43_radio_write16(dev, 0x007A,
2535 b43_radio_read16(dev, 0x007A) | 0x000F);
2536 b43_set_all_gains(dev, 3, 0, 1);
2537 b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043)
2538 & 0x00F0) | 0x000F);
2539 udelay(30);
2540 v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
2541 if (v47F >= 0x20)
2542 v47F -= 0x40;
2543 if (v47F == -32) {
2544 for (i = 0; i < 4; i++) {
2545 b43_radio_write16(dev, 0x007B, i);
2546 udelay(20);
2547 v47F =
2548 (s16) ((b43_phy_read(dev, 0x047F) >> 8) &
2549 0x003F);
2550 if (v47F >= 0x20)
2551 v47F -= 0x40;
2552 if (v47F > -31 && saved == 0xFFFF)
2553 saved = i;
2554 }
2555 if (saved == 0xFFFF)
2556 saved = 3;
2557 } else
2558 saved = 0;
2559 }
2560 b43_radio_write16(dev, 0x007B, saved);
2561
2562 if (phy->rev >= 6) {
2563 b43_phy_write(dev, 0x002E, backup[12]);
2564 b43_phy_write(dev, 0x002F, backup[13]);
2565 b43_phy_write(dev, 0x080F, backup[14]);
2566 b43_phy_write(dev, 0x0810, backup[15]);
2567 }
2568 if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
2569 b43_phy_write(dev, 0x0814, backup[3]);
2570 b43_phy_write(dev, 0x0815, backup[4]);
2571 }
2572 b43_phy_write(dev, 0x005A, backup[5]);
2573 b43_phy_write(dev, 0x0059, backup[6]);
2574 b43_phy_write(dev, 0x0058, backup[7]);
2575 b43_phy_write(dev, 0x000A, backup[8]);
2576 b43_phy_write(dev, 0x0003, backup[9]);
2577 b43_radio_write16(dev, 0x0043, backup[11]);
2578 b43_radio_write16(dev, 0x007A, backup[10]);
2579 b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2);
2580 b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000);
2581 b43_set_original_gains(dev);
2582 if (phy->rev >= 6) {
2583 b43_phy_write(dev, 0x0801, backup[16]);
2584 b43_phy_write(dev, 0x0060, backup[17]);
2585 b43_phy_write(dev, 0x0014, backup[18]);
2586 b43_phy_write(dev, 0x0478, backup[19]);
2587 }
2588 b43_phy_write(dev, 0x0001, backup[0]);
2589 b43_phy_write(dev, 0x0812, backup[2]);
2590 b43_phy_write(dev, 0x0811, backup[1]);
2591}
2592
2593void b43_calc_nrssi_slope(struct b43_wldev *dev)
2594{
2595 struct b43_phy *phy = &dev->phy;
2596 u16 backup[18] = { 0 };
2597 u16 tmp;
2598 s16 nrssi0, nrssi1;
2599
2600 switch (phy->type) {
2601 case B43_PHYTYPE_B:
2602 backup[0] = b43_radio_read16(dev, 0x007A);
2603 backup[1] = b43_radio_read16(dev, 0x0052);
2604 backup[2] = b43_radio_read16(dev, 0x0043);
2605 backup[3] = b43_phy_read(dev, 0x0030);
2606 backup[4] = b43_phy_read(dev, 0x0026);
2607 backup[5] = b43_phy_read(dev, 0x0015);
2608 backup[6] = b43_phy_read(dev, 0x002A);
2609 backup[7] = b43_phy_read(dev, 0x0020);
2610 backup[8] = b43_phy_read(dev, 0x005A);
2611 backup[9] = b43_phy_read(dev, 0x0059);
2612 backup[10] = b43_phy_read(dev, 0x0058);
2613 backup[11] = b43_read16(dev, 0x03E2);
2614 backup[12] = b43_read16(dev, 0x03E6);
2615 backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
2616
2617 tmp = b43_radio_read16(dev, 0x007A);
2618 tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
2619 b43_radio_write16(dev, 0x007A, tmp);
2620 b43_phy_write(dev, 0x0030, 0x00FF);
2621 b43_write16(dev, 0x03EC, 0x7F7F);
2622 b43_phy_write(dev, 0x0026, 0x0000);
2623 b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020);
2624 b43_phy_write(dev, 0x002A, 0x08A3);
2625 b43_radio_write16(dev, 0x007A,
2626 b43_radio_read16(dev, 0x007A) | 0x0080);
2627
2628 nrssi0 = (s16) b43_phy_read(dev, 0x0027);
2629 b43_radio_write16(dev, 0x007A,
2630 b43_radio_read16(dev, 0x007A) & 0x007F);
2631 if (phy->rev >= 2) {
2632 b43_write16(dev, 0x03E6, 0x0040);
2633 } else if (phy->rev == 0) {
2634 b43_write16(dev, 0x03E6, 0x0122);
2635 } else {
2636 b43_write16(dev, B43_MMIO_CHANNEL_EXT,
2637 b43_read16(dev,
2638 B43_MMIO_CHANNEL_EXT) & 0x2000);
2639 }
2640 b43_phy_write(dev, 0x0020, 0x3F3F);
2641 b43_phy_write(dev, 0x0015, 0xF330);
2642 b43_radio_write16(dev, 0x005A, 0x0060);
2643 b43_radio_write16(dev, 0x0043,
2644 b43_radio_read16(dev, 0x0043) & 0x00F0);
2645 b43_phy_write(dev, 0x005A, 0x0480);
2646 b43_phy_write(dev, 0x0059, 0x0810);
2647 b43_phy_write(dev, 0x0058, 0x000D);
2648 udelay(20);
2649
2650 nrssi1 = (s16) b43_phy_read(dev, 0x0027);
2651 b43_phy_write(dev, 0x0030, backup[3]);
2652 b43_radio_write16(dev, 0x007A, backup[0]);
2653 b43_write16(dev, 0x03E2, backup[11]);
2654 b43_phy_write(dev, 0x0026, backup[4]);
2655 b43_phy_write(dev, 0x0015, backup[5]);
2656 b43_phy_write(dev, 0x002A, backup[6]);
2657 b43_synth_pu_workaround(dev, phy->channel);
2658 if (phy->rev != 0)
2659 b43_write16(dev, 0x03F4, backup[13]);
2660
2661 b43_phy_write(dev, 0x0020, backup[7]);
2662 b43_phy_write(dev, 0x005A, backup[8]);
2663 b43_phy_write(dev, 0x0059, backup[9]);
2664 b43_phy_write(dev, 0x0058, backup[10]);
2665 b43_radio_write16(dev, 0x0052, backup[1]);
2666 b43_radio_write16(dev, 0x0043, backup[2]);
2667
2668 if (nrssi0 == nrssi1)
2669 phy->nrssislope = 0x00010000;
2670 else
2671 phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
2672
2673 if (nrssi0 <= -4) {
2674 phy->nrssi[0] = nrssi0;
2675 phy->nrssi[1] = nrssi1;
2676 }
2677 break;
2678 case B43_PHYTYPE_G:
2679 if (phy->radio_rev >= 9)
2680 return;
2681 if (phy->radio_rev == 8)
2682 b43_calc_nrssi_offset(dev);
2683
2684 b43_phy_write(dev, B43_PHY_G_CRS,
2685 b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
2686 b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
2687 backup[7] = b43_read16(dev, 0x03E2);
2688 b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000);
2689 backup[0] = b43_radio_read16(dev, 0x007A);
2690 backup[1] = b43_radio_read16(dev, 0x0052);
2691 backup[2] = b43_radio_read16(dev, 0x0043);
2692 backup[3] = b43_phy_read(dev, 0x0015);
2693 backup[4] = b43_phy_read(dev, 0x005A);
2694 backup[5] = b43_phy_read(dev, 0x0059);
2695 backup[6] = b43_phy_read(dev, 0x0058);
2696 backup[8] = b43_read16(dev, 0x03E6);
2697 backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
2698 if (phy->rev >= 3) {
2699 backup[10] = b43_phy_read(dev, 0x002E);
2700 backup[11] = b43_phy_read(dev, 0x002F);
2701 backup[12] = b43_phy_read(dev, 0x080F);
2702 backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL);
2703 backup[14] = b43_phy_read(dev, 0x0801);
2704 backup[15] = b43_phy_read(dev, 0x0060);
2705 backup[16] = b43_phy_read(dev, 0x0014);
2706 backup[17] = b43_phy_read(dev, 0x0478);
2707 b43_phy_write(dev, 0x002E, 0);
2708 b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0);
2709 switch (phy->rev) {
2710 case 4:
2711 case 6:
2712 case 7:
2713 b43_phy_write(dev, 0x0478,
2714 b43_phy_read(dev, 0x0478)
2715 | 0x0100);
2716 b43_phy_write(dev, 0x0801,
2717 b43_phy_read(dev, 0x0801)
2718 | 0x0040);
2719 break;
2720 case 3:
2721 case 5:
2722 b43_phy_write(dev, 0x0801,
2723 b43_phy_read(dev, 0x0801)
2724 & 0xFFBF);
2725 break;
2726 }
2727 b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060)
2728 | 0x0040);
2729 b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014)
2730 | 0x0200);
2731 }
2732 b43_radio_write16(dev, 0x007A,
2733 b43_radio_read16(dev, 0x007A) | 0x0070);
2734 b43_set_all_gains(dev, 0, 8, 0);
2735 b43_radio_write16(dev, 0x007A,
2736 b43_radio_read16(dev, 0x007A) & 0x00F7);
2737 if (phy->rev >= 2) {
2738 b43_phy_write(dev, 0x0811,
2739 (b43_phy_read(dev, 0x0811) & 0xFFCF) |
2740 0x0030);
2741 b43_phy_write(dev, 0x0812,
2742 (b43_phy_read(dev, 0x0812) & 0xFFCF) |
2743 0x0010);
2744 }
2745 b43_radio_write16(dev, 0x007A,
2746 b43_radio_read16(dev, 0x007A) | 0x0080);
2747 udelay(20);
2748
2749 nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
2750 if (nrssi0 >= 0x0020)
2751 nrssi0 -= 0x0040;
2752
2753 b43_radio_write16(dev, 0x007A,
2754 b43_radio_read16(dev, 0x007A) & 0x007F);
2755 if (phy->rev >= 2) {
2756 b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003)
2757 & 0xFF9F) | 0x0040);
2758 }
2759
2760 b43_write16(dev, B43_MMIO_CHANNEL_EXT,
2761 b43_read16(dev, B43_MMIO_CHANNEL_EXT)
2762 | 0x2000);
2763 b43_radio_write16(dev, 0x007A,
2764 b43_radio_read16(dev, 0x007A) | 0x000F);
2765 b43_phy_write(dev, 0x0015, 0xF330);
2766 if (phy->rev >= 2) {
2767 b43_phy_write(dev, 0x0812,
2768 (b43_phy_read(dev, 0x0812) & 0xFFCF) |
2769 0x0020);
2770 b43_phy_write(dev, 0x0811,
2771 (b43_phy_read(dev, 0x0811) & 0xFFCF) |
2772 0x0020);
2773 }
2774
2775 b43_set_all_gains(dev, 3, 0, 1);
2776 if (phy->radio_rev == 8) {
2777 b43_radio_write16(dev, 0x0043, 0x001F);
2778 } else {
2779 tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F;
2780 b43_radio_write16(dev, 0x0052, tmp | 0x0060);
2781 tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0;
2782 b43_radio_write16(dev, 0x0043, tmp | 0x0009);
2783 }
2784 b43_phy_write(dev, 0x005A, 0x0480);
2785 b43_phy_write(dev, 0x0059, 0x0810);
2786 b43_phy_write(dev, 0x0058, 0x000D);
2787 udelay(20);
2788 nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
2789 if (nrssi1 >= 0x0020)
2790 nrssi1 -= 0x0040;
2791 if (nrssi0 == nrssi1)
2792 phy->nrssislope = 0x00010000;
2793 else
2794 phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
2795 if (nrssi0 >= -4) {
2796 phy->nrssi[0] = nrssi1;
2797 phy->nrssi[1] = nrssi0;
2798 }
2799 if (phy->rev >= 3) {
2800 b43_phy_write(dev, 0x002E, backup[10]);
2801 b43_phy_write(dev, 0x002F, backup[11]);
2802 b43_phy_write(dev, 0x080F, backup[12]);
2803 b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]);
2804 }
2805 if (phy->rev >= 2) {
2806 b43_phy_write(dev, 0x0812,
2807 b43_phy_read(dev, 0x0812) & 0xFFCF);
2808 b43_phy_write(dev, 0x0811,
2809 b43_phy_read(dev, 0x0811) & 0xFFCF);
2810 }
2811
2812 b43_radio_write16(dev, 0x007A, backup[0]);
2813 b43_radio_write16(dev, 0x0052, backup[1]);
2814 b43_radio_write16(dev, 0x0043, backup[2]);
2815 b43_write16(dev, 0x03E2, backup[7]);
2816 b43_write16(dev, 0x03E6, backup[8]);
2817 b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]);
2818 b43_phy_write(dev, 0x0015, backup[3]);
2819 b43_phy_write(dev, 0x005A, backup[4]);
2820 b43_phy_write(dev, 0x0059, backup[5]);
2821 b43_phy_write(dev, 0x0058, backup[6]);
2822 b43_synth_pu_workaround(dev, phy->channel);
2823 b43_phy_write(dev, 0x0802,
2824 b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002));
2825 b43_set_original_gains(dev);
2826 b43_phy_write(dev, B43_PHY_G_CRS,
2827 b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
2828 if (phy->rev >= 3) {
2829 b43_phy_write(dev, 0x0801, backup[14]);
2830 b43_phy_write(dev, 0x0060, backup[15]);
2831 b43_phy_write(dev, 0x0014, backup[16]);
2832 b43_phy_write(dev, 0x0478, backup[17]);
2833 }
2834 b43_nrssi_mem_update(dev);
2835 b43_calc_nrssi_threshold(dev);
2836 break;
2837 default:
2838 B43_WARN_ON(1);
2839 }
2840}
2841
2842void b43_calc_nrssi_threshold(struct b43_wldev *dev)
2843{
2844 struct b43_phy *phy = &dev->phy;
2845 s32 threshold;
2846 s32 a, b;
2847 s16 tmp16;
2848 u16 tmp_u16;
2849
2850 switch (phy->type) {
2851 case B43_PHYTYPE_B:{
2852 if (phy->radio_ver != 0x2050)
2853 return;
2854 if (!
Larry Finger95de2842007-11-09 16:57:18 -06002855 (dev->dev->bus->sprom.
Michael Buesche4d6b792007-09-18 15:39:42 -04002856 boardflags_lo & B43_BFL_RSSI))
2857 return;
2858
2859 if (phy->radio_rev >= 6) {
2860 threshold =
2861 (phy->nrssi[1] - phy->nrssi[0]) * 32;
2862 threshold += 20 * (phy->nrssi[0] + 1);
2863 threshold /= 40;
2864 } else
2865 threshold = phy->nrssi[1] - 5;
2866
2867 threshold = limit_value(threshold, 0, 0x3E);
2868 b43_phy_read(dev, 0x0020); /* dummy read */
2869 b43_phy_write(dev, 0x0020,
2870 (((u16) threshold) << 8) | 0x001C);
2871
2872 if (phy->radio_rev >= 6) {
2873 b43_phy_write(dev, 0x0087, 0x0E0D);
2874 b43_phy_write(dev, 0x0086, 0x0C0B);
2875 b43_phy_write(dev, 0x0085, 0x0A09);
2876 b43_phy_write(dev, 0x0084, 0x0808);
2877 b43_phy_write(dev, 0x0083, 0x0808);
2878 b43_phy_write(dev, 0x0082, 0x0604);
2879 b43_phy_write(dev, 0x0081, 0x0302);
2880 b43_phy_write(dev, 0x0080, 0x0100);
2881 }
2882 break;
2883 }
2884 case B43_PHYTYPE_G:
2885 if (!phy->gmode ||
Larry Finger95de2842007-11-09 16:57:18 -06002886 !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04002887 tmp16 = b43_nrssi_hw_read(dev, 0x20);
2888 if (tmp16 >= 0x20)
2889 tmp16 -= 0x40;
2890 if (tmp16 < 3) {
2891 b43_phy_write(dev, 0x048A,
2892 (b43_phy_read(dev, 0x048A)
2893 & 0xF000) | 0x09EB);
2894 } else {
2895 b43_phy_write(dev, 0x048A,
2896 (b43_phy_read(dev, 0x048A)
2897 & 0xF000) | 0x0AED);
2898 }
2899 } else {
2900 if (phy->interfmode == B43_INTERFMODE_NONWLAN) {
2901 a = 0xE;
2902 b = 0xA;
2903 } else if (!phy->aci_wlan_automatic && phy->aci_enable) {
2904 a = 0x13;
2905 b = 0x12;
2906 } else {
2907 a = 0xE;
2908 b = 0x11;
2909 }
2910
2911 a = a * (phy->nrssi[1] - phy->nrssi[0]);
2912 a += (phy->nrssi[0] << 6);
2913 if (a < 32)
2914 a += 31;
2915 else
2916 a += 32;
2917 a = a >> 6;
2918 a = limit_value(a, -31, 31);
2919
2920 b = b * (phy->nrssi[1] - phy->nrssi[0]);
2921 b += (phy->nrssi[0] << 6);
2922 if (b < 32)
2923 b += 31;
2924 else
2925 b += 32;
2926 b = b >> 6;
2927 b = limit_value(b, -31, 31);
2928
2929 tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
2930 tmp_u16 |= ((u32) b & 0x0000003F);
2931 tmp_u16 |= (((u32) a & 0x0000003F) << 6);
2932 b43_phy_write(dev, 0x048A, tmp_u16);
2933 }
2934 break;
2935 default:
2936 B43_WARN_ON(1);
2937 }
2938}
2939
2940/* Stack implementation to save/restore values from the
2941 * interference mitigation code.
2942 * It is save to restore values in random order.
2943 */
2944static void _stack_save(u32 * _stackptr, size_t * stackidx,
2945 u8 id, u16 offset, u16 value)
2946{
2947 u32 *stackptr = &(_stackptr[*stackidx]);
2948
2949 B43_WARN_ON(offset & 0xF000);
2950 B43_WARN_ON(id & 0xF0);
2951 *stackptr = offset;
2952 *stackptr |= ((u32) id) << 12;
2953 *stackptr |= ((u32) value) << 16;
2954 (*stackidx)++;
2955 B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE);
2956}
2957
2958static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset)
2959{
2960 size_t i;
2961
2962 B43_WARN_ON(offset & 0xF000);
2963 B43_WARN_ON(id & 0xF0);
2964 for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) {
2965 if ((*stackptr & 0x00000FFF) != offset)
2966 continue;
2967 if (((*stackptr & 0x0000F000) >> 12) != id)
2968 continue;
2969 return ((*stackptr & 0xFFFF0000) >> 16);
2970 }
2971 B43_WARN_ON(1);
2972
2973 return 0;
2974}
2975
2976#define phy_stacksave(offset) \
2977 do { \
2978 _stack_save(stack, &stackidx, 0x1, (offset), \
2979 b43_phy_read(dev, (offset))); \
2980 } while (0)
2981#define phy_stackrestore(offset) \
2982 do { \
2983 b43_phy_write(dev, (offset), \
2984 _stack_restore(stack, 0x1, \
2985 (offset))); \
2986 } while (0)
2987#define radio_stacksave(offset) \
2988 do { \
2989 _stack_save(stack, &stackidx, 0x2, (offset), \
2990 b43_radio_read16(dev, (offset))); \
2991 } while (0)
2992#define radio_stackrestore(offset) \
2993 do { \
2994 b43_radio_write16(dev, (offset), \
2995 _stack_restore(stack, 0x2, \
2996 (offset))); \
2997 } while (0)
2998#define ofdmtab_stacksave(table, offset) \
2999 do { \
3000 _stack_save(stack, &stackidx, 0x3, (offset)|(table), \
3001 b43_ofdmtab_read16(dev, (table), (offset))); \
3002 } while (0)
3003#define ofdmtab_stackrestore(table, offset) \
3004 do { \
3005 b43_ofdmtab_write16(dev, (table), (offset), \
3006 _stack_restore(stack, 0x3, \
3007 (offset)|(table))); \
3008 } while (0)
3009
3010static void
3011b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
3012{
3013 struct b43_phy *phy = &dev->phy;
3014 u16 tmp, flipped;
3015 size_t stackidx = 0;
3016 u32 *stack = phy->interfstack;
3017
3018 switch (mode) {
3019 case B43_INTERFMODE_NONWLAN:
3020 if (phy->rev != 1) {
3021 b43_phy_write(dev, 0x042B,
3022 b43_phy_read(dev, 0x042B) | 0x0800);
3023 b43_phy_write(dev, B43_PHY_G_CRS,
3024 b43_phy_read(dev,
3025 B43_PHY_G_CRS) & ~0x4000);
3026 break;
3027 }
3028 radio_stacksave(0x0078);
3029 tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
3030 flipped = flip_4bit(tmp);
3031 if (flipped < 10 && flipped >= 8)
3032 flipped = 7;
3033 else if (flipped >= 10)
3034 flipped -= 3;
3035 flipped = flip_4bit(flipped);
3036 flipped = (flipped << 1) | 0x0020;
3037 b43_radio_write16(dev, 0x0078, flipped);
3038
3039 b43_calc_nrssi_threshold(dev);
3040
3041 phy_stacksave(0x0406);
3042 b43_phy_write(dev, 0x0406, 0x7E28);
3043
3044 b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800);
3045 b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
3046 b43_phy_read(dev,
3047 B43_PHY_RADIO_BITFIELD) | 0x1000);
3048
3049 phy_stacksave(0x04A0);
3050 b43_phy_write(dev, 0x04A0,
3051 (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008);
3052 phy_stacksave(0x04A1);
3053 b43_phy_write(dev, 0x04A1,
3054 (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605);
3055 phy_stacksave(0x04A2);
3056 b43_phy_write(dev, 0x04A2,
3057 (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204);
3058 phy_stacksave(0x04A8);
3059 b43_phy_write(dev, 0x04A8,
3060 (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803);
3061 phy_stacksave(0x04AB);
3062 b43_phy_write(dev, 0x04AB,
3063 (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605);
3064
3065 phy_stacksave(0x04A7);
3066 b43_phy_write(dev, 0x04A7, 0x0002);
3067 phy_stacksave(0x04A3);
3068 b43_phy_write(dev, 0x04A3, 0x287A);
3069 phy_stacksave(0x04A9);
3070 b43_phy_write(dev, 0x04A9, 0x2027);
3071 phy_stacksave(0x0493);
3072 b43_phy_write(dev, 0x0493, 0x32F5);
3073 phy_stacksave(0x04AA);
3074 b43_phy_write(dev, 0x04AA, 0x2027);
3075 phy_stacksave(0x04AC);
3076 b43_phy_write(dev, 0x04AC, 0x32F5);
3077 break;
3078 case B43_INTERFMODE_MANUALWLAN:
3079 if (b43_phy_read(dev, 0x0033) & 0x0800)
3080 break;
3081
3082 phy->aci_enable = 1;
3083
3084 phy_stacksave(B43_PHY_RADIO_BITFIELD);
3085 phy_stacksave(B43_PHY_G_CRS);
3086 if (phy->rev < 2) {
3087 phy_stacksave(0x0406);
3088 } else {
3089 phy_stacksave(0x04C0);
3090 phy_stacksave(0x04C1);
3091 }
3092 phy_stacksave(0x0033);
3093 phy_stacksave(0x04A7);
3094 phy_stacksave(0x04A3);
3095 phy_stacksave(0x04A9);
3096 phy_stacksave(0x04AA);
3097 phy_stacksave(0x04AC);
3098 phy_stacksave(0x0493);
3099 phy_stacksave(0x04A1);
3100 phy_stacksave(0x04A0);
3101 phy_stacksave(0x04A2);
3102 phy_stacksave(0x048A);
3103 phy_stacksave(0x04A8);
3104 phy_stacksave(0x04AB);
3105 if (phy->rev == 2) {
3106 phy_stacksave(0x04AD);
3107 phy_stacksave(0x04AE);
3108 } else if (phy->rev >= 3) {
3109 phy_stacksave(0x04AD);
3110 phy_stacksave(0x0415);
3111 phy_stacksave(0x0416);
3112 phy_stacksave(0x0417);
3113 ofdmtab_stacksave(0x1A00, 0x2);
3114 ofdmtab_stacksave(0x1A00, 0x3);
3115 }
3116 phy_stacksave(0x042B);
3117 phy_stacksave(0x048C);
3118
3119 b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
3120 b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
3121 & ~0x1000);
3122 b43_phy_write(dev, B43_PHY_G_CRS,
3123 (b43_phy_read(dev, B43_PHY_G_CRS)
3124 & 0xFFFC) | 0x0002);
3125
3126 b43_phy_write(dev, 0x0033, 0x0800);
3127 b43_phy_write(dev, 0x04A3, 0x2027);
3128 b43_phy_write(dev, 0x04A9, 0x1CA8);
3129 b43_phy_write(dev, 0x0493, 0x287A);
3130 b43_phy_write(dev, 0x04AA, 0x1CA8);
3131 b43_phy_write(dev, 0x04AC, 0x287A);
3132
3133 b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
3134 & 0xFFC0) | 0x001A);
3135 b43_phy_write(dev, 0x04A7, 0x000D);
3136
3137 if (phy->rev < 2) {
3138 b43_phy_write(dev, 0x0406, 0xFF0D);
3139 } else if (phy->rev == 2) {
3140 b43_phy_write(dev, 0x04C0, 0xFFFF);
3141 b43_phy_write(dev, 0x04C1, 0x00A9);
3142 } else {
3143 b43_phy_write(dev, 0x04C0, 0x00C1);
3144 b43_phy_write(dev, 0x04C1, 0x0059);
3145 }
3146
3147 b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
3148 & 0xC0FF) | 0x1800);
3149 b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
3150 & 0xFFC0) | 0x0015);
3151 b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
3152 & 0xCFFF) | 0x1000);
3153 b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
3154 & 0xF0FF) | 0x0A00);
3155 b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
3156 & 0xCFFF) | 0x1000);
3157 b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
3158 & 0xF0FF) | 0x0800);
3159 b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
3160 & 0xFFCF) | 0x0010);
3161 b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
3162 & 0xFFF0) | 0x0005);
3163 b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
3164 & 0xFFCF) | 0x0010);
3165 b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
3166 & 0xFFF0) | 0x0006);
3167 b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
3168 & 0xF0FF) | 0x0800);
3169 b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
3170 & 0xF0FF) | 0x0500);
3171 b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
3172 & 0xFFF0) | 0x000B);
3173
3174 if (phy->rev >= 3) {
3175 b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
3176 & ~0x8000);
3177 b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415)
3178 & 0x8000) | 0x36D8);
3179 b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416)
3180 & 0x8000) | 0x36D8);
3181 b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417)
3182 & 0xFE00) | 0x016D);
3183 } else {
3184 b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
3185 | 0x1000);
3186 b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A)
3187 & 0x9FFF) | 0x2000);
3188 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW);
3189 }
3190 if (phy->rev >= 2) {
3191 b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B)
3192 | 0x0800);
3193 }
3194 b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
3195 & 0xF0FF) | 0x0200);
3196 if (phy->rev == 2) {
3197 b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE)
3198 & 0xFF00) | 0x007F);
3199 b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD)
3200 & 0x00FF) | 0x1300);
3201 } else if (phy->rev >= 6) {
3202 b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F);
3203 b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F);
3204 b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD)
3205 & 0x00FF);
3206 }
3207 b43_calc_nrssi_slope(dev);
3208 break;
3209 default:
3210 B43_WARN_ON(1);
3211 }
3212}
3213
3214static void
3215b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode)
3216{
3217 struct b43_phy *phy = &dev->phy;
3218 u32 *stack = phy->interfstack;
3219
3220 switch (mode) {
3221 case B43_INTERFMODE_NONWLAN:
3222 if (phy->rev != 1) {
3223 b43_phy_write(dev, 0x042B,
3224 b43_phy_read(dev, 0x042B) & ~0x0800);
3225 b43_phy_write(dev, B43_PHY_G_CRS,
3226 b43_phy_read(dev,
3227 B43_PHY_G_CRS) | 0x4000);
3228 break;
3229 }
3230 radio_stackrestore(0x0078);
3231 b43_calc_nrssi_threshold(dev);
3232 phy_stackrestore(0x0406);
3233 b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800);
3234 if (!dev->bad_frames_preempt) {
3235 b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
3236 b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
3237 & ~(1 << 11));
3238 }
3239 b43_phy_write(dev, B43_PHY_G_CRS,
3240 b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000);
3241 phy_stackrestore(0x04A0);
3242 phy_stackrestore(0x04A1);
3243 phy_stackrestore(0x04A2);
3244 phy_stackrestore(0x04A8);
3245 phy_stackrestore(0x04AB);
3246 phy_stackrestore(0x04A7);
3247 phy_stackrestore(0x04A3);
3248 phy_stackrestore(0x04A9);
3249 phy_stackrestore(0x0493);
3250 phy_stackrestore(0x04AA);
3251 phy_stackrestore(0x04AC);
3252 break;
3253 case B43_INTERFMODE_MANUALWLAN:
3254 if (!(b43_phy_read(dev, 0x0033) & 0x0800))
3255 break;
3256
3257 phy->aci_enable = 0;
3258
3259 phy_stackrestore(B43_PHY_RADIO_BITFIELD);
3260 phy_stackrestore(B43_PHY_G_CRS);
3261 phy_stackrestore(0x0033);
3262 phy_stackrestore(0x04A3);
3263 phy_stackrestore(0x04A9);
3264 phy_stackrestore(0x0493);
3265 phy_stackrestore(0x04AA);
3266 phy_stackrestore(0x04AC);
3267 phy_stackrestore(0x04A0);
3268 phy_stackrestore(0x04A7);
3269 if (phy->rev >= 2) {
3270 phy_stackrestore(0x04C0);
3271 phy_stackrestore(0x04C1);
3272 } else
3273 phy_stackrestore(0x0406);
3274 phy_stackrestore(0x04A1);
3275 phy_stackrestore(0x04AB);
3276 phy_stackrestore(0x04A8);
3277 if (phy->rev == 2) {
3278 phy_stackrestore(0x04AD);
3279 phy_stackrestore(0x04AE);
3280 } else if (phy->rev >= 3) {
3281 phy_stackrestore(0x04AD);
3282 phy_stackrestore(0x0415);
3283 phy_stackrestore(0x0416);
3284 phy_stackrestore(0x0417);
3285 ofdmtab_stackrestore(0x1A00, 0x2);
3286 ofdmtab_stackrestore(0x1A00, 0x3);
3287 }
3288 phy_stackrestore(0x04A2);
3289 phy_stackrestore(0x048A);
3290 phy_stackrestore(0x042B);
3291 phy_stackrestore(0x048C);
3292 b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW);
3293 b43_calc_nrssi_slope(dev);
3294 break;
3295 default:
3296 B43_WARN_ON(1);
3297 }
3298}
3299
3300#undef phy_stacksave
3301#undef phy_stackrestore
3302#undef radio_stacksave
3303#undef radio_stackrestore
3304#undef ofdmtab_stacksave
3305#undef ofdmtab_stackrestore
3306
3307int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode)
3308{
3309 struct b43_phy *phy = &dev->phy;
3310 int currentmode;
3311
3312 if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode))
3313 return -ENODEV;
3314
3315 phy->aci_wlan_automatic = 0;
3316 switch (mode) {
3317 case B43_INTERFMODE_AUTOWLAN:
3318 phy->aci_wlan_automatic = 1;
3319 if (phy->aci_enable)
3320 mode = B43_INTERFMODE_MANUALWLAN;
3321 else
3322 mode = B43_INTERFMODE_NONE;
3323 break;
3324 case B43_INTERFMODE_NONE:
3325 case B43_INTERFMODE_NONWLAN:
3326 case B43_INTERFMODE_MANUALWLAN:
3327 break;
3328 default:
3329 return -EINVAL;
3330 }
3331
3332 currentmode = phy->interfmode;
3333 if (currentmode == mode)
3334 return 0;
3335 if (currentmode != B43_INTERFMODE_NONE)
3336 b43_radio_interference_mitigation_disable(dev, currentmode);
3337
3338 if (mode == B43_INTERFMODE_NONE) {
3339 phy->aci_enable = 0;
3340 phy->aci_hw_rssi = 0;
3341 } else
3342 b43_radio_interference_mitigation_enable(dev, mode);
3343 phy->interfmode = mode;
3344
3345 return 0;
3346}
3347
3348static u16 b43_radio_core_calibration_value(struct b43_wldev *dev)
3349{
3350 u16 reg, index, ret;
3351
3352 static const u8 rcc_table[] = {
3353 0x02, 0x03, 0x01, 0x0F,
3354 0x06, 0x07, 0x05, 0x0F,
3355 0x0A, 0x0B, 0x09, 0x0F,
3356 0x0E, 0x0F, 0x0D, 0x0F,
3357 };
3358
3359 reg = b43_radio_read16(dev, 0x60);
3360 index = (reg & 0x001E) >> 1;
3361 ret = rcc_table[index] << 1;
3362 ret |= (reg & 0x0001);
3363 ret |= 0x0020;
3364
3365 return ret;
3366}
3367
3368#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
3369static u16 radio2050_rfover_val(struct b43_wldev *dev,
3370 u16 phy_register, unsigned int lpd)
3371{
3372 struct b43_phy *phy = &dev->phy;
3373 struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
3374
3375 if (!phy->gmode)
3376 return 0;
3377
3378 if (has_loopback_gain(phy)) {
3379 int max_lb_gain = phy->max_lb_gain;
3380 u16 extlna;
3381 u16 i;
3382
3383 if (phy->radio_rev == 8)
3384 max_lb_gain += 0x3E;
3385 else
3386 max_lb_gain += 0x26;
3387 if (max_lb_gain >= 0x46) {
3388 extlna = 0x3000;
3389 max_lb_gain -= 0x46;
3390 } else if (max_lb_gain >= 0x3A) {
3391 extlna = 0x1000;
3392 max_lb_gain -= 0x3A;
3393 } else if (max_lb_gain >= 0x2E) {
3394 extlna = 0x2000;
3395 max_lb_gain -= 0x2E;
3396 } else {
3397 extlna = 0;
3398 max_lb_gain -= 0x10;
3399 }
3400
3401 for (i = 0; i < 16; i++) {
3402 max_lb_gain -= (i * 6);
3403 if (max_lb_gain < 6)
3404 break;
3405 }
3406
3407 if ((phy->rev < 7) ||
Larry Finger95de2842007-11-09 16:57:18 -06003408 !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04003409 if (phy_register == B43_PHY_RFOVER) {
3410 return 0x1B3;
3411 } else if (phy_register == B43_PHY_RFOVERVAL) {
3412 extlna |= (i << 8);
3413 switch (lpd) {
3414 case LPD(0, 1, 1):
3415 return 0x0F92;
3416 case LPD(0, 0, 1):
3417 case LPD(1, 0, 1):
3418 return (0x0092 | extlna);
3419 case LPD(1, 0, 0):
3420 return (0x0093 | extlna);
3421 }
3422 B43_WARN_ON(1);
3423 }
3424 B43_WARN_ON(1);
3425 } else {
3426 if (phy_register == B43_PHY_RFOVER) {
3427 return 0x9B3;
3428 } else if (phy_register == B43_PHY_RFOVERVAL) {
3429 if (extlna)
3430 extlna |= 0x8000;
3431 extlna |= (i << 8);
3432 switch (lpd) {
3433 case LPD(0, 1, 1):
3434 return 0x8F92;
3435 case LPD(0, 0, 1):
3436 return (0x8092 | extlna);
3437 case LPD(1, 0, 1):
3438 return (0x2092 | extlna);
3439 case LPD(1, 0, 0):
3440 return (0x2093 | extlna);
3441 }
3442 B43_WARN_ON(1);
3443 }
3444 B43_WARN_ON(1);
3445 }
3446 } else {
3447 if ((phy->rev < 7) ||
Larry Finger95de2842007-11-09 16:57:18 -06003448 !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
Michael Buesche4d6b792007-09-18 15:39:42 -04003449 if (phy_register == B43_PHY_RFOVER) {
3450 return 0x1B3;
3451 } else if (phy_register == B43_PHY_RFOVERVAL) {
3452 switch (lpd) {
3453 case LPD(0, 1, 1):
3454 return 0x0FB2;
3455 case LPD(0, 0, 1):
3456 return 0x00B2;
3457 case LPD(1, 0, 1):
3458 return 0x30B2;
3459 case LPD(1, 0, 0):
3460 return 0x30B3;
3461 }
3462 B43_WARN_ON(1);
3463 }
3464 B43_WARN_ON(1);
3465 } else {
3466 if (phy_register == B43_PHY_RFOVER) {
3467 return 0x9B3;
3468 } else if (phy_register == B43_PHY_RFOVERVAL) {
3469 switch (lpd) {
3470 case LPD(0, 1, 1):
3471 return 0x8FB2;
3472 case LPD(0, 0, 1):
3473 return 0x80B2;
3474 case LPD(1, 0, 1):
3475 return 0x20B2;
3476 case LPD(1, 0, 0):
3477 return 0x20B3;
3478 }
3479 B43_WARN_ON(1);
3480 }
3481 B43_WARN_ON(1);
3482 }
3483 }
3484 return 0;
3485}
3486
3487struct init2050_saved_values {
3488 /* Core registers */
3489 u16 reg_3EC;
3490 u16 reg_3E6;
3491 u16 reg_3F4;
3492 /* Radio registers */
3493 u16 radio_43;
3494 u16 radio_51;
3495 u16 radio_52;
3496 /* PHY registers */
3497 u16 phy_pgactl;
Michael Buesch52507032008-01-09 18:39:09 +01003498 u16 phy_cck_5A;
3499 u16 phy_cck_59;
3500 u16 phy_cck_58;
3501 u16 phy_cck_30;
Michael Buesche4d6b792007-09-18 15:39:42 -04003502 u16 phy_rfover;
3503 u16 phy_rfoverval;
3504 u16 phy_analogover;
3505 u16 phy_analogoverval;
3506 u16 phy_crs0;
3507 u16 phy_classctl;
3508 u16 phy_lo_mask;
3509 u16 phy_lo_ctl;
3510 u16 phy_syncctl;
3511};
3512
3513u16 b43_radio_init2050(struct b43_wldev *dev)
3514{
3515 struct b43_phy *phy = &dev->phy;
3516 struct init2050_saved_values sav;
3517 u16 rcc;
3518 u16 radio78;
3519 u16 ret;
3520 u16 i, j;
3521 u32 tmp1 = 0, tmp2 = 0;
3522
3523 memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */
3524
3525 sav.radio_43 = b43_radio_read16(dev, 0x43);
3526 sav.radio_51 = b43_radio_read16(dev, 0x51);
3527 sav.radio_52 = b43_radio_read16(dev, 0x52);
3528 sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
Michael Buesch52507032008-01-09 18:39:09 +01003529 sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A));
3530 sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59));
3531 sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58));
Michael Buesche4d6b792007-09-18 15:39:42 -04003532
3533 if (phy->type == B43_PHYTYPE_B) {
Michael Buesch52507032008-01-09 18:39:09 +01003534 sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
Michael Buesche4d6b792007-09-18 15:39:42 -04003535 sav.reg_3EC = b43_read16(dev, 0x3EC);
3536
Michael Buesch52507032008-01-09 18:39:09 +01003537 b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF);
Michael Buesche4d6b792007-09-18 15:39:42 -04003538 b43_write16(dev, 0x3EC, 0x3F3F);
3539 } else if (phy->gmode || phy->rev >= 2) {
3540 sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
3541 sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
3542 sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
3543 sav.phy_analogoverval =
3544 b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
3545 sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
3546 sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
3547
3548 b43_phy_write(dev, B43_PHY_ANALOGOVER,
3549 b43_phy_read(dev, B43_PHY_ANALOGOVER)
3550 | 0x0003);
3551 b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
3552 b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
3553 & 0xFFFC);
3554 b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
3555 & 0x7FFF);
3556 b43_phy_write(dev, B43_PHY_CLASSCTL,
3557 b43_phy_read(dev, B43_PHY_CLASSCTL)
3558 & 0xFFFC);
3559 if (has_loopback_gain(phy)) {
3560 sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
3561 sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL);
3562
3563 if (phy->rev >= 3)
3564 b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
3565 else
3566 b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
3567 b43_phy_write(dev, B43_PHY_LO_CTL, 0);
3568 }
3569
3570 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3571 radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
3572 LPD(0, 1, 1)));
3573 b43_phy_write(dev, B43_PHY_RFOVER,
3574 radio2050_rfover_val(dev, B43_PHY_RFOVER, 0));
3575 }
3576 b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000);
3577
3578 sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
3579 b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL)
3580 & 0xFF7F);
3581 sav.reg_3E6 = b43_read16(dev, 0x3E6);
3582 sav.reg_3F4 = b43_read16(dev, 0x3F4);
3583
3584 if (phy->analog == 0) {
3585 b43_write16(dev, 0x03E6, 0x0122);
3586 } else {
3587 if (phy->analog >= 2) {
Michael Buesch52507032008-01-09 18:39:09 +01003588 b43_phy_write(dev, B43_PHY_CCK(0x03),
3589 (b43_phy_read(dev, B43_PHY_CCK(0x03))
Michael Buesche4d6b792007-09-18 15:39:42 -04003590 & 0xFFBF) | 0x40);
3591 }
3592 b43_write16(dev, B43_MMIO_CHANNEL_EXT,
3593 (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000));
3594 }
3595
3596 rcc = b43_radio_core_calibration_value(dev);
3597
3598 if (phy->type == B43_PHYTYPE_B)
3599 b43_radio_write16(dev, 0x78, 0x26);
3600 if (phy->gmode || phy->rev >= 2) {
3601 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3602 radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
3603 LPD(0, 1, 1)));
3604 }
3605 b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
Michael Buesch52507032008-01-09 18:39:09 +01003606 b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403);
Michael Buesche4d6b792007-09-18 15:39:42 -04003607 if (phy->gmode || phy->rev >= 2) {
3608 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3609 radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
3610 LPD(0, 0, 1)));
3611 }
3612 b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0);
3613 b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51)
3614 | 0x0004);
3615 if (phy->radio_rev == 8) {
3616 b43_radio_write16(dev, 0x43, 0x1F);
3617 } else {
3618 b43_radio_write16(dev, 0x52, 0);
3619 b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
3620 & 0xFFF0) | 0x0009);
3621 }
Michael Buesch52507032008-01-09 18:39:09 +01003622 b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04003623
3624 for (i = 0; i < 16; i++) {
Michael Buesch52507032008-01-09 18:39:09 +01003625 b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480);
3626 b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
3627 b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
Michael Buesche4d6b792007-09-18 15:39:42 -04003628 if (phy->gmode || phy->rev >= 2) {
3629 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3630 radio2050_rfover_val(dev,
3631 B43_PHY_RFOVERVAL,
3632 LPD(1, 0, 1)));
3633 }
3634 b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
3635 udelay(10);
3636 if (phy->gmode || phy->rev >= 2) {
3637 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3638 radio2050_rfover_val(dev,
3639 B43_PHY_RFOVERVAL,
3640 LPD(1, 0, 1)));
3641 }
3642 b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
3643 udelay(10);
3644 if (phy->gmode || phy->rev >= 2) {
3645 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3646 radio2050_rfover_val(dev,
3647 B43_PHY_RFOVERVAL,
3648 LPD(1, 0, 0)));
3649 }
3650 b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
3651 udelay(20);
3652 tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
Michael Buesch52507032008-01-09 18:39:09 +01003653 b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04003654 if (phy->gmode || phy->rev >= 2) {
3655 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3656 radio2050_rfover_val(dev,
3657 B43_PHY_RFOVERVAL,
3658 LPD(1, 0, 1)));
3659 }
3660 b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
3661 }
3662 udelay(10);
3663
Michael Buesch52507032008-01-09 18:39:09 +01003664 b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04003665 tmp1++;
3666 tmp1 >>= 9;
3667
3668 for (i = 0; i < 16; i++) {
3669 radio78 = ((flip_4bit(i) << 1) | 0x20);
3670 b43_radio_write16(dev, 0x78, radio78);
3671 udelay(10);
3672 for (j = 0; j < 16; j++) {
Michael Buesch52507032008-01-09 18:39:09 +01003673 b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80);
3674 b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
3675 b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
Michael Buesche4d6b792007-09-18 15:39:42 -04003676 if (phy->gmode || phy->rev >= 2) {
3677 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3678 radio2050_rfover_val(dev,
3679 B43_PHY_RFOVERVAL,
3680 LPD(1, 0,
3681 1)));
3682 }
3683 b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
3684 udelay(10);
3685 if (phy->gmode || phy->rev >= 2) {
3686 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3687 radio2050_rfover_val(dev,
3688 B43_PHY_RFOVERVAL,
3689 LPD(1, 0,
3690 1)));
3691 }
3692 b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
3693 udelay(10);
3694 if (phy->gmode || phy->rev >= 2) {
3695 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3696 radio2050_rfover_val(dev,
3697 B43_PHY_RFOVERVAL,
3698 LPD(1, 0,
3699 0)));
3700 }
3701 b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
3702 udelay(10);
3703 tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
Michael Buesch52507032008-01-09 18:39:09 +01003704 b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04003705 if (phy->gmode || phy->rev >= 2) {
3706 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3707 radio2050_rfover_val(dev,
3708 B43_PHY_RFOVERVAL,
3709 LPD(1, 0,
3710 1)));
3711 }
3712 b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
3713 }
3714 tmp2++;
3715 tmp2 >>= 8;
3716 if (tmp1 < tmp2)
3717 break;
3718 }
3719
3720 /* Restore the registers */
3721 b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl);
3722 b43_radio_write16(dev, 0x51, sav.radio_51);
3723 b43_radio_write16(dev, 0x52, sav.radio_52);
3724 b43_radio_write16(dev, 0x43, sav.radio_43);
Michael Buesch52507032008-01-09 18:39:09 +01003725 b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A);
3726 b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59);
3727 b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58);
Michael Buesche4d6b792007-09-18 15:39:42 -04003728 b43_write16(dev, 0x3E6, sav.reg_3E6);
3729 if (phy->analog != 0)
3730 b43_write16(dev, 0x3F4, sav.reg_3F4);
3731 b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
3732 b43_synth_pu_workaround(dev, phy->channel);
3733 if (phy->type == B43_PHYTYPE_B) {
Michael Buesch52507032008-01-09 18:39:09 +01003734 b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30);
Michael Buesche4d6b792007-09-18 15:39:42 -04003735 b43_write16(dev, 0x3EC, sav.reg_3EC);
3736 } else if (phy->gmode) {
3737 b43_write16(dev, B43_MMIO_PHY_RADIO,
3738 b43_read16(dev, B43_MMIO_PHY_RADIO)
3739 & 0x7FFF);
3740 b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover);
3741 b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval);
3742 b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover);
3743 b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
3744 sav.phy_analogoverval);
3745 b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0);
3746 b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl);
3747 if (has_loopback_gain(phy)) {
3748 b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask);
3749 b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl);
3750 }
3751 }
3752 if (i > 15)
3753 ret = radio78;
3754 else
3755 ret = rcc;
3756
3757 return ret;
3758}
3759
3760void b43_radio_init2060(struct b43_wldev *dev)
3761{
3762 int err;
3763
3764 b43_radio_write16(dev, 0x0004, 0x00C0);
3765 b43_radio_write16(dev, 0x0005, 0x0008);
3766 b43_radio_write16(dev, 0x0009, 0x0040);
3767 b43_radio_write16(dev, 0x0005, 0x00AA);
3768 b43_radio_write16(dev, 0x0032, 0x008F);
3769 b43_radio_write16(dev, 0x0006, 0x008F);
3770 b43_radio_write16(dev, 0x0034, 0x008F);
3771 b43_radio_write16(dev, 0x002C, 0x0007);
3772 b43_radio_write16(dev, 0x0082, 0x0080);
3773 b43_radio_write16(dev, 0x0080, 0x0000);
3774 b43_radio_write16(dev, 0x003F, 0x00DA);
3775 b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
3776 b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010);
3777 b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
3778 b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
3779 msleep(1); /* delay 400usec */
3780
3781 b43_radio_write16(dev, 0x0081,
3782 (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
3783 msleep(1); /* delay 400usec */
3784
3785 b43_radio_write16(dev, 0x0005,
3786 (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
3787 b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010);
3788 b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
3789 b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040);
3790 b43_radio_write16(dev, 0x0081,
3791 (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040);
3792 b43_radio_write16(dev, 0x0005,
3793 (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008);
3794 b43_phy_write(dev, 0x0063, 0xDDC6);
3795 b43_phy_write(dev, 0x0069, 0x07BE);
3796 b43_phy_write(dev, 0x006A, 0x0000);
3797
3798 err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0);
3799 B43_WARN_ON(err);
3800
3801 msleep(1);
3802}
3803
3804static inline u16 freq_r3A_value(u16 frequency)
3805{
3806 u16 value;
3807
3808 if (frequency < 5091)
3809 value = 0x0040;
3810 else if (frequency < 5321)
3811 value = 0x0000;
3812 else if (frequency < 5806)
3813 value = 0x0080;
3814 else
3815 value = 0x0040;
3816
3817 return value;
3818}
3819
3820void b43_radio_set_tx_iq(struct b43_wldev *dev)
3821{
3822 static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
3823 static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
3824 u16 tmp = b43_radio_read16(dev, 0x001E);
3825 int i, j;
3826
3827 for (i = 0; i < 5; i++) {
3828 for (j = 0; j < 5; j++) {
3829 if (tmp == (data_high[i] << 4 | data_low[j])) {
3830 b43_phy_write(dev, 0x0069,
3831 (i - j) << 8 | 0x00C0);
3832 return;
3833 }
3834 }
3835 }
3836}
3837
3838int b43_radio_selectchannel(struct b43_wldev *dev,
3839 u8 channel, int synthetic_pu_workaround)
3840{
3841 struct b43_phy *phy = &dev->phy;
3842 u16 r8, tmp;
3843 u16 freq;
3844 u16 channelcookie;
3845
Michael Bueschfda9abc2007-09-20 22:14:18 +02003846 if (channel == 0xFF) {
3847 switch (phy->type) {
3848 case B43_PHYTYPE_A:
3849 channel = B43_DEFAULT_CHANNEL_A;
3850 break;
3851 case B43_PHYTYPE_B:
3852 case B43_PHYTYPE_G:
3853 channel = B43_DEFAULT_CHANNEL_BG;
3854 break;
3855 default:
3856 B43_WARN_ON(1);
3857 }
3858 }
3859
Michael Buesche4d6b792007-09-18 15:39:42 -04003860 /* First we set the channel radio code to prevent the
3861 * firmware from sending ghost packets.
3862 */
3863 channelcookie = channel;
3864 if (phy->type == B43_PHYTYPE_A)
3865 channelcookie |= 0x100;
3866 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
3867
3868 if (phy->type == B43_PHYTYPE_A) {
3869 if (channel > 200)
3870 return -EINVAL;
3871 freq = channel2freq_a(channel);
3872
3873 r8 = b43_radio_read16(dev, 0x0008);
3874 b43_write16(dev, 0x03F0, freq);
3875 b43_radio_write16(dev, 0x0008, r8);
3876
3877 //TODO: write max channel TX power? to Radio 0x2D
3878 tmp = b43_radio_read16(dev, 0x002E);
3879 tmp &= 0x0080;
3880 //TODO: OR tmp with the Power out estimation for this channel?
3881 b43_radio_write16(dev, 0x002E, tmp);
3882
3883 if (freq >= 4920 && freq <= 5500) {
3884 /*
3885 * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
3886 * = (freq * 0.025862069
3887 */
3888 r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
3889 }
3890 b43_radio_write16(dev, 0x0007, (r8 << 4) | r8);
3891 b43_radio_write16(dev, 0x0020, (r8 << 4) | r8);
3892 b43_radio_write16(dev, 0x0021, (r8 << 4) | r8);
3893 b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022)
3894 & 0x000F) | (r8 << 4));
3895 b43_radio_write16(dev, 0x002A, (r8 << 4));
3896 b43_radio_write16(dev, 0x002B, (r8 << 4));
3897 b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008)
3898 & 0x00F0) | (r8 << 4));
3899 b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029)
3900 & 0xFF0F) | 0x00B0);
3901 b43_radio_write16(dev, 0x0035, 0x00AA);
3902 b43_radio_write16(dev, 0x0036, 0x0085);
3903 b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A)
3904 & 0xFF20) |
3905 freq_r3A_value(freq));
3906 b43_radio_write16(dev, 0x003D,
3907 b43_radio_read16(dev, 0x003D) & 0x00FF);
3908 b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081)
3909 & 0xFF7F) | 0x0080);
3910 b43_radio_write16(dev, 0x0035,
3911 b43_radio_read16(dev, 0x0035) & 0xFFEF);
3912 b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035)
3913 & 0xFFEF) | 0x0010);
3914 b43_radio_set_tx_iq(dev);
3915 //TODO: TSSI2dbm workaround
3916 b43_phy_xmitpower(dev); //FIXME correct?
3917 } else {
3918 if ((channel < 1) || (channel > 14))
3919 return -EINVAL;
3920
3921 if (synthetic_pu_workaround)
3922 b43_synth_pu_workaround(dev, channel);
3923
3924 b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
3925
3926 if (channel == 14) {
Larry Finger95de2842007-11-09 16:57:18 -06003927 if (dev->dev->bus->sprom.country_code ==
Michael Buesche4d6b792007-09-18 15:39:42 -04003928 SSB_SPROM1CCODE_JAPAN)
3929 b43_hf_write(dev,
3930 b43_hf_read(dev) & ~B43_HF_ACPR);
3931 else
3932 b43_hf_write(dev,
3933 b43_hf_read(dev) | B43_HF_ACPR);
3934 b43_write16(dev, B43_MMIO_CHANNEL_EXT,
3935 b43_read16(dev, B43_MMIO_CHANNEL_EXT)
3936 | (1 << 11));
3937 } else {
3938 b43_write16(dev, B43_MMIO_CHANNEL_EXT,
3939 b43_read16(dev, B43_MMIO_CHANNEL_EXT)
3940 & 0xF7BF);
3941 }
3942 }
3943
3944 phy->channel = channel;
3945 /* Wait for the radio to tune to the channel and stabilize. */
3946 msleep(8);
3947
3948 return 0;
3949}
3950
Michael Buesche4d6b792007-09-18 15:39:42 -04003951void b43_radio_turn_on(struct b43_wldev *dev)
3952{
3953 struct b43_phy *phy = &dev->phy;
3954 int err;
Michael Bueschfda9abc2007-09-20 22:14:18 +02003955 u8 channel;
Michael Buesche4d6b792007-09-18 15:39:42 -04003956
3957 might_sleep();
3958
3959 if (phy->radio_on)
3960 return;
3961
3962 switch (phy->type) {
3963 case B43_PHYTYPE_A:
3964 b43_radio_write16(dev, 0x0004, 0x00C0);
3965 b43_radio_write16(dev, 0x0005, 0x0008);
3966 b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
3967 b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
3968 b43_radio_init2060(dev);
3969 break;
3970 case B43_PHYTYPE_B:
3971 case B43_PHYTYPE_G:
3972 b43_phy_write(dev, 0x0015, 0x8000);
3973 b43_phy_write(dev, 0x0015, 0xCC00);
3974 b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000));
Michael Bueschfda9abc2007-09-20 22:14:18 +02003975 if (phy->radio_off_context.valid) {
3976 /* Restore the RFover values. */
3977 b43_phy_write(dev, B43_PHY_RFOVER,
3978 phy->radio_off_context.rfover);
3979 b43_phy_write(dev, B43_PHY_RFOVERVAL,
3980 phy->radio_off_context.rfoverval);
3981 phy->radio_off_context.valid = 0;
3982 }
3983 channel = phy->channel;
Michael Buesche4d6b792007-09-18 15:39:42 -04003984 err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1);
Michael Bueschfda9abc2007-09-20 22:14:18 +02003985 err |= b43_radio_selectchannel(dev, channel, 0);
Michael Buesche4d6b792007-09-18 15:39:42 -04003986 B43_WARN_ON(err);
3987 break;
3988 default:
3989 B43_WARN_ON(1);
3990 }
3991 phy->radio_on = 1;
Michael Buesche4d6b792007-09-18 15:39:42 -04003992}
3993
Michael Buesch8e9f7522007-09-27 21:35:34 +02003994void b43_radio_turn_off(struct b43_wldev *dev, bool force)
Michael Buesche4d6b792007-09-18 15:39:42 -04003995{
3996 struct b43_phy *phy = &dev->phy;
3997
Michael Buesch8e9f7522007-09-27 21:35:34 +02003998 if (!phy->radio_on && !force)
3999 return;
4000
Michael Buesche4d6b792007-09-18 15:39:42 -04004001 if (phy->type == B43_PHYTYPE_A) {
4002 b43_radio_write16(dev, 0x0004, 0x00FF);
4003 b43_radio_write16(dev, 0x0005, 0x00FB);
4004 b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
4005 b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
4006 }
4007 if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) {
Michael Bueschfda9abc2007-09-20 22:14:18 +02004008 u16 rfover, rfoverval;
4009
4010 rfover = b43_phy_read(dev, B43_PHY_RFOVER);
4011 rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
Michael Buesch8e9f7522007-09-27 21:35:34 +02004012 if (!force) {
4013 phy->radio_off_context.rfover = rfover;
4014 phy->radio_off_context.rfoverval = rfoverval;
4015 phy->radio_off_context.valid = 1;
4016 }
Michael Bueschfda9abc2007-09-20 22:14:18 +02004017 b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
4018 b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
Michael Buesche4d6b792007-09-18 15:39:42 -04004019 } else
4020 b43_phy_write(dev, 0x0015, 0xAA00);
4021 phy->radio_on = 0;
Michael Buesche4d6b792007-09-18 15:39:42 -04004022}