Skip to contentSkip to conversation

ARM: omap_hwmod: add api to enable/disable module level wakeup

PATCH Superseded Govindraj.R 3 participants 5 messages Apr 16, 2012 – Apr 18, 2012

Subsystems (5)

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

cover ARM: omap_hwmod: add api to enable/disable module level wakeup

From: "Govindraj.R" <[email protected]>

On omap2/3 module level wakeup is handled using PM_WKEN registers. Expand the hwmod framework to handle the module level wakeup enable registers.

Tested on Beagle-xm by enabling and disabling uart wakeups from sysfs Series depends on following patch for testing.
http://marc.info/?l=linux-omap&m=133457952909998&w=2

Govindraj.R (2):
ARM: OMAP2+: omap_hwmod: Add interface to incorporate module level
wakeup
ARM: OMAP2+: omap_hwmod: Add api to enable/disable module level
wakeup events

 arch/arm/mach-omap2/omap_hwmod.c             |   31 ++++++++++++++++++++++++++
 arch/arm/mach-omap2/omap_hwmod_2420_data.c   |    6 +++++
 arch/arm/mach-omap2/omap_hwmod_2430_data.c   |    6 +++++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c   |    8 ++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    4 +++
 5 files changed, 55 insertions(+), 0 deletions(-)
Signature · 1 line
1.7.9
#1 lore raw

PATCH 1/2 ARM: OMAP2+: omap_hwmod: Add interface to incorporate module level wakeup

From: "Govindraj.R" <[email protected]>

On 24xx/34xx/36xx Module level wakeup events are enabled/disabled using PM_WKEN1_CORE/PM_WKEN_PER regs. The module level wakeups are enabled by default from bootloader, however the wakeups can be enabled/disabled using sysfs entry example for uart:
echo disabled > /sys/devices/platform/omap/omap_uart.X/power/wakeup [X=0,1,2,3]

So expand omap2 prcm structure to incorporate the PM_WKEN reg offset and bit mask to control the module level wakeup. This info from hwmod data can be used hwmod framework omap_hwmod_enable/disable_wakeup.

Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/omap_hwmod_2420_data.c   |    6 ++++++
 arch/arm/mach-omap2/omap_hwmod_2430_data.c   |    6 ++++++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c   |    8 ++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    4 ++++
 4 files changed, 24 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +6 -0
index a5409ce..676274b 100644
@@ -791,6 +791,8 @@ static struct omap_hwmod omap2420_uart1_hwmod = {
 			.module_bit = OMAP24XX_EN_UART1_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP24XX_ST_UART1_MASK,
 		},
 	},
 	.slaves		= omap2420_uart1_slaves,
@@ -816,6 +818,8 @@ static struct omap_hwmod omap2420_uart2_hwmod = {
 			.module_bit = OMAP24XX_EN_UART2_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP24XX_ST_UART2_MASK,
 		},
 	},
 	.slaves		= omap2420_uart2_slaves,
@@ -841,6 +845,8 @@ static struct omap_hwmod omap2420_uart3_hwmod = {
 			.module_bit = OMAP24XX_EN_UART3_SHIFT,
 			.idlest_reg_id = 2,
 			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+			.module_wakeup_offs = OMAP24XX_PM_WKEN2,
+			.module_wakeup_bit = OMAP24XX_ST_UART3_MASK,
 		},
 	},
 	.slaves		= omap2420_uart3_slaves,
arch/arm/mach-omap2/omap_hwmod_2430_data.c +6 -0
index c4f56cb..94d4463 100644
@@ -864,6 +864,8 @@ static struct omap_hwmod omap2430_uart1_hwmod = {
 			.module_bit = OMAP24XX_EN_UART1_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP24XX_ST_UART1_MASK,
 		},
 	},
 	.slaves		= omap2430_uart1_slaves,
@@ -889,6 +891,8 @@ static struct omap_hwmod omap2430_uart2_hwmod = {
 			.module_bit = OMAP24XX_EN_UART2_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP24XX_ST_UART2_MASK,
 		},
 	},
 	.slaves		= omap2430_uart2_slaves,
@@ -914,6 +918,8 @@ static struct omap_hwmod omap2430_uart3_hwmod = {
 			.module_bit = OMAP24XX_EN_UART3_SHIFT,
 			.idlest_reg_id = 2,
 			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+			.module_wakeup_offs = OMAP24XX_PM_WKEN2,
+			.module_wakeup_bit = OMAP24XX_ST_UART3_MASK,
 		},
 	},
 	.slaves		= omap2430_uart3_slaves,
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +8 -0
index 34b9766d..9ed038d 100644
@@ -1248,6 +1248,8 @@ static struct omap_hwmod omap3xxx_uart1_hwmod = {
 			.module_bit = OMAP3430_EN_UART1_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP3430_EN_UART1_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP3430_ST_UART1_MASK,
 		},
 	},
 	.slaves		= omap3xxx_uart1_slaves,
@@ -1273,6 +1275,8 @@ static struct omap_hwmod omap3xxx_uart2_hwmod = {
 			.module_bit = OMAP3430_EN_UART2_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP3430_EN_UART2_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP3430_ST_UART2_MASK,
 		},
 	},
 	.slaves		= omap3xxx_uart2_slaves,
@@ -1298,6 +1302,8 @@ static struct omap_hwmod omap3xxx_uart3_hwmod = {
 			.module_bit = OMAP3430_EN_UART3_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP3430_EN_UART3_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP3430_ST_UART3_MASK,
 		},
 	},
 	.slaves		= omap3xxx_uart3_slaves,
@@ -1334,6 +1340,8 @@ static struct omap_hwmod omap3xxx_uart4_hwmod = {
 			.module_bit = OMAP3630_EN_UART4_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP3630_EN_UART4_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP3630_ST_UART4_MASK,
 		},
 	},
 	.slaves		= omap3xxx_uart4_slaves,
arch/arm/plat-omap/include/plat/omap_hwmod.h +4 -0
index 8070145..5c7711b 100644
@@ -343,6 +343,8 @@ struct omap_hwmod_class_sysconfig {
  * @idlest_reg_id: IDLEST register ID (e.g., 3 for CM_IDLEST3)
  * @idlest_idle_bit: register bit shift for CM_IDLEST slave idle bit
  * @idlest_stdby_bit: register bit shift for CM_IDLEST master standby bit
+ * @module_wakeup_offs: PRCM register offset for PM_WKEN
+ * @module_wakeup_bit: regiter bit mask for PM_WKEN
  *
  * @prcm_reg_id and @module_bit are specific to the AUTOIDLE, WKST,
  * WKEN, GRPSEL registers.  In an ideal world, no extra information
@@ -357,6 +359,8 @@ struct omap_hwmod_omap2_prcm {
 	u8 idlest_reg_id;
 	u8 idlest_idle_bit;
 	u8 idlest_stdby_bit;
+	s16 module_wakeup_offs;
+	u32 module_wakeup_bit;
 };
 
 
Signature · 1 line
1.7.9
#2 lore raw

PATCH 1/2 ARM: OMAP2+: omap_hwmod: Add interface to incorporate module level wakeup

Quoted 5 lines · Govindraj.R

From: "Govindraj.R" <[email protected]>

On 24xx/34xx/36xx Module level wakeup events are enabled/disabled using PM_WKEN1_CORE/PM_WKEN_PER regs. The module level wakeups are enabled by default from bootloader,

Which bootloader? what board?

We cannot make any assumptions about what bootloader does (or doesn't do).

There is also some default init to these PM_WKEN values in prcm_setup_regs() for OMAP3 as well, which could be removed (at least for the UARTs) when this is handled by the UART init code.

Kevin

Quoted 141 lines

however the wakeups can be enabled/disabled
using sysfs entry example for uart:
echo disabled > /sys/devices/platform/omap/omap_uart.X/power/wakeup [X=0,1,2,3]

So expand omap2 prcm structure to incorporate the PM_WKEN reg offset and bit mask to control the module level wakeup. This info from hwmod data can be used hwmod framework omap_hwmod_enable/disable_wakeup.

Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/omap_hwmod_2420_data.c   |    6 ++++++
 arch/arm/mach-omap2/omap_hwmod_2430_data.c   |    6 ++++++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c   |    8 ++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    4 ++++
 4 files changed, 24 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +6 -0
index a5409ce..676274b 100644
@@ -791,6 +791,8 @@ static struct omap_hwmod omap2420_uart1_hwmod = {
 			.module_bit = OMAP24XX_EN_UART1_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP24XX_ST_UART1_MASK,
 		},
 	},
 	.slaves		= omap2420_uart1_slaves,
@@ -816,6 +818,8 @@ static struct omap_hwmod omap2420_uart2_hwmod = {
 			.module_bit = OMAP24XX_EN_UART2_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP24XX_ST_UART2_MASK,
 		},
 	},
 	.slaves		= omap2420_uart2_slaves,
@@ -841,6 +845,8 @@ static struct omap_hwmod omap2420_uart3_hwmod = {
 			.module_bit = OMAP24XX_EN_UART3_SHIFT,
 			.idlest_reg_id = 2,
 			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+			.module_wakeup_offs = OMAP24XX_PM_WKEN2,
+			.module_wakeup_bit = OMAP24XX_ST_UART3_MASK,
 		},
 	},
 	.slaves		= omap2420_uart3_slaves,
arch/arm/mach-omap2/omap_hwmod_2430_data.c +6 -0
index c4f56cb..94d4463 100644
@@ -864,6 +864,8 @@ static struct omap_hwmod omap2430_uart1_hwmod = {
 			.module_bit = OMAP24XX_EN_UART1_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP24XX_ST_UART1_MASK,
 		},
 	},
 	.slaves		= omap2430_uart1_slaves,
@@ -889,6 +891,8 @@ static struct omap_hwmod omap2430_uart2_hwmod = {
 			.module_bit = OMAP24XX_EN_UART2_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP24XX_ST_UART2_MASK,
 		},
 	},
 	.slaves		= omap2430_uart2_slaves,
@@ -914,6 +918,8 @@ static struct omap_hwmod omap2430_uart3_hwmod = {
 			.module_bit = OMAP24XX_EN_UART3_SHIFT,
 			.idlest_reg_id = 2,
 			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+			.module_wakeup_offs = OMAP24XX_PM_WKEN2,
+			.module_wakeup_bit = OMAP24XX_ST_UART3_MASK,
 		},
 	},
 	.slaves		= omap2430_uart3_slaves,
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +8 -0
index 34b9766d..9ed038d 100644
@@ -1248,6 +1248,8 @@ static struct omap_hwmod omap3xxx_uart1_hwmod = {
 			.module_bit = OMAP3430_EN_UART1_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP3430_EN_UART1_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP3430_ST_UART1_MASK,
 		},
 	},
 	.slaves		= omap3xxx_uart1_slaves,
@@ -1273,6 +1275,8 @@ static struct omap_hwmod omap3xxx_uart2_hwmod = {
 			.module_bit = OMAP3430_EN_UART2_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP3430_EN_UART2_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP3430_ST_UART2_MASK,
 		},
 	},
 	.slaves		= omap3xxx_uart2_slaves,
@@ -1298,6 +1302,8 @@ static struct omap_hwmod omap3xxx_uart3_hwmod = {
 			.module_bit = OMAP3430_EN_UART3_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP3430_EN_UART3_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP3430_ST_UART3_MASK,
 		},
 	},
 	.slaves		= omap3xxx_uart3_slaves,
@@ -1334,6 +1340,8 @@ static struct omap_hwmod omap3xxx_uart4_hwmod = {
 			.module_bit = OMAP3630_EN_UART4_SHIFT,
 			.idlest_reg_id = 1,
 			.idlest_idle_bit = OMAP3630_EN_UART4_SHIFT,
+			.module_wakeup_offs = PM_WKEN1,
+			.module_wakeup_bit = OMAP3630_ST_UART4_MASK,
 		},
 	},
 	.slaves		= omap3xxx_uart4_slaves,
arch/arm/plat-omap/include/plat/omap_hwmod.h +4 -0
index 8070145..5c7711b 100644
@@ -343,6 +343,8 @@ struct omap_hwmod_class_sysconfig {
  * @idlest_reg_id: IDLEST register ID (e.g., 3 for CM_IDLEST3)
  * @idlest_idle_bit: register bit shift for CM_IDLEST slave idle bit
  * @idlest_stdby_bit: register bit shift for CM_IDLEST master standby bit
+ * @module_wakeup_offs: PRCM register offset for PM_WKEN
+ * @module_wakeup_bit: regiter bit mask for PM_WKEN
  *
  * @prcm_reg_id and @module_bit are specific to the AUTOIDLE, WKST,
  * WKEN, GRPSEL registers.  In an ideal world, no extra information
@@ -357,6 +359,8 @@ struct omap_hwmod_omap2_prcm {
 	u8 idlest_reg_id;
 	u8 idlest_idle_bit;
 	u8 idlest_stdby_bit;
+	s16 module_wakeup_offs;
+	u32 module_wakeup_bit;
 };
#3 lore raw

PATCH 2/2 ARM: OMAP2+: omap_hwmod: Add api to enable/disable module level wakeup events

In reply to Govindraj.R

From: "Govindraj.R" <[email protected]>

On 24xx/34xx/36xx Module level wakeup events are enabled/disabled using PM_WKEN1_CORE/PM_WKEN_PER regs.

Add api to control the module level wakeup mechanism from info provided from hwmod data. If module level wakeups are available from hwmod data then they have to be enabled/disabled as per driver request.

omap_hwmod_enable/disable_wakeup is used from serial.c which should act on those registers to enable or disable the module level wakeup

Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/omap_hwmod.c |   31 +++++++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap_hwmod.c +31 -0
index 2c27fdb..05576ae 100644
@@ -382,6 +382,35 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
 }
 
 /**
+ * _enable_module_level_wakeup - enable/disable module level wakeup on hwmod.
+ * @oh: struct omap_hwmod *
+ * @set_wake: bool value indicating to set (true) or clear (false) module level
+ *		wakeup enable
+ *
+ * Set or clear the  module level wakeup capability the
+ * hwmod @oh. This function configures th PM_WKEN reg bits if they
+ * are available from hwmod. No return value
+ */
+static void _enable_module_level_wakeup(struct omap_hwmod *oh, bool set_wake)
+{
+	u32 v;
+
+	if (oh->prcm.omap2.module_wakeup_offs &&
+			oh->prcm.omap2.module_wakeup_bit) {
+		v = omap2_prm_read_mod_reg(oh->prcm.omap2.module_offs,
+				oh->prcm.omap2.module_wakeup_offs);
+
+		if (set_wake)
+			v |= oh->prcm.omap2.module_wakeup_bit;
+		else
+			v &= ~oh->prcm.omap2.module_wakeup_bit;
+
+		omap2_prm_write_mod_reg(v, oh->prcm.omap2.module_offs,
+				oh->prcm.omap2.module_wakeup_offs);
+	}
+}
+
+/**
  * _set_idle_ioring_wakeup - enable/disable IO pad wakeup on hwmod idle for mux
  * @oh: struct omap_hwmod *
  * @set_wake: bool value indicating to set (true) or clear (false) wakeup enable
@@ -2471,6 +2500,7 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
 		_write_sysconfig(v, oh);
 	}
 
+	_enable_module_level_wakeup(oh, true);
 	_set_idle_ioring_wakeup(oh, true);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
@@ -2504,6 +2534,7 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
 		_write_sysconfig(v, oh);
 	}
 
+	_enable_module_level_wakeup(oh, false);
 	_set_idle_ioring_wakeup(oh, false);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
Signature · 1 line
1.7.9
maintainer
#4 lore raw

PATCH 2/2 ARM: OMAP2+: omap_hwmod: Add api to enable/disable module level wakeup events

Hi

Quoted 25 lines · Govindraj.R
arch/arm/mach-omap2/omap_hwmod.c +17 -0
index 2c27fdb..05576ae 100644
@@ -382,6 +382,35 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
 }
 
 /**
+ * _enable_module_level_wakeup - enable/disable module level wakeup on hwmod.
+ * @oh: struct omap_hwmod *
+ * @set_wake: bool value indicating to set (true) or clear (false) module level
+ *		wakeup enable
+ *
+ * Set or clear the  module level wakeup capability the
+ * hwmod @oh. This function configures th PM_WKEN reg bits if they
+ * are available from hwmod. No return value
+ */
+static void _enable_module_level_wakeup(struct omap_hwmod *oh, bool set_wake)
+{
+	u32 v;
+
+	if (oh->prcm.omap2.module_wakeup_offs &&
+			oh->prcm.omap2.module_wakeup_bit) {
+		v = omap2_prm_read_mod_reg(oh->prcm.omap2.module_offs,
+				oh->prcm.omap2.module_wakeup_offs);

arch/arm/mach-omap2/omap_hwmod.c static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, · line 411

Quoted 10 lines
arch/arm/mach-omap2/omap_hwmod.c +10 -0
+
+		if (set_wake)
+			v |= oh->prcm.omap2.module_wakeup_bit;
+		else
+			v &= ~oh->prcm.omap2.module_wakeup_bit;
+
+		omap2_prm_write_mod_reg(v, oh->prcm.omap2.module_offs,
+				oh->prcm.omap2.module_wakeup_offs);
+	}
+}

Please move the direct PRM register accesses to the PRM code, such as prm2xxx_3xxx.c and prm44xx.c, as mentioned here:

    http://www.spinics.net/lists/linux-serial/msg05945.html

We are trying to move the PRM code to drivers/ and the only code that should be doing direct PRM register accesses is the PRM code itself. Other code (like the hwmod code) should be calling higher-level functions exported by the PRM code, such as something like "omap_prm_enable_prcm_module_wakeup()"

- Paul