|
@@ -555,3 +555,134 @@ static void _set_idle_ioring_wakeup(struct omap_hwmod *oh, bool set_wake)
|
|
|
int j;
|
|
|
|
|
|
if (!oh->mux || !oh->mux->enabled)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for (j = 0; j < oh->mux->nr_pads_dynamic; j++) {
|
|
|
+ pad = oh->mux->pads_dynamic[j];
|
|
|
+
|
|
|
+ if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ prev_idle = pad->idle;
|
|
|
+
|
|
|
+ if (set_wake)
|
|
|
+ pad->idle |= OMAP_WAKEUP_EN;
|
|
|
+ else
|
|
|
+ pad->idle &= ~OMAP_WAKEUP_EN;
|
|
|
+
|
|
|
+ if (prev_idle != pad->idle)
|
|
|
+ change = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (change && oh->_state == _HWMOD_STATE_IDLE)
|
|
|
+ omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Allow the hardware module @oh to send wakeups. Returns -EINVAL
|
|
|
+ * upon error or 0 upon success.
|
|
|
+ */
|
|
|
+static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
|
|
|
+{
|
|
|
+ if (!oh->class->sysc ||
|
|
|
+ !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
|
|
|
+ (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) ||
|
|
|
+ (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!oh->class->sysc->sysc_fields) {
|
|
|
+ WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)
|
|
|
+ *v |= 0x1 << oh->class->sysc->sysc_fields->enwkup_shift;
|
|
|
+
|
|
|
+ if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
|
|
|
+ _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
|
|
|
+ if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
|
|
|
+ _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
|
|
|
+
|
|
|
+ /* XXX test pwrdm_get_wken for this hwmod's subsystem */
|
|
|
+
|
|
|
+ oh->_int_flags |= _HWMOD_WAKEUP_ENABLED;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _disable_wakeup: clear OCP_SYSCONFIG.ENAWAKEUP bit in the hardware
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Prevent the hardware module @oh to send wakeups. Returns -EINVAL
|
|
|
+ * upon error or 0 upon success.
|
|
|
+ */
|
|
|
+static int _disable_wakeup(struct omap_hwmod *oh, u32 *v)
|
|
|
+{
|
|
|
+ if (!oh->class->sysc ||
|
|
|
+ !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
|
|
|
+ (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) ||
|
|
|
+ (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!oh->class->sysc->sysc_fields) {
|
|
|
+ WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)
|
|
|
+ *v &= ~(0x1 << oh->class->sysc->sysc_fields->enwkup_shift);
|
|
|
+
|
|
|
+ if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
|
|
|
+ _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v);
|
|
|
+ if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
|
|
|
+ _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART, v);
|
|
|
+
|
|
|
+ /* XXX test pwrdm_get_wken for this hwmod's subsystem */
|
|
|
+
|
|
|
+ oh->_int_flags &= ~_HWMOD_WAKEUP_ENABLED;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct clockdomain *_get_clkdm(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ struct clk_hw_omap *clk;
|
|
|
+
|
|
|
+ if (oh->clkdm) {
|
|
|
+ return oh->clkdm;
|
|
|
+ } else if (oh->_clk) {
|
|
|
+ clk = to_clk_hw_omap(__clk_get_hw(oh->_clk));
|
|
|
+ return clk->clkdm;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _add_initiator_dep: prevent @oh from smart-idling while @init_oh is active
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Prevent the hardware module @oh from entering idle while the
|
|
|
+ * hardare module initiator @init_oh is active. Useful when a module
|
|
|
+ * will be accessed by a particular initiator (e.g., if a module will
|
|
|
+ * be accessed by the IVA, there should be a sleepdep between the IVA
|
|
|
+ * initiator and the module). Only applies to modules in smart-idle
|
|
|
+ * mode. If the clockdomain is marked as not needing autodeps, return
|
|
|
+ * 0 without doing anything. Otherwise, returns -EINVAL upon error or
|
|
|
+ * passes along clkdm_add_sleepdep() value upon success.
|
|
|
+ */
|
|
|
+static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
|
|
|
+{
|
|
|
+ struct clockdomain *clkdm, *init_clkdm;
|
|
|
+
|
|
|
+ clkdm = _get_clkdm(oh);
|
|
|
+ init_clkdm = _get_clkdm(init_oh);
|
|
|
+
|
|
|
+ if (!clkdm || !init_clkdm)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (clkdm && clkdm->flags & CLKDM_NO_AUTODEPS)
|
|
|
+ return 0;
|