--- zzzz-none-000/linux-3.10.107/arch/arm/mach-omap2/omap_hwmod.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/arch/arm/mach-omap2/omap_hwmod.c 2021-02-04 17:41:59.000000000 +0000 @@ -72,7 +72,7 @@ * | (../mach-omap2/omap_hwmod*) | * +-------------------------------+ * | OMAP clock/PRCM/register fns | - * | (__raw_{read,write}l, clk*) | + * | ({read,write}l_relaxed, clk*) | * +-------------------------------+ * * Device drivers should not contain any OMAP-specific code or data in @@ -130,6 +130,7 @@ #include #include #include +#include #include #include #include @@ -153,7 +154,6 @@ #include "powerdomain.h" #include "cm2xxx.h" #include "cm3xxx.h" -#include "cminst44xx.h" #include "cm33xx.h" #include "prm.h" #include "prm3xxx.h" @@ -172,6 +172,12 @@ */ #define LINKS_PER_OCP_IF 2 +/* + * Address offset (in bytes) between the reset control and the reset + * status registers: 4 bytes on OMAP4 + */ +#define OMAP4_RST_CTRL_ST_OFFSET 4 + /** * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations * @enable_module: function to enable a module (via MODULEMODE) @@ -294,7 +300,20 @@ /* Module might have lost context, always update cache and register */ oh->_sysc_cache = v; + + /* + * Some IP blocks (such as RTC) require unlocking of IP before + * accessing its registers. If a function pointer is present + * to unlock, then call it before accessing sysconfig and + * call lock after writing sysconfig. + */ + if (oh->class->unlock) + oh->class->unlock(oh); + omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs); + + if (oh->class->lock) + oh->class->lock(oh); } /** @@ -686,6 +705,8 @@ if (oh->clkdm) { return oh->clkdm; } else if (oh->_clk) { + if (__clk_get_flags(oh->_clk) & CLK_IS_BASIC) + return NULL; clk = to_clk_hw_omap(__clk_get_hw(oh->_clk)); return clk->clkdm; } @@ -767,8 +788,8 @@ oh->_clk = clk_get(NULL, oh->main_clk); if (IS_ERR(oh->_clk)) { - pr_warning("omap_hwmod: %s: cannot clk_get main_clk %s\n", - oh->name, oh->main_clk); + pr_warn("omap_hwmod: %s: cannot clk_get main_clk %s\n", + oh->name, oh->main_clk); return -EINVAL; } /* @@ -812,9 +833,10 @@ c = clk_get(NULL, os->clk); if (IS_ERR(c)) { - pr_warning("omap_hwmod: %s: cannot clk_get interface_clk %s\n", - oh->name, os->clk); + pr_warn("omap_hwmod: %s: cannot clk_get interface_clk %s\n", + oh->name, os->clk); ret = -EINVAL; + continue; } os->_clk = c; /* @@ -848,9 +870,10 @@ for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) { c = clk_get(NULL, oc->clk); if (IS_ERR(c)) { - pr_warning("omap_hwmod: %s: cannot clk_get opt_clk %s\n", - oh->name, oc->clk); + pr_warn("omap_hwmod: %s: cannot clk_get opt_clk %s\n", + oh->name, oc->clk); ret = -EINVAL; + continue; } oc->_clk = c; /* @@ -867,6 +890,36 @@ return ret; } +static void _enable_optional_clocks(struct omap_hwmod *oh) +{ + struct omap_hwmod_opt_clk *oc; + int i; + + pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name); + + for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) + if (oc->_clk) { + pr_debug("omap_hwmod: enable %s:%s\n", oc->role, + __clk_get_name(oc->_clk)); + clk_enable(oc->_clk); + } +} + +static void _disable_optional_clocks(struct omap_hwmod *oh) +{ + struct omap_hwmod_opt_clk *oc; + int i; + + pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name); + + for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) + if (oc->_clk) { + pr_debug("omap_hwmod: disable %s:%s\n", oc->role, + __clk_get_name(oc->_clk)); + clk_disable(oc->_clk); + } +} + /** * _enable_clocks - enable hwmod main clock and interface clocks * @oh: struct omap_hwmod * @@ -894,6 +947,9 @@ clk_enable(os->_clk); } + if (oh->flags & HWMOD_OPT_CLKS_NEEDED) + _enable_optional_clocks(oh); + /* The opt clocks are controlled by the device driver. */ return 0; @@ -925,41 +981,14 @@ clk_disable(os->_clk); } + if (oh->flags & HWMOD_OPT_CLKS_NEEDED) + _disable_optional_clocks(oh); + /* The opt clocks are controlled by the device driver. */ return 0; } -static void _enable_optional_clocks(struct omap_hwmod *oh) -{ - struct omap_hwmod_opt_clk *oc; - int i; - - pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name); - - for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) - if (oc->_clk) { - pr_debug("omap_hwmod: enable %s:%s\n", oc->role, - __clk_get_name(oc->_clk)); - clk_enable(oc->_clk); - } -} - -static void _disable_optional_clocks(struct omap_hwmod *oh) -{ - struct omap_hwmod_opt_clk *oc; - int i; - - pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name); - - for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) - if (oc->_clk) { - pr_debug("omap_hwmod: disable %s:%s\n", oc->role, - __clk_get_name(oc->_clk)); - clk_disable(oc->_clk); - } -} - /** * _omap4_enable_module - enable CLKCTRL modulemode on OMAP4 * @oh: struct omap_hwmod * @@ -975,31 +1004,9 @@ pr_debug("omap_hwmod: %s: %s: %d\n", oh->name, __func__, oh->prcm.omap4.modulemode); - omap4_cminst_module_enable(oh->prcm.omap4.modulemode, - oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); -} - -/** - * _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX - * @oh: struct omap_hwmod * - * - * Enables the PRCM module mode related to the hwmod @oh. - * No return value. - */ -static void _am33xx_enable_module(struct omap_hwmod *oh) -{ - if (!oh->clkdm || !oh->prcm.omap4.modulemode) - return; - - pr_debug("omap_hwmod: %s: %s: %d\n", - oh->name, __func__, oh->prcm.omap4.modulemode); - - am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_enable(oh->prcm.omap4.modulemode, + oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs); } /** @@ -1022,35 +1029,9 @@ if (oh->flags & HWMOD_NO_IDLEST) return 0; - return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); -} - -/** - * _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to enter slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully enters - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_idle() function. - */ -static int _am33xx_wait_target_disable(struct omap_hwmod *oh) -{ - if (!oh) - return -EINVAL; - - if (oh->_int_flags & _HWMOD_NO_MPU_PORT) - return 0; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_idle(oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** @@ -1498,7 +1479,9 @@ _set_master_standbymode(oh, idlemode, &v); } - _write_sysconfig(v, oh); + /* If the cached value is the same as the new value, skip the write */ + if (oh->_sysc_cache != v) + _write_sysconfig(v, oh); } /** @@ -1570,9 +1553,9 @@ oh->clkdm = clkdm_lookup(oh->clkdm_name); if (!oh->clkdm) { - pr_warning("omap_hwmod: %s: could not associate to clkdm %s\n", + pr_warn("omap_hwmod: %s: could not associate to clkdm %s\n", oh->name, oh->clkdm_name); - return -EINVAL; + return 0; } pr_debug("omap_hwmod: %s: associated to clkdm %s\n", @@ -1610,7 +1593,7 @@ if (!ret) oh->_state = _HWMOD_STATE_CLKS_INITED; else - pr_warning("omap_hwmod: %s: cannot _init_clocks\n", oh->name); + pr_warn("omap_hwmod: %s: cannot _init_clocks\n", oh->name); return ret; } @@ -1733,18 +1716,17 @@ _disable_clocks(oh); if (ret == -EBUSY) - pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name); + pr_warn("omap_hwmod: %s: failed to hardreset\n", oh->name); - if (!ret) { + if (oh->clkdm) { /* * Set the clockdomain to HW_AUTO, assuming that the * previous state was HW_AUTO. */ - if (oh->clkdm && hwsup) + if (hwsup) clkdm_allow_idle(oh->clkdm); - } else { - if (oh->clkdm) - clkdm_hwmod_disable(oh->clkdm, oh); + + clkdm_hwmod_disable(oh->clkdm, oh); } return ret; @@ -1853,10 +1835,8 @@ pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); - omap4_cminst_module_disable(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_disable(oh->clkdm->prcm_partition, oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs); v = _omap4_wait_target_disable(oh); if (v) @@ -1867,36 +1847,6 @@ } /** - * _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX - * @oh: struct omap_hwmod * - * - * Disable the PRCM module mode related to the hwmod @oh. - * Return EINVAL if the modulemode is not supported and 0 in case of success. - */ -static int _am33xx_disable_module(struct omap_hwmod *oh) -{ - int v; - - if (!oh->clkdm || !oh->prcm.omap4.modulemode) - return -EINVAL; - - pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); - - if (_are_any_hardreset_lines_asserted(oh)) - return 0; - - am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); - - v = _am33xx_wait_target_disable(oh); - if (v) - pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", - oh->name); - - return 0; -} - -/** * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit * @oh: struct omap_hwmod * * @@ -1941,29 +1891,31 @@ goto dis_opt_clks; _write_sysconfig(v, oh); - ret = _clear_softreset(oh, &v); - if (ret) - goto dis_opt_clks; - - _write_sysconfig(v, oh); if (oh->class->sysc->srst_udelay) udelay(oh->class->sysc->srst_udelay); c = _wait_softreset_complete(oh); - if (c == MAX_MODULE_SOFTRESET_WAIT) - pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n", - oh->name, MAX_MODULE_SOFTRESET_WAIT); - else + if (c == MAX_MODULE_SOFTRESET_WAIT) { + pr_warn("omap_hwmod: %s: softreset failed (waited %d usec)\n", + oh->name, MAX_MODULE_SOFTRESET_WAIT); + ret = -ETIMEDOUT; + goto dis_opt_clks; + } else { pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c); + } + + ret = _clear_softreset(oh, &v); + if (ret) + goto dis_opt_clks; + + _write_sysconfig(v, oh); /* * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from * _wait_target_ready() or _reset() */ - ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0; - dis_opt_clks: if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET) _disable_optional_clocks(oh); @@ -2057,10 +2009,7 @@ spin_lock_irqsave(&io_chain_lock, flags); - if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl()) - omap3xxx_prm_reconfigure_io_chain(); - else if (cpu_is_omap44xx()) - omap44xx_prm_reconfigure_io_chain(); + omap_prm_reconfigure_io_chain(); spin_unlock_irqrestore(&io_chain_lock, flags); } @@ -2177,7 +2126,7 @@ oh->mux->pads_dynamic))) { omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); _reconfigure_io_chain(); - } else if (oh->flags & HWMOD_FORCE_MSTANDBY) { + } else if (oh->flags & HWMOD_RECONFIG_IO_CHAIN) { _reconfigure_io_chain(); } @@ -2231,8 +2180,8 @@ if (soc_ops.disable_module) soc_ops.disable_module(oh); _disable_clocks(oh); - pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", - oh->name, r); + pr_err("omap_hwmod: %s: _wait_target_ready failed: %d\n", + oh->name, r); if (oh->clkdm) clkdm_hwmod_disable(oh->clkdm, oh); @@ -2251,6 +2200,11 @@ */ static int _idle(struct omap_hwmod *oh) { + if (oh->flags & HWMOD_NO_IDLE) { + oh->_int_flags |= _HWMOD_SKIP_ENABLE; + return 0; + } + pr_debug("omap_hwmod: %s: idling\n", oh->name); if (oh->_state != _HWMOD_STATE_ENABLED) { @@ -2285,7 +2239,7 @@ if (oh->mux && oh->mux->pads_dynamic) { omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); _reconfigure_io_chain(); - } else if (oh->flags & HWMOD_FORCE_MSTANDBY) { + } else if (oh->flags & HWMOD_RECONFIG_IO_CHAIN) { _reconfigure_io_chain(); } @@ -2364,56 +2318,110 @@ return 0; } +static int of_dev_find_hwmod(struct device_node *np, + struct omap_hwmod *oh) +{ + int count, i, res; + const char *p; + + count = of_property_count_strings(np, "ti,hwmods"); + if (count < 1) + return -ENODEV; + + for (i = 0; i < count; i++) { + res = of_property_read_string_index(np, "ti,hwmods", + i, &p); + if (res) + continue; + if (!strcmp(p, oh->name)) { + pr_debug("omap_hwmod: dt %s[%i] uses hwmod %s\n", + np->name, i, oh->name); + return i; + } + } + + return -ENODEV; +} + /** * of_dev_hwmod_lookup - look up needed hwmod from dt blob * @np: struct device_node * * @oh: struct omap_hwmod * + * @index: index of the entry found + * @found: struct device_node * found or NULL * * 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. + * Return: Returns 0 on success, -ENODEV when not found. */ -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; +static int of_dev_hwmod_lookup(struct device_node *np, + struct omap_hwmod *oh, + int *index, + struct device_node **found) +{ + struct device_node *np0 = NULL; + int res; + + res = of_dev_find_hwmod(np, oh); + if (res >= 0) { + *found = np; + *index = res; + return 0; + } 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; + struct device_node *fc; + int i; + + res = of_dev_hwmod_lookup(np0, oh, &i, &fc); + if (res == 0) { + *found = fc; + *index = i; + return 0; } } - return NULL; + + *found = NULL; + *index = 0; + + return -ENODEV; } /** * _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) + * @index: index of the reg entry iospace in device tree + * @np: struct device_node * of the IP block's device node in the DT data * * Cache the virtual address used by the MPU to access this IP block's * registers. This address is needed early so the OCP registers that * are part of the device's address space can be ioremapped properly. - * No return value. + * + * If SYSC access is not needed, the registers will not be remapped + * and non-availability of MPU access is not treated as an error. + * + * Returns 0 on success, -EINVAL if an invalid hwmod is passed, and + * -ENXIO on absent or invalid register target address space. */ -static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) +static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data, + int index, struct device_node *np) { struct omap_hwmod_addr_space *mem; void __iomem *va_start = NULL; - struct device_node *np; if (!oh) - return; + return -EINVAL; _save_mpu_port_index(oh); + /* if we don't need sysc access we don't need to ioremap */ + if (!oh->class->sysc) + return 0; + + /* we can't continue without MPU PORT if we need sysc access */ if (oh->_int_flags & _HWMOD_NO_MPU_PORT) - return; + return -ENXIO; mem = _find_mpu_rt_addr_space(oh); if (!mem) { @@ -2421,25 +2429,30 @@ oh->name); /* Extract the IO space from device tree blob */ - if (!of_have_populated_dt()) - return; + if (!np) { + pr_err("omap_hwmod: %s: no dt node\n", oh->name); + return -ENXIO; + } - np = of_dev_hwmod_lookup(of_find_node_by_name(NULL, "ocp"), oh); - if (np) - va_start = of_iomap(np, 0); + va_start = of_iomap(np, index + oh->mpu_rt_idx); } else { 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; + if (mem) + pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name); + else + pr_err("omap_hwmod: %s: Missing dt reg%i for %s\n", + oh->name, index, np->full_name); + return -ENXIO; } pr_debug("omap_hwmod: %s: MPU register target at va %p\n", oh->name, va_start); oh->_mpu_rt_va = va_start; + return 0; } /** @@ -2452,18 +2465,38 @@ * registered at this point. This is the first of two phases for * hwmod initialization. Code called here does not touch any hardware * registers, it simply prepares internal data structures. Returns 0 - * upon success or if the hwmod isn't registered, or -EINVAL upon - * failure. + * upon success or if the hwmod isn't registered or if the hwmod's + * address space is not defined, or -EINVAL upon failure. */ static int __init _init(struct omap_hwmod *oh, void *data) { - int r; + int r, index; + struct device_node *np = NULL; if (oh->_state != _HWMOD_STATE_REGISTERED) return 0; - if (oh->class->sysc) - _init_mpu_rt_base(oh, NULL); + if (of_have_populated_dt()) { + struct device_node *bus; + + bus = of_find_node_by_name(NULL, "ocp"); + if (!bus) + return -ENODEV; + + r = of_dev_hwmod_lookup(bus, oh, &index, &np); + if (r) + pr_debug("omap_hwmod: %s missing dt data\n", oh->name); + else if (np && index) + pr_warn("omap_hwmod: %s using broken dt data from %s\n", + oh->name, np->name); + } + + r = _init_mpu_rt_base(oh, NULL, index, np); + if (r < 0) { + WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n", + oh->name); + return 0; + } r = _init_clocks(oh, NULL); if (r < 0) { @@ -2471,6 +2504,15 @@ return -EINVAL; } + if (np) { + if (of_find_property(np, "ti,no-reset-on-init", NULL)) + oh->flags |= HWMOD_INIT_NO_RESET; + if (of_find_property(np, "ti,no-idle-on-init", NULL)) + oh->flags |= HWMOD_INIT_NO_IDLE; + if (of_find_property(np, "ti,no-idle", NULL)) + oh->flags |= HWMOD_NO_IDLE; + } + oh->_state = _HWMOD_STATE_INITIALIZED; return 0; @@ -2532,8 +2574,8 @@ if (oh->rst_lines_cnt == 0) { r = _enable(oh); if (r) { - pr_warning("omap_hwmod: %s: cannot be enabled for reset (%d)\n", - oh->name, oh->_state); + pr_warn("omap_hwmod: %s: cannot be enabled for reset (%d)\n", + oh->name, oh->_state); return -EINVAL; } } @@ -2595,7 +2637,7 @@ * XXX HWMOD_INIT_NO_IDLE does not belong in hwmod data - * it should be set by the core code as a runtime flag during startup */ - if ((oh->flags & HWMOD_INIT_NO_IDLE) && + if ((oh->flags & (HWMOD_INIT_NO_IDLE | HWMOD_NO_IDLE)) && (postsetup_state == _HWMOD_STATE_IDLE)) { oh->_int_flags |= _HWMOD_SKIP_ENABLE; postsetup_state = _HWMOD_STATE_ENABLED; @@ -2633,11 +2675,33 @@ if (oh->_state != _HWMOD_STATE_INITIALIZED) return 0; + if (oh->parent_hwmod) { + int r; + + r = _enable(oh->parent_hwmod); + WARN(r, "hwmod: %s: setup: failed to enable parent hwmod %s\n", + oh->name, oh->parent_hwmod->name); + } + _setup_iclk_autoidle(oh); if (!_setup_reset(oh)) _setup_postsetup(oh); + if (oh->parent_hwmod) { + u8 postsetup_state; + + postsetup_state = oh->parent_hwmod->_postsetup_state; + + if (postsetup_state == _HWMOD_STATE_IDLE) + _idle(oh->parent_hwmod); + else if (postsetup_state == _HWMOD_STATE_DISABLED) + _shutdown(oh->parent_hwmod); + else if (postsetup_state != _HWMOD_STATE_ENABLED) + WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n", + oh->parent_hwmod->name, postsetup_state); + } + return 0; } @@ -2674,6 +2738,7 @@ INIT_LIST_HEAD(&oh->master_ports); INIT_LIST_HEAD(&oh->slave_ports); spin_lock_init(&oh->_lock); + lockdep_set_class(&oh->_lock, &oh->hwmod_key); oh->_state = _HWMOD_STATE_REGISTERED; @@ -2714,9 +2779,7 @@ sz = sizeof(struct omap_hwmod_link) * LINKS_PER_OCP_IF; *sl = NULL; - *ml = alloc_bootmem(sz); - - memset(*ml, 0, sz); + *ml = memblock_virt_alloc(sz, 0); *sl = (void *)(*ml) + sizeof(struct omap_hwmod_link); @@ -2748,12 +2811,10 @@ _alloc_links(&ml, &sl); ml->ocp_if = oi; - INIT_LIST_HEAD(&ml->node); list_add(&ml->node, &oi->master->master_ports); oi->master->masters_cnt++; sl->ocp_if = oi; - INIT_LIST_HEAD(&sl->node); list_add(&sl->node, &oi->slave->slave_ports); oi->slave->slaves_cnt++; @@ -2835,9 +2896,7 @@ pr_debug("omap_hwmod: %s: allocating %d byte linkspace (%d links)\n", __func__, sz, max_ls); - linkspace = alloc_bootmem(sz); - - memset(linkspace, 0, sz); + linkspace = memblock_virt_alloc(sz, 0); return 0; } @@ -2845,7 +2904,7 @@ /* Static functions intended only for use in soc_ops field function pointers */ /** - * _omap2xxx_wait_target_ready - wait for a module to leave slave idle + * _omap2xxx_3xxx_wait_target_ready - wait for a module to leave slave idle * @oh: struct omap_hwmod * * * Wait for a module @oh to leave slave idle. Returns 0 if the module @@ -2853,7 +2912,7 @@ * slave idle; otherwise, pass along the return value of the * appropriate *_cm*_wait_module_ready() function. */ -static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh) +static int _omap2xxx_3xxx_wait_target_ready(struct omap_hwmod *oh) { if (!oh) return -EINVAL; @@ -2866,36 +2925,9 @@ /* XXX check module SIDLEMODE, hardreset status, enabled clocks */ - return omap2xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs, - oh->prcm.omap2.idlest_reg_id, - oh->prcm.omap2.idlest_idle_bit); -} - -/** - * _omap3xxx_wait_target_ready - wait for a module to leave slave idle - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to leave slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully leaves - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_ready() function. - */ -static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh) -{ - if (!oh) - return -EINVAL; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - if (!_find_mpu_rt_port(oh)) - return 0; - - /* XXX check module SIDLEMODE, hardreset status, enabled clocks */ - - return omap3xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs, - oh->prcm.omap2.idlest_reg_id, - oh->prcm.omap2.idlest_idle_bit); + return omap_cm_wait_module_ready(0, oh->prcm.omap2.module_offs, + oh->prcm.omap2.idlest_reg_id, + oh->prcm.omap2.idlest_idle_bit); } /** @@ -2920,37 +2952,9 @@ /* XXX check module SIDLEMODE, hardreset status */ - return omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); -} - -/** - * _am33xx_wait_target_ready - wait for a module to leave slave idle - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to leave slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully leaves - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_ready() function. - */ -static int _am33xx_wait_target_ready(struct omap_hwmod *oh) -{ - if (!oh || !oh->clkdm) - return -EINVAL; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - if (!_find_mpu_rt_port(oh)) - return 0; - - /* XXX check module SIDLEMODE, hardreset status */ - - return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_ready(oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** @@ -2967,8 +2971,8 @@ static int _omap2_assert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, - ohri->rst_shift); + return omap_prm_assert_hardreset(ohri->rst_shift, 0, + oh->prcm.omap2.module_offs, 0); } /** @@ -2985,9 +2989,8 @@ static int _omap2_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, - ohri->rst_shift, - ohri->st_shift); + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0, + oh->prcm.omap2.module_offs, 0, 0); } /** @@ -3005,8 +3008,8 @@ static int _omap2_is_hardreset_asserted(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, - ohri->st_shift); + return omap_prm_is_hardreset_asserted(ohri->st_shift, 0, + oh->prcm.omap2.module_offs, 0); } /** @@ -3027,10 +3030,10 @@ if (!oh->clkdm) return -EINVAL; - return omap4_prminst_assert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_assert_hardreset(ohri->rst_shift, + oh->clkdm->pwrdm.ptr->prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3054,10 +3057,12 @@ 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 omap4_prminst_deassert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->rst_shift, + oh->clkdm->pwrdm.ptr->prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs, + oh->prcm.omap4.rstctrl_offs + + OMAP4_RST_CTRL_ST_OFFSET); } /** @@ -3078,31 +3083,11 @@ if (!oh->clkdm) return -EINVAL; - return omap4_prminst_is_hardreset_asserted(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); -} - -/** - * _am33xx_assert_hardreset - call AM33XX PRM hardreset fn with hwmod args - * @oh: struct omap_hwmod * to assert hardreset - * @ohri: hardreset line data - * - * Call am33xx_prminst_assert_hardreset() with parameters extracted - * from the hwmod @oh and the hardreset line data @ohri. Only - * intended for use as an soc_ops function pointer. Passes along the - * return value from am33xx_prminst_assert_hardreset(). XXX This - * function is scheduled for removal when the PRM code is moved into - * drivers/. - */ -static int _am33xx_assert_hardreset(struct omap_hwmod *oh, - struct omap_hwmod_rst_info *ohri) - -{ - return am33xx_prm_assert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_is_hardreset_asserted(ohri->rst_shift, + oh->clkdm->pwrdm.ptr-> + prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3120,31 +3105,11 @@ static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - 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); -} - -/** - * _am33xx_is_hardreset_asserted - call AM33XX PRM hardreset fn with hwmod args - * @oh: struct omap_hwmod * to test hardreset - * @ohri: hardreset line data - * - * Call am33xx_prminst_is_hardreset_asserted() with parameters - * extracted from the hwmod @oh and the hardreset line data @ohri. - * Only intended for use as an soc_ops function pointer. Passes along - * the return value from am33xx_prminst_is_hardreset_asserted(). XXX - * This function is scheduled for removal when the PRM code is moved - * into drivers/. - */ -static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh, - struct omap_hwmod_rst_info *ohri) -{ - return am33xx_prm_is_hardreset_asserted(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, + oh->clkdm->pwrdm.ptr->prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs, + oh->prcm.omap4.rstst_offs); } /* Public functions */ @@ -3152,17 +3117,17 @@ u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs) { if (oh->flags & HWMOD_16BIT_REG) - return __raw_readw(oh->_mpu_rt_va + reg_offs); + return readw_relaxed(oh->_mpu_rt_va + reg_offs); else - return __raw_readl(oh->_mpu_rt_va + reg_offs); + return readl_relaxed(oh->_mpu_rt_va + reg_offs); } void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs) { if (oh->flags & HWMOD_16BIT_REG) - __raw_writew(v, oh->_mpu_rt_va + reg_offs); + writew_relaxed(v, oh->_mpu_rt_va + reg_offs); else - __raw_writel(v, oh->_mpu_rt_va + reg_offs); + writel_relaxed(v, oh->_mpu_rt_va + reg_offs); } /** @@ -3267,6 +3232,9 @@ if (!ois) return 0; + if (ois[0] == NULL) /* Empty list */ + return 0; + if (!linkspace) { if (_alloc_linkspace(ois)) { pr_err("omap_hwmod: could not allocate link space\n"); @@ -3385,16 +3353,17 @@ */ int omap_hwmod_idle(struct omap_hwmod *oh) { + int r; unsigned long flags; if (!oh) return -EINVAL; spin_lock_irqsave(&oh->_lock, flags); - _idle(oh); + r = _idle(oh); spin_unlock_irqrestore(&oh->_lock, flags); - return 0; + return r; } /** @@ -3407,90 +3376,6 @@ */ int omap_hwmod_shutdown(struct omap_hwmod *oh) { - unsigned long flags; - - if (!oh) - return -EINVAL; - - spin_lock_irqsave(&oh->_lock, flags); - _shutdown(oh); - spin_unlock_irqrestore(&oh->_lock, flags); - - return 0; -} - -/** - * omap_hwmod_enable_clocks - enable main_clk, all interface clocks - * @oh: struct omap_hwmod *oh - * - * Intended to be called by the omap_device code. - */ -int omap_hwmod_enable_clocks(struct omap_hwmod *oh) -{ - unsigned long flags; - - spin_lock_irqsave(&oh->_lock, flags); - _enable_clocks(oh); - spin_unlock_irqrestore(&oh->_lock, flags); - - return 0; -} - -/** - * omap_hwmod_disable_clocks - disable main_clk, all interface clocks - * @oh: struct omap_hwmod *oh - * - * Intended to be called by the omap_device code. - */ -int omap_hwmod_disable_clocks(struct omap_hwmod *oh) -{ - unsigned long flags; - - spin_lock_irqsave(&oh->_lock, flags); - _disable_clocks(oh); - spin_unlock_irqrestore(&oh->_lock, flags); - - return 0; -} - -/** - * omap_hwmod_ocp_barrier - wait for posted writes against the hwmod to complete - * @oh: struct omap_hwmod *oh - * - * Intended to be called by drivers and core code when all posted - * writes to a device must complete before continuing further - * execution (for example, after clearing some device IRQSTATUS - * register bits) - * - * XXX what about targets with multiple OCP threads? - */ -void omap_hwmod_ocp_barrier(struct omap_hwmod *oh) -{ - BUG_ON(!oh); - - if (!oh->class->sysc || !oh->class->sysc->sysc_flags) { - WARN(1, "omap_device: %s: OCP barrier impossible due to device configuration\n", - oh->name); - return; - } - - /* - * Forces posted writes to complete on the OCP thread handling - * register writes - */ - omap_hwmod_read(oh, oh->class->sysc->sysc_offs); -} - -/** - * omap_hwmod_reset - reset the hwmod - * @oh: struct omap_hwmod * - * - * Under some conditions, a driver may wish to reset the entire device. - * Called from omap_device code. Returns -EINVAL on error or passes along - * the return value from _reset(). - */ -int omap_hwmod_reset(struct omap_hwmod *oh) -{ int r; unsigned long flags; @@ -3498,7 +3383,7 @@ return -EINVAL; spin_lock_irqsave(&oh->_lock, flags); - r = _reset(oh); + r = _shutdown(oh); spin_unlock_irqrestore(&oh->_lock, flags); return r; @@ -3569,9 +3454,15 @@ mpu_irqs_cnt = _count_mpu_irqs(oh); for (i = 0; i < mpu_irqs_cnt; i++) { + unsigned int irq; + + if (oh->xlate_irq) + irq = oh->xlate_irq((oh->mpu_irqs + i)->irq); + else + irq = (oh->mpu_irqs + i)->irq; (res + r)->name = (oh->mpu_irqs + i)->name; - (res + r)->start = (oh->mpu_irqs + i)->irq; - (res + r)->end = (oh->mpu_irqs + i)->irq; + (res + r)->start = irq; + (res + r)->end = irq; (res + r)->flags = IORESOURCE_IRQ; r++; } @@ -3758,52 +3649,12 @@ return oh->_mpu_rt_va; } -/** - * omap_hwmod_add_initiator_dep - add sleepdep from @init_oh to @oh - * @oh: struct omap_hwmod * - * @init_oh: struct omap_hwmod * (initiator) - * - * Add a sleep dependency between the initiator @init_oh and @oh. - * Intended to be called by DSP/Bridge code via platform_data for the - * DSP case; and by the DMA code in the sDMA case. DMA code, *Bridge - * code needs to add/del initiator dependencies dynamically - * before/after accessing a device. Returns the return value from - * _add_initiator_dep(). - * - * XXX Keep a usecount in the clockdomain code - */ -int omap_hwmod_add_initiator_dep(struct omap_hwmod *oh, - struct omap_hwmod *init_oh) -{ - return _add_initiator_dep(oh, init_oh); -} - /* * XXX what about functions for drivers to save/restore ocp_sysconfig * for context save/restore operations? */ /** - * omap_hwmod_del_initiator_dep - remove sleepdep from @init_oh to @oh - * @oh: struct omap_hwmod * - * @init_oh: struct omap_hwmod * (initiator) - * - * Remove a sleep dependency between the initiator @init_oh and @oh. - * Intended to be called by DSP/Bridge code via platform_data for the - * DSP case; and by the DMA code in the sDMA case. DMA code, *Bridge - * code needs to add/del initiator dependencies dynamically - * before/after accessing a device. Returns the return value from - * _del_initiator_dep(). - * - * XXX Keep a usecount in the clockdomain code - */ -int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh, - struct omap_hwmod *init_oh) -{ - return _del_initiator_dep(oh, init_oh); -} - -/** * omap_hwmod_enable_wakeup - allow device to wake up the system * @oh: struct omap_hwmod * * @@ -3924,33 +3775,6 @@ } /** - * omap_hwmod_read_hardreset - read the HW reset line state of submodules - * contained in the hwmod module - * @oh: struct omap_hwmod * - * @name: name of the reset line to look up and read - * - * Return the current state of the hwmod @oh's reset line named @name: - * returns -EINVAL upon parameter error or if this operation - * is unsupported on the current OMAP; otherwise, passes along the return - * value from _read_hardreset(). - */ -int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name) -{ - int ret; - unsigned long flags; - - if (!oh) - return -EINVAL; - - spin_lock_irqsave(&oh->_lock, flags); - ret = _read_hardreset(oh, name); - spin_unlock_irqrestore(&oh->_lock, flags); - - return ret; -} - - -/** * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname * @classname: struct omap_hwmod_class name to search for * @fn: callback function pointer to call for each hwmod in class @classname @@ -4060,86 +3884,6 @@ } /** - * omap_hwmod_no_setup_reset - prevent a hwmod from being reset upon setup - * @oh: struct omap_hwmod * - * - * Prevent the hwmod @oh from being reset during the setup process. - * Intended for use by board-*.c files on boards with devices that - * cannot tolerate being reset. Must be called before the hwmod has - * been set up. Returns 0 upon success or negative error code upon - * failure. - */ -int omap_hwmod_no_setup_reset(struct omap_hwmod *oh) -{ - if (!oh) - return -EINVAL; - - if (oh->_state != _HWMOD_STATE_REGISTERED) { - pr_err("omap_hwmod: %s: cannot prevent setup reset; in wrong state\n", - oh->name); - return -EINVAL; - } - - oh->flags |= HWMOD_INIT_NO_RESET; - - return 0; -} - -/** - * omap_hwmod_pad_route_irq - route an I/O pad wakeup to a particular MPU IRQ - * @oh: struct omap_hwmod * containing hwmod mux entries - * @pad_idx: array index in oh->mux of the hwmod mux entry to route wakeup - * @irq_idx: the hwmod mpu_irqs array index of the IRQ to trigger on wakeup - * - * When an I/O pad wakeup arrives for the dynamic or wakeup hwmod mux - * entry number @pad_idx for the hwmod @oh, trigger the interrupt - * service routine for the hwmod's mpu_irqs array index @irq_idx. If - * this function is not called for a given pad_idx, then the ISR - * associated with @oh's first MPU IRQ will be triggered when an I/O - * pad wakeup occurs on that pad. Note that @pad_idx is the index of - * the _dynamic or wakeup_ entry: if there are other entries not - * marked with OMAP_DEVICE_PAD_WAKEUP or OMAP_DEVICE_PAD_REMUX, these - * entries are NOT COUNTED in the dynamic pad index. This function - * must be called separately for each pad that requires its interrupt - * to be re-routed this way. Returns -EINVAL if there is an argument - * problem or if @oh does not have hwmod mux entries or MPU IRQs; - * returns -ENOMEM if memory cannot be allocated; or 0 upon success. - * - * XXX This function interface is fragile. Rather than using array - * indexes, which are subject to unpredictable change, it should be - * using hwmod IRQ names, and some other stable key for the hwmod mux - * pad records. - */ -int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx) -{ - int nr_irqs; - - might_sleep(); - - if (!oh || !oh->mux || !oh->mpu_irqs || pad_idx < 0 || - pad_idx >= oh->mux->nr_pads_dynamic) - return -EINVAL; - - /* Check the number of available mpu_irqs */ - for (nr_irqs = 0; oh->mpu_irqs[nr_irqs].irq >= 0; nr_irqs++) - ; - - if (irq_idx >= nr_irqs) - return -EINVAL; - - if (!oh->mux->irqs) { - /* XXX What frees this? */ - oh->mux->irqs = kzalloc(sizeof(int) * oh->mux->nr_pads_dynamic, - GFP_KERNEL); - if (!oh->mux->irqs) - return -ENOMEM; - } - oh->mux->irqs[pad_idx] = irq_idx; - - return 0; -} - -/** * omap_hwmod_init - initialize the hwmod code * * Sets up some function pointers needed by the hwmod code to operate on the @@ -4149,16 +3893,17 @@ void __init omap_hwmod_init(void) { if (cpu_is_omap24xx()) { - soc_ops.wait_target_ready = _omap2xxx_wait_target_ready; + soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready; soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; } else if (cpu_is_omap34xx()) { - soc_ops.wait_target_ready = _omap3xxx_wait_target_ready; + soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready; soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; - } else if (cpu_is_omap44xx() || soc_is_omap54xx()) { + soc_ops.init_clkdm = _init_clkdm; + } else if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) { soc_ops.enable_module = _omap4_enable_module; soc_ops.disable_module = _omap4_disable_module; soc_ops.wait_target_ready = _omap4_wait_target_ready; @@ -4168,13 +3913,14 @@ soc_ops.init_clkdm = _init_clkdm; soc_ops.update_context_lost = _omap4_update_context_lost; soc_ops.get_context_lost = _omap4_get_context_lost; - } else if (soc_is_am33xx()) { - soc_ops.enable_module = _am33xx_enable_module; - soc_ops.disable_module = _am33xx_disable_module; - soc_ops.wait_target_ready = _am33xx_wait_target_ready; - soc_ops.assert_hardreset = _am33xx_assert_hardreset; + } else if (cpu_is_ti814x() || cpu_is_ti816x() || soc_is_am33xx() || + soc_is_am43xx()) { + soc_ops.enable_module = _omap4_enable_module; + soc_ops.disable_module = _omap4_disable_module; + soc_ops.wait_target_ready = _omap4_wait_target_ready; + soc_ops.assert_hardreset = _omap4_assert_hardreset; soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; - soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; + soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; soc_ops.init_clkdm = _init_clkdm; } else { WARN(1, "omap_hwmod: unknown SoC type\n");