static int __init sh7780_pci_init()

in drivers/pci/pci-sh7780.c [244:406]


static int __init sh7780_pci_init(void)
{
	struct pci_channel *chan = &sh7780_pci_controller;
	phys_addr_t memphys;
	size_t memsize;
	unsigned int id;
	const char *type;
	int ret, i;

	pr_notice("PCI: Starting initialization.\n");

	chan->reg_base = 0xfe040000;

	/* Enable CPU access to the PCIC registers. */
	__raw_writel(PCIECR_ENBL, PCIECR);

	/* Reset */
	__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST | PCICR_ENDIANNESS,
		     chan->reg_base + SH4_PCICR);

	/*
	 * Wait for it to come back up. The spec says to allow for up to
	 * 1 second after toggling the reset pin, but in practice 100ms
	 * is more than enough.
	 */
	mdelay(100);

	id = __raw_readw(chan->reg_base + PCI_VENDOR_ID);
	if (id != PCI_VENDOR_ID_RENESAS) {
		pr_err("PCI: Unknown vendor ID 0x%04x.\n", id);
		return -ENODEV;
	}

	id = __raw_readw(chan->reg_base + PCI_DEVICE_ID);
	type = (id == PCI_DEVICE_ID_RENESAS_SH7763) ? "SH7763" :
	       (id == PCI_DEVICE_ID_RENESAS_SH7780) ? "SH7780" :
	       (id == PCI_DEVICE_ID_RENESAS_SH7781) ? "SH7781" :
	       (id == PCI_DEVICE_ID_RENESAS_SH7785) ? "SH7785" :
					  NULL;
	if (unlikely(!type)) {
		pr_err("PCI: Found an unsupported Renesas host controller, device id 0x%04x.\n",
		       id);
		return -EINVAL;
	}

	pr_notice("PCI: Found a Renesas %s host controller, revision %d.\n",
		  type, __raw_readb(chan->reg_base + PCI_REVISION_ID));

	/*
	 * Now throw it in to register initialization mode and
	 * start the real work.
	 */
	__raw_writel(SH4_PCICR_PREFIX | PCICR_ENDIANNESS,
		     chan->reg_base + SH4_PCICR);

	memphys = __pa(memory_start);
	memsize = roundup_pow_of_two(memory_end - memory_start);

	/*
	 * If there's more than 512MB of memory, we need to roll over to
	 * LAR1/LSR1.
	 */
	if (memsize > SZ_512M) {
		__raw_writel(memphys + SZ_512M, chan->reg_base + SH4_PCILAR1);
		__raw_writel((((memsize - SZ_512M) - SZ_1M) & 0x1ff00000) | 1,
			     chan->reg_base + SH4_PCILSR1);
		memsize = SZ_512M;
	} else {
		/*
		 * Otherwise just zero it out and disable it.
		 */
		__raw_writel(0, chan->reg_base + SH4_PCILAR1);
		__raw_writel(0, chan->reg_base + SH4_PCILSR1);
	}

	/*
	 * LAR0/LSR0 covers up to the first 512MB, which is enough to
	 * cover all of lowmem on most platforms.
	 */
	__raw_writel(memphys, chan->reg_base + SH4_PCILAR0);
	__raw_writel(((memsize - SZ_1M) & 0x1ff00000) | 1,
		     chan->reg_base + SH4_PCILSR0);

	/*
	 * Hook up the ERR and SERR IRQs.
	 */
	ret = sh7780_pci_setup_irqs(chan);
	if (unlikely(ret))
		return ret;

	/*
	 * Disable the cache snoop controller for non-coherent DMA.
	 */
	__raw_writel(0, chan->reg_base + SH7780_PCICSCR0);
	__raw_writel(0, chan->reg_base + SH7780_PCICSAR0);
	__raw_writel(0, chan->reg_base + SH7780_PCICSCR1);
	__raw_writel(0, chan->reg_base + SH7780_PCICSAR1);

	/*
	 * Setup the memory BARs
	 */
	for (i = 1; i < chan->nr_resources; i++) {
		struct resource *res = chan->resources + i;
		resource_size_t size;

		if (unlikely(res->flags & IORESOURCE_IO))
			continue;

		/*
		 * Make sure we're in the right physical addressing mode
		 * for dealing with the resource.
		 */
		if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode()) {
			chan->nr_resources--;
			continue;
		}

		size = resource_size(res);

		/*
		 * The MBMR mask is calculated in units of 256kB, which
		 * keeps things pretty simple.
		 */
		__raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18,
			     chan->reg_base + SH7780_PCIMBMR(i - 1));
		__raw_writel(res->start, chan->reg_base + SH7780_PCIMBR(i - 1));
	}

	/*
	 * And I/O.
	 */
	__raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0);
	__raw_writel(0, chan->reg_base + SH7780_PCIIOBR);
	__raw_writel(0, chan->reg_base + SH7780_PCIIOBMR);

	__raw_writew(PCI_COMMAND_SERR   | PCI_COMMAND_WAIT   | \
		     PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \
		     PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND);

	/*
	 * Initialization mode complete, release the control register and
	 * enable round robin mode to stop device overruns/starvation.
	 */
	__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO |
		     PCICR_ENDIANNESS,
		     chan->reg_base + SH4_PCICR);

	ret = register_pci_controller(chan);
	if (unlikely(ret))
		goto err;

	sh7780_pci66_init(chan);

	pr_notice("PCI: Running at %dMHz.\n",
		  (__raw_readw(chan->reg_base + PCI_STATUS) & PCI_STATUS_66MHZ)
		  ? 66 : 33);

	return 0;

err:
	sh7780_pci_teardown_irqs(chan);
	return ret;
}