From 005e0ee7c98fa04776cffb044b6c5d2bea2cb491 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 17 Jan 2013 22:29:13 +0000 Subject: mvebu: add preliminary support for PCI express Signed-off-by: Florian Fainelli git-svn-id: svn://svn.openwrt.org/openwrt/trunk@35211 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- ...rm_mvebu_add_functions_to_alloc_free_pcie.patch | 201 +++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 target/linux/mvebu/patches-3.8/033-arm_mvebu_add_functions_to_alloc_free_pcie.patch (limited to 'target/linux/mvebu/patches-3.8/033-arm_mvebu_add_functions_to_alloc_free_pcie.patch') 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 -- cgit v1.2.3