[PATCH] bcm43xx: add PCI-E code
authorStefano Brivio <stefano.brivio@polimi.it>
Mon, 16 Oct 2006 04:18:11 +0000 (23:18 -0500)
committerJeff Garzik <jeff@garzik.org>
Sat, 2 Dec 2006 05:11:58 +0000 (00:11 -0500)
The current bcm43xx driver does not contain code to handle PCI-E interfaces
such as the BCM4311 and BCM4312. This patch, originally written by Stefano
Brivio adds the necessary code to enable these interfaces.

Signed-off-by: Stefano Brivio <stefano.brivio@polimi.it>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/bcm43xx/bcm43xx.h
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/bcm43xx/bcm43xx_power.c

index 5f43d7f..94dfb92 100644 (file)
 
 /* Chipcommon registers. */
 #define BCM43xx_CHIPCOMMON_CAPABILITIES        0x04
+#define BCM43xx_CHIPCOMMON_CTL                 0x28
 #define BCM43xx_CHIPCOMMON_PLLONDELAY          0xB0
 #define BCM43xx_CHIPCOMMON_FREFSELDELAY                0xB4
 #define BCM43xx_CHIPCOMMON_SLOWCLKCTL          0xB8
 /* SBTOPCI2 values. */
 #define BCM43xx_SBTOPCI2_PREFETCH      0x4
 #define BCM43xx_SBTOPCI2_BURST         0x8
+#define BCM43xx_SBTOPCI2_MEMREAD_MULTI 0x20
+
+/* PCI-E core registers. */
+#define BCM43xx_PCIECORE_REG_ADDR      0x0130
+#define BCM43xx_PCIECORE_REG_DATA      0x0134
+#define BCM43xx_PCIECORE_MDIO_CTL      0x0128
+#define BCM43xx_PCIECORE_MDIO_DATA     0x012C
+
+/* PCI-E registers. */
+#define BCM43xx_PCIE_TLP_WORKAROUND    0x0004
+#define BCM43xx_PCIE_DLLP_LINKCTL      0x0100
+
+/* PCI-E MDIO bits. */
+#define BCM43xx_PCIE_MDIO_ST   0x40000000
+#define BCM43xx_PCIE_MDIO_WT   0x10000000
+#define BCM43xx_PCIE_MDIO_DEV  22
+#define BCM43xx_PCIE_MDIO_REG  18
+#define BCM43xx_PCIE_MDIO_TA   0x00020000
+#define BCM43xx_PCIE_MDIO_TC   0x0100
+
+/* MDIO devices. */
+#define BCM43xx_MDIO_SERDES_RX 0x1F
+
+/* SERDES RX registers. */
+#define BCM43xx_SERDES_RXTIMER 0x2
+#define BCM43xx_SERDES_CDR     0x6
+#define BCM43xx_SERDES_CDR_BW  0x7
 
 /* Chipcommon capabilities. */
 #define BCM43xx_CAPABILITIES_PCTL              0x00040000
 #define BCM43xx_COREID_USB20_HOST       0x819
 #define BCM43xx_COREID_USB20_DEV        0x81a
 #define BCM43xx_COREID_SDIO_HOST        0x81b
+#define BCM43xx_COREID_PCIE            0x820
 
 /* Core Information Registers */
 #define BCM43xx_CIR_BASE               0xf00
index 2ffc0d5..c6bd868 100644 (file)
@@ -130,6 +130,10 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
        { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        /* Broadcom 4307 802.11b */
        { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       /* Broadcom 4311 802.11(a)/b/g */
+       { PCI_VENDOR_ID_BROADCOM, 0x4311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       /* Broadcom 4312 802.11a/b/g */
+       { PCI_VENDOR_ID_BROADCOM, 0x4312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        /* Broadcom 4318 802.11b/g */
        { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        /* Broadcom 4319 802.11a/b/g */
@@ -2600,8 +2604,9 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
        /* fetch sb_id_hi from core information registers */
        sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
 
-       core_id = (sb_id_hi & 0xFFF0) >> 4;
-       core_rev = (sb_id_hi & 0xF);
+       core_id = (sb_id_hi & 0x8FF0) >> 4;
+       core_rev = (sb_id_hi & 0x7000) >> 8;
+       core_rev |= (sb_id_hi & 0xF);
        core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
 
        /* if present, chipcommon is always core 0; read the chipid from it */
@@ -2711,6 +2716,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
                core = NULL;
                switch (core_id) {
                case BCM43xx_COREID_PCI:
+               case BCM43xx_COREID_PCIE:
                        core = &bcm->core_pci;
                        if (core->available) {
                                printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
@@ -2749,12 +2755,12 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
                        case 6:
                        case 7:
                        case 9:
+                       case 10:
                                break;
                        default:
-                               printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
+                               printk(KERN_WARNING PFX
+                                      "Unsupported 80211 core revision %u\n",
                                       core_rev);
-                               err = -ENODEV;
-                               goto out;
                        }
                        bcm->nr_80211_available++;
                        core->priv = ext_80211;
@@ -2868,16 +2874,11 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
        u32 sbimconfiglow;
        u8 limit;
 
-       if (bcm->chip_rev < 5) {
+       if (bcm->core_pci.rev <= 5 && bcm->core_pci.id != BCM43xx_COREID_PCIE) {
                sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
                sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
                sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
-               if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
-                       sbimconfiglow |= 0x32;
-               else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
-                       sbimconfiglow |= 0x53;
-               else
-                       assert(0);
+               sbimconfiglow |= 0x32;
                bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
        }
 
@@ -3004,22 +3005,64 @@ static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
 
 static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
 {
-       int err;
-       struct bcm43xx_coreinfo *old_core;
+       int err = 0;
 
-       old_core = bcm->current_core;
-       err = bcm43xx_switch_core(bcm, &bcm->core_pci);
-       if (err)
-               goto out;
+       bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
 
-       bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
+       if (bcm->core_chipcommon.available) {
+               err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+               if (err)
+                       goto out;
+
+               bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
+
+               /* this function is always called when a PCI core is mapped */
+               err = bcm43xx_switch_core(bcm, &bcm->core_pci);
+               if (err)
+                       goto out;
+       } else
+               bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
+
+       bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
 
-       bcm43xx_switch_core(bcm, old_core);
-       assert(err == 0);
 out:
        return err;
 }
 
+static u32 bcm43xx_pcie_reg_read(struct bcm43xx_private *bcm, u32 address)
+{
+       bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address);
+       return bcm43xx_read32(bcm, BCM43xx_PCIECORE_REG_DATA);
+}
+
+static void bcm43xx_pcie_reg_write(struct bcm43xx_private *bcm, u32 address,
+                                   u32 data)
+{
+       bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address);
+       bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_DATA, data);
+}
+
+static void bcm43xx_pcie_mdio_write(struct bcm43xx_private *bcm, u8 dev, u8 reg,
+                                   u16 data)
+{
+       int i;
+
+       bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0x0082);
+       bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_DATA, BCM43xx_PCIE_MDIO_ST |
+                       BCM43xx_PCIE_MDIO_WT | (dev << BCM43xx_PCIE_MDIO_DEV) |
+                       (reg << BCM43xx_PCIE_MDIO_REG) | BCM43xx_PCIE_MDIO_TA |
+                       data);
+       udelay(10);
+
+       for (i = 0; i < 10; i++) {
+               if (bcm43xx_read32(bcm, BCM43xx_PCIECORE_MDIO_CTL) &
+                   BCM43xx_PCIE_MDIO_TC)
+                       break;
+               msleep(1);
+       }
+       bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0);
+}
+
 /* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
  * To enable core 0, pass a core_mask of 1<<0
  */
@@ -3039,7 +3082,8 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
        if (err)
                goto out;
 
-       if (bcm->core_pci.rev < 6) {
+       if (bcm->current_core->rev < 6 ||
+               bcm->current_core->id == BCM43xx_COREID_PCI) {
                value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
                value |= (1 << backplane_flag_nr);
                bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
@@ -3057,21 +3101,46 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
                }
        }
 
-       value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
-       value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
-       bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
-
-       if (bcm->core_pci.rev < 5) {
-               value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
-               value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
-                        & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
-               value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
-                        & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
-               bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
-               err = bcm43xx_pcicore_commit_settings(bcm);
-               assert(err == 0);
+       if (bcm->current_core->id == BCM43xx_COREID_PCI) {
+               value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
+               value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
+               bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
+
+               if (bcm->current_core->rev < 5) {
+                       value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
+                       value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
+                                & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
+                       value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
+                                & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
+                       bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
+                       err = bcm43xx_pcicore_commit_settings(bcm);
+                       assert(err == 0);
+               } else if (bcm->current_core->rev >= 11) {
+                       value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
+                       value |= BCM43xx_SBTOPCI2_MEMREAD_MULTI;
+                       bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
+               }
+       } else {
+               if (bcm->current_core->rev == 0 || bcm->current_core->rev == 1) {
+                       value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_TLP_WORKAROUND);
+                       value |= 0x8;
+                       bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_TLP_WORKAROUND,
+                                              value);
+               }
+               if (bcm->current_core->rev == 0) {
+                       bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX,
+                                               BCM43xx_SERDES_RXTIMER, 0x8128);
+                       bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX,
+                                               BCM43xx_SERDES_CDR, 0x0100);
+                       bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX,
+                                               BCM43xx_SERDES_CDR_BW, 0x1466);
+               } else if (bcm->current_core->rev == 1) {
+                       value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_DLLP_LINKCTL);
+                       value |= 0x40;
+                       bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_DLLP_LINKCTL,
+                                              value);
+               }
        }
-
 out_switch_back:
        err = bcm43xx_switch_core(bcm, old_core);
 out:
@@ -3676,7 +3745,7 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
                bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
                break;
        case BCM43xx_PHYTYPE_G:
-               if (phy_rev > 7)
+               if (phy_rev > 8)
                        phy_rev_ok = 0;
                bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
                                        IEEE80211_CCK_MODULATION;
index 6569da3..7e774f4 100644 (file)
@@ -153,8 +153,6 @@ int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
        int err, maxfreq;
        struct bcm43xx_coreinfo *old_core;
 
-       if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
-               return 0;
        old_core = bcm->current_core;
        err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
        if (err == -ENODEV)
@@ -162,11 +160,27 @@ int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
        if (err)
                goto out;
 
-       maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
-       bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
-                       (maxfreq * 150 + 999999) / 1000000);
-       bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
-                       (maxfreq * 15 + 999999) / 1000000);
+       if (bcm->chip_id == 0x4321) {
+               if (bcm->chip_rev == 0)
+                       bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x03A4);
+               if (bcm->chip_rev == 1)
+                       bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x00A4);
+       }
+
+       if (bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) {
+               if (bcm->current_core->rev >= 10) {
+                       /* Set Idle Power clock rate to 1Mhz */
+                       bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL,
+                                      (bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL)
+                                      & 0x0000FFFF) | 0x40000);
+               } else {
+                       maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
+                       bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
+                                      (maxfreq * 150 + 999999) / 1000000);
+                       bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
+                                      (maxfreq * 15 + 999999) / 1000000);
+               }
+       }
 
        err = bcm43xx_switch_core(bcm, old_core);
        assert(err == 0);