[PATCH] bcm43xx: Change initialization for 2050 radios
authorLarry Finger <Larry.Finger@lwfinger.net>
Wed, 28 Mar 2007 16:07:49 +0000 (11:07 -0500)
committerJeff Garzik <jeff@garzik.org>
Sat, 28 Apr 2007 15:01:03 +0000 (11:01 -0400)
This patch implements the changes in the specifications for
2050radio_init that were recently posted.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/bcm43xx/bcm43xx_phy.c
drivers/net/wireless/bcm43xx/bcm43xx_phy.h
drivers/net/wireless/bcm43xx/bcm43xx_radio.c

index c47e19a..b37f1e3 100644 (file)
@@ -300,16 +300,20 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)
 
        if (phy->rev > 2) {
                bcm43xx_phy_write(bcm, 0x0422, 0x287A);
-               bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); 
+               bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420)
+                                 & 0x0FFF) | 0x3000);
        }
                
-       bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
+       bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080)
+                                       | 0x7874);
        bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
 
        if (phy->rev == 1) {
-               bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
+               bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB)
+                                 & 0xF0FF) | 0x0600);
                bcm43xx_phy_write(bcm, 0x048B, 0x005E);
-               bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
+               bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C)
+                                 & 0xFF00) | 0x001E);
                bcm43xx_phy_write(bcm, 0x048D, 0x0002);
        }
 
@@ -335,7 +339,8 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
        if (phy->rev == 1) {
                bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
                bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
-                                 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
+                                 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+                                 & 0xFC3F) | 0x0340);
                bcm43xx_phy_write(bcm, 0x042C, 0x005A);
                bcm43xx_phy_write(bcm, 0x0427, 0x001A);
 
index 1f321ef..7311836 100644 (file)
@@ -48,6 +48,10 @@ void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm);
                local_irq_restore(flags);       \
        } while (0)
 
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+        (((phy)->rev > 1) || ((phy)->connected))
+
 u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
 void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
 
index 4025dd0..6a109f4 100644 (file)
@@ -1343,11 +1343,110 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
        return ret;
 }
 
+#define LPD(L, P, D)    (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd)
+{
+       struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+       struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+       u16 loop_or = 0;
+       u16 adj_loopback_gain = phy->loopback_gain[0];
+       u8 loop;
+       u16 extern_lna_control;
+
+       if (!phy->connected)
+               return 0;
+       if (!has_loopback_gain(phy)) {
+               if (phy->rev < 7 || !(bcm->sprom.boardflags
+                   & BCM43xx_BFL_EXTLNA)) {
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x0FB2;
+                       case LPD(0, 0, 1):
+                               return 0x00B2;
+                       case LPD(1, 0, 1):
+                               return 0x30B2;
+                       case LPD(1, 0, 0):
+                               return 0x30B3;
+                       default:
+                               assert(0);
+                       }
+               } else {
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x8FB2;
+                       case LPD(0, 0, 1):
+                               return 0x80B2;
+                       case LPD(1, 0, 1):
+                               return 0x20B2;
+                       case LPD(1, 0, 0):
+                               return 0x20B3;
+                       default:
+                               assert(0);
+                       }
+               }
+       } else {
+               if (radio->revision == 8)
+                       adj_loopback_gain += 0x003E;
+               else
+                       adj_loopback_gain += 0x0026;
+               if (adj_loopback_gain >= 0x46) {
+                       adj_loopback_gain -= 0x46;
+                       extern_lna_control = 0x3000;
+               } else if (adj_loopback_gain >= 0x3A) {
+                       adj_loopback_gain -= 0x3A;
+                       extern_lna_control = 0x2000;
+               } else if (adj_loopback_gain >= 0x2E) {
+                       adj_loopback_gain -= 0x2E;
+                       extern_lna_control = 0x1000;
+               } else {
+                       adj_loopback_gain -= 0x10;
+                       extern_lna_control = 0x0000;
+               }
+               for (loop = 0; loop < 16; loop++) {
+                       u16 tmp = adj_loopback_gain - 6 * loop;
+                       if (tmp < 6)
+                               break;
+               }
+
+               loop_or = (loop << 8) | extern_lna_control;
+               if (phy->rev >= 7 && bcm->sprom.boardflags
+                   & BCM43xx_BFL_EXTLNA) {
+                       if (extern_lna_control)
+                               loop_or |= 0x8000;
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x8F92;
+                       case LPD(0, 0, 1):
+                               return (0x8092 | loop_or);
+                       case LPD(1, 0, 1):
+                               return (0x2092 | loop_or);
+                       case LPD(1, 0, 0):
+                               return (0x2093 | loop_or);
+                       default:
+                               assert(0);
+                       }
+               } else {
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x0F92;
+                       case LPD(0, 0, 1):
+                       case LPD(1, 0, 1):
+                               return (0x0092 | loop_or);
+                       case LPD(1, 0, 0):
+                               return (0x0093 | loop_or);
+                       default:
+                               assert(0);
+                       }
+               }
+       }
+       return 0;
+}
+
 u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
-       u16 backup[19] = { 0 };
+       u16 backup[21] = { 0 };
        u16 ret;
        u16 i, j;
        u32 tmp1 = 0, tmp2 = 0;
@@ -1373,19 +1472,36 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                        backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
                        backup[9] = bcm43xx_phy_read(bcm, 0x0802);
                        bcm43xx_phy_write(bcm, 0x0814,
-                                         (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
+                                         (bcm43xx_phy_read(bcm, 0x0814)
+                                         | 0x0003));
                        bcm43xx_phy_write(bcm, 0x0815,
-                                         (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));    
+                                         (bcm43xx_phy_read(bcm, 0x0815)
+                                         & 0xFFFC));
                        bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
-                                         (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
+                                         (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+                                         & 0x7FFF));
                        bcm43xx_phy_write(bcm, 0x0802,
                                          (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
-                       bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
-                       bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
+                       if (phy->rev > 1) { /* loopback gain enabled */
+                               backup[19] = bcm43xx_phy_read(bcm, 0x080F);
+                               backup[20] = bcm43xx_phy_read(bcm, 0x0810);
+                               if (phy->rev >= 3)
+                                       bcm43xx_phy_write(bcm, 0x080F, 0xC020);
+                               else
+                                       bcm43xx_phy_write(bcm, 0x080F, 0x8020);
+                               bcm43xx_phy_write(bcm, 0x0810, 0x0000);
+                       }
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
+                       if (phy->rev < 7 || !(bcm->sprom.boardflags
+                           & BCM43xx_BFL_EXTLNA))
+                               bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+                       else
+                               bcm43xx_phy_write(bcm, 0x0811, 0x09B3);
                }
-               bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
-                               (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
        }
+       bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+                       (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
        backup[10] = bcm43xx_phy_read(bcm, 0x0035);
        bcm43xx_phy_write(bcm, 0x0035,
                          (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
@@ -1397,10 +1513,12 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                bcm43xx_write16(bcm, 0x03E6, 0x0122);
        } else {
                if (phy->analog >= 2)
-                       bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003)
-                                       & 0xFFBF) | 0x0040);
+                       bcm43xx_phy_write(bcm, 0x0003,
+                                         (bcm43xx_phy_read(bcm, 0x0003)
+                                         & 0xFFBF) | 0x0040);
                bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
-                               (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
+                               (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+                               | 0x2000));
        }
 
        ret = bcm43xx_radio_calibrationvalue(bcm);
@@ -1408,16 +1526,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
        if (phy->type == BCM43xx_PHYTYPE_B)
                bcm43xx_radio_write16(bcm, 0x0078, 0x0026);
 
+       if (phy->connected)
+               bcm43xx_phy_write(bcm, 0x0812,
+                                 bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
        bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
        bcm43xx_phy_write(bcm, 0x002B, 0x1403);
        if (phy->connected)
-               bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+               bcm43xx_phy_write(bcm, 0x0812,
+                                 bcm43xx_get_812_value(bcm, LPD(0, 0, 1)));
        bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
        bcm43xx_radio_write16(bcm, 0x0051,
                              (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
-       bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
-       bcm43xx_radio_write16(bcm, 0x0043,
-                             (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009);
+       if (radio->revision == 8)
+               bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
+       else {
+               bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+               bcm43xx_radio_write16(bcm, 0x0043,
+                                     (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0)
+                                     | 0x0009);
+       }
        bcm43xx_phy_write(bcm, 0x0058, 0x0000);
 
        for (i = 0; i < 16; i++) {
@@ -1425,21 +1552,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x0059, 0xC810);
                bcm43xx_phy_write(bcm, 0x0058, 0x000D);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
                bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
                udelay(10);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
                bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
                udelay(10);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 0)));
                bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
-               udelay(10);
+               udelay(20);
                tmp1 += bcm43xx_phy_read(bcm, 0x002D);
                bcm43xx_phy_write(bcm, 0x0058, 0x0000);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
                bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
        }
 
@@ -1457,21 +1588,29 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                        bcm43xx_phy_write(bcm, 0x0059, 0xC810);
                        bcm43xx_phy_write(bcm, 0x0058, 0x000D);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 1)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
                        udelay(10);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 1)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
                        udelay(10);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 0)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
                        udelay(10);
                        tmp2 += bcm43xx_phy_read(bcm, 0x002D);
                        bcm43xx_phy_write(bcm, 0x0058, 0x0000);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 1)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
                }
                tmp2++;
@@ -1497,15 +1636,20 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x0030, backup[2]);
                bcm43xx_write16(bcm, 0x03EC, backup[3]);
        } else {
-               bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
-                               (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
                if (phy->connected) {
+                       bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+                                       (bcm43xx_read16(bcm,
+                                       BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
                        bcm43xx_phy_write(bcm, 0x0811, backup[4]);
                        bcm43xx_phy_write(bcm, 0x0812, backup[5]);
                        bcm43xx_phy_write(bcm, 0x0814, backup[6]);
                        bcm43xx_phy_write(bcm, 0x0815, backup[7]);
                        bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
                        bcm43xx_phy_write(bcm, 0x0802, backup[9]);
+                       if (phy->rev > 1) {
+                               bcm43xx_phy_write(bcm, 0x080F, backup[19]);
+                               bcm43xx_phy_write(bcm, 0x0810, backup[20]);
+                       }
                }
        }
        if (i >= 15)