All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv12 0/9] OMAP3+: PRCM chain handler
@ 2011-12-15 21:36 ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel

Hi,

This is a repost of Tero's PRCM chain handler patch set with a few changes:

- A new mux patch has been added to place hwmod mux entries with
  OMAP_DEVICE_PAD_WAKEUP set into the dynamic list

- Several OCP barriers have been added to PRM writes to try to protect
  against races between PRM register writes and the MPU

- Kerneldoc documentation has been added

- The pending IRQ test functions have been split into per-SoC versions

- Some patches have been rearranged and merged to avoid churn

- The PRM IRQ handler is now installed on OMAP4

This updated series has been tested on OMAP3530 BeagleBoard in dynamic idle
with off-mode enabled, although the functions that do dynamic IRQ mapping
have not been tested.

I've preserved Signed-off-by:s and other tags, even though the patches
have been rearranged.  Any further testing would be appreciated, and if any
Signed-off-by: or other tag does not belong, please advise and I'll remove it.
I'd like to send Tony a pull request for this tomorrow.

Original series description follows:

From: Tero Kristo <t-kristo@ti.com>

PRCM chain handler is adding a support to the omap3+ kernel that
allows different drivers to use PRCM interrupt events for their
own purposes, typically this means IO wakeups. This work was
attempted to integrate as its own driver at some point of
the evolution of this set, however this was now postponed as
the lacking support is basically blocking a few drivers.

---

tk_prm_chain_handler_devel_3.3
   text	   data	    bss	    dec	    hex	filename
6476701	 671380	5588224	12736305	 c25731	vmlinux.omap2plus_defconfig.orig
6483705	 671468	5588224	12743397	 c272e5	vmlinux.omap2plus_defconfig.patched


Govindraj R (1):
      ARM: OMAP2+: hwmod: Add API to enable IO ring wakeup

Paul Walmsley (2):
      ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list
      ARM: OMAP3/4: PRM: add functions to read pending IRQs, PRM barrier

Tero Kristo (6):
      ARM: OMAP: PRCM: add support for chain interrupt handler
      ARM: OMAP: PRCM: add suspend prepare / finish support
      ARM: OMAP2+: mux: add support for PAD wakeup interrupts
      ARM: OMAP: hwmod: add support for selecting mpu_irq for each wakeup pad
      ARM: OMAP3: pm: use prcm chain handler
      ARM: OMAP4: PRM: use PRCM interrupt handler


 arch/arm/mach-omap2/Makefile                 |    5 
 arch/arm/mach-omap2/mux.c                    |   89 +++++++
 arch/arm/mach-omap2/omap_hwmod.c             |  102 ++++++++
 arch/arm/mach-omap2/pm34xx.c                 |  115 ++++-----
 arch/arm/mach-omap2/prcm-common.h            |   75 ++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.c           |   97 ++++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.h           |    9 +
 arch/arm/mach-omap2/prm44xx.c                |  116 +++++++++
 arch/arm/mach-omap2/prm44xx.h                |    8 +
 arch/arm/mach-omap2/prm_common.c             |  320 ++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    3 
 11 files changed, 860 insertions(+), 79 deletions(-)
 create mode 100644 arch/arm/mach-omap2/prm_common.c


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv12 0/9] OMAP3+: PRCM chain handler
@ 2011-12-15 21:36 ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This is a repost of Tero's PRCM chain handler patch set with a few changes:

- A new mux patch has been added to place hwmod mux entries with
  OMAP_DEVICE_PAD_WAKEUP set into the dynamic list

- Several OCP barriers have been added to PRM writes to try to protect
  against races between PRM register writes and the MPU

- Kerneldoc documentation has been added

- The pending IRQ test functions have been split into per-SoC versions

- Some patches have been rearranged and merged to avoid churn

- The PRM IRQ handler is now installed on OMAP4

This updated series has been tested on OMAP3530 BeagleBoard in dynamic idle
with off-mode enabled, although the functions that do dynamic IRQ mapping
have not been tested.

I've preserved Signed-off-by:s and other tags, even though the patches
have been rearranged.  Any further testing would be appreciated, and if any
Signed-off-by: or other tag does not belong, please advise and I'll remove it.
I'd like to send Tony a pull request for this tomorrow.

Original series description follows:

From: Tero Kristo <t-kristo@ti.com>

PRCM chain handler is adding a support to the omap3+ kernel that
allows different drivers to use PRCM interrupt events for their
own purposes, typically this means IO wakeups. This work was
attempted to integrate as its own driver at some point of
the evolution of this set, however this was now postponed as
the lacking support is basically blocking a few drivers.

---

tk_prm_chain_handler_devel_3.3
   text	   data	    bss	    dec	    hex	filename
6476701	 671380	5588224	12736305	 c25731	vmlinux.omap2plus_defconfig.orig
6483705	 671468	5588224	12743397	 c272e5	vmlinux.omap2plus_defconfig.patched


Govindraj R (1):
      ARM: OMAP2+: hwmod: Add API to enable IO ring wakeup

Paul Walmsley (2):
      ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list
      ARM: OMAP3/4: PRM: add functions to read pending IRQs, PRM barrier

Tero Kristo (6):
      ARM: OMAP: PRCM: add support for chain interrupt handler
      ARM: OMAP: PRCM: add suspend prepare / finish support
      ARM: OMAP2+: mux: add support for PAD wakeup interrupts
      ARM: OMAP: hwmod: add support for selecting mpu_irq for each wakeup pad
      ARM: OMAP3: pm: use prcm chain handler
      ARM: OMAP4: PRM: use PRCM interrupt handler


 arch/arm/mach-omap2/Makefile                 |    5 
 arch/arm/mach-omap2/mux.c                    |   89 +++++++
 arch/arm/mach-omap2/omap_hwmod.c             |  102 ++++++++
 arch/arm/mach-omap2/pm34xx.c                 |  115 ++++-----
 arch/arm/mach-omap2/prcm-common.h            |   75 ++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.c           |   97 ++++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.h           |    9 +
 arch/arm/mach-omap2/prm44xx.c                |  116 +++++++++
 arch/arm/mach-omap2/prm44xx.h                |    8 +
 arch/arm/mach-omap2/prm_common.c             |  320 ++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    3 
 11 files changed, 860 insertions(+), 79 deletions(-)
 create mode 100644 arch/arm/mach-omap2/prm_common.c

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 1/9] ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-15 21:36   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: Tony Lindgren, Tero Kristo, Govindraj R

omap_hwmod_mux() currently only iterates through the dynamic pad list.
This list currently only consists of pads with the
OMAP_DEVICE_MUX_REMUX flag set.

Subsequent patches in this series will cause hwmod mux entries with
the OMAP_DEVICE_MUX_WAKEUP flag set to be changed dynamically, to
control hwmod I/O ring wakeup.  For this to work correctly, hwmod mux
entries with the OMAP_DEVICE_MUX_WAKEUP flag set must also be added to
the dynamic pad list.  So this patch modifies omap_hwmod_mux_init() to
do so.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Tero Kristo <t-kristo@ti.com>
Cc: Govindraj R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/mux.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 655e948..a474c81 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -306,7 +306,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
 		pad->idle = bpad->idle;
 		pad->off = bpad->off;
 
-		if (pad->flags & OMAP_DEVICE_PAD_REMUX)
+		if (pad->flags &
+		    (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP))
 			nr_pads_dynamic++;
 
 		pr_debug("%s: Initialized %s\n", __func__, pad->name);
@@ -331,7 +332,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
 	for (i = 0; i < hmux->nr_pads; i++) {
 		struct omap_device_pad *pad = &hmux->pads[i];
 
-		if (pad->flags & OMAP_DEVICE_PAD_REMUX) {
+		if (pad->flags &
+		    (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) {
 			pr_debug("%s: pad %s tagged dynamic\n",
 					__func__, pad->name);
 			hmux->pads_dynamic[nr_pads_dynamic] = pad;



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 1/9] ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list
@ 2011-12-15 21:36   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

omap_hwmod_mux() currently only iterates through the dynamic pad list.
This list currently only consists of pads with the
OMAP_DEVICE_MUX_REMUX flag set.

Subsequent patches in this series will cause hwmod mux entries with
the OMAP_DEVICE_MUX_WAKEUP flag set to be changed dynamically, to
control hwmod I/O ring wakeup.  For this to work correctly, hwmod mux
entries with the OMAP_DEVICE_MUX_WAKEUP flag set must also be added to
the dynamic pad list.  So this patch modifies omap_hwmod_mux_init() to
do so.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Tero Kristo <t-kristo@ti.com>
Cc: Govindraj R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/mux.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 655e948..a474c81 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -306,7 +306,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
 		pad->idle = bpad->idle;
 		pad->off = bpad->off;
 
-		if (pad->flags & OMAP_DEVICE_PAD_REMUX)
+		if (pad->flags &
+		    (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP))
 			nr_pads_dynamic++;
 
 		pr_debug("%s: Initialized %s\n", __func__, pad->name);
@@ -331,7 +332,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
 	for (i = 0; i < hmux->nr_pads; i++) {
 		struct omap_device_pad *pad = &hmux->pads[i];
 
-		if (pad->flags & OMAP_DEVICE_PAD_REMUX) {
+		if (pad->flags &
+		    (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) {
 			pr_debug("%s: pad %s tagged dynamic\n",
 					__func__, pad->name);
 			hmux->pads_dynamic[nr_pads_dynamic] = pad;

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 2/9] ARM: OMAP2+: hwmod: Add API to enable IO ring wakeup
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-15 21:36   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: Tero Kristo, Govindraj.R, Kevin Hilman

From: Govindraj R <govindraj.raja@ti.com>

Add API to enable IO pad wakeup capability based on mux pad and
wake_up enable flag available from hwmod_mux initialization.

Use the wakeup_enable flag and enable wakeup capability for the given
pads. Wakeup capability will be enabled/disabled during hwmod idle
transition based on whether wakeup_flag is set or cleared.  If the
hwmod is currently idled, and any mux values were changed by
_set_idle_ioring_wakeup(), the SCM PADCTRL registers will be updated.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul@pwsan.com: rearranged code to limit indentation; cleaned up
 function documentation; removed unused non-static functions; modified
 to search all hwmod pads, not just dynamic remuxing ones; modified to
 update SCM regs if hwmod is currently idle and any pads have changed]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/omap_hwmod.c |   47 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 207a2ff..21ffd8a 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -381,6 +381,51 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
 }
 
 /**
+ * _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
+ *
+ * Set or clear the I/O pad wakeup flag in the mux entries for the
+ * hwmod @oh.  This function changes the @oh->mux->pads_dynamic array
+ * in memory.  If the hwmod is currently idled, and the new idle
+ * values don't match the previous ones, this function will also
+ * update the SCM PADCTRL registers.  Otherwise, if the hwmod is not
+ * currently idled, this function won't touch the hardware: the new
+ * mux settings are written to the SCM PADCTRL registers when the
+ * hwmod is idled.  No return value.
+ */
+static void _set_idle_ioring_wakeup(struct omap_hwmod *oh, bool set_wake)
+{
+	struct omap_device_pad *pad;
+	bool change = false;
+	u16 prev_idle;
+	int j;
+
+	if (!oh->mux || !oh->mux->enabled)
+		return;
+
+	for (j = 0; j < oh->mux->nr_pads_dynamic; j++) {
+		pad = oh->mux->pads_dynamic[j];
+
+		if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP))
+			continue;
+
+		prev_idle = pad->idle;
+
+		if (set_wake)
+			pad->idle |= OMAP_WAKEUP_EN;
+		else
+			pad->idle &= ~OMAP_WAKEUP_EN;
+
+		if (prev_idle != pad->idle)
+			change = true;
+	}
+
+	if (change && oh->_state == _HWMOD_STATE_IDLE)
+		omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
+}
+
+/**
  * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware
  * @oh: struct omap_hwmod *
  *
@@ -2416,6 +2461,7 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
 	v = oh->_sysc_cache;
 	_enable_wakeup(oh, &v);
 	_write_sysconfig(v, oh);
+	_set_idle_ioring_wakeup(oh, true);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
 	return 0;
@@ -2446,6 +2492,7 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
 	v = oh->_sysc_cache;
 	_disable_wakeup(oh, &v);
 	_write_sysconfig(v, oh);
+	_set_idle_ioring_wakeup(oh, false);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
 	return 0;



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 2/9] ARM: OMAP2+: hwmod: Add API to enable IO ring wakeup
@ 2011-12-15 21:36   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

From: Govindraj R <govindraj.raja@ti.com>

Add API to enable IO pad wakeup capability based on mux pad and
wake_up enable flag available from hwmod_mux initialization.

Use the wakeup_enable flag and enable wakeup capability for the given
pads. Wakeup capability will be enabled/disabled during hwmod idle
transition based on whether wakeup_flag is set or cleared.  If the
hwmod is currently idled, and any mux values were changed by
_set_idle_ioring_wakeup(), the SCM PADCTRL registers will be updated.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul at pwsan.com: rearranged code to limit indentation; cleaned up
 function documentation; removed unused non-static functions; modified
 to search all hwmod pads, not just dynamic remuxing ones; modified to
 update SCM regs if hwmod is currently idle and any pads have changed]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/omap_hwmod.c |   47 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 207a2ff..21ffd8a 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -381,6 +381,51 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
 }
 
 /**
+ * _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
+ *
+ * Set or clear the I/O pad wakeup flag in the mux entries for the
+ * hwmod @oh.  This function changes the @oh->mux->pads_dynamic array
+ * in memory.  If the hwmod is currently idled, and the new idle
+ * values don't match the previous ones, this function will also
+ * update the SCM PADCTRL registers.  Otherwise, if the hwmod is not
+ * currently idled, this function won't touch the hardware: the new
+ * mux settings are written to the SCM PADCTRL registers when the
+ * hwmod is idled.  No return value.
+ */
+static void _set_idle_ioring_wakeup(struct omap_hwmod *oh, bool set_wake)
+{
+	struct omap_device_pad *pad;
+	bool change = false;
+	u16 prev_idle;
+	int j;
+
+	if (!oh->mux || !oh->mux->enabled)
+		return;
+
+	for (j = 0; j < oh->mux->nr_pads_dynamic; j++) {
+		pad = oh->mux->pads_dynamic[j];
+
+		if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP))
+			continue;
+
+		prev_idle = pad->idle;
+
+		if (set_wake)
+			pad->idle |= OMAP_WAKEUP_EN;
+		else
+			pad->idle &= ~OMAP_WAKEUP_EN;
+
+		if (prev_idle != pad->idle)
+			change = true;
+	}
+
+	if (change && oh->_state == _HWMOD_STATE_IDLE)
+		omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
+}
+
+/**
  * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware
  * @oh: struct omap_hwmod *
  *
@@ -2416,6 +2461,7 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
 	v = oh->_sysc_cache;
 	_enable_wakeup(oh, &v);
 	_write_sysconfig(v, oh);
+	_set_idle_ioring_wakeup(oh, true);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
 	return 0;
@@ -2446,6 +2492,7 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
 	v = oh->_sysc_cache;
 	_disable_wakeup(oh, &v);
 	_write_sysconfig(v, oh);
+	_set_idle_ioring_wakeup(oh, false);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
 	return 0;

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 3/9] ARM: OMAP3/4: PRM: add functions to read pending IRQs, PRM barrier
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-15 21:36   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: Tero Kristo

Add PRM functions to test for pending PRM IRQs.  This will be used in
a subsequent patch to implement the PRM interrupt handler on the MPU.

Add PRM functions to ensure that all outstanding writes from the MPU
to the PRM IP block have completed before continuing execution.  This
will be used in a subsequent patch to ensure that all PRM interrupt
status bits are cleared in the hardware before exiting the ISR.
Normally we would not expose such a low-level function to other code.
But the current implementation of the PRM interrupt code, which uses
the generic IRQ chip code, doesn't give us a choice.

The pending PRM IRQ functions are based on code originally written by
Tero Kristo <t-kristo@ti.com>.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   34 ++++++++++++++++++++++++++++-
 arch/arm/mach-omap2/prm2xxx_3xxx.h |    7 +++++-
 arch/arm/mach-omap2/prm44xx.c      |   42 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm44xx.h      |    6 ++++-
 4 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index f02d87f..177c3dd 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -1,7 +1,7 @@
 /*
  * OMAP2/3 PRM module functions
  *
- * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2010-2011 Texas Instruments, Inc.
  * Copyright (C) 2010 Nokia Corporation
  * Benoît Cousson
  * Paul Walmsley
@@ -212,3 +212,35 @@ u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset)
 {
 	return omap2_prm_rmw_mod_reg_bits(mask, bits, OMAP3430_GR_MOD, offset);
 }
+
+/**
+ * omap3xxx_prm_read_pending_irqs - read pending PRM MPU IRQs into @events
+ * @events: ptr to a u32, preallocated by caller
+ *
+ * Read PRM_IRQSTATUS_MPU bits, AND'ed with the currently-enabled PRM
+ * MPU IRQs, and store the result into the u32 pointed to by @events.
+ * No return value.
+ */
+void omap3xxx_prm_read_pending_irqs(unsigned long *events)
+{
+	u32 mask, st;
+
+	/* XXX Can the mask read be avoided (e.g., can it come from RAM?) */
+	mask = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+	st = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
+	events[0] = mask & st;
+}
+
+/**
+ * omap3xxx_prm_ocp_barrier - force buffered MPU writes to the PRM to complete
+ *
+ * Force any buffered writes to the PRM IP block to complete.  Needed
+ * by the PRM IRQ handler, which reads and writes directly to the IP
+ * block, to avoid race conditions after acknowledging or clearing IRQ
+ * bits.  No return value.
+ */
+void omap3xxx_prm_ocp_barrier(void)
+{
+	omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET);
+}
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index cef533d..3ef0e77 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -1,7 +1,7 @@
 /*
  * OMAP2/3 Power/Reset Management (PRM) register definitions
  *
- * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ * Copyright (C) 2007-2009, 2011 Texas Instruments, Inc.
  * Copyright (C) 2008-2010 Nokia Corporation
  * Paul Walmsley
  *
@@ -314,6 +314,11 @@ void omap3_prm_vp_clear_txdone(u8 vp_id);
 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);
+
+/* PRM interrupt-related functions */
+extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
+extern void omap3xxx_prm_ocp_barrier(void);
+
 #endif	/* CONFIG_ARCH_OMAP4 */
 
 #endif
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index 495a31a..9b21154 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -121,3 +121,45 @@ u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset)
 					       OMAP4430_PRM_DEVICE_INST,
 					       offset);
 }
+
+static inline u32 _read_pending_irq_reg(u16 irqen_offs, u16 irqst_offs)
+{
+	u32 mask, st;
+
+	/* XXX read mask from RAM? */
+	mask = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, irqen_offs);
+	st = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, irqst_offs);
+
+	return mask & st;
+}
+
+/**
+ * omap44xx_prm_read_pending_irqs - read pending PRM MPU IRQs into @events
+ * @events: ptr to two consecutive u32s, preallocated by caller
+ *
+ * Read PRM_IRQSTATUS_MPU* bits, AND'ed with the currently-enabled PRM
+ * MPU IRQs, and store the result into the two u32s pointed to by @events.
+ * No return value.
+ */
+void omap44xx_prm_read_pending_irqs(unsigned long *events)
+{
+	events[0] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_OFFSET,
+					  OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
+
+	events[1] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_2_OFFSET,
+					  OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET);
+}
+
+/**
+ * omap44xx_prm_ocp_barrier - force buffered MPU writes to the PRM to complete
+ *
+ * Force any buffered writes to the PRM IP block to complete.  Needed
+ * by the PRM IRQ handler, which reads and writes directly to the IP
+ * block, to avoid race conditions after acknowledging or clearing IRQ
+ * bits.  No return value.
+ */
+void omap44xx_prm_ocp_barrier(void)
+{
+	omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+				OMAP4_REVISION_PRM_OFFSET);
+}
diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h
index 3d66ccd..bd7f248 100644
--- a/arch/arm/mach-omap2/prm44xx.h
+++ b/arch/arm/mach-omap2/prm44xx.h
@@ -1,7 +1,7 @@
 /*
  * OMAP44xx PRM instance offset macros
  *
- * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2011 Texas Instruments, Inc.
  * Copyright (C) 2009-2010 Nokia Corporation
  *
  * Paul Walmsley (paul@pwsan.com)
@@ -763,6 +763,10 @@ 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);
 
+/* PRM interrupt-related functions */
+extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
+extern void omap44xx_prm_ocp_barrier(void);
+
 # endif
 
 #endif


--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 3/9] ARM: OMAP3/4: PRM: add functions to read pending IRQs, PRM barrier
@ 2011-12-15 21:36   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

Add PRM functions to test for pending PRM IRQs.  This will be used in
a subsequent patch to implement the PRM interrupt handler on the MPU.

Add PRM functions to ensure that all outstanding writes from the MPU
to the PRM IP block have completed before continuing execution.  This
will be used in a subsequent patch to ensure that all PRM interrupt
status bits are cleared in the hardware before exiting the ISR.
Normally we would not expose such a low-level function to other code.
But the current implementation of the PRM interrupt code, which uses
the generic IRQ chip code, doesn't give us a choice.

The pending PRM IRQ functions are based on code originally written by
Tero Kristo <t-kristo@ti.com>.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   34 ++++++++++++++++++++++++++++-
 arch/arm/mach-omap2/prm2xxx_3xxx.h |    7 +++++-
 arch/arm/mach-omap2/prm44xx.c      |   42 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm44xx.h      |    6 ++++-
 4 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index f02d87f..177c3dd 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -1,7 +1,7 @@
 /*
  * OMAP2/3 PRM module functions
  *
- * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2010-2011 Texas Instruments, Inc.
  * Copyright (C) 2010 Nokia Corporation
  * Beno?t Cousson
  * Paul Walmsley
@@ -212,3 +212,35 @@ u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset)
 {
 	return omap2_prm_rmw_mod_reg_bits(mask, bits, OMAP3430_GR_MOD, offset);
 }
+
+/**
+ * omap3xxx_prm_read_pending_irqs - read pending PRM MPU IRQs into @events
+ * @events: ptr to a u32, preallocated by caller
+ *
+ * Read PRM_IRQSTATUS_MPU bits, AND'ed with the currently-enabled PRM
+ * MPU IRQs, and store the result into the u32 pointed to by @events.
+ * No return value.
+ */
+void omap3xxx_prm_read_pending_irqs(unsigned long *events)
+{
+	u32 mask, st;
+
+	/* XXX Can the mask read be avoided (e.g., can it come from RAM?) */
+	mask = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+	st = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
+	events[0] = mask & st;
+}
+
+/**
+ * omap3xxx_prm_ocp_barrier - force buffered MPU writes to the PRM to complete
+ *
+ * Force any buffered writes to the PRM IP block to complete.  Needed
+ * by the PRM IRQ handler, which reads and writes directly to the IP
+ * block, to avoid race conditions after acknowledging or clearing IRQ
+ * bits.  No return value.
+ */
+void omap3xxx_prm_ocp_barrier(void)
+{
+	omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET);
+}
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index cef533d..3ef0e77 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -1,7 +1,7 @@
 /*
  * OMAP2/3 Power/Reset Management (PRM) register definitions
  *
- * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ * Copyright (C) 2007-2009, 2011 Texas Instruments, Inc.
  * Copyright (C) 2008-2010 Nokia Corporation
  * Paul Walmsley
  *
@@ -314,6 +314,11 @@ void omap3_prm_vp_clear_txdone(u8 vp_id);
 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);
+
+/* PRM interrupt-related functions */
+extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
+extern void omap3xxx_prm_ocp_barrier(void);
+
 #endif	/* CONFIG_ARCH_OMAP4 */
 
 #endif
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index 495a31a..9b21154 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -121,3 +121,45 @@ u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset)
 					       OMAP4430_PRM_DEVICE_INST,
 					       offset);
 }
+
+static inline u32 _read_pending_irq_reg(u16 irqen_offs, u16 irqst_offs)
+{
+	u32 mask, st;
+
+	/* XXX read mask from RAM? */
+	mask = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, irqen_offs);
+	st = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, irqst_offs);
+
+	return mask & st;
+}
+
+/**
+ * omap44xx_prm_read_pending_irqs - read pending PRM MPU IRQs into @events
+ * @events: ptr to two consecutive u32s, preallocated by caller
+ *
+ * Read PRM_IRQSTATUS_MPU* bits, AND'ed with the currently-enabled PRM
+ * MPU IRQs, and store the result into the two u32s pointed to by @events.
+ * No return value.
+ */
+void omap44xx_prm_read_pending_irqs(unsigned long *events)
+{
+	events[0] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_OFFSET,
+					  OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
+
+	events[1] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_2_OFFSET,
+					  OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET);
+}
+
+/**
+ * omap44xx_prm_ocp_barrier - force buffered MPU writes to the PRM to complete
+ *
+ * Force any buffered writes to the PRM IP block to complete.  Needed
+ * by the PRM IRQ handler, which reads and writes directly to the IP
+ * block, to avoid race conditions after acknowledging or clearing IRQ
+ * bits.  No return value.
+ */
+void omap44xx_prm_ocp_barrier(void)
+{
+	omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+				OMAP4_REVISION_PRM_OFFSET);
+}
diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h
index 3d66ccd..bd7f248 100644
--- a/arch/arm/mach-omap2/prm44xx.h
+++ b/arch/arm/mach-omap2/prm44xx.h
@@ -1,7 +1,7 @@
 /*
  * OMAP44xx PRM instance offset macros
  *
- * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2011 Texas Instruments, Inc.
  * Copyright (C) 2009-2010 Nokia Corporation
  *
  * Paul Walmsley (paul at pwsan.com)
@@ -763,6 +763,10 @@ 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);
 
+/* PRM interrupt-related functions */
+extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
+extern void omap44xx_prm_ocp_barrier(void);
+
 # endif
 
 #endif

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 4/9] ARM: OMAP: PRCM: add support for chain interrupt handler
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-15 21:36   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel
  Cc: Kevin Hilman, Benoit Cousson, Tony Lindgren, Tero Kristo,
	Govindraj.R, Avinash.H.M

From: Tero Kristo <t-kristo@ti.com>

Introduce a chained interrupt handler mechanism for the PRCM
interrupt, so that individual PRCM event can cleanly be handled by
handlers in separate drivers. We do this by introducing PRCM event
names, which are then matched to the particular PRCM interrupt bit
depending on the specific OMAP SoC being used.

PRCM interrupts have two priority levels, high or normal. High priority
is needed for IO event handling, so that we can be sure that IO events
are processed before other events. This reduces latency for IO event
customers and also prevents incorrect ack sequence on OMAP3.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Avinash.H.M <avinashhm@ti.com>
Cc: Benoit Cousson <b-cousson@ti.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul@pwsan.com: drop some dead code; use SoC-specific pending IRQ
 detection; move code to prm_common.c; add lots of documentation;
 remove saved_mask; add OCP barrier on ISR exit; improved error
 handling; split out per-SoC initialization to a separate patch]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/Makefile      |    5 -
 arch/arm/mach-omap2/prcm-common.h |   63 ++++++++
 arch/arm/mach-omap2/prm_common.c  |  277 +++++++++++++++++++++++++++++++++++++
 3 files changed, 342 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/mach-omap2/prm_common.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index b009f17..2e1ab22 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -14,7 +14,7 @@ clock-common				= clock.o clock_common_data.o \
 
 obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
 obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common)
-obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common)
+obj-$(CONFIG_ARCH_OMAP4) += $(hwmod-common)
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
@@ -77,6 +77,7 @@ endif
 endif
 
 # PRCM
+obj-y					+= prm_common.o
 obj-$(CONFIG_ARCH_OMAP2)		+= prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o \
 					   vc3xxx_data.o vp3xxx_data.o
@@ -86,7 +87,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o \
 obj-$(CONFIG_ARCH_OMAP4)		+= prcm.o cm2xxx_3xxx.o cminst44xx.o \
 					   cm44xx.o prcm_mpu44xx.o \
 					   prminst44xx.o vc44xx_data.o \
-					   vp44xx_data.o
+					   vp44xx_data.o prm44xx.o
 
 # OMAP voltage domains
 voltagedomain-common			:= voltage.o vc.o vp.o
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 0363dcb..76db379 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -4,7 +4,7 @@
 /*
  * OMAP2/3 PRCM base and module definitions
  *
- * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ * Copyright (C) 2007-2009, 2011 Texas Instruments, Inc.
  * Copyright (C) 2007-2009 Nokia Corporation
  *
  * Written by Paul Walmsley
@@ -408,6 +408,67 @@
 extern void __iomem *prm_base;
 extern void __iomem *cm_base;
 extern void __iomem *cm2_base;
+
+/**
+ * struct omap_prcm_irq - describes a PRCM interrupt bit
+ * @name: a short name describing the interrupt type, e.g. "wkup" or "io"
+ * @offset: the bit shift of the interrupt inside the IRQ{ENABLE,STATUS} regs
+ * @priority: should this interrupt be handled before @priority=false IRQs?
+ *
+ * Describes interrupt bits inside the PRM_IRQ{ENABLE,STATUS}_MPU* registers.
+ * On systems with multiple PRM MPU IRQ registers, the bitfields read from
+ * the registers are concatenated, so @offset could be > 31 on these systems -
+ * see omap_prm_irq_handler() for more details.  I/O ring interrupts should
+ * have @priority set to true.
+ */
+struct omap_prcm_irq {
+	const char *name;
+	unsigned int offset;
+	bool priority;
+};
+
+/**
+ * struct omap_prcm_irq_setup - PRCM interrupt controller details
+ * @ack: PRM register offset for the first PRM_IRQSTATUS_MPU register
+ * @mask: PRM register offset for the first PRM_IRQENABLE_MPU register
+ * @nr_regs: number of PRM_IRQ{STATUS,ENABLE}_MPU* registers
+ * @nr_irqs: number of entries in the @irqs array
+ * @irqs: ptr to an array of PRCM interrupt bits (see @nr_irqs)
+ * @irq: MPU IRQ asserted when a PRCM interrupt arrives
+ * @read_pending_irqs: fn ptr to determine if any PRCM IRQs are pending
+ * @ocp_barrier: fn ptr to force buffered PRM writes to complete
+ * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true
+ * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init
+ *
+ * @priority_mask and @base_irq are populated dynamically during
+ * omap_prcm_register_chain_handler() - these fields are not to be
+ * specified in static initializers.
+ */
+struct omap_prcm_irq_setup {
+	u16 ack;
+	u16 mask;
+	u8 nr_regs;
+	u8 nr_irqs;
+	const struct omap_prcm_irq *irqs;
+	int irq;
+	void (*read_pending_irqs)(unsigned long *events);
+	void (*ocp_barrier)(void);
+	u32 *priority_mask;
+	int base_irq;
+};
+
+/* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */
+#define OMAP_PRCM_IRQ(_name, _offset, _priority) {	\
+	.name = _name,					\
+	.offset = _offset,				\
+	.priority = _priority				\
+	}
+
+extern void omap_prcm_irq_cleanup(void);
+extern int omap_prcm_register_chain_handler(
+	struct omap_prcm_irq_setup *irq_setup);
+extern int omap_prcm_event_to_irq(const char *event);
+
 # endif
 
 #endif
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
new file mode 100644
index 0000000..5694be5
--- /dev/null
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -0,0 +1,277 @@
+/*
+ * OMAP2+ common Power & Reset Management (PRM) IP block functions
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * For historical purposes, the API used to configure the PRM
+ * interrupt handler refers to it as the "PRCM interrupt."  The
+ * underlying registers are located in the PRM on OMAP3/4.
+ *
+ * XXX This code should eventually be moved to a PRM driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include <mach/system.h>
+#include <plat/common.h>
+#include <plat/prcm.h>
+#include <plat/irqs.h>
+
+#include "prm2xxx_3xxx.h"
+#include "prm44xx.h"
+
+/*
+ * OMAP_PRCM_MAX_NR_PENDING_REG: maximum number of PRM_IRQ*_MPU regs
+ * XXX this is technically not needed, since
+ * omap_prcm_register_chain_handler() could allocate this based on the
+ * actual amount of memory needed for the SoC
+ */
+#define OMAP_PRCM_MAX_NR_PENDING_REG		2
+
+/*
+ * prcm_irq_chips: an array of all of the "generic IRQ chips" in use
+ * by the PRCM interrupt handler code.  There will be one 'chip' per
+ * PRM_{IRQSTATUS,IRQENABLE}_MPU register pair.  (So OMAP3 will have
+ * one "chip" and OMAP4 will have two.)
+ */
+static struct irq_chip_generic **prcm_irq_chips;
+
+/*
+ * prcm_irq_setup: the PRCM IRQ parameters for the hardware the code
+ * is currently running on.  Defined and passed by initialization code
+ * that calls omap_prcm_register_chain_handler().
+ */
+static struct omap_prcm_irq_setup *prcm_irq_setup;
+
+/* Private functions */
+
+/*
+ * Move priority events from events to priority_events array
+ */
+static void omap_prcm_events_filter_priority(unsigned long *events,
+	unsigned long *priority_events)
+{
+	int i;
+
+	for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
+		priority_events[i] =
+			events[i] & prcm_irq_setup->priority_mask[i];
+		events[i] ^= priority_events[i];
+	}
+}
+
+/*
+ * PRCM Interrupt Handler
+ *
+ * This is a common handler for the OMAP PRCM interrupts. Pending
+ * interrupts are detected by a call to prcm_pending_events and
+ * dispatched accordingly. Clearing of the wakeup events should be
+ * done by the SoC specific individual handlers.
+ */
+static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
+	unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned int virtirq;
+	int nr_irqs = prcm_irq_setup->nr_regs * 32;
+
+	/*
+	 * Loop until all pending irqs are handled, since
+	 * generic_handle_irq() can cause new irqs to come
+	 */
+	while (1) {
+		prcm_irq_setup->read_pending_irqs(pending);
+
+		/* No bit set, then all IRQs are handled */
+		if (find_first_bit(pending, nr_irqs) >= nr_irqs)
+			break;
+
+		omap_prcm_events_filter_priority(pending, priority_pending);
+
+		/*
+		 * Loop on all currently pending irqs so that new irqs
+		 * cannot starve previously pending irqs
+		 */
+
+		/* Serve priority events first */
+		for_each_set_bit(virtirq, priority_pending, nr_irqs)
+			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
+
+		/* Serve normal events next */
+		for_each_set_bit(virtirq, pending, nr_irqs)
+			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
+	}
+	if (chip->irq_ack)
+		chip->irq_ack(&desc->irq_data);
+	if (chip->irq_eoi)
+		chip->irq_eoi(&desc->irq_data);
+	chip->irq_unmask(&desc->irq_data);
+
+	prcm_irq_setup->ocp_barrier(); /* avoid spurious IRQs */
+}
+
+/* Public functions */
+
+/**
+ * omap_prcm_event_to_irq - given a PRCM event name, returns the
+ * corresponding IRQ on which the handler should be registered
+ * @name: name of the PRCM interrupt bit to look up - see struct omap_prcm_irq
+ *
+ * Returns the Linux internal IRQ ID corresponding to @name upon success,
+ * or -ENOENT upon failure.
+ */
+int omap_prcm_event_to_irq(const char *name)
+{
+	int i;
+
+	if (!prcm_irq_setup || !name)
+		return -ENOENT;
+
+	for (i = 0; i < prcm_irq_setup->nr_irqs; i++)
+		if (!strcmp(prcm_irq_setup->irqs[i].name, name))
+			return prcm_irq_setup->base_irq +
+				prcm_irq_setup->irqs[i].offset;
+
+	return -ENOENT;
+}
+
+/**
+ * omap_prcm_irq_cleanup - reverses memory allocated and other steps
+ * done by omap_prcm_register_chain_handler()
+ *
+ * No return value.
+ */
+void omap_prcm_irq_cleanup(void)
+{
+	int i;
+
+	if (!prcm_irq_setup) {
+		pr_err("PRCM: IRQ handler not initialized; cannot cleanup\n");
+		return;
+	}
+
+	if (prcm_irq_chips) {
+		for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
+			if (prcm_irq_chips[i])
+				irq_remove_generic_chip(prcm_irq_chips[i],
+					0xffffffff, 0, 0);
+			prcm_irq_chips[i] = NULL;
+		}
+		kfree(prcm_irq_chips);
+		prcm_irq_chips = NULL;
+	}
+
+	kfree(prcm_irq_setup->priority_mask);
+	prcm_irq_setup->priority_mask = NULL;
+
+	irq_set_chained_handler(prcm_irq_setup->irq, NULL);
+
+	if (prcm_irq_setup->base_irq > 0)
+		irq_free_descs(prcm_irq_setup->base_irq,
+			prcm_irq_setup->nr_regs * 32);
+	prcm_irq_setup->base_irq = 0;
+}
+
+/**
+ * omap_prcm_register_chain_handler - initializes the prcm chained interrupt
+ * handler based on provided parameters
+ * @irq_setup: hardware data about the underlying PRM/PRCM
+ *
+ * Set up the PRCM chained interrupt handler on the PRCM IRQ.  Sets up
+ * one generic IRQ chip per PRM interrupt status/enable register pair.
+ * Returns 0 upon success, -EINVAL if called twice or if invalid
+ * arguments are passed, or -ENOMEM on any other error.
+ */
+int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
+{
+	int nr_regs = irq_setup->nr_regs;
+	u32 mask[OMAP_PRCM_MAX_NR_PENDING_REG];
+	int offset, i;
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+
+	if (!irq_setup)
+		return -EINVAL;
+
+	if (prcm_irq_setup) {
+		pr_err("PRCM: already initialized; won't reinitialize\n");
+		return -EINVAL;
+	}
+
+	if (nr_regs > OMAP_PRCM_MAX_NR_PENDING_REG) {
+		pr_err("PRCM: nr_regs too large\n");
+		return -EINVAL;
+	}
+
+	prcm_irq_setup = irq_setup;
+
+	prcm_irq_chips = kzalloc(sizeof(void *) * nr_regs, GFP_KERNEL);
+	prcm_irq_setup->priority_mask = kzalloc(sizeof(u32) * nr_regs,
+		GFP_KERNEL);
+
+	if (!prcm_irq_chips || !prcm_irq_setup->priority_mask) {
+		pr_err("PRCM: kzalloc failed\n");
+		goto err;
+	}
+
+	memset(mask, 0, sizeof(mask));
+
+	for (i = 0; i < irq_setup->nr_irqs; i++) {
+		offset = irq_setup->irqs[i].offset;
+		mask[offset >> 5] |= 1 << (offset & 0x1f);
+		if (irq_setup->irqs[i].priority)
+			irq_setup->priority_mask[offset >> 5] |=
+				1 << (offset & 0x1f);
+	}
+
+	irq_set_chained_handler(irq_setup->irq, omap_prcm_irq_handler);
+
+	irq_setup->base_irq = irq_alloc_descs(-1, 0, irq_setup->nr_regs * 32,
+		0);
+
+	if (irq_setup->base_irq < 0) {
+		pr_err("PRCM: failed to allocate irq descs: %d\n",
+			irq_setup->base_irq);
+		goto err;
+	}
+
+	for (i = 0; i <= irq_setup->nr_regs; i++) {
+		gc = irq_alloc_generic_chip("PRCM", 1,
+			irq_setup->base_irq + i * 32, prm_base,
+			handle_level_irq);
+
+		if (!gc) {
+			pr_err("PRCM: failed to allocate generic chip\n");
+			goto err;
+		}
+		ct = gc->chip_types;
+		ct->chip.irq_ack = irq_gc_ack_set_bit;
+		ct->chip.irq_mask = irq_gc_mask_clr_bit;
+		ct->chip.irq_unmask = irq_gc_mask_set_bit;
+
+		ct->regs.ack = irq_setup->ack + i * 4;
+		ct->regs.mask = irq_setup->mask + i * 4;
+
+		irq_setup_generic_chip(gc, mask[i], 0, IRQ_NOREQUEST, 0);
+		prcm_irq_chips[i] = gc;
+	}
+
+	return 0;
+
+err:
+	omap_prcm_irq_cleanup();
+	return -ENOMEM;
+}



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 4/9] ARM: OMAP: PRCM: add support for chain interrupt handler
@ 2011-12-15 21:36   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tero Kristo <t-kristo@ti.com>

Introduce a chained interrupt handler mechanism for the PRCM
interrupt, so that individual PRCM event can cleanly be handled by
handlers in separate drivers. We do this by introducing PRCM event
names, which are then matched to the particular PRCM interrupt bit
depending on the specific OMAP SoC being used.

PRCM interrupts have two priority levels, high or normal. High priority
is needed for IO event handling, so that we can be sure that IO events
are processed before other events. This reduces latency for IO event
customers and also prevents incorrect ack sequence on OMAP3.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Avinash.H.M <avinashhm@ti.com>
Cc: Benoit Cousson <b-cousson@ti.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul at pwsan.com: drop some dead code; use SoC-specific pending IRQ
 detection; move code to prm_common.c; add lots of documentation;
 remove saved_mask; add OCP barrier on ISR exit; improved error
 handling; split out per-SoC initialization to a separate patch]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/Makefile      |    5 -
 arch/arm/mach-omap2/prcm-common.h |   63 ++++++++
 arch/arm/mach-omap2/prm_common.c  |  277 +++++++++++++++++++++++++++++++++++++
 3 files changed, 342 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/mach-omap2/prm_common.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index b009f17..2e1ab22 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -14,7 +14,7 @@ clock-common				= clock.o clock_common_data.o \
 
 obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
 obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common)
-obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common)
+obj-$(CONFIG_ARCH_OMAP4) += $(hwmod-common)
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
@@ -77,6 +77,7 @@ endif
 endif
 
 # PRCM
+obj-y					+= prm_common.o
 obj-$(CONFIG_ARCH_OMAP2)		+= prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o \
 					   vc3xxx_data.o vp3xxx_data.o
@@ -86,7 +87,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o \
 obj-$(CONFIG_ARCH_OMAP4)		+= prcm.o cm2xxx_3xxx.o cminst44xx.o \
 					   cm44xx.o prcm_mpu44xx.o \
 					   prminst44xx.o vc44xx_data.o \
-					   vp44xx_data.o
+					   vp44xx_data.o prm44xx.o
 
 # OMAP voltage domains
 voltagedomain-common			:= voltage.o vc.o vp.o
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 0363dcb..76db379 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -4,7 +4,7 @@
 /*
  * OMAP2/3 PRCM base and module definitions
  *
- * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ * Copyright (C) 2007-2009, 2011 Texas Instruments, Inc.
  * Copyright (C) 2007-2009 Nokia Corporation
  *
  * Written by Paul Walmsley
@@ -408,6 +408,67 @@
 extern void __iomem *prm_base;
 extern void __iomem *cm_base;
 extern void __iomem *cm2_base;
+
+/**
+ * struct omap_prcm_irq - describes a PRCM interrupt bit
+ * @name: a short name describing the interrupt type, e.g. "wkup" or "io"
+ * @offset: the bit shift of the interrupt inside the IRQ{ENABLE,STATUS} regs
+ * @priority: should this interrupt be handled before @priority=false IRQs?
+ *
+ * Describes interrupt bits inside the PRM_IRQ{ENABLE,STATUS}_MPU* registers.
+ * On systems with multiple PRM MPU IRQ registers, the bitfields read from
+ * the registers are concatenated, so @offset could be > 31 on these systems -
+ * see omap_prm_irq_handler() for more details.  I/O ring interrupts should
+ * have @priority set to true.
+ */
+struct omap_prcm_irq {
+	const char *name;
+	unsigned int offset;
+	bool priority;
+};
+
+/**
+ * struct omap_prcm_irq_setup - PRCM interrupt controller details
+ * @ack: PRM register offset for the first PRM_IRQSTATUS_MPU register
+ * @mask: PRM register offset for the first PRM_IRQENABLE_MPU register
+ * @nr_regs: number of PRM_IRQ{STATUS,ENABLE}_MPU* registers
+ * @nr_irqs: number of entries in the @irqs array
+ * @irqs: ptr to an array of PRCM interrupt bits (see @nr_irqs)
+ * @irq: MPU IRQ asserted when a PRCM interrupt arrives
+ * @read_pending_irqs: fn ptr to determine if any PRCM IRQs are pending
+ * @ocp_barrier: fn ptr to force buffered PRM writes to complete
+ * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true
+ * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init
+ *
+ * @priority_mask and @base_irq are populated dynamically during
+ * omap_prcm_register_chain_handler() - these fields are not to be
+ * specified in static initializers.
+ */
+struct omap_prcm_irq_setup {
+	u16 ack;
+	u16 mask;
+	u8 nr_regs;
+	u8 nr_irqs;
+	const struct omap_prcm_irq *irqs;
+	int irq;
+	void (*read_pending_irqs)(unsigned long *events);
+	void (*ocp_barrier)(void);
+	u32 *priority_mask;
+	int base_irq;
+};
+
+/* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */
+#define OMAP_PRCM_IRQ(_name, _offset, _priority) {	\
+	.name = _name,					\
+	.offset = _offset,				\
+	.priority = _priority				\
+	}
+
+extern void omap_prcm_irq_cleanup(void);
+extern int omap_prcm_register_chain_handler(
+	struct omap_prcm_irq_setup *irq_setup);
+extern int omap_prcm_event_to_irq(const char *event);
+
 # endif
 
 #endif
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
new file mode 100644
index 0000000..5694be5
--- /dev/null
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -0,0 +1,277 @@
+/*
+ * OMAP2+ common Power & Reset Management (PRM) IP block functions
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * For historical purposes, the API used to configure the PRM
+ * interrupt handler refers to it as the "PRCM interrupt."  The
+ * underlying registers are located in the PRM on OMAP3/4.
+ *
+ * XXX This code should eventually be moved to a PRM driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include <mach/system.h>
+#include <plat/common.h>
+#include <plat/prcm.h>
+#include <plat/irqs.h>
+
+#include "prm2xxx_3xxx.h"
+#include "prm44xx.h"
+
+/*
+ * OMAP_PRCM_MAX_NR_PENDING_REG: maximum number of PRM_IRQ*_MPU regs
+ * XXX this is technically not needed, since
+ * omap_prcm_register_chain_handler() could allocate this based on the
+ * actual amount of memory needed for the SoC
+ */
+#define OMAP_PRCM_MAX_NR_PENDING_REG		2
+
+/*
+ * prcm_irq_chips: an array of all of the "generic IRQ chips" in use
+ * by the PRCM interrupt handler code.  There will be one 'chip' per
+ * PRM_{IRQSTATUS,IRQENABLE}_MPU register pair.  (So OMAP3 will have
+ * one "chip" and OMAP4 will have two.)
+ */
+static struct irq_chip_generic **prcm_irq_chips;
+
+/*
+ * prcm_irq_setup: the PRCM IRQ parameters for the hardware the code
+ * is currently running on.  Defined and passed by initialization code
+ * that calls omap_prcm_register_chain_handler().
+ */
+static struct omap_prcm_irq_setup *prcm_irq_setup;
+
+/* Private functions */
+
+/*
+ * Move priority events from events to priority_events array
+ */
+static void omap_prcm_events_filter_priority(unsigned long *events,
+	unsigned long *priority_events)
+{
+	int i;
+
+	for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
+		priority_events[i] =
+			events[i] & prcm_irq_setup->priority_mask[i];
+		events[i] ^= priority_events[i];
+	}
+}
+
+/*
+ * PRCM Interrupt Handler
+ *
+ * This is a common handler for the OMAP PRCM interrupts. Pending
+ * interrupts are detected by a call to prcm_pending_events and
+ * dispatched accordingly. Clearing of the wakeup events should be
+ * done by the SoC specific individual handlers.
+ */
+static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
+	unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned int virtirq;
+	int nr_irqs = prcm_irq_setup->nr_regs * 32;
+
+	/*
+	 * Loop until all pending irqs are handled, since
+	 * generic_handle_irq() can cause new irqs to come
+	 */
+	while (1) {
+		prcm_irq_setup->read_pending_irqs(pending);
+
+		/* No bit set, then all IRQs are handled */
+		if (find_first_bit(pending, nr_irqs) >= nr_irqs)
+			break;
+
+		omap_prcm_events_filter_priority(pending, priority_pending);
+
+		/*
+		 * Loop on all currently pending irqs so that new irqs
+		 * cannot starve previously pending irqs
+		 */
+
+		/* Serve priority events first */
+		for_each_set_bit(virtirq, priority_pending, nr_irqs)
+			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
+
+		/* Serve normal events next */
+		for_each_set_bit(virtirq, pending, nr_irqs)
+			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
+	}
+	if (chip->irq_ack)
+		chip->irq_ack(&desc->irq_data);
+	if (chip->irq_eoi)
+		chip->irq_eoi(&desc->irq_data);
+	chip->irq_unmask(&desc->irq_data);
+
+	prcm_irq_setup->ocp_barrier(); /* avoid spurious IRQs */
+}
+
+/* Public functions */
+
+/**
+ * omap_prcm_event_to_irq - given a PRCM event name, returns the
+ * corresponding IRQ on which the handler should be registered
+ * @name: name of the PRCM interrupt bit to look up - see struct omap_prcm_irq
+ *
+ * Returns the Linux internal IRQ ID corresponding to @name upon success,
+ * or -ENOENT upon failure.
+ */
+int omap_prcm_event_to_irq(const char *name)
+{
+	int i;
+
+	if (!prcm_irq_setup || !name)
+		return -ENOENT;
+
+	for (i = 0; i < prcm_irq_setup->nr_irqs; i++)
+		if (!strcmp(prcm_irq_setup->irqs[i].name, name))
+			return prcm_irq_setup->base_irq +
+				prcm_irq_setup->irqs[i].offset;
+
+	return -ENOENT;
+}
+
+/**
+ * omap_prcm_irq_cleanup - reverses memory allocated and other steps
+ * done by omap_prcm_register_chain_handler()
+ *
+ * No return value.
+ */
+void omap_prcm_irq_cleanup(void)
+{
+	int i;
+
+	if (!prcm_irq_setup) {
+		pr_err("PRCM: IRQ handler not initialized; cannot cleanup\n");
+		return;
+	}
+
+	if (prcm_irq_chips) {
+		for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
+			if (prcm_irq_chips[i])
+				irq_remove_generic_chip(prcm_irq_chips[i],
+					0xffffffff, 0, 0);
+			prcm_irq_chips[i] = NULL;
+		}
+		kfree(prcm_irq_chips);
+		prcm_irq_chips = NULL;
+	}
+
+	kfree(prcm_irq_setup->priority_mask);
+	prcm_irq_setup->priority_mask = NULL;
+
+	irq_set_chained_handler(prcm_irq_setup->irq, NULL);
+
+	if (prcm_irq_setup->base_irq > 0)
+		irq_free_descs(prcm_irq_setup->base_irq,
+			prcm_irq_setup->nr_regs * 32);
+	prcm_irq_setup->base_irq = 0;
+}
+
+/**
+ * omap_prcm_register_chain_handler - initializes the prcm chained interrupt
+ * handler based on provided parameters
+ * @irq_setup: hardware data about the underlying PRM/PRCM
+ *
+ * Set up the PRCM chained interrupt handler on the PRCM IRQ.  Sets up
+ * one generic IRQ chip per PRM interrupt status/enable register pair.
+ * Returns 0 upon success, -EINVAL if called twice or if invalid
+ * arguments are passed, or -ENOMEM on any other error.
+ */
+int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
+{
+	int nr_regs = irq_setup->nr_regs;
+	u32 mask[OMAP_PRCM_MAX_NR_PENDING_REG];
+	int offset, i;
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+
+	if (!irq_setup)
+		return -EINVAL;
+
+	if (prcm_irq_setup) {
+		pr_err("PRCM: already initialized; won't reinitialize\n");
+		return -EINVAL;
+	}
+
+	if (nr_regs > OMAP_PRCM_MAX_NR_PENDING_REG) {
+		pr_err("PRCM: nr_regs too large\n");
+		return -EINVAL;
+	}
+
+	prcm_irq_setup = irq_setup;
+
+	prcm_irq_chips = kzalloc(sizeof(void *) * nr_regs, GFP_KERNEL);
+	prcm_irq_setup->priority_mask = kzalloc(sizeof(u32) * nr_regs,
+		GFP_KERNEL);
+
+	if (!prcm_irq_chips || !prcm_irq_setup->priority_mask) {
+		pr_err("PRCM: kzalloc failed\n");
+		goto err;
+	}
+
+	memset(mask, 0, sizeof(mask));
+
+	for (i = 0; i < irq_setup->nr_irqs; i++) {
+		offset = irq_setup->irqs[i].offset;
+		mask[offset >> 5] |= 1 << (offset & 0x1f);
+		if (irq_setup->irqs[i].priority)
+			irq_setup->priority_mask[offset >> 5] |=
+				1 << (offset & 0x1f);
+	}
+
+	irq_set_chained_handler(irq_setup->irq, omap_prcm_irq_handler);
+
+	irq_setup->base_irq = irq_alloc_descs(-1, 0, irq_setup->nr_regs * 32,
+		0);
+
+	if (irq_setup->base_irq < 0) {
+		pr_err("PRCM: failed to allocate irq descs: %d\n",
+			irq_setup->base_irq);
+		goto err;
+	}
+
+	for (i = 0; i <= irq_setup->nr_regs; i++) {
+		gc = irq_alloc_generic_chip("PRCM", 1,
+			irq_setup->base_irq + i * 32, prm_base,
+			handle_level_irq);
+
+		if (!gc) {
+			pr_err("PRCM: failed to allocate generic chip\n");
+			goto err;
+		}
+		ct = gc->chip_types;
+		ct->chip.irq_ack = irq_gc_ack_set_bit;
+		ct->chip.irq_mask = irq_gc_mask_clr_bit;
+		ct->chip.irq_unmask = irq_gc_mask_set_bit;
+
+		ct->regs.ack = irq_setup->ack + i * 4;
+		ct->regs.mask = irq_setup->mask + i * 4;
+
+		irq_setup_generic_chip(gc, mask[i], 0, IRQ_NOREQUEST, 0);
+		prcm_irq_chips[i] = gc;
+	}
+
+	return 0;
+
+err:
+	omap_prcm_irq_cleanup();
+	return -ENOMEM;
+}

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 5/9] ARM: OMAP: PRCM: add suspend prepare / finish support
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-15 21:36   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: Tero Kristo, Kevin Hilman

From: Tero Kristo <t-kristo@ti.com>

PRCM chain handler needs to disable forwarding of interrupts during
suspend, because runtime PM is disabled and most of the drivers
are potentially not able to handle interrupts coming at this time.

This patch masks all the PRCM interrupt events if a PRCM interrupt
occurs during suspend, but does not ack them. Once suspend finish
is called, all the masked events will be re-enabled, which causes
immediate PRCM interrupt and handles the postponed event.

The suspend prepare and complete  callbacks will be called from
pm34xx.c / pm44xx.c files in the following patches.

The functions defined in this patch should eventually be moved to
suspend->prepare and suspend->finish driver hooks, once the PRCM
chain handler will be made as its own driver.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul@pwsan.com: add kerneldoc, add omap_prcm_irq_setup.saved_mask, add fn
 ptrs for save_and_clear_irqen() and restore_irqen()]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/prcm-common.h  |   16 +++++++++++-
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   37 ++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.h |    2 ++
 arch/arm/mach-omap2/prm44xx.c      |   48 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm44xx.h      |    2 ++
 arch/arm/mach-omap2/prm_common.c   |   47 ++++++++++++++++++++++++++++++++++-
 6 files changed, 148 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 76db379..0f69d8f 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -437,11 +437,16 @@ struct omap_prcm_irq {
  * @irq: MPU IRQ asserted when a PRCM interrupt arrives
  * @read_pending_irqs: fn ptr to determine if any PRCM IRQs are pending
  * @ocp_barrier: fn ptr to force buffered PRM writes to complete
+ * @save_and_clear_irqen: fn ptr to save and clear IRQENABLE regs
+ * @restore_irqen: fn ptr to save and clear IRQENABLE regs
+ * @saved_mask: IRQENABLE regs are saved here during suspend
  * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true
  * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init
+ * @suspended: set to true after Linux suspend code has called our ->prepare()
+ * @suspend_save_flag: set to true after IRQ masks have been saved and disabled
  *
- * @priority_mask and @base_irq are populated dynamically during
- * omap_prcm_register_chain_handler() - these fields are not to be
+ * @saved_mask, @priority_mask, @base_irq, @suspended, and
+ * @suspend_save_flag are populated dynamically, and are not to be
  * specified in static initializers.
  */
 struct omap_prcm_irq_setup {
@@ -453,8 +458,13 @@ struct omap_prcm_irq_setup {
 	int irq;
 	void (*read_pending_irqs)(unsigned long *events);
 	void (*ocp_barrier)(void);
+	void (*save_and_clear_irqen)(u32 *saved_mask);
+	void (*restore_irqen)(u32 *saved_mask);
+	u32 *saved_mask;
 	u32 *priority_mask;
 	int base_irq;
+	bool suspended;
+	bool suspend_save_flag;
 };
 
 /* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */
@@ -468,6 +478,8 @@ extern void omap_prcm_irq_cleanup(void);
 extern int omap_prcm_register_chain_handler(
 	struct omap_prcm_irq_setup *irq_setup);
 extern int omap_prcm_event_to_irq(const char *event);
+extern void omap_prcm_irq_prepare(void);
+extern void omap_prcm_irq_complete(void);
 
 # endif
 
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index 177c3dd..58d9ce70 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -244,3 +244,40 @@ void omap3xxx_prm_ocp_barrier(void)
 {
 	omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET);
 }
+
+/**
+ * omap3xxx_prm_save_and_clear_irqen - save/clear PRM_IRQENABLE_MPU reg
+ * @saved_mask: ptr to a u32 array to save IRQENABLE bits
+ *
+ * Save the PRM_IRQENABLE_MPU register to @saved_mask.  @saved_mask
+ * must be allocated by the caller.  Intended to be used in the PRM
+ * interrupt handler suspend callback.  The OCP barrier is needed to
+ * ensure the write to disable PRM interrupts reaches the PRM before
+ * returning; otherwise, spurious interrupts might occur.  No return
+ * value.
+ */
+void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask)
+{
+	saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD,
+					       OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+	omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+
+	/* OCP barrier */
+	omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET);
+}
+
+/**
+ * omap3xxx_prm_restore_irqen - set PRM_IRQENABLE_MPU register from args
+ * @saved_mask: ptr to a u32 array of IRQENABLE bits saved previously
+ *
+ * Restore the PRM_IRQENABLE_MPU register from @saved_mask.  Intended
+ * to be used in the PRM interrupt handler resume callback to restore
+ * values saved by omap3xxx_prm_save_and_clear_irqen().  No OCP
+ * barrier should be needed here; any pending PRM interrupts will fire
+ * once the writes reach the PRM.  No return value.
+ */
+void omap3xxx_prm_restore_irqen(u32 *saved_mask)
+{
+	omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD,
+				OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+}
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index 3ef0e77..70ac2a1 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -318,6 +318,8 @@ extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
 /* 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 */
 
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index 9b21154..c4be5d9 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -163,3 +163,51 @@ void omap44xx_prm_ocp_barrier(void)
 	omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
 				OMAP4_REVISION_PRM_OFFSET);
 }
+
+/**
+ * omap44xx_prm_save_and_clear_irqen - save/clear PRM_IRQENABLE_MPU* regs
+ * @saved_mask: ptr to a u32 array to save IRQENABLE bits
+ *
+ * Save the PRM_IRQENABLE_MPU and PRM_IRQENABLE_MPU_2 registers to
+ * @saved_mask.  @saved_mask must be allocated by the caller.
+ * Intended to be used in the PRM interrupt handler suspend callback.
+ * The OCP barrier is needed to ensure the write to disable PRM
+ * interrupts reaches the PRM before returning; otherwise, spurious
+ * interrupts might occur.  No return value.
+ */
+void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
+{
+	saved_mask[0] =
+		omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+					OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
+	saved_mask[1] =
+		omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+					OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET);
+
+	omap4_prm_write_inst_reg(0, OMAP4430_PRM_DEVICE_INST,
+				 OMAP4_PRM_IRQENABLE_MPU_OFFSET);
+	omap4_prm_write_inst_reg(0, OMAP4430_PRM_DEVICE_INST,
+				 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
+
+	/* OCP barrier */
+	omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+				OMAP4_REVISION_PRM_OFFSET);
+}
+
+/**
+ * omap44xx_prm_restore_irqen - set PRM_IRQENABLE_MPU* registers from args
+ * @saved_mask: ptr to a u32 array of IRQENABLE bits saved previously
+ *
+ * Restore the PRM_IRQENABLE_MPU and PRM_IRQENABLE_MPU_2 registers from
+ * @saved_mask.  Intended to be used in the PRM interrupt handler resume
+ * callback to restore values saved by omap44xx_prm_save_and_clear_irqen().
+ * No OCP barrier should be needed here; any pending PRM interrupts will fire
+ * once the writes reach the PRM.  No return value.
+ */
+void omap44xx_prm_restore_irqen(u32 *saved_mask)
+{
+	omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_DEVICE_INST,
+				 OMAP4_PRM_IRQENABLE_MPU_OFFSET);
+	omap4_prm_write_inst_reg(saved_mask[1], OMAP4430_PRM_DEVICE_INST,
+				 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
+}
diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h
index bd7f248..7978092 100644
--- a/arch/arm/mach-omap2/prm44xx.h
+++ b/arch/arm/mach-omap2/prm44xx.h
@@ -766,6 +766,8 @@ extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
 /* PRM interrupt-related functions */
 extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
 extern void omap44xx_prm_ocp_barrier(void);
+extern void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask);
+extern void omap44xx_prm_restore_irqen(u32 *saved_mask);
 
 # endif
 
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index 5694be5..860118a 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -89,10 +89,25 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
 	int nr_irqs = prcm_irq_setup->nr_regs * 32;
 
 	/*
+	 * If we are suspended, mask all interrupts from PRCM level,
+	 * this does not ack them, and they will be pending until we
+	 * re-enable the interrupts, at which point the
+	 * omap_prcm_irq_handler will be executed again.  The
+	 * _save_and_clear_irqen() function must ensure that the PRM
+	 * write to disable all IRQs has reached the PRM before
+	 * returning, or spurious PRCM interrupts may occur during
+	 * suspend.
+	 */
+	if (prcm_irq_setup->suspended) {
+		prcm_irq_setup->save_and_clear_irqen(prcm_irq_setup->saved_mask);
+		prcm_irq_setup->suspend_save_flag = true;
+	}
+
+	/*
 	 * Loop until all pending irqs are handled, since
 	 * generic_handle_irq() can cause new irqs to come
 	 */
-	while (1) {
+	while (!prcm_irq_setup->suspended) {
 		prcm_irq_setup->read_pending_irqs(pending);
 
 		/* No bit set, then all IRQs are handled */
@@ -174,6 +189,9 @@ void omap_prcm_irq_cleanup(void)
 		prcm_irq_chips = NULL;
 	}
 
+	kfree(prcm_irq_setup->saved_mask);
+	prcm_irq_setup->saved_mask = NULL;
+
 	kfree(prcm_irq_setup->priority_mask);
 	prcm_irq_setup->priority_mask = NULL;
 
@@ -185,6 +203,29 @@ void omap_prcm_irq_cleanup(void)
 	prcm_irq_setup->base_irq = 0;
 }
 
+void omap_prcm_irq_prepare(void)
+{
+	prcm_irq_setup->suspended = true;
+}
+
+void omap_prcm_irq_complete(void)
+{
+	prcm_irq_setup->suspended = false;
+
+	/* If we have not saved the masks, do not attempt to restore */
+	if (!prcm_irq_setup->suspend_save_flag)
+		return;
+
+	prcm_irq_setup->suspend_save_flag = false;
+
+	/*
+	 * Re-enable all masked PRCM irq sources, this causes the PRCM
+	 * interrupt to fire immediately if the events were masked
+	 * previously in the chain handler
+	 */
+	prcm_irq_setup->restore_irqen(prcm_irq_setup->saved_mask);
+}
+
 /**
  * omap_prcm_register_chain_handler - initializes the prcm chained interrupt
  * handler based on provided parameters
@@ -219,10 +260,12 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
 	prcm_irq_setup = irq_setup;
 
 	prcm_irq_chips = kzalloc(sizeof(void *) * nr_regs, GFP_KERNEL);
+	prcm_irq_setup->saved_mask = kzalloc(sizeof(u32) * nr_regs, GFP_KERNEL);
 	prcm_irq_setup->priority_mask = kzalloc(sizeof(u32) * nr_regs,
 		GFP_KERNEL);
 
-	if (!prcm_irq_chips || !prcm_irq_setup->priority_mask) {
+	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask ||
+	    !prcm_irq_setup->priority_mask) {
 		pr_err("PRCM: kzalloc failed\n");
 		goto err;
 	}



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 5/9] ARM: OMAP: PRCM: add suspend prepare / finish support
@ 2011-12-15 21:36   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tero Kristo <t-kristo@ti.com>

PRCM chain handler needs to disable forwarding of interrupts during
suspend, because runtime PM is disabled and most of the drivers
are potentially not able to handle interrupts coming at this time.

This patch masks all the PRCM interrupt events if a PRCM interrupt
occurs during suspend, but does not ack them. Once suspend finish
is called, all the masked events will be re-enabled, which causes
immediate PRCM interrupt and handles the postponed event.

The suspend prepare and complete  callbacks will be called from
pm34xx.c / pm44xx.c files in the following patches.

The functions defined in this patch should eventually be moved to
suspend->prepare and suspend->finish driver hooks, once the PRCM
chain handler will be made as its own driver.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul at pwsan.com: add kerneldoc, add omap_prcm_irq_setup.saved_mask, add fn
 ptrs for save_and_clear_irqen() and restore_irqen()]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/prcm-common.h  |   16 +++++++++++-
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   37 ++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.h |    2 ++
 arch/arm/mach-omap2/prm44xx.c      |   48 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm44xx.h      |    2 ++
 arch/arm/mach-omap2/prm_common.c   |   47 ++++++++++++++++++++++++++++++++++-
 6 files changed, 148 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 76db379..0f69d8f 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -437,11 +437,16 @@ struct omap_prcm_irq {
  * @irq: MPU IRQ asserted when a PRCM interrupt arrives
  * @read_pending_irqs: fn ptr to determine if any PRCM IRQs are pending
  * @ocp_barrier: fn ptr to force buffered PRM writes to complete
+ * @save_and_clear_irqen: fn ptr to save and clear IRQENABLE regs
+ * @restore_irqen: fn ptr to save and clear IRQENABLE regs
+ * @saved_mask: IRQENABLE regs are saved here during suspend
  * @priority_mask: 1 bit per IRQ, set to 1 if omap_prcm_irq.priority = true
  * @base_irq: base dynamic IRQ number, returned from irq_alloc_descs() in init
+ * @suspended: set to true after Linux suspend code has called our ->prepare()
+ * @suspend_save_flag: set to true after IRQ masks have been saved and disabled
  *
- * @priority_mask and @base_irq are populated dynamically during
- * omap_prcm_register_chain_handler() - these fields are not to be
+ * @saved_mask, @priority_mask, @base_irq, @suspended, and
+ * @suspend_save_flag are populated dynamically, and are not to be
  * specified in static initializers.
  */
 struct omap_prcm_irq_setup {
@@ -453,8 +458,13 @@ struct omap_prcm_irq_setup {
 	int irq;
 	void (*read_pending_irqs)(unsigned long *events);
 	void (*ocp_barrier)(void);
+	void (*save_and_clear_irqen)(u32 *saved_mask);
+	void (*restore_irqen)(u32 *saved_mask);
+	u32 *saved_mask;
 	u32 *priority_mask;
 	int base_irq;
+	bool suspended;
+	bool suspend_save_flag;
 };
 
 /* OMAP_PRCM_IRQ: convenience macro for creating struct omap_prcm_irq records */
@@ -468,6 +478,8 @@ extern void omap_prcm_irq_cleanup(void);
 extern int omap_prcm_register_chain_handler(
 	struct omap_prcm_irq_setup *irq_setup);
 extern int omap_prcm_event_to_irq(const char *event);
+extern void omap_prcm_irq_prepare(void);
+extern void omap_prcm_irq_complete(void);
 
 # endif
 
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index 177c3dd..58d9ce70 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -244,3 +244,40 @@ void omap3xxx_prm_ocp_barrier(void)
 {
 	omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET);
 }
+
+/**
+ * omap3xxx_prm_save_and_clear_irqen - save/clear PRM_IRQENABLE_MPU reg
+ * @saved_mask: ptr to a u32 array to save IRQENABLE bits
+ *
+ * Save the PRM_IRQENABLE_MPU register to @saved_mask.  @saved_mask
+ * must be allocated by the caller.  Intended to be used in the PRM
+ * interrupt handler suspend callback.  The OCP barrier is needed to
+ * ensure the write to disable PRM interrupts reaches the PRM before
+ * returning; otherwise, spurious interrupts might occur.  No return
+ * value.
+ */
+void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask)
+{
+	saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD,
+					       OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+	omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+
+	/* OCP barrier */
+	omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET);
+}
+
+/**
+ * omap3xxx_prm_restore_irqen - set PRM_IRQENABLE_MPU register from args
+ * @saved_mask: ptr to a u32 array of IRQENABLE bits saved previously
+ *
+ * Restore the PRM_IRQENABLE_MPU register from @saved_mask.  Intended
+ * to be used in the PRM interrupt handler resume callback to restore
+ * values saved by omap3xxx_prm_save_and_clear_irqen().  No OCP
+ * barrier should be needed here; any pending PRM interrupts will fire
+ * once the writes reach the PRM.  No return value.
+ */
+void omap3xxx_prm_restore_irqen(u32 *saved_mask)
+{
+	omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD,
+				OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+}
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index 3ef0e77..70ac2a1 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -318,6 +318,8 @@ extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
 /* 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 */
 
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index 9b21154..c4be5d9 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -163,3 +163,51 @@ void omap44xx_prm_ocp_barrier(void)
 	omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
 				OMAP4_REVISION_PRM_OFFSET);
 }
+
+/**
+ * omap44xx_prm_save_and_clear_irqen - save/clear PRM_IRQENABLE_MPU* regs
+ * @saved_mask: ptr to a u32 array to save IRQENABLE bits
+ *
+ * Save the PRM_IRQENABLE_MPU and PRM_IRQENABLE_MPU_2 registers to
+ * @saved_mask.  @saved_mask must be allocated by the caller.
+ * Intended to be used in the PRM interrupt handler suspend callback.
+ * The OCP barrier is needed to ensure the write to disable PRM
+ * interrupts reaches the PRM before returning; otherwise, spurious
+ * interrupts might occur.  No return value.
+ */
+void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
+{
+	saved_mask[0] =
+		omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+					OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
+	saved_mask[1] =
+		omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+					OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET);
+
+	omap4_prm_write_inst_reg(0, OMAP4430_PRM_DEVICE_INST,
+				 OMAP4_PRM_IRQENABLE_MPU_OFFSET);
+	omap4_prm_write_inst_reg(0, OMAP4430_PRM_DEVICE_INST,
+				 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
+
+	/* OCP barrier */
+	omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
+				OMAP4_REVISION_PRM_OFFSET);
+}
+
+/**
+ * omap44xx_prm_restore_irqen - set PRM_IRQENABLE_MPU* registers from args
+ * @saved_mask: ptr to a u32 array of IRQENABLE bits saved previously
+ *
+ * Restore the PRM_IRQENABLE_MPU and PRM_IRQENABLE_MPU_2 registers from
+ * @saved_mask.  Intended to be used in the PRM interrupt handler resume
+ * callback to restore values saved by omap44xx_prm_save_and_clear_irqen().
+ * No OCP barrier should be needed here; any pending PRM interrupts will fire
+ * once the writes reach the PRM.  No return value.
+ */
+void omap44xx_prm_restore_irqen(u32 *saved_mask)
+{
+	omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_DEVICE_INST,
+				 OMAP4_PRM_IRQENABLE_MPU_OFFSET);
+	omap4_prm_write_inst_reg(saved_mask[1], OMAP4430_PRM_DEVICE_INST,
+				 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
+}
diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h
index bd7f248..7978092 100644
--- a/arch/arm/mach-omap2/prm44xx.h
+++ b/arch/arm/mach-omap2/prm44xx.h
@@ -766,6 +766,8 @@ extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
 /* PRM interrupt-related functions */
 extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
 extern void omap44xx_prm_ocp_barrier(void);
+extern void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask);
+extern void omap44xx_prm_restore_irqen(u32 *saved_mask);
 
 # endif
 
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index 5694be5..860118a 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -89,10 +89,25 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
 	int nr_irqs = prcm_irq_setup->nr_regs * 32;
 
 	/*
+	 * If we are suspended, mask all interrupts from PRCM level,
+	 * this does not ack them, and they will be pending until we
+	 * re-enable the interrupts, at which point the
+	 * omap_prcm_irq_handler will be executed again.  The
+	 * _save_and_clear_irqen() function must ensure that the PRM
+	 * write to disable all IRQs has reached the PRM before
+	 * returning, or spurious PRCM interrupts may occur during
+	 * suspend.
+	 */
+	if (prcm_irq_setup->suspended) {
+		prcm_irq_setup->save_and_clear_irqen(prcm_irq_setup->saved_mask);
+		prcm_irq_setup->suspend_save_flag = true;
+	}
+
+	/*
 	 * Loop until all pending irqs are handled, since
 	 * generic_handle_irq() can cause new irqs to come
 	 */
-	while (1) {
+	while (!prcm_irq_setup->suspended) {
 		prcm_irq_setup->read_pending_irqs(pending);
 
 		/* No bit set, then all IRQs are handled */
@@ -174,6 +189,9 @@ void omap_prcm_irq_cleanup(void)
 		prcm_irq_chips = NULL;
 	}
 
+	kfree(prcm_irq_setup->saved_mask);
+	prcm_irq_setup->saved_mask = NULL;
+
 	kfree(prcm_irq_setup->priority_mask);
 	prcm_irq_setup->priority_mask = NULL;
 
@@ -185,6 +203,29 @@ void omap_prcm_irq_cleanup(void)
 	prcm_irq_setup->base_irq = 0;
 }
 
+void omap_prcm_irq_prepare(void)
+{
+	prcm_irq_setup->suspended = true;
+}
+
+void omap_prcm_irq_complete(void)
+{
+	prcm_irq_setup->suspended = false;
+
+	/* If we have not saved the masks, do not attempt to restore */
+	if (!prcm_irq_setup->suspend_save_flag)
+		return;
+
+	prcm_irq_setup->suspend_save_flag = false;
+
+	/*
+	 * Re-enable all masked PRCM irq sources, this causes the PRCM
+	 * interrupt to fire immediately if the events were masked
+	 * previously in the chain handler
+	 */
+	prcm_irq_setup->restore_irqen(prcm_irq_setup->saved_mask);
+}
+
 /**
  * omap_prcm_register_chain_handler - initializes the prcm chained interrupt
  * handler based on provided parameters
@@ -219,10 +260,12 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
 	prcm_irq_setup = irq_setup;
 
 	prcm_irq_chips = kzalloc(sizeof(void *) * nr_regs, GFP_KERNEL);
+	prcm_irq_setup->saved_mask = kzalloc(sizeof(u32) * nr_regs, GFP_KERNEL);
 	prcm_irq_setup->priority_mask = kzalloc(sizeof(u32) * nr_regs,
 		GFP_KERNEL);
 
-	if (!prcm_irq_chips || !prcm_irq_setup->priority_mask) {
+	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask ||
+	    !prcm_irq_setup->priority_mask) {
 		pr_err("PRCM: kzalloc failed\n");
 		goto err;
 	}

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 6/9] ARM: OMAP2+: mux: add support for PAD wakeup interrupts
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-15 21:36   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel
  Cc: Tero Kristo, Govindraj.R, Tony Lindgren, Kevin Hilman

From: Tero Kristo <t-kristo@ti.com>

OMAP mux now parses active wakeup events from pad registers and calls
corresponding hwmod ISRs once a wakeup is detected. This is
accomplished by registering an interrupt handler for PRCM IO event,
which is raised every time the HW detects wakeups.

[paul@pwsan.com: This patch is a merge of Govindraj R's "ARM: OMAP2+:
hwmod: Add API to check IO PAD wakeup status" patch, Tero Kristo's
"ARM: OMAP2+: mux: add support for PAD wakeup interrupts" patch, and
part of Tero's "ARM: OMAP: mux: add support for selecting mpu_irq for
each wakeup pad" patch.]

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
[paul@pwsan.com: reduced indentation level; renamed omap_hwmod function;
 improved function documentation; modified to iterate only through dynamic
 pads; modified to skip pads where idle mode doesn't enable wakeups; split
 patches]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/mux.c                    |   83 ++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    1 
 2 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index a474c81..e1cc75d 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -32,6 +32,8 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include <asm/system.h>
 
@@ -39,6 +41,7 @@
 
 #include "control.h"
 #include "mux.h"
+#include "prm.h"
 
 #define OMAP_MUX_BASE_OFFSET		0x30	/* Offset from CTRL_BASE */
 #define OMAP_MUX_BASE_SZ		0x5ca
@@ -353,6 +356,78 @@ err1:
 	return NULL;
 }
 
+/**
+ * omap_hwmod_mux_scan_wakeups - omap hwmod scan wakeup pads
+ * @hmux: Pads for a hwmod
+ * @mpu_irqs: MPU irq array for a hwmod
+ *
+ * Scans the wakeup status of pads for a single hwmod.  If an irq
+ * array is defined for this mux, the parser will call the registered
+ * ISRs for corresponding pads, otherwise the parser will stop at the
+ * first wakeup active pad and return.  Returns true if there is a
+ * pending and non-served wakeup event for the mux, otherwise false.
+ */
+static bool omap_hwmod_mux_scan_wakeups(struct omap_hwmod_mux_info *hmux,
+		struct omap_hwmod_irq_info *mpu_irqs)
+{
+	int i, irq;
+	unsigned int val;
+	u32 handled_irqs = 0;
+
+	for (i = 0; i < hmux->nr_pads_dynamic; i++) {
+		struct omap_device_pad *pad = hmux->pads_dynamic[i];
+
+		if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP) ||
+		    !(pad->idle & OMAP_WAKEUP_EN))
+			continue;
+
+		val = omap_mux_read(pad->partition, pad->mux->reg_offset);
+		if (!(val & OMAP_WAKEUP_EVENT))
+			continue;
+
+		if (!hmux->irqs)
+			return true;
+
+		irq = hmux->irqs[i];
+		/* make sure we only handle each irq once */
+		if (handled_irqs & 1 << irq)
+			continue;
+
+		handled_irqs |= 1 << irq;
+
+		generic_handle_irq(mpu_irqs[irq].irq);
+	}
+
+	return false;
+}
+
+/**
+ * _omap_hwmod_mux_handle_irq - Process wakeup events for a single hwmod
+ *
+ * Checks a single hwmod for every wakeup capable pad to see if there is an
+ * active wakeup event. If this is the case, call the corresponding ISR.
+ */
+static int _omap_hwmod_mux_handle_irq(struct omap_hwmod *oh, void *data)
+{
+	if (!oh->mux || !oh->mux->enabled)
+		return 0;
+	if (omap_hwmod_mux_scan_wakeups(oh->mux, oh->mpu_irqs))
+		generic_handle_irq(oh->mpu_irqs[0].irq);
+	return 0;
+}
+
+/**
+ * omap_hwmod_mux_handle_irq - Process pad wakeup irqs.
+ *
+ * Calls a function for each registered omap_hwmod to check
+ * pad wakeup statuses.
+ */
+static irqreturn_t omap_hwmod_mux_handle_irq(int irq, void *unused)
+{
+	omap_hwmod_for_each(_omap_hwmod_mux_handle_irq, NULL);
+	return IRQ_HANDLED;
+}
+
 /* Assumes the calling function takes care of locking */
 void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
 {
@@ -717,6 +792,7 @@ static void __init omap_mux_free_names(struct omap_mux *m)
 static int __init omap_mux_late_init(void)
 {
 	struct omap_mux_partition *partition;
+	int ret;
 
 	list_for_each_entry(partition, &mux_partitions, node) {
 		struct omap_mux_entry *e, *tmp;
@@ -737,6 +813,13 @@ static int __init omap_mux_late_init(void)
 		}
 	}
 
+	ret = request_irq(omap_prcm_event_to_irq("io"),
+		omap_hwmod_mux_handle_irq, IRQF_SHARED | IRQF_NO_SUSPEND,
+			"hwmod_io", omap_mux_late_init);
+
+	if (ret)
+		pr_warning("mux: Failed to setup hwmod io irq %d\n", ret);
+
 	omap_mux_dbg_init();
 
 	return 0;
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 8b372ed..f705492 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -97,6 +97,7 @@ struct omap_hwmod_mux_info {
 	struct omap_device_pad		*pads;
 	int				nr_pads_dynamic;
 	struct omap_device_pad		**pads_dynamic;
+	int				*irqs;
 	bool				enabled;
 };
 



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 6/9] ARM: OMAP2+: mux: add support for PAD wakeup interrupts
@ 2011-12-15 21:36   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tero Kristo <t-kristo@ti.com>

OMAP mux now parses active wakeup events from pad registers and calls
corresponding hwmod ISRs once a wakeup is detected. This is
accomplished by registering an interrupt handler for PRCM IO event,
which is raised every time the HW detects wakeups.

[paul at pwsan.com: This patch is a merge of Govindraj R's "ARM: OMAP2+:
hwmod: Add API to check IO PAD wakeup status" patch, Tero Kristo's
"ARM: OMAP2+: mux: add support for PAD wakeup interrupts" patch, and
part of Tero's "ARM: OMAP: mux: add support for selecting mpu_irq for
each wakeup pad" patch.]

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
[paul at pwsan.com: reduced indentation level; renamed omap_hwmod function;
 improved function documentation; modified to iterate only through dynamic
 pads; modified to skip pads where idle mode doesn't enable wakeups; split
 patches]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/mux.c                    |   83 ++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    1 
 2 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index a474c81..e1cc75d 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -32,6 +32,8 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include <asm/system.h>
 
@@ -39,6 +41,7 @@
 
 #include "control.h"
 #include "mux.h"
+#include "prm.h"
 
 #define OMAP_MUX_BASE_OFFSET		0x30	/* Offset from CTRL_BASE */
 #define OMAP_MUX_BASE_SZ		0x5ca
@@ -353,6 +356,78 @@ err1:
 	return NULL;
 }
 
+/**
+ * omap_hwmod_mux_scan_wakeups - omap hwmod scan wakeup pads
+ * @hmux: Pads for a hwmod
+ * @mpu_irqs: MPU irq array for a hwmod
+ *
+ * Scans the wakeup status of pads for a single hwmod.  If an irq
+ * array is defined for this mux, the parser will call the registered
+ * ISRs for corresponding pads, otherwise the parser will stop at the
+ * first wakeup active pad and return.  Returns true if there is a
+ * pending and non-served wakeup event for the mux, otherwise false.
+ */
+static bool omap_hwmod_mux_scan_wakeups(struct omap_hwmod_mux_info *hmux,
+		struct omap_hwmod_irq_info *mpu_irqs)
+{
+	int i, irq;
+	unsigned int val;
+	u32 handled_irqs = 0;
+
+	for (i = 0; i < hmux->nr_pads_dynamic; i++) {
+		struct omap_device_pad *pad = hmux->pads_dynamic[i];
+
+		if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP) ||
+		    !(pad->idle & OMAP_WAKEUP_EN))
+			continue;
+
+		val = omap_mux_read(pad->partition, pad->mux->reg_offset);
+		if (!(val & OMAP_WAKEUP_EVENT))
+			continue;
+
+		if (!hmux->irqs)
+			return true;
+
+		irq = hmux->irqs[i];
+		/* make sure we only handle each irq once */
+		if (handled_irqs & 1 << irq)
+			continue;
+
+		handled_irqs |= 1 << irq;
+
+		generic_handle_irq(mpu_irqs[irq].irq);
+	}
+
+	return false;
+}
+
+/**
+ * _omap_hwmod_mux_handle_irq - Process wakeup events for a single hwmod
+ *
+ * Checks a single hwmod for every wakeup capable pad to see if there is an
+ * active wakeup event. If this is the case, call the corresponding ISR.
+ */
+static int _omap_hwmod_mux_handle_irq(struct omap_hwmod *oh, void *data)
+{
+	if (!oh->mux || !oh->mux->enabled)
+		return 0;
+	if (omap_hwmod_mux_scan_wakeups(oh->mux, oh->mpu_irqs))
+		generic_handle_irq(oh->mpu_irqs[0].irq);
+	return 0;
+}
+
+/**
+ * omap_hwmod_mux_handle_irq - Process pad wakeup irqs.
+ *
+ * Calls a function for each registered omap_hwmod to check
+ * pad wakeup statuses.
+ */
+static irqreturn_t omap_hwmod_mux_handle_irq(int irq, void *unused)
+{
+	omap_hwmod_for_each(_omap_hwmod_mux_handle_irq, NULL);
+	return IRQ_HANDLED;
+}
+
 /* Assumes the calling function takes care of locking */
 void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
 {
@@ -717,6 +792,7 @@ static void __init omap_mux_free_names(struct omap_mux *m)
 static int __init omap_mux_late_init(void)
 {
 	struct omap_mux_partition *partition;
+	int ret;
 
 	list_for_each_entry(partition, &mux_partitions, node) {
 		struct omap_mux_entry *e, *tmp;
@@ -737,6 +813,13 @@ static int __init omap_mux_late_init(void)
 		}
 	}
 
+	ret = request_irq(omap_prcm_event_to_irq("io"),
+		omap_hwmod_mux_handle_irq, IRQF_SHARED | IRQF_NO_SUSPEND,
+			"hwmod_io", omap_mux_late_init);
+
+	if (ret)
+		pr_warning("mux: Failed to setup hwmod io irq %d\n", ret);
+
 	omap_mux_dbg_init();
 
 	return 0;
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 8b372ed..f705492 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -97,6 +97,7 @@ struct omap_hwmod_mux_info {
 	struct omap_device_pad		*pads;
 	int				nr_pads_dynamic;
 	struct omap_device_pad		**pads_dynamic;
+	int				*irqs;
 	bool				enabled;
 };
 

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 7/9] ARM: OMAP: hwmod: add support for selecting mpu_irq for each wakeup pad
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-15 21:36   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: Tero Kristo, Tony Lindgren, Kevin Hilman

From: Tero Kristo <t-kristo@ti.com>

By default all registered pads will trigger mpu_irqs[0]. Now there is
an API for selecting used mpu_irq on pad basis, which can be used to
trigger different irq handlers for different pads in the same hwmod.
Each pad that requires its interrupt to be re-routed this way must
have a separate call to omap_hwmod_pad_route_irq(hwmod, pad, irq).

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul@pwsan.com: moved fn to omap_hwmod.c; separated fn from mux scan_wakeups
 changes; added kerneldoc]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/omap_hwmod.c             |   55 ++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    2 +
 2 files changed, 57 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 21ffd8a..7ea3df5 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -136,6 +136,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
 
 #include <plat/common.h>
 #include <plat/cpu.h>
@@ -2709,3 +2710,57 @@ int omap_hwmod_no_setup_reset(struct omap_hwmod *oh)
 
 	return 0;
 }
+
+/**
+ * omap_hwmod_pad_route_irq - route an I/O pad wakeup to a particular MPU IRQ
+ * @oh: struct omap_hwmod * containing hwmod mux entries
+ * @pad_idx: array index in oh->mux of the hwmod mux entry to route wakeup
+ * @irq_idx: the hwmod mpu_irqs array index of the IRQ to trigger on wakeup
+ *
+ * When an I/O pad wakeup arrives for the dynamic or wakeup hwmod mux
+ * entry number @pad_idx for the hwmod @oh, trigger the interrupt
+ * service routine for the hwmod's mpu_irqs array index @irq_idx.  If
+ * this function is not called for a given pad_idx, then the ISR
+ * associated with @oh's first MPU IRQ will be triggered when an I/O
+ * pad wakeup occurs on that pad.  Note that @pad_idx is the index of
+ * the _dynamic or wakeup_ entry: if there are other entries not
+ * marked with OMAP_DEVICE_PAD_WAKEUP or OMAP_DEVICE_PAD_REMUX, these
+ * entries are NOT COUNTED in the dynamic pad index.  This function
+ * must be called separately for each pad that requires its interrupt
+ * to be re-routed this way.  Returns -EINVAL if there is an argument
+ * problem or if @oh does not have hwmod mux entries or MPU IRQs;
+ * returns -ENOMEM if memory cannot be allocated; or 0 upon success.
+ *
+ * XXX This function interface is fragile.  Rather than using array
+ * indexes, which are subject to unpredictable change, it should be
+ * using hwmod IRQ names, and some other stable key for the hwmod mux
+ * pad records.
+ */
+int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx)
+{
+	int nr_irqs;
+
+	might_sleep();
+
+	if (!oh || !oh->mux || !oh->mpu_irqs || pad_idx < 0 ||
+	    pad_idx >= oh->mux->nr_pads_dynamic)
+		return -EINVAL;
+
+	/* Check the number of available mpu_irqs */
+	for (nr_irqs = 0; oh->mpu_irqs[nr_irqs].irq >= 0; nr_irqs++)
+		;
+
+	if (irq_idx >= nr_irqs)
+		return -EINVAL;
+
+	if (!oh->mux->irqs) {
+		/* XXX What frees this? */
+		oh->mux->irqs = kzalloc(sizeof(int) * oh->mux->nr_pads_dynamic,
+			GFP_KERNEL);
+		if (!oh->mux->irqs)
+			return -ENOMEM;
+	}
+	oh->mux->irqs[pad_idx] = irq_idx;
+
+	return 0;
+}
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index f705492..ef4bf31 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -605,6 +605,8 @@ int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
 
 int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
 
+int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx);
+
 /*
  * Chip variant-specific hwmod init routines - XXX should be converted
  * to use initcalls once the initial boot ordering is straightened out



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 7/9] ARM: OMAP: hwmod: add support for selecting mpu_irq for each wakeup pad
@ 2011-12-15 21:36   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tero Kristo <t-kristo@ti.com>

By default all registered pads will trigger mpu_irqs[0]. Now there is
an API for selecting used mpu_irq on pad basis, which can be used to
trigger different irq handlers for different pads in the same hwmod.
Each pad that requires its interrupt to be re-routed this way must
have a separate call to omap_hwmod_pad_route_irq(hwmod, pad, irq).

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul at pwsan.com: moved fn to omap_hwmod.c; separated fn from mux scan_wakeups
 changes; added kerneldoc]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/omap_hwmod.c             |   55 ++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    2 +
 2 files changed, 57 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 21ffd8a..7ea3df5 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -136,6 +136,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
 
 #include <plat/common.h>
 #include <plat/cpu.h>
@@ -2709,3 +2710,57 @@ int omap_hwmod_no_setup_reset(struct omap_hwmod *oh)
 
 	return 0;
 }
+
+/**
+ * omap_hwmod_pad_route_irq - route an I/O pad wakeup to a particular MPU IRQ
+ * @oh: struct omap_hwmod * containing hwmod mux entries
+ * @pad_idx: array index in oh->mux of the hwmod mux entry to route wakeup
+ * @irq_idx: the hwmod mpu_irqs array index of the IRQ to trigger on wakeup
+ *
+ * When an I/O pad wakeup arrives for the dynamic or wakeup hwmod mux
+ * entry number @pad_idx for the hwmod @oh, trigger the interrupt
+ * service routine for the hwmod's mpu_irqs array index @irq_idx.  If
+ * this function is not called for a given pad_idx, then the ISR
+ * associated with @oh's first MPU IRQ will be triggered when an I/O
+ * pad wakeup occurs on that pad.  Note that @pad_idx is the index of
+ * the _dynamic or wakeup_ entry: if there are other entries not
+ * marked with OMAP_DEVICE_PAD_WAKEUP or OMAP_DEVICE_PAD_REMUX, these
+ * entries are NOT COUNTED in the dynamic pad index.  This function
+ * must be called separately for each pad that requires its interrupt
+ * to be re-routed this way.  Returns -EINVAL if there is an argument
+ * problem or if @oh does not have hwmod mux entries or MPU IRQs;
+ * returns -ENOMEM if memory cannot be allocated; or 0 upon success.
+ *
+ * XXX This function interface is fragile.  Rather than using array
+ * indexes, which are subject to unpredictable change, it should be
+ * using hwmod IRQ names, and some other stable key for the hwmod mux
+ * pad records.
+ */
+int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx)
+{
+	int nr_irqs;
+
+	might_sleep();
+
+	if (!oh || !oh->mux || !oh->mpu_irqs || pad_idx < 0 ||
+	    pad_idx >= oh->mux->nr_pads_dynamic)
+		return -EINVAL;
+
+	/* Check the number of available mpu_irqs */
+	for (nr_irqs = 0; oh->mpu_irqs[nr_irqs].irq >= 0; nr_irqs++)
+		;
+
+	if (irq_idx >= nr_irqs)
+		return -EINVAL;
+
+	if (!oh->mux->irqs) {
+		/* XXX What frees this? */
+		oh->mux->irqs = kzalloc(sizeof(int) * oh->mux->nr_pads_dynamic,
+			GFP_KERNEL);
+		if (!oh->mux->irqs)
+			return -ENOMEM;
+	}
+	oh->mux->irqs[pad_idx] = irq_idx;
+
+	return 0;
+}
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index f705492..ef4bf31 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -605,6 +605,8 @@ int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
 
 int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
 
+int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx);
+
 /*
  * Chip variant-specific hwmod init routines - XXX should be converted
  * to use initcalls once the initial boot ordering is straightened out

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 8/9] ARM: OMAP3: pm: use prcm chain handler
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-15 21:36   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: Tero Kristo, Kevin Hilman

From: Tero Kristo <t-kristo@ti.com>

PM interrupt handling is now done through the PRCM chain handler. The
interrupt handling logic is also split in two parts, to serve IO and
WKUP events separately. This allows us to handle IO chain events in a
clean way.

Core event code is also changed in accordance to this, as PRCM
interrupt handling is done by independent handlers, and the core
handler should not clear the IO events anymore.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul@pwsan.com: use pr_err(); combined with portions of earlier patches and
 the "do not enable PRCM MPU interrupts manually" patch]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/pm34xx.c       |  115 ++++++++++++++----------------------
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   26 ++++++++
 2 files changed, 70 insertions(+), 71 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index efa6649..ba1692e 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -194,7 +194,7 @@ static void omap3_save_secure_ram_context(void)
  * that any peripheral wake-up events occurring while attempting to
  * clear the PM_WKST_x are detected and cleared.
  */
-static int prcm_clear_mod_irqs(s16 module, u8 regs)
+static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
 {
 	u32 wkst, fclk, iclk, clken;
 	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
@@ -206,6 +206,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 
 	wkst = omap2_prm_read_mod_reg(module, wkst_off);
 	wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
+	wkst &= ~ignore_bits;
 	if (wkst) {
 		iclk = omap2_cm_read_mod_reg(module, iclk_off);
 		fclk = omap2_cm_read_mod_reg(module, fclk_off);
@@ -221,6 +222,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
 			omap2_prm_write_mod_reg(wkst, module, wkst_off);
 			wkst = omap2_prm_read_mod_reg(module, wkst_off);
+			wkst &= ~ignore_bits;
 			c++;
 		}
 		omap2_cm_write_mod_reg(iclk, module, iclk_off);
@@ -230,76 +232,35 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 	return c;
 }
 
-static int _prcm_int_handle_wakeup(void)
+static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
 {
 	int c;
 
-	c = prcm_clear_mod_irqs(WKUP_MOD, 1);
-	c += prcm_clear_mod_irqs(CORE_MOD, 1);
-	c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
-	if (omap_rev() > OMAP3430_REV_ES1_0) {
-		c += prcm_clear_mod_irqs(CORE_MOD, 3);
-		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
-	}
+	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
+		~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
 
-	return c;
+	return c ? IRQ_HANDLED : IRQ_NONE;
 }
 
-/*
- * PRCM Interrupt Handler
- *
- * The PRM_IRQSTATUS_MPU register indicates if there are any pending
- * interrupts from the PRCM for the MPU. These bits must be cleared in
- * order to clear the PRCM interrupt. The PRCM interrupt handler is
- * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
- * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
- * register indicates that a wake-up event is pending for the MPU and
- * this bit can only be cleared if the all the wake-up events latched
- * in the various PM_WKST_x registers have been cleared. The interrupt
- * handler is implemented using a do-while loop so that if a wake-up
- * event occurred during the processing of the prcm interrupt handler
- * (setting a bit in the corresponding PM_WKST_x register and thus
- * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
- * this would be handled.
- */
-static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
 {
-	u32 irqenable_mpu, irqstatus_mpu;
-	int c = 0;
-
-	irqenable_mpu = omap2_prm_read_mod_reg(OCP_MOD,
-					 OMAP3_PRM_IRQENABLE_MPU_OFFSET);
-	irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD,
-					 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
-	irqstatus_mpu &= irqenable_mpu;
-
-	do {
-		if (irqstatus_mpu & (OMAP3430_WKUP_ST_MASK |
-				     OMAP3430_IO_ST_MASK)) {
-			c = _prcm_int_handle_wakeup();
-
-			/*
-			 * Is the MPU PRCM interrupt handler racing with the
-			 * IVA2 PRCM interrupt handler ?
-			 */
-			WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
-			     "but no wakeup sources are marked\n");
-		} else {
-			/* XXX we need to expand our PRCM interrupt handler */
-			WARN(1, "prcm: WARNING: PRCM interrupt received, but "
-			     "no code to handle it (%08x)\n", irqstatus_mpu);
-		}
-
-		omap2_prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
-					OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
-
-		irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD,
-					OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
-		irqstatus_mpu &= irqenable_mpu;
+	int c;
 
-	} while (irqstatus_mpu);
+	/*
+	 * Clear all except ST_IO and ST_IO_CHAIN for wkup module,
+	 * these are handled in a separate handler to avoid acking
+	 * IO events before parsing in mux code
+	 */
+	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
+		OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK);
+	c += prcm_clear_mod_irqs(CORE_MOD, 1, 0);
+	c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0);
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		c += prcm_clear_mod_irqs(CORE_MOD, 3, 0);
+		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0);
+	}
 
-	return IRQ_HANDLED;
+	return c ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static void omap34xx_save_context(u32 *save)
@@ -580,6 +541,7 @@ static int omap3_pm_begin(suspend_state_t state)
 	disable_hlt();
 	suspend_state = state;
 	omap_uart_enable_irqs(0);
+	omap_prcm_irq_prepare();
 	return 0;
 }
 
@@ -591,10 +553,16 @@ static void omap3_pm_end(void)
 	return;
 }
 
+static void omap3_pm_finish(void)
+{
+	omap_prcm_irq_complete();
+}
+
 static const struct platform_suspend_ops omap_pm_ops = {
 	.begin		= omap3_pm_begin,
 	.end		= omap3_pm_end,
 	.enter		= omap3_pm_enter,
+	.finish		= omap3_pm_finish,
 	.valid		= suspend_valid_only_mem,
 };
 #endif /* CONFIG_SUSPEND */
@@ -700,10 +668,6 @@ static void __init prcm_setup_regs(void)
 			  OMAP3430_GRPSEL_GPT1_MASK |
 			  OMAP3430_GRPSEL_GPT12_MASK,
 			  WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
-	/* For some reason IO doesn't generate wakeup event even if
-	 * it is selected to mpu wakeup goup */
-	omap2_prm_write_mod_reg(OMAP3430_IO_EN_MASK | OMAP3430_WKUP_EN_MASK,
-			  OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 
 	/* Enable PM_WKEN to support DSS LPR */
 	omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK,
@@ -880,12 +844,21 @@ static int __init omap3_pm_init(void)
 	 * supervised mode for powerdomains */
 	prcm_setup_regs();
 
-	ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
-			  (irq_handler_t)prcm_interrupt_handler,
-			  IRQF_DISABLED, "prcm", NULL);
+	ret = request_irq(omap_prcm_event_to_irq("wkup"),
+		_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL);
+
+	if (ret) {
+		pr_err("pm: Failed to request pm_wkup irq\n");
+		goto err1;
+	}
+
+	/* IO interrupt is shared with mux code */
+	ret = request_irq(omap_prcm_event_to_irq("io"),
+		_prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io",
+		omap3_pm_init);
+
 	if (ret) {
-		printk(KERN_ERR "request_irq failed to register for 0x%x\n",
-		       INT_34XX_PRCM_MPU_IRQ);
+		pr_err("pm: Failed to request pm_io irq\n");
 		goto err1;
 	}
 
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index 58d9ce70..3545c9a 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -27,6 +27,24 @@
 #include "prm-regbits-24xx.h"
 #include "prm-regbits-34xx.h"
 
+static const struct omap_prcm_irq omap3_prcm_irqs[] = {
+	OMAP_PRCM_IRQ("wkup",	0,	0),
+	OMAP_PRCM_IRQ("io",	9,	1),
+};
+
+static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
+	.ack			= OMAP3_PRM_IRQSTATUS_MPU_OFFSET,
+	.mask			= OMAP3_PRM_IRQENABLE_MPU_OFFSET,
+	.nr_regs		= 1,
+	.irqs			= omap3_prcm_irqs,
+	.nr_irqs		= ARRAY_SIZE(omap3_prcm_irqs),
+	.irq			= INT_34XX_PRCM_MPU_IRQ,
+	.read_pending_irqs	= &omap3xxx_prm_read_pending_irqs,
+	.ocp_barrier		= &omap3xxx_prm_ocp_barrier,
+	.save_and_clear_irqen	= &omap3xxx_prm_save_and_clear_irqen,
+	.restore_irqen		= &omap3xxx_prm_restore_irqen,
+};
+
 u32 omap2_prm_read_mod_reg(s16 module, u16 idx)
 {
 	return __raw_readl(prm_base + module + idx);
@@ -281,3 +299,11 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 	omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD,
 				OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 }
+
+static int __init omap3xxx_prcm_init(void)
+{
+	if (cpu_is_omap34xx())
+		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
+	return 0;
+}
+subsys_initcall(omap3xxx_prcm_init);



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 8/9] ARM: OMAP3: pm: use prcm chain handler
@ 2011-12-15 21:36   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tero Kristo <t-kristo@ti.com>

PM interrupt handling is now done through the PRCM chain handler. The
interrupt handling logic is also split in two parts, to serve IO and
WKUP events separately. This allows us to handle IO chain events in a
clean way.

Core event code is also changed in accordance to this, as PRCM
interrupt handling is done by independent handlers, and the core
handler should not clear the IO events anymore.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul at pwsan.com: use pr_err(); combined with portions of earlier patches and
 the "do not enable PRCM MPU interrupts manually" patch]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/pm34xx.c       |  115 ++++++++++++++----------------------
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   26 ++++++++
 2 files changed, 70 insertions(+), 71 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index efa6649..ba1692e 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -194,7 +194,7 @@ static void omap3_save_secure_ram_context(void)
  * that any peripheral wake-up events occurring while attempting to
  * clear the PM_WKST_x are detected and cleared.
  */
-static int prcm_clear_mod_irqs(s16 module, u8 regs)
+static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
 {
 	u32 wkst, fclk, iclk, clken;
 	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
@@ -206,6 +206,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 
 	wkst = omap2_prm_read_mod_reg(module, wkst_off);
 	wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
+	wkst &= ~ignore_bits;
 	if (wkst) {
 		iclk = omap2_cm_read_mod_reg(module, iclk_off);
 		fclk = omap2_cm_read_mod_reg(module, fclk_off);
@@ -221,6 +222,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 			omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
 			omap2_prm_write_mod_reg(wkst, module, wkst_off);
 			wkst = omap2_prm_read_mod_reg(module, wkst_off);
+			wkst &= ~ignore_bits;
 			c++;
 		}
 		omap2_cm_write_mod_reg(iclk, module, iclk_off);
@@ -230,76 +232,35 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 	return c;
 }
 
-static int _prcm_int_handle_wakeup(void)
+static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
 {
 	int c;
 
-	c = prcm_clear_mod_irqs(WKUP_MOD, 1);
-	c += prcm_clear_mod_irqs(CORE_MOD, 1);
-	c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
-	if (omap_rev() > OMAP3430_REV_ES1_0) {
-		c += prcm_clear_mod_irqs(CORE_MOD, 3);
-		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
-	}
+	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
+		~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
 
-	return c;
+	return c ? IRQ_HANDLED : IRQ_NONE;
 }
 
-/*
- * PRCM Interrupt Handler
- *
- * The PRM_IRQSTATUS_MPU register indicates if there are any pending
- * interrupts from the PRCM for the MPU. These bits must be cleared in
- * order to clear the PRCM interrupt. The PRCM interrupt handler is
- * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
- * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
- * register indicates that a wake-up event is pending for the MPU and
- * this bit can only be cleared if the all the wake-up events latched
- * in the various PM_WKST_x registers have been cleared. The interrupt
- * handler is implemented using a do-while loop so that if a wake-up
- * event occurred during the processing of the prcm interrupt handler
- * (setting a bit in the corresponding PM_WKST_x register and thus
- * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
- * this would be handled.
- */
-static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
 {
-	u32 irqenable_mpu, irqstatus_mpu;
-	int c = 0;
-
-	irqenable_mpu = omap2_prm_read_mod_reg(OCP_MOD,
-					 OMAP3_PRM_IRQENABLE_MPU_OFFSET);
-	irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD,
-					 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
-	irqstatus_mpu &= irqenable_mpu;
-
-	do {
-		if (irqstatus_mpu & (OMAP3430_WKUP_ST_MASK |
-				     OMAP3430_IO_ST_MASK)) {
-			c = _prcm_int_handle_wakeup();
-
-			/*
-			 * Is the MPU PRCM interrupt handler racing with the
-			 * IVA2 PRCM interrupt handler ?
-			 */
-			WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
-			     "but no wakeup sources are marked\n");
-		} else {
-			/* XXX we need to expand our PRCM interrupt handler */
-			WARN(1, "prcm: WARNING: PRCM interrupt received, but "
-			     "no code to handle it (%08x)\n", irqstatus_mpu);
-		}
-
-		omap2_prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
-					OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
-
-		irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD,
-					OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
-		irqstatus_mpu &= irqenable_mpu;
+	int c;
 
-	} while (irqstatus_mpu);
+	/*
+	 * Clear all except ST_IO and ST_IO_CHAIN for wkup module,
+	 * these are handled in a separate handler to avoid acking
+	 * IO events before parsing in mux code
+	 */
+	c = prcm_clear_mod_irqs(WKUP_MOD, 1,
+		OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK);
+	c += prcm_clear_mod_irqs(CORE_MOD, 1, 0);
+	c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0);
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		c += prcm_clear_mod_irqs(CORE_MOD, 3, 0);
+		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0);
+	}
 
-	return IRQ_HANDLED;
+	return c ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static void omap34xx_save_context(u32 *save)
@@ -580,6 +541,7 @@ static int omap3_pm_begin(suspend_state_t state)
 	disable_hlt();
 	suspend_state = state;
 	omap_uart_enable_irqs(0);
+	omap_prcm_irq_prepare();
 	return 0;
 }
 
@@ -591,10 +553,16 @@ static void omap3_pm_end(void)
 	return;
 }
 
+static void omap3_pm_finish(void)
+{
+	omap_prcm_irq_complete();
+}
+
 static const struct platform_suspend_ops omap_pm_ops = {
 	.begin		= omap3_pm_begin,
 	.end		= omap3_pm_end,
 	.enter		= omap3_pm_enter,
+	.finish		= omap3_pm_finish,
 	.valid		= suspend_valid_only_mem,
 };
 #endif /* CONFIG_SUSPEND */
@@ -700,10 +668,6 @@ static void __init prcm_setup_regs(void)
 			  OMAP3430_GRPSEL_GPT1_MASK |
 			  OMAP3430_GRPSEL_GPT12_MASK,
 			  WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
-	/* For some reason IO doesn't generate wakeup event even if
-	 * it is selected to mpu wakeup goup */
-	omap2_prm_write_mod_reg(OMAP3430_IO_EN_MASK | OMAP3430_WKUP_EN_MASK,
-			  OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 
 	/* Enable PM_WKEN to support DSS LPR */
 	omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK,
@@ -880,12 +844,21 @@ static int __init omap3_pm_init(void)
 	 * supervised mode for powerdomains */
 	prcm_setup_regs();
 
-	ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
-			  (irq_handler_t)prcm_interrupt_handler,
-			  IRQF_DISABLED, "prcm", NULL);
+	ret = request_irq(omap_prcm_event_to_irq("wkup"),
+		_prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL);
+
+	if (ret) {
+		pr_err("pm: Failed to request pm_wkup irq\n");
+		goto err1;
+	}
+
+	/* IO interrupt is shared with mux code */
+	ret = request_irq(omap_prcm_event_to_irq("io"),
+		_prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io",
+		omap3_pm_init);
+
 	if (ret) {
-		printk(KERN_ERR "request_irq failed to register for 0x%x\n",
-		       INT_34XX_PRCM_MPU_IRQ);
+		pr_err("pm: Failed to request pm_io irq\n");
 		goto err1;
 	}
 
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index 58d9ce70..3545c9a 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -27,6 +27,24 @@
 #include "prm-regbits-24xx.h"
 #include "prm-regbits-34xx.h"
 
+static const struct omap_prcm_irq omap3_prcm_irqs[] = {
+	OMAP_PRCM_IRQ("wkup",	0,	0),
+	OMAP_PRCM_IRQ("io",	9,	1),
+};
+
+static struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
+	.ack			= OMAP3_PRM_IRQSTATUS_MPU_OFFSET,
+	.mask			= OMAP3_PRM_IRQENABLE_MPU_OFFSET,
+	.nr_regs		= 1,
+	.irqs			= omap3_prcm_irqs,
+	.nr_irqs		= ARRAY_SIZE(omap3_prcm_irqs),
+	.irq			= INT_34XX_PRCM_MPU_IRQ,
+	.read_pending_irqs	= &omap3xxx_prm_read_pending_irqs,
+	.ocp_barrier		= &omap3xxx_prm_ocp_barrier,
+	.save_and_clear_irqen	= &omap3xxx_prm_save_and_clear_irqen,
+	.restore_irqen		= &omap3xxx_prm_restore_irqen,
+};
+
 u32 omap2_prm_read_mod_reg(s16 module, u16 idx)
 {
 	return __raw_readl(prm_base + module + idx);
@@ -281,3 +299,11 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 	omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD,
 				OMAP3_PRM_IRQENABLE_MPU_OFFSET);
 }
+
+static int __init omap3xxx_prcm_init(void)
+{
+	if (cpu_is_omap34xx())
+		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
+	return 0;
+}
+subsys_initcall(omap3xxx_prcm_init);

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 9/9] ARM: OMAP4: PRM: use PRCM interrupt handler
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-15 21:36   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: Tero Kristo, Kevin Hilman

From: Tero Kristo <t-kristo@ti.com>

Use the new PRCM interrupt handler code on OMAP4 systems.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul@pwsan.com: split this from a previous patch to this patch; call
 omap4xxx_prcm_init() during init; write trivial commit log]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/prm44xx.c |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index c4be5d9..040c39c 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -27,6 +27,24 @@
 #include "prcm44xx.h"
 #include "prminst44xx.h"
 
+static const struct omap_prcm_irq omap4_prcm_irqs[] = {
+	OMAP_PRCM_IRQ("wkup",   0,      0),
+	OMAP_PRCM_IRQ("io",     9,      1),
+};
+
+static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
+	.ack			= OMAP4_PRM_IRQSTATUS_MPU_OFFSET,
+	.mask			= OMAP4_PRM_IRQENABLE_MPU_OFFSET,
+	.nr_regs		= 2,
+	.irqs			= omap4_prcm_irqs,
+	.nr_irqs		= ARRAY_SIZE(omap4_prcm_irqs),
+	.irq			= OMAP44XX_IRQ_PRCM,
+	.read_pending_irqs	= &omap44xx_prm_read_pending_irqs,
+	.ocp_barrier		= &omap44xx_prm_ocp_barrier,
+	.save_and_clear_irqen	= &omap44xx_prm_save_and_clear_irqen,
+	.restore_irqen		= &omap44xx_prm_restore_irqen,
+};
+
 /* PRM low-level functions */
 
 /* Read a register in a CM/PRM instance in the PRM module */
@@ -211,3 +229,11 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask)
 	omap4_prm_write_inst_reg(saved_mask[1], OMAP4430_PRM_DEVICE_INST,
 				 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
 }
+
+static int __init omap4xxx_prcm_init(void)
+{
+	if (cpu_is_omap44xx())
+		return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup);
+	return 0;
+}
+subsys_initcall(omap4xxx_prcm_init);



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 9/9] ARM: OMAP4: PRM: use PRCM interrupt handler
@ 2011-12-15 21:36   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-15 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tero Kristo <t-kristo@ti.com>

Use the new PRCM interrupt handler code on OMAP4 systems.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Tested-by: Kevin Hilman <khilman@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
[paul at pwsan.com: split this from a previous patch to this patch; call
 omap4xxx_prcm_init() during init; write trivial commit log]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/prm44xx.c |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index c4be5d9..040c39c 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -27,6 +27,24 @@
 #include "prcm44xx.h"
 #include "prminst44xx.h"
 
+static const struct omap_prcm_irq omap4_prcm_irqs[] = {
+	OMAP_PRCM_IRQ("wkup",   0,      0),
+	OMAP_PRCM_IRQ("io",     9,      1),
+};
+
+static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
+	.ack			= OMAP4_PRM_IRQSTATUS_MPU_OFFSET,
+	.mask			= OMAP4_PRM_IRQENABLE_MPU_OFFSET,
+	.nr_regs		= 2,
+	.irqs			= omap4_prcm_irqs,
+	.nr_irqs		= ARRAY_SIZE(omap4_prcm_irqs),
+	.irq			= OMAP44XX_IRQ_PRCM,
+	.read_pending_irqs	= &omap44xx_prm_read_pending_irqs,
+	.ocp_barrier		= &omap44xx_prm_ocp_barrier,
+	.save_and_clear_irqen	= &omap44xx_prm_save_and_clear_irqen,
+	.restore_irqen		= &omap44xx_prm_restore_irqen,
+};
+
 /* PRM low-level functions */
 
 /* Read a register in a CM/PRM instance in the PRM module */
@@ -211,3 +229,11 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask)
 	omap4_prm_write_inst_reg(saved_mask[1], OMAP4430_PRM_DEVICE_INST,
 				 OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
 }
+
+static int __init omap4xxx_prcm_init(void)
+{
+	if (cpu_is_omap44xx())
+		return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup);
+	return 0;
+}
+subsys_initcall(omap4xxx_prcm_init);

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH 1/9] ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list
  2011-12-15 21:36   ` Paul Walmsley
@ 2011-12-15 21:41     ` Tony Lindgren
  -1 siblings, 0 replies; 36+ messages in thread
From: Tony Lindgren @ 2011-12-15 21:41 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: linux-omap, linux-arm-kernel, Tero Kristo, Govindraj R

* Paul Walmsley <paul@pwsan.com> [111215 13:05]:
> omap_hwmod_mux() currently only iterates through the dynamic pad list.
> This list currently only consists of pads with the
> OMAP_DEVICE_MUX_REMUX flag set.
> 
> Subsequent patches in this series will cause hwmod mux entries with
> the OMAP_DEVICE_MUX_WAKEUP flag set to be changed dynamically, to
> control hwmod I/O ring wakeup.  For this to work correctly, hwmod mux
> entries with the OMAP_DEVICE_MUX_WAKEUP flag set must also be added to
> the dynamic pad list.  So this patch modifies omap_hwmod_mux_init() to
> do so.
> 
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> Cc: Tony Lindgren <tony@atomide.com>
> Cc: Tero Kristo <t-kristo@ti.com>
> Cc: Govindraj R <govindraj.raja@ti.com>

Acked-by: Tony Lindgren <tony@atomide.com>

> ---
>  arch/arm/mach-omap2/mux.c |    6 ++++--
>  1 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
> index 655e948..a474c81 100644
> --- a/arch/arm/mach-omap2/mux.c
> +++ b/arch/arm/mach-omap2/mux.c
> @@ -306,7 +306,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
>  		pad->idle = bpad->idle;
>  		pad->off = bpad->off;
>  
> -		if (pad->flags & OMAP_DEVICE_PAD_REMUX)
> +		if (pad->flags &
> +		    (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP))
>  			nr_pads_dynamic++;
>  
>  		pr_debug("%s: Initialized %s\n", __func__, pad->name);
> @@ -331,7 +332,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
>  	for (i = 0; i < hmux->nr_pads; i++) {
>  		struct omap_device_pad *pad = &hmux->pads[i];
>  
> -		if (pad->flags & OMAP_DEVICE_PAD_REMUX) {
> +		if (pad->flags &
> +		    (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) {
>  			pr_debug("%s: pad %s tagged dynamic\n",
>  					__func__, pad->name);
>  			hmux->pads_dynamic[nr_pads_dynamic] = pad;
> 
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 1/9] ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list
@ 2011-12-15 21:41     ` Tony Lindgren
  0 siblings, 0 replies; 36+ messages in thread
From: Tony Lindgren @ 2011-12-15 21:41 UTC (permalink / raw)
  To: linux-arm-kernel

* Paul Walmsley <paul@pwsan.com> [111215 13:05]:
> omap_hwmod_mux() currently only iterates through the dynamic pad list.
> This list currently only consists of pads with the
> OMAP_DEVICE_MUX_REMUX flag set.
> 
> Subsequent patches in this series will cause hwmod mux entries with
> the OMAP_DEVICE_MUX_WAKEUP flag set to be changed dynamically, to
> control hwmod I/O ring wakeup.  For this to work correctly, hwmod mux
> entries with the OMAP_DEVICE_MUX_WAKEUP flag set must also be added to
> the dynamic pad list.  So this patch modifies omap_hwmod_mux_init() to
> do so.
> 
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> Cc: Tony Lindgren <tony@atomide.com>
> Cc: Tero Kristo <t-kristo@ti.com>
> Cc: Govindraj R <govindraj.raja@ti.com>

Acked-by: Tony Lindgren <tony@atomide.com>

> ---
>  arch/arm/mach-omap2/mux.c |    6 ++++--
>  1 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
> index 655e948..a474c81 100644
> --- a/arch/arm/mach-omap2/mux.c
> +++ b/arch/arm/mach-omap2/mux.c
> @@ -306,7 +306,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
>  		pad->idle = bpad->idle;
>  		pad->off = bpad->off;
>  
> -		if (pad->flags & OMAP_DEVICE_PAD_REMUX)
> +		if (pad->flags &
> +		    (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP))
>  			nr_pads_dynamic++;
>  
>  		pr_debug("%s: Initialized %s\n", __func__, pad->name);
> @@ -331,7 +332,8 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
>  	for (i = 0; i < hmux->nr_pads; i++) {
>  		struct omap_device_pad *pad = &hmux->pads[i];
>  
> -		if (pad->flags & OMAP_DEVICE_PAD_REMUX) {
> +		if (pad->flags &
> +		    (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) {
>  			pr_debug("%s: pad %s tagged dynamic\n",
>  					__func__, pad->name);
>  			hmux->pads_dynamic[nr_pads_dynamic] = pad;
> 
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCHv12 0/9] OMAP3+: PRCM chain handler
  2011-12-15 21:36 ` Paul Walmsley
@ 2011-12-16  5:10   ` Paul Walmsley
  -1 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-16  5:10 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: t-kristo


Hi

This series was boot-tested on a 4430 ES2 Panda also.  It generates the 
following message on boot:

PRCM: failed to allocate irq descs: -12

which is an -ENOMEM coming from irq_alloc_descs().  This is probably 
because OMAP hasn't been converted to use sparse IRQs yet.

Until that happens, this message should be harmless.


- Paul

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv12 0/9] OMAP3+: PRCM chain handler
@ 2011-12-16  5:10   ` Paul Walmsley
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Walmsley @ 2011-12-16  5:10 UTC (permalink / raw)
  To: linux-arm-kernel


Hi

This series was boot-tested on a 4430 ES2 Panda also.  It generates the 
following message on boot:

PRCM: failed to allocate irq descs: -12

which is an -ENOMEM coming from irq_alloc_descs().  This is probably 
because OMAP hasn't been converted to use sparse IRQs yet.

Until that happens, this message should be harmless.


- Paul

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCHv12 0/9] OMAP3+: PRCM chain handler
  2011-12-16  5:10   ` Paul Walmsley
@ 2011-12-16 12:57     ` Tero Kristo
  -1 siblings, 0 replies; 36+ messages in thread
From: Tero Kristo @ 2011-12-16 12:57 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: linux-omap, linux-arm-kernel

On Thu, 2011-12-15 at 22:10 -0700, Paul Walmsley wrote:
> Hi
> 
> This series was boot-tested on a 4430 ES2 Panda also.  It generates the 
> following message on boot:
> 
> PRCM: failed to allocate irq descs: -12
> 
> which is an -ENOMEM coming from irq_alloc_descs().  This is probably 
> because OMAP hasn't been converted to use sparse IRQs yet.

You should be able to enable SPARSE_IRQ from the config and this
probably fixes it, this is what I saw with OMAP4 testing, not sure if it
was enabled on your config.

> Until that happens, this message should be harmless.

Currently I guess it is harmless as we don't have OMAP4 PM support
anyway, so nobody can use the PRCM interrupts on that platform anyway.
The error message itself indicates that PRCM interrupt support does not
work at all.

Other than that, the set looks good to me after your changes.

-Tero



^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv12 0/9] OMAP3+: PRCM chain handler
@ 2011-12-16 12:57     ` Tero Kristo
  0 siblings, 0 replies; 36+ messages in thread
From: Tero Kristo @ 2011-12-16 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 2011-12-15 at 22:10 -0700, Paul Walmsley wrote:
> Hi
> 
> This series was boot-tested on a 4430 ES2 Panda also.  It generates the 
> following message on boot:
> 
> PRCM: failed to allocate irq descs: -12
> 
> which is an -ENOMEM coming from irq_alloc_descs().  This is probably 
> because OMAP hasn't been converted to use sparse IRQs yet.

You should be able to enable SPARSE_IRQ from the config and this
probably fixes it, this is what I saw with OMAP4 testing, not sure if it
was enabled on your config.

> Until that happens, this message should be harmless.

Currently I guess it is harmless as we don't have OMAP4 PM support
anyway, so nobody can use the PRCM interrupts on that platform anyway.
The error message itself indicates that PRCM interrupt support does not
work at all.

Other than that, the set looks good to me after your changes.

-Tero

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [PATCHv12 0/9] OMAP3+: PRCM chain handler
  2011-12-15 21:36 ` Paul Walmsley
@ 2012-01-09  5:31   ` Bedia, Vaibhav
  -1 siblings, 0 replies; 36+ messages in thread
From: Bedia, Vaibhav @ 2012-01-09  5:31 UTC (permalink / raw)
  To: Paul Walmsley, linux-omap, linux-arm-kernel

Hi Paul,

On Fri, Dec 16, 2011 at 03:06:09, Paul Walmsley wrote:
> Hi,
> 
> This is a repost of Tero's PRCM chain handler patch set with a few changes:
> 
> - A new mux patch has been added to place hwmod mux entries with
>   OMAP_DEVICE_PAD_WAKEUP set into the dynamic list
> 
> - Several OCP barriers have been added to PRM writes to try to protect
>   against races between PRM register writes and the MPU
> 
> - Kerneldoc documentation has been added
> 
> - The pending IRQ test functions have been split into per-SoC versions
> 
> - Some patches have been rearranged and merged to avoid churn
> 
> - The PRM IRQ handler is now installed on OMAP4
> 

I found a few (minor) issues with this patch series.

1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
omap3xxx_prcm_init() to bypass the chain handler registration.

Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
Hope such cpu_is_*() checks are acceptable.

2. With the above check in place, there' a warning during boot

"mux: Failed to setup hwmod io irq -22"

This is coming due to request_irq() for the IO event without a PRCM chain
handler being registered. Maybe there should be check for *prcm_irq_setup
before request_irq()?

3. [PATCH 9/9] adds an entry for "wkup" event on OMAP4. Carried over from OMAP3?

Regards,
Vaibhav


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv12 0/9] OMAP3+: PRCM chain handler
@ 2012-01-09  5:31   ` Bedia, Vaibhav
  0 siblings, 0 replies; 36+ messages in thread
From: Bedia, Vaibhav @ 2012-01-09  5:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Paul,

On Fri, Dec 16, 2011 at 03:06:09, Paul Walmsley wrote:
> Hi,
> 
> This is a repost of Tero's PRCM chain handler patch set with a few changes:
> 
> - A new mux patch has been added to place hwmod mux entries with
>   OMAP_DEVICE_PAD_WAKEUP set into the dynamic list
> 
> - Several OCP barriers have been added to PRM writes to try to protect
>   against races between PRM register writes and the MPU
> 
> - Kerneldoc documentation has been added
> 
> - The pending IRQ test functions have been split into per-SoC versions
> 
> - Some patches have been rearranged and merged to avoid churn
> 
> - The PRM IRQ handler is now installed on OMAP4
> 

I found a few (minor) issues with this patch series.

1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
omap3xxx_prcm_init() to bypass the chain handler registration.

Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
Hope such cpu_is_*() checks are acceptable.

2. With the above check in place, there' a warning during boot

"mux: Failed to setup hwmod io irq -22"

This is coming due to request_irq() for the IO event without a PRCM chain
handler being registered. Maybe there should be check for *prcm_irq_setup
before request_irq()?

3. [PATCH 9/9] adds an entry for "wkup" event on OMAP4. Carried over from OMAP3?

Regards,
Vaibhav

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCHv12 0/9] OMAP3+: PRCM chain handler
  2012-01-09  5:31   ` Bedia, Vaibhav
@ 2012-01-10  1:19     ` Kevin Hilman
  -1 siblings, 0 replies; 36+ messages in thread
From: Kevin Hilman @ 2012-01-10  1:19 UTC (permalink / raw)
  To: Bedia, Vaibhav; +Cc: Paul Walmsley, linux-omap, linux-arm-kernel

"Bedia, Vaibhav" <vaibhav.bedia@ti.com> writes:

> Hi Paul,
>
> On Fri, Dec 16, 2011 at 03:06:09, Paul Walmsley wrote:
>> Hi,
>> 
>> This is a repost of Tero's PRCM chain handler patch set with a few changes:
>> 
>> - A new mux patch has been added to place hwmod mux entries with
>>   OMAP_DEVICE_PAD_WAKEUP set into the dynamic list
>> 
>> - Several OCP barriers have been added to PRM writes to try to protect
>>   against races between PRM register writes and the MPU
>> 
>> - Kerneldoc documentation has been added
>> 
>> - The pending IRQ test functions have been split into per-SoC versions
>> 
>> - Some patches have been rearranged and merged to avoid churn
>> 
>> - The PRM IRQ handler is now installed on OMAP4
>> 
>
> I found a few (minor) issues with this patch series.
>
> 1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
> holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
> omap3xxx_prcm_init() to bypass the chain handler registration.

> Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
> AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
> Hope such cpu_is_*() checks are acceptable.

We try to avoid them, especially when we already have existing feature
flag for IO wakeups.

Does something like (completely untested) patch below work for you?

Of course, that implies that that feature flag is initialized correctly
for AM33xx.

Kevin



diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index c1c4d86..87451d9 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 
 static int __init omap3xxx_prcm_init(void)
 {
-	if (cpu_is_omap34xx())
+	if (cpu_is_omap34xx() && omap3_has_io_wakeup())
 		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCHv12 0/9] OMAP3+: PRCM chain handler
@ 2012-01-10  1:19     ` Kevin Hilman
  0 siblings, 0 replies; 36+ messages in thread
From: Kevin Hilman @ 2012-01-10  1:19 UTC (permalink / raw)
  To: linux-arm-kernel

"Bedia, Vaibhav" <vaibhav.bedia@ti.com> writes:

> Hi Paul,
>
> On Fri, Dec 16, 2011 at 03:06:09, Paul Walmsley wrote:
>> Hi,
>> 
>> This is a repost of Tero's PRCM chain handler patch set with a few changes:
>> 
>> - A new mux patch has been added to place hwmod mux entries with
>>   OMAP_DEVICE_PAD_WAKEUP set into the dynamic list
>> 
>> - Several OCP barriers have been added to PRM writes to try to protect
>>   against races between PRM register writes and the MPU
>> 
>> - Kerneldoc documentation has been added
>> 
>> - The pending IRQ test functions have been split into per-SoC versions
>> 
>> - Some patches have been rearranged and merged to avoid churn
>> 
>> - The PRM IRQ handler is now installed on OMAP4
>> 
>
> I found a few (minor) issues with this patch series.
>
> 1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
> holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
> omap3xxx_prcm_init() to bypass the chain handler registration.

> Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
> AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
> Hope such cpu_is_*() checks are acceptable.

We try to avoid them, especially when we already have existing feature
flag for IO wakeups.

Does something like (completely untested) patch below work for you?

Of course, that implies that that feature flag is initialized correctly
for AM33xx.

Kevin



diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index c1c4d86..87451d9 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 
 static int __init omap3xxx_prcm_init(void)
 {
-	if (cpu_is_omap34xx())
+	if (cpu_is_omap34xx() && omap3_has_io_wakeup())
 		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* RE: [PATCHv12 0/9] OMAP3+: PRCM chain handler
  2012-01-10  1:19     ` Kevin Hilman
@ 2012-01-10 11:41       ` Bedia, Vaibhav
  -1 siblings, 0 replies; 36+ messages in thread
From: Bedia, Vaibhav @ 2012-01-10 11:41 UTC (permalink / raw)
  To: Hilman, Kevin; +Cc: Paul Walmsley, linux-omap, linux-arm-kernel

Hi Kevin,

On Tue, Jan 10, 2012 at 06:49:52, Hilman, Kevin wrote:
[...]
> >
> > 1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
> > holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
> > omap3xxx_prcm_init() to bypass the chain handler registration.
> 
> > Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
> > AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
> > Hope such cpu_is_*() checks are acceptable.
> 
> We try to avoid them, especially when we already have existing feature
> flag for IO wakeups.
> 
> Does something like (completely untested) patch below work for you?
> 
> Of course, that implies that that feature flag is initialized correctly
> for AM33xx.
> 
> Kevin
> 
> 
> 
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> index c1c4d86..87451d9 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> @@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
>  
>  static int __init omap3xxx_prcm_init(void)
>  {
> -	if (cpu_is_omap34xx())
> +	if (cpu_is_omap34xx() && omap3_has_io_wakeup())
>  		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
>  	return 0;
>  }
> 

I'll try this out once we have feature flag initialized on AM33xx.
Can the cpu_is_omap34xx() check be completely dropped in that case?
Or is there some other reason for retaining it?

I guess we'll still need a way to avoid the error message from mux.c

Regards,
Vaibhav

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv12 0/9] OMAP3+: PRCM chain handler
@ 2012-01-10 11:41       ` Bedia, Vaibhav
  0 siblings, 0 replies; 36+ messages in thread
From: Bedia, Vaibhav @ 2012-01-10 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Kevin,

On Tue, Jan 10, 2012 at 06:49:52, Hilman, Kevin wrote:
[...]
> >
> > 1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
> > holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
> > omap3xxx_prcm_init() to bypass the chain handler registration.
> 
> > Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
> > AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
> > Hope such cpu_is_*() checks are acceptable.
> 
> We try to avoid them, especially when we already have existing feature
> flag for IO wakeups.
> 
> Does something like (completely untested) patch below work for you?
> 
> Of course, that implies that that feature flag is initialized correctly
> for AM33xx.
> 
> Kevin
> 
> 
> 
> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> index c1c4d86..87451d9 100644
> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> @@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
>  
>  static int __init omap3xxx_prcm_init(void)
>  {
> -	if (cpu_is_omap34xx())
> +	if (cpu_is_omap34xx() && omap3_has_io_wakeup())
>  		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
>  	return 0;
>  }
> 

I'll try this out once we have feature flag initialized on AM33xx.
Can the cpu_is_omap34xx() check be completely dropped in that case?
Or is there some other reason for retaining it?

I guess we'll still need a way to avoid the error message from mux.c

Regards,
Vaibhav

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCHv12 0/9] OMAP3+: PRCM chain handler
  2012-01-10 11:41       ` Bedia, Vaibhav
@ 2012-01-10 15:13         ` Kevin Hilman
  -1 siblings, 0 replies; 36+ messages in thread
From: Kevin Hilman @ 2012-01-10 15:13 UTC (permalink / raw)
  To: Bedia, Vaibhav; +Cc: Paul Walmsley, linux-omap, linux-arm-kernel

"Bedia, Vaibhav" <vaibhav.bedia@ti.com> writes:

> Hi Kevin,
>
> On Tue, Jan 10, 2012 at 06:49:52, Hilman, Kevin wrote:
> [...]
>> >
>> > 1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
>> > holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
>> > omap3xxx_prcm_init() to bypass the chain handler registration.
>> 
>> > Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
>> > AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
>> > Hope such cpu_is_*() checks are acceptable.
>> 
>> We try to avoid them, especially when we already have existing feature
>> flag for IO wakeups.
>> 
>> Does something like (completely untested) patch below work for you?
>> 
>> Of course, that implies that that feature flag is initialized correctly
>> for AM33xx.
>> 
>> Kevin
>> 
>> 
>> 
>> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
>> index c1c4d86..87451d9 100644
>> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
>> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
>> @@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
>>  
>>  static int __init omap3xxx_prcm_init(void)
>>  {
>> -	if (cpu_is_omap34xx())
>> +	if (cpu_is_omap34xx() && omap3_has_io_wakeup())
>>  		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
>>  	return 0;
>>  }
>> 
>
> I'll try this out once we have feature flag initialized on AM33xx.
> Can the cpu_is_omap34xx() check be completely dropped in that case?
> Or is there some other reason for retaining it?

The reason it is there is because that function is called from an
initcall.  By default, the kernel builds in support for OMAP2/3/4, so
that initcall will get called on every SoC.  Since it should only happen
for OMAP3, the cpu_is_ check is used.

Kevin



^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv12 0/9] OMAP3+: PRCM chain handler
@ 2012-01-10 15:13         ` Kevin Hilman
  0 siblings, 0 replies; 36+ messages in thread
From: Kevin Hilman @ 2012-01-10 15:13 UTC (permalink / raw)
  To: linux-arm-kernel

"Bedia, Vaibhav" <vaibhav.bedia@ti.com> writes:

> Hi Kevin,
>
> On Tue, Jan 10, 2012 at 06:49:52, Hilman, Kevin wrote:
> [...]
>> >
>> > 1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
>> > holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
>> > omap3xxx_prcm_init() to bypass the chain handler registration.
>> 
>> > Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
>> > AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
>> > Hope such cpu_is_*() checks are acceptable.
>> 
>> We try to avoid them, especially when we already have existing feature
>> flag for IO wakeups.
>> 
>> Does something like (completely untested) patch below work for you?
>> 
>> Of course, that implies that that feature flag is initialized correctly
>> for AM33xx.
>> 
>> Kevin
>> 
>> 
>> 
>> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
>> index c1c4d86..87451d9 100644
>> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
>> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
>> @@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
>>  
>>  static int __init omap3xxx_prcm_init(void)
>>  {
>> -	if (cpu_is_omap34xx())
>> +	if (cpu_is_omap34xx() && omap3_has_io_wakeup())
>>  		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
>>  	return 0;
>>  }
>> 
>
> I'll try this out once we have feature flag initialized on AM33xx.
> Can the cpu_is_omap34xx() check be completely dropped in that case?
> Or is there some other reason for retaining it?

The reason it is there is because that function is called from an
initcall.  By default, the kernel builds in support for OMAP2/3/4, so
that initcall will get called on every SoC.  Since it should only happen
for OMAP3, the cpu_is_ check is used.

Kevin

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RE: [PATCHv12 0/9] OMAP3+: PRCM chain handler
  2012-01-10 15:13         ` Kevin Hilman
@ 2012-01-11 13:49           ` Bedia, Vaibhav
  -1 siblings, 0 replies; 36+ messages in thread
From: Bedia, Vaibhav @ 2012-01-11 13:49 UTC (permalink / raw)
  To: Hilman, Kevin; +Cc: Paul Walmsley, linux-omap, linux-arm-kernel

On Tue, Jan 10, 2012 at 20:43:33, Hilman, Kevin wrote:
> "Bedia, Vaibhav" <vaibhav.bedia@ti.com> writes:
> 
> > Hi Kevin,
> >
> > On Tue, Jan 10, 2012 at 06:49:52, Hilman, Kevin wrote:
> > [...]
> >> >
> >> > 1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
> >> > holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
> >> > omap3xxx_prcm_init() to bypass the chain handler registration.
> >> 
> >> > Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
> >> > AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
> >> > Hope such cpu_is_*() checks are acceptable.
> >> 
> >> We try to avoid them, especially when we already have existing feature
> >> flag for IO wakeups.
> >> 
> >> Does something like (completely untested) patch below work for you?
> >> 
> >> Of course, that implies that that feature flag is initialized correctly
> >> for AM33xx.
> >> 
> >> Kevin
> >> 
> >> 
> >> 
> >> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> >> index c1c4d86..87451d9 100644
> >> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
> >> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> >> @@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
> >>  
> >>  static int __init omap3xxx_prcm_init(void)
> >>  {
> >> -	if (cpu_is_omap34xx())
> >> +	if (cpu_is_omap34xx() && omap3_has_io_wakeup())
> >>  		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
> >>  	return 0;
> >>  }
> >> 
> >
> > I'll try this out once we have feature flag initialized on AM33xx.
> > Can the cpu_is_omap34xx() check be completely dropped in that case?
> > Or is there some other reason for retaining it?
> 
> The reason it is there is because that function is called from an
> initcall.  By default, the kernel builds in support for OMAP2/3/4, so
> that initcall will get called on every SoC.  Since it should only happen
> for OMAP3, the cpu_is_ check is used.
> 

I guess my question was misunderstood. My question was regarding your proposed
patch. If omap3_has_io_wakeup() is sufficient to decide whether or not to
register the chain handler is there still a need for cpu_is_omap34xx()?

Regards,
Vaibhav

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCHv12 0/9] OMAP3+: PRCM chain handler
@ 2012-01-11 13:49           ` Bedia, Vaibhav
  0 siblings, 0 replies; 36+ messages in thread
From: Bedia, Vaibhav @ 2012-01-11 13:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 10, 2012 at 20:43:33, Hilman, Kevin wrote:
> "Bedia, Vaibhav" <vaibhav.bedia@ti.com> writes:
> 
> > Hi Kevin,
> >
> > On Tue, Jan 10, 2012 at 06:49:52, Hilman, Kevin wrote:
> > [...]
> >> >
> >> > 1. IO and wakeup events are not supported on AM33XX. Since cpu_is_34xx()
> >> > holds true for AM33XX I ended up adding a !cpu_is_am33xx() check in 
> >> > omap3xxx_prcm_init() to bypass the chain handler registration.
> >> 
> >> > Without such a check we were seeing a crash in USB since USB_CLKCTRL on 
> >> > AM33XX just happens to be at the IRQENABLE_MPU_OFFSET of OMAP3.
> >> > Hope such cpu_is_*() checks are acceptable.
> >> 
> >> We try to avoid them, especially when we already have existing feature
> >> flag for IO wakeups.
> >> 
> >> Does something like (completely untested) patch below work for you?
> >> 
> >> Of course, that implies that that feature flag is initialized correctly
> >> for AM33xx.
> >> 
> >> Kevin
> >> 
> >> 
> >> 
> >> diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> >> index c1c4d86..87451d9 100644
> >> --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
> >> +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
> >> @@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
> >>  
> >>  static int __init omap3xxx_prcm_init(void)
> >>  {
> >> -	if (cpu_is_omap34xx())
> >> +	if (cpu_is_omap34xx() && omap3_has_io_wakeup())
> >>  		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
> >>  	return 0;
> >>  }
> >> 
> >
> > I'll try this out once we have feature flag initialized on AM33xx.
> > Can the cpu_is_omap34xx() check be completely dropped in that case?
> > Or is there some other reason for retaining it?
> 
> The reason it is there is because that function is called from an
> initcall.  By default, the kernel builds in support for OMAP2/3/4, so
> that initcall will get called on every SoC.  Since it should only happen
> for OMAP3, the cpu_is_ check is used.
> 

I guess my question was misunderstood. My question was regarding your proposed
patch. If omap3_has_io_wakeup() is sufficient to decide whether or not to
register the chain handler is there still a need for cpu_is_omap34xx()?

Regards,
Vaibhav

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2012-01-11 13:49 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-15 21:36 [PATCHv12 0/9] OMAP3+: PRCM chain handler Paul Walmsley
2011-12-15 21:36 ` Paul Walmsley
2011-12-15 21:36 ` [PATCH 1/9] ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list Paul Walmsley
2011-12-15 21:36   ` Paul Walmsley
2011-12-15 21:41   ` Tony Lindgren
2011-12-15 21:41     ` Tony Lindgren
2011-12-15 21:36 ` [PATCH 2/9] ARM: OMAP2+: hwmod: Add API to enable IO ring wakeup Paul Walmsley
2011-12-15 21:36   ` Paul Walmsley
2011-12-15 21:36 ` [PATCH 3/9] ARM: OMAP3/4: PRM: add functions to read pending IRQs, PRM barrier Paul Walmsley
2011-12-15 21:36   ` Paul Walmsley
2011-12-15 21:36 ` [PATCH 4/9] ARM: OMAP: PRCM: add support for chain interrupt handler Paul Walmsley
2011-12-15 21:36   ` Paul Walmsley
2011-12-15 21:36 ` [PATCH 5/9] ARM: OMAP: PRCM: add suspend prepare / finish support Paul Walmsley
2011-12-15 21:36   ` Paul Walmsley
2011-12-15 21:36 ` [PATCH 6/9] ARM: OMAP2+: mux: add support for PAD wakeup interrupts Paul Walmsley
2011-12-15 21:36   ` Paul Walmsley
2011-12-15 21:36 ` [PATCH 7/9] ARM: OMAP: hwmod: add support for selecting mpu_irq for each wakeup pad Paul Walmsley
2011-12-15 21:36   ` Paul Walmsley
2011-12-15 21:36 ` [PATCH 8/9] ARM: OMAP3: pm: use prcm chain handler Paul Walmsley
2011-12-15 21:36   ` Paul Walmsley
2011-12-15 21:36 ` [PATCH 9/9] ARM: OMAP4: PRM: use PRCM interrupt handler Paul Walmsley
2011-12-15 21:36   ` Paul Walmsley
2011-12-16  5:10 ` [PATCHv12 0/9] OMAP3+: PRCM chain handler Paul Walmsley
2011-12-16  5:10   ` Paul Walmsley
2011-12-16 12:57   ` Tero Kristo
2011-12-16 12:57     ` Tero Kristo
2012-01-09  5:31 ` Bedia, Vaibhav
2012-01-09  5:31   ` Bedia, Vaibhav
2012-01-10  1:19   ` Kevin Hilman
2012-01-10  1:19     ` Kevin Hilman
2012-01-10 11:41     ` Bedia, Vaibhav
2012-01-10 11:41       ` Bedia, Vaibhav
2012-01-10 15:13       ` Kevin Hilman
2012-01-10 15:13         ` Kevin Hilman
2012-01-11 13:49         ` Bedia, Vaibhav
2012-01-11 13:49           ` Bedia, Vaibhav

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.