]> Pileus Git - ~andy/linux/commitdiff
Merge tag 'omap-devel-c-for-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorTony Lindgren <tony@atomide.com>
Mon, 25 Jun 2012 14:41:17 +0000 (07:41 -0700)
committerTony Lindgren <tony@atomide.com>
Mon, 25 Jun 2012 14:41:17 +0000 (07:41 -0700)
Reimplement the OMAP PRCM I/O chain code.  Needed for I/O wakeups to
work correctly.

Conflicts:
arch/arm/mach-omap2/prm2xxx_3xxx.c

arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/prcm-common.h
arch/arm/mach-omap2/prm2xxx_3xxx.c
arch/arm/mach-omap2/prm2xxx_3xxx.h
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-omap2/prm44xx.h

index 773193670ea265cefa67f938fa780e938400dbce..09f44d56e026f7b8292b740a867e09e102193c93 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
@@ -1737,6 +1741,32 @@ static int _reset(struct omap_hwmod *oh)
        return r;
 }
 
+/**
+ * _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;
 
index 3a595e8997245495672d703fc52c7a148ffb0a9f..e67d898433fbec4d572f17eddf7e25c7df4e626c 100644 (file)
@@ -72,33 +72,6 @@ static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
 static struct powerdomain *core_pwrdm, *per_pwrdm;
 static struct powerdomain *cam_pwrdm;
 
-static void omap3_enable_io_chain(void)
-{
-       int timeout = 0;
-
-       omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
-                                  PM_WKEN);
-       /* Do a readback to assure write has been done */
-       omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);
-
-       while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN) &
-                OMAP3430_ST_IO_CHAIN_MASK)) {
-               timeout++;
-               if (timeout > 1000) {
-                       pr_err("Wake up daisy chain activation failed.\n");
-                       return;
-               }
-               omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK,
-                                          WKUP_MOD, PM_WKEN);
-       }
-}
-
-static void omap3_disable_io_chain(void)
-{
-       omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
-                                    PM_WKEN);
-}
-
 static void omap3_core_save_context(void)
 {
        omap3_ctrl_save_padconf();
@@ -299,13 +272,6 @@ void omap_sram_idle(void)
        /* Enable IO-PAD and IO-CHAIN wakeups */
        per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
        core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
-       if (omap3_has_io_wakeup() &&
-           (per_next_state < PWRDM_POWER_ON ||
-            core_next_state < PWRDM_POWER_ON)) {
-               omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN);
-               if (omap3_has_io_chain_ctrl())
-                       omap3_enable_io_chain();
-       }
 
        pwrdm_pre_transition();
 
@@ -378,16 +344,6 @@ void omap_sram_idle(void)
        if (per_next_state < PWRDM_POWER_ON)
                omap2_gpio_resume_after_idle();
 
-       /* Disable IO-PAD and IO-CHAIN wakeup */
-       if (omap3_has_io_wakeup() &&
-           (per_next_state < PWRDM_POWER_ON ||
-            core_next_state < PWRDM_POWER_ON)) {
-               omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
-                                            PM_WKEN);
-               if (omap3_has_io_chain_ctrl())
-                       omap3_disable_io_chain();
-       }
-
        clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
 }
 
index 6da3ba483ad118ea0b0e8082fa9e5e3417635465..fca23cbea708798a1adca967041cbfe1d51b2d3a 100644 (file)
  */
 #define MAX_MODULE_HARDRESET_WAIT              10000
 
+/*
+ * Maximum time(us) it takes to output the signal WUCLKOUT of the last
+ * pad of the I/O ring after asserting WUCLKIN high.  Tero measured
+ * the actual time at 7 to 8 microseconds on OMAP3 and 2 to 4
+ * microseconds on OMAP4, so this timeout may be too high.
+ */
+#define MAX_IOPAD_LATCH_TIME                   100
+
 # ifndef __ASSEMBLER__
 extern void __iomem *prm_base;
 extern void __iomem *cm_base;
index 21cb74003a562f27bc2a5a8538093d92503c44d0..e10fd1e9446baa395672fbffc65924bb5baed63a 100644 (file)
@@ -302,17 +302,60 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
                                OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 }
 
-static int __init omap3xxx_prcm_init(void)
+/**
+ * omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
+ *
+ * Clear any previously-latched I/O wakeup events and ensure that the
+ * I/O wakeup gates are aligned with the current mux settings.  Works
+ * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then
+ * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit.  No
+ * return value.
+ */
+void omap3xxx_prm_reconfigure_io_chain(void)
+{
+       int i = 0;
+
+       omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
+                                  PM_WKEN);
+
+       omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
+                         OMAP3430_ST_IO_CHAIN_MASK,
+                         MAX_IOPAD_LATCH_TIME, i);
+       if (i == MAX_IOPAD_LATCH_TIME)
+               pr_warn("PRM: I/O chain clock line assertion timed out\n");
+
+       omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
+                                    PM_WKEN);
+
+       omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, WKUP_MOD,
+                                  PM_WKST);
+
+       omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST);
+}
+
+/**
+ * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches
+ *
+ * Activates the I/O wakeup event latches and allows events logged by
+ * those latches to signal a wakeup event to the PRCM.  For I/O
+ * wakeups to occur, WAKEUPENABLE bits must be set in the pad mux
+ * registers, and omap3xxx_prm_reconfigure_io_chain() must be called.
+ * No return value.
+ */
+static void __init omap3xxx_prm_enable_io_wakeup(void)
 {
-       int ret = 0;
+       if (omap3_has_io_wakeup())
+               omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
+                                          PM_WKEN);
+}
 
+static int __init omap3xxx_prcm_init(void)
+{
        if (cpu_is_omap34xx()) {
-               ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
-               if (!ret)
-                       irq_set_status_flags(omap_prcm_event_to_irq("io"),
-                                            IRQ_NOAUTOEN);
+               omap3xxx_prm_enable_io_wakeup();
+               return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
        }
 
-       return ret;
+       return 0;
 }
 subsys_initcall(omap3xxx_prcm_init);
index 70ac2a19dc5f9d3bea6b0cc2d290bb171b7697e2..a8c946f318ab798b5abeb79dbe9c3349324f8b17 100644 (file)
@@ -303,6 +303,8 @@ extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
 extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
 extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift);
 
+#endif /* CONFIG_ARCH_OMAP4 */
+
 /* OMAP3-specific VP functions */
 u32 omap3_prm_vp_check_txdone(u8 vp_id);
 void omap3_prm_vp_clear_txdone(u8 vp_id);
@@ -315,14 +317,14 @@ extern u32 omap3_prm_vcvp_read(u8 offset);
 extern void omap3_prm_vcvp_write(u32 val, u8 offset);
 extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
 
+extern void omap3xxx_prm_reconfigure_io_chain(void);
+
 /* PRM interrupt-related functions */
 extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
 extern void omap3xxx_prm_ocp_barrier(void);
 extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
 extern void omap3xxx_prm_restore_irqen(u32 *saved_mask);
 
-#endif /* CONFIG_ARCH_OMAP4 */
-
 #endif
 
 /*
index f106d21ff581a3af4894fd45f58fe53aaebc6dd2..bb727c2d9337b73358c6e6509fdd1bef14425ffe 100644 (file)
@@ -233,10 +233,71 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask)
                                 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
 }
 
+/**
+ * omap44xx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
+ *
+ * Clear any previously-latched I/O wakeup events and ensure that the
+ * I/O wakeup gates are aligned with the current mux settings.  Works
+ * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then
+ * deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted.
+ * No return value. XXX Are the final two steps necessary?
+ */
+void omap44xx_prm_reconfigure_io_chain(void)
+{
+       int i = 0;
+
+       /* Trigger WUCLKIN enable */
+       omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK,
+                                   OMAP4430_WUCLK_CTRL_MASK,
+                                   OMAP4430_PRM_DEVICE_INST,
+                                   OMAP4_PRM_IO_PMCTRL_OFFSET);
+       omap_test_timeout(
+               (((omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+                                          OMAP4_PRM_IO_PMCTRL_OFFSET) &
+                  OMAP4430_WUCLK_STATUS_MASK) >>
+                 OMAP4430_WUCLK_STATUS_SHIFT) == 1),
+               MAX_IOPAD_LATCH_TIME, i);
+       if (i == MAX_IOPAD_LATCH_TIME)
+               pr_warn("PRM: I/O chain clock line assertion timed out\n");
+
+       /* Trigger WUCLKIN disable */
+       omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK, 0x0,
+                                   OMAP4430_PRM_DEVICE_INST,
+                                   OMAP4_PRM_IO_PMCTRL_OFFSET);
+       omap_test_timeout(
+               (((omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+                                          OMAP4_PRM_IO_PMCTRL_OFFSET) &
+                  OMAP4430_WUCLK_STATUS_MASK) >>
+                 OMAP4430_WUCLK_STATUS_SHIFT) == 0),
+               MAX_IOPAD_LATCH_TIME, i);
+       if (i == MAX_IOPAD_LATCH_TIME)
+               pr_warn("PRM: I/O chain clock line deassertion timed out\n");
+
+       return;
+}
+
+/**
+ * omap44xx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches
+ *
+ * Activates the I/O wakeup event latches and allows events logged by
+ * those latches to signal a wakeup event to the PRCM.  For I/O wakeups
+ * to occur, WAKEUPENABLE bits must be set in the pad mux registers, and
+ * omap44xx_prm_reconfigure_io_chain() must be called.  No return value.
+ */
+static void __init omap44xx_prm_enable_io_wakeup(void)
+{
+       omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK,
+                                   OMAP4430_GLOBAL_WUEN_MASK,
+                                   OMAP4430_PRM_DEVICE_INST,
+                                   OMAP4_PRM_IO_PMCTRL_OFFSET);
+}
+
 static int __init omap4xxx_prcm_init(void)
 {
-       if (cpu_is_omap44xx())
+       if (cpu_is_omap44xx()) {
+               omap44xx_prm_enable_io_wakeup();
                return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup);
+       }
        return 0;
 }
 subsys_initcall(omap4xxx_prcm_init);
index 7978092946db5a64ec37e4c66d7f992267ba2914..ee72ae6bd8c961350be2ebb343a027f6d1f4fddf 100644 (file)
@@ -763,6 +763,8 @@ extern u32 omap4_prm_vcvp_read(u8 offset);
 extern void omap4_prm_vcvp_write(u32 val, u8 offset);
 extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
 
+extern void omap44xx_prm_reconfigure_io_chain(void);
+
 /* PRM interrupt-related functions */
 extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
 extern void omap44xx_prm_ocp_barrier(void);