@@ -1204,6 +1204,9 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
r = _wait_target_ready(oh);
if (!r) {
+ if (oh->enable_delay)
+ udelay(oh->enable_delay);
+
oh->_state = _HWMOD_STATE_ENABLED;
/* Access the sysconfig only if the target is ready */
@@ -434,6 +434,7 @@ struct omap_hwmod_class {
* @main_clk: main clock: OMAP clock name
* @_clk: pointer to the main struct clk (filled in at runtime)
* @opt_clks: other device clocks that drivers can request (0..*)
+ * @enable_delay: number of microseconds to wait after IdleReq is deasserted
* @masters: ptr to array of OCP ifs that this hwmod can initiate on
* @slaves: ptr to array of OCP ifs that this hwmod can respond on
* @dev_attr: arbitrary device attributes that can be passed to the driver
@@ -460,8 +461,35 @@ struct omap_hwmod_class {
* accesses to complete." Modules may not have a main clock if the
* interface clock also serves as a main clock.
*
- * Parameter names beginning with an underscore are managed internally by
- * the omap_hwmod code and should not be set during initialization.
+ * On OMAP SoCs prior to OMAP4, some hwmods may require a non-zero
+ * @enable_delay value. A hwmod needs a non-zero @enable_delay if an
+ * imprecise external abort occurs while the hwmod is being enabled.
+ * This can happen if the hwmod takes a significant time to become
+ * ready for OCP transactions after the PRCM deasserts IdleAck to the
+ * module. @enable_delay specifies the number of microseconds for the
+ * hwmod code to udelay() between the time that the PRCM deasserts the
+ * IdleAck, and the time when the module is ready to handle register
+ * reads/writes. Most hwmods shouldn't need anything here and can
+ * leave @enable_delay blank. For hwmods that do need a value here,
+ * to estimate the required value, the best thing to do is to set the
+ * IP block to run at the slowest interface and functional clock rates
+ * and the lowest voltages. First, try out a small value, say, 10
+ * microseconds, and keep increasing it until the kernel no longer
+ * crashes. Then add a safety margin to the value that you arrived at
+ * -- say, 50% -- and specify the value in the structure record
+ * initializer for @enable_delay as (value + safety_margin). Try not
+ * to overestimate this number; if @enable_delay is too large, then
+ * energy will be wasted and the CPU will spin for an unnecessarily
+ * long time while enabling the device. If @enable_delay is too
+ * small, the device will trigger an abort. More information is
+ * available here:
+ * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg36300.html
+ * XXX @enable_value will need to be taken into consideration by the
+ * omap_device code to determine whether the device's current wakeup
+ * latency constraint can be satisfied if the module is placed into idle.
+ *
+ * Parameter names beginning with an underscore are managed internally
+ * by the omap_hwmod code and should not be set during initialization.
*/
struct omap_hwmod {
const char *name;
@@ -484,6 +512,7 @@ struct omap_hwmod {
void __iomem *_mpu_rt_va;
struct mutex _mutex;
struct list_head node;
+ u16 enable_delay;
u16 flags;
u8 _mpu_port_index;
u8 msuspendmux_reg_id;