mvebu: add preliminary support for PCI express

Signed-off-by: Florian Fainelli <florian@openwrt.org>

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@35211 3c298f89-4303-0410-b956-a3cf2f4a3e73
master
Florian Fainelli 2013-01-17 22:29:13 +00:00
parent 4d55ef2877
commit 005e0ee7c9
16 changed files with 1434 additions and 0 deletions

View File

@ -172,6 +172,7 @@ CONFIG_MACH_ARMADA_XP=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_MDIO_BOARDINFO=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_MIGHT_HAVE_PCI=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MPCORE_WATCHDOG is not set
CONFIG_MSDOS_FS=y
@ -210,6 +211,7 @@ CONFIG_OUTER_CACHE=y
CONFIG_OUTER_CACHE_SYNC=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PCI is not set
# CONFIG_PCI_SYSCALL is not set
CONFIG_PERCPU_RWSEM=y
CONFIG_PERF_USE_VMALLOC=y

View File

@ -0,0 +1,28 @@
The pcim_*() functions are used by the libata-sff subsystem, and this
subsystem is used for many SATA drivers on ARM platforms that do not
necessarily have I/O ports.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: linux-kernel@vger.kernel.org
---
lib/devres.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -195,6 +195,7 @@ void devm_ioport_unmap(struct device *de
devm_ioport_map_match, (void *)addr));
}
EXPORT_SYMBOL(devm_ioport_unmap);
+#endif /* CONFIG_HAS_IOPORT */
#ifdef CONFIG_PCI
/*
@@ -400,4 +401,3 @@ void pcim_iounmap_regions(struct pci_dev
}
EXPORT_SYMBOL(pcim_iounmap_regions);
#endif /* CONFIG_PCI */
-#endif /* CONFIG_HAS_IOPORT */

View File

@ -0,0 +1,24 @@
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(-)
--- 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 __in
{ "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 },

View File

@ -0,0 +1,28 @@
Instead of hardcoding "1" as being the bit value to enable an address
decoding window, introduce and use a WIN_CTRL_ENABLE definition.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/plat-orion/addr-map.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/arch/arm/plat-orion/addr-map.c
+++ b/arch/arm/plat-orion/addr-map.c
@@ -38,6 +38,7 @@ EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
* CPU Address Decode Windows registers
*/
#define WIN_CTRL_OFF 0x0000
+#define WIN_CTRL_ENABLE BIT(0)
#define WIN_BASE_OFF 0x0004
#define WIN_REMAP_LO_OFF 0x0008
#define WIN_REMAP_HI_OFF 0x000c
@@ -79,7 +80,8 @@ void __init orion_setup_cpu_win(const st
}
base_high = base & 0xffff0000;
- ctrl = ((size - 1) & 0xffff0000) | (attr << 8) | (target << 4) | 1;
+ ctrl = ((size - 1) & 0xffff0000) | (attr << 8) | (target << 4) |
+ WIN_CTRL_ENABLE;
writel(base_high, addr + WIN_BASE_OFF);
writel(ctrl, addr + WIN_CTRL_OFF);

View File

@ -0,0 +1,80 @@
In the address decoding code, the orion_disable_wins() function is
used at boot time to disable all address decoding windows, before
configuring only the ones that are needed. This allows to make sure
that no configuration is left from the bootloader.
As a preparation for the introduction of address decoding window
allocation/deallocation function, we refactor this function into an
orion_disable_cpu_win() which disables a single window.
The orion_config_wins() function is changed to call
orion_disable_cpu_win() in a loop, to preserve an identical behavior.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/plat-orion/addr-map.c | 35 +++++++++++++++++------------------
1 file changed, 17 insertions(+), 18 deletions(-)
--- a/arch/arm/plat-orion/addr-map.c
+++ b/arch/arm/plat-orion/addr-map.c
@@ -95,6 +95,19 @@ void __init orion_setup_cpu_win(const st
}
}
+static void __init orion_disable_cpu_win(const struct orion_addr_map_cfg *cfg,
+ const int win)
+{
+ void __iomem *addr = cfg->win_cfg_base(cfg, win);
+
+ writel(0, addr + WIN_BASE_OFF);
+ writel(0, addr + WIN_CTRL_OFF);
+ if (cfg->cpu_win_can_remap(cfg, win)) {
+ writel(0, addr + WIN_REMAP_LO_OFF);
+ writel(0, addr + WIN_REMAP_HI_OFF);
+ }
+}
+
/*
* Configure a number of windows.
*/
@@ -108,36 +121,22 @@ static void __init orion_setup_cpu_wins(
}
}
-static void __init orion_disable_wins(const struct orion_addr_map_cfg * cfg)
-{
- void __iomem *addr;
- int i;
-
- for (i = 0; i < cfg->num_wins; i++) {
- addr = cfg->win_cfg_base(cfg, i);
-
- writel(0, addr + WIN_BASE_OFF);
- writel(0, addr + WIN_CTRL_OFF);
- if (cfg->cpu_win_can_remap(cfg, i)) {
- writel(0, addr + WIN_REMAP_LO_OFF);
- writel(0, addr + WIN_REMAP_HI_OFF);
- }
- }
-}
-
/*
* Disable, clear and configure windows.
*/
void __init orion_config_wins(struct orion_addr_map_cfg * cfg,
const struct orion_addr_map_info *info)
{
+ int win;
+
if (!cfg->cpu_win_can_remap)
cfg->cpu_win_can_remap = orion_cpu_win_can_remap;
if (!cfg->win_cfg_base)
cfg->win_cfg_base = orion_win_cfg_base;
- orion_disable_wins(cfg);
+ for (win = 0; win < cfg->num_wins; win++)
+ orion_disable_cpu_win(cfg, win);
if (info)
orion_setup_cpu_wins(cfg, info);

View File

@ -0,0 +1,96 @@
In the address decoding code, we implement two new functions:
orion_alloc_cpu_win() and orion_free_cpu_win(). The first function
finds an unused address decoding window, and configures it according
to the given arguments (in terms of base address, size, target,
attributes). The second function frees an address decoding window,
given a physical base address.
Those two new functions will be used by the PCIe code, which needs to
dynamically register address decoding windows depending on the PCIe
devices that are detected.
The orion_free_cpu_win() function is only here to handle error cases
in the PCIe devices initialization, in the normal case, address
decoding windows are never freed.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/plat-orion/addr-map.c | 50 +++++++++++++++++++++++++++
arch/arm/plat-orion/include/plat/addr-map.h | 7 ++++
2 files changed, 57 insertions(+)
--- a/arch/arm/plat-orion/addr-map.c
+++ b/arch/arm/plat-orion/addr-map.c
@@ -109,6 +109,56 @@ static void __init orion_disable_cpu_win
}
/*
+ * Find an unused address decoding window, and enable it according to
+ * the arguments passed (base, size, target, attributes, remap).
+ */
+int __init orion_alloc_cpu_win(const struct orion_addr_map_cfg *cfg,
+ const u32 base, const u32 size,
+ const u8 target, const u8 attr, const int remap)
+{
+ int win;
+
+ for (win = 0; win < cfg->num_wins; win++) {
+ void __iomem *addr = cfg->win_cfg_base(cfg, win);
+ u32 ctrl = readl(addr + WIN_CTRL_OFF);
+ if (!(ctrl & WIN_CTRL_ENABLE))
+ break;
+ }
+
+ /* No more windows available */
+ if (win == cfg->num_wins)
+ return -ENOMEM;
+
+ orion_setup_cpu_win(cfg, win, base, size, target, attr, remap);
+ return 0;
+}
+
+/*
+ * Free an address decoding window, given its base address.
+ */
+int __init orion_free_cpu_win(const struct orion_addr_map_cfg *cfg,
+ const u32 base)
+{
+ int win;
+
+ for (win = 0; win < cfg->num_wins; win++) {
+ void __iomem *addr = cfg->win_cfg_base(cfg, win);
+ u32 winbase = readl(addr + WIN_BASE_OFF);
+ u32 ctrl = readl(addr + WIN_CTRL_OFF);
+
+ if (!(ctrl & WIN_CTRL_ENABLE))
+ continue;
+
+ if (winbase == (base & 0xffff0000)) {
+ orion_disable_cpu_win(cfg, win);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*
* Configure a number of windows.
*/
static void __init orion_setup_cpu_wins(const struct orion_addr_map_cfg * cfg,
--- a/arch/arm/plat-orion/include/plat/addr-map.h
+++ b/arch/arm/plat-orion/include/plat/addr-map.h
@@ -49,6 +49,13 @@ void __init orion_setup_cpu_win(const st
const u32 size, const u8 target,
const u8 attr, const int remap);
+int __init orion_alloc_cpu_win(const struct orion_addr_map_cfg *cfg,
+ const u32 base, const u32 size,
+ const u8 target, const u8 attr, const int remap);
+
+int __init orion_free_cpu_win(const struct orion_addr_map_cfg *cfg,
+ const u32 base);
+
void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg,
const void __iomem *ddr_window_cpu_base);
#endif

View File

@ -0,0 +1,201 @@
This commit adds two functions armada_370_xp_alloc_pcie_window() and
armada_370_xp_free_pcie_window() that respectively allocate and free
an address decoding window pointing to either a memory or I/O region
of a PCIe device.
Those functions will be used by the PCIe driver to create and remove
those regions depending on the PCIe devices that are detected.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/mach-mvebu/addr-map.c | 156 ++++++++++++++++++++++++++++++++++++++--
arch/arm/mach-mvebu/common.h | 4 ++
2 files changed, 156 insertions(+), 4 deletions(-)
--- a/arch/arm/mach-mvebu/addr-map.c
+++ b/arch/arm/mach-mvebu/addr-map.c
@@ -24,14 +24,10 @@
#define ARMADA_XP_TARGET_DEV_BUS 1
#define ARMADA_XP_ATTR_DEV_BOOTROM 0x1D
#define ARMADA_XP_TARGET_ETH1 3
-#define ARMADA_XP_TARGET_PCIE_0_2 4
#define ARMADA_XP_TARGET_ETH0 7
-#define ARMADA_XP_TARGET_PCIE_1_3 8
#define ARMADA_370_TARGET_DEV_BUS 1
#define ARMADA_370_ATTR_DEV_BOOTROM 0x1D
-#define ARMADA_370_TARGET_PCIE_0 4
-#define ARMADA_370_TARGET_PCIE_1 8
#define ARMADA_WINDOW_8_PLUS_OFFSET 0x90
#define ARMADA_SDRAM_ADDR_DECODING_OFFSET 0x180
@@ -89,6 +85,158 @@ static struct __initdata orion_addr_map_
.win_cfg_base = armada_cfg_base,
};
+#ifdef CONFIG_PCI
+/*
+ * PCIe windows allocation code.
+ */
+#define ARMADA_370_XP_PCIE_MEM_START 0xC0000000
+#define ARMADA_370_XP_PCIE_MEM_END (ARMADA_370_XP_PCIE_MEM_START + SZ_256M)
+#define ARMADA_370_XP_PCIE_IO_START 0xF2000000
+#define ARMADA_370_XP_PCIE_IO_END (ARMADA_370_XP_PCIE_IO_START + SZ_1M)
+
+static unsigned long armada_370_xp_pcie_memaddr = ARMADA_370_XP_PCIE_MEM_START;
+static unsigned long armada_370_xp_pcie_ioaddr = ARMADA_370_XP_PCIE_IO_START;
+
+/*
+ * This structure and the following arrays allow to map a PCIe (port,
+ * lane) tuple to the corresponding (target, attribute) tuple needed
+ * to configure an address decoding window for the given PCIe (port,
+ * lane).
+ */
+struct pcie_mapping {
+ int port;
+ int lane;
+ u8 target;
+ u8 attr;
+};
+
+struct pcie_mapping armada_xp_pcie_mappings[] = {
+ { .port = 0, .lane = 0, .target = 4, .attr = 0xE0 },
+ { .port = 0, .lane = 1, .target = 4, .attr = 0xD0 },
+ { .port = 0, .lane = 2, .target = 4, .attr = 0xB0 },
+ { .port = 0, .lane = 3, .target = 4, .attr = 0x70 },
+ { .port = 1, .lane = 0, .target = 8, .attr = 0xE0 },
+ { .port = 1, .lane = 1, .target = 8, .attr = 0xD0 },
+ { .port = 1, .lane = 2, .target = 8, .attr = 0xB0 },
+ { .port = 1, .lane = 3, .target = 8, .attr = 0x70 },
+ { .port = 2, .lane = 0, .target = 4, .attr = 0xF0 },
+ { .port = 3, .lane = 0, .target = 8, .attr = 0xF0 },
+ { .port = -1 },
+};
+
+struct pcie_mapping armada_370_pcie_mappings[] = {
+ { .port = 0, .lane = 0, .target = 4, .attr = 0xE0 },
+ { .port = 1, .lane = 0, .target = 8, .attr = 0xE0 },
+ { .port = -1 },
+};
+
+/*
+ * This function finds an available physical address range between
+ * ARMADA_370_XP_PCIE_MEM_START and ARMADA_370_XP_PCIE_MEM_END (for
+ * PCIe memory regions) or between ARMADA_370_XP_PCIE_IO_START and
+ * ARMADA_370_XP_PCIE_IO_END (for PCIe I/O regions) and creates an
+ * address decoding window from this allocated address pointing to the
+ * right PCIe device.
+ *
+ * An error code is returned, the allocated base address is returned
+ * through the 'outbase' argument.
+ */
+int __init armada_370_xp_alloc_pcie_window(int pcie_port, int pcie_lane,
+ int type, u32 size,
+ unsigned long *outbase)
+{
+ struct pcie_mapping *mapping, *mappings;
+ u8 target, attr;
+ u32 base;
+ int ret;
+
+ if (of_machine_is_compatible("marvell,armadaxp"))
+ mappings = armada_xp_pcie_mappings;
+ else if (of_machine_is_compatible("marvell,armada370"))
+ mappings = armada_370_pcie_mappings;
+ else
+ return -ENODEV;
+
+ for (mapping = mappings; mapping->port != -1; mapping++)
+ if (mapping->port == pcie_port && mapping->lane == pcie_lane)
+ break;
+
+ if (mapping->port == -1)
+ return -ENODEV;
+
+ target = mapping->target;
+ attr = mapping->attr;
+
+ if (type == IORESOURCE_MEM) {
+ /*
+ * Bit 3 of the attributes indicates that it is a
+ * memory region, as opposed to an I/O region
+ */
+ attr |= (1 << 3);
+
+ if (armada_370_xp_pcie_memaddr + size >
+ ARMADA_370_XP_PCIE_MEM_END)
+ return -ENOMEM;
+
+ base = armada_370_xp_pcie_memaddr;
+ armada_370_xp_pcie_memaddr += size;
+
+ ret = orion_alloc_cpu_win(&addr_map_cfg, base, size, target,
+ attr, -1);
+ if (ret) {
+ armada_370_xp_pcie_memaddr -= size;
+ return ret;
+ }
+ } else if (type == IORESOURCE_IO) {
+ if (armada_370_xp_pcie_ioaddr + size >
+ ARMADA_370_XP_PCIE_IO_END)
+ return -ENOMEM;
+
+ base = armada_370_xp_pcie_ioaddr;
+ armada_370_xp_pcie_ioaddr += size;
+
+ ret = orion_alloc_cpu_win(&addr_map_cfg, base, size, target,
+ attr, -1);
+ if (ret) {
+ armada_370_xp_pcie_ioaddr -= size;
+ return ret;
+ }
+ } else
+ return -ENODEV;
+
+ *outbase = base;
+ return 0;
+}
+
+/*
+ * Frees an address decoding window previously allocated by
+ * armada_370_xp_alloc_pcie_window(). Note that only the last window
+ * allocated for a given type (MEM or IO) can be freed, due to the
+ * simplicity of the allocator. This is however sufficient to handle
+ * the error cases when initializing one PCIe device.
+ */
+int __init armada_370_xp_free_pcie_window(int type, unsigned long base,
+ u32 size)
+{
+ if (type == IORESOURCE_MEM) {
+ /* We can only free the last allocated window */
+ if (base + size != armada_370_xp_pcie_memaddr)
+ return -EINVAL;
+ orion_free_cpu_win(&addr_map_cfg, base);
+ armada_370_xp_pcie_memaddr -= size;
+ } else if (type == IORESOURCE_IO) {
+ /* We can only free the last allocated window */
+ if (base + size != armada_370_xp_pcie_ioaddr)
+ return -EINVAL;
+ orion_free_cpu_win(&addr_map_cfg, base);
+ armada_370_xp_pcie_ioaddr -= size;
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+#endif
+
static int __init armada_setup_cpu_mbus(void)
{
struct device_node *np;
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -25,4 +25,8 @@ int armada_370_xp_coherency_init(void);
int armada_370_xp_pmsu_init(void);
void armada_xp_secondary_startup(void);
extern struct smp_operations armada_xp_smp_ops;
+
+int armada_370_xp_alloc_pcie_window(int pcie_port, int pcie_lane,
+ int type, u32 size, unsigned long *outbase);
+int armada_370_xp_free_pcie_window(int type, unsigned long base, u32 size);
#endif

View File

@ -0,0 +1,25 @@
mvebu is a new-style Orion platform, so it only selects PLAT_ORION,
but not PLAT_ORION_LEGACY. It will however need the common PCIe code
from plat-orion, so make this code available for PLAT_ORION platforms
as a whole, and not only PLAT_ORION_LEGACY platforms.
We also take this opportunity to build the PCIe code only when
CONFIG_PCI is enabled.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/plat-orion/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/arch/arm/plat-orion/Makefile
+++ b/arch/arm/plat-orion/Makefile
@@ -4,7 +4,8 @@
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
obj-y += addr-map.o
+obj-$(CONFIG_PCI) += pcie.o
orion-gpio-$(CONFIG_GENERIC_GPIO) += gpio.o
-obj-$(CONFIG_PLAT_ORION_LEGACY) += irq.o pcie.o time.o common.o mpp.o
+obj-$(CONFIG_PLAT_ORION_LEGACY) += irq.o time.o common.o mpp.o
obj-$(CONFIG_PLAT_ORION_LEGACY) += $(orion-gpio-y)

View File

@ -0,0 +1,474 @@
This 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.
In addition, this driver enumerates the different PCIe slots, and for
those having a device plugged in, it allocates 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/armada-370-xp-pcie.txt | 136 +++++++++
arch/arm/mach-mvebu/Makefile | 1 +
arch/arm/mach-mvebu/pcie.c | 306 ++++++++++++++++++++
3 files changed, 443 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/armada-370-xp-pcie.txt
create mode 100644 arch/arm/mach-mvebu/pcie.c
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/armada-370-xp-pcie.txt
@@ -0,0 +1,136 @@
+* Marvell Armada 370/XP PCIe interfaces
+
+Mandatory properties:
+- compatible: must be "marvell,armada-370-xp-pcie"
+- status: either "disabled" or "okay"
+- #address-cells, set to <1>
+- #size-cells, set to <1>
+- ranges: describes the association between the physical addresses of
+ the PCIe registers for each PCIe interface with "virtual" addresses
+ as seen by the sub-nodes. One entry per PCIe interface. Each entry
+ must have 3 values: the "virtual" address seen by the sub-nodes, the
+ real physical address of the PCIe registers, and the size.
+
+In addition, the Device Tree node must have sub-nodes describing each
+PCIe interface, having the following mandatory properties:
+- reg: the address and size of the PCIe registers (translated
+ addresses according to the ranges property of the parent)
+- interrupts: the interrupt number of this PCIe interface
+- clocks: the clock associated to this PCIe interface
+- marvell,pcie-port: the physical PCIe port number
+- status: either "disabled" or "okay"
+
+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-370-xp-pcie";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0xd0040000 0x2000 /* port0x1_port0 */
+ 0x2000 0xd0042000 0x2000 /* port2x1_port0 */
+ 0x4000 0xd0044000 0x2000 /* port0x1_port1 */
+ 0x8000 0xd0048000 0x2000 /* port0x1_port2 */
+ 0xC000 0xd004C000 0x2000 /* port0x1_port3 */
+ 0x10000 0xd0080000 0x2000 /* port1x1_port0 */
+ 0x12000 0xd0082000 0x2000 /* port3x1_port0 */
+ 0x14000 0xd0084000 0x2000 /* port1x1_port1 */
+ 0x18000 0xd0088000 0x2000 /* port1x1_port2 */
+ 0x1C000 0xd008C000 0x2000 /* port1x1_port3 */>;
+
+ pcie0.0@0xd0040000 {
+ reg = <0x0 0x2000>;
+ interrupts = <58>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+
+ pcie0.1@0xd0044000 {
+ reg = <0x4000 0x2000>;
+ interrupts = <59>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ status = "disabled";
+ };
+
+ pcie0.2@0xd0048000 {
+ reg = <0x8000 0x2000>;
+ interrupts = <60>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ status = "disabled";
+ };
+
+ pcie0.3@0xd004C000 {
+ reg = <0xC000 0x2000>;
+ interrupts = <61>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ status = "disabled";
+ };
+
+ pcie1.0@0xd0040000 {
+ reg = <0x10000 0x2000>;
+ interrupts = <62>;
+ clocks = <&gateclk 6>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+
+ pcie1.1@0xd0044000 {
+ reg = <0x14000 0x2000>;
+ interrupts = <63>;
+ clocks = <&gateclk 6>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <1>;
+ status = "disabled";
+ };
+
+ pcie1.2@0xd0048000 {
+ reg = <0x18000 0x2000>;
+ interrupts = <64>;
+ clocks = <&gateclk 6>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <2>;
+ status = "disabled";
+ };
+
+ pcie1.3@0xd004C000 {
+ reg = <0x1C000 0x2000>;
+ interrupts = <65>;
+ clocks = <&gateclk 6>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <3>;
+ status = "disabled";
+ };
+
+ pcie2@0xd0042000 {
+ reg = <0x2000 0x2000>;
+ interrupts = <99>;
+ clocks = <&gateclk 7>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+
+ pcie3@0xd0082000 {
+ reg = <0x12000 0x2000>;
+ interrupts = <103>;
+ clocks = <&gateclk 8>;
+ marvell,pcie-port = <3>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+};
+
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -5,3 +5,4 @@ obj-y += system-controller.o
obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o coherency.o coherency_ll.o pmsu.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+obj-$(CONFIG_PCI) += pcie.o
--- /dev/null
+++ b/arch/arm/mach-mvebu/pcie.c
@@ -0,0 +1,306 @@
+/*
+ * 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/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>
+#include <plat/pcie.h>
+#include "common.h"
+
+struct pcie_port {
+ u8 root_bus_nr;
+ void __iomem *base;
+ spinlock_t conf_lock;
+ int irq;
+ struct resource res;
+ int haslink;
+ u32 port;
+ u32 lane;
+ struct clk *clk;
+};
+
+static struct pcie_port *pcie_ports;
+
+static int pcie_valid_config(struct pcie_port *pp, int bus, int dev)
+{
+ /*
+ * Don't go out when trying to access --
+ * 1. nonexisting device on local bus
+ * 2. where there's no device connected (no link)
+ */
+ if (bus == pp->root_bus_nr && dev == 0)
+ return 1;
+
+ if (!orion_pcie_link_up(pp->base))
+ return 0;
+
+ if (bus == pp->root_bus_nr && dev != 1)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * PCIe config cycles are done by programming the PCIE_CONF_ADDR register
+ * and then reading the PCIE_CONF_DATA register. Need to make sure these
+ * transactions are atomic.
+ */
+static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+ int size, u32 *val)
+{
+ struct pci_sys_data *sys = bus->sysdata;
+ struct pcie_port *pp = sys->private_data;
+ unsigned long flags;
+ int ret;
+
+ if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ spin_lock_irqsave(&pp->conf_lock, flags);
+ ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val);
+ spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+ return ret;
+}
+
+static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 val)
+{
+ struct pci_sys_data *sys = bus->sysdata;
+ struct pcie_port *pp = sys->private_data;
+ unsigned long flags;
+ int ret;
+
+ if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ spin_lock_irqsave(&pp->conf_lock, flags);
+ ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val);
+ spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+ return ret;
+}
+
+static struct pci_ops pcie_ops = {
+ .read = pcie_rd_conf,
+ .write = pcie_wr_conf,
+};
+
+/*
+ * Returns 0 when the device could not be initialized, 1 when
+ * initialization is successful
+ */
+static int __init armada_370_xp_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+ struct pcie_port *port = &pcie_ports[nr];
+ unsigned long membase, iobase;
+ int ret;
+
+ if (!port->haslink)
+ return 0;
+
+ sys->private_data = port;
+ port->root_bus_nr = sys->busnr;
+ spin_lock_init(&port->conf_lock);
+
+ ret = armada_370_xp_alloc_pcie_window(port->port, port->lane,
+ IORESOURCE_MEM, SZ_64M, &membase);
+ if (ret) {
+ pr_err("PCIe%d.%d: Cannot get memory window, device disabled\n",
+ port->port, port->lane);
+ return 0;
+ }
+
+ ret = armada_370_xp_alloc_pcie_window(port->port, port->lane,
+ IORESOURCE_IO, SZ_64K, &iobase);
+ if (ret) {
+ pr_err("PCIe%d.%d: Cannot get I/O window, device disabled\n",
+ port->port, port->lane);
+ armada_370_xp_free_pcie_window(IORESOURCE_MEM, membase, SZ_64M);
+ return 0;
+ }
+
+ port->res.name = kasprintf(GFP_KERNEL, "PCIe %d.%d MEM",
+ port->port, port->lane);
+ if (!port->res.name) {
+ armada_370_xp_free_pcie_window(IORESOURCE_IO, iobase, SZ_64K);
+ armada_370_xp_free_pcie_window(IORESOURCE_MEM, membase, SZ_64M);
+ return 0;
+ }
+
+ port->res.start = membase;
+ port->res.end = membase + SZ_32M - 1;
+ port->res.flags = IORESOURCE_MEM;
+
+ pci_ioremap_io(SZ_64K * sys->busnr, iobase);
+
+ if (request_resource(&iomem_resource, &port->res)) {
+ pr_err("PCIe%d.%d: Cannot request memory resource\n",
+ port->port, port->lane);
+ kfree(port->res.name);
+ armada_370_xp_free_pcie_window(IORESOURCE_IO, iobase, SZ_64K);
+ armada_370_xp_free_pcie_window(IORESOURCE_MEM, membase, SZ_64M);
+ return 0;
+ }
+
+ pci_add_resource_offset(&sys->resources, &port->res, sys->mem_offset);
+
+ orion_pcie_set_local_bus_nr(port->base, sys->busnr);
+ orion_pcie_setup(port->base);
+
+ return 1;
+}
+
+static void __devinit rc_pci_fixup(struct pci_dev *dev)
+{
+ /*
+ * Prevent enumeration of root complex.
+ */
+ if (dev->bus->parent == NULL && dev->devfn == 0) {
+ int i;
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ dev->resource[i].start = 0;
+ dev->resource[i].end = 0;
+ dev->resource[i].flags = 0;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup);
+
+static int __init armada_370_xp_pcie_map_irq(const struct pci_dev *dev, u8 slot,
+ u8 pin)
+{
+ struct pci_sys_data *sys = dev->sysdata;
+ struct pcie_port *port = sys->private_data;
+
+ return port->irq;
+}
+
+static struct hw_pci armada_370_xp_pci __initdata = {
+ .setup = armada_370_xp_pcie_setup,
+ .map_irq = armada_370_xp_pcie_map_irq,
+ .ops = &pcie_ops,
+};
+
+static int __init armada_370_xp_pcie_probe(struct platform_device *pdev)
+{
+ struct device_node *child;
+ int nports, i;
+
+ nports = 0;
+ for_each_child_of_node(pdev->dev.of_node, child) {
+ if (!of_device_is_available(child))
+ continue;
+ nports++;
+ }
+
+ pcie_ports = devm_kzalloc(&pdev->dev, nports * sizeof(*pcie_ports),
+ GFP_KERNEL);
+ if (!pcie_ports)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_child_of_node(pdev->dev.of_node, child) {
+ struct pcie_port *port = &pcie_ports[i];
+
+ if (!of_device_is_available(child))
+ continue;
+
+ if (of_property_read_u32(child, "marvell,pcie-port",
+ &port->port))
+ continue;
+
+ if (of_property_read_u32(child, "marvell,pcie-lane",
+ &port->lane))
+ port->lane = 0;
+
+ port->base = of_iomap(child, 0);
+ if (!port->base) {
+ dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
+ port->port, port->lane);
+ continue;
+ }
+
+ if (orion_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);
+ iounmap(port->base);
+ continue;
+ }
+
+ port->irq = irq_of_parse_and_map(child, 0);
+ if (port->irq == 0) {
+ dev_err(&pdev->dev, "PCIe%d.%d: cannot parse and map IRQ\n",
+ port->port, port->lane);
+ iounmap(port->base);
+ port->haslink = 0;
+ continue;
+ }
+
+ 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);
+ irq_dispose_mapping(port->irq);
+ iounmap(port->base);
+ port->haslink = 0;
+ continue;
+ }
+
+ clk_prepare_enable(port->clk);
+
+ i++;
+ }
+
+ armada_370_xp_pci.nr_controllers = nports;
+ pci_common_init(&armada_370_xp_pci);
+
+ return 0;
+}
+
+static const struct of_device_id armada_370_xp_pcie_of_match_table[] = {
+ { .compatible = "marvell,armada-370-xp-pcie", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, armada_370_xp_pcie_of_match_table);
+
+static struct platform_driver armada_370_xp_pcie_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "armada-370-xp-pcie",
+ .of_match_table =
+ of_match_ptr(armada_370_xp_pcie_of_match_table),
+ },
+};
+
+static int armada_370_xp_pcie_init(void)
+{
+ return platform_driver_probe(&armada_370_xp_pcie_driver,
+ armada_370_xp_pcie_probe);
+}
+
+subsys_initcall(armada_370_xp_pcie_init);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Armada 370/XP PCIe driver");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,20 @@
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(+)
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -13,6 +13,8 @@ config ARCH_MVEBU
select MVEBU_CLK_CORE
select MVEBU_CLK_CPU
select MVEBU_CLK_GATING
+ select MIGHT_HAVE_PCI
+ select PCI_QUIRKS if PCI
if ARCH_MVEBU

View File

@ -0,0 +1,40 @@
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 | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -153,5 +153,29 @@
clocks = <&coreclk 0>;
};
+ pcie-controller {
+ compatible = "marvell,armada-370-xp-pcie";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0xd0040000 0x2000
+ 0x2000 0xd0080000 0x2000>;
+
+ pcie0@0xd0040000 {
+ reg = <0x0 0x2000>;
+ interrupts = <58>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ marvell,pcie-port = <0>;
+ };
+
+ pcie1@0xd0080000 {
+ reg = <0x2000 0x2000>;
+ interrupts = <62>;
+ clocks = <&gateclk 9>;
+ status = "disabled";
+ marvell,pcie-port = <1>;
+ };
+ };
};
};

View File

@ -0,0 +1,284 @@
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 | 62 +++++++++++++++++
arch/arm/boot/dts/armada-xp-mv78260.dtsi | 72 +++++++++++++++++++
arch/arm/boot/dts/armada-xp-mv78460.dtsi | 112 ++++++++++++++++++++++++++++++
3 files changed, 246 insertions(+)
--- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
@@ -76,5 +76,67 @@
#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-370-xp-pcie";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0xd0040000 0x2000 /* port0x1_port0 */
+ 0x2000 0xd0042000 0x2000 /* port2x1_port0 */
+ 0x4000 0xd0044000 0x2000 /* port0x1_port1 */
+ 0x8000 0xd0048000 0x2000 /* port0x1_port2 */
+ 0xC000 0xd004C000 0x2000 /* port0x1_port3 */>;
+
+ pcie0.0@0xd0040000 {
+ reg = <0x0 0x2000>;
+ interrupts = <58>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+
+ pcie0.1@0xd0044000 {
+ reg = <0x4000 0x2000>;
+ interrupts = <59>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ status = "disabled";
+ };
+
+ pcie0.2@0xd0048000 {
+ reg = <0x8000 0x2000>;
+ interrupts = <60>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ status = "disabled";
+ };
+
+ pcie0.3@0xd004C000 {
+ reg = <0xC000 0x2000>;
+ interrupts = <61>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ status = "disabled";
+ };
+
+ pcie2@0xd0042000 {
+ reg = <0x2000 0x2000>;
+ interrupts = <99>;
+ clocks = <&gateclk 7>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+ };
};
};
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -96,5 +96,77 @@
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-370-xp-pcie";
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0xd0040000 0x2000 /* port0x1_port0 */
+ 0x2000 0xd0042000 0x2000 /* port2x1_port0 */
+ 0x4000 0xd0044000 0x2000 /* port0x1_port1 */
+ 0x8000 0xd0048000 0x2000 /* port0x1_port2 */
+ 0xC000 0xd004C000 0x2000 /* port0x1_port3 */
+ 0x12000 0xd0082000 0x2000 /* port3x1_port0 */>;
+
+ pcie0.0@0xd0040000 {
+ reg = <0x0 0x2000>;
+ interrupts = <58>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+
+ pcie0.1@0xd0044000 {
+ reg = <0x4000 0x2000>;
+ interrupts = <59>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ status = "disabled";
+ };
+
+ pcie0.2@0xd0048000 {
+ reg = <0x8000 0x2000>;
+ interrupts = <60>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ status = "disabled";
+ };
+
+ pcie0.3@0xd004C000 {
+ reg = <0xC000 0x2000>;
+ interrupts = <61>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ status = "disabled";
+ };
+
+ pcie2@0xd0042000 {
+ reg = <0x2000 0x2000>;
+ interrupts = <99>;
+ clocks = <&gateclk 7>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+
+ pcie3@0xd0082000 {
+ reg = <0x12000 0x2000>;
+ interrupts = <103>;
+ clocks = <&gateclk 8>;
+ marvell,pcie-port = <3>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+ };
};
};
--- a/arch/arm/boot/dts/armada-xp-mv78460.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
@@ -111,5 +111,117 @@
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-370-xp-pcie";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0xd0040000 0x2000 /* port0x1_port0 */
+ 0x2000 0xd0042000 0x2000 /* port2x1_port0 */
+ 0x4000 0xd0044000 0x2000 /* port0x1_port1 */
+ 0x8000 0xd0048000 0x2000 /* port0x1_port2 */
+ 0xC000 0xd004C000 0x2000 /* port0x1_port3 */
+ 0x10000 0xd0080000 0x2000 /* port1x1_port0 */
+ 0x12000 0xd0082000 0x2000 /* port3x1_port0 */
+ 0x14000 0xd0084000 0x2000 /* port1x1_port1 */
+ 0x18000 0xd0088000 0x2000 /* port1x1_port2 */
+ 0x1C000 0xd008C000 0x2000 /* port1x1_port3 */>;
+
+ pcie0.0@0xd0040000 {
+ reg = <0x0 0x2000>;
+ interrupts = <58>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+
+ pcie0.1@0xd0044000 {
+ reg = <0x4000 0x2000>;
+ interrupts = <59>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ status = "disabled";
+ };
+
+ pcie0.2@0xd0048000 {
+ reg = <0x8000 0x2000>;
+ interrupts = <60>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ status = "disabled";
+ };
+
+ pcie0.3@0xd004C000 {
+ reg = <0xC000 0x2000>;
+ interrupts = <61>;
+ clocks = <&gateclk 5>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ status = "disabled";
+ };
+
+ pcie1.0@0xd0040000 {
+ reg = <0x10000 0x2000>;
+ interrupts = <62>;
+ clocks = <&gateclk 6>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+
+ pcie1.1@0xd0044000 {
+ reg = <0x14000 0x2000>;
+ interrupts = <63>;
+ clocks = <&gateclk 6>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <1>;
+ status = "disabled";
+ };
+
+ pcie1.2@0xd0048000 {
+ reg = <0x18000 0x2000>;
+ interrupts = <64>;
+ clocks = <&gateclk 6>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <2>;
+ status = "disabled";
+ };
+
+ pcie1.3@0xd004C000 {
+ reg = <0x1C000 0x2000>;
+ interrupts = <65>;
+ clocks = <&gateclk 6>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <3>;
+ status = "disabled";
+ };
+
+ pcie2@0xd0042000 {
+ reg = <0x2000 0x2000>;
+ interrupts = <99>;
+ clocks = <&gateclk 7>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+
+ pcie3@0xd0082000 {
+ reg = <0x12000 0x2000>;
+ interrupts = <103>;
+ clocks = <&gateclk 8>;
+ marvell,pcie-port = <3>;
+ marvell,pcie-lane = <0>;
+ status = "disabled";
+ };
+ };
};
};

View File

@ -0,0 +1,24 @@
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 | 7 +++++++
1 file changed, 7 insertions(+)
--- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
+++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
@@ -130,5 +130,12 @@
usb@d0052000 {
status = "okay";
};
+ pcie-controller {
+ status = "okay";
+ /* Internal mini-PCIe connector */
+ pcie0.0@0xd0040000 {
+ status = "okay";
+ };
+ };
};
};

View File

@ -0,0 +1,44 @@
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(+)
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -109,5 +109,32 @@
usb@d0052000 {
status = "okay";
};
+
+ pcie-controller {
+ status = "okay";
+
+ /*
+ * All 6 slots are physically present as
+ * standard PCIe slots on the board.
+ */
+ pcie0.0@0xd0040000 {
+ status = "okay";
+ };
+ pcie0.1@0xd0044000 {
+ status = "okay";
+ };
+ pcie0.2@0xd0048000 {
+ status = "okay";
+ };
+ pcie0.3@0xd004C000 {
+ status = "okay";
+ };
+ pcie2@0xd0042000 {
+ status = "okay";
+ };
+ pcie3@0xd0082000 {
+ status = "okay";
+ };
+ };
};
};

View File

@ -0,0 +1,32 @@
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(+)
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -70,5 +70,19 @@
usb@d0051000 {
status = "okay";
};
+
+ pcie-controller {
+ status = "okay";
+
+ /* Internal mini-PCIe connector */
+ pcie0@0xd0040000 {
+ status = "okay";
+ };
+
+ /* Connected on the PCB to a USB 3.0 XHCI controller */
+ pcie1@0xd0080000 {
+ status = "okay";
+ };
+ };
};
};

View File

@ -0,0 +1,32 @@
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(+)
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -82,5 +82,20 @@
usb@d0051000 {
status = "okay";
};
+
+ pcie-controller {
+ status = "okay";
+ /*
+ * The two PCIe units are accessible through
+ * both standard PCIe slots and mini-PCIe
+ * slots on the board.
+ */
+ pcie0@0xd0040000 {
+ status = "okay";
+ };
+ pcie1@0xd0080000 {
+ status = "okay";
+ };
+ };
};
};