diff options
Diffstat (limited to 'target/linux/generic-2.6/files/drivers/ssb/driver_pcicore.c')
-rw-r--r-- | target/linux/generic-2.6/files/drivers/ssb/driver_pcicore.c | 72 |
1 files changed, 46 insertions, 26 deletions
diff --git a/target/linux/generic-2.6/files/drivers/ssb/driver_pcicore.c b/target/linux/generic-2.6/files/drivers/ssb/driver_pcicore.c index a59dff083e..2faaa906d5 100644 --- a/target/linux/generic-2.6/files/drivers/ssb/driver_pcicore.c +++ b/target/linux/generic-2.6/files/drivers/ssb/driver_pcicore.c @@ -34,8 +34,10 @@ void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value) #ifdef CONFIG_SSB_PCICORE_HOSTMODE #include <asm/paccess.h> -/* Read the bus and catch bus exceptions. This is MIPS specific. */ -#define mips_busprobe(val, addr) get_dbe((val), (addr)) +/* Probe a 32bit value on the bus and catch bus exceptions. + * Returns nonzero on a bus exception. + * This is MIPS specific */ +#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr))) /* Assume one-hot slot wiring */ #define SSB_PCI_SLOT_MAX 16 @@ -45,8 +47,8 @@ static DEFINE_SPINLOCK(cfgspace_lock); /* Core to access the external PCI config space. Can only have one. */ static struct ssb_pcicore *extpci_core; -u32 pci_iobase = 0x100; -u32 pci_membase = SSB_PCI_DMA; +static u32 ssb_pcicore_pcibus_iobase = 0x100; +static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; int pcibios_plat_dev_init(struct pci_dev *d) { @@ -54,12 +56,16 @@ int pcibios_plat_dev_init(struct pci_dev *d) int pos, size; u32 *base; - printk("PCI: Fixing up device %s\n", pci_name(d)); + ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", + pci_name(d)); /* Fix up resource bases */ for (pos = 0; pos < 6; pos++) { res = &d->resource[pos]; - base = ((res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase); + if (res->flags & IORESOURCE_IO) + base = &ssb_pcicore_pcibus_iobase; + else + base = &ssb_pcicore_pcibus_membase; if (res->end) { size = res->end - res->start + 1; if (*base & (size - 1)) @@ -85,7 +91,7 @@ static void __init ssb_fixup_pcibridge(struct pci_dev *dev) if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) return; - printk("PCI: fixing up bridge\n"); + ssb_printk(KERN_INFO "PCI: fixing up bridge\n"); /* Enable PCI bridge bus mastering and memory space */ pci_set_master(dev); @@ -93,10 +99,13 @@ static void __init ssb_fixup_pcibridge(struct pci_dev *dev) /* Enable PCI bridge BAR1 prefetch and burst */ pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); + + /* Make sure our latency is high enough to handle the devices behind us */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); } DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); -int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { return ssb_mips_irq(extpci_core->dev) + 2; } @@ -147,7 +156,7 @@ static int ssb_extpci_read_config(struct ssb_pcicore *pc, u32 addr, val; void __iomem *mmio; - assert(pc->hostmode); + SSB_WARN_ON(!pc->hostmode); if (unlikely(len != 1 && len != 2 && len != 4)) goto out; addr = get_cfgspace_addr(pc, bus, dev, func, off); @@ -158,7 +167,7 @@ static int ssb_extpci_read_config(struct ssb_pcicore *pc, if (!mmio) goto out; - if (mips_busprobe(val, (u32 *) mmio)) { + if (mips_busprobe32(val, mmio)) { val = 0xffffffff; goto unmap; } @@ -193,7 +202,7 @@ static int ssb_extpci_write_config(struct ssb_pcicore *pc, u32 addr, val = 0; void __iomem *mmio; - assert(pc->hostmode); + SSB_WARN_ON(!pc->hostmode); if (unlikely(len != 1 && len != 2 && len != 4)) goto out; addr = get_cfgspace_addr(pc, bus, dev, func, off); @@ -204,7 +213,7 @@ static int ssb_extpci_write_config(struct ssb_pcicore *pc, if (!mmio) goto out; - if (mips_busprobe(val, (u32 *) mmio)) { + if (mips_busprobe32(val, mmio)) { val = 0xffffffff; goto unmap; } @@ -224,7 +233,7 @@ static int ssb_extpci_write_config(struct ssb_pcicore *pc, val = *((const u32 *)buf); break; } - writel(*((const u32 *)buf), mmio); + writel(val, mmio); err = 0; unmap: @@ -269,7 +278,7 @@ static struct pci_ops ssb_pcicore_pciops = { static struct resource ssb_pcicore_mem_resource = { .name = "SSB PCIcore external memory", .start = SSB_PCI_DMA, - .end = (u32)SSB_PCI_DMA + (u32)SSB_PCI_DMA_SZ - 1, + .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1, .flags = IORESOURCE_MEM, }; @@ -291,10 +300,8 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) { u32 val; - if (extpci_core) { - WARN_ON(1); + if (WARN_ON(extpci_core)) return; - } extpci_core = pc; ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n"); @@ -304,12 +311,14 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) pcicore_write32(pc, SSB_PCICORE_CTL, val); val |= SSB_PCICORE_CTL_CLK; /* Clock on */ pcicore_write32(pc, SSB_PCICORE_CTL, val); - udelay(150); + udelay(150); /* Assertion time demanded by the PCI standard */ val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */ pcicore_write32(pc, SSB_PCICORE_CTL, val); - udelay(1); + val = SSB_PCICORE_ARBCTL_INTERN; + pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); + udelay(1); /* Assertion time demanded by the PCI standard */ - //TODO cardbus mode + /*TODO cardbus mode */ /* 64MB I/O window */ pcicore_write32(pc, SSB_PCICORE_SBTOPCI0, @@ -336,6 +345,9 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) * The following needs change, if we want to port hostmode * to non-MIPS platform. */ set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000)); + /* Give some time to the PCI controller to configure itself with the new + * values. Not waiting at this point causes crashes of the machine. */ + mdelay(10); register_pci_controller(&ssb_pcicore_controller); } @@ -364,7 +376,7 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc) if (bus->chip_id == 0x5350) return 0; - return !mips_busprobe(tmp, (u32 *) (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE))); + return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE))); } #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ @@ -430,6 +442,7 @@ static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, 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++) { v = pcicore_read32(pc, mdio_control); @@ -458,7 +471,8 @@ static void ssb_commit_settings(struct ssb_bus *bus) struct ssb_device *dev; dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; - assert(dev); + if (WARN_ON(!dev)) + return; /* This forces an update of the cached registers. */ ssb_broadcast_value(dev, 0xFD8, 0); } @@ -496,9 +510,15 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, u32 intvec; intvec = ssb_read32(pdev, SSB_INTVEC); - tmp = ssb_read32(dev, SSB_TPSFLAG); - tmp &= SSB_TPSFLAG_BPFLAG; - intvec |= tmp; + if ((bus->chip_id & 0xFF00) == 0x4400) { + /* Workaround: On the BCM44XX the BPFLAG routing + * bit is wrong. Use a hardcoded constant. */ + intvec |= 0x00000002; + } else { + tmp = ssb_read32(dev, SSB_TPSFLAG); + tmp &= SSB_TPSFLAG_BPFLAG; + intvec |= tmp; + } ssb_write32(pdev, SSB_INTVEC, intvec); } @@ -525,7 +545,7 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); } } else { - assert(pdev->id.coreid == SSB_DEV_PCIE); + 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. */ |