|
@@ -2434,3 +2434,183 @@ static void __init _setup_iclk_autoidle(struct omap_hwmod *oh)
|
|
|
/**
|
|
|
* _setup_reset - reset an IP block during the setup process
|
|
|
* @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Reset the IP block corresponding to the hwmod @oh during the setup
|
|
|
+ * process. The IP block is first enabled so it can be successfully
|
|
|
+ * reset. Returns 0 upon success or a negative error code upon
|
|
|
+ * failure.
|
|
|
+ */
|
|
|
+static int __init _setup_reset(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+
|
|
|
+ if (oh->_state != _HWMOD_STATE_INITIALIZED)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (oh->flags & HWMOD_EXT_OPT_MAIN_CLK)
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ 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))
|
|
|
+ r = _reset(oh);
|
|
|
+
|
|
|
+ return r;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _setup_postsetup - transition to the appropriate state after _setup
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Place an IP block represented by @oh into a "post-setup" state --
|
|
|
+ * either IDLE, ENABLED, or DISABLED. ("post-setup" simply means that
|
|
|
+ * this function is called at the end of _setup().) The postsetup
|
|
|
+ * state for an IP block can be changed by calling
|
|
|
+ * omap_hwmod_enter_postsetup_state() early in the boot process,
|
|
|
+ * before one of the omap_hwmod_setup*() functions are called for the
|
|
|
+ * IP block.
|
|
|
+ *
|
|
|
+ * The IP block stays in this state until a PM runtime-based driver is
|
|
|
+ * loaded for that IP block. A post-setup state of IDLE is
|
|
|
+ * appropriate for almost all IP blocks with runtime PM-enabled
|
|
|
+ * drivers, since those drivers are able to enable the IP block. A
|
|
|
+ * post-setup state of ENABLED is appropriate for kernels with PM
|
|
|
+ * runtime disabled. The DISABLED state is appropriate for unusual IP
|
|
|
+ * blocks such as the MPU WDTIMER on kernels without WDTIMER drivers
|
|
|
+ * included, since the WDTIMER starts running on reset and will reset
|
|
|
+ * the MPU if left active.
|
|
|
+ *
|
|
|
+ * This post-setup mechanism is deprecated. Once all of the OMAP
|
|
|
+ * drivers have been converted to use PM runtime, and all of the IP
|
|
|
+ * block data and interconnect data is available to the hwmod code, it
|
|
|
+ * should be possible to replace this mechanism with a "lazy reset"
|
|
|
+ * arrangement. In a "lazy reset" setup, each IP block is enabled
|
|
|
+ * when the driver first probes, then all remaining IP blocks without
|
|
|
+ * drivers are either shut down or enabled after the drivers have
|
|
|
+ * loaded. However, this cannot take place until the above
|
|
|
+ * preconditions have been met, since otherwise the late reset code
|
|
|
+ * has no way of knowing which IP blocks are in use by drivers, and
|
|
|
+ * which ones are unused.
|
|
|
+ *
|
|
|
+ * No return value.
|
|
|
+ */
|
|
|
+static void __init _setup_postsetup(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ u8 postsetup_state;
|
|
|
+
|
|
|
+ if (oh->rst_lines_cnt > 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ postsetup_state = oh->_postsetup_state;
|
|
|
+ if (postsetup_state == _HWMOD_STATE_UNKNOWN)
|
|
|
+ postsetup_state = _HWMOD_STATE_ENABLED;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 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) &&
|
|
|
+ (postsetup_state == _HWMOD_STATE_IDLE)) {
|
|
|
+ oh->_int_flags |= _HWMOD_SKIP_ENABLE;
|
|
|
+ postsetup_state = _HWMOD_STATE_ENABLED;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (postsetup_state == _HWMOD_STATE_IDLE)
|
|
|
+ _idle(oh);
|
|
|
+ else if (postsetup_state == _HWMOD_STATE_DISABLED)
|
|
|
+ _shutdown(oh);
|
|
|
+ else if (postsetup_state != _HWMOD_STATE_ENABLED)
|
|
|
+ WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n",
|
|
|
+ oh->name, postsetup_state);
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _setup - prepare IP block hardware for use
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @n: (unused, pass NULL)
|
|
|
+ *
|
|
|
+ * Configure the IP block represented by @oh. This may include
|
|
|
+ * enabling the IP block, resetting it, and placing it into a
|
|
|
+ * post-setup state, depending on the type of IP block and applicable
|
|
|
+ * flags. IP blocks are reset to prevent any previous configuration
|
|
|
+ * by the bootloader or previous operating system from interfering
|
|
|
+ * with power management or other parts of the system. The reset can
|
|
|
+ * be avoided; see omap_hwmod_no_setup_reset(). This is the second of
|
|
|
+ * two phases for hwmod initialization. Code called here generally
|
|
|
+ * affects the IP block hardware, or system integration hardware
|
|
|
+ * associated with the IP block. Returns 0.
|
|
|
+ */
|
|
|
+static int __init _setup(struct omap_hwmod *oh, void *data)
|
|
|
+{
|
|
|
+ if (oh->_state != _HWMOD_STATE_INITIALIZED)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ _setup_iclk_autoidle(oh);
|
|
|
+
|
|
|
+ if (!_setup_reset(oh))
|
|
|
+ _setup_postsetup(oh);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _register - register a struct omap_hwmod
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Registers the omap_hwmod @oh. Returns -EEXIST if an omap_hwmod
|
|
|
+ * already has been registered by the same name; -EINVAL if the
|
|
|
+ * omap_hwmod is in the wrong state, if @oh is NULL, if the
|
|
|
+ * omap_hwmod's class field is NULL; if the omap_hwmod is missing a
|
|
|
+ * name, or if the omap_hwmod's class is missing a name; or 0 upon
|
|
|
+ * success.
|
|
|
+ *
|
|
|
+ * XXX The data should be copied into bootmem, so the original data
|
|
|
+ * should be marked __initdata and freed after init. This would allow
|
|
|
+ * unneeded omap_hwmods to be freed on multi-OMAP configurations. Note
|
|
|
+ * that the copy process would be relatively complex due to the large number
|
|
|
+ * of substructures.
|
|
|
+ */
|
|
|
+static int __init _register(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ if (!oh || !oh->name || !oh->class || !oh->class->name ||
|
|
|
+ (oh->_state != _HWMOD_STATE_UNKNOWN))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ pr_debug("omap_hwmod: %s: registering\n", oh->name);
|
|
|
+
|
|
|
+ if (_lookup(oh->name))
|
|
|
+ return -EEXIST;
|
|
|
+
|
|
|
+ list_add_tail(&oh->node, &omap_hwmod_list);
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&oh->master_ports);
|
|
|
+ INIT_LIST_HEAD(&oh->slave_ports);
|
|
|
+ spin_lock_init(&oh->_lock);
|
|
|
+
|
|
|
+ oh->_state = _HWMOD_STATE_REGISTERED;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * XXX Rather than doing a strcmp(), this should test a flag
|
|
|
+ * set in the hwmod data, inserted by the autogenerator code.
|
|
|
+ */
|
|
|
+ if (!strcmp(oh->name, MPU_INITIATOR_NAME))
|
|
|
+ mpu_oh = oh;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _alloc_links - return allocated memory for hwmod links
|
|
|
+ * @ml: pointer to a struct omap_hwmod_link * for the master link
|
|
|
+ * @sl: pointer to a struct omap_hwmod_link * for the slave link
|
|
|
+ *
|
|
|
+ * Return pointers to two struct omap_hwmod_link records, via the
|