|
@@ -3094,3 +3094,164 @@ void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs)
|
|
|
* @oh: struct omap_hwmod *
|
|
|
*
|
|
|
* This is a public function exposed to drivers. Some drivers may need to do
|
|
|
+ * some settings before and after resetting the device. Those drivers after
|
|
|
+ * doing the necessary settings could use this function to start a reset by
|
|
|
+ * setting the SYSCONFIG.SOFTRESET bit.
|
|
|
+ */
|
|
|
+int omap_hwmod_softreset(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ u32 v;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!oh || !(oh->_sysc_cache))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ v = oh->_sysc_cache;
|
|
|
+ ret = _set_softreset(oh, &v);
|
|
|
+ if (ret)
|
|
|
+ goto error;
|
|
|
+ _write_sysconfig(v, oh);
|
|
|
+
|
|
|
+error:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @idlemode: SIDLEMODE field bits (shifted to bit 0)
|
|
|
+ *
|
|
|
+ * Sets the IP block's OCP slave idlemode in hardware, and updates our
|
|
|
+ * local copy. Intended to be used by drivers that have some erratum
|
|
|
+ * that requires direct manipulation of the SIDLEMODE bits. Returns
|
|
|
+ * -EINVAL if @oh is null, or passes along the return value from
|
|
|
+ * _set_slave_idlemode().
|
|
|
+ *
|
|
|
+ * XXX Does this function have any current users? If not, we should
|
|
|
+ * remove it; it is better to let the rest of the hwmod code handle this.
|
|
|
+ * Any users of this function should be scrutinized carefully.
|
|
|
+ */
|
|
|
+int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode)
|
|
|
+{
|
|
|
+ u32 v;
|
|
|
+ int retval = 0;
|
|
|
+
|
|
|
+ if (!oh)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ v = oh->_sysc_cache;
|
|
|
+
|
|
|
+ retval = _set_slave_idlemode(oh, idlemode, &v);
|
|
|
+ if (!retval)
|
|
|
+ _write_sysconfig(v, oh);
|
|
|
+
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_lookup - look up a registered omap_hwmod by name
|
|
|
+ * @name: name of the omap_hwmod to look up
|
|
|
+ *
|
|
|
+ * Given a @name of an omap_hwmod, return a pointer to the registered
|
|
|
+ * struct omap_hwmod *, or NULL upon error.
|
|
|
+ */
|
|
|
+struct omap_hwmod *omap_hwmod_lookup(const char *name)
|
|
|
+{
|
|
|
+ struct omap_hwmod *oh;
|
|
|
+
|
|
|
+ if (!name)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ oh = _lookup(name);
|
|
|
+
|
|
|
+ return oh;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_for_each - call function for each registered omap_hwmod
|
|
|
+ * @fn: pointer to a callback function
|
|
|
+ * @data: void * data to pass to callback function
|
|
|
+ *
|
|
|
+ * Call @fn for each registered omap_hwmod, passing @data to each
|
|
|
+ * function. @fn must return 0 for success or any other value for
|
|
|
+ * failure. If @fn returns non-zero, the iteration across omap_hwmods
|
|
|
+ * will stop and the non-zero return value will be passed to the
|
|
|
+ * caller of omap_hwmod_for_each(). @fn is called with
|
|
|
+ * omap_hwmod_for_each() held.
|
|
|
+ */
|
|
|
+int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ struct omap_hwmod *temp_oh;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (!fn)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
|
|
|
+ ret = (*fn)(temp_oh, data);
|
|
|
+ if (ret)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_register_links - register an array of hwmod links
|
|
|
+ * @ois: pointer to an array of omap_hwmod_ocp_if to register
|
|
|
+ *
|
|
|
+ * Intended to be called early in boot before the clock framework is
|
|
|
+ * initialized. If @ois is not null, will register all omap_hwmods
|
|
|
+ * listed in @ois that are valid for this chip. Returns -EINVAL if
|
|
|
+ * omap_hwmod_init() hasn't been called before calling this function,
|
|
|
+ * -ENOMEM if the link memory area can't be allocated, or 0 upon
|
|
|
+ * success.
|
|
|
+ */
|
|
|
+int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois)
|
|
|
+{
|
|
|
+ int r, i;
|
|
|
+
|
|
|
+ if (!inited)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!ois)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (!linkspace) {
|
|
|
+ if (_alloc_linkspace(ois)) {
|
|
|
+ pr_err("omap_hwmod: could not allocate link space\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ i = 0;
|
|
|
+ do {
|
|
|
+ r = _register_link(ois[i]);
|
|
|
+ WARN(r && r != -EEXIST,
|
|
|
+ "omap_hwmod: _register_link(%s -> %s) returned %d\n",
|
|
|
+ ois[i]->master->name, ois[i]->slave->name, r);
|
|
|
+ } while (ois[++i]);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _ensure_mpu_hwmod_is_setup - ensure the MPU SS hwmod is init'ed and set up
|
|
|
+ * @oh: pointer to the hwmod currently being set up (usually not the MPU)
|
|
|
+ *
|
|
|
+ * If the hwmod data corresponding to the MPU subsystem IP block
|
|
|
+ * hasn't been initialized and set up yet, do so now. This must be
|
|
|
+ * done first since sleep dependencies may be added from other hwmods
|
|
|
+ * to the MPU. Intended to be called only by omap_hwmod_setup*(). No
|
|
|
+ * return value.
|
|
|
+ */
|
|
|
+static void __init _ensure_mpu_hwmod_is_setup(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ if (!mpu_oh || mpu_oh->_state == _HWMOD_STATE_UNKNOWN)
|
|
|
+ pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n",
|
|
|
+ __func__, MPU_INITIATOR_NAME);
|
|
|
+ else if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh)
|
|
|
+ omap_hwmod_setup_one(MPU_INITIATOR_NAME);
|
|
|
+}
|
|
|
+
|