All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] PRCM chain interrupt handler
@ 2011-06-09 13:25 Tero Kristo
  2011-06-09 13:25 ` [PATCH 1/3] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Tero Kristo @ 2011-06-09 13:25 UTC (permalink / raw)
  To: linux-omap

Hello,

Following set contains PRCM chain interrupt handling for OMAP3/4. Contents
of this set:

- Patch 1 was initially made by Thomas Petazzoni I believe, I made some
  OMAP4 specific fixes on that one and updated this to conform to latest
  kernel APIs. This patch contains the main logic for the PRCM chain
  handling.

- Patch 2 adds a support for chaining PRCM IO wakeup events to interrupts.
  This is accomplished by simply registering pad -> irq relationship and
  launching the interrupt handler from PRCM hardirq with generic_handle_irq().

- Patch 3 is just a hack to enable serial to work with PRCM IO wakeups,
  this should be written properly by someone when the initial framework
  (patch 1 & 2) are okay.

Any comments welcome.

-Tero



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


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

* [PATCH 1/3] omap: prcm: switch to a chained IRQ handler mechanism
  2011-06-09 13:25 [PATCH 0/3] PRCM chain interrupt handler Tero Kristo
@ 2011-06-09 13:25 ` Tero Kristo
  2011-06-09 13:25 ` [PATCH 2/3] PRCM: Add support for PAD wakeup interrupts Tero Kristo
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Tero Kristo @ 2011-06-09 13:25 UTC (permalink / raw)
  To: linux-omap

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 individual PRCM events for OMAP3 and OMAP4 being
described in arch/arm/mach-omap2/prcm3xxx.c and
arch/arm/mach-omap2/prcm4xxx.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.

The wakeup and I/O PRCM events are now handled as two separate
interrupts, and their handler is registered with IRQF_NO_SUSPEND,
otherwise the IRQ gets disabled during suspend, which prevents resume.

Patch tested on OMAP4 blaze board, no testing done on OMAP3.

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>
---
 arch/arm/mach-omap2/Makefile           |    4 +
 arch/arm/mach-omap2/pm34xx.c           |  104 ++++++------------
 arch/arm/mach-omap2/pm44xx.c           |   18 +++-
 arch/arm/mach-omap2/prcm.c             |  187 ++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/prcm3xxx.c         |  117 ++++++++++++++++++++
 arch/arm/mach-omap2/prcm4xxx.c         |  146 +++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/irqs.h |    9 ++-
 arch/arm/plat-omap/include/plat/prcm.h |   45 ++++++++
 8 files changed, 554 insertions(+), 76 deletions(-)
 create mode 100644 arch/arm/mach-omap2/prcm3xxx.c
 create mode 100644 arch/arm/mach-omap2/prcm4xxx.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 52dcc1d..6d3d527 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -40,6 +40,10 @@ AFLAGS_sram242x.o			:=-Wa,-march=armv6
 AFLAGS_sram243x.o			:=-Wa,-march=armv6
 AFLAGS_sram34xx.o			:=-Wa,-march=armv7-a
 
+# PRCM
+obj-$(CONFIG_ARCH_OMAP3)                += prcm3xxx.o
+obj-$(CONFIG_ARCH_OMAP4)                += prcm4xxx.o
+
 # Pin multiplexing
 obj-$(CONFIG_SOC_OMAP2420)		+= mux2420.o
 obj-$(CONFIG_SOC_OMAP2430)		+= mux2430.o
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index dc045cc..8da13df 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -240,7 +240,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;
 
@@ -252,64 +252,10 @@ 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;
+	if (c)
+		return IRQ_HANDLED;
+	else
+		return IRQ_NONE;
 }
 
 /* Function to restore the table entry that was modified for enabling MMU */
@@ -894,20 +840,32 @@ 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 = omap_prcm_irq_init();
+	if (ret) {
+		pr_err("omap_prcm_irq_init() failed with %d\n", ret);
+		goto err_prcm_irq_init;
+	}
+
+	ret = request_irq(omap_prcm_event_to_irq("wkup"),
+			  _prcm_int_handle_wakeup,
+			  IRQF_NO_SUSPEND, "prcm_wkup", NULL);
+	if (ret) {
+		pr_err("request_irq failed to register for PRCM wakeup\n");
+		goto err_prcm_irq_wkup;
+	}
 
-	ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
-			  (irq_handler_t)prcm_interrupt_handler,
-			  IRQF_DISABLED, "prcm", NULL);
+	ret = request_irq(omap_prcm_event_to_irq("io"),
+			  _prcm_int_handle_wakeup,
+			  IRQF_NO_SUSPEND, "prcm_io", NULL);
 	if (ret) {
-		printk(KERN_ERR "request_irq failed to register for 0x%x\n",
-		       INT_34XX_PRCM_MPU_IRQ);
-		goto err1;
+		pr_err("request_irq failed to register for PRCM io\n");
+		goto err_prcm_irq_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);
@@ -915,7 +873,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");
@@ -967,14 +925,20 @@ static int __init omap3_pm_init(void)
 	pm_dbg_regset_init(2);
 
 	omap3_save_scratchpad_contents();
-err1:
+
 	return ret;
-err2:
-	free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
+
+ err_pwrdms_setup:
+	free_irq(omap_prcm_event_to_irq("io"), NULL);
 	list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
 		list_del(&pwrst->node);
 		kfree(pwrst);
 	}
+ err_prcm_irq_io:
+	free_irq(omap_prcm_event_to_irq("wkup"), NULL);
+ err_prcm_irq_wkup:
+	omap_prcm_irq_cleanup();
+ err_prcm_irq_init:
 	return ret;
 }
 
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index b0cf93b..f70a9ad 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -23,6 +23,7 @@
 
 #include <mach/omap4-common.h>
 #include <plat/common.h>
+#include <plat/prcm.h>
 
 #include "powerdomain.h"
 #include "clockdomain.h"
@@ -354,7 +355,7 @@ static void __init prcm_setup_regs(void)
 	omap4_prminst_write_inst_reg(0x3, OMAP4430_PRM_PARTITION,
 		OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_PWRREQCTRL_OFFSET);
 }
-static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+static irqreturn_t _prcm_int_handle_wakeup(int irq, void *dev_id)
 {
 	u32 irqenable_mpu, irqstatus_mpu;
 
@@ -403,12 +404,17 @@ static int __init omap4_pm_init(void)
 	}
 
 	pr_err("Power Management for TI OMAP4.\n");
+	ret = omap_prcm_irq_init();
+	if (ret) {
+		pr_err("omap_prcm_irq_init() failed with %d\n", ret);
+		goto err1;
+	}
 
 	prcm_setup_regs();
 
-	ret = request_irq(OMAP44XX_IRQ_PRCM,
-			  (irq_handler_t)prcm_interrupt_handler,
-			  IRQF_DISABLED, "prcm", NULL);
+	ret = request_irq(omap_prcm_event_to_irq("io"),
+			_prcm_int_handle_wakeup,
+			IRQF_NO_SUSPEND, "prcm_io", NULL);
 	if (ret) {
 		printk(KERN_ERR "request_irq failed to register for 0x%x\n",
 		       OMAP44XX_IRQ_PRCM);
@@ -471,8 +477,10 @@ static int __init omap4_pm_init(void)
 #ifdef CONFIG_PM
 	local_irq_enable();
 #endif
-
+	return ret;
 err2:
+	omap_prcm_irq_cleanup();
+err1:
 	return ret;
 }
 late_initcall(omap4_pm_init);
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 6be1438..362c59c 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,191 @@ void __iomem *cm2_base;
 
 #define MAX_MODULE_ENABLE_WAIT		100000
 
+/* Array of valid PRCM events for the current OMAP */
+static struct omap_prcm_irq *omap_prcm_irqs;
+
+/* Number of entries in omap_prcm_irqs */
+static int omap_prcm_irqs_nr;
+
+/* Pointers to either OMAP3 or OMAP4 specific functions */
+static void (*omap_prcm_mask_event)(unsigned event);
+static void (*omap_prcm_unmask_event)(unsigned event);
+static void (*omap_prcm_ack_event)(unsigned event);
+static void (*omap_prcm_pending_events)(unsigned long *pending);
+
+static void prcm_irq_ack(struct irq_data *data)
+{
+	unsigned int prcm_irq = data->irq - OMAP_PRCM_IRQ_BASE;
+	omap_prcm_ack_event(prcm_irq);
+}
+
+static void prcm_irq_mask(struct irq_data *data)
+{
+	unsigned int prcm_irq = data->irq - OMAP_PRCM_IRQ_BASE;
+	omap_prcm_mask_event(prcm_irq);
+}
+
+static void prcm_irq_unmask(struct irq_data *data)
+{
+	unsigned int prcm_irq = data->irq - OMAP_PRCM_IRQ_BASE;
+	omap_prcm_unmask_event(prcm_irq);
+}
+
+static struct irq_chip prcm_irq_chip = {
+	.name		= "PRCM",
+	.irq_ack	= prcm_irq_ack,
+	.irq_mask	= prcm_irq_mask,
+	.irq_unmask	= prcm_irq_unmask,
+};
+
+/*
+ * 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(), called by prcm_irq_handle_virtirqs()
+	 * can cause new irqs to come
+	 */
+	while (1) {
+		unsigned int virtirq;
+
+		chip->irq_ack(&desc->irq_data);
+
+		memset(pending, 0, sizeof(pending));
+		omap_prcm_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(OMAP_PRCM_IRQ_BASE + 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 < omap_prcm_irqs_nr; i++)
+		if (!strcmp(omap_prcm_irqs[i].name, name))
+			return OMAP_PRCM_IRQ_BASE + omap_prcm_irqs[i].offset;
+
+	return -ENOENT;
+}
+
+/*
+ * Prepare the array of PRCM events corresponding to the current SoC,
+ * and set-up the chained interrupt handler mechanism.
+ */
+int omap_prcm_irq_init(void)
+{
+	int i, j;
+	struct omap_prcm_irq *unfiltered_irqs;
+	unsigned unfiltered_irqs_nr;
+
+	if (cpu_is_omap34xx() || cpu_is_omap3630()) {
+		unfiltered_irqs          = omap_prcm_3xxx_irqs;
+		unfiltered_irqs_nr       = omap_prcm_3xxx_irqs_nr;
+		omap_prcm_mask_event     = omap3_prcm_mask_event;
+		omap_prcm_unmask_event   = omap3_prcm_unmask_event;
+		omap_prcm_ack_event      = omap3_prcm_ack_event;
+		omap_prcm_pending_events = omap3_prcm_pending_events;
+		irq_set_chained_handler(INT_34XX_PRCM_MPU_IRQ,
+					prcm_irq_handler);
+	} else if (cpu_is_omap44xx()) {
+		unfiltered_irqs          = omap_prcm_4xxx_irqs;
+		unfiltered_irqs_nr       = omap_prcm_4xxx_irqs_nr;
+		omap_prcm_mask_event     = omap4_prcm_mask_event;
+		omap_prcm_unmask_event   = omap4_prcm_unmask_event;
+		omap_prcm_ack_event      = omap4_prcm_ack_event;
+		omap_prcm_pending_events = omap4_prcm_pending_events;
+		irq_set_chained_handler(OMAP44XX_IRQ_PRCM, prcm_irq_handler);
+	} else {
+		return -ENODEV;
+	}
+
+	for (i = 0; i < unfiltered_irqs_nr; i++)
+		if (omap_chip_is(unfiltered_irqs[i].omap_chip))
+			omap_prcm_irqs_nr++;
+
+	omap_prcm_irqs = kmalloc(omap_prcm_irqs_nr *
+				 sizeof(struct omap_prcm_irq),
+				 GFP_KERNEL);
+	if (!omap_prcm_irqs)
+		return -ENOMEM;
+
+	for (i = 0, j = 0; i < unfiltered_irqs_nr; i++)
+		if (omap_chip_is(unfiltered_irqs[i].omap_chip)) {
+			memcpy(&omap_prcm_irqs[j], &unfiltered_irqs[i],
+			       sizeof(struct omap_prcm_irq));
+			j++;
+		}
+
+	for (i = OMAP_PRCM_IRQ_BASE; i < OMAP_PRCM_IRQ_END; i++) {
+		irq_set_chip(i, &prcm_irq_chip);
+		irq_set_handler(i, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	return 0;
+}
+
+/*
+ * Reverses memory allocated and other setups done by
+ * omap_prcm_irq_init().
+ */
+void omap_prcm_irq_cleanup(void)
+{
+	int i;
+
+	for (i = OMAP_PRCM_IRQ_BASE; i < OMAP_PRCM_IRQ_END; i++) {
+		irq_set_chip(i, NULL);
+		irq_set_handler(i, NULL);
+		set_irq_flags(i, 0);
+	}
+
+	kfree(omap_prcm_irqs);
+
+	if (cpu_is_omap34xx() || cpu_is_omap3630()) {
+		irq_set_chained_handler(INT_34XX_PRCM_MPU_IRQ, NULL);
+	} else {
+		irq_set_chained_handler(OMAP44XX_IRQ_PRCM, NULL);
+	}
+}
+
 u32 omap_prcm_get_reset_sources(void)
 {
 	/* XXX This presumably needs modification for 34XX */
diff --git a/arch/arm/mach-omap2/prcm3xxx.c b/arch/arm/mach-omap2/prcm3xxx.c
new file mode 100644
index 0000000..a57fe69
--- /dev/null
+++ b/arch/arm/mach-omap2/prcm3xxx.c
@@ -0,0 +1,117 @@
+/*
+ * linux/arch/arm/mach-omap2/prcm3xxx.c
+ *
+ * OMAP 3xxx Power Reset and Clock Management (PRCM) interrupt
+ * definitions
+ *
+ * Written by Thomas Petazzoni <t-petazzoni@ti.com>
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <plat/prcm.h>
+
+#include "prm-regbits-24xx.h"
+
+struct omap_prcm_irq  __initdata omap_prcm_3xxx_irqs[] = {
+	OMAP_PRCM_IRQ("wkup",                  0,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("evgenon",               2,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("evgenoff",              3,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("transition",            4,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("core_dpll_recal",       5,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("periph_dpll_recal",     6,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("mpu_dpll_recal",        7,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("iva2_dpll_recal",       8,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("io",	            9,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp1_oppchangedone",    10,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp1_minvdd",           11,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp1_maxvdd",           12,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp1_nosmpsack",        13,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp1_eqvalue",          14,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp1_tranxdone",        15,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp2_oppchangedone",    16,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp2_minvdd",           17,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp2_maxvdd",           18,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp2_nosmpsack",        19,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp2_eqvalue",          20,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vp2_tranxdone",        21,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vc_saerr",             22,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vc_raerr",             23,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vc_timeout_err",       24,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("snd_periph_recal",     25,
+		      CHIP_IS_OMAP3430 | CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("abb_ldo_tranxdone",    26,
+		      CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vc_vp1_ack",           27,
+		      CHIP_GE_OMAP3630ES1_1),
+	OMAP_PRCM_IRQ("vc_bypass_ack",        28,
+		      CHIP_GE_OMAP3630ES1_1),
+};
+
+unsigned int __initdata
+omap_prcm_3xxx_irqs_nr = ARRAY_SIZE(omap_prcm_3xxx_irqs);
+
+void omap3_prcm_mask_event(unsigned event)
+{
+	unsigned int bit = BIT(event);
+
+	omap2_prm_rmw_mod_reg_bits(bit, 0, OCP_MOD,
+				   OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+}
+
+void omap3_prcm_unmask_event(unsigned event)
+{
+	unsigned int bit = BIT(event);
+
+	omap2_prm_rmw_mod_reg_bits(0, bit, OCP_MOD,
+				   OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+}
+
+void omap3_prcm_ack_event(unsigned event)
+{
+	unsigned int bit = BIT(event);
+
+	omap2_prm_write_mod_reg(bit, OCP_MOD,
+				OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+}
+
+void omap3_prcm_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;
+}
diff --git a/arch/arm/mach-omap2/prcm4xxx.c b/arch/arm/mach-omap2/prcm4xxx.c
new file mode 100644
index 0000000..e70f267
--- /dev/null
+++ b/arch/arm/mach-omap2/prcm4xxx.c
@@ -0,0 +1,146 @@
+/*
+ * linux/arch/arm/mach-omap2/prcm4xxx.c
+ *
+ * OMAP 4xxx Power Reset and Clock Management (PRCM) interrupt
+ * definitions
+ *
+ * Written by Thomas Petazzoni <t-petazzoni@ti.com>
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <plat/prcm.h>
+
+#include "prcm44xx.h"
+#include "prm44xx.h"
+
+struct omap_prcm_irq __initdata omap_prcm_4xxx_irqs[] = {
+	OMAP_PRCM_IRQ("dpll_core_recal",       0,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("dpll_mpu_recal",        1,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("dpll_iva_recal",        2,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("dpll_per_recal",        3,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("dpll_abe_recal",        4,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("dpll_usb_recal",        5,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("dpll_unipro_recal",     7,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("transition",            8,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("io",                    9,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vc_saerr",              11,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vc_raerr",              12,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vc_toerr",              13,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vc_bypassack",          14,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_core_oppchangedone", 16,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_core_minvdd",        17,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_core_maxvdd",        18,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_core_nosmpsack",     19,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_core_eqvalue",       20,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_core_tranxdone",     21,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_iva_oppchangedone",  24,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_iva_minvdd",         25,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_iva_maxvdd",         26,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_iva_nosmpsack",      27,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_iva_eqvalue",        28,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_iva_tranxdone",      29,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_iva_vpack",          30,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("abb_iva_done",          31,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_mpu_oppchangedone",  32,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_mpu_minvdd",         33,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_mpu_maxvdd",         34,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_mpu_nosmpsack",      35,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_mpu_eqvalue",        36,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_mpu_tranxdone",      37,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("vp_mpu_vpack",          38,
+		      CHIP_IS_OMAP4430),
+	OMAP_PRCM_IRQ("abb_mpu_done",          39,
+		      CHIP_IS_OMAP4430),
+};
+
+unsigned int __initdata
+omap_prcm_4xxx_irqs_nr = ARRAY_SIZE(omap_prcm_4xxx_irqs);
+
+void omap4_prcm_mask_event(unsigned event)
+{
+	unsigned int bit = BIT(event % 32);
+	unsigned int off = (event / 32) * 4;
+
+	omap4_prm_rmw_inst_reg_bits(bit, 0,
+				    OMAP4430_PRM_OCP_SOCKET_INST,
+				    OMAP4_PRM_IRQENABLE_MPU_OFFSET + off);
+}
+
+void omap4_prcm_unmask_event(unsigned event)
+{
+	unsigned int bit = BIT(event % 32);
+	unsigned int off = (event / 32) * 4;
+
+	omap4_prm_rmw_inst_reg_bits(0, bit,
+				    OMAP4430_PRM_OCP_SOCKET_INST,
+				    OMAP4_PRM_IRQENABLE_MPU_OFFSET + off);
+}
+
+void omap4_prcm_ack_event(unsigned event)
+{
+	unsigned int bit = BIT(event % 32);
+	unsigned int off = (event / 32) * 4;
+
+	omap4_prm_write_inst_reg(bit,
+				 OMAP4430_PRM_OCP_SOCKET_INST,
+				 OMAP4_PRM_IRQSTATUS_MPU_OFFSET + off);
+}
+
+void omap4_prcm_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;
+	}
+}
diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h
index 5a25098..23b9680 100644
--- a/arch/arm/plat-omap/include/plat/irqs.h
+++ b/arch/arm/plat-omap/include/plat/irqs.h
@@ -366,7 +366,14 @@
 #define OMAP_MAX_GPIO_LINES	192
 #define IH_GPIO_BASE		(128 + IH2_BASE)
 #define IH_MPUIO_BASE		(OMAP_MAX_GPIO_LINES + IH_GPIO_BASE)
-#define OMAP_IRQ_END		(IH_MPUIO_BASE + 16)
+#define OMAP_MPUIO_IRQ_END	(IH_MPUIO_BASE + 16)
+
+/* 64 IRQs for the PRCM (32 are needed on OMAP3, 64 on OMAP4) */
+#define OMAP_PRCM_IRQ_BASE      (OMAP_MPUIO_IRQ_END)
+#define OMAP_PRCM_NR_IRQS       64
+#define OMAP_PRCM_IRQ_END       (OMAP_PRCM_IRQ_BASE + OMAP_PRCM_NR_IRQS)
+
+#define OMAP_IRQ_END            (OMAP_PRCM_IRQ_END)
 
 /* External FPGA handles interrupts on Innovator boards */
 #define	OMAP_FPGA_IRQ_BASE	(OMAP_IRQ_END)
diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h
index 267f43b..5785555 100644
--- a/arch/arm/plat-omap/include/plat/prcm.h
+++ b/arch/arm/plat-omap/include/plat/prcm.h
@@ -27,6 +27,51 @@
 #ifndef __ASM_ARM_ARCH_OMAP_PRCM_H
 #define __ASM_ARM_ARCH_OMAP_PRCM_H
 
+#include <plat/cpu.h>
+
+/*
+ * 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
+	 * 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) }
+
+/* Maximum number of PRCM interrupt status registers */
+#define OMAP_PRCM_MAX_NR_PENDING_REG 2
+
+extern struct omap_prcm_irq omap_prcm_3xxx_irqs[];
+extern unsigned int omap_prcm_3xxx_irqs_nr;
+void omap3_prcm_mask_event(unsigned event);
+void omap3_prcm_unmask_event(unsigned event);
+void omap3_prcm_ack_event(unsigned event);
+void omap3_prcm_pending_events(unsigned long *pending);
+
+extern struct omap_prcm_irq omap_prcm_4xxx_irqs[];
+extern unsigned int omap_prcm_4xxx_irqs_nr;
+void omap4_prcm_mask_event(unsigned event);
+void omap4_prcm_unmask_event(unsigned event);
+void omap4_prcm_ack_event(unsigned event);
+void omap4_prcm_pending_events(unsigned long *pending);
+
+int omap_prcm_event_to_irq(const char *name);
+int omap_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] 9+ messages in thread

* [PATCH 2/3] PRCM: Add support for PAD wakeup interrupts
  2011-06-09 13:25 [PATCH 0/3] PRCM chain interrupt handler Tero Kristo
  2011-06-09 13:25 ` [PATCH 1/3] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
@ 2011-06-09 13:25 ` Tero Kristo
  2011-06-09 13:25 ` [PATCH 3/3] HACK: OMAP: Serial: use PRCM wakeup events to enable clocks Tero Kristo
  2011-06-16 18:56 ` [PATCH 0/3] PRCM chain interrupt handler Kevin Hilman
  3 siblings, 0 replies; 9+ messages in thread
From: Tero Kristo @ 2011-06-09 13:25 UTC (permalink / raw)
  To: linux-omap

PRCM interrupt handler will now parse registered pads to see whether there
is an active wakeup event. If this is the case, the corresponding interrupt
will be triggered. This can be used for example with UART driver to register
PAD wakeup event for the UART RX pin, and when this happens, UART interrupt
will be triggered.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/prcm.c             |   53 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/prcm.h |    3 ++
 2 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 362c59c..754a5a6 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -53,6 +53,15 @@ static struct omap_prcm_irq *omap_prcm_irqs;
 /* Number of entries in omap_prcm_irqs */
 static int omap_prcm_irqs_nr;
 
+/* PAD handlers list */
+struct pad_def {
+	u32 pad;
+	unsigned int irq;
+	struct list_head node;
+};
+
+static LIST_HEAD(pad_handler_list);
+
 /* Pointers to either OMAP3 or OMAP4 specific functions */
 static void (*omap_prcm_mask_event)(unsigned event);
 static void (*omap_prcm_unmask_event)(unsigned event);
@@ -84,6 +93,28 @@ static struct irq_chip prcm_irq_chip = {
 	.irq_unmask	= prcm_irq_unmask,
 };
 
+
+/*
+ * Handler for PAD irqs, called from PRCM interrupt handler
+ */
+static void omap_prcm_handle_pad_irqs(void)
+{
+	struct pad_def *def;
+	u16 val = 0;
+	list_for_each_entry(def, &pad_handler_list, node) {
+		/* Read padconf value based on cpu type */
+		if (cpu_is_omap34xx())
+			val = omap_ctrl_readw(def->pad);
+
+		if (cpu_is_omap44xx())
+			val = omap4_ctrl_pad_readw(def->pad);
+
+		/* if pad wakeupevent is active, fire registered IRQ */
+		if (val & OMAP3_PADCONF_WAKEUPEVENT0)
+			generic_handle_irq(def->irq);
+	}
+}
+
 /*
  * PRCM Interrupt Handler
  *
@@ -106,6 +137,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_prcm_handle_pad_irqs();
+
 	/*
 	 * Loop until all pending irqs are handled, since
 	 * generic_handle_irq(), called by prcm_irq_handle_virtirqs()
@@ -153,6 +187,25 @@ int omap_prcm_event_to_irq(const char *name)
 }
 
 /*
+ * Register interrupt handler for a given pad. When the PRCM interrupt
+ * handler detects wakeupevent on the corresponding pad, the IRQ will
+ * be triggered.
+ */
+int omap_prcm_register_pad_irq(u32 pad, unsigned int irq)
+{
+	struct pad_def *def;
+
+	def = kmalloc(sizeof(struct pad_def), GFP_ATOMIC);
+	if (!def)
+		return -ENOMEM;
+
+	def->pad = pad;
+	def->irq = irq;
+	list_add(&def->node, &pad_handler_list);
+	return 0;
+}
+
+/*
  * Prepare the array of PRCM events corresponding to the current SoC,
  * and set-up the chained interrupt handler mechanism.
  */
diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h
index 5785555..854b2de 100644
--- a/arch/arm/plat-omap/include/plat/prcm.h
+++ b/arch/arm/plat-omap/include/plat/prcm.h
@@ -72,6 +74,7 @@ void omap4_prcm_pending_events(unsigned long *pending);
 int omap_prcm_event_to_irq(const char *name);
 int omap_prcm_irq_init(void);
 void omap_prcm_irq_cleanup(void);
+int omap_prcm_register_pad_irq(u32 pad, unsigned int irq);
 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] 9+ messages in thread

* [PATCH 3/3] HACK: OMAP: Serial: use PRCM wakeup events to enable clocks
  2011-06-09 13:25 [PATCH 0/3] PRCM chain interrupt handler Tero Kristo
  2011-06-09 13:25 ` [PATCH 1/3] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
  2011-06-09 13:25 ` [PATCH 2/3] PRCM: Add support for PAD wakeup interrupts Tero Kristo
@ 2011-06-09 13:25 ` Tero Kristo
  2011-06-14 12:34   ` Govindraj
  2011-06-16 18:56 ` [PATCH 0/3] PRCM chain interrupt handler Kevin Hilman
  3 siblings, 1 reply; 9+ messages in thread
From: Tero Kristo @ 2011-06-09 13:25 UTC (permalink / raw)
  To: linux-omap

This patch is just to test that the idea works generally, proper implementation
should be done for the OMAP UART driver.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/pm44xx.c     |    4 ----
 arch/arm/mach-omap2/serial.c     |    3 +++
 drivers/tty/serial/omap-serial.c |    7 +++++++
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index f70a9ad..ac6aa77 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -103,10 +103,6 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
 
 	if (core_next_state < PWRDM_POWER_ON) {
 		omap2_gpio_resume_after_idle();
-		omap_uart_resume_idle(0);
-		omap_uart_resume_idle(1);
-		omap_uart_resume_idle(2);
-		omap_uart_resume_idle(3);
 	}
 
 	return;
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 6959d65..4cf8c4a 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"
@@ -574,6 +575,8 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
 	ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
 				   IRQF_SHARED, "serial idle", (void *)uart);
 	WARN_ON(ret);
+	ret = omap_prcm_register_pad_irq(uart->padconf, uart->irq);
+	WARN_ON(ret);
 }
 
 void omap_uart_enable_irqs(int enable)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 0275c28..cfe2e7c 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;
@@ -947,6 +951,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;
@@ -1303,6 +1309,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 		goto do_release_region;
 
 	platform_set_drvdata(pdev, up);
+	pr_info("OMAP UART %d is up\n", pdev->id);
 	return 0;
 err:
 	dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
-- 
1.7.4.1


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


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

* Re: [PATCH 3/3] HACK: OMAP: Serial: use PRCM wakeup events to enable clocks
  2011-06-09 13:25 ` [PATCH 3/3] HACK: OMAP: Serial: use PRCM wakeup events to enable clocks Tero Kristo
@ 2011-06-14 12:34   ` Govindraj
  2011-06-15  7:21     ` Tero Kristo
  2011-06-16 12:29     ` Tero Kristo
  0 siblings, 2 replies; 9+ messages in thread
From: Govindraj @ 2011-06-14 12:34 UTC (permalink / raw)
  To: Tero Kristo; +Cc: linux-omap, Basak, Partha, Sripathy, Vishwanath

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

On Thu, Jun 9, 2011 at 6:55 PM, Tero Kristo <t-kristo@ti.com> wrote:
> This patch is just to test that the idea works generally, proper implementation
> should be done for the OMAP UART driver.
>

Doesn't seem to wake-up from off mode.
(uart pad wakeup after enable_offmode and uart timeouts)

I used attached patch which has some more additions to this patch.
(basically to get rid of prepare idle and resume idle calls from sram
idle path and cut clocks independently).

IIUC we have to comment out all resume calls even from omap-serial.c
irq_chaining should call uart_irq handler registered in serial.c
and block sleep.

And on 3430SDP even for module level wakeup after cutting clocks
I see it gets looped in prcm_irq handler trying to clear wakeup status bits
trying to handle same from serial_omap_irq calling resume_idle
doesn't seem to help though if I use the same call from prcm_clear_mod_irqs
helps in wakeup.

Also patch series doesn't seem to apply cleanly on 3.0 kernel conflicts with
4430pm things.

--
Thanks,
Govindraj.R


> Signed-off-by: Tero Kristo <t-kristo@ti.com>
> ---
>  arch/arm/mach-omap2/pm44xx.c     |    4 ----
>  arch/arm/mach-omap2/serial.c     |    3 +++
>  drivers/tty/serial/omap-serial.c |    7 +++++++
>  3 files changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
> index f70a9ad..ac6aa77 100644
> --- a/arch/arm/mach-omap2/pm44xx.c
> +++ b/arch/arm/mach-omap2/pm44xx.c
> @@ -103,10 +103,6 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
>
>        if (core_next_state < PWRDM_POWER_ON) {
>                omap2_gpio_resume_after_idle();
> -               omap_uart_resume_idle(0);
> -               omap_uart_resume_idle(1);
> -               omap_uart_resume_idle(2);
> -               omap_uart_resume_idle(3);
>        }
>
>        return;
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index 6959d65..4cf8c4a 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"
> @@ -574,6 +575,8 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
>        ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
>                                   IRQF_SHARED, "serial idle", (void *)uart);
>        WARN_ON(ret);
> +       ret = omap_prcm_register_pad_irq(uart->padconf, uart->irq);
> +       WARN_ON(ret);
>  }
>
>  void omap_uart_enable_irqs(int enable)
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index 0275c28..cfe2e7c 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;
> @@ -947,6 +951,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;
> @@ -1303,6 +1309,7 @@ static int serial_omap_probe(struct platform_device *pdev)
>                goto do_release_region;
>
>        platform_set_drvdata(pdev, up);
> +       pr_info("OMAP UART %d is up\n", pdev->id);
>        return 0;
>  err:
>        dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
> --
> 1.7.4.1
>
>
> Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

[-- Attachment #2: test_irqchn_uart.patch --]
[-- Type: application/octet-stream, Size: 7504 bytes --]

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index c7eaa32..574e1a4 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -216,6 +216,17 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
 
 	wkst = omap2_prm_read_mod_reg(module, wkst_off);
 	wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
+
+#if 0
+	if (module == OMAP3430_PER_MOD) {
+		if (wkst & OMAP3430_ST_UART3_MASK) {
+			printk("PRCM IRQ: UART3 wakeup\n");
+			omap_uart_resume_idle(0);
+			c++;
+		}
+	} else
+
+#endif
 	if (wkst) {
 		iclk = omap2_cm_read_mod_reg(module, iclk_off);
 		fclk = omap2_cm_read_mod_reg(module, fclk_off);
@@ -337,18 +348,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();
@@ -356,8 +358,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();
@@ -404,8 +404,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,
@@ -419,14 +417,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 ||
@@ -445,8 +437,6 @@ int omap3_can_sleep(void)
 {
 	if (!sleep_while_idle)
 		return 0;
-	if (!omap_uart_can_sleep())
-		return 0;
 	return 1;
 }
 
@@ -495,7 +485,6 @@ static int omap3_pm_suspend(void)
 			goto restore;
 	}
 
-	omap_uart_prepare_suspend();
 	omap3_intc_suspend();
 
 	omap_sram_idle();
@@ -542,14 +531,12 @@ static int omap3_pm_begin(suspend_state_t state)
 {
 	disable_hlt();
 	suspend_state = state;
-	omap_uart_enable_irqs(0);
 	return 0;
 }
 
 static void omap3_pm_end(void)
 {
 	suspend_state = PM_SUSPEND_ON;
-	omap_uart_enable_irqs(1);
 	enable_hlt();
 	return;
 }
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 1ac361b..af7c278 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"
@@ -102,6 +103,9 @@ struct omap_uart_state {
 	u16 wer;
 	u16 mcr;
 #endif
+	bool console;
+	bool console_locked;
+	bool is_suspending;
 };
 
 static LIST_HEAD(uart_list);
@@ -365,10 +369,26 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart)
 		mod_timer(&uart->timer, jiffies + uart->timeout);
 	else
 		del_timer(&uart->timer);
+
+	if (uart->console && uart->console_locked) {
+		console_unlock();
+		uart->console_locked = false;
+	}
 }
 
 static void omap_uart_allow_sleep(struct omap_uart_state *uart)
 {
+	/* If console is busy, wait another second */
+	if (uart->console && !uart->is_suspending) {
+		if (console_trylock()) {
+			uart->console_locked = true;
+		} else {
+			printk("%s: console locked, delaying\n", __func__);
+			mod_timer(&uart->timer, jiffies + HZ);
+			return;
+		}
+	}
+
 	if (device_may_wakeup(&uart->pdev->dev))
 		omap_uart_enable_wakeup(uart);
 	else
@@ -380,6 +400,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 +412,20 @@ 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);
-
-			/* 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 */
-			if (__raw_readl(uart->wk_st) & uart->wk_mask)
-				omap_uart_block_sleep(uart);
+			omap_uart_block_sleep(uart);
+			/* Check for normal UART wakeup (and clear it) */
+			wkst = __raw_readl(uart->wk_st) & uart->wk_mask;
+			if (wkst)
+				__raw_writel(wkst, uart->wk_st);
 			return;
 		}
 	}
@@ -430,7 +436,9 @@ void omap_uart_prepare_suspend(void)
 	struct omap_uart_state *uart;
 
 	list_for_each_entry(uart, &uart_list, node) {
+		uart->is_suspending = true;
 		omap_uart_allow_sleep(uart);
+		uart->is_suspending = false;
 	}
 }
 
@@ -550,6 +558,8 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
 	ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
 				   IRQF_SHARED, "serial idle", (void *)uart);
 	WARN_ON(ret);
+	ret = omap_prcm_register_pad_irq(uart->padconf, uart->irq);
+	WARN_ON(ret);
 }
 
 void omap_uart_enable_irqs(int enable)
@@ -679,6 +689,10 @@ static int __init omap_serial_early_init(void)
 		list_add_tail(&uart->node, &uart_list);
 		num_uarts++;
 
+		/* HACK HACK: hard-code console at UART1 */
+		if (uart->num == 0)
+			uart->console = true;
+
 		/*
 		 * NOTE: omap_hwmod_setup*() has not yet been called,
 		 *       so no hwmod functions will work yet.
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 47cadf4..1312c33 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;
@@ -947,6 +951,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;
@@ -1303,6 +1309,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 		goto do_release_region;
 
 	platform_set_drvdata(pdev, up);
+	pr_info("OMAP UART %d is up\n", pdev->id);
 	return 0;
 err:
 	dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",

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

* Re: [PATCH 3/3] HACK: OMAP: Serial: use PRCM wakeup events to enable clocks
  2011-06-14 12:34   ` Govindraj
@ 2011-06-15  7:21     ` Tero Kristo
  2011-06-16 12:29     ` Tero Kristo
  1 sibling, 0 replies; 9+ messages in thread
From: Tero Kristo @ 2011-06-15  7:21 UTC (permalink / raw)
  To: Govindraj; +Cc: linux-omap, Basak, Partha, Sripathy, Vishwanath

On Tue, 2011-06-14 at 14:34 +0200, Govindraj wrote:
> On Thu, Jun 9, 2011 at 6:55 PM, Tero Kristo <t-kristo@ti.com> wrote:
> > This patch is just to test that the idea works generally, proper implementation
> > should be done for the OMAP UART driver.
> >

Hi Govindraj,

Thanks for testing this out on OMAP3.

> 
> Doesn't seem to wake-up from off mode.
> (uart pad wakeup after enable_offmode and uart timeouts)
> 
> I used attached patch which has some more additions to this patch.
> (basically to get rid of prepare idle and resume idle calls from sram
> idle path and cut clocks independently).

I am currently checking out your patch on my code base on OMAP4, so far
I have not succeeded to get it work properly.

> 
> IIUC we have to comment out all resume calls even from omap-serial.c
> irq_chaining should call uart_irq handler registered in serial.c
> and block sleep.

Yep, this would be the case. A few calls are probably required in the
omap-serial.c because console can try to print something out, and if
this happens while clocks are cut, it dies. This is at least what I saw
on my setup.

> And on 3430SDP even for module level wakeup after cutting clocks
> I see it gets looped in prcm_irq handler trying to clear wakeup status bits
> trying to handle same from serial_omap_irq calling resume_idle
> doesn't seem to help though if I use the same call from prcm_clear_mod_irqs
> helps in wakeup.

Not sure about this as I don't have OMAP3.

> Also patch series doesn't seem to apply cleanly on 3.0 kernel conflicts with
> 4430pm things.

This is probably true, I was forced to apply quite a large amount of
code on top of PM branch to get sleep to work properly on OMAP4.

Anyway, I'll continue testing on OMAP4 on top of your patch.

-Tero

> 
> --
> Thanks,
> Govindraj.R
> 
> 
> > Signed-off-by: Tero Kristo <t-kristo@ti.com>
> > ---
> >  arch/arm/mach-omap2/pm44xx.c     |    4 ----
> >  arch/arm/mach-omap2/serial.c     |    3 +++
> >  drivers/tty/serial/omap-serial.c |    7 +++++++
> >  3 files changed, 10 insertions(+), 4 deletions(-)
> >
> > diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
> > index f70a9ad..ac6aa77 100644
> > --- a/arch/arm/mach-omap2/pm44xx.c
> > +++ b/arch/arm/mach-omap2/pm44xx.c
> > @@ -103,10 +103,6 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
> >
> >        if (core_next_state < PWRDM_POWER_ON) {
> >                omap2_gpio_resume_after_idle();
> > -               omap_uart_resume_idle(0);
> > -               omap_uart_resume_idle(1);
> > -               omap_uart_resume_idle(2);
> > -               omap_uart_resume_idle(3);
> >        }
> >
> >        return;
> > diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> > index 6959d65..4cf8c4a 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"
> > @@ -574,6 +575,8 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
> >        ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
> >                                   IRQF_SHARED, "serial idle", (void *)uart);
> >        WARN_ON(ret);
> > +       ret = omap_prcm_register_pad_irq(uart->padconf, uart->irq);
> > +       WARN_ON(ret);
> >  }
> >
> >  void omap_uart_enable_irqs(int enable)
> > diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> > index 0275c28..cfe2e7c 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;
> > @@ -947,6 +951,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;
> > @@ -1303,6 +1309,7 @@ static int serial_omap_probe(struct platform_device *pdev)
> >                goto do_release_region;
> >
> >        platform_set_drvdata(pdev, up);
> > +       pr_info("OMAP UART %d is up\n", pdev->id);
> >        return 0;
> >  err:
> >        dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
> > --
> > 1.7.4.1
> >
> >
> > Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >



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


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

* Re: [PATCH 3/3] HACK: OMAP: Serial: use PRCM wakeup events to enable clocks
  2011-06-14 12:34   ` Govindraj
  2011-06-15  7:21     ` Tero Kristo
@ 2011-06-16 12:29     ` Tero Kristo
  1 sibling, 0 replies; 9+ messages in thread
From: Tero Kristo @ 2011-06-16 12:29 UTC (permalink / raw)
  To: Govindraj; +Cc: linux-omap, Basak, Partha, Sripathy, Vishwanath

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

Hi,

I was able to get this implementation to work on my setup, turned out
there was something wrong in the patch set I used on top of
linux-omap/pm to get cpuidle work on OMAP4. Anyway, attached two patches
I used for the UART part (to replace patch 3), patches 1/2 of the
original set did not need any modifications. I don't know what is the
issue with OMAP3, and I can't debug it as I don't have OMAP3 HW yet. I
should receive one in hopefully a couple of weeks though.

-Tero

On Tue, 2011-06-14 at 14:34 +0200, Govindraj wrote:
> On Thu, Jun 9, 2011 at 6:55 PM, Tero Kristo <t-kristo@ti.com> wrote:
> > This patch is just to test that the idea works generally, proper implementation
> > should be done for the OMAP UART driver.
> >
> 
> Doesn't seem to wake-up from off mode.
> (uart pad wakeup after enable_offmode and uart timeouts)
> 
> I used attached patch which has some more additions to this patch.
> (basically to get rid of prepare idle and resume idle calls from sram
> idle path and cut clocks independently).
> 
> IIUC we have to comment out all resume calls even from omap-serial.c
> irq_chaining should call uart_irq handler registered in serial.c
> and block sleep.
> 
> And on 3430SDP even for module level wakeup after cutting clocks
> I see it gets looped in prcm_irq handler trying to clear wakeup status bits
> trying to handle same from serial_omap_irq calling resume_idle
> doesn't seem to help though if I use the same call from prcm_clear_mod_irqs
> helps in wakeup.
> 
> Also patch series doesn't seem to apply cleanly on 3.0 kernel conflicts with
> 4430pm things.
> 
> --
> Thanks,
> Govindraj.R
> 
> 
> > Signed-off-by: Tero Kristo <t-kristo@ti.com>
> > ---
> >  arch/arm/mach-omap2/pm44xx.c     |    4 ----
> >  arch/arm/mach-omap2/serial.c     |    3 +++
> >  drivers/tty/serial/omap-serial.c |    7 +++++++
> >  3 files changed, 10 insertions(+), 4 deletions(-)
> >
> > diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
> > index f70a9ad..ac6aa77 100644
> > --- a/arch/arm/mach-omap2/pm44xx.c
> > +++ b/arch/arm/mach-omap2/pm44xx.c
> > @@ -103,10 +103,6 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
> >
> >        if (core_next_state < PWRDM_POWER_ON) {
> >                omap2_gpio_resume_after_idle();
> > -               omap_uart_resume_idle(0);
> > -               omap_uart_resume_idle(1);
> > -               omap_uart_resume_idle(2);
> > -               omap_uart_resume_idle(3);
> >        }
> >
> >        return;
> > diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> > index 6959d65..4cf8c4a 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"
> > @@ -574,6 +575,8 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
> >        ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
> >                                   IRQF_SHARED, "serial idle", (void *)uart);
> >        WARN_ON(ret);
> > +       ret = omap_prcm_register_pad_irq(uart->padconf, uart->irq);
> > +       WARN_ON(ret);
> >  }
> >
> >  void omap_uart_enable_irqs(int enable)
> > diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> > index 0275c28..cfe2e7c 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;
> > @@ -947,6 +951,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;
> > @@ -1303,6 +1309,7 @@ static int serial_omap_probe(struct platform_device *pdev)
> >                goto do_release_region;
> >
> >        platform_set_drvdata(pdev, up);
> > +       pr_info("OMAP UART %d is up\n", pdev->id);
> >        return 0;
> >  err:
> >        dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
> > --
> > 1.7.4.1
> >
> >
> > Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >


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


[-- Attachment #2: 0001-OMAP4-UART-remove-resume-prepare-idle-hooks-from-PM-.patch --]
[-- Type: text/x-patch, Size: 1230 bytes --]

>From 109743ff53f9fca746b41381cc1d603f042e9347 Mon Sep 17 00:00:00 2001
From: Tero Kristo <t-kristo@ti.com>
Date: Wed, 15 Jun 2011 15:01:18 +0300
Subject: [PATCH 1/2] OMAP4: UART: remove resume / prepare idle hooks from PM code

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

diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index df5e2ee..fd365c3 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -91,10 +91,6 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
 	core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
 
 	if (core_next_state < PWRDM_POWER_ON) {
-		omap_uart_prepare_idle(0);
-		omap_uart_prepare_idle(1);
-		omap_uart_prepare_idle(2);
-		omap_uart_prepare_idle(3);
 		omap2_gpio_prepare_for_idle(0);
 		omap4_trigger_ioctrl();
 	}
@@ -103,10 +99,6 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state)
 
 	if (core_next_state < PWRDM_POWER_ON) {
 		omap2_gpio_resume_after_idle();
-		omap_uart_resume_idle(0);
-		omap_uart_resume_idle(1);
-		omap_uart_resume_idle(2);
-		omap_uart_resume_idle(3);
 	}
 
 	return;
-- 
1.7.4.1


[-- Attachment #3: 0002-OMAP-serial-use-chained-interrupt-handler-for-IO-pad.patch --]
[-- Type: text/x-patch, Size: 3469 bytes --]

>From 52d23bb47644c1a48d10d552066ac86885137e8a Mon Sep 17 00:00:00 2001
From: Tero Kristo <t-kristo@ti.com>
Date: Thu, 16 Jun 2011 15:21:14 +0300
Subject: [PATCH 2/2] OMAP: serial: use chained interrupt handler for IO pad wakeup

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

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 6959d65..c443c0f 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"
@@ -386,6 +387,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)
@@ -397,36 +399,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);
-
-			/* Check for IO pad wakeup */
-			if (cpu_is_omap34xx() && uart->padconf) {
-				u16 p = omap_ctrl_readw(uart->padconf);
+			omap_uart_block_sleep(uart);
 
-				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 (uart->wk_st && uart->wk_mask)
-				if (__raw_readl(uart->wk_st) & uart->wk_mask)
-					omap_uart_block_sleep(uart);
 			return;
 		}
 	}
@@ -574,6 +563,8 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
 	ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
 				   IRQF_SHARED, "serial idle", (void *)uart);
 	WARN_ON(ret);
+	ret = omap_prcm_register_pad_irq(uart->padconf, uart->irq);
+	WARN_ON(ret);
 }
 
 void omap_uart_enable_irqs(int enable)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 0275c28..bbea099 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;
@@ -947,6 +951,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


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

* Re: [PATCH 0/3] PRCM chain interrupt handler
  2011-06-09 13:25 [PATCH 0/3] PRCM chain interrupt handler Tero Kristo
                   ` (2 preceding siblings ...)
  2011-06-09 13:25 ` [PATCH 3/3] HACK: OMAP: Serial: use PRCM wakeup events to enable clocks Tero Kristo
@ 2011-06-16 18:56 ` Kevin Hilman
  2011-06-17  7:44   ` Tero Kristo
  3 siblings, 1 reply; 9+ messages in thread
From: Kevin Hilman @ 2011-06-16 18:56 UTC (permalink / raw)
  To: Tero Kristo; +Cc: linux-omap

Hi Tero,

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

> Following set contains PRCM chain interrupt handling for OMAP3/4. 

What does this series apply to?  It doesn't seem to apply to mainline
(v3.0-rc3) or l-o master.

Kevin


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

* Re: [PATCH 0/3] PRCM chain interrupt handler
  2011-06-16 18:56 ` [PATCH 0/3] PRCM chain interrupt handler Kevin Hilman
@ 2011-06-17  7:44   ` Tero Kristo
  0 siblings, 0 replies; 9+ messages in thread
From: Tero Kristo @ 2011-06-17  7:44 UTC (permalink / raw)
  To: Hilman, Kevin; +Cc: linux-omap

On Thu, 2011-06-16 at 20:56 +0200, Hilman, Kevin wrote:
> Hi Tero,
> 
> Tero Kristo <t-kristo@ti.com> writes:
> 
> > Following set contains PRCM chain interrupt handling for OMAP3/4. 
> 
> What does this series apply to?  It doesn't seem to apply to mainline
> (v3.0-rc3) or l-o master.

You are right, it does not apply cleanly. OMAP4 part requires support
from OMAP4 PM which is not integrated yet (e.g. PRCM interrupt
handling.) I will repost the series in such format that applies on top
of PM branch and drop OMAP4 support out of it for now.

-Tero



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


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

end of thread, other threads:[~2011-06-17  7:44 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-09 13:25 [PATCH 0/3] PRCM chain interrupt handler Tero Kristo
2011-06-09 13:25 ` [PATCH 1/3] omap: prcm: switch to a chained IRQ handler mechanism Tero Kristo
2011-06-09 13:25 ` [PATCH 2/3] PRCM: Add support for PAD wakeup interrupts Tero Kristo
2011-06-09 13:25 ` [PATCH 3/3] HACK: OMAP: Serial: use PRCM wakeup events to enable clocks Tero Kristo
2011-06-14 12:34   ` Govindraj
2011-06-15  7:21     ` Tero Kristo
2011-06-16 12:29     ` Tero Kristo
2011-06-16 18:56 ` [PATCH 0/3] PRCM chain interrupt handler Kevin Hilman
2011-06-17  7:44   ` 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.