* [PATCH v4 01/18] of/pci: Provide support for parsing PCI DT ranges property
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 02/18] of/pci: Add of_pci_get_devfn() function Thomas Petazzoni
` (16 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
From: Andrew Murray <andrew.murray@arm.com>
DT bindings for PCI host bridges often use the ranges property to describe
memory and IO ranges - this binding tends to be the same across architectures
yet several parsing implementations exist, e.g. arch/mips/pci/pci.c,
arch/powerpc/kernel/pci-common.c, arch/sparc/kernel/pci.c and
arch/microblaze/pci/pci-common.c (clone of PPC). Some of these duplicate
functionality provided by drivers/of/address.c.
This patch provides a common iterator-based parser for the ranges property, it
is hoped this will reduce DT representation differences between architectures
and that architectures will migrate in part to this new parser.
It is also hoped (and the motativation for the patch) that this patch will
reduce duplication of code when writing host bridge drivers that are supported
by multiple architectures.
This patch provides struct resources from a device tree node, e.g.:
u32 *last = NULL;
struct resource res;
while ((last = of_pci_process_ranges(np, res, last))) {
//do something with res
}
Platforms with quirks can then do what they like with the resource or migrate
common quirk handling to the parser. In an ideal world drivers can just request
the obtained resources and pass them on (e.g. pci_add_resource_offset).
Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
drivers/of/address.c | 63 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_address.h | 9 +++++++
2 files changed, 72 insertions(+)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 04da786..f607008 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -13,6 +13,7 @@
#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0)
static struct of_bus *of_match_bus(struct device_node *np);
+static struct of_bus *of_find_bus(const char *name);
static int __of_address_to_resource(struct device_node *dev,
const __be32 *addrp, u64 size, unsigned int flags,
const char *name, struct resource *r);
@@ -227,6 +228,57 @@ 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);
+
+const __be32 *of_pci_process_ranges(struct device_node *node,
+ struct resource *res, const __be32 *from)
+{
+ const __be32 *start, *end;
+ int na, ns, np, pna;
+ int rlen;
+ struct of_bus *bus;
+
+ WARN_ON(!res);
+
+ bus = of_find_bus("pci");
+ bus->count_cells(node, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ pr_err("Bad cell count for %s\n", node->full_name);
+ return NULL;
+ }
+
+ pna = of_n_addr_cells(node);
+ np = pna + na + ns;
+
+ start = of_get_property(node, "ranges", &rlen);
+ if (start == NULL)
+ return NULL;
+
+ end = start + rlen / sizeof(__be32);
+
+ if (!from)
+ from = start;
+
+ while (from + np <= end) {
+ u64 cpu_addr, size;
+
+ cpu_addr = of_translate_address(node, from + na);
+ size = of_read_number(from + na + pna, ns);
+ res->flags = bus->get_flags(from);
+ from += np;
+
+ if (cpu_addr == OF_BAD_ADDR || size == 0)
+ continue;
+
+ res->name = node->full_name;
+ res->start = cpu_addr;
+ res->end = res->start + size - 1;
+ res->parent = res->child = res->sibling = NULL;
+ return from;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(of_pci_process_ranges);
#endif /* CONFIG_PCI */
/*
@@ -337,6 +389,17 @@ static struct of_bus *of_match_bus(struct device_node *np)
return NULL;
}
+static struct of_bus *of_find_bus(const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(of_busses); i++)
+ if (strcmp(name, of_busses[i].name) == 0)
+ return &of_busses[i];
+
+ return NULL;
+}
+
static int of_translate_one(struct device_node *parent, struct of_bus *bus,
struct of_bus *pbus, __be32 *addr,
int na, int ns, int pna, const char *rprop)
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 0506eb5..751e889 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -27,6 +27,8 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
#define pci_address_to_pio pci_address_to_pio
#endif
+const __be32 *of_pci_process_ranges(struct device_node *node,
+ struct resource *res, const __be32 *from);
#else /* CONFIG_OF_ADDRESS */
#ifndef of_address_to_resource
static inline int of_address_to_resource(struct device_node *dev, int index,
@@ -53,6 +55,13 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index,
{
return NULL;
}
+
+static inline const __be32 *of_pci_process_ranges(struct device_node *node,
+ struct resource *res,
+ const __be32 *from)
+{
+ return NULL;
+}
#endif /* CONFIG_OF_ADDRESS */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 02/18] of/pci: Add of_pci_get_devfn() function
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 01/18] of/pci: Provide support for parsing PCI DT ranges property Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 03/18] of/pci: Add of_pci_get_bus() function Thomas Petazzoni
` (15 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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>
---
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 13e37e2..4dd7b9b 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -5,14 +5,15 @@
#include <asm/prom.h>
static inline int __of_pci_pci_compare(struct device_node *node,
- unsigned int devfn)
+ unsigned int data)
{
- unsigned int size;
- const __be32 *reg = of_get_property(node, "reg", &size);
+ int devfn;
- if (!reg || size < 5 * sizeof(__be32))
+ devfn = of_pci_get_devfn(node);
+ if (devfn < 0)
return 0;
- return ((be32_to_cpup(®[0]) >> 8) & 0xff) == devfn;
+
+ return devfn == data;
}
struct device_node *of_pci_find_child_device(struct device_node *parent,
@@ -40,3 +41,26 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
return NULL;
}
EXPORT_SYMBOL_GPL(of_pci_find_child_device);
+
+/**
+ * of_pci_get_devfn() - Get device and function numbers for a device node
+ * @np: device node
+ *
+ * Parses a standard 5-cell PCI resource and returns an 8-bit value that can
+ * be passed to the PCI_SLOT() and PCI_FUNC() macros to extract the device
+ * and function numbers respectively. On error a negative error code is
+ * returned.
+ */
+int of_pci_get_devfn(struct device_node *np)
+{
+ unsigned int size;
+ const __be32 *reg;
+
+ reg = of_get_property(np, "reg", &size);
+
+ if (!reg || size < 5 * sizeof(__be32))
+ return -EINVAL;
+
+ return (be32_to_cpup(reg) >> 8) & 0xff;
+}
+EXPORT_SYMBOL_GPL(of_pci_get_devfn);
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index bb115de..91ec484 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -10,5 +10,6 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq);
struct device_node;
struct device_node *of_pci_find_child_device(struct device_node *parent,
unsigned int devfn);
+int of_pci_get_devfn(struct device_node *np);
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 03/18] of/pci: Add of_pci_get_bus() function
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 01/18] of/pci: Provide support for parsing PCI DT ranges property Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 02/18] of/pci: Add of_pci_get_devfn() function Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 04/18] of/pci: Add of_pci_parse_bus_range() function Thomas Petazzoni
` (14 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
From: Thierry Reding <thierry.reding@avionic-design.de>
This function can be used to parse the number of a device's parent PCI
bus from a standard 5-cell PCI resource.
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
drivers/of/of_pci.c | 21 +++++++++++++++++++++
include/linux/of_pci.h | 1 +
2 files changed, 22 insertions(+)
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 4dd7b9b..d6e6de5 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -43,6 +43,27 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
EXPORT_SYMBOL_GPL(of_pci_find_child_device);
/**
+ * of_pci_get_bus() - Get bus number for a device node
+ * @np: device node
+ *
+ * Parses a standard 5-cell PCI resource and returns the 8-bit bus number of
+ * the device's parent PCI bus. On error a negative error code is returned.
+ */
+int of_pci_get_bus(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) >> 16) & 0xff;
+}
+EXPORT_SYMBOL_GPL(of_pci_get_bus);
+
+/**
* of_pci_get_devfn() - Get device and function numbers for a device node
* @np: device node
*
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 91ec484..9118321 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -10,6 +10,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_bus(struct device_node *np);
int of_pci_get_devfn(struct device_node *np);
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 04/18] of/pci: Add of_pci_parse_bus_range() function
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (2 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 03/18] of/pci: Add of_pci_get_bus() function Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 05/18] pci: infrastructure to add drivers in drivers/pci/host Thomas Petazzoni
` (13 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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 d6e6de5..fb92ded 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -85,3 +85,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 9118321..fb6e95e 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -12,5 +12,6 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
unsigned int devfn);
int of_pci_get_bus(struct device_node *np);
int of_pci_get_devfn(struct device_node *np);
+int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
#endif
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 05/18] pci: infrastructure to add drivers in drivers/pci/host
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (3 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 04/18] of/pci: Add of_pci_parse_bus_range() function Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 06/18] arm: pci: add a align_resource hook Thomas Petazzoni
` (12 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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>
---
drivers/pci/Kconfig | 2 ++
drivers/pci/Makefile | 3 +++
drivers/pci/host/Kconfig | 4 ++++
3 files changed, 9 insertions(+)
create mode 100644 drivers/pci/host/Kconfig
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
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 06/18] arm: pci: add a align_resource hook
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (4 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 05/18] pci: infrastructure to add drivers in drivers/pci/host Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-20 20:02 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 07/18] clk: mvebu: create parent-child relation for PCIe clocks on Armada 370 Thomas Petazzoni
` (11 subsequent siblings)
17 siblings, 1 reply; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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] 20+ messages in thread* [PATCH v4 06/18] arm: pci: add a align_resource hook
2013-03-08 15:19 ` [PATCH v4 06/18] arm: pci: add a align_resource hook Thomas Petazzoni
@ 2013-03-20 20:02 ` Thomas Petazzoni
0 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-20 20:02 UTC (permalink / raw)
To: linux-arm-kernel
Russell,
Shall I submit the following patch to the ARM patch system? It is
an important dependency of the Marvell PCIe driver.
Note that this patch had already been submitted, and you suggested
using numerical values instead of a function hook, but in fact a
function hook is really needed as the PCIe alignment constraints of the
Marvell HW cannot be simply expressed through numerical values: the
alignment constraints depend on the size of the PCIe region being
considered.
See mvebu_pcie_align_resource() in
http://lists.infradead.org/pipermail/linux-arm-kernel/2013-March/153659.html
if you want to see how we use this hook.
Thanks,
Thomas
On Fri, 8 Mar 2013 16:19:08 +0100, 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;
> }
>
--
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] 20+ messages in thread
* [PATCH v4 07/18] clk: mvebu: create parent-child relation for PCIe clocks on Armada 370
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (5 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 06/18] arm: pci: add a align_resource hook Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 08/18] clk: mvebu: add more PCIe clocks for Armada XP Thomas Petazzoni
` (10 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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] 20+ messages in thread* [PATCH v4 08/18] clk: mvebu: add more PCIe clocks for Armada XP
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (6 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 07/18] clk: mvebu: create parent-child relation for PCIe clocks on Armada 370 Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 09/18] pci: PCIe driver for Marvell Armada 370/XP systems Thomas Petazzoni
` (9 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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>
---
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] 20+ messages in thread* [PATCH v4 09/18] pci: PCIe driver for Marvell Armada 370/XP systems
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (7 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 08/18] clk: mvebu: add more PCIe clocks for Armada XP Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 10/18] arm: mvebu: PCIe support is now available on mvebu Thomas Petazzoni
` (8 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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>
---
.../devicetree/bindings/pci/mvebu-pci.txt | 199 +++++
drivers/pci/host/Kconfig | 4 +
drivers/pci/host/Makefile | 4 +
drivers/pci/host/pci-mvebu.c | 927 ++++++++++++++++++++
4 files changed, 1134 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/mvebu-pci.txt
create mode 100644 drivers/pci/host/Makefile
create mode 100644 drivers/pci/host/pci-mvebu.c
diff --git a/Documentation/devicetree/bindings/pci/mvebu-pci.txt b/Documentation/devicetree/bindings/pci/mvebu-pci.txt
new file mode 100644
index 0000000..33bd999
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/mvebu-pci.txt
@@ -0,0 +1,199 @@
+* 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
+- reg: list of the PCIe registers for each PCIe interface
+- reg-names: names of the PCIe interfaces, used to find the
+ corresponding registers
+- ranges: ranges for the PCI memory and I/O regions
+
+In addition, the Device Tree node must have sub-nodes describing each
+PCIe interface, having the following mandatory properties:
+- reg: used only for interrupt mapping, so only the first four bytes
+ are used to refer to the correct bus number and device number.
+- clocks: the clock associated to this PCIe interface
+- marvell,pcie-port: the physical PCIe port number
+- status: either "disabled" or "okay"
+- device_type, set to "pci"
+- #address-cells, set to <3>
+- #size-cells, set to <2>
+- #interrupt-cells, set to <1>
+- interrupt-map-mask and interrupt-map, standard PCI properties to
+ define the mapping of the PCIe interface to interrupt numbers.
+
+and the following optional properties:
+- marvell,pcie-lane: the physical PCIe lane number, for ports having
+ multiple lanes. If this property is not found, we assume that the
+ value is 0.
+
+Example:
+
+pcie-controller {
+ compatible = "marvell,armada-xp-pcie";
+ status = "disabled";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ reg = <0xd0040000 0x2000>, <0xd0042000 0x2000>,
+ <0xd0044000 0x2000>, <0xd0048000 0x2000>,
+ <0xd004C000 0x2000>, <0xd0080000 0x2000>,
+ <0xd0082000 0x2000>, <0xd0084000 0x2000>,
+ <0xd0088000 0x2000>, <0xd008C000 0x2000>;
+
+ reg-names = "pcie0.0", "pcie2.0",
+ "pcie0.1", "pcie0.2",
+ "pcie0.3", "pcie1.0",
+ "pcie3.0", "pcie1.1",
+ "pcie1.2", "pcie1.3";
+
+ ranges = <0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+ pcie at 0,0 {
+ device_type = "pci";
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 58>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 0,1 {
+ device_type = "pci";
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 59>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 6>;
+ status = "disabled";
+ };
+
+ pcie at 0,2 {
+ device_type = "pci";
+ reg = <0x1800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 60>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 7>;
+ status = "disabled";
+ };
+
+ pcie at 0,3 {
+ device_type = "pci";
+ reg = <0x2000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 61>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 8>;
+ status = "disabled";
+ };
+
+ pcie at 1,0 {
+ device_type = "pci";
+ reg = <0x2800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 62>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 9>;
+ status = "disabled";
+ };
+
+ pcie at 1,1 {
+ device_type = "pci";
+ reg = <0x3000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 63>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 10>;
+ status = "disabled";
+ };
+
+ pcie at 1,2 {
+ device_type = "pci";
+ reg = <0x3800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 64>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 11>;
+ status = "disabled";
+ };
+
+ pcie at 1,3 {
+ device_type = "pci";
+ reg = <0x4000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 65>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 12>;
+ status = "disabled";
+ };
+ pcie at 2,0 {
+ device_type = "pci";
+ reg = <0x4800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 99>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 26>;
+ status = "disabled";
+ };
+
+ pcie at 3,0 {
+ device_type = "pci";
+ reg = <0x5000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 103>;
+ marvell,pcie-port = <3>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 27>;
+ status = "disabled";
+ };
+};
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
new file mode 100644
index 0000000..3ad563f
--- /dev/null
+++ b/drivers/pci/host/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
+CFLAGS_pci-mvebu.o += \
+ -I$(srctree)/arch/arm/plat-orion/include \
+ -I$(srctree)/arch/arm/mach-mvebu/include
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
new file mode 100644
index 0000000..b812750
--- /dev/null
+++ b/drivers/pci/host/pci-mvebu.c
@@ -0,0 +1,927 @@
+/*
+ * 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_DATA_OFF 0x18fc
+#define PCIE_MASK_OFF 0x1910
+#define PCIE_CTRL_OFF 0x1a00
+#define PCIE_CTRL_X1_MODE 0x0001
+#define PCIE_STAT_OFF 0x1a04
+#define PCIE_STAT_DEV_OFFS 20
+#define PCIE_STAT_DEV_MASK 0x1f
+#define PCIE_STAT_BUS_OFFS 8
+#define PCIE_STAT_BUS_MASK 0xff
+#define PCIE_STAT_LINK_DOWN 1
+#define PCIE_DEBUG_CTRL 0x1a60
+#define PCIE_DEBUG_SOFT_RESET (1<<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 int mvebu_pcie_link_up(void __iomem *base)
+{
+ return !(readl(base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
+}
+
+static void mvebu_pcie_set_local_bus_nr(void __iomem *base, int nr)
+{
+ u32 stat;
+
+ stat = readl(base + PCIE_STAT_OFF);
+ stat &= ~(PCIE_STAT_BUS_MASK << PCIE_STAT_BUS_OFFS);
+ stat |= nr << PCIE_STAT_BUS_OFFS;
+ writel(stat, 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(void __iomem *base)
+{
+ 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 <= 2; i++) {
+ writel(0, base + PCIE_BAR_CTRL_OFF(i));
+ writel(0, base + PCIE_BAR_LO_OFF(i));
+ writel(0, base + PCIE_BAR_HI_OFF(i));
+ }
+
+ for (i = 0; i < 5; i++) {
+ writel(0, base + PCIE_WIN04_CTRL_OFF(i));
+ writel(0, base + PCIE_WIN04_BASE_OFF(i));
+ writel(0, base + PCIE_WIN04_REMAP_OFF(i));
+ }
+
+ writel(0, base + PCIE_WIN5_CTRL_OFF);
+ writel(0, base + PCIE_WIN5_BASE_OFF);
+ writel(0, 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, base + PCIE_WIN04_BASE_OFF(i));
+ writel(0, base + PCIE_WIN04_REMAP_OFF(i));
+ writel(((cs->size - 1) & 0xffff0000) |
+ (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ 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, base + PCIE_BAR_LO_OFF(1));
+ writel(0, base + PCIE_BAR_HI_OFF(1));
+ writel(((size - 1) & 0xffff0000) | 1, base + PCIE_BAR_CTRL_OFF(1));
+}
+
+static void __init mvebu_pcie_setup_hw(void __iomem *base)
+{
+ u16 cmd;
+ u32 mask;
+
+ /*
+ * Point PCIe unit MBUS decode windows to DRAM space.
+ */
+ mvebu_pcie_setup_wins(base);
+
+ /*
+ * Master + slave enable.
+ */
+ cmd = readw(base + PCIE_CMD_OFF);
+ cmd |= PCI_COMMAND_IO;
+ cmd |= PCI_COMMAND_MEMORY;
+ cmd |= PCI_COMMAND_MASTER;
+ writew(cmd, base + PCIE_CMD_OFF);
+
+ /*
+ * Enable interrupt lines A-D.
+ */
+ mask = readl(base + PCIE_MASK_OFF);
+ mask |= 0x0f000000;
+ writel(mask, base + PCIE_MASK_OFF);
+}
+
+static int mvebu_pcie_hw_rd_conf(void __iomem *base, struct pci_bus *bus,
+ u32 devfn, int where, int size, u32 *val)
+{
+ writel(PCIE_CONF_BUS(bus->number) |
+ PCIE_CONF_DEV(PCI_SLOT(devfn)) |
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
+ PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
+ base + PCIE_CONF_ADDR_OFF);
+
+ *val = readl(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(void __iomem *base, struct pci_bus *bus,
+ u32 devfn, int where, int size, u32 val)
+{
+ int ret = PCIBIOS_SUCCESSFUL;
+
+ writel(PCIE_CONF_BUS(bus->number) |
+ PCIE_CONF_DEV(PCI_SLOT(devfn)) |
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
+ PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
+ base + PCIE_CONF_ADDR_OFF);
+
+ if (size == 4)
+ writel(val, base + PCIE_CONF_DATA_OFF);
+ else if (size == 2)
+ writew(val, base + PCIE_CONF_DATA_OFF + (where & 3));
+ else if (size == 1)
+ writeb(val, 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 current 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 current 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->base, 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;
+}
+
+/* Find the PCIe interface that corresponds to the given bus */
+static struct mvebu_pcie_port *mvebu_find_port_from_bus(struct mvebu_pcie *pcie,
+ int bus)
+{
+ int porti;
+
+ for (porti = 0; porti < pcie->nports; porti++)
+ if (pcie->ports[porti].bridge.secondary_bus == bus)
+ return &pcie->ports[porti];
+
+ return NULL;
+}
+
+/* Find the PCIe interface that corresponds to the given devfn */
+static struct mvebu_pcie_port *
+mvebu_find_port_from_devfn(struct mvebu_pcie *pcie, int devfn)
+{
+ int porti;
+
+ for (porti = 0; porti < pcie->nports; porti++)
+ if (pcie->ports[porti].devfn == devfn)
+ return &pcie->ports[porti];
+
+ 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);
+
+ if (bus->number != 0) {
+ /*
+ * Accessing a real PCIe interface.
+ */
+ struct mvebu_pcie_port *port;
+ unsigned long flags;
+ int ret;
+
+ port = mvebu_find_port_from_bus(pcie, bus->number);
+ if (!port)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (!port->haslink)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (PCI_SLOT(devfn) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ spin_lock_irqsave(&port->conf_lock, flags);
+ ret = mvebu_pcie_hw_wr_conf(port->base, bus,
+ PCI_DEVFN(1, PCI_FUNC(devfn)),
+ where, size, val);
+ spin_unlock_irqrestore(&port->conf_lock, flags);
+
+ return ret;
+ } else {
+ /*
+ * Access the emulated PCI-to-PCI bridges.
+ */
+ struct mvebu_pcie_port *port;
+ port = mvebu_find_port_from_devfn(pcie, devfn);
+ if (!port)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return mvebu_sw_pci_bridge_write(port, where, size, val);
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/* 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);
+
+ if (bus->number != 0) {
+ /*
+ * Accessing a real PCIe interface.
+ */
+ struct mvebu_pcie_port *port;
+ unsigned long flags;
+ int ret;
+
+ port = mvebu_find_port_from_bus(pcie, bus->number);
+ if (!port) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ if (!port->haslink || PCI_SLOT(devfn) != 0) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ spin_lock_irqsave(&port->conf_lock, flags);
+ ret = mvebu_pcie_hw_rd_conf(port->base, bus,
+ PCI_DEVFN(1, PCI_FUNC(devfn)),
+ where, size, val);
+ spin_unlock_irqrestore(&port->conf_lock, flags);
+
+ return ret;
+ } else {
+ /*
+ * Access the emulated PCI-to-PCI bridges.
+ */
+ struct mvebu_pcie_port *port;
+ port = mvebu_find_port_from_devfn(pcie, devfn);
+ if (!port) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ return mvebu_sw_pci_bridge_read(port, where, size, val);
+ }
+}
+
+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->base);
+ }
+
+ 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);
+ return pci_scan_root_bus(&pcie->pdev->dev, sys->busnr,
+ &mvebu_pcie_ops, sys, &sys->resources);
+}
+
+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;
+ int i;
+
+ for (i = 0; ; i++) {
+ ret = of_address_to_resource(np, i, ®s);
+ if (ret)
+ break;
+
+ if (!strcmp(regs.name, port->name))
+ break;
+ }
+
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot find regs for '%s'\n",
+ port->name);
+ 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 device_node *child;
+ const __be32 *range = NULL;
+ struct resource res;
+ int i, ret;
+
+ pcie = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pcie),
+ GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie->pdev = pdev;
+
+ /* Get the I/O and memory ranges from DT */
+ while ((range = of_pci_process_ranges(np, &res, range)) != NULL) {
+ if (resource_type(&res) == IORESOURCE_IO) {
+ memcpy(&pcie->io, &res, sizeof(res));
+ memcpy(&pcie->realio, &res, sizeof(res));
+ pcie->io.name = "I/O";
+ pcie->realio.start = PCIBIOS_MIN_IO;
+ pcie->realio.end = min(resource_size(&pcie->io),
+ IO_SPACE_LIMIT);
+ }
+ if (resource_type(&res) == IORESOURCE_MEM) {
+ memcpy(&pcie->mem, &res, sizeof(res));
+ 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, np, 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->base)) {
+ 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] 20+ messages in thread* [PATCH v4 10/18] arm: mvebu: PCIe support is now available on mvebu
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (8 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 09/18] pci: PCIe driver for Marvell Armada 370/XP systems Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 11/18] arm: mvebu: add PCIe Device Tree informations for Armada 370 Thomas Petazzoni
` (7 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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] 20+ messages in thread* [PATCH v4 11/18] arm: mvebu: add PCIe Device Tree informations for Armada 370
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (9 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 10/18] arm: mvebu: PCIe support is now available on mvebu Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 12/18] arm: mvebu: add PCIe Device Tree informations for Armada XP Thomas Petazzoni
` (6 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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 | 44 +++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index e46955b..8ac27a7 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -156,5 +156,49 @@
clocks = <&coreclk 0>;
};
+ pcie-controller {
+ compatible = "marvell,armada-370-pcie";
+ status = "disabled";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ reg = <0xd0040000 0x2000>, <0xd0080000 0x2000>;
+
+ reg-names = "pcie0.0", "pcie1.0";
+
+ ranges = <0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+ pcie at 0,0 {
+ device_type = "pci";
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 58>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 1,0 {
+ device_type = "pci";
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 62>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 9>;
+ status = "disabled";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 12/18] arm: mvebu: add PCIe Device Tree informations for Armada XP
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (10 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 11/18] arm: mvebu: add PCIe Device Tree informations for Armada 370 Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 13/18] arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4 Thomas Petazzoni
` (5 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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 | 97 +++++++++++++++++
arch/arm/boot/dts/armada-xp-mv78260.dtsi | 112 ++++++++++++++++++++
arch/arm/boot/dts/armada-xp-mv78460.dtsi | 169 ++++++++++++++++++++++++++++++
3 files changed, 378 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-mv78230.dtsi b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
index f56c405..7d28e7b 100644
--- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
@@ -76,5 +76,102 @@
#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";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ reg = <0xd0040000 0x2000>, <0xd0042000 0x2000>,
+ <0xd0044000 0x2000>, <0xd0048000 0x2000>,
+ <0xd004C000 0x2000>;
+
+ reg-names = "pcie0.0", "pcie2.0",
+ "pcie0.1", "pcie0.2",
+ "pcie0.3";
+
+ ranges = <0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+
+ pcie at 0,0 {
+ device_type = "pci";
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 58>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 0,1 {
+ device_type = "pci";
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 59>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 6>;
+ status = "disabled";
+ };
+
+ pcie at 0,2 {
+ device_type = "pci";
+ reg = <0x1800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 60>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 7>;
+ status = "disabled";
+ };
+
+ pcie at 0,3 {
+ device_type = "pci";
+ reg = <0x2000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 61>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 8>;
+ status = "disabled";
+ };
+
+ pcie at 2,0 {
+ device_type = "pci";
+ reg = <0x4800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 99>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 26>;
+ status = "disabled";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
index f8f2b78..7b629d5 100644
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -96,5 +96,117 @@
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";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ reg = <0xd0040000 0x2000>, <0xd0042000 0x2000>,
+ <0xd0044000 0x2000>, <0xd0048000 0x2000>,
+ <0xd004C000 0x2000>, <0xd0080000 0x2000>,
+ <0xd0082000 0x2000>;
+
+ reg-names = "pcie0.0", "pcie2.0",
+ "pcie0.1", "pcie0.2",
+ "pcie0.3", "pcie1.0",
+ "pcie3.0";
+
+ ranges = <0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+ pcie at 0,0 {
+ device_type = "pci";
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 58>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 0,1 {
+ device_type = "pci";
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 59>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 6>;
+ status = "disabled";
+ };
+
+ pcie at 0,2 {
+ device_type = "pci";
+ reg = <0x1800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 60>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 7>;
+ status = "disabled";
+ };
+
+ pcie at 0,3 {
+ device_type = "pci";
+ reg = <0x2000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 61>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 8>;
+ status = "disabled";
+ };
+
+ pcie at 2,0 {
+ device_type = "pci";
+ reg = <0x4800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 99>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 26>;
+ status = "disabled";
+ };
+
+ pcie at 3,0 {
+ device_type = "pci";
+ reg = <0x5000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 103>;
+ marvell,pcie-port = <3>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 27>;
+ status = "disabled";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/armada-xp-mv78460.dtsi b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
index 936c25d..ce7ec0a 100644
--- a/arch/arm/boot/dts/armada-xp-mv78460.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
@@ -111,5 +111,174 @@
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";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ reg = <0xd0040000 0x2000>, <0xd0042000 0x2000>,
+ <0xd0044000 0x2000>, <0xd0048000 0x2000>,
+ <0xd004C000 0x2000>, <0xd0080000 0x2000>,
+ <0xd0082000 0x2000>, <0xd0084000 0x2000>,
+ <0xd0088000 0x2000>, <0xd008C000 0x2000>;
+
+ reg-names = "pcie0.0", "pcie2.0",
+ "pcie0.1", "pcie0.2",
+ "pcie0.3", "pcie1.0",
+ "pcie3.0", "pcie1.1",
+ "pcie1.2", "pcie1.3";
+
+ ranges = <0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */
+ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */
+
+ pcie at 0,0 {
+ device_type = "pci";
+ reg = <0x0800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 58>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 0,1 {
+ device_type = "pci";
+ reg = <0x1000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 59>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 6>;
+ status = "disabled";
+ };
+
+ pcie at 0,2 {
+ device_type = "pci";
+ reg = <0x1800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 60>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 7>;
+ status = "disabled";
+ };
+
+ pcie at 0,3 {
+ device_type = "pci";
+ reg = <0x2000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 61>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 8>;
+ status = "disabled";
+ };
+
+ pcie at 1,0 {
+ device_type = "pci";
+ reg = <0x2800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 62>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 9>;
+ status = "disabled";
+ };
+
+ pcie at 1,1 {
+ device_type = "pci";
+ reg = <0x3000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 63>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 10>;
+ status = "disabled";
+ };
+
+ pcie at 1,2 {
+ device_type = "pci";
+ reg = <0x3800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 64>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 11>;
+ status = "disabled";
+ };
+
+ pcie at 1,3 {
+ device_type = "pci";
+ reg = <0x4000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 65>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 12>;
+ status = "disabled";
+ };
+ pcie at 2,0 {
+ device_type = "pci";
+ reg = <0x4800 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 99>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 26>;
+ status = "disabled";
+ };
+
+ pcie at 3,0 {
+ device_type = "pci";
+ reg = <0x5000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &mpic 103>;
+ marvell,pcie-port = <3>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 27>;
+ status = "disabled";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 13/18] arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (11 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 12/18] arm: mvebu: add PCIe Device Tree informations for Armada XP Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 14/18] arm: mvebu: PCIe Device Tree informations for Armada XP DB Thomas Petazzoni
` (4 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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 | 8 ++++++++
1 file changed, 8 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..5f87bc8 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,13 @@
usb at d0051000 {
status = "okay";
};
+
+ pcie-controller {
+ status = "okay";
+ /* Internal mini-PCIe connector */
+ pcie at 0,0 {
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 14/18] arm: mvebu: PCIe Device Tree informations for Armada XP DB
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (12 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 13/18] arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4 Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 15/18] arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox Thomas Petazzoni
` (3 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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 | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index e83505e..fdfdfc6 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -121,5 +121,32 @@
spi-max-frequency = <20000000>;
};
};
+
+ pcie-controller {
+ status = "okay";
+
+ /*
+ * All 6 slots are physically present as
+ * standard PCIe slots on the board.
+ */
+ pcie at 0,0 {
+ status = "okay";
+ };
+ pcie at 0,1 {
+ status = "okay";
+ };
+ pcie at 0,2 {
+ status = "okay";
+ };
+ pcie at 0,3 {
+ status = "okay";
+ };
+ pcie at 2,0 {
+ status = "okay";
+ };
+ pcie at 3,0 {
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 15/18] arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (13 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 14/18] arm: mvebu: PCIe Device Tree informations for Armada XP DB Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 16/18] arm: mvebu: PCIe Device Tree informations for Armada 370 DB Thomas Petazzoni
` (2 subsequent siblings)
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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 | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index dd0c57d..84e96a4 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -70,5 +70,19 @@
usb at d0051000 {
status = "okay";
};
+
+ pcie-controller {
+ status = "okay";
+
+ /* Internal mini-PCIe connector */
+ pcie at 0,0 {
+ status = "okay";
+ };
+
+ /* Connected on the PCB to a USB 3.0 XHCI controller */
+ pcie at 1,0 {
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 16/18] arm: mvebu: PCIe Device Tree informations for Armada 370 DB
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (14 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 15/18] arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 17/18] arm: mvebu: PCIe Device Tree informations for Armada XP GP Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 18/18] arm: mvebu: update defconfig with PCI and USB support Thomas Petazzoni
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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 | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index e34b280..97956fc 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -94,5 +94,20 @@
spi-max-frequency = <50000000>;
};
};
+
+ pcie-controller {
+ status = "okay";
+ /*
+ * The two PCIe units are accessible through
+ * both standard PCIe slots and mini-PCIe
+ * slots on the board.
+ */
+ pcie at 0,0 {
+ status = "okay";
+ };
+ pcie at 1,0 {
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 17/18] arm: mvebu: PCIe Device Tree informations for Armada XP GP
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (15 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 16/18] arm: mvebu: PCIe Device Tree informations for Armada 370 DB Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
2013-03-08 15:19 ` [PATCH v4 18/18] arm: mvebu: update defconfig with PCI and USB support Thomas Petazzoni
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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 | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index 1c8afe2..34d7426 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -109,5 +109,23 @@
spi-max-frequency = <108000000>;
};
};
+
+ pcie-controller {
+ status = "okay";
+
+ /*
+ * The 3 slots are physically present as
+ * standard PCIe slots on the board.
+ */
+ pcie at 0,0 {
+ status = "okay";
+ };
+ pcie at 2,0 {
+ status = "okay";
+ };
+ pcie at 3,0 {
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH v4 18/18] arm: mvebu: update defconfig with PCI and USB support
2013-03-08 15:19 [PATCH v4 00/18] PCIe support for the Armada 370 and Armada XP SoCs Thomas Petazzoni
` (16 preceding siblings ...)
2013-03-08 15:19 ` [PATCH v4 17/18] arm: mvebu: PCIe Device Tree informations for Armada XP GP Thomas Petazzoni
@ 2013-03-08 15:19 ` Thomas Petazzoni
17 siblings, 0 replies; 20+ messages in thread
From: Thomas Petazzoni @ 2013-03-08 15:19 UTC (permalink / raw)
To: linux-arm-kernel
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] 20+ messages in thread