* [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs
@ 2013-04-09 21:06 Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 01/19] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC Thomas Petazzoni
` (19 more replies)
0 siblings, 20 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Here is the current status of the different patches:
* Patches 1-5 are awaiting a formal Acked-by from the Device Tree
maintainers. Patches 1-3 are the new version of the OF PCI range
parsing functions from Andrew Murray, which he worked on after the
comments from Rob Herring. Patches 4 and 5 are much more trivial
and have been around since many versions of this series.
* Patch 6 and 10, that are touching drivers/pci/ have been formally
Acked-by Bjorn Helgaas, the PCI maintainer.
* Patch 7, which is touching arch/arm/kernel, has been merged by
Russell King already, see
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7683/1.
* Patches 8 and 9 are touching drivers/clk, and are awaiting an
Acked-by from Mike Turquette. However, they are fairly trivial
patches, so they shouldn't cause too much problem.
* All the other patches touch mvebu-specific things, either
mach-mvebu or the related Device Tree files or defconfig, so it's
up to the Marvell maintainers to pick them up.
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-v8
This PATCHv8 follows:
* PATCHv7, sent on March, 27th 2013
* PATCHv6, sent on March, 26st 2013
* PATCHv5, sent on March, 21st 2013
* 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 v7 and v8:
* In the patch introducing the drivers/pci/host directory, add an
empty drivers/pci/host/Makefile to ensure that the kernel still
build. This Makefile will actually gets its first useful line when
the Marvell PCIe driver gets added. Noted by Neil Greatorex.
* Remove bogus (and useless) CFLAGS in drivers/pci/host/Makefile for
the compilation of the Marvell PCIe driver. Noticed by Bjorn
Helgaas.
* Added missing parenthesis in the definition of the
PCIE_BAR_CTRL_OFF macro. Noticed by Bjorn Helgaas.
* Make mvebu_pcie_link_up() return 'bool' instead of 'int'. Suggested
by Bjorn Helgaas.
* Change mvebu_pcie_link_up(), mvebu_pcie_set_local_bus_nr(),
mvebu_pcie_setup_wins(), mvebu_pcie_setup_hw(),
mvebu_pcie_hw_rd_conf(), mvebu_pcie_hw_wr_conf() so that they take
a 'struct mvebu_pcie_port *' instead of a 'void __iomem *' as first
argument. The base address of the PCIe interface register are
available using the 'base' field of 'struct
mvebu_pcie_port'. Suggested by Bjorn Helgaas.
* Fixed multi-line comments that should have been one line
comments. Noticed by Bjorn Helgaas.
* Fixed a for() loop in mvebu_pcie_setup_wins() to use the more
conventional 'ii < 3' ending condition instead of 'i <=
2'. Suggested by Bjorn Helgaas.
* Add a #define instead of an hardcoded magic value when enabling
interrupts A-D in mvebu_pcie_setup_hw(). Suggested by Bjorn
Helgaas.
* Add a PCIE_CONF_ADDR() to simplify the code in
mvebu_pcie_hw_rd_conf() and mvebu_pcie_hw_wr_conf(). Suggested by
Bjorn Helgaas.
* Clarify the comments in mvebu_pcie_handle_iobase_change() and
mvebu_pcie_handle_membase_change() so that it is clear we look at
the new iobase/iolimit (respectively membase/memlimit)
values. Suggested by Bjorn Helgaas.
* Replace mvebu_pcie_find_port_by_bus() and
mvebu_pcie_find_port_by_devfn() by a single mvebu_pcie_find_port()
function, and simplify the mvebu_pcie_rd_conf() and
mvebu_pcie_wr_conf() functions. Suggested by Bjorn Helgaas.
* Fix the computation of the real I/O resource start and end
addresses, according to the suggestions of Arnd Bergmann and Jason
Gunthorpe.
* Remove the MASK/OFFS definition, and use definitions more in the
style of pci_regs.h. Suggested by Bjorn Helgaas.
* Integrate the latest version of 'of/pci: Provide support for
parsing PCI DT ranges property' from Andrew Murray, fixed according
to the review of Rob Herring.
* Added the Acked-by tags from Bjorn Helgaas on the PCI patches.
Changes between v6 and v7:
* Use assigned-addresses in the DT subnodes for the MMIO PCIe
registers, in order to align with what Thierry is doing on the
Tegra PCIe driver.
* Added empty 'ranges;' properties in the subnodes, as requested by
Arnd. Note that due to this, it is not possible to remove the
#address-cells and #size-cells properties from the subnodes, as
Jason Gunthorpe requested, otherwise the DT compiler complains with:
Warning (ranges_format): /soc/pcie-controller/pcie@1,0 has empty
"ranges" property but its #address-cells (2) differs from
/soc/pcie-controller (3)
Warning (ranges_format): /soc/pcie-controller/pcie@1,0 has empty
"ranges" property but its #size-cells (1) differs from
/soc/pcie-controller (2)
* Use the new RFCv3 patch from Andrew Murray for 'of/pci: Provide
support for parsing PCI DT ranges property'.
* Updated the DT binding documentation accordingly.
Changes between v5 and v6:
* Use pci_create_root_bus() + pci_scan_child_bus() instead of
pci_scan_root_bus(). This is needed to be able to add MSI support
later on. Moreover Thierry Reding suggested that
pci_scan_root_bus() "does a pci_bus_add_devices(), which is called
again in pci_common_init() in the ARM code". Thanks Thierry for
pointing out this issue.
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@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 (3):
of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and
PowerPC
of/pci: Provide support for parsing PCI DT ranges property
of/pci: mips: convert to common of_pci_range_parser
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 | 220 +++++
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 | 51 ++
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 | 104 +++
arch/arm/boot/dts/armada-xp-mv78260.dtsi | 122 +++
arch/arm/boot/dts/armada-xp-mv78460.dtsi | 188 +++++
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/include/asm/pci-bridge.h | 5 +-
arch/microblaze/pci/pci-common.c | 192 -----
arch/mips/pci/pci.c | 50 +-
arch/powerpc/include/asm/pci-bridge.h | 5 +-
arch/powerpc/kernel/pci-common.c | 192 -----
drivers/clk/mvebu/clk-gating-ctrl.c | 18 +-
drivers/of/address.c | 63 ++
drivers/of/of_pci.c | 227 ++++-
drivers/pci/Kconfig | 2 +
drivers/pci/Makefile | 3 +
drivers/pci/host/Kconfig | 8 +
drivers/pci/host/Makefile | 1 +
drivers/pci/host/pci-mvebu.c | 879 ++++++++++++++++++++
include/linux/of_address.h | 42 +
include/linux/of_pci.h | 6 +
29 files changed, 2059 insertions(+), 437 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
--
1.7.9.5
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCHv8 01/19] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 02/19] of/pci: Provide support for parsing PCI DT ranges property Thomas Petazzoni
` (18 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray,
Andrew Murray, Liviu Dudau, monstr, benh, paulus, Ralf Baechle
From: Andrew Murray <Andrew.Murray@arm.com>
The pci_process_bridge_OF_ranges function, used to parse the "ranges"
property of a PCI host device, is found in both Microblaze and PowerPC
architectures. These implementations are nearly identical. This patch
moves this common code to a common place.
Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: monstr@monstr.eu
Cc: benh@kernel.crashing.org
Cc: paulus@samba.org
Cc: Ralf Baechle <ralf@linux-mips.org>
---
arch/microblaze/include/asm/pci-bridge.h | 5 +-
arch/microblaze/pci/pci-common.c | 192 ----------------------------
arch/powerpc/include/asm/pci-bridge.h | 5 +-
arch/powerpc/kernel/pci-common.c | 192 ----------------------------
drivers/of/of_pci.c | 200 ++++++++++++++++++++++++++++++
include/linux/of_pci.h | 4 +
6 files changed, 206 insertions(+), 392 deletions(-)
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index cb5d397..5783cd6 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -10,6 +10,7 @@
#include <linux/pci.h>
#include <linux/list.h>
#include <linux/ioport.h>
+#include <linux/of_pci.h>
struct device_node;
@@ -132,10 +133,6 @@ extern void setup_indirect_pci(struct pci_controller *hose,
extern struct pci_controller *pci_find_hose_for_OF_device(
struct device_node *node);
-/* Fill up host controller resources from the OF node */
-extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
- struct device_node *dev, int primary);
-
/* Allocate & free a PCI host bridge structure */
extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
extern void pcibios_free_controller(struct pci_controller *phb);
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 9ea521e..2735ad9 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -622,198 +622,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
*end = rsrc->end - offset;
}
-/**
- * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
- * @hose: newly allocated pci_controller to be setup
- * @dev: device node of the host bridge
- * @primary: set if primary bus (32 bits only, soon to be deprecated)
- *
- * This function will parse the "ranges" property of a PCI host bridge device
- * node and setup the resource mapping of a pci controller based on its
- * content.
- *
- * Life would be boring if it wasn't for a few issues that we have to deal
- * with here:
- *
- * - We can only cope with one IO space range and up to 3 Memory space
- * ranges. However, some machines (thanks Apple !) tend to split their
- * space into lots of small contiguous ranges. So we have to coalesce.
- *
- * - We can only cope with all memory ranges having the same offset
- * between CPU addresses and PCI addresses. Unfortunately, some bridges
- * are setup for a large 1:1 mapping along with a small "window" which
- * maps PCI address 0 to some arbitrary high address of the CPU space in
- * order to give access to the ISA memory hole.
- * The way out of here that I've chosen for now is to always set the
- * offset based on the first resource found, then override it if we
- * have a different offset and the previous was set by an ISA hole.
- *
- * - Some busses have IO space not starting at 0, which causes trouble with
- * the way we do our IO resource renumbering. The code somewhat deals with
- * it for 64 bits but I would expect problems on 32 bits.
- *
- * - Some 32 bits platforms such as 4xx can have physical space larger than
- * 32 bits so we need to use 64 bits values for the parsing
- */
-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;
-
- 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) {
- /* 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;
-
- /* 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)
- 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 */
- pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
- cpu_addr, cpu_addr + size - 1, pci_addr);
-
- /* We support only one IO range */
- if (hose->pci_io_size) {
- pr_info(" \\--> Skipped (too many) !\n");
- continue;
- }
- /* On 32 bits, limit I/O space to 16MB */
- if (size > 0x01000000)
- size = 0x01000000;
-
- /* 32 bits needs to map IOs here */
- hose->io_base_virt = ioremap(cpu_addr, size);
-
- /* Expect trouble if pci_addr is not 0 */
- if (primary)
- isa_io_base =
- (unsigned long)hose->io_base_virt;
- /* 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;
-
- /* 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 */
- pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
- cpu_addr, cpu_addr + size - 1, pci_addr,
- (pci_space & 0x40000000) ? "Prefetch" : "");
-
- /* We support only 3 memory ranges */
- if (memno >= 3) {
- pr_info(" \\--> Skipped (too many) !\n");
- continue;
- }
- /* Handles ISA memory hole space here */
- if (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;
- }
-
- /* We get the PCI/Mem offset from the first range or
- * the, current one if the offset came from an ISA
- * hole. If they don't match, bugger.
- */
- if (memno == 0 ||
- (isa_hole >= 0 && 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) {
- 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 there's an ISA hole and the pci_mem_offset is -not- matching
- * the ISA hole offset, then we need to remove the ISA hole from
- * the resource list for that brige
- */
- if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
- unsigned int next = isa_hole + 1;
- pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
- if (next < memno)
- memmove(&hose->mem_resources[isa_hole],
- &hose->mem_resources[next],
- sizeof(struct resource) * (memno - next));
- hose->mem_resources[--memno].flags = 0;
- }
-}
-
/* Decide whether to display the domain number in /proc */
int pci_proc_domain(struct pci_bus *bus)
{
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 025a130..205bfba 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -10,6 +10,7 @@
#include <linux/pci.h>
#include <linux/list.h>
#include <linux/ioport.h>
+#include <linux/of_pci.h>
#include <asm-generic/pci-bridge.h>
struct device_node;
@@ -231,10 +232,6 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
extern struct pci_controller *pci_find_hose_for_OF_device(
struct device_node* node);
-/* Fill up host controller resources from the OF node */
-extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
- struct device_node *dev, int primary);
-
/* Allocate & free a PCI host bridge structure */
extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
extern void pcibios_free_controller(struct pci_controller *phb);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index fa12ae4..6edf396 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -640,198 +640,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
*end = rsrc->end - offset;
}
-/**
- * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
- * @hose: newly allocated pci_controller to be setup
- * @dev: device node of the host bridge
- * @primary: set if primary bus (32 bits only, soon to be deprecated)
- *
- * This function will parse the "ranges" property of a PCI host bridge device
- * node and setup the resource mapping of a pci controller based on its
- * content.
- *
- * Life would be boring if it wasn't for a few issues that we have to deal
- * with here:
- *
- * - We can only cope with one IO space range and up to 3 Memory space
- * ranges. However, some machines (thanks Apple !) tend to split their
- * space into lots of small contiguous ranges. So we have to coalesce.
- *
- * - We can only cope with all memory ranges having the same offset
- * between CPU addresses and PCI addresses. Unfortunately, some bridges
- * are setup for a large 1:1 mapping along with a small "window" which
- * maps PCI address 0 to some arbitrary high address of the CPU space in
- * order to give access to the ISA memory hole.
- * The way out of here that I've chosen for now is to always set the
- * offset based on the first resource found, then override it if we
- * have a different offset and the previous was set by an ISA hole.
- *
- * - Some busses have IO space not starting at 0, which causes trouble with
- * the way we do our IO resource renumbering. The code somewhat deals with
- * it for 64 bits but I would expect problems on 32 bits.
- *
- * - Some 32 bits platforms such as 4xx can have physical space larger than
- * 32 bits so we need to use 64 bits values for the parsing
- */
-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;
-
- printk(KERN_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 */
- while ((rlen -= np * 4) >= 0) {
- /* 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);
- ranges += np;
-
- /* 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)
- 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 */
- printk(KERN_INFO
- " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
- cpu_addr, cpu_addr + size - 1, pci_addr);
-
- /* We support only one IO range */
- if (hose->pci_io_size) {
- printk(KERN_INFO
- " \\--> Skipped (too many) !\n");
- continue;
- }
-#ifdef CONFIG_PPC32
- /* On 32 bits, limit I/O space to 16MB */
- if (size > 0x01000000)
- size = 0x01000000;
-
- /* 32 bits needs to map IOs here */
- hose->io_base_virt = ioremap(cpu_addr, size);
-
- /* Expect trouble if pci_addr is not 0 */
- if (primary)
- isa_io_base =
- (unsigned long)hose->io_base_virt;
-#endif /* CONFIG_PPC32 */
- /* 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;
-
- /* 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 */
- printk(KERN_INFO
- " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
- cpu_addr, cpu_addr + size - 1, pci_addr,
- (pci_space & 0x40000000) ? "Prefetch" : "");
-
- /* We support only 3 memory ranges */
- if (memno >= 3) {
- printk(KERN_INFO
- " \\--> Skipped (too many) !\n");
- continue;
- }
- /* Handles ISA memory hole space here */
- if (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;
- }
-
- /* We get the PCI/Mem offset from the first range or
- * the, current one if the offset came from an ISA
- * hole. If they don't match, bugger.
- */
- if (memno == 0 ||
- (isa_hole >= 0 && 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) {
- printk(KERN_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 there's an ISA hole and the pci_mem_offset is -not- matching
- * the ISA hole offset, then we need to remove the ISA hole from
- * the resource list for that brige
- */
- if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
- unsigned int next = isa_hole + 1;
- printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
- if (next < memno)
- memmove(&hose->mem_resources[isa_hole],
- &hose->mem_resources[next],
- sizeof(struct resource) * (memno - next));
- hose->mem_resources[--memno].flags = 0;
- }
-}
-
/* Decide whether to display the domain number in /proc */
int pci_proc_domain(struct pci_bus *bus)
{
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 13e37e2..9dd8a10 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -4,6 +4,10 @@
#include <linux/of_pci.h>
#include <asm/prom.h>
+#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
+#include <asm/pci-bridge.h>
+#endif
+
static inline int __of_pci_pci_compare(struct device_node *node,
unsigned int devfn)
{
@@ -40,3 +44,199 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
return NULL;
}
EXPORT_SYMBOL_GPL(of_pci_find_child_device);
+
+/**
+ * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
+ * @hose: newly allocated pci_controller to be setup
+ * @dev: device node of the host bridge
+ * @primary: set if primary bus (32 bits only, soon to be deprecated)
+ *
+ * This function will parse the "ranges" property of a PCI host bridge device
+ * node and setup the resource mapping of a pci controller based on its
+ * content.
+ *
+ * Life would be boring if it wasn't for a few issues that we have to deal
+ * with here:
+ *
+ * - We can only cope with one IO space range and up to 3 Memory space
+ * ranges. However, some machines (thanks Apple !) tend to split their
+ * space into lots of small contiguous ranges. So we have to coalesce.
+ *
+ * - We can only cope with all memory ranges having the same offset
+ * between CPU addresses and PCI addresses. Unfortunately, some bridges
+ * are setup for a large 1:1 mapping along with a small "window" which
+ * maps PCI address 0 to some arbitrary high address of the CPU space in
+ * order to give access to the ISA memory hole.
+ * The way out of here that I've chosen for now is to always set the
+ * offset based on the first resource found, then override it if we
+ * have a different offset and the previous was set by an ISA hole.
+ *
+ * - Some busses have IO space not starting at 0, which causes trouble with
+ * the way we do our IO resource renumbering. The code somewhat deals with
+ * it for 64 bits but I would expect problems on 32 bits.
+ *
+ * - Some 32 bits platforms such as 4xx can have physical space larger than
+ * 32 bits so we need to use 64 bits values for the parsing
+ */
+#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
+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;
+
+ 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) {
+ /* 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;
+
+ /* 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)
+ 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 */
+ pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
+ cpu_addr, cpu_addr + size - 1, pci_addr);
+
+ /* We support only one IO range */
+ if (hose->pci_io_size) {
+ pr_info(" \\--> Skipped (too many) !\n");
+ continue;
+ }
+#if defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)
+ /* On 32 bits, limit I/O space to 16MB */
+ if (size > 0x01000000)
+ size = 0x01000000;
+
+ /* 32 bits needs to map IOs here */
+ hose->io_base_virt = ioremap(cpu_addr, size);
+
+ /* Expect trouble if pci_addr is not 0 */
+ if (primary)
+ isa_io_base =
+ (unsigned long)hose->io_base_virt;
+#endif /* CONFIG_PPC32 || CONFIG_MICROBLAZE */
+ /* 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;
+
+ /* 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 */
+ pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
+ cpu_addr, cpu_addr + size - 1, pci_addr,
+ (pci_space & 0x40000000) ? "Prefetch" : "");
+
+ /* We support only 3 memory ranges */
+ if (memno >= 3) {
+ pr_info(" \\--> Skipped (too many) !\n");
+ continue;
+ }
+ /* Handles ISA memory hole space here */
+ if (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;
+ }
+
+ /* We get the PCI/Mem offset from the first range or
+ * the, current one if the offset came from an ISA
+ * hole. If they don't match, bugger.
+ */
+ if (memno == 0 ||
+ (isa_hole >= 0 && 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) {
+ 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 there's an ISA hole and the pci_mem_offset is -not- matching
+ * the ISA hole offset, then we need to remove the ISA hole from
+ * the resource list for that brige
+ */
+ if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
+ unsigned int next = isa_hole + 1;
+ pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
+ if (next < memno)
+ memmove(&hose->mem_resources[isa_hole],
+ &hose->mem_resources[next],
+ sizeof(struct resource) * (memno - next));
+ hose->mem_resources[--memno].flags = 0;
+ }
+}
+#endif
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index bb115de..e56182f 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -4,6 +4,7 @@
#include <linux/pci.h>
struct pci_dev;
+struct pci_controller;
struct of_irq;
int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq);
@@ -11,4 +12,7 @@ struct device_node;
struct device_node *of_pci_find_child_device(struct device_node *parent,
unsigned int devfn);
+void pci_process_bridge_OF_ranges(struct pci_controller *hose,
+ struct device_node *dev, int primary);
+
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 02/19] of/pci: Provide support for parsing PCI DT ranges property
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 01/19] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 03/19] of/pci: mips: convert to common of_pci_range_parser Thomas Petazzoni
` (17 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray,
Andrew Murray, Liviu Dudau, monstr, benh, paulus, Ralf Baechle
From: Andrew Murray <Andrew.Murray@arm.com>
This patch factors out common implementation 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_parser parser;
struct of_pci_range range;
if (of_pci_range_parser(&parser, np))
; //no ranges property
for_each_of_pci_range(&parser, &range) {
/*
directly access properties of the address range, e.g.:
range.pci_space, range.pci_addr, range.cpu_addr,
range.size, range.flags
alternatively obtain a struct resource, e.g.:
struct resource res;
of_pci_range_to_resource(&range, 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).
Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: monstr@monstr.eu
Cc: benh@kernel.crashing.org
Cc: paulus@samba.org
Cc: Ralf Baechle <ralf@linux-mips.org>
---
drivers/of/address.c | 63 +++++++++++++++++++++++++
drivers/of/of_pci.c | 112 ++++++++++++++++----------------------------
include/linux/of_address.h | 42 +++++++++++++++++
3 files changed, 145 insertions(+), 72 deletions(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 04da786..e87f45e 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -227,6 +227,69 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
}
EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
+
+int of_pci_range_parser(struct of_pci_range_parser *parser,
+ struct device_node *node)
+{
+ const int na = 3, ns = 2;
+ int rlen;
+
+ parser->node = node;
+ parser->pna = of_n_addr_cells(node);
+ parser->np = parser->pna + na + ns;
+
+ parser->range = of_get_property(node, "ranges", &rlen);
+ if (parser->range == NULL)
+ return -ENOENT;
+
+ parser->end = parser->range + rlen / sizeof(__be32);
+
+ return 0;
+}
+
+struct of_pci_range *of_pci_process_ranges(struct of_pci_range_parser *parser,
+ struct of_pci_range *range)
+{
+ const int na = 3, ns = 2;
+
+ if (!parser->range || parser->range + parser->np > parser->end)
+ return NULL;
+
+ range->pci_space = be32_to_cpup(parser->range);
+ range->flags = of_bus_pci_get_flags(parser->range);
+ range->pci_addr = of_read_number(parser->range + 1, ns);
+ range->cpu_addr = of_translate_address(parser->node,
+ parser->range + na);
+ range->size = of_read_number(parser->range + parser->pna + na, ns);
+
+ parser->range += parser->np;
+
+ /* Now consume following elements while they are contiguous */
+ while (parser->range + parser->np <= parser->end) {
+ u32 flags, pci_space;
+ u64 pci_addr, cpu_addr, size;
+
+ pci_space = be32_to_cpup(parser->range);
+ flags = of_bus_pci_get_flags(parser->range);
+ pci_addr = of_read_number(parser->range + 1, ns);
+ cpu_addr = of_translate_address(parser->node,
+ parser->range + na);
+ size = of_read_number(parser->range + parser->pna + na, ns);
+
+ if (flags != range->flags)
+ break;
+ if (pci_addr != range->pci_addr + range->size ||
+ cpu_addr != range->cpu_addr + range->size)
+ break;
+
+ range->size += size;
+ parser->range += parser->np;
+ }
+
+ return range;
+}
+EXPORT_SYMBOL_GPL(of_pci_process_ranges);
+
#endif /* CONFIG_PCI */
/*
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 9dd8a10..ebb408b 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -82,67 +82,43 @@ EXPORT_SYMBOL_GPL(of_pci_find_child_device);
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 range;
+ struct of_pci_range_parser parser;
+ u32 res_type;
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)
+ /* Check for ranges property */
+ if (of_pci_range_parser(&parser, dev))
return;
- /* Parse it */
pr_debug("Parsing ranges property...\n");
- while ((rlen -= np * 4) >= 0) {
+ for_each_of_pci_range(&parser, &range) {
/* 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 ",
+ range.pci_space, range.pci_addr);
+ pr_debug("cpu_addr: 0x%016llx size: 0x%016llx\n",
+ range.cpu_addr, range.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 (range.cpu_addr == OF_BAD_ADDR || range.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 */
+ res_type = range.flags & IORESOURCE_TYPE_BITS;
+ if (res_type == IORESOURCE_IO) {
pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
- cpu_addr, cpu_addr + size - 1, pci_addr);
+ range.cpu_addr, range.cpu_addr + range.size - 1,
+ range.pci_addr);
/* We support only one IO range */
if (hose->pci_io_size) {
@@ -151,11 +127,12 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
}
#if defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)
/* On 32 bits, limit I/O space to 16MB */
- if (size > 0x01000000)
- size = 0x01000000;
+ if (range.size > 0x01000000)
+ range.size = 0x01000000;
/* 32 bits needs to map IOs here */
- hose->io_base_virt = ioremap(cpu_addr, size);
+ hose->io_base_virt = ioremap(range.cpu_addr,
+ range.size);
/* Expect trouble if pci_addr is not 0 */
if (primary)
@@ -165,19 +142,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 = range.pci_addr + range.size;
+ hose->io_base_phys = range.cpu_addr - range.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 */
+ range.cpu_addr = range.pci_addr;
+ } else if (res_type == 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" : "");
+ range.cpu_addr, range.cpu_addr + range.size - 1,
+ range.pci_addr,
+ (range.pci_space & 0x40000000) ?
+ "Prefetch" : "");
/* We support only 3 memory ranges */
if (memno >= 3) {
@@ -185,13 +161,13 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
continue;
}
/* Handles ISA memory hole space here */
- if (pci_addr == 0) {
- isa_mb = cpu_addr;
+ if (range.pci_addr == 0) {
+ isa_mb = range.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 = range.cpu_addr;
+ hose->isa_mem_phys = range.cpu_addr;
+ hose->isa_mem_size = range.size;
}
/* We get the PCI/Mem offset from the first range or
@@ -199,30 +175,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 && range.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 = range.cpu_addr -
+ range.pci_addr;
+ else if (range.pci_addr != 0 &&
+ hose->pci_mem_offset != range.cpu_addr -
+ range.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)
+ of_pci_range_to_resource(&range, dev, res);
}
/* If there's an ISA hole and the pci_mem_offset is -not- matching
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 0506eb5..c7003a3 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -4,6 +4,32 @@
#include <linux/errno.h>
#include <linux/of.h>
+struct of_pci_range_parser {
+ struct device_node *node;
+ const __be32 *range, *end;
+ int np, pna;
+};
+
+struct of_pci_range {
+ u32 pci_space;
+ u64 pci_addr;
+ u64 cpu_addr;
+ u64 size;
+ u32 flags;
+};
+
+#define for_each_of_pci_range(parser, range) \
+ for (; of_pci_process_ranges(parser, range);)
+
+#define of_pci_range_to_resource(range, np, res) \
+ do { \
+ (res)->flags = (range)->flags; \
+ (res)->start = (range)->cpu_addr; \
+ (res)->end = (range)->cpu_addr + (range)->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 +53,10 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
#define pci_address_to_pio pci_address_to_pio
#endif
+int of_pci_range_parser(struct of_pci_range_parser *parser,
+ struct device_node *node);
+struct of_pci_range *of_pci_process_ranges(struct of_pci_range_parser *parser,
+ struct of_pci_range *range);
#else /* CONFIG_OF_ADDRESS */
#ifndef of_address_to_resource
static inline int of_address_to_resource(struct device_node *dev, int index,
@@ -53,6 +83,18 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index,
{
return NULL;
}
+
+int of_pci_range_parser(struct of_pci_range_parser *parser,
+ struct device_noed *node)
+{
+ return -1;
+}
+
+struct of_pci_range *of_pci_process_ranges(struct of_pci_range_parser *parser,
+ struct of_pci_range *range)
+{
+ return NULL;
+}
#endif /* CONFIG_OF_ADDRESS */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 03/19] of/pci: mips: convert to common of_pci_range_parser
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 01/19] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 02/19] of/pci: Provide support for parsing PCI DT ranges property Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 04/19] of/pci: Add of_pci_get_devfn() function Thomas Petazzoni
` (16 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray,
Andrew Murray, Liviu Dudau, monstr, benh, paulus, Ralf Baechle
From: Andrew Murray <Andrew.Murray@arm.com>
This patch converts the pci_load_of_ranges function to use the new
common of_pci_range_parser.
Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: monstr@monstr.eu
Cc: benh@kernel.crashing.org
Cc: paulus@samba.org
Cc: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/pci/pci.c | 50 ++++++++++++++++----------------------------------
1 file changed, 16 insertions(+), 34 deletions(-)
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 0872f12..bee49a4 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -122,51 +122,33 @@ static void pcibios_scanbus(struct pci_controller *hose)
#ifdef CONFIG_OF
void pci_load_of_ranges(struct pci_controller *hose, struct device_node *node)
{
- const __be32 *ranges;
- int rlen;
- int pna = of_n_addr_cells(node);
- int np = pna + 5;
+ struct of_pci_range_range range;
+ struct of_pci_range_parser parser;
+ u32 res_type;
pr_info("PCI host bridge %s ranges:\n", node->full_name);
- ranges = of_get_property(node, "ranges", &rlen);
- if (ranges == NULL)
- return;
hose->of_node = node;
- while ((rlen -= np * 4) >= 0) {
- u32 pci_space;
+ if (of_pci_range_parser(&parser, node))
+ return;
+
+ for_each_of_pci_range(&parser, &range) {
struct resource *res = NULL;
- u64 addr, size;
-
- pci_space = be32_to_cpup(&ranges[0]);
- addr = of_translate_address(node, ranges + 3);
- size = of_read_number(ranges + pna + 3, 2);
- ranges += np;
- switch ((pci_space >> 24) & 0x3) {
- case 1: /* PCI IO space */
+
+ res_type = range.flags & IORESOURCE_TYPE_BITS;
+ if (res_type == IORESOURCE_IO) {
pr_info(" IO 0x%016llx..0x%016llx\n",
- addr, addr + size - 1);
+ range.addr, range.addr + range.size - 1);
hose->io_map_base =
- (unsigned long)ioremap(addr, size);
+ (unsigned long)ioremap(range.addr, range.size);
res = hose->io_resource;
- res->flags = IORESOURCE_IO;
- break;
- case 2: /* PCI Memory space */
- case 3: /* PCI 64 bits Memory space */
+ } else if (res_type == IORESOURCE_MEM) {
pr_info(" MEM 0x%016llx..0x%016llx\n",
- addr, addr + size - 1);
+ range.addr, range.addr + range.size - 1);
res = hose->mem_resource;
- res->flags = IORESOURCE_MEM;
- break;
- }
- if (res != NULL) {
- res->start = addr;
- res->name = node->full_name;
- res->end = res->start + size - 1;
- res->parent = NULL;
- res->sibling = NULL;
- res->child = NULL;
}
+ if (res != NULL)
+ of_pci_range_to_resource(&range, node, res);
}
}
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 04/19] of/pci: Add of_pci_get_devfn() function
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (2 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 03/19] of/pci: mips: convert to common of_pci_range_parser Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-10 18:33 ` Rob Herring
2013-04-09 21:06 ` [PATCHv8 05/19] of/pci: Add of_pci_parse_bus_range() function Thomas Petazzoni
` (15 subsequent siblings)
19 siblings, 1 reply; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
From: Thierry Reding <thierry.reding@avionic-design.de>
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.
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/of/of_pci.c | 34 +++++++++++++++++++++++++++++-----
include/linux/of_pci.h | 1 +
2 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index ebb408b..b77e8d8 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -9,14 +9,15 @@
#endif
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(®[0]) >> 8) & 0xff) == devfn;
+
+ return devfn == data;
}
struct device_node *of_pci_find_child_device(struct device_node *parent,
@@ -208,3 +209,26 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
}
}
#endif
+
+/**
+ * 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);
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index e56182f..302aca0 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -11,6 +11,7 @@ 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);
void pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int primary);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 05/19] of/pci: Add of_pci_parse_bus_range() function
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (3 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 04/19] of/pci: Add of_pci_get_devfn() function Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-10 18:37 ` Rob Herring
2013-04-09 21:06 ` [PATCHv8 06/19] pci: infrastructure to add drivers in drivers/pci/host Thomas Petazzoni
` (14 subsequent siblings)
19 siblings, 1 reply; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
From: Thierry Reding <thierry.reding@avionic-design.de>
This function can be used to parse a bus-range property as specified by
device nodes representing PCI bridges.
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
drivers/of/of_pci.c | 25 +++++++++++++++++++++++++
include/linux/of_pci.h | 1 +
2 files changed, 26 insertions(+)
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index b77e8d8..e9106dc 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -232,3 +232,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);
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 302aca0..be97a6f 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -12,6 +12,7 @@ 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);
void pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int primary);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 06/19] pci: infrastructure to add drivers in drivers/pci/host
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (4 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 05/19] of/pci: Add of_pci_parse_bus_range() function Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 07/19] arm: pci: add a align_resource hook Thomas Petazzoni
` (13 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
---
drivers/pci/Kconfig | 2 ++
drivers/pci/Makefile | 3 +++
drivers/pci/host/Kconfig | 4 ++++
drivers/pci/host/Makefile | 1 +
4 files changed, 10 insertions(+)
create mode 100644 drivers/pci/host/Kconfig
create mode 100644 drivers/pci/host/Makefile
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 6d51aa6..ac45398 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -119,3 +119,5 @@ config PCI_IOAPIC
config PCI_LABEL
def_bool y if (DMI || ACPI)
select NLS
+
+source "drivers/pci/host/Kconfig"
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 0c3efcf..6ebf5bf 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -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/
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
new file mode 100644
index 0000000..cc3a1af
--- /dev/null
+++ b/drivers/pci/host/Kconfig
@@ -0,0 +1,4 @@
+menu "PCI host controller drivers"
+ depends on PCI
+
+endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
new file mode 100644
index 0000000..636bc1a
--- /dev/null
+++ b/drivers/pci/host/Makefile
@@ -0,0 +1 @@
+# intentionally empty
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 07/19] arm: pci: add a align_resource hook
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (5 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 06/19] pci: infrastructure to add drivers in drivers/pci/host Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-15 16:36 ` Jason Cooper
2013-04-09 21:06 ` [PATCHv8 08/19] clk: mvebu: create parent-child relation for PCIe clocks on Armada 370 Thomas Petazzoni
` (12 subsequent siblings)
19 siblings, 1 reply; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Russell King <linux@arm.linux.org.uk>
---
arch/arm/include/asm/mach/pci.h | 11 +++++++++++
arch/arm/kernel/bios32.c | 6 ++++++
2 files changed, 17 insertions(+)
diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
index 5cf2e97..7d2c3c8 100644
--- a/arch/arm/include/asm/mach/pci.h
+++ b/arch/arm/include/asm/mach/pci.h
@@ -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 */
};
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index a1f73b5..b2ed73c 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -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;
}
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 08/19] clk: mvebu: create parent-child relation for PCIe clocks on Armada 370
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (6 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 07/19] arm: pci: add a align_resource hook Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 09/19] clk: mvebu: add more PCIe clocks for Armada XP Thomas Petazzoni
` (11 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray,
Mike Turquette
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Mike Turquette <mturquette@linaro.org>
---
drivers/clk/mvebu/clk-gating-ctrl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/mvebu/clk-gating-ctrl.c b/drivers/clk/mvebu/clk-gating-ctrl.c
index ebf141d..b35785a 100644
--- a/drivers/clk/mvebu/clk-gating-ctrl.c
+++ b/drivers/clk/mvebu/clk-gating-ctrl.c
@@ -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 },
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 09/19] clk: mvebu: add more PCIe clocks for Armada XP
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (7 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 08/19] clk: mvebu: create parent-child relation for PCIe clocks on Armada 370 Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 10/19] pci: PCIe driver for Marvell Armada 370/XP systems Thomas Petazzoni
` (10 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray,
Mike Turquette
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Mike Turquette <mturquette@linaro.org>
---
drivers/clk/mvebu/clk-gating-ctrl.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/mvebu/clk-gating-ctrl.c b/drivers/clk/mvebu/clk-gating-ctrl.c
index b35785a..2f03723 100644
--- a/drivers/clk/mvebu/clk-gating-ctrl.c
+++ b/drivers/clk/mvebu/clk-gating-ctrl.c
@@ -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 },
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 10/19] pci: PCIe driver for Marvell Armada 370/XP systems
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (8 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 09/19] clk: mvebu: add more PCIe clocks for Armada XP Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:12 ` Bjorn Helgaas
2013-04-09 21:06 ` [PATCHv8 11/19] arm: mvebu: PCIe support is now available on mvebu Thomas Petazzoni
` (9 subsequent siblings)
19 siblings, 1 reply; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
---
.../devicetree/bindings/pci/mvebu-pci.txt | 220 +++++
drivers/pci/host/Kconfig | 4 +
drivers/pci/host/Makefile | 2 +-
drivers/pci/host/pci-mvebu.c | 879 ++++++++++++++++++++
4 files changed, 1104 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/pci/mvebu-pci.txt
create mode 100644 drivers/pci/host/pci-mvebu.c
diff --git a/Documentation/devicetree/bindings/pci/mvebu-pci.txt b/Documentation/devicetree/bindings/pci/mvebu-pci.txt
new file mode 100644
index 0000000..eb69d92
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/mvebu-pci.txt
@@ -0,0 +1,220 @@
+* 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"
+- ranges: ranges for the PCI memory and I/O regions, as well as the
+ MMIO registers to control the PCIe interfaces.
+
+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.
+- assigned-addresses: reference to the MMIO registers used to control
+ this PCIe interface.
+- 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>
+- ranges, empty property.
+- 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>;
+
+ ranges = <0x82000000 0 0xd0040000 0xd0040000 0 0x00002000 /* Port 0.0 registers */
+ 0x82000000 0 0xd0042000 0xd0042000 0 0x00002000 /* Port 2.0 registers */
+ 0x82000000 0 0xd0044000 0xd0044000 0 0x00002000 /* Port 0.1 registers */
+ 0x82000000 0 0xd0048000 0xd0048000 0 0x00002000 /* Port 0.2 registers */
+ 0x82000000 0 0xd004c000 0xd004c000 0 0x00002000 /* Port 0.3 registers */
+ 0x82000000 0 0xd0080000 0xd0080000 0 0x00002000 /* Port 1.0 registers */
+ 0x82000000 0 0xd0082000 0xd0082000 0 0x00002000 /* Port 3.0 registers */
+ 0x82000000 0 0xd0084000 0xd0084000 0 0x00002000 /* Port 1.1 registers */
+ 0x82000000 0 0xd0088000 0xd0088000 0 0x00002000 /* Port 1.2 registers */
+ 0x82000000 0 0xd008c000 0xd008c000 0 0x00002000 /* Port 1.3 registers */
+ 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+ pcie@1,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0040000 0 0x2000>;
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@2,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82001000 0 0xd0044000 0 0x2000>;
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@3,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82001800 0 0xd0048000 0 0x2000>;
+ reg = <0x1800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@4,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82002000 0 0xd004c000 0 0x2000>;
+ reg = <0x2000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@5,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82002800 0 0xd0080000 0 0x2000>;
+ reg = <0x2800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@6,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82003000 0 0xd0084000 0 0x2000>;
+ reg = <0x3000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@7,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82003800 0 0xd0088000 0 0x2000>;
+ reg = <0x3800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@8,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82004000 0 0xd008c000 0 0x2000>;
+ reg = <0x4000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@9,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82004800 0 0xd0042000 0 0x2000>;
+ reg = <0x4800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@10,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82005000 0 0xd0082000 0 0x2000>;
+ reg = <0x5000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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";
+ };
+};
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index cc3a1af..6918fbc 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -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
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 636bc1a..5ea2d8b 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -1 +1 @@
-# intentionally empty
+obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
new file mode 100644
index 0000000..9c15a25
--- /dev/null
+++ b/drivers/pci/host/pci-mvebu.c
@@ -0,0 +1,879 @@
+/*
+ * PCIe driver for Marvell Armada 370 and Armada XP SoCs
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/mbus.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+/*
+ * PCIe unit register offsets.
+ */
+#define PCIE_DEV_ID_OFF 0x0000
+#define PCIE_CMD_OFF 0x0004
+#define PCIE_DEV_REV_OFF 0x0008
+#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3))
+#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3))
+#define PCIE_HEADER_LOG_4_OFF 0x0128
+#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4))
+#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
+#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4))
+#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4))
+#define PCIE_WIN5_CTRL_OFF 0x1880
+#define PCIE_WIN5_BASE_OFF 0x1884
+#define PCIE_WIN5_REMAP_OFF 0x188c
+#define PCIE_CONF_ADDR_OFF 0x18f8
+#define PCIE_CONF_ADDR_EN 0x80000000
+#define PCIE_CONF_REG(r) ((((r) & 0xf00) << 16) | ((r) & 0xfc))
+#define PCIE_CONF_BUS(b) (((b) & 0xff) << 16)
+#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 11)
+#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8)
+#define PCIE_CONF_ADDR(bus, devfn, where) \
+ (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where) | \
+ PCIE_CONF_ADDR_EN)
+#define PCIE_CONF_DATA_OFF 0x18fc
+#define PCIE_MASK_OFF 0x1910
+#define PCIE_MASK_ENABLE_INTS 0x0f000000
+#define PCIE_CTRL_OFF 0x1a00
+#define PCIE_CTRL_X1_MODE 0x0001
+#define PCIE_STAT_OFF 0x1a04
+#define PCIE_STAT_BUS 0xff00
+#define PCIE_STAT_LINK_DOWN BIT(1)
+#define PCIE_DEBUG_CTRL 0x1a60
+#define PCIE_DEBUG_SOFT_RESET BIT(20)
+
+/*
+ * This product ID is registered by Marvell, and used when the Marvell
+ * SoC is not the root complex, but an endpoint on the PCIe bus. It is
+ * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI
+ * bridge.
+ */
+#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846
+
+/* PCI configuration space of a PCI-to-PCI bridge */
+struct mvebu_sw_pci_bridge {
+ u16 vendor;
+ u16 device;
+ u16 command;
+ u16 status;
+ u16 class;
+ u8 interface;
+ u8 revision;
+ u8 bist;
+ u8 header_type;
+ u8 latency_timer;
+ u8 cache_line_size;
+ u32 bar[2];
+ u8 primary_bus;
+ u8 secondary_bus;
+ u8 subordinate_bus;
+ u8 secondary_latency_timer;
+ u8 iobase;
+ u8 iolimit;
+ u16 secondary_status;
+ u16 membase;
+ u16 memlimit;
+ u16 prefmembase;
+ u16 prefmemlimit;
+ u32 prefbaseupper;
+ u32 preflimitupper;
+ u16 iobaseupper;
+ u16 iolimitupper;
+ u8 cappointer;
+ u8 reserved1;
+ u16 reserved2;
+ u32 romaddr;
+ u8 intline;
+ u8 intpin;
+ u16 bridgectrl;
+};
+
+struct mvebu_pcie_port;
+
+/* Structure representing all PCIe interfaces */
+struct mvebu_pcie {
+ struct platform_device *pdev;
+ struct mvebu_pcie_port *ports;
+ struct resource io;
+ struct resource realio;
+ struct resource mem;
+ struct resource busn;
+ int nports;
+};
+
+/* Structure representing one PCIe interface */
+struct mvebu_pcie_port {
+ char *name;
+ void __iomem *base;
+ spinlock_t conf_lock;
+ int haslink;
+ u32 port;
+ u32 lane;
+ int devfn;
+ struct clk *clk;
+ struct mvebu_sw_pci_bridge bridge;
+ struct device_node *dn;
+ struct mvebu_pcie *pcie;
+ phys_addr_t memwin_base;
+ size_t memwin_size;
+ phys_addr_t iowin_base;
+ size_t iowin_size;
+};
+
+static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port)
+{
+ return !(readl(port->base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
+}
+
+static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie_port *port, int nr)
+{
+ u32 stat;
+
+ stat = readl(port->base + PCIE_STAT_OFF);
+ stat &= ~PCIE_STAT_BUS;
+ stat |= nr << 8;
+ writel(stat, port->base + PCIE_STAT_OFF);
+}
+
+/*
+ * Setup PCIE BARs and Address Decode Wins:
+ * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
+ * WIN[0-3] -> DRAM bank[0-3]
+ */
+static void __init mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
+{
+ const struct mbus_dram_target_info *dram;
+ u32 size;
+ int i;
+
+ dram = mv_mbus_dram_info();
+
+ /* First, disable and clear BARs and windows. */
+ for (i = 1; i < 3; i++) {
+ writel(0, port->base + PCIE_BAR_CTRL_OFF(i));
+ writel(0, port->base + PCIE_BAR_LO_OFF(i));
+ writel(0, port->base + PCIE_BAR_HI_OFF(i));
+ }
+
+ for (i = 0; i < 5; i++) {
+ writel(0, port->base + PCIE_WIN04_CTRL_OFF(i));
+ writel(0, port->base + PCIE_WIN04_BASE_OFF(i));
+ writel(0, port->base + PCIE_WIN04_REMAP_OFF(i));
+ }
+
+ writel(0, port->base + PCIE_WIN5_CTRL_OFF);
+ writel(0, port->base + PCIE_WIN5_BASE_OFF);
+ writel(0, port->base + PCIE_WIN5_REMAP_OFF);
+
+ /* Setup windows for DDR banks. Count total DDR size on the fly. */
+ size = 0;
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ writel(cs->base & 0xffff0000,
+ port->base + PCIE_WIN04_BASE_OFF(i));
+ writel(0, port->base + PCIE_WIN04_REMAP_OFF(i));
+ writel(((cs->size - 1) & 0xffff0000) |
+ (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ port->base + PCIE_WIN04_CTRL_OFF(i));
+
+ size += cs->size;
+ }
+
+ /* Round up 'size' to the nearest power of two. */
+ if ((size & (size - 1)) != 0)
+ size = 1 << fls(size);
+
+ /* Setup BAR[1] to all DRAM banks. */
+ writel(dram->cs[0].base, port->base + PCIE_BAR_LO_OFF(1));
+ writel(0, port->base + PCIE_BAR_HI_OFF(1));
+ writel(((size - 1) & 0xffff0000) | 1,
+ port->base + PCIE_BAR_CTRL_OFF(1));
+}
+
+static void __init mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
+{
+ u16 cmd;
+ u32 mask;
+
+ /* Point PCIe unit MBUS decode windows to DRAM space. */
+ mvebu_pcie_setup_wins(port);
+
+ /* Master + slave enable. */
+ cmd = readw(port->base + PCIE_CMD_OFF);
+ cmd |= PCI_COMMAND_IO;
+ cmd |= PCI_COMMAND_MEMORY;
+ cmd |= PCI_COMMAND_MASTER;
+ writew(cmd, port->base + PCIE_CMD_OFF);
+
+ /* Enable interrupt lines A-D. */
+ mask = readl(port->base + PCIE_MASK_OFF);
+ mask |= PCIE_MASK_ENABLE_INTS;
+ writel(mask, port->base + PCIE_MASK_OFF);
+}
+
+static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port,
+ struct pci_bus *bus,
+ u32 devfn, int where, int size, u32 *val)
+{
+ writel(PCIE_CONF_ADDR(bus->number, devfn, where),
+ port->base + PCIE_CONF_ADDR_OFF);
+
+ *val = readl(port->base + PCIE_CONF_DATA_OFF);
+
+ if (size == 1)
+ *val = (*val >> (8 * (where & 3))) & 0xff;
+ else if (size == 2)
+ *val = (*val >> (8 * (where & 3))) & 0xffff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port,
+ struct pci_bus *bus,
+ u32 devfn, int where, int size, u32 val)
+{
+ int ret = PCIBIOS_SUCCESSFUL;
+
+ writel(PCIE_CONF_ADDR(bus->number, devfn, where),
+ port->base + PCIE_CONF_ADDR_OFF);
+
+ if (size == 4)
+ writel(val, port->base + PCIE_CONF_DATA_OFF);
+ else if (size == 2)
+ writew(val, port->base + PCIE_CONF_DATA_OFF + (where & 3));
+ else if (size == 1)
+ writeb(val, port->base + PCIE_CONF_DATA_OFF + (where & 3));
+ else
+ ret = PCIBIOS_BAD_REGISTER_NUMBER;
+
+ return ret;
+}
+
+static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
+{
+ phys_addr_t iobase;
+
+ /* Are the new iobase/iolimit values invalid? */
+ if (port->bridge.iolimit < port->bridge.iobase ||
+ port->bridge.iolimitupper < port->bridge.iobaseupper) {
+
+ /* If a window was configured, remove it */
+ if (port->iowin_base) {
+ mvebu_mbus_del_window(port->iowin_base,
+ port->iowin_size);
+ port->iowin_base = 0;
+ port->iowin_size = 0;
+ }
+
+ return;
+ }
+
+ /*
+ * We read the PCI-to-PCI bridge emulated registers, and
+ * calculate the base address and size of the address decoding
+ * window to setup, according to the PCI-to-PCI bridge
+ * specifications. iobase is the bus address, port->iowin_base
+ * is the CPU address.
+ */
+ iobase = ((port->bridge.iobase & 0xF0) << 8) |
+ (port->bridge.iobaseupper << 16);
+ port->iowin_base = port->pcie->io.start + iobase;
+ port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
+ (port->bridge.iolimitupper << 16)) -
+ iobase);
+
+ mvebu_mbus_add_window_remap_flags(port->name, port->iowin_base,
+ port->iowin_size,
+ iobase,
+ MVEBU_MBUS_PCI_IO);
+
+ pci_ioremap_io(iobase, port->iowin_base);
+}
+
+static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
+{
+ /* Are the new membase/memlimit values invalid? */
+ if (port->bridge.memlimit < port->bridge.membase) {
+
+ /* If a window was configured, remove it */
+ if (port->memwin_base) {
+ mvebu_mbus_del_window(port->memwin_base,
+ port->memwin_size);
+ port->memwin_base = 0;
+ port->memwin_size = 0;
+ }
+
+ return;
+ }
+
+ /*
+ * We read the PCI-to-PCI bridge emulated registers, and
+ * calculate the base address and size of the address decoding
+ * window to setup, according to the PCI-to-PCI bridge
+ * specifications.
+ */
+ port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16);
+ port->memwin_size =
+ (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
+ port->memwin_base;
+
+ mvebu_mbus_add_window_remap_flags(port->name, port->memwin_base,
+ port->memwin_size,
+ MVEBU_MBUS_NO_REMAP,
+ MVEBU_MBUS_PCI_MEM);
+}
+
+/*
+ * Initialize the configuration space of the PCI-to-PCI bridge
+ * associated with the given PCIe interface.
+ */
+static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
+{
+ struct mvebu_sw_pci_bridge *bridge = &port->bridge;
+
+ memset(bridge, 0, sizeof(struct mvebu_sw_pci_bridge));
+
+ bridge->status = PCI_STATUS_CAP_LIST;
+ bridge->class = PCI_CLASS_BRIDGE_PCI;
+ bridge->vendor = PCI_VENDOR_ID_MARVELL;
+ bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
+ bridge->header_type = PCI_HEADER_TYPE_BRIDGE;
+ bridge->cache_line_size = 0x10;
+
+ /* We support 32 bits I/O addressing */
+ bridge->iobase = PCI_IO_RANGE_TYPE_32;
+ bridge->iolimit = PCI_IO_RANGE_TYPE_32;
+}
+
+/*
+ * Read the configuration space of the PCI-to-PCI bridge associated to
+ * the given PCIe interface.
+ */
+static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
+ unsigned int where, int size, u32 *value)
+{
+ struct mvebu_sw_pci_bridge *bridge = &port->bridge;
+
+ switch (where & ~3) {
+ case PCI_VENDOR_ID:
+ *value = bridge->device << 16 | bridge->vendor;
+ break;
+
+ case PCI_COMMAND:
+ *value = bridge->status << 16 | bridge->command;
+ break;
+
+ case PCI_CLASS_REVISION:
+ *value = bridge->class << 16 | bridge->interface << 8 |
+ bridge->revision;
+ break;
+
+ case PCI_CACHE_LINE_SIZE:
+ *value = bridge->bist << 24 | bridge->header_type << 16 |
+ bridge->latency_timer << 8 | bridge->cache_line_size;
+ break;
+
+ case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
+ *value = bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4];
+ break;
+
+ case PCI_PRIMARY_BUS:
+ *value = (bridge->secondary_latency_timer << 24 |
+ bridge->subordinate_bus << 16 |
+ bridge->secondary_bus << 8 |
+ bridge->primary_bus);
+ break;
+
+ case PCI_IO_BASE:
+ *value = (bridge->secondary_status << 16 |
+ bridge->iolimit << 8 |
+ bridge->iobase);
+ break;
+
+ case PCI_MEMORY_BASE:
+ *value = (bridge->memlimit << 16 | bridge->membase);
+ break;
+
+ case PCI_PREF_MEMORY_BASE:
+ *value = (bridge->prefmemlimit << 16 | bridge->prefmembase);
+ break;
+
+ case PCI_PREF_BASE_UPPER32:
+ *value = bridge->prefbaseupper;
+ break;
+
+ case PCI_PREF_LIMIT_UPPER32:
+ *value = bridge->preflimitupper;
+ break;
+
+ case PCI_IO_BASE_UPPER16:
+ *value = (bridge->iolimitupper << 16 | bridge->iobaseupper);
+ break;
+
+ case PCI_ROM_ADDRESS1:
+ *value = 0;
+ break;
+
+ default:
+ *value = 0xffffffff;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ if (size == 2)
+ *value = (*value >> (8 * (where & 3))) & 0xffff;
+ else if (size == 1)
+ *value = (*value >> (8 * (where & 3))) & 0xff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/* Write to the PCI-to-PCI bridge configuration space */
+static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
+ unsigned int where, int size, u32 value)
+{
+ struct mvebu_sw_pci_bridge *bridge = &port->bridge;
+ u32 mask, reg;
+ int err;
+
+ if (size == 4)
+ mask = 0x0;
+ else if (size == 2)
+ mask = ~(0xffff << ((where & 3) * 8));
+ else if (size == 1)
+ mask = ~(0xff << ((where & 3) * 8));
+ else
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ err = mvebu_sw_pci_bridge_read(port, where & ~3, 4, ®);
+ if (err)
+ return err;
+
+ value = (reg & mask) | value << ((where & 3) * 8);
+
+ switch (where & ~3) {
+ case PCI_COMMAND:
+ bridge->command = value & 0xffff;
+ bridge->status = value >> 16;
+ break;
+
+ case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
+ bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value;
+ break;
+
+ case PCI_IO_BASE:
+ /*
+ * We also keep bit 1 set, it is a read-only bit that
+ * indicates we support 32 bits addressing for the
+ * I/O
+ */
+ bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32;
+ bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32;
+ bridge->secondary_status = value >> 16;
+ mvebu_pcie_handle_iobase_change(port);
+ break;
+
+ case PCI_MEMORY_BASE:
+ bridge->membase = value & 0xffff;
+ bridge->memlimit = value >> 16;
+ mvebu_pcie_handle_membase_change(port);
+ break;
+
+ case PCI_PREF_MEMORY_BASE:
+ bridge->prefmembase = value & 0xffff;
+ bridge->prefmemlimit = value >> 16;
+ break;
+
+ case PCI_PREF_BASE_UPPER32:
+ bridge->prefbaseupper = value;
+ break;
+
+ case PCI_PREF_LIMIT_UPPER32:
+ bridge->preflimitupper = value;
+ break;
+
+ case PCI_IO_BASE_UPPER16:
+ bridge->iobaseupper = value & 0xffff;
+ bridge->iolimitupper = value >> 16;
+ mvebu_pcie_handle_iobase_change(port);
+ break;
+
+ case PCI_PRIMARY_BUS:
+ bridge->primary_bus = value & 0xff;
+ bridge->secondary_bus = (value >> 8) & 0xff;
+ bridge->subordinate_bus = (value >> 16) & 0xff;
+ bridge->secondary_latency_timer = (value >> 24) & 0xff;
+ mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus);
+ break;
+
+ default:
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys)
+{
+ return sys->private_data;
+}
+
+static struct mvebu_pcie_port *
+mvebu_pcie_find_port(struct mvebu_pcie *pcie, struct pci_bus *bus,
+ int devfn)
+{
+ int i;
+
+ for (i = 0; i < pcie->nports; i++) {
+ struct mvebu_pcie_port *port = &pcie->ports[i];
+ if (bus->number == 0 && port->devfn == devfn)
+ return port;
+ if (bus->number != 0 &&
+ port->bridge.secondary_bus == bus->number)
+ return port;
+ }
+
+ return NULL;
+}
+
+/* PCI configuration space write function */
+static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 val)
+{
+ struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
+ struct mvebu_pcie_port *port;
+ unsigned long flags;
+ int ret;
+
+ port = mvebu_pcie_find_port(pcie, bus, devfn);
+ if (!port)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /* Access the emulated PCI-to-PCI bridge */
+ if (bus->number == 0)
+ return mvebu_sw_pci_bridge_write(port, where, size, val);
+
+ if (!port->haslink || PCI_SLOT(devfn) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /* Access the real PCIe interface */
+ spin_lock_irqsave(&port->conf_lock, flags);
+ ret = mvebu_pcie_hw_wr_conf(port, bus,
+ PCI_DEVFN(1, PCI_FUNC(devfn)),
+ where, size, val);
+ spin_unlock_irqrestore(&port->conf_lock, flags);
+
+ return ret;
+}
+
+/* PCI configuration space read function */
+static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+ int size, u32 *val)
+{
+ struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
+ struct mvebu_pcie_port *port;
+ unsigned long flags;
+ int ret;
+
+ port = mvebu_pcie_find_port(pcie, bus, devfn);
+ if (!port) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ /* Access the emulated PCI-to-PCI bridge */
+ if (bus->number == 0)
+ return mvebu_sw_pci_bridge_read(port, where, size, val);
+
+ if (!port->haslink || PCI_SLOT(devfn) != 0) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ /* Access the real PCIe interface */
+ spin_lock_irqsave(&port->conf_lock, flags);
+ ret = mvebu_pcie_hw_rd_conf(port, bus,
+ PCI_DEVFN(1, PCI_FUNC(devfn)),
+ where, size, val);
+ spin_unlock_irqrestore(&port->conf_lock, flags);
+
+ return ret;
+}
+
+static struct pci_ops mvebu_pcie_ops = {
+ .read = mvebu_pcie_rd_conf,
+ .write = mvebu_pcie_wr_conf,
+};
+
+static int __init mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+ struct mvebu_pcie *pcie = sys_to_pcie(sys);
+ int i;
+
+ pci_add_resource_offset(&sys->resources, &pcie->realio, sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
+ pci_add_resource(&sys->resources, &pcie->busn);
+
+ for (i = 0; i < pcie->nports; i++) {
+ struct mvebu_pcie_port *port = &pcie->ports[i];
+ mvebu_pcie_setup_hw(port);
+ }
+
+ return 1;
+}
+
+static int __init mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct of_irq oirq;
+ int ret;
+
+ ret = of_irq_map_pci(dev, &oirq);
+ if (ret)
+ return ret;
+
+ return irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+}
+
+static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+{
+ struct mvebu_pcie *pcie = sys_to_pcie(sys);
+ struct pci_bus *bus;
+
+ bus = pci_create_root_bus(&pcie->pdev->dev, sys->busnr,
+ &mvebu_pcie_ops, sys, &sys->resources);
+ if (!bus)
+ return NULL;
+
+ pci_scan_child_bus(bus);
+
+ return bus;
+}
+
+resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
+ const struct resource *res,
+ resource_size_t start,
+ resource_size_t size,
+ resource_size_t align)
+{
+ if (dev->bus->number != 0)
+ return start;
+
+ /*
+ * On the PCI-to-PCI bridge side, the I/O windows must have at
+ * least a 64 KB size and be aligned on their size, and the
+ * memory windows must have at least a 1 MB size and be
+ * aligned on their size
+ */
+ if (res->flags & IORESOURCE_IO)
+ return round_up(start, max((resource_size_t)SZ_64K, size));
+ else if (res->flags & IORESOURCE_MEM)
+ return round_up(start, max((resource_size_t)SZ_1M, size));
+ else
+ return start;
+}
+
+static void mvebu_pcie_enable(struct mvebu_pcie *pcie)
+{
+ struct hw_pci hw;
+
+ memset(&hw, 0, sizeof(hw));
+
+ hw.nr_controllers = 1;
+ hw.private_data = (void **)&pcie;
+ hw.setup = mvebu_pcie_setup;
+ hw.scan = mvebu_pcie_scan_bus;
+ hw.map_irq = mvebu_pcie_map_irq;
+ hw.ops = &mvebu_pcie_ops;
+ hw.align_resource = mvebu_pcie_align_resource;
+
+ pci_common_init(&hw);
+}
+
+/*
+ * Looks up the list of register addresses encoded into the reg =
+ * <...> property for one that matches the given port/lane. Once
+ * found, maps it.
+ */
+static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
+ struct device_node *np,
+ struct mvebu_pcie_port *port)
+{
+ struct resource regs;
+ int ret = 0;
+
+ ret = of_address_to_resource(np, 0, ®s);
+ if (ret)
+ return NULL;
+
+ return devm_request_and_ioremap(&pdev->dev, ®s);
+}
+
+static int __init mvebu_pcie_probe(struct platform_device *pdev)
+{
+ struct mvebu_pcie *pcie;
+ struct device_node *np = pdev->dev.of_node;
+ struct of_pci_range range;
+ struct of_pci_range_parser parser;
+ struct device_node *child;
+ int i, ret;
+
+ pcie = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pcie),
+ GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie->pdev = pdev;
+
+ if (of_pci_range_parser(&parser, np))
+ return -EINVAL;
+
+ /* Get the I/O and memory ranges from DT */
+ for_each_of_pci_range(&parser, &range) {
+ unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
+ if (restype == IORESOURCE_IO) {
+ of_pci_range_to_resource(&range, np, &pcie->io);
+ of_pci_range_to_resource(&range, np, &pcie->realio);
+ pcie->io.name = "I/O";
+ pcie->realio.start = max_t(resource_size_t,
+ PCIBIOS_MIN_IO,
+ range.pci_addr);
+ pcie->realio.end = min_t(resource_size_t,
+ IO_SPACE_LIMIT,
+ range.pci_addr + range.size);
+ }
+ if (restype == IORESOURCE_MEM) {
+ of_pci_range_to_resource(&range, np, &pcie->mem);
+ pcie->mem.name = "MEM";
+ }
+ }
+
+ /* Get the bus range */
+ ret = of_pci_parse_bus_range(np, &pcie->busn);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse bus-range property: %d\n",
+ ret);
+ return ret;
+ }
+
+ for_each_child_of_node(pdev->dev.of_node, child) {
+ if (!of_device_is_available(child))
+ continue;
+ pcie->nports++;
+ }
+
+ pcie->ports = devm_kzalloc(&pdev->dev, pcie->nports *
+ sizeof(struct mvebu_pcie_port),
+ GFP_KERNEL);
+ if (!pcie->ports)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_child_of_node(pdev->dev.of_node, child) {
+ struct mvebu_pcie_port *port = &pcie->ports[i];
+
+ if (!of_device_is_available(child))
+ continue;
+
+ port->pcie = pcie;
+
+ if (of_property_read_u32(child, "marvell,pcie-port",
+ &port->port)) {
+ dev_warn(&pdev->dev,
+ "ignoring PCIe DT node, missing pcie-port property\n");
+ continue;
+ }
+
+ if (of_property_read_u32(child, "marvell,pcie-lane",
+ &port->lane))
+ port->lane = 0;
+
+ port->name = kasprintf(GFP_KERNEL, "pcie%d.%d",
+ port->port, port->lane);
+
+ port->devfn = of_pci_get_devfn(child);
+ if (port->devfn < 0)
+ continue;
+
+ port->base = mvebu_pcie_map_registers(pdev, child, port);
+ if (!port->base) {
+ dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
+ port->port, port->lane);
+ continue;
+ }
+
+ if (mvebu_pcie_link_up(port)) {
+ port->haslink = 1;
+ dev_info(&pdev->dev, "PCIe%d.%d: link up\n",
+ port->port, port->lane);
+ } else {
+ port->haslink = 0;
+ dev_info(&pdev->dev, "PCIe%d.%d: link down\n",
+ port->port, port->lane);
+ }
+
+ port->clk = of_clk_get_by_name(child, NULL);
+ if (!port->clk) {
+ dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
+ port->port, port->lane);
+ iounmap(port->base);
+ port->haslink = 0;
+ continue;
+ }
+
+ port->dn = child;
+
+ clk_prepare_enable(port->clk);
+ spin_lock_init(&port->conf_lock);
+
+ mvebu_sw_pci_bridge_init(port);
+
+ i++;
+ }
+
+ mvebu_pcie_enable(pcie);
+
+ return 0;
+}
+
+static const struct of_device_id mvebu_pcie_of_match_table[] = {
+ { .compatible = "marvell,armada-xp-pcie", },
+ { .compatible = "marvell,armada-370-pcie", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver mvebu_pcie_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mvebu-pcie",
+ .of_match_table =
+ of_match_ptr(mvebu_pcie_of_match_table),
+ },
+};
+
+static int mvebu_pcie_init(void)
+{
+ return platform_driver_probe(&mvebu_pcie_driver,
+ mvebu_pcie_probe);
+}
+
+subsys_initcall(mvebu_pcie_init);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell EBU PCIe driver");
+MODULE_LICENSE("GPLv2");
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 11/19] arm: mvebu: PCIe support is now available on mvebu
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (9 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 10/19] pci: PCIe driver for Marvell Armada 370/XP systems Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 12/19] arm: mvebu: add PCIe Device Tree informations for Armada 370 Thomas Petazzoni
` (8 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/mach-mvebu/Kconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index c3715a5..d353249 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -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
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 12/19] arm: mvebu: add PCIe Device Tree informations for Armada 370
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (10 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 11/19] arm: mvebu: PCIe support is now available on mvebu Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-12 0:28 ` Jason Cooper
2013-04-09 21:06 ` [PATCHv8 13/19] arm: mvebu: add PCIe Device Tree informations for Armada XP Thomas Petazzoni
` (7 subsequent siblings)
19 siblings, 1 reply; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
The Armada 370 SoC has two 1x PCIe 2.0 interfaces, so we add the
necessary Device Tree informations to make these interfaces availabel.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-370.dtsi | 51 +++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 8188d13..2d9f8d6 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -153,5 +153,56 @@
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 0xd0040000 0xd0040000 0 0x00002000 /* Port 0.0 registers */
+ 0x82000000 0 0xd0080000 0xd0080000 0 0x00002000 /* Port 1.0 registers */
+ 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+ pcie@1,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0040000 0 0x2000>;
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@2,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82002800 0 0xd0080000 0 0x2000>;
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 13/19] arm: mvebu: add PCIe Device Tree informations for Armada XP
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (11 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 12/19] arm: mvebu: add PCIe Device Tree informations for Armada 370 Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 14/19] arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4 Thomas Petazzoni
` (6 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-xp-mv78230.dtsi | 104 +++++++++++++++++
arch/arm/boot/dts/armada-xp-mv78260.dtsi | 122 +++++++++++++++++++
arch/arm/boot/dts/armada-xp-mv78460.dtsi | 188 ++++++++++++++++++++++++++++++
3 files changed, 414 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-mv78230.dtsi b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
index f56c405..c2c7845 100644
--- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
@@ -76,5 +76,109 @@
#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>;
+
+ ranges = <0x82000000 0 0xd0040000 0xd0040000 0 0x00002000 /* Port 0.0 registers */
+ 0x82000000 0 0xd0042000 0xd0042000 0 0x00002000 /* Port 2.0 registers */
+ 0x82000000 0 0xd0044000 0xd0044000 0 0x00002000 /* Port 0.1 registers */
+ 0x82000000 0 0xd0048000 0xd0048000 0 0x00002000 /* Port 0.2 registers */
+ 0x82000000 0 0xd004c000 0xd004c000 0 0x00002000 /* Port 0.3 registers */
+ 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+ pcie@1,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0040000 0 0x2000>;
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@2,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0044000 0 0x2000>;
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@3,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0048000 0 0x2000>;
+ reg = <0x1800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@4,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd004c000 0 0x2000>;
+ reg = <0x2000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@9,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0042000 0 0x2000>;
+ reg = <0x4800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
index f8f2b78..885bf22 100644
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -96,5 +96,127 @@
clocks = <&gateclk 1>;
status = "disabled";
};
+
+ /*
+ * MV78260 has 3 PCIe units Gen2.0: Two units 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>;
+
+ ranges = <0x82000000 0 0xd0040000 0xd0040000 0 0x00002000 /* Port 0.0 registers */
+ 0x82000000 0 0xd0042000 0xd0042000 0 0x00002000 /* Port 2.0 registers */
+ 0x82000000 0 0xd0044000 0xd0044000 0 0x00002000 /* Port 0.1 registers */
+ 0x82000000 0 0xd0048000 0xd0048000 0 0x00002000 /* Port 0.2 registers */
+ 0x82000000 0 0xd004c000 0xd004c000 0 0x00002000 /* Port 0.3 registers */
+ 0x82000000 0 0xd0080000 0xd0080000 0 0x00002000 /* Port 1.0 registers */
+ 0x82000000 0 0xd0082000 0xd0082000 0 0x00002000 /* Port 3.0 registers */
+ 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+ pcie@1,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0040000 0 0x2000>;
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@2,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0044000 0 0x2000>;
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@3,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0048000 0 0x2000>;
+ reg = <0x1800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@4,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd004c000 0 0x2000>;
+ reg = <0x2000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@9,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0042000 0 0x2000>;
+ reg = <0x4800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@10,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0082000 0 0x2000>;
+ reg = <0x5000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/armada-xp-mv78460.dtsi b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
index 936c25d..23a5ac4 100644
--- a/arch/arm/boot/dts/armada-xp-mv78460.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
@@ -111,5 +111,193 @@
clocks = <&gateclk 1>;
status = "disabled";
};
+
+ /*
+ * MV78460 has 4 PCIe units Gen2.0: Two units can be
+ * configured as x4 or quad x1 lanes. Two units are
+ * x4/x1.
+ */
+ pcie-controller {
+ compatible = "marvell,armada-xp-pcie";
+ status = "disabled";
+ device_type = "pci";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ ranges = <0x82000000 0 0xd0040000 0xd0040000 0 0x00002000 /* Port 0.0 registers */
+ 0x82000000 0 0xd0042000 0xd0042000 0 0x00002000 /* Port 2.0 registers */
+ 0x82000000 0 0xd0044000 0xd0044000 0 0x00002000 /* Port 0.1 registers */
+ 0x82000000 0 0xd0048000 0xd0048000 0 0x00002000 /* Port 0.2 registers */
+ 0x82000000 0 0xd004c000 0xd004c000 0 0x00002000 /* Port 0.3 registers */
+ 0x82000000 0 0xd0080000 0xd0080000 0 0x00002000 /* Port 1.0 registers */
+ 0x82000000 0 0xd0082000 0xd0082000 0 0x00002000 /* Port 3.0 registers */
+ 0x82000000 0 0xd0084000 0xd0084000 0 0x00002000 /* Port 1.1 registers */
+ 0x82000000 0 0xd0088000 0xd0088000 0 0x00002000 /* Port 1.2 registers */
+ 0x82000000 0 0xd008c000 0xd008c000 0 0x00002000 /* Port 1.3 registers */
+ 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+ pcie@1,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82000800 0 0xd0040000 0 0x2000>;
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@2,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82001000 0 0xd0044000 0 0x2000>;
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@3,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82001800 0 0xd0048000 0 0x2000>;
+ reg = <0x1800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@4,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82002000 0 0xd004c000 0 0x2000>;
+ reg = <0x2000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@5,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82002800 0 0xd0080000 0 0x2000>;
+ reg = <0x2800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@6,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82003000 0 0xd0084000 0 0x2000>;
+ reg = <0x3000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@7,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82003800 0 0xd0088000 0 0x2000>;
+ reg = <0x3800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@8,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82004000 0 0xd008c000 0 0x2000>;
+ reg = <0x4000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@9,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82004800 0 0xd0042000 0 0x2000>;
+ reg = <0x4800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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@10,0 {
+ device_type = "pci";
+ assigned-addresses = <0x82005000 0 0xd0082000 0 0x2000>;
+ reg = <0x5000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges;
+ 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";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 14/19] arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (12 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 13/19] arm: mvebu: add PCIe Device Tree informations for Armada XP Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 15/19] arm: mvebu: PCIe Device Tree informations for Armada XP DB Thomas Petazzoni
` (5 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
index 3818a82..5a748bd 100644
--- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
+++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
@@ -139,5 +139,14 @@
usb@d0051000 {
status = "okay";
};
+
+ pcie-controller {
+ status = "okay";
+ /* Internal mini-PCIe connector */
+ pcie@1,0 {
+ /* Port 0, Lane 0 */
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 15/19] arm: mvebu: PCIe Device Tree informations for Armada XP DB
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (13 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 14/19] arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4 Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 16/19] arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox Thomas Petazzoni
` (4 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-xp-db.dts | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index e83505e..54cc5bb 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -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@1,0 {
+ /* Port 0, Lane 0 */
+ status = "okay";
+ };
+ pcie@2,0 {
+ /* Port 0, Lane 1 */
+ status = "okay";
+ };
+ pcie@3,0 {
+ /* Port 0, Lane 2 */
+ status = "okay";
+ };
+ pcie@4,0 {
+ /* Port 0, Lane 3 */
+ status = "okay";
+ };
+ pcie@9,0 {
+ /* Port 2, Lane 0 */
+ status = "okay";
+ };
+ pcie@10,0 {
+ /* Port 3, Lane 0 */
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 16/19] arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (14 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 15/19] arm: mvebu: PCIe Device Tree informations for Armada XP DB Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 17/19] arm: mvebu: PCIe Device Tree informations for Armada 370 DB Thomas Petazzoni
` (3 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-370-mirabox.dts | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index dd0c57d..5549de6 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -70,5 +70,21 @@
usb@d0051000 {
status = "okay";
};
+
+ pcie-controller {
+ status = "okay";
+
+ /* Internal mini-PCIe connector */
+ pcie@1,0 {
+ /* Port 0, Lane 0 */
+ status = "okay";
+ };
+
+ /* Connected on the PCB to a USB 3.0 XHCI controller */
+ pcie@2,0 {
+ /* Port 1, Lane 0 */
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 17/19] arm: mvebu: PCIe Device Tree informations for Armada 370 DB
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (15 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 16/19] arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 18/19] arm: mvebu: PCIe Device Tree informations for Armada XP GP Thomas Petazzoni
` (2 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-370-db.dts | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index e34b280..6403acd 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -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@1,0 {
+ /* Port 0, Lane 0 */
+ status = "okay";
+ };
+ pcie@2,0 {
+ /* Port 1, Lane 0 */
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 18/19] arm: mvebu: PCIe Device Tree informations for Armada XP GP
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (16 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 17/19] arm: mvebu: PCIe Device Tree informations for Armada 370 DB Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 19/19] arm: mvebu: update defconfig with PCI and USB support Thomas Petazzoni
2013-04-15 15:46 ` [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Jason Cooper
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
The Marvell Armada XP GP board has 3 physical full-size PCIe slots, so
we enable the corresponding PCIe interfaces in the Device Tree.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-xp-gp.dts | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index 1c8afe2..e2bf6b4 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -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@1,0 {
+ /* Port 0, Lane 0 */
+ status = "okay";
+ };
+ pcie@9,0 {
+ /* Port 2, Lane 0 */
+ status = "okay";
+ };
+ pcie@10,0 {
+ /* Port 3, Lane 0 */
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCHv8 19/19] arm: mvebu: update defconfig with PCI and USB support
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (17 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 18/19] arm: mvebu: PCIe Device Tree informations for Armada XP GP Thomas Petazzoni
@ 2013-04-09 21:06 ` Thomas Petazzoni
2013-04-15 15:46 ` [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Jason Cooper
19 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:06 UTC (permalink / raw)
To: Bjorn Helgaas, Grant Likely, Russell King
Cc: linux-pci, linux-arm-kernel, devicetree-discuss, Lior Amsalem,
Andrew Lunn, Jason Cooper, Arnd Bergmann, Maen Suleiman,
Thierry Reding, Gregory Clement, Ezequiel Garcia, Olof Johansson,
Tawfik Bayouk, Jason Gunthorpe, Mitch Bradley, Andrew Murray
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.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/configs/mvebu_defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig
index 2ec8119..071a5b1 100644
--- a/arch/arm/configs/mvebu_defconfig
+++ b/arch/arm/configs/mvebu_defconfig
@@ -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
--
1.7.9.5
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCHv8 10/19] pci: PCIe driver for Marvell Armada 370/XP systems
2013-04-09 21:06 ` [PATCHv8 10/19] pci: PCIe driver for Marvell Armada 370/XP systems Thomas Petazzoni
@ 2013-04-09 21:12 ` Bjorn Helgaas
2013-04-09 21:22 ` Thomas Petazzoni
0 siblings, 1 reply; 33+ messages in thread
From: Bjorn Helgaas @ 2013-04-09 21:12 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: Grant Likely, Russell King, linux-pci@vger.kernel.org, linux-arm,
devicetree-discuss@lists.ozlabs.org, Lior Amsalem, Andrew Lunn,
Jason Cooper, Arnd Bergmann, Maen Suleiman, Thierry Reding,
Gregory Clement, Ezequiel Garcia, Olof Johansson, Tawfik Bayouk,
Jason Gunthorpe, Mitch Bradley, Andrew Murray
On Tue, Apr 9, 2013 at 3:06 PM, Thomas Petazzoni
<thomas.petazzoni@free-electrons.com> wrote:
> 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.
>
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
This and 06/19 look good to me.
> ---
> .../devicetree/bindings/pci/mvebu-pci.txt | 220 +++++
> drivers/pci/host/Kconfig | 4 +
> drivers/pci/host/Makefile | 2 +-
> drivers/pci/host/pci-mvebu.c | 879 ++++++++++++++++++++
> 4 files changed, 1104 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/devicetree/bindings/pci/mvebu-pci.txt
> create mode 100644 drivers/pci/host/pci-mvebu.c
>
> diff --git a/Documentation/devicetree/bindings/pci/mvebu-pci.txt b/Documentation/devicetree/bindings/pci/mvebu-pci.txt
> new file mode 100644
> index 0000000..eb69d92
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/mvebu-pci.txt
> @@ -0,0 +1,220 @@
> +* 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"
> +- ranges: ranges for the PCI memory and I/O regions, as well as the
> + MMIO registers to control the PCIe interfaces.
> +
> +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.
> +- assigned-addresses: reference to the MMIO registers used to control
> + this PCIe interface.
> +- 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>
> +- ranges, empty property.
> +- 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>;
> +
> + ranges = <0x82000000 0 0xd0040000 0xd0040000 0 0x00002000 /* Port 0.0 registers */
> + 0x82000000 0 0xd0042000 0xd0042000 0 0x00002000 /* Port 2.0 registers */
> + 0x82000000 0 0xd0044000 0xd0044000 0 0x00002000 /* Port 0.1 registers */
> + 0x82000000 0 0xd0048000 0xd0048000 0 0x00002000 /* Port 0.2 registers */
> + 0x82000000 0 0xd004c000 0xd004c000 0 0x00002000 /* Port 0.3 registers */
> + 0x82000000 0 0xd0080000 0xd0080000 0 0x00002000 /* Port 1.0 registers */
> + 0x82000000 0 0xd0082000 0xd0082000 0 0x00002000 /* Port 3.0 registers */
> + 0x82000000 0 0xd0084000 0xd0084000 0 0x00002000 /* Port 1.1 registers */
> + 0x82000000 0 0xd0088000 0xd0088000 0 0x00002000 /* Port 1.2 registers */
> + 0x82000000 0 0xd008c000 0xd008c000 0 0x00002000 /* Port 1.3 registers */
> + 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
> + 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
> +
> + pcie@1,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82000800 0 0xd0040000 0 0x2000>;
> + reg = <0x0800 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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@2,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82001000 0 0xd0044000 0 0x2000>;
> + reg = <0x1000 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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@3,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82001800 0 0xd0048000 0 0x2000>;
> + reg = <0x1800 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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@4,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82002000 0 0xd004c000 0 0x2000>;
> + reg = <0x2000 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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@5,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82002800 0 0xd0080000 0 0x2000>;
> + reg = <0x2800 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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@6,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82003000 0 0xd0084000 0 0x2000>;
> + reg = <0x3000 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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@7,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82003800 0 0xd0088000 0 0x2000>;
> + reg = <0x3800 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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@8,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82004000 0 0xd008c000 0 0x2000>;
> + reg = <0x4000 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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@9,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82004800 0 0xd0042000 0 0x2000>;
> + reg = <0x4800 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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@10,0 {
> + device_type = "pci";
> + assigned-addresses = <0x82005000 0 0xd0082000 0 0x2000>;
> + reg = <0x5000 0 0 0 0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + #interrupt-cells = <1>;
> + ranges;
> + 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";
> + };
> +};
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index cc3a1af..6918fbc 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -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
> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> index 636bc1a..5ea2d8b 100644
> --- a/drivers/pci/host/Makefile
> +++ b/drivers/pci/host/Makefile
> @@ -1 +1 @@
> -# intentionally empty
> +obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
> diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
> new file mode 100644
> index 0000000..9c15a25
> --- /dev/null
> +++ b/drivers/pci/host/pci-mvebu.c
> @@ -0,0 +1,879 @@
> +/*
> + * PCIe driver for Marvell Armada 370 and Armada XP SoCs
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/pci.h>
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <linux/mbus.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_address.h>
> +#include <linux/of_pci.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +
> +/*
> + * PCIe unit register offsets.
> + */
> +#define PCIE_DEV_ID_OFF 0x0000
> +#define PCIE_CMD_OFF 0x0004
> +#define PCIE_DEV_REV_OFF 0x0008
> +#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3))
> +#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3))
> +#define PCIE_HEADER_LOG_4_OFF 0x0128
> +#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4))
> +#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
> +#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4))
> +#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4))
> +#define PCIE_WIN5_CTRL_OFF 0x1880
> +#define PCIE_WIN5_BASE_OFF 0x1884
> +#define PCIE_WIN5_REMAP_OFF 0x188c
> +#define PCIE_CONF_ADDR_OFF 0x18f8
> +#define PCIE_CONF_ADDR_EN 0x80000000
> +#define PCIE_CONF_REG(r) ((((r) & 0xf00) << 16) | ((r) & 0xfc))
> +#define PCIE_CONF_BUS(b) (((b) & 0xff) << 16)
> +#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 11)
> +#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8)
> +#define PCIE_CONF_ADDR(bus, devfn, where) \
> + (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \
> + PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where) | \
> + PCIE_CONF_ADDR_EN)
> +#define PCIE_CONF_DATA_OFF 0x18fc
> +#define PCIE_MASK_OFF 0x1910
> +#define PCIE_MASK_ENABLE_INTS 0x0f000000
> +#define PCIE_CTRL_OFF 0x1a00
> +#define PCIE_CTRL_X1_MODE 0x0001
> +#define PCIE_STAT_OFF 0x1a04
> +#define PCIE_STAT_BUS 0xff00
> +#define PCIE_STAT_LINK_DOWN BIT(1)
> +#define PCIE_DEBUG_CTRL 0x1a60
> +#define PCIE_DEBUG_SOFT_RESET BIT(20)
> +
> +/*
> + * This product ID is registered by Marvell, and used when the Marvell
> + * SoC is not the root complex, but an endpoint on the PCIe bus. It is
> + * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI
> + * bridge.
> + */
> +#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846
> +
> +/* PCI configuration space of a PCI-to-PCI bridge */
> +struct mvebu_sw_pci_bridge {
> + u16 vendor;
> + u16 device;
> + u16 command;
> + u16 status;
> + u16 class;
> + u8 interface;
> + u8 revision;
> + u8 bist;
> + u8 header_type;
> + u8 latency_timer;
> + u8 cache_line_size;
> + u32 bar[2];
> + u8 primary_bus;
> + u8 secondary_bus;
> + u8 subordinate_bus;
> + u8 secondary_latency_timer;
> + u8 iobase;
> + u8 iolimit;
> + u16 secondary_status;
> + u16 membase;
> + u16 memlimit;
> + u16 prefmembase;
> + u16 prefmemlimit;
> + u32 prefbaseupper;
> + u32 preflimitupper;
> + u16 iobaseupper;
> + u16 iolimitupper;
> + u8 cappointer;
> + u8 reserved1;
> + u16 reserved2;
> + u32 romaddr;
> + u8 intline;
> + u8 intpin;
> + u16 bridgectrl;
> +};
> +
> +struct mvebu_pcie_port;
> +
> +/* Structure representing all PCIe interfaces */
> +struct mvebu_pcie {
> + struct platform_device *pdev;
> + struct mvebu_pcie_port *ports;
> + struct resource io;
> + struct resource realio;
> + struct resource mem;
> + struct resource busn;
> + int nports;
> +};
> +
> +/* Structure representing one PCIe interface */
> +struct mvebu_pcie_port {
> + char *name;
> + void __iomem *base;
> + spinlock_t conf_lock;
> + int haslink;
> + u32 port;
> + u32 lane;
> + int devfn;
> + struct clk *clk;
> + struct mvebu_sw_pci_bridge bridge;
> + struct device_node *dn;
> + struct mvebu_pcie *pcie;
> + phys_addr_t memwin_base;
> + size_t memwin_size;
> + phys_addr_t iowin_base;
> + size_t iowin_size;
> +};
> +
> +static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port)
> +{
> + return !(readl(port->base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
> +}
> +
> +static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie_port *port, int nr)
> +{
> + u32 stat;
> +
> + stat = readl(port->base + PCIE_STAT_OFF);
> + stat &= ~PCIE_STAT_BUS;
> + stat |= nr << 8;
> + writel(stat, port->base + PCIE_STAT_OFF);
> +}
> +
> +/*
> + * Setup PCIE BARs and Address Decode Wins:
> + * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
> + * WIN[0-3] -> DRAM bank[0-3]
> + */
> +static void __init mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
> +{
> + const struct mbus_dram_target_info *dram;
> + u32 size;
> + int i;
> +
> + dram = mv_mbus_dram_info();
> +
> + /* First, disable and clear BARs and windows. */
> + for (i = 1; i < 3; i++) {
> + writel(0, port->base + PCIE_BAR_CTRL_OFF(i));
> + writel(0, port->base + PCIE_BAR_LO_OFF(i));
> + writel(0, port->base + PCIE_BAR_HI_OFF(i));
> + }
> +
> + for (i = 0; i < 5; i++) {
> + writel(0, port->base + PCIE_WIN04_CTRL_OFF(i));
> + writel(0, port->base + PCIE_WIN04_BASE_OFF(i));
> + writel(0, port->base + PCIE_WIN04_REMAP_OFF(i));
> + }
> +
> + writel(0, port->base + PCIE_WIN5_CTRL_OFF);
> + writel(0, port->base + PCIE_WIN5_BASE_OFF);
> + writel(0, port->base + PCIE_WIN5_REMAP_OFF);
> +
> + /* Setup windows for DDR banks. Count total DDR size on the fly. */
> + size = 0;
> + for (i = 0; i < dram->num_cs; i++) {
> + const struct mbus_dram_window *cs = dram->cs + i;
> +
> + writel(cs->base & 0xffff0000,
> + port->base + PCIE_WIN04_BASE_OFF(i));
> + writel(0, port->base + PCIE_WIN04_REMAP_OFF(i));
> + writel(((cs->size - 1) & 0xffff0000) |
> + (cs->mbus_attr << 8) |
> + (dram->mbus_dram_target_id << 4) | 1,
> + port->base + PCIE_WIN04_CTRL_OFF(i));
> +
> + size += cs->size;
> + }
> +
> + /* Round up 'size' to the nearest power of two. */
> + if ((size & (size - 1)) != 0)
> + size = 1 << fls(size);
> +
> + /* Setup BAR[1] to all DRAM banks. */
> + writel(dram->cs[0].base, port->base + PCIE_BAR_LO_OFF(1));
> + writel(0, port->base + PCIE_BAR_HI_OFF(1));
> + writel(((size - 1) & 0xffff0000) | 1,
> + port->base + PCIE_BAR_CTRL_OFF(1));
> +}
> +
> +static void __init mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
> +{
> + u16 cmd;
> + u32 mask;
> +
> + /* Point PCIe unit MBUS decode windows to DRAM space. */
> + mvebu_pcie_setup_wins(port);
> +
> + /* Master + slave enable. */
> + cmd = readw(port->base + PCIE_CMD_OFF);
> + cmd |= PCI_COMMAND_IO;
> + cmd |= PCI_COMMAND_MEMORY;
> + cmd |= PCI_COMMAND_MASTER;
> + writew(cmd, port->base + PCIE_CMD_OFF);
> +
> + /* Enable interrupt lines A-D. */
> + mask = readl(port->base + PCIE_MASK_OFF);
> + mask |= PCIE_MASK_ENABLE_INTS;
> + writel(mask, port->base + PCIE_MASK_OFF);
> +}
> +
> +static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port,
> + struct pci_bus *bus,
> + u32 devfn, int where, int size, u32 *val)
> +{
> + writel(PCIE_CONF_ADDR(bus->number, devfn, where),
> + port->base + PCIE_CONF_ADDR_OFF);
> +
> + *val = readl(port->base + PCIE_CONF_DATA_OFF);
> +
> + if (size == 1)
> + *val = (*val >> (8 * (where & 3))) & 0xff;
> + else if (size == 2)
> + *val = (*val >> (8 * (where & 3))) & 0xffff;
> +
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port,
> + struct pci_bus *bus,
> + u32 devfn, int where, int size, u32 val)
> +{
> + int ret = PCIBIOS_SUCCESSFUL;
> +
> + writel(PCIE_CONF_ADDR(bus->number, devfn, where),
> + port->base + PCIE_CONF_ADDR_OFF);
> +
> + if (size == 4)
> + writel(val, port->base + PCIE_CONF_DATA_OFF);
> + else if (size == 2)
> + writew(val, port->base + PCIE_CONF_DATA_OFF + (where & 3));
> + else if (size == 1)
> + writeb(val, port->base + PCIE_CONF_DATA_OFF + (where & 3));
> + else
> + ret = PCIBIOS_BAD_REGISTER_NUMBER;
> +
> + return ret;
> +}
> +
> +static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
> +{
> + phys_addr_t iobase;
> +
> + /* Are the new iobase/iolimit values invalid? */
> + if (port->bridge.iolimit < port->bridge.iobase ||
> + port->bridge.iolimitupper < port->bridge.iobaseupper) {
> +
> + /* If a window was configured, remove it */
> + if (port->iowin_base) {
> + mvebu_mbus_del_window(port->iowin_base,
> + port->iowin_size);
> + port->iowin_base = 0;
> + port->iowin_size = 0;
> + }
> +
> + return;
> + }
> +
> + /*
> + * We read the PCI-to-PCI bridge emulated registers, and
> + * calculate the base address and size of the address decoding
> + * window to setup, according to the PCI-to-PCI bridge
> + * specifications. iobase is the bus address, port->iowin_base
> + * is the CPU address.
> + */
> + iobase = ((port->bridge.iobase & 0xF0) << 8) |
> + (port->bridge.iobaseupper << 16);
> + port->iowin_base = port->pcie->io.start + iobase;
> + port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
> + (port->bridge.iolimitupper << 16)) -
> + iobase);
> +
> + mvebu_mbus_add_window_remap_flags(port->name, port->iowin_base,
> + port->iowin_size,
> + iobase,
> + MVEBU_MBUS_PCI_IO);
> +
> + pci_ioremap_io(iobase, port->iowin_base);
> +}
> +
> +static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
> +{
> + /* Are the new membase/memlimit values invalid? */
> + if (port->bridge.memlimit < port->bridge.membase) {
> +
> + /* If a window was configured, remove it */
> + if (port->memwin_base) {
> + mvebu_mbus_del_window(port->memwin_base,
> + port->memwin_size);
> + port->memwin_base = 0;
> + port->memwin_size = 0;
> + }
> +
> + return;
> + }
> +
> + /*
> + * We read the PCI-to-PCI bridge emulated registers, and
> + * calculate the base address and size of the address decoding
> + * window to setup, according to the PCI-to-PCI bridge
> + * specifications.
> + */
> + port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16);
> + port->memwin_size =
> + (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
> + port->memwin_base;
> +
> + mvebu_mbus_add_window_remap_flags(port->name, port->memwin_base,
> + port->memwin_size,
> + MVEBU_MBUS_NO_REMAP,
> + MVEBU_MBUS_PCI_MEM);
> +}
> +
> +/*
> + * Initialize the configuration space of the PCI-to-PCI bridge
> + * associated with the given PCIe interface.
> + */
> +static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
> +{
> + struct mvebu_sw_pci_bridge *bridge = &port->bridge;
> +
> + memset(bridge, 0, sizeof(struct mvebu_sw_pci_bridge));
> +
> + bridge->status = PCI_STATUS_CAP_LIST;
> + bridge->class = PCI_CLASS_BRIDGE_PCI;
> + bridge->vendor = PCI_VENDOR_ID_MARVELL;
> + bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
> + bridge->header_type = PCI_HEADER_TYPE_BRIDGE;
> + bridge->cache_line_size = 0x10;
> +
> + /* We support 32 bits I/O addressing */
> + bridge->iobase = PCI_IO_RANGE_TYPE_32;
> + bridge->iolimit = PCI_IO_RANGE_TYPE_32;
> +}
> +
> +/*
> + * Read the configuration space of the PCI-to-PCI bridge associated to
> + * the given PCIe interface.
> + */
> +static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
> + unsigned int where, int size, u32 *value)
> +{
> + struct mvebu_sw_pci_bridge *bridge = &port->bridge;
> +
> + switch (where & ~3) {
> + case PCI_VENDOR_ID:
> + *value = bridge->device << 16 | bridge->vendor;
> + break;
> +
> + case PCI_COMMAND:
> + *value = bridge->status << 16 | bridge->command;
> + break;
> +
> + case PCI_CLASS_REVISION:
> + *value = bridge->class << 16 | bridge->interface << 8 |
> + bridge->revision;
> + break;
> +
> + case PCI_CACHE_LINE_SIZE:
> + *value = bridge->bist << 24 | bridge->header_type << 16 |
> + bridge->latency_timer << 8 | bridge->cache_line_size;
> + break;
> +
> + case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
> + *value = bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4];
> + break;
> +
> + case PCI_PRIMARY_BUS:
> + *value = (bridge->secondary_latency_timer << 24 |
> + bridge->subordinate_bus << 16 |
> + bridge->secondary_bus << 8 |
> + bridge->primary_bus);
> + break;
> +
> + case PCI_IO_BASE:
> + *value = (bridge->secondary_status << 16 |
> + bridge->iolimit << 8 |
> + bridge->iobase);
> + break;
> +
> + case PCI_MEMORY_BASE:
> + *value = (bridge->memlimit << 16 | bridge->membase);
> + break;
> +
> + case PCI_PREF_MEMORY_BASE:
> + *value = (bridge->prefmemlimit << 16 | bridge->prefmembase);
> + break;
> +
> + case PCI_PREF_BASE_UPPER32:
> + *value = bridge->prefbaseupper;
> + break;
> +
> + case PCI_PREF_LIMIT_UPPER32:
> + *value = bridge->preflimitupper;
> + break;
> +
> + case PCI_IO_BASE_UPPER16:
> + *value = (bridge->iolimitupper << 16 | bridge->iobaseupper);
> + break;
> +
> + case PCI_ROM_ADDRESS1:
> + *value = 0;
> + break;
> +
> + default:
> + *value = 0xffffffff;
> + return PCIBIOS_BAD_REGISTER_NUMBER;
> + }
> +
> + if (size == 2)
> + *value = (*value >> (8 * (where & 3))) & 0xffff;
> + else if (size == 1)
> + *value = (*value >> (8 * (where & 3))) & 0xff;
> +
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +/* Write to the PCI-to-PCI bridge configuration space */
> +static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
> + unsigned int where, int size, u32 value)
> +{
> + struct mvebu_sw_pci_bridge *bridge = &port->bridge;
> + u32 mask, reg;
> + int err;
> +
> + if (size == 4)
> + mask = 0x0;
> + else if (size == 2)
> + mask = ~(0xffff << ((where & 3) * 8));
> + else if (size == 1)
> + mask = ~(0xff << ((where & 3) * 8));
> + else
> + return PCIBIOS_BAD_REGISTER_NUMBER;
> +
> + err = mvebu_sw_pci_bridge_read(port, where & ~3, 4, ®);
> + if (err)
> + return err;
> +
> + value = (reg & mask) | value << ((where & 3) * 8);
> +
> + switch (where & ~3) {
> + case PCI_COMMAND:
> + bridge->command = value & 0xffff;
> + bridge->status = value >> 16;
> + break;
> +
> + case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
> + bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value;
> + break;
> +
> + case PCI_IO_BASE:
> + /*
> + * We also keep bit 1 set, it is a read-only bit that
> + * indicates we support 32 bits addressing for the
> + * I/O
> + */
> + bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32;
> + bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32;
> + bridge->secondary_status = value >> 16;
> + mvebu_pcie_handle_iobase_change(port);
> + break;
> +
> + case PCI_MEMORY_BASE:
> + bridge->membase = value & 0xffff;
> + bridge->memlimit = value >> 16;
> + mvebu_pcie_handle_membase_change(port);
> + break;
> +
> + case PCI_PREF_MEMORY_BASE:
> + bridge->prefmembase = value & 0xffff;
> + bridge->prefmemlimit = value >> 16;
> + break;
> +
> + case PCI_PREF_BASE_UPPER32:
> + bridge->prefbaseupper = value;
> + break;
> +
> + case PCI_PREF_LIMIT_UPPER32:
> + bridge->preflimitupper = value;
> + break;
> +
> + case PCI_IO_BASE_UPPER16:
> + bridge->iobaseupper = value & 0xffff;
> + bridge->iolimitupper = value >> 16;
> + mvebu_pcie_handle_iobase_change(port);
> + break;
> +
> + case PCI_PRIMARY_BUS:
> + bridge->primary_bus = value & 0xff;
> + bridge->secondary_bus = (value >> 8) & 0xff;
> + bridge->subordinate_bus = (value >> 16) & 0xff;
> + bridge->secondary_latency_timer = (value >> 24) & 0xff;
> + mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus);
> + break;
> +
> + default:
> + break;
> + }
> +
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys)
> +{
> + return sys->private_data;
> +}
> +
> +static struct mvebu_pcie_port *
> +mvebu_pcie_find_port(struct mvebu_pcie *pcie, struct pci_bus *bus,
> + int devfn)
> +{
> + int i;
> +
> + for (i = 0; i < pcie->nports; i++) {
> + struct mvebu_pcie_port *port = &pcie->ports[i];
> + if (bus->number == 0 && port->devfn == devfn)
> + return port;
> + if (bus->number != 0 &&
> + port->bridge.secondary_bus == bus->number)
> + return port;
> + }
> +
> + return NULL;
> +}
> +
> +/* PCI configuration space write function */
> +static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
> + int where, int size, u32 val)
> +{
> + struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
> + struct mvebu_pcie_port *port;
> + unsigned long flags;
> + int ret;
> +
> + port = mvebu_pcie_find_port(pcie, bus, devfn);
> + if (!port)
> + return PCIBIOS_DEVICE_NOT_FOUND;
> +
> + /* Access the emulated PCI-to-PCI bridge */
> + if (bus->number == 0)
> + return mvebu_sw_pci_bridge_write(port, where, size, val);
> +
> + if (!port->haslink || PCI_SLOT(devfn) != 0)
> + return PCIBIOS_DEVICE_NOT_FOUND;
> +
> + /* Access the real PCIe interface */
> + spin_lock_irqsave(&port->conf_lock, flags);
> + ret = mvebu_pcie_hw_wr_conf(port, bus,
> + PCI_DEVFN(1, PCI_FUNC(devfn)),
> + where, size, val);
> + spin_unlock_irqrestore(&port->conf_lock, flags);
> +
> + return ret;
> +}
> +
> +/* PCI configuration space read function */
> +static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
> + int size, u32 *val)
> +{
> + struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
> + struct mvebu_pcie_port *port;
> + unsigned long flags;
> + int ret;
> +
> + port = mvebu_pcie_find_port(pcie, bus, devfn);
> + if (!port) {
> + *val = 0xffffffff;
> + return PCIBIOS_DEVICE_NOT_FOUND;
> + }
> +
> + /* Access the emulated PCI-to-PCI bridge */
> + if (bus->number == 0)
> + return mvebu_sw_pci_bridge_read(port, where, size, val);
> +
> + if (!port->haslink || PCI_SLOT(devfn) != 0) {
> + *val = 0xffffffff;
> + return PCIBIOS_DEVICE_NOT_FOUND;
> + }
> +
> + /* Access the real PCIe interface */
> + spin_lock_irqsave(&port->conf_lock, flags);
> + ret = mvebu_pcie_hw_rd_conf(port, bus,
> + PCI_DEVFN(1, PCI_FUNC(devfn)),
> + where, size, val);
> + spin_unlock_irqrestore(&port->conf_lock, flags);
> +
> + return ret;
> +}
> +
> +static struct pci_ops mvebu_pcie_ops = {
> + .read = mvebu_pcie_rd_conf,
> + .write = mvebu_pcie_wr_conf,
> +};
> +
> +static int __init mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
> +{
> + struct mvebu_pcie *pcie = sys_to_pcie(sys);
> + int i;
> +
> + pci_add_resource_offset(&sys->resources, &pcie->realio, sys->io_offset);
> + pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
> + pci_add_resource(&sys->resources, &pcie->busn);
> +
> + for (i = 0; i < pcie->nports; i++) {
> + struct mvebu_pcie_port *port = &pcie->ports[i];
> + mvebu_pcie_setup_hw(port);
> + }
> +
> + return 1;
> +}
> +
> +static int __init mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> +{
> + struct of_irq oirq;
> + int ret;
> +
> + ret = of_irq_map_pci(dev, &oirq);
> + if (ret)
> + return ret;
> +
> + return irq_create_of_mapping(oirq.controller, oirq.specifier,
> + oirq.size);
> +}
> +
> +static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
> +{
> + struct mvebu_pcie *pcie = sys_to_pcie(sys);
> + struct pci_bus *bus;
> +
> + bus = pci_create_root_bus(&pcie->pdev->dev, sys->busnr,
> + &mvebu_pcie_ops, sys, &sys->resources);
> + if (!bus)
> + return NULL;
> +
> + pci_scan_child_bus(bus);
> +
> + return bus;
> +}
> +
> +resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
> + const struct resource *res,
> + resource_size_t start,
> + resource_size_t size,
> + resource_size_t align)
> +{
> + if (dev->bus->number != 0)
> + return start;
> +
> + /*
> + * On the PCI-to-PCI bridge side, the I/O windows must have at
> + * least a 64 KB size and be aligned on their size, and the
> + * memory windows must have at least a 1 MB size and be
> + * aligned on their size
> + */
> + if (res->flags & IORESOURCE_IO)
> + return round_up(start, max((resource_size_t)SZ_64K, size));
> + else if (res->flags & IORESOURCE_MEM)
> + return round_up(start, max((resource_size_t)SZ_1M, size));
> + else
> + return start;
> +}
> +
> +static void mvebu_pcie_enable(struct mvebu_pcie *pcie)
> +{
> + struct hw_pci hw;
> +
> + memset(&hw, 0, sizeof(hw));
> +
> + hw.nr_controllers = 1;
> + hw.private_data = (void **)&pcie;
> + hw.setup = mvebu_pcie_setup;
> + hw.scan = mvebu_pcie_scan_bus;
> + hw.map_irq = mvebu_pcie_map_irq;
> + hw.ops = &mvebu_pcie_ops;
> + hw.align_resource = mvebu_pcie_align_resource;
> +
> + pci_common_init(&hw);
> +}
> +
> +/*
> + * Looks up the list of register addresses encoded into the reg =
> + * <...> property for one that matches the given port/lane. Once
> + * found, maps it.
> + */
> +static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
> + struct device_node *np,
> + struct mvebu_pcie_port *port)
> +{
> + struct resource regs;
> + int ret = 0;
> +
> + ret = of_address_to_resource(np, 0, ®s);
> + if (ret)
> + return NULL;
> +
> + return devm_request_and_ioremap(&pdev->dev, ®s);
> +}
> +
> +static int __init mvebu_pcie_probe(struct platform_device *pdev)
> +{
> + struct mvebu_pcie *pcie;
> + struct device_node *np = pdev->dev.of_node;
> + struct of_pci_range range;
> + struct of_pci_range_parser parser;
> + struct device_node *child;
> + int i, ret;
> +
> + pcie = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pcie),
> + GFP_KERNEL);
> + if (!pcie)
> + return -ENOMEM;
> +
> + pcie->pdev = pdev;
> +
> + if (of_pci_range_parser(&parser, np))
> + return -EINVAL;
> +
> + /* Get the I/O and memory ranges from DT */
> + for_each_of_pci_range(&parser, &range) {
> + unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
> + if (restype == IORESOURCE_IO) {
> + of_pci_range_to_resource(&range, np, &pcie->io);
> + of_pci_range_to_resource(&range, np, &pcie->realio);
> + pcie->io.name = "I/O";
> + pcie->realio.start = max_t(resource_size_t,
> + PCIBIOS_MIN_IO,
> + range.pci_addr);
> + pcie->realio.end = min_t(resource_size_t,
> + IO_SPACE_LIMIT,
> + range.pci_addr + range.size);
> + }
> + if (restype == IORESOURCE_MEM) {
> + of_pci_range_to_resource(&range, np, &pcie->mem);
> + pcie->mem.name = "MEM";
> + }
> + }
> +
> + /* Get the bus range */
> + ret = of_pci_parse_bus_range(np, &pcie->busn);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to parse bus-range property: %d\n",
> + ret);
> + return ret;
> + }
> +
> + for_each_child_of_node(pdev->dev.of_node, child) {
> + if (!of_device_is_available(child))
> + continue;
> + pcie->nports++;
> + }
> +
> + pcie->ports = devm_kzalloc(&pdev->dev, pcie->nports *
> + sizeof(struct mvebu_pcie_port),
> + GFP_KERNEL);
> + if (!pcie->ports)
> + return -ENOMEM;
> +
> + i = 0;
> + for_each_child_of_node(pdev->dev.of_node, child) {
> + struct mvebu_pcie_port *port = &pcie->ports[i];
> +
> + if (!of_device_is_available(child))
> + continue;
> +
> + port->pcie = pcie;
> +
> + if (of_property_read_u32(child, "marvell,pcie-port",
> + &port->port)) {
> + dev_warn(&pdev->dev,
> + "ignoring PCIe DT node, missing pcie-port property\n");
> + continue;
> + }
> +
> + if (of_property_read_u32(child, "marvell,pcie-lane",
> + &port->lane))
> + port->lane = 0;
> +
> + port->name = kasprintf(GFP_KERNEL, "pcie%d.%d",
> + port->port, port->lane);
> +
> + port->devfn = of_pci_get_devfn(child);
> + if (port->devfn < 0)
> + continue;
> +
> + port->base = mvebu_pcie_map_registers(pdev, child, port);
> + if (!port->base) {
> + dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
> + port->port, port->lane);
> + continue;
> + }
> +
> + if (mvebu_pcie_link_up(port)) {
> + port->haslink = 1;
> + dev_info(&pdev->dev, "PCIe%d.%d: link up\n",
> + port->port, port->lane);
> + } else {
> + port->haslink = 0;
> + dev_info(&pdev->dev, "PCIe%d.%d: link down\n",
> + port->port, port->lane);
> + }
> +
> + port->clk = of_clk_get_by_name(child, NULL);
> + if (!port->clk) {
> + dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
> + port->port, port->lane);
> + iounmap(port->base);
> + port->haslink = 0;
> + continue;
> + }
> +
> + port->dn = child;
> +
> + clk_prepare_enable(port->clk);
> + spin_lock_init(&port->conf_lock);
> +
> + mvebu_sw_pci_bridge_init(port);
> +
> + i++;
> + }
> +
> + mvebu_pcie_enable(pcie);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id mvebu_pcie_of_match_table[] = {
> + { .compatible = "marvell,armada-xp-pcie", },
> + { .compatible = "marvell,armada-370-pcie", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
> +
> +static struct platform_driver mvebu_pcie_driver = {
> + .driver = {
> + .owner = THIS_MODULE,
> + .name = "mvebu-pcie",
> + .of_match_table =
> + of_match_ptr(mvebu_pcie_of_match_table),
> + },
> +};
> +
> +static int mvebu_pcie_init(void)
> +{
> + return platform_driver_probe(&mvebu_pcie_driver,
> + mvebu_pcie_probe);
> +}
> +
> +subsys_initcall(mvebu_pcie_init);
> +
> +MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
> +MODULE_DESCRIPTION("Marvell EBU PCIe driver");
> +MODULE_LICENSE("GPLv2");
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 10/19] pci: PCIe driver for Marvell Armada 370/XP systems
2013-04-09 21:12 ` Bjorn Helgaas
@ 2013-04-09 21:22 ` Thomas Petazzoni
0 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-09 21:22 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Grant Likely, Russell King, linux-pci@vger.kernel.org, linux-arm,
devicetree-discuss@lists.ozlabs.org, Lior Amsalem, Andrew Lunn,
Jason Cooper, Arnd Bergmann, Maen Suleiman, Thierry Reding,
Gregory Clement, Ezequiel Garcia, Olof Johansson, Tawfik Bayouk,
Jason Gunthorpe, Mitch Bradley, Andrew Murray
Dear Bjorn Helgaas,
On Tue, 9 Apr 2013 15:12:58 -0600, Bjorn Helgaas wrote:
> On Tue, Apr 9, 2013 at 3:06 PM, Thomas Petazzoni
> <thomas.petazzoni@free-electrons.com> wrote:
> > 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.
> >
> > Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> > Acked-by: Bjorn Helgaas <bhelgaas@google.com>
>
> This and 06/19 look good to me.
Thanks!
Thomas
--
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 04/19] of/pci: Add of_pci_get_devfn() function
2013-04-09 21:06 ` [PATCHv8 04/19] of/pci: Add of_pci_get_devfn() function Thomas Petazzoni
@ 2013-04-10 18:33 ` Rob Herring
0 siblings, 0 replies; 33+ messages in thread
From: Rob Herring @ 2013-04-10 18:33 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: Bjorn Helgaas, Grant Likely, Russell King, Lior Amsalem,
Andrew Lunn, Jason Cooper, linux-pci, devicetree-discuss,
Jason Gunthorpe, Maen Suleiman, Andrew Murray, Tawfik Bayouk,
linux-arm-kernel, Mitch Bradley
On 04/09/2013 04:06 PM, Thomas Petazzoni wrote:
> From: Thierry Reding <thierry.reding@avionic-design.de>
>
> 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.
>
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Reviewed-by: Rob Herring <rob.herring@calxeda.com>
> ---
> drivers/of/of_pci.c | 34 +++++++++++++++++++++++++++++-----
> include/linux/of_pci.h | 1 +
> 2 files changed, 30 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index ebb408b..b77e8d8 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -9,14 +9,15 @@
> #endif
>
> 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(®[0]) >> 8) & 0xff) == devfn;
> +
> + return devfn == data;
> }
>
> struct device_node *of_pci_find_child_device(struct device_node *parent,
> @@ -208,3 +209,26 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> }
> }
> #endif
> +
> +/**
> + * 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);
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index e56182f..302aca0 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -11,6 +11,7 @@ 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);
>
> void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> struct device_node *dev, int primary);
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 05/19] of/pci: Add of_pci_parse_bus_range() function
2013-04-09 21:06 ` [PATCHv8 05/19] of/pci: Add of_pci_parse_bus_range() function Thomas Petazzoni
@ 2013-04-10 18:37 ` Rob Herring
0 siblings, 0 replies; 33+ messages in thread
From: Rob Herring @ 2013-04-10 18:37 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: Bjorn Helgaas, Grant Likely, Russell King, Lior Amsalem,
Andrew Lunn, Jason Cooper, linux-pci, devicetree-discuss,
Jason Gunthorpe, Maen Suleiman, Andrew Murray, Tawfik Bayouk,
linux-arm-kernel, Mitch Bradley
On 04/09/2013 04:06 PM, Thomas Petazzoni wrote:
> From: Thierry Reding <thierry.reding@avionic-design.de>
>
> This function can be used to parse a bus-range property as specified by
> device nodes representing PCI bridges.
>
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Reviewed-by: Rob Herring <rob.herring@calxeda.com>
> ---
> drivers/of/of_pci.c | 25 +++++++++++++++++++++++++
> include/linux/of_pci.h | 1 +
> 2 files changed, 26 insertions(+)
>
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index b77e8d8..e9106dc 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -232,3 +232,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);
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index 302aca0..be97a6f 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -12,6 +12,7 @@ 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);
>
> void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> struct device_node *dev, int primary);
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 12/19] arm: mvebu: add PCIe Device Tree informations for Armada 370
2013-04-09 21:06 ` [PATCHv8 12/19] arm: mvebu: add PCIe Device Tree informations for Armada 370 Thomas Petazzoni
@ 2013-04-12 0:28 ` Jason Cooper
[not found] ` <20130412002811.GS28693-u4khhh1J0LxI1Ri9qeTfzeTW4wlIGRCZ@public.gmane.org>
0 siblings, 1 reply; 33+ messages in thread
From: Jason Cooper @ 2013-04-12 0:28 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: Lior Amsalem, Andrew Lunn, Russell King, Tawfik Bayouk,
Arnd Bergmann, Maen Suleiman, linux-pci, devicetree-discuss,
Thierry Reding, Grant Likely, Olof Johansson, Ezequiel Garcia,
Andrew Murray, Bjorn Helgaas, Gregory Clement, Mitch Bradley,
linux-arm-kernel, Jason Gunthorpe
On Tue, Apr 09, 2013 at 11:06:33PM +0200, Thomas Petazzoni wrote:
> The Armada 370 SoC has two 1x PCIe 2.0 interfaces, so we add the
> necessary Device Tree informations to make these interfaces availabel.
>
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> ---
> arch/arm/boot/dts/armada-370.dtsi | 51 +++++++++++++++++++++++++++++++++++++
> 1 file changed, 51 insertions(+)
Patches 12 through 18 applied to mvebu/dt. Now Gregory can rebase LPAE
:)
thx,
Jason.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 12/19] arm: mvebu: add PCIe Device Tree informations for Armada 370
[not found] ` <20130412002811.GS28693-u4khhh1J0LxI1Ri9qeTfzeTW4wlIGRCZ@public.gmane.org>
@ 2013-04-12 0:48 ` Jason Cooper
0 siblings, 0 replies; 33+ messages in thread
From: Jason Cooper @ 2013-04-12 0:48 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: Lior Amsalem, Andrew Lunn, Russell King, Tawfik Bayouk,
linux-pci-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Jason Gunthorpe,
Maen Suleiman, Andrew Murray, Bjorn Helgaas,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Mitch Bradley
On Thu, Apr 11, 2013 at 08:28:11PM -0400, Jason Cooper wrote:
> On Tue, Apr 09, 2013 at 11:06:33PM +0200, Thomas Petazzoni wrote:
> > The Armada 370 SoC has two 1x PCIe 2.0 interfaces, so we add the
> > necessary Device Tree informations to make these interfaces availabel.
> >
> > Signed-off-by: Thomas Petazzoni <thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> > ---
> > arch/arm/boot/dts/armada-370.dtsi | 51 +++++++++++++++++++++++++++++++++++++
> > 1 file changed, 51 insertions(+)
>
> Patches 12 through 18 applied to mvebu/dt. Now Gregory can rebase LPAE
> :)
Gregory,
Hold off for an hour or so. I just realized that mvebu/fixes contains a
few more relevant dts changes than I had pulled in to mvebu/dt. I'll
let you know once I push an updated branch.
thx,
Jason.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (18 preceding siblings ...)
2013-04-09 21:06 ` [PATCHv8 19/19] arm: mvebu: update defconfig with PCI and USB support Thomas Petazzoni
@ 2013-04-15 15:46 ` Jason Cooper
2013-04-15 16:36 ` Thomas Petazzoni
19 siblings, 1 reply; 33+ messages in thread
From: Jason Cooper @ 2013-04-15 15:46 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: Lior Amsalem, Andrew Lunn, Russell King, Tawfik Bayouk,
Arnd Bergmann, Maen Suleiman, linux-pci, devicetree-discuss,
Thierry Reding, Grant Likely, Olof Johansson, Ezequiel Garcia,
Andrew Murray, Bjorn Helgaas, Gregory Clement, Mitch Bradley,
linux-arm-kernel, Jason Gunthorpe
Thomas,
On Tue, Apr 09, 2013 at 11:06:21PM +0200, Thomas Petazzoni wrote:
> 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.
>
> Here is the current status of the different patches:
>
> * Patches 1-5 are awaiting a formal Acked-by from the Device Tree
> maintainers. Patches 1-3 are the new version of the OF PCI range
> parsing functions from Andrew Murray, which he worked on after the
> comments from Rob Herring. Patches 4 and 5 are much more trivial
> and have been around since many versions of this series.
Applied to mvebu/drivers
> * Patch 6 and 10, that are touching drivers/pci/ have been formally
> Acked-by Bjorn Helgaas, the PCI maintainer.
Applied to mvebu/drivers
> * Patch 7, which is touching arch/arm/kernel, has been merged by
> Russell King already, see
> http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7683/1.
Added remote branch dependency on rmk/for-next in mvebu/soc
> * Patches 8 and 9 are touching drivers/clk, and are awaiting an
> Acked-by from Mike Turquette. However, they are fairly trivial
> patches, so they shouldn't cause too much problem.
Applied to mvebu/drivers
>
> * All the other patches touch mvebu-specific things, either
> mach-mvebu or the related Device Tree files or defconfig, so it's
> up to the Marvell maintainers to pick them up.
Patches 10,11,19 applied to mvebu/soc with dep on rmk/for-next, and
mvebu/drivers (in /soc to catch mvebu-mbus dependency).
I'm going to flag a separate PR for this marked "late" so that it goes
in *after* rmk/for-next.
thx,
Jason.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 07/19] arm: pci: add a align_resource hook
2013-04-09 21:06 ` [PATCHv8 07/19] arm: pci: add a align_resource hook Thomas Petazzoni
@ 2013-04-15 16:36 ` Jason Cooper
[not found] ` <20130415163609.GJ28693-u4khhh1J0LxI1Ri9qeTfzeTW4wlIGRCZ@public.gmane.org>
2013-04-19 14:33 ` Russell King - ARM Linux
0 siblings, 2 replies; 33+ messages in thread
From: Jason Cooper @ 2013-04-15 16:36 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: Bjorn Helgaas, Grant Likely, Russell King, Lior Amsalem,
Andrew Lunn, Arnd Bergmann, Olof Johansson, linux-pci,
devicetree-discuss, Thierry Reding, Jason Gunthorpe,
Maen Suleiman, Ezequiel Garcia, Gregory Clement, Andrew Murray,
Tawfik Bayouk, linux-arm-kernel, Mitch Bradley
Russell,
Thanks for applying this patch (7683/1) to your tree. I see it's in
your for-next, which I understand *isn't* stable.
029baf1 ARM: 7683/1: pci: add a align_resource hook
Is there a stable branch I could depend on for the rest of this series
(particularly, patch 10)? It looks like you applied it to your misc
branch, but that's not currently available.
thx,
Jason.
On Tue, Apr 09, 2013 at 11:06:28PM +0200, Thomas Petazzoni wrote:
> 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.
>
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Cc: Russell King <linux@arm.linux.org.uk>
> ---
> arch/arm/include/asm/mach/pci.h | 11 +++++++++++
> arch/arm/kernel/bios32.c | 6 ++++++
> 2 files changed, 17 insertions(+)
>
> diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
> index 5cf2e97..7d2c3c8 100644
> --- a/arch/arm/include/asm/mach/pci.h
> +++ b/arch/arm/include/asm/mach/pci.h
> @@ -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 */
> };
>
> diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
> index a1f73b5..b2ed73c 100644
> --- a/arch/arm/kernel/bios32.c
> +++ b/arch/arm/kernel/bios32.c
> @@ -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;
> }
>
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs
2013-04-15 15:46 ` [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Jason Cooper
@ 2013-04-15 16:36 ` Thomas Petazzoni
2013-04-15 16:38 ` Jason Cooper
0 siblings, 1 reply; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-15 16:36 UTC (permalink / raw)
To: Jason Cooper
Cc: Bjorn Helgaas, Grant Likely, Russell King, Lior Amsalem,
Andrew Lunn, Arnd Bergmann, Olof Johansson, linux-pci,
devicetree-discuss, Thierry Reding, Jason Gunthorpe,
Maen Suleiman, Ezequiel Garcia, Gregory Clement, Andrew Murray,
Tawfik Bayouk, linux-arm-kernel, Mitch Bradley
Dear Jason Cooper,
On Mon, 15 Apr 2013 11:46:20 -0400, Jason Cooper wrote:
> > * Patches 1-5 are awaiting a formal Acked-by from the Device Tree
> > maintainers. Patches 1-3 are the new version of the OF PCI range
> > parsing functions from Andrew Murray, which he worked on after the
> > comments from Rob Herring. Patches 4 and 5 are much more trivial
> > and have been around since many versions of this series.
>
> Applied to mvebu/drivers
Patches 1-3 have a newer version that has been posted by Andrew Murray
recently, see:
Subject: [PATCH v6 0/3] of/pci: Provide common support for PCI DT
parsing Date: Thu, 11 Apr 2013 16:26:06 +0100
Message-Id: <1365693969-23907-1-git-send-email-Andrew.Murray@arm.com>
http://lists.infradead.org/pipermail/linux-arm-kernel/2013-April/162558.html
This ones are more recent than the v5 I originally used as a base for
my PCIe v8. I can resend a v9 of my PCIe patch set based on the v6 of
Andrew, or you can directly use PATCH 1,2,3 from Andrew series to
replace PATCH 1,2,3 from my series. Andrew v6 has quite a number of
changes compared to v5, so I really recommend using those ones.
Thanks!
Thomas
--
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs
2013-04-15 16:36 ` Thomas Petazzoni
@ 2013-04-15 16:38 ` Jason Cooper
2013-04-15 16:40 ` Thomas Petazzoni
0 siblings, 1 reply; 33+ messages in thread
From: Jason Cooper @ 2013-04-15 16:38 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: Bjorn Helgaas, Grant Likely, Russell King, Lior Amsalem,
Andrew Lunn, Arnd Bergmann, Olof Johansson, linux-pci,
devicetree-discuss, Thierry Reding, Jason Gunthorpe,
Maen Suleiman, Ezequiel Garcia, Gregory Clement, Andrew Murray,
Tawfik Bayouk, linux-arm-kernel, Mitch Bradley
On Mon, Apr 15, 2013 at 06:36:23PM +0200, Thomas Petazzoni wrote:
> Dear Jason Cooper,
>
> On Mon, 15 Apr 2013 11:46:20 -0400, Jason Cooper wrote:
>
> > > * Patches 1-5 are awaiting a formal Acked-by from the Device Tree
> > > maintainers. Patches 1-3 are the new version of the OF PCI range
> > > parsing functions from Andrew Murray, which he worked on after the
> > > comments from Rob Herring. Patches 4 and 5 are much more trivial
> > > and have been around since many versions of this series.
> >
> > Applied to mvebu/drivers
>
> Patches 1-3 have a newer version that has been posted by Andrew Murray
> recently, see:
>
> Subject: [PATCH v6 0/3] of/pci: Provide common support for PCI DT
> parsing Date: Thu, 11 Apr 2013 16:26:06 +0100
> Message-Id: <1365693969-23907-1-git-send-email-Andrew.Murray@arm.com>
>
> http://lists.infradead.org/pipermail/linux-arm-kernel/2013-April/162558.html
>
> This ones are more recent than the v5 I originally used as a base for
> my PCIe v8. I can resend a v9 of my PCIe patch set based on the v6 of
> Andrew, or you can directly use PATCH 1,2,3 from Andrew series to
> replace PATCH 1,2,3 from my series. Andrew v6 has quite a number of
> changes compared to v5, so I really recommend using those ones.
No need to mess with v9, I'll pull AndrewM's v6.
thx,
Jason.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs
2013-04-15 16:38 ` Jason Cooper
@ 2013-04-15 16:40 ` Thomas Petazzoni
0 siblings, 0 replies; 33+ messages in thread
From: Thomas Petazzoni @ 2013-04-15 16:40 UTC (permalink / raw)
To: Jason Cooper
Cc: Bjorn Helgaas, Grant Likely, Russell King, Lior Amsalem,
Andrew Lunn, Arnd Bergmann, Olof Johansson, linux-pci,
devicetree-discuss, Thierry Reding, Jason Gunthorpe,
Maen Suleiman, Ezequiel Garcia, Gregory Clement, Andrew Murray,
Tawfik Bayouk, linux-arm-kernel, Mitch Bradley
Dear Jason Cooper,
On Mon, 15 Apr 2013 12:38:45 -0400, Jason Cooper wrote:
> > This ones are more recent than the v5 I originally used as a base for
> > my PCIe v8. I can resend a v9 of my PCIe patch set based on the v6 of
> > Andrew, or you can directly use PATCH 1,2,3 from Andrew series to
> > replace PATCH 1,2,3 from my series. Andrew v6 has quite a number of
> > changes compared to v5, so I really recommend using those ones.
>
> No need to mess with v9, I'll pull AndrewM's v6.
Excellent, thanks.
Thomas
--
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 07/19] arm: pci: add a align_resource hook
[not found] ` <20130415163609.GJ28693-u4khhh1J0LxI1Ri9qeTfzeTW4wlIGRCZ@public.gmane.org>
@ 2013-04-17 14:08 ` Jason Cooper
0 siblings, 0 replies; 33+ messages in thread
From: Jason Cooper @ 2013-04-17 14:08 UTC (permalink / raw)
To: Russell King, Thomas Petazzoni, Olof Johansson, Arnd Bergmann
Cc: Lior Amsalem, Andrew Lunn, Mitch Bradley, Tawfik Bayouk,
linux-pci-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Maen Suleiman,
Bjorn Helgaas, Andrew Murray,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Jason Gunthorpe
Russell,
I saw you were back online this morning, could you please consider the
following request?
On Mon, Apr 15, 2013 at 12:36:09PM -0400, Jason Cooper wrote:
> Russell,
>
> Thanks for applying this patch (7683/1) to your tree. I see it's in
> your for-next, which I understand *isn't* stable.
>
> 029baf1 ARM: 7683/1: pci: add a align_resource hook
>
> Is there a stable branch I could depend on for the rest of this series
> (particularly, patch 10)? It looks like you applied it to your misc
> branch, but that's not currently available.
I'd really like to get this in for v3.10. As Thomas has mentioned
before, the series has had plenty of review on the list.
thx,
Jason.
> On Tue, Apr 09, 2013 at 11:06:28PM +0200, Thomas Petazzoni wrote:
> > 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.
> >
> > Signed-off-by: Thomas Petazzoni <thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> > Cc: Russell King <linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>
> > ---
> > arch/arm/include/asm/mach/pci.h | 11 +++++++++++
> > arch/arm/kernel/bios32.c | 6 ++++++
> > 2 files changed, 17 insertions(+)
> >
> > diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
> > index 5cf2e97..7d2c3c8 100644
> > --- a/arch/arm/include/asm/mach/pci.h
> > +++ b/arch/arm/include/asm/mach/pci.h
> > @@ -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 */
> > };
> >
> > diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
> > index a1f73b5..b2ed73c 100644
> > --- a/arch/arm/kernel/bios32.c
> > +++ b/arch/arm/kernel/bios32.c
> > @@ -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;
> > }
> >
> > --
> > 1.7.9.5
> >
> >
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCHv8 07/19] arm: pci: add a align_resource hook
2013-04-15 16:36 ` Jason Cooper
[not found] ` <20130415163609.GJ28693-u4khhh1J0LxI1Ri9qeTfzeTW4wlIGRCZ@public.gmane.org>
@ 2013-04-19 14:33 ` Russell King - ARM Linux
1 sibling, 0 replies; 33+ messages in thread
From: Russell King - ARM Linux @ 2013-04-19 14:33 UTC (permalink / raw)
To: Jason Cooper
Cc: Thomas Petazzoni, Olof Johansson, Arnd Bergmann, Bjorn Helgaas,
Grant Likely, Lior Amsalem, Andrew Lunn, linux-pci,
devicetree-discuss, Thierry Reding, Jason Gunthorpe,
Maen Suleiman, Ezequiel Garcia, Gregory Clement, Andrew Murray,
Tawfik Bayouk, linux-arm-kernel, Mitch Bradley
On Mon, Apr 15, 2013 at 12:36:09PM -0400, Jason Cooper wrote:
> Russell,
>
> Thanks for applying this patch (7683/1) to your tree. I see it's in
> your for-next, which I understand *isn't* stable.
That is correct.
> 029baf1 ARM: 7683/1: pci: add a align_resource hook
>
> Is there a stable branch I could depend on for the rest of this series
> (particularly, patch 10)? It looks like you applied it to your misc
> branch, but that's not currently available.
I will have to look at that; as I'm still catching up with mail three
days after having returned and there's still quite an amount outstanding,
it's going to be a while before I can look at this. Given that we're at
-rc7 and the amount of outstanding mail, it's likely that may happen
after the merge window has opened.
^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2013-04-19 14:33 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-09 21:06 [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 01/19] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 02/19] of/pci: Provide support for parsing PCI DT ranges property Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 03/19] of/pci: mips: convert to common of_pci_range_parser Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 04/19] of/pci: Add of_pci_get_devfn() function Thomas Petazzoni
2013-04-10 18:33 ` Rob Herring
2013-04-09 21:06 ` [PATCHv8 05/19] of/pci: Add of_pci_parse_bus_range() function Thomas Petazzoni
2013-04-10 18:37 ` Rob Herring
2013-04-09 21:06 ` [PATCHv8 06/19] pci: infrastructure to add drivers in drivers/pci/host Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 07/19] arm: pci: add a align_resource hook Thomas Petazzoni
2013-04-15 16:36 ` Jason Cooper
[not found] ` <20130415163609.GJ28693-u4khhh1J0LxI1Ri9qeTfzeTW4wlIGRCZ@public.gmane.org>
2013-04-17 14:08 ` Jason Cooper
2013-04-19 14:33 ` Russell King - ARM Linux
2013-04-09 21:06 ` [PATCHv8 08/19] clk: mvebu: create parent-child relation for PCIe clocks on Armada 370 Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 09/19] clk: mvebu: add more PCIe clocks for Armada XP Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 10/19] pci: PCIe driver for Marvell Armada 370/XP systems Thomas Petazzoni
2013-04-09 21:12 ` Bjorn Helgaas
2013-04-09 21:22 ` Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 11/19] arm: mvebu: PCIe support is now available on mvebu Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 12/19] arm: mvebu: add PCIe Device Tree informations for Armada 370 Thomas Petazzoni
2013-04-12 0:28 ` Jason Cooper
[not found] ` <20130412002811.GS28693-u4khhh1J0LxI1Ri9qeTfzeTW4wlIGRCZ@public.gmane.org>
2013-04-12 0:48 ` Jason Cooper
2013-04-09 21:06 ` [PATCHv8 13/19] arm: mvebu: add PCIe Device Tree informations for Armada XP Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 14/19] arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4 Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 15/19] arm: mvebu: PCIe Device Tree informations for Armada XP DB Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 16/19] arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 17/19] arm: mvebu: PCIe Device Tree informations for Armada 370 DB Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 18/19] arm: mvebu: PCIe Device Tree informations for Armada XP GP Thomas Petazzoni
2013-04-09 21:06 ` [PATCHv8 19/19] arm: mvebu: update defconfig with PCI and USB support Thomas Petazzoni
2013-04-15 15:46 ` [PATCHv8 00/19] PCIe support for the Armada 370 and Armada XP SoCs Jason Cooper
2013-04-15 16:36 ` Thomas Petazzoni
2013-04-15 16:38 ` Jason Cooper
2013-04-15 16:40 ` Thomas Petazzoni
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).