summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/dts/armada-37xx.dtsi15
-rw-r--r--arch/arm/mach-mvebu/armada3700/cpu.c78
2 files changed, 72 insertions, 21 deletions
diff --git a/arch/arm/dts/armada-37xx.dtsi b/arch/arm/dts/armada-37xx.dtsi
index a1052add0cc..2615b8c748c 100644
--- a/arch/arm/dts/armada-37xx.dtsi
+++ b/arch/arm/dts/armada-37xx.dtsi
@@ -323,7 +323,7 @@
};
pcie0: pcie@d0070000 {
- compatible = "marvell,armada-37xx-pcie";
+ compatible = "marvell,armada-3700-pcie";
reg = <0 0xd0070000 0 0x20000>;
#address-cells = <3>;
#size-cells = <2>;
@@ -332,10 +332,17 @@
status = "disabled";
bus-range = <0 0xff>;
+ /*
+ * The 128 MiB address range [0xe8000000-0xf0000000] is
+ * dedicated for PCIe and can be assigned to 8 windows
+ * with size a power of two. Use one 64 KiB window for
+ * IO at the end and the remaining seven windows
+ * (totaling 127 MiB) for MEM.
+ */
ranges = <0x82000000 0 0xe8000000
- 0 0xe8000000 0 0x1000000 /* Port 0 MEM */
- 0x81000000 0 0xe9000000
- 0 0xe9000000 0 0x10000>; /* Port 0 IO*/
+ 0 0xe8000000 0 0x7f00000 /* Port 0 MEM */
+ 0x81000000 0 0xefff0000
+ 0 0xefff0000 0 0x10000>; /* Port 0 IO*/
};
};
};
diff --git a/arch/arm/mach-mvebu/armada3700/cpu.c b/arch/arm/mach-mvebu/armada3700/cpu.c
index 0cf60d7cdd7..9aec0ce9a43 100644
--- a/arch/arm/mach-mvebu/armada3700/cpu.c
+++ b/arch/arm/mach-mvebu/armada3700/cpu.c
@@ -8,6 +8,7 @@
#include <cpu_func.h>
#include <dm.h>
#include <fdtdec.h>
+#include <fdt_support.h>
#include <init.h>
#include <asm/global_data.h>
#include <linux/bitops.h>
@@ -53,8 +54,6 @@
#define A3700_PTE_BLOCK_DEVICE \
(PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
-#define PCIE_PATH "/soc/pcie@d0070000"
-
DECLARE_GLOBAL_DATA_PTR;
static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
@@ -282,36 +281,81 @@ static u32 find_pcie_window_base(void)
return -1;
}
+static int fdt_setprop_inplace_u32_partial(void *blob, int node,
+ const char *name,
+ u32 idx, u32 val)
+{
+ val = cpu_to_fdt32(val);
+
+ return fdt_setprop_inplace_namelen_partial(blob, node, name,
+ strlen(name),
+ idx * sizeof(u32),
+ &val, sizeof(u32));
+}
+
int a3700_fdt_fix_pcie_regions(void *blob)
{
- u32 new_ranges[14], base;
+ int acells, pacells, scells;
+ u32 base, fix_offset;
const u32 *ranges;
- int node, len;
+ int node, pnode;
+ int ret, i, len;
+
+ base = find_pcie_window_base();
+ if (base == -1)
+ return -ENOENT;
- node = fdt_path_offset(blob, PCIE_PATH);
+ node = fdt_node_offset_by_compatible(blob, -1, "marvell,armada-3700-pcie");
if (node < 0)
return node;
ranges = fdt_getprop(blob, node, "ranges", &len);
- if (!ranges)
+ if (!ranges || len % sizeof(u32))
return -ENOENT;
- if (len != sizeof(new_ranges))
- return -EINVAL;
-
- memcpy(new_ranges, ranges, len);
+ /*
+ * The "ranges" property is an array of
+ * { <child address> <parent address> <size in child address space> }
+ *
+ * All 3 elements can span a diffent number of cells. Fetch their sizes.
+ */
+ pnode = fdt_parent_offset(blob, node);
+ acells = fdt_address_cells(blob, node);
+ pacells = fdt_address_cells(blob, pnode);
+ scells = fdt_size_cells(blob, node);
- base = find_pcie_window_base();
- if (base == -1)
+ /* Child PCI addresses always use 3 cells */
+ if (acells != 3)
return -ENOENT;
- new_ranges[2] = cpu_to_fdt32(base);
- new_ranges[4] = new_ranges[2];
+ /* Calculate fixup offset from first child address (in last cell) */
+ fix_offset = base - fdt32_to_cpu(ranges[2]);
- new_ranges[9] = cpu_to_fdt32(base + 0x1000000);
- new_ranges[11] = new_ranges[9];
+ /*
+ * Fix address (last cell) of each child address and each parent
+ * address
+ */
+ for (i = 0; i < len / sizeof(u32); i += acells + pacells + scells) {
+ int idx;
+
+ /* fix child address */
+ idx = i + acells - 1;
+ ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
+ fdt32_to_cpu(ranges[idx]) +
+ fix_offset);
+ if (ret)
+ return ret;
+
+ /* fix parent address */
+ idx = i + acells + pacells - 1;
+ ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
+ fdt32_to_cpu(ranges[idx]) +
+ fix_offset);
+ if (ret)
+ return ret;
+ }
- return fdt_setprop_inplace(blob, node, "ranges", new_ranges, len);
+ return 0;
}
void reset_cpu(void)