All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv7 00/11] PRCM chain handler
@ 2011-07-25 16:36 Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
                   ` (10 more replies)
  0 siblings, 11 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap

Hello,

Changes compared to previous set:
- moved OMAP3/OMAP4 specific code under prmXXXX.c files
- dropped most of the event definitions for now, and just left
  wkup and io events in
- PRCM events are now defined as a common struct under prcm.c
- moved mux handling routines from omap_hwmod.c to mux.c
- some other minor tweaks based on received comments

-Tero


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 17:03   ` Felipe Balbi
  2011-08-26  9:12   ` Paul Walmsley
  2011-07-25 16:36 ` [PATCHv6 02/11] OMAP2+: hwmod: Add API to enable IO ring wakeup Tero Kristo
                   ` (9 subsequent siblings)
  10 siblings, 2 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap
  Cc: Thomas Petazzoni, Avinash.H.M, Kevin Hilman, Cousson, Benoit,
	Tony Lindgren, Govindraj.R, Felipe Balbi, Paul Walmsley

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.

arch/arm/mach-omap2/prcm.c implements the chained interrupt mechanism
itself, with SoC specific support / init structure defined in
arch/arm/mach-omap2/prm2xxx_3xxx.c and arch/arm/mach-omap2/prm4xxx.c
respectively. At initialization time, the set of PRCM events is filtered
against the SoC on which we are running, keeping only the ones that are
actually useful. All the logic is written to be generic with regard to
OMAP3/OMAP4, even though OMAP3 has single PRCM event registers and OMAP4
has two PRCM event registers.

Patch tested on OMAP3 beagleboard.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Avinash.H.M <avinashhm@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Cousson, Benoit <b-cousson@ti.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
Cc: Felipe Balbi <balbi@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/pm34xx.c           |  106 ++++++-----------
 arch/arm/mach-omap2/prcm.c             |  205 ++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prm2xxx_3xxx.c     |   18 +++
 arch/arm/mach-omap2/prm2xxx_3xxx.h     |    4 +
 arch/arm/mach-omap2/prm44xx.c          |   29 +++++
 arch/arm/mach-omap2/prm44xx.h          |    2 +
 arch/arm/plat-omap/include/plat/prcm.h |   15 +++
 7 files changed, 309 insertions(+), 70 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 7255d9b..7805a07 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -64,6 +64,9 @@ static inline bool is_suspending(void)
 }
 #endif
 
+static int prcm_io_irq;
+static int prcm_wkup_irq;
+
 /* pm34xx errata defined in pm.h */
 u16 pm34xx_errata;
 
@@ -234,7 +237,7 @@ 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_wakeup(int irq, void *unused)
 {
 	int c;
 
@@ -246,64 +249,7 @@ static int _prcm_int_handle_wakeup(void)
 		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
 	}
 
-	return c;
-}
-
-/*
- * 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)
-{
-	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;
-
-	} while (irqstatus_mpu);
-
-	return IRQ_HANDLED;
+	return c ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static void omap34xx_save_context(u32 *save)
@@ -875,20 +821,35 @@ static int __init omap3_pm_init(void)
 	/* XXX prcm_setup_regs needs to be before enabling hw
 	 * supervised mode for powerdomains */
 	prcm_setup_regs();
+	ret = omap3_prcm_irq_init();
+	if (ret) {
+		pr_err("omap_prcm_irq_init() failed with %d\n", ret);
+		goto err_prcm_irq_init;
+	}
+
+	prcm_wkup_irq = omap_prcm_event_to_irq("wkup");
+	prcm_io_irq = omap_prcm_event_to_irq("io");
+
+	ret = request_irq(prcm_wkup_irq, _prcm_int_handle_wakeup,
+			IRQF_NO_SUSPEND, "prcm_wkup", NULL);
 
-	ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
-			  (irq_handler_t)prcm_interrupt_handler,
-			  IRQF_DISABLED, "prcm", NULL);
 	if (ret) {
-		printk(KERN_ERR "request_irq failed to register for 0x%x\n",
-		       INT_34XX_PRCM_MPU_IRQ);
-		goto err1;
+		printk(KERN_ERR "Failed to request prcm_wkup irq\n");
+		goto err_prcm_wkup;
+	}
+
+	ret = request_irq(prcm_io_irq, _prcm_int_handle_wakeup,
+			IRQF_NO_SUSPEND, "prcm_io", NULL);
+
+	if (ret) {
+		printk(KERN_ERR "Failed to request prcm_io irq\n");
+		goto err_prcm_io;
 	}
 
 	ret = pwrdm_for_each(pwrdms_setup, NULL);
 	if (ret) {
 		printk(KERN_ERR "Failed to setup powerdomains\n");
-		goto err2;
+		goto err_pwrdms_setup;
 	}
 
 	(void) clkdm_for_each(clkdms_setup, NULL);
@@ -896,7 +857,7 @@ static int __init omap3_pm_init(void)
 	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
 	if (mpu_pwrdm == NULL) {
 		printk(KERN_ERR "Failed to get mpu_pwrdm\n");
-		goto err2;
+		goto err_pwrdms_setup;
 	}
 
 	neon_pwrdm = pwrdm_lookup("neon_pwrdm");
@@ -944,14 +905,19 @@ static int __init omap3_pm_init(void)
 	}
 
 	omap3_save_scratchpad_contents();
-err1:
+
 	return ret;
-err2:
-	free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
+
+ err_pwrdms_setup:
 	list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
 		list_del(&pwrst->node);
 		kfree(pwrst);
 	}
+ err_prcm_io:
+	free_irq(prcm_wkup_irq, NULL);
+ err_prcm_wkup:
+	omap_prcm_irq_cleanup();
+ err_prcm_irq_init:
 	return ret;
 }
 
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 2e40a5c..83cf8ae 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -23,6 +23,8 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
 
 #include <mach/system.h>
 #include <plat/common.h>
@@ -45,6 +47,209 @@ void __iomem *cm2_base;
 
 #define MAX_MODULE_ENABLE_WAIT		100000
 
+/* Maximum number of PRCM interrupt status registers */
+#define OMAP_PRCM_MAX_NR_PENDING_REG	2
+
+/* 64 interrupts needed on OMAP4, 32 on OMAP3 */
+#define OMAP_PRCM_NR_IRQS		64
+
+/* Setup for the interrupt handling based on used platform */
+static struct omap_prcm_irq_setup *irq_setup;
+
+static struct irq_chip_generic *prcm_irq_chips[OMAP_PRCM_MAX_NR_PENDING_REG];
+
+/*
+ * Structure describing the interrupt corresponding to each PRCM event
+ */
+struct omap_prcm_irq {
+	/* Logical name for the interrupt */
+	const char *name;
+
+	/*
+	 * Corresponding offset in the status/enable register. The
+	 * offset can be greater than 32, in which case it spans over
+	 * to the second status register
+	 */
+	unsigned int offset;
+
+	/* OMAP chip for which this PRCM event exists */
+	const struct omap_chip_id omap_chip;
+};
+
+#define OMAP_PRCM_IRQ(_name, _offset, _chip) {	\
+	.name = _name,				\
+	.offset = _offset,			\
+	.omap_chip = OMAP_CHIP_INIT(_chip)	\
+	}
+
+static struct omap_prcm_irq omap_prcm_irqs[] = {
+	OMAP_PRCM_IRQ("wkup",			0,
+			CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("io",			9,
+			CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1 |
+			CHIP_IS_OMAP4430),
+};
+
+/*
+ * 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 void prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	/*
+	 * Loop until all pending irqs are handled, since
+	 * generic_handle_irq() can cause new irqs to come
+	 */
+	while (1) {
+		unsigned int virtirq;
+
+		chip->irq_ack(&desc->irq_data);
+
+		memset(pending, 0, sizeof(pending));
+		irq_setup->pending_events(pending);
+
+		/* No bit set, then all IRQs are handled */
+		if (find_first_bit(pending, OMAP_PRCM_NR_IRQS)
+		    >= OMAP_PRCM_NR_IRQS) {
+			chip->irq_unmask(&desc->irq_data);
+			break;
+		}
+
+		/*
+		 * Loop on all currently pending irqs so that new irqs
+		 * cannot starve previously pending irqs
+		 */
+		for_each_set_bit(virtirq, pending, OMAP_PRCM_NR_IRQS)
+			generic_handle_irq(irq_setup->base_irq + virtirq);
+
+		chip->irq_unmask(&desc->irq_data);
+	}
+}
+
+/*
+ * Given a PRCM event name, returns the corresponding IRQ on which the
+ * handler should be registered.
+ */
+int omap_prcm_event_to_irq(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(omap_prcm_irqs); i++)
+		if (!strcmp(omap_prcm_irqs[i].name, name))
+			return irq_setup->base_irq + omap_prcm_irqs[i].offset;
+
+	return -ENOENT;
+}
+
+/*
+ * Reverses memory allocated and other setups done by
+ * omap_prcm_irq_init().
+ */
+void omap_prcm_irq_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < OMAP_PRCM_MAX_NR_PENDING_REG; i++) {
+		if (prcm_irq_chips[i])
+			irq_remove_generic_chip(prcm_irq_chips[i], 0xffffffff,
+						0, 0);
+		prcm_irq_chips[i] = NULL;
+	}
+
+	irq_set_chained_handler(irq_setup->irq, NULL);
+
+	if (irq_setup->base_irq > 0)
+		irq_free_descs(irq_setup->base_irq, OMAP_PRCM_NR_IRQS);
+	irq_setup->base_irq = 0;
+}
+
+/*
+ * Prepare the array of PRCM events corresponding to the current SoC,
+ * and set-up the chained interrupt handler mechanism.
+ */
+static int __init omap_prcm_irq_init(void)
+{
+	int i;
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+	u32 mask[2] = { 0, 0 };
+	int offset;
+	int max_irq = 0;
+
+	for (i = 0; i < ARRAY_SIZE(omap_prcm_irqs); i++)
+		if (omap_chip_is(omap_prcm_irqs[i].omap_chip)) {
+			offset = omap_prcm_irqs[i].offset;
+			if (offset < 32)
+				mask[0] |= 1 << offset;
+			else
+				mask[1] |= 1 << (offset - 32);
+			if (offset > max_irq)
+				max_irq = offset;
+		}
+
+	irq_set_chained_handler(irq_setup->irq, prcm_irq_handler);
+
+	irq_setup->base_irq = irq_alloc_descs(-1, 0, OMAP_PRCM_NR_IRQS, 0);
+
+	if (irq_setup->base_irq < 0) {
+		pr_err("PRCM: failed to allocate irq descs\n");
+		goto err;
+	}
+
+	for (i = 0; i <= max_irq / 32; i++) {
+		gc = irq_alloc_generic_chip("PRCM", 1,
+			irq_setup->base_irq + i * 32, NULL, 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;
+		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 << 2);
+		ct->regs.mask = irq_setup->mask + (i << 2);
+
+		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;
+}
+
+int __init omap3_prcm_irq_init(void)
+{
+	irq_setup = &omap3_prcm_irq_setup;
+	return omap_prcm_irq_init();
+}
+
+int __init omap4_prcm_irq_init(void)
+{
+	irq_setup = &omap4_prcm_irq_setup;
+	return omap_prcm_irq_init();
+}
+
 u32 omap_prcm_get_reset_sources(void)
 {
 	/* XXX This presumably needs modification for 34XX */
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index 3b83763..3af3313 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -19,6 +19,7 @@
 #include <plat/common.h>
 #include <plat/cpu.h>
 #include <plat/prcm.h>
+#include <plat/irqs.h>
 
 #include "vp.h"
 
@@ -212,3 +213,20 @@ u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset)
 {
 	return omap2_prm_rmw_mod_reg_bits(mask, bits, OMAP3430_GR_MOD, offset);
 }
+
+static void omap3_prm_pending_events(unsigned long *events)
+{
+	u32 irqenable_mpu =
+		omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+	u32 irqstatus_mpu =
+		omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
+	events[0] = irqenable_mpu & irqstatus_mpu;
+}
+
+struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
+	.ack = (u32)OMAP3430_PRM_IRQSTATUS_MPU,
+	.mask = (u32)OMAP3430_PRM_IRQENABLE_MPU,
+	.pending_events = omap3_prm_pending_events,
+	.irq = INT_34XX_PRCM_MPU_IRQ,
+};
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index cef533d..8bf8af7 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -314,6 +314,10 @@ 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);
+
+/* PRCM irq setup struct, used by common PRCM irq routines */
+extern struct omap_prcm_irq_setup omap3_prcm_irq_setup;
+
 #endif	/* CONFIG_ARCH_OMAP4 */
 
 #endif
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index 495a31a..2beeb40 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -20,6 +20,7 @@
 #include <plat/common.h>
 #include <plat/cpu.h>
 #include <plat/prcm.h>
+#include <plat/irqs.h>
 
 #include "vp.h"
 #include "prm44xx.h"
@@ -121,3 +122,31 @@ u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset)
 					       OMAP4430_PRM_DEVICE_INST,
 					       offset);
 }
+
+static void omap4_prm_pending_events(unsigned long *events)
+{
+	u32 irqenable_mpu, irqstatus_mpu;
+	int i;
+
+	/* OMAP4 has two enable/status registers for the PRCM */
+	for (i = 0; i < 2; i++) {
+		irqenable_mpu =
+			omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
+						OMAP4_PRM_IRQENABLE_MPU_OFFSET
+						+ i * 4);
+		irqstatus_mpu =
+			omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
+						OMAP4_PRM_IRQSTATUS_MPU_OFFSET
+						+ i * 4);
+		events[i] = irqenable_mpu & irqstatus_mpu;
+	}
+}
+
+struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
+	.ack = (u32)OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_INST,
+			OMAP4_PRM_IRQSTATUS_MPU_OFFSET),
+	.mask = (u32)OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_INST,
+			OMAP4_PRM_IRQENABLE_MPU_OFFSET),
+	.pending_events = omap4_prm_pending_events,
+	.irq = OMAP44XX_IRQ_PRCM,
+};
diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h
index 3d66ccd..0c71933 100644
--- a/arch/arm/mach-omap2/prm44xx.h
+++ b/arch/arm/mach-omap2/prm44xx.h
@@ -765,4 +765,6 @@ extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
 
 # endif
 
+extern struct omap_prcm_irq_setup omap4_prcm_irq_setup;
+
 #endif
diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h
index 267f43b..798c175 100644
--- a/arch/arm/plat-omap/include/plat/prcm.h
+++ b/arch/arm/plat-omap/include/plat/prcm.h
@@ -27,6 +27,21 @@
 #ifndef __ASM_ARM_ARCH_OMAP_PRCM_H
 #define __ASM_ARM_ARCH_OMAP_PRCM_H
 
+#include <plat/cpu.h>
+
+/* Setup for the PRCM interrupt handler */
+struct omap_prcm_irq_setup {
+	void (*pending_events)(unsigned long *);
+	u32 ack;
+	u32 mask;
+	int irq;
+	int base_irq;
+};
+
+int omap_prcm_event_to_irq(const char *name);
+int omap3_prcm_irq_init(void);
+int omap4_prcm_irq_init(void);
+void omap_prcm_irq_cleanup(void);
 u32 omap_prcm_get_reset_sources(void);
 int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, u8 idlest,
 			 const char *name);
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 02/11] OMAP2+: hwmod: Add API to enable IO ring wakeup.
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 03/11] OMAP2+: hwmod: Add API to check IO PAD wakeup status Tero Kristo
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap; +Cc: R, Govindraj

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

Add API to enable IO pad wakeup capability based on mux dynamic 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.

Map the enable/disable pad wakeup API's to hwmod_wakeup_enable/disable.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod.c |   59 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 84cc0bd..e751dd9 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2062,6 +2062,34 @@ static int __init omap_hwmod_setup_all(void)
 core_initcall(omap_hwmod_setup_all);
 
 /**
+ * omap_hwmod_set_ioring_wakeup - enable io pad wakeup flag.
+ * @oh: struct omap_hwmod *
+ * @set: bool value indicating to set or clear wakeup status.
+ *
+ * Set or Clear wakeup flag for the io_pad.
+ */
+static int omap_hwmod_set_ioring_wakeup(struct omap_hwmod *oh, bool set_wake)
+{
+	struct omap_device_pad *pad;
+	int ret = -EINVAL, j;
+
+	if (oh->mux && oh->mux->enabled) {
+		for (j = 0; j < oh->mux->nr_pads_dynamic; j++) {
+			pad = oh->mux->pads_dynamic[j];
+			if (pad->flags & OMAP_DEVICE_PAD_WAKEUP) {
+				if (set_wake)
+					pad->idle |= OMAP_WAKEUP_EN;
+				else
+					pad->idle &= ~OMAP_WAKEUP_EN;
+				ret = 0;
+			}
+		}
+	}
+
+	return ret;
+}
+
+/**
  * omap_hwmod_enable - enable an omap_hwmod
  * @oh: struct omap_hwmod *
  *
@@ -2393,6 +2421,35 @@ int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh,
 {
 	return _del_initiator_dep(oh, init_oh);
 }
+/**
+ * omap_hwmod_enable_ioring_wakeup - Set wakeup flag for iopad.
+ * @oh: struct omap_hwmod *
+ *
+ * Traverse through dynamic pads, if pad is enabled then
+ * set wakeup enable bit flag for the mux pin. Wakeup pad bit
+ * will be set during hwmod idle transistion.
+ * Return error if pads are not enabled or not available.
+ */
+int omap_hwmod_enable_ioring_wakeup(struct omap_hwmod *oh)
+{
+	/* Enable pad wake-up capability */
+	return omap_hwmod_set_ioring_wakeup(oh, true);
+}
+
+/**
+ * omap_hwmod_disable_ioring_wakeup - Clear wakeup flag for iopad.
+ * @oh: struct omap_hwmod *
+ *
+ * Traverse through dynamic pads, if pad is enabled then
+ * clear wakeup enable bit flag for the mux pin. Wakeup pad bit
+ * will be set during hwmod idle transistion.
+ * Return error if pads are not enabled or not available.
+ */
+int omap_hwmod_disable_ioring_wakeup(struct omap_hwmod *oh)
+{
+	/* Disable pad wakeup capability */
+	return omap_hwmod_set_ioring_wakeup(oh, false);
+}
 
 /**
  * omap_hwmod_enable_wakeup - allow device to wake up the system
@@ -2419,6 +2476,7 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
 	v = oh->_sysc_cache;
 	_enable_wakeup(oh, &v);
 	_write_sysconfig(v, oh);
+	omap_hwmod_enable_ioring_wakeup(oh);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
 	return 0;
@@ -2449,6 +2507,7 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
 	v = oh->_sysc_cache;
 	_disable_wakeup(oh, &v);
 	_write_sysconfig(v, oh);
+	omap_hwmod_disable_ioring_wakeup(oh);
 	spin_unlock_irqrestore(&oh->_lock, flags);
 
 	return 0;
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 03/11] OMAP2+: hwmod: Add API to check IO PAD wakeup status
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 02/11] OMAP2+: hwmod: Add API to enable IO ring wakeup Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 04/11] OMAP2+: mux: add support for PAD wakeup interrupts Tero Kristo
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap; +Cc: R, Govindraj

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

Add API to determine IO-PAD wakeup event status for a given
hwmod dynamic_mux pad.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
 arch/arm/mach-omap2/mux.c                    |   30 ++++++++++++++++++++++++++
 arch/arm/mach-omap2/mux.h                    |   13 +++++++++++
 arch/arm/mach-omap2/omap_hwmod.c             |    7 ++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    1 +
 4 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index c7fb22a..50ee806 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -351,6 +351,36 @@ err1:
 	return NULL;
 }
 
+/**
+ * omap_hwmod_mux_get_wake_status - omap hwmod check pad wakeup
+ * @hmux:		Pads for a hwmod
+ *
+ * Gets the wakeup status of given pad from omap-hwmod.
+ * Returns true if wakeup event is set for pad else false
+ * if wakeup is not occured or pads are not avialable.
+ */
+bool omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux)
+{
+	int i;
+	unsigned int val;
+	u8 ret = false;
+
+	for (i = 0; i < hmux->nr_pads; i++) {
+		struct omap_device_pad *pad = &hmux->pads[i];
+
+		if (pad->flags & OMAP_DEVICE_PAD_WAKEUP) {
+			val = omap_mux_read(pad->partition,
+					pad->mux->reg_offset);
+			if (val & OMAP_WAKEUP_EVENT) {
+				ret = true;
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
 /* Assumes the calling function takes care of locking */
 void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
 {
diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h
index 2132308..8b2150a 100644
--- a/arch/arm/mach-omap2/mux.h
+++ b/arch/arm/mach-omap2/mux.h
@@ -225,8 +225,21 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads);
  */
 void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state);
 
+/**
+ * omap_hwmod_mux_get_wake_status - omap hwmod check pad wakeup
+ * @hmux:		Pads for a hwmod
+ *
+ * Called only from omap_hwmod.c, do not use.
+ */
+bool omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux);
 #else
 
+static inline bool
+omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux)
+{
+	return 0;
+}
+
 static inline int omap_mux_init_gpio(int gpio, int val)
 {
 	return 0;
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e751dd9..a8b24d7 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2724,3 +2724,10 @@ int omap_hwmod_no_setup_reset(struct omap_hwmod *oh)
 
 	return 0;
 }
+
+int omap_hwmod_pad_get_wakeup_status(struct omap_hwmod *oh)
+{
+	if (oh && oh->mux)
+		return omap_hwmod_mux_get_wake_status(oh->mux);
+	return -EINVAL;
+}
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 38ac4af..9c70cc8 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -606,6 +606,7 @@ u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
 
 int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
 
+int omap_hwmod_pad_get_wakeup_status(struct omap_hwmod *oh);
 /*
  * Chip variant-specific hwmod init routines - XXX should be converted
  * to use initcalls once the initial boot ordering is straightened out
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 04/11] OMAP2+: mux: add support for PAD wakeup interrupts
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
                   ` (2 preceding siblings ...)
  2011-07-25 16:36 ` [PATCHv6 03/11] OMAP2+: hwmod: Add API to check IO PAD wakeup status Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 05/11] TEMP: OMAP3: pm: remove serial resume / idle calls from idle path Tero Kristo
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap

OMAP mux now provides a service routine to parse pending wakeup events
and to call registered ISR whenever active wakeups are detected. This
routine is called directly from PRCM interrupt handler.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/mux.c  |   27 +++++++++++++++++++++++++++
 arch/arm/mach-omap2/mux.h  |   11 +++++++++++
 arch/arm/mach-omap2/prcm.c |    4 ++++
 3 files changed, 42 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 50ee806..b6c4ea1 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -32,6 +32,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
+#include <linux/irq.h>
 
 #include <asm/system.h>
 
@@ -381,6 +382,32 @@ bool omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux)
 	return ret;
 }
 
+/**
+ * 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_get_wake_status(oh->mux))
+		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.
+ */
+void omap_hwmod_mux_handle_irq(void)
+{
+	omap_hwmod_for_each(_omap_hwmod_mux_handle_irq, NULL);
+}
+
 /* Assumes the calling function takes care of locking */
 void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
 {
diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h
index 8b2150a..6e7f1a4 100644
--- a/arch/arm/mach-omap2/mux.h
+++ b/arch/arm/mach-omap2/mux.h
@@ -232,6 +232,13 @@ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state);
  * Called only from omap_hwmod.c, do not use.
  */
 bool omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux);
+
+/**
+ * omap_hwmod_mux_handle_irq - handler for IO pad wakeup events
+ *
+ * Called only from prcm.c to process PRCM IO events, do not use.
+ */
+void omap_hwmod_mux_handle_irq(void);
 #else
 
 static inline bool
@@ -259,6 +266,10 @@ static inline void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
 {
 }
 
+static inline void omap_hwmod_mux_handle_irq(void)
+{
+}
+
 static struct omap_board_mux *board_mux __initdata __maybe_unused;
 
 #endif
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 83cf8ae..7d8a6d8 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -40,6 +40,7 @@
 #include "prm-regbits-24xx.h"
 #include "prm-regbits-44xx.h"
 #include "control.h"
+#include "mux.h"
 
 void __iomem *prm_base;
 void __iomem *cm_base;
@@ -112,6 +113,9 @@ static void prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
 	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 
+	/* Handle PAD events first, we don't want to ack them before parse */
+	omap_hwmod_mux_handle_irq();
+
 	/*
 	 * Loop until all pending irqs are handled, since
 	 * generic_handle_irq() can cause new irqs to come
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 05/11] TEMP: OMAP3: pm: remove serial resume / idle calls from idle path
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
                   ` (3 preceding siblings ...)
  2011-07-25 16:36 ` [PATCHv6 04/11] OMAP2+: mux: add support for PAD wakeup interrupts Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 06/11] TEMP: OMAP3: serial: made serial to work properly with PRCM chain handler Tero Kristo
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap

This is no longer needed as it will be handled within serial driver itself.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/pm34xx.c |   19 -------------------
 1 files changed, 0 insertions(+), 19 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 7805a07..b9b5128 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -325,18 +325,9 @@ void omap_sram_idle(void)
 		omap3_enable_io_chain();
 	}
 
-	/* Block console output in case it is on one of the OMAP UARTs */
-	if (!is_suspending())
-		if (per_next_state < PWRDM_POWER_ON ||
-		    core_next_state < PWRDM_POWER_ON)
-			if (!console_trylock())
-				goto console_still_active;
-
 	/* PER */
 	if (per_next_state < PWRDM_POWER_ON) {
 		per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
-		omap_uart_prepare_idle(2);
-		omap_uart_prepare_idle(3);
 		omap2_gpio_prepare_for_idle(per_going_off);
 		if (per_next_state == PWRDM_POWER_OFF)
 				omap3_per_save_context();
@@ -344,8 +335,6 @@ void omap_sram_idle(void)
 
 	/* CORE */
 	if (core_next_state < PWRDM_POWER_ON) {
-		omap_uart_prepare_idle(0);
-		omap_uart_prepare_idle(1);
 		if (core_next_state == PWRDM_POWER_OFF) {
 			omap3_core_save_context();
 			omap3_cm_save_context();
@@ -392,8 +381,6 @@ void omap_sram_idle(void)
 			omap3_sram_restore_context();
 			omap2_sms_restore_context();
 		}
-		omap_uart_resume_idle(0);
-		omap_uart_resume_idle(1);
 		if (core_next_state == PWRDM_POWER_OFF)
 			omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
 					       OMAP3430_GR_MOD,
@@ -407,14 +394,8 @@ void omap_sram_idle(void)
 		omap2_gpio_resume_after_idle();
 		if (per_prev_state == PWRDM_POWER_OFF)
 			omap3_per_restore_context();
-		omap_uart_resume_idle(2);
-		omap_uart_resume_idle(3);
 	}
 
-	if (!is_suspending())
-		console_unlock();
-
-console_still_active:
 	/* Disable IO-PAD and IO-CHAIN wakeup */
 	if (omap3_has_io_wakeup() &&
 	    (per_next_state < PWRDM_POWER_ON ||
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 06/11] TEMP: OMAP3: serial: made serial to work properly with PRCM chain handler
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
                   ` (4 preceding siblings ...)
  2011-07-25 16:36 ` [PATCHv6 05/11] TEMP: OMAP3: pm: remove serial resume / idle calls from idle path Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 07/11] TEMP: serial: added mux support Tero Kristo
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap

This patch is just a temporary hack to allow serial to work properly with
the PRCM chain handler. Should be replaced with a proper implementation.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/serial.c     |   28 +++++++++-------------------
 drivers/tty/serial/omap-serial.c |    8 ++++++++
 2 files changed, 17 insertions(+), 19 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 466fc722..651fb91 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -39,6 +39,7 @@
 #include <plat/dma.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/prcm.h>
 
 #include "prm2xxx_3xxx.h"
 #include "pm.h"
@@ -380,6 +381,7 @@ static void omap_uart_allow_sleep(struct omap_uart_state *uart)
 	omap_uart_smart_idle_enable(uart, 1);
 	uart->can_sleep = 1;
 	del_timer(&uart->timer);
+	omap_uart_disable_clocks(uart);
 }
 
 static void omap_uart_idle_timer(unsigned long data)
@@ -391,35 +393,23 @@ static void omap_uart_idle_timer(unsigned long data)
 
 void omap_uart_prepare_idle(int num)
 {
-	struct omap_uart_state *uart;
-
-	list_for_each_entry(uart, &uart_list, node) {
-		if (num == uart->num && uart->can_sleep) {
-			omap_uart_disable_clocks(uart);
-			return;
-		}
-	}
 }
 
 void omap_uart_resume_idle(int num)
 {
 	struct omap_uart_state *uart;
+	u32 wkst;
 
 	list_for_each_entry(uart, &uart_list, node) {
 		if (num == uart->num && uart->can_sleep) {
-			omap_uart_enable_clocks(uart);
+			omap_uart_block_sleep(uart);
 
-			/* Check for IO pad wakeup */
-			if (cpu_is_omap34xx() && uart->padconf) {
-				u16 p = omap_ctrl_readw(uart->padconf);
-
-				if (p & OMAP3_PADCONF_WAKEUPEVENT0)
-					omap_uart_block_sleep(uart);
+			/* Check for normal UART wakeup (and clear it) */
+			if (uart->wk_st && uart->wk_mask) {
+				wkst = __raw_readl(uart->wk_st) & uart->wk_mask;
+				if (wkst)
+					__raw_writel(wkst, uart->wk_st);
 			}
-
-			/* Check for normal UART wakeup */
-			if (__raw_readl(uart->wk_st) & uart->wk_mask)
-				omap_uart_block_sleep(uart);
 			return;
 		}
 	}
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 47cadf4..bd6ae02 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -261,6 +261,8 @@ static void serial_omap_start_tx(struct uart_port *port)
 	unsigned int start;
 	int ret = 0;
 
+	omap_uart_resume_idle(up->pdev->id);
+
 	if (!up->use_dma) {
 		serial_omap_enable_ier_thri(up);
 		return;
@@ -354,6 +356,8 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
 	unsigned int iir, lsr;
 	unsigned long flags;
 
+	omap_uart_resume_idle(up->pdev->id);
+
 	iir = serial_in(up, UART_IIR);
 	if (iir & UART_IIR_NO_INT)
 		return IRQ_NONE;
@@ -641,6 +645,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 	unsigned long flags = 0;
 	unsigned int baud, quot;
 
+	omap_uart_resume_idle(up->pdev->id);
+
 	switch (termios->c_cflag & CSIZE) {
 	case CS5:
 		cval = UART_LCR_WLEN5;
@@ -947,6 +953,8 @@ serial_omap_console_write(struct console *co, const char *s,
 	unsigned int ier;
 	int locked = 1;
 
+	omap_uart_resume_idle(up->pdev->id);
+
 	local_irq_save(flags);
 	if (up->port.sysrq)
 		locked = 0;
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 07/11] TEMP: serial: added mux support
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
                   ` (5 preceding siblings ...)
  2011-07-25 16:36 ` [PATCHv6 06/11] TEMP: OMAP3: serial: made serial to work properly with PRCM chain handler Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 08/11] TEMP: OMAP device: change pr_warnings to pr_debugs Tero Kristo
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap

Just for PRCM chain handler testing purposes. This should be replaced with
a proper implementation.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/serial.c |   71 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 651fb91..47c4353 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -852,17 +852,84 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
  * can call this function when they want to have default behaviour
  * for serial ports (e.g initialize them all as serial ports).
  */
+
+struct serial_mux_conf {
+	char *name;
+	int omap3_mux;
+	int omap4_mux;
+};
+
+#define OMAP3_SERIAL_MUX_IN_PU (OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0)
+#define OMAP3_SERIAL_MUX_IN_PD (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0)
+#define OMAP3_SERIAL_MUX_IN (OMAP_PIN_INPUT | OMAP_MUX_MODE0)
+#define OMAP3_SERIAL_MUX_OUT (OMAP_PIN_OUTPUT | OMAP_MUX_MODE0)
+#define OMAP4_SERIAL_MUX_IN_PU (OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0)
+#define OMAP4_SERIAL_MUX_OUT (OMAP_PIN_OUTPUT | OMAP_MUX_MODE0)
+#define OMAP4_SERIAL_MUX_IN (OMAP_PIN_INPUT | OMAP_MUX_MODE0)
+#define SERIAL_DISABLED OMAP_MUX_MODE7
+
+#define OMAP_SERIAL_NUM_PADS_PER_PORT 4
+
+static const struct serial_mux_conf serial_mux_data[] = {
+	{ "uart1_cts.uart1_cts", OMAP3_SERIAL_MUX_IN, SERIAL_DISABLED, },
+	{ "uart1_rts.uart1_rts", OMAP3_SERIAL_MUX_OUT, SERIAL_DISABLED, },
+	{ "uart1_rx.uart1_rx", OMAP3_SERIAL_MUX_IN, SERIAL_DISABLED, },
+	{ "uart1_tx.uart1_tx", OMAP3_SERIAL_MUX_OUT, SERIAL_DISABLED, },
+	{ "uart2_cts.uart2_cts", OMAP3_SERIAL_MUX_IN,
+		OMAP4_SERIAL_MUX_IN_PU, },
+	{ "uart2_rts.uart2_rts", OMAP3_SERIAL_MUX_OUT, OMAP4_SERIAL_MUX_OUT, },
+	{ "uart2_rx.uart2_rx", OMAP3_SERIAL_MUX_IN, OMAP4_SERIAL_MUX_IN_PU, },
+	{ "uart2_tx.uart2_tx", OMAP3_SERIAL_MUX_OUT, OMAP4_SERIAL_MUX_OUT },
+	{ "uart3_cts_rctx.uart3_cts_rctx", OMAP3_SERIAL_MUX_IN_PD,
+		OMAP4_SERIAL_MUX_IN_PU, },
+	{ "uart3_rts_sd.uart3_rts_sd", OMAP3_SERIAL_MUX_OUT,
+		OMAP4_SERIAL_MUX_OUT, },
+	{ "uart3_rx_irrx.uart3_rx_irrx", OMAP3_SERIAL_MUX_IN,
+		OMAP4_SERIAL_MUX_IN, },
+	{ "uart3_tx_irtx.uart3_tx_irtx", OMAP3_SERIAL_MUX_OUT,
+		OMAP4_SERIAL_MUX_OUT, },
+	{ "uart4_rx.uart4_rx", SERIAL_DISABLED, OMAP4_SERIAL_MUX_IN, },
+	{ "uart4_tx.uart4_tx", SERIAL_DISABLED, OMAP4_SERIAL_MUX_OUT, },
+	{ NULL, 0, 0, },
+	{ NULL, 0, 0, },
+};
+
 void __init omap_serial_init(void)
 {
 	struct omap_uart_state *uart;
 	struct omap_board_data bdata;
+	struct omap_device_pad *pads;
+	int idx;
+	int i;
 
+	pads = kmalloc(sizeof(struct omap_device_pad) * 4, GFP_KERNEL);
 	list_for_each_entry(uart, &uart_list, node) {
 		bdata.id = uart->num;
 		bdata.flags = 0;
-		bdata.pads = NULL;
 		bdata.pads_cnt = 0;
+		bdata.pads = pads;
+
+		for (i = 0; i < OMAP_SERIAL_NUM_PADS_PER_PORT; i++) {
+			idx = bdata.id * OMAP_SERIAL_NUM_PADS_PER_PORT + i;
+			pads[i].name = serial_mux_data[idx].name;
+			pads[i].enable = 0;
+			pads[i].idle = 0;
+			pads[i].flags = 0;
+			if (cpu_is_omap34xx())
+				pads[i].enable = serial_mux_data[idx].omap3_mux;
+			if (cpu_is_omap44xx())
+				pads[i].enable = serial_mux_data[idx].omap4_mux;
+			if (pads[i].enable != SERIAL_DISABLED)
+				bdata.pads_cnt++;
+			if (pads[i].enable & OMAP_PIN_INPUT) {
+				pads[i].flags = OMAP_DEVICE_PAD_REMUX |
+					OMAP_DEVICE_PAD_WAKEUP;
+			}
+			pads[i].idle = pads[i].enable;
+		}
+		if (bdata.pads_cnt == 0)
+			bdata.pads = NULL;
 		omap_serial_init_port(&bdata);
-
 	}
+	kfree(pads);
 }
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 08/11] TEMP: OMAP device: change pr_warnings to pr_debugs
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
                   ` (6 preceding siblings ...)
  2011-07-25 16:36 ` [PATCHv6 07/11] TEMP: serial: added mux support Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 09/11] TEMP: OMAP: serial: remove padconf hacks Tero Kristo
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap

Prevents a hang when omap_device would want to print something for
serial console device while enabling / disabling its clocks.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/plat-omap/omap_device.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index b6b4097..de2cd21 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -146,12 +146,12 @@ static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
 			odpl->activate_lat_worst = act_lat;
 			if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
 				odpl->activate_lat = act_lat;
-				pr_warning("omap_device: %s.%d: new worst case "
+				pr_debug("omap_device: %s.%d: new worst case "
 					   "activate latency %d: %llu\n",
 					   od->pdev.name, od->pdev.id,
 					   od->pm_lat_level, act_lat);
 			} else
-				pr_warning("omap_device: %s.%d: activate "
+				pr_debug("omap_device: %s.%d: activate "
 					   "latency %d higher than exptected. "
 					   "(%llu > %d)\n",
 					   od->pdev.name, od->pdev.id,
@@ -214,12 +214,12 @@ static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
 			odpl->deactivate_lat_worst = deact_lat;
 			if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
 				odpl->deactivate_lat = deact_lat;
-				pr_warning("omap_device: %s.%d: new worst case "
+				pr_debug("omap_device: %s.%d: new worst case "
 					   "deactivate latency %d: %llu\n",
 					   od->pdev.name, od->pdev.id,
 					   od->pm_lat_level, deact_lat);
 			} else
-				pr_warning("omap_device: %s.%d: deactivate "
+				pr_debug("omap_device: %s.%d: deactivate "
 					   "latency %d higher than exptected. "
 					   "(%llu > %d)\n",
 					   od->pdev.name, od->pdev.id,
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 09/11] TEMP: OMAP: serial: remove padconf hacks
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
                   ` (7 preceding siblings ...)
  2011-07-25 16:36 ` [PATCHv6 08/11] TEMP: OMAP device: change pr_warnings to pr_debugs Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 10/11] TEMP: OMAP3: pm: disable / enable PRCM chain interrupts during wakeup from suspend Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 11/11] OMAP3: pm: do not enable PRCM MPU interrupts manually Tero Kristo
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap

These are no longer needed as omap_hwmod takes care of multiplexing of pads.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/serial.c |   25 +------------------------
 1 files changed, 1 insertions(+), 24 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 47c4353..3c1a108 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -73,7 +73,6 @@ struct omap_uart_state {
 	void __iomem *wk_st;
 	void __iomem *wk_en;
 	u32 wk_mask;
-	u32 padconf;
 	u32 dma_enabled;
 
 	struct clk *ick;
@@ -309,13 +308,6 @@ static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
 		v |= uart->wk_mask;
 		__raw_writel(v, uart->wk_en);
 	}
-
-	/* Ensure IOPAD wake-enables are set */
-	if (cpu_is_omap34xx() && uart->padconf) {
-		u16 v = omap_ctrl_readw(uart->padconf);
-		v |= OMAP3_PADCONF_WAKEUPENABLE0;
-		omap_ctrl_writew(v, uart->padconf);
-	}
 }
 
 static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
@@ -326,13 +318,6 @@ static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
 		v &= ~uart->wk_mask;
 		__raw_writel(v, uart->wk_en);
 	}
-
-	/* Ensure IOPAD wake-enables are cleared */
-	if (cpu_is_omap34xx() && uart->padconf) {
-		u16 v = omap_ctrl_readw(uart->padconf);
-		v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
-		omap_ctrl_writew(v, uart->padconf);
-	}
 }
 
 static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
@@ -479,7 +464,6 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
 	if (cpu_is_omap34xx() && !cpu_is_ti816x()) {
 		u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
 		u32 wk_mask = 0;
-		u32 padconf = 0;
 
 		/* XXX These PRM accesses do not belong here */
 		uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
@@ -487,23 +471,18 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
 		switch (uart->num) {
 		case 0:
 			wk_mask = OMAP3430_ST_UART1_MASK;
-			padconf = 0x182;
 			break;
 		case 1:
 			wk_mask = OMAP3430_ST_UART2_MASK;
-			padconf = 0x17a;
 			break;
 		case 2:
 			wk_mask = OMAP3430_ST_UART3_MASK;
-			padconf = 0x19e;
 			break;
 		case 3:
 			wk_mask = OMAP3630_ST_UART4_MASK;
-			padconf = 0x0d2;
 			break;
 		}
 		uart->wk_mask = wk_mask;
-		uart->padconf = padconf;
 	} else if (cpu_is_omap24xx()) {
 		u32 wk_mask = 0;
 		u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
@@ -533,7 +512,6 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
 		uart->wk_en = NULL;
 		uart->wk_st = NULL;
 		uart->wk_mask = 0;
-		uart->padconf = 0;
 	}
 
 	uart->irqflags |= IRQF_SHARED;
@@ -834,8 +812,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 
 	console_unlock();
 
-	if ((cpu_is_omap34xx() && uart->padconf) ||
-	    (uart->wk_en && uart->wk_mask)) {
+	if (uart->oh->mux || (uart->wk_en && uart->wk_mask)) {
 		device_init_wakeup(&od->pdev.dev, true);
 		DEV_CREATE_FILE(&od->pdev.dev, &dev_attr_sleep_timeout);
 	}
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 10/11] TEMP: OMAP3: pm: disable / enable PRCM chain interrupts during wakeup from suspend
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
                   ` (8 preceding siblings ...)
  2011-07-25 16:36 ` [PATCHv6 09/11] TEMP: OMAP: serial: remove padconf hacks Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  2011-07-25 16:36 ` [PATCHv6 11/11] OMAP3: pm: do not enable PRCM MPU interrupts manually Tero Kristo
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap

This prevents system hang while attempting to access suspended console. Should
most likely be fixed with proper console locking.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/pm34xx.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index b9b5128..b071857 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -506,6 +506,8 @@ static int omap3_pm_begin(suspend_state_t state)
 	disable_hlt();
 	suspend_state = state;
 	omap_uart_enable_irqs(0);
+	disable_irq(prcm_io_irq);
+	disable_irq(prcm_wkup_irq);
 	return 0;
 }
 
@@ -514,6 +516,8 @@ static void omap3_pm_end(void)
 	suspend_state = PM_SUSPEND_ON;
 	omap_uart_enable_irqs(1);
 	enable_hlt();
+	enable_irq(prcm_io_irq);
+	enable_irq(prcm_wkup_irq);
 	return;
 }
 
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* [PATCHv6 11/11] OMAP3: pm: do not enable PRCM MPU interrupts manually
  2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
                   ` (9 preceding siblings ...)
  2011-07-25 16:36 ` [PATCHv6 10/11] TEMP: OMAP3: pm: disable / enable PRCM chain interrupts during wakeup from suspend Tero Kristo
@ 2011-07-25 16:36 ` Tero Kristo
  10 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-07-25 16:36 UTC (permalink / raw)
  To: linux-omap

This is handled automatically by the PRCM chain interrupt mechanism now.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/pm34xx.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index b071857..926e13c 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -630,10 +630,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,
-- 
1.7.4.1


Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* Re: [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-07-25 16:36 ` [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
@ 2011-07-25 17:03   ` Felipe Balbi
  2011-07-26 10:33     ` Tero Kristo
  2011-08-26  9:12   ` Paul Walmsley
  1 sibling, 1 reply; 21+ messages in thread
From: Felipe Balbi @ 2011-07-25 17:03 UTC (permalink / raw)
  To: Tero Kristo
  Cc: linux-omap, Thomas Petazzoni, Avinash.H.M, Kevin Hilman, Cousson,
	Benoit, Tony Lindgren, Govindraj.R, Felipe Balbi, Paul Walmsley,
	Thomas Gleixner

[-- Attachment #1: Type: text/plain, Size: 12896 bytes --]

Hi,

On Mon, Jul 25, 2011 at 07:36:01PM +0300, Tero Kristo wrote:
> 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

which drivers ? Are those somehow "children" of the "PRCM device" ??
If that's the case, you shouldn't need to match against names as you
could allocate a platform_device for your children and pass in your
resources with correct IRQ numbers.

> names, which are then matched to the particular PRCM interrupt bit
> depending on the specific OMAP SoC being used.
> 
> arch/arm/mach-omap2/prcm.c implements the chained interrupt mechanism
> itself, with SoC specific support / init structure defined in
> arch/arm/mach-omap2/prm2xxx_3xxx.c and arch/arm/mach-omap2/prm4xxx.c
> respectively. At initialization time, the set of PRCM events is filtered
> against the SoC on which we are running, keeping only the ones that are
> actually useful. All the logic is written to be generic with regard to
> OMAP3/OMAP4, even though OMAP3 has single PRCM event registers and OMAP4
> has two PRCM event registers.

Then if OMAP5 has 3, OMAP6 4 and OMAP7 5, OMAP3 will also have an array
of 5 PRCM events even though it only needs one, another argument for
dynamic allocation ?

> ---

[snip]

> @@ -246,64 +249,7 @@ static int _prcm_int_handle_wakeup(void)
>  		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
>  	}
>  
> -	return c;
> -}
> -
> -/*
> - * 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)
> -{
> -	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;
> -
> -	} while (irqstatus_mpu);
> -
> -	return IRQ_HANDLED;
> +	return c ? IRQ_HANDLED : IRQ_NONE;
>  }
>  
>  static void omap34xx_save_context(u32 *save)
> @@ -875,20 +821,35 @@ static int __init omap3_pm_init(void)
>  	/* XXX prcm_setup_regs needs to be before enabling hw
>  	 * supervised mode for powerdomains */
>  	prcm_setup_regs();
> +	ret = omap3_prcm_irq_init();
> +	if (ret) {
> +		pr_err("omap_prcm_irq_init() failed with %d\n", ret);
> +		goto err_prcm_irq_init;
> +	}
> +
> +	prcm_wkup_irq = omap_prcm_event_to_irq("wkup");
> +	prcm_io_irq = omap_prcm_event_to_irq("io");
> +
> +	ret = request_irq(prcm_wkup_irq, _prcm_int_handle_wakeup,
> +			IRQF_NO_SUSPEND, "prcm_wkup", NULL);
>  
> -	ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
> -			  (irq_handler_t)prcm_interrupt_handler,
> -			  IRQF_DISABLED, "prcm", NULL);
>  	if (ret) {
> -		printk(KERN_ERR "request_irq failed to register for 0x%x\n",
> -		       INT_34XX_PRCM_MPU_IRQ);
> -		goto err1;
> +		printk(KERN_ERR "Failed to request prcm_wkup irq\n");
> +		goto err_prcm_wkup;
> +	}
> +
> +	ret = request_irq(prcm_io_irq, _prcm_int_handle_wakeup,
> +			IRQF_NO_SUSPEND, "prcm_io", NULL);
> +
> +	if (ret) {
> +		printk(KERN_ERR "Failed to request prcm_io irq\n");
> +		goto err_prcm_io;
>  	}
>  
>  	ret = pwrdm_for_each(pwrdms_setup, NULL);
>  	if (ret) {
>  		printk(KERN_ERR "Failed to setup powerdomains\n");
> -		goto err2;
> +		goto err_pwrdms_setup;
>  	}
>  
>  	(void) clkdm_for_each(clkdms_setup, NULL);
> @@ -896,7 +857,7 @@ static int __init omap3_pm_init(void)
>  	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
>  	if (mpu_pwrdm == NULL) {
>  		printk(KERN_ERR "Failed to get mpu_pwrdm\n");
> -		goto err2;
> +		goto err_pwrdms_setup;
>  	}
>  
>  	neon_pwrdm = pwrdm_lookup("neon_pwrdm");
> @@ -944,14 +905,19 @@ static int __init omap3_pm_init(void)
>  	}
>  
>  	omap3_save_scratchpad_contents();
> -err1:
> +
>  	return ret;
> -err2:
> -	free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
> +
> + err_pwrdms_setup:
>  	list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
>  		list_del(&pwrst->node);
>  		kfree(pwrst);
>  	}
> + err_prcm_io:
> +	free_irq(prcm_wkup_irq, NULL);
> + err_prcm_wkup:
> +	omap_prcm_irq_cleanup();
> + err_prcm_irq_init:
>  	return ret;
>  }
>  
> diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
> index 2e40a5c..83cf8ae 100644
> --- a/arch/arm/mach-omap2/prcm.c
> +++ b/arch/arm/mach-omap2/prcm.c
> @@ -45,6 +47,209 @@ void __iomem *cm2_base;
>  
>  #define MAX_MODULE_ENABLE_WAIT		100000
>  
> +/* Maximum number of PRCM interrupt status registers */
> +#define OMAP_PRCM_MAX_NR_PENDING_REG	2
> +
> +/* 64 interrupts needed on OMAP4, 32 on OMAP3 */
> +#define OMAP_PRCM_NR_IRQS		64
> +
> +/* Setup for the interrupt handling based on used platform */
> +static struct omap_prcm_irq_setup *irq_setup;
> +
> +static struct irq_chip_generic *prcm_irq_chips[OMAP_PRCM_MAX_NR_PENDING_REG];

I still think this would be better dynamically allocated. If this
happens to increase in OMAP6/7/8... noone will convert to dynamic
allocation, rather will only increase the macro above.

> +/*
> + * 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 void prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> +	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> +	/*
> +	 * Loop until all pending irqs are handled, since
> +	 * generic_handle_irq() can cause new irqs to come
> +	 */
> +	while (1) {
> +		unsigned int virtirq;
> +
> +		chip->irq_ack(&desc->irq_data);
> +
> +		memset(pending, 0, sizeof(pending));
> +		irq_setup->pending_events(pending);
> +
> +		/* No bit set, then all IRQs are handled */
> +		if (find_first_bit(pending, OMAP_PRCM_NR_IRQS)
> +		    >= OMAP_PRCM_NR_IRQS) {
> +			chip->irq_unmask(&desc->irq_data);
> +			break;
> +		}
> +
> +		/*
> +		 * Loop on all currently pending irqs so that new irqs
> +		 * cannot starve previously pending irqs
> +		 */
> +		for_each_set_bit(virtirq, pending, OMAP_PRCM_NR_IRQS)
> +			generic_handle_irq(irq_setup->base_irq + virtirq);
> +
> +		chip->irq_unmask(&desc->irq_data);

can't the IRQ subsystem handle this for you ? I was expecting it would
call irq_ack() and irq_unmask() automatically and you wouldn't have to
do it yourself. Maybe Thomas can clear this out ? Thomas, should we call
->irq_ack() ->irq_mask ourselves here ?

> +/*
> + * Given a PRCM event name, returns the corresponding IRQ on which the
> + * handler should be registered.
> + */
> +int omap_prcm_event_to_irq(const char *name)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(omap_prcm_irqs); i++)
> +		if (!strcmp(omap_prcm_irqs[i].name, name))
> +			return irq_setup->base_irq + omap_prcm_irqs[i].offset;
> +
> +	return -ENOENT;
> +}
> +
> +/*
> + * Reverses memory allocated and other setups done by
> + * omap_prcm_irq_init().
> + */
> +void omap_prcm_irq_cleanup(void)
> +{
> +	int i;
> +
> +	for (i = 0; i < OMAP_PRCM_MAX_NR_PENDING_REG; i++) {
> +		if (prcm_irq_chips[i])
> +			irq_remove_generic_chip(prcm_irq_chips[i], 0xffffffff,
> +						0, 0);
> +		prcm_irq_chips[i] = NULL;
> +	}
> +
> +	irq_set_chained_handler(irq_setup->irq, NULL);
> +
> +	if (irq_setup->base_irq > 0)
> +		irq_free_descs(irq_setup->base_irq, OMAP_PRCM_NR_IRQS);
> +	irq_setup->base_irq = 0;
> +}
> +
> +/*
> + * Prepare the array of PRCM events corresponding to the current SoC,
> + * and set-up the chained interrupt handler mechanism.
> + */
> +static int __init omap_prcm_irq_init(void)
> +{
> +	int i;
> +	struct irq_chip_generic *gc;
> +	struct irq_chip_type *ct;
> +	u32 mask[2] = { 0, 0 };
> +	int offset;
> +	int max_irq = 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(omap_prcm_irqs); i++)
> +		if (omap_chip_is(omap_prcm_irqs[i].omap_chip)) {
> +			offset = omap_prcm_irqs[i].offset;
> +			if (offset < 32)
> +				mask[0] |= 1 << offset;
> +			else
> +				mask[1] |= 1 << (offset - 32);
> +			if (offset > max_irq)
> +				max_irq = offset;
> +		}
> +
> +	irq_set_chained_handler(irq_setup->irq, prcm_irq_handler);
> +
> +	irq_setup->base_irq = irq_alloc_descs(-1, 0, OMAP_PRCM_NR_IRQS, 0);
> +
> +	if (irq_setup->base_irq < 0) {
> +		pr_err("PRCM: failed to allocate irq descs\n");
> +		goto err;
> +	}
> +
> +	for (i = 0; i <= max_irq / 32; i++) {
> +		gc = irq_alloc_generic_chip("PRCM", 1,
> +			irq_setup->base_irq + i * 32, NULL, 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;
> +		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 << 2);
> +		ct->regs.mask = irq_setup->mask + (i << 2);
> +
> +		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;
> +}
> +
> +int __init omap3_prcm_irq_init(void)
> +{
> +	irq_setup = &omap3_prcm_irq_setup;

if you make this a platform_driver, there would be no need for this
trickery. You could pass this as driver data. Something like:


struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
	.ack		= (u32)OMAP3430_PRM_IRQSTATUS_MPU,
	.mask		= (u32)OMAP3430_PRM_IRQENABLE_MPU,
	.pending_events	= omap3_prm_pending_events,
	.irq		= INT_34XX_PRCM_MPU_IRQ,
};

struct const struct platform_device_id prcm_id_table[] __devinitconst =
{
	{
		.name		= "omap3-prcm",
		.driver_data	= &omap3_prcm_irq_setup,
	},
	{
		.name		= "omap4-prcm",
		.driver_data	= &omap4_prcm_irq_setup,
	},
};
MODULE_DEVICE_TABLE(platform, prcm_id_table);

static struct platform_driver prcm_driver = {
	.probe		= prcm_probe,
	.remove		= __devexit_p(prcm_remove),
	.driver		= {
		.name	= "prcm",
		.pm	= DEV_PM_OPS,
	},
	.id_table	= &prcm_id_table,
};

or something similar. Then on probe you can make a copy of irq_setup to
your driver's context structure, or only use temporarily to initialize
some fields and so on...

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* Re: [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-07-25 17:03   ` Felipe Balbi
@ 2011-07-26 10:33     ` Tero Kristo
  2011-07-26 10:40       ` Felipe Balbi
  0 siblings, 1 reply; 21+ messages in thread
From: Tero Kristo @ 2011-07-26 10:33 UTC (permalink / raw)
  To: Balbi, Felipe
  Cc: linux-omap, Thomas Petazzoni, Mahadeva, Avinash, Hilman, Kevin,
	Cousson, Benoit, Tony Lindgren, R, Govindraj, Paul Walmsley,
	Thomas Gleixner

On Mon, 2011-07-25 at 19:03 +0200, Balbi, Felipe wrote:
> Hi,
> 
> On Mon, Jul 25, 2011 at 07:36:01PM +0300, Tero Kristo wrote:
> > 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
> 
> which drivers ? Are those somehow "children" of the "PRCM device" ??
> If that's the case, you shouldn't need to match against names as you
> could allocate a platform_device for your children and pass in your
> resources with correct IRQ numbers.

I am not quite sure what you mean by children in this case. There are a
couple of devices that might be interested in using these, e.g. SR and
ABB come to my mind. They are closely related to PRCM yes.

> 
> > names, which are then matched to the particular PRCM interrupt bit
> > depending on the specific OMAP SoC being used.
> > 
> > arch/arm/mach-omap2/prcm.c implements the chained interrupt mechanism
> > itself, with SoC specific support / init structure defined in
> > arch/arm/mach-omap2/prm2xxx_3xxx.c and arch/arm/mach-omap2/prm4xxx.c
> > respectively. At initialization time, the set of PRCM events is filtered
> > against the SoC on which we are running, keeping only the ones that are
> > actually useful. All the logic is written to be generic with regard to
> > OMAP3/OMAP4, even though OMAP3 has single PRCM event registers and OMAP4
> > has two PRCM event registers.
> 
> Then if OMAP5 has 3, OMAP6 4 and OMAP7 5, OMAP3 will also have an array
> of 5 PRCM events even though it only needs one, another argument for
> dynamic allocation ?
> 
> > ---
> 
> [snip]
> 
> > @@ -246,64 +249,7 @@ static int _prcm_int_handle_wakeup(void)
> >  		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
> >  	}
> >  
> > -	return c;
> > -}
> > -
> > -/*
> > - * 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)
> > -{
> > -	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;
> > -
> > -	} while (irqstatus_mpu);
> > -
> > -	return IRQ_HANDLED;
> > +	return c ? IRQ_HANDLED : IRQ_NONE;
> >  }
> >  
> >  static void omap34xx_save_context(u32 *save)
> > @@ -875,20 +821,35 @@ static int __init omap3_pm_init(void)
> >  	/* XXX prcm_setup_regs needs to be before enabling hw
> >  	 * supervised mode for powerdomains */
> >  	prcm_setup_regs();
> > +	ret = omap3_prcm_irq_init();
> > +	if (ret) {
> > +		pr_err("omap_prcm_irq_init() failed with %d\n", ret);
> > +		goto err_prcm_irq_init;
> > +	}
> > +
> > +	prcm_wkup_irq = omap_prcm_event_to_irq("wkup");
> > +	prcm_io_irq = omap_prcm_event_to_irq("io");
> > +
> > +	ret = request_irq(prcm_wkup_irq, _prcm_int_handle_wakeup,
> > +			IRQF_NO_SUSPEND, "prcm_wkup", NULL);
> >  
> > -	ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
> > -			  (irq_handler_t)prcm_interrupt_handler,
> > -			  IRQF_DISABLED, "prcm", NULL);
> >  	if (ret) {
> > -		printk(KERN_ERR "request_irq failed to register for 0x%x\n",
> > -		       INT_34XX_PRCM_MPU_IRQ);
> > -		goto err1;
> > +		printk(KERN_ERR "Failed to request prcm_wkup irq\n");
> > +		goto err_prcm_wkup;
> > +	}
> > +
> > +	ret = request_irq(prcm_io_irq, _prcm_int_handle_wakeup,
> > +			IRQF_NO_SUSPEND, "prcm_io", NULL);
> > +
> > +	if (ret) {
> > +		printk(KERN_ERR "Failed to request prcm_io irq\n");
> > +		goto err_prcm_io;
> >  	}
> >  
> >  	ret = pwrdm_for_each(pwrdms_setup, NULL);
> >  	if (ret) {
> >  		printk(KERN_ERR "Failed to setup powerdomains\n");
> > -		goto err2;
> > +		goto err_pwrdms_setup;
> >  	}
> >  
> >  	(void) clkdm_for_each(clkdms_setup, NULL);
> > @@ -896,7 +857,7 @@ static int __init omap3_pm_init(void)
> >  	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
> >  	if (mpu_pwrdm == NULL) {
> >  		printk(KERN_ERR "Failed to get mpu_pwrdm\n");
> > -		goto err2;
> > +		goto err_pwrdms_setup;
> >  	}
> >  
> >  	neon_pwrdm = pwrdm_lookup("neon_pwrdm");
> > @@ -944,14 +905,19 @@ static int __init omap3_pm_init(void)
> >  	}
> >  
> >  	omap3_save_scratchpad_contents();
> > -err1:
> > +
> >  	return ret;
> > -err2:
> > -	free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
> > +
> > + err_pwrdms_setup:
> >  	list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
> >  		list_del(&pwrst->node);
> >  		kfree(pwrst);
> >  	}
> > + err_prcm_io:
> > +	free_irq(prcm_wkup_irq, NULL);
> > + err_prcm_wkup:
> > +	omap_prcm_irq_cleanup();
> > + err_prcm_irq_init:
> >  	return ret;
> >  }
> >  
> > diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
> > index 2e40a5c..83cf8ae 100644
> > --- a/arch/arm/mach-omap2/prcm.c
> > +++ b/arch/arm/mach-omap2/prcm.c
> > @@ -45,6 +47,209 @@ void __iomem *cm2_base;
> >  
> >  #define MAX_MODULE_ENABLE_WAIT		100000
> >  
> > +/* Maximum number of PRCM interrupt status registers */
> > +#define OMAP_PRCM_MAX_NR_PENDING_REG	2
> > +
> > +/* 64 interrupts needed on OMAP4, 32 on OMAP3 */
> > +#define OMAP_PRCM_NR_IRQS		64
> > +
> > +/* Setup for the interrupt handling based on used platform */
> > +static struct omap_prcm_irq_setup *irq_setup;
> > +
> > +static struct irq_chip_generic *prcm_irq_chips[OMAP_PRCM_MAX_NR_PENDING_REG];
> 
> I still think this would be better dynamically allocated. If this
> happens to increase in OMAP6/7/8... noone will convert to dynamic
> allocation, rather will only increase the macro above.

It might increase to 3 at some point, there is lots of space in the
second register at the moment. :) And I still stand behind my reasoning
that allocating this dynamically would eat more memory.

> 
> > +/*
> > + * 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 void prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
> > +{
> > +	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
> > +	struct irq_chip *chip = irq_desc_get_chip(desc);
> > +
> > +	/*
> > +	 * Loop until all pending irqs are handled, since
> > +	 * generic_handle_irq() can cause new irqs to come
> > +	 */
> > +	while (1) {
> > +		unsigned int virtirq;
> > +
> > +		chip->irq_ack(&desc->irq_data);
> > +
> > +		memset(pending, 0, sizeof(pending));
> > +		irq_setup->pending_events(pending);
> > +
> > +		/* No bit set, then all IRQs are handled */
> > +		if (find_first_bit(pending, OMAP_PRCM_NR_IRQS)
> > +		    >= OMAP_PRCM_NR_IRQS) {
> > +			chip->irq_unmask(&desc->irq_data);
> > +			break;
> > +		}
> > +
> > +		/*
> > +		 * Loop on all currently pending irqs so that new irqs
> > +		 * cannot starve previously pending irqs
> > +		 */
> > +		for_each_set_bit(virtirq, pending, OMAP_PRCM_NR_IRQS)
> > +			generic_handle_irq(irq_setup->base_irq + virtirq);
> > +
> > +		chip->irq_unmask(&desc->irq_data);
> 
> can't the IRQ subsystem handle this for you ? I was expecting it would
> call irq_ack() and irq_unmask() automatically and you wouldn't have to
> do it yourself. Maybe Thomas can clear this out ? Thomas, should we call
> ->irq_ack() ->irq_mask ourselves here ?

These are needed, as we are using a handle and a level interrupt. If you
leave out the ack, we will return to the handler immediately as nobody
else acks it. If you leave out the unmask, we will only ever get 1
interrupt and no more.

> 
> > +/*
> > + * Given a PRCM event name, returns the corresponding IRQ on which the
> > + * handler should be registered.
> > + */
> > +int omap_prcm_event_to_irq(const char *name)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(omap_prcm_irqs); i++)
> > +		if (!strcmp(omap_prcm_irqs[i].name, name))
> > +			return irq_setup->base_irq + omap_prcm_irqs[i].offset;
> > +
> > +	return -ENOENT;
> > +}
> > +
> > +/*
> > + * Reverses memory allocated and other setups done by
> > + * omap_prcm_irq_init().
> > + */
> > +void omap_prcm_irq_cleanup(void)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < OMAP_PRCM_MAX_NR_PENDING_REG; i++) {
> > +		if (prcm_irq_chips[i])
> > +			irq_remove_generic_chip(prcm_irq_chips[i], 0xffffffff,
> > +						0, 0);
> > +		prcm_irq_chips[i] = NULL;
> > +	}
> > +
> > +	irq_set_chained_handler(irq_setup->irq, NULL);
> > +
> > +	if (irq_setup->base_irq > 0)
> > +		irq_free_descs(irq_setup->base_irq, OMAP_PRCM_NR_IRQS);
> > +	irq_setup->base_irq = 0;
> > +}
> > +
> > +/*
> > + * Prepare the array of PRCM events corresponding to the current SoC,
> > + * and set-up the chained interrupt handler mechanism.
> > + */
> > +static int __init omap_prcm_irq_init(void)
> > +{
> > +	int i;
> > +	struct irq_chip_generic *gc;
> > +	struct irq_chip_type *ct;
> > +	u32 mask[2] = { 0, 0 };
> > +	int offset;
> > +	int max_irq = 0;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(omap_prcm_irqs); i++)
> > +		if (omap_chip_is(omap_prcm_irqs[i].omap_chip)) {
> > +			offset = omap_prcm_irqs[i].offset;
> > +			if (offset < 32)
> > +				mask[0] |= 1 << offset;
> > +			else
> > +				mask[1] |= 1 << (offset - 32);
> > +			if (offset > max_irq)
> > +				max_irq = offset;
> > +		}
> > +
> > +	irq_set_chained_handler(irq_setup->irq, prcm_irq_handler);
> > +
> > +	irq_setup->base_irq = irq_alloc_descs(-1, 0, OMAP_PRCM_NR_IRQS, 0);
> > +
> > +	if (irq_setup->base_irq < 0) {
> > +		pr_err("PRCM: failed to allocate irq descs\n");
> > +		goto err;
> > +	}
> > +
> > +	for (i = 0; i <= max_irq / 32; i++) {
> > +		gc = irq_alloc_generic_chip("PRCM", 1,
> > +			irq_setup->base_irq + i * 32, NULL, 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;
> > +		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 << 2);
> > +		ct->regs.mask = irq_setup->mask + (i << 2);
> > +
> > +		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;
> > +}
> > +
> > +int __init omap3_prcm_irq_init(void)
> > +{
> > +	irq_setup = &omap3_prcm_irq_setup;
> 
> if you make this a platform_driver, there would be no need for this
> trickery. You could pass this as driver data. Something like:
> 
> 
> struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
> 	.ack		= (u32)OMAP3430_PRM_IRQSTATUS_MPU,
> 	.mask		= (u32)OMAP3430_PRM_IRQENABLE_MPU,
> 	.pending_events	= omap3_prm_pending_events,
> 	.irq		= INT_34XX_PRCM_MPU_IRQ,
> };
> 
> struct const struct platform_device_id prcm_id_table[] __devinitconst =
> {
> 	{
> 		.name		= "omap3-prcm",
> 		.driver_data	= &omap3_prcm_irq_setup,
> 	},
> 	{
> 		.name		= "omap4-prcm",
> 		.driver_data	= &omap4_prcm_irq_setup,
> 	},
> };
> MODULE_DEVICE_TABLE(platform, prcm_id_table);
> 
> static struct platform_driver prcm_driver = {
> 	.probe		= prcm_probe,
> 	.remove		= __devexit_p(prcm_remove),
> 	.driver		= {
> 		.name	= "prcm",
> 		.pm	= DEV_PM_OPS,
> 	},
> 	.id_table	= &prcm_id_table,
> };
> 
> or something similar. Then on probe you can make a copy of irq_setup to
> your driver's context structure, or only use temporarily to initialize
> some fields and so on...
> 

Hmm, this might be useful, however you would still need a way to
register the driver from somewhere, and you would essentially end up
with omap_chip version check somewhere. The reason for all this trickery
is that the omap chip version detection is heavily frowned upon right
now... it would be much cleaner if there was an accepted way of doing
this already in place.

-Tero



Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* Re: [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-07-26 10:33     ` Tero Kristo
@ 2011-07-26 10:40       ` Felipe Balbi
  0 siblings, 0 replies; 21+ messages in thread
From: Felipe Balbi @ 2011-07-26 10:40 UTC (permalink / raw)
  To: Tero Kristo
  Cc: Balbi, Felipe, linux-omap, Thomas Petazzoni, Mahadeva, Avinash,
	Hilman, Kevin, Cousson, Benoit, Tony Lindgren, R, Govindraj,
	Paul Walmsley, Thomas Gleixner

[-- Attachment #1: Type: text/plain, Size: 3396 bytes --]

Hi,

On Tue, Jul 26, 2011 at 01:33:35PM +0300, Tero Kristo wrote:
> > > +	while (1) {
> > > +		unsigned int virtirq;
> > > +
> > > +		chip->irq_ack(&desc->irq_data);
> > > +
> > > +		memset(pending, 0, sizeof(pending));
> > > +		irq_setup->pending_events(pending);
> > > +
> > > +		/* No bit set, then all IRQs are handled */
> > > +		if (find_first_bit(pending, OMAP_PRCM_NR_IRQS)
> > > +		    >= OMAP_PRCM_NR_IRQS) {
> > > +			chip->irq_unmask(&desc->irq_data);
> > > +			break;
> > > +		}
> > > +
> > > +		/*
> > > +		 * Loop on all currently pending irqs so that new irqs
> > > +		 * cannot starve previously pending irqs
> > > +		 */
> > > +		for_each_set_bit(virtirq, pending, OMAP_PRCM_NR_IRQS)
> > > +			generic_handle_irq(irq_setup->base_irq + virtirq);
> > > +
> > > +		chip->irq_unmask(&desc->irq_data);
> > 
> > can't the IRQ subsystem handle this for you ? I was expecting it would
> > call irq_ack() and irq_unmask() automatically and you wouldn't have to
> > do it yourself. Maybe Thomas can clear this out ? Thomas, should we call
> > ->irq_ack() ->irq_mask ourselves here ?
> 
> These are needed, as we are using a handle and a level interrupt. If you
> leave out the ack, we will return to the handler immediately as nobody
> else acks it. If you leave out the unmask, we will only ever get 1
> interrupt and no more.

but that's the thing, I guess IRQ subsystem can handle this
automatically. At least from what I remember. That's how I converted the
retu driver, for instance, and I checked that IRQ subsystem calls
->irq_ack() and ->irq_mask/unmask() for me...

Maybe the irq_gc stuff is different, dunno.

> > if you make this a platform_driver, there would be no need for this
> > trickery. You could pass this as driver data. Something like:
> > 
> > 
> > struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
> > 	.ack		= (u32)OMAP3430_PRM_IRQSTATUS_MPU,
> > 	.mask		= (u32)OMAP3430_PRM_IRQENABLE_MPU,
> > 	.pending_events	= omap3_prm_pending_events,
> > 	.irq		= INT_34XX_PRCM_MPU_IRQ,
> > };
> > 
> > struct const struct platform_device_id prcm_id_table[] __devinitconst =
> > {
> > 	{
> > 		.name		= "omap3-prcm",
> > 		.driver_data	= &omap3_prcm_irq_setup,
> > 	},
> > 	{
> > 		.name		= "omap4-prcm",
> > 		.driver_data	= &omap4_prcm_irq_setup,
> > 	},
> > };
> > MODULE_DEVICE_TABLE(platform, prcm_id_table);
> > 
> > static struct platform_driver prcm_driver = {
> > 	.probe		= prcm_probe,
> > 	.remove		= __devexit_p(prcm_remove),
> > 	.driver		= {
> > 		.name	= "prcm",
> > 		.pm	= DEV_PM_OPS,
> > 	},
> > 	.id_table	= &prcm_id_table,
> > };
> > 
> > or something similar. Then on probe you can make a copy of irq_setup to
> > your driver's context structure, or only use temporarily to initialize
> > some fields and so on...
> > 
> 
> Hmm, this might be useful, however you would still need a way to
> register the driver from somewhere, and you would essentially end up
> with omap_chip version check somewhere. The reason for all this trickery
> is that the omap chip version detection is heavily frowned upon right
> now... it would be much cleaner if there was an accepted way of doing
> this already in place.

wouldn't hwmod be able to handle this for you ? I mean, it's just the
driver name that has to change, rather than exporting a few functions.

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* Re: [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-07-25 16:36 ` [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
  2011-07-25 17:03   ` Felipe Balbi
@ 2011-08-26  9:12   ` Paul Walmsley
  2011-09-01 14:00     ` Tero Kristo
  1 sibling, 1 reply; 21+ messages in thread
From: Paul Walmsley @ 2011-08-26  9:12 UTC (permalink / raw)
  To: Tero Kristo
  Cc: linux-omap, Thomas Petazzoni, Avinash.H.M, Kevin Hilman, Cousson,
	Benoit, Tony Lindgren, Govindraj.R, Felipe Balbi

Hello Tero,

a few comments on this patch:

On Mon, 25 Jul 2011, Tero Kristo wrote:

> 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.
> 
> arch/arm/mach-omap2/prcm.c implements the chained interrupt mechanism
> itself, with SoC specific support / init structure defined in
> arch/arm/mach-omap2/prm2xxx_3xxx.c and arch/arm/mach-omap2/prm4xxx.c
> respectively. At initialization time, the set of PRCM events is filtered
> against the SoC on which we are running, keeping only the ones that are
> actually useful. All the logic is written to be generic with regard to
> OMAP3/OMAP4, even though OMAP3 has single PRCM event registers and OMAP4
> has two PRCM event registers.

Looking over this patch, it seems that this functionality should be
part of a PRM device driver.  That would allow the separation of the
SoC-specific data from the code, so there wouldn't be a need to embed
the OMAP_PRCM_IRQ data in the driver code.  Rather, that data could go
into the dev_attr data for the PRM hwmod.  That avoids putting
SoC-specific data in driver code, allows the removal of
omap[34]_prcm_irq_setup(), and should also remove the dependency on
omap_chip.

Similarly, OMAP_PRCM_MAX_NR_PENDING_REG and OMAP_PRCM_NR_IRQS should
be defined somewhere SoC-specific.  I'd suggest defining those in the
hwmod dev_attr data.  That way that file won't need to be patched if
those constants need change in the future.  Unfortunately, doing this
in a clean way will probably mean that the variables that are
allocated via these constants will need to be allocated and freed
dynamically.

What I'd suggest is to create a short series that:

1. adds PRM hwmod data for OMAP2430+ platforms

2. adds a basic PRM device driver skeleton in a directory such as
   drivers/power -- (I'm not convinced that this is the right place,
   in the end; but seems like a good place to start)

3. creates the chained interrupt handler in the PRM device driver,
   and removes the old PRCM interrupt handler from pm34xx.c 

...

A few other relatively minor comments:

- Probably omap_prcm_irq_cleanup() shouldn't be called from pm34xx.c,
  since other code outside of pm34xx.c might wish to use the PRCM
  interrupt, even in the (admittedly unlikely) circumstance that some
  of the code in pm34xx.c fails?

- It would be good to document struct omap_prcm_irq via KernelDoc,
  rather than inline comments
  (Documentation/kernel-doc-nano-HOWTO.txt).  It would be ideal if the
  patch's function documentation followed the same standard.


- Paul

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

* Re: [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-08-26  9:12   ` Paul Walmsley
@ 2011-09-01 14:00     ` Tero Kristo
  2011-09-02  9:20       ` Paul Walmsley
  0 siblings, 1 reply; 21+ messages in thread
From: Tero Kristo @ 2011-09-01 14:00 UTC (permalink / raw)
  To: Paul Walmsley
  Cc: linux-omap, Thomas Petazzoni, Mahadeva, Avinash, Hilman, Kevin,
	Cousson, Benoit, Tony Lindgren, R, Govindraj, Balbi, Felipe

Hey Paul,

I've been looking at this now and got one question below. Otherwise your
comments look okay to me and I can work with those.

On Fri, 2011-08-26 at 11:12 +0200, Paul Walmsley wrote:
> Hello Tero,
> 
> a few comments on this patch:
> 
> On Mon, 25 Jul 2011, Tero Kristo wrote:
> 
> > 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.
> > 
> > arch/arm/mach-omap2/prcm.c implements the chained interrupt mechanism
> > itself, with SoC specific support / init structure defined in
> > arch/arm/mach-omap2/prm2xxx_3xxx.c and arch/arm/mach-omap2/prm4xxx.c
> > respectively. At initialization time, the set of PRCM events is filtered
> > against the SoC on which we are running, keeping only the ones that are
> > actually useful. All the logic is written to be generic with regard to
> > OMAP3/OMAP4, even though OMAP3 has single PRCM event registers and OMAP4
> > has two PRCM event registers.
> 
> Looking over this patch, it seems that this functionality should be
> part of a PRM device driver.  That would allow the separation of the
> SoC-specific data from the code, so there wouldn't be a need to embed
> the OMAP_PRCM_IRQ data in the driver code.  Rather, that data could go
> into the dev_attr data for the PRM hwmod.  That avoids putting
> SoC-specific data in driver code, allows the removal of
> omap[34]_prcm_irq_setup(), and should also remove the dependency on
> omap_chip.
> 
> Similarly, OMAP_PRCM_MAX_NR_PENDING_REG and OMAP_PRCM_NR_IRQS should
> be defined somewhere SoC-specific.  I'd suggest defining those in the
> hwmod dev_attr data.  That way that file won't need to be patched if
> those constants need change in the future.  Unfortunately, doing this
> in a clean way will probably mean that the variables that are
> allocated via these constants will need to be allocated and freed
> dynamically.
> 
> What I'd suggest is to create a short series that:
> 
> 1. adds PRM hwmod data for OMAP2430+ platforms

How should this be done? It believe all the data in the hwmods should be
autogenerated somehow... should I just make a temporary hack patch for
one platform that could be then autogenerated by someone for all omap
platforms?


> 
> 2. adds a basic PRM device driver skeleton in a directory such as
>    drivers/power -- (I'm not convinced that this is the right place,
>    in the end; but seems like a good place to start)
> 
> 3. creates the chained interrupt handler in the PRM device driver,
>    and removes the old PRCM interrupt handler from pm34xx.c 
> 
> ...
> 
> A few other relatively minor comments:
> 
> - Probably omap_prcm_irq_cleanup() shouldn't be called from pm34xx.c,
>   since other code outside of pm34xx.c might wish to use the PRCM
>   interrupt, even in the (admittedly unlikely) circumstance that some
>   of the code in pm34xx.c fails?
> 
> - It would be good to document struct omap_prcm_irq via KernelDoc,
>   rather than inline comments
>   (Documentation/kernel-doc-nano-HOWTO.txt).  It would be ideal if the
>   patch's function documentation followed the same standard.
> 
> 
> - Paul



Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* Re: [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-09-01 14:00     ` Tero Kristo
@ 2011-09-02  9:20       ` Paul Walmsley
  2011-09-02 12:15         ` Tero Kristo
  0 siblings, 1 reply; 21+ messages in thread
From: Paul Walmsley @ 2011-09-02  9:20 UTC (permalink / raw)
  To: Tero Kristo
  Cc: linux-omap, Thomas Petazzoni, Mahadeva, Avinash, Hilman, Kevin,
	Cousson, Benoit, Tony Lindgren, R, Govindraj, Balbi, Felipe

Hi Tero,

On Thu, 1 Sep 2011, Tero Kristo wrote:

> I've been looking at this now and got one question below. Otherwise your
> comments look okay to me and I can work with those.

Great.  As you work on it, please let me know if there's something that 
doesn't make sense with this arrangement.  I think this will work, and 
will move some code out of arch/arm/*omap*, but it's hard to tell, until 
someone tries it.

> On Fri, 2011-08-26 at 11:12 +0200, Paul Walmsley wrote:
> 
> > What I'd suggest is to create a short series that:
> > 
> > 1. adds PRM hwmod data for OMAP2430+ platforms
> 
> How should this be done? It believe all the data in the hwmods should be
> autogenerated somehow... should I just make a temporary hack patch for
> one platform that could be then autogenerated by someone for all omap
> platforms?

Only OMAP4 is autogenerated, currently.  OMAP2 & 3 are still done by hand. 
I'd suggest starting with either OMAP4 (because the hwmod data should be 
autogeneratable) or OMAP3 (because we know that one pretty well and the 
hwmod data should not be too difficult to build).

If it would help, I'd be happy to do a first draft of the OMAP3430 PRM 
hwmod data.


regards,

- Paul

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

* Re: [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-09-02  9:20       ` Paul Walmsley
@ 2011-09-02 12:15         ` Tero Kristo
  2011-09-14 12:10           ` Paul Walmsley
  0 siblings, 1 reply; 21+ messages in thread
From: Tero Kristo @ 2011-09-02 12:15 UTC (permalink / raw)
  To: Paul Walmsley
  Cc: linux-omap, Thomas Petazzoni, Mahadeva, Avinash, Hilman, Kevin,
	Cousson, Benoit, Tony Lindgren, R, Govindraj, Balbi, Felipe

Hi Paul,

On Fri, 2011-09-02 at 11:20 +0200, Paul Walmsley wrote:
> Hi Tero,
> 
> On Thu, 1 Sep 2011, Tero Kristo wrote:
> 
> > I've been looking at this now and got one question below. Otherwise your
> > comments look okay to me and I can work with those.
> 
> Great.  As you work on it, please let me know if there's something that 
> doesn't make sense with this arrangement.  I think this will work, and 
> will move some code out of arch/arm/*omap*, but it's hard to tell, until 
> someone tries it.
> 
> > On Fri, 2011-08-26 at 11:12 +0200, Paul Walmsley wrote:
> > 
> > > What I'd suggest is to create a short series that:
> > > 
> > > 1. adds PRM hwmod data for OMAP2430+ platforms
> > 
> > How should this be done? It believe all the data in the hwmods should be
> > autogenerated somehow... should I just make a temporary hack patch for
> > one platform that could be then autogenerated by someone for all omap
> > platforms?
> 
> Only OMAP4 is autogenerated, currently.  OMAP2 & 3 are still done by hand. 
> I'd suggest starting with either OMAP4 (because the hwmod data should be 
> autogeneratable) or OMAP3 (because we know that one pretty well and the 
> hwmod data should not be too difficult to build).
> 
> If it would help, I'd be happy to do a first draft of the OMAP3430 PRM 
> hwmod data.

If you can do this it would help, as you have much better understanding
of the hwmod data than I do. It will probably drop a couple of review
rounds away as the hwmod data would be close to what it should be from
beginning.

If you are busy with other things, I can see what I can craft myself.

> 
> 
> regards,
> 
> - Paul



Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

* Re: [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-09-02 12:15         ` Tero Kristo
@ 2011-09-14 12:10           ` Paul Walmsley
  2011-09-14 12:33             ` Tero Kristo
  0 siblings, 1 reply; 21+ messages in thread
From: Paul Walmsley @ 2011-09-14 12:10 UTC (permalink / raw)
  To: Tero Kristo
  Cc: linux-omap, Thomas Petazzoni, Mahadeva, Avinash, Hilman, Kevin,
	Cousson, Benoit, Tony Lindgren, R, Govindraj, Balbi, Felipe

Hello Tero,

On Fri, 2 Sep 2011, Tero Kristo wrote:

> On Fri, 2011-09-02 at 11:20 +0200, Paul Walmsley wrote:
>
> > If it would help, I'd be happy to do a first draft of the OMAP3430 PRM 
> > hwmod data.
> 
> If you can do this it would help, as you have much better understanding
> of the hwmod data than I do. It will probably drop a couple of review
> rounds away as the hwmod data would be close to what it should be from
> beginning.
> 
> If you are busy with other things, I can see what I can craft myself.

Not sure if you're still waiting on this, but here's a draft of a PRM 
hwmod for OMAP34xx for testing purposes.  It needs a little more review 
and thought before being ready for merging, but I think it will work for 
your purposes.  The OMAP2430 version should be quite similar.  Comments 
welcome,


- Paul

From: Paul Walmsley <paul@pwsan.com>
Date: Sun, 4 Sep 2011 18:26:58 -0600
Subject: [PATCH] OMAP3xxx: hwmod data: add PRM hwmod

*** DRAFT ***
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   63 ++++++++++++++++++++++++++++
 1 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 25bf43b..4b3640e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -161,6 +161,7 @@ static struct omap_hwmod omap3xxx_l3_main_hwmod = {
 };
 
 static struct omap_hwmod omap3xxx_l4_wkup_hwmod;
+static struct omap_hwmod omap3xxx_prm_hwmod;
 static struct omap_hwmod omap3xxx_uart1_hwmod;
 static struct omap_hwmod omap3xxx_uart2_hwmod;
 static struct omap_hwmod omap3xxx_uart3_hwmod;
@@ -478,6 +479,29 @@ static struct omap_hwmod omap3xxx_l4_per_hwmod = {
 	.flags		= HWMOD_NO_IDLEST,
 };
 
+static struct omap_hwmod_addr_space omap3xxx_prm_addrs[] = {
+	{
+		.pa_start	= 0x48306000,
+		.pa_end		= 0x48306000 + SZ_8K + SZ_4K - 1,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+/* L4_WKUP -> PRM interface */
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__prm = {
+	.master		= &omap3xxx_l4_wkup_hwmod,
+	.slave		= &omap3xxx_prm_hwmod,
+	.clk		= "wkup_l4_ick",
+	.addr		= omap3xxx_prm_addrs,
+	.user		= OCP_USER_MPU,
+};
+
+/* Master interfaces on the L4_WKUP interconnect */
+static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_masters[] = {
+	&omap3xxx_l4_wkup__prm,
+};
+
 /* Slave interfaces on the L4_WKUP interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_slaves[] = {
 	&omap3xxx_l4_core__l4_wkup,
@@ -487,12 +511,48 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_slaves[] = {
 static struct omap_hwmod omap3xxx_l4_wkup_hwmod = {
 	.name		= "l4_wkup",
 	.class		= &l4_hwmod_class,
+	.masters	= omap3xxx_l4_wkup_masters,
+	.masters_cnt	= ARRAY_SIZE(omap3xxx_l4_wkup_masters),
 	.slaves		= omap3xxx_l4_wkup_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3xxx_l4_wkup_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 	.flags		= HWMOD_NO_IDLEST,
 };
 
+/* Slave interfaces on the L4_WKUP interconnect */
+static struct omap_hwmod_ocp_if *omap3xxx_prm_slaves[] = {
+	&omap3xxx_l4_wkup__prm,
+};
+
+static struct omap_hwmod_class_sysconfig omap3xxx_prm_sysc = {
+	.rev_offs	= 0x0804,
+	.sysc_offs	= 0x0814,
+	.sysc_flags	= SYSC_HAS_AUTOIDLE,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_prm_hwmod_class = {
+	.name		= "prm",
+	.sysc		= &omap3xxx_prm_sysc,
+};
+
+static struct omap_hwmod_irq_info omap3xxx_prm_irqs[] = {
+	{ .irq = 11 },
+	{ .irq = -1 }
+};
+
+/* PRM */
+static struct omap_hwmod omap3xxx_prm_hwmod = {
+	.name		= "prm",
+	.mpu_irqs	= omap3xxx_prm_irqs,
+	.class		= &omap3xxx_prm_hwmod_class,
+	.main_clk	= "wkup_32k_fck",
+	.slaves		= omap3xxx_prm_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_prm_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags		= HWMOD_NO_IDLEST,
+};
+
 /* Master interfaces on the MPU device */
 static struct omap_hwmod_ocp_if *omap3xxx_mpu_masters[] = {
 	&omap3xxx_mpu__l3_main,
@@ -3201,6 +3261,9 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
 	&omap3xxx_l4_core_hwmod,
 	&omap3xxx_l4_per_hwmod,
 	&omap3xxx_l4_wkup_hwmod,
+
+	&omap3xxx_prm_hwmod,
+
 	&omap3xxx_mmc1_hwmod,
 	&omap3xxx_mmc2_hwmod,
 	&omap3xxx_mmc3_hwmod,
-- 
1.7.5.4


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

* Re: [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism
  2011-09-14 12:10           ` Paul Walmsley
@ 2011-09-14 12:33             ` Tero Kristo
  0 siblings, 0 replies; 21+ messages in thread
From: Tero Kristo @ 2011-09-14 12:33 UTC (permalink / raw)
  To: Paul Walmsley
  Cc: linux-omap, Thomas Petazzoni, Mahadeva, Avinash, Hilman, Kevin,
	Cousson, Benoit, Tony Lindgren, R, Govindraj, Balbi, Felipe

On Wed, 2011-09-14 at 14:10 +0200, Paul Walmsley wrote:
> Hello Tero,
> 
> On Fri, 2 Sep 2011, Tero Kristo wrote:
> 
> > On Fri, 2011-09-02 at 11:20 +0200, Paul Walmsley wrote:
> >
> > > If it would help, I'd be happy to do a first draft of the OMAP3430 PRM 
> > > hwmod data.
> > 
> > If you can do this it would help, as you have much better understanding
> > of the hwmod data than I do. It will probably drop a couple of review
> > rounds away as the hwmod data would be close to what it should be from
> > beginning.
> > 
> > If you are busy with other things, I can see what I can craft myself.
> 
> Not sure if you're still waiting on this, but here's a draft of a PRM 
> hwmod for OMAP34xx for testing purposes.  It needs a little more review 
> and thought before being ready for merging, but I think it will work for 
> your purposes.  The OMAP2430 version should be quite similar.  Comments 
> welcome,
> 

Thanks Paul,

I'll start experimenting with this.

> 
> - Paul
> 
> From: Paul Walmsley <paul@pwsan.com>
> Date: Sun, 4 Sep 2011 18:26:58 -0600
> Subject: [PATCH] OMAP3xxx: hwmod data: add PRM hwmod
> 
> *** DRAFT ***
> ---
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   63 ++++++++++++++++++++++++++++
>  1 files changed, 63 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> index 25bf43b..4b3640e 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> @@ -161,6 +161,7 @@ static struct omap_hwmod omap3xxx_l3_main_hwmod = {
>  };
>  
>  static struct omap_hwmod omap3xxx_l4_wkup_hwmod;
> +static struct omap_hwmod omap3xxx_prm_hwmod;
>  static struct omap_hwmod omap3xxx_uart1_hwmod;
>  static struct omap_hwmod omap3xxx_uart2_hwmod;
>  static struct omap_hwmod omap3xxx_uart3_hwmod;
> @@ -478,6 +479,29 @@ static struct omap_hwmod omap3xxx_l4_per_hwmod = {
>  	.flags		= HWMOD_NO_IDLEST,
>  };
>  
> +static struct omap_hwmod_addr_space omap3xxx_prm_addrs[] = {
> +	{
> +		.pa_start	= 0x48306000,
> +		.pa_end		= 0x48306000 + SZ_8K + SZ_4K - 1,
> +		.flags		= ADDR_TYPE_RT
> +	},
> +	{ }
> +};
> +
> +/* L4_WKUP -> PRM interface */
> +static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__prm = {
> +	.master		= &omap3xxx_l4_wkup_hwmod,
> +	.slave		= &omap3xxx_prm_hwmod,
> +	.clk		= "wkup_l4_ick",
> +	.addr		= omap3xxx_prm_addrs,
> +	.user		= OCP_USER_MPU,
> +};
> +
> +/* Master interfaces on the L4_WKUP interconnect */
> +static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_masters[] = {
> +	&omap3xxx_l4_wkup__prm,
> +};
> +
>  /* Slave interfaces on the L4_WKUP interconnect */
>  static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_slaves[] = {
>  	&omap3xxx_l4_core__l4_wkup,
> @@ -487,12 +511,48 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_slaves[] = {
>  static struct omap_hwmod omap3xxx_l4_wkup_hwmod = {
>  	.name		= "l4_wkup",
>  	.class		= &l4_hwmod_class,
> +	.masters	= omap3xxx_l4_wkup_masters,
> +	.masters_cnt	= ARRAY_SIZE(omap3xxx_l4_wkup_masters),
>  	.slaves		= omap3xxx_l4_wkup_slaves,
>  	.slaves_cnt	= ARRAY_SIZE(omap3xxx_l4_wkup_slaves),
>  	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
>  	.flags		= HWMOD_NO_IDLEST,
>  };
>  
> +/* Slave interfaces on the L4_WKUP interconnect */
> +static struct omap_hwmod_ocp_if *omap3xxx_prm_slaves[] = {
> +	&omap3xxx_l4_wkup__prm,
> +};
> +
> +static struct omap_hwmod_class_sysconfig omap3xxx_prm_sysc = {
> +	.rev_offs	= 0x0804,
> +	.sysc_offs	= 0x0814,
> +	.sysc_flags	= SYSC_HAS_AUTOIDLE,
> +	.sysc_fields	= &omap_hwmod_sysc_type1,
> +};
> +
> +static struct omap_hwmod_class omap3xxx_prm_hwmod_class = {
> +	.name		= "prm",
> +	.sysc		= &omap3xxx_prm_sysc,
> +};
> +
> +static struct omap_hwmod_irq_info omap3xxx_prm_irqs[] = {
> +	{ .irq = 11 },
> +	{ .irq = -1 }
> +};
> +
> +/* PRM */
> +static struct omap_hwmod omap3xxx_prm_hwmod = {
> +	.name		= "prm",
> +	.mpu_irqs	= omap3xxx_prm_irqs,
> +	.class		= &omap3xxx_prm_hwmod_class,
> +	.main_clk	= "wkup_32k_fck",
> +	.slaves		= omap3xxx_prm_slaves,
> +	.slaves_cnt	= ARRAY_SIZE(omap3xxx_prm_slaves),
> +	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
> +	.flags		= HWMOD_NO_IDLEST,
> +};
> +
>  /* Master interfaces on the MPU device */
>  static struct omap_hwmod_ocp_if *omap3xxx_mpu_masters[] = {
>  	&omap3xxx_mpu__l3_main,
> @@ -3201,6 +3261,9 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
>  	&omap3xxx_l4_core_hwmod,
>  	&omap3xxx_l4_per_hwmod,
>  	&omap3xxx_l4_wkup_hwmod,
> +
> +	&omap3xxx_prm_hwmod,
> +
>  	&omap3xxx_mmc1_hwmod,
>  	&omap3xxx_mmc2_hwmod,
>  	&omap3xxx_mmc3_hwmod,



Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
 


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

end of thread, other threads:[~2011-09-14 12:33 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-25 16:36 [PATCHv7 00/11] PRCM chain handler Tero Kristo
2011-07-25 16:36 ` [PATCHv6 01/11] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
2011-07-25 17:03   ` Felipe Balbi
2011-07-26 10:33     ` Tero Kristo
2011-07-26 10:40       ` Felipe Balbi
2011-08-26  9:12   ` Paul Walmsley
2011-09-01 14:00     ` Tero Kristo
2011-09-02  9:20       ` Paul Walmsley
2011-09-02 12:15         ` Tero Kristo
2011-09-14 12:10           ` Paul Walmsley
2011-09-14 12:33             ` Tero Kristo
2011-07-25 16:36 ` [PATCHv6 02/11] OMAP2+: hwmod: Add API to enable IO ring wakeup Tero Kristo
2011-07-25 16:36 ` [PATCHv6 03/11] OMAP2+: hwmod: Add API to check IO PAD wakeup status Tero Kristo
2011-07-25 16:36 ` [PATCHv6 04/11] OMAP2+: mux: add support for PAD wakeup interrupts Tero Kristo
2011-07-25 16:36 ` [PATCHv6 05/11] TEMP: OMAP3: pm: remove serial resume / idle calls from idle path Tero Kristo
2011-07-25 16:36 ` [PATCHv6 06/11] TEMP: OMAP3: serial: made serial to work properly with PRCM chain handler Tero Kristo
2011-07-25 16:36 ` [PATCHv6 07/11] TEMP: serial: added mux support Tero Kristo
2011-07-25 16:36 ` [PATCHv6 08/11] TEMP: OMAP device: change pr_warnings to pr_debugs Tero Kristo
2011-07-25 16:36 ` [PATCHv6 09/11] TEMP: OMAP: serial: remove padconf hacks Tero Kristo
2011-07-25 16:36 ` [PATCHv6 10/11] TEMP: OMAP3: pm: disable / enable PRCM chain interrupts during wakeup from suspend Tero Kristo
2011-07-25 16:36 ` [PATCHv6 11/11] OMAP3: pm: do not enable PRCM MPU interrupts manually Tero Kristo

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.