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