diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 80 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.h | 5 |
2 files changed, 84 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); } diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index 7dfd5989b665..3f95c40008b8 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -690,11 +690,16 @@ struct omap_hwmod { struct omap_hwmod *parent_hwmod; }; +struct device_node; + struct omap_hwmod *omap_hwmod_lookup(const char *name); int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), void *data); int __init omap_hwmod_setup_one(const char *name); +int omap_hwmod_parse_module_range(struct omap_hwmod *oh, + struct device_node *np, + struct resource *res); int omap_hwmod_enable(struct omap_hwmod *oh); int omap_hwmod_idle(struct omap_hwmod *oh); |