linux/drivers/net/wireless/broadcom/b43legacy/radio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3
   4  Broadcom B43legacy wireless driver
   5
   6  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
   7                     Stefano Brivio <stefano.brivio@polimi.it>
   8                     Michael Buesch <m@bues.ch>
   9                     Danny van Dyk <kugelfang@gentoo.org>
  10                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
  11  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
  12
  13  Some parts of the code in this file are derived from the ipw2200
  14  driver  Copyright(c) 2003 - 2004 Intel Corporation.
  15
  16
  17*/
  18
  19#include <linux/delay.h>
  20
  21#include "b43legacy.h"
  22#include "main.h"
  23#include "phy.h"
  24#include "radio.h"
  25#include "ilt.h"
  26
  27
  28/* Table for b43legacy_radio_calibrationvalue() */
  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 1011
  38 */
  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 inline
  55u16 channel2freq_bg(u8 channel)
  56{
  57        /* Frequencies are given as frequencies_bg[index] + 2.4GHz
  58         * Starting with channel 1
  59         */
  60        static const u16 frequencies_bg[14] = {
  61                12, 17, 22, 27,
  62                32, 37, 42, 47,
  63                52, 57, 62, 67,
  64                72, 84,
  65        };
  66
  67        if (unlikely(channel < 1 || channel > 14)) {
  68                printk(KERN_INFO "b43legacy: Channel %d is out of range\n",
  69                                  channel);
  70                dump_stack();
  71                return 2412;
  72        }
  73
  74        return frequencies_bg[channel - 1];
  75}
  76
  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                else
 113                        B43legacy_WARN_ON(1);
 114                break;
 115        case B43legacy_PHYTYPE_G:
 116                offset |= 0x80;
 117                break;
 118        default:
 119                B43legacy_BUG_ON(1);
 120        }
 121
 122        b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
 123        return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
 124}
 125
 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        else
 223                b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
 224                                  channel2freq_bg(channel));
 225        msleep(1);
 226        b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
 227                          channel2freq_bg(channel));
 228}
 229
 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        else
 246                rssi = saved & 0x3F;
 247        /* clamp temp to signed 5bit */
 248        if (rssi > 32)
 249                rssi -= 64;
 250        for (i = 0; i < 100; i++) {
 251                temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;
 252                if (temp > 32)
 253                        temp -= 64;
 254                if (temp < rssi)
 255                        j++;
 256                if (j >= 20)
 257                        ret = 1;
 258        }
 259        b43legacy_phy_write(dev, 0x0403, saved);
 260
 261        return ret;
 262}
 263
 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 > 0) ? 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                else
 466                        b43legacy_phy_write(dev, 0x000A,
 467                                            b43legacy_phy_read(dev, 0x000A)
 468                                            | 0x2000);
 469                b43legacy_phy_write(dev, 0x0814,
 470                                    b43legacy_phy_read(dev, 0x0814) | 0x0004);
 471                b43legacy_phy_write(dev, 0x0815,
 472                                    b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
 473                b43legacy_phy_write(dev, 0x0003,
 474                                    (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)
 475                                    | 0x0040);
 476                b43legacy_radio_write16(dev, 0x007A,
 477                                        b43legacy_radio_read16(dev, 0x007A)
 478                                        | 0x000F);
 479                b43legacy_set_all_gains(dev, 3, 0, 1);
 480                b43legacy_radio_write16(dev, 0x0043,
 481                                        (b43legacy_radio_read16(dev, 0x0043)
 482                                        & 0x00F0) | 0x000F);
 483                udelay(30);
 484                v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
 485                if (v47F >= 0x20)
 486                        v47F -= 0x40;
 487                if (v47F == -32) {
 488                        for (i = 0; i < 4; i++) {
 489                                b43legacy_radio_write16(dev, 0x007B, i);
 490                                udelay(20);
 491                                v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>
 492                                                                 8) & 0x003F);
 493                                if (v47F >= 0x20)
 494                                        v47F -= 0x40;
 495                                if (v47F > -31 && saved == 0xFFFF)
 496                                        saved = i;
 497                        }
 498                        if (saved == 0xFFFF)
 499                                saved = 3;
 500                } else
 501                        saved = 0;
 502        }
 503        b43legacy_radio_write16(dev, 0x007B, saved);
 504
 505        if (phy->rev >= 6) {
 506                b43legacy_phy_write(dev, 0x002E, backup[12]);
 507                b43legacy_phy_write(dev, 0x002F, backup[13]);
 508                b43legacy_phy_write(dev, 0x080F, backup[14]);
 509                b43legacy_phy_write(dev, 0x0810, backup[15]);
 510        }
 511        b43legacy_phy_write(dev, 0x0814, backup[3]);
 512        b43legacy_phy_write(dev, 0x0815, backup[4]);
 513        b43legacy_phy_write(dev, 0x005A, backup[5]);
 514        b43legacy_phy_write(dev, 0x0059, backup[6]);
 515        b43legacy_phy_write(dev, 0x0058, backup[7]);
 516        b43legacy_phy_write(dev, 0x000A, backup[8]);
 517        b43legacy_phy_write(dev, 0x0003, backup[9]);
 518        b43legacy_radio_write16(dev, 0x0043, backup[11]);
 519        b43legacy_radio_write16(dev, 0x007A, backup[10]);
 520        b43legacy_phy_write(dev, 0x0802,
 521                            b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);
 522        b43legacy_phy_write(dev, 0x0429,
 523                            b43legacy_phy_read(dev, 0x0429) | 0x8000);
 524        b43legacy_set_original_gains(dev);
 525        if (phy->rev >= 6) {
 526                b43legacy_phy_write(dev, 0x0801, backup[16]);
 527                b43legacy_phy_write(dev, 0x0060, backup[17]);
 528                b43legacy_phy_write(dev, 0x0014, backup[18]);
 529                b43legacy_phy_write(dev, 0x0478, backup[19]);
 530        }
 531        b43legacy_phy_write(dev, 0x0001, backup[0]);
 532        b43legacy_phy_write(dev, 0x0812, backup[2]);
 533        b43legacy_phy_write(dev, 0x0811, backup[1]);
 534}
 535
 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                else
 583                        b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
 584                                          b43legacy_read16(dev,
 585                                          B43legacy_MMIO_CHANNEL_EXT) & 0x2000);
 586                b43legacy_phy_write(dev, 0x0020, 0x3F3F);
 587                b43legacy_phy_write(dev, 0x0015, 0xF330);
 588                b43legacy_radio_write16(dev, 0x005A, 0x0060);
 589                b43legacy_radio_write16(dev, 0x0043,
 590                                        b43legacy_radio_read16(dev, 0x0043)
 591                                        & 0x00F0);
 592                b43legacy_phy_write(dev, 0x005A, 0x0480);
 593                b43legacy_phy_write(dev, 0x0059, 0x0810);
 594                b43legacy_phy_write(dev, 0x0058, 0x000D);
 595                udelay(20);
 596
 597                nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);
 598                b43legacy_phy_write(dev, 0x0030, backup[3]);
 599                b43legacy_radio_write16(dev, 0x007A, backup[0]);
 600                b43legacy_write16(dev, 0x03E2, backup[11]);
 601                b43legacy_phy_write(dev, 0x0026, backup[4]);
 602                b43legacy_phy_write(dev, 0x0015, backup[5]);
 603                b43legacy_phy_write(dev, 0x002A, backup[6]);
 604                b43legacy_synth_pu_workaround(dev, phy->channel);
 605                if (phy->analog != 0)
 606                        b43legacy_write16(dev, 0x03F4, backup[13]);
 607
 608                b43legacy_phy_write(dev, 0x0020, backup[7]);
 609                b43legacy_phy_write(dev, 0x005A, backup[8]);
 610                b43legacy_phy_write(dev, 0x0059, backup[9]);
 611                b43legacy_phy_write(dev, 0x0058, backup[10]);
 612                b43legacy_radio_write16(dev, 0x0052, backup[1]);
 613                b43legacy_radio_write16(dev, 0x0043, backup[2]);
 614
 615                if (nrssi0 == nrssi1)
 616                        phy->nrssislope = 0x00010000;
 617                else
 618                        phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
 619
 620                if (nrssi0 <= -4) {
 621                        phy->nrssi[0] = nrssi0;
 622                        phy->nrssi[1] = nrssi1;
 623                }
 624                break;
 625        case B43legacy_PHYTYPE_G:
 626                if (phy->radio_rev >= 9)
 627                        return;
 628                if (phy->radio_rev == 8)
 629                        b43legacy_calc_nrssi_offset(dev);
 630
 631                b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
 632                                    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
 633                                    & 0x7FFF);
 634                b43legacy_phy_write(dev, 0x0802,
 635                                    b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
 636                backup[7] = b43legacy_read16(dev, 0x03E2);
 637                b43legacy_write16(dev, 0x03E2,
 638                                  b43legacy_read16(dev, 0x03E2) | 0x8000);
 639                backup[0] = b43legacy_radio_read16(dev, 0x007A);
 640                backup[1] = b43legacy_radio_read16(dev, 0x0052);
 641                backup[2] = b43legacy_radio_read16(dev, 0x0043);
 642                backup[3] = b43legacy_phy_read(dev, 0x0015);
 643                backup[4] = b43legacy_phy_read(dev, 0x005A);
 644                backup[5] = b43legacy_phy_read(dev, 0x0059);
 645                backup[6] = b43legacy_phy_read(dev, 0x0058);
 646                backup[8] = b43legacy_read16(dev, 0x03E6);
 647                backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
 648                if (phy->rev >= 3) {
 649                        backup[10] = b43legacy_phy_read(dev, 0x002E);
 650                        backup[11] = b43legacy_phy_read(dev, 0x002F);
 651                        backup[12] = b43legacy_phy_read(dev, 0x080F);
 652                        backup[13] = b43legacy_phy_read(dev,
 653                                                B43legacy_PHY_G_LO_CONTROL);
 654                        backup[14] = b43legacy_phy_read(dev, 0x0801);
 655                        backup[15] = b43legacy_phy_read(dev, 0x0060);
 656                        backup[16] = b43legacy_phy_read(dev, 0x0014);
 657                        backup[17] = b43legacy_phy_read(dev, 0x0478);
 658                        b43legacy_phy_write(dev, 0x002E, 0);
 659                        b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);
 660                        switch (phy->rev) {
 661                        case 4: case 6: case 7:
 662                                b43legacy_phy_write(dev, 0x0478,
 663                                                    b43legacy_phy_read(dev,
 664                                                    0x0478) | 0x0100);
 665                                b43legacy_phy_write(dev, 0x0801,
 666                                                    b43legacy_phy_read(dev,
 667                                                    0x0801) | 0x0040);
 668                                break;
 669                        case 3: case 5:
 670                                b43legacy_phy_write(dev, 0x0801,
 671                                                    b43legacy_phy_read(dev,
 672                                                    0x0801) & 0xFFBF);
 673                                break;
 674                        }
 675                        b43legacy_phy_write(dev, 0x0060,
 676                                            b43legacy_phy_read(dev, 0x0060)
 677                                            | 0x0040);
 678                        b43legacy_phy_write(dev, 0x0014,
 679                                            b43legacy_phy_read(dev, 0x0014)
 680                                            | 0x0200);
 681                }
 682                b43legacy_radio_write16(dev, 0x007A,
 683                                        b43legacy_radio_read16(dev, 0x007A)
 684                                        | 0x0070);
 685                b43legacy_set_all_gains(dev, 0, 8, 0);
 686                b43legacy_radio_write16(dev, 0x007A,
 687                                        b43legacy_radio_read16(dev, 0x007A)
 688                                        & 0x00F7);
 689                if (phy->rev >= 2) {
 690                        b43legacy_phy_write(dev, 0x0811,
 691                                            (b43legacy_phy_read(dev, 0x0811)
 692                                            & 0xFFCF) | 0x0030);
 693                        b43legacy_phy_write(dev, 0x0812,
 694                                            (b43legacy_phy_read(dev, 0x0812)
 695                                            & 0xFFCF) | 0x0010);
 696                }
 697                b43legacy_radio_write16(dev, 0x007A,
 698                                        b43legacy_radio_read16(dev, 0x007A)
 699                                        | 0x0080);
 700                udelay(20);
 701
 702                nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
 703                if (nrssi0 >= 0x0020)
 704                        nrssi0 -= 0x0040;
 705
 706                b43legacy_radio_write16(dev, 0x007A,
 707                                        b43legacy_radio_read16(dev, 0x007A)
 708                                        & 0x007F);
 709                if (phy->analog >= 2)
 710                        b43legacy_phy_write(dev, 0x0003,
 711                                            (b43legacy_phy_read(dev, 0x0003)
 712                                            & 0xFF9F) | 0x0040);
 713
 714                b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
 715                                  b43legacy_read16(dev,
 716                                  B43legacy_MMIO_CHANNEL_EXT) | 0x2000);
 717                b43legacy_radio_write16(dev, 0x007A,
 718                                        b43legacy_radio_read16(dev, 0x007A)
 719                                        | 0x000F);
 720                b43legacy_phy_write(dev, 0x0015, 0xF330);
 721                if (phy->rev >= 2) {
 722                        b43legacy_phy_write(dev, 0x0812,
 723                                            (b43legacy_phy_read(dev, 0x0812)
 724                                            & 0xFFCF) | 0x0020);
 725                        b43legacy_phy_write(dev, 0x0811,
 726                                            (b43legacy_phy_read(dev, 0x0811)
 727                                            & 0xFFCF) | 0x0020);
 728                }
 729
 730                b43legacy_set_all_gains(dev, 3, 0, 1);
 731                if (phy->radio_rev == 8)
 732                        b43legacy_radio_write16(dev, 0x0043, 0x001F);
 733                else {
 734                        tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;
 735                        b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);
 736                        tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;
 737                        b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);
 738                }
 739                b43legacy_phy_write(dev, 0x005A, 0x0480);
 740                b43legacy_phy_write(dev, 0x0059, 0x0810);
 741                b43legacy_phy_write(dev, 0x0058, 0x000D);
 742                udelay(20);
 743                nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
 744                if (nrssi1 >= 0x0020)
 745                        nrssi1 -= 0x0040;
 746                if (nrssi0 == nrssi1)
 747                        phy->nrssislope = 0x00010000;
 748                else
 749                        phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
 750                if (nrssi0 >= -4) {
 751                        phy->nrssi[0] = nrssi1;
 752                        phy->nrssi[1] = nrssi0;
 753                }
 754                if (phy->rev >= 3) {
 755                        b43legacy_phy_write(dev, 0x002E, backup[10]);
 756                        b43legacy_phy_write(dev, 0x002F, backup[11]);
 757                        b43legacy_phy_write(dev, 0x080F, backup[12]);
 758                        b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,
 759                                            backup[13]);
 760                }
 761                if (phy->rev >= 2) {
 762                        b43legacy_phy_write(dev, 0x0812,
 763                                            b43legacy_phy_read(dev, 0x0812)
 764                                            & 0xFFCF);
 765                        b43legacy_phy_write(dev, 0x0811,
 766                                            b43legacy_phy_read(dev, 0x0811)
 767                                            & 0xFFCF);
 768                }
 769
 770                b43legacy_radio_write16(dev, 0x007A, backup[0]);
 771                b43legacy_radio_write16(dev, 0x0052, backup[1]);
 772                b43legacy_radio_write16(dev, 0x0043, backup[2]);
 773                b43legacy_write16(dev, 0x03E2, backup[7]);
 774                b43legacy_write16(dev, 0x03E6, backup[8]);
 775                b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);
 776                b43legacy_phy_write(dev, 0x0015, backup[3]);
 777                b43legacy_phy_write(dev, 0x005A, backup[4]);
 778                b43legacy_phy_write(dev, 0x0059, backup[5]);
 779                b43legacy_phy_write(dev, 0x0058, backup[6]);
 780                b43legacy_synth_pu_workaround(dev, phy->channel);
 781                b43legacy_phy_write(dev, 0x0802,
 782                                    b43legacy_phy_read(dev, 0x0802) | 0x0003);
 783                b43legacy_set_original_gains(dev);
 784                b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
 785                                    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
 786                                    | 0x8000);
 787                if (phy->rev >= 3) {
 788                        b43legacy_phy_write(dev, 0x0801, backup[14]);
 789                        b43legacy_phy_write(dev, 0x0060, backup[15]);
 790                        b43legacy_phy_write(dev, 0x0014, backup[16]);
 791                        b43legacy_phy_write(dev, 0x0478, backup[17]);
 792                }
 793                b43legacy_nrssi_mem_update(dev);
 794                b43legacy_calc_nrssi_threshold(dev);
 795                break;
 796        default:
 797                B43legacy_BUG_ON(1);
 798        }
 799}
 800
 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                } else
 823                        threshold = phy->nrssi[1] - 5;
 824
 825                threshold = clamp_val(threshold, 0, 0x3E);
 826                b43legacy_phy_read(dev, 0x0020); /* dummy read */
 827                b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
 828                                    | 0x001C);
 829
 830                if (phy->radio_rev >= 6) {
 831                        b43legacy_phy_write(dev, 0x0087, 0x0E0D);
 832                        b43legacy_phy_write(dev, 0x0086, 0x0C0B);
 833                        b43legacy_phy_write(dev, 0x0085, 0x0A09);
 834                        b43legacy_phy_write(dev, 0x0084, 0x0808);
 835                        b43legacy_phy_write(dev, 0x0083, 0x0808);
 836                        b43legacy_phy_write(dev, 0x0082, 0x0604);
 837                        b43legacy_phy_write(dev, 0x0081, 0x0302);
 838                        b43legacy_phy_write(dev, 0x0080, 0x0100);
 839                }
 840                break;
 841        }
 842        case B43legacy_PHYTYPE_G:
 843                if (!phy->gmode ||
 844                    !(dev->dev->bus->sprom.boardflags_lo &
 845                    B43legacy_BFL_RSSI)) {
 846                        tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
 847                        if (tmp16 >= 0x20)
 848                                tmp16 -= 0x40;
 849                        if (tmp16 < 3)
 850                                b43legacy_phy_write(dev, 0x048A,
 851                                                    (b43legacy_phy_read(dev,
 852                                                    0x048A) & 0xF000) | 0x09EB);
 853                        else
 854                                b43legacy_phy_write(dev, 0x048A,
 855                                                    (b43legacy_phy_read(dev,
 856                                                    0x048A) & 0xF000) | 0x0AED);
 857                } else {
 858                        if (phy->interfmode ==
 859                            B43legacy_RADIO_INTERFMODE_NONWLAN) {
 860                                a = 0xE;
 861                                b = 0xA;
 862                        } else if (!phy->aci_wlan_automatic &&
 863                                    phy->aci_enable) {
 864                                a = 0x13;
 865                                b = 0x12;
 866                        } else {
 867                                a = 0xE;
 868                                b = 0x11;
 869                        }
 870
 871                        a = a * (phy->nrssi[1] - phy->nrssi[0]);
 872                        a += (phy->nrssi[0] << 6);
 873                        if (a < 32)
 874                                a += 31;
 875                        else
 876                                a += 32;
 877                        a = a >> 6;
 878                        a = clamp_val(a, -31, 31);
 879
 880                        b = b * (phy->nrssi[1] - phy->nrssi[0]);
 881                        b += (phy->nrssi[0] << 6);
 882                        if (b < 32)
 883                                b += 31;
 884                        else
 885                                b += 32;
 886                        b = b >> 6;
 887                        b = clamp_val(b, -31, 31);
 888
 889                        tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
 890                        tmp_u16 |= ((u32)b & 0x0000003F);
 891                        tmp_u16 |= (((u32)a & 0x0000003F) << 6);
 892                        b43legacy_phy_write(dev, 0x048A, tmp_u16);
 893                }
 894                break;
 895        default:
 896                B43legacy_BUG_ON(1);
 897        }
 898}
 899
 900/* Stack implementation to save/restore values from the
 901 * interference mitigation code.
 902 * It is save to restore values in random order.
 903 */
 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 void
 972b43legacy_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 void
1218b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,
1219                                                int mode)
1220{
1221        struct b43legacy_phy *phy = &dev->phy;
1222        u32 tmp32;
1223        u32 *stack = phy->interfstack;
1224
1225        switch (mode) {
1226        case B43legacy_RADIO_INTERFMODE_NONWLAN:
1227                if (phy->rev != 1) {
1228                        b43legacy_phy_write(dev, 0x042B,
1229                                            b43legacy_phy_read(dev, 0x042B)
1230                                            & ~0x0800);
1231                        b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1232                                            b43legacy_phy_read(dev,
1233                                            B43legacy_PHY_G_CRS) | 0x4000);
1234                        break;
1235                }
1236                phy_stackrestore(0x0078);
1237                b43legacy_calc_nrssi_threshold(dev);
1238                phy_stackrestore(0x0406);
1239                b43legacy_phy_write(dev, 0x042B,
1240                                    b43legacy_phy_read(dev, 0x042B) & ~0x0800);
1241                if (!dev->bad_frames_preempt)
1242                        b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1243                                            b43legacy_phy_read(dev,
1244                                            B43legacy_PHY_RADIO_BITFIELD)
1245                                            & ~(1 << 11));
1246                b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1247                                    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
1248                                    | 0x4000);
1249                phy_stackrestore(0x04A0);
1250                phy_stackrestore(0x04A1);
1251                phy_stackrestore(0x04A2);
1252                phy_stackrestore(0x04A8);
1253                phy_stackrestore(0x04AB);
1254                phy_stackrestore(0x04A7);
1255                phy_stackrestore(0x04A3);
1256                phy_stackrestore(0x04A9);
1257                phy_stackrestore(0x0493);
1258                phy_stackrestore(0x04AA);
1259                phy_stackrestore(0x04AC);
1260                break;
1261        case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1262                if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))
1263                        break;
1264
1265                phy->aci_enable = false;
1266
1267                phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);
1268                phy_stackrestore(B43legacy_PHY_G_CRS);
1269                phy_stackrestore(0x0033);
1270                phy_stackrestore(0x04A3);
1271                phy_stackrestore(0x04A9);
1272                phy_stackrestore(0x0493);
1273                phy_stackrestore(0x04AA);
1274                phy_stackrestore(0x04AC);
1275                phy_stackrestore(0x04A0);
1276                phy_stackrestore(0x04A7);
1277                if (phy->rev >= 2) {
1278                        phy_stackrestore(0x04C0);
1279                        phy_stackrestore(0x04C1);
1280                } else
1281                        phy_stackrestore(0x0406);
1282                phy_stackrestore(0x04A1);
1283                phy_stackrestore(0x04AB);
1284                phy_stackrestore(0x04A8);
1285                if (phy->rev == 2) {
1286                        phy_stackrestore(0x04AD);
1287                        phy_stackrestore(0x04AE);
1288                } else if (phy->rev >= 3) {
1289                        phy_stackrestore(0x04AD);
1290                        phy_stackrestore(0x0415);
1291                        phy_stackrestore(0x0416);
1292                        phy_stackrestore(0x0417);
1293                        ilt_stackrestore(0x1A00 + 0x2);
1294                        ilt_stackrestore(0x1A00 + 0x3);
1295                }
1296                phy_stackrestore(0x04A2);
1297                phy_stackrestore(0x04A8);
1298                phy_stackrestore(0x042B);
1299                phy_stackrestore(0x048C);
1300                tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
1301                                             B43legacy_UCODEFLAGS_OFFSET);
1302                if (tmp32 & 0x800) {
1303                        tmp32 &= ~0x800;
1304                        b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1305                                              B43legacy_UCODEFLAGS_OFFSET,
1306                                              tmp32);
1307                }
1308                b43legacy_calc_nrssi_slope(dev);
1309                break;
1310        default:
1311                B43legacy_BUG_ON(1);
1312        }
1313}
1314
1315#undef phy_stacksave
1316#undef phy_stackrestore
1317#undef radio_stacksave
1318#undef radio_stackrestore
1319#undef ilt_stacksave
1320#undef ilt_stackrestore
1321
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                else
1339                        mode = B43legacy_RADIO_INTERFMODE_NONE;
1340                break;
1341        case B43legacy_RADIO_INTERFMODE_NONE:
1342        case B43legacy_RADIO_INTERFMODE_NONWLAN:
1343        case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1344                break;
1345        default:
1346                return -EINVAL;
1347        }
1348
1349        currentmode = phy->interfmode;
1350        if (currentmode == mode)
1351                return 0;
1352        if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)
1353                b43legacy_radio_interference_mitigation_disable(dev,
1354                                                                currentmode);
1355
1356        if (mode == B43legacy_RADIO_INTERFMODE_NONE) {
1357                phy->aci_enable = false;
1358                phy->aci_hw_rssi = false;
1359        } else
1360                b43legacy_radio_interference_mitigation_enable(dev, mode);
1361        phy->interfmode = mode;
1362
1363        return 0;
1364}
1365
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_lo
1394                    & B43legacy_BFL_EXTLNA)) {
1395                        switch (lpd) {
1396                        case LPD(0, 1, 1):
1397                                return 0x0FB2;
1398                        case LPD(0, 0, 1):
1399                                return 0x00B2;
1400                        case LPD(1, 0, 1):
1401                                return 0x30B2;
1402                        case LPD(1, 0, 0):
1403                                return 0x30B3;
1404                        default:
1405                                B43legacy_BUG_ON(1);
1406                        }
1407                } else {
1408                        switch (lpd) {
1409                        case LPD(0, 1, 1):
1410                                return 0x8FB2;
1411                        case LPD(0, 0, 1):
1412                                return 0x80B2;
1413                        case LPD(1, 0, 1):
1414                                return 0x20B2;
1415                        case LPD(1, 0, 0):
1416                                return 0x20B3;
1417                        default:
1418                                B43legacy_BUG_ON(1);
1419                        }
1420                }
1421        } else {
1422                if (phy->radio_rev == 8)
1423                        adj_loopback_gain += 0x003E;
1424                else
1425                        adj_loopback_gain += 0x0026;
1426                if (adj_loopback_gain >= 0x46) {
1427                        adj_loopback_gain -= 0x46;
1428                        extern_lna_control = 0x3000;
1429                } else if (adj_loopback_gain >= 0x3A) {
1430                        adj_loopback_gain -= 0x3A;
1431                        extern_lna_control = 0x2000;
1432                } else if (adj_loopback_gain >= 0x2E) {
1433                        adj_loopback_gain -= 0x2E;
1434                        extern_lna_control = 0x1000;
1435                } else {
1436                        adj_loopback_gain -= 0x10;
1437                        extern_lna_control = 0x0000;
1438                }
1439                for (loop = 0; loop < 16; loop++) {
1440                        u16 tmp = adj_loopback_gain - 6 * loop;
1441                        if (tmp < 6)
1442                                break;
1443                }
1444
1445                loop_or = (loop << 8) | extern_lna_control;
1446                if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo
1447                    & B43legacy_BFL_EXTLNA) {
1448                        if (extern_lna_control)
1449                                loop_or |= 0x8000;
1450                        switch (lpd) {
1451                        case LPD(0, 1, 1):
1452                                return 0x8F92;
1453                        case LPD(0, 0, 1):
1454                                return (0x8092 | loop_or);
1455                        case LPD(1, 0, 1):
1456                                return (0x2092 | loop_or);
1457                        case LPD(1, 0, 0):
1458                                return (0x2093 | loop_or);
1459                        default:
1460                                B43legacy_BUG_ON(1);
1461                        }
1462                } else {
1463                        switch (lpd) {
1464                        case LPD(0, 1, 1):
1465                                return 0x0F92;
1466                        case LPD(0, 0, 1):
1467                        case LPD(1, 0, 1):
1468                                return (0x0092 | loop_or);
1469                        case LPD(1, 0, 0):
1470                                return (0x0093 | loop_or);
1471                        default:
1472                                B43legacy_BUG_ON(1);
1473                        }
1474                }
1475        }
1476        return 0;
1477}
1478
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                                else
1529                                        b43legacy_phy_write(dev, 0x080F,
1530                                                            0x8020);
1531                                b43legacy_phy_write(dev, 0x0810, 0x0000);
1532                        }
1533                        b43legacy_phy_write(dev, 0x0812,
1534                                            b43legacy_get_812_value(dev,
1535                                            LPD(0, 1, 1)));
1536                        if (phy->rev < 7 ||
1537                            !(dev->dev->bus->sprom.boardflags_lo
1538                            & B43legacy_BFL_EXTLNA))
1539                                b43legacy_phy_write(dev, 0x0811, 0x01B3);
1540                        else
1541                                b43legacy_phy_write(dev, 0x0811, 0x09B3);
1542                }
1543        }
1544        b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1545                        (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)
1546                                          | 0x8000));
1547        backup[10] = b43legacy_phy_read(dev, 0x0035);
1548        b43legacy_phy_write(dev, 0x0035,
1549                            (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));
1550        backup[11] = b43legacy_read16(dev, 0x03E6);
1551        backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
1552
1553        /* Initialization */
1554        if (phy->analog == 0)
1555                b43legacy_write16(dev, 0x03E6, 0x0122);
1556        else {
1557                if (phy->analog >= 2)
1558                        b43legacy_phy_write(dev, 0x0003,
1559                                            (b43legacy_phy_read(dev, 0x0003)
1560                                            & 0xFFBF) | 0x0040);
1561                b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1562                                  (b43legacy_read16(dev,
1563                                  B43legacy_MMIO_CHANNEL_EXT) | 0x2000));
1564        }
1565
1566        ret = b43legacy_radio_calibrationvalue(dev);
1567
1568        if (phy->type == B43legacy_PHYTYPE_B)
1569                b43legacy_radio_write16(dev, 0x0078, 0x0026);
1570
1571        if (phy->gmode)
1572                b43legacy_phy_write(dev, 0x0812,
1573                                    b43legacy_get_812_value(dev,
1574                                    LPD(0, 1, 1)));
1575        b43legacy_phy_write(dev, 0x0015, 0xBFAF);
1576        b43legacy_phy_write(dev, 0x002B, 0x1403);
1577        if (phy->gmode)
1578                b43legacy_phy_write(dev, 0x0812,
1579                                    b43legacy_get_812_value(dev,
1580                                    LPD(0, 0, 1)));
1581        b43legacy_phy_write(dev, 0x0015, 0xBFA0);
1582        b43legacy_radio_write16(dev, 0x0051,
1583                                (b43legacy_radio_read16(dev, 0x0051)
1584                                | 0x0004));
1585        if (phy->radio_rev == 8)
1586                b43legacy_radio_write16(dev, 0x0043, 0x001F);
1587        else {
1588                b43legacy_radio_write16(dev, 0x0052, 0x0000);
1589                b43legacy_radio_write16(dev, 0x0043,
1590                                        (b43legacy_radio_read16(dev, 0x0043)
1591                                        & 0xFFF0) | 0x0009);
1592        }
1593        b43legacy_phy_write(dev, 0x0058, 0x0000);
1594
1595        for (i = 0; i < 16; i++) {
1596                b43legacy_phy_write(dev, 0x005A, 0x0480);
1597                b43legacy_phy_write(dev, 0x0059, 0xC810);
1598                b43legacy_phy_write(dev, 0x0058, 0x000D);
1599                if (phy->gmode)
1600                        b43legacy_phy_write(dev, 0x0812,
1601                                            b43legacy_get_812_value(dev,
1602                                            LPD(1, 0, 1)));
1603                b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1604                udelay(10);
1605                if (phy->gmode)
1606                        b43legacy_phy_write(dev, 0x0812,
1607                                            b43legacy_get_812_value(dev,
1608                                            LPD(1, 0, 1)));
1609                b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1610                udelay(10);
1611                if (phy->gmode)
1612                        b43legacy_phy_write(dev, 0x0812,
1613                                            b43legacy_get_812_value(dev,
1614                                            LPD(1, 0, 0)));
1615                b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1616                udelay(20);
1617                tmp1 += b43legacy_phy_read(dev, 0x002D);
1618                b43legacy_phy_write(dev, 0x0058, 0x0000);
1619                if (phy->gmode)
1620                        b43legacy_phy_write(dev, 0x0812,
1621                                            b43legacy_get_812_value(dev,
1622                                            LPD(1, 0, 1)));
1623                b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1624        }
1625
1626        tmp1++;
1627        tmp1 >>= 9;
1628        udelay(10);
1629        b43legacy_phy_write(dev, 0x0058, 0x0000);
1630
1631        for (i = 0; i < 16; i++) {
1632                b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)
1633                                        | 0x0020);
1634                backup[13] = b43legacy_radio_read16(dev, 0x0078);
1635                udelay(10);
1636                for (j = 0; j < 16; j++) {
1637                        b43legacy_phy_write(dev, 0x005A, 0x0D80);
1638                        b43legacy_phy_write(dev, 0x0059, 0xC810);
1639                        b43legacy_phy_write(dev, 0x0058, 0x000D);
1640                        if (phy->gmode)
1641                                b43legacy_phy_write(dev, 0x0812,
1642                                                    b43legacy_get_812_value(dev,
1643                                                    LPD(1, 0, 1)));
1644                        b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1645                        udelay(10);
1646                        if (phy->gmode)
1647                                b43legacy_phy_write(dev, 0x0812,
1648                                                    b43legacy_get_812_value(dev,
1649                                                    LPD(1, 0, 1)));
1650                        b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1651                        udelay(10);
1652                        if (phy->gmode)
1653                                b43legacy_phy_write(dev, 0x0812,
1654                                                    b43legacy_get_812_value(dev,
1655                                                    LPD(1, 0, 0)));
1656                        b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1657                        udelay(10);
1658                        tmp2 += b43legacy_phy_read(dev, 0x002D);
1659                        b43legacy_phy_write(dev, 0x0058, 0x0000);
1660                        if (phy->gmode)
1661                                b43legacy_phy_write(dev, 0x0812,
1662                                                    b43legacy_get_812_value(dev,
1663                                                    LPD(1, 0, 1)));
1664                        b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1665                }
1666                tmp2++;
1667                tmp2 >>= 8;
1668                if (tmp1 < tmp2)
1669                        break;
1670        }
1671
1672        /* Restore the registers */
1673        b43legacy_phy_write(dev, 0x0015, backup[1]);
1674        b43legacy_radio_write16(dev, 0x0051, backup[14]);
1675        b43legacy_radio_write16(dev, 0x0052, backup[15]);
1676        b43legacy_radio_write16(dev, 0x0043, backup[0]);
1677        b43legacy_phy_write(dev, 0x005A, backup[16]);
1678        b43legacy_phy_write(dev, 0x0059, backup[17]);
1679        b43legacy_phy_write(dev, 0x0058, backup[18]);
1680        b43legacy_write16(dev, 0x03E6, backup[11]);
1681        if (phy->analog != 0)
1682                b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);
1683        b43legacy_phy_write(dev, 0x0035, backup[10]);
1684        b43legacy_radio_selectchannel(dev, phy->channel, 1);
1685        if (phy->type == B43legacy_PHYTYPE_B) {
1686                b43legacy_phy_write(dev, 0x0030, backup[2]);
1687                b43legacy_write16(dev, 0x03EC, backup[3]);
1688        } else {
1689                if (phy->gmode) {
1690                        b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1691                                          (b43legacy_read16(dev,
1692                                          B43legacy_MMIO_PHY_RADIO) & 0x7FFF));
1693                        b43legacy_phy_write(dev, 0x0811, backup[4]);
1694                        b43legacy_phy_write(dev, 0x0812, backup[5]);
1695                        b43legacy_phy_write(dev, 0x0814, backup[6]);
1696                        b43legacy_phy_write(dev, 0x0815, backup[7]);
1697                        b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1698                                            backup[8]);
1699                        b43legacy_phy_write(dev, 0x0802, backup[9]);
1700                        if (phy->rev > 1) {
1701                                b43legacy_phy_write(dev, 0x080F, backup[19]);
1702                                b43legacy_phy_write(dev, 0x0810, backup[20]);
1703                        }
1704                }
1705        }
1706        if (i >= 15)
1707                ret = backup[13];
1708
1709        return ret;
1710}
1711
1712static inline
1713u16 freq_r3A_value(u16 frequency)
1714{
1715        u16 value;
1716
1717        if (frequency < 5091)
1718                value = 0x0040;
1719        else if (frequency < 5321)
1720                value = 0x0000;
1721        else if (frequency < 5806)
1722                value = 0x0080;
1723        else
1724                value = 0x0040;
1725
1726        return value;
1727}
1728
1729int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
1730                                  u8 channel,
1731                                  int synthetic_pu_workaround)
1732{
1733        struct b43legacy_phy *phy = &dev->phy;
1734
1735        if (channel == 0xFF) {
1736                switch (phy->type) {
1737                case B43legacy_PHYTYPE_B:
1738                case B43legacy_PHYTYPE_G:
1739                        channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;
1740                        break;
1741                default:
1742                        B43legacy_WARN_ON(1);
1743                }
1744        }
1745
1746/* TODO: Check if channel is valid - return -EINVAL if not */
1747        if (synthetic_pu_workaround)
1748                b43legacy_synth_pu_workaround(dev, channel);
1749
1750        b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
1751                          channel2freq_bg(channel));
1752
1753        if (channel == 14) {
1754                if (dev->dev->bus->sprom.country_code == 5)   /* JAPAN) */
1755                        b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1756                                              B43legacy_UCODEFLAGS_OFFSET,
1757                                              b43legacy_shm_read32(dev,
1758                                              B43legacy_SHM_SHARED,
1759                                              B43legacy_UCODEFLAGS_OFFSET)
1760                                              & ~(1 << 7));
1761                else
1762                        b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1763                                              B43legacy_UCODEFLAGS_OFFSET,
1764                                              b43legacy_shm_read32(dev,
1765                                              B43legacy_SHM_SHARED,
1766                                              B43legacy_UCODEFLAGS_OFFSET)
1767                                              | (1 << 7));
1768                b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1769                                  b43legacy_read16(dev,
1770                                  B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
1771        } else
1772                b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1773                                  b43legacy_read16(dev,
1774                                  B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
1775
1776        phy->channel = channel;
1777        /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
1778         *     that 2000 usecs might suffice. */
1779        msleep(8);
1780
1781        return 0;
1782}
1783
1784void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
1785{
1786        u16 tmp;
1787
1788        val <<= 8;
1789        tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
1790        b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
1791        tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
1792        b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
1793        tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
1794        b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
1795}
1796
1797/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
1798static u16 b43legacy_get_txgain_base_band(u16 txpower)
1799{
1800        u16 ret;
1801
1802        B43legacy_WARN_ON(txpower > 63);
1803
1804        if (txpower >= 54)
1805                ret = 2;
1806        else if (txpower >= 49)
1807                ret = 4;
1808        else if (txpower >= 44)
1809                ret = 5;
1810        else
1811                ret = 6;
1812
1813        return ret;
1814}
1815
1816/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
1817static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
1818{
1819        u16 ret;
1820
1821        B43legacy_WARN_ON(txpower > 63);
1822
1823        if (txpower >= 32)
1824                ret = 0;
1825        else if (txpower >= 25)
1826                ret = 1;
1827        else if (txpower >= 20)
1828                ret = 2;
1829        else if (txpower >= 12)
1830                ret = 3;
1831        else
1832                ret = 4;
1833
1834        return ret;
1835}
1836
1837/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
1838static u16 b43legacy_get_txgain_dac(u16 txpower)
1839{
1840        u16 ret;
1841
1842        B43legacy_WARN_ON(txpower > 63);
1843
1844        if (txpower >= 54)
1845                ret = txpower - 53;
1846        else if (txpower >= 49)
1847                ret = txpower - 42;
1848        else if (txpower >= 44)
1849                ret = txpower - 37;
1850        else if (txpower >= 32)
1851                ret = txpower - 32;
1852        else if (txpower >= 25)
1853                ret = txpower - 20;
1854        else if (txpower >= 20)
1855                ret = txpower - 13;
1856        else if (txpower >= 12)
1857                ret = txpower - 8;
1858        else
1859                ret = txpower;
1860
1861        return ret;
1862}
1863
1864void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
1865{
1866        struct b43legacy_phy *phy = &dev->phy;
1867        u16 pamp;
1868        u16 base;
1869        u16 dac;
1870        u16 ilt;
1871
1872        txpower = clamp_val(txpower, 0, 63);
1873
1874        pamp = b43legacy_get_txgain_freq_power_amp(txpower);
1875        pamp <<= 5;
1876        pamp &= 0x00E0;
1877        b43legacy_phy_write(dev, 0x0019, pamp);
1878
1879        base = b43legacy_get_txgain_base_band(txpower);
1880        base &= 0x000F;
1881        b43legacy_phy_write(dev, 0x0017, base | 0x0020);
1882
1883        ilt = b43legacy_ilt_read(dev, 0x3001);
1884        ilt &= 0x0007;
1885
1886        dac = b43legacy_get_txgain_dac(txpower);
1887        dac <<= 3;
1888        dac |= ilt;
1889
1890        b43legacy_ilt_write(dev, 0x3001, dac);
1891
1892        phy->txpwr_offset = txpower;
1893
1894        /* TODO: FuncPlaceholder (Adjust BB loft cancel) */
1895}
1896
1897void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
1898                                    u16 baseband_attenuation,
1899                                    u16 radio_attenuation,
1900                                    u16 txpower)
1901{
1902        struct b43legacy_phy *phy = &dev->phy;
1903
1904        if (baseband_attenuation == 0xFFFF)
1905                baseband_attenuation = phy->bbatt;
1906        if (radio_attenuation == 0xFFFF)
1907                radio_attenuation = phy->rfatt;
1908        if (txpower == 0xFFFF)
1909                txpower = phy->txctl1;
1910        phy->bbatt = baseband_attenuation;
1911        phy->rfatt = radio_attenuation;
1912        phy->txctl1 = txpower;
1913
1914        B43legacy_WARN_ON(baseband_attenuation > 11);
1915        if (phy->radio_rev < 6)
1916                B43legacy_WARN_ON(radio_attenuation > 9);
1917        else
1918                B43legacy_WARN_ON(radio_attenuation > 31);
1919        B43legacy_WARN_ON(txpower > 7);
1920
1921        b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
1922        b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
1923        b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
1924                              radio_attenuation);
1925        if (phy->radio_ver == 0x2050)
1926                b43legacy_radio_write16(dev, 0x0052,
1927                                        (b43legacy_radio_read16(dev, 0x0052)
1928                                        & ~0x0070) | ((txpower << 4) & 0x0070));
1929        /* FIXME: The spec is very weird and unclear here. */
1930        if (phy->type == B43legacy_PHYTYPE_G)
1931                b43legacy_phy_lo_adjust(dev, 0);
1932}
1933
1934u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
1935{
1936        struct b43legacy_phy *phy = &dev->phy;
1937
1938        if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
1939                return 0;
1940        return 2;
1941}
1942
1943u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
1944{
1945        struct b43legacy_phy *phy = &dev->phy;
1946        u16 att = 0xFFFF;
1947
1948        switch (phy->radio_ver) {
1949        case 0x2053:
1950                switch (phy->radio_rev) {
1951                case 1:
1952                        att = 6;
1953                        break;
1954                }
1955                break;
1956        case 0x2050:
1957                switch (phy->radio_rev) {
1958                case 0:
1959                        att = 5;
1960                        break;
1961                case 1:
1962                        if (phy->type == B43legacy_PHYTYPE_G) {
1963                                if (is_bcm_board_vendor(dev) &&
1964                                    dev->dev->bus->boardinfo.type == 0x421 &&
1965                                    dev->dev->bus->sprom.board_rev >= 30)
1966                                        att = 3;
1967                                else if (is_bcm_board_vendor(dev) &&
1968                                         dev->dev->bus->boardinfo.type == 0x416)
1969                                        att = 3;
1970                                else
1971                                        att = 1;
1972                        } else {
1973                                if (is_bcm_board_vendor(dev) &&
1974                                    dev->dev->bus->boardinfo.type == 0x421 &&
1975                                    dev->dev->bus->sprom.board_rev >= 30)
1976                                        att = 7;
1977                                else
1978                                        att = 6;
1979                        }
1980                        break;
1981                case 2:
1982                        if (phy->type == B43legacy_PHYTYPE_G) {
1983                                if (is_bcm_board_vendor(dev) &&
1984                                    dev->dev->bus->boardinfo.type == 0x421 &&
1985                                    dev->dev->bus->sprom.board_rev >= 30)
1986                                        att = 3;
1987                                else if (is_bcm_board_vendor(dev) &&
1988                                         dev->dev->bus->boardinfo.type ==
1989                                         0x416)
1990                                        att = 5;
1991                                else if (dev->dev->bus->chip_id == 0x4320)
1992                                        att = 4;
1993                                else
1994                                        att = 3;
1995                        } else
1996                                att = 6;
1997                        break;
1998                case 3:
1999                        att = 5;
2000                        break;
2001                case 4:
2002                case 5:
2003                        att = 1;
2004                        break;
2005                case 6:
2006                case 7:
2007                        att = 5;
2008                        break;
2009                case 8:
2010                        att = 0x1A;
2011                        break;
2012                case 9:
2013                default:
2014                        att = 5;
2015                }
2016        }
2017        if (is_bcm_board_vendor(dev) &&
2018            dev->dev->bus->boardinfo.type == 0x421) {
2019                if (dev->dev->bus->sprom.board_rev < 0x43)
2020                        att = 2;
2021                else if (dev->dev->bus->sprom.board_rev < 0x51)
2022                        att = 3;
2023        }
2024        if (att == 0xFFFF)
2025                att = 5;
2026
2027        return att;
2028}
2029
2030u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
2031{
2032        struct b43legacy_phy *phy = &dev->phy;
2033
2034        if (phy->radio_ver != 0x2050)
2035                return 0;
2036        if (phy->radio_rev == 1)
2037                return 3;
2038        if (phy->radio_rev < 6)
2039                return 2;
2040        if (phy->radio_rev == 8)
2041                return 1;
2042        return 0;
2043}
2044
2045void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
2046{
2047        struct b43legacy_phy *phy = &dev->phy;
2048        int err;
2049        u8 channel;
2050
2051        might_sleep();
2052
2053        if (phy->radio_on)
2054                return;
2055
2056        switch (phy->type) {
2057        case B43legacy_PHYTYPE_B:
2058        case B43legacy_PHYTYPE_G:
2059                b43legacy_phy_write(dev, 0x0015, 0x8000);
2060                b43legacy_phy_write(dev, 0x0015, 0xCC00);
2061                b43legacy_phy_write(dev, 0x0015,
2062                                    (phy->gmode ? 0x00C0 : 0x0000));
2063                if (phy->radio_off_context.valid) {
2064                        /* Restore the RFover values. */
2065                        b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,
2066                                            phy->radio_off_context.rfover);
2067                        b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
2068                                            phy->radio_off_context.rfoverval);
2069                        phy->radio_off_context.valid = false;
2070                }
2071                channel = phy->channel;
2072                err = b43legacy_radio_selectchannel(dev,
2073                                        B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
2074                err |= b43legacy_radio_selectchannel(dev, channel, 0);
2075                B43legacy_WARN_ON(err);
2076                break;
2077        default:
2078                B43legacy_BUG_ON(1);
2079        }
2080        phy->radio_on = true;
2081}
2082
2083void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force)
2084{
2085        struct b43legacy_phy *phy = &dev->phy;
2086
2087        if (!phy->radio_on && !force)
2088                return;
2089
2090        if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
2091                u16 rfover, rfoverval;
2092
2093                rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
2094                rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
2095                if (!force) {
2096                        phy->radio_off_context.rfover = rfover;
2097                        phy->radio_off_context.rfoverval = rfoverval;
2098                        phy->radio_off_context.valid = true;
2099                }
2100                b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
2101                b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
2102                                    rfoverval & 0xFF73);
2103        } else
2104                b43legacy_phy_write(dev, 0x0015, 0xAA00);
2105        phy->radio_on = false;
2106        b43legacydbg(dev->wl, "Radio initialized\n");
2107}
2108
2109void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
2110{
2111        struct b43legacy_phy *phy = &dev->phy;
2112
2113        switch (phy->type) {
2114        case B43legacy_PHYTYPE_B:
2115        case B43legacy_PHYTYPE_G:
2116                b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
2117                                      0x7F7F);
2118                b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
2119                                      0x7F7F);
2120                b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
2121                                      0x7F7F);
2122                b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
2123                                      0x7F7F);
2124                break;
2125        }
2126}
2127