OMAP4: hwmod & CM: Implement the omap4_cm_wait_module_ready function
authorBenoit Cousson <b-cousson@ti.com>
Thu, 20 May 2010 18:31:08 +0000 (12:31 -0600)
committerPaul Walmsley <paul@pwsan.com>
Thu, 20 May 2010 18:31:08 +0000 (12:31 -0600)
The return of the omap4_cm_wait_module_ready function is checked
in order to avoid accessing the sysconfig register if the module is
not in the correct state.
In that case the _setup will exit without trying to reset
using sysconfig.
For the moment a warning is printed. A proper management of fclk
and module reset will have to be done in order to init correctly
the problematic IPs listed below.

  <4>omap_hwmod: ivahd: cannot be enabled (3)
  <4>omap_hwmod: iss: cannot be enabled (3)
  <4>omap_hwmod: tesla: cannot be enabled (3)
  <4>omap_hwmod: sdma: cannot be enabled (3)
  <4>omap_hwmod: sl2: cannot be enabled (3)
  <4>omap_hwmod: sad2d: cannot be enabled (3)
  <4>omap_hwmod: ducati: cannot be enabled (3)

Signed-off-by: Benoit Cousson <b-cousson@ti.com>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
arch/arm/mach-omap2/cm.h
arch/arm/mach-omap2/cm4xxx.c
arch/arm/mach-omap2/omap_hwmod.c

index bbc69df..a02ca30 100644 (file)
@@ -112,7 +112,7 @@ extern u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx);
 
 extern int omap2_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id,
                                      u8 idlest_shift);
-extern int omap4_cm_wait_module_ready(u32 prcm_mod, u8 prcm_dev_offs);
+extern int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg);
 
 static inline u32 cm_set_mod_reg_bits(u32 bits, s16 module, s16 idx)
 {
index af32a45..b101091 100644 (file)
 
 #include <asm/atomic.h>
 
+#include <plat/common.h>
+
 #include "cm.h"
 #include "cm-regbits-44xx.h"
 
 /**
- * omap4_cm_wait_idlest_ready - wait for a module to leave idle or standby
- * @prcm_mod: PRCM module offset (XXX example)
- * @prcm_dev_offs: PRCM device offset (e.g. MCASP XXX example)
+ * omap4_cm_wait_module_ready - wait for a module to be in 'func' state
+ * @clkctrl_reg: CLKCTRL module address
+ *
+ * Wait for the module IDLEST to be functional. If the idle state is in any
+ * the non functional state (trans, idle or disabled), module and thus the
+ * sysconfig cannot be accessed and will probably lead to an "imprecise
+ * external abort"
+ *
+ * Module idle state:
+ *   0x0 func:     Module is fully functional, including OCP
+ *   0x1 trans:    Module is performing transition: wakeup, or sleep, or sleep
+ *                 abortion
+ *   0x2 idle:     Module is in Idle mode (only OCP part). It is functional if
+ *                 using separate functional clock
+ *   0x3 disabled: Module is disabled and cannot be accessed
  *
- * XXX document
+ * TODO: Need to handle module accessible in idle state
  */
-int omap4_cm_wait_idlest_ready(u32 prcm_mod, u8 prcm_dev_offs)
+int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg)
 {
-       /* FIXME: Add clock manager related code */
-       return 0;
+       int i = 0;
+
+       if (!clkctrl_reg)
+               return 0;
+
+       omap_test_timeout(((__raw_readl(clkctrl_reg) &
+                           OMAP4430_IDLEST_MASK) == 0),
+                         MAX_MODULE_READY_TIME, i);
+
+       return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
 }
 
index e436dcb..4a134c4 100644 (file)
@@ -819,11 +819,8 @@ static int _wait_target_ready(struct omap_hwmod *oh)
                ret = omap2_cm_wait_module_ready(oh->prcm.omap2.module_offs,
                                                 oh->prcm.omap2.idlest_reg_id,
                                                 oh->prcm.omap2.idlest_idle_bit);
-#if 0
        } else if (cpu_is_omap44xx()) {
-               ret = omap4_cm_wait_module_ready(oh->prcm.omap4.module_offs,
-                                                oh->prcm.omap4.device_offs);
-#endif
+               ret = omap4_cm_wait_module_ready(oh->prcm.omap4.clkctrl_reg);
        } else {
                BUG();
        };
@@ -912,16 +909,21 @@ static int _enable(struct omap_hwmod *oh)
        _add_initiator_dep(oh, mpu_oh);
        _enable_clocks(oh);
 
-       if (oh->class->sysc) {
-               if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
-                       _update_sysc_cache(oh);
-               _sysc_enable(oh);
-       }
-
        r = _wait_target_ready(oh);
-       if (!r)
+       if (!r) {
                oh->_state = _HWMOD_STATE_ENABLED;
 
+               /* Access the sysconfig only if the target is ready */
+               if (oh->class->sysc) {
+                       if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
+                               _update_sysc_cache(oh);
+                       _sysc_enable(oh);
+               }
+       } else {
+               pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
+                        oh->name, r);
+       }
+
        return r;
 }
 
@@ -999,7 +1001,7 @@ static int _shutdown(struct omap_hwmod *oh)
 static int _setup(struct omap_hwmod *oh)
 {
        struct omap_hwmod_ocp_if *os;
-       int i;
+       int i, r;
 
        if (!oh)
                return -EINVAL;
@@ -1023,7 +1025,12 @@ static int _setup(struct omap_hwmod *oh)
 
        oh->_state = _HWMOD_STATE_INITIALIZED;
 
-       _enable(oh);
+       r = _enable(oh);
+       if (r) {
+               pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",
+                          oh->name, oh->_state);
+               return 0;
+       }
 
        if (!(oh->flags & HWMOD_INIT_NO_RESET)) {
                /*