Commit f3d1fca3 authored by Stefano Brivio's avatar Stefano Brivio Committed by Jeff Garzik

[PATCH] bcm43xx: add PCI-E code

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: default avatarStefano Brivio <stefano.brivio@polimi.it>
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 995cdaa4
...@@ -159,6 +159,7 @@ ...@@ -159,6 +159,7 @@
/* Chipcommon registers. */ /* Chipcommon registers. */
#define BCM43xx_CHIPCOMMON_CAPABILITIES 0x04 #define BCM43xx_CHIPCOMMON_CAPABILITIES 0x04
#define BCM43xx_CHIPCOMMON_CTL 0x28
#define BCM43xx_CHIPCOMMON_PLLONDELAY 0xB0 #define BCM43xx_CHIPCOMMON_PLLONDELAY 0xB0
#define BCM43xx_CHIPCOMMON_FREFSELDELAY 0xB4 #define BCM43xx_CHIPCOMMON_FREFSELDELAY 0xB4
#define BCM43xx_CHIPCOMMON_SLOWCLKCTL 0xB8 #define BCM43xx_CHIPCOMMON_SLOWCLKCTL 0xB8
...@@ -172,6 +173,33 @@ ...@@ -172,6 +173,33 @@
/* SBTOPCI2 values. */ /* SBTOPCI2 values. */
#define BCM43xx_SBTOPCI2_PREFETCH 0x4 #define BCM43xx_SBTOPCI2_PREFETCH 0x4
#define BCM43xx_SBTOPCI2_BURST 0x8 #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. */ /* Chipcommon capabilities. */
#define BCM43xx_CAPABILITIES_PCTL 0x00040000 #define BCM43xx_CAPABILITIES_PCTL 0x00040000
...@@ -221,6 +249,7 @@ ...@@ -221,6 +249,7 @@
#define BCM43xx_COREID_USB20_HOST 0x819 #define BCM43xx_COREID_USB20_HOST 0x819
#define BCM43xx_COREID_USB20_DEV 0x81a #define BCM43xx_COREID_USB20_DEV 0x81a
#define BCM43xx_COREID_SDIO_HOST 0x81b #define BCM43xx_COREID_SDIO_HOST 0x81b
#define BCM43xx_COREID_PCIE 0x820
/* Core Information Registers */ /* Core Information Registers */
#define BCM43xx_CIR_BASE 0xf00 #define BCM43xx_CIR_BASE 0xf00
......
...@@ -130,6 +130,10 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); ...@@ -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 }, { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
/* Broadcom 4307 802.11b */ /* Broadcom 4307 802.11b */
{ PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 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 */ /* Broadcom 4318 802.11b/g */
{ PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
/* Broadcom 4319 802.11a/b/g */ /* Broadcom 4319 802.11a/b/g */
...@@ -2600,8 +2604,9 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) ...@@ -2600,8 +2604,9 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
/* fetch sb_id_hi from core information registers */ /* fetch sb_id_hi from core information registers */
sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
core_id = (sb_id_hi & 0xFFF0) >> 4; core_id = (sb_id_hi & 0x8FF0) >> 4;
core_rev = (sb_id_hi & 0xF); core_rev = (sb_id_hi & 0x7000) >> 8;
core_rev |= (sb_id_hi & 0xF);
core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
/* if present, chipcommon is always core 0; read the chipid from it */ /* 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) ...@@ -2711,6 +2716,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
core = NULL; core = NULL;
switch (core_id) { switch (core_id) {
case BCM43xx_COREID_PCI: case BCM43xx_COREID_PCI:
case BCM43xx_COREID_PCIE:
core = &bcm->core_pci; core = &bcm->core_pci;
if (core->available) { if (core->available) {
printk(KERN_WARNING PFX "Multiple PCI cores found.\n"); printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
...@@ -2749,12 +2755,12 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) ...@@ -2749,12 +2755,12 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
case 6: case 6:
case 7: case 7:
case 9: case 9:
case 10:
break; break;
default: default:
printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n", printk(KERN_WARNING PFX
"Unsupported 80211 core revision %u\n",
core_rev); core_rev);
err = -ENODEV;
goto out;
} }
bcm->nr_80211_available++; bcm->nr_80211_available++;
core->priv = ext_80211; core->priv = ext_80211;
...@@ -2868,16 +2874,11 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm, ...@@ -2868,16 +2874,11 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
u32 sbimconfiglow; u32 sbimconfiglow;
u8 limit; 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_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
sbimconfiglow |= 0x32; sbimconfiglow |= 0x32;
else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
sbimconfiglow |= 0x53;
else
assert(0);
bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow); bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
} }
...@@ -3004,22 +3005,64 @@ static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, ...@@ -3004,22 +3005,64 @@ static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm) static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
{ {
int err; int err = 0;
struct bcm43xx_coreinfo *old_core;
old_core = bcm->current_core; bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
err = bcm43xx_switch_core(bcm, &bcm->core_pci);
if (bcm->core_chipcommon.available) {
err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
if (err) if (err)
goto out; goto out;
bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
bcm43xx_switch_core(bcm, old_core); /* this function is always called when a PCI core is mapped */
assert(err == 0); 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);
out: out:
return err; 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. /* 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 * 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, ...@@ -3039,7 +3082,8 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
if (err) if (err)
goto out; 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 = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
value |= (1 << backplane_flag_nr); value |= (1 << backplane_flag_nr);
bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value); bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
...@@ -3057,11 +3101,12 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, ...@@ -3057,11 +3101,12 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
} }
} }
if (bcm->current_core->id == BCM43xx_COREID_PCI) {
value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST; value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
if (bcm->core_pci.rev < 5) { if (bcm->current_core->rev < 5) {
value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT) value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
& BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
...@@ -3070,8 +3115,32 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, ...@@ -3070,8 +3115,32 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value); bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
err = bcm43xx_pcicore_commit_settings(bcm); err = bcm43xx_pcicore_commit_settings(bcm);
assert(err == 0); 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: out_switch_back:
err = bcm43xx_switch_core(bcm, old_core); err = bcm43xx_switch_core(bcm, old_core);
out: out:
...@@ -3676,7 +3745,7 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) ...@@ -3676,7 +3745,7 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
break; break;
case BCM43xx_PHYTYPE_G: case BCM43xx_PHYTYPE_G:
if (phy_rev > 7) if (phy_rev > 8)
phy_rev_ok = 0; phy_rev_ok = 0;
bcm->ieee->modulation = IEEE80211_OFDM_MODULATION | bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
IEEE80211_CCK_MODULATION; IEEE80211_CCK_MODULATION;
......
...@@ -153,8 +153,6 @@ int bcm43xx_pctl_init(struct bcm43xx_private *bcm) ...@@ -153,8 +153,6 @@ int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
int err, maxfreq; int err, maxfreq;
struct bcm43xx_coreinfo *old_core; struct bcm43xx_coreinfo *old_core;
if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
return 0;
old_core = bcm->current_core; old_core = bcm->current_core;
err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
if (err == -ENODEV) if (err == -ENODEV)
...@@ -162,11 +160,27 @@ int bcm43xx_pctl_init(struct bcm43xx_private *bcm) ...@@ -162,11 +160,27 @@ int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
if (err) if (err)
goto out; goto out;
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); maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY, bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
(maxfreq * 150 + 999999) / 1000000); (maxfreq * 150 + 999999) / 1000000);
bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY, bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
(maxfreq * 15 + 999999) / 1000000); (maxfreq * 15 + 999999) / 1000000);
}
}
err = bcm43xx_switch_core(bcm, old_core); err = bcm43xx_switch_core(bcm, old_core);
assert(err == 0); assert(err == 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment