OMAP2+: hwmod: add postsetup state
authorPaul Walmsley <paul@pwsan.com>
Tue, 14 Dec 2010 19:42:35 +0000 (12:42 -0700)
committerPaul Walmsley <paul@pwsan.com>
Wed, 22 Dec 2010 02:55:12 +0000 (19:55 -0700)
Allow board files and OMAP core code to control the state that some or
all of the hwmods end up in at the end of _setup() (called by
omap_hwmod_late_init() ).  Reimplement the old skip_setup_idle code in
terms of this new postsetup state code.

There are two use-cases for this patch: the !CONFIG_PM_RUNTIME case,
in which all IP blocks should stay enabled after _setup() finishes;
and the MPU watchdog case, in which the watchdog IP block should enter
idle if watchdog coverage of kernel initialization is desired, and
should be disabled otherwise.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: BenoƮt Cousson <b-cousson@ti.com>
Cc: Kevin Hilman <khilman@deeprootsystems.com>
Cc: Charulatha Varadarajan <charu@ti.com>
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/plat-omap/include/plat/omap_hwmod.h

index 77bf0d1baeefe32738efeb76b47963e8a1d7b85d..7362b69a154de95c5d4d36116630ee2d2720018e 100644 (file)
@@ -312,6 +312,11 @@ static int __init _omap2_init_reprogram_sdrc(void)
        return v;
 }
 
+static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data)
+{
+       return omap_hwmod_set_postsetup_state(oh, *(u8 *)data);
+}
+
 /*
  * Initialize asm_irq_base for entry-macro.S
  */
@@ -333,6 +338,8 @@ static inline void omap_irq_base_init(void)
 
 void __init omap2_init_common_infrastructure(void)
 {
+       u8 postsetup_state;
+
        pwrdm_init(powerdomains_omap);
        clkdm_init(clockdomains_omap, clkdm_autodeps);
        if (cpu_is_omap242x())
@@ -343,6 +350,16 @@ void __init omap2_init_common_infrastructure(void)
                omap3xxx_hwmod_init();
        else if (cpu_is_omap44xx())
                omap44xx_hwmod_init();
+       else
+               pr_err("Could not init hwmod data - unknown SoC\n");
+
+       /* Set the default postsetup state for all hwmods */
+#ifdef CONFIG_PM_RUNTIME
+       postsetup_state = _HWMOD_STATE_IDLE;
+#else
+       postsetup_state = _HWMOD_STATE_ENABLED;
+#endif
+       omap_hwmod_for_each(_set_hwmod_postsetup_state, &postsetup_state);
 
        omap_pm_if_early_init();
 
@@ -355,25 +372,16 @@ void __init omap2_init_common_infrastructure(void)
        else if (cpu_is_omap44xx())
                omap4xxx_clk_init();
        else
-               pr_err("Could not init clock framework - unknown CPU\n");
+               pr_err("Could not init clock framework - unknown SoC\n");
 }
 
-/*
- * XXX Ideally, this function will dwindle into nothingness over time;
- * almost all device init code should be possible through initcalls
- * and other generalized mechanisms
- */
 void __init omap2_init_common_devices(struct omap_sdrc_params *sdrc_cs0,
                                      struct omap_sdrc_params *sdrc_cs1)
 {
-       u8 skip_setup_idle = 0;
-
        omap_serial_early_init();
 
-#ifndef CONFIG_PM_RUNTIME
-       skip_setup_idle = 1;
-#endif
-       omap_hwmod_late_init(skip_setup_idle);
+       omap_hwmod_late_init();
+
        if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
                omap2_sdrc_init(sdrc_cs0, sdrc_cs1);
                _omap2_init_reprogram_sdrc();
index c051fa49359479ef8a58b472d1ab531b1e5d72de..683428fa91f4280d2acb7ea1a59d71f6d84e8c71 100644 (file)
@@ -1313,23 +1313,15 @@ static int _shutdown(struct omap_hwmod *oh)
 /**
  * _setup - do initial configuration of omap_hwmod
  * @oh: struct omap_hwmod *
- * @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1
  *
  * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh
- * OCP_SYSCONFIG register.  @skip_setup_idle is intended to be used on
- * a system that will not call omap_hwmod_enable() to enable devices
- * (e.g., a system without PM runtime).  Returns -EINVAL if the hwmod
- * is in the wrong state or returns 0.
+ * OCP_SYSCONFIG register.  Returns -EINVAL if the hwmod is in the
+ * wrong state or returns 0.
  */
 static int _setup(struct omap_hwmod *oh, void *data)
 {
        int i, r;
-       u8 skip_setup_idle;
-
-       if (!oh || !data)
-               return -EINVAL;
-
-       skip_setup_idle = *(u8 *)data;
+       u8 postsetup_state;
 
        /* Set iclk autoidle mode */
        if (oh->slaves_cnt > 0) {
@@ -1349,7 +1341,6 @@ static int _setup(struct omap_hwmod *oh, void *data)
                }
        }
 
-       mutex_init(&oh->_mutex);
        oh->_state = _HWMOD_STATE_INITIALIZED;
 
        /*
@@ -1383,8 +1374,25 @@ static int _setup(struct omap_hwmod *oh, void *data)
                }
        }
 
-       if (!(oh->flags & HWMOD_INIT_NO_IDLE) && !skip_setup_idle)
+       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))
+               postsetup_state = _HWMOD_STATE_ENABLED;
+
+       if (postsetup_state == _HWMOD_STATE_IDLE)
                _omap_hwmod_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 0;
 }
@@ -1485,6 +1493,8 @@ int omap_hwmod_register(struct omap_hwmod *oh)
 
        list_add_tail(&oh->node, &omap_hwmod_list);
 
+       mutex_init(&oh->_mutex);
+
        oh->_state = _HWMOD_STATE_REGISTERED;
 
        ret = 0;
@@ -1585,13 +1595,12 @@ int omap_hwmod_init(struct omap_hwmod **ohs)
 
 /**
  * omap_hwmod_late_init - do some post-clock framework initialization
- * @skip_setup_idle: if 1, do not idle hwmods in _setup()
  *
  * Must be called after omap2_clk_init().  Resolves the struct clk names
  * to struct clk pointers for each registered omap_hwmod.  Also calls
  * _setup() on each hwmod.  Returns 0.
  */
-int omap_hwmod_late_init(u8 skip_setup_idle)
+int omap_hwmod_late_init(void)
 {
        int r;
 
@@ -1603,10 +1612,7 @@ int omap_hwmod_late_init(u8 skip_setup_idle)
        WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n",
             MPU_INITIATOR_NAME);
 
-       if (skip_setup_idle)
-               pr_debug("omap_hwmod: will leave hwmods enabled during setup\n");
-
-       omap_hwmod_for_each(_setup, &skip_setup_idle);
+       omap_hwmod_for_each(_setup, NULL);
 
        return 0;
 }
@@ -2132,3 +2138,41 @@ int omap_hwmod_for_each_by_class(const char *classname,
        return ret;
 }
 
+/**
+ * omap_hwmod_set_postsetup_state - set the post-_setup() state for this hwmod
+ * @oh: struct omap_hwmod *
+ * @state: state that _setup() should leave the hwmod in
+ *
+ * Sets the hwmod state that @oh will enter at the end of _setup() (called by
+ * omap_hwmod_late_init()).  Only valid to call between calls to
+ * omap_hwmod_init() and omap_hwmod_late_init().  Returns 0 upon success or
+ * -EINVAL if there is a problem with the arguments or if the hwmod is
+ * in the wrong state.
+ */
+int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
+{
+       int ret;
+
+       if (!oh)
+               return -EINVAL;
+
+       if (state != _HWMOD_STATE_DISABLED &&
+           state != _HWMOD_STATE_ENABLED &&
+           state != _HWMOD_STATE_IDLE)
+               return -EINVAL;
+
+       mutex_lock(&oh->_mutex);
+
+       if (oh->_state != _HWMOD_STATE_REGISTERED) {
+               ret = -EINVAL;
+               goto ohsps_unlock;
+       }
+
+       oh->_postsetup_state = state;
+       ret = 0;
+
+ohsps_unlock:
+       mutex_unlock(&oh->_mutex);
+
+       return ret;
+}
index d1f1265fc4a627e786cab97553b3f04dd8c2f322..b445ecdb95b800d45b2c24ceebdb8faa86350046 100644 (file)
@@ -462,6 +462,7 @@ struct omap_hwmod_class {
  * @response_lat: device OCP response latency (in interface clock cycles)
  * @_int_flags: internal-use hwmod flags
  * @_state: internal-use hwmod state
+ * @_postsetup_state: internal-use state to leave the hwmod in after _setup()
  * @flags: hwmod flags (documented below)
  * @omap_chip: OMAP chips this hwmod is present on
  * @_mutex: mutex serializing operations on this hwmod
@@ -510,6 +511,7 @@ struct omap_hwmod {
        u8                              hwmods_cnt;
        u8                              _int_flags;
        u8                              _state;
+       u8                              _postsetup_state;
        const struct omap_chip_id       omap_chip;
 };
 
@@ -519,7 +521,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh);
 struct omap_hwmod *omap_hwmod_lookup(const char *name);
 int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
                        void *data);
-int omap_hwmod_late_init(u8 skip_setup_idle);
+int omap_hwmod_late_init(void);
 
 int omap_hwmod_enable(struct omap_hwmod *oh);
 int _omap_hwmod_enable(struct omap_hwmod *oh);
@@ -566,6 +568,8 @@ int omap_hwmod_for_each_by_class(const char *classname,
                                           void *user),
                                 void *user);
 
+int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state);
+
 /*
  * Chip variant-specific hwmod init routines - XXX should be converted
  * to use initcalls once the initial boot ordering is straightened out