diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
| -rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 97 |
1 files changed, 80 insertions, 17 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 4653efb87a2..d25a95fe992 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -138,6 +138,11 @@ #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/bootmem.h> +#include <linux/cpu.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include <asm/system_misc.h> #include "clock.h" #include "omap_hwmod.h" @@ -608,8 +613,6 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) /* XXX test pwrdm_get_wken for this hwmod's subsystem */ - oh->_int_flags |= _HWMOD_WAKEUP_ENABLED; - return 0; } @@ -643,8 +646,6 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) /* XXX test pwrdm_get_wken for this hwmod's subsystem */ - oh->_int_flags &= ~_HWMOD_WAKEUP_ENABLED; - return 0; } @@ -1366,7 +1367,9 @@ static void _enable_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + if (oh->flags & HWMOD_FORCE_MSTANDBY) { + idlemode = HWMOD_IDLEMODE_FORCE; + } else if (oh->flags & HWMOD_SWSUP_MSTANDBY) { idlemode = HWMOD_IDLEMODE_NO; } else { if (sf & SYSC_HAS_ENAWAKEUP) @@ -1438,7 +1441,8 @@ static void _idle_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + if ((oh->flags & HWMOD_SWSUP_MSTANDBY) || + (oh->flags & HWMOD_FORCE_MSTANDBY)) { idlemode = HWMOD_IDLEMODE_FORCE; } else { if (sf & SYSC_HAS_ENAWAKEUP) @@ -1661,7 +1665,7 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) return -ENOSYS; ret = _lookup_hardreset(oh, name, &ohri); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; if (oh->clkdm) { @@ -2053,6 +2057,23 @@ static int _omap4_get_context_lost(struct omap_hwmod *oh) } /** + * _enable_preprogram - Pre-program an IP block during the _enable() process + * @oh: struct omap_hwmod * + * + * Some IP blocks (such as AESS) require some additional programming + * after enable before they can enter idle. If a function pointer to + * do so is present in the hwmod data, then call it and pass along the + * return value; otherwise, return 0. + */ +static int __init _enable_preprogram(struct omap_hwmod *oh) +{ + if (!oh->class->enable_preprogram) + return 0; + + return oh->class->enable_preprogram(oh); +} + +/** * _enable - enable an omap_hwmod * @oh: struct omap_hwmod * * @@ -2134,6 +2155,8 @@ static int _enable(struct omap_hwmod *oh) _enable_clocks(oh); if (soc_ops.enable_module) soc_ops.enable_module(oh); + if (oh->flags & HWMOD_BLOCK_WFI) + cpu_idle_poll_ctrl(true); if (soc_ops.update_context_lost) soc_ops.update_context_lost(oh); @@ -2156,6 +2179,7 @@ static int _enable(struct omap_hwmod *oh) _update_sysc_cache(oh); _enable_sysc(oh); } + r = _enable_preprogram(oh); } else { if (soc_ops.disable_module) soc_ops.disable_module(oh); @@ -2195,6 +2219,8 @@ static int _idle(struct omap_hwmod *oh) _idle_sysc(oh); _del_initiator_dep(oh, mpu_oh); + if (oh->flags & HWMOD_BLOCK_WFI) + cpu_idle_poll_ctrl(false); if (soc_ops.disable_module) soc_ops.disable_module(oh); @@ -2303,6 +2329,8 @@ static int _shutdown(struct omap_hwmod *oh) if (oh->_state == _HWMOD_STATE_ENABLED) { _del_initiator_dep(oh, mpu_oh); /* XXX what about the other system initiators here? dma, dsp */ + if (oh->flags & HWMOD_BLOCK_WFI) + cpu_idle_poll_ctrl(false); if (soc_ops.disable_module) soc_ops.disable_module(oh); _disable_clocks(oh); @@ -2324,6 +2352,34 @@ static int _shutdown(struct omap_hwmod *oh) } /** + * of_dev_hwmod_lookup - look up needed hwmod from dt blob + * @np: struct device_node * + * @oh: struct omap_hwmod * + * + * Parse the dt blob and find out needed hwmod. Recursive function is + * implemented to take care hierarchical dt blob parsing. + * Return: The device node on success or NULL on failure. + */ +static struct device_node *of_dev_hwmod_lookup(struct device_node *np, + struct omap_hwmod *oh) +{ + struct device_node *np0 = NULL, *np1 = NULL; + const char *p; + + for_each_child_of_node(np, np0) { + if (of_find_property(np0, "ti,hwmods", NULL)) { + p = of_get_property(np0, "ti,hwmods", NULL); + if (!strcmp(p, oh->name)) + return np0; + np1 = of_dev_hwmod_lookup(np0, oh); + if (np1) + return np1; + } + } + return NULL; +} + +/** * _init_mpu_rt_base - populate the virtual address for a hwmod * @oh: struct omap_hwmod * to locate the virtual address * @@ -2335,7 +2391,8 @@ static int _shutdown(struct omap_hwmod *oh) static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) { struct omap_hwmod_addr_space *mem; - void __iomem *va_start; + void __iomem *va_start = NULL; + struct device_node *np; if (!oh) return; @@ -2349,10 +2406,18 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) if (!mem) { pr_debug("omap_hwmod: %s: no MPU register target found\n", oh->name); - return; + + /* Extract the IO space from device tree blob */ + if (!of_have_populated_dt()) + return; + + np = of_dev_hwmod_lookup(of_find_node_by_name(NULL, "ocp"), oh); + if (np) + va_start = of_iomap(np, 0); + } else { + va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); } - va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); if (!va_start) { pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name); return; @@ -2384,10 +2449,11 @@ static int __init _init(struct omap_hwmod *oh, void *data) if (oh->_state != _HWMOD_STATE_REGISTERED) return 0; - _init_mpu_rt_base(oh, NULL); + if (oh->class->sysc) + _init_mpu_rt_base(oh, NULL); r = _init_clocks(oh, NULL); - if (IS_ERR_VALUE(r)) { + if (r < 0) { WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name); return -EINVAL; } @@ -3041,11 +3107,8 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - if (ohri->st_shift) - pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", - oh->name, ohri->name); - return am33xx_prm_deassert_hardreset(ohri->rst_shift, + ohri->st_shift, oh->clkdm->pwrdm.ptr->prcm_offs, oh->prcm.omap4.rstctrl_offs, oh->prcm.omap4.rstst_offs); @@ -3303,7 +3366,7 @@ static int __init omap_hwmod_setup_all(void) return 0; } -core_initcall(omap_hwmod_setup_all); +omap_core_initcall(omap_hwmod_setup_all); /** * omap_hwmod_enable - enable an omap_hwmod |