Skip to contentSkip to conversation

ARM: OMAP3+: IO daisy chain support fixes

PATCH Superseded Tero Kristo 4 participants 30 messages Mar 6, 2012 – Jun 22, 2012

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

v5 cover ARM: OMAP3+: IO daisy chain support fixes

Hi,

Changes compared to previous version:

- patch2:
* fixed the timeout for waiting for ST_IO_CHAIN == 1
* added clear for ST_IO_CHAIN bit (as per spec + implementation in patch 1)
* replaced the timeout at the end of function with a simple register readback (timing out on a register value that we are clearing does not make that much sense, the bit is cleared the very first time CPU manages to read it)
- patch5:
* added spinlock for protecting io_chain_trigger operation

Tested on omap3 beagle + omap4 blaze. Also did measurements for the cost of IO chain trigger operation with ARM performance counters:

- omap3 approx 7...8us
- omap4 approx 2...4us

-Tero

#1 lore raw

PATCH v5 1/6 ARM: OMAP3 PM: correct enable/disable of daisy io chain

From: Mohan V <[email protected]>

Currently the enabling and disabling of IO Daisy chain is not according to the TRM. The below steps are followed to enable/ disable the IO chain according to the "Sec 3.5.7.2.2 I/O Wake-Up Mechanism" in OMAP3630 Public TRM[1].

Steps to enable IO chain:
[a] Set PM_WKEN_WKUP.EN_IO bit
[b] Set the PM_WKEN_WKUP.EN_IO_CHAIN bit
[c] Poll for PM_WKST_WKUP.ST_IO_CHAIN.
[d] When ST_IO_CHAIN bit set to 1, clear PM_WKEN_WKUP.EN_IO_CHAIN
[e] Clear ST_IO_CHAIN bit.

Steps to disable IO chain:
[a] Clear PM_WKEN_WKUP.EN_IO_CHAIN bit
[b] Clear PM_WKEN_WKUP.EN_IO bit
[c] Clear PM_WKST_WKUP.ST_IO bit by writing 1 to it.

Step [e] & [c] in each case can be skipped, as these are handled by the PRCM interrupt handler later.

[1] http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vV.zip

---
 arch/arm/mach-omap2/pm34xx.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)
arch/arm/mach-omap2/pm34xx.c +4 -3
index fc69875..b0821a8 100644
@@ -94,16 +94,17 @@ static void omap3_enable_io_chain(void)
 	/* 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) &
+	while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
 		 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);
 	}
+	omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
+			PM_WKEN);
+
 }
 
 static void omap3_disable_io_chain(void)
Signature · 1 line
1.7.4.1
maintainer
#2 lore raw

PATCH v5 1/6 ARM: OMAP3 PM: correct enable/disable of daisy io chain

Hi

Quoted 19 lines · Tero Kristo

From: Mohan V <[email protected]>

Currently the enabling and disabling of IO Daisy chain is not according to the TRM. The below steps are followed to enable/ disable the IO chain according to the "Sec 3.5.7.2.2 I/O Wake-Up Mechanism" in OMAP3630 Public TRM[1].

Steps to enable IO chain:
[a] Set PM_WKEN_WKUP.EN_IO bit
[b] Set the PM_WKEN_WKUP.EN_IO_CHAIN bit
[c] Poll for PM_WKST_WKUP.ST_IO_CHAIN.
[d] When ST_IO_CHAIN bit set to 1, clear PM_WKEN_WKUP.EN_IO_CHAIN
[e] Clear ST_IO_CHAIN bit.

Steps to disable IO chain:
[a] Clear PM_WKEN_WKUP.EN_IO_CHAIN bit
[b] Clear PM_WKEN_WKUP.EN_IO bit
[c] Clear PM_WKST_WKUP.ST_IO bit by writing 1 to it.

Quoted 8 lines

Step [e] & [c] in each case can be skipped, as these are handled by the PRCM interrupt handler later.

[1] http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vV.zip

I modified the commit message to better reflect the reality of what's in the TRM. Updated version is below.

- Paul

From: Mohan V <[email protected]>
Date: Fri, 2 Mar 2012 17:17:50 +0200
Subject: [PATCH 1/6] ARM: OMAP3: PM: correct enable/disable of daisy io chain

Currently the enabling and disabling of IO Daisy chain is not according to the TRM. The below steps are followed to enable/ disable the IO chain, based loosely on the "Sec 3.5.7.2.2 I/O Wake-Up Mechanism" section in OMAP3630 Public TRM[1].

Steps to enable IO chain:
[a] Set PM_WKEN_WKUP.EN_IO bit
[b] Set the PM_WKEN_WKUP.EN_IO_CHAIN bit
[c] Poll for PM_WKST_WKUP.ST_IO_CHAIN.
[d] When ST_IO_CHAIN bit set to 1, clear PM_WKEN_WKUP.EN_IO_CHAIN
[e] Clear ST_IO_CHAIN bit.

Steps to disable IO chain:
[a] Clear PM_WKEN_WKUP.EN_IO_CHAIN bit
[b] Clear PM_WKEN_WKUP.EN_IO bit
[c] Clear PM_WKST_WKUP.ST_IO bit by writing 1 to it.

Step [e] & [c] in each case can be skipped, as these are handled by the PRCM interrupt handler later.

[1] http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vV.zip

[paul at pwsan.com: modified commit message to clarify that these steps are
based loosely on the TRM section, rather than documented exactly]

---
 arch/arm/mach-omap2/pm34xx.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)
arch/arm/mach-omap2/pm34xx.c +4 -3
index fc69875..b0821a8 100644
@@ -94,16 +94,17 @@ static void omap3_enable_io_chain(void)
 	/* 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) &
+	while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
 		 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);
 	}
+	omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
+			PM_WKEN);
+
 }
 
 static void omap3_disable_io_chain(void)
Signature · 1 line
1.7.9.1
#3 lore raw

PATCH v5 2/6 ARM: OMAP3 PM: Move IO Daisychain function to omap3 prm file

In reply to Tero Kristo

From: Vishwanath BS <[email protected]>

Since IO Daisychain modifies only PRM registers, it makes sense to move it to PRM File. Also changed the timeout value for IO chain enable to 100us and added a wait for status disable at the end.

---
 arch/arm/mach-omap2/pm34xx.c       |   30 +----------------------------
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   37 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.h |   14 +++++++++++++
 3 files changed, 52 insertions(+), 29 deletions(-)
arch/arm/mach-omap2/pm34xx.c +1 -29
index b0821a8..e97ec3f 100644
@@ -85,34 +85,6 @@ static inline void omap3_per_restore_context(void)
 	omap_gpio_restore_context();
 }
 
-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_WKST) &
-		 OMAP3430_ST_IO_CHAIN_MASK)) {
-		timeout++;
-		if (timeout > 1000) {
-			pr_err("Wake up daisy chain activation failed.\n");
-			return;
-		}
-	}
-	omap2_prm_clear_mod_reg_bits(OMAP3430_EN_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();
@@ -324,7 +296,7 @@ void omap_sram_idle(void)
 	     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();
+			omap3_trigger_io_chain();
 	}
 
 	pwrdm_pre_transition();
arch/arm/mach-omap2/prm2xxx_3xxx.c +37 -0
index 9ce7654..2f45b96 100644
@@ -301,6 +301,43 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 				OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 }
 
+/*
+ * Maximum time(us) it takes to output the signal WUCLKOUT of the last pad of
+ * the I/O ring after asserting WUCLKIN high
+ */
+#define MAX_IOPAD_LATCH_TIME 100
+
+/* OMAP3 Daisychain enable sequence */
+void omap3_trigger_io_chain(void)
+{
+	int i = 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);
+
+	omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
+			  OMAP3430_ST_IO_CHAIN_MASK,
+			  MAX_IOPAD_LATCH_TIME, i);
+
+	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);
+}
+
+/* OMAP3 Daisychain disable sequence */
+void omap3_disable_io_chain(void)
+{
+	if (omap_rev() >= OMAP3430_REV_ES3_1)
+		omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK,
+					     WKUP_MOD, PM_WKEN);
+}
+
 static int __init omap3xxx_prcm_init(void)
 {
 	if (cpu_is_omap34xx())
arch/arm/mach-omap2/prm2xxx_3xxx.h +14 -0
index 70ac2a1..15973aa 100644
@@ -289,6 +289,18 @@ static inline int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift,
 		"not suppose to be used on omap4\n");
 	return 0;
 }
+static inline void omap3_trigger_io_chain(void)
+{
+	WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+		"not suppose to be used on omap4\n");
+	return 0;
+}
+static inline void omap3_disable_io_chain(void)
+{
+	WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+		"not suppose to be used on omap4\n");
+	return 0;
+}
 #else
 /* Power/reset management domain register get/set */
 extern u32 omap2_prm_read_mod_reg(s16 module, u16 idx);
@@ -302,6 +314,8 @@ extern u32 omap2_prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask);
 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);
+extern void omap3_trigger_io_chain(void);
+extern void omap3_disable_io_chain(void);
 
 /* OMAP3-specific VP functions */
 u32 omap3_prm_vp_check_txdone(u8 vp_id);
Signature · 1 line
1.7.4.1
#4 lore raw

PATCH v5 2/6 ARM: OMAP3 PM: Move IO Daisychain function to omap3 prm file

Quoted 5 lines · Tero Kristo

From: Vishwanath BS <[email protected]>

Since IO Daisychain modifies only PRM registers, it makes sense to move it to PRM File. Also changed the timeout value for IO chain enable to 100us and added a wait for status disable at the end.

[...]

Quoted 17 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +9 -0
index 9ce7654..2f45b96 100644
@@ -301,6 +301,43 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 				OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 }
 
+/*
+ * Maximum time(us) it takes to output the signal WUCLKOUT of the last pad of
+ * the I/O ring after asserting WUCLKIN high
+ */
+#define MAX_IOPAD_LATCH_TIME 100
+
+/* OMAP3 Daisychain enable sequence */
+void omap3_trigger_io_chain(void)
+{

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 322

Quoted 10 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +10 -0
+	int i = 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);
+
+	omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
+			  OMAP3430_ST_IO_CHAIN_MASK,
+			  MAX_IOPAD_LATCH_TIME, i);

probably a nitpick, but would'nt you like to keep the OMAP3 and OMAP4 style consistent?

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 330

Quoted 8 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +8 -0
+
+	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);

in the previous iteration it had:
omap_test_timeout(((omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) & OMAP3430_ST_IO_CHAIN_MASK) == 0), MAX_IOPAD_LATCH_TIME,
i);
gone now?

Signature · 2 lines
Regards,
Nishanth Menon
#5 lore raw

PATCH v5 2/6 ARM: OMAP3 PM: Move IO Daisychain function to omap3 prm file

Quoted 36 lines · Nishanth Menon
Quoted 5 lines · Tero Kristo

From: Vishwanath BS <[email protected]>

Since IO Daisychain modifies only PRM registers, it makes sense to move it to PRM File. Also changed the timeout value for IO chain enable to 100us and added a wait for status disable at the end.

[...]

Quoted 17 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +9 -0
index 9ce7654..2f45b96 100644
@@ -301,6 +301,43 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 				OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 }
 
+/*
+ * Maximum time(us) it takes to output the signal WUCLKOUT of the last pad of
+ * the I/O ring after asserting WUCLKIN high
+ */
+#define MAX_IOPAD_LATCH_TIME 100
+
+/* OMAP3 Daisychain enable sequence */
+void omap3_trigger_io_chain(void)
+{

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 322

Quoted 10 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +10 -0
+	int i = 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);
+
+	omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
+			  OMAP3430_ST_IO_CHAIN_MASK,
+			  MAX_IOPAD_LATCH_TIME, i);

probably a nitpick, but would'nt you like to keep the OMAP3 and OMAP4 style consistent?

Quoted 14 lines

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 330

Quoted 8 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +8 -0
+
+	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);

in the previous iteration it had:
omap_test_timeout(((omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) & OMAP3430_ST_IO_CHAIN_MASK) == 0), MAX_IOPAD_LATCH_TIME,
i);
gone now?

Yea, according to TRM this is not what should be done on omap3, apparently one of the comments I received was in error for one of the previous versions. Also, the implementation in patch 1 is closer to what is here now.

-Tero

maintainer
#6 lore raw

PATCH v5 2/6 ARM: OMAP3 PM: Move IO Daisychain function to omap3 prm file

In reply to Tero Kristo

cc Rajendra

Hi Tero,

a few comments:

On Tue, 6 Mar 2012, Tero Kristo wrote:

...

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 318

Quoted 9 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +9 -0
+/* OMAP3 Daisychain enable sequence */
+void omap3_trigger_io_chain(void)
+{
+	int i = 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);

Looks like this barrier shouldn't be needed? The write is immediately followed by another read from the same IP block.

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 331

Quoted 13 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +13 -0
+
+	omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
+			  OMAP3430_ST_IO_CHAIN_MASK,
+			  MAX_IOPAD_LATCH_TIME, i);
+
+	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);
+}

I see that you removed the second timeout test from this code, but not from the OMAP4 version. Any reason why? Seems like if the second timeout can be removed from one, then it can also be removed from the other?

- Paul

#7 lore raw

PATCH v5 2/6 ARM: OMAP3 PM: Move IO Daisychain function to omap3 prm file

Quoted 32 lines · Paul Walmsley

cc Rajendra

Hi Tero,

a few comments:

On Tue, 6 Mar 2012, Tero Kristo wrote:

...

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 318

Quoted 9 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +9 -0
+/* OMAP3 Daisychain enable sequence */
+void omap3_trigger_io_chain(void)
+{
+	int i = 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);

Looks like this barrier shouldn't be needed? The write is immediately followed by another read from the same IP block.

Quoted 9 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +9 -0
+
+	omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST)&
+			  OMAP3430_ST_IO_CHAIN_MASK,
+			  MAX_IOPAD_LATCH_TIME, i);
+
+	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,
Quoted 8 lines

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 331

Quoted 4 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +4 -0
+				     PM_WKST);
+
+	omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST);
+}

I see that you removed the second timeout test from this code, but not from the OMAP4 version. Any reason why? Seems like if the second timeout can be removed from one, then it can also be removed from the other?

Actually FWIK, its nteeded in both OMAP3 and OMAP4. The OMAP3 documentation does no mention about it. but that is just bad documentation.

Quoted 3 lines

- Paul

#8 lore raw

PATCH v5 2/6 ARM: OMAP3 PM: Move IO Daisychain function to omap3 prm file

Quoted 11 lines · Rajendra Nayak
Quoted 10 lines · Paul Walmsley

cc Rajendra

Hi Tero,

a few comments:

On Tue, 6 Mar 2012, Tero Kristo wrote:

...

Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +4 -0
+/* OMAP3 Daisychain enable sequence */
+void omap3_trigger_io_chain(void)
+{
+	int i = 0;
Quoted 8 lines

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 318

Quoted 5 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +5 -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);

Looks like this barrier shouldn't be needed? The write is immediately followed by another read from the same IP block.

I think you are right here, this can be dropped.

Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +9 -0
+
+	omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST)&
+			  OMAP3430_ST_IO_CHAIN_MASK,
+			  MAX_IOPAD_LATCH_TIME, i);
+
+	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,
Quoted 8 lines

arch/arm/mach-omap2/prm2xxx_3xxx.c void omap3xxx_prm_restore_irqen(u32 *saved_mask) · line 331

Quoted 4 lines
arch/arm/mach-omap2/prm2xxx_3xxx.c +4 -0
+				     PM_WKST);
+
+	omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST);
+}

I see that you removed the second timeout test from this code, but not from the OMAP4 version. Any reason why? Seems like if the second timeout can be removed from one, then it can also be removed from the other?

Quoted 3 lines

Actually FWIK, its nteeded in both OMAP3 and OMAP4. The OMAP3 documentation does no mention about it. but that is just bad documentation.

Both documentation and actual functionality appears to be different for OMAP3 / OMAP4. The status bit on OMAP3 is read / write, and writing 1 to it clears it. On OMAP4, it is read only and both values 0 / 1 indicate something has happened. On OMAP3 the bit must be cleared by writing 1 to it, otherwise it remains high indefinitely and will break all the subsequent trigger calls. Also, clearing EN_IO_CHAIN on OMAP3 does not appear to trigger any activity that would change the status of ST_IO_CHAIN, so there is nothing to poll at the end.

Here is a sample trace I just generated for the trigger on OMAP3:

[    7.707824] omap3_trigger_io_chain(1): PM_WKST=00000000
[    7.707855] omap3_trigger_io_chain(2): PM_WKST=00000000
[    7.707855] omap3_trigger_io_chain(3): PM_WKST=00010000
[    7.707885] omap3_trigger_io_chain(4): PM_WKST=00000000
[    7.707977] omap3_trigger_io_chain(5): PM_WKST=00000000

1 = enter trigger function
2 = just after enabling io chain
3 = just after first poll loop
4 = just after clear of io status and disabling of io chain 5 = after udelay(100) from last event (you can see the status bit never raises)

So, you can see that there is no change in the status bit between 4...5, so there is no point for polling anything there. I even tried changing the clear of IO status and disabling of IO chain to see if it had any impact on this result but no. The main point is that we must clear the status bit at #4, and thus polling for it to change at #5 makes no sense. We just need to force the register writes to PRCM by doing some access to the IP block.

Looking at similar trace on omap4:

[    8.097503] omap4_trigger_io_chain(1): IO=00010020
[    8.097503] omap4_trigger_io_chain(2): IO=00010320
[    8.097534] omap4_trigger_io_chain(3): IO=00010320
[    8.097534] omap4_trigger_io_chain(4): IO=00010020
[    8.097534] omap4_trigger_io_chain(5): IO=00010020

1 = enter function
2 = just after enabling WUCLK_CTRL
3 = just after poll
4 = just after disabling WUCLK_CTRL
5 = just after poll

Well, the status bit follows the state of the WUCLK_CTRL, but there is no time to actually poll the registers it seems, their state has already changed when the value from first read arrives back as the register access itself is so slow. But... we are not manually clearing the status bit, thus polling kind of makes sense (and it might make more sense if some future version of PRCM would allow faster register access.)

I also did both of these tests by caching the register values to memory (no immediate printks to avoid delays) but the results are still the same.

-Tero

#9 lore raw

PATCH v5 2/6 ARM: OMAP3 PM: Move IO Daisychain function to omap3 prm file

Hi Tero,

Quoted 24 lines · Tero Kristo
Quoted 7 lines
Quoted 7 lines

I see that you removed the second timeout test from this code, but not

Quoted 2 lines
Quoted 2 lines

from the OMAP4 version. Any reason why? Seems like if the second timeout can be removed from one, then it can also be removed from the other?

Actually FWIK, its nteeded in both OMAP3 and OMAP4. The OMAP3 documentation does no mention about it. but that is just bad documentation.

Both documentation and actual functionality appears to be different for OMAP3 / OMAP4. The status bit on OMAP3 is read / write, and writing 1 to it clears it. On OMAP4, it is read only and both values 0 / 1 indicate something has happened. On OMAP3 the bit must be cleared by writing 1 to it, otherwise it remains high indefinitely and will break all the subsequent trigger calls. Also, clearing EN_IO_CHAIN on OMAP3 does not appear to trigger any activity that would change the status of ST_IO_CHAIN, so there is nothing to poll at the end.

Here is a sample trace I just generated for the trigger on OMAP3:

[    7.707824] omap3_trigger_io_chain(1): PM_WKST=00000000
[    7.707855] omap3_trigger_io_chain(2): PM_WKST=00000000
[    7.707855] omap3_trigger_io_chain(3): PM_WKST=00010000
[    7.707885] omap3_trigger_io_chain(4): PM_WKST=00000000
[    7.707977] omap3_trigger_io_chain(5): PM_WKST=00000000
Quoted 6 lines

1 = enter trigger function
2 = just after enabling io chain
3 = just after first poll loop
4 = just after clear of io status and disabling of io chain 5 = after udelay(100) from last event (you can see the status bit never raises)

Ok, I guess then the omap3 and omap4 implementations are indeed different and should be handled differently. Thanks for the explanation.

regards,
Rajendra

Quoted 35 lines

So, you can see that there is no change in the status bit between 4...5, so there is no point for polling anything there. I even tried changing the clear of IO status and disabling of IO chain to see if it had any impact on this result but no. The main point is that we must clear the status bit at #4, and thus polling for it to change at #5 makes no sense. We just need to force the register writes to PRCM by doing some access to the IP block.

Looking at similar trace on omap4:

[    8.097503] omap4_trigger_io_chain(1): IO=00010020
[    8.097503] omap4_trigger_io_chain(2): IO=00010320
[    8.097534] omap4_trigger_io_chain(3): IO=00010320
[    8.097534] omap4_trigger_io_chain(4): IO=00010020
[    8.097534] omap4_trigger_io_chain(5): IO=00010020

1 = enter function
2 = just after enabling WUCLK_CTRL
3 = just after poll
4 = just after disabling WUCLK_CTRL
5 = just after poll

Well, the status bit follows the state of the WUCLK_CTRL, but there is no time to actually poll the registers it seems, their state has already changed when the value from first read arrives back as the register access itself is so slow. But... we are not manually clearing the status bit, thus polling kind of makes sense (and it might make more sense if some future version of PRCM would allow faster register access.)

I also did both of these tests by caching the register values to memory (no immediate printks to avoid delays) but the results are still the same.

maintainer
#10 lore raw

PATCH v5 2/6 ARM: OMAP3 PM: Move IO Daisychain function to omap3 prm file

In reply to Tero Kristo

Hi

Quoted 8 lines · Tero Kristo

From: Vishwanath BS <[email protected]>

Since IO Daisychain modifies only PRM registers, it makes sense to move it to PRM File. Also changed the timeout value for IO chain enable to 100us and added a wait for status disable at the end.

This patch has been updated in a few different ways, described below. Please let me know if you're okay with it.

- Paul

From: Vishwanath BS <[email protected]>
Date: Fri, 2 Mar 2012 17:17:51 +0200
Subject: [PATCH 2/6] ARM: OMAP3: PM: Move IO Daisychain function to omap3 prm
file

Since IO Daisychain modifies only PRM registers, it makes sense to move it to PRM File. Also changed the timeout value for IO chain enable to 100us and added a wait for status disable at the end.

Thanks to Nishanth Menon <[email protected]> for contributing a fix to the timeout code waiting for WUCLKOUT to go high.

[paul at pwsan.com: renamed omap3_trigger_io_chain() to better describe the
end result and to match other PRM functions; removed omap3_disable_io_chain(); moved MAX_IOPAD_LATCH_TIME to prcm-common as it will also be used by the OMAP4 code; removed unnecessary barrier; added kerneldoc; added credit for fix from Nishanth]

---
 arch/arm/mach-omap2/pm34xx.c       |   35 ++---------------------------------
 arch/arm/mach-omap2/prcm-common.h  |    8 ++++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   31 +++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.h |    2 ++
 4 files changed, 43 insertions(+), 33 deletions(-)
arch/arm/mach-omap2/pm34xx.c +2 -33
index b0821a8..378a0de 100644
@@ -85,34 +85,6 @@ static inline void omap3_per_restore_context(void)
 	omap_gpio_restore_context();
 }
 
-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_WKST) &
-		 OMAP3430_ST_IO_CHAIN_MASK)) {
-		timeout++;
-		if (timeout > 1000) {
-			pr_err("Wake up daisy chain activation failed.\n");
-			return;
-		}
-	}
-	omap2_prm_clear_mod_reg_bits(OMAP3430_EN_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();
@@ -324,7 +296,7 @@ void omap_sram_idle(void)
 	     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();
+			omap3_reconfigure_io_chain();
 	}
 
 	pwrdm_pre_transition();
@@ -407,12 +379,9 @@ void omap_sram_idle(void)
 	/* Disable IO-PAD and IO-CHAIN wakeup */
 	if (omap3_has_io_wakeup() &&
 	    (per_next_state < PWRDM_POWER_ON ||
-	     core_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]);
 }
arch/arm/mach-omap2/prcm-common.h +8 -0
index 5aa5435..f057c15 100644
@@ -406,6 +406,14 @@
  */
 #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;
arch/arm/mach-omap2/prm2xxx_3xxx.c +31 -0
index 9ce7654..7d62bd6 100644
@@ -301,6 +301,37 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 				OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 }
 
+/**
+ * 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);
+}
+
 static int __init omap3xxx_prcm_init(void)
 {
 	if (cpu_is_omap34xx())
arch/arm/mach-omap2/prm2xxx_3xxx.h +2 -0
index 70ac2a1..1ba3d65 100644
@@ -315,6 +315,8 @@ 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);
Signature · 1 line
1.7.9.1
#11 lore raw

PATCH v5 3/6 ARM: OMAP4 PM: Add IO Daisychain support

In reply to Tero Kristo

From: Rajendra Nayak <[email protected]>

IO daisychain is a mechanism that allows individual IO pads to generate wakeup events on their own based on a switch of an input signal level. This allows the hardware module behind the pad to be powered down, but still have device level capability to detect IO events, and once this happens the module can be powered back up to resume IO. See section 3.9.4 in OMAP4430 Public TRM for details.

---
 arch/arm/mach-omap2/prm44xx.c |   41 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm44xx.h |    1 +
 2 files changed, 42 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/prm44xx.c +41 -0
index a37bfd4..caa5e0f 100644
@@ -231,6 +231,47 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask)
 				 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
 }
 
+/*
+ * Maximum time(us) it takes to output the signal WUCLKOUT of the last pad of
+ * the I/O ring after asserting WUCLKIN high
+ */
+#define MAX_IOPAD_LATCH_TIME 100
+
+/* OMAP4 IO Daisychain trigger sequence */
+void omap4_trigger_io_chain(void)
+{
+	int i = 0;
+
+	/* Enable GLOBAL_WUEN */
+	if (!(omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+		OMAP4_PRM_IO_PMCTRL_OFFSET) & OMAP4430_GLOBAL_WUEN_MASK))
+		omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK,
+			OMAP4430_GLOBAL_WUEN_MASK, OMAP4430_PRM_DEVICE_INST,
+			OMAP4_PRM_IO_PMCTRL_OFFSET);
+
+	/* 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);
+
+	/* 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);
+	return;
+}
+
 static int __init omap4xxx_prcm_init(void)
 {
 	if (cpu_is_omap44xx())
arch/arm/mach-omap2/prm44xx.h +1 -0
index 7978092..54a057e 100644
@@ -762,6 +762,7 @@ void omap4_prm_vp_clear_txdone(u8 vp_id);
 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 omap4_trigger_io_chain(void);
 
 /* PRM interrupt-related functions */
 extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
Signature · 1 line
1.7.4.1
maintainer
#12 lore raw

PATCH v5 3/6 ARM: OMAP4 PM: Add IO Daisychain support

Hi

Quoted 9 lines · Tero Kristo

From: Rajendra Nayak <[email protected]>

IO daisychain is a mechanism that allows individual IO pads to generate wakeup events on their own based on a switch of an input signal level. This allows the hardware module behind the pad to be powered down, but still have device level capability to detect IO events, and once this happens the module can be powered back up to resume IO. See section 3.9.4 in OMAP4430 Public TRM for details.

Quoted 3 lines

Here's an updated version of this patch. Please let me know if you think we should remove the poll on the WUCLKOUT line to conform with the change that Tero made to the OMAP3 version.

- Paul

From: Rajendra Nayak <[email protected]>
Date: Fri, 2 Mar 2012 17:17:52 +0200
Subject: [PATCH 3/6] ARM: OMAP4: PRM: Add IO Daisychain support

IO daisychain is a mechanism that allows individual IO pads to generate wakeup events on their own based on a switch of an input signal level. This allows the hardware module behind the pad to be powered down, but still have device level capability to detect IO events, and once this happens the module can be powered back up to resume IO. See section 3.9.4 in OMAP4430 Public TRM for details.

[paul at pwsan.com: removed MAX_IOPAD_LATCH_TIME declaration; renamed
omap4_trigger_io_chain() to conform to other PRM function names; added kerneldoc]

---
 arch/arm/mach-omap2/prm44xx.c |   48 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm44xx.h |    2 +
 2 files changed, 50 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/prm44xx.c +48 -0
index a1d6154..5868a12 100644
@@ -231,6 +231,54 @@ 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;
+
+	/* Enable GLOBAL_WUEN */
+	if (!(omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+		OMAP4_PRM_IO_PMCTRL_OFFSET) & OMAP4430_GLOBAL_WUEN_MASK))
+		omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK,
+			OMAP4430_GLOBAL_WUEN_MASK, OMAP4430_PRM_DEVICE_INST,
+			OMAP4_PRM_IO_PMCTRL_OFFSET);
+
+	/* 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;
+}
+
 static int __init omap4xxx_prcm_init(void)
 {
 	if (cpu_is_omap44xx())
arch/arm/mach-omap2/prm44xx.h +2 -0
index 7978092..ee72ae6 100644
@@ -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);
Signature · 1 line
1.7.9.1
#13 lore raw

PATCH v5 3/6 ARM: OMAP4 PM: Add IO Daisychain support

Quoted 13 lines · Paul Walmsley

Hi

Quoted 9 lines · Tero Kristo

From: Rajendra Nayak<[email protected]>

IO daisychain is a mechanism that allows individual IO pads to generate wakeup events on their own based on a switch of an input signal level. This allows the hardware module behind the pad to be powered down, but still have device level capability to detect IO events, and once this happens the module can be powered back up to resume IO. See section 3.9.4 in OMAP4430 Public TRM for details.

Quoted 7 lines
Quoted 3 lines

Here's an updated version of this patch. Please let me know if you think we should remove the poll on the WUCLKOUT line to conform with the change that Tero made to the OMAP3 version.

Thanks Paul, for the updates patch. Just one comment below..

Quoted 15 lines

- Paul

From: Rajendra Nayak<[email protected]>
Date: Fri, 2 Mar 2012 17:17:52 +0200
Subject: [PATCH 3/6] ARM: OMAP4: PRM: Add IO Daisychain support

IO daisychain is a mechanism that allows individual IO pads to generate wakeup events on their own based on a switch of an input signal level. This allows the hardware module behind the pad to be powered down, but still have device level capability to detect IO events, and once this happens the module can be powered back up to resume IO. See section 3.9.4 in OMAP4430 Public TRM for details.

Quoted 2 lines

documentation.

Quoted 2 lines

[paul at pwsan.com: removed MAX_IOPAD_LATCH_TIME declaration; renamed

But the code below still seems to use it. Is it now defined in some common header so the same value is used in omap3 and omap4?

regards,
Rajendra

Quoted 80 lines

omap4_trigger_io_chain() to conform to other PRM function names; added kerneldoc]

---
  arch/arm/mach-omap2/prm44xx.c |   48 +++++++++++++++++++++++++++++++++++++++++
  arch/arm/mach-omap2/prm44xx.h |    2 +
  2 files changed, 50 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/prm44xx.c +48 -0
index a1d6154..5868a12 100644
@@ -231,6 +231,54 @@ 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;
+
+	/* Enable GLOBAL_WUEN */
+	if (!(omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+		OMAP4_PRM_IO_PMCTRL_OFFSET)&  OMAP4430_GLOBAL_WUEN_MASK))
+		omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK,
+			OMAP4430_GLOBAL_WUEN_MASK, OMAP4430_PRM_DEVICE_INST,
+			OMAP4_PRM_IO_PMCTRL_OFFSET);
+
+	/* 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;
+}
+
  static int __init omap4xxx_prcm_init(void)
  {
  	if (cpu_is_omap44xx())
arch/arm/mach-omap2/prm44xx.h +2 -0
index 7978092..ee72ae6 100644
@@ -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);
#14 lore raw

PATCH v5 3/6 ARM: OMAP4 PM: Add IO Daisychain support

Quoted 14 lines · Rajendra Nayak
Quoted 12 lines

From: Rajendra Nayak<[email protected]>
Date: Fri, 2 Mar 2012 17:17:52 +0200
Subject: [PATCH 3/6] ARM: OMAP4: PRM: Add IO Daisychain support

IO daisychain is a mechanism that allows individual IO pads to generate wakeup events on their own based on a switch of an input signal level. This allows the hardware module behind the pad to be powered down, but still have device level capability to detect IO events, and once this happens the module can be powered back up to resume IO. See section 3.9.4 in OMAP4430 Public TRM for details.

Quoted 2 lines
Quoted 7 lines

documentation.

Quoted 2 lines

[paul at pwsan.com: removed MAX_IOPAD_LATCH_TIME declaration; renamed

But the code below still seems to use it. Is it now defined in some common header so the same value is used in omap3 and omap4?

never mind, just saw the other updates from you. The patches look good to me, except for the comment I add to add the second timeout back in omap3.

Tero, was there a specific reason you got rid of it for omap3 in your latest patch-set?

maintainer
#15 lore raw

PATCH v5 3/6 ARM: OMAP4 PM: Add IO Daisychain support

In reply to Rajendra Nayak
Quoted 5 lines · Rajendra Nayak
Quoted 2 lines

[paul at pwsan.com: removed MAX_IOPAD_LATCH_TIME declaration; renamed

But the code below still seems to use it. Is it now defined in some common header so the same value is used in omap3 and omap4?

Yes, I put it into prcm-common.h in the previous patch that added it for OMAP3. I'll update that comment to clarify.

- Paul

#16 lore raw

PATCH v5 4/6 ARM: OMAP3+: PRM: Enable IO wake up

In reply to Tero Kristo

Enable IO Wake up for OMAP3/4 as part of PRM Init. Currently this has been managed in cpuidle path which is not the right place. Subsequent patch will remove IO Daisy chain handling in cpuidle path once daisy chain is handled as part of hwmod mux. This patch also moves the OMAP4 IO wakeup enable code from the trigger function to init time setup.

---
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   11 ++++++++++-
 arch/arm/mach-omap2/prm44xx.c      |   18 ++++++++++--------
 2 files changed, 20 insertions(+), 9 deletions(-)
arch/arm/mach-omap2/prm2xxx_3xxx.c +10 -1
index 2f45b96..f0179f6 100644
@@ -338,10 +338,19 @@ void omap3_disable_io_chain(void)
 					     WKUP_MOD, PM_WKEN);
 }
 
+static void __init omap3_enable_io_wakeup(void)
+{
+	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())
+	if (cpu_is_omap34xx()) {
+		omap3_enable_io_wakeup();
 		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
+	}
 	return 0;
 }
 subsys_initcall(omap3xxx_prcm_init);
arch/arm/mach-omap2/prm44xx.c +10 -8
index caa5e0f..4ce6f08 100644
@@ -242,13 +242,6 @@ void omap4_trigger_io_chain(void)
 {
 	int i = 0;
 
-	/* Enable GLOBAL_WUEN */
-	if (!(omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
-		OMAP4_PRM_IO_PMCTRL_OFFSET) & OMAP4430_GLOBAL_WUEN_MASK))
-		omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK,
-			OMAP4430_GLOBAL_WUEN_MASK, OMAP4430_PRM_DEVICE_INST,
-			OMAP4_PRM_IO_PMCTRL_OFFSET);
-
 	/* Trigger WUCLKIN enable */
 	omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK,
 			OMAP4430_WUCLK_CTRL_MASK, OMAP4430_PRM_DEVICE_INST,
@@ -272,10 +265,19 @@ void omap4_trigger_io_chain(void)
 	return;
 }
 
+static void __init omap4_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()) {
+		omap4_enable_io_wakeup();
 		return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup);
+	}
 	return 0;
 }
 subsys_initcall(omap4xxx_prcm_init);
Signature · 1 line
1.7.4.1
maintainer
#17 lore raw

PATCH v5 4/6 ARM: OMAP3+: PRM: Enable IO wake up

Quoted 8 lines · Tero Kristo

Enable IO Wake up for OMAP3/4 as part of PRM Init. Currently this has been managed in cpuidle path which is not the right place. Subsequent patch will remove IO Daisy chain handling in cpuidle path once daisy chain is handled as part of hwmod mux. This patch also moves the OMAP4 IO wakeup enable code from the trigger function to init time setup.

Here's an updated version of this patch. Please let me know if you have any comments.

- Paul

From: Tero Kristo <[email protected]>
Date: Fri, 2 Mar 2012 17:17:53 +0200
Subject: [PATCH 4/6] ARM: OMAP3+: PRM: Enable IO wake up

Enable IO Wake up for OMAP3/4 as part of PRM Init. Currently this has been managed in cpuidle path which is not the right place. Subsequent patch will remove IO Daisy chain handling in cpuidle path once daisy chain is handled as part of hwmod mux. This patch also moves the OMAP4 IO wakeup enable code from the trigger function to init time setup.

[paul at pwsan.com: harmonize function names with other PRM functions; add
kerneldoc]

---
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   20 +++++++++++++++++++-
 arch/arm/mach-omap2/prm44xx.c      |   26 ++++++++++++++++++--------
 2 files changed, 37 insertions(+), 9 deletions(-)
arch/arm/mach-omap2/prm2xxx_3xxx.c +19 -1
index 7d62bd6..1471a33 100644
@@ -332,10 +332,28 @@ void omap3xxx_prm_reconfigure_io_chain(void)
 	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)
+{
+	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())
+	if (cpu_is_omap34xx()) {
+		omap3xxx_prm_enable_io_wakeup();
 		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
+	}
 	return 0;
 }
 subsys_initcall(omap3xxx_prcm_init);
arch/arm/mach-omap2/prm44xx.c +18 -8
index 5868a12..af251c7 100644
@@ -244,13 +244,6 @@ void omap44xx_prm_reconfigure_io_chain(void)
 {
 	int i = 0;
 
-	/* Enable GLOBAL_WUEN */
-	if (!(omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
-		OMAP4_PRM_IO_PMCTRL_OFFSET) & OMAP4430_GLOBAL_WUEN_MASK))
-		omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK,
-			OMAP4430_GLOBAL_WUEN_MASK, OMAP4430_PRM_DEVICE_INST,
-			OMAP4_PRM_IO_PMCTRL_OFFSET);
-
 	/* Trigger WUCLKIN enable */
 	omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK,
 			OMAP4430_WUCLK_CTRL_MASK, OMAP4430_PRM_DEVICE_INST,
@@ -279,10 +272,27 @@ void omap44xx_prm_reconfigure_io_chain(void)
 	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);
Signature · 1 line
1.7.9.1
#18 lore raw

PATCH v5 5/6 ARM: OMAP3PLUS PM: Add IO Daisychain support via hwmod mux

In reply to Tero Kristo

From: Vishwanath BS <[email protected]>

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

---
 arch/arm/mach-omap2/omap_hwmod.c |    9 +++++++--
 arch/arm/mach-omap2/pm.c         |   21 +++++++++++++++++++++
 arch/arm/mach-omap2/pm.h         |    1 +
 3 files changed, 29 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/omap_hwmod.c +7 -2
index 5192cab..56adbfb 100644
@@ -152,6 +152,7 @@
 #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
@@ -1535,8 +1536,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);
+		omap_trigger_io_chain();
+	}
 
 	_add_initiator_dep(oh, mpu_oh);
 
@@ -1622,8 +1625,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);
+		omap_trigger_io_chain();
+	}
 
 	oh->_state = _HWMOD_STATE_IDLE;
 
arch/arm/mach-omap2/pm.c +21 -0
index 1881fe9..b7ac0f4 100644
@@ -25,8 +25,12 @@
 #include "clockdomain.h"
 #include "pm.h"
 #include "twl-common.h"
+#include "prm2xxx_3xxx.h"
+#include "prm44xx.h"
 
 static struct omap_device_pm_latency *pm_lats;
+static void (*io_chain_trigger_func) (void);
+static DEFINE_SPINLOCK(io_chain_lock);
 
 static int _init_omap_device(char *name)
 {
@@ -64,6 +68,17 @@ static void omap2_init_processor_devices(void)
 	}
 }
 
+void omap_trigger_io_chain(void)
+{
+	unsigned long flags;
+
+	if (io_chain_trigger_func) {
+		spin_lock_irqsave(&io_chain_lock, flags);
+		io_chain_trigger_func();
+		spin_unlock_irqrestore(&io_chain_lock, flags);
+	}
+}
+
 /* Types of sleep_switch used in omap_set_pwrdm_state */
 #define FORCEWAKEUP_SWITCH	0
 #define LOWPOWERSTATE_SWITCH	1
@@ -221,6 +236,12 @@ static int __init omap2_common_pm_init(void)
 		omap2_init_processor_devices();
 	omap_pm_if_init();
 
+	if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl())
+		io_chain_trigger_func = omap3_trigger_io_chain;
+
+	if (cpu_is_omap44xx())
+		io_chain_trigger_func = omap4_trigger_io_chain;
+
 	return 0;
 }
 postcore_initcall(omap2_common_pm_init);
arch/arm/mach-omap2/pm.h +1 -0
index b737b11..f9dac40 100644
@@ -22,6 +22,7 @@ extern int omap3_can_sleep(void);
 extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
 extern int omap4_idle_init(void);
+extern void omap_trigger_io_chain(void);
 
 #if defined(CONFIG_PM_OPP)
 extern int omap3_opp_init(void);
Signature · 1 line
1.7.4.1
maintainer
#19 lore raw

PATCH v5 5/6 ARM: OMAP3PLUS PM: Add IO Daisychain support via hwmod mux

Hi

Quoted 14 lines · Tero Kristo

From: Vishwanath BS <[email protected]>

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

Quoted 5 lines

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

Here's an updated version of this patch that removes the dependency on mach-omap2/pm.*.

- Paul

From: Vishwanath BS <[email protected]>
Date: Fri, 2 Mar 2012 17:17:54 +0200
Subject: [PATCH 5/6] ARM: OMAP3PLUS: hwmod: reconfigure IO Daisychain during
hwmod mux

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

[paul at pwsan.com: remove dependency on pm.c & pm.h; add kerneldoc]
---
 arch/arm/mach-omap2/omap_hwmod.c |   37 +++++++++++++++++++++++++++++++++++--
 1 files changed, 35 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/omap_hwmod.c +35 -2
index eba6cd3..58a5920 100644
@@ -152,6 +152,7 @@
 #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
@@ -165,6 +166,8 @@ 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);
 
 /* Private functions */
 
@@ -1481,6 +1484,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 *
  *
@@ -1535,8 +1564,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);
 
@@ -1622,8 +1653,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;
 
Signature · 1 line
1.7.9.1
#20 lore raw

PATCH v5 5/6 ARM: OMAP3PLUS PM: Add IO Daisychain support via hwmod mux

In reply to Tero Kristo

Hi,

Quoted 30 lines · Tero Kristo

From: Vishwanath BS<[email protected]>

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

---
  arch/arm/mach-omap2/omap_hwmod.c |    9 +++++++--
  arch/arm/mach-omap2/pm.c         |   21 +++++++++++++++++++++
  arch/arm/mach-omap2/pm.h         |    1 +
  3 files changed, 29 insertions(+), 2 deletions(-)
  /* Types of sleep_switch used in omap_set_pwrdm_state */
  #define FORCEWAKEUP_SWITCH	0
  #define LOWPOWERSTATE_SWITCH	1

arch/arm/mach-omap2/pm.c static int __init omap2_common_pm_init(void) · line 240

Quoted 5 lines
arch/arm/mach-omap2/pm.c +2 -0
@@ -221,6 +236,12 @@ static int __init omap2_common_pm_init(void)
  		omap2_init_processor_devices();
  	omap_pm_if_init();
 
+	if (cpu_is_omap34xx()&&  omap3_has_io_chain_ctrl())
+		io_chain_trigger_func = omap3_trigger_io_chain;

While testing with one of Tero's OMAP4 OFF mode support branches (which also include these patches) I found a OMAP4 standalone build fails here..

CC arch/arm/mach-omap2/omap_hwmod.o
arch/arm/mach-omap2/omap_hwmod.c: In function '_reconfigure_io_chain':
arch/arm/mach-omap2/omap_hwmod.c:1797: error: implicit declaration of function 'omap3xxx_prm_reconfigure_io_chain'
make[1]: *** [arch/arm/mach-omap2/omap_hwmod.o] Error 1
make: *** [arch/arm/mach-omap2] Error 2

regards,
Rajendra

Quoted 19 lines
arch/arm/mach-omap2/pm.c +4 -0
+
+	if (cpu_is_omap44xx())
+		io_chain_trigger_func = omap4_trigger_io_chain;
+
  	return 0;
  }
  postcore_initcall(omap2_common_pm_init);
arch/arm/mach-omap2/pm.h +1 -0
index b737b11..f9dac40 100644
@@ -22,6 +22,7 @@ extern int omap3_can_sleep(void);
  extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
  extern int omap3_idle_init(void);
  extern int omap4_idle_init(void);
+extern void omap_trigger_io_chain(void);
 
  #if defined(CONFIG_PM_OPP)
  extern int omap3_opp_init(void);
maintainer
#21 lore raw

PATCH v5 5/6 ARM: OMAP3PLUS PM: Add IO Daisychain support via hwmod mux

Quoted 10 lines · Rajendra Nayak

While testing with one of Tero's OMAP4 OFF mode support branches (which also include these patches) I found a OMAP4 standalone build fails here..

CC arch/arm/mach-omap2/omap_hwmod.o
arch/arm/mach-omap2/omap_hwmod.c: In function '_reconfigure_io_chain':
arch/arm/mach-omap2/omap_hwmod.c:1797: error: implicit declaration of function 'omap3xxx_prm_reconfigure_io_chain'
make[1]: *** [arch/arm/mach-omap2/omap_hwmod.o] Error 1
make: *** [arch/arm/mach-omap2] Error 2

This should be fixed by Kevin's "ARM: OMAP2+: PRM: fix compile for OMAP4-only build" patch, part of the following pull request:

http://marc.info/?l=linux-omap&m=134037965609802&w=2

- Paul

#22 lore raw

PATCH v5 6/6 ARM: OMAP3 PM: Remove IO Daisychain control from cpuidle

In reply to Tero Kristo

From: Vishwanath BS <[email protected]>

As IO Daisy chain sequence is triggered via hwmod mux, there is no need to control it from cpuidle path for OMAP3.

Also as omap3_disable_io_chain is no longer being used, just remove the function.

---
 arch/arm/mach-omap2/pm34xx.c       |   17 -----------------
 arch/arm/mach-omap2/prm2xxx_3xxx.c |    8 --------
 arch/arm/mach-omap2/prm2xxx_3xxx.h |    7 -------
 3 files changed, 0 insertions(+), 32 deletions(-)
arch/arm/mach-omap2/pm34xx.c +0 -17
index e97ec3f..ed12bb4 100644
@@ -291,13 +291,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_trigger_io_chain();
-	}
 
 	pwrdm_pre_transition();
 
@@ -376,16 +369,6 @@ void omap_sram_idle(void)
 			omap3_per_restore_context();
 	}
 
-	/* 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]);
 }
 
arch/arm/mach-omap2/prm2xxx_3xxx.c +0 -8
index f0179f6..b8962fe 100644
@@ -330,14 +330,6 @@ void omap3_trigger_io_chain(void)
 	omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST);
 }
 
-/* OMAP3 Daisychain disable sequence */
-void omap3_disable_io_chain(void)
-{
-	if (omap_rev() >= OMAP3430_REV_ES3_1)
-		omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK,
-					     WKUP_MOD, PM_WKEN);
-}
-
 static void __init omap3_enable_io_wakeup(void)
 {
 	if (omap3_has_io_wakeup())
arch/arm/mach-omap2/prm2xxx_3xxx.h +0 -7
index 15973aa..391b844 100644
@@ -295,12 +295,6 @@ static inline void omap3_trigger_io_chain(void)
 		"not suppose to be used on omap4\n");
 	return 0;
 }
-static inline void omap3_disable_io_chain(void)
-{
-	WARN(1, "prm: omap2xxx/omap3xxx specific function and "
-		"not suppose to be used on omap4\n");
-	return 0;
-}
 #else
 /* Power/reset management domain register get/set */
 extern u32 omap2_prm_read_mod_reg(s16 module, u16 idx);
@@ -315,7 +309,6 @@ 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);
 extern void omap3_trigger_io_chain(void);
-extern void omap3_disable_io_chain(void);
 
 /* OMAP3-specific VP functions */
 u32 omap3_prm_vp_check_txdone(u8 vp_id);
Signature · 1 line
1.7.4.1
maintainer
#23 lore raw

PATCH v5 6/6 ARM: OMAP3 PM: Remove IO Daisychain control from cpuidle

Quoted 11 lines · Tero Kristo

From: Vishwanath BS <[email protected]>

As IO Daisy chain sequence is triggered via hwmod mux, there is no need to control it from cpuidle path for OMAP3.

Also as omap3_disable_io_chain is no longer being used, just remove the function.

And here's a modified version of this one that takes into account the earlier changes.

- Paul

Quoted 1 line

From ad04159c4ec89eef4026fa2e2aeefc3795d98b89 Mon Sep 17 00:00:00 2001

From: Vishwanath BS <[email protected]>
Date: Fri, 2 Mar 2012 17:17:55 +0200
Subject: [PATCH 6/6] ARM: OMAP3: PM: Remove IO Daisychain control from
cpuidle

As IO Daisy chain sequence is triggered via hwmod mux, there is no need to control it from cpuidle path for OMAP3.

Also as omap3_disable_io_chain is no longer being used, just remove the function.

---
 arch/arm/mach-omap2/pm34xx.c |   14 --------------
 1 files changed, 0 insertions(+), 14 deletions(-)
arch/arm/mach-omap2/pm34xx.c +0 -14
index 378a0de..ed12bb4 100644
@@ -291,13 +291,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_reconfigure_io_chain();
-	}
 
 	pwrdm_pre_transition();
 
@@ -376,13 +369,6 @@ void omap_sram_idle(void)
 			omap3_per_restore_context();
 	}
 
-	/* 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);
-
 	clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
 }
 
Signature · 1 line
1.7.9.1
maintainer
#24 lore raw

v5 cover ARM: OMAP3+: IO daisy chain support fixes

In reply to Tero Kristo

Hi

Quoted 12 lines · Tero Kristo

Changes compared to previous version:

- patch2:
* fixed the timeout for waiting for ST_IO_CHAIN == 1
* added clear for ST_IO_CHAIN bit (as per spec + implementation in patch 1)
* replaced the timeout at the end of function with a simple register readback (timing out on a register value that we are clearing does not make that much sense, the bit is cleared the very first time CPU manages to read it)
- patch5:
* added spinlock for protecting io_chain_trigger operation

Quoted 5 lines

Tested on omap3 beagle + omap4 blaze. Also did measurements for the cost of IO chain trigger operation with ARM performance counters:

- omap3 approx 7...8us
- omap4 approx 2...4us

Thanks for the changes. So as you probably already saw, a few changes have been made. The updated series is in the branch 'io_chain_devel_3.4' on git://git.pwsan.com/linux-2.6.

The main outstanding question is whether the OMAP4 WUCLKOUT poll should be removed to match the v5 changes to the OMAP3 function. Please let me
know. Any other testing or comments are of course welcome.

- Paul

#25 lore raw

v5 cover ARM: OMAP3+: IO daisy chain support fixes

Quoted 3 lines · Paul Walmsley

The main outstanding question is whether the OMAP4 WUCLKOUT poll should be removed to match the v5 changes to the OMAP3 function. Please let me
know. Any other testing or comments are of course welcome.

I think we should instead add it back in omap3 and keep the omap4 as is.

#26 lore raw

v5 cover ARM: OMAP3+: IO daisy chain support fixes

In reply to Paul Walmsley
Quoted 22 lines · Paul Walmsley

Hi

Quoted 12 lines · Tero Kristo

Changes compared to previous version:

- patch2:
* fixed the timeout for waiting for ST_IO_CHAIN == 1
* added clear for ST_IO_CHAIN bit (as per spec + implementation in patch 1)
* replaced the timeout at the end of function with a simple register readback (timing out on a register value that we are clearing does not make that much sense, the bit is cleared the very first time CPU manages to read it)
- patch5:
* added spinlock for protecting io_chain_trigger operation

Quoted 5 lines

Tested on omap3 beagle + omap4 blaze. Also did measurements for the cost of IO chain trigger operation with ARM performance counters:

- omap3 approx 7...8us
- omap4 approx 2...4us

Quoted 7 lines

Thanks for the changes. So as you probably already saw, a few changes have been made. The updated series is in the branch 'io_chain_devel_3.4' on git://git.pwsan.com/linux-2.6.

The main outstanding question is whether the OMAP4 WUCLKOUT poll should be removed to match the v5 changes to the OMAP3 function. Please let me
know. Any other testing or comments are of course welcome.

Just tested your branch with omap3 beagle + omap4 blaze (with my omap4 cswr set on top), and it works on both.

For the WUCLK poll bit I added detailed comments on patch 2 thread, but my current understanding is that the implementation now on omap3 / omap4 is what they should be due to IP differences (except maybe the small optimization for omap3 part you commented about.)

-Tero

maintainer
#27 lore raw

v5 cover ARM: OMAP3+: IO daisy chain support fixes

Hi Tero, Rajendra,

Quoted 7 lines · Tero Kristo

Just tested your branch with omap3 beagle + omap4 blaze (with my omap4 cswr set on top), and it works on both.

For the WUCLK poll bit I added detailed comments on patch 2 thread, but my current understanding is that the implementation now on omap3 / omap4 is what they should be due to IP differences (except maybe the small optimization for omap3 part you commented about.)

Thank you both for the detailed comments and explanation on this series, and the testing... sounds like this set is okay to go.

- Paul

maintainer
#28 lore raw

v5 cover ARM: OMAP3+: IO daisy chain support fixes

In reply to Tero Kristo

Hi

By the way, one other thing I forgot to mention. It would be really great if kerneldoc comments can be created for any new functions added to hwmod, PRCM, clock, or omap_device code. The intention is to help not only people unfamiliar with the code, but even ourselves in the future. I've been adding these by hand on Tero's last few patch series, but at some point I'll probably stop accepting patches without kerneldoc.

thanks,

- Paul

#29 lore raw

v5 cover ARM: OMAP3+: IO daisy chain support fixes

Quoted 2 lines · Paul Walmsley

Hi

Hi Paul,

Quoted 7 lines

By the way, one other thing I forgot to mention. It would be really great if kerneldoc comments can be created for any new functions added to hwmod, PRCM, clock, or omap_device code. The intention is to help not only people unfamiliar with the code, but even ourselves in the future. I've been adding these by hand on Tero's last few patch series, but at some point I'll probably stop accepting patches without kerneldoc.

Thanks for updating the kerneldoc comments this time around. Will make sure patches hence forth come with adequate documentation added.

thanks,
Rajendra

Quoted 5 lines

thanks,

- Paul