OSDN Git Service

ARM: OMAP3PLUS: hwmod: reconfigure IO Daisychain during hwmod mux
authorVishwanath BS <vishwanath.bs@ti.com>
Fri, 22 Jun 2012 14:40:04 +0000 (08:40 -0600)
committerPaul Walmsley <paul@pwsan.com>
Fri, 22 Jun 2012 14:40:04 +0000 (08:40 -0600)
IO Daisychain feature has to be triggered whenever there is a change in
device's mux configuration (See section 3.9.4 in OMAP4 Public TRM vP).

Now devices can idle independent of the powerdomain, there can be a
window where device is idled and corresponding powerdomain can be
ON/INACTIVE state. In such situations, since both module wake up is
enabled at padlevel as well as io daisychain sequence is triggered,
there will be 2 PRCM interrupts (Module async wake up via swakeup and
IO Pad interrupt). But as PRCM Interrupt handler clears the Module
Padlevel WKST bit in the first interrupt, module specific interrupt
handler will not triggered for the second time

Also look at detailed explanation given by Rajendra at
http://www.spinics.net/lists/linux-serial/msg04480.html

Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Reviewed-by: Rajendra Nayak <rnayak@ti.com>
[paul@pwsan.com: remove dependency on pm.c & pm.h; add kerneldoc]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
arch/arm/mach-omap2/omap_hwmod.c

index bf86f7e..6d6c31a 100644 (file)
 #include "prm44xx.h"
 #include "prminst44xx.h"
 #include "mux.h"
+#include "pm.h"
 
 /* Maximum microseconds to wait for OMAP module to softreset */
 #define MAX_MODULE_SOFTRESET_WAIT      10000
@@ -172,6 +173,9 @@ static LIST_HEAD(omap_hwmod_list);
 /* mpu_oh: used to add/remove MPU initiator from sleepdep list */
 static struct omap_hwmod *mpu_oh;
 
+/* io_chain_lock: used to serialize reconfigurations of the I/O chain */
+static DEFINE_SPINLOCK(io_chain_lock);
+
 /*
  * linkspace: ptr to a buffer that struct omap_hwmod_link records are
  * allocated from - used to reduce the number of small memory
@@ -1738,6 +1742,32 @@ static int _reset(struct omap_hwmod *oh)
 }
 
 /**
+ * _reconfigure_io_chain - clear any I/O chain wakeups and reconfigure chain
+ *
+ * Call the appropriate PRM function to clear any logged I/O chain
+ * wakeups and to reconfigure the chain.  This apparently needs to be
+ * done upon every mux change.  Since hwmods can be concurrently
+ * enabled and idled, hold a spinlock around the I/O chain
+ * reconfiguration sequence.  No return value.
+ *
+ * XXX When the PRM code is moved to drivers, this function can be removed,
+ * as the PRM infrastructure should abstract this.
+ */
+static void _reconfigure_io_chain(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&io_chain_lock, flags);
+
+       if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl())
+               omap3xxx_prm_reconfigure_io_chain();
+       else if (cpu_is_omap44xx())
+               omap44xx_prm_reconfigure_io_chain();
+
+       spin_unlock_irqrestore(&io_chain_lock, flags);
+}
+
+/**
  * _enable - enable an omap_hwmod
  * @oh: struct omap_hwmod *
  *
@@ -1793,8 +1823,10 @@ static int _enable(struct omap_hwmod *oh)
        /* Mux pins for device runtime if populated */
        if (oh->mux && (!oh->mux->enabled ||
                        ((oh->_state == _HWMOD_STATE_IDLE) &&
-                        oh->mux->pads_dynamic)))
+                        oh->mux->pads_dynamic))) {
                omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
+               _reconfigure_io_chain();
+       }
 
        _add_initiator_dep(oh, mpu_oh);
 
@@ -1883,8 +1915,10 @@ static int _idle(struct omap_hwmod *oh)
                clkdm_hwmod_disable(oh->clkdm, oh);
 
        /* Mux pins for device idle if populated */
-       if (oh->mux && oh->mux->pads_dynamic)
+       if (oh->mux && oh->mux->pads_dynamic) {
                omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
+               _reconfigure_io_chain();
+       }
 
        oh->_state = _HWMOD_STATE_IDLE;