in driver_pcicore.c [320:395]
static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
{
u32 val;
if (WARN_ON(extpci_core))
return;
extpci_core = pc;
dev_dbg(pc->dev->dev, "PCIcore in host mode found\n");
/* Reset devices on the external PCI bus */
val = SSB_PCICORE_CTL_RST_OE;
val |= SSB_PCICORE_CTL_CLK_OE;
pcicore_write32(pc, SSB_PCICORE_CTL, val);
val |= SSB_PCICORE_CTL_CLK; /* Clock on */
pcicore_write32(pc, SSB_PCICORE_CTL, val);
udelay(150); /* Assertion time demanded by the PCI standard */
val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */
pcicore_write32(pc, SSB_PCICORE_CTL, val);
val = SSB_PCICORE_ARBCTL_INTERN;
pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
udelay(1); /* Assertion time demanded by the PCI standard */
if (pc->dev->bus->has_cardbus_slot) {
dev_dbg(pc->dev->dev, "CardBus slot detected\n");
pc->cardbusmode = 1;
/* GPIO 1 resets the bridge */
ssb_gpio_out(pc->dev->bus, 1, 1);
ssb_gpio_outen(pc->dev->bus, 1, 1);
pcicore_write16(pc, SSB_PCICORE_SPROM(0),
pcicore_read16(pc, SSB_PCICORE_SPROM(0))
| 0x0400);
}
/* 64MB I/O window */
pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
SSB_PCICORE_SBTOPCI_IO);
/* 64MB config space */
pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
SSB_PCICORE_SBTOPCI_CFG0);
/* 1GB memory window */
pcicore_write32(pc, SSB_PCICORE_SBTOPCI2,
SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA);
/*
* Accessing PCI config without a proper delay after devices reset (not
* GPIO reset) was causing reboots on WRT300N v1.0 (BCM4704).
* Tested delay 850 us lowered reboot chance to 50-80%, 1000 us fixed it
* completely. Flushing all writes was also tested but with no luck.
* The same problem was reported for WRT350N v1 (BCM4705), so we just
* sleep here unconditionally.
*/
usleep_range(1000, 2000);
/* Enable PCI bridge BAR0 prefetch and burst */
val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2);
/* Clear error conditions */
val = 0;
ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2);
/* Enable PCI interrupts */
pcicore_write32(pc, SSB_PCICORE_IMASK,
SSB_PCICORE_IMASK_INTA);
/* Ok, ready to run, register it to the system.
* The following needs change, if we want to port hostmode
* to non-MIPS platform.
*/
ssb_pcicore_controller.io_map_base = (unsigned long)ioremap(SSB_PCI_MEM, 0x04000000);
set_io_port_base(ssb_pcicore_controller.io_map_base);
/* 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);
}