static void ssb_pcicore_init_hostmode()

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