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

[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
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -159,6 +159,7 @@

/* 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
@@ -172,6 +173,33 @@
/* 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
@@ -221,6 +249,7 @@
#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
+106 −37
Original line number Diff line number Diff line
@@ -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);
		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);
	bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);

	if (bcm->core_chipcommon.available) {
		err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
		if (err)
			goto out;

		bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);

	bcm43xx_switch_core(bcm, old_core);
	assert(err == 0);
		/* 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);

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,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_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
		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 |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
				 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
@@ -3070,8 +3115,32 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
			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;
+21 −7
Original line number Diff line number Diff line
@@ -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;

	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);