summaryrefslogtreecommitdiff
path: root/drivers/ssb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ssb')
-rw-r--r--drivers/ssb/driver_chipcommon.c68
-rw-r--r--drivers/ssb/driver_chipcommon_pmu.c2
-rw-r--r--drivers/ssb/driver_pcicore.c255
-rw-r--r--drivers/ssb/main.c54
-rw-r--r--drivers/ssb/scan.c7
5 files changed, 286 insertions, 100 deletions
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 7c031fdc820..06d15b6f221 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
if (!ccdev)
return;
bus = ccdev->bus;
+
+ /* We support SLOW only on 6..9 */
+ if (ccdev->id.revision >= 10 && mode == SSB_CLKMODE_SLOW)
+ mode = SSB_CLKMODE_DYNAMIC;
+
+ if (cc->capabilities & SSB_CHIPCO_CAP_PMU)
+ return; /* PMU controls clockmode, separated function needed */
+ SSB_WARN_ON(ccdev->id.revision >= 20);
+
/* chipcommon cores prior to rev6 don't support dynamic clock control */
if (ccdev->id.revision < 6)
return;
- /* chipcommon cores rev10 are a whole new ball game */
+
+ /* ChipCommon cores rev10+ need testing */
if (ccdev->id.revision >= 10)
return;
+
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
return;
switch (mode) {
- case SSB_CLKMODE_SLOW:
+ case SSB_CLKMODE_SLOW: /* For revs 6..9 only */
tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW;
chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
break;
case SSB_CLKMODE_FAST:
- ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
- tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
- tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
- tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
- chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+ if (ccdev->id.revision < 10) {
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+ tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
+ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+ } else {
+ chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
+ (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) |
+ SSB_CHIPCO_SYSCLKCTL_FORCEHT));
+ /* udelay(150); TODO: not available in early init */
+ }
break;
case SSB_CLKMODE_DYNAMIC:
- tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
- tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
- tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
- tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
- if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
- tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
- chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
-
- /* for dynamic control, we have to release our xtal_pu "force on" */
- if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
- ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
+ if (ccdev->id.revision < 10) {
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+ if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) !=
+ SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
+ tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+
+ /* For dynamic control, we have to release our xtal_pu
+ * "force on" */
+ if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
+ } else {
+ chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
+ (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) &
+ ~SSB_CHIPCO_SYSCLKCTL_FORCEHT));
+ }
break;
default:
SSB_WARN_ON(1);
@@ -260,6 +286,12 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
if (cc->dev->id.revision >= 11)
cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
+
+ if (cc->dev->id.revision >= 20) {
+ chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0);
+ chipco_write32(cc, SSB_CHIPCO_GPIOPULLDOWN, 0);
+ }
+
ssb_pmu_init(cc);
chipco_powercontrol_init(cc);
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 5732bb2c357..305ade7825f 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -423,6 +423,8 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
switch (bus->chip_id) {
case 0x4312:
+ min_msk = 0xCBB;
+ break;
case 0x4322:
/* We keep the default settings:
* min_msk = 0xCBB
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 0e8d3522461..82feb348c8b 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -15,6 +15,11 @@
#include "ssb_private.h"
+static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address);
+static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data);
+static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address);
+static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
+ u8 address, u16 data);
static inline
u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
@@ -403,6 +408,107 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
}
#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
+/**************************************************
+ * Workarounds.
+ **************************************************/
+
+static void ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc)
+{
+ u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0));
+ if (((tmp & 0xF000) >> 12) != pc->dev->core_index) {
+ tmp &= ~0xF000;
+ tmp |= (pc->dev->core_index << 12);
+ pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp);
+ }
+}
+
+static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc)
+{
+ return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
+}
+
+static void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc)
+{
+ const u8 serdes_pll_device = 0x1D;
+ const u8 serdes_rx_device = 0x1F;
+ u16 tmp;
+
+ ssb_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
+ ssb_pcicore_polarity_workaround(pc));
+ tmp = ssb_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
+ if (tmp & 0x4000)
+ ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
+}
+
+static void ssb_pcicore_pci_setup_workarounds(struct ssb_pcicore *pc)
+{
+ struct ssb_device *pdev = pc->dev;
+ struct ssb_bus *bus = pdev->bus;
+ u32 tmp;
+
+ tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+ tmp |= SSB_PCICORE_SBTOPCI_PREF;
+ tmp |= SSB_PCICORE_SBTOPCI_BURST;
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+
+ if (pdev->id.revision < 5) {
+ tmp = ssb_read32(pdev, SSB_IMCFGLO);
+ tmp &= ~SSB_IMCFGLO_SERTO;
+ tmp |= 2;
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
+ ssb_write32(pdev, SSB_IMCFGLO, tmp);
+ ssb_commit_settings(bus);
+ } else if (pdev->id.revision >= 11) {
+ tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+ tmp |= SSB_PCICORE_SBTOPCI_MRM;
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+ }
+}
+
+static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc)
+{
+ u32 tmp;
+ u8 rev = pc->dev->id.revision;
+
+ if (rev == 0 || rev == 1) {
+ /* TLP Workaround register. */
+ tmp = ssb_pcie_read(pc, 0x4);
+ tmp |= 0x8;
+ ssb_pcie_write(pc, 0x4, tmp);
+ }
+ if (rev == 1) {
+ /* DLLP Link Control register. */
+ tmp = ssb_pcie_read(pc, 0x100);
+ tmp |= 0x40;
+ ssb_pcie_write(pc, 0x100, tmp);
+ }
+
+ if (rev == 0) {
+ const u8 serdes_rx_device = 0x1F;
+
+ ssb_pcie_mdio_write(pc, serdes_rx_device,
+ 2 /* Timer */, 0x8128);
+ ssb_pcie_mdio_write(pc, serdes_rx_device,
+ 6 /* CDR */, 0x0100);
+ ssb_pcie_mdio_write(pc, serdes_rx_device,
+ 7 /* CDR BW */, 0x1466);
+ } else if (rev == 3 || rev == 4 || rev == 5) {
+ /* TODO: DLLP Power Management Threshold */
+ ssb_pcicore_serdes_workaround(pc);
+ /* TODO: ASPM */
+ } else if (rev == 7) {
+ /* TODO: No PLL down */
+ }
+
+ if (rev >= 6) {
+ /* Miscellaneous Configuration Fixup */
+ tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(5));
+ if (!(tmp & 0x8000))
+ pcicore_write16(pc, SSB_PCICORE_SPROM(5),
+ tmp | 0x8000);
+ }
+}
/**************************************************
* Generic and Clientmode operation code.
@@ -417,14 +523,14 @@ static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
void ssb_pcicore_init(struct ssb_pcicore *pc)
{
struct ssb_device *dev = pc->dev;
- struct ssb_bus *bus;
if (!dev)
return;
- bus = dev->bus;
if (!ssb_device_is_enabled(dev))
ssb_device_enable(dev, 0);
+ ssb_pcicore_fix_sprom_core_index(pc);
+
#ifdef CONFIG_SSB_PCICORE_HOSTMODE
pc->hostmode = pcicore_is_in_hostmode(pc);
if (pc->hostmode)
@@ -432,6 +538,11 @@ void ssb_pcicore_init(struct ssb_pcicore *pc)
#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
if (!pc->hostmode)
ssb_pcicore_init_clientmode(pc);
+
+ /* Additional always once-executed workarounds */
+ ssb_pcicore_serdes_workaround(pc);
+ /* TODO: ASPM */
+ /* TODO: Clock Request Update */
}
static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
@@ -446,58 +557,104 @@ static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data)
pcicore_write32(pc, 0x134, data);
}
-static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
- u8 address, u16 data)
+static void ssb_pcie_mdio_set_phy(struct ssb_pcicore *pc, u8 phy)
{
const u16 mdio_control = 0x128;
const u16 mdio_data = 0x12C;
u32 v;
int i;
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 28); /* Write Transaction */
+ v |= (1 << 17); /* Turnaround */
+ v |= (0x1F << 18);
+ v |= (phy << 4);
+ pcicore_write32(pc, mdio_data, v);
+
+ udelay(10);
+ for (i = 0; i < 200; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */)
+ break;
+ msleep(1);
+ }
+}
+
+static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address)
+{
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ int max_retries = 10;
+ u16 ret = 0;
+ u32 v;
+ int i;
+
v = 0x80; /* Enable Preamble Sequence */
v |= 0x2; /* MDIO Clock Divisor */
pcicore_write32(pc, mdio_control, v);
+ if (pc->dev->id.revision >= 10) {
+ max_retries = 200;
+ ssb_pcie_mdio_set_phy(pc, device);
+ }
+
v = (1 << 30); /* Start of Transaction */
- v |= (1 << 28); /* Write Transaction */
+ v |= (1 << 29); /* Read Transaction */
v |= (1 << 17); /* Turnaround */
- v |= (u32)device << 22;
+ if (pc->dev->id.revision < 10)
+ v |= (u32)device << 22;
v |= (u32)address << 18;
- v |= data;
pcicore_write32(pc, mdio_data, v);
/* Wait for the device to complete the transaction */
udelay(10);
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < max_retries; i++) {
v = pcicore_read32(pc, mdio_control);
- if (v & 0x100 /* Trans complete */)
+ if (v & 0x100 /* Trans complete */) {
+ udelay(10);
+ ret = pcicore_read32(pc, mdio_data);
break;
+ }
msleep(1);
}
pcicore_write32(pc, mdio_control, 0);
+ return ret;
}
-static void ssb_broadcast_value(struct ssb_device *dev,
- u32 address, u32 data)
+static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
+ u8 address, u16 data)
{
- /* This is used for both, PCI and ChipCommon core, so be careful. */
- BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
- BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
-
- ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
- ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
- ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
- ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
-}
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ int max_retries = 10;
+ u32 v;
+ int i;
-static void ssb_commit_settings(struct ssb_bus *bus)
-{
- struct ssb_device *dev;
+ v = 0x80; /* Enable Preamble Sequence */
+ v |= 0x2; /* MDIO Clock Divisor */
+ pcicore_write32(pc, mdio_control, v);
- dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
- if (WARN_ON(!dev))
- return;
- /* This forces an update of the cached registers. */
- ssb_broadcast_value(dev, 0xFD8, 0);
+ if (pc->dev->id.revision >= 10) {
+ max_retries = 200;
+ ssb_pcie_mdio_set_phy(pc, device);
+ }
+
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 28); /* Write Transaction */
+ v |= (1 << 17); /* Turnaround */
+ if (pc->dev->id.revision < 10)
+ v |= (u32)device << 22;
+ v |= (u32)address << 18;
+ v |= data;
+ pcicore_write32(pc, mdio_data, v);
+ /* Wait for the device to complete the transaction */
+ udelay(10);
+ for (i = 0; i < max_retries; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */)
+ break;
+ msleep(1);
+ }
+ pcicore_write32(pc, mdio_control, 0);
}
int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
@@ -550,48 +707,10 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
if (pc->setup_done)
goto out;
if (pdev->id.coreid == SSB_DEV_PCI) {
- tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
- tmp |= SSB_PCICORE_SBTOPCI_PREF;
- tmp |= SSB_PCICORE_SBTOPCI_BURST;
- pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
-
- if (pdev->id.revision < 5) {
- tmp = ssb_read32(pdev, SSB_IMCFGLO);
- tmp &= ~SSB_IMCFGLO_SERTO;
- tmp |= 2;
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
- ssb_write32(pdev, SSB_IMCFGLO, tmp);
- ssb_commit_settings(bus);
- } else if (pdev->id.revision >= 11) {
- tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
- tmp |= SSB_PCICORE_SBTOPCI_MRM;
- pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
- }
+ ssb_pcicore_pci_setup_workarounds(pc);
} else {
WARN_ON(pdev->id.coreid != SSB_DEV_PCIE);
- //TODO: Better make defines for all these magic PCIE values.
- if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) {
- /* TLP Workaround register. */
- tmp = ssb_pcie_read(pc, 0x4);
- tmp |= 0x8;
- ssb_pcie_write(pc, 0x4, tmp);
- }
- if (pdev->id.revision == 0) {
- const u8 serdes_rx_device = 0x1F;
-
- ssb_pcie_mdio_write(pc, serdes_rx_device,
- 2 /* Timer */, 0x8128);
- ssb_pcie_mdio_write(pc, serdes_rx_device,
- 6 /* CDR */, 0x0100);
- ssb_pcie_mdio_write(pc, serdes_rx_device,
- 7 /* CDR BW */, 0x1466);
- } else if (pdev->id.revision == 1) {
- /* DLLP Link Control register. */
- tmp = ssb_pcie_read(pc, 0x100);
- tmp |= 0x40;
- ssb_pcie_write(pc, 0x100, tmp);
- }
+ ssb_pcicore_pcie_setup_workarounds(pc);
}
pc->setup_done = 1;
out:
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index e05ba6eefc7..f8a13f86321 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -1117,23 +1117,22 @@ static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)
{
u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
- /* The REJECT bit changed position in TMSLOW between
- * Backplane revisions. */
+ /* The REJECT bit seems to be different for Backplane rev 2.3 */
switch (rev) {
case SSB_IDLOW_SSBREV_22:
- return SSB_TMSLOW_REJECT_22;
+ case SSB_IDLOW_SSBREV_24:
+ case SSB_IDLOW_SSBREV_26:
+ return SSB_TMSLOW_REJECT;
case SSB_IDLOW_SSBREV_23:
return SSB_TMSLOW_REJECT_23;
- case SSB_IDLOW_SSBREV_24: /* TODO - find the proper REJECT bits */
- case SSB_IDLOW_SSBREV_25: /* same here */
- case SSB_IDLOW_SSBREV_26: /* same here */
+ case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */
case SSB_IDLOW_SSBREV_27: /* same here */
- return SSB_TMSLOW_REJECT_23; /* this is a guess */
+ return SSB_TMSLOW_REJECT; /* this is a guess */
default:
printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
WARN_ON(1);
}
- return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
+ return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
}
int ssb_device_is_enabled(struct ssb_device *dev)
@@ -1309,20 +1308,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
{
- struct ssb_chipcommon *cc;
int err;
enum ssb_clkmode mode;
err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
if (err)
goto error;
- cc = &bus->chipco;
- mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
- ssb_chipco_set_clockmode(cc, mode);
#ifdef CONFIG_SSB_DEBUG
bus->powered_up = 1;
#endif
+
+ mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
+ ssb_chipco_set_clockmode(&bus->chipco, mode);
+
return 0;
error:
ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
@@ -1330,6 +1329,37 @@ error:
}
EXPORT_SYMBOL(ssb_bus_powerup);
+static void ssb_broadcast_value(struct ssb_device *dev,
+ u32 address, u32 data)
+{
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ /* This is used for both, PCI and ChipCommon core, so be careful. */
+ BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
+ BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
+#endif
+
+ ssb_write32(dev, SSB_CHIPCO_BCAST_ADDR, address);
+ ssb_read32(dev, SSB_CHIPCO_BCAST_ADDR); /* flush */
+ ssb_write32(dev, SSB_CHIPCO_BCAST_DATA, data);
+ ssb_read32(dev, SSB_CHIPCO_BCAST_DATA); /* flush */
+}
+
+void ssb_commit_settings(struct ssb_bus *bus)
+{
+ struct ssb_device *dev;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
+#else
+ dev = bus->chipco.dev;
+#endif
+ if (WARN_ON(!dev))
+ return;
+ /* This forces an update of the cached registers. */
+ ssb_broadcast_value(dev, 0xFD8, 0);
+}
+EXPORT_SYMBOL(ssb_commit_settings);
+
u32 ssb_admatch_base(u32 adm)
{
u32 base = 0;
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 29884c00c4d..45e5babd396 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -258,7 +258,10 @@ static int we_support_multiple_80211_cores(struct ssb_bus *bus)
#ifdef CONFIG_SSB_PCIHOST
if (bus->bustype == SSB_BUSTYPE_PCI) {
if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
- bus->host_pci->device == 0x4324)
+ ((bus->host_pci->device == 0x4313) ||
+ (bus->host_pci->device == 0x431A) ||
+ (bus->host_pci->device == 0x4321) ||
+ (bus->host_pci->device == 0x4324)))
return 1;
}
#endif /* CONFIG_SSB_PCIHOST */
@@ -307,7 +310,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
} else {
if (bus->bustype == SSB_BUSTYPE_PCI) {
bus->chip_id = pcidev_to_chipid(bus->host_pci);
- pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+ pci_read_config_byte(bus->host_pci, PCI_REVISION_ID,
&bus->chip_rev);
bus->chip_package = 0;
} else {