diff options
Diffstat (limited to 'arch/powerpc/sysdev/ppc4xx_pci.c')
| -rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 180 | 
1 files changed, 131 insertions, 49 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 1814adbd223..b4a54c52e88 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -1387,28 +1387,59 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,  	resource_size_t size = res->end - res->start + 1;  	u64 sa; -	/* Calculate window size */ -	sa = (0xffffffffffffffffull << ilog2(size));; -	if (res->flags & IORESOURCE_PREFETCH) -		sa |= 0x8; +	if (port->endpoint) { +		resource_size_t ep_addr = 0; +		resource_size_t ep_size = 32 << 20; + +		/* Currently we map a fixed 64MByte window to PLB address +		 * 0 (SDRAM). This should probably be configurable via a dts +		 * property. +		 */ + +		/* Calculate window size */ +		sa = (0xffffffffffffffffull << ilog2(ep_size));; + +		/* Setup BAR0 */ +		out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); +		out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa) | +			 PCI_BASE_ADDRESS_MEM_TYPE_64); -	out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); -	out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); +		/* Disable BAR1 & BAR2 */ +		out_le32(mbase + PECFG_BAR1MPA, 0); +		out_le32(mbase + PECFG_BAR2HMPA, 0); +		out_le32(mbase + PECFG_BAR2LMPA, 0); -	/* The setup of the split looks weird to me ... let's see if it works */ -	out_le32(mbase + PECFG_PIM0LAL, 0x00000000); -	out_le32(mbase + PECFG_PIM0LAH, 0x00000000); -	out_le32(mbase + PECFG_PIM1LAL, 0x00000000); -	out_le32(mbase + PECFG_PIM1LAH, 0x00000000); -	out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); -	out_le32(mbase + PECFG_PIM01SAL, 0x00000000); +		out_le32(mbase + PECFG_PIM01SAH, RES_TO_U32_HIGH(sa)); +		out_le32(mbase + PECFG_PIM01SAL, RES_TO_U32_LOW(sa)); + +		out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(ep_addr)); +		out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(ep_addr)); +	} else { +		/* Calculate window size */ +		sa = (0xffffffffffffffffull << ilog2(size));; +		if (res->flags & IORESOURCE_PREFETCH) +			sa |= 0x8; + +		out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); +		out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); + +		/* The setup of the split looks weird to me ... let's see +		 * if it works +		 */ +		out_le32(mbase + PECFG_PIM0LAL, 0x00000000); +		out_le32(mbase + PECFG_PIM0LAH, 0x00000000); +		out_le32(mbase + PECFG_PIM1LAL, 0x00000000); +		out_le32(mbase + PECFG_PIM1LAH, 0x00000000); +		out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); +		out_le32(mbase + PECFG_PIM01SAL, 0x00000000); + +		out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(res->start)); +		out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(res->start)); +	}  	/* Enable inbound mapping */  	out_le32(mbase + PECFG_PIMEN, 0x1); -	out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(res->start)); -	out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(res->start)); -  	/* Enable I/O, Mem, and Busmaster cycles */  	out_le16(mbase + PCI_COMMAND,  		 in_le16(mbase + PCI_COMMAND) | @@ -1422,13 +1453,8 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port)  	const int *bus_range;  	int primary = 0, busses;  	void __iomem *mbase = NULL, *cfg_data = NULL; - -	/* XXX FIXME: Handle endpoint mode properly */ -	if (port->endpoint) { -		printk(KERN_WARNING "PCIE%d: Port in endpoint mode !\n", -		       port->index); -		return; -	} +	const u32 *pval; +	u32 val;  	/* Check if primary bridge */  	if (of_get_property(port->node, "primary", NULL)) @@ -1462,21 +1488,30 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port)  		hose->last_busno = hose->first_busno + busses;  	} -	/* We map the external config space in cfg_data and the host config -	 * space in cfg_addr. External space is 1M per bus, internal space -	 * is 4K +	if (!port->endpoint) { +		/* Only map the external config space in cfg_data for +		 * PCIe root-complexes. External space is 1M per bus +		 */ +		cfg_data = ioremap(port->cfg_space.start + +				   (hose->first_busno + 1) * 0x100000, +				   busses * 0x100000); +		if (cfg_data == NULL) { +			printk(KERN_ERR "%s: Can't map external config space !", +			       port->node->full_name); +			goto fail; +		} +		hose->cfg_data = cfg_data; +	} + +	/* Always map the host config space in cfg_addr. +	 * Internal space is 4K  	 */ -	cfg_data = ioremap(port->cfg_space.start + -				 (hose->first_busno + 1) * 0x100000, -				 busses * 0x100000);  	mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); -	if (cfg_data == NULL || mbase == NULL) { -		printk(KERN_ERR "%s: Can't map config space !", +	if (mbase == NULL) { +		printk(KERN_ERR "%s: Can't map internal config space !",  		       port->node->full_name);  		goto fail;  	} - -	hose->cfg_data = cfg_data;  	hose->cfg_addr = mbase;  	pr_debug("PCIE %s, bus %d..%d\n", port->node->full_name, @@ -1489,12 +1524,14 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port)  	port->hose = hose;  	mbase = (void __iomem *)hose->cfg_addr; -	/* -	 * Set bus numbers on our root port -	 */ -	out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno); -	out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1); -	out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno); +	if (!port->endpoint) { +		/* +		 * Set bus numbers on our root port +		 */ +		out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno); +		out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1); +		out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno); +	}  	/*  	 * OMRs are already reset, also disable PIMs @@ -1515,17 +1552,49 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port)  	ppc4xx_configure_pciex_PIMs(port, hose, mbase, &dma_window);  	/* The root complex doesn't show up if we don't set some vendor -	 * and device IDs into it. Those are the same bogus one that the -	 * initial code in arch/ppc add. We might want to change that. +	 * and device IDs into it. The defaults below are the same bogus +	 * one that the initial code in arch/ppc had. This can be +	 * overwritten by setting the "vendor-id/device-id" properties +	 * in the pciex node.  	 */ -	out_le16(mbase + 0x200, 0xaaa0 + port->index); -	out_le16(mbase + 0x202, 0xbed0 + port->index); -	/* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ -	out_le32(mbase + 0x208, 0x06040001); +	/* Get the (optional) vendor-/device-id from the device-tree */ +	pval = of_get_property(port->node, "vendor-id", NULL); +	if (pval) { +		val = *pval; +	} else { +		if (!port->endpoint) +			val = 0xaaa0 + port->index; +		else +			val = 0xeee0 + port->index; +	} +	out_le16(mbase + 0x200, val); + +	pval = of_get_property(port->node, "device-id", NULL); +	if (pval) { +		val = *pval; +	} else { +		if (!port->endpoint) +			val = 0xbed0 + port->index; +		else +			val = 0xfed0 + port->index; +	} +	out_le16(mbase + 0x202, val); + +	if (!port->endpoint) { +		/* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ +		out_le32(mbase + 0x208, 0x06040001); + +		printk(KERN_INFO "PCIE%d: successfully set as root-complex\n", +		       port->index); +	} else { +		/* Set Class Code to Processor/PPC */ +		out_le32(mbase + 0x208, 0x0b200001); + +		printk(KERN_INFO "PCIE%d: successfully set as endpoint\n", +		       port->index); +	} -	printk(KERN_INFO "PCIE%d: successfully set as root-complex\n", -	       port->index);  	return;   fail:  	if (hose) @@ -1542,6 +1611,7 @@ static void __init ppc4xx_probe_pciex_bridge(struct device_node *np)  	const u32 *pval;  	int portno;  	unsigned int dcrs; +	const char *val;  	/* First, proceed to core initialization as we assume there's  	 * only one PCIe core in the system @@ -1573,8 +1643,20 @@ static void __init ppc4xx_probe_pciex_bridge(struct device_node *np)  	}  	port->sdr_base = *pval; -	/* XXX Currently, we only support root complex mode */ -	port->endpoint = 0; +	/* Check if device_type property is set to "pci" or "pci-endpoint". +	 * Resulting from this setup this PCIe port will be configured +	 * as root-complex or as endpoint. +	 */ +	val = of_get_property(port->node, "device_type", NULL); +	if (!strcmp(val, "pci-endpoint")) { +		port->endpoint = 1; +	} else if (!strcmp(val, "pci")) { +		port->endpoint = 0; +	} else { +		printk(KERN_ERR "PCIE: missing or incorrect device_type for %s\n", +		       np->full_name); +		return; +	}  	/* Fetch config space registers address */  	if (of_address_to_resource(np, 0, &port->cfg_space)) {  |