|
@@ -2393,6 +2393,75 @@ static int of_dev_hwmod_lookup(struct device_node *np,
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * omap_hwmod_parse_module_range - map module IO range from device tree
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @np: struct device_node *
|
|
|
+ *
|
|
|
+ * Parse the device tree range an interconnect target module provides
|
|
|
+ * for it's child device IP blocks. This way we can support the old
|
|
|
+ * "ti,hwmods" property with just dts data without a need for platform
|
|
|
+ * data for IO resources. And we don't need all the child IP device
|
|
|
+ * nodes available in the dts.
|
|
|
+ */
|
|
|
+int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
|
|
|
+ struct device_node *np,
|
|
|
+ struct resource *res)
|
|
|
+{
|
|
|
+ struct property *prop;
|
|
|
+ const __be32 *ranges;
|
|
|
+ const char *name;
|
|
|
+ u32 nr_addr, nr_size;
|
|
|
+ u64 base, size;
|
|
|
+ int len, error;
|
|
|
+
|
|
|
+ if (!res)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ranges = of_get_property(np, "ranges", &len);
|
|
|
+ if (!ranges)
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ len /= sizeof(*ranges);
|
|
|
+
|
|
|
+ if (len < 3)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ of_property_for_each_string(np, "compatible", prop, name)
|
|
|
+ if (!strncmp("ti,sysc-", name, 8))
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (!name)
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ error = of_property_read_u32(np, "#address-cells", &nr_addr);
|
|
|
+ if (error)
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ error = of_property_read_u32(np, "#size-cells", &nr_size);
|
|
|
+ if (error)
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ if (nr_addr != 1 || nr_size != 1) {
|
|
|
+ pr_err("%s: invalid range for %s->%s\n", __func__,
|
|
|
+ oh->name, np->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ranges++;
|
|
|
+ base = of_translate_address(np, ranges++);
|
|
|
+ size = be32_to_cpup(ranges);
|
|
|
+
|
|
|
+ pr_debug("omap_hwmod: %s %s at 0x%llx size 0x%llx\n",
|
|
|
+ oh->name, np->name, base, size);
|
|
|
+
|
|
|
+ res->start = base;
|
|
|
+ res->end = base + size - 1;
|
|
|
+ res->flags = IORESOURCE_MEM;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* _init_mpu_rt_base - populate the virtual address for a hwmod
|
|
|
* @oh: struct omap_hwmod * to locate the virtual address
|
|
@@ -2415,6 +2484,8 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
|
|
|
{
|
|
|
struct omap_hwmod_addr_space *mem;
|
|
|
void __iomem *va_start = NULL;
|
|
|
+ struct resource res;
|
|
|
+ int error;
|
|
|
|
|
|
if (!oh)
|
|
|
return -EINVAL;
|
|
@@ -2440,7 +2511,14 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
|
|
|
return -ENXIO;
|
|
|
}
|
|
|
|
|
|
- va_start = of_iomap(np, index + oh->mpu_rt_idx);
|
|
|
+ /* Do we have a dts range for the interconnect target module? */
|
|
|
+ error = omap_hwmod_parse_module_range(oh, np, &res);
|
|
|
+ if (!error)
|
|
|
+ va_start = ioremap(res.start, resource_size(&res));
|
|
|
+
|
|
|
+ /* No ranges, rely on device reg entry */
|
|
|
+ if (!va_start)
|
|
|
+ va_start = of_iomap(np, index + oh->mpu_rt_idx);
|
|
|
} else {
|
|
|
va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
|
|
|
}
|