static int v3_pci_probe()

in controller/pci-v3-semi.c [706:893]


static int v3_pci_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct resource *regs;
	struct resource_entry *win;
	struct v3_pci *v3;
	struct pci_host_bridge *host;
	struct clk *clk;
	u16 val;
	int irq;
	int ret;

	host = devm_pci_alloc_host_bridge(dev, sizeof(*v3));
	if (!host)
		return -ENOMEM;

	host->ops = &v3_pci_ops;
	v3 = pci_host_bridge_priv(host);
	host->sysdata = v3;
	v3->dev = dev;

	/* Get and enable host clock */
	clk = devm_clk_get(dev, NULL);
	if (IS_ERR(clk)) {
		dev_err(dev, "clock not found\n");
		return PTR_ERR(clk);
	}
	ret = clk_prepare_enable(clk);
	if (ret) {
		dev_err(dev, "unable to enable clock\n");
		return ret;
	}

	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	v3->base = devm_ioremap_resource(dev, regs);
	if (IS_ERR(v3->base))
		return PTR_ERR(v3->base);
	/*
	 * The hardware has a register with the physical base address
	 * of the V3 controller itself, verify that this is the same
	 * as the physical memory we've remapped it from.
	 */
	if (readl(v3->base + V3_LB_IO_BASE) != (regs->start >> 16))
		dev_err(dev, "V3_LB_IO_BASE = %08x but device is @%pR\n",
			readl(v3->base + V3_LB_IO_BASE), regs);

	/* Configuration space is 16MB directly mapped */
	regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	if (resource_size(regs) != SZ_16M) {
		dev_err(dev, "config mem is not 16MB!\n");
		return -EINVAL;
	}
	v3->config_mem = regs->start;
	v3->config_base = devm_ioremap_resource(dev, regs);
	if (IS_ERR(v3->config_base))
		return PTR_ERR(v3->config_base);

	/* Get and request error IRQ resource */
	irq = platform_get_irq(pdev, 0);
	if (irq < 0)
		return irq;

	ret = devm_request_irq(dev, irq, v3_irq, 0,
			"PCIv3 error", v3);
	if (ret < 0) {
		dev_err(dev,
			"unable to request PCIv3 error IRQ %d (%d)\n",
			irq, ret);
		return ret;
	}

	/*
	 * Unlock V3 registers, but only if they were previously locked.
	 */
	if (readw(v3->base + V3_SYSTEM) & V3_SYSTEM_M_LOCK)
		writew(V3_SYSTEM_UNLOCK, v3->base + V3_SYSTEM);

	/* Disable all slave access while we set up the windows */
	val = readw(v3->base + V3_PCI_CMD);
	val &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
	writew(val, v3->base + V3_PCI_CMD);

	/* Put the PCI bus into reset */
	val = readw(v3->base + V3_SYSTEM);
	val &= ~V3_SYSTEM_M_RST_OUT;
	writew(val, v3->base + V3_SYSTEM);

	/* Retry until we're ready */
	val = readw(v3->base + V3_PCI_CFG);
	val |= V3_PCI_CFG_M_RETRY_EN;
	writew(val, v3->base + V3_PCI_CFG);

	/* Set up the local bus protocol */
	val = readw(v3->base + V3_LB_CFG);
	val |= V3_LB_CFG_LB_BE_IMODE; /* Byte enable input */
	val |= V3_LB_CFG_LB_BE_OMODE; /* Byte enable output */
	val &= ~V3_LB_CFG_LB_ENDIAN; /* Little endian */
	val &= ~V3_LB_CFG_LB_PPC_RDY; /* TODO: when using on PPC403Gx, set to 1 */
	writew(val, v3->base + V3_LB_CFG);

	/* Enable the PCI bus master */
	val = readw(v3->base + V3_PCI_CMD);
	val |= PCI_COMMAND_MASTER;
	writew(val, v3->base + V3_PCI_CMD);

	/* Get the I/O and memory ranges from DT */
	resource_list_for_each_entry(win, &host->windows) {
		ret = v3_pci_setup_resource(v3, host, win);
		if (ret) {
			dev_err(dev, "error setting up resources\n");
			return ret;
		}
	}
	ret = v3_pci_parse_map_dma_ranges(v3, np);
	if (ret)
		return ret;

	/*
	 * Disable PCI to host IO cycles, enable I/O buffers @3.3V,
	 * set AD_LOW0 to 1 if one of the LB_MAP registers choose
	 * to use this (should be unused).
	 */
	writel(0x00000000, v3->base + V3_PCI_IO_BASE);
	val = V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS |
		V3_PCI_CFG_M_EN3V | V3_PCI_CFG_M_AD_LOW0;
	/*
	 * DMA read and write from PCI bus commands types
	 */
	val |=  V3_PCI_CFG_TYPE_DEFAULT << V3_PCI_CFG_M_RTYPE_SHIFT;
	val |=  V3_PCI_CFG_TYPE_DEFAULT << V3_PCI_CFG_M_WTYPE_SHIFT;
	writew(val, v3->base + V3_PCI_CFG);

	/*
	 * Set the V3 FIFO such that writes have higher priority than
	 * reads, and local bus write causes local bus read fifo flush
	 * on aperture 1. Same for PCI.
	 */
	writew(V3_FIFO_PRIO_LB_RD1_FLUSH_AP1 |
	       V3_FIFO_PRIO_LB_RD0_FLUSH_AP1 |
	       V3_FIFO_PRIO_PCI_RD1_FLUSH_AP1 |
	       V3_FIFO_PRIO_PCI_RD0_FLUSH_AP1,
	       v3->base + V3_FIFO_PRIORITY);


	/*
	 * Clear any error interrupts, and enable parity and write error
	 * interrupts
	 */
	writeb(0, v3->base + V3_LB_ISTAT);
	val = readw(v3->base + V3_LB_CFG);
	val |= V3_LB_CFG_LB_LB_INT;
	writew(val, v3->base + V3_LB_CFG);
	writeb(V3_LB_ISTAT_PCI_WR | V3_LB_ISTAT_PCI_PERR,
	       v3->base + V3_LB_IMASK);

	/* Special Integrator initialization */
	if (of_device_is_compatible(np, "arm,integrator-ap-pci")) {
		ret = v3_integrator_init(v3);
		if (ret)
			return ret;
	}

	/* Post-init: enable PCI memory and invalidate (master already on) */
	val = readw(v3->base + V3_PCI_CMD);
	val |= PCI_COMMAND_MEMORY | PCI_COMMAND_INVALIDATE;
	writew(val, v3->base + V3_PCI_CMD);

	/* Clear pending interrupts */
	writeb(0, v3->base + V3_LB_ISTAT);
	/* Read or write errors and parity errors cause interrupts */
	writeb(V3_LB_ISTAT_PCI_RD | V3_LB_ISTAT_PCI_WR | V3_LB_ISTAT_PCI_PERR,
	       v3->base + V3_LB_IMASK);

	/* Take the PCI bus out of reset so devices can initialize */
	val = readw(v3->base + V3_SYSTEM);
	val |= V3_SYSTEM_M_RST_OUT;
	writew(val, v3->base + V3_SYSTEM);

	/*
	 * Re-lock the system register.
	 */
	val = readw(v3->base + V3_SYSTEM);
	val |= V3_SYSTEM_M_LOCK;
	writew(val, v3->base + V3_SYSTEM);

	return pci_host_probe(host);
}