summaryrefslogtreecommitdiffstats
path: root/drivers/bus
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2014-08-07 06:14:59 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2014-08-07 06:14:59 +0200
commitf1ee4e8b73a356278056666da8d0c6b5aa53088d (patch)
tree160f8440f19bd0702aed7323900e7412ea11ff0f /drivers/bus
parentc138893990013fa9f3008325fdf4fd8ac0628ba2 (diff)
parent11b34ab22f4072db0cdbf605d6ffbd472618175b (diff)
downloadbarebox-f1ee4e8b73a356278056666da8d0c6b5aa53088d.tar.gz
barebox-f1ee4e8b73a356278056666da8d0c6b5aa53088d.tar.xz
Merge branch 'for-next/marvell'
Diffstat (limited to 'drivers/bus')
-rw-r--r--drivers/bus/mvebu-mbus.c97
1 files changed, 92 insertions, 5 deletions
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 11e3777a60..b7f78367d4 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -53,6 +53,7 @@
#include <common.h>
#include <init.h>
#include <io.h>
+#include <malloc.h>
#include <of.h>
#include <of_address.h>
#include <linux/mbus.h>
@@ -187,7 +188,7 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
phys_addr_t base, size_t size,
u8 target, u8 attr)
{
- u64 end = (u64)base + size;
+ u64 end = (u64)base + size - 1;
int win;
for (win = 0; win < mbus->soc->num_wins; win++) {
@@ -203,7 +204,7 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
if (!enabled)
continue;
- wend = wbase + wsize;
+ wend = wbase + wsize - 1;
/*
* Check if the current window overlaps with the
@@ -546,7 +547,7 @@ void mvebu_mbus_get_pcie_io_aperture(struct resource *res)
* - bits 16 to 23: window attribute ID
* - bits 0 to 15: unused
*/
-#define CUSTOM(id) (((id) & 0xF0000000) >> 24)
+#define CUSTOM(id) (((id) & 0xF0000000) >> 28)
#define TARGET(id) (((id) & 0x0F000000) >> 24)
#define ATTR(id) (((id) & 0x00FF0000) >> 16)
@@ -661,7 +662,7 @@ static void mvebu_mbus_get_pcie_resources(struct device_node *np,
reg, ARRAY_SIZE(reg));
if (!ret) {
mem->start = reg[0];
- mem->end = mem->start + reg[1];
+ mem->end = mem->start + reg[1] - 1;
mem->flags = IORESOURCE_MEM;
}
@@ -669,7 +670,7 @@ static void mvebu_mbus_get_pcie_resources(struct device_node *np,
reg, ARRAY_SIZE(reg));
if (!ret) {
io->start = reg[0];
- io->end = io->start + reg[1];
+ io->end = io->start + reg[1] - 1;
io->flags = IORESOURCE_IO;
}
}
@@ -741,3 +742,89 @@ static int mvebu_mbus_init(void)
return platform_driver_register(&mvebu_mbus_driver);
}
postcore_initcall(mvebu_mbus_init);
+
+struct mbus_range {
+ u32 mbusid;
+ u32 remap;
+ struct list_head list;
+};
+
+#define MBUS_ID(t,a) (((t) << 24) | ((attr) << 16))
+static LIST_HEAD(mbus_ranges);
+
+void mvebu_mbus_add_range(u8 target, u8 attr, u32 remap)
+{
+ struct mbus_range *r = xzalloc(sizeof(*r));
+
+ r->mbusid = MBUS_ID(target, attr);
+ r->remap = remap;
+ list_add_tail(&r->list, &mbus_ranges);
+}
+
+/*
+ * Barebox always remaps internal registers to 0xf1000000 on every SoC.
+ * As we (and Linux) need a working DT and there is no way to tell the current
+ * remap address, fixup any provided DT to ensure custom MBUS_IDs are correct.
+ */
+static int mvebu_mbus_of_fixup(struct device_node *root, void *context)
+{
+ struct device_node *np;
+
+ for_each_matching_node(np, mvebu_mbus_dt_ids) {
+ struct property *p;
+ int n, pa, na, ns, lenp, size;
+ u32 *ranges;
+
+ p = of_find_property(np, "ranges", &lenp);
+ if (!p)
+ return -EINVAL;
+
+ pa = of_n_addr_cells(np);
+ if (of_property_read_u32(np, "#address-cells", &na) ||
+ of_property_read_u32(np, "#size-cells", &ns))
+ return -EINVAL;
+
+ size = pa + na + ns;
+ ranges = xzalloc(lenp);
+ of_property_read_u32_array(np, "ranges", ranges, lenp/4);
+
+ /*
+ * Iterate through each ranges tuple and fixup the custom
+ * window ranges low base address. Because Armada XP supports
+ * LPAE, it has 2 cells for the parent address:
+ * <windowid child_base high_base low_base size>
+ *
+ * whereas for Armada 370, there's just one:
+ * <windowid child_base base size>
+ *
+ * For instance, the following tuple:
+ * <MBUS_ID(0xf0, 0x01) child_base {0} base 0x100000>
+ *
+ * would be fixed-up like:
+ * <MBUS_ID(0xf0, 0x01) child_base {0} remap 0x100000>
+ */
+ for (n = 0; n < lenp/4; n += size) {
+ struct mbus_range *r;
+ u32 mbusid = ranges[n];
+
+ if (!CUSTOM(mbusid))
+ continue;
+
+ list_for_each_entry(r, &mbus_ranges, list) {
+ if (r->mbusid == mbusid)
+ ranges[n + na + pa - 1] = r->remap;
+ }
+ }
+
+ if (of_property_write_u32_array(np, "ranges", ranges, lenp/4))
+ pr_err("Unable to fixup mbus ranges\n");
+ free(ranges);
+ }
+
+ return 0;
+}
+
+static int mvebu_mbus_fixup_register(void) {
+ return of_register_fixup(mvebu_mbus_of_fixup, NULL);
+}
+pure_initcall(mvebu_mbus_fixup_register);