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