Skip to contentSkip to conversation

PCIe support for the Armada 370 and Armada XP SoCs

PATCH Superseded Thomas Petazzoni 3 participants 22 messages Mar 21, 2013 – Mar 22, 2013

Subsystems (11)

v5 of 10 Superseded Latest is v10 →

lore
Share & tools
lore
#0 lore raw

v5 cover PCIe support for the Armada 370 and Armada XP SoCs

Hello,

This series of patches introduces PCIe support for the Marvell Armada 370 and Armada XP. In the future, we plan to extend the driver to cover Kirkwood platforms, and possibly other Marvell EBU platforms as well.

As we are approaching 3.10, I would now like to get formal Acked-by, or disagreements from the following maintainers/developers :

* Grant Likely, as the OF maintainer, for patches 1, 2 and 3

[PATCH v5 01/17] of/pci: Provide support for parsing PCI DT ranges [PATCH v5 02/17] of/pci: Add of_pci_get_devfn() function [PATCH v5 03/17] of/pci: Add of_pci_parse_bus_range() function

* Bjorn Helgaas, as the PCI maintainer, for patches 4 and 8

[PATCH v5 04/17] pci: infrastructure to add drivers in drivers/pci/host [PATCH v5 08/17] pci: PCIe driver for Marvell Armada 370/XP systems

* Russell King, as the ARM maintainer, for patch 5

[PATCH v5 05/17] arm: pci: add a align_resource hook

* Arnd Bergmann, Mitch Bradley and Jason Gunthorpe, for patch 8 (the PCIe driver itself), and specifically the Device Tree binding.

[PATCH v5 08/17] pci: PCIe driver for Marvell Armada 370/XP systems

This patch set depends on:

* The arm-soc/mvebu/cleanup branch in Arnd and Olof arm-soc tree

* [PATCH v3 for 3.10] Introduce a Marvell EBU MBus driver
http://lists.infradead.org/pipermail/linux-arm-kernel/2013-March/156883.html

For easier testing, the code has been pushed to:

git://github.com/MISL-EBU-System-SW/mainline-public.git marvell-pcie-v5

(note however that this branch will no work as-is, due to completely
unrelated regressions, that have in the mean-time been fixed in 3.9-rc3. At least 1b72b78fda0433a7e115bc2d78603fde65fae0e7 and e366154f70c54dee3665d1c0f780007e514412f3 must be cherry-picked)

This PATCHv5 follows:
* PATCHv4, sent on March, 8th 2013
* PATCHv3, sent on February, 12th 2013
* PATCHv2, sent on January, 28th 2013
* RFCv1, sent on December, 7th 2012

Changes between v4 and v5:

* Rebased on top of 3.9-rc2 + the new mvebu-mbus driver (v3).

* Changed the names of the PCI DT sub-nodes to match the OF
specifications: they should be named pcie at DD,FF where DD is the device number and FF the function number. Requested by Mitch Bradley.

* Add the device_type = "pci" property at the pcie-controller level. Requested by Mitch Bradley.

* Drop patch 'of/pci: Add of_pci_get_bus() function' because it wasn't actually used in the rest of the patch series.

* Updated the patch 'of/pci: Provide support for parsing PCI DT ranges property' to use the latest version proposed by Andrew Murray on the devicetree-discuss@ mailing list.

Changes between v3 and v4:

* Rebased on top of 3.9-rc1.

* Drop patch "ARM: pci: Allow passing per-controller private data" because it was merged in 3.9.

* Drop patch "lib: devres: don't enclose pcim_*() functions in CONFIG_HAS_IOPORT", because it was merged in 3.9.

* Added CONFIG_PCI_MVEBU=y in mvebu_defconfig, so that the right PCI host controller driver is automatically enabled.

* Instead of using the DT 'ranges' property to encode the PCIe register ranges, use a 'reg' property on the main PCIe controller DT node together with a 'reg-names' property. Suggested by Jason Gunthorpe.

* Don't select PCI_SW_HOST_BRIDGE and PCI_SW_PCI_PCI_BRIDGE, they don't exist anymore. Reported by Bjorn Helgaas.

* Added support for the Armada XP GP board.

* Fix the 'ranges' property so that the memory range is an identity map between CPU addresses and bus addresses. Suggested by Arnd Bergmann.

* Changed the 'ranges' property to have the I/O region after the memory region.

* Use the new mvebu-mbus driver API to create/remove address decoding windows when needed. This remove the need to include <mach/addr-map.h>. Requested by Arnd Bergmann.

* Include directly into the driver the few common PCIe functions we were using from arch/arm/plat-orion/pcie.c. This allows to remove the inclusion of <plat/pcie.h>. Requested by Arnd Bergmann.

* Directly set up the address decoding windows when the memory base/limit and I/O base/limit are configured in the PCI-to-PCI bridge instead of relying on the memory and I/O accesses being enabled in the PCI_COMMAND register. Suggested by Bjorn Helgaas.

* Added some comments on top of the calculations of the I/O base/limit and memory base/limit. Suggested by Arnd Bergmann.

* Changed a bit the way the "realio" resource is created, from suggestions given by Arnd Bergmann.

* Updated the Device Tree binding documentation. Reported by Jason Gunthorpe.

* Instead of using "marvell,armada-370-xp-pcie" as the DT compatible string, use two separate compatible strings:
"marvell,armada-370-pcie" and "marvell,armada-xp-pcie". For now, the driver does the same thing for both.

Changes between v2 and v3:

* Use of_irq_map_pci() instead of of_irq_map_raw(), as suggested by Andrew Murray. In order to do this, we moved the interrupt-map and interrupt-map-mask DT properties from the main PCIe controller node to the DT subnodes representing each PCIe interface.

* Remove the usage of the emulated host bridge.

* Move the emulated PCI-to-PCI bridge code into the Marvell PCI driver itself, in order to allow a tighter integration. Suggested by Bjorn Helgaas and Jason Gunthorpe.

* Make the allocation of address decoding windows dynamic: it's when memory accesses or I/O accesses are enabled at the PCI-to-PCI bridge level that we allocate and setup the corresponding address decoding window. Requested by Bjorn Helgaas.

* Fixed the implementation of I/O accesses to use I/O addresses that fall within the normal IO_SPACE_LIMIT. This required using the "remap" functionality of address decoding windows, and therefore some changes in the address decoding window allocator. Follows a long discussion about I/O accesses.

* Set up a correct bus number in the configuration of the PCIe interfaces so that we don't have to fake bus numbers anymore. Requested by Jason Gunthorpe.

* Fix the of_pci_get_devfn() implementation according to Stephen Warren's comment.

* Use CFLAGS_ instead of ccflags to add the mach-mvebu and plat-orion include paths when building the pci-mvebu driver. This ensures that the include paths are only added when building this specific driver. Requested by Stephen Warren.

* Fix the ->resource_align() to only apply on bus 0 (the one on which the emulated PCI-to-PCI bridges sit), and to request an alignment on the size of the window (and not only 64 KB for I/O windows and 1 MB for memory windows).

* Clarified the commit log of "clk: mvebu: create parent-child relation for PCIe clocks on Armada 370"

Thanks,

Thomas

Andrew Murray (1):
of/pci: Provide support for parsing PCI DT ranges property

Thierry Reding (2):
of/pci: Add of_pci_get_devfn() function
of/pci: Add of_pci_parse_bus_range() function

Thomas Petazzoni (14):
pci: infrastructure to add drivers in drivers/pci/host
arm: pci: add a align_resource hook
clk: mvebu: create parent-child relation for PCIe clocks on Armada

    370

clk: mvebu: add more PCIe clocks for Armada XP
pci: PCIe driver for Marvell Armada 370/XP systems
arm: mvebu: PCIe support is now available on mvebu
arm: mvebu: add PCIe Device Tree informations for Armada 370
arm: mvebu: add PCIe Device Tree informations for Armada XP
arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4
arm: mvebu: PCIe Device Tree informations for Armada XP DB
arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox
arm: mvebu: PCIe Device Tree informations for Armada 370 DB
arm: mvebu: PCIe Device Tree informations for Armada XP GP
arm: mvebu: update defconfig with PCI and USB support

 .../devicetree/bindings/pci/mvebu-pci.txt          |  201 +++++
 arch/arm/boot/dts/armada-370-db.dts                |   17 +
 arch/arm/boot/dts/armada-370-mirabox.dts           |   16 +
 arch/arm/boot/dts/armada-370.dtsi                  |   45 +
 arch/arm/boot/dts/armada-xp-db.dts                 |   33 +
 arch/arm/boot/dts/armada-xp-gp.dts                 |   21 +
 arch/arm/boot/dts/armada-xp-mv78230.dtsi           |   98 +++
 arch/arm/boot/dts/armada-xp-mv78260.dtsi           |  113 +++
 arch/arm/boot/dts/armada-xp-mv78460.dtsi           |  170 ++++
 arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts   |    9 +
 arch/arm/configs/mvebu_defconfig                   |    3 +
 arch/arm/include/asm/mach/pci.h                    |   11 +
 arch/arm/kernel/bios32.c                           |    6 +
 arch/arm/mach-mvebu/Kconfig                        |    2 +
 arch/microblaze/pci/pci-common.c                   |  106 +--
 arch/mips/pci/pci.c                                |   44 +-
 arch/powerpc/kernel/pci-common.c                   |   93 +-
 drivers/clk/mvebu/clk-gating-ctrl.c                |   18 +-
 drivers/of/address.c                               |   54 ++
 drivers/of/of_pci.c                                |   59 +-
 drivers/pci/Kconfig                                |    2 +
 drivers/pci/Makefile                               |    3 +
 drivers/pci/host/Kconfig                           |    8 +
 drivers/pci/host/Makefile                          |    4 +
 drivers/pci/host/pci-mvebu.c                       |  927 ++++++++++++++++++++
 include/linux/of_address.h                         |   31 +
 include/linux/of_pci.h                             |    2 +
 27 files changed, 1912 insertions(+), 184 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/mvebu-pci.txt
 create mode 100644 drivers/pci/host/Kconfig
 create mode 100644 drivers/pci/host/Makefile
 create mode 100644 drivers/pci/host/pci-mvebu.c
Signature · 1 line
1.7.9.5
#1 lore raw

PATCH v5 1/17 of/pci: Provide support for parsing PCI DT ranges property

From: Andrew Murray <[email protected]>

This patch factors out common implementations patterns to reduce overall kernel code and provide a means for host bridge drivers to directly obtain struct resources from the DT's ranges property without relying on architecture specific DT handling. This will make it easier to write archiecture independent host bridge drivers and mitigate against further duplication of DT parsing code.

This patch can be used in the following way:

	struct of_pci_range_iter iter;
	for_each_of_pci_range(&iter, np) {

		//directly access properties of the address range, e.g.:
		//iter.pci_space, iter.pci_addr, iter.cpu_addr, iter.size or
		//iter.flags

		//alternatively obtain a struct resource, e.g.:
		//struct resource res;
		//range_iter_fill_resource(iter, np, res);
	}

Additionally the implementation takes care of adjacent ranges and merges them into a single range (as was the case with powerpc and microblaze).

The modifications to microblaze, mips and powerpc have not been tested.

---

Compared to the v2 sent by Andrew Murray, Thomas Petazzoni did:

* Add a memset() on the struct of_pci_range_iter when starting the for loop in for_each_pci_range(). Otherwise, with an uninitialized of_pci_range_iter, of_pci_process_ranges() may crash.

* Add parenthesis around 'res', 'np' and 'iter' in the for_each_of_pci_range macro definitions. Otherwise, passing something like &foobar as 'res' didn't work.

* Rebased on top of 3.9-rc2, which required fixing a few conflicts in the Microblaze code.

v2:
This follows on from suggestions made by Grant Likely (marc.info/?l=linux-kernel&m=136079602806328)

---
 arch/microblaze/pci/pci-common.c |  106 ++++++++++++--------------------------
 arch/mips/pci/pci.c              |   44 ++++------------
 arch/powerpc/kernel/pci-common.c |   93 ++++++++++-----------------------
 drivers/of/address.c             |   54 +++++++++++++++++++
 include/linux/of_address.h       |   31 +++++++++++
 5 files changed, 155 insertions(+), 173 deletions(-)
arch/microblaze/pci/pci-common.c +33 -73
index 9ea521e..85adf91 100644
@@ -658,67 +658,36 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
 void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 				  struct device_node *dev, int primary)
 {
-	const u32 *ranges;
-	int rlen;
-	int pna = of_n_addr_cells(dev);
-	int np = pna + 5;
 	int memno = 0, isa_hole = -1;
-	u32 pci_space;
-	unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
 	unsigned long long isa_mb = 0;
 	struct resource *res;
+	struct of_pci_range_iter iter;
 
 	pr_info("PCI host bridge %s %s ranges:\n",
 	       dev->full_name, primary ? "(primary)" : "");
 
-	/* Get ranges property */
-	ranges = of_get_property(dev, "ranges", &rlen);
-	if (ranges == NULL)
-		return;
-
-	/* Parse it */
 	pr_debug("Parsing ranges property...\n");
-	while ((rlen -= np * 4) >= 0) {
+	for_each_of_pci_range(&iter, dev) {
 		/* Read next ranges element */
-		pci_space = ranges[0];
-		pci_addr = of_read_number(ranges + 1, 2);
-		cpu_addr = of_translate_address(dev, ranges + 3);
-		size = of_read_number(ranges + pna + 3, 2);
-
-		pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
-				pci_space, pci_addr);
-		pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
-					cpu_addr, size);
-
-		ranges += np;
+		pr_debug("pci_space: 0x%08x pci_addr:0x%016llx "
+				"cpu_addr:0x%016llx size:0x%016llx\n",
+				iter.pci_space, iter.pci_addr, iter.cpu_addr,
+				iter.size);
 
 		/* If we failed translation or got a zero-sized region
 		 * (some FW try to feed us with non sensical zero sized regions
 		 * such as power3 which look like some kind of attempt
 		 * at exposing the VGA memory hole)
 		 */
-		if (cpu_addr == OF_BAD_ADDR || size == 0)
+		if (iter.cpu_addr == OF_BAD_ADDR || iter.size == 0)
 			continue;
 
-		/* Now consume following elements while they are contiguous */
-		for (; rlen >= np * sizeof(u32);
-		     ranges += np, rlen -= np * 4) {
-			if (ranges[0] != pci_space)
-				break;
-			pci_next = of_read_number(ranges + 1, 2);
-			cpu_next = of_translate_address(dev, ranges + 3);
-			if (pci_next != pci_addr + size ||
-			    cpu_next != cpu_addr + size)
-				break;
-			size += of_read_number(ranges + pna + 3, 2);
-		}
-
 		/* Act based on address space type */
 		res = NULL;
-		switch ((pci_space >> 24) & 0x3) {
-		case 1:		/* PCI IO space */
+		if (iter.flags & IORESOURCE_IO) {
 			pr_info("  IO 0x%016llx..0x%016llx -> 0x%016llx\n",
-			       cpu_addr, cpu_addr + size - 1, pci_addr);
+				iter.cpu_addr, iter.cpu_addr + iter.size - 1,
+				iter.pci_addr);
 
 			/* We support only one IO range */
 			if (hose->pci_io_size) {
@@ -726,11 +695,11 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 				continue;
 			}
 			/* On 32 bits, limit I/O space to 16MB */
-			if (size > 0x01000000)
-				size = 0x01000000;
+			if (iter.size > 0x01000000)
+				iter.size = 0x01000000;
 
 			/* 32 bits needs to map IOs here */
-			hose->io_base_virt = ioremap(cpu_addr, size);
+			hose->io_base_virt = ioremap(iter.cpu_addr, iter.size);
 
 			/* Expect trouble if pci_addr is not 0 */
 			if (primary)
@@ -739,19 +708,18 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 			/* pci_io_size and io_base_phys always represent IO
 			 * space starting at 0 so we factor in pci_addr
 			 */
-			hose->pci_io_size = pci_addr + size;
-			hose->io_base_phys = cpu_addr - pci_addr;
+			hose->pci_io_size = iter.pci_addr + iter.size;
+			hose->io_base_phys = iter.cpu_addr - iter.pci_addr;
 
 			/* Build resource */
 			res = &hose->io_resource;
-			res->flags = IORESOURCE_IO;
-			res->start = pci_addr;
-			break;
-		case 2:		/* PCI Memory space */
-		case 3:		/* PCI 64 bits Memory space */
+			iter.cpu_addr = iter.pci_addr;
+		} else if (iter.flags & IORESOURCE_MEM) {
 			pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
-			       cpu_addr, cpu_addr + size - 1, pci_addr,
-			       (pci_space & 0x40000000) ? "Prefetch" : "");
+				iter.cpu_addr, iter.cpu_addr + iter.size - 1,
+				iter.pci_addr,
+				(iter.pci_space & 0x40000000) ?
+				"Prefetch" : "");
 
 			/* We support only 3 memory ranges */
 			if (memno >= 3) {
@@ -759,13 +727,13 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 				continue;
 			}
 			/* Handles ISA memory hole space here */
-			if (pci_addr == 0) {
+			if (iter.pci_addr == 0) {
 				isa_mb = cpu_addr;
 				isa_hole = memno;
 				if (primary || isa_mem_base == 0)
-					isa_mem_base = cpu_addr;
-				hose->isa_mem_phys = cpu_addr;
-				hose->isa_mem_size = size;
+					isa_mem_base = iter.cpu_addr;
+				hose->isa_mem_phys = iter.cpu_addr;
+				hose->isa_mem_size = iter.size;
 			}
 
 			/* We get the PCI/Mem offset from the first range or
@@ -773,30 +741,22 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 			 * hole. If they don't match, bugger.
 			 */
 			if (memno == 0 ||
-			    (isa_hole >= 0 && pci_addr != 0 &&
+			    (isa_hole >= 0 && iter.pci_addr != 0 &&
 			     hose->pci_mem_offset == isa_mb))
-				hose->pci_mem_offset = cpu_addr - pci_addr;
-			else if (pci_addr != 0 &&
-				 hose->pci_mem_offset != cpu_addr - pci_addr) {
+				hose->pci_mem_offset = iter.cpu_addr
+							- iter.pci_addr;
+			else if (iter.pci_addr != 0 &&
+				 hose->pci_mem_offset != iter.cpu_addr
+							- iter.pci_addr) {
 				pr_info(" \\--> Skipped (offset mismatch) !\n");
 				continue;
 			}
 
 			/* Build resource */
 			res = &hose->mem_resources[memno++];
-			res->flags = IORESOURCE_MEM;
-			if (pci_space & 0x40000000)
-				res->flags |= IORESOURCE_PREFETCH;
-			res->start = cpu_addr;
-			break;
-		}
-		if (res != NULL) {
-			res->name = dev->full_name;
-			res->end = res->start + size - 1;
-			res->parent = NULL;
-			res->sibling = NULL;
-			res->child = NULL;
 		}
+		if (res != NULL)
+			range_iter_fill_resource(iter, dev, res);
 	}
 
 	/* If there's an ISA hole and the pci_mem_offset is -not- matching
arch/mips/pci/pci.c +10 -34

61 lines not on this page · raw message

arch/powerpc/kernel/pci-common.c +27 -66

162 lines not on this page · raw message

drivers/of/address.c +54 -0

60 lines not on this page · raw message

include/linux/of_address.h +31 -0
index 0506eb5..7d5cd11 100644
@@ -4,6 +4,30 @@
 #include <linux/errno.h>
 #include <linux/of.h>
 
+struct of_pci_range_iter {
+	const __be32 *range, *end;
+	int np, pna;
+
+	u32 pci_space;
+	u64 pci_addr;
+	u64 cpu_addr;
+	u64 size;
+	u32 flags;
+};
+
+#define for_each_of_pci_range(iter, np) \
+	for (memset((iter), 0, sizeof(struct of_pci_range_iter)); \
+	     of_pci_process_ranges(iter, np);)
+
+#define range_iter_fill_resource(iter, np, res) \
+	do { \
+		(res)->flags = (iter).flags; \
+		(res)->start = (iter).cpu_addr; \
+		(res)->end = (iter).cpu_addr + (iter).size - 1; \
+		(res)->parent = (res)->child = (res)->sibling = NULL; \
+		(res)->name = (np)->full_name; \
+	} while (0)
+
 #ifdef CONFIG_OF_ADDRESS
 extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
 extern bool of_can_translate_address(struct device_node *dev);
@@ -27,6 +51,8 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
 #define pci_address_to_pio pci_address_to_pio
 #endif
 
+struct of_pci_range_iter *of_pci_process_ranges(struct of_pci_range_iter *iter,
+						struct device_node *node);
 #else /* CONFIG_OF_ADDRESS */
 #ifndef of_address_to_resource
 static inline int of_address_to_resource(struct device_node *dev, int index,
@@ -53,6 +79,11 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index,
 {
 	return NULL;
 }
+struct of_pci_range_iter *of_pci_process_ranges(struct of_pci_range_iter *iter,
+						struct device_node *node)
+{
+	return NULL;
+}
 #endif /* CONFIG_OF_ADDRESS */
 
 
Signature · 1 line
1.7.9.5
#2 lore raw

PATCH v5 1/17 of/pci: Provide support for parsing PCI DT ranges property

Quoted 38 lines · Thomas Petazzoni

From: Andrew Murray <[email protected]>

This patch factors out common implementations patterns to reduce overall kernel code and provide a means for host bridge drivers to directly obtain struct resources from the DT's ranges property without relying on architecture specific DT handling. This will make it easier to write archiecture independent host bridge drivers and mitigate against further duplication of DT parsing code.

This patch can be used in the following way:

        struct of_pci_range_iter iter;
        for_each_of_pci_range(&iter, np) {

                //directly access properties of the address range, e.g.:
                //iter.pci_space, iter.pci_addr, iter.cpu_addr, iter.size or
                //iter.flags

                //alternatively obtain a struct resource, e.g.:
                //struct resource res;
                //range_iter_fill_resource(iter, np, res);
        }

Additionally the implementation takes care of adjacent ranges and merges them into a single range (as was the case with powerpc and microblaze).

The modifications to microblaze, mips and powerpc have not been tested.

---

Compared to the v2 sent by Andrew Murray, Thomas Petazzoni did:

* Add a memset() on the struct of_pci_range_iter when starting the for loop in for_each_pci_range(). Otherwise, with an uninitialized of_pci_range_iter, of_pci_process_ranges() may crash.

Quoted 7 lines

* Add parenthesis around 'res', 'np' and 'iter' in the for_each_of_pci_range macro definitions. Otherwise, passing something like &foobar as 'res' didn't work.

* Rebased on top of 3.9-rc2, which required fixing a few conflicts in the Microblaze code.

The changes here against my v2 look good to me.

#3 lore raw

PATCH v5 1/17 of/pci: Provide support for parsing PCI DT ranges property

In reply to Thomas Petazzoni
Quoted 30 lines · Thomas Petazzoni

From: Andrew Murray <[email protected]>

This patch factors out common implementations patterns to reduce overall kernel code and provide a means for host bridge drivers to directly obtain struct resources from the DT's ranges property without relying on architecture specific DT handling. This will make it easier to write archiecture independent host bridge drivers and mitigate against further duplication of DT parsing code.

This patch can be used in the following way:

	struct of_pci_range_iter iter;
	for_each_of_pci_range(&iter, np) {

		//directly access properties of the address range, e.g.:
		//iter.pci_space, iter.pci_addr, iter.cpu_addr, iter.size or
		//iter.flags

		//alternatively obtain a struct resource, e.g.:
		//struct resource res;
		//range_iter_fill_resource(iter, np, res);
	}

Additionally the implementation takes care of adjacent ranges and merges them into a single range (as was the case with powerpc and microblaze).

The modifications to microblaze, mips and powerpc have not been tested.

Quoted 7 lines

---

Compared to the v2 sent by Andrew Murray, Thomas Petazzoni did:

* Add a memset() on the struct of_pci_range_iter when starting the for loop in for_each_pci_range(). Otherwise, with an uninitialized of_pci_range_iter, of_pci_process_ranges() may crash.

This sounds like you're trying to do too much within the for loop. When we discussed this previously I had a vague idea that this functionality could be wrapped into something a bit more object-like.

What I had in mind was something like:

	struct of_pci_range_parser;
	struct of_pci_range;

	struct of_pci_range_parser parser;
	struct of_pci_range range;

	err = of_pci_range_parser(&parser, np);
	if (err < 0)
		return err;

	for_each_of_pci_range(range, parser) {
		struct resource res;

		...
		usage of range similar to iterator
		...

		of_pci_range_to_resource(&res, &range);
	}

In the above the of_pci_range structure pretty much replaces the iterator and the whole is wrapped up within a parser structure to give some extra flexibility and provides for easier (or more structured) setup compared to doing all of it within the loop statement.

But aside from the (perceived?) increased robustness there's not a lot of technical benefit over your implementation, so it isn't a very hard objection. I find it to be a little more encapsulated and therefore easier to work with, but that's possibly just a matter of taste.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130322/2d6a0f6d/attachment.sig>

#4 lore raw

PATCH v5 1/17 of/pci: Provide support for parsing PCI DT ranges property

Quoted 31 lines · Thierry Reding

This sounds like you're trying to do too much within the for loop. When we discussed this previously I had a vague idea that this functionality could be wrapped into something a bit more object-like.

What I had in mind was something like:

	struct of_pci_range_parser;
	struct of_pci_range;

	struct of_pci_range_parser parser;
	struct of_pci_range range;

	err = of_pci_range_parser(&parser, np);
	if (err < 0)
		return err;

	for_each_of_pci_range(range, parser) {
		struct resource res;

		...
		usage of range similar to iterator
		...

		of_pci_range_to_resource(&res, &range);
	}

In the above the of_pci_range structure pretty much replaces the iterator and the whole is wrapped up within a parser structure to give some extra flexibility and provides for easier (or more structured) setup compared to doing all of it within the loop statement.

Quoted 4 lines

But aside from the (perceived?) increased robustness there's not a lot of technical benefit over your implementation, so it isn't a very hard objection. I find it to be a little more encapsulated and therefore easier to work with, but that's possibly just a matter of taste.

I don't have a strong opinion on this. Andrew, what do you think?

Thomas

Signature · 4 lines
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#5 lore raw

PATCH v5 1/17 of/pci: Provide support for parsing PCI DT ranges property

Quoted 34 lines · Thomas Petazzoni
Quoted 31 lines · Thierry Reding

This sounds like you're trying to do too much within the for loop. When we discussed this previously I had a vague idea that this functionality could be wrapped into something a bit more object-like.

What I had in mind was something like:

	struct of_pci_range_parser;
	struct of_pci_range;

	struct of_pci_range_parser parser;
	struct of_pci_range range;

	err = of_pci_range_parser(&parser, np);
	if (err < 0)
		return err;

	for_each_of_pci_range(range, parser) {
		struct resource res;

		...
		usage of range similar to iterator
		...

		of_pci_range_to_resource(&res, &range);
	}

In the above the of_pci_range structure pretty much replaces the iterator and the whole is wrapped up within a parser structure to give some extra flexibility and provides for easier (or more structured) setup compared to doing all of it within the loop statement.

Quoted 6 lines
Quoted 4 lines

But aside from the (perceived?) increased robustness there's not a lot of technical benefit over your implementation, so it isn't a very hard objection. I find it to be a little more encapsulated and therefore easier to work with, but that's possibly just a matter of taste.

I don't have a strong opinion on this. Andrew, what do you think?

The changes Thierry suggest are subtle but it does look a lot cleaner, it would move the memset elsewhere and probably split the of_pci_process_ranges function into two. I think this is all good. Though I'm not sure when of_pci_range_parser would ever return an error (perhaps if ranges doesn't exist? - should that be treated as an error?).

Perhaps Grant can provide some feedback - the patch originally provided a parser for ARM without adding more arch code - this then became a refactoring exercise for ranges parsing across the kernel. I think this patch has gone as far as it can in that vein without introducing common pci_controller structures. All we need here is a parser that [at least] ARM can use to support the pending ARM host-bridge drivers. Is its current form likely to be acceptable?

I'm happy to update the patch for Thierry's suggestions.

Thanks,

Andrew Murray

#6 lore raw

PATCH v5 2/17 of/pci: Add of_pci_get_devfn() function

In reply to Thomas Petazzoni

From: Thierry Reding <[email protected]>

This function can be used to parse the device and function number from a standard 5-cell PCI resource. PCI_SLOT() and PCI_FUNC() can be used on the returned value obtain the device and function numbers respectively.

---
 drivers/of/of_pci.c    |   34 +++++++++++++++++++++++++++++-----
 include/linux/of_pci.h |    1 +
 2 files changed, 30 insertions(+), 5 deletions(-)
drivers/of/of_pci.c +29 -5
index 13e37e2..4dd7b9b 100644
@@ -5,14 +5,15 @@
 #include <asm/prom.h>
 
 static inline int __of_pci_pci_compare(struct device_node *node,
-				       unsigned int devfn)
+				       unsigned int data)
 {
-	unsigned int size;
-	const __be32 *reg = of_get_property(node, "reg", &size);
+	int devfn;
 
-	if (!reg || size < 5 * sizeof(__be32))
+	devfn = of_pci_get_devfn(node);
+	if (devfn < 0)
 		return 0;
-	return ((be32_to_cpup(&reg[0]) >> 8) & 0xff) == devfn;
+
+	return devfn == data;
 }
 
 struct device_node *of_pci_find_child_device(struct device_node *parent,
@@ -40,3 +41,26 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(of_pci_find_child_device);
+
+/**
+ * of_pci_get_devfn() - Get device and function numbers for a device node
+ * @np: device node
+ *
+ * Parses a standard 5-cell PCI resource and returns an 8-bit value that can
+ * be passed to the PCI_SLOT() and PCI_FUNC() macros to extract the device
+ * and function numbers respectively. On error a negative error code is
+ * returned.
+ */
+int of_pci_get_devfn(struct device_node *np)
+{
+	unsigned int size;
+	const __be32 *reg;
+
+	reg = of_get_property(np, "reg", &size);
+
+	if (!reg || size < 5 * sizeof(__be32))
+		return -EINVAL;
+
+	return (be32_to_cpup(reg) >> 8) & 0xff;
+}
+EXPORT_SYMBOL_GPL(of_pci_get_devfn);
include/linux/of_pci.h +1 -0
index bb115de..91ec484 100644
@@ -10,5 +10,6 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq);
 struct device_node;
 struct device_node *of_pci_find_child_device(struct device_node *parent,
 					     unsigned int devfn);
+int of_pci_get_devfn(struct device_node *np);
 
 #endif
Signature · 1 line
1.7.9.5
#7 lore raw

PATCH v5 3/17 of/pci: Add of_pci_parse_bus_range() function

In reply to Thomas Petazzoni

From: Thierry Reding <[email protected]>

This function can be used to parse a bus-range property as specified by device nodes representing PCI bridges.

---
 drivers/of/of_pci.c    |   25 +++++++++++++++++++++++++
 include/linux/of_pci.h |    1 +
 2 files changed, 26 insertions(+)
drivers/of/of_pci.c +25 -0
index 4dd7b9b..42c687a 100644
@@ -64,3 +64,28 @@ int of_pci_get_devfn(struct device_node *np)
 	return (be32_to_cpup(reg) >> 8) & 0xff;
 }
 EXPORT_SYMBOL_GPL(of_pci_get_devfn);
+
+/**
+ * of_pci_parse_bus_range() - parse the bus-range property of a PCI device
+ * @node: device node
+ * @res: address to a struct resource to return the bus-range
+ *
+ * Returns 0 on success or a negative error-code on failure.
+ */
+int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
+{
+	const __be32 *values;
+	int len;
+
+	values = of_get_property(node, "bus-range", &len);
+	if (!values || len < sizeof(*values) * 2)
+		return -EINVAL;
+
+	res->name = node->name;
+	res->start = be32_to_cpup(values++);
+	res->end = be32_to_cpup(values);
+	res->flags = IORESOURCE_BUS;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
include/linux/of_pci.h +1 -0
index 91ec484..7a04826 100644
@@ -11,5 +11,6 @@ struct device_node;
 struct device_node *of_pci_find_child_device(struct device_node *parent,
 					     unsigned int devfn);
 int of_pci_get_devfn(struct device_node *np);
+int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
 
 #endif
Signature · 1 line
1.7.9.5
#8 lore raw

PATCH v5 4/17 pci: infrastructure to add drivers in drivers/pci/host

In reply to Thomas Petazzoni

As agreed by the community, PCI host drivers will now be stored in drivers/pci/host. This commit adds this directory and the related Kconfig/Makefile changes to allow new drivers to be added in this directory.

---
 drivers/pci/Kconfig      |    2 ++
 drivers/pci/Makefile     |    3 +++
 drivers/pci/host/Kconfig |    4 ++++
 3 files changed, 9 insertions(+)
 create mode 100644 drivers/pci/host/Kconfig
drivers/pci/Kconfig +2 -0
index 6d51aa6..ac45398 100644
@@ -119,3 +119,5 @@ config PCI_IOAPIC
 config PCI_LABEL
 	def_bool y if (DMI || ACPI)
 	select NLS
+
+source "drivers/pci/host/Kconfig"
drivers/pci/Makefile +3 -0
index 0c3efcf..6ebf5bf 100644
@@ -67,3 +67,6 @@ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
 obj-$(CONFIG_OF) += of.o
 
 ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
+
+# PCI host controller drivers
+obj-y += host/
drivers/pci/host/Kconfig new file +4 -0
new file mode 100644
index 0000000..cc3a1af
@@ -0,0 +1,4 @@
+menu "PCI host controller drivers"
+	depends on PCI
+
+endmenu
Signature · 1 line
1.7.9.5
#9 lore raw

PATCH v5 5/17 arm: pci: add a align_resource hook

In reply to Thomas Petazzoni

The PCI specifications says that an I/O region must be aligned on a 4 KB boundary, and a memory region aligned on a 1 MB boundary.

However, the Marvell PCIe interfaces rely on address decoding windows (which allow to associate a range of physical addresses with a given device). For PCIe memory windows, those windows are defined with a 1 MB granularity (which matches the PCI specs), but PCIe I/O windows can only be defined with a 64 KB granularity, so they have to be 64 KB aligned. We therefore need to tell the PCI core about this special alignement requirement.

The PCI core already calls pcibios_align_resource() in the ARM PCI core, specifically for such purposes. So this patch extends the ARM PCI core so that it calls a ->align_resource() hook registered by the PCI driver, exactly like the existing ->map_irq() and ->swizzle() hooks.

A particular PCI driver can register a align_resource() hook, and do its own specific alignement, depending on the specific constraints of the underlying hardware.

---
 arch/arm/include/asm/mach/pci.h |   11 +++++++++++
 arch/arm/kernel/bios32.c        |    6 ++++++
 2 files changed, 17 insertions(+)
arch/arm/include/asm/mach/pci.h +11 -0
index 5cf2e97..7d2c3c8 100644
@@ -30,6 +30,11 @@ struct hw_pci {
 	void		(*postinit)(void);
 	u8		(*swizzle)(struct pci_dev *dev, u8 *pin);
 	int		(*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
+	resource_size_t (*align_resource)(struct pci_dev *dev,
+					  const struct resource *res,
+					  resource_size_t start,
+					  resource_size_t size,
+					  resource_size_t align);
 };
 
 /*
@@ -51,6 +56,12 @@ struct pci_sys_data {
 	u8		(*swizzle)(struct pci_dev *, u8 *);
 					/* IRQ mapping				*/
 	int		(*map_irq)(const struct pci_dev *, u8, u8);
+					/* Resource alignement requirements	*/
+	resource_size_t (*align_resource)(struct pci_dev *dev,
+					  const struct resource *res,
+					  resource_size_t start,
+					  resource_size_t size,
+					  resource_size_t align);
 	void		*private_data;	/* platform controller private data	*/
 };
 
arch/arm/kernel/bios32.c +6 -0
index a1f73b5..b2ed73c 100644
@@ -462,6 +462,7 @@ static void pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
 		sys->busnr   = busnr;
 		sys->swizzle = hw->swizzle;
 		sys->map_irq = hw->map_irq;
+		sys->align_resource = hw->align_resource;
 		INIT_LIST_HEAD(&sys->resources);
 
 		if (hw->private_data)
@@ -574,6 +575,8 @@ char * __init pcibios_setup(char *str)
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 				resource_size_t size, resource_size_t align)
 {
+	struct pci_dev *dev = data;
+	struct pci_sys_data *sys = dev->sysdata;
 	resource_size_t start = res->start;
 
 	if (res->flags & IORESOURCE_IO && start & 0x300)
@@ -581,6 +584,9 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
 
 	start = (start + align - 1) & ~(align - 1);
 
+	if (sys->align_resource)
+		return sys->align_resource(dev, res, start, size, align);
+
 	return start;
 }
 
Signature · 1 line
1.7.9.5
#10 lore raw

PATCH v5 6/17 clk: mvebu: create parent-child relation for PCIe clocks on Armada 370

In reply to Thomas Petazzoni

The Armada 370 has two gatable clocks for each PCIe interface, and we want both of them to be enabled. We therefore make one of the two clocks a child of the other, as we did for the sataX and sataXlnk clocks on Armada XP.

---
 drivers/clk/mvebu/clk-gating-ctrl.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clk/mvebu/clk-gating-ctrl.c +2 -2
index ebf141d..b35785a 100644
@@ -119,8 +119,8 @@ static const struct mvebu_soc_descr __initconst armada_370_gating_descr[] = {
 	{ "pex1_en", NULL,  2 },
 	{ "ge1", NULL, 3 },
 	{ "ge0", NULL, 4 },
-	{ "pex0", NULL, 5 },
-	{ "pex1", NULL, 9 },
+	{ "pex0", "pex0_en", 5 },
+	{ "pex1", "pex1_en", 9 },
 	{ "sata0", NULL, 15 },
 	{ "sdio", NULL, 17 },
 	{ "tdm", NULL, 25 },
Signature · 1 line
1.7.9.5
#11 lore raw

PATCH v5 7/17 clk: mvebu: add more PCIe clocks for Armada XP

In reply to Thomas Petazzoni

The current revision of the datasheet only mentions the gatable clocks for the PCIe 0.0, 0.1, 0.2 and 0.3 interfaces, and forgot to mention the ones for the PCIe 1.0, 1.1, 1.2, 1.3, 2.0 and 3.0 interfaces. After confirmation with Marvell engineers, this patch adds the missing gatable clocks for those PCIe interfaces.

It also changes the name of the previously existing PCIe gatable clocks, in order to match the naming using the datasheets.

---
 drivers/clk/mvebu/clk-gating-ctrl.c |   14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/clk/mvebu/clk-gating-ctrl.c +10 -4
index b35785a..2f03723 100644
@@ -137,10 +137,14 @@ static const struct mvebu_soc_descr __initconst armada_xp_gating_descr[] = {
 	{ "ge2", NULL,  2 },
 	{ "ge1", NULL, 3 },
 	{ "ge0", NULL, 4 },
-	{ "pex0", NULL, 5 },
-	{ "pex1", NULL, 6 },
-	{ "pex2", NULL, 7 },
-	{ "pex3", NULL, 8 },
+	{ "pex00", NULL, 5 },
+	{ "pex01", NULL, 6 },
+	{ "pex02", NULL, 7 },
+	{ "pex03", NULL, 8 },
+	{ "pex10", NULL, 9 },
+	{ "pex11", NULL, 10 },
+	{ "pex12", NULL, 11 },
+	{ "pex13", NULL, 12 },
 	{ "bp", NULL, 13 },
 	{ "sata0lnk", NULL, 14 },
 	{ "sata0", "sata0lnk", 15 },
@@ -152,6 +156,8 @@ static const struct mvebu_soc_descr __initconst armada_xp_gating_descr[] = {
 	{ "xor0", NULL, 22 },
 	{ "crypto", NULL, 23 },
 	{ "tdm", NULL, 25 },
+	{ "pex20", NULL, 26 },
+	{ "pex30", NULL, 27 },
 	{ "xor1", NULL, 28 },
 	{ "sata1lnk", NULL, 29 },
 	{ "sata1", "sata1lnk", 30 },
Signature · 1 line
1.7.9.5
#12 lore raw

PATCH v5 8/17 pci: PCIe driver for Marvell Armada 370/XP systems

In reply to Thomas Petazzoni

This driver implements the support for the PCIe interfaces on the Marvell Armada 370/XP ARM SoCs. In the future, it might be extended to cover earlier families of Marvell SoCs, such as Dove, Orion and Kirkwood.

The driver implements the hw_pci operations needed by the core ARM PCI code to setup PCI devices and get their corresponding IRQs, and the pci_ops operations that are used by the PCI core to read/write the configuration space of PCI devices.

Since the PCIe interfaces of Marvell SoCs are completely separate and not linked together in a bus, this driver sets up an emulated PCI host bridge, with one PCI-to-PCI bridge as child for each hardware PCIe interface.

In addition, this driver enumerates the different PCIe slots, and for those having a device plugged in, it sets up the necessary address decoding windows, using the new armada_370_xp_alloc_pcie_window() function from mach-mvebu/addr-map.c.

---
 .../devicetree/bindings/pci/mvebu-pci.txt          |  201 +++++
 drivers/pci/host/Kconfig                           |    4 +
 drivers/pci/host/Makefile                          |    4 +
 drivers/pci/host/pci-mvebu.c                       |  927 ++++++++++++++++++++
 4 files changed, 1136 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/mvebu-pci.txt
 create mode 100644 drivers/pci/host/Makefile
 create mode 100644 drivers/pci/host/pci-mvebu.c
Documentation/devicetree/bindings/pci/mvebu-pci.txt new file +201 -0
new file mode 100644
index 0000000..192bdfb
@@ -0,0 +1,201 @@
+* Marvell EBU PCIe interfaces
+
+Mandatory properties:
+- compatible: one of the following values:
+    marvell,armada-370-pcie
+    marvell,armada-xp-pcie
+- #address-cells, set to <3>
+- #size-cells, set to <2>
+- #interrupt-cells, set to <1>
+- bus-range: PCI bus numbers covered
+- device_type, set to "pci"
+- reg: list of the PCIe registers for each PCIe interface
+- reg-names: names of the PCIe interfaces, used to find the
+  corresponding registers
+- ranges: ranges for the PCI memory and I/O regions
+
+In addition, the Device Tree node must have sub-nodes describing each
+PCIe interface, having the following mandatory properties:
+- reg: used only for interrupt mapping, so only the first four bytes
+  are used to refer to the correct bus number and device number.
+- clocks: the clock associated to this PCIe interface
+- marvell,pcie-port: the physical PCIe port number
+- status: either "disabled" or "okay"
+- device_type, set to "pci"
+- #address-cells, set to <3>
+- #size-cells, set to <2>
+- #interrupt-cells, set to <1>
+- interrupt-map-mask and interrupt-map, standard PCI properties to
+  define the mapping of the PCIe interface to interrupt numbers.
+
+and the following optional properties:
+- marvell,pcie-lane: the physical PCIe lane number, for ports having
+  multiple lanes. If this property is not found, we assume that the
+  value is 0.
+
+Example:
+
+pcie-controller {
+	compatible = "marvell,armada-xp-pcie";
+	status = "disabled";
+        device_type = "pci";
+
+	#address-cells = <3>;
+	#size-cells = <2>;
+
+	bus-range = <0x00 0xff>;
+
+	reg = <0xd0040000 0x2000>, <0xd0042000 0x2000>,
+	      <0xd0044000 0x2000>, <0xd0048000 0x2000>,
+	      <0xd004C000 0x2000>, <0xd0080000 0x2000>,
+	      <0xd0082000 0x2000>, <0xd0084000 0x2000>,
+	      <0xd0088000 0x2000>, <0xd008C000 0x2000>;
+
+	reg-names = "pcie0.0", "pcie2.0",
+		  "pcie0.1", "pcie0.2",
+		  "pcie0.3", "pcie1.0",
+		  "pcie3.0", "pcie1.1",
+		  "pcie1.2", "pcie1.3";
+
+	ranges = <0x82000000 0 0xe0000000 0xe0000000 0 0x08000000   /* non-prefetchable memory */
+	          0x81000000 0 0          0xe8000000 0 0x00100000>; /* downstream I/O */
+
+	pcie at 1,0 {
+		device_type = "pci";
+		reg = <0x0800 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 58>;
+		marvell,pcie-port = <0>;
+		marvell,pcie-lane = <0>;
+		clocks = <&gateclk 5>;
+		status = "disabled";
+	};
+
+	pcie at 2,0 {
+		device_type = "pci";
+		reg = <0x1000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 59>;
+		marvell,pcie-port = <0>;
+		marvell,pcie-lane = <1>;
+		clocks = <&gateclk 6>;
+		status = "disabled";
+	};
+
+	pcie at 3,0 {
+		device_type = "pci";
+		reg = <0x1800 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 60>;
+		marvell,pcie-port = <0>;
+		marvell,pcie-lane = <2>;
+		clocks = <&gateclk 7>;
+		status = "disabled";
+	};
+
+	pcie at 4,0 {
+		device_type = "pci";
+		reg = <0x2000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 61>;
+		marvell,pcie-port = <0>;
+		marvell,pcie-lane = <3>;
+		clocks = <&gateclk 8>;
+		status = "disabled";
+	};
+
+	pcie at 5,0 {
+		device_type = "pci";
+		reg = <0x2800 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 62>;
+		marvell,pcie-port = <1>;
+		marvell,pcie-lane = <0>;
+		clocks = <&gateclk 9>;
+		status = "disabled";
+	};
+
+	pcie at 6,0 {
+		device_type = "pci";
+		reg = <0x3000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 63>;
+		marvell,pcie-port = <1>;
+		marvell,pcie-lane = <1>;
+		clocks = <&gateclk 10>;
+		status = "disabled";
+	};
+
+	pcie at 7,0 {
+		device_type = "pci";
+		reg = <0x3800 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 64>;
+		marvell,pcie-port = <1>;
+		marvell,pcie-lane = <2>;
+		clocks = <&gateclk 11>;
+		status = "disabled";
+	};
+
+	pcie at 8,0 {
+		device_type = "pci";
+		reg = <0x4000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 65>;
+		marvell,pcie-port = <1>;
+		marvell,pcie-lane = <3>;
+		clocks = <&gateclk 12>;
+		status = "disabled";
+	};
+	pcie at 9,0 {
+		device_type = "pci";
+		reg = <0x4800 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 99>;
+		marvell,pcie-port = <2>;
+		marvell,pcie-lane = <0>;
+		clocks = <&gateclk 26>;
+		status = "disabled";
+	};
+
+	pcie at 10,0 {
+		device_type = "pci";
+		reg = <0x5000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &mpic 103>;
+		marvell,pcie-port = <3>;
+		marvell,pcie-lane = <0>;
+		clocks = <&gateclk 27>;
+		status = "disabled";
+	};
+};
drivers/pci/host/Kconfig +4 -0
index cc3a1af..6918fbc 100644
@@ -1,4 +1,8 @@
 menu "PCI host controller drivers"
 	depends on PCI
 
+config PCI_MVEBU
+	bool "Marvell EBU PCIe controller"
+	depends on ARCH_MVEBU
+
 endmenu
drivers/pci/host/Makefile new file +4 -0
new file mode 100644
index 0000000..3ad563f
@@ -0,0 +1,4 @@
+obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
+CFLAGS_pci-mvebu.o += \
+	-I$(srctree)/arch/arm/plat-orion/include \
+	-I$(srctree)/arch/arm/mach-mvebu/include
drivers/pci/host/pci-mvebu.c new file +927 -0

927 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#13 lore raw

PATCH v5 9/17 arm: mvebu: PCIe support is now available on mvebu

In reply to Thomas Petazzoni

Now that the PCIe driver for mvebu has been integrated and all its relevant dependencies, we can mark the ARCH_MVEBU platform has MIGHT_HAVE_PCI, which allows to select the PCI bus support if needed.

---
 arch/arm/mach-mvebu/Kconfig |    2 ++
 1 file changed, 2 insertions(+)
arch/arm/mach-mvebu/Kconfig +2 -0
index c3715a5..d353249 100644
@@ -14,6 +14,8 @@ config ARCH_MVEBU
 	select MVEBU_CLK_CPU
 	select MVEBU_CLK_GATING
 	select MVEBU_MBUS
+	select MIGHT_HAVE_PCI
+	select PCI_QUIRKS if PCI
 
 if ARCH_MVEBU
 
Signature · 1 line
1.7.9.5
#14 lore raw

PATCH v5 10/17 arm: mvebu: add PCIe Device Tree informations for Armada 370

In reply to Thomas Petazzoni

The Armada 370 SoC has two 1x PCIe 2.0 interfaces, so we add the necessary Device Tree informations to make these interfaces availabel.

---
 arch/arm/boot/dts/armada-370.dtsi |   45 +++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
arch/arm/boot/dts/armada-370.dtsi +45 -0
index 8188d13..b0468fd 100644
@@ -153,5 +153,50 @@
 			clocks = <&coreclk 0>;
 		};
 
+		pcie-controller {
+			compatible = "marvell,armada-370-pcie";
+			status = "disabled";
+			device_type = "pci";
+
+			#address-cells = <3>;
+			#size-cells = <2>;
+
+			bus-range = <0x00 0xff>;
+
+			reg = <0xd0040000 0x2000>, <0xd0080000 0x2000>;
+
+			reg-names = "pcie0.0", "pcie1.0";
+
+			ranges = <0x82000000 0 0xe0000000 0xe0000000 0 0x08000000   /* non-prefetchable memory */
+			          0x81000000 0 0          0xe8000000 0 0x00100000>; /* downstream I/O */
+
+			pcie at 1,0 {
+				device_type = "pci";
+				reg = <0x0800 0 0 0 0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				#interrupt-cells = <1>;
+				interrupt-map-mask = <0 0 0 0>;
+				interrupt-map = <0 0 0 0 &mpic 58>;
+				marvell,pcie-port = <0>;
+				marvell,pcie-lane = <0>;
+				clocks = <&gateclk 5>;
+				status = "disabled";
+			};
+
+			pcie at 2,0 {
+				device_type = "pci";
+				reg = <0x1000 0 0 0 0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				#interrupt-cells = <1>;
+				interrupt-map-mask = <0 0 0 0>;
+				interrupt-map = <0 0 0 0 &mpic 62>;
+				marvell,pcie-port = <1>;
+				marvell,pcie-lane = <0>;
+				clocks = <&gateclk 9>;
+				status = "disabled";
+			};
+		};
 	};
 };
Signature · 1 line
1.7.9.5
#15 lore raw

PATCH v5 11/17 arm: mvebu: add PCIe Device Tree informations for Armada XP

In reply to Thomas Petazzoni

The Armada XP SoCs have multiple PCIe interfaces. The MV78230 has 2 PCIe units (one 4x or quad 1x, the other 1x only), the MV78260 has 3 PCIe units (two 4x or quad 1x and one 4x/1x), the MV78460 has 4 PCIe units (two 4x or quad 1x and two 4x/1x). We therefore add the necessary Device Tree informations to make those PCIe interfaces usable.

---
 arch/arm/boot/dts/armada-xp-mv78230.dtsi |   98 +++++++++++++++++
 arch/arm/boot/dts/armada-xp-mv78260.dtsi |  113 ++++++++++++++++++++
 arch/arm/boot/dts/armada-xp-mv78460.dtsi |  170 ++++++++++++++++++++++++++++++
 3 files changed, 381 insertions(+)
arch/arm/boot/dts/armada-xp-mv78230.dtsi +98 -0
index f56c405..4b05815 100644
@@ -76,5 +76,103 @@
 			#interrupts-cells = <2>;
 			interrupts = <87>, <88>, <89>;
 		};
+
+		/*
+		 * MV78230 has 2 PCIe units Gen2.0: One unit can be
+		 * configured as x4 or quad x1 lanes. One unit is
+		 * x4/x1.
+		 */
+		pcie-controller {
+			compatible = "marvell,armada-xp-pcie";
+			status = "disabled";
+			device_type = "pci";
+
+			#address-cells = <3>;
+			#size-cells = <2>;
+
+			bus-range = <0x00 0xff>;
+
+			reg = <0xd0040000 0x2000>, <0xd0042000 0x2000>,
+			      <0xd0044000 0x2000>, <0xd0048000 0x2000>,
+			      <0xd004C000 0x2000>;
+
+			reg-names = "pcie0.0", "pcie2.0",
+				  "pcie0.1", "pcie0.2",
+				  "pcie0.3";
+
+			ranges = <0x82000000 0 0xe0000000 0xe0000000 0 0x08000000   /* non-prefetchable memory */
+			          0x81000000 0 0          0xe8000000 0 0x00100000>; /* downstream I/O */
+
+
+			pcie at 1,0 {
+				device_type = "pci";
+				reg = <0x0800 0 0 0 0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				#interrupt-cells = <1>;
+				interrupt-map-mask = <0 0 0 0>;
+				interrupt-map = <0 0 0 0 &mpic 58>;
+				marvell,pcie-port = <0>;
+				marvell,pcie-lane = <0>;
+				clocks = <&gateclk 5>;
+				status = "disabled";
+			};
+
+			pcie at 2,0 {
+				device_type = "pci";
+				reg = <0x1000 0 0 0 0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				#interrupt-cells = <1>;
+				interrupt-map-mask = <0 0 0 0>;
+				interrupt-map = <0 0 0 0 &mpic 59>;
+				marvell,pcie-port = <0>;
+				marvell,pcie-lane = <1>;
+				clocks = <&gateclk 6>;
+				status = "disabled";
+			};
+
+			pcie at 3,0 {
+				device_type = "pci";
+				reg = <0x1800 0 0 0 0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				#interrupt-cells = <1>;
+				interrupt-map-mask = <0 0 0 0>;
+				interrupt-map = <0 0 0 0 &mpic 60>;
+				marvell,pcie-port = <0>;
+				marvell,pcie-lane = <2>;
+				clocks = <&gateclk 7>;
+				status = "disabled";
+			};
+
+			pcie at 4,0 {
+				device_type = "pci";
+				reg = <0x2000 0 0 0 0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				#interrupt-cells = <1>;
+				interrupt-map-mask = <0 0 0 0>;
+				interrupt-map = <0 0 0 0 &mpic 61>;
+				marvell,pcie-port = <0>;
+				marvell,pcie-lane = <3>;
+				clocks = <&gateclk 8>;
+				status = "disabled";
+			};
+
+			pcie at 9,0 {
+				device_type = "pci";
+				reg = <0x4800 0 0 0 0>;
+				#address-cells = <3>;
+				#size-cells = <2>;
+				#interrupt-cells = <1>;
+				interrupt-map-mask = <0 0 0 0>;
+				interrupt-map = <0 0 0 0 &mpic 99>;
+				marvell,pcie-port = <2>;
+				marvell,pcie-lane = <0>;
+				clocks = <&gateclk 26>;
+				status = "disabled";
+			};
+		};
 	};
 };
arch/arm/boot/dts/armada-xp-mv78260.dtsi +113 -0

118 lines not on this page · raw message

arch/arm/boot/dts/armada-xp-mv78460.dtsi +170 -0

175 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#16 lore raw

PATCH v5 12/17 arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4

In reply to Thomas Petazzoni

The PlatHome OpenBlocks AX3-4 has an internal mini-PCIe slot that can be used to plug mini-PCIe devices. We therefore enable the PCIe interface that corresponds to this slot.

---
 arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts |    9 +++++++++
 1 file changed, 9 insertions(+)
arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts +9 -0
index 3818a82..5a748bd 100644
@@ -139,5 +139,14 @@
 		usb at d0051000 {
 			status = "okay";
 		};
+
+		pcie-controller {
+			status = "okay";
+			/* Internal mini-PCIe connector */
+			pcie at 1,0 {
+				/* Port 0, Lane 0 */
+				status = "okay";
+			};
+		};
 	};
 };
Signature · 1 line
1.7.9.5
#17 lore raw

PATCH v5 13/17 arm: mvebu: PCIe Device Tree informations for Armada XP DB

In reply to Thomas Petazzoni

The Marvell evaluation board (DB) for the Armada XP SoC has 6 physicals full-size PCIe slots, so we enable the corresponding PCIe interfaces in the Device Tree.

---
 arch/arm/boot/dts/armada-xp-db.dts |   33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
arch/arm/boot/dts/armada-xp-db.dts +33 -0
index e83505e..54cc5bb 100644
@@ -121,5 +121,38 @@
 				spi-max-frequency = <20000000>;
 			};
 		};
+
+		pcie-controller {
+			status = "okay";
+
+			/*
+			 * All 6 slots are physically present as
+			 * standard PCIe slots on the board.
+			 */
+			pcie at 1,0 {
+				/* Port 0, Lane 0 */
+				status = "okay";
+			};
+			pcie at 2,0 {
+				/* Port 0, Lane 1 */
+				status = "okay";
+			};
+			pcie at 3,0 {
+				/* Port 0, Lane 2 */
+				status = "okay";
+			};
+			pcie at 4,0 {
+				/* Port 0, Lane 3 */
+				status = "okay";
+			};
+			pcie at 9,0 {
+				/* Port 2, Lane 0 */
+				status = "okay";
+			};
+			pcie at 10,0 {
+				/* Port 3, Lane 0 */
+				status = "okay";
+			};
+		};
 	};
 };
Signature · 1 line
1.7.9.5
#18 lore raw

PATCH v5 14/17 arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox

In reply to Thomas Petazzoni

The Globalscale Mirabox platform uses one PCIe interface for an available mini-PCIe slot, and the other PCIe interface for an internal USB 3.0 controller. We add the necessary Device Tree informations to enable those two interfaces.

---
 arch/arm/boot/dts/armada-370-mirabox.dts |   16 ++++++++++++++++
 1 file changed, 16 insertions(+)
arch/arm/boot/dts/armada-370-mirabox.dts +16 -0
index dd0c57d..5549de6 100644
@@ -70,5 +70,21 @@
 		usb at d0051000 {
 			status = "okay";
 		};
+
+		pcie-controller {
+			status = "okay";
+
+			/* Internal mini-PCIe connector */
+			pcie at 1,0 {
+				/* Port 0, Lane 0 */
+				status = "okay";
+			};
+
+			/* Connected on the PCB to a USB 3.0 XHCI controller */
+			pcie at 2,0 {
+				/* Port 1, Lane 0 */
+				status = "okay";
+			};
+		};
 	};
 };
Signature · 1 line
1.7.9.5
#19 lore raw

PATCH v5 15/17 arm: mvebu: PCIe Device Tree informations for Armada 370 DB

In reply to Thomas Petazzoni

The Marvell evaluation board (DB) for the Armada 370 SoC has 2 physical full-size PCIe slots, so we enable the corresponding PCIe interfaces in the Device Tree.

---
 arch/arm/boot/dts/armada-370-db.dts |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)
arch/arm/boot/dts/armada-370-db.dts +17 -0
index e34b280..6403acd 100644
@@ -94,5 +94,22 @@
 				spi-max-frequency = <50000000>;
 			};
 		};
+
+		pcie-controller {
+			status = "okay";
+			/*
+			 * The two PCIe units are accessible through
+			 * both standard PCIe slots and mini-PCIe
+			 * slots on the board.
+			 */
+			pcie at 1,0 {
+				/* Port 0, Lane 0 */
+				status = "okay";
+			};
+			pcie at 2,0 {
+				/* Port 1, Lane 0 */
+				status = "okay";
+			};
+		};
 	};
 };
Signature · 1 line
1.7.9.5
#20 lore raw

PATCH v5 16/17 arm: mvebu: PCIe Device Tree informations for Armada XP GP

In reply to Thomas Petazzoni

The Marvell Armada XP GP board has 3 physical full-size PCIe slots, so we enable the corresponding PCIe interfaces in the Device Tree.

---
 arch/arm/boot/dts/armada-xp-gp.dts |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
arch/arm/boot/dts/armada-xp-gp.dts +21 -0
index 1c8afe2..e2bf6b4 100644
@@ -109,5 +109,26 @@
 				spi-max-frequency = <108000000>;
 			};
 		};
+
+		pcie-controller {
+			status = "okay";
+
+			/*
+			 * The 3 slots are physically present as
+			 * standard PCIe slots on the board.
+			 */
+			pcie at 1,0 {
+				/* Port 0, Lane 0 */
+				status = "okay";
+			};
+			pcie at 9,0 {
+				/* Port 2, Lane 0 */
+				status = "okay";
+			};
+			pcie at 10,0 {
+				/* Port 3, Lane 0 */
+				status = "okay";
+			};
+		};
 	};
 };
Signature · 1 line
1.7.9.5
#21 lore raw

PATCH v5 17/17 arm: mvebu: update defconfig with PCI and USB support

In reply to Thomas Petazzoni

Now that we have the necessary drivers and Device Tree informations to support PCIe on Armada 370 and Armada XP, enable the CONFIG_PCI option.

Also, since the Armada 370 Mirabox has a built-in USB XHCI controller connected on the PCIe bus, enable the corresponding options as well.

---
 arch/arm/configs/mvebu_defconfig |    3 +++
 1 file changed, 3 insertions(+)
arch/arm/configs/mvebu_defconfig +3 -0
index 2ec8119..071a5b1 100644
@@ -13,6 +13,8 @@ CONFIG_MACH_ARMADA_370=y
 CONFIG_MACH_ARMADA_XP=y
 # CONFIG_CACHE_L2X0 is not set
 # CONFIG_SWP_EMULATE is not set
+CONFIG_PCI=y
+CONFIG_PCI_MVEBU=y
 CONFIG_SMP=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
@@ -53,6 +55,7 @@ CONFIG_USB_SUPPORT=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_XHCI_HCD=y
 CONFIG_MMC=y
 CONFIG_MMC_MVSDIO=y
 CONFIG_NEW_LEDS=y
Signature · 1 line
1.7.9.5