Skip to contentSkip to conversation

OMAP3+: PRCM chain handler

PATCH Superseded Paul Walmsley 5 participants 18 messages Dec 15, 2011 – Jan 11, 2012

Subsystems (6)
lore
Share & tools
lore

Paul Walmsley

author maintainer
#0 lore raw

v12 cover OMAP3+: PRCM chain handler

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 <[email protected]>

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
author maintainer
#1 lore raw

PATCH v12 1/9 ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list

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.

Cc Tony Lindgren <[email protected]>
Cc Tero Kristo <[email protected]>
Cc Govindraj R <[email protected]>
---
 arch/arm/mach-omap2/mux.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/mux.c +4 -2
index 655e948..a474c81 100644
@@ -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;
maintainer
#2 lore raw

PATCH 1/9 ARM: OMAP2+: mux: add wakeup-capable hwmod mux entries to dynamic list

Quoted 11 lines · Paul Walmsley

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.

Quoted 4 lines
Cc Tony Lindgren <[email protected]>
Cc Tero Kristo <[email protected]>
Cc Govindraj R <[email protected]>
Quoted 30 lines
---
 arch/arm/mach-omap2/mux.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/mux.c +4 -2
index 655e948..a474c81 100644
@@ -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;
author maintainer
#3 lore raw

PATCH v12 2/9 ARM: OMAP2+: hwmod: Add API to enable IO ring wakeup

In reply to Paul Walmsley

From: Govindraj R <[email protected]>

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.

[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]

---
 arch/arm/mach-omap2/omap_hwmod.c |   47 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 47 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap_hwmod.c +47 -0
index 207a2ff..21ffd8a 100644
@@ -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;
author maintainer
#4 lore raw

PATCH v12 3/9 ARM: OMAP3/4: PRM: add functions to read pending IRQs, PRM barrier

In reply to Paul Walmsley

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 <[email protected]>.

---
 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(-)
arch/arm/mach-omap2/prm2xxx_3xxx.c +33 -1
index f02d87f..177c3dd 100644
@@ -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);
+}
arch/arm/mach-omap2/prm2xxx_3xxx.h +6 -1
index cef533d..3ef0e77 100644
@@ -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
arch/arm/mach-omap2/prm44xx.c +42 -0

45 lines not on this page · raw message

arch/arm/mach-omap2/prm44xx.h +5 -1
index 3d66ccd..bd7f248 100644
@@ -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
author maintainer
#5 lore raw

PATCH v12 4/9 ARM: OMAP: PRCM: add support for chain interrupt handler

In reply to Paul Walmsley

From: Tero Kristo <[email protected]>

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.

Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>
Cc Avinash.H.M <[email protected]>
Cc Benoit Cousson <[email protected]>
Cc Tony Lindgren <[email protected]>
Cc Govindraj.R <[email protected]>

[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]

---
 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
arch/arm/mach-omap2/Makefile +3 -2
index b009f17..2e1ab22 100644
@@ -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
arch/arm/mach-omap2/prcm-common.h +62 -1

75 lines not on this page · raw message

arch/arm/mach-omap2/prm_common.c new file +277 -0

277 lines not on this page · raw message

author maintainer
#6 lore raw

PATCH v12 5/9 ARM: OMAP: PRCM: add suspend prepare / finish support

In reply to Paul Walmsley

From: Tero Kristo <[email protected]>

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.

[paul at pwsan.com: add kerneldoc, add omap_prcm_irq_setup.saved_mask, add fn
ptrs for save_and_clear_irqen() and restore_irqen()]

---
 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(-)
arch/arm/mach-omap2/prcm-common.h +14 -2
index 76db379..0f69d8f 100644
@@ -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
 
arch/arm/mach-omap2/prm2xxx_3xxx.c +37 -0
index 177c3dd..58d9ce70 100644
@@ -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);
+}
arch/arm/mach-omap2/prm2xxx_3xxx.h +2 -0
index 3ef0e77..70ac2a1 100644
@@ -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 */
 
arch/arm/mach-omap2/prm44xx.c +48 -0

51 lines not on this page · raw message

arch/arm/mach-omap2/prm44xx.h +2 -0
index bd7f248..7978092 100644
@@ -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
 
arch/arm/mach-omap2/prm_common.c +45 -2

77 lines not on this page · raw message

author maintainer
#7 lore raw

PATCH v12 6/9 ARM: OMAP2+: mux: add support for PAD wakeup interrupts

In reply to Paul Walmsley

From: Tero Kristo <[email protected]>

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.]

[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]

---
 arch/arm/mach-omap2/mux.c                    |   83 ++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    1 
 2 files changed, 84 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/mux.c +83 -0
index a474c81..e1cc75d 100644
@@ -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;
arch/arm/plat-omap/include/plat/omap_hwmod.h +1 -0
index 8b372ed..f705492 100644
@@ -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;
 };
 
author maintainer
#8 lore raw

PATCH v12 7/9 ARM: OMAP: hwmod: add support for selecting mpu_irq for each wakeup pad

In reply to Paul Walmsley

From: Tero Kristo <[email protected]>

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).

[paul at pwsan.com: moved fn to omap_hwmod.c; separated fn from mux scan_wakeups
changes; added kerneldoc]

---
 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(-)
arch/arm/mach-omap2/omap_hwmod.c +55 -0
index 21ffd8a..7ea3df5 100644
@@ -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;
+}
arch/arm/plat-omap/include/plat/omap_hwmod.h +2 -0
index f705492..ef4bf31 100644
@@ -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
author maintainer
#9 lore raw

PATCH v12 8/9 ARM: OMAP3: pm: use prcm chain handler

In reply to Paul Walmsley

From: Tero Kristo <[email protected]>

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.

[paul at pwsan.com: use pr_err(); combined with portions of earlier patches and
the "do not enable PRCM MPU interrupts manually" patch]

---
 arch/arm/mach-omap2/pm34xx.c       |  115 ++++++++++++++----------------------
 arch/arm/mach-omap2/prm2xxx_3xxx.c |   26 ++++++++
 2 files changed, 70 insertions(+), 71 deletions(-)
arch/arm/mach-omap2/pm34xx.c +44 -71
index efa6649..ba1692e 100644
@@ -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;
 	}
 
arch/arm/mach-omap2/prm2xxx_3xxx.c +26 -0
index 58d9ce70..3545c9a 100644
@@ -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);
author maintainer
#10 lore raw

PATCH v12 9/9 ARM: OMAP4: PRM: use PRCM interrupt handler

In reply to Paul Walmsley

From: Tero Kristo <[email protected]>

Use the new PRCM interrupt handler code on OMAP4 systems.

[paul at pwsan.com: split this from a previous patch to this patch; call
omap4xxx_prcm_init() during init; write trivial commit log]

---
 arch/arm/mach-omap2/prm44xx.c |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/prm44xx.c +26 -0
index c4be5d9..040c39c 100644
@@ -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);
author maintainer
#11 lore raw

v12 cover OMAP3+: PRCM chain handler

In reply to Paul Walmsley

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

#12 lore raw

v12 cover OMAP3+: PRCM chain handler

Quoted 9 lines · Paul Walmsley

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.

Quoted 1 line

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

#13 lore raw

v12 cover OMAP3+: PRCM chain handler

In reply to Paul Walmsley

Hi Paul,

Quoted 10 lines · Paul Walmsley

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

Quoted 8 lines

- 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

#14 lore raw

v12 cover OMAP3+: PRCM chain handler

Quoted 24 lines · Vaibhav

Hi Paul,

Quoted 10 lines · Paul Walmsley

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

Quoted 8 lines

- 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.

Quoted 7 lines

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

arch/arm/mach-omap2/prm2xxx_3xxx.c +1 -1
index c1c4d86..87451d9 100644
@@ -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;
 }
#15 lore raw

v12 cover OMAP3+: PRCM chain handler

Hi Kevin,

On Tue, Jan 10, 2012 at 06:49:52, Hilman, Kevin wrote:
[...]

Quoted 27 lines
Quoted 8 lines

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

arch/arm/mach-omap2/prm2xxx_3xxx.c +0 -0
index c1c4d86..87451d9 100644

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

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

#16 lore raw

v12 cover OMAP3+: PRCM chain handler

Quoted 31 lines · Vaibhav

Hi Kevin,

On Tue, Jan 10, 2012 at 06:49:52, Hilman, Kevin wrote:
[...]

Quoted 27 lines
Quoted 8 lines

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

arch/arm/mach-omap2/prm2xxx_3xxx.c +0 -0
index c1c4d86..87451d9 100644
@@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 
Quoted 12 lines

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

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

#17 lore raw

v12 cover OMAP3+: PRCM chain handler

Quoted 46 lines · Kevin
Quoted 31 lines · Vaibhav

Hi Kevin,

On Tue, Jan 10, 2012 at 06:49:52, Hilman, Kevin wrote:
[...]

Quoted 27 lines
Quoted 8 lines

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

arch/arm/mach-omap2/prm2xxx_3xxx.c +0 -0
index c1c4d86..87451d9 100644
@@ -302,7 +302,7 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
 
Quoted 12 lines

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

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

Quoted 5 lines

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