linux/drivers/net/wireless/broadcom/b43legacy/phy.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#include <linux/pci.h>
  21#include <linux/sched.h>
  22#include <linux/slab.h>
  23#include <linux/types.h>
  24
  25#include "b43legacy.h"
  26#include "phy.h"
  27#include "main.h"
  28#include "radio.h"
  29#include "ilt.h"
  30
  31
  32static const s8 b43legacy_tssi2dbm_b_table[] = {
  33        0x4D, 0x4C, 0x4B, 0x4A,
  34        0x4A, 0x49, 0x48, 0x47,
  35        0x47, 0x46, 0x45, 0x45,
  36        0x44, 0x43, 0x42, 0x42,
  37        0x41, 0x40, 0x3F, 0x3E,
  38        0x3D, 0x3C, 0x3B, 0x3A,
  39        0x39, 0x38, 0x37, 0x36,
  40        0x35, 0x34, 0x32, 0x31,
  41        0x30, 0x2F, 0x2D, 0x2C,
  42        0x2B, 0x29, 0x28, 0x26,
  43        0x25, 0x23, 0x21, 0x1F,
  44        0x1D, 0x1A, 0x17, 0x14,
  45        0x10, 0x0C, 0x06, 0x00,
  46          -7,   -7,   -7,   -7,
  47          -7,   -7,   -7,   -7,
  48          -7,   -7,   -7,   -7,
  49};
  50
  51static const s8 b43legacy_tssi2dbm_g_table[] = {
  52         77,  77,  77,  76,
  53         76,  76,  75,  75,
  54         74,  74,  73,  73,
  55         73,  72,  72,  71,
  56         71,  70,  70,  69,
  57         68,  68,  67,  67,
  58         66,  65,  65,  64,
  59         63,  63,  62,  61,
  60         60,  59,  58,  57,
  61         56,  55,  54,  53,
  62         52,  50,  49,  47,
  63         45,  43,  40,  37,
  64         33,  28,  22,  14,
  65          5,  -7, -20, -20,
  66        -20, -20, -20, -20,
  67        -20, -20, -20, -20,
  68};
  69
  70static void b43legacy_phy_initg(struct b43legacy_wldev *dev);
  71
  72
  73static inline
  74void b43legacy_voluntary_preempt(void)
  75{
  76        B43legacy_BUG_ON(!(!in_atomic() && !in_irq() &&
  77                          !in_interrupt() && !irqs_disabled()));
  78#ifndef CONFIG_PREEMPT
  79        cond_resched();
  80#endif /* CONFIG_PREEMPT */
  81}
  82
  83/* Lock the PHY registers against concurrent access from the microcode.
  84 * This lock is nonrecursive. */
  85void b43legacy_phy_lock(struct b43legacy_wldev *dev)
  86{
  87#if B43legacy_DEBUG
  88        B43legacy_WARN_ON(dev->phy.phy_locked);
  89        dev->phy.phy_locked = 1;
  90#endif
  91
  92        if (dev->dev->id.revision < 3) {
  93                b43legacy_mac_suspend(dev);
  94        } else {
  95                if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
  96                        b43legacy_power_saving_ctl_bits(dev, -1, 1);
  97        }
  98}
  99
 100void b43legacy_phy_unlock(struct b43legacy_wldev *dev)
 101{
 102#if B43legacy_DEBUG
 103        B43legacy_WARN_ON(!dev->phy.phy_locked);
 104        dev->phy.phy_locked = 0;
 105#endif
 106
 107        if (dev->dev->id.revision < 3) {
 108                b43legacy_mac_enable(dev);
 109        } else {
 110                if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
 111                        b43legacy_power_saving_ctl_bits(dev, -1, -1);
 112        }
 113}
 114
 115u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
 116{
 117        b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
 118        return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA);
 119}
 120
 121void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
 122{
 123        b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
 124        b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val);
 125}
 126
 127void b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
 128{
 129        struct b43legacy_phy *phy = &dev->phy;
 130
 131        b43legacy_read32(dev, B43legacy_MMIO_MACCTL); /* Dummy read. */
 132        if (phy->calibrated)
 133                return;
 134        if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) {
 135                b43legacy_wireless_core_reset(dev, 0);
 136                b43legacy_phy_initg(dev);
 137                b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE);
 138        }
 139        phy->calibrated = 1;
 140}
 141
 142/* initialize B PHY power control
 143 * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
 144 */
 145static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev)
 146{
 147        struct b43legacy_phy *phy = &dev->phy;
 148        u16 saved_batt = 0;
 149        u16 saved_ratt = 0;
 150        u16 saved_txctl1 = 0;
 151        int must_reset_txpower = 0;
 152
 153        B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
 154                          phy->type == B43legacy_PHYTYPE_G));
 155        if (is_bcm_board_vendor(dev) &&
 156            (dev->dev->bus->boardinfo.type == 0x0416))
 157                return;
 158
 159        b43legacy_phy_write(dev, 0x0028, 0x8018);
 160        b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF);
 161
 162        if (phy->type == B43legacy_PHYTYPE_G) {
 163                if (!phy->gmode)
 164                        return;
 165                b43legacy_phy_write(dev, 0x047A, 0xC111);
 166        }
 167        if (phy->savedpctlreg != 0xFFFF)
 168                return;
 169#ifdef CONFIG_B43LEGACY_DEBUG
 170        if (phy->manual_txpower_control)
 171                return;
 172#endif
 173
 174        if (phy->type == B43legacy_PHYTYPE_B &&
 175            phy->rev >= 2 &&
 176            phy->radio_ver == 0x2050)
 177                b43legacy_radio_write16(dev, 0x0076,
 178                                        b43legacy_radio_read16(dev, 0x0076)
 179                                        | 0x0084);
 180        else {
 181                saved_batt = phy->bbatt;
 182                saved_ratt = phy->rfatt;
 183                saved_txctl1 = phy->txctl1;
 184                if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8)
 185                    && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
 186                        b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0);
 187                else
 188                        b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0);
 189                must_reset_txpower = 1;
 190        }
 191        b43legacy_dummy_transmission(dev);
 192
 193        phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL);
 194
 195        if (must_reset_txpower)
 196                b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt,
 197                                               saved_txctl1);
 198        else
 199                b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev,
 200                                        0x0076) & 0xFF7B);
 201        b43legacy_radio_clear_tssi(dev);
 202}
 203
 204static void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev)
 205{
 206        struct b43legacy_phy *phy = &dev->phy;
 207        u16 offset = 0x0000;
 208
 209        if (phy->rev == 1)
 210                offset = 0x4C00;
 211
 212        b43legacy_ilt_write(dev, offset, 0x00FE);
 213        b43legacy_ilt_write(dev, offset + 1, 0x000D);
 214        b43legacy_ilt_write(dev, offset + 2, 0x0013);
 215        b43legacy_ilt_write(dev, offset + 3, 0x0019);
 216
 217        if (phy->rev == 1) {
 218                b43legacy_ilt_write(dev, 0x1800, 0x2710);
 219                b43legacy_ilt_write(dev, 0x1801, 0x9B83);
 220                b43legacy_ilt_write(dev, 0x1802, 0x9B83);
 221                b43legacy_ilt_write(dev, 0x1803, 0x0F8D);
 222                b43legacy_phy_write(dev, 0x0455, 0x0004);
 223        }
 224
 225        b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5)
 226                                          & 0x00FF) | 0x5700);
 227        b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
 228                                          & 0xFF80) | 0x000F);
 229        b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
 230                                          & 0xC07F) | 0x2B80);
 231        b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C)
 232                                          & 0xF0FF) | 0x0300);
 233
 234        b43legacy_radio_write16(dev, 0x007A,
 235                                b43legacy_radio_read16(dev, 0x007A)
 236                                | 0x0008);
 237
 238        b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
 239                            & 0xFFF0) | 0x0008);
 240        b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1)
 241                            & 0xF0FF) | 0x0600);
 242        b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2)
 243                            & 0xF0FF) | 0x0700);
 244        b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
 245                            & 0xF0FF) | 0x0100);
 246
 247        if (phy->rev == 1)
 248                b43legacy_phy_write(dev, 0x04A2,
 249                                    (b43legacy_phy_read(dev, 0x04A2)
 250                                    & 0xFFF0) | 0x0007);
 251
 252        b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
 253                            & 0xFF00) | 0x001C);
 254        b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
 255                            & 0xC0FF) | 0x0200);
 256        b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
 257                            & 0xFF00) | 0x001C);
 258        b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
 259                            & 0xFF00) | 0x0020);
 260        b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
 261                            & 0xC0FF) | 0x0200);
 262        b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482)
 263                            & 0xFF00) | 0x002E);
 264        b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
 265                            & 0x00FF) | 0x1A00);
 266        b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
 267                            & 0xFF00) | 0x0028);
 268        b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
 269                            & 0x00FF) | 0x2C00);
 270
 271        if (phy->rev == 1) {
 272                b43legacy_phy_write(dev, 0x0430, 0x092B);
 273                b43legacy_phy_write(dev, 0x041B,
 274                                    (b43legacy_phy_read(dev, 0x041B)
 275                                    & 0xFFE1) | 0x0002);
 276        } else {
 277                b43legacy_phy_write(dev, 0x041B,
 278                                    b43legacy_phy_read(dev, 0x041B) & 0xFFE1);
 279                b43legacy_phy_write(dev, 0x041F, 0x287A);
 280                b43legacy_phy_write(dev, 0x0420,
 281                                    (b43legacy_phy_read(dev, 0x0420)
 282                                    & 0xFFF0) | 0x0004);
 283        }
 284
 285        if (phy->rev > 2) {
 286                b43legacy_phy_write(dev, 0x0422, 0x287A);
 287                b43legacy_phy_write(dev, 0x0420,
 288                                    (b43legacy_phy_read(dev, 0x0420)
 289                                    & 0x0FFF) | 0x3000);
 290        }
 291
 292        b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8)
 293                            & 0x8080) | 0x7874);
 294        b43legacy_phy_write(dev, 0x048E, 0x1C00);
 295
 296        if (phy->rev == 1) {
 297                b43legacy_phy_write(dev, 0x04AB,
 298                                    (b43legacy_phy_read(dev, 0x04AB)
 299                                    & 0xF0FF) | 0x0600);
 300                b43legacy_phy_write(dev, 0x048B, 0x005E);
 301                b43legacy_phy_write(dev, 0x048C,
 302                                    (b43legacy_phy_read(dev, 0x048C) & 0xFF00)
 303                                    | 0x001E);
 304                b43legacy_phy_write(dev, 0x048D, 0x0002);
 305        }
 306
 307        b43legacy_ilt_write(dev, offset + 0x0800, 0);
 308        b43legacy_ilt_write(dev, offset + 0x0801, 7);
 309        b43legacy_ilt_write(dev, offset + 0x0802, 16);
 310        b43legacy_ilt_write(dev, offset + 0x0803, 28);
 311
 312        if (phy->rev >= 6) {
 313                b43legacy_phy_write(dev, 0x0426,
 314                                    (b43legacy_phy_read(dev, 0x0426) & 0xFFFC));
 315                b43legacy_phy_write(dev, 0x0426,
 316                                    (b43legacy_phy_read(dev, 0x0426) & 0xEFFF));
 317        }
 318}
 319
 320static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
 321{
 322        struct b43legacy_phy *phy = &dev->phy;
 323        u16 i;
 324
 325        B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G);
 326        if (phy->rev == 1) {
 327                b43legacy_phy_write(dev, 0x0406, 0x4F19);
 328                b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
 329                                    (b43legacy_phy_read(dev,
 330                                    B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340);
 331                b43legacy_phy_write(dev, 0x042C, 0x005A);
 332                b43legacy_phy_write(dev, 0x0427, 0x001A);
 333
 334                for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++)
 335                        b43legacy_ilt_write(dev, 0x5800 + i,
 336                                            b43legacy_ilt_finefreqg[i]);
 337                for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++)
 338                        b43legacy_ilt_write(dev, 0x1800 + i,
 339                                            b43legacy_ilt_noiseg1[i]);
 340                for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++)
 341                        b43legacy_ilt_write32(dev, 0x2000 + i,
 342                                              b43legacy_ilt_rotor[i]);
 343        } else {
 344                /* nrssi values are signed 6-bit values. Why 0x7654 here? */
 345                b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654);
 346
 347                if (phy->rev == 2) {
 348                        b43legacy_phy_write(dev, 0x04C0, 0x1861);
 349                        b43legacy_phy_write(dev, 0x04C1, 0x0271);
 350                } else if (phy->rev > 2) {
 351                        b43legacy_phy_write(dev, 0x04C0, 0x0098);
 352                        b43legacy_phy_write(dev, 0x04C1, 0x0070);
 353                        b43legacy_phy_write(dev, 0x04C9, 0x0080);
 354                }
 355                b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev,
 356                                    0x042B) | 0x800);
 357
 358                for (i = 0; i < 64; i++)
 359                        b43legacy_ilt_write(dev, 0x4000 + i, i);
 360                for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++)
 361                        b43legacy_ilt_write(dev, 0x1800 + i,
 362                                            b43legacy_ilt_noiseg2[i]);
 363        }
 364
 365        if (phy->rev <= 2)
 366                for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
 367                        b43legacy_ilt_write(dev, 0x1400 + i,
 368                                            b43legacy_ilt_noisescaleg1[i]);
 369        else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200))
 370                for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
 371                        b43legacy_ilt_write(dev, 0x1400 + i,
 372                                            b43legacy_ilt_noisescaleg3[i]);
 373        else
 374                for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
 375                        b43legacy_ilt_write(dev, 0x1400 + i,
 376                                            b43legacy_ilt_noisescaleg2[i]);
 377
 378        if (phy->rev == 2)
 379                for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
 380                        b43legacy_ilt_write(dev, 0x5000 + i,
 381                                            b43legacy_ilt_sigmasqr1[i]);
 382        else if ((phy->rev > 2) && (phy->rev <= 8))
 383                for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
 384                        b43legacy_ilt_write(dev, 0x5000 + i,
 385                                            b43legacy_ilt_sigmasqr2[i]);
 386
 387        if (phy->rev == 1) {
 388                for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++)
 389                        b43legacy_ilt_write32(dev, 0x2400 + i,
 390                                              b43legacy_ilt_retard[i]);
 391                for (i = 4; i < 20; i++)
 392                        b43legacy_ilt_write(dev, 0x5400 + i, 0x0020);
 393                b43legacy_phy_agcsetup(dev);
 394
 395                if (is_bcm_board_vendor(dev) &&
 396                    (dev->dev->bus->boardinfo.type == 0x0416) &&
 397                    (dev->dev->bus->sprom.board_rev == 0x0017))
 398                        return;
 399
 400                b43legacy_ilt_write(dev, 0x5001, 0x0002);
 401                b43legacy_ilt_write(dev, 0x5002, 0x0001);
 402        } else {
 403                for (i = 0; i <= 0x20; i++)
 404                        b43legacy_ilt_write(dev, 0x1000 + i, 0x0820);
 405                b43legacy_phy_agcsetup(dev);
 406                b43legacy_phy_read(dev, 0x0400); /* dummy read */
 407                b43legacy_phy_write(dev, 0x0403, 0x1000);
 408                b43legacy_ilt_write(dev, 0x3C02, 0x000F);
 409                b43legacy_ilt_write(dev, 0x3C03, 0x0014);
 410
 411                if (is_bcm_board_vendor(dev) &&
 412                    (dev->dev->bus->boardinfo.type == 0x0416) &&
 413                    (dev->dev->bus->sprom.board_rev == 0x0017))
 414                        return;
 415
 416                b43legacy_ilt_write(dev, 0x0401, 0x0002);
 417                b43legacy_ilt_write(dev, 0x0402, 0x0001);
 418        }
 419}
 420
 421/* Initialize the APHY portion of a GPHY. */
 422static void b43legacy_phy_inita(struct b43legacy_wldev *dev)
 423{
 424
 425        might_sleep();
 426
 427        b43legacy_phy_setupg(dev);
 428        if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL)
 429                b43legacy_phy_write(dev, 0x046E, 0x03CF);
 430}
 431
 432static void b43legacy_phy_initb2(struct b43legacy_wldev *dev)
 433{
 434        struct b43legacy_phy *phy = &dev->phy;
 435        u16 offset;
 436        int val;
 437
 438        b43legacy_write16(dev, 0x03EC, 0x3F22);
 439        b43legacy_phy_write(dev, 0x0020, 0x301C);
 440        b43legacy_phy_write(dev, 0x0026, 0x0000);
 441        b43legacy_phy_write(dev, 0x0030, 0x00C6);
 442        b43legacy_phy_write(dev, 0x0088, 0x3E00);
 443        val = 0x3C3D;
 444        for (offset = 0x0089; offset < 0x00A7; offset++) {
 445                b43legacy_phy_write(dev, offset, val);
 446                val -= 0x0202;
 447        }
 448        b43legacy_phy_write(dev, 0x03E4, 0x3000);
 449        b43legacy_radio_selectchannel(dev, phy->channel, 0);
 450        if (phy->radio_ver != 0x2050) {
 451                b43legacy_radio_write16(dev, 0x0075, 0x0080);
 452                b43legacy_radio_write16(dev, 0x0079, 0x0081);
 453        }
 454        b43legacy_radio_write16(dev, 0x0050, 0x0020);
 455        b43legacy_radio_write16(dev, 0x0050, 0x0023);
 456        if (phy->radio_ver == 0x2050) {
 457                b43legacy_radio_write16(dev, 0x0050, 0x0020);
 458                b43legacy_radio_write16(dev, 0x005A, 0x0070);
 459                b43legacy_radio_write16(dev, 0x005B, 0x007B);
 460                b43legacy_radio_write16(dev, 0x005C, 0x00B0);
 461                b43legacy_radio_write16(dev, 0x007A, 0x000F);
 462                b43legacy_phy_write(dev, 0x0038, 0x0677);
 463                b43legacy_radio_init2050(dev);
 464        }
 465        b43legacy_phy_write(dev, 0x0014, 0x0080);
 466        b43legacy_phy_write(dev, 0x0032, 0x00CA);
 467        b43legacy_phy_write(dev, 0x0032, 0x00CC);
 468        b43legacy_phy_write(dev, 0x0035, 0x07C2);
 469        b43legacy_phy_lo_b_measure(dev);
 470        b43legacy_phy_write(dev, 0x0026, 0xCC00);
 471        if (phy->radio_ver != 0x2050)
 472                b43legacy_phy_write(dev, 0x0026, 0xCE00);
 473        b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000);
 474        b43legacy_phy_write(dev, 0x002A, 0x88A3);
 475        if (phy->radio_ver != 0x2050)
 476                b43legacy_phy_write(dev, 0x002A, 0x88C2);
 477        b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
 478        b43legacy_phy_init_pctl(dev);
 479}
 480
 481static void b43legacy_phy_initb4(struct b43legacy_wldev *dev)
 482{
 483        struct b43legacy_phy *phy = &dev->phy;
 484        u16 offset;
 485        u16 val;
 486
 487        b43legacy_write16(dev, 0x03EC, 0x3F22);
 488        b43legacy_phy_write(dev, 0x0020, 0x301C);
 489        b43legacy_phy_write(dev, 0x0026, 0x0000);
 490        b43legacy_phy_write(dev, 0x0030, 0x00C6);
 491        b43legacy_phy_write(dev, 0x0088, 0x3E00);
 492        val = 0x3C3D;
 493        for (offset = 0x0089; offset < 0x00A7; offset++) {
 494                b43legacy_phy_write(dev, offset, val);
 495                val -= 0x0202;
 496        }
 497        b43legacy_phy_write(dev, 0x03E4, 0x3000);
 498        b43legacy_radio_selectchannel(dev, phy->channel, 0);
 499        if (phy->radio_ver != 0x2050) {
 500                b43legacy_radio_write16(dev, 0x0075, 0x0080);
 501                b43legacy_radio_write16(dev, 0x0079, 0x0081);
 502        }
 503        b43legacy_radio_write16(dev, 0x0050, 0x0020);
 504        b43legacy_radio_write16(dev, 0x0050, 0x0023);
 505        if (phy->radio_ver == 0x2050) {
 506                b43legacy_radio_write16(dev, 0x0050, 0x0020);
 507                b43legacy_radio_write16(dev, 0x005A, 0x0070);
 508                b43legacy_radio_write16(dev, 0x005B, 0x007B);
 509                b43legacy_radio_write16(dev, 0x005C, 0x00B0);
 510                b43legacy_radio_write16(dev, 0x007A, 0x000F);
 511                b43legacy_phy_write(dev, 0x0038, 0x0677);
 512                b43legacy_radio_init2050(dev);
 513        }
 514        b43legacy_phy_write(dev, 0x0014, 0x0080);
 515        b43legacy_phy_write(dev, 0x0032, 0x00CA);
 516        if (phy->radio_ver == 0x2050)
 517                b43legacy_phy_write(dev, 0x0032, 0x00E0);
 518        b43legacy_phy_write(dev, 0x0035, 0x07C2);
 519
 520        b43legacy_phy_lo_b_measure(dev);
 521
 522        b43legacy_phy_write(dev, 0x0026, 0xCC00);
 523        if (phy->radio_ver == 0x2050)
 524                b43legacy_phy_write(dev, 0x0026, 0xCE00);
 525        b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100);
 526        b43legacy_phy_write(dev, 0x002A, 0x88A3);
 527        if (phy->radio_ver == 0x2050)
 528                b43legacy_phy_write(dev, 0x002A, 0x88C2);
 529        b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
 530        if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) {
 531                b43legacy_calc_nrssi_slope(dev);
 532                b43legacy_calc_nrssi_threshold(dev);
 533        }
 534        b43legacy_phy_init_pctl(dev);
 535}
 536
 537static void b43legacy_phy_initb5(struct b43legacy_wldev *dev)
 538{
 539        struct b43legacy_phy *phy = &dev->phy;
 540        u16 offset;
 541        u16 value;
 542        u8 old_channel;
 543
 544        if (phy->analog == 1)
 545                b43legacy_radio_write16(dev, 0x007A,
 546                                        b43legacy_radio_read16(dev, 0x007A)
 547                                        | 0x0050);
 548        if (!is_bcm_board_vendor(dev) &&
 549            (dev->dev->bus->boardinfo.type != 0x0416)) {
 550                value = 0x2120;
 551                for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
 552                        b43legacy_phy_write(dev, offset, value);
 553                        value += 0x0202;
 554                }
 555        }
 556        b43legacy_phy_write(dev, 0x0035,
 557                            (b43legacy_phy_read(dev, 0x0035) & 0xF0FF)
 558                            | 0x0700);
 559        if (phy->radio_ver == 0x2050)
 560                b43legacy_phy_write(dev, 0x0038, 0x0667);
 561
 562        if (phy->gmode) {
 563                if (phy->radio_ver == 0x2050) {
 564                        b43legacy_radio_write16(dev, 0x007A,
 565                                        b43legacy_radio_read16(dev, 0x007A)
 566                                        | 0x0020);
 567                        b43legacy_radio_write16(dev, 0x0051,
 568                                        b43legacy_radio_read16(dev, 0x0051)
 569                                        | 0x0004);
 570                }
 571                b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000);
 572
 573                b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802)
 574                                    | 0x0100);
 575                b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B)
 576                                    | 0x2000);
 577
 578                b43legacy_phy_write(dev, 0x001C, 0x186A);
 579
 580                b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev,
 581                                    0x0013) & 0x00FF) | 0x1900);
 582                b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev,
 583                                    0x0035) & 0xFFC0) | 0x0064);
 584                b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
 585                                    0x005D) & 0xFF80) | 0x000A);
 586                b43legacy_phy_write(dev, 0x5B, 0x0000);
 587                b43legacy_phy_write(dev, 0x5C, 0x0000);
 588        }
 589
 590        if (dev->bad_frames_preempt)
 591                b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
 592                                    b43legacy_phy_read(dev,
 593                                    B43legacy_PHY_RADIO_BITFIELD) | (1 << 12));
 594
 595        if (phy->analog == 1) {
 596                b43legacy_phy_write(dev, 0x0026, 0xCE00);
 597                b43legacy_phy_write(dev, 0x0021, 0x3763);
 598                b43legacy_phy_write(dev, 0x0022, 0x1BC3);
 599                b43legacy_phy_write(dev, 0x0023, 0x06F9);
 600                b43legacy_phy_write(dev, 0x0024, 0x037E);
 601        } else
 602                b43legacy_phy_write(dev, 0x0026, 0xCC00);
 603        b43legacy_phy_write(dev, 0x0030, 0x00C6);
 604        b43legacy_write16(dev, 0x03EC, 0x3F22);
 605
 606        if (phy->analog == 1)
 607                b43legacy_phy_write(dev, 0x0020, 0x3E1C);
 608        else
 609                b43legacy_phy_write(dev, 0x0020, 0x301C);
 610
 611        if (phy->analog == 0)
 612                b43legacy_write16(dev, 0x03E4, 0x3000);
 613
 614        old_channel = (phy->channel == 0xFF) ? 1 : phy->channel;
 615        /* Force to channel 7, even if not supported. */
 616        b43legacy_radio_selectchannel(dev, 7, 0);
 617
 618        if (phy->radio_ver != 0x2050) {
 619                b43legacy_radio_write16(dev, 0x0075, 0x0080);
 620                b43legacy_radio_write16(dev, 0x0079, 0x0081);
 621        }
 622
 623        b43legacy_radio_write16(dev, 0x0050, 0x0020);
 624        b43legacy_radio_write16(dev, 0x0050, 0x0023);
 625
 626        if (phy->radio_ver == 0x2050) {
 627                b43legacy_radio_write16(dev, 0x0050, 0x0020);
 628                b43legacy_radio_write16(dev, 0x005A, 0x0070);
 629        }
 630
 631        b43legacy_radio_write16(dev, 0x005B, 0x007B);
 632        b43legacy_radio_write16(dev, 0x005C, 0x00B0);
 633
 634        b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev,
 635                                0x007A) | 0x0007);
 636
 637        b43legacy_radio_selectchannel(dev, old_channel, 0);
 638
 639        b43legacy_phy_write(dev, 0x0014, 0x0080);
 640        b43legacy_phy_write(dev, 0x0032, 0x00CA);
 641        b43legacy_phy_write(dev, 0x002A, 0x88A3);
 642
 643        b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
 644
 645        if (phy->radio_ver == 0x2050)
 646                b43legacy_radio_write16(dev, 0x005D, 0x000D);
 647
 648        b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) &
 649                          0xFFC0) | 0x0004);
 650}
 651
 652static void b43legacy_phy_initb6(struct b43legacy_wldev *dev)
 653{
 654        struct b43legacy_phy *phy = &dev->phy;
 655        u16 offset;
 656        u16 val;
 657        u8 old_channel;
 658
 659        b43legacy_phy_write(dev, 0x003E, 0x817A);
 660        b43legacy_radio_write16(dev, 0x007A,
 661                                (b43legacy_radio_read16(dev, 0x007A) | 0x0058));
 662        if (phy->radio_rev == 4 ||
 663             phy->radio_rev == 5) {
 664                b43legacy_radio_write16(dev, 0x0051, 0x0037);
 665                b43legacy_radio_write16(dev, 0x0052, 0x0070);
 666                b43legacy_radio_write16(dev, 0x0053, 0x00B3);
 667                b43legacy_radio_write16(dev, 0x0054, 0x009B);
 668                b43legacy_radio_write16(dev, 0x005A, 0x0088);
 669                b43legacy_radio_write16(dev, 0x005B, 0x0088);
 670                b43legacy_radio_write16(dev, 0x005D, 0x0088);
 671                b43legacy_radio_write16(dev, 0x005E, 0x0088);
 672                b43legacy_radio_write16(dev, 0x007D, 0x0088);
 673                b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
 674                                      B43legacy_UCODEFLAGS_OFFSET,
 675                                      (b43legacy_shm_read32(dev,
 676                                      B43legacy_SHM_SHARED,
 677                                      B43legacy_UCODEFLAGS_OFFSET)
 678                                      | 0x00000200));
 679        }
 680        if (phy->radio_rev == 8) {
 681                b43legacy_radio_write16(dev, 0x0051, 0x0000);
 682                b43legacy_radio_write16(dev, 0x0052, 0x0040);
 683                b43legacy_radio_write16(dev, 0x0053, 0x00B7);
 684                b43legacy_radio_write16(dev, 0x0054, 0x0098);
 685                b43legacy_radio_write16(dev, 0x005A, 0x0088);
 686                b43legacy_radio_write16(dev, 0x005B, 0x006B);
 687                b43legacy_radio_write16(dev, 0x005C, 0x000F);
 688                if (dev->dev->bus->sprom.boardflags_lo & 0x8000) {
 689                        b43legacy_radio_write16(dev, 0x005D, 0x00FA);
 690                        b43legacy_radio_write16(dev, 0x005E, 0x00D8);
 691                } else {
 692                        b43legacy_radio_write16(dev, 0x005D, 0x00F5);
 693                        b43legacy_radio_write16(dev, 0x005E, 0x00B8);
 694                }
 695                b43legacy_radio_write16(dev, 0x0073, 0x0003);
 696                b43legacy_radio_write16(dev, 0x007D, 0x00A8);
 697                b43legacy_radio_write16(dev, 0x007C, 0x0001);
 698                b43legacy_radio_write16(dev, 0x007E, 0x0008);
 699        }
 700        val = 0x1E1F;
 701        for (offset = 0x0088; offset < 0x0098; offset++) {
 702                b43legacy_phy_write(dev, offset, val);
 703                val -= 0x0202;
 704        }
 705        val = 0x3E3F;
 706        for (offset = 0x0098; offset < 0x00A8; offset++) {
 707                b43legacy_phy_write(dev, offset, val);
 708                val -= 0x0202;
 709        }
 710        val = 0x2120;
 711        for (offset = 0x00A8; offset < 0x00C8; offset++) {
 712                b43legacy_phy_write(dev, offset, (val & 0x3F3F));
 713                val += 0x0202;
 714        }
 715        if (phy->type == B43legacy_PHYTYPE_G) {
 716                b43legacy_radio_write16(dev, 0x007A,
 717                                        b43legacy_radio_read16(dev, 0x007A) |
 718                                        0x0020);
 719                b43legacy_radio_write16(dev, 0x0051,
 720                                        b43legacy_radio_read16(dev, 0x0051) |
 721                                        0x0004);
 722                b43legacy_phy_write(dev, 0x0802,
 723                                    b43legacy_phy_read(dev, 0x0802) | 0x0100);
 724                b43legacy_phy_write(dev, 0x042B,
 725                                    b43legacy_phy_read(dev, 0x042B) | 0x2000);
 726                b43legacy_phy_write(dev, 0x5B, 0x0000);
 727                b43legacy_phy_write(dev, 0x5C, 0x0000);
 728        }
 729
 730        old_channel = phy->channel;
 731        if (old_channel >= 8)
 732                b43legacy_radio_selectchannel(dev, 1, 0);
 733        else
 734                b43legacy_radio_selectchannel(dev, 13, 0);
 735
 736        b43legacy_radio_write16(dev, 0x0050, 0x0020);
 737        b43legacy_radio_write16(dev, 0x0050, 0x0023);
 738        udelay(40);
 739        if (phy->radio_rev < 6 || phy->radio_rev == 8) {
 740                b43legacy_radio_write16(dev, 0x007C,
 741                                        (b43legacy_radio_read16(dev, 0x007C)
 742                                        | 0x0002));
 743                b43legacy_radio_write16(dev, 0x0050, 0x0020);
 744        }
 745        if (phy->radio_rev <= 2) {
 746                b43legacy_radio_write16(dev, 0x0050, 0x0020);
 747                b43legacy_radio_write16(dev, 0x005A, 0x0070);
 748                b43legacy_radio_write16(dev, 0x005B, 0x007B);
 749                b43legacy_radio_write16(dev, 0x005C, 0x00B0);
 750        }
 751        b43legacy_radio_write16(dev, 0x007A,
 752                                (b43legacy_radio_read16(dev,
 753                                0x007A) & 0x00F8) | 0x0007);
 754
 755        b43legacy_radio_selectchannel(dev, old_channel, 0);
 756
 757        b43legacy_phy_write(dev, 0x0014, 0x0200);
 758        if (phy->radio_rev >= 6)
 759                b43legacy_phy_write(dev, 0x002A, 0x88C2);
 760        else
 761                b43legacy_phy_write(dev, 0x002A, 0x8AC0);
 762        b43legacy_phy_write(dev, 0x0038, 0x0668);
 763        b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
 764        if (phy->radio_rev == 4 || phy->radio_rev == 5)
 765                b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
 766                                    0x005D) & 0xFF80) | 0x0003);
 767        if (phy->radio_rev <= 2)
 768                b43legacy_radio_write16(dev, 0x005D, 0x000D);
 769
 770        if (phy->analog == 4) {
 771                b43legacy_write16(dev, 0x03E4, 0x0009);
 772                b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61)
 773                                    & 0xFFF);
 774        } else
 775                b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev,
 776                                    0x0002) & 0xFFC0) | 0x0004);
 777        if (phy->type == B43legacy_PHYTYPE_G)
 778                b43legacy_write16(dev, 0x03E6, 0x0);
 779        if (phy->type == B43legacy_PHYTYPE_B) {
 780                b43legacy_write16(dev, 0x03E6, 0x8140);
 781                b43legacy_phy_write(dev, 0x0016, 0x0410);
 782                b43legacy_phy_write(dev, 0x0017, 0x0820);
 783                b43legacy_phy_write(dev, 0x0062, 0x0007);
 784                b43legacy_radio_init2050(dev);
 785                b43legacy_phy_lo_g_measure(dev);
 786                if (dev->dev->bus->sprom.boardflags_lo &
 787                    B43legacy_BFL_RSSI) {
 788                        b43legacy_calc_nrssi_slope(dev);
 789                        b43legacy_calc_nrssi_threshold(dev);
 790                }
 791                b43legacy_phy_init_pctl(dev);
 792        }
 793}
 794
 795static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev)
 796{
 797        struct b43legacy_phy *phy = &dev->phy;
 798        u16 backup_phy[15] = {0};
 799        u16 backup_radio[3];
 800        u16 backup_bband;
 801        u16 i;
 802        u16 loop1_cnt;
 803        u16 loop1_done;
 804        u16 loop1_omitted;
 805        u16 loop2_done;
 806
 807        backup_phy[0] = b43legacy_phy_read(dev, 0x0429);
 808        backup_phy[1] = b43legacy_phy_read(dev, 0x0001);
 809        backup_phy[2] = b43legacy_phy_read(dev, 0x0811);
 810        backup_phy[3] = b43legacy_phy_read(dev, 0x0812);
 811        if (phy->rev != 1) {
 812                backup_phy[4] = b43legacy_phy_read(dev, 0x0814);
 813                backup_phy[5] = b43legacy_phy_read(dev, 0x0815);
 814        }
 815        backup_phy[6] = b43legacy_phy_read(dev, 0x005A);
 816        backup_phy[7] = b43legacy_phy_read(dev, 0x0059);
 817        backup_phy[8] = b43legacy_phy_read(dev, 0x0058);
 818        backup_phy[9] = b43legacy_phy_read(dev, 0x000A);
 819        backup_phy[10] = b43legacy_phy_read(dev, 0x0003);
 820        backup_phy[11] = b43legacy_phy_read(dev, 0x080F);
 821        backup_phy[12] = b43legacy_phy_read(dev, 0x0810);
 822        backup_phy[13] = b43legacy_phy_read(dev, 0x002B);
 823        backup_phy[14] = b43legacy_phy_read(dev, 0x0015);
 824        b43legacy_phy_read(dev, 0x002D); /* dummy read */
 825        backup_bband = phy->bbatt;
 826        backup_radio[0] = b43legacy_radio_read16(dev, 0x0052);
 827        backup_radio[1] = b43legacy_radio_read16(dev, 0x0043);
 828        backup_radio[2] = b43legacy_radio_read16(dev, 0x007A);
 829
 830        b43legacy_phy_write(dev, 0x0429,
 831                            b43legacy_phy_read(dev, 0x0429) & 0x3FFF);
 832        b43legacy_phy_write(dev, 0x0001,
 833                            b43legacy_phy_read(dev, 0x0001) & 0x8000);
 834        b43legacy_phy_write(dev, 0x0811,
 835                            b43legacy_phy_read(dev, 0x0811) | 0x0002);
 836        b43legacy_phy_write(dev, 0x0812,
 837                            b43legacy_phy_read(dev, 0x0812) & 0xFFFD);
 838        b43legacy_phy_write(dev, 0x0811,
 839                            b43legacy_phy_read(dev, 0x0811) | 0x0001);
 840        b43legacy_phy_write(dev, 0x0812,
 841                            b43legacy_phy_read(dev, 0x0812) & 0xFFFE);
 842        if (phy->rev != 1) {
 843                b43legacy_phy_write(dev, 0x0814,
 844                                    b43legacy_phy_read(dev, 0x0814) | 0x0001);
 845                b43legacy_phy_write(dev, 0x0815,
 846                                    b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
 847                b43legacy_phy_write(dev, 0x0814,
 848                                    b43legacy_phy_read(dev, 0x0814) | 0x0002);
 849                b43legacy_phy_write(dev, 0x0815,
 850                                    b43legacy_phy_read(dev, 0x0815) & 0xFFFD);
 851        }
 852        b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) |
 853                            0x000C);
 854        b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) |
 855                            0x000C);
 856
 857        b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811)
 858                            & 0xFFCF) | 0x0030);
 859        b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812)
 860                            & 0xFFCF) | 0x0010);
 861
 862        b43legacy_phy_write(dev, 0x005A, 0x0780);
 863        b43legacy_phy_write(dev, 0x0059, 0xC810);
 864        b43legacy_phy_write(dev, 0x0058, 0x000D);
 865        if (phy->analog == 0)
 866                b43legacy_phy_write(dev, 0x0003, 0x0122);
 867        else
 868                b43legacy_phy_write(dev, 0x000A,
 869                                    b43legacy_phy_read(dev, 0x000A)
 870                                    | 0x2000);
 871        if (phy->rev != 1) {
 872                b43legacy_phy_write(dev, 0x0814,
 873                                    b43legacy_phy_read(dev, 0x0814) | 0x0004);
 874                b43legacy_phy_write(dev, 0x0815,
 875                                    b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
 876        }
 877        b43legacy_phy_write(dev, 0x0003,
 878                            (b43legacy_phy_read(dev, 0x0003)
 879                             & 0xFF9F) | 0x0040);
 880        if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) {
 881                b43legacy_radio_write16(dev, 0x0052, 0x0000);
 882                b43legacy_radio_write16(dev, 0x0043,
 883                                        (b43legacy_radio_read16(dev, 0x0043)
 884                                         & 0xFFF0) | 0x0009);
 885                loop1_cnt = 9;
 886        } else if (phy->radio_rev == 8) {
 887                b43legacy_radio_write16(dev, 0x0043, 0x000F);
 888                loop1_cnt = 15;
 889        } else
 890                loop1_cnt = 0;
 891
 892        b43legacy_phy_set_baseband_attenuation(dev, 11);
 893
 894        if (phy->rev >= 3)
 895                b43legacy_phy_write(dev, 0x080F, 0xC020);
 896        else
 897                b43legacy_phy_write(dev, 0x080F, 0x8020);
 898        b43legacy_phy_write(dev, 0x0810, 0x0000);
 899
 900        b43legacy_phy_write(dev, 0x002B,
 901                            (b43legacy_phy_read(dev, 0x002B)
 902                             & 0xFFC0) | 0x0001);
 903        b43legacy_phy_write(dev, 0x002B,
 904                            (b43legacy_phy_read(dev, 0x002B)
 905                             & 0xC0FF) | 0x0800);
 906        b43legacy_phy_write(dev, 0x0811,
 907                            b43legacy_phy_read(dev, 0x0811) | 0x0100);
 908        b43legacy_phy_write(dev, 0x0812,
 909                            b43legacy_phy_read(dev, 0x0812) & 0xCFFF);
 910        if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA) {
 911                if (phy->rev >= 7) {
 912                        b43legacy_phy_write(dev, 0x0811,
 913                                            b43legacy_phy_read(dev, 0x0811)
 914                                            | 0x0800);
 915                        b43legacy_phy_write(dev, 0x0812,
 916                                            b43legacy_phy_read(dev, 0x0812)
 917                                            | 0x8000);
 918                }
 919        }
 920        b43legacy_radio_write16(dev, 0x007A,
 921                                b43legacy_radio_read16(dev, 0x007A)
 922                                & 0x00F7);
 923
 924        for (i = 0; i < loop1_cnt; i++) {
 925                b43legacy_radio_write16(dev, 0x0043, loop1_cnt);
 926                b43legacy_phy_write(dev, 0x0812,
 927                                    (b43legacy_phy_read(dev, 0x0812)
 928                                     & 0xF0FF) | (i << 8));
 929                b43legacy_phy_write(dev, 0x0015,
 930                                    (b43legacy_phy_read(dev, 0x0015)
 931                                     & 0x0FFF) | 0xA000);
 932                b43legacy_phy_write(dev, 0x0015,
 933                                    (b43legacy_phy_read(dev, 0x0015)
 934                                     & 0x0FFF) | 0xF000);
 935                udelay(20);
 936                if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
 937                        break;
 938        }
 939        loop1_done = i;
 940        loop1_omitted = loop1_cnt - loop1_done;
 941
 942        loop2_done = 0;
 943        if (loop1_done >= 8) {
 944                b43legacy_phy_write(dev, 0x0812,
 945                                    b43legacy_phy_read(dev, 0x0812)
 946                                    | 0x0030);
 947                for (i = loop1_done - 8; i < 16; i++) {
 948                        b43legacy_phy_write(dev, 0x0812,
 949                                            (b43legacy_phy_read(dev, 0x0812)
 950                                             & 0xF0FF) | (i << 8));
 951                        b43legacy_phy_write(dev, 0x0015,
 952                                            (b43legacy_phy_read(dev, 0x0015)
 953                                             & 0x0FFF) | 0xA000);
 954                        b43legacy_phy_write(dev, 0x0015,
 955                                            (b43legacy_phy_read(dev, 0x0015)
 956                                             & 0x0FFF) | 0xF000);
 957                        udelay(20);
 958                        if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
 959                                break;
 960                }
 961        }
 962
 963        if (phy->rev != 1) {
 964                b43legacy_phy_write(dev, 0x0814, backup_phy[4]);
 965                b43legacy_phy_write(dev, 0x0815, backup_phy[5]);
 966        }
 967        b43legacy_phy_write(dev, 0x005A, backup_phy[6]);
 968        b43legacy_phy_write(dev, 0x0059, backup_phy[7]);
 969        b43legacy_phy_write(dev, 0x0058, backup_phy[8]);
 970        b43legacy_phy_write(dev, 0x000A, backup_phy[9]);
 971        b43legacy_phy_write(dev, 0x0003, backup_phy[10]);
 972        b43legacy_phy_write(dev, 0x080F, backup_phy[11]);
 973        b43legacy_phy_write(dev, 0x0810, backup_phy[12]);
 974        b43legacy_phy_write(dev, 0x002B, backup_phy[13]);
 975        b43legacy_phy_write(dev, 0x0015, backup_phy[14]);
 976
 977        b43legacy_phy_set_baseband_attenuation(dev, backup_bband);
 978
 979        b43legacy_radio_write16(dev, 0x0052, backup_radio[0]);
 980        b43legacy_radio_write16(dev, 0x0043, backup_radio[1]);
 981        b43legacy_radio_write16(dev, 0x007A, backup_radio[2]);
 982
 983        b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003);
 984        udelay(10);
 985        b43legacy_phy_write(dev, 0x0811, backup_phy[2]);
 986        b43legacy_phy_write(dev, 0x0812, backup_phy[3]);
 987        b43legacy_phy_write(dev, 0x0429, backup_phy[0]);
 988        b43legacy_phy_write(dev, 0x0001, backup_phy[1]);
 989
 990        phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
 991        phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
 992}
 993
 994static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
 995{
 996        struct b43legacy_phy *phy = &dev->phy;
 997        u16 tmp;
 998
 999        if (phy->rev == 1)
1000                b43legacy_phy_initb5(dev);
1001        else
1002                b43legacy_phy_initb6(dev);
1003        if (phy->rev >= 2 && phy->gmode)
1004                b43legacy_phy_inita(dev);
1005
1006        if (phy->rev >= 2) {
1007                b43legacy_phy_write(dev, 0x0814, 0x0000);
1008                b43legacy_phy_write(dev, 0x0815, 0x0000);
1009        }
1010        if (phy->rev == 2) {
1011                b43legacy_phy_write(dev, 0x0811, 0x0000);
1012                b43legacy_phy_write(dev, 0x0015, 0x00C0);
1013        }
1014        if (phy->rev > 5) {
1015                b43legacy_phy_write(dev, 0x0811, 0x0400);
1016                b43legacy_phy_write(dev, 0x0015, 0x00C0);
1017        }
1018        if (phy->gmode) {
1019                tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF;
1020                if (tmp == 3) {
1021                        b43legacy_phy_write(dev, 0x04C2, 0x1816);
1022                        b43legacy_phy_write(dev, 0x04C3, 0x8606);
1023                }
1024                if (tmp == 4 || tmp == 5) {
1025                        b43legacy_phy_write(dev, 0x04C2, 0x1816);
1026                        b43legacy_phy_write(dev, 0x04C3, 0x8006);
1027                        b43legacy_phy_write(dev, 0x04CC,
1028                                            (b43legacy_phy_read(dev,
1029                                             0x04CC) & 0x00FF) |
1030                                             0x1F00);
1031                }
1032                if (phy->rev >= 2)
1033                        b43legacy_phy_write(dev, 0x047E, 0x0078);
1034        }
1035        if (phy->radio_rev == 8) {
1036                b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801)
1037                                    | 0x0080);
1038                b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E)
1039                                    | 0x0004);
1040        }
1041        if (phy->rev >= 2 && phy->gmode)
1042                b43legacy_calc_loopback_gain(dev);
1043        if (phy->radio_rev != 8) {
1044                if (phy->initval == 0xFFFF)
1045                        phy->initval = b43legacy_radio_init2050(dev);
1046                else
1047                        b43legacy_radio_write16(dev, 0x0078, phy->initval);
1048        }
1049        if (phy->txctl2 == 0xFFFF)
1050                b43legacy_phy_lo_g_measure(dev);
1051        else {
1052                if (phy->radio_ver == 0x2050 && phy->radio_rev == 8)
1053                        b43legacy_radio_write16(dev, 0x0052,
1054                                                (phy->txctl1 << 4) |
1055                                                phy->txctl2);
1056                else
1057                        b43legacy_radio_write16(dev, 0x0052,
1058                                                (b43legacy_radio_read16(dev,
1059                                                 0x0052) & 0xFFF0) |
1060                                                 phy->txctl1);
1061                if (phy->rev >= 6)
1062                        b43legacy_phy_write(dev, 0x0036,
1063                                            (b43legacy_phy_read(dev, 0x0036)
1064                                             & 0x0FFF) | (phy->txctl2 << 12));
1065                if (dev->dev->bus->sprom.boardflags_lo &
1066                    B43legacy_BFL_PACTRL)
1067                        b43legacy_phy_write(dev, 0x002E, 0x8075);
1068                else
1069                        b43legacy_phy_write(dev, 0x002E, 0x807F);
1070                if (phy->rev < 2)
1071                        b43legacy_phy_write(dev, 0x002F, 0x0101);
1072                else
1073                        b43legacy_phy_write(dev, 0x002F, 0x0202);
1074        }
1075        if (phy->gmode) {
1076                b43legacy_phy_lo_adjust(dev, 0);
1077                b43legacy_phy_write(dev, 0x080F, 0x8078);
1078        }
1079
1080        if (!(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) {
1081                /* The specs state to update the NRSSI LT with
1082                 * the value 0x7FFFFFFF here. I think that is some weird
1083                 * compiler optimization in the original driver.
1084                 * Essentially, what we do here is resetting all NRSSI LT
1085                 * entries to -32 (see the clamp_val() in nrssi_hw_update())
1086                 */
1087                b43legacy_nrssi_hw_update(dev, 0xFFFF);
1088                b43legacy_calc_nrssi_threshold(dev);
1089        } else if (phy->gmode || phy->rev >= 2) {
1090                if (phy->nrssi[0] == -1000) {
1091                        B43legacy_WARN_ON(phy->nrssi[1] != -1000);
1092                        b43legacy_calc_nrssi_slope(dev);
1093                } else {
1094                        B43legacy_WARN_ON(phy->nrssi[1] == -1000);
1095                        b43legacy_calc_nrssi_threshold(dev);
1096                }
1097        }
1098        if (phy->radio_rev == 8)
1099                b43legacy_phy_write(dev, 0x0805, 0x3230);
1100        b43legacy_phy_init_pctl(dev);
1101        if (dev->dev->bus->chip_id == 0x4306
1102            && dev->dev->bus->chip_package == 2) {
1103                b43legacy_phy_write(dev, 0x0429,
1104                                    b43legacy_phy_read(dev, 0x0429) & 0xBFFF);
1105                b43legacy_phy_write(dev, 0x04C3,
1106                                    b43legacy_phy_read(dev, 0x04C3) & 0x7FFF);
1107        }
1108}
1109
1110static u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev)
1111{
1112        int i;
1113        u16 ret = 0;
1114        unsigned long flags;
1115
1116        local_irq_save(flags);
1117        for (i = 0; i < 10; i++) {
1118                b43legacy_phy_write(dev, 0x0015, 0xAFA0);
1119                udelay(1);
1120                b43legacy_phy_write(dev, 0x0015, 0xEFA0);
1121                udelay(10);
1122                b43legacy_phy_write(dev, 0x0015, 0xFFA0);
1123                udelay(40);
1124                ret += b43legacy_phy_read(dev, 0x002C);
1125        }
1126        local_irq_restore(flags);
1127        b43legacy_voluntary_preempt();
1128
1129        return ret;
1130}
1131
1132void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev)
1133{
1134        struct b43legacy_phy *phy = &dev->phy;
1135        u16 regstack[12] = { 0 };
1136        u16 mls;
1137        u16 fval;
1138        int i;
1139        int j;
1140
1141        regstack[0] = b43legacy_phy_read(dev, 0x0015);
1142        regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0;
1143
1144        if (phy->radio_ver == 0x2053) {
1145                regstack[2] = b43legacy_phy_read(dev, 0x000A);
1146                regstack[3] = b43legacy_phy_read(dev, 0x002A);
1147                regstack[4] = b43legacy_phy_read(dev, 0x0035);
1148                regstack[5] = b43legacy_phy_read(dev, 0x0003);
1149                regstack[6] = b43legacy_phy_read(dev, 0x0001);
1150                regstack[7] = b43legacy_phy_read(dev, 0x0030);
1151
1152                regstack[8] = b43legacy_radio_read16(dev, 0x0043);
1153                regstack[9] = b43legacy_radio_read16(dev, 0x007A);
1154                regstack[10] = b43legacy_read16(dev, 0x03EC);
1155                regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0;
1156
1157                b43legacy_phy_write(dev, 0x0030, 0x00FF);
1158                b43legacy_write16(dev, 0x03EC, 0x3F3F);
1159                b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
1160                b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
1161        }
1162        b43legacy_phy_write(dev, 0x0015, 0xB000);
1163        b43legacy_phy_write(dev, 0x002B, 0x0004);
1164
1165        if (phy->radio_ver == 0x2053) {
1166                b43legacy_phy_write(dev, 0x002B, 0x0203);
1167                b43legacy_phy_write(dev, 0x002A, 0x08A3);
1168        }
1169
1170        phy->minlowsig[0] = 0xFFFF;
1171
1172        for (i = 0; i < 4; i++) {
1173                b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
1174                b43legacy_phy_lo_b_r15_loop(dev);
1175        }
1176        for (i = 0; i < 10; i++) {
1177                b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
1178                mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
1179                if (mls < phy->minlowsig[0]) {
1180                        phy->minlowsig[0] = mls;
1181                        phy->minlowsigpos[0] = i;
1182                }
1183        }
1184        b43legacy_radio_write16(dev, 0x0052, regstack[1]
1185                                | phy->minlowsigpos[0]);
1186
1187        phy->minlowsig[1] = 0xFFFF;
1188
1189        for (i = -4; i < 5; i += 2) {
1190                for (j = -4; j < 5; j += 2) {
1191                        if (j < 0)
1192                                fval = (0x0100 * i) + j + 0x0100;
1193                        else
1194                                fval = (0x0100 * i) + j;
1195                        b43legacy_phy_write(dev, 0x002F, fval);
1196                        mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
1197                        if (mls < phy->minlowsig[1]) {
1198                                phy->minlowsig[1] = mls;
1199                                phy->minlowsigpos[1] = fval;
1200                        }
1201                }
1202        }
1203        phy->minlowsigpos[1] += 0x0101;
1204
1205        b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
1206        if (phy->radio_ver == 0x2053) {
1207                b43legacy_phy_write(dev, 0x000A, regstack[2]);
1208                b43legacy_phy_write(dev, 0x002A, regstack[3]);
1209                b43legacy_phy_write(dev, 0x0035, regstack[4]);
1210                b43legacy_phy_write(dev, 0x0003, regstack[5]);
1211                b43legacy_phy_write(dev, 0x0001, regstack[6]);
1212                b43legacy_phy_write(dev, 0x0030, regstack[7]);
1213
1214                b43legacy_radio_write16(dev, 0x0043, regstack[8]);
1215                b43legacy_radio_write16(dev, 0x007A, regstack[9]);
1216
1217                b43legacy_radio_write16(dev, 0x0052,
1218                                        (b43legacy_radio_read16(dev, 0x0052)
1219                                        & 0x000F) | regstack[11]);
1220
1221                b43legacy_write16(dev, 0x03EC, regstack[10]);
1222        }
1223        b43legacy_phy_write(dev, 0x0015, regstack[0]);
1224}
1225
1226static inline
1227u16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev,
1228                                        u16 control)
1229{
1230        struct b43legacy_phy *phy = &dev->phy;
1231        u16 ret;
1232        unsigned long flags;
1233
1234        local_irq_save(flags);
1235        if (phy->gmode) {
1236                b43legacy_phy_write(dev, 0x15, 0xE300);
1237                control <<= 8;
1238                b43legacy_phy_write(dev, 0x0812, control | 0x00B0);
1239                udelay(5);
1240                b43legacy_phy_write(dev, 0x0812, control | 0x00B2);
1241                udelay(2);
1242                b43legacy_phy_write(dev, 0x0812, control | 0x00B3);
1243                udelay(4);
1244                b43legacy_phy_write(dev, 0x0015, 0xF300);
1245                udelay(8);
1246        } else {
1247                b43legacy_phy_write(dev, 0x0015, control | 0xEFA0);
1248                udelay(2);
1249                b43legacy_phy_write(dev, 0x0015, control | 0xEFE0);
1250                udelay(4);
1251                b43legacy_phy_write(dev, 0x0015, control | 0xFFE0);
1252                udelay(8);
1253        }
1254        ret = b43legacy_phy_read(dev, 0x002D);
1255        local_irq_restore(flags);
1256        b43legacy_voluntary_preempt();
1257
1258        return ret;
1259}
1260
1261static u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev,
1262                                              u16 control)
1263{
1264        int i;
1265        u32 ret = 0;
1266
1267        for (i = 0; i < 8; i++)
1268                ret += b43legacy_phy_lo_g_deviation_subval(dev, control);
1269
1270        return ret;
1271}
1272
1273/* Write the LocalOscillator CONTROL */
1274static inline
1275void b43legacy_lo_write(struct b43legacy_wldev *dev,
1276                        struct b43legacy_lopair *pair)
1277{
1278        u16 value;
1279
1280        value = (u8)(pair->low);
1281        value |= ((u8)(pair->high)) << 8;
1282
1283#ifdef CONFIG_B43LEGACY_DEBUG
1284        /* Sanity check. */
1285        if (pair->low < -8 || pair->low > 8 ||
1286            pair->high < -8 || pair->high > 8) {
1287                b43legacydbg(dev->wl,
1288                       "WARNING: Writing invalid LOpair "
1289                       "(low: %d, high: %d)\n",
1290                       pair->low, pair->high);
1291                dump_stack();
1292        }
1293#endif
1294
1295        b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value);
1296}
1297
1298static inline
1299struct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev,
1300                                               u16 bbatt,
1301                                               u16 rfatt,
1302                                               u16 tx)
1303{
1304        static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
1305        struct b43legacy_phy *phy = &dev->phy;
1306
1307        if (bbatt > 6)
1308                bbatt = 6;
1309        B43legacy_WARN_ON(rfatt >= 10);
1310
1311        if (tx == 3)
1312                return b43legacy_get_lopair(phy, rfatt, bbatt);
1313        return b43legacy_get_lopair(phy, dict[rfatt], bbatt);
1314}
1315
1316static inline
1317struct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev)
1318{
1319        struct b43legacy_phy *phy = &dev->phy;
1320
1321        return b43legacy_find_lopair(dev, phy->bbatt,
1322                                     phy->rfatt, phy->txctl1);
1323}
1324
1325/* Adjust B/G LO */
1326void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed)
1327{
1328        struct b43legacy_lopair *pair;
1329
1330        if (fixed) {
1331                /* Use fixed values. Only for initialization. */
1332                pair = b43legacy_find_lopair(dev, 2, 3, 0);
1333        } else
1334                pair = b43legacy_current_lopair(dev);
1335        b43legacy_lo_write(dev, pair);
1336}
1337
1338static void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev)
1339{
1340        struct b43legacy_phy *phy = &dev->phy;
1341        u16 txctl2 = 0;
1342        u16 i;
1343        u32 smallest;
1344        u32 tmp;
1345
1346        b43legacy_radio_write16(dev, 0x0052, 0x0000);
1347        udelay(10);
1348        smallest = b43legacy_phy_lo_g_singledeviation(dev, 0);
1349        for (i = 0; i < 16; i++) {
1350                b43legacy_radio_write16(dev, 0x0052, i);
1351                udelay(10);
1352                tmp = b43legacy_phy_lo_g_singledeviation(dev, 0);
1353                if (tmp < smallest) {
1354                        smallest = tmp;
1355                        txctl2 = i;
1356                }
1357        }
1358        phy->txctl2 = txctl2;
1359}
1360
1361static
1362void b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev,
1363                              const struct b43legacy_lopair *in_pair,
1364                              struct b43legacy_lopair *out_pair,
1365                              u16 r27)
1366{
1367        static const struct b43legacy_lopair transitions[8] = {
1368                { .high =  1,  .low =  1, },
1369                { .high =  1,  .low =  0, },
1370                { .high =  1,  .low = -1, },
1371                { .high =  0,  .low = -1, },
1372                { .high = -1,  .low = -1, },
1373                { .high = -1,  .low =  0, },
1374                { .high = -1,  .low =  1, },
1375                { .high =  0,  .low =  1, },
1376        };
1377        struct b43legacy_lopair lowest_transition = {
1378                .high = in_pair->high,
1379                .low = in_pair->low,
1380        };
1381        struct b43legacy_lopair tmp_pair;
1382        struct b43legacy_lopair transition;
1383        int i = 12;
1384        int state = 0;
1385        int found_lower;
1386        int j;
1387        int begin;
1388        int end;
1389        u32 lowest_deviation;
1390        u32 tmp;
1391
1392        /* Note that in_pair and out_pair can point to the same pair.
1393         * Be careful. */
1394
1395        b43legacy_lo_write(dev, &lowest_transition);
1396        lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27);
1397        do {
1398                found_lower = 0;
1399                B43legacy_WARN_ON(!(state >= 0 && state <= 8));
1400                if (state == 0) {
1401                        begin = 1;
1402                        end = 8;
1403                } else if (state % 2 == 0) {
1404                        begin = state - 1;
1405                        end = state + 1;
1406                } else {
1407                        begin = state - 2;
1408                        end = state + 2;
1409                }
1410                if (begin < 1)
1411                        begin += 8;
1412                if (end > 8)
1413                        end -= 8;
1414
1415                j = begin;
1416                tmp_pair.high = lowest_transition.high;
1417                tmp_pair.low = lowest_transition.low;
1418                while (1) {
1419                        B43legacy_WARN_ON(!(j >= 1 && j <= 8));
1420                        transition.high = tmp_pair.high +
1421                                          transitions[j - 1].high;
1422                        transition.low = tmp_pair.low + transitions[j - 1].low;
1423                        if ((abs(transition.low) < 9)
1424                             && (abs(transition.high) < 9)) {
1425                                b43legacy_lo_write(dev, &transition);
1426                                tmp = b43legacy_phy_lo_g_singledeviation(dev,
1427                                                                       r27);
1428                                if (tmp < lowest_deviation) {
1429                                        lowest_deviation = tmp;
1430                                        state = j;
1431                                        found_lower = 1;
1432
1433                                        lowest_transition.high =
1434                                                                transition.high;
1435                                        lowest_transition.low = transition.low;
1436                                }
1437                        }
1438                        if (j == end)
1439                                break;
1440                        if (j == 8)
1441                                j = 1;
1442                        else
1443                                j++;
1444                }
1445        } while (i-- && found_lower);
1446
1447        out_pair->high = lowest_transition.high;
1448        out_pair->low = lowest_transition.low;
1449}
1450
1451/* Set the baseband attenuation value on chip. */
1452void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
1453                                            u16 bbatt)
1454{
1455        struct b43legacy_phy *phy = &dev->phy;
1456        u16 value;
1457
1458        if (phy->analog == 0) {
1459                value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0);
1460                value |= (bbatt & 0x000F);
1461                b43legacy_write16(dev, 0x03E6, value);
1462                return;
1463        }
1464
1465        if (phy->analog > 1) {
1466                value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3;
1467                value |= (bbatt << 2) & 0x003C;
1468        } else {
1469                value = b43legacy_phy_read(dev, 0x0060) & 0xFF87;
1470                value |= (bbatt << 3) & 0x0078;
1471        }
1472        b43legacy_phy_write(dev, 0x0060, value);
1473}
1474
1475/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
1476void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev)
1477{
1478        static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
1479        const int is_initializing = (b43legacy_status(dev)
1480                                     < B43legacy_STAT_STARTED);
1481        struct b43legacy_phy *phy = &dev->phy;
1482        u16 h;
1483        u16 i;
1484        u16 oldi = 0;
1485        u16 j;
1486        struct b43legacy_lopair control;
1487        struct b43legacy_lopair *tmp_control;
1488        u16 tmp;
1489        u16 regstack[16] = { 0 };
1490        u8 oldchannel;
1491
1492        /* XXX: What are these? */
1493        u8 r27 = 0;
1494        u16 r31;
1495
1496        oldchannel = phy->channel;
1497        /* Setup */
1498        if (phy->gmode) {
1499                regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS);
1500                regstack[1] = b43legacy_phy_read(dev, 0x0802);
1501                b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
1502                                    & 0x7FFF);
1503                b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
1504        }
1505        regstack[3] = b43legacy_read16(dev, 0x03E2);
1506        b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000);
1507        regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
1508        regstack[5] = b43legacy_phy_read(dev, 0x15);
1509        regstack[6] = b43legacy_phy_read(dev, 0x2A);
1510        regstack[7] = b43legacy_phy_read(dev, 0x35);
1511        regstack[8] = b43legacy_phy_read(dev, 0x60);
1512        regstack[9] = b43legacy_radio_read16(dev, 0x43);
1513        regstack[10] = b43legacy_radio_read16(dev, 0x7A);
1514        regstack[11] = b43legacy_radio_read16(dev, 0x52);
1515        if (phy->gmode) {
1516                regstack[12] = b43legacy_phy_read(dev, 0x0811);
1517                regstack[13] = b43legacy_phy_read(dev, 0x0812);
1518                regstack[14] = b43legacy_phy_read(dev, 0x0814);
1519                regstack[15] = b43legacy_phy_read(dev, 0x0815);
1520        }
1521        b43legacy_radio_selectchannel(dev, 6, 0);
1522        if (phy->gmode) {
1523                b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
1524                                    & 0x7FFF);
1525                b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
1526                b43legacy_dummy_transmission(dev);
1527        }
1528        b43legacy_radio_write16(dev, 0x0043, 0x0006);
1529
1530        b43legacy_phy_set_baseband_attenuation(dev, 2);
1531
1532        b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000);
1533        b43legacy_phy_write(dev, 0x002E, 0x007F);
1534        b43legacy_phy_write(dev, 0x080F, 0x0078);
1535        b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7));
1536        b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0);
1537        b43legacy_phy_write(dev, 0x002B, 0x0203);
1538        b43legacy_phy_write(dev, 0x002A, 0x08A3);
1539        if (phy->gmode) {
1540                b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003);
1541                b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC);
1542                b43legacy_phy_write(dev, 0x0811, 0x01B3);
1543                b43legacy_phy_write(dev, 0x0812, 0x00B2);
1544        }
1545        if (is_initializing)
1546                b43legacy_phy_lo_g_measure_txctl2(dev);
1547        b43legacy_phy_write(dev, 0x080F, 0x8078);
1548
1549        /* Measure */
1550        control.low = 0;
1551        control.high = 0;
1552        for (h = 0; h < 10; h++) {
1553                /* Loop over each possible RadioAttenuation (0-9) */
1554                i = pairorder[h];
1555                if (is_initializing) {
1556                        if (i == 3) {
1557                                control.low = 0;
1558                                control.high = 0;
1559                        } else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
1560                                  ((i % 2 == 0) && (oldi % 2 == 0))) {
1561                                tmp_control = b43legacy_get_lopair(phy, oldi,
1562                                                                   0);
1563                                memcpy(&control, tmp_control, sizeof(control));
1564                        } else {
1565                                tmp_control = b43legacy_get_lopair(phy, 3, 0);
1566                                memcpy(&control, tmp_control, sizeof(control));
1567                        }
1568                }
1569                /* Loop over each possible BasebandAttenuation/2 */
1570                for (j = 0; j < 4; j++) {
1571                        if (is_initializing) {
1572                                tmp = i * 2 + j;
1573                                r27 = 0;
1574                                r31 = 0;
1575                                if (tmp > 14) {
1576                                        r31 = 1;
1577                                        if (tmp > 17)
1578                                                r27 = 1;
1579                                        if (tmp > 19)
1580                                                r27 = 2;
1581                                }
1582                        } else {
1583                                tmp_control = b43legacy_get_lopair(phy, i,
1584                                                                   j * 2);
1585                                if (!tmp_control->used)
1586                                        continue;
1587                                memcpy(&control, tmp_control, sizeof(control));
1588                                r27 = 3;
1589                                r31 = 0;
1590                        }
1591                        b43legacy_radio_write16(dev, 0x43, i);
1592                        b43legacy_radio_write16(dev, 0x52, phy->txctl2);
1593                        udelay(10);
1594                        b43legacy_voluntary_preempt();
1595
1596                        b43legacy_phy_set_baseband_attenuation(dev, j * 2);
1597
1598                        tmp = (regstack[10] & 0xFFF0);
1599                        if (r31)
1600                                tmp |= 0x0008;
1601                        b43legacy_radio_write16(dev, 0x007A, tmp);
1602
1603                        tmp_control = b43legacy_get_lopair(phy, i, j * 2);
1604                        b43legacy_phy_lo_g_state(dev, &control, tmp_control,
1605                                                 r27);
1606                }
1607                oldi = i;
1608        }
1609        /* Loop over each possible RadioAttenuation (10-13) */
1610        for (i = 10; i < 14; i++) {
1611                /* Loop over each possible BasebandAttenuation/2 */
1612                for (j = 0; j < 4; j++) {
1613                        if (is_initializing) {
1614                                tmp_control = b43legacy_get_lopair(phy, i - 9,
1615                                                                 j * 2);
1616                                memcpy(&control, tmp_control, sizeof(control));
1617                                /* FIXME: The next line is wrong, as the
1618                                 * following if statement can never trigger. */
1619                                tmp = (i - 9) * 2 + j - 5;
1620                                r27 = 0;
1621                                r31 = 0;
1622                                if (tmp > 14) {
1623                                        r31 = 1;
1624                                        if (tmp > 17)
1625                                                r27 = 1;
1626                                        if (tmp > 19)
1627                                                r27 = 2;
1628                                }
1629                        } else {
1630                                tmp_control = b43legacy_get_lopair(phy, i - 9,
1631                                                                   j * 2);
1632                                if (!tmp_control->used)
1633                                        continue;
1634                                memcpy(&control, tmp_control, sizeof(control));
1635                                r27 = 3;
1636                                r31 = 0;
1637                        }
1638                        b43legacy_radio_write16(dev, 0x43, i - 9);
1639                        /* FIXME: shouldn't txctl1 be zero in the next line
1640                         * and 3 in the loop above? */
1641                        b43legacy_radio_write16(dev, 0x52,
1642                                              phy->txctl2
1643                                              | (3/*txctl1*/ << 4));
1644                        udelay(10);
1645                        b43legacy_voluntary_preempt();
1646
1647                        b43legacy_phy_set_baseband_attenuation(dev, j * 2);
1648
1649                        tmp = (regstack[10] & 0xFFF0);
1650                        if (r31)
1651                                tmp |= 0x0008;
1652                        b43legacy_radio_write16(dev, 0x7A, tmp);
1653
1654                        tmp_control = b43legacy_get_lopair(phy, i, j * 2);
1655                        b43legacy_phy_lo_g_state(dev, &control, tmp_control,
1656                                                 r27);
1657                }
1658        }
1659
1660        /* Restoration */
1661        if (phy->gmode) {
1662                b43legacy_phy_write(dev, 0x0015, 0xE300);
1663                b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0);
1664                udelay(5);
1665                b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2);
1666                udelay(2);
1667                b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3);
1668                b43legacy_voluntary_preempt();
1669        } else
1670                b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0);
1671        b43legacy_phy_lo_adjust(dev, is_initializing);
1672        b43legacy_phy_write(dev, 0x002E, 0x807F);
1673        if (phy->gmode)
1674                b43legacy_phy_write(dev, 0x002F, 0x0202);
1675        else
1676                b43legacy_phy_write(dev, 0x002F, 0x0101);
1677        b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]);
1678        b43legacy_phy_write(dev, 0x0015, regstack[5]);
1679        b43legacy_phy_write(dev, 0x002A, regstack[6]);
1680        b43legacy_phy_write(dev, 0x0035, regstack[7]);
1681        b43legacy_phy_write(dev, 0x0060, regstack[8]);
1682        b43legacy_radio_write16(dev, 0x0043, regstack[9]);
1683        b43legacy_radio_write16(dev, 0x007A, regstack[10]);
1684        regstack[11] &= 0x00F0;
1685        regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F);
1686        b43legacy_radio_write16(dev, 0x52, regstack[11]);
1687        b43legacy_write16(dev, 0x03E2, regstack[3]);
1688        if (phy->gmode) {
1689                b43legacy_phy_write(dev, 0x0811, regstack[12]);
1690                b43legacy_phy_write(dev, 0x0812, regstack[13]);
1691                b43legacy_phy_write(dev, 0x0814, regstack[14]);
1692                b43legacy_phy_write(dev, 0x0815, regstack[15]);
1693                b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]);
1694                b43legacy_phy_write(dev, 0x0802, regstack[1]);
1695        }
1696        b43legacy_radio_selectchannel(dev, oldchannel, 1);
1697
1698#ifdef CONFIG_B43LEGACY_DEBUG
1699        {
1700                /* Sanity check for all lopairs. */
1701                for (i = 0; i < B43legacy_LO_COUNT; i++) {
1702                        tmp_control = phy->_lo_pairs + i;
1703                        if (tmp_control->low < -8 || tmp_control->low > 8 ||
1704                            tmp_control->high < -8 || tmp_control->high > 8)
1705                                b43legacywarn(dev->wl,
1706                                       "WARNING: Invalid LOpair (low: %d, high:"
1707                                       " %d, index: %d)\n",
1708                                       tmp_control->low, tmp_control->high, i);
1709                }
1710        }
1711#endif /* CONFIG_B43LEGACY_DEBUG */
1712}
1713
1714static
1715void b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev)
1716{
1717        struct b43legacy_lopair *pair;
1718
1719        pair = b43legacy_current_lopair(dev);
1720        pair->used = 1;
1721}
1722
1723void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev)
1724{
1725        struct b43legacy_phy *phy = &dev->phy;
1726        struct b43legacy_lopair *pair;
1727        int i;
1728
1729        for (i = 0; i < B43legacy_LO_COUNT; i++) {
1730                pair = phy->_lo_pairs + i;
1731                pair->used = 0;
1732        }
1733}
1734
1735/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
1736 * This function converts a TSSI value to dBm in Q5.2
1737 */
1738static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi)
1739{
1740        struct b43legacy_phy *phy = &dev->phy;
1741        s8 dbm = 0;
1742        s32 tmp;
1743
1744        tmp = phy->idle_tssi;
1745        tmp += tssi;
1746        tmp -= phy->savedpctlreg;
1747
1748        switch (phy->type) {
1749        case B43legacy_PHYTYPE_B:
1750        case B43legacy_PHYTYPE_G:
1751                tmp = clamp_val(tmp, 0x00, 0x3F);
1752                dbm = phy->tssi2dbm[tmp];
1753                break;
1754        default:
1755                B43legacy_BUG_ON(1);
1756        }
1757
1758        return dbm;
1759}
1760
1761/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
1762void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
1763{
1764        struct b43legacy_phy *phy = &dev->phy;
1765        u16 tmp;
1766        u16 txpower;
1767        s8 v0;
1768        s8 v1;
1769        s8 v2;
1770        s8 v3;
1771        s8 average;
1772        int max_pwr;
1773        s16 desired_pwr;
1774        s16 estimated_pwr;
1775        s16 pwr_adjust;
1776        s16 radio_att_delta;
1777        s16 baseband_att_delta;
1778        s16 radio_attenuation;
1779        s16 baseband_attenuation;
1780
1781        if (phy->savedpctlreg == 0xFFFF)
1782                return;
1783        if ((dev->dev->bus->boardinfo.type == 0x0416) &&
1784            is_bcm_board_vendor(dev))
1785                return;
1786#ifdef CONFIG_B43LEGACY_DEBUG
1787        if (phy->manual_txpower_control)
1788                return;
1789#endif
1790
1791        B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
1792                         phy->type == B43legacy_PHYTYPE_G));
1793        tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058);
1794        v0 = (s8)(tmp & 0x00FF);
1795        v1 = (s8)((tmp & 0xFF00) >> 8);
1796        tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A);
1797        v2 = (s8)(tmp & 0x00FF);
1798        v3 = (s8)((tmp & 0xFF00) >> 8);
1799        tmp = 0;
1800
1801        if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
1802                tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1803                                         0x0070);
1804                v0 = (s8)(tmp & 0x00FF);
1805                v1 = (s8)((tmp & 0xFF00) >> 8);
1806                tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1807                                         0x0072);
1808                v2 = (s8)(tmp & 0x00FF);
1809                v3 = (s8)((tmp & 0xFF00) >> 8);
1810                if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
1811                        return;
1812                v0 = (v0 + 0x20) & 0x3F;
1813                v1 = (v1 + 0x20) & 0x3F;
1814                v2 = (v2 + 0x20) & 0x3F;
1815                v3 = (v3 + 0x20) & 0x3F;
1816                tmp = 1;
1817        }
1818        b43legacy_radio_clear_tssi(dev);
1819
1820        average = (v0 + v1 + v2 + v3 + 2) / 4;
1821
1822        if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E)
1823            & 0x8))
1824                average -= 13;
1825
1826        estimated_pwr = b43legacy_phy_estimate_power_out(dev, average);
1827
1828        max_pwr = dev->dev->bus->sprom.maxpwr_bg;
1829
1830        if ((dev->dev->bus->sprom.boardflags_lo
1831             & B43legacy_BFL_PACTRL) &&
1832            (phy->type == B43legacy_PHYTYPE_G))
1833                max_pwr -= 0x3;
1834        if (unlikely(max_pwr <= 0)) {
1835                b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM."
1836                        "\n");
1837                max_pwr = 74; /* fake it */
1838                dev->dev->bus->sprom.maxpwr_bg = max_pwr;
1839        }
1840
1841        /* Use regulatory information to get the maximum power.
1842         * In the absence of such data from mac80211, we will use 20 dBm, which
1843         * is the value for the EU, US, Canada, and most of the world.
1844         * The regulatory maximum is reduced by the antenna gain (from sprom)
1845         * and 1.5 dBm (a safety factor??). The result is in Q5.2 format
1846         * which accounts for the factor of 4 */
1847#define REG_MAX_PWR 20
1848        max_pwr = min(REG_MAX_PWR * 4
1849                      - dev->dev->bus->sprom.antenna_gain.a0
1850                      - 0x6, max_pwr);
1851
1852        /* find the desired power in Q5.2 - power_level is in dBm
1853         * and limit it - max_pwr is already in Q5.2 */
1854        desired_pwr = clamp_val(phy->power_level << 2, 0, max_pwr);
1855        if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
1856                b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
1857                       " dBm, Desired TX power output: " Q52_FMT
1858                       " dBm\n", Q52_ARG(estimated_pwr),
1859                       Q52_ARG(desired_pwr));
1860        /* Check if we need to adjust the current power. The factor of 2 is
1861         * for damping */
1862        pwr_adjust = (desired_pwr - estimated_pwr) / 2;
1863        /* RF attenuation delta
1864         * The minus sign is because lower attenuation => more power */
1865        radio_att_delta = -(pwr_adjust + 7) >> 3;
1866        /* Baseband attenuation delta */
1867        baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
1868        /* Do we need to adjust anything? */
1869        if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
1870                b43legacy_phy_lo_mark_current_used(dev);
1871                return;
1872        }
1873
1874        /* Calculate the new attenuation values. */
1875        baseband_attenuation = phy->bbatt;
1876        baseband_attenuation += baseband_att_delta;
1877        radio_attenuation = phy->rfatt;
1878        radio_attenuation += radio_att_delta;
1879
1880        /* Get baseband and radio attenuation values into permitted ranges.
1881         * baseband 0-11, radio 0-9.
1882         * Radio attenuation affects power level 4 times as much as baseband.
1883         */
1884        if (radio_attenuation < 0) {
1885                baseband_attenuation -= (4 * -radio_attenuation);
1886                radio_attenuation = 0;
1887        } else if (radio_attenuation > 9) {
1888                baseband_attenuation += (4 * (radio_attenuation - 9));
1889                radio_attenuation = 9;
1890        } else {
1891                while (baseband_attenuation < 0 && radio_attenuation > 0) {
1892                        baseband_attenuation += 4;
1893                        radio_attenuation--;
1894                }
1895                while (baseband_attenuation > 11 && radio_attenuation < 9) {
1896                        baseband_attenuation -= 4;
1897                        radio_attenuation++;
1898                }
1899        }
1900        baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
1901
1902        txpower = phy->txctl1;
1903        if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
1904                if (radio_attenuation <= 1) {
1905                        if (txpower == 0) {
1906                                txpower = 3;
1907                                radio_attenuation += 2;
1908                                baseband_attenuation += 2;
1909                        } else if (dev->dev->bus->sprom.boardflags_lo
1910                                   & B43legacy_BFL_PACTRL) {
1911                                baseband_attenuation += 4 *
1912                                                     (radio_attenuation - 2);
1913                                radio_attenuation = 2;
1914                        }
1915                } else if (radio_attenuation > 4 && txpower != 0) {
1916                        txpower = 0;
1917                        if (baseband_attenuation < 3) {
1918                                radio_attenuation -= 3;
1919                                baseband_attenuation += 2;
1920                        } else {
1921                                radio_attenuation -= 2;
1922                                baseband_attenuation -= 2;
1923                        }
1924                }
1925        }
1926        /* Save the control values */
1927        phy->txctl1 = txpower;
1928        baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
1929        radio_attenuation = clamp_val(radio_attenuation, 0, 9);
1930        phy->rfatt = radio_attenuation;
1931        phy->bbatt = baseband_attenuation;
1932
1933        /* Adjust the hardware */
1934        b43legacy_phy_lock(dev);
1935        b43legacy_radio_lock(dev);
1936        b43legacy_radio_set_txpower_bg(dev, baseband_attenuation,
1937                                       radio_attenuation, txpower);
1938        b43legacy_phy_lo_mark_current_used(dev);
1939        b43legacy_radio_unlock(dev);
1940        b43legacy_phy_unlock(dev);
1941}
1942
1943static inline
1944s32 b43legacy_tssi2dbm_ad(s32 num, s32 den)
1945{
1946        if (num < 0)
1947                return num/den;
1948        else
1949                return (num+den/2)/den;
1950}
1951
1952static inline
1953s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
1954{
1955        s32 m1;
1956        s32 m2;
1957        s32 f = 256;
1958        s32 q;
1959        s32 delta;
1960        s8 i = 0;
1961
1962        m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
1963        m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1);
1964        do {
1965                if (i > 15)
1966                        return -EINVAL;
1967                q = b43legacy_tssi2dbm_ad(f * 4096 -
1968                                          b43legacy_tssi2dbm_ad(m2 * f, 16) *
1969                                          f, 2048);
1970                delta = abs(q - f);
1971                f = q;
1972                i++;
1973        } while (delta >= 2);
1974        entry[index] = clamp_val(b43legacy_tssi2dbm_ad(m1 * f, 8192),
1975                                   -127, 128);
1976        return 0;
1977}
1978
1979/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
1980int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev)
1981{
1982        struct b43legacy_phy *phy = &dev->phy;
1983        s16 pab0;
1984        s16 pab1;
1985        s16 pab2;
1986        u8 idx;
1987        s8 *dyn_tssi2dbm;
1988
1989        B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B ||
1990                          phy->type == B43legacy_PHYTYPE_G));
1991        pab0 = (s16)(dev->dev->bus->sprom.pa0b0);
1992        pab1 = (s16)(dev->dev->bus->sprom.pa0b1);
1993        pab2 = (s16)(dev->dev->bus->sprom.pa0b2);
1994
1995        if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
1996                phy->idle_tssi = 0x34;
1997                phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
1998                return 0;
1999        }
2000
2001        if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
2002            pab0 != -1 && pab1 != -1 && pab2 != -1) {
2003                /* The pabX values are set in SPROM. Use them. */
2004                if ((s8)dev->dev->bus->sprom.itssi_bg != 0 &&
2005                    (s8)dev->dev->bus->sprom.itssi_bg != -1)
2006                        phy->idle_tssi = (s8)(dev->dev->bus->sprom.
2007                                          itssi_bg);
2008                else
2009                        phy->idle_tssi = 62;
2010                dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
2011                if (dyn_tssi2dbm == NULL) {
2012                        b43legacyerr(dev->wl, "Could not allocate memory "
2013                               "for tssi2dbm table\n");
2014                        return -ENOMEM;
2015                }
2016                for (idx = 0; idx < 64; idx++)
2017                        if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0,
2018                                                     pab1, pab2)) {
2019                                phy->tssi2dbm = NULL;
2020                                b43legacyerr(dev->wl, "Could not generate "
2021                                       "tssi2dBm table\n");
2022                                kfree(dyn_tssi2dbm);
2023                                return -ENODEV;
2024                        }
2025                phy->tssi2dbm = dyn_tssi2dbm;
2026                phy->dyn_tssi_tbl = 1;
2027        } else {
2028                /* pabX values not set in SPROM. */
2029                switch (phy->type) {
2030                case B43legacy_PHYTYPE_B:
2031                        phy->idle_tssi = 0x34;
2032                        phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
2033                        break;
2034                case B43legacy_PHYTYPE_G:
2035                        phy->idle_tssi = 0x34;
2036                        phy->tssi2dbm = b43legacy_tssi2dbm_g_table;
2037                        break;
2038                }
2039        }
2040
2041        return 0;
2042}
2043
2044int b43legacy_phy_init(struct b43legacy_wldev *dev)
2045{
2046        struct b43legacy_phy *phy = &dev->phy;
2047        int err = -ENODEV;
2048
2049        switch (phy->type) {
2050        case B43legacy_PHYTYPE_B:
2051                switch (phy->rev) {
2052                case 2:
2053                        b43legacy_phy_initb2(dev);
2054                        err = 0;
2055                        break;
2056                case 4:
2057                        b43legacy_phy_initb4(dev);
2058                        err = 0;
2059                        break;
2060                case 5:
2061                        b43legacy_phy_initb5(dev);
2062                        err = 0;
2063                        break;
2064                case 6:
2065                        b43legacy_phy_initb6(dev);
2066                        err = 0;
2067                        break;
2068                }
2069                break;
2070        case B43legacy_PHYTYPE_G:
2071                b43legacy_phy_initg(dev);
2072                err = 0;
2073                break;
2074        }
2075        if (err)
2076                b43legacyerr(dev->wl, "Unknown PHYTYPE found\n");
2077
2078        return err;
2079}
2080
2081void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev)
2082{
2083        struct b43legacy_phy *phy = &dev->phy;
2084        u16 antennadiv;
2085        u16 offset;
2086        u16 value;
2087        u32 ucodeflags;
2088
2089        antennadiv = phy->antenna_diversity;
2090
2091        if (antennadiv == 0xFFFF)
2092                antennadiv = 3;
2093        B43legacy_WARN_ON(antennadiv > 3);
2094
2095        ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
2096                                          B43legacy_UCODEFLAGS_OFFSET);
2097        b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
2098                              B43legacy_UCODEFLAGS_OFFSET,
2099                              ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV);
2100
2101        switch (phy->type) {
2102        case B43legacy_PHYTYPE_G:
2103                offset = 0x0400;
2104
2105                if (antennadiv == 2)
2106                        value = (3/*automatic*/ << 7);
2107                else
2108                        value = (antennadiv << 7);
2109                b43legacy_phy_write(dev, offset + 1,
2110                                    (b43legacy_phy_read(dev, offset + 1)
2111                                    & 0x7E7F) | value);
2112
2113                if (antennadiv >= 2) {
2114                        if (antennadiv == 2)
2115                                value = (antennadiv << 7);
2116                        else
2117                                value = (0/*force0*/ << 7);
2118                        b43legacy_phy_write(dev, offset + 0x2B,
2119                                            (b43legacy_phy_read(dev,
2120                                            offset + 0x2B)
2121                                            & 0xFEFF) | value);
2122                }
2123
2124                if (phy->type == B43legacy_PHYTYPE_G) {
2125                        if (antennadiv >= 2)
2126                                b43legacy_phy_write(dev, 0x048C,
2127                                                    b43legacy_phy_read(dev,
2128                                                    0x048C) | 0x2000);
2129                        else
2130                                b43legacy_phy_write(dev, 0x048C,
2131                                                    b43legacy_phy_read(dev,
2132                                                    0x048C) & ~0x2000);
2133                        if (phy->rev >= 2) {
2134                                b43legacy_phy_write(dev, 0x0461,
2135                                                    b43legacy_phy_read(dev,
2136                                                    0x0461) | 0x0010);
2137                                b43legacy_phy_write(dev, 0x04AD,
2138                                                    (b43legacy_phy_read(dev,
2139                                                    0x04AD)
2140                                                    & 0x00FF) | 0x0015);
2141                                if (phy->rev == 2)
2142                                        b43legacy_phy_write(dev, 0x0427,
2143                                                            0x0008);
2144                                else
2145                                        b43legacy_phy_write(dev, 0x0427,
2146                                                (b43legacy_phy_read(dev, 0x0427)
2147                                                 & 0x00FF) | 0x0008);
2148                        } else if (phy->rev >= 6)
2149                                b43legacy_phy_write(dev, 0x049B, 0x00DC);
2150                } else {
2151                        if (phy->rev < 3)
2152                                b43legacy_phy_write(dev, 0x002B,
2153                                                    (b43legacy_phy_read(dev,
2154                                                    0x002B) & 0x00FF)
2155                                                    | 0x0024);
2156                        else {
2157                                b43legacy_phy_write(dev, 0x0061,
2158                                                    b43legacy_phy_read(dev,
2159                                                    0x0061) | 0x0010);
2160                                if (phy->rev == 3) {
2161                                        b43legacy_phy_write(dev, 0x0093,
2162                                                            0x001D);
2163                                        b43legacy_phy_write(dev, 0x0027,
2164                                                            0x0008);
2165                                } else {
2166                                        b43legacy_phy_write(dev, 0x0093,
2167                                                            0x003A);
2168                                        b43legacy_phy_write(dev, 0x0027,
2169                                                (b43legacy_phy_read(dev, 0x0027)
2170                                                 & 0x00FF) | 0x0008);
2171                                }
2172                        }
2173                }
2174                break;
2175        case B43legacy_PHYTYPE_B:
2176                if (dev->dev->id.revision == 2)
2177                        value = (3/*automatic*/ << 7);
2178                else
2179                        value = (antennadiv << 7);
2180                b43legacy_phy_write(dev, 0x03E2,
2181                                    (b43legacy_phy_read(dev, 0x03E2)
2182                                    & 0xFE7F) | value);
2183                break;
2184        default:
2185                B43legacy_WARN_ON(1);
2186        }
2187
2188        if (antennadiv >= 2) {
2189                ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
2190                                                  B43legacy_UCODEFLAGS_OFFSET);
2191                b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
2192                                      B43legacy_UCODEFLAGS_OFFSET,
2193                                      ucodeflags | B43legacy_UCODEFLAG_AUTODIV);
2194        }
2195
2196        phy->antenna_diversity = antennadiv;
2197}
2198
2199/* Set the PowerSavingControlBits.
2200 * Bitvalues:
2201 *   0  => unset the bit
2202 *   1  => set the bit
2203 *   -1 => calculate the bit
2204 */
2205void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
2206                                     int bit25, int bit26)
2207{
2208        int i;
2209        u32 status;
2210
2211/* FIXME: Force 25 to off and 26 to on for now: */
2212bit25 = 0;
2213bit26 = 1;
2214
2215        if (bit25 == -1) {
2216                /* TODO: If powersave is not off and FIXME is not set and we
2217                 *      are not in adhoc and thus is not an AP and we arei
2218                 *      associated, set bit 25 */
2219        }
2220        if (bit26 == -1) {
2221                /* TODO: If the device is awake or this is an AP, or we are
2222                 *      scanning, or FIXME, or we are associated, or FIXME,
2223                 *      or the latest PS-Poll packet sent was successful,
2224                 *      set bit26  */
2225        }
2226        status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
2227        if (bit25)
2228                status |= B43legacy_MACCTL_HWPS;
2229        else
2230                status &= ~B43legacy_MACCTL_HWPS;
2231        if (bit26)
2232                status |= B43legacy_MACCTL_AWAKE;
2233        else
2234                status &= ~B43legacy_MACCTL_AWAKE;
2235        b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
2236        if (bit26 && dev->dev->id.revision >= 5) {
2237                for (i = 0; i < 100; i++) {
2238                        if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
2239                                                 0x0040) != 4)
2240                                break;
2241                        udelay(10);
2242                }
2243        }
2244}
2245