|
@@ -780,39 +780,6 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh)
|
|
|
oh->prcm.omap4.clkctrl_offs);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
|
|
|
- * @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 _omap4_disable_module(struct omap_hwmod *oh)
|
|
|
-{
|
|
|
- int v;
|
|
|
-
|
|
|
- /* The module mode does not exist prior OMAP4 */
|
|
|
- if (!cpu_is_omap44xx())
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (!oh->clkdm || !oh->prcm.omap4.modulemode)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- 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);
|
|
|
-
|
|
|
- v = _omap4_wait_target_disable(oh);
|
|
|
- if (v)
|
|
|
- pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
|
|
|
- oh->name);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
|
|
|
* @oh: struct omap_hwmod *oh
|
|
@@ -1377,6 +1344,66 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * _are_any_hardreset_lines_asserted - return true if part of @oh is hard-reset
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * If any hardreset line associated with @oh is asserted, then return true.
|
|
|
+ * Otherwise, if @oh has no hardreset lines associated with it, or if
|
|
|
+ * no hardreset lines associated with @oh are asserted, then return false.
|
|
|
+ * This function is used to avoid executing some parts of the IP block
|
|
|
+ * enable/disable sequence if a hardreset line is set.
|
|
|
+ */
|
|
|
+static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (oh->rst_lines_cnt == 0)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ for (i = 0; i < oh->rst_lines_cnt; i++)
|
|
|
+ if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
|
|
|
+ * @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 _omap4_disable_module(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ int v;
|
|
|
+
|
|
|
+ /* The module mode does not exist prior OMAP4 */
|
|
|
+ if (!cpu_is_omap44xx())
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!oh->clkdm || !oh->prcm.omap4.modulemode)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ if (_are_any_hardreset_lines_asserted(oh))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ v = _omap4_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 *
|
|
@@ -1528,7 +1555,7 @@ static int _reset(struct omap_hwmod *oh)
|
|
|
*/
|
|
|
static int _enable(struct omap_hwmod *oh)
|
|
|
{
|
|
|
- int r, i;
|
|
|
+ int r;
|
|
|
int hwsup = 0;
|
|
|
|
|
|
pr_debug("omap_hwmod: %s: enabling\n", oh->name);
|
|
@@ -1560,14 +1587,16 @@ static int _enable(struct omap_hwmod *oh)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * If an IP contains HW reset lines, then de-assert them in order
|
|
|
- * to allow the module state transition. Otherwise the PRCM will return
|
|
|
- * Intransition status, and the init will failed.
|
|
|
+ * If an IP block contains HW reset lines and any of them are
|
|
|
+ * asserted, we let integration code associated with that
|
|
|
+ * block handle the enable. We've received very little
|
|
|
+ * information on what those driver authors need, and until
|
|
|
+ * detailed information is provided and the driver code is
|
|
|
+ * posted to the public lists, this is probably the best we
|
|
|
+ * can do.
|
|
|
*/
|
|
|
- if (oh->_state == _HWMOD_STATE_INITIALIZED ||
|
|
|
- oh->_state == _HWMOD_STATE_DISABLED)
|
|
|
- for (i = 0; i < oh->rst_lines_cnt; i++)
|
|
|
- _deassert_hardreset(oh, oh->rst_lines[i].name);
|
|
|
+ if (_are_any_hardreset_lines_asserted(oh))
|
|
|
+ return 0;
|
|
|
|
|
|
/* Mux pins for device runtime if populated */
|
|
|
if (oh->mux && (!oh->mux->enabled ||
|
|
@@ -1642,6 +1671,9 @@ static int _idle(struct omap_hwmod *oh)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ if (_are_any_hardreset_lines_asserted(oh))
|
|
|
+ return 0;
|
|
|
+
|
|
|
if (oh->class->sysc)
|
|
|
_idle_sysc(oh);
|
|
|
_del_initiator_dep(oh, mpu_oh);
|
|
@@ -1724,6 +1756,9 @@ static int _shutdown(struct omap_hwmod *oh)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ if (_are_any_hardreset_lines_asserted(oh))
|
|
|
+ return 0;
|
|
|
+
|
|
|
pr_debug("omap_hwmod: %s: disabling\n", oh->name);
|
|
|
|
|
|
if (oh->class->pre_shutdown) {
|
|
@@ -1866,21 +1901,13 @@ static int __init _setup_reset(struct omap_hwmod *oh)
|
|
|
if (oh->_state != _HWMOD_STATE_INITIALIZED)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- /*
|
|
|
- * In the case of hwmod with hardreset that should not be
|
|
|
- * de-assert at boot time, we have to keep the module
|
|
|
- * initialized, because we cannot enable it properly with the
|
|
|
- * reset asserted. Exit without warning because that behavior
|
|
|
- * is expected.
|
|
|
- */
|
|
|
- if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt > 0)
|
|
|
- return 0;
|
|
|
-
|
|
|
- r = _enable(oh);
|
|
|
- if (r) {
|
|
|
- pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",
|
|
|
- oh->name, oh->_state);
|
|
|
- return 0;
|
|
|
+ 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);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (!(oh->flags & HWMOD_INIT_NO_RESET))
|