From: Florian Fainelli Date: Thu, 17 Jan 2013 22:29:13 +0000 (+0000) Subject: mvebu: add preliminary support for PCI express X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=7e1e7063c26dccb6f47a00db72612e9f8c57c016;p=openwrt%2Fstaging%2Fdedeckeh.git mvebu: add preliminary support for PCI express Signed-off-by: Florian Fainelli SVN-Revision: 35211 --- diff --git a/target/linux/mvebu/config-default b/target/linux/mvebu/config-default index 1fe6b839e6..f41c7c227b 100644 --- a/target/linux/mvebu/config-default +++ b/target/linux/mvebu/config-default @@ -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 diff --git a/target/linux/mvebu/patches-3.8/028-lib_devres_dont_enclose_pcim.patch b/target/linux/mvebu/patches-3.8/028-lib_devres_dont_enclose_pcim.patch new file mode 100644 index 0000000000..3872924a61 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/028-lib_devres_dont_enclose_pcim.patch @@ -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 +Cc: Paul Gortmaker +Cc: Jesse Barnes +Cc: Yinghai Lu +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 */ diff --git a/target/linux/mvebu/patches-3.8/029-clk_mvebu_create_parent_child_relation.patch b/target/linux/mvebu/patches-3.8/029-clk_mvebu_create_parent_child_relation.patch new file mode 100644 index 0000000000..2cccc0357b --- /dev/null +++ b/target/linux/mvebu/patches-3.8/029-clk_mvebu_create_parent_child_relation.patch @@ -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 +Cc: Mike Turquette +--- + 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 }, diff --git a/target/linux/mvebu/patches-3.8/030-arm_plat_orion_introduce_win_ctrl_enable.patch b/target/linux/mvebu/patches-3.8/030-arm_plat_orion_introduce_win_ctrl_enable.patch new file mode 100644 index 0000000000..9a237ec9b9 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/030-arm_plat_orion_introduce_win_ctrl_enable.patch @@ -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 +--- + 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); diff --git a/target/linux/mvebu/patches-3.8/031-arm_plat_orion_refactor.patch b/target/linux/mvebu/patches-3.8/031-arm_plat_orion_refactor.patch new file mode 100644 index 0000000000..fe9f6285f7 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/031-arm_plat_orion_refactor.patch @@ -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 +--- + 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); diff --git a/target/linux/mvebu/patches-3.8/032-arm_plat_orion_introduce_orion_alloc_free_cpu_win.patch b/target/linux/mvebu/patches-3.8/032-arm_plat_orion_introduce_orion_alloc_free_cpu_win.patch new file mode 100644 index 0000000000..91ed678b27 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/032-arm_plat_orion_introduce_orion_alloc_free_cpu_win.patch @@ -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 +--- + 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 diff --git a/target/linux/mvebu/patches-3.8/033-arm_mvebu_add_functions_to_alloc_free_pcie.patch b/target/linux/mvebu/patches-3.8/033-arm_mvebu_add_functions_to_alloc_free_pcie.patch new file mode 100644 index 0000000000..fd3c1af92e --- /dev/null +++ b/target/linux/mvebu/patches-3.8/033-arm_mvebu_add_functions_to_alloc_free_pcie.patch @@ -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 +--- + 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 diff --git a/target/linux/mvebu/patches-3.8/034-arm_plat_orion_make_common_pcie.patch b/target/linux/mvebu/patches-3.8/034-arm_plat_orion_make_common_pcie.patch new file mode 100644 index 0000000000..40ac714c10 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/034-arm_plat_orion_make_common_pcie.patch @@ -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 +--- + 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) diff --git a/target/linux/mvebu/patches-3.8/035-arm_mvebu_the_core_pcie_driver.patch b/target/linux/mvebu/patches-3.8/035-arm_mvebu_the_core_pcie_driver.patch new file mode 100644 index 0000000000..48f828344f --- /dev/null +++ b/target/linux/mvebu/patches-3.8/035-arm_mvebu_the_core_pcie_driver.patch @@ -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 +--- + .../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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 "); ++MODULE_DESCRIPTION("Marvell Armada 370/XP PCIe driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/mvebu/patches-3.8/036-arm_mvebu_pcie_support_is_now_available.patch b/target/linux/mvebu/patches-3.8/036-arm_mvebu_pcie_support_is_now_available.patch new file mode 100644 index 0000000000..b3c9a63d53 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/036-arm_mvebu_pcie_support_is_now_available.patch @@ -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 +--- + 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 + diff --git a/target/linux/mvebu/patches-3.8/037-arm_mvebu_add_pcie_dt_a370.patch b/target/linux/mvebu/patches-3.8/037-arm_mvebu_add_pcie_dt_a370.patch new file mode 100644 index 0000000000..2cb8a17f07 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/037-arm_mvebu_add_pcie_dt_a370.patch @@ -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 +--- + 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>; ++ }; ++ }; + }; + }; diff --git a/target/linux/mvebu/patches-3.8/038-arm_mvebu_add_pcie_dt_axp.patch b/target/linux/mvebu/patches-3.8/038-arm_mvebu_add_pcie_dt_axp.patch new file mode 100644 index 0000000000..647f1da5f7 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/038-arm_mvebu_add_pcie_dt_axp.patch @@ -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 +--- + 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"; ++ }; ++ }; + }; + }; diff --git a/target/linux/mvebu/patches-3.8/039-arm_mvebu_add_pcie_dt_ax34.patch b/target/linux/mvebu/patches-3.8/039-arm_mvebu_add_pcie_dt_ax34.patch new file mode 100644 index 0000000000..893c073eb5 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/039-arm_mvebu_add_pcie_dt_ax34.patch @@ -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 +--- + 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"; ++ }; ++ }; + }; + }; diff --git a/target/linux/mvebu/patches-3.8/040-arm_mvebu_add_pcie_axp_db.patch b/target/linux/mvebu/patches-3.8/040-arm_mvebu_add_pcie_axp_db.patch new file mode 100644 index 0000000000..af15d4b85d --- /dev/null +++ b/target/linux/mvebu/patches-3.8/040-arm_mvebu_add_pcie_axp_db.patch @@ -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 +--- + 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"; ++ }; ++ }; + }; + }; diff --git a/target/linux/mvebu/patches-3.8/041-arm_mvebu_add_pcie_dt_mirabox.patch b/target/linux/mvebu/patches-3.8/041-arm_mvebu_add_pcie_dt_mirabox.patch new file mode 100644 index 0000000000..1b6089eef8 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/041-arm_mvebu_add_pcie_dt_mirabox.patch @@ -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 +--- + 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"; ++ }; ++ }; + }; + }; diff --git a/target/linux/mvebu/patches-3.8/042-arm_mvebu_add_pcie_dt_a370_db.patch b/target/linux/mvebu/patches-3.8/042-arm_mvebu_add_pcie_dt_a370_db.patch new file mode 100644 index 0000000000..1a853f35c7 --- /dev/null +++ b/target/linux/mvebu/patches-3.8/042-arm_mvebu_add_pcie_dt_a370_db.patch @@ -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 +--- + 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"; ++ }; ++ }; + }; + };