diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 80 |
1 files changed, 79 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index d50101d44795..de69fb37098c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2394,6 +2394,75 @@ static int of_dev_hwmod_lookup(struct device_node *np, } /** + * 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 * @data: (unused, caller should pass NULL) @@ -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); } |