OMAP3 hwmod: Add automatic OCP_SYSCONFIG AUTOIDLE handling
authorPaul Walmsley <paul@pwsan.com>
Tue, 8 Dec 2009 23:34:15 +0000 (16:34 -0700)
committerpaul <paul@twilight.(none)>
Sat, 12 Dec 2009 00:00:43 +0000 (17:00 -0700)
This patch fills in the OCP_SYSCONFIG.AUTOIDLE handling in the OMAP
hwmod code.

After this patch, the hwmod code will set the module AUTOIDLE bit
(generally <module>.OCP_SYSCONFIG.AUTOIDLE) to 1 by default upon
enable.  If the hwmod flag HWMOD_NO_OCP_AUTOIDLE is set, AUTOIDLE will
be set to 0 upon enable.  Upon module disable, AUTOIDLE will be set to
1.

Enabling module autoidle should save some power.  The only reason to
not set the OCP_SYSCONFIG.AUTOIDLE bit is if there is a bug in the
module RTL, e.g., the MPUINTC block on OMAP3.

Comments from Kevin Hilman <khilman@deeprootsystems.com> inspired this patch,
and Kevin tested an earlier version of this patch.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Tested-by: Kevin Hilman <khilman@deeprootsystems.com>
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/plat-omap/include/plat/omap_hwmod.h

index 65a8e0ae394fcb0f27887e1fb01904f98cfd1b87..b01da1ed822d34c0a69f25b451828c10cdaed717 100644 (file)
@@ -210,6 +210,32 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v)
        return 0;
 }
 
+/**
+ * _set_module_autoidle: set the OCP_SYSCONFIG AUTOIDLE field in @v
+ * @oh: struct omap_hwmod *
+ * @autoidle: desired AUTOIDLE bitfield value (0 or 1)
+ * @v: pointer to register contents to modify
+ *
+ * Update the module autoidle bit in @v to be @autoidle for the @oh
+ * hwmod.  The autoidle bit controls whether the module can gate
+ * internal clocks automatically when it isn't doing anything; the
+ * exact function of this bit varies on a per-module basis.  This
+ * function does not write to the hardware.  Returns -EINVAL upon
+ * error or 0 upon success.
+ */
+static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
+                               u32 *v)
+{
+       if (!oh->sysconfig ||
+           !(oh->sysconfig->sysc_flags & SYSC_HAS_AUTOIDLE))
+               return -EINVAL;
+
+       *v &= ~SYSC_AUTOIDLE_MASK;
+       *v |= autoidle << SYSC_AUTOIDLE_SHIFT;
+
+       return 0;
+}
+
 /**
  * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware
  * @oh: struct omap_hwmod *
@@ -558,7 +584,13 @@ static void _sysc_enable(struct omap_hwmod *oh)
                _set_master_standbymode(oh, idlemode, &v);
        }
 
-       /* XXX OCP AUTOIDLE bit? */
+       if (oh->sysconfig->sysc_flags & SYSC_HAS_AUTOIDLE) {
+               idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ?
+                       0 : 1;
+               _set_module_autoidle(oh, idlemode, &v);
+       }
+
+       /* XXX OCP ENAWAKEUP bit? */
 
        if (oh->flags & HWMOD_SET_DEFAULT_CLOCKACT &&
            oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY)
@@ -623,7 +655,8 @@ static void _sysc_shutdown(struct omap_hwmod *oh)
        if (oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE)
                _set_master_standbymode(oh, HWMOD_IDLEMODE_FORCE, &v);
 
-       /* XXX clear OCP AUTOIDLE bit? */
+       if (oh->sysconfig->sysc_flags & SYSC_HAS_AUTOIDLE)
+               _set_module_autoidle(oh, 1, &v);
 
        _write_sysconfig(v, oh);
 }
index dbdd123eca162a3c54f61347411326a0996d2c58..643a9727de35dc56e5e0d0e6fb0151aac2d3a83b 100644 (file)
@@ -50,6 +50,8 @@ struct omap_device;
 #define SYSC_ENAWAKEUP_MASK            (1 << SYSC_ENAWAKEUP_SHIFT)
 #define SYSC_SOFTRESET_SHIFT           1
 #define SYSC_SOFTRESET_MASK            (1 << SYSC_SOFTRESET_SHIFT)
+#define SYSC_AUTOIDLE_SHIFT            0
+#define SYSC_AUTOIDLE_MASK             (1 << SYSC_AUTOIDLE_SHIFT)
 
 /* OCP SYSSTATUS bit shifts/masks */
 #define SYSS_RESETDONE_SHIFT           0
@@ -294,13 +296,17 @@ struct omap_hwmod_omap4_prcm {
  *     SDRAM controller, etc.
  * HWMOD_INIT_NO_IDLE: don't idle this module at boot - important for SDRAM
  *     controller, etc.
+ * HWMOD_NO_AUTOIDLE: disable module autoidle (OCP_SYSCONFIG.AUTOIDLE)
+ *     when module is enabled, rather than the default, which is to
+ *     enable autoidle
  * HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup
  */
 #define HWMOD_SWSUP_SIDLE                      (1 << 0)
 #define HWMOD_SWSUP_MSTANDBY                   (1 << 1)
 #define HWMOD_INIT_NO_RESET                    (1 << 2)
 #define HWMOD_INIT_NO_IDLE                     (1 << 3)
-#define HWMOD_SET_DEFAULT_CLOCKACT             (1 << 4)
+#define HWMOD_NO_OCP_AUTOIDLE                  (1 << 4)
+#define HWMOD_SET_DEFAULT_CLOCKACT             (1 << 5)
 
 /*
  * omap_hwmod._int_flags definitions